-Removed system ui on main player for Kitkat or above.

-[#1151] Hide video player UI on playing to avoid unnecessary interruptions after pause, seek and resize.
This commit is contained in:
John Zhen Mo 2018-03-03 20:58:53 -08:00
parent 59558efed1
commit 7f068b691b
5 changed files with 99 additions and 63 deletions

View file

@ -449,15 +449,13 @@ public abstract class BasePlayer implements
if (!isCurrentWindowValid()) seekToDefault(); if (!isCurrentWindowValid()) seekToDefault();
} }
public void onBuffering() { public void onBuffering() {}
}
public void onPaused() { public void onPaused() {
if (isProgressLoopRunning()) stopProgressLoop(); if (isProgressLoopRunning()) stopProgressLoop();
} }
public void onPausedSeek() { public void onPausedSeek() {}
}
public void onCompleted() { public void onCompleted() {
if (DEBUG) Log.d(TAG, "onCompleted() called"); if (DEBUG) Log.d(TAG, "onCompleted() called");

View file

@ -69,6 +69,9 @@ import org.schabi.newpipe.util.ThemeHelper;
import java.util.List; import java.util.List;
import static org.schabi.newpipe.player.BasePlayer.STATE_PLAYING;
import static org.schabi.newpipe.player.VideoPlayer.DEFAULT_CONTROLS_DURATION;
import static org.schabi.newpipe.player.VideoPlayer.DEFAULT_CONTROLS_HIDE_TIME;
import static org.schabi.newpipe.util.AnimationUtils.animateView; import static org.schabi.newpipe.util.AnimationUtils.animateView;
/** /**
@ -114,7 +117,7 @@ public final class MainVideoPlayer extends Activity {
return; return;
} }
showSystemUi(); changeSystemUi();
setContentView(R.layout.activity_main_player); setContentView(R.layout.activity_main_player);
playerImpl = new VideoPlayerImpl(this); playerImpl = new VideoPlayerImpl(this);
playerImpl.setup(findViewById(android.R.id.content)); playerImpl.setup(findViewById(android.R.id.content));
@ -206,31 +209,53 @@ public final class MainVideoPlayer extends Activity {
// Utils // Utils
//////////////////////////////////////////////////////////////////////////*/ //////////////////////////////////////////////////////////////////////////*/
/**
* Prior to Kitkat, hiding system ui causes the player view to be overlaid and require two
* clicks to get rid of that invisible overlay. By showing the system UI on actions/events,
* that overlay is removed and the player view is put to the foreground.
*
* Post Kitkat, navbar and status bar can be pulled out by swiping the edge of
* screen, therefore, we can do nothing or hide the UI on actions/events.
* */
private void changeSystemUi() {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
showSystemUi();
} else {
hideSystemUi();
}
}
private void showSystemUi() { private void showSystemUi() {
if (DEBUG) Log.d(TAG, "showSystemUi() called"); if (DEBUG) Log.d(TAG, "showSystemUi() called");
if (playerImpl != null && playerImpl.queueVisible) return; if (playerImpl != null && playerImpl.queueVisible) return;
final int visibility;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
getWindow().getDecorView().setSystemUiVisibility( visibility = View.SYSTEM_UI_FLAG_LAYOUT_STABLE
View.SYSTEM_UI_FLAG_LAYOUT_STABLE
| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
); } else {
} else getWindow().getDecorView().setSystemUiVisibility(0); visibility = View.STATUS_BAR_VISIBLE;
}
getWindow().getDecorView().setSystemUiVisibility(visibility);
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN); getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
} }
private void hideSystemUi() { private void hideSystemUi() {
if (DEBUG) Log.d(TAG, "hideSystemUi() called"); if (DEBUG) Log.d(TAG, "hideSystemUi() called");
if (android.os.Build.VERSION.SDK_INT >= 16) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
int visibility = View.SYSTEM_UI_FLAG_LAYOUT_STABLE int visibility = View.SYSTEM_UI_FLAG_LAYOUT_STABLE
| View.SYSTEM_UI_FLAG_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
| View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN; | View.SYSTEM_UI_FLAG_FULLSCREEN
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT) visibility |= View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY; | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
visibility |= View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
}
getWindow().getDecorView().setSystemUiVisibility(visibility); getWindow().getDecorView().setSystemUiVisibility(visibility);
} }
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
} }
private void toggleOrientation() { private void toggleOrientation() {
@ -307,6 +332,7 @@ public final class MainVideoPlayer extends Activity {
private ImageButton switchPopupButton; private ImageButton switchPopupButton;
private ImageButton switchBackgroundButton; private ImageButton switchBackgroundButton;
private RelativeLayout windowRootLayout;
private View secondaryControls; private View secondaryControls;
VideoPlayerImpl(final Context context) { VideoPlayerImpl(final Context context) {
@ -334,6 +360,19 @@ public final class MainVideoPlayer extends Activity {
this.switchBackgroundButton = rootView.findViewById(R.id.switchBackground); this.switchBackgroundButton = rootView.findViewById(R.id.switchBackground);
this.switchPopupButton = rootView.findViewById(R.id.switchPopup); this.switchPopupButton = rootView.findViewById(R.id.switchPopup);
this.queueLayout = findViewById(R.id.playQueuePanel);
this.itemsListCloseButton = findViewById(R.id.playQueueClose);
this.itemsList = findViewById(R.id.playQueue);
this.windowRootLayout = rootView.findViewById(R.id.playbackWindowRoot);
// Prior to Kitkat, there is no way of setting translucent navbar programmatically.
// Thus, fit system windows is opted instead.
// See https://stackoverflow.com/questions/29069070/completely-transparent-status-bar-and-navigation-bar-on-lollipop
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
windowRootLayout.setFitsSystemWindows(false);
windowRootLayout.invalidate();
}
titleTextView.setSelected(true); titleTextView.setSelected(true);
channelTextView.setSelected(true); channelTextView.setSelected(true);
@ -509,9 +548,9 @@ public final class MainVideoPlayer extends Activity {
if (getCurrentState() != STATE_COMPLETED) { if (getCurrentState() != STATE_COMPLETED) {
getControlsVisibilityHandler().removeCallbacksAndMessages(null); getControlsVisibilityHandler().removeCallbacksAndMessages(null);
animateView(getControlsRoot(), true, 300, 0, () -> { animateView(getControlsRoot(), true, DEFAULT_CONTROLS_DURATION, 0, () -> {
if (getCurrentState() == STATE_PLAYING && !isSomePopupMenuVisible()) { if (getCurrentState() == STATE_PLAYING && !isSomePopupMenuVisible()) {
hideControls(300, DEFAULT_CONTROLS_HIDE_TIME); hideControls(DEFAULT_CONTROLS_DURATION, DEFAULT_CONTROLS_HIDE_TIME);
} }
}); });
} }
@ -547,7 +586,7 @@ public final class MainVideoPlayer extends Activity {
R.drawable.ic_expand_less_white_24dp)); R.drawable.ic_expand_less_white_24dp));
animateView(secondaryControls, true, 200); animateView(secondaryControls, true, 200);
} }
showControls(300); showControls(DEFAULT_CONTROLS_DURATION);
} }
private void onScreenRotationClicked() { private void onScreenRotationClicked() {
@ -559,15 +598,13 @@ public final class MainVideoPlayer extends Activity {
@Override @Override
public void onStopTrackingTouch(SeekBar seekBar) { public void onStopTrackingTouch(SeekBar seekBar) {
super.onStopTrackingTouch(seekBar); super.onStopTrackingTouch(seekBar);
if (wasPlaying()) { if (wasPlaying()) showControlsThenHide();
hideControls(100, 0);
}
} }
@Override @Override
public void onDismiss(PopupMenu menu) { public void onDismiss(PopupMenu menu) {
super.onDismiss(menu); super.onDismiss(menu);
if (isPlaying()) hideControls(300, 0); if (isPlaying()) hideControls(DEFAULT_CONTROLS_DURATION, 0);
} }
@Override @Override
@ -625,7 +662,8 @@ public final class MainVideoPlayer extends Activity {
playPauseButton.setImageResource(R.drawable.ic_pause_white); playPauseButton.setImageResource(R.drawable.ic_pause_white);
animatePlayButtons(true, 200); animatePlayButtons(true, 200);
}); });
showSystemUi();
changeSystemUi();
getRootView().setKeepScreenOn(true); getRootView().setKeepScreenOn(true);
} }
@ -637,7 +675,7 @@ public final class MainVideoPlayer extends Activity {
animatePlayButtons(true, 200); animatePlayButtons(true, 200);
}); });
showSystemUi(); changeSystemUi();
getRootView().setKeepScreenOn(false); getRootView().setKeepScreenOn(false);
} }
@ -651,10 +689,9 @@ public final class MainVideoPlayer extends Activity {
@Override @Override
public void onCompleted() { public void onCompleted() {
showSystemUi();
animateView(playPauseButton, AnimationUtils.Type.SCALE_AND_ALPHA, false, 0, 0, () -> { animateView(playPauseButton, AnimationUtils.Type.SCALE_AND_ALPHA, false, 0, 0, () -> {
playPauseButton.setImageResource(R.drawable.ic_replay_white); playPauseButton.setImageResource(R.drawable.ic_replay_white);
animatePlayButtons(true, 300); animatePlayButtons(true, DEFAULT_CONTROLS_DURATION);
}); });
getRootView().setKeepScreenOn(false); getRootView().setKeepScreenOn(false);
@ -684,8 +721,9 @@ public final class MainVideoPlayer extends Activity {
if (DEBUG) Log.d(TAG, "hideControls() called with: delay = [" + delay + "]"); if (DEBUG) Log.d(TAG, "hideControls() called with: delay = [" + delay + "]");
getControlsVisibilityHandler().removeCallbacksAndMessages(null); getControlsVisibilityHandler().removeCallbacksAndMessages(null);
getControlsVisibilityHandler().postDelayed(() -> getControlsVisibilityHandler().postDelayed(() ->
animateView(getControlsRoot(), false, duration, 0, MainVideoPlayer.this::hideSystemUi), animateView(getControlsRoot(), false, duration, 0,
delay MainVideoPlayer.this::hideSystemUi),
/*delayMillis=*/delay
); );
} }
@ -698,11 +736,6 @@ public final class MainVideoPlayer extends Activity {
} }
private void buildQueue() { private void buildQueue() {
queueLayout = findViewById(R.id.playQueuePanel);
itemsListCloseButton = findViewById(R.id.playQueueClose);
itemsList = findViewById(R.id.playQueue);
itemsList.setAdapter(playQueueAdapter); itemsList.setAdapter(playQueueAdapter);
itemsList.setClickable(true); itemsList.setClickable(true);
itemsList.setLongClickable(true); itemsList.setLongClickable(true);
@ -831,10 +864,11 @@ public final class MainVideoPlayer extends Activity {
if (DEBUG) Log.d(TAG, "onSingleTapConfirmed() called with: e = [" + e + "]"); if (DEBUG) Log.d(TAG, "onSingleTapConfirmed() called with: e = [" + e + "]");
if (playerImpl.getCurrentState() == BasePlayer.STATE_BLOCKED) return true; if (playerImpl.getCurrentState() == BasePlayer.STATE_BLOCKED) return true;
if (playerImpl.isControlsVisible()) playerImpl.hideControls(150, 0); if (playerImpl.isControlsVisible()) {
else { playerImpl.hideControls(150, 0);
} else {
playerImpl.showControlsThenHide(); playerImpl.showControlsThenHide();
showSystemUi(); changeSystemUi();
} }
return true; return true;
} }
@ -917,11 +951,15 @@ public final class MainVideoPlayer extends Activity {
eventsNum = 0; eventsNum = 0;
/* if (playerImpl.getVolumeTextView().getVisibility() == View.VISIBLE) playerImpl.getVolumeTextView().setVisibility(View.GONE); /* if (playerImpl.getVolumeTextView().getVisibility() == View.VISIBLE) playerImpl.getVolumeTextView().setVisibility(View.GONE);
if (playerImpl.getBrightnessTextView().getVisibility() == View.VISIBLE) playerImpl.getBrightnessTextView().setVisibility(View.GONE);*/ if (playerImpl.getBrightnessTextView().getVisibility() == View.VISIBLE) playerImpl.getBrightnessTextView().setVisibility(View.GONE);*/
if (playerImpl.getVolumeTextView().getVisibility() == View.VISIBLE) animateView(playerImpl.getVolumeTextView(), false, 200, 200); if (playerImpl.getVolumeTextView().getVisibility() == View.VISIBLE) {
if (playerImpl.getBrightnessTextView().getVisibility() == View.VISIBLE) animateView(playerImpl.getBrightnessTextView(), false, 200, 200); animateView(playerImpl.getVolumeTextView(), false, 200, 200);
}
if (playerImpl.getBrightnessTextView().getVisibility() == View.VISIBLE) {
animateView(playerImpl.getBrightnessTextView(), false, 200, 200);
}
if (playerImpl.isControlsVisible() && playerImpl.getCurrentState() == BasePlayer.STATE_PLAYING) { if (playerImpl.isControlsVisible() && playerImpl.getCurrentState() == STATE_PLAYING) {
playerImpl.hideControls(300, VideoPlayer.DEFAULT_CONTROLS_HIDE_TIME); playerImpl.hideControls(DEFAULT_CONTROLS_DURATION, DEFAULT_CONTROLS_HIDE_TIME);
} }
} }

View file

@ -70,6 +70,9 @@ import org.schabi.newpipe.util.ThemeHelper;
import java.util.List; import java.util.List;
import static org.schabi.newpipe.player.BasePlayer.STATE_PLAYING;
import static org.schabi.newpipe.player.VideoPlayer.DEFAULT_CONTROLS_DURATION;
import static org.schabi.newpipe.player.VideoPlayer.DEFAULT_CONTROLS_HIDE_TIME;
import static org.schabi.newpipe.player.helper.PlayerHelper.isUsingOldPlayer; import static org.schabi.newpipe.player.helper.PlayerHelper.isUsingOldPlayer;
import static org.schabi.newpipe.util.AnimationUtils.animateView; import static org.schabi.newpipe.util.AnimationUtils.animateView;
@ -650,6 +653,8 @@ public final class PopupVideoPlayer extends Service {
super.onPlaying(); super.onPlaying();
updateNotification(R.drawable.ic_pause_white); updateNotification(R.drawable.ic_pause_white);
lockManager.acquireWifiAndCpu(); lockManager.acquireWifiAndCpu();
hideControls(DEFAULT_CONTROLS_DURATION, DEFAULT_CONTROLS_HIDE_TIME);
} }
@Override @Override
@ -782,8 +787,8 @@ public final class PopupVideoPlayer extends Service {
private void onScrollEnd() { private void onScrollEnd() {
if (DEBUG) Log.d(TAG, "onScrollEnd() called"); if (DEBUG) Log.d(TAG, "onScrollEnd() called");
if (playerImpl == null) return; if (playerImpl == null) return;
if (playerImpl.isControlsVisible() && playerImpl.getCurrentState() == BasePlayer.STATE_PLAYING) { if (playerImpl.isControlsVisible() && playerImpl.getCurrentState() == STATE_PLAYING) {
playerImpl.hideControls(300, VideoPlayer.DEFAULT_CONTROLS_HIDE_TIME); playerImpl.hideControls(DEFAULT_CONTROLS_DURATION, DEFAULT_CONTROLS_HIDE_TIME);
} }
} }

View file

@ -101,6 +101,7 @@ public abstract class VideoPlayer extends BasePlayer
//////////////////////////////////////////////////////////////////////////*/ //////////////////////////////////////////////////////////////////////////*/
protected static final int RENDERER_UNAVAILABLE = -1; protected static final int RENDERER_UNAVAILABLE = -1;
public static final int DEFAULT_CONTROLS_DURATION = 300; // 300 millis
public static final int DEFAULT_CONTROLS_HIDE_TIME = 2000; // 2 Seconds public static final int DEFAULT_CONTROLS_HIDE_TIME = 2000; // 2 Seconds
private ArrayList<VideoStream> availableStreams; private ArrayList<VideoStream> availableStreams;
@ -450,7 +451,7 @@ public abstract class VideoPlayer extends BasePlayer
super.onBlocked(); super.onBlocked();
controlsVisibilityHandler.removeCallbacksAndMessages(null); controlsVisibilityHandler.removeCallbacksAndMessages(null);
animateView(controlsRoot, false, 300); animateView(controlsRoot, false, DEFAULT_CONTROLS_DURATION);
playbackSeekBar.setEnabled(false); playbackSeekBar.setEnabled(false);
// Bug on lower api, disabling and enabling the seekBar resets the thumb color -.-, so sets the color again // Bug on lower api, disabling and enabling the seekBar resets the thumb color -.-, so sets the color again
@ -475,7 +476,7 @@ public abstract class VideoPlayer extends BasePlayer
playbackSeekBar.getThumb().setColorFilter(Color.RED, PorterDuff.Mode.SRC_IN); playbackSeekBar.getThumb().setColorFilter(Color.RED, PorterDuff.Mode.SRC_IN);
loadingPanel.setVisibility(View.GONE); loadingPanel.setVisibility(View.GONE);
showControlsThenHide();
animateView(currentDisplaySeek, AnimationUtils.Type.SCALE_AND_ALPHA, false, 200); animateView(currentDisplaySeek, AnimationUtils.Type.SCALE_AND_ALPHA, false, 200);
animateView(endScreen, false, 0); animateView(endScreen, false, 0);
} }
@ -707,7 +708,7 @@ public abstract class VideoPlayer extends BasePlayer
if (DEBUG) Log.d(TAG, "onQualitySelectorClicked() called"); if (DEBUG) Log.d(TAG, "onQualitySelectorClicked() called");
qualityPopupMenu.show(); qualityPopupMenu.show();
isSomePopupMenuVisible = true; isSomePopupMenuVisible = true;
showControls(300); showControls(DEFAULT_CONTROLS_DURATION);
final VideoStream videoStream = getSelectedVideoStream(); final VideoStream videoStream = getSelectedVideoStream();
if (videoStream != null) { if (videoStream != null) {
@ -723,14 +724,14 @@ public abstract class VideoPlayer extends BasePlayer
if (DEBUG) Log.d(TAG, "onPlaybackSpeedClicked() called"); if (DEBUG) Log.d(TAG, "onPlaybackSpeedClicked() called");
playbackSpeedPopupMenu.show(); playbackSpeedPopupMenu.show();
isSomePopupMenuVisible = true; isSomePopupMenuVisible = true;
showControls(300); showControls(DEFAULT_CONTROLS_DURATION);
} }
private void onCaptionClicked() { private void onCaptionClicked() {
if (DEBUG) Log.d(TAG, "onCaptionClicked() called"); if (DEBUG) Log.d(TAG, "onCaptionClicked() called");
captionPopupMenu.show(); captionPopupMenu.show();
isSomePopupMenuVisible = true; isSomePopupMenuVisible = true;
showControls(300); showControls(DEFAULT_CONTROLS_DURATION);
} }
private void onResizeClicked() { private void onResizeClicked() {
@ -763,7 +764,8 @@ public abstract class VideoPlayer extends BasePlayer
if (isPlaying()) simpleExoPlayer.setPlayWhenReady(false); if (isPlaying()) simpleExoPlayer.setPlayWhenReady(false);
showControls(0); showControls(0);
animateView(currentDisplaySeek, AnimationUtils.Type.SCALE_AND_ALPHA, true, 300); animateView(currentDisplaySeek, AnimationUtils.Type.SCALE_AND_ALPHA, true,
DEFAULT_CONTROLS_DURATION);
} }
@Override @Override
@ -819,7 +821,7 @@ public abstract class VideoPlayer extends BasePlayer
PropertyValuesHolder.ofFloat(View.ALPHA, 1f, 0f), PropertyValuesHolder.ofFloat(View.ALPHA, 1f, 0f),
PropertyValuesHolder.ofFloat(View.SCALE_X, 1.4f, 1f), PropertyValuesHolder.ofFloat(View.SCALE_X, 1.4f, 1f),
PropertyValuesHolder.ofFloat(View.SCALE_Y, 1.4f, 1f) PropertyValuesHolder.ofFloat(View.SCALE_Y, 1.4f, 1f)
).setDuration(300); ).setDuration(DEFAULT_CONTROLS_DURATION);
controlViewAnimator.addListener(new AnimatorListenerAdapter() { controlViewAnimator.addListener(new AnimatorListenerAdapter() {
@Override @Override
public void onAnimationEnd(Animator animation) { public void onAnimationEnd(Animator animation) {
@ -861,12 +863,8 @@ public abstract class VideoPlayer extends BasePlayer
public void showControlsThenHide() { public void showControlsThenHide() {
if (DEBUG) Log.d(TAG, "showControlsThenHide() called"); if (DEBUG) Log.d(TAG, "showControlsThenHide() called");
animateView(controlsRoot, true, 300, 0, new Runnable() { animateView(controlsRoot, true, DEFAULT_CONTROLS_DURATION, 0,
@Override () -> hideControls(DEFAULT_CONTROLS_DURATION, DEFAULT_CONTROLS_HIDE_TIME));
public void run() {
hideControls(300, DEFAULT_CONTROLS_HIDE_TIME);
}
});
} }
public void showControls(long duration) { public void showControls(long duration) {
@ -878,12 +876,8 @@ public abstract class VideoPlayer extends BasePlayer
public void hideControls(final long duration, long delay) { public void hideControls(final long duration, long delay) {
if (DEBUG) Log.d(TAG, "hideControls() called with: delay = [" + delay + "]"); if (DEBUG) Log.d(TAG, "hideControls() called with: delay = [" + delay + "]");
controlsVisibilityHandler.removeCallbacksAndMessages(null); controlsVisibilityHandler.removeCallbacksAndMessages(null);
controlsVisibilityHandler.postDelayed(new Runnable() { controlsVisibilityHandler.postDelayed(
@Override () -> animateView(controlsRoot, false, duration), delay);
public void run() {
animateView(controlsRoot, false, duration);
}
}, delay);
} }
/*////////////////////////////////////////////////////////////////////////// /*//////////////////////////////////////////////////////////////////////////

View file

@ -134,6 +134,7 @@
tools:visibility="visible"> tools:visibility="visible">
<RelativeLayout <RelativeLayout
android:id="@+id/playbackWindowRoot"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:fitsSystemWindows="true"> android:fitsSystemWindows="true">