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
This commit is contained in:
Avently 2020-01-03 08:05:31 +03:00
parent bc2dc8d933
commit 4519dd010d
9 changed files with 87 additions and 50 deletions

View File

@ -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()
* */

View File

@ -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() {

View File

@ -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;
}

View File

@ -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;

View File

@ -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);

View File

@ -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;
}

View File

@ -377,12 +377,17 @@
android:visibility="gone"
tools:visibility="visible"/>
<View
android:layout_width="match_parent"
android:layout_height="30dp"
android:background="@drawable/player_controls_bg"
android:layout_alignParentBottom="true" />
<LinearLayout
android:id="@+id/bottomControls"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:background="@drawable/player_controls_bg"
android:gravity="center"
android:orientation="horizontal"
android:paddingBottom="6dp"

View File

@ -375,12 +375,17 @@
android:visibility="gone"
tools:visibility="visible"/>
<View
android:layout_width="match_parent"
android:layout_height="30dp"
android:background="@drawable/player_controls_bg"
android:layout_alignParentBottom="true" />
<LinearLayout
android:id="@+id/bottomControls"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:background="@drawable/player_controls_bg"
android:gravity="center"
android:orientation="horizontal"
android:paddingBottom="6dp"

View File

@ -549,11 +549,10 @@
android:layout_height="match_parent"
android:alpha="0"
tools:alpha="1"
android:paddingLeft="@dimen/video_item_search_padding"
android:paddingRight="@dimen/video_item_search_padding"
android:background="?attr/windowBackground" >
<ImageButton
android:paddingLeft="@dimen/video_item_search_padding"
android:id="@+id/overlay_thumbnail"
android:layout_width="50dp"
android:layout_height="60dp"
@ -613,6 +612,7 @@
android:layout_height="60dp"
android:gravity="center_vertical"
android:paddingLeft="@dimen/video_item_search_padding"
android:paddingRight="@dimen/video_item_search_padding"
android:layout_alignParentEnd="true"
tools:ignore="RtlHardcoded">