503 lines
20 KiB
Java
503 lines
20 KiB
Java
/*
|
|
* Copyright (C) 2020 Stefan Schüller <sschueller@techdroid.com>
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU Affero General Public License as
|
|
* published by the Free Software Foundation, either version 3 of the
|
|
* License, or (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU Affero General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Affero General Public License
|
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
package net.schueller.peertube.activity;
|
|
|
|
|
|
import android.annotation.SuppressLint;
|
|
import android.app.AppOpsManager;
|
|
import android.app.PendingIntent;
|
|
import android.app.PictureInPictureParams;
|
|
import android.app.RemoteAction;
|
|
import android.content.BroadcastReceiver;
|
|
import android.content.Context;
|
|
import android.content.Intent;
|
|
import android.content.IntentFilter;
|
|
import android.content.SharedPreferences;
|
|
import android.content.res.Configuration;
|
|
import android.graphics.drawable.Icon;
|
|
import android.os.Build;
|
|
import android.os.Bundle;
|
|
|
|
import android.preference.PreferenceManager;
|
|
|
|
import androidx.annotation.NonNull;
|
|
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;
|
|
import android.widget.FrameLayout;
|
|
|
|
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.ArrayList;
|
|
|
|
import androidx.fragment.app.FragmentManager;
|
|
import androidx.fragment.app.FragmentTransaction;
|
|
|
|
|
|
import static com.google.android.exoplayer2.ui.PlayerNotificationManager.ACTION_PAUSE;
|
|
import static com.google.android.exoplayer2.ui.PlayerNotificationManager.ACTION_PLAY;
|
|
import static com.google.android.exoplayer2.ui.PlayerNotificationManager.ACTION_STOP;
|
|
import static net.schueller.peertube.helper.VideoHelper.canEnterPipMode;
|
|
|
|
public class VideoPlayActivity extends AppCompatActivity {
|
|
|
|
private static final String TAG = "VideoPlayActivity";
|
|
|
|
static boolean floatMode = false;
|
|
|
|
private static final int REQUEST_CODE = 101;
|
|
private BroadcastReceiver receiver;
|
|
|
|
//This can only be called when in entering pip mode which can't happen if the device doesn't support pip mode.
|
|
@SuppressLint("NewApi")
|
|
public void makePipControls() {
|
|
FragmentManager fragmentManager = getSupportFragmentManager();
|
|
VideoPlayerFragment videoPlayerFragment = (VideoPlayerFragment) fragmentManager.findFragmentById(R.id.video_player_fragment);
|
|
|
|
ArrayList<RemoteAction> actions = new ArrayList<>();
|
|
|
|
Intent actionIntent = new Intent(getString(R.string.app_background_audio));
|
|
PendingIntent pendingIntent = PendingIntent.getBroadcast(getApplicationContext(), REQUEST_CODE, actionIntent, 0);
|
|
@SuppressLint({"NewApi", "LocalSuppress"}) Icon icon = Icon.createWithResource(getApplicationContext(), android.R.drawable.stat_sys_speakerphone);
|
|
@SuppressLint({"NewApi", "LocalSuppress"}) RemoteAction remoteAction = new RemoteAction(icon, "close pip", "from pip window custom command", pendingIntent);
|
|
actions.add(remoteAction);
|
|
|
|
actionIntent = new Intent(ACTION_STOP);
|
|
pendingIntent = PendingIntent.getBroadcast(getApplicationContext(), REQUEST_CODE, actionIntent, 0);
|
|
icon = Icon.createWithResource(getApplicationContext(), com.google.android.exoplayer2.ui.R.drawable.exo_notification_stop);
|
|
remoteAction = new RemoteAction(icon, "play", "stop the media", pendingIntent);
|
|
actions.add(remoteAction);
|
|
|
|
assert videoPlayerFragment != null;
|
|
if (videoPlayerFragment.isPaused()) {
|
|
Log.e(TAG, "setting actions with play button");
|
|
actionIntent = new Intent(ACTION_PLAY);
|
|
pendingIntent = PendingIntent.getBroadcast(getApplicationContext(), REQUEST_CODE, actionIntent, 0);
|
|
icon = Icon.createWithResource(getApplicationContext(), com.google.android.exoplayer2.ui.R.drawable.exo_notification_play);
|
|
remoteAction = new RemoteAction(icon, "play", "play the media", pendingIntent);
|
|
} else {
|
|
Log.e(TAG, "setting actions with pause button");
|
|
actionIntent = new Intent(ACTION_PAUSE);
|
|
pendingIntent = PendingIntent.getBroadcast(getApplicationContext(), REQUEST_CODE, actionIntent, 0);
|
|
icon = Icon.createWithResource(getApplicationContext(), com.google.android.exoplayer2.ui.R.drawable.exo_notification_pause);
|
|
remoteAction = new RemoteAction(icon, "pause", "pause the media", pendingIntent);
|
|
}
|
|
actions.add(remoteAction);
|
|
|
|
|
|
//add custom actions to pip window
|
|
PictureInPictureParams params =
|
|
new PictureInPictureParams.Builder()
|
|
.setActions(actions)
|
|
.build();
|
|
setPictureInPictureParams(params);
|
|
}
|
|
|
|
public void changedToPipMode() {
|
|
FragmentManager fragmentManager = getSupportFragmentManager();
|
|
VideoPlayerFragment videoPlayerFragment = (VideoPlayerFragment) fragmentManager.findFragmentById(R.id.video_player_fragment);
|
|
|
|
assert videoPlayerFragment != null;
|
|
videoPlayerFragment.showControls(false);
|
|
//create custom actions
|
|
makePipControls();
|
|
|
|
//setup receiver to handle customer actions
|
|
IntentFilter filter = new IntentFilter();
|
|
filter.addAction(ACTION_STOP);
|
|
filter.addAction(ACTION_PAUSE);
|
|
filter.addAction(ACTION_PLAY);
|
|
filter.addAction((getString(R.string.app_background_audio)));
|
|
receiver = new BroadcastReceiver() {
|
|
@Override
|
|
public void onReceive(Context context, Intent intent) {
|
|
String action = intent.getAction();
|
|
assert action != null;
|
|
if (action.equals(ACTION_PAUSE)) {
|
|
videoPlayerFragment.pauseVideo();
|
|
makePipControls();
|
|
}
|
|
if (action.equals(ACTION_PLAY)) {
|
|
videoPlayerFragment.unPauseVideo();
|
|
makePipControls();
|
|
}
|
|
|
|
if (action.equals(getString(R.string.app_background_audio))) {
|
|
unregisterReceiver(receiver);
|
|
finish();
|
|
}
|
|
if (action.equals(ACTION_STOP)) {
|
|
unregisterReceiver(receiver);
|
|
finishAndRemoveTask();
|
|
}
|
|
}
|
|
};
|
|
registerReceiver(receiver, filter);
|
|
|
|
Log.v(TAG, "switched to pip ");
|
|
floatMode = true;
|
|
videoPlayerFragment.showControls(false);
|
|
}
|
|
|
|
public void changedToNormalMode() {
|
|
FragmentManager fragmentManager = getSupportFragmentManager();
|
|
VideoPlayerFragment videoPlayerFragment = (VideoPlayerFragment) fragmentManager.findFragmentById(R.id.video_player_fragment);
|
|
|
|
assert videoPlayerFragment != null;
|
|
videoPlayerFragment.showControls(true);
|
|
if (receiver != null) {
|
|
unregisterReceiver(receiver);
|
|
}
|
|
Log.v(TAG, "switched to normal");
|
|
floatMode = false;
|
|
}
|
|
|
|
@Override
|
|
protected void onCreate(Bundle savedInstanceState) {
|
|
super.onCreate(savedInstanceState);
|
|
|
|
// Set theme
|
|
SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(this);
|
|
setTheme(getResources().getIdentifier(
|
|
sharedPref.getString(
|
|
getString(R.string.pref_theme_key),
|
|
getString(R.string.app_default_theme)
|
|
),
|
|
"style",
|
|
getPackageName())
|
|
);
|
|
|
|
setContentView(R.layout.activity_video_play);
|
|
|
|
// get video ID
|
|
Intent intent = getIntent();
|
|
String videoUuid = intent.getStringExtra(VideoListActivity.EXTRA_VIDEOID);
|
|
VideoPlayerFragment videoPlayerFragment = (VideoPlayerFragment)
|
|
getSupportFragmentManager().findFragmentById(R.id.video_player_fragment);
|
|
|
|
assert videoPlayerFragment != null;
|
|
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;
|
|
if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
|
|
setOrientation(true);
|
|
}
|
|
}
|
|
|
|
@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());
|
|
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(@NonNull Configuration newConfig) {
|
|
Log.v(TAG, "onConfigurationChanged()...");
|
|
|
|
super.onConfigurationChanged(newConfig);
|
|
|
|
// Checking the orientation changes of the screen
|
|
if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
|
|
setOrientation(true);
|
|
} else if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT) {
|
|
setOrientation(false);
|
|
}
|
|
}
|
|
|
|
private void setOrientation(Boolean isLandscape) {
|
|
FragmentManager fragmentManager = getSupportFragmentManager();
|
|
VideoPlayerFragment videoPlayerFragment = (VideoPlayerFragment) fragmentManager.findFragmentById(R.id.video_player_fragment);
|
|
VideoMetaDataFragment videoMetaFragment = (VideoMetaDataFragment) fragmentManager.findFragmentById(R.id.video_meta_data_fragment);
|
|
|
|
assert videoPlayerFragment != null;
|
|
RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) videoPlayerFragment.requireView().getLayoutParams();
|
|
params.width = FrameLayout.LayoutParams.MATCH_PARENT;
|
|
params.height = isLandscape ? FrameLayout.LayoutParams.MATCH_PARENT : (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 250, getResources().getDisplayMetrics());
|
|
|
|
videoPlayerFragment.requireView().setLayoutParams(params);
|
|
|
|
if (videoMetaFragment != null) {
|
|
FragmentTransaction transaction = fragmentManager.beginTransaction()
|
|
.setCustomAnimations(android.R.anim.fade_in, android.R.anim.fade_out);
|
|
|
|
if (isLandscape) {
|
|
transaction.hide(videoMetaFragment);
|
|
} else {
|
|
transaction.show(videoMetaFragment);
|
|
}
|
|
|
|
transaction.commit();
|
|
}
|
|
|
|
videoPlayerFragment.setIsFullscreen(isLandscape);
|
|
|
|
if ( isLandscape ) {
|
|
getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
|
|
} else {
|
|
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
protected void onDestroy() {
|
|
VideoPlayerFragment videoPlayerFragment = (VideoPlayerFragment)
|
|
getSupportFragmentManager().findFragmentById(R.id.video_player_fragment);
|
|
|
|
assert videoPlayerFragment != null;
|
|
videoPlayerFragment.destroyVideo();
|
|
|
|
super.onDestroy();
|
|
Log.v(TAG, "onDestroy...");
|
|
}
|
|
|
|
@Override
|
|
protected void onPause() {
|
|
super.onPause();
|
|
Log.v(TAG, "onPause()...");
|
|
}
|
|
|
|
@Override
|
|
protected void onResume() {
|
|
super.onResume();
|
|
Log.v(TAG, "onResume()...");
|
|
}
|
|
|
|
@Override
|
|
protected void onStop() {
|
|
super.onStop();
|
|
|
|
VideoPlayerFragment videoPlayerFragment = (VideoPlayerFragment)
|
|
getSupportFragmentManager().findFragmentById(R.id.video_player_fragment);
|
|
|
|
assert videoPlayerFragment != null;
|
|
videoPlayerFragment.stopVideo();
|
|
|
|
Log.v(TAG, "onStop()...");
|
|
}
|
|
|
|
@Override
|
|
protected void onStart() {
|
|
super.onStart();
|
|
|
|
Log.v(TAG, "onStart()...");
|
|
}
|
|
|
|
@SuppressLint("NewApi")
|
|
@Override
|
|
public void onUserLeaveHint() {
|
|
|
|
Log.v(TAG, "onUserLeaveHint()...");
|
|
|
|
SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(this);
|
|
FragmentManager fragmentManager = getSupportFragmentManager();
|
|
VideoPlayerFragment videoPlayerFragment = (VideoPlayerFragment) fragmentManager.findFragmentById(R.id.video_player_fragment);
|
|
VideoMetaDataFragment videoMetaDataFragment = (VideoMetaDataFragment) fragmentManager.findFragmentById(R.id.video_meta_data_fragment);
|
|
|
|
String backgroundBehavior = sharedPref.getString(getString(R.string.pref_background_behavior_key), getString(R.string.pref_background_stop_key));
|
|
|
|
assert videoPlayerFragment != null;
|
|
assert backgroundBehavior != null;
|
|
if ( videoMetaDataFragment.isLeaveAppExpected() )
|
|
{
|
|
super.onUserLeaveHint();
|
|
return;
|
|
}
|
|
|
|
if (backgroundBehavior.equals(getString(R.string.pref_background_stop_key))) {
|
|
Log.v(TAG, "stop the video");
|
|
|
|
videoPlayerFragment.pauseVideo();
|
|
stopService(new Intent(this, VideoPlayerService.class));
|
|
super.onBackPressed();
|
|
|
|
} else if (backgroundBehavior.equals(getString(R.string.pref_background_audio_key))) {
|
|
Log.v(TAG, "play the Audio");
|
|
super.onBackPressed();
|
|
|
|
} else if (backgroundBehavior.equals(getString(R.string.pref_background_float_key))) {
|
|
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");
|
|
}
|
|
|
|
} else {
|
|
// Deal with bad entries from older version
|
|
Log.v(TAG, "No setting, fallback");
|
|
super.onBackPressed();
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
// @RequiresApi(api = Build.VERSION_CODES.O)
|
|
@SuppressLint("NewApi")
|
|
public void onBackPressed() {
|
|
|
|
Log.v(TAG, "onBackPressed()...");
|
|
|
|
SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(this);
|
|
VideoPlayerFragment videoPlayerFragment = (VideoPlayerFragment)
|
|
getSupportFragmentManager().findFragmentById(R.id.video_player_fragment);
|
|
|
|
assert videoPlayerFragment != null;
|
|
|
|
// copying Youtube behavior to have back button exit full screen.
|
|
if (videoPlayerFragment.getIsFullscreen()) {
|
|
Log.v(TAG, "exiting full screen");
|
|
videoPlayerFragment.fullScreenToggle();
|
|
return;
|
|
}
|
|
// pause video if pref is enabled
|
|
if (sharedPref.getBoolean(getString(R.string.pref_back_pause_key), true)) {
|
|
videoPlayerFragment.pauseVideo();
|
|
}
|
|
|
|
String backgroundBehavior = sharedPref.getString(getString(R.string.pref_background_behavior_key), getString(R.string.pref_background_stop_key));
|
|
|
|
assert backgroundBehavior != null;
|
|
|
|
if (backgroundBehavior.equals(getString(R.string.pref_background_stop_key))) {
|
|
Log.v(TAG, "stop the video");
|
|
videoPlayerFragment.pauseVideo();
|
|
stopService(new Intent(this, VideoPlayerService.class));
|
|
super.onBackPressed();
|
|
|
|
} else if (backgroundBehavior.equals(getString(R.string.pref_background_audio_key))) {
|
|
Log.v(TAG, "play the Audio");
|
|
super.onBackPressed();
|
|
|
|
} else if (backgroundBehavior.equals(getString(R.string.pref_background_float_key))) {
|
|
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();
|
|
}
|
|
|
|
} else {
|
|
// Deal with bad entries from older version
|
|
Log.v(TAG, "No setting, fallback");
|
|
super.onBackPressed();
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
@RequiresApi(api = Build.VERSION_CODES.O)
|
|
public void enterPipMode() {
|
|
final FragmentManager fragmentManager = getSupportFragmentManager();
|
|
final VideoPlayerFragment videoPlayerFragment = (VideoPlayerFragment) fragmentManager.findFragmentById( R.id.video_player_fragment );
|
|
|
|
if ( videoPlayerFragment.getVideoAspectRatio() == 0 ) {
|
|
Log.i( TAG, "impossible to switch to pip" );
|
|
} else {
|
|
Rational rational = new Rational( (int) ( videoPlayerFragment.getVideoAspectRatio() * 100 ), 100 );
|
|
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) {
|
|
FragmentManager fragmentManager = getSupportFragmentManager();
|
|
VideoPlayerFragment videoPlayerFragment = (VideoPlayerFragment) fragmentManager.findFragmentById(R.id.video_player_fragment);
|
|
|
|
if (videoPlayerFragment != null) {
|
|
|
|
if (isInPictureInPictureMode) {
|
|
changedToPipMode();
|
|
Log.v(TAG, "switched to pip ");
|
|
videoPlayerFragment.useController(false);
|
|
} else {
|
|
changedToNormalMode();
|
|
Log.v(TAG, "switched to normal");
|
|
videoPlayerFragment.useController(true);
|
|
}
|
|
|
|
} else {
|
|
Log.e(TAG, "videoPlayerFragment is NULL");
|
|
}
|
|
}
|
|
|
|
}
|