From 040d6585402601d5bb72f32a24e611b511258a14 Mon Sep 17 00:00:00 2001 From: Mauricio Colli Date: Mon, 1 May 2017 02:23:50 -0300 Subject: [PATCH] Implement resizable popup --- .../fragments/detail/VideoDetailFragment.java | 6 +- .../newpipe/player/PopupVideoPlayer.java | 159 +++++++++++++++--- app/src/main/res/layout/player_popup.xml | 21 ++- app/src/main/res/values-sw600dp/dimens.xml | 3 +- app/src/main/res/values/dimens.xml | 3 +- app/src/main/res/values/settings_keys.xml | 3 + app/src/main/res/values/strings.xml | 4 + app/src/main/res/xml/settings.xml | 30 +++- 8 files changed, 197 insertions(+), 32 deletions(-) diff --git a/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java index 7ad62d99f..8d50f0035 100644 --- a/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java +++ b/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java @@ -19,6 +19,7 @@ import android.text.TextUtils; import android.text.method.LinkMovementMethod; import android.util.Log; import android.util.TypedValue; +import android.view.Gravity; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuInflater; @@ -420,7 +421,10 @@ public class VideoDetailFragment extends BaseFragment implements StreamExtractor if (isLoading.get()) return; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && !PermissionHelper.checkSystemAlertWindowPermission(activity)) { - Toast.makeText(activity, R.string.msg_popup_permission, Toast.LENGTH_LONG).show(); + Toast toast = Toast.makeText(activity, R.string.msg_popup_permission, Toast.LENGTH_LONG); + TextView messageView = (TextView) toast.getView().findViewById(android.R.id.message); + if (messageView != null) messageView.setGravity(Gravity.CENTER); + toast.show(); return; } diff --git a/app/src/main/java/org/schabi/newpipe/player/PopupVideoPlayer.java b/app/src/main/java/org/schabi/newpipe/player/PopupVideoPlayer.java index ded6f34f9..920f119e3 100644 --- a/app/src/main/java/org/schabi/newpipe/player/PopupVideoPlayer.java +++ b/app/src/main/java/org/schabi/newpipe/player/PopupVideoPlayer.java @@ -7,13 +7,14 @@ import android.app.Service; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.content.SharedPreferences; import android.content.res.Configuration; -import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.PixelFormat; import android.os.Build; import android.os.Handler; import android.os.IBinder; +import android.preference.PreferenceManager; import android.support.v4.app.NotificationCompat; import android.util.DisplayMetrics; import android.util.Log; @@ -24,6 +25,7 @@ import android.view.View; import android.view.WindowManager; import android.widget.PopupMenu; import android.widget.RemoteViews; +import android.widget.TextView; import android.widget.Toast; import com.nostra13.universalimageloader.core.DisplayImageOptions; @@ -58,14 +60,19 @@ public class PopupVideoPlayer extends Service { public static final String ACTION_OPEN_DETAIL = "org.schabi.newpipe.player.PopupVideoPlayer.OPEN_DETAIL"; public static final String ACTION_REPEAT = "org.schabi.newpipe.player.PopupVideoPlayer.REPEAT"; + private static final String POPUP_SAVED_WIDTH = "popup_saved_width"; + private static final String POPUP_SAVED_X = "popup_saved_x"; + private static final String POPUP_SAVED_Y = "popup_saved_y"; + private WindowManager windowManager; private WindowManager.LayoutParams windowLayoutParams; private GestureDetector gestureDetector; private float screenWidth, screenHeight; private float popupWidth, popupHeight; - private float currentPopupHeight = 110.0f * Resources.getSystem().getDisplayMetrics().density; - //private float minimumHeight = 100; // TODO: Use it when implementing the resize of the popup + + private float minimumWidth, minimumHeight; + private float maximumWidth, maximumHeight; private final String setAlphaMethodName = (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) ? "setImageAlpha" : "setAlpha"; private NotificationManager notificationManager; @@ -114,6 +121,8 @@ public class PopupVideoPlayer extends Service { @Override public void onConfigurationChanged(Configuration newConfig) { updateScreenSize(); + updatePopupSize(windowLayoutParams.width, -1); + checkPositionBounds(); } @Override @@ -129,6 +138,8 @@ public class PopupVideoPlayer extends Service { currentExtractorWorker.cancel(); currentExtractorWorker = null; } + + savePositionAndSize(); } @Override @@ -144,21 +155,33 @@ public class PopupVideoPlayer extends Service { private void initPopup() { if (DEBUG) Log.d(TAG, "initPopup() called"); View rootView = View.inflate(this, R.layout.player_popup, null); - playerImpl.setup(rootView); updateScreenSize(); + + SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this); + boolean popupRememberSizeAndPos = sharedPreferences.getBoolean(getString(R.string.popup_remember_size_pos_key), true); + + float defaultSize = getResources().getDimension(R.dimen.popup_default_width); + popupWidth = popupRememberSizeAndPos ? sharedPreferences.getFloat(POPUP_SAVED_WIDTH, defaultSize) : defaultSize; + windowLayoutParams = new WindowManager.LayoutParams( - (int) getMinimumVideoWidth(currentPopupHeight), (int) currentPopupHeight, + (int) popupWidth, (int) getMinimumVideoHeight(popupWidth), WindowManager.LayoutParams.TYPE_PHONE, WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, PixelFormat.TRANSLUCENT); - windowLayoutParams.gravity = Gravity.LEFT | Gravity.TOP; + int centerX = (int) (screenWidth / 2f - popupWidth / 2f); + int centerY = (int) (screenHeight / 2f - popupHeight / 2f); + windowLayoutParams.x = popupRememberSizeAndPos ? sharedPreferences.getInt(POPUP_SAVED_X, centerX) : centerX; + windowLayoutParams.y = popupRememberSizeAndPos ? sharedPreferences.getInt(POPUP_SAVED_Y, centerY) : centerY; + + checkPositionBounds(); + MySimpleOnGestureListener listener = new MySimpleOnGestureListener(); gestureDetector = new GestureDetector(this, listener); - gestureDetector.setIsLongpressEnabled(false); + //gestureDetector.setIsLongpressEnabled(false); rootView.setOnTouchListener(listener); playerImpl.getLoadingPanel().setMinimumWidth(windowLayoutParams.width); playerImpl.getLoadingPanel().setMinimumHeight(windowLayoutParams.height); @@ -219,13 +242,13 @@ public class PopupVideoPlayer extends Service { notificationManager.notify(NOTIFICATION_ID, notBuilder.build()); } - /*////////////////////////////////////////////////////////////////////////// // Misc //////////////////////////////////////////////////////////////////////////*/ public void onVideoClose() { if (DEBUG) Log.d(TAG, "onVideoClose() called"); + savePositionAndSize(); stopSelf(); } @@ -245,10 +268,23 @@ public class PopupVideoPlayer extends Service { // Utils //////////////////////////////////////////////////////////////////////////*/ - private float getMinimumVideoWidth(float height) { - float width = height * (16.0f / 9.0f); // Respect the 16:9 ratio that most videos have - if (DEBUG) Log.d(TAG, "getMinimumVideoWidth() called with: height = [" + height + "], returned: " + width); - return width; + private void checkPositionBounds() { + if (windowLayoutParams.x > screenWidth - windowLayoutParams.width) windowLayoutParams.x = (int) (screenWidth - windowLayoutParams.width); + if (windowLayoutParams.x < 0) windowLayoutParams.x = 0; + if (windowLayoutParams.y > screenHeight - windowLayoutParams.height) windowLayoutParams.y = (int) (screenHeight - windowLayoutParams.height); + if (windowLayoutParams.y < 0) windowLayoutParams.y = 0; + } + + private void savePositionAndSize() { + SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(PopupVideoPlayer.this); + sharedPreferences.edit().putInt(POPUP_SAVED_X, windowLayoutParams.x).apply(); + sharedPreferences.edit().putInt(POPUP_SAVED_Y, windowLayoutParams.y).apply(); + sharedPreferences.edit().putFloat(POPUP_SAVED_WIDTH, windowLayoutParams.width).apply(); + } + + private float getMinimumVideoHeight(float width) { + //if (DEBUG) Log.d(TAG, "getMinimumVideoHeight() called with: width = [" + width + "], returned: " + height); + return width / (16.0f / 9.0f); // Respect the 16:9 ratio that most videos have } private void updateScreenSize() { @@ -258,11 +294,39 @@ public class PopupVideoPlayer extends Service { screenWidth = metrics.widthPixels; screenHeight = metrics.heightPixels; if (DEBUG) Log.d(TAG, "updateScreenSize() called > screenWidth = " + screenWidth + ", screenHeight = " + screenHeight); + + popupWidth = getResources().getDimension(R.dimen.popup_default_width); + popupHeight = getMinimumVideoHeight(popupWidth); + + minimumWidth = getResources().getDimension(R.dimen.popup_minimum_width); + minimumHeight = getMinimumVideoHeight(minimumWidth); + + maximumWidth = screenWidth; + maximumHeight = screenHeight; + } + + private void updatePopupSize(int width, int height) { + //if (DEBUG) Log.d(TAG, "updatePopupSize() called with: width = [" + width + "], height = [" + height + "]"); + + width = (int) (width > maximumWidth ? maximumWidth : width < minimumWidth ? minimumWidth : width); + + if (height == -1) height = (int) getMinimumVideoHeight(width); + else height = (int) (height > maximumHeight ? maximumHeight : height < minimumHeight ? minimumHeight : height); + + windowLayoutParams.width = width; + windowLayoutParams.height = height; + popupWidth = width; + popupHeight = height; + + if (DEBUG) Log.d(TAG, "updatePopupSize() updated values: width = [" + width + "], height = [" + height + "]"); + windowManager.updateViewLayout(playerImpl.getRootView(), windowLayoutParams); } /////////////////////////////////////////////////////////////////////////// private class VideoPlayerImpl extends VideoPlayer { + private TextView resizingIndicator; + VideoPlayerImpl() { super("VideoPlayerImpl" + PopupVideoPlayer.TAG, PopupVideoPlayer.this); } @@ -271,13 +335,20 @@ public class PopupVideoPlayer extends Service { public void playUrl(String url, String format, boolean autoPlay) { super.playUrl(url, format, autoPlay); - windowLayoutParams.width = (int) getMinimumVideoWidth(currentPopupHeight); + windowLayoutParams.width = (int) popupWidth; + windowLayoutParams.height = (int) getMinimumVideoHeight(popupWidth); windowManager.updateViewLayout(getRootView(), windowLayoutParams); notBuilder = createNotification(); startForeground(NOTIFICATION_ID, notBuilder.build()); } + @Override + public void initViews(View rootView) { + super.initViews(rootView); + resizingIndicator = (TextView) rootView.findViewById(R.id.resizing_indicator); + } + @Override public void destroy() { super.destroy(); @@ -422,12 +493,21 @@ public class PopupVideoPlayer extends Service { showAndAnimateControl(R.drawable.ic_replay_white, false); } + + @SuppressWarnings("WeakerAccess") + public TextView getResizingIndicator() { + return resizingIndicator; + } } private class MySimpleOnGestureListener extends GestureDetector.SimpleOnGestureListener implements View.OnTouchListener { private int initialPopupX, initialPopupY; private boolean isMoving; + private int onDownPopupWidth = 0; + private boolean isResizing; + private boolean isResizingRightSide; + @Override public boolean onDoubleTap(MotionEvent e) { if (DEBUG) Log.d(TAG, "onDoubleTap() called with: e = [" + e + "]" + "rawXy = " + e.getRawX() + ", " + e.getRawY() + ", xy = " + e.getX() + ", " + e.getY()); @@ -450,15 +530,32 @@ public class PopupVideoPlayer extends Service { if (DEBUG) Log.d(TAG, "onDown() called with: e = [" + e + "]"); initialPopupX = windowLayoutParams.x; initialPopupY = windowLayoutParams.y; - popupWidth = playerImpl.getRootView().getWidth(); - popupHeight = playerImpl.getRootView().getHeight(); + popupWidth = windowLayoutParams.width; + popupHeight = windowLayoutParams.height; + onDownPopupWidth = windowLayoutParams.width; return false; } + @Override + public void onLongPress(MotionEvent e) { + if (DEBUG) Log.d(TAG, "onLongPress() called with: e = [" + e + "]"); + playerImpl.showAndAnimateControl(-1, true); + playerImpl.getLoadingPanel().setVisibility(View.GONE); + playerImpl.animateView(playerImpl.getControlsRoot(), false, 0, 0); + playerImpl.animateView(playerImpl.getCurrentDisplaySeek(), false, 0, 0); + playerImpl.animateView(playerImpl.getResizingIndicator(), true, 200, 0); + + isResizing = true; + isResizingRightSide = e.getRawX() > windowLayoutParams.x + (windowLayoutParams.width / 2f); + } + @Override public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { - if (!isMoving || playerImpl.getControlsRoot().getAlpha() != 1f) playerImpl.animateView(playerImpl.getControlsRoot(), true, 30, 0); + if (isResizing) return false; + + if (!isMoving || playerImpl.getControlsRoot().getAlpha() != 1f) playerImpl.animateView(playerImpl.getControlsRoot(), true, 0, 0); isMoving = true; + float diffX = (int) (e2.getRawX() - e1.getRawX()), posX = (int) (initialPopupX + diffX); float diffY = (int) (e2.getRawY() - e1.getRawY()), posY = (int) (initialPopupY + diffY); @@ -477,7 +574,7 @@ public class PopupVideoPlayer extends Service { ", e2.getRaw = [" + e2.getRawX() + ", " + e2.getRawY() + "]" + ", distanceXy = [" + distanceX + ", " + distanceY + "]" + ", posXy = [" + posX + ", " + posY + "]" + - ", popupWh rootView.get wh = [" + popupWidth + " x " + popupHeight + "]"); + ", popupWh = [" + popupWidth + " x " + popupHeight + "]"); windowManager.updateViewLayout(playerImpl.getRootView(), windowLayoutParams); return true; } @@ -492,9 +589,31 @@ public class PopupVideoPlayer extends Service { @Override public boolean onTouch(View v, MotionEvent event) { gestureDetector.onTouchEvent(event); - if (event.getAction() == MotionEvent.ACTION_UP && isMoving) { - isMoving = false; - onScrollEnd(); + if (event.getAction() == MotionEvent.ACTION_MOVE && isResizing && !isMoving) { + //if (DEBUG) Log.d(TAG, "onTouch() ACTION_MOVE > v = [" + v + "], e1.getRaw = [" + event.getRawX() + ", " + event.getRawY() + "]"); + int width; + if (isResizingRightSide) width = (int) event.getRawX() - windowLayoutParams.x; + else { + width = (int) (windowLayoutParams.width + (windowLayoutParams.x - event.getRawX())); + if (width > minimumWidth) windowLayoutParams.x = initialPopupX - (width - onDownPopupWidth); + } + if (width <= maximumWidth && width >= minimumWidth) updatePopupSize(width, -1); + return true; + } + + if (event.getAction() == MotionEvent.ACTION_UP) { + if (DEBUG) Log.d(TAG, "onTouch() ACTION_UP > v = [" + v + "], e1.getRaw = [" + event.getRawX() + ", " + event.getRawY() + "]"); + if (isMoving) { + isMoving = false; + onScrollEnd(); + } + + if (isResizing) { + isResizing = false; + playerImpl.animateView(playerImpl.getResizingIndicator(), false, 100, 0); + playerImpl.changeState(playerImpl.getCurrentState()); + } + savePositionAndSize(); } return true; } diff --git a/app/src/main/res/layout/player_popup.xml b/app/src/main/res/layout/player_popup.xml index a3be1511c..9ff3db76a 100644 --- a/app/src/main/res/layout/player_popup.xml +++ b/app/src/main/res/layout/player_popup.xml @@ -5,7 +5,9 @@ android:layout_width="match_parent" android:layout_height="match_parent" android:background="@android:color/black" - android:gravity="center"> + android:gravity="center" + tools:layout_width="@dimen/popup_default_width" + tools:layout_height="101.25dp"> + + + \ No newline at end of file diff --git a/app/src/main/res/values-sw600dp/dimens.xml b/app/src/main/res/values-sw600dp/dimens.xml index ed40aa04b..8ab553bb6 100644 --- a/app/src/main/res/values-sw600dp/dimens.xml +++ b/app/src/main/res/values-sw600dp/dimens.xml @@ -1,6 +1,7 @@ - + 230dp + 140dp 18sp diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml index b39348290..5fe9e47aa 100644 --- a/app/src/main/res/values/dimens.xml +++ b/app/src/main/res/values/dimens.xml @@ -17,7 +17,8 @@ 5sp 2sp - + 180dp + 120dp 16sp diff --git a/app/src/main/res/values/settings_keys.xml b/app/src/main/res/values/settings_keys.xml index 0d2cbbf50..34898377b 100644 --- a/app/src/main/res/values/settings_keys.xml +++ b/app/src/main/res/values/settings_keys.xml @@ -2,6 +2,7 @@ settings_category_video_audio + settings_category_popup settings_category_appearance settings_content_options settings_category_other @@ -27,6 +28,8 @@ 144p + popup_remember_size_pos_key + default_popup_resolution_key 480p diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index bcfa65ed2..e518b7811 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -59,6 +59,8 @@ Light Dark Black + Remember popup size and position + Remember the last size and position set to the popup Download @@ -86,6 +88,7 @@ Similar videos Preferred content language Video & Audio + Popup Appearance Other %1$s - NewPipe @@ -109,6 +112,7 @@ Filter Refresh Clear + Resizing Error diff --git a/app/src/main/res/xml/settings.xml b/app/src/main/res/xml/settings.xml index 55b0c8196..9e76ff57a 100644 --- a/app/src/main/res/xml/settings.xml +++ b/app/src/main/res/xml/settings.xml @@ -27,14 +27,6 @@ android:summary="%s" android:defaultValue="@string/default_resolution_value"/> - - + + + + + + + + +