Move popup layout param to PopupPlayerUi

This commit is contained in:
Stypox 2022-07-08 22:33:35 +02:00
parent 9c51fc3ade
commit 3692858a3d
No known key found for this signature in database
GPG Key ID: 4BDF1B40A49FDD23
3 changed files with 144 additions and 140 deletions

View File

@ -7,7 +7,6 @@ import android.view.ViewConfiguration
import org.schabi.newpipe.MainActivity import org.schabi.newpipe.MainActivity
import org.schabi.newpipe.ktx.AnimationType import org.schabi.newpipe.ktx.AnimationType
import org.schabi.newpipe.ktx.animate import org.schabi.newpipe.ktx.animate
import org.schabi.newpipe.player.helper.PlayerHelper
import org.schabi.newpipe.player.ui.PopupPlayerUi import org.schabi.newpipe.player.ui.PopupPlayerUi
import kotlin.math.abs import kotlin.math.abs
import kotlin.math.hypot import kotlin.math.hypot
@ -87,7 +86,7 @@ class PopupPlayerGestureListener(
player.changeState(player.currentState) player.changeState(player.currentState)
} }
if (!playerUi.isPopupClosing) { if (!playerUi.isPopupClosing) {
PlayerHelper.savePopupPositionAndSizeToPrefs(playerUi) playerUi.savePopupPositionAndSizeToPrefs()
} }
} }
@ -106,7 +105,10 @@ class PopupPlayerGestureListener(
} }
private fun handleMultiDrag(event: MotionEvent): Boolean { private fun handleMultiDrag(event: MotionEvent): Boolean {
if (initPointerDistance != -1.0 && event.pointerCount == 2) { if (initPointerDistance == -1.0 || event.pointerCount != 2) {
return false
}
// get the movements of the fingers // get the movements of the fingers
val firstPointerMove = hypot( val firstPointerMove = hypot(
event.getX(0) - initFirstPointerX.toDouble(), event.getX(0) - initFirstPointerX.toDouble(),
@ -119,8 +121,10 @@ class PopupPlayerGestureListener(
// minimum threshold beyond which pinch gesture will work // minimum threshold beyond which pinch gesture will work
val minimumMove = ViewConfiguration.get(player.context).scaledTouchSlop val minimumMove = ViewConfiguration.get(player.context).scaledTouchSlop
if (max(firstPointerMove, secPointerMove) <= minimumMove) {
return false
}
if (max(firstPointerMove, secPointerMove) > minimumMove) {
// calculate current distance between the pointers // calculate current distance between the pointers
val currentPointerDistance = hypot( val currentPointerDistance = hypot(
event.getX(0) - event.getX(1).toDouble(), event.getX(0) - event.getX(1).toDouble(),
@ -138,9 +142,6 @@ class PopupPlayerGestureListener(
playerUi.changePopupSize(min(playerUi.screenWidth.toDouble(), newWidth).toInt()) playerUi.changePopupSize(min(playerUi.screenWidth.toDouble(), newWidth).toInt())
return true return true
} }
}
return false
}
private fun onPopupResizingStart() { private fun onPopupResizingStart() {
if (DEBUG) { if (DEBUG) {

View File

@ -10,19 +10,13 @@ import static org.schabi.newpipe.player.helper.PlayerHelper.AutoplayType.AUTOPLA
import static org.schabi.newpipe.player.helper.PlayerHelper.MinimizeMode.MINIMIZE_ON_EXIT_MODE_BACKGROUND; import static org.schabi.newpipe.player.helper.PlayerHelper.MinimizeMode.MINIMIZE_ON_EXIT_MODE_BACKGROUND;
import static org.schabi.newpipe.player.helper.PlayerHelper.MinimizeMode.MINIMIZE_ON_EXIT_MODE_NONE; import static org.schabi.newpipe.player.helper.PlayerHelper.MinimizeMode.MINIMIZE_ON_EXIT_MODE_NONE;
import static org.schabi.newpipe.player.helper.PlayerHelper.MinimizeMode.MINIMIZE_ON_EXIT_MODE_POPUP; import static org.schabi.newpipe.player.helper.PlayerHelper.MinimizeMode.MINIMIZE_ON_EXIT_MODE_POPUP;
import static org.schabi.newpipe.player.ui.PopupPlayerUi.IDLE_WINDOW_FLAGS;
import static java.lang.annotation.RetentionPolicy.SOURCE; import static java.lang.annotation.RetentionPolicy.SOURCE;
import android.annotation.SuppressLint; import android.annotation.SuppressLint;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.graphics.PixelFormat;
import android.os.Build;
import android.provider.Settings; import android.provider.Settings;
import android.view.Gravity;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.view.accessibility.CaptioningManager; import android.view.accessibility.CaptioningManager;
import androidx.annotation.IntDef; import androidx.annotation.IntDef;
@ -49,12 +43,11 @@ import org.schabi.newpipe.extractor.stream.StreamInfo;
import org.schabi.newpipe.extractor.stream.StreamInfoItem; import org.schabi.newpipe.extractor.stream.StreamInfoItem;
import org.schabi.newpipe.extractor.stream.SubtitlesStream; import org.schabi.newpipe.extractor.stream.SubtitlesStream;
import org.schabi.newpipe.extractor.utils.Utils; import org.schabi.newpipe.extractor.utils.Utils;
import org.schabi.newpipe.player.PlayerService;
import org.schabi.newpipe.player.Player; import org.schabi.newpipe.player.Player;
import org.schabi.newpipe.player.PlayerService;
import org.schabi.newpipe.player.playqueue.PlayQueue; import org.schabi.newpipe.player.playqueue.PlayQueue;
import org.schabi.newpipe.player.playqueue.PlayQueueItem; import org.schabi.newpipe.player.playqueue.PlayQueueItem;
import org.schabi.newpipe.player.playqueue.SinglePlayQueue; import org.schabi.newpipe.player.playqueue.SinglePlayQueue;
import org.schabi.newpipe.player.ui.PopupPlayerUi;
import org.schabi.newpipe.util.ListHelper; import org.schabi.newpipe.util.ListHelper;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
@ -77,20 +70,6 @@ public final class PlayerHelper {
private static final NumberFormat SPEED_FORMATTER = new DecimalFormat("0.##x"); private static final NumberFormat SPEED_FORMATTER = new DecimalFormat("0.##x");
private static final NumberFormat PITCH_FORMATTER = new DecimalFormat("##%"); private static final NumberFormat PITCH_FORMATTER = new DecimalFormat("##%");
/**
* Maximum opacity allowed for Android 12 and higher to allow touches on other apps when using
* NewPipe's popup player.
*
* <p>
* This value is hardcoded instead of being get dynamically with the method linked of the
* constant documentation below, because it is not static and popup player layout parameters
* are generated with static methods.
* </p>
*
* @see WindowManager.LayoutParams#FLAG_NOT_TOUCHABLE
*/
private static final float MAXIMUM_OPACITY_ALLOWED_FOR_S_AND_HIGHER = 0.8f;
@Retention(SOURCE) @Retention(SOURCE)
@IntDef({AUTOPLAY_TYPE_ALWAYS, AUTOPLAY_TYPE_WIFI, @IntDef({AUTOPLAY_TYPE_ALWAYS, AUTOPLAY_TYPE_WIFI,
AUTOPLAY_TYPE_NEVER}) AUTOPLAY_TYPE_NEVER})
@ -525,90 +504,10 @@ public final class PlayerHelper {
.apply(); .apply();
} }
/**
* @param playerUi {@code screenWidth} and {@code screenHeight} must have been initialized
* @return the popup starting layout params
*/
@SuppressLint("RtlHardcoded")
public static WindowManager.LayoutParams retrievePopupLayoutParamsFromPrefs(
final PopupPlayerUi playerUi) {
final SharedPreferences prefs = playerUi.getPlayer().getPrefs();
final Context context = playerUi.getPlayer().getContext();
final boolean popupRememberSizeAndPos = prefs.getBoolean(
context.getString(R.string.popup_remember_size_pos_key), true);
final float defaultSize = context.getResources().getDimension(R.dimen.popup_default_width);
final float popupWidth = popupRememberSizeAndPos
? prefs.getFloat(context.getString(R.string.popup_saved_width_key), defaultSize)
: defaultSize;
final float popupHeight = getMinimumVideoHeight(popupWidth);
final WindowManager.LayoutParams popupLayoutParams = new WindowManager.LayoutParams(
(int) popupWidth, (int) popupHeight,
popupLayoutParamType(),
IDLE_WINDOW_FLAGS,
PixelFormat.TRANSLUCENT);
popupLayoutParams.gravity = Gravity.LEFT | Gravity.TOP;
popupLayoutParams.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
final int centerX = (int) (playerUi.getScreenWidth() / 2f - popupWidth / 2f);
final int centerY = (int) (playerUi.getScreenHeight() / 2f - popupHeight / 2f);
popupLayoutParams.x = popupRememberSizeAndPos
? prefs.getInt(context.getString(R.string.popup_saved_x_key), centerX) : centerX;
popupLayoutParams.y = popupRememberSizeAndPos
? prefs.getInt(context.getString(R.string.popup_saved_y_key), centerY) : centerY;
return popupLayoutParams;
}
public static void savePopupPositionAndSizeToPrefs(final PopupPlayerUi playerUi) {
if (playerUi.getPopupLayoutParams() != null) {
final Context context = playerUi.getPlayer().getContext();
playerUi.getPlayer().getPrefs().edit()
.putFloat(context.getString(R.string.popup_saved_width_key),
playerUi.getPopupLayoutParams().width)
.putInt(context.getString(R.string.popup_saved_x_key),
playerUi.getPopupLayoutParams().x)
.putInt(context.getString(R.string.popup_saved_y_key),
playerUi.getPopupLayoutParams().y)
.apply();
}
}
public static float getMinimumVideoHeight(final float width) { public static float getMinimumVideoHeight(final float width) {
return width / (16.0f / 9.0f); // Respect the 16:9 ratio that most videos have return width / (16.0f / 9.0f); // Respect the 16:9 ratio that most videos have
} }
@SuppressLint("RtlHardcoded")
public static WindowManager.LayoutParams buildCloseOverlayLayoutParams() {
final int flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
| WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
| WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
final WindowManager.LayoutParams closeOverlayLayoutParams = new WindowManager.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT,
popupLayoutParamType(),
flags,
PixelFormat.TRANSLUCENT);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
// Setting maximum opacity allowed for touch events to other apps for Android 12 and
// higher to prevent non interaction when using other apps with the popup player
closeOverlayLayoutParams.alpha = MAXIMUM_OPACITY_ALLOWED_FOR_S_AND_HIGHER;
}
closeOverlayLayoutParams.gravity = Gravity.LEFT | Gravity.TOP;
closeOverlayLayoutParams.softInputMode =
WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
return closeOverlayLayoutParams;
}
public static int popupLayoutParamType() {
return Build.VERSION.SDK_INT < Build.VERSION_CODES.O
? WindowManager.LayoutParams.TYPE_PHONE
: WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
}
public static int retrieveSeekDurationFromPreferences(final Player player) { public static int retrieveSeekDurationFromPreferences(final Player player) {
return Integer.parseInt(Objects.requireNonNull(player.getPrefs().getString( return Integer.parseInt(Objects.requireNonNull(player.getPrefs().getString(
player.getContext().getString(R.string.seek_duration_key), player.getContext().getString(R.string.seek_duration_key),

View File

@ -2,21 +2,25 @@ package org.schabi.newpipe.player.ui;
import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT; import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
import static org.schabi.newpipe.MainActivity.DEBUG; import static org.schabi.newpipe.MainActivity.DEBUG;
import static org.schabi.newpipe.player.helper.PlayerHelper.buildCloseOverlayLayoutParams;
import static org.schabi.newpipe.player.helper.PlayerHelper.getMinimumVideoHeight; import static org.schabi.newpipe.player.helper.PlayerHelper.getMinimumVideoHeight;
import static org.schabi.newpipe.player.helper.PlayerHelper.retrievePopupLayoutParamsFromPrefs;
import android.animation.Animator; import android.animation.Animator;
import android.animation.AnimatorListenerAdapter; import android.animation.AnimatorListenerAdapter;
import android.annotation.SuppressLint; import android.annotation.SuppressLint;
import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.SharedPreferences;
import android.content.res.Resources; import android.content.res.Resources;
import android.graphics.Bitmap; import android.graphics.Bitmap;
import android.graphics.PixelFormat;
import android.os.Build;
import android.util.DisplayMetrics; import android.util.DisplayMetrics;
import android.util.Log; import android.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.MotionEvent; import android.view.MotionEvent;
import android.view.View; import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager; import android.view.WindowManager;
import android.view.animation.AnticipateInterpolator; import android.view.animation.AnticipateInterpolator;
import android.widget.LinearLayout; import android.widget.LinearLayout;
@ -38,6 +42,20 @@ import org.schabi.newpipe.player.helper.PlayerHelper;
public final class PopupPlayerUi extends VideoPlayerUi { public final class PopupPlayerUi extends VideoPlayerUi {
private static final String TAG = PopupPlayerUi.class.getSimpleName(); private static final String TAG = PopupPlayerUi.class.getSimpleName();
/**
* Maximum opacity allowed for Android 12 and higher to allow touches on other apps when using
* NewPipe's popup player.
*
* <p>
* This value is hardcoded instead of being get dynamically with the method linked of the
* constant documentation below, because it is not static and popup player layout parameters
* are generated with static methods.
* </p>
*
* @see WindowManager.LayoutParams#FLAG_NOT_TOUCHABLE
*/
private static final float MAXIMUM_OPACITY_ALLOWED_FOR_S_AND_HIGHER = 0.8f;
/*////////////////////////////////////////////////////////////////////////// /*//////////////////////////////////////////////////////////////////////////
// Popup player // Popup player
//////////////////////////////////////////////////////////////////////////*/ //////////////////////////////////////////////////////////////////////////*/
@ -98,7 +116,7 @@ public final class PopupPlayerUi extends VideoPlayerUi {
updateScreenSize(); updateScreenSize();
popupLayoutParams = retrievePopupLayoutParamsFromPrefs(this); popupLayoutParams = retrievePopupLayoutParamsFromPrefs();
binding.surfaceView.setHeights(popupLayoutParams.height, popupLayoutParams.height); binding.surfaceView.setHeights(popupLayoutParams.height, popupLayoutParams.height);
checkPopupPositionBounds(); checkPopupPositionBounds();
@ -446,6 +464,92 @@ public final class PopupPlayerUi extends VideoPlayerUi {
//endregion //endregion
/*//////////////////////////////////////////////////////////////////////////
// Popup & closing overlay layout params + saving popup position and size
//////////////////////////////////////////////////////////////////////////*/
//region Popup & closing overlay layout params + saving popup position and size
/**
* {@code screenWidth} and {@code screenHeight} must have been initialized.
* @return the popup starting layout params
*/
@SuppressLint("RtlHardcoded")
public WindowManager.LayoutParams retrievePopupLayoutParamsFromPrefs() {
final SharedPreferences prefs = getPlayer().getPrefs();
final Context context = getPlayer().getContext();
final boolean popupRememberSizeAndPos = prefs.getBoolean(
context.getString(R.string.popup_remember_size_pos_key), true);
final float defaultSize = context.getResources().getDimension(R.dimen.popup_default_width);
final float popupWidth = popupRememberSizeAndPos
? prefs.getFloat(context.getString(R.string.popup_saved_width_key), defaultSize)
: defaultSize;
final float popupHeight = getMinimumVideoHeight(popupWidth);
final WindowManager.LayoutParams params = new WindowManager.LayoutParams(
(int) popupWidth, (int) popupHeight,
popupLayoutParamType(),
IDLE_WINDOW_FLAGS,
PixelFormat.TRANSLUCENT);
params.gravity = Gravity.LEFT | Gravity.TOP;
params.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
final int centerX = (int) (screenWidth / 2f - popupWidth / 2f);
final int centerY = (int) (screenHeight / 2f - popupHeight / 2f);
params.x = popupRememberSizeAndPos
? prefs.getInt(context.getString(R.string.popup_saved_x_key), centerX) : centerX;
params.y = popupRememberSizeAndPos
? prefs.getInt(context.getString(R.string.popup_saved_y_key), centerY) : centerY;
return params;
}
public void savePopupPositionAndSizeToPrefs() {
if (getPopupLayoutParams() != null) {
final Context context = getPlayer().getContext();
getPlayer().getPrefs().edit()
.putFloat(context.getString(R.string.popup_saved_width_key),
popupLayoutParams.width)
.putInt(context.getString(R.string.popup_saved_x_key),
popupLayoutParams.x)
.putInt(context.getString(R.string.popup_saved_y_key),
popupLayoutParams.y)
.apply();
}
}
@SuppressLint("RtlHardcoded")
public static WindowManager.LayoutParams buildCloseOverlayLayoutParams() {
final int flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
| WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
| WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
final WindowManager.LayoutParams closeOverlayLayoutParams = new WindowManager.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT,
popupLayoutParamType(),
flags,
PixelFormat.TRANSLUCENT);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
// Setting maximum opacity allowed for touch events to other apps for Android 12 and
// higher to prevent non interaction when using other apps with the popup player
closeOverlayLayoutParams.alpha = MAXIMUM_OPACITY_ALLOWED_FOR_S_AND_HIGHER;
}
closeOverlayLayoutParams.gravity = Gravity.LEFT | Gravity.TOP;
closeOverlayLayoutParams.softInputMode =
WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
return closeOverlayLayoutParams;
}
public static int popupLayoutParamType() {
return Build.VERSION.SDK_INT < Build.VERSION_CODES.O
? WindowManager.LayoutParams.TYPE_PHONE
: WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
}
//endregion
/*////////////////////////////////////////////////////////////////////////// /*//////////////////////////////////////////////////////////////////////////
// Getters // Getters
//////////////////////////////////////////////////////////////////////////*/ //////////////////////////////////////////////////////////////////////////*/