From 4519dd010dcc8ac8791d97046363481d9afebe72 Mon Sep 17 00:00:00 2001
From: Avently <7953703+avently@users.noreply.github.com>
Date: Fri, 3 Jan 2020 08:05:31 +0300
Subject: [PATCH] Second block of fixes for review - hide/show controls with
respect of SystemUI. In fullscreen mode controls will stay away from
NavigationBar - notification from running service will be hidden if a user
disabled background playback - fixed incorrect handling of a system method in
API 19 - better MultiWindow support
---
.../fragments/detail/VideoDetailFragment.java | 28 ++++++------
.../org/schabi/newpipe/player/MainPlayer.java | 7 ++-
.../schabi/newpipe/player/VideoPlayer.java | 10 ++---
.../newpipe/player/VideoPlayerImpl.java | 45 ++++++++++++++++---
.../event/CustomBottomSheetBehavior.java | 21 +++++----
.../player/event/PlayerGestureListener.java | 8 ----
.../activity_main_player.xml | 7 ++-
.../main/res/layout/activity_main_player.xml | 7 ++-
.../main/res/layout/fragment_video_detail.xml | 4 +-
9 files changed, 87 insertions(+), 50 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 d0ca95d6b..8813d139d 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
@@ -1244,7 +1244,7 @@ public class VideoDetailFragment
int height;
if (player != null && player.isInFullscreen())
- height = activity.getWindow().getDecorView().getHeight();
+ height = isInMultiWindow() ? getView().getHeight() : activity.getWindow().getDecorView().getHeight();
else
height = isPortrait
? (int) (metrics.widthPixels / (16.0f / 9.0f))
@@ -1669,8 +1669,7 @@ public class VideoDetailFragment
player.useVideoSource(false);
else if (player.minimizeOnPopupEnabled())
NavigationHelper.playOnPopupPlayer(activity, playQueue, true);
- else
- player.getPlayer().setPlayWhenReady(false);
+ else player.onPause();
}
else player.useVideoSource(true);
}
@@ -1751,23 +1750,18 @@ public class VideoDetailFragment
getActivity().getWindow().getDecorView().setSystemUiVisibility(0);
getActivity().getWindow().clearFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS);
- getActivity().getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
}
private void hideSystemUi() {
if (DEBUG) Log.d(TAG, "hideSystemUi() called");
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
- int visibility = View.SYSTEM_UI_FLAG_LAYOUT_STABLE
- | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
- | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
- | View.SYSTEM_UI_FLAG_FULLSCREEN
- | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
- visibility |= View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
- }
- activity.getWindow().getDecorView().setSystemUiVisibility(visibility);
- }
+ int visibility = View.SYSTEM_UI_FLAG_LAYOUT_STABLE
+ | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
+ | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
+ | View.SYSTEM_UI_FLAG_FULLSCREEN
+ | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
+ | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
+ activity.getWindow().getDecorView().setSystemUiVisibility(visibility);
activity.getWindow().setFlags(
WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS, WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS);
}
@@ -1813,6 +1807,10 @@ public class VideoDetailFragment
return getResources().getDisplayMetrics().heightPixels < getResources().getDisplayMetrics().widthPixels;
}
+ private boolean isInMultiWindow() {
+ return Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && activity.isInMultiWindowMode();
+ }
+
/*
* Means that the player fragment was swiped away via BottomSheetLayout and is empty but ready for any new actions. See cleanUp()
* */
diff --git a/app/src/main/java/org/schabi/newpipe/player/MainPlayer.java b/app/src/main/java/org/schabi/newpipe/player/MainPlayer.java
index a0d4eb7d9..6e5082494 100644
--- a/app/src/main/java/org/schabi/newpipe/player/MainPlayer.java
+++ b/app/src/main/java/org/schabi/newpipe/player/MainPlayer.java
@@ -26,6 +26,7 @@ import android.content.Context;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
+import android.util.DisplayMetrics;
import android.view.ViewGroup;
import android.view.WindowManager;
import androidx.core.app.NotificationCompat;
@@ -183,7 +184,11 @@ public final class MainPlayer extends Service {
//////////////////////////////////////////////////////////////////////////*/
boolean isLandscape() {
- return getResources().getDisplayMetrics().heightPixels < getResources().getDisplayMetrics().widthPixels;
+ // DisplayMetrics from activity context knows about MultiWindow feature while DisplayMetrics from app context doesn't
+ final DisplayMetrics metrics = playerImpl.getParentActivity() != null ?
+ playerImpl.getParentActivity().getResources().getDisplayMetrics()
+ : getResources().getDisplayMetrics();
+ return metrics.heightPixels < metrics.widthPixels;
}
public View getView() {
diff --git a/app/src/main/java/org/schabi/newpipe/player/VideoPlayer.java b/app/src/main/java/org/schabi/newpipe/player/VideoPlayer.java
index 3a906d80c..07f485e7a 100644
--- a/app/src/main/java/org/schabi/newpipe/player/VideoPlayer.java
+++ b/app/src/main/java/org/schabi/newpipe/player/VideoPlayer.java
@@ -38,11 +38,7 @@ import android.view.Menu;
import android.view.MenuItem;
import android.view.SurfaceView;
import android.view.View;
-import android.widget.ImageView;
-import android.widget.PopupMenu;
-import android.widget.ProgressBar;
-import android.widget.SeekBar;
-import android.widget.TextView;
+import android.widget.*;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@@ -131,7 +127,7 @@ public abstract class VideoPlayer extends BasePlayer
private TextView playbackLiveSync;
private TextView playbackSpeedTextView;
- private View topControlsRoot;
+ private LinearLayout topControlsRoot;
private TextView qualityTextView;
private SubtitleView subtitleView;
@@ -961,7 +957,7 @@ public abstract class VideoPlayer extends BasePlayer
return playbackEndTime;
}
- public View getTopControlsRoot() {
+ public LinearLayout getTopControlsRoot() {
return topControlsRoot;
}
diff --git a/app/src/main/java/org/schabi/newpipe/player/VideoPlayerImpl.java b/app/src/main/java/org/schabi/newpipe/player/VideoPlayerImpl.java
index 71fe21b6d..76c8106be 100644
--- a/app/src/main/java/org/schabi/newpipe/player/VideoPlayerImpl.java
+++ b/app/src/main/java/org/schabi/newpipe/player/VideoPlayerImpl.java
@@ -25,6 +25,7 @@ import android.annotation.SuppressLint;
import android.content.*;
import android.graphics.Bitmap;
import android.graphics.PixelFormat;
+import android.graphics.Point;
import android.net.Uri;
import android.os.Build;
import android.preference.PreferenceManager;
@@ -124,7 +125,6 @@ public class VideoPlayerImpl extends VideoPlayer
private ImageButton shareButton;
private View primaryControls;
- private LinearLayout topControls;
private View secondaryControls;
private int maxGestureLength;
@@ -245,7 +245,6 @@ public class VideoPlayerImpl extends VideoPlayer
this.moreOptionsButton = rootView.findViewById(R.id.moreOptionsButton);
this.primaryControls = rootView.findViewById(R.id.primaryControls);
- this.topControls = rootView.findViewById(R.id.topControls);
this.secondaryControls = rootView.findViewById(R.id.secondaryControls);
this.shareButton = rootView.findViewById(R.id.share);
@@ -285,7 +284,7 @@ public class VideoPlayerImpl extends VideoPlayer
getRootView().findViewById(R.id.metadataView).setVisibility(View.GONE);
queueButton.setVisibility(View.GONE);
moreOptionsButton.setVisibility(View.GONE);
- topControls.setOrientation(LinearLayout.HORIZONTAL);
+ getTopControlsRoot().setOrientation(LinearLayout.HORIZONTAL);
primaryControls.getLayoutParams().width = LinearLayout.LayoutParams.WRAP_CONTENT;
secondaryControls.setAlpha(1f);
secondaryControls.setVisibility(View.VISIBLE);
@@ -297,7 +296,7 @@ public class VideoPlayerImpl extends VideoPlayer
fullscreenButton.setVisibility(View.GONE);
getRootView().findViewById(R.id.metadataView).setVisibility(View.VISIBLE);
moreOptionsButton.setVisibility(View.VISIBLE);
- topControls.setOrientation(LinearLayout.VERTICAL);
+ getTopControlsRoot().setOrientation(LinearLayout.VERTICAL);
primaryControls.getLayoutParams().width = LinearLayout.LayoutParams.MATCH_PARENT;
secondaryControls.setVisibility(View.GONE);
moreOptionsButton.setImageDrawable(service.getResources().getDrawable(
@@ -507,7 +506,7 @@ public class VideoPlayerImpl extends VideoPlayer
@Override
public void toggleFullscreen() {
- if (DEBUG) Log.d(TAG, "onFullScreenButtonClicked() called");
+ if (DEBUG) Log.d(TAG, "toggleFullscreen() called");
if (simpleExoPlayer == null || getCurrentMetadata() == null) return;
if (popupPlayerSelected()) {
@@ -535,6 +534,7 @@ public class VideoPlayerImpl extends VideoPlayer
if (fragmentListener == null) return;
isFullscreen = !isFullscreen;
+ setControlsWidth();
fragmentListener.onFullscreenStateChanged(isInFullscreen());
// When user presses back button in landscape mode and in fullscreen and uses ZOOM mode
// a video can be larger than screen. Prevent it like this
@@ -595,7 +595,8 @@ public class VideoPlayerImpl extends VideoPlayer
getControlsVisibilityHandler().removeCallbacksAndMessages(null);
animateView(getControlsRoot(), true, DEFAULT_CONTROLS_DURATION, 0, () -> {
if (getCurrentState() == STATE_PLAYING && !isSomePopupMenuVisible()) {
- hideControls(DEFAULT_CONTROLS_DURATION, DEFAULT_CONTROLS_HIDE_TIME);
+ if (v.getId() == playPauseButton.getId()) hideControls(0, 0);
+ else hideControls(DEFAULT_CONTROLS_DURATION, DEFAULT_CONTROLS_HIDE_TIME);
}
});
}
@@ -816,6 +817,8 @@ public class VideoPlayerImpl extends VideoPlayer
service.getLockManager().acquireWifiAndCpu();
service.resetNotification();
service.updateNotification(R.drawable.ic_pause_white);
+
+ service.startForeground(NOTIFICATION_ID, service.getNotBuilder().build());
}
@Override
@@ -831,6 +834,10 @@ public class VideoPlayerImpl extends VideoPlayer
service.resetNotification();
service.updateNotification(R.drawable.ic_play_arrow_white);
+ // Remove running notification when user don't want music (or video in popup) to be played in background
+ if (!minimizeOnPopupEnabled() && !backgroundPlaybackEnabled() && videoPlayerSelected())
+ service.stopForeground(true);
+
getRootView().setKeepScreenOn(false);
service.getLockManager().releaseWifiAndCpu();
@@ -1033,6 +1040,7 @@ public class VideoPlayerImpl extends VideoPlayer
if (queueVisible) return;
showOrHideButtons();
+ showSystemUIPartially();
super.showControlsThenHide();
}
@@ -1041,6 +1049,7 @@ public class VideoPlayerImpl extends VideoPlayer
if (queueVisible) return;
showOrHideButtons();
+ showSystemUIPartially();
super.showControls(duration);
}
@@ -1078,12 +1087,36 @@ public class VideoPlayerImpl extends VideoPlayer
queueButton.setVisibility(View.VISIBLE);
}
+ private void showSystemUIPartially() {
+ if (isInFullscreen()) {
+ int visibility = View.SYSTEM_UI_FLAG_LAYOUT_STABLE
+ | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
+ | View.SYSTEM_UI_FLAG_FULLSCREEN;
+ getParentActivity().getWindow().getDecorView().setSystemUiVisibility(visibility);
+ }
+ }
+
@Override
public void hideSystemUIIfNeeded() {
if (fragmentListener != null)
fragmentListener.hideSystemUIIfNeeded();
}
+ private void setControlsWidth() {
+ Point size = new Point();
+ // This method will give a correct size of a usable area of a window.
+ // It doesn't include NavigationBar, notches, etc.
+ getRootView().getDisplay().getSize(size);
+
+ int width = isFullscreen ? size.x : ViewGroup.LayoutParams.MATCH_PARENT;
+ primaryControls.getLayoutParams().width = width;
+ primaryControls.requestLayout();
+ secondaryControls.getLayoutParams().width = width;
+ secondaryControls.requestLayout();
+ getBottomControlsRoot().getLayoutParams().width = width;
+ getBottomControlsRoot().requestLayout();
+ }
+
private void updatePlaybackButtons() {
if (repeatButton == null || shuffleButton == null ||
simpleExoPlayer == null || playQueue == null) return;
diff --git a/app/src/main/java/org/schabi/newpipe/player/event/CustomBottomSheetBehavior.java b/app/src/main/java/org/schabi/newpipe/player/event/CustomBottomSheetBehavior.java
index 85db3b201..6f4cf41de 100644
--- a/app/src/main/java/org/schabi/newpipe/player/event/CustomBottomSheetBehavior.java
+++ b/app/src/main/java/org/schabi/newpipe/player/event/CustomBottomSheetBehavior.java
@@ -18,27 +18,30 @@ public class CustomBottomSheetBehavior extends BottomSheetBehavior {
@Override
public boolean onInterceptTouchEvent(CoordinatorLayout parent, View child, MotionEvent event) {
+ // Behavior of globalVisibleRect is different on different APIs.
+ // For example, on API 19 getGlobalVisibleRect returns a filled rect of a collapsed view while on the latest API
+ // it returns empty rect in that case. So check visibility with return value too
+ boolean visible;
+ Rect rect = new Rect();
+
// Without overriding scrolling will not work in detail_content_root_layout
ViewGroup controls = child.findViewById(R.id.detail_content_root_layout);
if (controls != null) {
- Rect rect = new Rect();
- controls.getGlobalVisibleRect(rect);
- if (rect.contains((int) event.getX(), (int) event.getY())) return false;
+ visible = controls.getGlobalVisibleRect(rect);
+ if (rect.contains((int) event.getX(), (int) event.getY()) && visible) return false;
}
// Without overriding scrolling will not work on relatedStreamsLayout
ViewGroup relatedStreamsLayout = child.findViewById(R.id.relatedStreamsLayout);
if (relatedStreamsLayout != null) {
- Rect rect = new Rect();
- relatedStreamsLayout.getGlobalVisibleRect(rect);
- if (rect.contains((int) event.getX(), (int) event.getY())) return false;
+ visible = relatedStreamsLayout.getGlobalVisibleRect(rect);
+ if (rect.contains((int) event.getX(), (int) event.getY()) && visible) return false;
}
ViewGroup playQueue = child.findViewById(R.id.playQueue);
if (playQueue != null) {
- Rect rect = new Rect();
- playQueue.getGlobalVisibleRect(rect);
- if (rect.contains((int) event.getX(), (int) event.getY())) return false;
+ visible = playQueue.getGlobalVisibleRect(rect);
+ if (rect.contains((int) event.getX(), (int) event.getY()) && visible) return false;
}
return super.onInterceptTouchEvent(parent, child, event);
diff --git a/app/src/main/java/org/schabi/newpipe/player/event/PlayerGestureListener.java b/app/src/main/java/org/schabi/newpipe/player/event/PlayerGestureListener.java
index 00a511ca3..db7d8d615 100644
--- a/app/src/main/java/org/schabi/newpipe/player/event/PlayerGestureListener.java
+++ b/app/src/main/java/org/schabi/newpipe/player/event/PlayerGestureListener.java
@@ -139,14 +139,6 @@ public class PlayerGestureListener extends GestureDetector.SimpleOnGestureListen
} else {
playerImpl.showControlsThenHide();
}
- if (playerImpl.isInFullscreen()) {
- int visibility = View.SYSTEM_UI_FLAG_LAYOUT_STABLE
- | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
- | View.SYSTEM_UI_FLAG_FULLSCREEN;
- playerImpl.getParentActivity().getWindow().getDecorView().setSystemUiVisibility(visibility);
- playerImpl.getParentActivity().getWindow().clearFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS);
- playerImpl.getParentActivity().getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
- }
}
return true;
}
diff --git a/app/src/main/res/layout-large-land/activity_main_player.xml b/app/src/main/res/layout-large-land/activity_main_player.xml
index 8d7d9b639..ff57bc2bf 100644
--- a/app/src/main/res/layout-large-land/activity_main_player.xml
+++ b/app/src/main/res/layout-large-land/activity_main_player.xml
@@ -377,12 +377,17 @@
android:visibility="gone"
tools:visibility="visible"/>
+
+
+
+