Merge pull request #4272 from avently/small-fixes2
Small fixes of issues with old devices support, brightness, etc
This commit is contained in:
commit
541eb70b9c
|
@ -11,6 +11,7 @@ import android.content.ServiceConnection;
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
import android.content.pm.ActivityInfo;
|
import android.content.pm.ActivityInfo;
|
||||||
import android.database.ContentObserver;
|
import android.database.ContentObserver;
|
||||||
|
import android.graphics.Color;
|
||||||
import android.graphics.drawable.Drawable;
|
import android.graphics.drawable.Drawable;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
@ -102,13 +103,12 @@ import org.schabi.newpipe.util.ListHelper;
|
||||||
import org.schabi.newpipe.util.Localization;
|
import org.schabi.newpipe.util.Localization;
|
||||||
import org.schabi.newpipe.util.NavigationHelper;
|
import org.schabi.newpipe.util.NavigationHelper;
|
||||||
import org.schabi.newpipe.util.PermissionHelper;
|
import org.schabi.newpipe.util.PermissionHelper;
|
||||||
|
import org.schabi.newpipe.util.SerializedCache;
|
||||||
import org.schabi.newpipe.util.ShareUtils;
|
import org.schabi.newpipe.util.ShareUtils;
|
||||||
import org.schabi.newpipe.util.ThemeHelper;
|
import org.schabi.newpipe.util.ThemeHelper;
|
||||||
import org.schabi.newpipe.views.AnimatedProgressBar;
|
import org.schabi.newpipe.views.AnimatedProgressBar;
|
||||||
import org.schabi.newpipe.views.LargeTextMovementMethod;
|
import org.schabi.newpipe.views.LargeTextMovementMethod;
|
||||||
|
|
||||||
import java.io.Serializable;
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -125,6 +125,7 @@ import io.reactivex.schedulers.Schedulers;
|
||||||
|
|
||||||
import static org.schabi.newpipe.extractor.StreamingService.ServiceInfo.MediaCapability.COMMENTS;
|
import static org.schabi.newpipe.extractor.StreamingService.ServiceInfo.MediaCapability.COMMENTS;
|
||||||
import static org.schabi.newpipe.extractor.stream.StreamExtractor.NO_AGE_LIMIT;
|
import static org.schabi.newpipe.extractor.stream.StreamExtractor.NO_AGE_LIMIT;
|
||||||
|
import static org.schabi.newpipe.player.helper.PlayerHelper.globalScreenOrientationLocked;
|
||||||
import static org.schabi.newpipe.player.helper.PlayerHelper.isClearingQueueConfirmationRequired;
|
import static org.schabi.newpipe.player.helper.PlayerHelper.isClearingQueueConfirmationRequired;
|
||||||
import static org.schabi.newpipe.player.playqueue.PlayQueueItem.RECOVERY_UNSET;
|
import static org.schabi.newpipe.player.playqueue.PlayQueueItem.RECOVERY_UNSET;
|
||||||
import static org.schabi.newpipe.util.AnimationUtils.animateView;
|
import static org.schabi.newpipe.util.AnimationUtils.animateView;
|
||||||
|
@ -337,7 +338,7 @@ public class VideoDetailFragment
|
||||||
stopPlayerListener();
|
stopPlayerListener();
|
||||||
playerService = null;
|
playerService = null;
|
||||||
player = null;
|
player = null;
|
||||||
saveCurrentAndRestoreDefaultBrightness();
|
restoreDefaultBrightness();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -404,7 +405,7 @@ public class VideoDetailFragment
|
||||||
settingsContentObserver = new ContentObserver(new Handler()) {
|
settingsContentObserver = new ContentObserver(new Handler()) {
|
||||||
@Override
|
@Override
|
||||||
public void onChange(final boolean selfChange) {
|
public void onChange(final boolean selfChange) {
|
||||||
if (activity != null && !PlayerHelper.globalScreenOrientationLocked(activity)) {
|
if (activity != null && !globalScreenOrientationLocked(activity)) {
|
||||||
activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
|
activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -426,7 +427,7 @@ public class VideoDetailFragment
|
||||||
if (currentWorker != null) {
|
if (currentWorker != null) {
|
||||||
currentWorker.dispose();
|
currentWorker.dispose();
|
||||||
}
|
}
|
||||||
saveCurrentAndRestoreDefaultBrightness();
|
restoreDefaultBrightness();
|
||||||
PreferenceManager.getDefaultSharedPreferences(requireContext())
|
PreferenceManager.getDefaultSharedPreferences(requireContext())
|
||||||
.edit()
|
.edit()
|
||||||
.putString(getString(R.string.stream_info_selected_tab_key),
|
.putString(getString(R.string.stream_info_selected_tab_key),
|
||||||
|
@ -538,31 +539,51 @@ public class VideoDetailFragment
|
||||||
super.onSaveInstanceState(outState);
|
super.onSaveInstanceState(outState);
|
||||||
|
|
||||||
if (!isLoading.get() && currentInfo != null && isVisible()) {
|
if (!isLoading.get() && currentInfo != null && isVisible()) {
|
||||||
outState.putSerializable(INFO_KEY, currentInfo);
|
final String infoCacheKey = SerializedCache.getInstance()
|
||||||
|
.put(currentInfo, StreamInfo.class);
|
||||||
|
if (infoCacheKey != null) {
|
||||||
|
outState.putString(INFO_KEY, infoCacheKey);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (playQueue != null) {
|
if (playQueue != null) {
|
||||||
outState.putSerializable(VideoPlayer.PLAY_QUEUE_KEY, playQueue);
|
final String queueCacheKey = SerializedCache.getInstance()
|
||||||
|
.put(playQueue, PlayQueue.class);
|
||||||
|
if (queueCacheKey != null) {
|
||||||
|
outState.putString(VideoPlayer.PLAY_QUEUE_KEY, queueCacheKey);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
final String stackCacheKey = SerializedCache.getInstance().put(stack, LinkedList.class);
|
||||||
|
if (stackCacheKey != null) {
|
||||||
|
outState.putString(STACK_KEY, stackCacheKey);
|
||||||
}
|
}
|
||||||
outState.putSerializable(STACK_KEY, stack);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onRestoreInstanceState(@NonNull final Bundle savedState) {
|
protected void onRestoreInstanceState(@NonNull final Bundle savedState) {
|
||||||
super.onRestoreInstanceState(savedState);
|
super.onRestoreInstanceState(savedState);
|
||||||
|
|
||||||
Serializable serializable = savedState.getSerializable(INFO_KEY);
|
final String infoCacheKey = savedState.getString(INFO_KEY);
|
||||||
if (serializable instanceof StreamInfo) {
|
if (infoCacheKey != null) {
|
||||||
currentInfo = (StreamInfo) serializable;
|
currentInfo = SerializedCache.getInstance().take(infoCacheKey, StreamInfo.class);
|
||||||
InfoCache.getInstance().putInfo(serviceId, url, currentInfo, InfoItem.InfoType.STREAM);
|
if (currentInfo != null) {
|
||||||
|
InfoCache.getInstance()
|
||||||
|
.putInfo(serviceId, url, currentInfo, InfoItem.InfoType.STREAM);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
serializable = savedState.getSerializable(STACK_KEY);
|
final String stackCacheKey = savedState.getString(STACK_KEY);
|
||||||
if (serializable instanceof Collection) {
|
if (stackCacheKey != null) {
|
||||||
//noinspection unchecked
|
final LinkedList<StackItem> cachedStack =
|
||||||
stack.addAll((Collection<? extends StackItem>) serializable);
|
SerializedCache.getInstance().take(stackCacheKey, LinkedList.class);
|
||||||
|
if (cachedStack != null) {
|
||||||
|
stack.addAll(cachedStack);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
final String queueCacheKey = savedState.getString(VideoPlayer.PLAY_QUEUE_KEY);
|
||||||
|
if (queueCacheKey != null) {
|
||||||
|
playQueue = SerializedCache.getInstance().take(queueCacheKey, PlayQueue.class);
|
||||||
}
|
}
|
||||||
playQueue = (PlayQueue) savedState.getSerializable(VideoPlayer.PLAY_QUEUE_KEY);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -1808,9 +1829,6 @@ public class VideoDetailFragment
|
||||||
setOverlayPlayPauseImage();
|
setOverlayPlayPauseImage();
|
||||||
|
|
||||||
switch (state) {
|
switch (state) {
|
||||||
case BasePlayer.STATE_COMPLETED:
|
|
||||||
restoreDefaultOrientation();
|
|
||||||
break;
|
|
||||||
case BasePlayer.STATE_PLAYING:
|
case BasePlayer.STATE_PLAYING:
|
||||||
if (positionView.getAlpha() != 1.0f
|
if (positionView.getAlpha() != 1.0f
|
||||||
&& player.getPlayQueue() != null
|
&& player.getPlayQueue() != null
|
||||||
|
@ -1869,10 +1887,11 @@ public class VideoDetailFragment
|
||||||
public void onPlayerError(final ExoPlaybackException error) {
|
public void onPlayerError(final ExoPlaybackException error) {
|
||||||
if (error.type == ExoPlaybackException.TYPE_SOURCE
|
if (error.type == ExoPlaybackException.TYPE_SOURCE
|
||||||
|| error.type == ExoPlaybackException.TYPE_UNEXPECTED) {
|
|| error.type == ExoPlaybackException.TYPE_UNEXPECTED) {
|
||||||
hideMainPlayer();
|
// Properly exit from fullscreen
|
||||||
if (playerService != null && player.isFullscreen()) {
|
if (playerService != null && player.isFullscreen()) {
|
||||||
player.toggleFullscreen();
|
player.toggleFullscreen();
|
||||||
}
|
}
|
||||||
|
hideMainPlayer();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1911,7 +1930,13 @@ public class VideoDetailFragment
|
||||||
}
|
}
|
||||||
scrollToTop();
|
scrollToTop();
|
||||||
|
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||||
addVideoPlayerView();
|
addVideoPlayerView();
|
||||||
|
} else {
|
||||||
|
// KitKat needs a delay before addVideoPlayerView call or it reports wrong height in
|
||||||
|
// activity.getWindow().getDecorView().getHeight()
|
||||||
|
new Handler().post(this::addVideoPlayerView);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -1919,13 +1944,15 @@ public class VideoDetailFragment
|
||||||
// In tablet user experience will be better if screen will not be rotated
|
// In tablet user experience will be better if screen will not be rotated
|
||||||
// from landscape to portrait every time.
|
// from landscape to portrait every time.
|
||||||
// Just turn on fullscreen mode in landscape orientation
|
// Just turn on fullscreen mode in landscape orientation
|
||||||
if (isLandscape() && DeviceUtils.isTablet(activity)) {
|
// or portrait & unlocked global orientation
|
||||||
|
if (DeviceUtils.isTablet(activity)
|
||||||
|
&& (!globalScreenOrientationLocked(activity) || isLandscape())) {
|
||||||
player.toggleFullscreen();
|
player.toggleFullscreen();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
final int newOrientation = isLandscape()
|
final int newOrientation = isLandscape()
|
||||||
? ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED
|
? ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
|
||||||
: ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE;
|
: ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE;
|
||||||
|
|
||||||
activity.setRequestedOrientation(newOrientation);
|
activity.setRequestedOrientation(newOrientation);
|
||||||
|
@ -1970,7 +1997,11 @@ public class VideoDetailFragment
|
||||||
WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT;
|
WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT;
|
||||||
}
|
}
|
||||||
activity.getWindow().getDecorView().setSystemUiVisibility(0);
|
activity.getWindow().getDecorView().setSystemUiVisibility(0);
|
||||||
activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS);
|
activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||||
|
activity.getWindow().setStatusBarColor(ThemeHelper.resolveColorFromAttr(
|
||||||
|
requireContext(), android.R.attr.colorPrimary));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void hideSystemUi() {
|
private void hideSystemUi() {
|
||||||
|
@ -1985,18 +2016,26 @@ public class VideoDetailFragment
|
||||||
// Prevent jumping of the player on devices with cutout
|
// Prevent jumping of the player on devices with cutout
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
||||||
activity.getWindow().getAttributes().layoutInDisplayCutoutMode =
|
activity.getWindow().getAttributes().layoutInDisplayCutoutMode =
|
||||||
WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER;
|
WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
|
||||||
}
|
}
|
||||||
final int visibility = View.SYSTEM_UI_FLAG_LAYOUT_STABLE
|
int visibility = 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
|
||||||
| View.SYSTEM_UI_FLAG_FULLSCREEN
|
|
||||||
| View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
|
| View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
|
||||||
| View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
|
| View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
|
||||||
|
// In multiWindow mode status bar is not transparent for devices with cutout
|
||||||
|
// if I include this flag. So without it is better in this case
|
||||||
|
if (!isInMultiWindow()) {
|
||||||
|
visibility |= View.SYSTEM_UI_FLAG_FULLSCREEN;
|
||||||
|
}
|
||||||
activity.getWindow().getDecorView().setSystemUiVisibility(visibility);
|
activity.getWindow().getDecorView().setSystemUiVisibility(visibility);
|
||||||
activity.getWindow().setFlags(
|
|
||||||
WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS,
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP
|
||||||
WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS);
|
&& (isInMultiWindow() || (player != null && player.isFullscreen()))) {
|
||||||
|
activity.getWindow().setStatusBarColor(Color.TRANSPARENT);
|
||||||
|
activity.getWindow().setNavigationBarColor(Color.TRANSPARENT);
|
||||||
|
}
|
||||||
|
activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Listener implementation
|
// Listener implementation
|
||||||
|
@ -2014,13 +2053,11 @@ public class VideoDetailFragment
|
||||||
&& player.getPlayer().getPlaybackState() != Player.STATE_IDLE;
|
&& player.getPlayer().getPlaybackState() != Player.STATE_IDLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void saveCurrentAndRestoreDefaultBrightness() {
|
private void restoreDefaultBrightness() {
|
||||||
final WindowManager.LayoutParams lp = activity.getWindow().getAttributes();
|
final WindowManager.LayoutParams lp = activity.getWindow().getAttributes();
|
||||||
if (lp.screenBrightness == -1) {
|
if (lp.screenBrightness == -1) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Save current brightness level
|
|
||||||
PlayerHelper.setScreenBrightness(activity, lp.screenBrightness);
|
|
||||||
|
|
||||||
// Restore the old brightness when fragment.onPause() called or
|
// Restore the old brightness when fragment.onPause() called or
|
||||||
// when a player is in portrait
|
// when a player is in portrait
|
||||||
|
@ -2039,7 +2076,7 @@ public class VideoDetailFragment
|
||||||
|| !player.isFullscreen()
|
|| !player.isFullscreen()
|
||||||
|| bottomSheetState != BottomSheetBehavior.STATE_EXPANDED) {
|
|| bottomSheetState != BottomSheetBehavior.STATE_EXPANDED) {
|
||||||
// Apply system brightness when the player is not in fullscreen
|
// Apply system brightness when the player is not in fullscreen
|
||||||
saveCurrentAndRestoreDefaultBrightness();
|
restoreDefaultBrightness();
|
||||||
} else {
|
} else {
|
||||||
// Restore already saved brightness level
|
// Restore already saved brightness level
|
||||||
final float brightnessLevel = PlayerHelper.getScreenBrightness(activity);
|
final float brightnessLevel = PlayerHelper.getScreenBrightness(activity);
|
||||||
|
@ -2058,11 +2095,9 @@ public class VideoDetailFragment
|
||||||
}
|
}
|
||||||
|
|
||||||
player.checkLandscape();
|
player.checkLandscape();
|
||||||
final boolean orientationLocked = PlayerHelper.globalScreenOrientationLocked(activity);
|
|
||||||
// Let's give a user time to look at video information page if video is not playing
|
// Let's give a user time to look at video information page if video is not playing
|
||||||
if (orientationLocked && !player.isPlaying()) {
|
if (globalScreenOrientationLocked(activity) && !player.isPlaying()) {
|
||||||
player.onPlay();
|
player.onPlay();
|
||||||
player.showControlsThenHide();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2265,6 +2300,7 @@ public class VideoDetailFragment
|
||||||
&& player.videoPlayerSelected()) {
|
&& player.videoPlayerSelected()) {
|
||||||
player.toggleFullscreen();
|
player.toggleFullscreen();
|
||||||
}
|
}
|
||||||
|
setOverlayLook(appBarLayout, behavior, 1);
|
||||||
break;
|
break;
|
||||||
case BottomSheetBehavior.STATE_COLLAPSED:
|
case BottomSheetBehavior.STATE_COLLAPSED:
|
||||||
moveFocusToMainFragment(true);
|
moveFocusToMainFragment(true);
|
||||||
|
@ -2274,6 +2310,7 @@ public class VideoDetailFragment
|
||||||
if (player != null) {
|
if (player != null) {
|
||||||
player.onQueueClosed();
|
player.onQueueClosed();
|
||||||
}
|
}
|
||||||
|
setOverlayLook(appBarLayout, behavior, 0);
|
||||||
break;
|
break;
|
||||||
case BottomSheetBehavior.STATE_DRAGGING:
|
case BottomSheetBehavior.STATE_DRAGGING:
|
||||||
case BottomSheetBehavior.STATE_SETTLING:
|
case BottomSheetBehavior.STATE_SETTLING:
|
||||||
|
|
|
@ -147,6 +147,7 @@ public final class MainPlayer extends Service {
|
||||||
// Android TV will handle back button in case controls will be visible
|
// Android TV will handle back button in case controls will be visible
|
||||||
// (one more additional unneeded click while the player is hidden)
|
// (one more additional unneeded click while the player is hidden)
|
||||||
playerImpl.hideControls(0, 0);
|
playerImpl.hideControls(0, 0);
|
||||||
|
playerImpl.onQueueClosed();
|
||||||
// Notification shows information about old stream but if a user selects
|
// Notification shows information about old stream but if a user selects
|
||||||
// a stream from backStack it's not actual anymore
|
// a stream from backStack it's not actual anymore
|
||||||
// So we should hide the notification at all.
|
// So we should hide the notification at all.
|
||||||
|
@ -195,6 +196,10 @@ public final class MainPlayer extends Service {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (playerImpl != null) {
|
if (playerImpl != null) {
|
||||||
|
// Exit from fullscreen when user closes the player via notification
|
||||||
|
if (playerImpl.isFullscreen()) {
|
||||||
|
playerImpl.toggleFullscreen();
|
||||||
|
}
|
||||||
removeViewFromParent();
|
removeViewFromParent();
|
||||||
|
|
||||||
playerImpl.setRecovery();
|
playerImpl.setRecovery();
|
||||||
|
|
|
@ -128,6 +128,8 @@ public abstract class VideoPlayer extends BasePlayer
|
||||||
|
|
||||||
private View controlsRoot;
|
private View controlsRoot;
|
||||||
private TextView currentDisplaySeek;
|
private TextView currentDisplaySeek;
|
||||||
|
private View playerTopShadow;
|
||||||
|
private View playerBottomShadow;
|
||||||
|
|
||||||
private View bottomControlsRoot;
|
private View bottomControlsRoot;
|
||||||
private SeekBar playbackSeekBar;
|
private SeekBar playbackSeekBar;
|
||||||
|
@ -190,6 +192,8 @@ public abstract class VideoPlayer extends BasePlayer
|
||||||
this.controlAnimationView = view.findViewById(R.id.controlAnimationView);
|
this.controlAnimationView = view.findViewById(R.id.controlAnimationView);
|
||||||
this.controlsRoot = view.findViewById(R.id.playbackControlRoot);
|
this.controlsRoot = view.findViewById(R.id.playbackControlRoot);
|
||||||
this.currentDisplaySeek = view.findViewById(R.id.currentDisplaySeek);
|
this.currentDisplaySeek = view.findViewById(R.id.currentDisplaySeek);
|
||||||
|
this.playerTopShadow = view.findViewById(R.id.playerTopShadow);
|
||||||
|
this.playerBottomShadow = view.findViewById(R.id.playerBottomShadow);
|
||||||
this.playbackSeekBar = view.findViewById(R.id.playbackSeekBar);
|
this.playbackSeekBar = view.findViewById(R.id.playbackSeekBar);
|
||||||
this.playbackCurrentTime = view.findViewById(R.id.playbackCurrentTime);
|
this.playbackCurrentTime = view.findViewById(R.id.playbackCurrentTime);
|
||||||
this.playbackEndTime = view.findViewById(R.id.playbackEndTime);
|
this.playbackEndTime = view.findViewById(R.id.playbackEndTime);
|
||||||
|
@ -356,11 +360,11 @@ public abstract class VideoPlayer extends BasePlayer
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
// apply caption language from previous user preference
|
// apply caption language from previous user preference
|
||||||
if (userPreferredLanguage != null && (captionLanguage.equals(userPreferredLanguage)
|
if (userPreferredLanguage != null
|
||||||
|| searchForAutogenerated && captionLanguage.startsWith(userPreferredLanguage)
|
&& (captionLanguage.equals(userPreferredLanguage)
|
||||||
|| userPreferredLanguage.contains("(") && captionLanguage.startsWith(
|
|| (searchForAutogenerated && captionLanguage.startsWith(userPreferredLanguage))
|
||||||
userPreferredLanguage
|
|| (userPreferredLanguage.contains("(") && captionLanguage.startsWith(
|
||||||
.substring(0, userPreferredLanguage.indexOf('('))))) {
|
userPreferredLanguage.substring(0, userPreferredLanguage.indexOf('(')))))) {
|
||||||
final int textRendererIndex = getRendererIndex(C.TRACK_TYPE_TEXT);
|
final int textRendererIndex = getRendererIndex(C.TRACK_TYPE_TEXT);
|
||||||
if (textRendererIndex != RENDERER_UNAVAILABLE) {
|
if (textRendererIndex != RENDERER_UNAVAILABLE) {
|
||||||
trackSelector.setPreferredTextLanguage(captionLanguage);
|
trackSelector.setPreferredTextLanguage(captionLanguage);
|
||||||
|
@ -754,7 +758,6 @@ public abstract class VideoPlayer extends BasePlayer
|
||||||
}
|
}
|
||||||
qualityPopupMenu.show();
|
qualityPopupMenu.show();
|
||||||
isSomePopupMenuVisible = true;
|
isSomePopupMenuVisible = true;
|
||||||
showControls(DEFAULT_CONTROLS_DURATION);
|
|
||||||
|
|
||||||
final VideoStream videoStream = getSelectedVideoStream();
|
final VideoStream videoStream = getSelectedVideoStream();
|
||||||
if (videoStream != null) {
|
if (videoStream != null) {
|
||||||
|
@ -772,7 +775,6 @@ public abstract class VideoPlayer extends BasePlayer
|
||||||
}
|
}
|
||||||
playbackSpeedPopupMenu.show();
|
playbackSpeedPopupMenu.show();
|
||||||
isSomePopupMenuVisible = true;
|
isSomePopupMenuVisible = true;
|
||||||
showControls(DEFAULT_CONTROLS_DURATION);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onCaptionClicked() {
|
private void onCaptionClicked() {
|
||||||
|
@ -781,7 +783,6 @@ public abstract class VideoPlayer extends BasePlayer
|
||||||
}
|
}
|
||||||
captionPopupMenu.show();
|
captionPopupMenu.show();
|
||||||
isSomePopupMenuVisible = true;
|
isSomePopupMenuVisible = true;
|
||||||
showControls(DEFAULT_CONTROLS_DURATION);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void onResizeClicked() {
|
void onResizeClicked() {
|
||||||
|
@ -958,6 +959,7 @@ public abstract class VideoPlayer extends BasePlayer
|
||||||
? DEFAULT_CONTROLS_HIDE_TIME
|
? DEFAULT_CONTROLS_HIDE_TIME
|
||||||
: DPAD_CONTROLS_HIDE_TIME;
|
: DPAD_CONTROLS_HIDE_TIME;
|
||||||
|
|
||||||
|
showHideShadow(true, DEFAULT_CONTROLS_DURATION, 0);
|
||||||
animateView(controlsRoot, true, DEFAULT_CONTROLS_DURATION, 0,
|
animateView(controlsRoot, true, DEFAULT_CONTROLS_DURATION, 0,
|
||||||
() -> hideControls(DEFAULT_CONTROLS_DURATION, hideTime));
|
() -> hideControls(DEFAULT_CONTROLS_DURATION, hideTime));
|
||||||
}
|
}
|
||||||
|
@ -967,6 +969,7 @@ public abstract class VideoPlayer extends BasePlayer
|
||||||
Log.d(TAG, "showControls() called");
|
Log.d(TAG, "showControls() called");
|
||||||
}
|
}
|
||||||
controlsVisibilityHandler.removeCallbacksAndMessages(null);
|
controlsVisibilityHandler.removeCallbacksAndMessages(null);
|
||||||
|
showHideShadow(true, duration, 0);
|
||||||
animateView(controlsRoot, true, duration);
|
animateView(controlsRoot, true, duration);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -986,8 +989,10 @@ public abstract class VideoPlayer extends BasePlayer
|
||||||
Log.d(TAG, "hideControls() called with: delay = [" + delay + "]");
|
Log.d(TAG, "hideControls() called with: delay = [" + delay + "]");
|
||||||
}
|
}
|
||||||
controlsVisibilityHandler.removeCallbacksAndMessages(null);
|
controlsVisibilityHandler.removeCallbacksAndMessages(null);
|
||||||
controlsVisibilityHandler.postDelayed(() ->
|
controlsVisibilityHandler.postDelayed(() -> {
|
||||||
animateView(controlsRoot, false, duration), delay);
|
showHideShadow(false, duration, 0);
|
||||||
|
animateView(controlsRoot, false, duration);
|
||||||
|
}, delay);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void hideControlsAndButton(final long duration, final long delay, final View button) {
|
public void hideControlsAndButton(final long duration, final long delay, final View button) {
|
||||||
|
@ -1006,6 +1011,11 @@ public abstract class VideoPlayer extends BasePlayer
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void showHideShadow(final boolean show, final long duration, final long delay) {
|
||||||
|
animateView(playerTopShadow, show, duration, delay, null);
|
||||||
|
animateView(playerBottomShadow, show, duration, delay, null);
|
||||||
|
}
|
||||||
|
|
||||||
public abstract void hideSystemUIIfNeeded();
|
public abstract void hideSystemUIIfNeeded();
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
|
@ -27,22 +27,21 @@ import android.content.IntentFilter;
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
import android.database.ContentObserver;
|
import android.database.ContentObserver;
|
||||||
import android.graphics.Bitmap;
|
import android.graphics.Bitmap;
|
||||||
|
import android.graphics.Color;
|
||||||
import android.graphics.PixelFormat;
|
import android.graphics.PixelFormat;
|
||||||
import android.graphics.Point;
|
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
|
import android.view.DisplayCutout;
|
||||||
import androidx.preference.PreferenceManager;
|
import androidx.preference.PreferenceManager;
|
||||||
import android.provider.Settings;
|
import android.provider.Settings;
|
||||||
import android.util.DisplayMetrics;
|
import android.util.DisplayMetrics;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.util.TypedValue;
|
import android.util.TypedValue;
|
||||||
import android.view.Display;
|
|
||||||
import android.view.GestureDetector;
|
import android.view.GestureDetector;
|
||||||
import android.view.Gravity;
|
import android.view.Gravity;
|
||||||
import android.view.KeyEvent;
|
import android.view.KeyEvent;
|
||||||
import android.view.MotionEvent;
|
import android.view.MotionEvent;
|
||||||
import android.view.Surface;
|
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.view.WindowManager;
|
import android.view.WindowManager;
|
||||||
|
@ -104,7 +103,6 @@ import org.schabi.newpipe.util.ShareUtils;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import static android.content.Context.WINDOW_SERVICE;
|
import static android.content.Context.WINDOW_SERVICE;
|
||||||
import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
|
|
||||||
import static org.schabi.newpipe.player.MainPlayer.ACTION_CLOSE;
|
import static org.schabi.newpipe.player.MainPlayer.ACTION_CLOSE;
|
||||||
import static org.schabi.newpipe.player.MainPlayer.ACTION_FAST_FORWARD;
|
import static org.schabi.newpipe.player.MainPlayer.ACTION_FAST_FORWARD;
|
||||||
import static org.schabi.newpipe.player.MainPlayer.ACTION_FAST_REWIND;
|
import static org.schabi.newpipe.player.MainPlayer.ACTION_FAST_REWIND;
|
||||||
|
@ -116,6 +114,7 @@ import static org.schabi.newpipe.player.MainPlayer.ACTION_RECREATE_NOTIFICATION;
|
||||||
import static org.schabi.newpipe.player.MainPlayer.ACTION_REPEAT;
|
import static org.schabi.newpipe.player.MainPlayer.ACTION_REPEAT;
|
||||||
import static org.schabi.newpipe.player.MainPlayer.ACTION_SHUFFLE;
|
import static org.schabi.newpipe.player.MainPlayer.ACTION_SHUFFLE;
|
||||||
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_BACKGROUND;
|
||||||
|
import static org.schabi.newpipe.player.helper.PlayerHelper.globalScreenOrientationLocked;
|
||||||
import static org.schabi.newpipe.util.AnimationUtils.Type.SLIDE_AND_ALPHA;
|
import static org.schabi.newpipe.util.AnimationUtils.Type.SLIDE_AND_ALPHA;
|
||||||
import static org.schabi.newpipe.util.AnimationUtils.animateRotation;
|
import static org.schabi.newpipe.util.AnimationUtils.animateRotation;
|
||||||
import static org.schabi.newpipe.util.AnimationUtils.animateView;
|
import static org.schabi.newpipe.util.AnimationUtils.animateView;
|
||||||
|
@ -138,7 +137,6 @@ public class VideoPlayerImpl extends VideoPlayer
|
||||||
static final String POPUP_SAVED_WIDTH = "popup_saved_width";
|
static final String POPUP_SAVED_WIDTH = "popup_saved_width";
|
||||||
static final String POPUP_SAVED_X = "popup_saved_x";
|
static final String POPUP_SAVED_X = "popup_saved_x";
|
||||||
static final String POPUP_SAVED_Y = "popup_saved_y";
|
static final String POPUP_SAVED_Y = "popup_saved_y";
|
||||||
private static final int MINIMUM_SHOW_EXTRA_WIDTH_DP = 300;
|
|
||||||
private static final int IDLE_WINDOW_FLAGS = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
|
private static final int IDLE_WINDOW_FLAGS = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
|
||||||
| WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
|
| WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
|
||||||
private static final int ONGOING_PLAYBACK_WINDOW_FLAGS = IDLE_WINDOW_FLAGS
|
private static final int ONGOING_PLAYBACK_WINDOW_FLAGS = IDLE_WINDOW_FLAGS
|
||||||
|
@ -254,6 +252,7 @@ public class VideoPlayerImpl extends VideoPlayer
|
||||||
} else {
|
} else {
|
||||||
getRootView().setVisibility(View.VISIBLE);
|
getRootView().setVisibility(View.VISIBLE);
|
||||||
initVideoPlayer();
|
initVideoPlayer();
|
||||||
|
onQueueClosed();
|
||||||
// Android TV: without it focus will frame the whole player
|
// Android TV: without it focus will frame the whole player
|
||||||
playPauseButton.requestFocus();
|
playPauseButton.requestFocus();
|
||||||
}
|
}
|
||||||
|
@ -310,6 +309,9 @@ public class VideoPlayerImpl extends VideoPlayer
|
||||||
|
|
||||||
titleTextView.setSelected(true);
|
titleTextView.setSelected(true);
|
||||||
channelTextView.setSelected(true);
|
channelTextView.setSelected(true);
|
||||||
|
|
||||||
|
// Prevent hiding of bottom sheet via swipe inside queue
|
||||||
|
this.itemsList.setNestedScrollingEnabled(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -334,7 +336,6 @@ public class VideoPlayerImpl extends VideoPlayer
|
||||||
* This method ensures that popup and main players have different look.
|
* This method ensures that popup and main players have different look.
|
||||||
* We use one layout for both players and need to decide what to show and what to hide.
|
* We use one layout for both players and need to decide what to show and what to hide.
|
||||||
* Additional measuring should be done inside {@link #setupElementsSize}.
|
* Additional measuring should be done inside {@link #setupElementsSize}.
|
||||||
* {@link #setControlsSize} is used to adapt the UI to fullscreen mode, multiWindow, navBar, etc
|
|
||||||
*/
|
*/
|
||||||
private void setupElementsVisibility() {
|
private void setupElementsVisibility() {
|
||||||
if (popupPlayerSelected()) {
|
if (popupPlayerSelected()) {
|
||||||
|
@ -469,6 +470,17 @@ public class VideoPlayerImpl extends VideoPlayer
|
||||||
Settings.System.getUriFor(Settings.System.ACCELEROMETER_ROTATION), false,
|
Settings.System.getUriFor(Settings.System.ACCELEROMETER_ROTATION), false,
|
||||||
settingsContentObserver);
|
settingsContentObserver);
|
||||||
getRootView().addOnLayoutChangeListener(this);
|
getRootView().addOnLayoutChangeListener(this);
|
||||||
|
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
||||||
|
queueLayout.setOnApplyWindowInsetsListener((view, windowInsets) -> {
|
||||||
|
final DisplayCutout cutout = windowInsets.getDisplayCutout();
|
||||||
|
if (cutout != null) {
|
||||||
|
view.setPadding(cutout.getSafeInsetLeft(), cutout.getSafeInsetTop(),
|
||||||
|
cutout.getSafeInsetRight(), cutout.getSafeInsetBottom());
|
||||||
|
}
|
||||||
|
return windowInsets;
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean onKeyDown(final int keyCode) {
|
public boolean onKeyDown(final int keyCode) {
|
||||||
|
@ -696,11 +708,46 @@ public class VideoPlayerImpl extends VideoPlayer
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
Log.d(TAG, "toggleFullscreen() called");
|
Log.d(TAG, "toggleFullscreen() called");
|
||||||
}
|
}
|
||||||
if (simpleExoPlayer == null || getCurrentMetadata() == null) {
|
if (popupPlayerSelected()
|
||||||
|
|| simpleExoPlayer == null
|
||||||
|
|| getCurrentMetadata() == null
|
||||||
|
|| fragmentListener == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
isFullscreen = !isFullscreen;
|
||||||
|
if (!isFullscreen) {
|
||||||
|
// Apply window insets because Android will not do it when orientation changes
|
||||||
|
// from landscape to portrait (open vertical video to reproduce)
|
||||||
|
getControlsRoot().setPadding(0, 0, 0, 0);
|
||||||
|
} else {
|
||||||
|
// Android needs tens milliseconds to send new insets but a user is able to see
|
||||||
|
// how controls changes it's position from `0` to `nav bar height` padding.
|
||||||
|
// So just hide the controls to hide this visual inconsistency
|
||||||
|
hideControls(0, 0);
|
||||||
|
}
|
||||||
|
fragmentListener.onFullscreenStateChanged(isFullscreen());
|
||||||
|
|
||||||
|
if (!isFullscreen()) {
|
||||||
|
titleTextView.setVisibility(View.GONE);
|
||||||
|
channelTextView.setVisibility(View.GONE);
|
||||||
|
playerCloseButton.setVisibility(videoPlayerSelected() ? View.VISIBLE : View.GONE);
|
||||||
|
} else {
|
||||||
|
titleTextView.setVisibility(View.VISIBLE);
|
||||||
|
channelTextView.setVisibility(View.VISIBLE);
|
||||||
|
playerCloseButton.setVisibility(View.GONE);
|
||||||
|
}
|
||||||
|
setupScreenRotationButton();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void switchFromPopupToMain() {
|
||||||
|
if (DEBUG) {
|
||||||
|
Log.d(TAG, "switchFromPopupToMain() called");
|
||||||
|
}
|
||||||
|
if (!popupPlayerSelected() || simpleExoPlayer == null || getCurrentMetadata() == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (popupPlayerSelected()) {
|
|
||||||
setRecovery();
|
setRecovery();
|
||||||
service.removeViewFromParent();
|
service.removeViewFromParent();
|
||||||
final Intent intent = NavigationHelper.getPlayerIntent(
|
final Intent intent = NavigationHelper.getPlayerIntent(
|
||||||
|
@ -725,27 +772,6 @@ public class VideoPlayerImpl extends VideoPlayer
|
||||||
intent.putExtra(VideoDetailFragment.AUTO_PLAY, true);
|
intent.putExtra(VideoDetailFragment.AUTO_PLAY, true);
|
||||||
service.onDestroy();
|
service.onDestroy();
|
||||||
context.startActivity(intent);
|
context.startActivity(intent);
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
if (fragmentListener == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
isFullscreen = !isFullscreen;
|
|
||||||
setControlsSize();
|
|
||||||
fragmentListener.onFullscreenStateChanged(isFullscreen());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isFullscreen()) {
|
|
||||||
titleTextView.setVisibility(View.GONE);
|
|
||||||
channelTextView.setVisibility(View.GONE);
|
|
||||||
playerCloseButton.setVisibility(videoPlayerSelected() ? View.VISIBLE : View.GONE);
|
|
||||||
} else {
|
|
||||||
titleTextView.setVisibility(View.VISIBLE);
|
|
||||||
channelTextView.setVisibility(View.VISIBLE);
|
|
||||||
playerCloseButton.setVisibility(View.GONE);
|
|
||||||
}
|
|
||||||
setupScreenRotationButton();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -775,9 +801,12 @@ public class VideoPlayerImpl extends VideoPlayer
|
||||||
} else if (v.getId() == openInBrowser.getId()) {
|
} else if (v.getId() == openInBrowser.getId()) {
|
||||||
onOpenInBrowserClicked();
|
onOpenInBrowserClicked();
|
||||||
} else if (v.getId() == fullscreenButton.getId()) {
|
} else if (v.getId() == fullscreenButton.getId()) {
|
||||||
toggleFullscreen();
|
switchFromPopupToMain();
|
||||||
} else if (v.getId() == screenRotationButton.getId()) {
|
} else if (v.getId() == screenRotationButton.getId()) {
|
||||||
if (!isVerticalVideo) {
|
// Only if it's not a vertical video or vertical video but in landscape with locked
|
||||||
|
// orientation a screen orientation can be changed automatically
|
||||||
|
if (!isVerticalVideo
|
||||||
|
|| (service.isLandscape() && globalScreenOrientationLocked(service))) {
|
||||||
fragmentListener.onScreenRotationButtonClicked();
|
fragmentListener.onScreenRotationButtonClicked();
|
||||||
} else {
|
} else {
|
||||||
toggleFullscreen();
|
toggleFullscreen();
|
||||||
|
@ -790,9 +819,12 @@ public class VideoPlayerImpl extends VideoPlayer
|
||||||
|
|
||||||
if (getCurrentState() != STATE_COMPLETED) {
|
if (getCurrentState() != STATE_COMPLETED) {
|
||||||
getControlsVisibilityHandler().removeCallbacksAndMessages(null);
|
getControlsVisibilityHandler().removeCallbacksAndMessages(null);
|
||||||
|
showHideShadow(true, DEFAULT_CONTROLS_DURATION, 0);
|
||||||
animateView(getControlsRoot(), true, DEFAULT_CONTROLS_DURATION, 0, () -> {
|
animateView(getControlsRoot(), true, DEFAULT_CONTROLS_DURATION, 0, () -> {
|
||||||
if (getCurrentState() == STATE_PLAYING && !isSomePopupMenuVisible()) {
|
if (getCurrentState() == STATE_PLAYING && !isSomePopupMenuVisible()) {
|
||||||
if (v.getId() == playPauseButton.getId()) {
|
if (v.getId() == playPauseButton.getId()
|
||||||
|
// Hide controls in fullscreen immediately
|
||||||
|
|| (v.getId() == screenRotationButton.getId() && isFullscreen)) {
|
||||||
hideControls(0, 0);
|
hideControls(0, 0);
|
||||||
} else {
|
} else {
|
||||||
hideControls(DEFAULT_CONTROLS_DURATION, DEFAULT_CONTROLS_HIDE_TIME);
|
hideControls(DEFAULT_CONTROLS_DURATION, DEFAULT_CONTROLS_HIDE_TIME);
|
||||||
|
@ -819,7 +851,7 @@ public class VideoPlayerImpl extends VideoPlayer
|
||||||
buildQueue();
|
buildQueue();
|
||||||
updatePlaybackButtons();
|
updatePlaybackButtons();
|
||||||
|
|
||||||
getControlsRoot().setVisibility(View.INVISIBLE);
|
hideControls(0, 0);
|
||||||
queueLayout.requestFocus();
|
queueLayout.requestFocus();
|
||||||
animateView(queueLayout, SLIDE_AND_ALPHA, true,
|
animateView(queueLayout, SLIDE_AND_ALPHA, true,
|
||||||
DEFAULT_CONTROLS_DURATION);
|
DEFAULT_CONTROLS_DURATION);
|
||||||
|
@ -911,9 +943,8 @@ public class VideoPlayerImpl extends VideoPlayer
|
||||||
|
|
||||||
private void setupScreenRotationButton() {
|
private void setupScreenRotationButton() {
|
||||||
final boolean orientationLocked = PlayerHelper.globalScreenOrientationLocked(service);
|
final boolean orientationLocked = PlayerHelper.globalScreenOrientationLocked(service);
|
||||||
final boolean tabletInLandscape = DeviceUtils.isTablet(service) && service.isLandscape();
|
|
||||||
final boolean showButton = videoPlayerSelected()
|
final boolean showButton = videoPlayerSelected()
|
||||||
&& (orientationLocked || isVerticalVideo || tabletInLandscape);
|
&& (orientationLocked || isVerticalVideo || DeviceUtils.isTablet(service));
|
||||||
screenRotationButton.setVisibility(showButton ? View.VISIBLE : View.GONE);
|
screenRotationButton.setVisibility(showButton ? View.VISIBLE : View.GONE);
|
||||||
screenRotationButton.setImageDrawable(AppCompatResources.getDrawable(service, isFullscreen()
|
screenRotationButton.setImageDrawable(AppCompatResources.getDrawable(service, isFullscreen()
|
||||||
? R.drawable.ic_fullscreen_exit_white_24dp
|
? R.drawable.ic_fullscreen_exit_white_24dp
|
||||||
|
@ -925,6 +956,8 @@ public class VideoPlayerImpl extends VideoPlayer
|
||||||
if (orientationLocked
|
if (orientationLocked
|
||||||
&& isFullscreen()
|
&& isFullscreen()
|
||||||
&& service.isLandscape() == isVerticalVideo
|
&& service.isLandscape() == isVerticalVideo
|
||||||
|
&& !DeviceUtils.isTv(service)
|
||||||
|
&& !DeviceUtils.isTablet(service)
|
||||||
&& fragmentListener != null) {
|
&& fragmentListener != null) {
|
||||||
fragmentListener.onScreenRotationButtonClicked();
|
fragmentListener.onScreenRotationButtonClicked();
|
||||||
}
|
}
|
||||||
|
@ -955,6 +988,7 @@ public class VideoPlayerImpl extends VideoPlayer
|
||||||
super.onDismiss(menu);
|
super.onDismiss(menu);
|
||||||
if (isPlaying()) {
|
if (isPlaying()) {
|
||||||
hideControls(DEFAULT_CONTROLS_DURATION, 0);
|
hideControls(DEFAULT_CONTROLS_DURATION, 0);
|
||||||
|
hideSystemUIIfNeeded();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -979,15 +1013,6 @@ public class VideoPlayerImpl extends VideoPlayer
|
||||||
|
|
||||||
setInitialGestureValues();
|
setInitialGestureValues();
|
||||||
queueLayout.getLayoutParams().height = height - queueLayout.getTop();
|
queueLayout.getLayoutParams().height = height - queueLayout.getTop();
|
||||||
|
|
||||||
if (popupPlayerSelected()) {
|
|
||||||
final float widthDp = Math.abs(r - l) / service.getResources()
|
|
||||||
.getDisplayMetrics().density;
|
|
||||||
final int visibility = widthDp > MINIMUM_SHOW_EXTRA_WIDTH_DP
|
|
||||||
? View.VISIBLE
|
|
||||||
: View.GONE;
|
|
||||||
secondaryControls.setVisibility(visibility);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1146,6 +1171,9 @@ public class VideoPlayerImpl extends VideoPlayer
|
||||||
updateWindowFlags(IDLE_WINDOW_FLAGS);
|
updateWindowFlags(IDLE_WINDOW_FLAGS);
|
||||||
|
|
||||||
NotificationUtil.getInstance().createNotificationIfNeededAndUpdate(this, false);
|
NotificationUtil.getInstance().createNotificationIfNeededAndUpdate(this, false);
|
||||||
|
if (isFullscreen) {
|
||||||
|
toggleFullscreen();
|
||||||
|
}
|
||||||
super.onCompleted();
|
super.onCompleted();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1255,20 +1283,6 @@ public class VideoPlayerImpl extends VideoPlayer
|
||||||
updatePopupSize(getPopupLayoutParams().width, -1);
|
updatePopupSize(getPopupLayoutParams().width, -1);
|
||||||
checkPopupPositionBounds();
|
checkPopupPositionBounds();
|
||||||
}
|
}
|
||||||
|
|
||||||
// The only situation I need to re-calculate elements sizes is
|
|
||||||
// when a user rotates a device from landscape to landscape
|
|
||||||
// because in that case the controls should be aligned to another side of a screen.
|
|
||||||
// The problem is when user leaves the app and returns back
|
|
||||||
// (while the app in landscape) Android reports via DisplayMetrics that orientation
|
|
||||||
// is portrait and it gives wrong sizes calculations.
|
|
||||||
// Let's skip re-calculation in every case but landscape
|
|
||||||
final boolean reportedOrientationIsLandscape = service.isLandscape();
|
|
||||||
final boolean actualOrientationIsLandscape = context.getResources()
|
|
||||||
.getConfiguration().orientation == ORIENTATION_LANDSCAPE;
|
|
||||||
if (reportedOrientationIsLandscape && actualOrientationIsLandscape) {
|
|
||||||
setControlsSize();
|
|
||||||
}
|
|
||||||
// Close it because when changing orientation from portrait
|
// Close it because when changing orientation from portrait
|
||||||
// (in fullscreen mode) the size of queue layout can be larger than the screen size
|
// (in fullscreen mode) the size of queue layout can be larger than the screen size
|
||||||
onQueueClosed();
|
onQueueClosed();
|
||||||
|
@ -1278,18 +1292,14 @@ public class VideoPlayerImpl extends VideoPlayer
|
||||||
// Interrupt playback only when screen turns on
|
// Interrupt playback only when screen turns on
|
||||||
// and user is watching video in popup player.
|
// and user is watching video in popup player.
|
||||||
// Same actions for video player will be handled in ACTION_VIDEO_FRAGMENT_RESUMED
|
// Same actions for video player will be handled in ACTION_VIDEO_FRAGMENT_RESUMED
|
||||||
if (backgroundPlaybackEnabled()
|
if (popupPlayerSelected() && (isPlaying() || isLoading())) {
|
||||||
&& popupPlayerSelected()
|
|
||||||
&& (isPlaying() || isLoading())) {
|
|
||||||
useVideoSource(true);
|
useVideoSource(true);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case Intent.ACTION_SCREEN_OFF:
|
case Intent.ACTION_SCREEN_OFF:
|
||||||
shouldUpdateOnProgress = false;
|
shouldUpdateOnProgress = false;
|
||||||
// Interrupt playback only when screen turns off with popup player working
|
// Interrupt playback only when screen turns off with popup player working
|
||||||
if (backgroundPlaybackEnabled()
|
if (popupPlayerSelected() && (isPlaying() || isLoading())) {
|
||||||
&& popupPlayerSelected()
|
|
||||||
&& (isPlaying() || isLoading())) {
|
|
||||||
useVideoSource(false);
|
useVideoSource(false);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -1426,9 +1436,10 @@ public class VideoPlayerImpl extends VideoPlayer
|
||||||
showOrHideButtons();
|
showOrHideButtons();
|
||||||
|
|
||||||
getControlsVisibilityHandler().removeCallbacksAndMessages(null);
|
getControlsVisibilityHandler().removeCallbacksAndMessages(null);
|
||||||
getControlsVisibilityHandler().postDelayed(() ->
|
getControlsVisibilityHandler().postDelayed(() -> {
|
||||||
animateView(getControlsRoot(), false, duration, 0,
|
showHideShadow(false, duration, 0);
|
||||||
this::hideSystemUIIfNeeded), delay
|
animateView(getControlsRoot(), false, duration, 0, this::hideSystemUIIfNeeded);
|
||||||
|
}, delay
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1456,11 +1467,17 @@ public class VideoPlayerImpl extends VideoPlayer
|
||||||
}
|
}
|
||||||
|
|
||||||
private void showSystemUIPartially() {
|
private void showSystemUIPartially() {
|
||||||
if (isFullscreen() && getParentActivity() != null) {
|
final AppCompatActivity activity = getParentActivity();
|
||||||
|
if (isFullscreen() && activity != null) {
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||||
|
activity.getWindow().setStatusBarColor(Color.TRANSPARENT);
|
||||||
|
activity.getWindow().setNavigationBarColor(Color.TRANSPARENT);
|
||||||
|
}
|
||||||
final int visibility = View.SYSTEM_UI_FLAG_LAYOUT_STABLE
|
final int visibility = 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;
|
||||||
getParentActivity().getWindow().getDecorView().setSystemUiVisibility(visibility);
|
activity.getWindow().getDecorView().setSystemUiVisibility(visibility);
|
||||||
|
activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1475,92 +1492,6 @@ public class VideoPlayerImpl extends VideoPlayer
|
||||||
getLoadController().disablePreloadingOfCurrentTrack();
|
getLoadController().disablePreloadingOfCurrentTrack();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Measures width and height of controls visible on screen.
|
|
||||||
* It ensures that controls will be side-by-side with NavigationBar and notches
|
|
||||||
* but not under them. Tablets have only bottom NavigationBar
|
|
||||||
*/
|
|
||||||
public void setControlsSize() {
|
|
||||||
final Point size = new Point();
|
|
||||||
final Display display = getRootView().getDisplay();
|
|
||||||
if (display == null || !videoPlayerSelected()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// This method will give a correct size of a usable area of a window.
|
|
||||||
// It doesn't include NavigationBar, notches, etc.
|
|
||||||
display.getSize(size);
|
|
||||||
|
|
||||||
final boolean isLandscape = service.isLandscape();
|
|
||||||
final int width = isFullscreen
|
|
||||||
? (isLandscape ? size.x : size.y)
|
|
||||||
: ViewGroup.LayoutParams.MATCH_PARENT;
|
|
||||||
final int gravity = isFullscreen
|
|
||||||
? (display.getRotation() == Surface.ROTATION_90
|
|
||||||
? Gravity.START : Gravity.END)
|
|
||||||
: Gravity.TOP;
|
|
||||||
|
|
||||||
getTopControlsRoot().getLayoutParams().width = width;
|
|
||||||
final RelativeLayout.LayoutParams topParams =
|
|
||||||
((RelativeLayout.LayoutParams) getTopControlsRoot().getLayoutParams());
|
|
||||||
topParams.removeRule(RelativeLayout.ALIGN_PARENT_START);
|
|
||||||
topParams.removeRule(RelativeLayout.ALIGN_PARENT_END);
|
|
||||||
topParams.addRule(gravity == Gravity.END
|
|
||||||
? RelativeLayout.ALIGN_PARENT_END
|
|
||||||
: RelativeLayout.ALIGN_PARENT_START);
|
|
||||||
getTopControlsRoot().requestLayout();
|
|
||||||
|
|
||||||
getBottomControlsRoot().getLayoutParams().width = width;
|
|
||||||
final RelativeLayout.LayoutParams bottomParams =
|
|
||||||
((RelativeLayout.LayoutParams) getBottomControlsRoot().getLayoutParams());
|
|
||||||
bottomParams.removeRule(RelativeLayout.ALIGN_PARENT_START);
|
|
||||||
bottomParams.removeRule(RelativeLayout.ALIGN_PARENT_END);
|
|
||||||
bottomParams.addRule(gravity == Gravity.END
|
|
||||||
? RelativeLayout.ALIGN_PARENT_END
|
|
||||||
: RelativeLayout.ALIGN_PARENT_START);
|
|
||||||
getBottomControlsRoot().requestLayout();
|
|
||||||
|
|
||||||
final ViewGroup controlsRoot = getRootView().findViewById(R.id.playbackWindowRoot);
|
|
||||||
// In tablet navigationBar located at the bottom of the screen.
|
|
||||||
// And the situations when we need to set custom height is
|
|
||||||
// in fullscreen mode in tablet in non-multiWindow mode or with vertical video.
|
|
||||||
// Other than that MATCH_PARENT is good
|
|
||||||
final boolean navBarAtTheBottom = DeviceUtils.isTablet(service) || !isLandscape;
|
|
||||||
controlsRoot.getLayoutParams().height = isFullscreen && !isInMultiWindow()
|
|
||||||
&& navBarAtTheBottom ? size.y : ViewGroup.LayoutParams.MATCH_PARENT;
|
|
||||||
controlsRoot.requestLayout();
|
|
||||||
|
|
||||||
final DisplayMetrics metrics = getRootView().getResources().getDisplayMetrics();
|
|
||||||
int topPadding = isFullscreen && !isInMultiWindow() ? getStatusBarHeight() : 0;
|
|
||||||
topPadding = !isLandscape && DeviceUtils.hasCutout(topPadding, metrics) ? 0 : topPadding;
|
|
||||||
getRootView().findViewById(R.id.playbackWindowRoot).setTranslationY(topPadding);
|
|
||||||
getBottomControlsRoot().setTranslationY(-topPadding);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return statusBar height that was found inside system resources
|
|
||||||
* or default value if no value was provided inside resources
|
|
||||||
*/
|
|
||||||
private int getStatusBarHeight() {
|
|
||||||
int statusBarHeight = 0;
|
|
||||||
final int resourceId = service.isLandscape()
|
|
||||||
? service.getResources().getIdentifier(
|
|
||||||
"status_bar_height_landscape", "dimen", "android")
|
|
||||||
: service.getResources().getIdentifier(
|
|
||||||
"status_bar_height", "dimen", "android");
|
|
||||||
|
|
||||||
if (resourceId > 0) {
|
|
||||||
statusBarHeight = service.getResources().getDimensionPixelSize(resourceId);
|
|
||||||
}
|
|
||||||
if (statusBarHeight == 0) {
|
|
||||||
// Some devices provide wrong value for status bar height in landscape mode,
|
|
||||||
// this is workaround
|
|
||||||
final DisplayMetrics metrics = getRootView().getResources().getDisplayMetrics();
|
|
||||||
statusBarHeight = (int) TypedValue.applyDimension(
|
|
||||||
TypedValue.COMPLEX_UNIT_DIP, 24, metrics);
|
|
||||||
}
|
|
||||||
return statusBarHeight;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void setMuteButton(final ImageButton button, final boolean isMuted) {
|
protected void setMuteButton(final ImageButton button, final boolean isMuted) {
|
||||||
button.setImageDrawable(AppCompatResources.getDrawable(service, isMuted
|
button.setImageDrawable(AppCompatResources.getDrawable(service, isMuted
|
||||||
? R.drawable.ic_volume_off_white_24dp : R.drawable.ic_volume_up_white_24dp));
|
? R.drawable.ic_volume_off_white_24dp : R.drawable.ic_volume_up_white_24dp));
|
||||||
|
@ -1603,8 +1534,6 @@ public class VideoPlayerImpl extends VideoPlayer
|
||||||
&& !DeviceUtils.isTablet(service)) {
|
&& !DeviceUtils.isTablet(service)) {
|
||||||
toggleFullscreen();
|
toggleFullscreen();
|
||||||
}
|
}
|
||||||
|
|
||||||
setControlsSize();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void buildQueue() {
|
private void buildQueue() {
|
||||||
|
@ -2001,6 +1930,12 @@ public class VideoPlayerImpl extends VideoPlayer
|
||||||
public void setFragmentListener(final PlayerServiceEventListener listener) {
|
public void setFragmentListener(final PlayerServiceEventListener listener) {
|
||||||
fragmentListener = listener;
|
fragmentListener = listener;
|
||||||
fragmentIsVisible = true;
|
fragmentIsVisible = true;
|
||||||
|
// Apply window insets because Android will not do it when orientation changes
|
||||||
|
// from landscape to portrait
|
||||||
|
if (!isFullscreen) {
|
||||||
|
getControlsRoot().setPadding(0, 0, 0, 0);
|
||||||
|
}
|
||||||
|
queueLayout.setPadding(0, 0, 0, 0);
|
||||||
updateMetadata();
|
updateMetadata();
|
||||||
updatePlayback();
|
updatePlayback();
|
||||||
triggerProgressUpdate();
|
triggerProgressUpdate();
|
||||||
|
|
|
@ -39,12 +39,13 @@ public class CustomBottomSheetBehavior extends BottomSheetBehavior<FrameLayout>
|
||||||
}
|
}
|
||||||
|
|
||||||
// Found that user still swiping, continue following
|
// Found that user still swiping, continue following
|
||||||
if (skippingInterception) {
|
if (skippingInterception || getState() == BottomSheetBehavior.STATE_SETTLING) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Don't need to do anything if bottomSheet isn't expanded
|
// Don't need to do anything if bottomSheet isn't expanded
|
||||||
if (getState() == BottomSheetBehavior.STATE_EXPANDED) {
|
if (getState() == BottomSheetBehavior.STATE_EXPANDED
|
||||||
|
&& event.getAction() == MotionEvent.ACTION_DOWN) {
|
||||||
// Without overriding scrolling will not work when user touches these elements
|
// Without overriding scrolling will not work when user touches these elements
|
||||||
for (final Integer element : skipInterceptionOfElements) {
|
for (final Integer element : skipInterceptionOfElements) {
|
||||||
final ViewGroup viewGroup = child.findViewById(element);
|
final ViewGroup viewGroup = child.findViewById(element);
|
||||||
|
|
|
@ -9,6 +9,7 @@ import android.view.View;
|
||||||
import android.view.ViewConfiguration;
|
import android.view.ViewConfiguration;
|
||||||
import android.view.Window;
|
import android.view.Window;
|
||||||
import android.view.WindowManager;
|
import android.view.WindowManager;
|
||||||
|
import android.widget.ProgressBar;
|
||||||
import androidx.appcompat.content.res.AppCompatResources;
|
import androidx.appcompat.content.res.AppCompatResources;
|
||||||
import org.schabi.newpipe.R;
|
import org.schabi.newpipe.R;
|
||||||
import org.schabi.newpipe.player.BasePlayer;
|
import org.schabi.newpipe.player.BasePlayer;
|
||||||
|
@ -264,14 +265,19 @@ public class PlayerGestureListener
|
||||||
}
|
}
|
||||||
|
|
||||||
final Window window = parent.getWindow();
|
final Window window = parent.getWindow();
|
||||||
|
|
||||||
playerImpl.getBrightnessProgressBar().incrementProgressBy((int) distanceY);
|
|
||||||
final float currentProgressPercent = (float) playerImpl.getBrightnessProgressBar()
|
|
||||||
.getProgress() / playerImpl.getMaxGestureLength();
|
|
||||||
final WindowManager.LayoutParams layoutParams = window.getAttributes();
|
final WindowManager.LayoutParams layoutParams = window.getAttributes();
|
||||||
|
final ProgressBar bar = playerImpl.getBrightnessProgressBar();
|
||||||
|
final float oldBrightness = layoutParams.screenBrightness;
|
||||||
|
bar.setProgress((int) (bar.getMax() * Math.max(0, Math.min(1, oldBrightness))));
|
||||||
|
bar.incrementProgressBy((int) distanceY);
|
||||||
|
|
||||||
|
final float currentProgressPercent = (float) bar.getProgress() / bar.getMax();
|
||||||
layoutParams.screenBrightness = currentProgressPercent;
|
layoutParams.screenBrightness = currentProgressPercent;
|
||||||
window.setAttributes(layoutParams);
|
window.setAttributes(layoutParams);
|
||||||
|
|
||||||
|
// Save current brightness level
|
||||||
|
PlayerHelper.setScreenBrightness(parent, currentProgressPercent);
|
||||||
|
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
Log.d(TAG, "onScroll().brightnessControl, "
|
Log.d(TAG, "onScroll().brightnessControl, "
|
||||||
+ "currentBrightness = " + currentProgressPercent);
|
+ "currentBrightness = " + currentProgressPercent);
|
||||||
|
|
|
@ -6,8 +6,6 @@ import android.content.pm.PackageManager;
|
||||||
import android.content.res.Configuration;
|
import android.content.res.Configuration;
|
||||||
import android.os.BatteryManager;
|
import android.os.BatteryManager;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.util.DisplayMetrics;
|
|
||||||
import android.util.TypedValue;
|
|
||||||
import android.view.KeyEvent;
|
import android.view.KeyEvent;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
|
@ -74,17 +72,4 @@ public final class DeviceUtils {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Compares current status bar height with default status bar height in Android and decides,
|
|
||||||
* does the device has cutout or not
|
|
||||||
* */
|
|
||||||
public static boolean hasCutout(final float statusBarHeight, final DisplayMetrics metrics) {
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
|
||||||
final float defaultStatusBarHeight = TypedValue.applyDimension(
|
|
||||||
TypedValue.COMPLEX_UNIT_DIP, 25, metrics);
|
|
||||||
return statusBarHeight > defaultStatusBarHeight;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,39 @@
|
||||||
|
package org.schabi.newpipe.views;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.util.AttributeSet;
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
import androidx.core.view.ViewCompat;
|
||||||
|
import androidx.core.view.WindowInsetsCompat;
|
||||||
|
import com.google.android.material.appbar.CollapsingToolbarLayout;
|
||||||
|
|
||||||
|
public class CustomCollapsingToolbarLayout extends CollapsingToolbarLayout {
|
||||||
|
public CustomCollapsingToolbarLayout(@NonNull final Context context) {
|
||||||
|
super(context);
|
||||||
|
overrideListener();
|
||||||
|
}
|
||||||
|
|
||||||
|
public CustomCollapsingToolbarLayout(@NonNull final Context context,
|
||||||
|
@Nullable final AttributeSet attrs) {
|
||||||
|
super(context, attrs);
|
||||||
|
overrideListener();
|
||||||
|
}
|
||||||
|
|
||||||
|
public CustomCollapsingToolbarLayout(@NonNull final Context context,
|
||||||
|
@Nullable final AttributeSet attrs,
|
||||||
|
final int defStyleAttr) {
|
||||||
|
super(context, attrs, defStyleAttr);
|
||||||
|
overrideListener();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* CollapsingToolbarLayout sets it's own setOnApplyInsetsListener which consumes
|
||||||
|
* system insets {@link CollapsingToolbarLayout#onWindowInsetChanged(WindowInsetsCompat)}
|
||||||
|
* so we will not receive them in subviews with fitsSystemWindows = true.
|
||||||
|
* Override Google's behavior
|
||||||
|
* */
|
||||||
|
public void overrideListener() {
|
||||||
|
ViewCompat.setOnApplyWindowInsetsListener(this, (v, insets) -> insets);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,14 +1,17 @@
|
||||||
package org.schabi.newpipe.views;
|
package org.schabi.newpipe.views;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.os.Build.VERSION;
|
||||||
|
import android.os.Build.VERSION_CODES;
|
||||||
import android.util.AttributeSet;
|
import android.util.AttributeSet;
|
||||||
import android.view.SurfaceView;
|
import android.view.SurfaceView;
|
||||||
import com.google.android.exoplayer2.ui.AspectRatioFrameLayout;
|
import com.google.android.exoplayer2.ui.AspectRatioFrameLayout;
|
||||||
|
|
||||||
|
import static com.google.android.exoplayer2.ui.AspectRatioFrameLayout.RESIZE_MODE_FIT;
|
||||||
import static com.google.android.exoplayer2.ui.AspectRatioFrameLayout.RESIZE_MODE_ZOOM;
|
import static com.google.android.exoplayer2.ui.AspectRatioFrameLayout.RESIZE_MODE_ZOOM;
|
||||||
|
|
||||||
public class ExpandableSurfaceView extends SurfaceView {
|
public class ExpandableSurfaceView extends SurfaceView {
|
||||||
private int resizeMode = AspectRatioFrameLayout.RESIZE_MODE_FIT;
|
private int resizeMode = RESIZE_MODE_FIT;
|
||||||
private int baseHeight = 0;
|
private int baseHeight = 0;
|
||||||
private int maxHeight = 0;
|
private int maxHeight = 0;
|
||||||
private float videoAspectRatio = 0.0f;
|
private float videoAspectRatio = 0.0f;
|
||||||
|
@ -30,7 +33,7 @@ public class ExpandableSurfaceView extends SurfaceView {
|
||||||
final boolean verticalVideo = videoAspectRatio < 1;
|
final boolean verticalVideo = videoAspectRatio < 1;
|
||||||
// Use maxHeight only on non-fit resize mode and in vertical videos
|
// Use maxHeight only on non-fit resize mode and in vertical videos
|
||||||
int height = maxHeight != 0
|
int height = maxHeight != 0
|
||||||
&& resizeMode != AspectRatioFrameLayout.RESIZE_MODE_FIT
|
&& resizeMode != RESIZE_MODE_FIT
|
||||||
&& verticalVideo ? maxHeight : baseHeight;
|
&& verticalVideo ? maxHeight : baseHeight;
|
||||||
|
|
||||||
if (height == 0) {
|
if (height == 0) {
|
||||||
|
@ -42,26 +45,22 @@ public class ExpandableSurfaceView extends SurfaceView {
|
||||||
scaleX = 1.0f;
|
scaleX = 1.0f;
|
||||||
scaleY = 1.0f;
|
scaleY = 1.0f;
|
||||||
|
|
||||||
switch (resizeMode) {
|
if (resizeMode == RESIZE_MODE_FIT
|
||||||
case AspectRatioFrameLayout.RESIZE_MODE_FIT:
|
// KitKat doesn't work well when a view has a scale like needed for ZOOM
|
||||||
|
|| (resizeMode == RESIZE_MODE_ZOOM && VERSION.SDK_INT < VERSION_CODES.LOLLIPOP)) {
|
||||||
if (aspectDeformation > 0) {
|
if (aspectDeformation > 0) {
|
||||||
height = (int) (width / videoAspectRatio);
|
height = (int) (width / videoAspectRatio);
|
||||||
} else {
|
} else {
|
||||||
width = (int) (height * videoAspectRatio);
|
width = (int) (height * videoAspectRatio);
|
||||||
}
|
}
|
||||||
|
} else if (resizeMode == RESIZE_MODE_ZOOM) {
|
||||||
break;
|
|
||||||
case RESIZE_MODE_ZOOM:
|
|
||||||
if (aspectDeformation < 0) {
|
if (aspectDeformation < 0) {
|
||||||
scaleY = viewAspectRatio / videoAspectRatio;
|
scaleY = viewAspectRatio / videoAspectRatio;
|
||||||
} else {
|
} else {
|
||||||
scaleX = videoAspectRatio / viewAspectRatio;
|
scaleX = videoAspectRatio / viewAspectRatio;
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
super.onMeasure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
|
super.onMeasure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
|
||||||
MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY));
|
MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY));
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,15 +17,19 @@
|
||||||
*/
|
*/
|
||||||
package org.schabi.newpipe.views;
|
package org.schabi.newpipe.views;
|
||||||
|
|
||||||
|
import android.annotation.TargetApi;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.graphics.Rect;
|
import android.graphics.Rect;
|
||||||
|
import android.os.Build;
|
||||||
import android.util.AttributeSet;
|
import android.util.AttributeSet;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
|
|
||||||
|
import android.view.WindowInsets;
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.coordinatorlayout.widget.CoordinatorLayout;
|
import androidx.coordinatorlayout.widget.CoordinatorLayout;
|
||||||
|
import org.schabi.newpipe.R;
|
||||||
|
|
||||||
public final class FocusAwareCoordinator extends CoordinatorLayout {
|
public final class FocusAwareCoordinator extends CoordinatorLayout {
|
||||||
private final Rect childFocus = new Rect();
|
private final Rect childFocus = new Rect();
|
||||||
|
@ -63,4 +67,41 @@ public final class FocusAwareCoordinator extends CoordinatorLayout {
|
||||||
requestChildRectangleOnScreen(child, childFocus, false);
|
requestChildRectangleOnScreen(child, childFocus, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Applies window insets to all children, not just for the first who consume the insets.
|
||||||
|
* Makes possible for multiple fragments to co-exist. Without this code
|
||||||
|
* the first ViewGroup who consumes will be the last who receive the insets
|
||||||
|
*/
|
||||||
|
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
|
||||||
|
@Override
|
||||||
|
public WindowInsets dispatchApplyWindowInsets(final WindowInsets insets) {
|
||||||
|
boolean consumed = false;
|
||||||
|
for (int i = 0; i < getChildCount(); i++) {
|
||||||
|
final View child = getChildAt(i);
|
||||||
|
final WindowInsets res = child.dispatchApplyWindowInsets(insets);
|
||||||
|
if (res.isConsumed()) {
|
||||||
|
consumed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (consumed) {
|
||||||
|
insets.consumeSystemWindowInsets();
|
||||||
|
}
|
||||||
|
return insets;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adjusts player's controls manually because fitsSystemWindows doesn't work when multiple
|
||||||
|
* receivers adjust its bounds. So when two listeners are present (like in profile page)
|
||||||
|
* the player's controls will not receive insets. This method fixes it
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected boolean fitSystemWindows(final Rect insets) {
|
||||||
|
final ViewGroup controls = findViewById(R.id.playbackControlRoot);
|
||||||
|
if (controls != null) {
|
||||||
|
controls.setPadding(insets.left, insets.top, insets.right, insets.bottom);
|
||||||
|
}
|
||||||
|
return super.fitSystemWindows(insets);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,7 +20,6 @@
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:layout_weight="5"
|
android:layout_weight="5"
|
||||||
android:fitsSystemWindows="true"
|
|
||||||
android:isScrollContainer="true">
|
android:isScrollContainer="true">
|
||||||
|
|
||||||
<com.google.android.material.appbar.AppBarLayout
|
<com.google.android.material.appbar.AppBarLayout
|
||||||
|
@ -28,12 +27,11 @@
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:background="@android:color/transparent"
|
android:background="@android:color/transparent"
|
||||||
android:fitsSystemWindows="true"
|
|
||||||
android:touchscreenBlocksFocus="false"
|
android:touchscreenBlocksFocus="false"
|
||||||
app:elevation="0dp"
|
app:elevation="0dp"
|
||||||
app:layout_behavior="com.google.android.material.appbar.FlingBehavior">
|
app:layout_behavior="com.google.android.material.appbar.FlingBehavior">
|
||||||
|
|
||||||
<com.google.android.material.appbar.CollapsingToolbarLayout
|
<org.schabi.newpipe.views.CustomCollapsingToolbarLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
app:layout_scrollFlags="scroll">
|
app:layout_scrollFlags="scroll">
|
||||||
|
@ -162,7 +160,7 @@
|
||||||
|
|
||||||
</FrameLayout>
|
</FrameLayout>
|
||||||
|
|
||||||
</com.google.android.material.appbar.CollapsingToolbarLayout>
|
</org.schabi.newpipe.views.CustomCollapsingToolbarLayout>
|
||||||
|
|
||||||
<!-- CONTENT -->
|
<!-- CONTENT -->
|
||||||
<RelativeLayout
|
<RelativeLayout
|
||||||
|
|
|
@ -28,6 +28,22 @@
|
||||||
android:layout_centerInParent="true"
|
android:layout_centerInParent="true"
|
||||||
android:layout_gravity="center"/>
|
android:layout_gravity="center"/>
|
||||||
|
|
||||||
|
<View
|
||||||
|
android:id="@+id/playerTopShadow"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="30dp"
|
||||||
|
android:background="@drawable/player_controls_top_background"
|
||||||
|
android:layout_alignParentTop="true"
|
||||||
|
android:visibility="gone"/>
|
||||||
|
|
||||||
|
<View
|
||||||
|
android:id="@+id/playerBottomShadow"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="30dp"
|
||||||
|
android:background="@drawable/player_controls_background"
|
||||||
|
android:layout_alignParentBottom="true"
|
||||||
|
android:visibility="gone"/>
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
android:id="@+id/endScreen"
|
android:id="@+id/endScreen"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
|
@ -42,28 +58,16 @@
|
||||||
android:id="@+id/playbackControlRoot"
|
android:id="@+id/playbackControlRoot"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
|
android:fitsSystemWindows="true"
|
||||||
android:background="@color/video_overlay_color"
|
android:background="@color/video_overlay_color"
|
||||||
android:visibility="gone"
|
android:visibility="gone"
|
||||||
tools:visibility="visible">
|
tools:visibility="visible">
|
||||||
|
|
||||||
<View
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="30dp"
|
|
||||||
android:background="@drawable/player_controls_top_background"
|
|
||||||
android:layout_alignParentTop="true" />
|
|
||||||
|
|
||||||
<View
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="30dp"
|
|
||||||
android:background="@drawable/player_controls_background"
|
|
||||||
android:layout_alignParentBottom="true" />
|
|
||||||
|
|
||||||
<!-- All top controls in this layout -->
|
<!-- All top controls in this layout -->
|
||||||
<RelativeLayout
|
<RelativeLayout
|
||||||
android:id="@+id/playbackWindowRoot"
|
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">
|
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:id="@+id/topControls"
|
android:id="@+id/topControls"
|
||||||
|
@ -228,7 +232,12 @@
|
||||||
tools:ignore="HardcodedText,RtlHardcoded"
|
tools:ignore="HardcodedText,RtlHardcoded"
|
||||||
tools:text="FIT"/>
|
tools:text="FIT"/>
|
||||||
|
|
||||||
<Button
|
<FrameLayout
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="3">
|
||||||
|
|
||||||
|
<TextView
|
||||||
android:id="@+id/captionTextView"
|
android:id="@+id/captionTextView"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
@ -241,16 +250,11 @@
|
||||||
android:minWidth="50dp"
|
android:minWidth="50dp"
|
||||||
android:textColor="@android:color/white"
|
android:textColor="@android:color/white"
|
||||||
android:textStyle="bold"
|
android:textStyle="bold"
|
||||||
android:textAllCaps="false"
|
|
||||||
android:background="?attr/selectableItemBackground"
|
android:background="?attr/selectableItemBackground"
|
||||||
tools:ignore="RelativeOverlap,RtlHardcoded"
|
tools:ignore="RelativeOverlap,RtlHardcoded"
|
||||||
tools:text="English"/>
|
tools:text="English"/>
|
||||||
|
|
||||||
<Space
|
</FrameLayout>
|
||||||
android:id="@+id/spaceBeforeButton"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="0dp"
|
|
||||||
android:layout_weight="3"/>
|
|
||||||
|
|
||||||
<androidx.appcompat.widget.AppCompatImageButton
|
<androidx.appcompat.widget.AppCompatImageButton
|
||||||
android:id="@+id/playWithKodi"
|
android:id="@+id/playWithKodi"
|
||||||
|
@ -307,16 +311,11 @@
|
||||||
android:contentDescription="@string/mute"
|
android:contentDescription="@string/mute"
|
||||||
tools:ignore="RtlHardcoded" />
|
tools:ignore="RtlHardcoded" />
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
<androidx.appcompat.widget.AppCompatImageButton
|
<androidx.appcompat.widget.AppCompatImageButton
|
||||||
android:id="@+id/fullScreenButton"
|
android:id="@+id/fullScreenButton"
|
||||||
android:layout_width="40dp"
|
android:layout_width="40dp"
|
||||||
android:layout_height="40dp"
|
android:layout_height="40dp"
|
||||||
android:padding="@dimen/player_main_buttons_padding"
|
android:padding="@dimen/player_main_buttons_padding"
|
||||||
android:layout_alignParentRight="true"
|
|
||||||
android:background="?attr/selectableItemBackground"
|
android:background="?attr/selectableItemBackground"
|
||||||
android:clickable="true"
|
android:clickable="true"
|
||||||
android:focusable="true"
|
android:focusable="true"
|
||||||
|
@ -326,6 +325,10 @@
|
||||||
android:visibility="gone"
|
android:visibility="gone"
|
||||||
tools:visibility="visible"/>
|
tools:visibility="visible"/>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:id="@+id/bottomControls"
|
android:id="@+id/bottomControls"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
|
@ -353,10 +356,10 @@
|
||||||
android:id="@+id/playbackSeekBar"
|
android:id="@+id/playbackSeekBar"
|
||||||
style="@style/Widget.AppCompat.SeekBar"
|
style="@style/Widget.AppCompat.SeekBar"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center"
|
||||||
android:layout_weight="1"
|
android:layout_weight="1"
|
||||||
android:paddingBottom="4dp"
|
android:layout_marginTop="2dp"
|
||||||
android:paddingTop="8dp"
|
|
||||||
tools:progress="25"
|
tools:progress="25"
|
||||||
android:nextFocusDown="@id/screenRotationButton"
|
android:nextFocusDown="@id/screenRotationButton"
|
||||||
tools:secondaryProgress="50"/>
|
tools:secondaryProgress="50"/>
|
||||||
|
|
|
@ -4,8 +4,7 @@
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
android:id="@+id/drawer_layout"
|
android:id="@+id/drawer_layout"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent">
|
||||||
android:fitsSystemWindows="true">
|
|
||||||
|
|
||||||
<org.schabi.newpipe.views.FocusAwareCoordinator
|
<org.schabi.newpipe.views.FocusAwareCoordinator
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
|
|
|
@ -18,11 +18,10 @@
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:background="@android:color/transparent"
|
android:background="@android:color/transparent"
|
||||||
android:fitsSystemWindows="true"
|
|
||||||
app:elevation="0dp"
|
app:elevation="0dp"
|
||||||
app:layout_behavior="com.google.android.material.appbar.FlingBehavior">
|
app:layout_behavior="com.google.android.material.appbar.FlingBehavior">
|
||||||
|
|
||||||
<com.google.android.material.appbar.CollapsingToolbarLayout
|
<org.schabi.newpipe.views.CustomCollapsingToolbarLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
app:layout_scrollFlags="scroll">
|
app:layout_scrollFlags="scroll">
|
||||||
|
@ -148,8 +147,7 @@
|
||||||
/>
|
/>
|
||||||
|
|
||||||
</FrameLayout>
|
</FrameLayout>
|
||||||
|
</org.schabi.newpipe.views.CustomCollapsingToolbarLayout>
|
||||||
</com.google.android.material.appbar.CollapsingToolbarLayout>
|
|
||||||
|
|
||||||
<!-- CONTENT -->
|
<!-- CONTENT -->
|
||||||
<RelativeLayout
|
<RelativeLayout
|
||||||
|
|
|
@ -28,6 +28,22 @@
|
||||||
android:layout_centerInParent="true"
|
android:layout_centerInParent="true"
|
||||||
android:layout_gravity="center"/>
|
android:layout_gravity="center"/>
|
||||||
|
|
||||||
|
<View
|
||||||
|
android:id="@+id/playerTopShadow"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="30dp"
|
||||||
|
android:background="@drawable/player_controls_top_background"
|
||||||
|
android:layout_alignParentTop="true"
|
||||||
|
android:visibility="gone"/>
|
||||||
|
|
||||||
|
<View
|
||||||
|
android:id="@+id/playerBottomShadow"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="30dp"
|
||||||
|
android:background="@drawable/player_controls_background"
|
||||||
|
android:layout_alignParentBottom="true"
|
||||||
|
android:visibility="gone"/>
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
android:id="@+id/endScreen"
|
android:id="@+id/endScreen"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
|
@ -42,28 +58,16 @@
|
||||||
android:id="@+id/playbackControlRoot"
|
android:id="@+id/playbackControlRoot"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
|
android:fitsSystemWindows="true"
|
||||||
android:background="@color/video_overlay_color"
|
android:background="@color/video_overlay_color"
|
||||||
android:visibility="gone"
|
android:visibility="gone"
|
||||||
tools:visibility="visible">
|
tools:visibility="visible">
|
||||||
|
|
||||||
<View
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="30dp"
|
|
||||||
android:background="@drawable/player_controls_top_background"
|
|
||||||
android:layout_alignParentTop="true" />
|
|
||||||
|
|
||||||
<View
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="30dp"
|
|
||||||
android:background="@drawable/player_controls_background"
|
|
||||||
android:layout_alignParentBottom="true" />
|
|
||||||
|
|
||||||
<!-- All top controls in this layout -->
|
<!-- All top controls in this layout -->
|
||||||
<RelativeLayout
|
<RelativeLayout
|
||||||
android:id="@+id/playbackWindowRoot"
|
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">
|
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:id="@+id/topControls"
|
android:id="@+id/topControls"
|
||||||
|
@ -227,6 +231,11 @@
|
||||||
tools:ignore="HardcodedText,RtlHardcoded"
|
tools:ignore="HardcodedText,RtlHardcoded"
|
||||||
tools:text="FIT"/>
|
tools:text="FIT"/>
|
||||||
|
|
||||||
|
<FrameLayout
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="3">
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/captionTextView"
|
android:id="@+id/captionTextView"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
|
@ -235,7 +244,6 @@
|
||||||
android:layout_marginEnd="8dp"
|
android:layout_marginEnd="8dp"
|
||||||
android:gravity="center|left"
|
android:gravity="center|left"
|
||||||
android:minHeight="35dp"
|
android:minHeight="35dp"
|
||||||
android:maxWidth="100dp"
|
|
||||||
android:lines="1"
|
android:lines="1"
|
||||||
android:ellipsize="end"
|
android:ellipsize="end"
|
||||||
android:minWidth="50dp"
|
android:minWidth="50dp"
|
||||||
|
@ -245,11 +253,7 @@
|
||||||
tools:ignore="RelativeOverlap,RtlHardcoded"
|
tools:ignore="RelativeOverlap,RtlHardcoded"
|
||||||
tools:text="English"/>
|
tools:text="English"/>
|
||||||
|
|
||||||
<Space
|
</FrameLayout>
|
||||||
android:id="@+id/spaceBeforeButton"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="0dp"
|
|
||||||
android:layout_weight="3"/>
|
|
||||||
|
|
||||||
<androidx.appcompat.widget.AppCompatImageButton
|
<androidx.appcompat.widget.AppCompatImageButton
|
||||||
android:id="@+id/playWithKodi"
|
android:id="@+id/playWithKodi"
|
||||||
|
@ -306,16 +310,11 @@
|
||||||
android:contentDescription="@string/mute"
|
android:contentDescription="@string/mute"
|
||||||
tools:ignore="RtlHardcoded" />
|
tools:ignore="RtlHardcoded" />
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
<androidx.appcompat.widget.AppCompatImageButton
|
<androidx.appcompat.widget.AppCompatImageButton
|
||||||
android:id="@+id/fullScreenButton"
|
android:id="@+id/fullScreenButton"
|
||||||
android:layout_width="40dp"
|
android:layout_width="40dp"
|
||||||
android:layout_height="40dp"
|
android:layout_height="40dp"
|
||||||
android:padding="@dimen/player_main_buttons_padding"
|
android:padding="@dimen/player_main_buttons_padding"
|
||||||
android:layout_alignParentRight="true"
|
|
||||||
android:background="?attr/selectableItemBackground"
|
android:background="?attr/selectableItemBackground"
|
||||||
android:clickable="true"
|
android:clickable="true"
|
||||||
android:focusable="true"
|
android:focusable="true"
|
||||||
|
@ -325,6 +324,10 @@
|
||||||
android:visibility="gone"
|
android:visibility="gone"
|
||||||
tools:visibility="visible"/>
|
tools:visibility="visible"/>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:id="@+id/bottomControls"
|
android:id="@+id/bottomControls"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
|
@ -352,10 +355,10 @@
|
||||||
android:id="@+id/playbackSeekBar"
|
android:id="@+id/playbackSeekBar"
|
||||||
style="@style/Widget.AppCompat.SeekBar"
|
style="@style/Widget.AppCompat.SeekBar"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center"
|
||||||
android:layout_weight="1"
|
android:layout_weight="1"
|
||||||
android:paddingBottom="4dp"
|
android:layout_marginTop="2dp"
|
||||||
android:paddingTop="8dp"
|
|
||||||
tools:progress="25"
|
tools:progress="25"
|
||||||
tools:secondaryProgress="50"/>
|
tools:secondaryProgress="50"/>
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
<style name="Base.V29.LightTheme" parent="Theme.AppCompat.Light.NoActionBar">
|
||||||
|
<item name="android:navigationBarColor">@android:color/transparent</item>
|
||||||
|
<item name="android:enforceNavigationBarContrast">false</item>
|
||||||
|
</style>
|
||||||
|
<style name="Base.LightTheme" parent="Base.V29.LightTheme" />
|
||||||
|
|
||||||
|
<style name="Base.V29.DarkTheme" parent="Base.V7.DarkTheme">
|
||||||
|
<item name="android:navigationBarColor">@android:color/transparent</item>
|
||||||
|
<item name="android:enforceNavigationBarContrast">false</item>
|
||||||
|
</style>
|
||||||
|
<style name="Base.DarkTheme" parent="Base.V29.DarkTheme" />
|
||||||
|
|
||||||
|
<style name="Base.V29.BlackTheme" parent="Base.V7.BlackTheme">
|
||||||
|
<item name="android:navigationBarColor">@android:color/transparent</item>
|
||||||
|
<item name="android:enforceNavigationBarContrast">false</item>
|
||||||
|
</style>
|
||||||
|
<style name="Base.BlackTheme" parent="Base.V29.BlackTheme" />
|
||||||
|
</resources>
|
|
@ -9,8 +9,8 @@
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<!-- Base themes -->
|
<!-- Base themes -->
|
||||||
|
<style name="Base.LightTheme" parent="Theme.AppCompat.Light.NoActionBar" />
|
||||||
<style name="LightTheme" parent="Theme.AppCompat.Light.NoActionBar">
|
<style name="LightTheme" parent="Base.LightTheme">
|
||||||
<item name="colorPrimary">@color/light_youtube_primary_color</item>
|
<item name="colorPrimary">@color/light_youtube_primary_color</item>
|
||||||
<item name="colorPrimaryDark">@color/light_youtube_primary_color</item>
|
<item name="colorPrimaryDark">@color/light_youtube_primary_color</item>
|
||||||
<item name="colorAccent">@color/light_youtube_accent_color</item>
|
<item name="colorAccent">@color/light_youtube_accent_color</item>
|
||||||
|
|
Loading…
Reference in New Issue