Merge pull request #2506 from ByteHamster/picture-in-picture
Added Picure in picture
This commit is contained in:
commit
a9e269b3bf
|
@ -222,7 +222,8 @@
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".activity.VideoplayerActivity"
|
android:name=".activity.VideoplayerActivity"
|
||||||
android:configChanges="keyboardHidden|orientation"
|
android:configChanges="keyboardHidden|orientation|screenSize|screenLayout|smallestScreenSize"
|
||||||
|
android:supportsPictureInPicture="true"
|
||||||
android:screenOrientation="sensorLandscape">
|
android:screenOrientation="sensorLandscape">
|
||||||
<meta-data
|
<meta-data
|
||||||
android:name="android.support.PARENT_ACTIVITY"
|
android:name="android.support.PARENT_ACTIVITY"
|
||||||
|
|
|
@ -46,6 +46,7 @@ import de.danoeh.antennapod.core.util.Flavors;
|
||||||
import de.danoeh.antennapod.core.util.ShareUtils;
|
import de.danoeh.antennapod.core.util.ShareUtils;
|
||||||
import de.danoeh.antennapod.core.util.StorageUtils;
|
import de.danoeh.antennapod.core.util.StorageUtils;
|
||||||
import de.danoeh.antennapod.core.util.Supplier;
|
import de.danoeh.antennapod.core.util.Supplier;
|
||||||
|
import de.danoeh.antennapod.core.util.gui.PictureInPictureUtil;
|
||||||
import de.danoeh.antennapod.core.util.playback.MediaPlayerError;
|
import de.danoeh.antennapod.core.util.playback.MediaPlayerError;
|
||||||
import de.danoeh.antennapod.core.util.playback.Playable;
|
import de.danoeh.antennapod.core.util.playback.Playable;
|
||||||
import de.danoeh.antennapod.core.util.playback.PlaybackController;
|
import de.danoeh.antennapod.core.util.playback.PlaybackController;
|
||||||
|
@ -225,9 +226,11 @@ public abstract class MediaplayerActivity extends CastEnabledActivity implements
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onPause() {
|
protected void onPause() {
|
||||||
if(controller != null) {
|
if (!PictureInPictureUtil.isInPictureInPictureMode(this)) {
|
||||||
controller.reinitServiceIfPaused();
|
if (controller != null) {
|
||||||
controller.pause();
|
controller.reinitServiceIfPaused();
|
||||||
|
controller.pause();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
super.onPause();
|
super.onPause();
|
||||||
}
|
}
|
||||||
|
@ -379,6 +382,7 @@ public abstract class MediaplayerActivity extends CastEnabledActivity implements
|
||||||
} else {
|
} else {
|
||||||
startActivity(intent);
|
startActivity(intent);
|
||||||
}
|
}
|
||||||
|
finish();
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
if (media != null) {
|
if (media != null) {
|
||||||
|
|
|
@ -10,27 +10,31 @@ import android.support.v4.view.WindowCompat;
|
||||||
import android.support.v7.app.ActionBar;
|
import android.support.v7.app.ActionBar;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.util.Pair;
|
import android.util.Pair;
|
||||||
|
import android.view.Menu;
|
||||||
|
import android.view.MenuItem;
|
||||||
import android.view.MotionEvent;
|
import android.view.MotionEvent;
|
||||||
import android.view.SurfaceHolder;
|
import android.view.SurfaceHolder;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.WindowManager;
|
import android.view.WindowManager;
|
||||||
import android.view.animation.Animation;
|
import android.view.animation.Animation;
|
||||||
import android.view.animation.AnimationUtils;
|
import android.view.animation.AnimationUtils;
|
||||||
|
import android.widget.FrameLayout;
|
||||||
import android.widget.LinearLayout;
|
import android.widget.LinearLayout;
|
||||||
import android.widget.ProgressBar;
|
import android.widget.ProgressBar;
|
||||||
import android.widget.SeekBar;
|
import android.widget.SeekBar;
|
||||||
|
|
||||||
import java.lang.ref.WeakReference;
|
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
|
||||||
|
|
||||||
import de.danoeh.antennapod.R;
|
import de.danoeh.antennapod.R;
|
||||||
import de.danoeh.antennapod.core.feed.MediaType;
|
import de.danoeh.antennapod.core.feed.MediaType;
|
||||||
|
import de.danoeh.antennapod.core.preferences.UserPreferences;
|
||||||
import de.danoeh.antennapod.core.service.playback.PlaybackService;
|
import de.danoeh.antennapod.core.service.playback.PlaybackService;
|
||||||
import de.danoeh.antennapod.core.service.playback.PlayerStatus;
|
import de.danoeh.antennapod.core.service.playback.PlayerStatus;
|
||||||
|
import de.danoeh.antennapod.core.util.gui.PictureInPictureUtil;
|
||||||
import de.danoeh.antennapod.core.util.playback.ExternalMedia;
|
import de.danoeh.antennapod.core.util.playback.ExternalMedia;
|
||||||
import de.danoeh.antennapod.core.util.playback.Playable;
|
import de.danoeh.antennapod.core.util.playback.Playable;
|
||||||
import de.danoeh.antennapod.view.AspectRatioVideoView;
|
import de.danoeh.antennapod.view.AspectRatioVideoView;
|
||||||
|
|
||||||
|
import java.lang.ref.WeakReference;
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Activity for playing video files.
|
* Activity for playing video files.
|
||||||
*/
|
*/
|
||||||
|
@ -52,6 +56,7 @@ public class VideoplayerActivity extends MediaplayerActivity {
|
||||||
private LinearLayout videoOverlay;
|
private LinearLayout videoOverlay;
|
||||||
private AspectRatioVideoView videoview;
|
private AspectRatioVideoView videoview;
|
||||||
private ProgressBar progressIndicator;
|
private ProgressBar progressIndicator;
|
||||||
|
private FrameLayout videoframe;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void chooseTheme() {
|
protected void chooseTheme() {
|
||||||
|
@ -95,11 +100,28 @@ public class VideoplayerActivity extends MediaplayerActivity {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onStop() {
|
||||||
|
super.onStop();
|
||||||
|
if (!PictureInPictureUtil.isInPictureInPictureMode(this)) {
|
||||||
|
videoControlsHider.stop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onUserLeaveHint () {
|
||||||
|
if (!PictureInPictureUtil.isInPictureInPictureMode(this) && UserPreferences.getVideoBackgroundBehavior()
|
||||||
|
== UserPreferences.VideoBackgroundBehavior.PICTURE_IN_PICTURE) {
|
||||||
|
compatEnterPictureInPicture();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onPause() {
|
protected void onPause() {
|
||||||
videoControlsHider.stop();
|
if (!PictureInPictureUtil.isInPictureInPictureMode(this)) {
|
||||||
if (controller != null && controller.getStatus() == PlayerStatus.PLAYING) {
|
if (controller != null && controller.getStatus() == PlayerStatus.PLAYING) {
|
||||||
controller.pause();
|
controller.pause();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
super.onPause();
|
super.onPause();
|
||||||
}
|
}
|
||||||
|
@ -127,7 +149,7 @@ public class VideoplayerActivity extends MediaplayerActivity {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void setupGUI() {
|
protected void setupGUI() {
|
||||||
if(isSetup.getAndSet(true)) {
|
if (isSetup.getAndSet(true)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
super.setupGUI();
|
super.setupGUI();
|
||||||
|
@ -135,20 +157,23 @@ public class VideoplayerActivity extends MediaplayerActivity {
|
||||||
controls = (LinearLayout) findViewById(R.id.controls);
|
controls = (LinearLayout) findViewById(R.id.controls);
|
||||||
videoOverlay = (LinearLayout) findViewById(R.id.overlay);
|
videoOverlay = (LinearLayout) findViewById(R.id.overlay);
|
||||||
videoview = (AspectRatioVideoView) findViewById(R.id.videoview);
|
videoview = (AspectRatioVideoView) findViewById(R.id.videoview);
|
||||||
|
videoframe = (FrameLayout) findViewById(R.id.videoframe);
|
||||||
progressIndicator = (ProgressBar) findViewById(R.id.progressIndicator);
|
progressIndicator = (ProgressBar) findViewById(R.id.progressIndicator);
|
||||||
videoview.getHolder().addCallback(surfaceHolderCallback);
|
videoview.getHolder().addCallback(surfaceHolderCallback);
|
||||||
videoview.setOnTouchListener(onVideoviewTouched);
|
videoframe.setOnTouchListener(onVideoviewTouched);
|
||||||
|
videoOverlay.setOnTouchListener((view, motionEvent) -> true); // To suppress touches directly below the slider
|
||||||
|
|
||||||
if (Build.VERSION.SDK_INT >= 16) {
|
if (Build.VERSION.SDK_INT >= 16) {
|
||||||
videoview.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION);
|
videoview.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION);
|
||||||
}
|
}
|
||||||
if (Build.VERSION.SDK_INT >= 14) {
|
videoOverlay.setFitsSystemWindows(true);
|
||||||
videoOverlay.setFitsSystemWindows(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
setupVideoControlsToggler();
|
setupVideoControlsToggler();
|
||||||
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
|
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
|
||||||
WindowManager.LayoutParams.FLAG_FULLSCREEN);
|
WindowManager.LayoutParams.FLAG_FULLSCREEN);
|
||||||
|
|
||||||
|
videoframe.getViewTreeObserver().addOnGlobalLayoutListener(() ->
|
||||||
|
videoview.setAvailableSize(videoframe.getWidth(), videoframe.getHeight()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -176,6 +201,9 @@ public class VideoplayerActivity extends MediaplayerActivity {
|
||||||
|
|
||||||
private final View.OnTouchListener onVideoviewTouched = (v, event) -> {
|
private final View.OnTouchListener onVideoviewTouched = (v, event) -> {
|
||||||
if (event.getAction() == MotionEvent.ACTION_DOWN) {
|
if (event.getAction() == MotionEvent.ACTION_DOWN) {
|
||||||
|
if (PictureInPictureUtil.isInPictureInPictureMode(this)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
videoControlsHider.stop();
|
videoControlsHider.stop();
|
||||||
toggleVideoControlsVisibility();
|
toggleVideoControlsVisibility();
|
||||||
if (videoControlsShowing) {
|
if (videoControlsShowing) {
|
||||||
|
@ -260,7 +288,9 @@ public class VideoplayerActivity extends MediaplayerActivity {
|
||||||
public void surfaceDestroyed(SurfaceHolder holder) {
|
public void surfaceDestroyed(SurfaceHolder holder) {
|
||||||
Log.d(TAG, "Videosurface was destroyed");
|
Log.d(TAG, "Videosurface was destroyed");
|
||||||
videoSurfaceCreated = false;
|
videoSurfaceCreated = false;
|
||||||
if (controller != null && !destroyingDueToReload) {
|
if (controller != null && !destroyingDueToReload
|
||||||
|
&& UserPreferences.getVideoBackgroundBehavior()
|
||||||
|
!= UserPreferences.VideoBackgroundBehavior.CONTINUE_PLAYING) {
|
||||||
controller.notifyVideoSurfaceAbandoned();
|
controller.notifyVideoSurfaceAbandoned();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -269,6 +299,13 @@ public class VideoplayerActivity extends MediaplayerActivity {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onReloadNotification(int notificationCode) {
|
protected void onReloadNotification(int notificationCode) {
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && PictureInPictureUtil.isInPictureInPictureMode(this)) {
|
||||||
|
if (notificationCode == PlaybackService.EXTRA_CODE_AUDIO
|
||||||
|
|| notificationCode == PlaybackService.EXTRA_CODE_CAST) {
|
||||||
|
finish();
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (notificationCode == PlaybackService.EXTRA_CODE_AUDIO) {
|
if (notificationCode == PlaybackService.EXTRA_CODE_AUDIO) {
|
||||||
Log.d(TAG, "ReloadNotification received, switching to Audioplayer now");
|
Log.d(TAG, "ReloadNotification received, switching to Audioplayer now");
|
||||||
destroyingDueToReload = true;
|
destroyingDueToReload = true;
|
||||||
|
@ -313,28 +350,31 @@ public class VideoplayerActivity extends MediaplayerActivity {
|
||||||
videoOverlay.startAnimation(animation);
|
videoOverlay.startAnimation(animation);
|
||||||
controls.startAnimation(animation);
|
controls.startAnimation(animation);
|
||||||
}
|
}
|
||||||
if (Build.VERSION.SDK_INT >= 14) {
|
videoview.setSystemUiVisibility(View.SYSTEM_UI_FLAG_VISIBLE);
|
||||||
videoview.setSystemUiVisibility(View.SYSTEM_UI_FLAG_VISIBLE);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressLint("NewApi")
|
@SuppressLint("NewApi")
|
||||||
private void hideVideoControls() {
|
private void hideVideoControls(boolean showAnimation) {
|
||||||
final Animation animation = AnimationUtils.loadAnimation(this, R.anim.fade_out);
|
if (showAnimation) {
|
||||||
if (animation != null) {
|
final Animation animation = AnimationUtils.loadAnimation(this, R.anim.fade_out);
|
||||||
videoOverlay.startAnimation(animation);
|
if (animation != null) {
|
||||||
controls.startAnimation(animation);
|
videoOverlay.startAnimation(animation);
|
||||||
}
|
controls.startAnimation(animation);
|
||||||
if (Build.VERSION.SDK_INT >= 14) {
|
}
|
||||||
int videoviewFlag = (Build.VERSION.SDK_INT >= 16) ? View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION : 0;
|
|
||||||
getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LOW_PROFILE | View.SYSTEM_UI_FLAG_FULLSCREEN
|
|
||||||
| View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | videoviewFlag);
|
|
||||||
videoOverlay.setFitsSystemWindows(true);
|
|
||||||
}
|
}
|
||||||
|
int videoviewFlag = (Build.VERSION.SDK_INT >= 16) ? View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION : 0;
|
||||||
|
getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LOW_PROFILE | View.SYSTEM_UI_FLAG_FULLSCREEN
|
||||||
|
| View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | videoviewFlag);
|
||||||
|
videoOverlay.setFitsSystemWindows(true);
|
||||||
|
|
||||||
videoOverlay.setVisibility(View.GONE);
|
videoOverlay.setVisibility(View.GONE);
|
||||||
controls.setVisibility(View.GONE);
|
controls.setVisibility(View.GONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void hideVideoControls() {
|
||||||
|
hideVideoControls(true);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected int getContentViewResourceId() {
|
protected int getContentViewResourceId() {
|
||||||
return R.layout.videoplayer_activity;
|
return R.layout.videoplayer_activity;
|
||||||
|
@ -350,6 +390,32 @@ public class VideoplayerActivity extends MediaplayerActivity {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onPrepareOptionsMenu(Menu menu) {
|
||||||
|
super.onPrepareOptionsMenu(menu);
|
||||||
|
if (PictureInPictureUtil.supportsPictureInPicture(this)) {
|
||||||
|
menu.findItem(R.id.player_go_to_picture_in_picture).setVisible(true);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onOptionsItemSelected(MenuItem item) {
|
||||||
|
if (item.getItemId() == R.id.player_go_to_picture_in_picture) {
|
||||||
|
compatEnterPictureInPicture();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return super.onOptionsItemSelected(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void compatEnterPictureInPicture() {
|
||||||
|
if (PictureInPictureUtil.supportsPictureInPicture(this) && Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||||
|
getSupportActionBar().hide();
|
||||||
|
hideVideoControls(false);
|
||||||
|
enterPictureInPictureMode();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static class VideoControlsHider extends Handler {
|
private static class VideoControlsHider extends Handler {
|
||||||
|
|
||||||
private static final int DELAY = 2500;
|
private static final int DELAY = 2500;
|
||||||
|
@ -362,7 +428,7 @@ public class VideoplayerActivity extends MediaplayerActivity {
|
||||||
|
|
||||||
private final Runnable hideVideoControls = () -> {
|
private final Runnable hideVideoControls = () -> {
|
||||||
VideoplayerActivity vpa = activity != null ? activity.get() : null;
|
VideoplayerActivity vpa = activity != null ? activity.get() : null;
|
||||||
if(vpa == null) {
|
if (vpa == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (vpa.videoControlsShowing) {
|
if (vpa.videoControlsShowing) {
|
||||||
|
|
|
@ -3,6 +3,7 @@ package de.danoeh.antennapod.config;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
|
|
||||||
|
import android.os.Build;
|
||||||
import de.danoeh.antennapod.R;
|
import de.danoeh.antennapod.R;
|
||||||
import de.danoeh.antennapod.activity.AudioplayerActivity;
|
import de.danoeh.antennapod.activity.AudioplayerActivity;
|
||||||
import de.danoeh.antennapod.activity.CastplayerActivity;
|
import de.danoeh.antennapod.activity.CastplayerActivity;
|
||||||
|
@ -18,7 +19,11 @@ public class PlaybackServiceCallbacksImpl implements PlaybackServiceCallbacks {
|
||||||
return new Intent(context, CastplayerActivity.class);
|
return new Intent(context, CastplayerActivity.class);
|
||||||
}
|
}
|
||||||
if (mediaType == MediaType.VIDEO) {
|
if (mediaType == MediaType.VIDEO) {
|
||||||
return new Intent(context, VideoplayerActivity.class);
|
Intent i = new Intent(context, VideoplayerActivity.class);
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||||
|
i.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT);
|
||||||
|
}
|
||||||
|
return i;
|
||||||
} else {
|
} else {
|
||||||
return new Intent(context, AudioplayerActivity.class);
|
return new Intent(context, AudioplayerActivity.class);
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,8 +38,10 @@ import android.widget.Toast;
|
||||||
|
|
||||||
import com.afollestad.materialdialogs.MaterialDialog;
|
import com.afollestad.materialdialogs.MaterialDialog;
|
||||||
|
|
||||||
|
import com.afollestad.materialdialogs.prefs.MaterialListPreference;
|
||||||
import de.danoeh.antennapod.activity.ImportExportActivity;
|
import de.danoeh.antennapod.activity.ImportExportActivity;
|
||||||
import de.danoeh.antennapod.activity.OpmlImportFromPathActivity;
|
import de.danoeh.antennapod.activity.OpmlImportFromPathActivity;
|
||||||
|
import de.danoeh.antennapod.core.util.gui.PictureInPictureUtil;
|
||||||
import org.apache.commons.lang3.ArrayUtils;
|
import org.apache.commons.lang3.ArrayUtils;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
@ -426,6 +428,11 @@ public class PreferenceController implements SharedPreferences.OnSharedPreferenc
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
if (!PictureInPictureUtil.supportsPictureInPicture(activity)) {
|
||||||
|
MaterialListPreference behaviour = (MaterialListPreference) ui.findPreference(UserPreferences.PREF_VIDEO_BEHAVIOR);
|
||||||
|
behaviour.setEntries(R.array.video_background_behavior_options_without_pip);
|
||||||
|
behaviour.setEntryValues(R.array.video_background_behavior_values_without_pip);
|
||||||
|
}
|
||||||
ui.findPreference(PREF_PROXY).setOnPreferenceClickListener(preference -> {
|
ui.findPreference(PREF_PROXY).setOnPreferenceClickListener(preference -> {
|
||||||
ProxyDialog dialog = new ProxyDialog(ui.getActivity());
|
ProxyDialog dialog = new ProxyDialog(ui.getActivity());
|
||||||
dialog.createDialog().show();
|
dialog.createDialog().show();
|
||||||
|
|
|
@ -25,6 +25,8 @@ public class AspectRatioVideoView extends VideoView {
|
||||||
|
|
||||||
private int mVideoWidth;
|
private int mVideoWidth;
|
||||||
private int mVideoHeight;
|
private int mVideoHeight;
|
||||||
|
private float mAvailableWidth = -1;
|
||||||
|
private float mAvailableHeight = -1;
|
||||||
|
|
||||||
public AspectRatioVideoView(Context context) {
|
public AspectRatioVideoView(Context context) {
|
||||||
this(context, null);
|
this(context, null);
|
||||||
|
@ -48,8 +50,13 @@ public class AspectRatioVideoView extends VideoView {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
float heightRatio = (float) mVideoHeight / (float) getHeight();
|
if (mAvailableWidth < 0 || mAvailableHeight < 0) {
|
||||||
float widthRatio = (float) mVideoWidth / (float) getWidth();
|
mAvailableWidth = getWidth();
|
||||||
|
mAvailableHeight = getHeight();
|
||||||
|
}
|
||||||
|
|
||||||
|
float heightRatio = (float) mVideoHeight / mAvailableHeight;
|
||||||
|
float widthRatio = (float) mVideoWidth / mAvailableWidth;
|
||||||
|
|
||||||
int scaledHeight;
|
int scaledHeight;
|
||||||
int scaledWidth;
|
int scaledWidth;
|
||||||
|
@ -94,4 +101,15 @@ public class AspectRatioVideoView extends VideoView {
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the maximum size that the view might expand to
|
||||||
|
* @param width
|
||||||
|
* @param height
|
||||||
|
*/
|
||||||
|
public void setAvailableSize(float width, float height) {
|
||||||
|
mAvailableWidth = width;
|
||||||
|
mAvailableHeight = height;
|
||||||
|
requestLayout();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,8 @@
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:background="@color/black"
|
android:background="@color/black"
|
||||||
android:orientation="vertical">
|
android:orientation="vertical"
|
||||||
|
android:id="@+id/videoframe">
|
||||||
|
|
||||||
<de.danoeh.antennapod.view.AspectRatioVideoView
|
<de.danoeh.antennapod.view.AspectRatioVideoView
|
||||||
android:id="@+id/videoview"
|
android:id="@+id/videoview"
|
||||||
|
@ -103,6 +104,7 @@
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_toLeftOf="@+id/txtvLength"
|
android:layout_toLeftOf="@+id/txtvLength"
|
||||||
android:layout_toRightOf="@+id/txtvPosition"
|
android:layout_toRightOf="@+id/txtvPosition"
|
||||||
|
android:layout_centerInParent="true"
|
||||||
android:max="500" />
|
android:max="500" />
|
||||||
|
|
||||||
</RelativeLayout>
|
</RelativeLayout>
|
||||||
|
|
|
@ -41,6 +41,14 @@
|
||||||
android:title="@string/visit_website_label"
|
android:title="@string/visit_website_label"
|
||||||
android:visible="false">
|
android:visible="false">
|
||||||
</item>
|
</item>
|
||||||
|
|
||||||
|
<item
|
||||||
|
android:id="@+id/player_go_to_picture_in_picture"
|
||||||
|
custom:showAsAction="collapseActionView"
|
||||||
|
android:title="@string/player_go_to_picture_in_picture"
|
||||||
|
android:visible="false">
|
||||||
|
</item>
|
||||||
|
|
||||||
<item
|
<item
|
||||||
android:id="@+id/share_item"
|
android:id="@+id/share_item"
|
||||||
android:icon="?attr/social_share"
|
android:icon="?attr/social_share"
|
||||||
|
|
|
@ -171,6 +171,14 @@
|
||||||
android:key="prefResumeAfterCall"
|
android:key="prefResumeAfterCall"
|
||||||
android:summary="@string/pref_resumeAfterCall_sum"
|
android:summary="@string/pref_resumeAfterCall_sum"
|
||||||
android:title="@string/pref_resumeAfterCall_title"/>
|
android:title="@string/pref_resumeAfterCall_title"/>
|
||||||
|
<com.afollestad.materialdialogs.prefs.MaterialListPreference
|
||||||
|
android:defaultValue="stop"
|
||||||
|
android:entries="@array/video_background_behavior_options"
|
||||||
|
android:entryValues="@array/video_background_behavior_values"
|
||||||
|
android:key="prefVideoBehavior"
|
||||||
|
android:summary="@string/pref_videoBehavior_sum"
|
||||||
|
android:title="@string/pref_videoBehavior_title"
|
||||||
|
app:useStockLayout="true"/>
|
||||||
|
|
||||||
</PreferenceCategory>
|
</PreferenceCategory>
|
||||||
<PreferenceCategory android:title="@string/network_pref">
|
<PreferenceCategory android:title="@string/network_pref">
|
||||||
|
|
|
@ -74,6 +74,7 @@ public class UserPreferences {
|
||||||
private static final String PREF_PLAYBACK_SPEED_ARRAY = "prefPlaybackSpeedArray";
|
private static final String PREF_PLAYBACK_SPEED_ARRAY = "prefPlaybackSpeedArray";
|
||||||
private static final String PREF_PAUSE_PLAYBACK_FOR_FOCUS_LOSS = "prefPauseForFocusLoss";
|
private static final String PREF_PAUSE_PLAYBACK_FOR_FOCUS_LOSS = "prefPauseForFocusLoss";
|
||||||
private static final String PREF_RESUME_AFTER_CALL = "prefResumeAfterCall";
|
private static final String PREF_RESUME_AFTER_CALL = "prefResumeAfterCall";
|
||||||
|
public static final String PREF_VIDEO_BEHAVIOR = "prefVideoBehavior";
|
||||||
|
|
||||||
// Network
|
// Network
|
||||||
private static final String PREF_ENQUEUE_DOWNLOADED = "prefEnqueueDownloaded";
|
private static final String PREF_ENQUEUE_DOWNLOADED = "prefEnqueueDownloaded";
|
||||||
|
@ -661,6 +662,14 @@ public class UserPreferences {
|
||||||
.apply();
|
.apply();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static VideoBackgroundBehavior getVideoBackgroundBehavior() {
|
||||||
|
switch (prefs.getString(PREF_VIDEO_BEHAVIOR, "stop")) {
|
||||||
|
case "stop": return VideoBackgroundBehavior.STOP;
|
||||||
|
case "pip": return VideoBackgroundBehavior.PICTURE_IN_PICTURE;
|
||||||
|
case "continue": return VideoBackgroundBehavior.CONTINUE_PLAYING;
|
||||||
|
default: return VideoBackgroundBehavior.STOP;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static EpisodeCleanupAlgorithm getEpisodeCleanupAlgorithm() {
|
public static EpisodeCleanupAlgorithm getEpisodeCleanupAlgorithm() {
|
||||||
int cleanupValue = Integer.parseInt(prefs.getString(PREF_EPISODE_CLEANUP, "-1"));
|
int cleanupValue = Integer.parseInt(prefs.getString(PREF_EPISODE_CLEANUP, "-1"));
|
||||||
|
@ -839,4 +848,8 @@ public class UserPreferences {
|
||||||
public static boolean isCastEnabled() {
|
public static boolean isCastEnabled() {
|
||||||
return prefs.getBoolean(PREF_CAST_ENABLED, false);
|
return prefs.getBoolean(PREF_CAST_ENABLED, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public enum VideoBackgroundBehavior {
|
||||||
|
STOP, PICTURE_IN_PICTURE, CONTINUE_PLAYING
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,27 @@
|
||||||
|
package de.danoeh.antennapod.core.util.gui;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.content.pm.PackageManager;
|
||||||
|
import android.os.Build;
|
||||||
|
|
||||||
|
public class PictureInPictureUtil {
|
||||||
|
private PictureInPictureUtil() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean supportsPictureInPicture(Activity activity) {
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||||
|
PackageManager packageManager = activity.getPackageManager();
|
||||||
|
return packageManager.hasSystemFeature(PackageManager.FEATURE_PICTURE_IN_PICTURE);
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isInPictureInPictureMode(Activity activity) {
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && supportsPictureInPicture(activity)) {
|
||||||
|
return activity.isInPictureInPictureMode();
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -224,4 +224,26 @@
|
||||||
<item>@string/fast_forward_label</item>
|
<item>@string/fast_forward_label</item>
|
||||||
<item>@string/skip_episode_label</item>
|
<item>@string/skip_episode_label</item>
|
||||||
</string-array>
|
</string-array>
|
||||||
|
|
||||||
|
<string-array name="video_background_behavior_options">
|
||||||
|
<item>@string/stop_playback</item>
|
||||||
|
<item>@string/player_go_to_picture_in_picture</item>
|
||||||
|
<item>@string/continue_playback</item>
|
||||||
|
</string-array>
|
||||||
|
|
||||||
|
<string-array name="video_background_behavior_values">
|
||||||
|
<item>stop</item>
|
||||||
|
<item>pip</item>
|
||||||
|
<item>continue</item>
|
||||||
|
</string-array>
|
||||||
|
|
||||||
|
<string-array name="video_background_behavior_options_without_pip">
|
||||||
|
<item>@string/stop_playback</item>
|
||||||
|
<item>@string/continue_playback</item>
|
||||||
|
</string-array>
|
||||||
|
|
||||||
|
<string-array name="video_background_behavior_values_without_pip">
|
||||||
|
<item>stop</item>
|
||||||
|
<item>continue</item>
|
||||||
|
</string-array>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
@ -237,6 +237,7 @@
|
||||||
<string name="no_media_playing_label">No media playing</string>
|
<string name="no_media_playing_label">No media playing</string>
|
||||||
<string name="position_default_label" translate="false">00:00:00</string>
|
<string name="position_default_label" translate="false">00:00:00</string>
|
||||||
<string name="player_buffering_msg">Buffering</string>
|
<string name="player_buffering_msg">Buffering</string>
|
||||||
|
<string name="player_go_to_picture_in_picture">Picture-in-picture mode</string>
|
||||||
<string name="playbackservice_notification_title">Playing podcast</string>
|
<string name="playbackservice_notification_title">Playing podcast</string>
|
||||||
<string name="unknown_media_key">AntennaPod - Unknown media key: %1$d</string>
|
<string name="unknown_media_key">AntennaPod - Unknown media key: %1$d</string>
|
||||||
|
|
||||||
|
@ -440,6 +441,10 @@
|
||||||
<string name="pref_cast_message_free_flavor">Chromecast requires third party proprietary libraries that are disabled in this version of AntennaPod</string>
|
<string name="pref_cast_message_free_flavor">Chromecast requires third party proprietary libraries that are disabled in this version of AntennaPod</string>
|
||||||
<string name="pref_enqueue_downloaded_title">Enqueue Downloaded</string>
|
<string name="pref_enqueue_downloaded_title">Enqueue Downloaded</string>
|
||||||
<string name="pref_enqueue_downloaded_summary">Add downloaded episodes to the queue</string>
|
<string name="pref_enqueue_downloaded_summary">Add downloaded episodes to the queue</string>
|
||||||
|
<string name="pref_videoBehavior_title">Video behavior</string>
|
||||||
|
<string name="pref_videoBehavior_sum">Behavior when leaving video playback</string>
|
||||||
|
<string name="stop_playback">Stop playback</string>
|
||||||
|
<string name="continue_playback">Continue playback</string>
|
||||||
|
|
||||||
<!-- Auto-Flattr dialog -->
|
<!-- Auto-Flattr dialog -->
|
||||||
<string name="auto_flattr_enable">Enable automatic flattring</string>
|
<string name="auto_flattr_enable">Enable automatic flattring</string>
|
||||||
|
|
Loading…
Reference in New Issue