diff --git a/CHANGELOG.md b/CHANGELOG.md index 690e375..8de2769 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +### Version 1.0.39 Tag: v1.0.39 (2020-06-27) + * exoplayer update (@lishoujun) + * Floating window support (@dhk2) + * Various translations + ### Version 1.0.38 Tag: v1.0.38 (2020-06-21) * Multi server login address book * Clear search history (@dhk2) diff --git a/app/build.gradle b/app/build.gradle index 2e7865f..6016cfa 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -6,12 +6,12 @@ android { applicationId "net.schueller.peertube" minSdkVersion 21 targetSdkVersion 29 - versionCode 1038 - versionName "1.0.38" + versionCode 1039 + versionName "1.0.39" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" ext { libVersions = [ - exoplayer: '2.9.3' + exoplayer: '2.11.6' ] } javaCompileOptions { diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 11f705c..32125e5 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -34,7 +34,8 @@ android:name=".activity.VideoPlayActivity" android:configChanges="keyboard|keyboardHidden|orientation|screenSize|screenLayout|smallestScreenSize|uiMode" android:label="@string/title_activity_video_play" - android:launchMode="singleTop" + android:launchMode="singleInstance" + android:supportsPictureInPicture="true" android:theme="@style/AppTheme.NoActionBar" /> { + int position = viewHolder.getAdapterPosition(); + Server server = adapter.getServerAtPosition(position); +// Toast.makeText(ServerAddressBookActivity.this, "Deleting " + +// server.getServerName(), Toast.LENGTH_LONG).show(); + // Delete the server + mServerViewModel.delete(server); + }) + .setNegativeButton(android.R.string.no, (dialog, which) -> { + adapter.notifyItemChanged(viewHolder.getAdapterPosition()); + }) + .setIcon(android.R.drawable.ic_dialog_alert) + .show(); + } }); helper.attachToRecyclerView(recyclerView); diff --git a/app/src/main/java/net/schueller/peertube/activity/VideoPlayActivity.java b/app/src/main/java/net/schueller/peertube/activity/VideoPlayActivity.java index 3c6c3f5..28e80ad 100644 --- a/app/src/main/java/net/schueller/peertube/activity/VideoPlayActivity.java +++ b/app/src/main/java/net/schueller/peertube/activity/VideoPlayActivity.java @@ -19,16 +19,24 @@ package net.schueller.peertube.activity; +import android.annotation.SuppressLint; +import android.app.AppOpsManager; +import android.app.PictureInPictureParams; +import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; import android.content.res.Configuration; +import android.os.Build; import android.os.Bundle; import android.preference.PreferenceManager; +import androidx.annotation.RequiresApi; import androidx.appcompat.app.AppCompatActivity; +import android.text.TextUtils; import android.util.Log; +import android.util.Rational; import android.util.TypedValue; import android.view.WindowManager; @@ -39,6 +47,7 @@ import android.widget.RelativeLayout; import net.schueller.peertube.R; import net.schueller.peertube.fragment.VideoMetaDataFragment; import net.schueller.peertube.fragment.VideoPlayerFragment; +import net.schueller.peertube.service.VideoPlayerService; import java.util.Objects; @@ -71,13 +80,23 @@ public class VideoPlayActivity extends AppCompatActivity { // get video ID Intent intent = getIntent(); String videoUuid = intent.getStringExtra(VideoListActivity.EXTRA_VIDEOID); - Log.v(TAG, "click: " + videoUuid); - VideoPlayerFragment videoPlayerFragment = (VideoPlayerFragment) getSupportFragmentManager().findFragmentById(R.id.video_player_fragment); assert videoPlayerFragment != null; - videoPlayerFragment.start(videoUuid); + String playingVideo = videoPlayerFragment.getVideoUuid(); + Log.v(TAG, "oncreate click: " + videoUuid +" is trying to replace: "+playingVideo); + + if (TextUtils.isEmpty(playingVideo)){ + Log.v(TAG,"oncreate no video currently playing"); + videoPlayerFragment.start(videoUuid); + } else if(!playingVideo.equals(videoUuid)){ + Log.v(TAG,"oncreate different video playing currently"); + videoPlayerFragment.stopVideo(); + videoPlayerFragment.start(videoUuid); + } else { + Log.v(TAG,"oncreate same video playing currently"); + } // if we are in landscape set the video to fullscreen int orientation = this.getResources().getConfiguration().orientation; @@ -86,6 +105,36 @@ public class VideoPlayActivity extends AppCompatActivity { } } + @Override + protected void onNewIntent(Intent intent) { + super.onNewIntent(intent); + setIntent(intent); + VideoPlayerFragment videoPlayerFragment = (VideoPlayerFragment) + getSupportFragmentManager().findFragmentById(R.id.video_player_fragment); + assert videoPlayerFragment != null; + String videoUuid = intent.getStringExtra(VideoListActivity.EXTRA_VIDEOID); + Log.v(TAG, "new intent click: " + videoUuid +" is trying to replace: "+videoPlayerFragment.getVideoUuid()); + assert videoPlayerFragment != null; + String playingVideo = videoPlayerFragment.getVideoUuid(); + + if (TextUtils.isEmpty(playingVideo)){ + Log.v(TAG,"new intent no video currently playing"); + videoPlayerFragment.start(videoUuid); + } else if(!playingVideo.equals(videoUuid)){ + Log.v(TAG,"new intent different video playing currently"); + videoPlayerFragment.stopVideo(); + videoPlayerFragment.start(videoUuid); + } else { + Log.v(TAG,"new intent same video playing currently"); + } + + // if we are in landscape set the video to fullscreen + int orientation = this.getResources().getConfiguration().orientation; + if (orientation == Configuration.ORIENTATION_LANDSCAPE) { + setOrientation(true); + } + + } @Override public void onConfigurationChanged(Configuration newConfig) { @@ -199,16 +248,115 @@ public class VideoPlayActivity extends AppCompatActivity { Log.v(TAG, "onStart()..."); } + @SuppressLint("NewApi") + @Override + public void onUserLeaveHint () { + SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(this); + FragmentManager fragmentManager = getSupportFragmentManager(); + VideoPlayerFragment videoPlayerFragment = (VideoPlayerFragment) fragmentManager.findFragmentById(R.id.video_player_fragment); + VideoMetaDataFragment videoMetaFragment = (VideoMetaDataFragment) fragmentManager.findFragmentById(R.id.video_meta_data_fragment); + String backgroundBehavior = sharedPref.getString("pref_background_behavior","backgroundStop"); + + switch(backgroundBehavior){ + case "backgroundStop": + Log.v(TAG,"stop the video"); + videoPlayerFragment.pauseVideo(); + stopService(new Intent(this, VideoPlayerService.class)); + super.onBackPressed(); + break; + case "backgroundAudio": + Log.v(TAG,"play the Audio"); + super.onBackPressed(); + break; + case "backgroundFloat": + Log.v(TAG,"play in floating video"); + //canEnterPIPMode makes sure API level is high enough + if (canEnterPipMode(this)) { + Log.v(TAG, "enabling pip"); + enterPipMode(); + } else { + Log.v(TAG, "unable to use pip"); + } + break; + } + Log.v(TAG, "onUserLeaveHint()..."); + } + + // @RequiresApi(api = Build.VERSION_CODES.O) + @SuppressLint("NewApi") public void onBackPressed() { SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(this); + VideoPlayerFragment videoPlayerFragment = (VideoPlayerFragment) + getSupportFragmentManager().findFragmentById(R.id.video_player_fragment); + + //copying Youtube behavior to have back button exit full screen. + if (videoPlayerFragment.getIsFullscreen()){ + Log.v(TAG,"exiting full screen"); + videoPlayerFragment.fullScreenToggle(); + return; + } + if (sharedPref.getBoolean("pref_back_pause", true)) { - VideoPlayerFragment videoPlayerFragment = (VideoPlayerFragment) - getSupportFragmentManager().findFragmentById(R.id.video_player_fragment); assert videoPlayerFragment != null; videoPlayerFragment.pauseVideo(); } + + String backgroundBehavior = sharedPref.getString("pref_background_behavior","backgroundStop"); + switch (backgroundBehavior){ + case "backgroundStop": + Log.v(TAG,"stop the video"); + videoPlayerFragment.pauseVideo(); + stopService(new Intent(this, VideoPlayerService.class)); + super.onBackPressed(); + break; + case "backgroundAudio": + Log.v(TAG,"play the Audio"); + super.onBackPressed(); + break; + case "backgroundFloat": + Log.v(TAG,"play in floating video"); + //canEnterPIPMode makes sure API level is high enough + if (canEnterPipMode(this)) { + Log.v(TAG, "enabling pip"); + enterPipMode(); + //fixes problem where back press doesn't bring up video list after returning from PIP mode + Intent intentSettings = new Intent(this, VideoListActivity.class); + this.startActivity(intentSettings); + } else { + Log.v(TAG,"Unable to enter PIP mode"); + super.onBackPressed(); + } + break; + } Log.v(TAG, "onBackPressed()..."); - super.onBackPressed(); + } + public boolean canEnterPipMode(Context context) { + Log.v(TAG,"api version "+Build.VERSION.SDK_INT); + if (Build.VERSION.SDK_INT<28){ + return false; + } + AppOpsManager appOpsManager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE); + return (AppOpsManager.MODE_ALLOWED== appOpsManager.checkOpNoThrow(AppOpsManager.OPSTR_PICTURE_IN_PICTURE, android.os.Process.myUid(), context.getPackageName())); + } + @RequiresApi(api = Build.VERSION_CODES.O) + public void enterPipMode() { + Rational rational = new Rational(239, 100); + Log.v(TAG,rational.toString()); + PictureInPictureParams mParams = + new PictureInPictureParams.Builder() + .setAspectRatio(rational) +// .setSourceRectHint(new Rect(0,500,400,600)) + .build(); + + enterPictureInPictureMode(mParams); + } + @Override + public void onPictureInPictureModeChanged (boolean isInPictureInPictureMode, Configuration newConfig) { + if (isInPictureInPictureMode) { + Log.v(TAG,"switched to pip "); + } else { + Log.v(TAG,"switched to normal"); + } } } diff --git a/app/src/main/java/net/schueller/peertube/fragment/VideoPlayerFragment.java b/app/src/main/java/net/schueller/peertube/fragment/VideoPlayerFragment.java index 39e142d..a37af1c 100644 --- a/app/src/main/java/net/schueller/peertube/fragment/VideoPlayerFragment.java +++ b/app/src/main/java/net/schueller/peertube/fragment/VideoPlayerFragment.java @@ -18,6 +18,7 @@ package net.schueller.peertube.fragment; import android.app.Activity; +import android.app.AppOpsManager; import android.content.ComponentName; import android.content.Context; import android.content.Intent; @@ -25,12 +26,15 @@ import android.content.ServiceConnection; import android.content.SharedPreferences; import android.content.pm.ActivityInfo; import android.net.Uri; +import android.os.Build; import android.os.Bundle; import android.os.Environment; import android.os.IBinder; import android.preference.PreferenceManager; import android.util.Log; +import android.view.GestureDetector; import android.view.LayoutInflater; +import android.view.MotionEvent; import android.view.Surface; import android.view.View; import android.view.ViewGroup; @@ -65,6 +69,7 @@ import net.schueller.peertube.service.VideoPlayerService; import java.util.Objects; import androidx.annotation.NonNull; +import androidx.annotation.RequiresApi; import androidx.fragment.app.Fragment; import retrofit2.Call; import retrofit2.Callback; @@ -83,7 +88,7 @@ public class VideoPlayerFragment extends Fragment implements VideoRendererEventL private LinearLayout torrentStatus; private static final String TAG = "VideoPlayerFragment"; - + private GestureDetector mDetector; private ServiceConnection mConnection = new ServiceConnection() { @@ -135,6 +140,9 @@ public class VideoPlayerFragment extends Fragment implements VideoRendererEventL simpleExoPlayerView.setControllerShowTimeoutMs(1000); simpleExoPlayerView.setResizeMode(AspectRatioFrameLayout.RESIZE_MODE_FIT); + mDetector = new GestureDetector(context, new MyGestureListener()); + simpleExoPlayerView.setOnTouchListener(touchListener); + torrentStatus = activity.findViewById(R.id.exo_torrent_status); // Full screen Icon @@ -146,13 +154,7 @@ public class VideoPlayerFragment extends Fragment implements VideoRendererEventL fullscreenButton.setOnClickListener(view -> { Log.d(TAG, "Fullscreen"); - if (!isFullscreen) { - isFullscreen = true; - activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); - } else { - isFullscreen = false; - activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); - } + fullScreenToggle(); }); if (!mBound) { @@ -182,7 +184,7 @@ public class VideoPlayerFragment extends Fragment implements VideoRendererEventL mService.setCurrentVideo(video); if (video == null) { - Toast.makeText(context, "Something went wrong...Please try later!", Toast.LENGTH_SHORT).show(); + Toast.makeText(context, "Unable to retrieve video information, try again later.", Toast.LENGTH_SHORT).show(); return; } @@ -193,7 +195,7 @@ public class VideoPlayerFragment extends Fragment implements VideoRendererEventL @Override public void onFailure(@NonNull Call