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.ktx.AnimationType
import org.schabi.newpipe.ktx.animate
import org.schabi.newpipe.player.helper.PlayerHelper
import org.schabi.newpipe.player.ui.PopupPlayerUi
import kotlin.math.abs
import kotlin.math.hypot
@ -87,7 +86,7 @@ class PopupPlayerGestureListener(
player.changeState(player.currentState)
}
if (!playerUi.isPopupClosing) {
PlayerHelper.savePopupPositionAndSizeToPrefs(playerUi)
playerUi.savePopupPositionAndSizeToPrefs()
}
}
@ -106,40 +105,42 @@ class PopupPlayerGestureListener(
}
private fun handleMultiDrag(event: MotionEvent): Boolean {
if (initPointerDistance != -1.0 && event.pointerCount == 2) {
// get the movements of the fingers
val firstPointerMove = hypot(
event.getX(0) - initFirstPointerX.toDouble(),
event.getY(0) - initFirstPointerY.toDouble()
)
val secPointerMove = hypot(
event.getX(1) - initSecPointerX.toDouble(),
event.getY(1) - initSecPointerY.toDouble()
)
// minimum threshold beyond which pinch gesture will work
val minimumMove = ViewConfiguration.get(player.context).scaledTouchSlop
if (max(firstPointerMove, secPointerMove) > minimumMove) {
// calculate current distance between the pointers
val currentPointerDistance = hypot(
event.getX(0) - event.getX(1).toDouble(),
event.getY(0) - event.getY(1).toDouble()
)
val popupWidth = playerUi.popupLayoutParams.width.toDouble()
// change co-ordinates of popup so the center stays at the same position
val newWidth = popupWidth * currentPointerDistance / initPointerDistance
initPointerDistance = currentPointerDistance
playerUi.popupLayoutParams.x += ((popupWidth - newWidth) / 2.0).toInt()
playerUi.checkPopupPositionBounds()
playerUi.updateScreenSize()
playerUi.changePopupSize(min(playerUi.screenWidth.toDouble(), newWidth).toInt())
return true
}
if (initPointerDistance == -1.0 || event.pointerCount != 2) {
return false
}
return false
// get the movements of the fingers
val firstPointerMove = hypot(
event.getX(0) - initFirstPointerX.toDouble(),
event.getY(0) - initFirstPointerY.toDouble()
)
val secPointerMove = hypot(
event.getX(1) - initSecPointerX.toDouble(),
event.getY(1) - initSecPointerY.toDouble()
)
// minimum threshold beyond which pinch gesture will work
val minimumMove = ViewConfiguration.get(player.context).scaledTouchSlop
if (max(firstPointerMove, secPointerMove) <= minimumMove) {
return false
}
// calculate current distance between the pointers
val currentPointerDistance = hypot(
event.getX(0) - event.getX(1).toDouble(),
event.getY(0) - event.getY(1).toDouble()
)
val popupWidth = playerUi.popupLayoutParams.width.toDouble()
// change co-ordinates of popup so the center stays at the same position
val newWidth = popupWidth * currentPointerDistance / initPointerDistance
initPointerDistance = currentPointerDistance
playerUi.popupLayoutParams.x += ((popupWidth - newWidth) / 2.0).toInt()
playerUi.checkPopupPositionBounds()
playerUi.updateScreenSize()
playerUi.changePopupSize(min(playerUi.screenWidth.toDouble(), newWidth).toInt())
return true
}
private fun onPopupResizingStart() {

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_NONE;
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 android.annotation.SuppressLint;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.graphics.PixelFormat;
import android.os.Build;
import android.provider.Settings;
import android.view.Gravity;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.view.accessibility.CaptioningManager;
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.SubtitlesStream;
import org.schabi.newpipe.extractor.utils.Utils;
import org.schabi.newpipe.player.PlayerService;
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.PlayQueueItem;
import org.schabi.newpipe.player.playqueue.SinglePlayQueue;
import org.schabi.newpipe.player.ui.PopupPlayerUi;
import org.schabi.newpipe.util.ListHelper;
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 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)
@IntDef({AUTOPLAY_TYPE_ALWAYS, AUTOPLAY_TYPE_WIFI,
AUTOPLAY_TYPE_NEVER})
@ -525,90 +504,10 @@ public final class PlayerHelper {
.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) {
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) {
return Integer.parseInt(Objects.requireNonNull(player.getPrefs().getString(
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 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.retrievePopupLayoutParamsFromPrefs;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.PixelFormat;
import android.os.Build;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.view.animation.AnticipateInterpolator;
import android.widget.LinearLayout;
@ -38,6 +42,20 @@ import org.schabi.newpipe.player.helper.PlayerHelper;
public final class PopupPlayerUi extends VideoPlayerUi {
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
//////////////////////////////////////////////////////////////////////////*/
@ -98,7 +116,7 @@ public final class PopupPlayerUi extends VideoPlayerUi {
updateScreenSize();
popupLayoutParams = retrievePopupLayoutParamsFromPrefs(this);
popupLayoutParams = retrievePopupLayoutParamsFromPrefs();
binding.surfaceView.setHeights(popupLayoutParams.height, popupLayoutParams.height);
checkPopupPositionBounds();
@ -446,6 +464,92 @@ public final class PopupPlayerUi extends VideoPlayerUi {
//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
//////////////////////////////////////////////////////////////////////////*/