mirror of
https://github.com/TeamNewPipe/NewPipe.git
synced 2024-11-25 20:42:34 +01:00
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.pm.ActivityInfo;
|
||||
import android.database.ContentObserver;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Build;
|
||||
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.NavigationHelper;
|
||||
import org.schabi.newpipe.util.PermissionHelper;
|
||||
import org.schabi.newpipe.util.SerializedCache;
|
||||
import org.schabi.newpipe.util.ShareUtils;
|
||||
import org.schabi.newpipe.util.ThemeHelper;
|
||||
import org.schabi.newpipe.views.AnimatedProgressBar;
|
||||
import org.schabi.newpipe.views.LargeTextMovementMethod;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
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.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.playqueue.PlayQueueItem.RECOVERY_UNSET;
|
||||
import static org.schabi.newpipe.util.AnimationUtils.animateView;
|
||||
@ -337,7 +338,7 @@ public class VideoDetailFragment
|
||||
stopPlayerListener();
|
||||
playerService = null;
|
||||
player = null;
|
||||
saveCurrentAndRestoreDefaultBrightness();
|
||||
restoreDefaultBrightness();
|
||||
}
|
||||
}
|
||||
|
||||
@ -404,7 +405,7 @@ public class VideoDetailFragment
|
||||
settingsContentObserver = new ContentObserver(new Handler()) {
|
||||
@Override
|
||||
public void onChange(final boolean selfChange) {
|
||||
if (activity != null && !PlayerHelper.globalScreenOrientationLocked(activity)) {
|
||||
if (activity != null && !globalScreenOrientationLocked(activity)) {
|
||||
activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
|
||||
}
|
||||
}
|
||||
@ -426,7 +427,7 @@ public class VideoDetailFragment
|
||||
if (currentWorker != null) {
|
||||
currentWorker.dispose();
|
||||
}
|
||||
saveCurrentAndRestoreDefaultBrightness();
|
||||
restoreDefaultBrightness();
|
||||
PreferenceManager.getDefaultSharedPreferences(requireContext())
|
||||
.edit()
|
||||
.putString(getString(R.string.stream_info_selected_tab_key),
|
||||
@ -538,31 +539,51 @@ public class VideoDetailFragment
|
||||
super.onSaveInstanceState(outState);
|
||||
|
||||
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) {
|
||||
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
|
||||
protected void onRestoreInstanceState(@NonNull final Bundle savedState) {
|
||||
super.onRestoreInstanceState(savedState);
|
||||
|
||||
Serializable serializable = savedState.getSerializable(INFO_KEY);
|
||||
if (serializable instanceof StreamInfo) {
|
||||
currentInfo = (StreamInfo) serializable;
|
||||
InfoCache.getInstance().putInfo(serviceId, url, currentInfo, InfoItem.InfoType.STREAM);
|
||||
final String infoCacheKey = savedState.getString(INFO_KEY);
|
||||
if (infoCacheKey != null) {
|
||||
currentInfo = SerializedCache.getInstance().take(infoCacheKey, StreamInfo.class);
|
||||
if (currentInfo != null) {
|
||||
InfoCache.getInstance()
|
||||
.putInfo(serviceId, url, currentInfo, InfoItem.InfoType.STREAM);
|
||||
}
|
||||
}
|
||||
|
||||
serializable = savedState.getSerializable(STACK_KEY);
|
||||
if (serializable instanceof Collection) {
|
||||
//noinspection unchecked
|
||||
stack.addAll((Collection<? extends StackItem>) serializable);
|
||||
final String stackCacheKey = savedState.getString(STACK_KEY);
|
||||
if (stackCacheKey != null) {
|
||||
final LinkedList<StackItem> cachedStack =
|
||||
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();
|
||||
|
||||
switch (state) {
|
||||
case BasePlayer.STATE_COMPLETED:
|
||||
restoreDefaultOrientation();
|
||||
break;
|
||||
case BasePlayer.STATE_PLAYING:
|
||||
if (positionView.getAlpha() != 1.0f
|
||||
&& player.getPlayQueue() != null
|
||||
@ -1869,10 +1887,11 @@ public class VideoDetailFragment
|
||||
public void onPlayerError(final ExoPlaybackException error) {
|
||||
if (error.type == ExoPlaybackException.TYPE_SOURCE
|
||||
|| error.type == ExoPlaybackException.TYPE_UNEXPECTED) {
|
||||
hideMainPlayer();
|
||||
// Properly exit from fullscreen
|
||||
if (playerService != null && player.isFullscreen()) {
|
||||
player.toggleFullscreen();
|
||||
}
|
||||
hideMainPlayer();
|
||||
}
|
||||
}
|
||||
|
||||
@ -1911,7 +1930,13 @@ public class VideoDetailFragment
|
||||
}
|
||||
scrollToTop();
|
||||
|
||||
addVideoPlayerView();
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
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
|
||||
@ -1919,13 +1944,15 @@ public class VideoDetailFragment
|
||||
// In tablet user experience will be better if screen will not be rotated
|
||||
// from landscape to portrait every time.
|
||||
// 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();
|
||||
return;
|
||||
}
|
||||
|
||||
final int newOrientation = isLandscape()
|
||||
? ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED
|
||||
? ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
|
||||
: ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE;
|
||||
|
||||
activity.setRequestedOrientation(newOrientation);
|
||||
@ -1970,7 +1997,11 @@ public class VideoDetailFragment
|
||||
WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT;
|
||||
}
|
||||
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() {
|
||||
@ -1985,18 +2016,26 @@ public class VideoDetailFragment
|
||||
// Prevent jumping of the player on devices with cutout
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
||||
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_HIDE_NAVIGATION
|
||||
| View.SYSTEM_UI_FLAG_FULLSCREEN
|
||||
| View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
|
||||
| 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().setFlags(
|
||||
WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS,
|
||||
WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS);
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP
|
||||
&& (isInMultiWindow() || (player != null && player.isFullscreen()))) {
|
||||
activity.getWindow().setStatusBarColor(Color.TRANSPARENT);
|
||||
activity.getWindow().setNavigationBarColor(Color.TRANSPARENT);
|
||||
}
|
||||
activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
|
||||
}
|
||||
|
||||
// Listener implementation
|
||||
@ -2014,13 +2053,11 @@ public class VideoDetailFragment
|
||||
&& player.getPlayer().getPlaybackState() != Player.STATE_IDLE;
|
||||
}
|
||||
|
||||
private void saveCurrentAndRestoreDefaultBrightness() {
|
||||
private void restoreDefaultBrightness() {
|
||||
final WindowManager.LayoutParams lp = activity.getWindow().getAttributes();
|
||||
if (lp.screenBrightness == -1) {
|
||||
return;
|
||||
}
|
||||
// Save current brightness level
|
||||
PlayerHelper.setScreenBrightness(activity, lp.screenBrightness);
|
||||
|
||||
// Restore the old brightness when fragment.onPause() called or
|
||||
// when a player is in portrait
|
||||
@ -2039,7 +2076,7 @@ public class VideoDetailFragment
|
||||
|| !player.isFullscreen()
|
||||
|| bottomSheetState != BottomSheetBehavior.STATE_EXPANDED) {
|
||||
// Apply system brightness when the player is not in fullscreen
|
||||
saveCurrentAndRestoreDefaultBrightness();
|
||||
restoreDefaultBrightness();
|
||||
} else {
|
||||
// Restore already saved brightness level
|
||||
final float brightnessLevel = PlayerHelper.getScreenBrightness(activity);
|
||||
@ -2058,11 +2095,9 @@ public class VideoDetailFragment
|
||||
}
|
||||
|
||||
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
|
||||
if (orientationLocked && !player.isPlaying()) {
|
||||
if (globalScreenOrientationLocked(activity) && !player.isPlaying()) {
|
||||
player.onPlay();
|
||||
player.showControlsThenHide();
|
||||
}
|
||||
}
|
||||
|
||||
@ -2265,6 +2300,7 @@ public class VideoDetailFragment
|
||||
&& player.videoPlayerSelected()) {
|
||||
player.toggleFullscreen();
|
||||
}
|
||||
setOverlayLook(appBarLayout, behavior, 1);
|
||||
break;
|
||||
case BottomSheetBehavior.STATE_COLLAPSED:
|
||||
moveFocusToMainFragment(true);
|
||||
@ -2274,6 +2310,7 @@ public class VideoDetailFragment
|
||||
if (player != null) {
|
||||
player.onQueueClosed();
|
||||
}
|
||||
setOverlayLook(appBarLayout, behavior, 0);
|
||||
break;
|
||||
case BottomSheetBehavior.STATE_DRAGGING:
|
||||
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
|
||||
// (one more additional unneeded click while the player is hidden)
|
||||
playerImpl.hideControls(0, 0);
|
||||
playerImpl.onQueueClosed();
|
||||
// Notification shows information about old stream but if a user selects
|
||||
// a stream from backStack it's not actual anymore
|
||||
// So we should hide the notification at all.
|
||||
@ -195,6 +196,10 @@ public final class MainPlayer extends Service {
|
||||
}
|
||||
|
||||
if (playerImpl != null) {
|
||||
// Exit from fullscreen when user closes the player via notification
|
||||
if (playerImpl.isFullscreen()) {
|
||||
playerImpl.toggleFullscreen();
|
||||
}
|
||||
removeViewFromParent();
|
||||
|
||||
playerImpl.setRecovery();
|
||||
|
@ -128,6 +128,8 @@ public abstract class VideoPlayer extends BasePlayer
|
||||
|
||||
private View controlsRoot;
|
||||
private TextView currentDisplaySeek;
|
||||
private View playerTopShadow;
|
||||
private View playerBottomShadow;
|
||||
|
||||
private View bottomControlsRoot;
|
||||
private SeekBar playbackSeekBar;
|
||||
@ -190,6 +192,8 @@ public abstract class VideoPlayer extends BasePlayer
|
||||
this.controlAnimationView = view.findViewById(R.id.controlAnimationView);
|
||||
this.controlsRoot = view.findViewById(R.id.playbackControlRoot);
|
||||
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.playbackCurrentTime = view.findViewById(R.id.playbackCurrentTime);
|
||||
this.playbackEndTime = view.findViewById(R.id.playbackEndTime);
|
||||
@ -356,11 +360,11 @@ public abstract class VideoPlayer extends BasePlayer
|
||||
return true;
|
||||
});
|
||||
// apply caption language from previous user preference
|
||||
if (userPreferredLanguage != null && (captionLanguage.equals(userPreferredLanguage)
|
||||
|| searchForAutogenerated && captionLanguage.startsWith(userPreferredLanguage)
|
||||
|| userPreferredLanguage.contains("(") && captionLanguage.startsWith(
|
||||
userPreferredLanguage
|
||||
.substring(0, userPreferredLanguage.indexOf('('))))) {
|
||||
if (userPreferredLanguage != null
|
||||
&& (captionLanguage.equals(userPreferredLanguage)
|
||||
|| (searchForAutogenerated && captionLanguage.startsWith(userPreferredLanguage))
|
||||
|| (userPreferredLanguage.contains("(") && captionLanguage.startsWith(
|
||||
userPreferredLanguage.substring(0, userPreferredLanguage.indexOf('(')))))) {
|
||||
final int textRendererIndex = getRendererIndex(C.TRACK_TYPE_TEXT);
|
||||
if (textRendererIndex != RENDERER_UNAVAILABLE) {
|
||||
trackSelector.setPreferredTextLanguage(captionLanguage);
|
||||
@ -754,7 +758,6 @@ public abstract class VideoPlayer extends BasePlayer
|
||||
}
|
||||
qualityPopupMenu.show();
|
||||
isSomePopupMenuVisible = true;
|
||||
showControls(DEFAULT_CONTROLS_DURATION);
|
||||
|
||||
final VideoStream videoStream = getSelectedVideoStream();
|
||||
if (videoStream != null) {
|
||||
@ -772,7 +775,6 @@ public abstract class VideoPlayer extends BasePlayer
|
||||
}
|
||||
playbackSpeedPopupMenu.show();
|
||||
isSomePopupMenuVisible = true;
|
||||
showControls(DEFAULT_CONTROLS_DURATION);
|
||||
}
|
||||
|
||||
private void onCaptionClicked() {
|
||||
@ -781,7 +783,6 @@ public abstract class VideoPlayer extends BasePlayer
|
||||
}
|
||||
captionPopupMenu.show();
|
||||
isSomePopupMenuVisible = true;
|
||||
showControls(DEFAULT_CONTROLS_DURATION);
|
||||
}
|
||||
|
||||
void onResizeClicked() {
|
||||
@ -958,6 +959,7 @@ public abstract class VideoPlayer extends BasePlayer
|
||||
? DEFAULT_CONTROLS_HIDE_TIME
|
||||
: DPAD_CONTROLS_HIDE_TIME;
|
||||
|
||||
showHideShadow(true, DEFAULT_CONTROLS_DURATION, 0);
|
||||
animateView(controlsRoot, true, DEFAULT_CONTROLS_DURATION, 0,
|
||||
() -> hideControls(DEFAULT_CONTROLS_DURATION, hideTime));
|
||||
}
|
||||
@ -967,6 +969,7 @@ public abstract class VideoPlayer extends BasePlayer
|
||||
Log.d(TAG, "showControls() called");
|
||||
}
|
||||
controlsVisibilityHandler.removeCallbacksAndMessages(null);
|
||||
showHideShadow(true, duration, 0);
|
||||
animateView(controlsRoot, true, duration);
|
||||
}
|
||||
|
||||
@ -986,8 +989,10 @@ public abstract class VideoPlayer extends BasePlayer
|
||||
Log.d(TAG, "hideControls() called with: delay = [" + delay + "]");
|
||||
}
|
||||
controlsVisibilityHandler.removeCallbacksAndMessages(null);
|
||||
controlsVisibilityHandler.postDelayed(() ->
|
||||
animateView(controlsRoot, false, duration), delay);
|
||||
controlsVisibilityHandler.postDelayed(() -> {
|
||||
showHideShadow(false, duration, 0);
|
||||
animateView(controlsRoot, false, duration);
|
||||
}, delay);
|
||||
}
|
||||
|
||||
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();
|
||||
|
||||
/*//////////////////////////////////////////////////////////////////////////
|
||||
|
@ -27,22 +27,21 @@ import android.content.IntentFilter;
|
||||
import android.content.SharedPreferences;
|
||||
import android.database.ContentObserver;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.PixelFormat;
|
||||
import android.graphics.Point;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Handler;
|
||||
import android.view.DisplayCutout;
|
||||
import androidx.preference.PreferenceManager;
|
||||
import android.provider.Settings;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.util.Log;
|
||||
import android.util.TypedValue;
|
||||
import android.view.Display;
|
||||
import android.view.GestureDetector;
|
||||
import android.view.Gravity;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.Surface;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.WindowManager;
|
||||
@ -104,7 +103,6 @@ import org.schabi.newpipe.util.ShareUtils;
|
||||
import java.util.List;
|
||||
|
||||
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_FAST_FORWARD;
|
||||
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_SHUFFLE;
|
||||
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.animateRotation;
|
||||
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_X = "popup_saved_x";
|
||||
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
|
||||
| WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
|
||||
private static final int ONGOING_PLAYBACK_WINDOW_FLAGS = IDLE_WINDOW_FLAGS
|
||||
@ -254,6 +252,7 @@ public class VideoPlayerImpl extends VideoPlayer
|
||||
} else {
|
||||
getRootView().setVisibility(View.VISIBLE);
|
||||
initVideoPlayer();
|
||||
onQueueClosed();
|
||||
// Android TV: without it focus will frame the whole player
|
||||
playPauseButton.requestFocus();
|
||||
}
|
||||
@ -310,6 +309,9 @@ public class VideoPlayerImpl extends VideoPlayer
|
||||
|
||||
titleTextView.setSelected(true);
|
||||
channelTextView.setSelected(true);
|
||||
|
||||
// Prevent hiding of bottom sheet via swipe inside queue
|
||||
this.itemsList.setNestedScrollingEnabled(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -334,7 +336,6 @@ public class VideoPlayerImpl extends VideoPlayer
|
||||
* 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.
|
||||
* 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() {
|
||||
if (popupPlayerSelected()) {
|
||||
@ -469,6 +470,17 @@ public class VideoPlayerImpl extends VideoPlayer
|
||||
Settings.System.getUriFor(Settings.System.ACCELEROMETER_ROTATION), false,
|
||||
settingsContentObserver);
|
||||
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) {
|
||||
@ -688,53 +700,33 @@ public class VideoPlayerImpl extends VideoPlayer
|
||||
}
|
||||
|
||||
/*//////////////////////////////////////////////////////////////////////////
|
||||
// Player Overrides
|
||||
//////////////////////////////////////////////////////////////////////////*/
|
||||
// Player Overrides
|
||||
//////////////////////////////////////////////////////////////////////////*/
|
||||
|
||||
@Override
|
||||
public void toggleFullscreen() {
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "toggleFullscreen() called");
|
||||
}
|
||||
if (simpleExoPlayer == null || getCurrentMetadata() == null) {
|
||||
if (popupPlayerSelected()
|
||||
|| simpleExoPlayer == null
|
||||
|| getCurrentMetadata() == null
|
||||
|| fragmentListener == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (popupPlayerSelected()) {
|
||||
setRecovery();
|
||||
service.removeViewFromParent();
|
||||
final Intent intent = NavigationHelper.getPlayerIntent(
|
||||
service,
|
||||
MainActivity.class,
|
||||
this.getPlayQueue(),
|
||||
this.getRepeatMode(),
|
||||
this.getPlaybackSpeed(),
|
||||
this.getPlaybackPitch(),
|
||||
this.getPlaybackSkipSilence(),
|
||||
null,
|
||||
true,
|
||||
!isPlaying(),
|
||||
isMuted()
|
||||
);
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
intent.putExtra(Constants.KEY_SERVICE_ID,
|
||||
getCurrentMetadata().getMetadata().getServiceId());
|
||||
intent.putExtra(Constants.KEY_LINK_TYPE, StreamingService.LinkType.STREAM);
|
||||
intent.putExtra(Constants.KEY_URL, getVideoUrl());
|
||||
intent.putExtra(Constants.KEY_TITLE, getVideoTitle());
|
||||
intent.putExtra(VideoDetailFragment.AUTO_PLAY, true);
|
||||
service.onDestroy();
|
||||
context.startActivity(intent);
|
||||
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 {
|
||||
if (fragmentListener == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
isFullscreen = !isFullscreen;
|
||||
setControlsSize();
|
||||
fragmentListener.onFullscreenStateChanged(isFullscreen());
|
||||
// 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);
|
||||
@ -748,6 +740,40 @@ public class VideoPlayerImpl extends VideoPlayer
|
||||
setupScreenRotationButton();
|
||||
}
|
||||
|
||||
public void switchFromPopupToMain() {
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "switchFromPopupToMain() called");
|
||||
}
|
||||
if (!popupPlayerSelected() || simpleExoPlayer == null || getCurrentMetadata() == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
setRecovery();
|
||||
service.removeViewFromParent();
|
||||
final Intent intent = NavigationHelper.getPlayerIntent(
|
||||
service,
|
||||
MainActivity.class,
|
||||
this.getPlayQueue(),
|
||||
this.getRepeatMode(),
|
||||
this.getPlaybackSpeed(),
|
||||
this.getPlaybackPitch(),
|
||||
this.getPlaybackSkipSilence(),
|
||||
null,
|
||||
true,
|
||||
!isPlaying(),
|
||||
isMuted()
|
||||
);
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
intent.putExtra(Constants.KEY_SERVICE_ID,
|
||||
getCurrentMetadata().getMetadata().getServiceId());
|
||||
intent.putExtra(Constants.KEY_LINK_TYPE, StreamingService.LinkType.STREAM);
|
||||
intent.putExtra(Constants.KEY_URL, getVideoUrl());
|
||||
intent.putExtra(Constants.KEY_TITLE, getVideoTitle());
|
||||
intent.putExtra(VideoDetailFragment.AUTO_PLAY, true);
|
||||
service.onDestroy();
|
||||
context.startActivity(intent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(final View v) {
|
||||
super.onClick(v);
|
||||
@ -775,9 +801,12 @@ public class VideoPlayerImpl extends VideoPlayer
|
||||
} else if (v.getId() == openInBrowser.getId()) {
|
||||
onOpenInBrowserClicked();
|
||||
} else if (v.getId() == fullscreenButton.getId()) {
|
||||
toggleFullscreen();
|
||||
switchFromPopupToMain();
|
||||
} 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();
|
||||
} else {
|
||||
toggleFullscreen();
|
||||
@ -790,9 +819,12 @@ public class VideoPlayerImpl extends VideoPlayer
|
||||
|
||||
if (getCurrentState() != STATE_COMPLETED) {
|
||||
getControlsVisibilityHandler().removeCallbacksAndMessages(null);
|
||||
showHideShadow(true, DEFAULT_CONTROLS_DURATION, 0);
|
||||
animateView(getControlsRoot(), true, DEFAULT_CONTROLS_DURATION, 0, () -> {
|
||||
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);
|
||||
} else {
|
||||
hideControls(DEFAULT_CONTROLS_DURATION, DEFAULT_CONTROLS_HIDE_TIME);
|
||||
@ -819,7 +851,7 @@ public class VideoPlayerImpl extends VideoPlayer
|
||||
buildQueue();
|
||||
updatePlaybackButtons();
|
||||
|
||||
getControlsRoot().setVisibility(View.INVISIBLE);
|
||||
hideControls(0, 0);
|
||||
queueLayout.requestFocus();
|
||||
animateView(queueLayout, SLIDE_AND_ALPHA, true,
|
||||
DEFAULT_CONTROLS_DURATION);
|
||||
@ -911,9 +943,8 @@ public class VideoPlayerImpl extends VideoPlayer
|
||||
|
||||
private void setupScreenRotationButton() {
|
||||
final boolean orientationLocked = PlayerHelper.globalScreenOrientationLocked(service);
|
||||
final boolean tabletInLandscape = DeviceUtils.isTablet(service) && service.isLandscape();
|
||||
final boolean showButton = videoPlayerSelected()
|
||||
&& (orientationLocked || isVerticalVideo || tabletInLandscape);
|
||||
&& (orientationLocked || isVerticalVideo || DeviceUtils.isTablet(service));
|
||||
screenRotationButton.setVisibility(showButton ? View.VISIBLE : View.GONE);
|
||||
screenRotationButton.setImageDrawable(AppCompatResources.getDrawable(service, isFullscreen()
|
||||
? R.drawable.ic_fullscreen_exit_white_24dp
|
||||
@ -925,6 +956,8 @@ public class VideoPlayerImpl extends VideoPlayer
|
||||
if (orientationLocked
|
||||
&& isFullscreen()
|
||||
&& service.isLandscape() == isVerticalVideo
|
||||
&& !DeviceUtils.isTv(service)
|
||||
&& !DeviceUtils.isTablet(service)
|
||||
&& fragmentListener != null) {
|
||||
fragmentListener.onScreenRotationButtonClicked();
|
||||
}
|
||||
@ -955,6 +988,7 @@ public class VideoPlayerImpl extends VideoPlayer
|
||||
super.onDismiss(menu);
|
||||
if (isPlaying()) {
|
||||
hideControls(DEFAULT_CONTROLS_DURATION, 0);
|
||||
hideSystemUIIfNeeded();
|
||||
}
|
||||
}
|
||||
|
||||
@ -979,15 +1013,6 @@ public class VideoPlayerImpl extends VideoPlayer
|
||||
|
||||
setInitialGestureValues();
|
||||
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);
|
||||
|
||||
NotificationUtil.getInstance().createNotificationIfNeededAndUpdate(this, false);
|
||||
if (isFullscreen) {
|
||||
toggleFullscreen();
|
||||
}
|
||||
super.onCompleted();
|
||||
}
|
||||
|
||||
@ -1255,20 +1283,6 @@ public class VideoPlayerImpl extends VideoPlayer
|
||||
updatePopupSize(getPopupLayoutParams().width, -1);
|
||||
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
|
||||
// (in fullscreen mode) the size of queue layout can be larger than the screen size
|
||||
onQueueClosed();
|
||||
@ -1278,18 +1292,14 @@ public class VideoPlayerImpl extends VideoPlayer
|
||||
// Interrupt playback only when screen turns on
|
||||
// and user is watching video in popup player.
|
||||
// Same actions for video player will be handled in ACTION_VIDEO_FRAGMENT_RESUMED
|
||||
if (backgroundPlaybackEnabled()
|
||||
&& popupPlayerSelected()
|
||||
&& (isPlaying() || isLoading())) {
|
||||
if (popupPlayerSelected() && (isPlaying() || isLoading())) {
|
||||
useVideoSource(true);
|
||||
}
|
||||
break;
|
||||
case Intent.ACTION_SCREEN_OFF:
|
||||
shouldUpdateOnProgress = false;
|
||||
// Interrupt playback only when screen turns off with popup player working
|
||||
if (backgroundPlaybackEnabled()
|
||||
&& popupPlayerSelected()
|
||||
&& (isPlaying() || isLoading())) {
|
||||
if (popupPlayerSelected() && (isPlaying() || isLoading())) {
|
||||
useVideoSource(false);
|
||||
}
|
||||
break;
|
||||
@ -1426,9 +1436,10 @@ public class VideoPlayerImpl extends VideoPlayer
|
||||
showOrHideButtons();
|
||||
|
||||
getControlsVisibilityHandler().removeCallbacksAndMessages(null);
|
||||
getControlsVisibilityHandler().postDelayed(() ->
|
||||
animateView(getControlsRoot(), false, duration, 0,
|
||||
this::hideSystemUIIfNeeded), delay
|
||||
getControlsVisibilityHandler().postDelayed(() -> {
|
||||
showHideShadow(false, duration, 0);
|
||||
animateView(getControlsRoot(), false, duration, 0, this::hideSystemUIIfNeeded);
|
||||
}, delay
|
||||
);
|
||||
}
|
||||
|
||||
@ -1456,11 +1467,17 @@ public class VideoPlayerImpl extends VideoPlayer
|
||||
}
|
||||
|
||||
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
|
||||
| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
|
||||
| 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();
|
||||
}
|
||||
|
||||
/**
|
||||
* 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) {
|
||||
button.setImageDrawable(AppCompatResources.getDrawable(service, isMuted
|
||||
? 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)) {
|
||||
toggleFullscreen();
|
||||
}
|
||||
|
||||
setControlsSize();
|
||||
}
|
||||
|
||||
private void buildQueue() {
|
||||
@ -2001,6 +1930,12 @@ public class VideoPlayerImpl extends VideoPlayer
|
||||
public void setFragmentListener(final PlayerServiceEventListener listener) {
|
||||
fragmentListener = listener;
|
||||
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();
|
||||
updatePlayback();
|
||||
triggerProgressUpdate();
|
||||
|
@ -39,12 +39,13 @@ public class CustomBottomSheetBehavior extends BottomSheetBehavior<FrameLayout>
|
||||
}
|
||||
|
||||
// Found that user still swiping, continue following
|
||||
if (skippingInterception) {
|
||||
if (skippingInterception || getState() == BottomSheetBehavior.STATE_SETTLING) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 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
|
||||
for (final Integer element : skipInterceptionOfElements) {
|
||||
final ViewGroup viewGroup = child.findViewById(element);
|
||||
|
@ -9,6 +9,7 @@ import android.view.View;
|
||||
import android.view.ViewConfiguration;
|
||||
import android.view.Window;
|
||||
import android.view.WindowManager;
|
||||
import android.widget.ProgressBar;
|
||||
import androidx.appcompat.content.res.AppCompatResources;
|
||||
import org.schabi.newpipe.R;
|
||||
import org.schabi.newpipe.player.BasePlayer;
|
||||
@ -264,14 +265,19 @@ public class PlayerGestureListener
|
||||
}
|
||||
|
||||
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 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;
|
||||
window.setAttributes(layoutParams);
|
||||
|
||||
// Save current brightness level
|
||||
PlayerHelper.setScreenBrightness(parent, currentProgressPercent);
|
||||
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "onScroll().brightnessControl, "
|
||||
+ "currentBrightness = " + currentProgressPercent);
|
||||
|
@ -6,8 +6,6 @@ import android.content.pm.PackageManager;
|
||||
import android.content.res.Configuration;
|
||||
import android.os.BatteryManager;
|
||||
import android.os.Build;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.util.TypedValue;
|
||||
import android.view.KeyEvent;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
@ -74,17 +72,4 @@ public final class DeviceUtils {
|
||||
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;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Build.VERSION;
|
||||
import android.os.Build.VERSION_CODES;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.SurfaceView;
|
||||
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;
|
||||
|
||||
public class ExpandableSurfaceView extends SurfaceView {
|
||||
private int resizeMode = AspectRatioFrameLayout.RESIZE_MODE_FIT;
|
||||
private int resizeMode = RESIZE_MODE_FIT;
|
||||
private int baseHeight = 0;
|
||||
private int maxHeight = 0;
|
||||
private float videoAspectRatio = 0.0f;
|
||||
@ -30,7 +33,7 @@ public class ExpandableSurfaceView extends SurfaceView {
|
||||
final boolean verticalVideo = videoAspectRatio < 1;
|
||||
// Use maxHeight only on non-fit resize mode and in vertical videos
|
||||
int height = maxHeight != 0
|
||||
&& resizeMode != AspectRatioFrameLayout.RESIZE_MODE_FIT
|
||||
&& resizeMode != RESIZE_MODE_FIT
|
||||
&& verticalVideo ? maxHeight : baseHeight;
|
||||
|
||||
if (height == 0) {
|
||||
@ -42,26 +45,22 @@ public class ExpandableSurfaceView extends SurfaceView {
|
||||
scaleX = 1.0f;
|
||||
scaleY = 1.0f;
|
||||
|
||||
switch (resizeMode) {
|
||||
case AspectRatioFrameLayout.RESIZE_MODE_FIT:
|
||||
if (aspectDeformation > 0) {
|
||||
height = (int) (width / videoAspectRatio);
|
||||
} else {
|
||||
width = (int) (height * videoAspectRatio);
|
||||
}
|
||||
|
||||
break;
|
||||
case RESIZE_MODE_ZOOM:
|
||||
if (aspectDeformation < 0) {
|
||||
scaleY = viewAspectRatio / videoAspectRatio;
|
||||
} else {
|
||||
scaleX = videoAspectRatio / viewAspectRatio;
|
||||
}
|
||||
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
if (resizeMode == 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) {
|
||||
height = (int) (width / videoAspectRatio);
|
||||
} else {
|
||||
width = (int) (height * videoAspectRatio);
|
||||
}
|
||||
} else if (resizeMode == RESIZE_MODE_ZOOM) {
|
||||
if (aspectDeformation < 0) {
|
||||
scaleY = viewAspectRatio / videoAspectRatio;
|
||||
} else {
|
||||
scaleX = videoAspectRatio / viewAspectRatio;
|
||||
}
|
||||
}
|
||||
|
||||
super.onMeasure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
|
||||
MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY));
|
||||
}
|
||||
|
@ -17,15 +17,19 @@
|
||||
*/
|
||||
package org.schabi.newpipe.views;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.content.Context;
|
||||
import android.graphics.Rect;
|
||||
import android.os.Build;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import android.view.WindowInsets;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.coordinatorlayout.widget.CoordinatorLayout;
|
||||
import org.schabi.newpipe.R;
|
||||
|
||||
public final class FocusAwareCoordinator extends CoordinatorLayout {
|
||||
private final Rect childFocus = new Rect();
|
||||
@ -63,4 +67,41 @@ public final class FocusAwareCoordinator extends CoordinatorLayout {
|
||||
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_height="match_parent"
|
||||
android:layout_weight="5"
|
||||
android:fitsSystemWindows="true"
|
||||
android:isScrollContainer="true">
|
||||
|
||||
<com.google.android.material.appbar.AppBarLayout
|
||||
@ -28,12 +27,11 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@android:color/transparent"
|
||||
android:fitsSystemWindows="true"
|
||||
android:touchscreenBlocksFocus="false"
|
||||
app:elevation="0dp"
|
||||
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_height="wrap_content"
|
||||
app:layout_scrollFlags="scroll">
|
||||
@ -162,7 +160,7 @@
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
</com.google.android.material.appbar.CollapsingToolbarLayout>
|
||||
</org.schabi.newpipe.views.CustomCollapsingToolbarLayout>
|
||||
|
||||
<!-- CONTENT -->
|
||||
<RelativeLayout
|
||||
|
@ -28,6 +28,22 @@
|
||||
android:layout_centerInParent="true"
|
||||
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
|
||||
android:id="@+id/endScreen"
|
||||
android:layout_width="match_parent"
|
||||
@ -42,28 +58,16 @@
|
||||
android:id="@+id/playbackControlRoot"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:fitsSystemWindows="true"
|
||||
android:background="@color/video_overlay_color"
|
||||
android:visibility="gone"
|
||||
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 -->
|
||||
<RelativeLayout
|
||||
android:id="@+id/playbackWindowRoot"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:fitsSystemWindows="true">
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/topControls"
|
||||
@ -228,29 +232,29 @@
|
||||
tools:ignore="HardcodedText,RtlHardcoded"
|
||||
tools:text="FIT"/>
|
||||
|
||||
<Button
|
||||
android:id="@+id/captionTextView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="@dimen/player_main_buttons_padding"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:gravity="center|left"
|
||||
android:minHeight="35dp"
|
||||
android:lines="1"
|
||||
android:ellipsize="end"
|
||||
android:minWidth="50dp"
|
||||
android:textColor="@android:color/white"
|
||||
android:textStyle="bold"
|
||||
android:textAllCaps="false"
|
||||
android:background="?attr/selectableItemBackground"
|
||||
tools:ignore="RelativeOverlap,RtlHardcoded"
|
||||
tools:text="English"/>
|
||||
|
||||
<Space
|
||||
android:id="@+id/spaceBeforeButton"
|
||||
<FrameLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="3"/>
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="3">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/captionTextView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="@dimen/player_main_buttons_padding"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:gravity="center|left"
|
||||
android:minHeight="35dp"
|
||||
android:lines="1"
|
||||
android:ellipsize="end"
|
||||
android:minWidth="50dp"
|
||||
android:textColor="@android:color/white"
|
||||
android:textStyle="bold"
|
||||
android:background="?attr/selectableItemBackground"
|
||||
tools:ignore="RelativeOverlap,RtlHardcoded"
|
||||
tools:text="English"/>
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
<androidx.appcompat.widget.AppCompatImageButton
|
||||
android:id="@+id/playWithKodi"
|
||||
@ -307,25 +311,24 @@
|
||||
android:contentDescription="@string/mute"
|
||||
tools:ignore="RtlHardcoded" />
|
||||
|
||||
<androidx.appcompat.widget.AppCompatImageButton
|
||||
android:id="@+id/fullScreenButton"
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="40dp"
|
||||
android:padding="@dimen/player_main_buttons_padding"
|
||||
android:background="?attr/selectableItemBackground"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:scaleType="fitCenter"
|
||||
app:srcCompat="@drawable/ic_fullscreen_white_24dp"
|
||||
tools:ignore="ContentDescription,RtlHardcoded"
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<androidx.appcompat.widget.AppCompatImageButton
|
||||
android:id="@+id/fullScreenButton"
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="40dp"
|
||||
android:padding="@dimen/player_main_buttons_padding"
|
||||
android:layout_alignParentRight="true"
|
||||
android:background="?attr/selectableItemBackground"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:scaleType="fitCenter"
|
||||
app:srcCompat="@drawable/ic_fullscreen_white_24dp"
|
||||
tools:ignore="ContentDescription,RtlHardcoded"
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible"/>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/bottomControls"
|
||||
android:layout_width="match_parent"
|
||||
@ -353,10 +356,10 @@
|
||||
android:id="@+id/playbackSeekBar"
|
||||
style="@style/Widget.AppCompat.SeekBar"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:layout_weight="1"
|
||||
android:paddingBottom="4dp"
|
||||
android:paddingTop="8dp"
|
||||
android:layout_marginTop="2dp"
|
||||
tools:progress="25"
|
||||
android:nextFocusDown="@id/screenRotationButton"
|
||||
tools:secondaryProgress="50"/>
|
||||
|
@ -4,8 +4,7 @@
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:id="@+id/drawer_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:fitsSystemWindows="true">
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<org.schabi.newpipe.views.FocusAwareCoordinator
|
||||
android:layout_width="match_parent"
|
||||
|
@ -18,11 +18,10 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@android:color/transparent"
|
||||
android:fitsSystemWindows="true"
|
||||
app:elevation="0dp"
|
||||
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_height="wrap_content"
|
||||
app:layout_scrollFlags="scroll">
|
||||
@ -148,8 +147,7 @@
|
||||
/>
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
</com.google.android.material.appbar.CollapsingToolbarLayout>
|
||||
</org.schabi.newpipe.views.CustomCollapsingToolbarLayout>
|
||||
|
||||
<!-- CONTENT -->
|
||||
<RelativeLayout
|
||||
|
@ -28,6 +28,22 @@
|
||||
android:layout_centerInParent="true"
|
||||
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
|
||||
android:id="@+id/endScreen"
|
||||
android:layout_width="match_parent"
|
||||
@ -42,28 +58,16 @@
|
||||
android:id="@+id/playbackControlRoot"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:fitsSystemWindows="true"
|
||||
android:background="@color/video_overlay_color"
|
||||
android:visibility="gone"
|
||||
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 -->
|
||||
<RelativeLayout
|
||||
android:id="@+id/playbackWindowRoot"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:fitsSystemWindows="true">
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/topControls"
|
||||
@ -227,6 +231,11 @@
|
||||
tools:ignore="HardcodedText,RtlHardcoded"
|
||||
tools:text="FIT"/>
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="3">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/captionTextView"
|
||||
android:layout_width="wrap_content"
|
||||
@ -235,7 +244,6 @@
|
||||
android:layout_marginEnd="8dp"
|
||||
android:gravity="center|left"
|
||||
android:minHeight="35dp"
|
||||
android:maxWidth="100dp"
|
||||
android:lines="1"
|
||||
android:ellipsize="end"
|
||||
android:minWidth="50dp"
|
||||
@ -245,11 +253,7 @@
|
||||
tools:ignore="RelativeOverlap,RtlHardcoded"
|
||||
tools:text="English"/>
|
||||
|
||||
<Space
|
||||
android:id="@+id/spaceBeforeButton"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="3"/>
|
||||
</FrameLayout>
|
||||
|
||||
<androidx.appcompat.widget.AppCompatImageButton
|
||||
android:id="@+id/playWithKodi"
|
||||
@ -306,25 +310,24 @@
|
||||
android:contentDescription="@string/mute"
|
||||
tools:ignore="RtlHardcoded" />
|
||||
|
||||
<androidx.appcompat.widget.AppCompatImageButton
|
||||
android:id="@+id/fullScreenButton"
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="40dp"
|
||||
android:padding="@dimen/player_main_buttons_padding"
|
||||
android:background="?attr/selectableItemBackground"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:scaleType="fitCenter"
|
||||
app:srcCompat="@drawable/ic_fullscreen_white_24dp"
|
||||
tools:ignore="ContentDescription,RtlHardcoded"
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<androidx.appcompat.widget.AppCompatImageButton
|
||||
android:id="@+id/fullScreenButton"
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="40dp"
|
||||
android:padding="@dimen/player_main_buttons_padding"
|
||||
android:layout_alignParentRight="true"
|
||||
android:background="?attr/selectableItemBackground"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:scaleType="fitCenter"
|
||||
app:srcCompat="@drawable/ic_fullscreen_white_24dp"
|
||||
tools:ignore="ContentDescription,RtlHardcoded"
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible"/>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/bottomControls"
|
||||
android:layout_width="match_parent"
|
||||
@ -352,10 +355,10 @@
|
||||
android:id="@+id/playbackSeekBar"
|
||||
style="@style/Widget.AppCompat.SeekBar"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:layout_weight="1"
|
||||
android:paddingBottom="4dp"
|
||||
android:paddingTop="8dp"
|
||||
android:layout_marginTop="2dp"
|
||||
tools:progress="25"
|
||||
tools:secondaryProgress="50"/>
|
||||
|
||||
|
20
app/src/main/res/values-v29/themes.xml
Normal file
20
app/src/main/res/values-v29/themes.xml
Normal file
@ -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>
|
||||
|
||||
<!-- Base themes -->
|
||||
|
||||
<style name="LightTheme" parent="Theme.AppCompat.Light.NoActionBar">
|
||||
<style name="Base.LightTheme" parent="Theme.AppCompat.Light.NoActionBar" />
|
||||
<style name="LightTheme" parent="Base.LightTheme">
|
||||
<item name="colorPrimary">@color/light_youtube_primary_color</item>
|
||||
<item name="colorPrimaryDark">@color/light_youtube_primary_color</item>
|
||||
<item name="colorAccent">@color/light_youtube_accent_color</item>
|
||||
|
Loading…
Reference in New Issue
Block a user