sortedVideos,
+ String playbackQuality) {
+ return videoPlayerSelected() ? getResolutionIndex(context, sortedVideos, playbackQuality)
+ : getPopupResolutionIndex(context, sortedVideos, playbackQuality);
+ }
+ };
+ }
+
+ /*//////////////////////////////////////////////////////////////////////////
+ // States
+ //////////////////////////////////////////////////////////////////////////*/
+
+ private void animatePlayButtons(final boolean show, final int duration) {
+ animateView(playPauseButton, AnimationUtils.Type.SCALE_AND_ALPHA, show, duration);
+ if (playQueue.getIndex() > 0)
+ animateView(playPreviousButton, AnimationUtils.Type.SCALE_AND_ALPHA, show, duration);
+ if (playQueue.getIndex() + 1 < playQueue.getStreams().size())
+ animateView(playNextButton, AnimationUtils.Type.SCALE_AND_ALPHA, show, duration);
+
+ }
+
+ @Override
+ public void changeState(int state) {
+ super.changeState(state);
+ updatePlayback();
+ }
+
+ @Override
+ public void onBlocked() {
+ super.onBlocked();
+ playPauseButton.setImageResource(R.drawable.ic_pause_white);
+ animatePlayButtons(false, 100);
+ getRootView().setKeepScreenOn(false);
+
+ service.resetNotification();
+ service.updateNotification(R.drawable.ic_play_arrow_white);
+ }
+
+ @Override
+ public void onBuffering() {
+ super.onBuffering();
+ getRootView().setKeepScreenOn(true);
+
+ service.resetNotification();
+ service.updateNotification(R.drawable.ic_play_arrow_white);
+ }
+
+ @Override
+ public void onPlaying() {
+ super.onPlaying();
+ animateView(playPauseButton, AnimationUtils.Type.SCALE_AND_ALPHA, false, 80, 0, () -> {
+ playPauseButton.setImageResource(R.drawable.ic_pause_white);
+ animatePlayButtons(true, 200);
+ });
+
+ updateWindowFlags(ONGOING_PLAYBACK_WINDOW_FLAGS);
+ checkLandscape();
+ getRootView().setKeepScreenOn(true);
+
+ service.getLockManager().acquireWifiAndCpu();
+ service.resetNotification();
+ service.updateNotification(R.drawable.ic_pause_white);
+ }
+
+ @Override
+ public void onPaused() {
+ super.onPaused();
+ animateView(playPauseButton, AnimationUtils.Type.SCALE_AND_ALPHA, false, 80, 0, () -> {
+ playPauseButton.setImageResource(R.drawable.ic_play_arrow_white);
+ animatePlayButtons(true, 200);
+ });
+
+ updateWindowFlags(IDLE_WINDOW_FLAGS);
+
+ service.resetNotification();
+ service.updateNotification(R.drawable.ic_play_arrow_white);
+
+ getRootView().setKeepScreenOn(false);
+
+ service.getLockManager().releaseWifiAndCpu();
+ }
+
+ @Override
+ public void onPausedSeek() {
+ super.onPausedSeek();
+ animatePlayButtons(false, 100);
+ getRootView().setKeepScreenOn(true);
+
+ service.resetNotification();
+ service.updateNotification(R.drawable.ic_play_arrow_white);
+ }
+
+
+ @Override
+ public void onCompleted() {
+ animateView(playPauseButton, AnimationUtils.Type.SCALE_AND_ALPHA, false, 0, 0, () -> {
+ playPauseButton.setImageResource(R.drawable.ic_replay_white);
+ animatePlayButtons(true, DEFAULT_CONTROLS_DURATION);
+ });
+ getRootView().setKeepScreenOn(false);
+
+ updateWindowFlags(IDLE_WINDOW_FLAGS);
+
+ service.resetNotification();
+ service.updateNotification(R.drawable.ic_replay_white);
+
+ service.getLockManager().releaseWifiAndCpu();
+
+ super.onCompleted();
+ }
+
+ /*//////////////////////////////////////////////////////////////////////////
+ // Broadcast Receiver
+ //////////////////////////////////////////////////////////////////////////*/
+
+ @Override
+ protected void setupBroadcastReceiver(IntentFilter intentFilter) {
+ super.setupBroadcastReceiver(intentFilter);
+ if (DEBUG) Log.d(TAG, "setupBroadcastReceiver() called with: intentFilter = [" + intentFilter + "]");
+
+ intentFilter.addAction(ACTION_CLOSE);
+ intentFilter.addAction(ACTION_PLAY_PAUSE);
+ intentFilter.addAction(ACTION_OPEN_CONTROLS);
+ intentFilter.addAction(ACTION_REPEAT);
+ intentFilter.addAction(ACTION_PLAY_PREVIOUS);
+ intentFilter.addAction(ACTION_PLAY_NEXT);
+ intentFilter.addAction(ACTION_FAST_REWIND);
+ intentFilter.addAction(ACTION_FAST_FORWARD);
+
+ intentFilter.addAction(Intent.ACTION_SCREEN_ON);
+ intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
+
+ intentFilter.addAction(Intent.ACTION_HEADSET_PLUG);
+ }
+
+ @Override
+ public void onBroadcastReceived(Intent intent) {
+ super.onBroadcastReceived(intent);
+ if (intent == null || intent.getAction() == null)
+ return;
+
+ if (DEBUG) Log.d(TAG, "onBroadcastReceived() called with: intent = [" + intent + "]");
+
+ switch (intent.getAction()) {
+ case ACTION_CLOSE:
+ service.onDestroy();
+ break;
+ case ACTION_PLAY_NEXT:
+ onPlayNext();
+ break;
+ case ACTION_PLAY_PREVIOUS:
+ onPlayPrevious();
+ break;
+ case ACTION_FAST_FORWARD:
+ onFastForward();
+ break;
+ case ACTION_FAST_REWIND:
+ onFastRewind();
+ break;
+ case ACTION_PLAY_PAUSE:
+ onPlayPause();
+ break;
+ case ACTION_REPEAT:
+ onRepeatClicked();
+ break;
+ case Intent.ACTION_SCREEN_ON:
+ shouldUpdateOnProgress = true;
+ // Interrupt playback only when screen turns on and user is watching video in fragment
+ if (backgroundPlaybackEnabled() && getPlayer() != null && (isPlaying() || getPlayer().isLoading()))
+ useVideoSource(true);
+ break;
+ case Intent.ACTION_SCREEN_OFF:
+ shouldUpdateOnProgress = false;
+ // Interrupt playback only when screen turns off with video working
+ if (backgroundPlaybackEnabled() && getPlayer() != null && (isPlaying() || getPlayer().isLoading()))
+ useVideoSource(false);
+ break;
+ }
+ service.resetNotification();
+ }
+
+ /*//////////////////////////////////////////////////////////////////////////
+ // Thumbnail Loading
+ //////////////////////////////////////////////////////////////////////////*/
+
+ @Override
+ public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) {
+ super.onLoadingComplete(imageUri, view, loadedImage);
+ // rebuild notification here since remote view does not release bitmaps,
+ // causing memory leaks
+ service.resetNotification();
+ service.updateNotification(-1);
+ }
+
+ @Override
+ public void onLoadingFailed(String imageUri, View view, FailReason failReason) {
+ super.onLoadingFailed(imageUri, view, failReason);
+ service.resetNotification();
+ service.updateNotification(-1);
+ }
+
+ @Override
+ public void onLoadingCancelled(String imageUri, View view) {
+ super.onLoadingCancelled(imageUri, view);
+ service.resetNotification();
+ service.updateNotification(-1);
+ }
+
+ /*//////////////////////////////////////////////////////////////////////////
+ // Utils
+ //////////////////////////////////////////////////////////////////////////*/
+
+ private void setInitialGestureValues() {
+ if (getAudioReactor() != null) {
+ final float currentVolumeNormalized = (float) getAudioReactor().getVolume() / getAudioReactor().getMaxVolume();
+ volumeProgressBar.setProgress((int) (volumeProgressBar.getMax() * currentVolumeNormalized));
+ }
+ }
+
+ private void choosePlayerTypeFromIntent(Intent intent) {
+ // If you want to open popup from the app just include Constants.POPUP_ONLY into an extra
+ if (intent.getIntExtra(PLAYER_TYPE, PLAYER_TYPE_VIDEO) == PLAYER_TYPE_AUDIO) {
+ playerType = MainPlayer.PlayerType.AUDIO;
+ } else if (intent.getIntExtra(PLAYER_TYPE, PLAYER_TYPE_VIDEO) == PLAYER_TYPE_POPUP) {
+ playerType = MainPlayer.PlayerType.POPUP;
+ } else {
+ playerType = MainPlayer.PlayerType.VIDEO;
+ }
+ }
+
+ public boolean backgroundPlaybackEnabled() {
+ return PlayerHelper.getMinimizeOnExitAction(service) == MINIMIZE_ON_EXIT_MODE_BACKGROUND;
+ }
+
+ public boolean minimizeOnPopupEnabled() {
+ return PlayerHelper.getMinimizeOnExitAction(service) == PlayerHelper.MinimizeMode.MINIMIZE_ON_EXIT_MODE_POPUP;
+ }
+
+ public boolean audioPlayerSelected() {
+ return playerType == MainPlayer.PlayerType.AUDIO;
+ }
+
+ public boolean videoPlayerSelected() {
+ return playerType == MainPlayer.PlayerType.VIDEO;
+ }
+
+ public boolean popupPlayerSelected() {
+ return playerType == MainPlayer.PlayerType.POPUP;
+ }
+
+ private int distanceFromCloseButton(MotionEvent popupMotionEvent) {
+ final int closeOverlayButtonX = closeOverlayButton.getLeft() + closeOverlayButton.getWidth() / 2;
+ final int closeOverlayButtonY = closeOverlayButton.getTop() + closeOverlayButton.getHeight() / 2;
+
+ float fingerX = popupLayoutParams.x + popupMotionEvent.getX();
+ float fingerY = popupLayoutParams.y + popupMotionEvent.getY();
+
+ return (int) Math.sqrt(Math.pow(closeOverlayButtonX - fingerX, 2) + Math.pow(closeOverlayButtonY - fingerY, 2));
+ }
+
+ private float getClosingRadius() {
+ final int buttonRadius = closeOverlayButton.getWidth() / 2;
+ // 20% wider than the button itself
+ return buttonRadius * 1.2f;
+ }
+
+ public boolean isInsideClosingRadius(MotionEvent popupMotionEvent) {
+ return distanceFromCloseButton(popupMotionEvent) <= getClosingRadius();
+ }
+
+ public boolean isInFullscreen() {
+ return isFullscreen;
+ }
+
+ @Override
+ public void showControlsThenHide() {
+ if (queueVisible) return;
+
+ showOrHideButtons();
+ super.showControlsThenHide();
+ }
+
+ @Override
+ public void showControls(long duration) {
+ if (queueVisible) return;
+
+ showOrHideButtons();
+ super.showControls(duration);
+ }
+
+ @Override
+ public void hideControls(final long duration, long delay) {
+ if (DEBUG) Log.d(TAG, "hideControls() called with: delay = [" + delay + "]");
+
+ showOrHideButtons();
+
+ getControlsVisibilityHandler().removeCallbacksAndMessages(null);
+ getControlsVisibilityHandler().postDelayed(() ->
+ animateView(getControlsRoot(), false, duration, 0,
+ this::hideSystemUIIfNeeded),
+ /*delayMillis=*/delay
+ );
+ }
+
+ private void showOrHideButtons() {
+ if (playQueue == null)
+ return;
+
+ if (playQueue.getIndex() == 0)
+ playPreviousButton.setVisibility(View.INVISIBLE);
+ else
+ playPreviousButton.setVisibility(View.VISIBLE);
+
+ if (playQueue.getIndex() + 1 == playQueue.getStreams().size())
+ playNextButton.setVisibility(View.INVISIBLE);
+ else
+ playNextButton.setVisibility(View.VISIBLE);
+
+ if (playQueue.getStreams().size() <= 1 || popupPlayerSelected())
+ queueButton.setVisibility(View.GONE);
+ else
+ queueButton.setVisibility(View.VISIBLE);
+ }
+
+ @Override
+ public void hideSystemUIIfNeeded() {
+ if (fragmentListener != null)
+ fragmentListener.hideSystemUIIfNeeded();
+ }
+
+ private void updatePlaybackButtons() {
+ if (repeatButton == null || shuffleButton == null ||
+ simpleExoPlayer == null || playQueue == null) return;
+
+ setRepeatModeButton(repeatButton, getRepeatMode());
+ setShuffleButton(shuffleButton, playQueue.isShuffled());
+ }
+
+ public void checkLandscape() {
+ AppCompatActivity parent = getParentActivity();
+ if (parent != null && service.isLandscape() != isInFullscreen()
+ && getCurrentState() != STATE_COMPLETED && videoPlayerSelected())
+ toggleFullscreen();
+ }
+
+ private void buildQueue() {
+ itemsList.setAdapter(playQueueAdapter);
+ itemsList.setClickable(true);
+ itemsList.setLongClickable(true);
+
+ itemsList.clearOnScrollListeners();
+ itemsList.addOnScrollListener(getQueueScrollListener());
+
+ itemTouchHelper = new ItemTouchHelper(getItemTouchCallback());
+ itemTouchHelper.attachToRecyclerView(itemsList);
+
+ playQueueAdapter.setSelectedListener(getOnSelectedListener());
+
+ itemsListCloseButton.setOnClickListener(view -> onQueueClosed());
+ }
+
+ public void useVideoSource(boolean video) {
+ // Return when: old value of audioOnly equals to the new value, audio player is selected,
+ // video player is selected AND fragment is not shown
+ if (playQueue == null
+ || audioOnly == !video
+ || audioPlayerSelected()
+ || (video && videoPlayerSelected() && fragmentListener.isFragmentStopped()))
+ return;
+
+ audioOnly = !video;
+ setRecovery();
+ reload();
+ }
+
+ private OnScrollBelowItemsListener getQueueScrollListener() {
+ return new OnScrollBelowItemsListener() {
+ @Override
+ public void onScrolledDown(RecyclerView recyclerView) {
+ if (playQueue != null && !playQueue.isComplete()) {
+ playQueue.fetch();
+ } else if (itemsList != null) {
+ itemsList.clearOnScrollListeners();
+ }
+ }
+ };
+ }
+
+ private ItemTouchHelper.SimpleCallback getItemTouchCallback() {
+ return new PlayQueueItemTouchCallback() {
+ @Override
+ public void onMove(int sourceIndex, int targetIndex) {
+ if (playQueue != null) playQueue.move(sourceIndex, targetIndex);
+ }
+
+ @Override
+ public void onSwiped(int index) {
+ if (index != -1) playQueue.remove(index);
+ }
+ };
+ }
+
+ private PlayQueueItemBuilder.OnSelectedListener getOnSelectedListener() {
+ return new PlayQueueItemBuilder.OnSelectedListener() {
+ @Override
+ public void selected(PlayQueueItem item, View view) {
+ onSelected(item);
+ }
+
+ @Override
+ public void held(PlayQueueItem item, View view) {
+ final int index = playQueue.indexOf(item);
+ if (index != -1) playQueue.remove(index);
+ }
+
+ @Override
+ public void onStartDrag(PlayQueueItemHolder viewHolder) {
+ if (itemTouchHelper != null) itemTouchHelper.startDrag(viewHolder);
+ }
+ };
+ }
+
+ /*//////////////////////////////////////////////////////////////////////////
+ // Init
+ //////////////////////////////////////////////////////////////////////////*/
+
+ @SuppressLint("RtlHardcoded")
+ private void initPopup() {
+ if (DEBUG) Log.d(TAG, "initPopup() called");
+
+ updateScreenSize();
+
+ final boolean popupRememberSizeAndPos = PlayerHelper.isRememberingPopupDimensions(service);
+ final float defaultSize = service.getResources().getDimension(R.dimen.popup_default_width);
+ SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(service);
+ popupWidth = popupRememberSizeAndPos ? sharedPreferences.getFloat(POPUP_SAVED_WIDTH, defaultSize) : defaultSize;
+
+ final int layoutParamType = Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.O ?
+ WindowManager.LayoutParams.TYPE_PHONE :
+ WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
+
+ popupLayoutParams = new WindowManager.LayoutParams(
+ (int) popupWidth, (int) getMinimumVideoHeight(popupWidth),
+ layoutParamType,
+ IDLE_WINDOW_FLAGS,
+ PixelFormat.TRANSLUCENT);
+ popupLayoutParams.gravity = Gravity.LEFT | Gravity.TOP;
+ popupLayoutParams.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
+
+ int centerX = (int) (screenWidth / 2f - popupWidth / 2f);
+ int centerY = (int) (screenHeight / 2f - popupHeight / 2f);
+ popupLayoutParams.x = popupRememberSizeAndPos ? sharedPreferences.getInt(POPUP_SAVED_X, centerX) : centerX;
+ popupLayoutParams.y = popupRememberSizeAndPos ? sharedPreferences.getInt(POPUP_SAVED_Y, centerY) : centerY;
+
+ checkPopupPositionBounds();
+
+ getLoadingPanel().setMinimumWidth(popupLayoutParams.width);
+ getLoadingPanel().setMinimumHeight(popupLayoutParams.height);
+
+ service.removeViewFromParent();
+ windowManager.addView(service.getView(), popupLayoutParams);
+
+ if (getAspectRatioFrameLayout().getResizeMode() == AspectRatioFrameLayout.RESIZE_MODE_ZOOM)
+ onResizeClicked();
+ }
+
+ @SuppressLint("RtlHardcoded")
+ private void initPopupCloseOverlay() {
+ if (DEBUG) Log.d(TAG, "initPopupCloseOverlay() called");
+ closeOverlayView = View.inflate(service, R.layout.player_popup_close_overlay, null);
+ closeOverlayButton = closeOverlayView.findViewById(R.id.closeButton);
+
+ final int layoutParamType = Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.O ?
+ WindowManager.LayoutParams.TYPE_PHONE :
+ WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
+ final int flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
+ | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
+
+ WindowManager.LayoutParams closeOverlayLayoutParams = new WindowManager.LayoutParams(
+ ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT,
+ layoutParamType,
+ flags,
+ PixelFormat.TRANSLUCENT);
+ closeOverlayLayoutParams.gravity = Gravity.LEFT | Gravity.TOP;
+ closeOverlayLayoutParams.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
+
+ closeOverlayButton.setVisibility(View.GONE);
+ windowManager.addView(closeOverlayView, closeOverlayLayoutParams);
+ }
+
+ private void initVideoPlayer() {
+ service.getView().setLayoutParams(new FrameLayout.LayoutParams(
+ FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT));
+ }
+
+ /*//////////////////////////////////////////////////////////////////////////
+ // Popup utils
+ //////////////////////////////////////////////////////////////////////////*/
+
+ /**
+ * @see #checkPopupPositionBounds(float, float)
+ */
+ @SuppressWarnings("UnusedReturnValue")
+ public boolean checkPopupPositionBounds() {
+ return checkPopupPositionBounds(screenWidth, screenHeight);
+ }
+
+ /**
+ * Check if {@link #popupLayoutParams}' position is within a arbitrary boundary that goes from (0,0) to (boundaryWidth,
+ * boundaryHeight).
+ *
+ * If it's out of these boundaries, {@link #popupLayoutParams}' position is changed and {@code true} is returned
+ * to represent this change.
+ *
+ * @return if the popup was out of bounds and have been moved back to it
+ */
+ public boolean checkPopupPositionBounds(final float boundaryWidth, final float boundaryHeight) {
+ if (DEBUG) {
+ Log.d(TAG, "checkPopupPositionBounds() called with: boundaryWidth = ["
+ + boundaryWidth + "], boundaryHeight = [" + boundaryHeight + "]");
+ }
+
+ if (popupLayoutParams.x < 0) {
+ popupLayoutParams.x = 0;
+ return true;
+ } else if (popupLayoutParams.x > boundaryWidth - popupLayoutParams.width) {
+ popupLayoutParams.x = (int) (boundaryWidth - popupLayoutParams.width);
+ return true;
+ }
+
+ if (popupLayoutParams.y < 0) {
+ popupLayoutParams.y = 0;
+ return true;
+ } else if (popupLayoutParams.y > boundaryHeight - popupLayoutParams.height) {
+ popupLayoutParams.y = (int) (boundaryHeight - popupLayoutParams.height);
+ return true;
+ }
+
+ return false;
+ }
+
+ public void savePositionAndSize() {
+ SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(service);
+ sharedPreferences.edit().putInt(POPUP_SAVED_X, popupLayoutParams.x).apply();
+ sharedPreferences.edit().putInt(POPUP_SAVED_Y, popupLayoutParams.y).apply();
+ sharedPreferences.edit().putFloat(POPUP_SAVED_WIDTH, popupLayoutParams.width).apply();
+ }
+
+ private float getMinimumVideoHeight(float width) {
+ //if (DEBUG) Log.d(TAG, "getMinimumVideoHeight() called with: width = [" + width + "], returned: " + height);
+ return width / (16.0f / 9.0f); // Respect the 16:9 ratio that most videos have
+ }
+
+ public void updateScreenSize() {
+ DisplayMetrics metrics = new DisplayMetrics();
+ windowManager.getDefaultDisplay().getMetrics(metrics);
+
+ screenWidth = metrics.widthPixels;
+ screenHeight = metrics.heightPixels;
+ if (DEBUG)
+ Log.d(TAG, "updateScreenSize() called > screenWidth = " + screenWidth + ", screenHeight = " + screenHeight);
+
+ popupWidth = service.getResources().getDimension(R.dimen.popup_default_width);
+ popupHeight = getMinimumVideoHeight(popupWidth);
+
+ minimumWidth = service.getResources().getDimension(R.dimen.popup_minimum_width);
+ minimumHeight = getMinimumVideoHeight(minimumWidth);
+
+ maximumWidth = screenWidth;
+ maximumHeight = screenHeight;
+ }
+
+ public void updatePopupSize(int width, int height) {
+ if (DEBUG) Log.d(TAG, "updatePopupSize() called with: width = [" + width + "], height = [" + height + "]");
+
+ if (popupLayoutParams == null || windowManager == null || !popupPlayerSelected() || getRootView().getParent() == null)
+ return;
+
+ width = (int) (width > maximumWidth ? maximumWidth : width < minimumWidth ? minimumWidth : width);
+
+ if (height == -1) height = (int) getMinimumVideoHeight(width);
+ else height = (int) (height > maximumHeight ? maximumHeight : height < minimumHeight ? minimumHeight : height);
+
+ popupLayoutParams.width = width;
+ popupLayoutParams.height = height;
+ popupWidth = width;
+ popupHeight = height;
+
+ if (DEBUG) Log.d(TAG, "updatePopupSize() updated values: width = [" + width + "], height = [" + height + "]");
+ windowManager.updateViewLayout(getRootView(), popupLayoutParams);
+ }
+
+ private void updateWindowFlags(final int flags) {
+ if (popupLayoutParams == null || windowManager == null || !popupPlayerSelected() || getRootView().getParent() == null)
+ return;
+
+ popupLayoutParams.flags = flags;
+ windowManager.updateViewLayout(getRootView(), popupLayoutParams);
+ }
+
+ /*//////////////////////////////////////////////////////////////////////////
+ // Misc
+ //////////////////////////////////////////////////////////////////////////*/
+
+ public void closePopup() {
+ if (DEBUG) Log.d(TAG, "closePopup() called, isPopupClosing = " + isPopupClosing);
+ if (isPopupClosing) return;
+ isPopupClosing = true;
+
+ savePlaybackState();
+ windowManager.removeView(getRootView());
+
+ animateOverlayAndFinishService();
+ }
+
+ private void animateOverlayAndFinishService() {
+ final int targetTranslationY = (int) (closeOverlayButton.getRootView().getHeight() - closeOverlayButton.getY());
+
+ closeOverlayButton.animate().setListener(null).cancel();
+ closeOverlayButton.animate()
+ .setInterpolator(new AnticipateInterpolator())
+ .translationY(targetTranslationY)
+ .setDuration(400)
+ .setListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationCancel(Animator animation) {
+ end();
+ }
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ end();
+ }
+
+ private void end() {
+ windowManager.removeView(closeOverlayView);
+
+ service.onDestroy();
+ }
+ }).start();
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+ // Manipulations with listener
+ ///////////////////////////////////////////////////////////////////////////
+
+ public void setFragmentListener(PlayerServiceEventListener listener) {
+ fragmentListener = listener;
+ updateMetadata();
+ updatePlayback();
+ triggerProgressUpdate();
+ }
+
+ public void removeFragmentListener(PlayerServiceEventListener listener) {
+ if (fragmentListener == listener) {
+ fragmentListener = null;
+ }
+ }
+
+ /*package-private*/ void setActivityListener(PlayerEventListener listener) {
+ activityListener = listener;
+ updateMetadata();
+ updatePlayback();
+ triggerProgressUpdate();
+ }
+
+ /*package-private*/ void removeActivityListener(PlayerEventListener listener) {
+ if (activityListener == listener) {
+ activityListener = null;
+ }
+ }
+
+ private void updateMetadata() {
+ if (fragmentListener != null && getCurrentMetadata() != null) {
+ fragmentListener.onMetadataUpdate(getCurrentMetadata().getMetadata());
+ }
+ if (activityListener != null && getCurrentMetadata() != null) {
+ activityListener.onMetadataUpdate(getCurrentMetadata().getMetadata());
+ }
+ }
+
+ private void updatePlayback() {
+ if (fragmentListener != null && simpleExoPlayer != null && playQueue != null) {
+ fragmentListener.onPlaybackUpdate(currentState, getRepeatMode(),
+ playQueue.isShuffled(), simpleExoPlayer.getPlaybackParameters());
+ }
+ if (activityListener != null && simpleExoPlayer != null && playQueue != null) {
+ activityListener.onPlaybackUpdate(currentState, getRepeatMode(),
+ playQueue.isShuffled(), getPlaybackParameters());
+ }
+ }
+
+ private void updateProgress(int currentProgress, int duration, int bufferPercent) {
+ if (fragmentListener != null) {
+ fragmentListener.onProgressUpdate(currentProgress, duration, bufferPercent);
+ }
+ if (activityListener != null) {
+ activityListener.onProgressUpdate(currentProgress, duration, bufferPercent);
+ }
+ }
+
+ void stopActivityBinding() {
+ if (fragmentListener != null) {
+ fragmentListener.onServiceStopped();
+ fragmentListener = null;
+ }
+ if (activityListener != null) {
+ activityListener.onServiceStopped();
+ activityListener = null;
+ }
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+ // Getters
+ ///////////////////////////////////////////////////////////////////////////
+
+ public RelativeLayout getVolumeRelativeLayout() {
+ return volumeRelativeLayout;
+ }
+
+ public ProgressBar getVolumeProgressBar() {
+ return volumeProgressBar;
+ }
+
+ public ImageView getVolumeImageView() {
+ return volumeImageView;
+ }
+
+ public RelativeLayout getBrightnessRelativeLayout() {
+ return brightnessRelativeLayout;
+ }
+
+ public ProgressBar getBrightnessProgressBar() {
+ return brightnessProgressBar;
+ }
+
+ public ImageView getBrightnessImageView() {
+ return brightnessImageView;
+ }
+
+ public ImageButton getPlayPauseButton() {
+ return playPauseButton;
+ }
+
+ public int getMaxGestureLength() {
+ return maxGestureLength;
+ }
+
+ public TextView getResizingIndicator() {
+ return resizingIndicator;
+ }
+
+ public GestureDetector getGestureDetector() {
+ return gestureDetector;
+ }
+
+ public WindowManager.LayoutParams getPopupLayoutParams() {
+ return popupLayoutParams;
+ }
+
+ public float getScreenWidth() {
+ return screenWidth;
+ }
+
+ public float getScreenHeight() {
+ return screenHeight;
+ }
+
+ public float getPopupWidth() {
+ return popupWidth;
+ }
+
+ public float getPopupHeight() {
+ return popupHeight;
+ }
+
+ public void setPopupWidth(float width) {
+ popupWidth = width;
+ }
+
+ public void setPopupHeight(float height) {
+ popupHeight = height;
+ }
+
+ public View getCloseOverlayButton() {
+ return closeOverlayButton;
+ }
+
+ public View getCloseOverlayView() {
+ return closeOverlayView;
+ }
+
+ public View getClosingOverlayView() {
+ return closingOverlayView;
+ }
+}
diff --git a/app/src/main/java/org/schabi/newpipe/player/event/CustomBottomSheetBehavior.java b/app/src/main/java/org/schabi/newpipe/player/event/CustomBottomSheetBehavior.java
new file mode 100644
index 00000000000..85db3b2017c
--- /dev/null
+++ b/app/src/main/java/org/schabi/newpipe/player/event/CustomBottomSheetBehavior.java
@@ -0,0 +1,47 @@
+package org.schabi.newpipe.player.event;
+
+import android.content.Context;
+import android.graphics.Rect;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import androidx.coordinatorlayout.widget.CoordinatorLayout;
+import com.google.android.material.bottomsheet.BottomSheetBehavior;
+import org.schabi.newpipe.R;
+
+public class CustomBottomSheetBehavior extends BottomSheetBehavior {
+
+ public CustomBottomSheetBehavior(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ @Override
+ public boolean onInterceptTouchEvent(CoordinatorLayout parent, View child, MotionEvent event) {
+ // Without overriding scrolling will not work in detail_content_root_layout
+ ViewGroup controls = child.findViewById(R.id.detail_content_root_layout);
+ if (controls != null) {
+ Rect rect = new Rect();
+ controls.getGlobalVisibleRect(rect);
+ if (rect.contains((int) event.getX(), (int) event.getY())) return false;
+ }
+
+ // Without overriding scrolling will not work on relatedStreamsLayout
+ ViewGroup relatedStreamsLayout = child.findViewById(R.id.relatedStreamsLayout);
+ if (relatedStreamsLayout != null) {
+ Rect rect = new Rect();
+ relatedStreamsLayout.getGlobalVisibleRect(rect);
+ if (rect.contains((int) event.getX(), (int) event.getY())) return false;
+ }
+
+ ViewGroup playQueue = child.findViewById(R.id.playQueue);
+ if (playQueue != null) {
+ Rect rect = new Rect();
+ playQueue.getGlobalVisibleRect(rect);
+ if (rect.contains((int) event.getX(), (int) event.getY())) return false;
+ }
+
+ return super.onInterceptTouchEvent(parent, child, event);
+ }
+
+}
diff --git a/app/src/main/java/org/schabi/newpipe/player/event/PlayerGestureListener.java b/app/src/main/java/org/schabi/newpipe/player/event/PlayerGestureListener.java
new file mode 100644
index 00000000000..72462beffcb
--- /dev/null
+++ b/app/src/main/java/org/schabi/newpipe/player/event/PlayerGestureListener.java
@@ -0,0 +1,462 @@
+package org.schabi.newpipe.player.event;
+
+import android.app.Activity;
+import android.util.Log;
+import android.view.*;
+import androidx.appcompat.content.res.AppCompatResources;
+import org.schabi.newpipe.R;
+import org.schabi.newpipe.player.BasePlayer;
+import org.schabi.newpipe.player.MainPlayer;
+import org.schabi.newpipe.player.VideoPlayerImpl;
+import org.schabi.newpipe.player.helper.PlayerHelper;
+
+import static org.schabi.newpipe.player.BasePlayer.*;
+import static org.schabi.newpipe.player.VideoPlayer.DEFAULT_CONTROLS_DURATION;
+import static org.schabi.newpipe.player.VideoPlayer.DEFAULT_CONTROLS_HIDE_TIME;
+import static org.schabi.newpipe.util.AnimationUtils.Type.SCALE_AND_ALPHA;
+import static org.schabi.newpipe.util.AnimationUtils.animateView;
+
+public class PlayerGestureListener extends GestureDetector.SimpleOnGestureListener implements View.OnTouchListener {
+ private static final String TAG = ".PlayerGestureListener";
+ private static final boolean DEBUG = BasePlayer.DEBUG;
+
+ private VideoPlayerImpl playerImpl;
+ private MainPlayer service;
+
+ private int initialPopupX, initialPopupY;
+
+ private boolean isMovingInMain, isMovingInPopup;
+
+ private boolean isResizing;
+
+ private int tossFlingVelocity;
+
+ private final boolean isVolumeGestureEnabled;
+ private final boolean isBrightnessGestureEnabled;
+ private final int maxVolume;
+ private static final int MOVEMENT_THRESHOLD = 40;
+
+
+ public PlayerGestureListener(final VideoPlayerImpl playerImpl, final MainPlayer service) {
+ this.playerImpl = playerImpl;
+ this.service = service;
+ this.tossFlingVelocity = PlayerHelper.getTossFlingVelocity(service);
+
+ isVolumeGestureEnabled = PlayerHelper.isVolumeGestureEnabled(service);
+ isBrightnessGestureEnabled = PlayerHelper.isBrightnessGestureEnabled(service);
+ maxVolume = playerImpl.getAudioReactor().getMaxVolume();
+ }
+
+ /*//////////////////////////////////////////////////////////////////////////
+ // Helpers
+ //////////////////////////////////////////////////////////////////////////*/
+
+ /*
+ * Main and popup players' gesture listeners is too different.
+ * So it will be better to have different implementations of them
+ * */
+ @Override
+ public boolean onDoubleTap(MotionEvent e) {
+ if (DEBUG) Log.d(TAG, "onDoubleTap() called with: e = [" + e + "]" + "rawXy = " + e.getRawX() + ", " + e.getRawY() + ", xy = " + e.getX() + ", " + e.getY());
+
+ if (playerImpl.popupPlayerSelected()) return onDoubleTapInPopup(e);
+ else return onDoubleTapInMain(e);
+ }
+
+ @Override
+ public boolean onSingleTapConfirmed(MotionEvent e) {
+ if (DEBUG) Log.d(TAG, "onSingleTapConfirmed() called with: e = [" + e + "]");
+
+ if (playerImpl.popupPlayerSelected()) return onSingleTapConfirmedInPopup(e);
+ else return onSingleTapConfirmedInMain(e);
+ }
+
+ @Override
+ public boolean onDown(MotionEvent e) {
+ if (DEBUG) Log.d(TAG, "onDown() called with: e = [" + e + "]");
+
+ if (playerImpl.popupPlayerSelected()) return onDownInPopup(e);
+ else return true;
+ }
+ @Override
+ public void onLongPress(MotionEvent e) {
+ if (DEBUG) Log.d(TAG, "onLongPress() called with: e = [" + e + "]");
+
+ if (playerImpl.popupPlayerSelected()) onLongPressInPopup(e);
+ }
+
+ @Override
+ public boolean onScroll(MotionEvent initialEvent, MotionEvent movingEvent, float distanceX, float distanceY) {
+ if (playerImpl.popupPlayerSelected()) return onScrollInPopup(initialEvent, movingEvent, distanceX, distanceY);
+ else return onScrollInMain(initialEvent, movingEvent, distanceX, distanceY);
+ }
+
+ @Override
+ public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
+ if (DEBUG) Log.d(TAG, "onFling() called with velocity: dX=[" + velocityX + "], dY=[" + velocityY + "]");
+
+ if (playerImpl.popupPlayerSelected()) return onFlingInPopup(e1, e2, velocityX, velocityY);
+ else return true;
+ }
+
+ @Override
+ public boolean onTouch(View v, MotionEvent event) {
+ //noinspection PointlessBooleanExpression,ConstantConditions
+ if (DEBUG && false) Log.d(TAG, "onTouch() called with: v = [" + v + "], event = [" + event + "]");
+
+ if (playerImpl.popupPlayerSelected()) return onTouchInPopup(v, event);
+ else return onTouchInMain(v, event);
+ }
+
+
+ /*//////////////////////////////////////////////////////////////////////////
+ // Main player listener
+ //////////////////////////////////////////////////////////////////////////*/
+
+ private boolean onDoubleTapInMain(MotionEvent e) {
+ if (e.getX() > playerImpl.getRootView().getWidth() * 2 / 3) {
+ playerImpl.onFastForward();
+ } else if (e.getX() < playerImpl.getRootView().getWidth() / 3) {
+ playerImpl.onFastRewind();
+ } else {
+ playerImpl.getPlayPauseButton().performClick();
+ }
+
+ return true;
+ }
+
+
+ private boolean onSingleTapConfirmedInMain(MotionEvent e) {
+ if (DEBUG) Log.d(TAG, "onSingleTapConfirmed() called with: e = [" + e + "]");
+
+ if (playerImpl.getCurrentState() == BasePlayer.STATE_BLOCKED) return true;
+
+ if (playerImpl.isControlsVisible()) {
+ playerImpl.hideControls(150, 0);
+ } else {
+ if (playerImpl.getCurrentState() == BasePlayer.STATE_COMPLETED) {
+ playerImpl.showControls(0);
+ } else {
+ playerImpl.showControlsThenHide();
+ }
+ if (playerImpl.isInFullscreen()) {
+ int visibility = View.SYSTEM_UI_FLAG_LAYOUT_STABLE
+ | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
+ | View.SYSTEM_UI_FLAG_FULLSCREEN;
+ playerImpl.getParentActivity().getWindow().getDecorView().setSystemUiVisibility(visibility);
+ playerImpl.getParentActivity().getWindow().clearFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS);
+ playerImpl.getParentActivity().getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
+ }
+ }
+ return true;
+ }
+
+ private boolean onScrollInMain(MotionEvent initialEvent, MotionEvent movingEvent, float distanceX, float distanceY) {
+ if (!isVolumeGestureEnabled && !isBrightnessGestureEnabled) return false;
+
+ //noinspection PointlessBooleanExpression
+ if (DEBUG && false) Log.d(TAG, "MainVideoPlayer.onScroll = " +
+ ", e1.getRaw = [" + initialEvent.getRawX() + ", " + initialEvent.getRawY() + "]" +
+ ", e2.getRaw = [" + movingEvent.getRawX() + ", " + movingEvent.getRawY() + "]" +
+ ", distanceXy = [" + distanceX + ", " + distanceY + "]");
+
+ final boolean insideThreshold = Math.abs(movingEvent.getY() - initialEvent.getY()) <= MOVEMENT_THRESHOLD;
+ if (!isMovingInMain && (insideThreshold || Math.abs(distanceX) > Math.abs(distanceY))
+ || playerImpl.getCurrentState() == BasePlayer.STATE_COMPLETED) {
+ return false;
+ }
+
+ isMovingInMain = true;
+
+ boolean acceptAnyArea = isVolumeGestureEnabled != isBrightnessGestureEnabled;
+ boolean acceptVolumeArea = acceptAnyArea || initialEvent.getX() > playerImpl.getRootView().getWidth() / 2;
+ boolean acceptBrightnessArea = acceptAnyArea || !acceptVolumeArea;
+
+ if (isVolumeGestureEnabled && acceptVolumeArea) {
+ playerImpl.getVolumeProgressBar().incrementProgressBy((int) distanceY);
+ float currentProgressPercent =
+ (float) playerImpl.getVolumeProgressBar().getProgress() / playerImpl.getMaxGestureLength();
+ int currentVolume = (int) (maxVolume * currentProgressPercent);
+ playerImpl.getAudioReactor().setVolume(currentVolume);
+
+ if (DEBUG) Log.d(TAG, "onScroll().volumeControl, currentVolume = " + currentVolume);
+
+ final int resId =
+ currentProgressPercent <= 0 ? R.drawable.ic_volume_off_white_72dp
+ : currentProgressPercent < 0.25 ? R.drawable.ic_volume_mute_white_72dp
+ : currentProgressPercent < 0.75 ? R.drawable.ic_volume_down_white_72dp
+ : R.drawable.ic_volume_up_white_72dp;
+
+ playerImpl.getVolumeImageView().setImageDrawable(
+ AppCompatResources.getDrawable(service, resId)
+ );
+
+ if (playerImpl.getVolumeRelativeLayout().getVisibility() != View.VISIBLE) {
+ animateView(playerImpl.getVolumeRelativeLayout(), SCALE_AND_ALPHA, true, 200);
+ }
+ if (playerImpl.getBrightnessRelativeLayout().getVisibility() == View.VISIBLE) {
+ playerImpl.getBrightnessRelativeLayout().setVisibility(View.GONE);
+ }
+ } else if (isBrightnessGestureEnabled && acceptBrightnessArea) {
+ Activity parent = playerImpl.getParentActivity();
+ if (parent == null) return true;
+
+ Window window = parent.getWindow();
+
+ playerImpl.getBrightnessProgressBar().incrementProgressBy((int) distanceY);
+ float currentProgressPercent =
+ (float) playerImpl.getBrightnessProgressBar().getProgress() / playerImpl.getMaxGestureLength();
+ WindowManager.LayoutParams layoutParams = window.getAttributes();
+ layoutParams.screenBrightness = currentProgressPercent;
+ window.setAttributes(layoutParams);
+
+ if (DEBUG) Log.d(TAG, "onScroll().brightnessControl, currentBrightness = " + currentProgressPercent);
+
+ final int resId =
+ currentProgressPercent < 0.25 ? R.drawable.ic_brightness_low_white_72dp
+ : currentProgressPercent < 0.75 ? R.drawable.ic_brightness_medium_white_72dp
+ : R.drawable.ic_brightness_high_white_72dp;
+
+ playerImpl.getBrightnessImageView().setImageDrawable(
+ AppCompatResources.getDrawable(service, resId)
+ );
+
+ if (playerImpl.getBrightnessRelativeLayout().getVisibility() != View.VISIBLE) {
+ animateView(playerImpl.getBrightnessRelativeLayout(), SCALE_AND_ALPHA, true, 200);
+ }
+ if (playerImpl.getVolumeRelativeLayout().getVisibility() == View.VISIBLE) {
+ playerImpl.getVolumeRelativeLayout().setVisibility(View.GONE);
+ }
+ }
+ return true;
+ }
+
+ private void onScrollEndInMain() {
+ if (DEBUG) Log.d(TAG, "onScrollEnd() called");
+
+ if (playerImpl.getVolumeRelativeLayout().getVisibility() == View.VISIBLE) {
+ animateView(playerImpl.getVolumeRelativeLayout(), SCALE_AND_ALPHA, false, 200, 200);
+ }
+ if (playerImpl.getBrightnessRelativeLayout().getVisibility() == View.VISIBLE) {
+ animateView(playerImpl.getBrightnessRelativeLayout(), SCALE_AND_ALPHA, false, 200, 200);
+ }
+
+ if (playerImpl.isControlsVisible() && playerImpl.getCurrentState() == STATE_PLAYING) {
+ playerImpl.hideControls(DEFAULT_CONTROLS_DURATION, DEFAULT_CONTROLS_HIDE_TIME);
+ }
+ }
+
+ private boolean onTouchInMain(View v, MotionEvent event) {
+ playerImpl.getGestureDetector().onTouchEvent(event);
+ if (event.getAction() == MotionEvent.ACTION_UP && isMovingInMain) {
+ isMovingInMain = false;
+ onScrollEndInMain();
+ }
+ // This hack allows to stop receiving touch events on appbar while touching video player view
+ switch (event.getAction()) {
+ case MotionEvent.ACTION_DOWN:
+ case MotionEvent.ACTION_MOVE:
+ v.getParent().requestDisallowInterceptTouchEvent(playerImpl.isInFullscreen());
+ return true;
+ case MotionEvent.ACTION_UP:
+ v.getParent().requestDisallowInterceptTouchEvent(false);
+ return false;
+ default:
+ return true;
+ }
+ }
+
+ /*//////////////////////////////////////////////////////////////////////////
+ // Popup player listener
+ //////////////////////////////////////////////////////////////////////////*/
+
+ private boolean onDoubleTapInPopup(MotionEvent e) {
+ if (playerImpl == null || !playerImpl.isPlaying()) return false;
+
+ playerImpl.hideControls(0, 0);
+
+ if (e.getX() > playerImpl.getPopupWidth() / 2) {
+ playerImpl.onFastForward();
+ } else {
+ playerImpl.onFastRewind();
+ }
+
+ return true;
+ }
+
+ private boolean onSingleTapConfirmedInPopup(MotionEvent e) {
+ if (playerImpl == null || playerImpl.getPlayer() == null) return false;
+ if (playerImpl.isControlsVisible()) {
+ playerImpl.hideControls(100, 100);
+ } else {
+ playerImpl.showControlsThenHide();
+
+ }
+ playerImpl.onPlayPause();
+ return true;
+ }
+
+ private boolean onDownInPopup(MotionEvent e) {
+ // Fix popup position when the user touch it, it may have the wrong one
+ // because the soft input is visible (the draggable area is currently resized).
+ playerImpl.checkPopupPositionBounds(playerImpl.getCloseOverlayView().getWidth(), playerImpl.getCloseOverlayView().getHeight());
+
+ initialPopupX = playerImpl.getPopupLayoutParams().x;
+ initialPopupY = playerImpl.getPopupLayoutParams().y;
+ playerImpl.setPopupWidth(playerImpl.getPopupLayoutParams().width);
+ playerImpl.setPopupHeight(playerImpl.getPopupLayoutParams().height);
+ return super.onDown(e);
+ }
+
+ private void onLongPressInPopup(MotionEvent e) {
+ playerImpl.updateScreenSize();
+ playerImpl.checkPopupPositionBounds();
+ playerImpl.updatePopupSize((int) playerImpl.getScreenWidth(), -1);
+ }
+
+ private boolean onScrollInPopup(MotionEvent initialEvent, MotionEvent movingEvent, float distanceX, float distanceY) {
+ if (isResizing || playerImpl == null) return super.onScroll(initialEvent, movingEvent, distanceX, distanceY);
+
+ if (!isMovingInPopup) {
+ animateView(playerImpl.getCloseOverlayButton(), true, 200);
+ }
+
+ isMovingInPopup = true;
+
+ float diffX = (int) (movingEvent.getRawX() - initialEvent.getRawX()), posX = (int) (initialPopupX + diffX);
+ float diffY = (int) (movingEvent.getRawY() - initialEvent.getRawY()), posY = (int) (initialPopupY + diffY);
+
+ if (posX > (playerImpl.getScreenWidth() - playerImpl.getPopupWidth())) posX = (int) (playerImpl.getScreenWidth() - playerImpl.getPopupWidth());
+ else if (posX < 0) posX = 0;
+
+ if (posY > (playerImpl.getScreenHeight() - playerImpl.getPopupHeight())) posY = (int) (playerImpl.getScreenHeight() - playerImpl.getPopupHeight());
+ else if (posY < 0) posY = 0;
+
+ playerImpl.getPopupLayoutParams().x = (int) posX;
+ playerImpl.getPopupLayoutParams().y = (int) posY;
+
+ final View closingOverlayView = playerImpl.getClosingOverlayView();
+ if (playerImpl.isInsideClosingRadius(movingEvent)) {
+ if (closingOverlayView.getVisibility() == View.GONE) {
+ animateView(closingOverlayView, true, 250);
+ }
+ } else {
+ if (closingOverlayView.getVisibility() == View.VISIBLE) {
+ animateView(closingOverlayView, false, 0);
+ }
+ }
+
+ //noinspection PointlessBooleanExpression
+ if (DEBUG && false) {
+ Log.d(TAG, "PopupVideoPlayer.onScroll = " +
+ ", e1.getRaw = [" + initialEvent.getRawX() + ", " + initialEvent.getRawY() + "]" + ", e1.getX,Y = [" + initialEvent.getX() + ", " + initialEvent.getY() + "]" +
+ ", e2.getRaw = [" + movingEvent.getRawX() + ", " + movingEvent.getRawY() + "]" + ", e2.getX,Y = [" + movingEvent.getX() + ", " + movingEvent.getY() + "]" +
+ ", distanceX,Y = [" + distanceX + ", " + distanceY + "]" +
+ ", posX,Y = [" + posX + ", " + posY + "]" +
+ ", popupW,H = [" + playerImpl.getPopupWidth() + " x " + playerImpl.getPopupHeight() + "]");
+ }
+ playerImpl.windowManager.updateViewLayout(playerImpl.getRootView(), playerImpl.getPopupLayoutParams());
+ return true;
+ }
+
+ private void onScrollEndInPopup(MotionEvent event) {
+ if (playerImpl == null) return;
+ if (playerImpl.isControlsVisible() && playerImpl.getCurrentState() == STATE_PLAYING) {
+ playerImpl.hideControls(DEFAULT_CONTROLS_DURATION, DEFAULT_CONTROLS_HIDE_TIME);
+ }
+
+ if (playerImpl.isInsideClosingRadius(event)) {
+ playerImpl.closePopup();
+ } else {
+ animateView(playerImpl.getClosingOverlayView(), false, 0);
+
+ if (!playerImpl.isPopupClosing) {
+ animateView(playerImpl.getCloseOverlayButton(), false, 200);
+ }
+ }
+ }
+
+ private boolean onFlingInPopup(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
+ if (playerImpl == null) return false;
+
+ final float absVelocityX = Math.abs(velocityX);
+ final float absVelocityY = Math.abs(velocityY);
+ if (Math.max(absVelocityX, absVelocityY) > tossFlingVelocity) {
+ if (absVelocityX > tossFlingVelocity) playerImpl.getPopupLayoutParams().x = (int) velocityX;
+ if (absVelocityY > tossFlingVelocity) playerImpl.getPopupLayoutParams().y = (int) velocityY;
+ playerImpl.checkPopupPositionBounds();
+ playerImpl.windowManager.updateViewLayout(playerImpl.getRootView(), playerImpl.getPopupLayoutParams());
+ return true;
+ }
+ return false;
+ }
+
+ private boolean onTouchInPopup(View v, MotionEvent event) {
+ playerImpl.getGestureDetector().onTouchEvent(event);
+ if (playerImpl == null) return false;
+ if (event.getPointerCount() == 2 && !isMovingInPopup && !isResizing) {
+ if (DEBUG) Log.d(TAG, "onTouch() 2 finger pointer detected, enabling resizing.");
+ playerImpl.showAndAnimateControl(-1, true);
+ playerImpl.getLoadingPanel().setVisibility(View.GONE);
+
+ playerImpl.hideControls(0, 0);
+ animateView(playerImpl.getCurrentDisplaySeek(), false, 0, 0);
+ animateView(playerImpl.getResizingIndicator(), true, 200, 0);
+ isResizing = true;
+ }
+
+ if (event.getAction() == MotionEvent.ACTION_MOVE && !isMovingInPopup && isResizing) {
+ if (DEBUG) Log.d(TAG, "onTouch() ACTION_MOVE > v = [" + v + "], e1.getRaw = [" + event.getRawX() + ", " + event.getRawY() + "]");
+ return handleMultiDrag(event);
+ }
+
+ if (event.getAction() == MotionEvent.ACTION_UP) {
+ if (DEBUG)
+ Log.d(TAG, "onTouch() ACTION_UP > v = [" + v + "], e1.getRaw = [" + event.getRawX() + ", " + event.getRawY() + "]");
+ if (isMovingInPopup) {
+ isMovingInPopup = false;
+ onScrollEndInPopup(event);
+ }
+
+ if (isResizing) {
+ isResizing = false;
+ animateView(playerImpl.getResizingIndicator(), false, 100, 0);
+ playerImpl.changeState(playerImpl.getCurrentState());
+ }
+
+ if (!playerImpl.isPopupClosing) {
+ playerImpl.savePositionAndSize();
+ }
+ }
+
+ v.performClick();
+ return true;
+ }
+
+ private boolean handleMultiDrag(final MotionEvent event) {
+ if (event.getPointerCount() != 2) return false;
+
+ final float firstPointerX = event.getX(0);
+ final float secondPointerX = event.getX(1);
+
+ final float diff = Math.abs(firstPointerX - secondPointerX);
+ if (firstPointerX > secondPointerX) {
+ // second pointer is the anchor (the leftmost pointer)
+ playerImpl.getPopupLayoutParams().x = (int) (event.getRawX() - diff);
+ } else {
+ // first pointer is the anchor
+ playerImpl.getPopupLayoutParams().x = (int) event.getRawX();
+ }
+
+ playerImpl.checkPopupPositionBounds();
+ playerImpl.updateScreenSize();
+
+ final int width = (int) Math.min(playerImpl.getScreenWidth(), diff);
+ playerImpl.updatePopupSize(width, -1);
+
+ return true;
+ }
+
+}
+
+
diff --git a/app/src/main/java/org/schabi/newpipe/player/event/PlayerServiceEventListener.java b/app/src/main/java/org/schabi/newpipe/player/event/PlayerServiceEventListener.java
new file mode 100644
index 00000000000..7422f9442b6
--- /dev/null
+++ b/app/src/main/java/org/schabi/newpipe/player/event/PlayerServiceEventListener.java
@@ -0,0 +1,15 @@
+package org.schabi.newpipe.player.event;
+
+import com.google.android.exoplayer2.ExoPlaybackException;
+
+public interface PlayerServiceEventListener extends PlayerEventListener {
+ void onFullscreenStateChanged(boolean fullscreen);
+
+ void onMoreOptionsLongClicked();
+
+ void onPlayerError(ExoPlaybackException error);
+
+ boolean isFragmentStopped();
+
+ void hideSystemUIIfNeeded();
+}
\ No newline at end of file
diff --git a/app/src/main/java/org/schabi/newpipe/player/helper/PlaybackParameterDialog.java b/app/src/main/java/org/schabi/newpipe/player/helper/PlaybackParameterDialog.java
index 4feed74fee9..457b7212021 100644
--- a/app/src/main/java/org/schabi/newpipe/player/helper/PlaybackParameterDialog.java
+++ b/app/src/main/java/org/schabi/newpipe/player/helper/PlaybackParameterDialog.java
@@ -80,8 +80,10 @@ void onPlaybackParameterChanged(final float playbackTempo, final float playbackP
public static PlaybackParameterDialog newInstance(final double playbackTempo,
final double playbackPitch,
- final boolean playbackSkipSilence) {
+ final boolean playbackSkipSilence,
+ Callback callback) {
PlaybackParameterDialog dialog = new PlaybackParameterDialog();
+ dialog.callback = callback;
dialog.initialTempo = playbackTempo;
dialog.initialPitch = playbackPitch;
@@ -99,9 +101,9 @@ public static PlaybackParameterDialog newInstance(final double playbackTempo,
@Override
public void onAttach(Context context) {
super.onAttach(context);
- if (context != null && context instanceof Callback) {
+ if (context instanceof Callback) {
callback = (Callback) context;
- } else {
+ } else if (callback == null) {
dismiss();
}
}
diff --git a/app/src/main/java/org/schabi/newpipe/settings/SettingsContentObserver.java b/app/src/main/java/org/schabi/newpipe/settings/SettingsContentObserver.java
new file mode 100644
index 00000000000..534fb26c3a9
--- /dev/null
+++ b/app/src/main/java/org/schabi/newpipe/settings/SettingsContentObserver.java
@@ -0,0 +1,29 @@
+package org.schabi.newpipe.settings;
+
+import android.database.ContentObserver;
+import android.os.Handler;
+
+public class SettingsContentObserver extends ContentObserver {
+ private OnChangeListener listener;
+
+ public interface OnChangeListener {
+ void onSettingsChanged();
+ }
+
+ public SettingsContentObserver(Handler handler, OnChangeListener listener) {
+ super(handler);
+ this.listener = listener;
+ }
+
+ @Override
+ public boolean deliverSelfNotifications() {
+ return super.deliverSelfNotifications();
+ }
+
+ @Override
+ public void onChange(boolean selfChange) {
+ super.onChange(selfChange);
+ if (listener != null)
+ listener.onSettingsChanged();
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/org/schabi/newpipe/util/NavigationHelper.java b/app/src/main/java/org/schabi/newpipe/util/NavigationHelper.java
index e2b03c8e830..07ef0b6acfb 100644
--- a/app/src/main/java/org/schabi/newpipe/util/NavigationHelper.java
+++ b/app/src/main/java/org/schabi/newpipe/util/NavigationHelper.java
@@ -10,6 +10,7 @@
import android.preference.PreferenceManager;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentTransaction;
@@ -44,14 +45,9 @@
import org.schabi.newpipe.local.playlist.LocalPlaylistFragment;
import org.schabi.newpipe.local.subscription.SubscriptionFragment;
import org.schabi.newpipe.local.subscription.SubscriptionsImportFragment;
-import org.schabi.newpipe.player.BackgroundPlayer;
-import org.schabi.newpipe.player.BackgroundPlayerActivity;
-import org.schabi.newpipe.player.BasePlayer;
-import org.schabi.newpipe.player.MainVideoPlayer;
-import org.schabi.newpipe.player.PopupVideoPlayer;
-import org.schabi.newpipe.player.PopupVideoPlayerActivity;
-import org.schabi.newpipe.player.VideoPlayer;
+import org.schabi.newpipe.player.*;
import org.schabi.newpipe.player.playqueue.PlayQueue;
+import org.schabi.newpipe.player.playqueue.PlayQueueItem;
import org.schabi.newpipe.settings.SettingsActivity;
import java.util.ArrayList;
@@ -78,6 +74,9 @@ public static Intent getPlayerIntent(@NonNull final Context context,
if (quality != null) intent.putExtra(VideoPlayer.PLAYBACK_QUALITY, quality);
intent.putExtra(VideoPlayer.RESUME_PLAYBACK, resumePlayback);
+ int playerType = intent.getIntExtra(VideoPlayer.PLAYER_TYPE, VideoPlayer.PLAYER_TYPE_VIDEO);
+ intent.putExtra(VideoPlayer.PLAYER_TYPE, playerType);
+
return intent;
}
@@ -117,10 +116,13 @@ public static Intent getPlayerIntent(@NonNull final Context context,
.putExtra(BasePlayer.PLAYBACK_SKIP_SILENCE, playbackSkipSilence);
}
- public static void playOnMainPlayer(final Context context, final PlayQueue queue, final boolean resumePlayback) {
- final Intent playerIntent = getPlayerIntent(context, MainVideoPlayer.class, queue, resumePlayback);
- playerIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- context.startActivity(playerIntent);
+ public static void playOnMainPlayer(final AppCompatActivity activity, final PlayQueue queue, final boolean resumePlayback) {
+ playOnMainPlayer(activity.getSupportFragmentManager(), queue, resumePlayback);
+ }
+
+ public static void playOnMainPlayer(final FragmentManager fragmentManager, final PlayQueue queue, boolean autoPlay) {
+ PlayQueueItem currentStream = queue.getItem();
+ NavigationHelper.openVideoDetailFragment(fragmentManager, currentStream.getServiceId(), currentStream.getUrl(), currentStream.getTitle(), autoPlay, queue);
}
public static void playOnPopupPlayer(final Context context, final PlayQueue queue, final boolean resumePlayback) {
@@ -130,12 +132,16 @@ public static void playOnPopupPlayer(final Context context, final PlayQueue queu
}
Toast.makeText(context, R.string.popup_playing_toast, Toast.LENGTH_SHORT).show();
- startService(context, getPlayerIntent(context, PopupVideoPlayer.class, queue, resumePlayback));
+ Intent intent = getPlayerIntent(context, MainPlayer.class, queue, resumePlayback);
+ intent.putExtra(VideoPlayer.PLAYER_TYPE, VideoPlayer.PLAYER_TYPE_POPUP);
+ startService(context, intent);
}
public static void playOnBackgroundPlayer(final Context context, final PlayQueue queue, final boolean resumePlayback) {
Toast.makeText(context, R.string.background_player_playing_toast, Toast.LENGTH_SHORT).show();
- startService(context, getPlayerIntent(context, BackgroundPlayer.class, queue, resumePlayback));
+ Intent intent = getPlayerIntent(context, MainPlayer.class, queue, resumePlayback);
+ intent.putExtra(VideoPlayer.PLAYER_TYPE, VideoPlayer.PLAYER_TYPE_AUDIO);
+ startService(context, intent);
}
public static void enqueueOnPopupPlayer(final Context context, final PlayQueue queue, final boolean resumePlayback) {
@@ -149,8 +155,9 @@ public static void enqueueOnPopupPlayer(final Context context, final PlayQueue q
}
Toast.makeText(context, R.string.popup_playing_append, Toast.LENGTH_SHORT).show();
- startService(context,
- getPlayerEnqueueIntent(context, PopupVideoPlayer.class, queue, selectOnAppend, resumePlayback));
+ Intent intent = getPlayerEnqueueIntent(context, MainPlayer.class, queue, selectOnAppend, resumePlayback);
+ intent.putExtra(VideoPlayer.PLAYER_TYPE, VideoPlayer.PLAYER_TYPE_POPUP);
+ startService(context, intent);
}
public static void enqueueOnBackgroundPlayer(final Context context, final PlayQueue queue, final boolean resumePlayback) {
@@ -159,8 +166,9 @@ public static void enqueueOnBackgroundPlayer(final Context context, final PlayQu
public static void enqueueOnBackgroundPlayer(final Context context, final PlayQueue queue, boolean selectOnAppend, final boolean resumePlayback) {
Toast.makeText(context, R.string.background_player_append, Toast.LENGTH_SHORT).show();
- startService(context,
- getPlayerEnqueueIntent(context, BackgroundPlayer.class, queue, selectOnAppend, resumePlayback));
+ Intent intent = getPlayerEnqueueIntent(context, MainPlayer.class, queue, selectOnAppend, resumePlayback);
+ intent.putExtra(VideoPlayer.PLAYER_TYPE, VideoPlayer.PLAYER_TYPE_AUDIO);
+ startService(context, intent);
}
public static void startService(@NonNull final Context context, @NonNull final Intent intent) {
@@ -281,29 +289,35 @@ public static void openSearchFragment(FragmentManager fragmentManager,
}
public static void openVideoDetailFragment(FragmentManager fragmentManager, int serviceId, String url, String title) {
- openVideoDetailFragment(fragmentManager, serviceId, url, title, false);
+ openVideoDetailFragment(fragmentManager, serviceId, url, title, true, null);
}
- public static void openVideoDetailFragment(FragmentManager fragmentManager, int serviceId, String url, String title, boolean autoPlay) {
- Fragment fragment = fragmentManager.findFragmentById(R.id.fragment_holder);
+ public static void openVideoDetailFragment(FragmentManager fragmentManager, int serviceId, String url, String title, boolean autoPlay, PlayQueue playQueue) {
+ Fragment fragment = fragmentManager.findFragmentById(R.id.fragment_player_holder);
if (title == null) title = "";
if (fragment instanceof VideoDetailFragment && fragment.isVisible()) {
+ expandMainPlayer(fragment.getActivity());
VideoDetailFragment detailFragment = (VideoDetailFragment) fragment;
detailFragment.setAutoplay(autoPlay);
- detailFragment.selectAndLoadVideo(serviceId, url, title);
+ detailFragment.selectAndLoadVideo(serviceId, url, title, playQueue);
return;
}
- VideoDetailFragment instance = VideoDetailFragment.getInstance(serviceId, url, title);
+ VideoDetailFragment instance = VideoDetailFragment.getInstance(serviceId, url, title, playQueue);
instance.setAutoplay(autoPlay);
defaultTransaction(fragmentManager)
- .replace(R.id.fragment_holder, instance)
- .addToBackStack(null)
+ .replace(R.id.fragment_player_holder, instance)
+ .runOnCommit(() -> expandMainPlayer(instance.getActivity()))
.commit();
}
+ public static void expandMainPlayer(Context context) {
+ final Intent intent = new Intent(VideoDetailFragment.ACTION_SHOW_MAIN_PLAYER);
+ context.sendBroadcast(intent);
+ }
+
public static void openChannelFragment(
FragmentManager fragmentManager,
int serviceId,
@@ -458,10 +472,6 @@ public static Intent getBackgroundPlayerActivityIntent(final Context context) {
return getServicePlayerActivityIntent(context, BackgroundPlayerActivity.class);
}
- public static Intent getPopupPlayerActivityIntent(final Context context) {
- return getServicePlayerActivityIntent(context, PopupVideoPlayerActivity.class);
- }
-
private static Intent getServicePlayerActivityIntent(final Context context,
final Class activityClass) {
Intent intent = new Intent(context, activityClass);
diff --git a/app/src/main/java/org/schabi/newpipe/util/ShareUtils.java b/app/src/main/java/org/schabi/newpipe/util/ShareUtils.java
index c5c78a726bd..17768cd08c9 100644
--- a/app/src/main/java/org/schabi/newpipe/util/ShareUtils.java
+++ b/app/src/main/java/org/schabi/newpipe/util/ShareUtils.java
@@ -17,6 +17,6 @@ public static void shareUrl(Context context, String subject, String url) {
intent.setType("text/plain");
intent.putExtra(Intent.EXTRA_SUBJECT, subject);
intent.putExtra(Intent.EXTRA_TEXT, url);
- context.startActivity(Intent.createChooser(intent, context.getString(R.string.share_dialog_title)));
+ context.startActivity(Intent.createChooser(intent, context.getString(R.string.share_dialog_title)).setFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
}
}
diff --git a/app/src/main/res/layout-large-land/activity_main_player.xml b/app/src/main/res/layout-large-land/activity_main_player.xml
index b535db2b890..cbcc6eeb054 100644
--- a/app/src/main/res/layout-large-land/activity_main_player.xml
+++ b/app/src/main/res/layout-large-land/activity_main_player.xml
@@ -2,9 +2,10 @@
@@ -120,7 +121,7 @@
android:layout_height="match_parent"
android:layout_below="@id/playQueueControl"
android:scrollbars="vertical"
- app:layoutManager="LinearLayoutManager"
+ app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
tools:listitem="@layout/play_queue_item"/>
@@ -133,37 +134,46 @@
android:visibility="gone"
tools:visibility="visible">
+
-
+
+
+ tools:ignore="RtlHardcoded"
+ android:layout_weight="1">
+ tools:text="1x"/>
+ tools:ignore="ContentDescription,RtlHardcoded"
+ android:visibility="gone"/>
-
-
+
+
@@ -274,9 +284,7 @@
android:id="@+id/resizeTextView"
android:layout_width="wrap_content"
android:layout_height="35dp"
- android:layout_marginLeft="8dp"
android:layout_marginRight="8dp"
- android:layout_alignParentLeft="true"
android:gravity="center"
android:minWidth="50dp"
android:textColor="@android:color/white"
@@ -291,86 +299,85 @@
android:layout_height="wrap_content"
android:layout_marginLeft="8dp"
android:layout_marginRight="8dp"
- android:layout_toLeftOf="@id/switchBackground"
- android:layout_toRightOf="@id/resizeTextView"
android:gravity="center|left"
android:minHeight="35dp"
- android:minWidth="40dp"
- android:paddingLeft="2dp"
- android:paddingRight="2dp"
+ android:minWidth="50dp"
android:textColor="@android:color/white"
android:textStyle="bold"
android:background="?attr/selectableItemBackground"
tools:ignore="RelativeOverlap,RtlHardcoded"
- tools:text="English" />
+ tools:text="English"/>
+
+
+
+
+
+
-
+ android:scaleType="fitCenter"
+ android:src="@drawable/ic_fullscreen_white"
+ tools:ignore="ContentDescription,RtlHardcoded"
+ android:visibility="gone"
+ tools:visibility="visible"/>
@@ -388,7 +396,7 @@
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:gravity="center"
- android:minHeight="40dp"
+ android:minHeight="30dp"
android:text="-:--:--"
android:textColor="@android:color/white"
tools:ignore="HardcodedText"
@@ -433,65 +441,52 @@
+
+
+
+
-
+
@@ -533,10 +528,7 @@
+
+
+
+
+
+
diff --git a/app/src/main/res/layout-large-land/fragment_video_detail.xml b/app/src/main/res/layout-large-land/fragment_video_detail.xml
index 02b0a7b8646..266133a8c44 100644
--- a/app/src/main/res/layout-large-land/fragment_video_detail.xml
+++ b/app/src/main/res/layout-large-land/fragment_video_detail.xml
@@ -1,7 +1,12 @@
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -153,7 +189,6 @@
android:id="@+id/detail_content_root_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:background="?android:windowBackground"
app:layout_scrollFlags="scroll">
@@ -506,26 +541,6 @@
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml
index 92e73234f27..46b88873c0b 100644
--- a/app/src/main/res/layout/activity_main.xml
+++ b/app/src/main/res/layout/activity_main.xml
@@ -2,6 +2,7 @@
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/activity_main_player.xml b/app/src/main/res/layout/activity_main_player.xml
index f2b204b7508..6bc259b8839 100644
--- a/app/src/main/res/layout/activity_main_player.xml
+++ b/app/src/main/res/layout/activity_main_player.xml
@@ -2,9 +2,10 @@
@@ -131,37 +132,46 @@
android:visibility="gone"
tools:visibility="visible">
+
-
+
+
+ tools:ignore="RtlHardcoded"
+ android:layout_weight="1">
+ tools:text="1x"/>
+ tools:ignore="ContentDescription,RtlHardcoded"
+ android:visibility="gone"/>
-
-
+
+
@@ -272,9 +282,7 @@
android:id="@+id/resizeTextView"
android:layout_width="wrap_content"
android:layout_height="35dp"
- android:layout_marginLeft="8dp"
android:layout_marginRight="8dp"
- android:layout_alignParentLeft="true"
android:gravity="center"
android:minWidth="50dp"
android:textColor="@android:color/white"
@@ -289,86 +297,85 @@
android:layout_height="wrap_content"
android:layout_marginLeft="8dp"
android:layout_marginRight="8dp"
- android:layout_toLeftOf="@id/switchBackground"
- android:layout_toRightOf="@id/resizeTextView"
android:gravity="center|left"
android:minHeight="35dp"
- android:minWidth="40dp"
- android:paddingLeft="2dp"
- android:paddingRight="2dp"
+ android:minWidth="50dp"
android:textColor="@android:color/white"
android:textStyle="bold"
android:background="?attr/selectableItemBackground"
tools:ignore="RelativeOverlap,RtlHardcoded"
- tools:text="English" />
+ tools:text="English"/>
+
+
+
+
+
+
-
+ android:scaleType="fitCenter"
+ android:src="@drawable/ic_fullscreen_white"
+ tools:ignore="ContentDescription,RtlHardcoded"
+ android:visibility="gone"
+ tools:visibility="visible"/>
@@ -386,7 +394,7 @@
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:gravity="center"
- android:minHeight="40dp"
+ android:minHeight="30dp"
android:text="-:--:--"
android:textColor="@android:color/white"
tools:ignore="HardcodedText"
@@ -431,65 +439,52 @@
+
+
+
+
-
+
@@ -531,10 +526,7 @@
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/fragment_video_detail.xml b/app/src/main/res/layout/fragment_video_detail.xml
index cc57e09d4b3..5e8d1658940 100644
--- a/app/src/main/res/layout/fragment_video_detail.xml
+++ b/app/src/main/res/layout/fragment_video_detail.xml
@@ -5,13 +5,44 @@
android:id="@+id/video_item_detail"
android:layout_width="match_parent"
android:layout_height="match_parent"
+ android:background="?attr/windowBackground"
android:focusableInTouchMode="true">
+ android:layout_height="wrap_content">
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -149,7 +187,6 @@
android:id="@+id/detail_content_root_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:background="?android:windowBackground"
app:layout_scrollFlags="scroll">
@@ -504,25 +541,106 @@
+
-
-
-
-
+
+
+
+
-
-
+ android:layout_height="60dp"
+ android:gravity="center_vertical"
+ android:orientation="vertical"
+ android:paddingLeft="@dimen/video_item_search_padding"
+ android:paddingRight="@dimen/video_item_search_padding"
+ android:clickable="true"
+ android:focusable="true"
+ android:layout_toEndOf="@+id/overlay_thumbnail"
+ android:layout_toStartOf="@+id/overlay_buttons_layout"
+ tools:ignore="RtlHardcoded">
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
diff --git a/app/src/main/res/menu/menu_play_queue_bg.xml b/app/src/main/res/menu/menu_play_queue_bg.xml
index 1a3ed0e5ac0..92f5ae67b5a 100644
--- a/app/src/main/res/menu/menu_play_queue_bg.xml
+++ b/app/src/main/res/menu/menu_play_queue_bg.xml
@@ -7,4 +7,9 @@
android:orderInCategory="1999"
android:title="@string/switch_to_popup"
app:showAsAction="never"/>
+
+
diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml
index 582c4bade2d..07b71e5ee82 100644
--- a/app/src/main/res/values/dimens.xml
+++ b/app/src/main/res/values/dimens.xml
@@ -48,6 +48,7 @@
18sp
18sp
70dp
+ 60dp
5dp
50dp
diff --git a/app/src/main/res/xml/history_settings.xml b/app/src/main/res/xml/history_settings.xml
index 81dc195f35e..6d64f248956 100644
--- a/app/src/main/res/xml/history_settings.xml
+++ b/app/src/main/res/xml/history_settings.xml
@@ -21,7 +21,6 @@
Date: Tue, 31 Dec 2019 05:07:07 +0300
Subject: [PATCH 002/398] Optimizations and fixes of rare situations - popup
after orientation change had incorrect allowed bounds for swiping - popup
could cause a crash after many quick switches to main player and back -
better method of setting fullscreen/non-fullscreen layout using thumbnail
view. Also fixed thumbnail height in fullscreen layout - global settings
observer didn't work when a user closed a service manually via notification
because it checked for service existing - app will now exits from fullscreen
mode when the user switches players - playQueuePanel has visibility "gone" by
default (not "invisible") because "invisible" can cause problems
---
.../fragments/detail/VideoDetailFragment.java | 32 +++++++++----------
.../newpipe/player/VideoPlayerImpl.java | 4 +--
.../player/event/PlayerGestureListener.java | 3 +-
.../activity_main_player.xml | 2 +-
.../main/res/layout/activity_main_player.xml | 2 +-
5 files changed, 22 insertions(+), 21 deletions(-)
diff --git a/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java
index bae6e57aaa1..245a9a495df 100644
--- a/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java
+++ b/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java
@@ -1040,6 +1040,9 @@ private void openBackgroundPlayer(final boolean append) {
boolean useExternalAudioPlayer = PreferenceManager.getDefaultSharedPreferences(activity)
.getBoolean(activity.getString(R.string.use_external_audio_player_key), false);
+ // If a user watched video inside fullscreen mode and than chose another player return to non-fullscreen mode
+ if (player != null && player.isInFullscreen()) player.toggleFullscreen();
+
if (!useExternalAudioPlayer && android.os.Build.VERSION.SDK_INT >= 16) {
openNormalBackgroundPlayer(append);
} else {
@@ -1056,6 +1059,9 @@ private void openPopupPlayer(final boolean append) {
// See UI changes while remote playQueue changes
if (!bounded) startService(false);
+ // If a user watched video inside fullscreen mode and than chose another player return to non-fullscreen mode
+ if (player != null && player.isInFullscreen()) player.toggleFullscreen();
+
PlayQueue queue = setupPlayQueueForIntent(append);
if (append) {
NavigationHelper.enqueueOnPopupPlayer(activity, queue, false);
@@ -1181,17 +1187,7 @@ private void addVideoPlayerView() {
// Check if viewHolder already contains a child
if (player.getRootView() != viewHolder) removeVideoPlayerView();
-
- final int newHeight;
- if (player.isInFullscreen())
- newHeight = activity.getWindow().getDecorView().getHeight();
- else
- newHeight = FrameLayout.LayoutParams.MATCH_PARENT;
-
- if (viewHolder.getLayoutParams().height != newHeight) {
- viewHolder.getLayoutParams().height = newHeight;
- viewHolder.requestLayout();
- }
+ setHeightThumbnail();
// Prevent from re-adding a view multiple times
if (player.getRootView().getParent() == null) viewHolder.addView(player.getRootView());
@@ -1242,9 +1238,15 @@ private void prepareDescription(final String descriptionHtml) {
private void setHeightThumbnail() {
final DisplayMetrics metrics = getResources().getDisplayMetrics();
boolean isPortrait = metrics.heightPixels > metrics.widthPixels;
- int height = isPortrait
- ? (int) (metrics.widthPixels / (16.0f / 9.0f))
- : (int) (metrics.heightPixels / 2f);
+
+ int height;
+ if (player != null && player.isInFullscreen())
+ height = activity.getWindow().getDecorView().getHeight();
+ else
+ height = isPortrait
+ ? (int) (metrics.widthPixels / (16.0f / 9.0f))
+ : (int) (metrics.heightPixels / 2f);;
+
thumbnailImageView.setLayoutParams(
new FrameLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, height));
thumbnailImageView.setMinimumHeight(height);
@@ -1334,8 +1336,6 @@ private void setupOrientation() {
@Override
public void onSettingsChanged() {
- if (player == null) return;
-
if(!globalScreenOrientationLocked())
getActivity().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
}
diff --git a/app/src/main/java/org/schabi/newpipe/player/VideoPlayerImpl.java b/app/src/main/java/org/schabi/newpipe/player/VideoPlayerImpl.java
index 8cef5b4539f..492fd9ac5e3 100644
--- a/app/src/main/java/org/schabi/newpipe/player/VideoPlayerImpl.java
+++ b/app/src/main/java/org/schabi/newpipe/player/VideoPlayerImpl.java
@@ -1329,7 +1329,7 @@ public void updateScreenSize() {
public void updatePopupSize(int width, int height) {
if (DEBUG) Log.d(TAG, "updatePopupSize() called with: width = [" + width + "], height = [" + height + "]");
- if (popupLayoutParams == null || windowManager == null || !popupPlayerSelected() || getRootView().getParent() == null)
+ if (popupLayoutParams == null || windowManager == null || getParentActivity() != null || getRootView().getParent() == null)
return;
width = (int) (width > maximumWidth ? maximumWidth : width < minimumWidth ? minimumWidth : width);
@@ -1347,7 +1347,7 @@ public void updatePopupSize(int width, int height) {
}
private void updateWindowFlags(final int flags) {
- if (popupLayoutParams == null || windowManager == null || !popupPlayerSelected() || getRootView().getParent() == null)
+ if (popupLayoutParams == null || windowManager == null || getParentActivity() != null || getRootView().getParent() == null)
return;
popupLayoutParams.flags = flags;
diff --git a/app/src/main/java/org/schabi/newpipe/player/event/PlayerGestureListener.java b/app/src/main/java/org/schabi/newpipe/player/event/PlayerGestureListener.java
index 72462beffcb..398cf95349e 100644
--- a/app/src/main/java/org/schabi/newpipe/player/event/PlayerGestureListener.java
+++ b/app/src/main/java/org/schabi/newpipe/player/event/PlayerGestureListener.java
@@ -299,7 +299,8 @@ private boolean onSingleTapConfirmedInPopup(MotionEvent e) {
private boolean onDownInPopup(MotionEvent e) {
// Fix popup position when the user touch it, it may have the wrong one
// because the soft input is visible (the draggable area is currently resized).
- playerImpl.checkPopupPositionBounds(playerImpl.getCloseOverlayView().getWidth(), playerImpl.getCloseOverlayView().getHeight());
+ playerImpl.updateScreenSize();
+ playerImpl.checkPopupPositionBounds();
initialPopupX = playerImpl.getPopupLayoutParams().x;
initialPopupY = playerImpl.getPopupLayoutParams().y;
diff --git a/app/src/main/res/layout-large-land/activity_main_player.xml b/app/src/main/res/layout-large-land/activity_main_player.xml
index cbcc6eeb054..0e2011910df 100644
--- a/app/src/main/res/layout-large-land/activity_main_player.xml
+++ b/app/src/main/res/layout-large-land/activity_main_player.xml
@@ -53,7 +53,7 @@
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:layout_height="match_parent"
- android:visibility="invisible"
+ android:visibility="gone"
android:background="?attr/queue_background_color"
tools:visibility="visible">
diff --git a/app/src/main/res/layout/activity_main_player.xml b/app/src/main/res/layout/activity_main_player.xml
index 6bc259b8839..39c3f4410ce 100644
--- a/app/src/main/res/layout/activity_main_player.xml
+++ b/app/src/main/res/layout/activity_main_player.xml
@@ -51,7 +51,7 @@
android:id="@+id/playQueuePanel"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:visibility="invisible"
+ android:visibility="gone"
android:background="?attr/queue_background_color"
tools:visibility="visible">
From bc2dc8d933181aca8f9ea62d0d2f102577286e78 Mon Sep 17 00:00:00 2001
From: Avently <7953703+avently@users.noreply.github.com>
Date: Tue, 31 Dec 2019 19:06:39 +0300
Subject: [PATCH 003/398] First block of fixes for review - popup player click
event changed to show/hide buttons - queue panel WORKS. Finally - removed
theme overriding in fragment - added scroll to top after stream selection -
adjusted padding/margin of buttons in player - player will itself in
fullscreen after user hides it in fullscreen mode and then expands it again
while video still playing
---
.../material/appbar/FlingBehavior.java | 42 +++++++++---
.../fragments/detail/VideoDetailFragment.java | 11 +++-
.../newpipe/player/VideoPlayerImpl.java | 6 +-
.../player/event/PlayerGestureListener.java | 1 -
.../schabi/newpipe/util/NavigationHelper.java | 1 +
.../activity_main_player.xml | 66 +++++++++----------
.../main/res/layout/activity_main_player.xml | 66 +++++++++----------
7 files changed, 109 insertions(+), 84 deletions(-)
diff --git a/app/src/main/java/com/google/android/material/appbar/FlingBehavior.java b/app/src/main/java/com/google/android/material/appbar/FlingBehavior.java
index 4a2662f5384..ff2860558fd 100644
--- a/app/src/main/java/com/google/android/material/appbar/FlingBehavior.java
+++ b/app/src/main/java/com/google/android/material/appbar/FlingBehavior.java
@@ -1,12 +1,17 @@
package com.google.android.material.appbar;
import android.content.Context;
+import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewGroup;
import android.widget.OverScroller;
import androidx.annotation.Nullable;
import androidx.coordinatorlayout.widget.CoordinatorLayout;
+import org.jetbrains.annotations.NotNull;
+import org.schabi.newpipe.R;
import java.lang.reflect.Field;
@@ -17,21 +22,40 @@ public FlingBehavior(Context context, AttributeSet attrs) {
super(context, attrs);
}
+ private boolean allowScroll = true;
+ private Rect playQueueRect = new Rect();
+
@Override
public boolean onInterceptTouchEvent(CoordinatorLayout parent, AppBarLayout child, MotionEvent ev) {
- switch (ev.getActionMasked()) {
- case MotionEvent.ACTION_DOWN:
- // remove reference to old nested scrolling child
- resetNestedScrollingChild();
- // Stop fling when your finger touches the screen
- stopAppBarLayoutFling();
- break;
- default:
- break;
+ ViewGroup playQueue = child.findViewById(R.id.playQueue);
+ if (playQueue != null) {
+ playQueue.getGlobalVisibleRect(playQueueRect);
+ if (playQueueRect.contains((int) ev.getX(), (int) ev.getY())) {
+ allowScroll = false;
+ return false;
+ }
+ }
+ allowScroll = true;
+
+ if (ev.getActionMasked() == MotionEvent.ACTION_DOWN) {
+ // remove reference to old nested scrolling child
+ resetNestedScrollingChild();
+ // Stop fling when your finger touches the screen
+ stopAppBarLayoutFling();
}
return super.onInterceptTouchEvent(parent, child, ev);
}
+ @Override
+ public boolean onStartNestedScroll(CoordinatorLayout parent, AppBarLayout child, View directTargetChild, View target, int nestedScrollAxes, int type) {
+ return allowScroll && super.onStartNestedScroll(parent, child, directTargetChild, target, nestedScrollAxes, type);
+ }
+
+ @Override
+ public boolean onNestedFling(@NotNull CoordinatorLayout coordinatorLayout, @NotNull AppBarLayout child, @NotNull View target, float velocityX, float velocityY, boolean consumed) {
+ return allowScroll && super.onNestedFling(coordinatorLayout, child, target, velocityX, velocityY, consumed);
+ }
+
@Nullable
private OverScroller getScrollerField() {
try {
diff --git a/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java
index 245a9a495df..d0ca95d6b3b 100644
--- a/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java
+++ b/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java
@@ -311,7 +311,6 @@ public static VideoDetailFragment getInstance(int serviceId, String videoUrl, St
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
- ThemeHelper.setTheme(getContext());
// Let's play all streams automatically
setAutoplay(true);
@@ -953,14 +952,14 @@ public void prepareAndHandleInfo(final StreamInfo info, boolean scrollToTop) {
showLoading();
initTabs();
- if (scrollToTop) appBarLayout.setExpanded(true, true);
+ if (scrollToTop) scrollToTop();
handleResult(info);
showContent();
}
protected void prepareAndLoadInfo() {
- appBarLayout.setExpanded(true, true);
+ scrollToTop();
startLoading(false);
}
@@ -1029,6 +1028,10 @@ private boolean shouldShowComments() {
}
}
+ public void scrollToTop() {
+ appBarLayout.setExpanded(true, true);
+ }
+
/*//////////////////////////////////////////////////////////////////////////
// Play Utils
//////////////////////////////////////////////////////////////////////////*/
@@ -1862,6 +1865,8 @@ else if (bottomSheetState == BottomSheetBehavior.STATE_EXPANDED)
// Disable click because overlay buttons located on top of buttons from the player
setOverlayElementsClickable(false);
hideSystemUIIfNeeded();
+ if (isLandscape() && player != null && player.isPlaying() && !player.isInFullscreen())
+ player.toggleFullscreen();
break;
case BottomSheetBehavior.STATE_COLLAPSED:
// Re-enable clicks
diff --git a/app/src/main/java/org/schabi/newpipe/player/VideoPlayerImpl.java b/app/src/main/java/org/schabi/newpipe/player/VideoPlayerImpl.java
index 492fd9ac5e3..71fe21b6d40 100644
--- a/app/src/main/java/org/schabi/newpipe/player/VideoPlayerImpl.java
+++ b/app/src/main/java/org/schabi/newpipe/player/VideoPlayerImpl.java
@@ -346,7 +346,8 @@ public void initListeners() {
// Use smaller value to be consistent between screen orientations
// (and to make usage easier)
int width = r - l, height = b - t;
- maxGestureLength = (int) (Math.min(width, height) * MAX_GESTURE_LENGTH);
+ int min = Math.min(width, height);
+ maxGestureLength = (int) (min * MAX_GESTURE_LENGTH);
if (DEBUG) Log.d(TAG, "maxGestureLength = " + maxGestureLength);
@@ -354,6 +355,7 @@ public void initListeners() {
brightnessProgressBar.setMax(maxGestureLength);
setInitialGestureValues();
+ queueLayout.getLayoutParams().height = min - queueLayout.getTop();
}
});
}
@@ -620,8 +622,6 @@ private void onQueueClicked() {
DEFAULT_CONTROLS_DURATION);
itemsList.scrollToPosition(playQueue.getIndex());
-
- if (playQueue.getStreams().size() > 4 && !isInFullscreen()) toggleFullscreen();
}
private void onQueueClosed() {
diff --git a/app/src/main/java/org/schabi/newpipe/player/event/PlayerGestureListener.java b/app/src/main/java/org/schabi/newpipe/player/event/PlayerGestureListener.java
index 398cf95349e..00a511ca361 100644
--- a/app/src/main/java/org/schabi/newpipe/player/event/PlayerGestureListener.java
+++ b/app/src/main/java/org/schabi/newpipe/player/event/PlayerGestureListener.java
@@ -292,7 +292,6 @@ private boolean onSingleTapConfirmedInPopup(MotionEvent e) {
playerImpl.showControlsThenHide();
}
- playerImpl.onPlayPause();
return true;
}
diff --git a/app/src/main/java/org/schabi/newpipe/util/NavigationHelper.java b/app/src/main/java/org/schabi/newpipe/util/NavigationHelper.java
index 07ef0b6acfb..648894cc1d7 100644
--- a/app/src/main/java/org/schabi/newpipe/util/NavigationHelper.java
+++ b/app/src/main/java/org/schabi/newpipe/util/NavigationHelper.java
@@ -301,6 +301,7 @@ public static void openVideoDetailFragment(FragmentManager fragmentManager, int
VideoDetailFragment detailFragment = (VideoDetailFragment) fragment;
detailFragment.setAutoplay(autoPlay);
detailFragment.selectAndLoadVideo(serviceId, url, title, playQueue);
+ detailFragment.scrollToTop();
return;
}
diff --git a/app/src/main/res/layout-large-land/activity_main_player.xml b/app/src/main/res/layout-large-land/activity_main_player.xml
index 0e2011910df..8d7d9b6398a 100644
--- a/app/src/main/res/layout-large-land/activity_main_player.xml
+++ b/app/src/main/res/layout-large-land/activity_main_player.xml
@@ -149,6 +149,7 @@
android:background="@drawable/player_top_controls_bg"
android:orientation="vertical"
android:gravity="top"
+ android:paddingTop="4dp"
android:baselineAligned="false"
android:layout_toStartOf="@id/fullScreenButton">
@@ -158,7 +159,6 @@
android:layout_height="wrap_content"
android:baselineAligned="false"
android:gravity="top"
- android:paddingTop="4dp"
android:paddingBottom="7dp"
android:paddingLeft="2dp"
android:paddingRight="6dp"
@@ -170,7 +170,8 @@
android:layout_height="wrap_content"
android:gravity="top"
android:orientation="vertical"
- android:paddingLeft="8dp"
+ android:paddingTop="6dp"
+ android:paddingLeft="16dp"
android:paddingRight="8dp"
tools:ignore="RtlHardcoded"
android:layout_weight="1">
@@ -212,8 +213,9 @@
android:id="@+id/qualityTextView"
android:layout_width="wrap_content"
android:layout_height="35dp"
- android:layout_marginLeft="2dp"
- android:layout_marginRight="2dp"
+ android:padding="6dp"
+ android:layout_marginStart="5dp"
+ android:layout_marginEnd="8dp"
android:gravity="center"
android:minWidth="50dp"
android:text="720p"
@@ -227,7 +229,8 @@
android:id="@+id/playbackSpeed"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_marginRight="2dp"
+ android:padding="6dp"
+ android:layout_marginEnd="8dp"
android:gravity="center"
android:minHeight="35dp"
android:minWidth="40dp"
@@ -241,11 +244,10 @@
android:id="@+id/queueButton"
android:layout_width="30dp"
android:layout_height="35dp"
- android:layout_marginLeft="2dp"
- android:layout_marginRight="2dp"
+ android:padding="6dp"
+ android:layout_marginEnd="8dp"
android:clickable="true"
android:focusable="true"
- android:padding="5dp"
android:scaleType="fitXY"
android:src="@drawable/ic_list_white_24dp"
android:background="?attr/selectableItemBackground"
@@ -256,8 +258,8 @@
android:id="@+id/moreOptionsButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_marginLeft="2dp"
- android:padding="5dp"
+ android:padding="8dp"
+ android:layout_marginEnd="8dp"
android:clickable="true"
android:focusable="true"
android:scaleType="fitXY"
@@ -272,9 +274,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="top"
- android:paddingTop="4dp"
- android:paddingBottom="7dp"
- android:paddingStart="6dp"
+ android:paddingStart="16dp"
android:paddingEnd="6dp"
android:visibility="invisible"
tools:ignore="RtlHardcoded"
@@ -284,7 +284,8 @@
android:id="@+id/resizeTextView"
android:layout_width="wrap_content"
android:layout_height="35dp"
- android:layout_marginRight="8dp"
+ android:padding="6dp"
+ android:layout_marginEnd="8dp"
android:gravity="center"
android:minWidth="50dp"
android:textColor="@android:color/white"
@@ -297,8 +298,8 @@
android:id="@+id/captionTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_marginLeft="8dp"
- android:layout_marginRight="8dp"
+ android:padding="6dp"
+ android:layout_marginEnd="8dp"
android:gravity="center|left"
android:minHeight="35dp"
android:minWidth="50dp"
@@ -316,13 +317,12 @@
diff --git a/app/src/main/res/layout/activity_main_player.xml b/app/src/main/res/layout/activity_main_player.xml
index 39c3f4410ce..8d00142a899 100644
--- a/app/src/main/res/layout/activity_main_player.xml
+++ b/app/src/main/res/layout/activity_main_player.xml
@@ -147,6 +147,7 @@
android:background="@drawable/player_top_controls_bg"
android:orientation="vertical"
android:gravity="top"
+ android:paddingTop="4dp"
android:baselineAligned="false"
android:layout_toStartOf="@id/fullScreenButton">
@@ -156,7 +157,6 @@
android:layout_height="wrap_content"
android:baselineAligned="false"
android:gravity="top"
- android:paddingTop="4dp"
android:paddingBottom="7dp"
android:paddingLeft="2dp"
android:paddingRight="6dp"
@@ -168,7 +168,8 @@
android:layout_height="wrap_content"
android:gravity="top"
android:orientation="vertical"
- android:paddingLeft="8dp"
+ android:paddingTop="6dp"
+ android:paddingLeft="16dp"
android:paddingRight="8dp"
tools:ignore="RtlHardcoded"
android:layout_weight="1">
@@ -210,8 +211,9 @@
android:id="@+id/qualityTextView"
android:layout_width="wrap_content"
android:layout_height="35dp"
- android:layout_marginLeft="2dp"
- android:layout_marginRight="2dp"
+ android:padding="6dp"
+ android:layout_marginStart="5dp"
+ android:layout_marginEnd="8dp"
android:gravity="center"
android:minWidth="50dp"
android:text="720p"
@@ -225,7 +227,8 @@
android:id="@+id/playbackSpeed"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_marginRight="2dp"
+ android:padding="6dp"
+ android:layout_marginEnd="8dp"
android:gravity="center"
android:minHeight="35dp"
android:minWidth="40dp"
@@ -239,11 +242,10 @@
android:id="@+id/queueButton"
android:layout_width="30dp"
android:layout_height="35dp"
- android:layout_marginLeft="2dp"
- android:layout_marginRight="2dp"
+ android:padding="6dp"
+ android:layout_marginEnd="8dp"
android:clickable="true"
android:focusable="true"
- android:padding="5dp"
android:scaleType="fitXY"
android:src="@drawable/ic_list_white_24dp"
android:background="?attr/selectableItemBackground"
@@ -254,8 +256,8 @@
android:id="@+id/moreOptionsButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_marginLeft="2dp"
- android:padding="5dp"
+ android:padding="8dp"
+ android:layout_marginEnd="8dp"
android:clickable="true"
android:focusable="true"
android:scaleType="fitXY"
@@ -270,9 +272,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="top"
- android:paddingTop="4dp"
- android:paddingBottom="7dp"
- android:paddingStart="6dp"
+ android:paddingStart="16dp"
android:paddingEnd="6dp"
android:visibility="invisible"
tools:ignore="RtlHardcoded"
@@ -282,7 +282,8 @@
android:id="@+id/resizeTextView"
android:layout_width="wrap_content"
android:layout_height="35dp"
- android:layout_marginRight="8dp"
+ android:padding="6dp"
+ android:layout_marginEnd="8dp"
android:gravity="center"
android:minWidth="50dp"
android:textColor="@android:color/white"
@@ -295,8 +296,8 @@
android:id="@+id/captionTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_marginLeft="8dp"
- android:layout_marginRight="8dp"
+ android:padding="6dp"
+ android:layout_marginEnd="8dp"
android:gravity="center|left"
android:minHeight="35dp"
android:minWidth="50dp"
@@ -314,13 +315,12 @@
From 4519dd010dcc8ac8791d97046363481d9afebe72 Mon Sep 17 00:00:00 2001
From: Avently <7953703+avently@users.noreply.github.com>
Date: Fri, 3 Jan 2020 08:05:31 +0300
Subject: [PATCH 004/398] Second block of fixes for review - hide/show controls
with respect of SystemUI. In fullscreen mode controls will stay away from
NavigationBar - notification from running service will be hidden if a user
disabled background playback - fixed incorrect handling of a system method in
API 19 - better MultiWindow support
---
.../fragments/detail/VideoDetailFragment.java | 28 ++++++------
.../org/schabi/newpipe/player/MainPlayer.java | 7 ++-
.../schabi/newpipe/player/VideoPlayer.java | 10 ++---
.../newpipe/player/VideoPlayerImpl.java | 45 ++++++++++++++++---
.../event/CustomBottomSheetBehavior.java | 21 +++++----
.../player/event/PlayerGestureListener.java | 8 ----
.../activity_main_player.xml | 7 ++-
.../main/res/layout/activity_main_player.xml | 7 ++-
.../main/res/layout/fragment_video_detail.xml | 4 +-
9 files changed, 87 insertions(+), 50 deletions(-)
diff --git a/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java
index d0ca95d6b3b..8813d139d20 100644
--- a/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java
+++ b/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java
@@ -1244,7 +1244,7 @@ private void setHeightThumbnail() {
int height;
if (player != null && player.isInFullscreen())
- height = activity.getWindow().getDecorView().getHeight();
+ height = isInMultiWindow() ? getView().getHeight() : activity.getWindow().getDecorView().getHeight();
else
height = isPortrait
? (int) (metrics.widthPixels / (16.0f / 9.0f))
@@ -1669,8 +1669,7 @@ public void onProgressUpdate(int currentProgress, int duration, int bufferPercen
player.useVideoSource(false);
else if (player.minimizeOnPopupEnabled())
NavigationHelper.playOnPopupPlayer(activity, playQueue, true);
- else
- player.getPlayer().setPlayWhenReady(false);
+ else player.onPause();
}
else player.useVideoSource(true);
}
@@ -1751,23 +1750,18 @@ private void showSystemUi() {
getActivity().getWindow().getDecorView().setSystemUiVisibility(0);
getActivity().getWindow().clearFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS);
- getActivity().getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
}
private void hideSystemUi() {
if (DEBUG) Log.d(TAG, "hideSystemUi() called");
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
- int visibility = View.SYSTEM_UI_FLAG_LAYOUT_STABLE
- | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
- | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
- | View.SYSTEM_UI_FLAG_FULLSCREEN
- | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
- visibility |= View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
- }
- activity.getWindow().getDecorView().setSystemUiVisibility(visibility);
- }
+ int visibility = View.SYSTEM_UI_FLAG_LAYOUT_STABLE
+ | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
+ | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
+ | View.SYSTEM_UI_FLAG_FULLSCREEN
+ | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
+ | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
+ activity.getWindow().getDecorView().setSystemUiVisibility(visibility);
activity.getWindow().setFlags(
WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS, WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS);
}
@@ -1813,6 +1807,10 @@ private boolean isLandscape() {
return getResources().getDisplayMetrics().heightPixels < getResources().getDisplayMetrics().widthPixels;
}
+ private boolean isInMultiWindow() {
+ return Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && activity.isInMultiWindowMode();
+ }
+
/*
* Means that the player fragment was swiped away via BottomSheetLayout and is empty but ready for any new actions. See cleanUp()
* */
diff --git a/app/src/main/java/org/schabi/newpipe/player/MainPlayer.java b/app/src/main/java/org/schabi/newpipe/player/MainPlayer.java
index a0d4eb7d91d..6e5082494fb 100644
--- a/app/src/main/java/org/schabi/newpipe/player/MainPlayer.java
+++ b/app/src/main/java/org/schabi/newpipe/player/MainPlayer.java
@@ -26,6 +26,7 @@
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
+import android.util.DisplayMetrics;
import android.view.ViewGroup;
import android.view.WindowManager;
import androidx.core.app.NotificationCompat;
@@ -183,7 +184,11 @@ private void onClose() {
//////////////////////////////////////////////////////////////////////////*/
boolean isLandscape() {
- return getResources().getDisplayMetrics().heightPixels < getResources().getDisplayMetrics().widthPixels;
+ // DisplayMetrics from activity context knows about MultiWindow feature while DisplayMetrics from app context doesn't
+ final DisplayMetrics metrics = playerImpl.getParentActivity() != null ?
+ playerImpl.getParentActivity().getResources().getDisplayMetrics()
+ : getResources().getDisplayMetrics();
+ return metrics.heightPixels < metrics.widthPixels;
}
public View getView() {
diff --git a/app/src/main/java/org/schabi/newpipe/player/VideoPlayer.java b/app/src/main/java/org/schabi/newpipe/player/VideoPlayer.java
index 3a906d80c92..07f485e7abc 100644
--- a/app/src/main/java/org/schabi/newpipe/player/VideoPlayer.java
+++ b/app/src/main/java/org/schabi/newpipe/player/VideoPlayer.java
@@ -38,11 +38,7 @@
import android.view.MenuItem;
import android.view.SurfaceView;
import android.view.View;
-import android.widget.ImageView;
-import android.widget.PopupMenu;
-import android.widget.ProgressBar;
-import android.widget.SeekBar;
-import android.widget.TextView;
+import android.widget.*;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@@ -131,7 +127,7 @@ public abstract class VideoPlayer extends BasePlayer
private TextView playbackLiveSync;
private TextView playbackSpeedTextView;
- private View topControlsRoot;
+ private LinearLayout topControlsRoot;
private TextView qualityTextView;
private SubtitleView subtitleView;
@@ -961,7 +957,7 @@ public TextView getPlaybackEndTime() {
return playbackEndTime;
}
- public View getTopControlsRoot() {
+ public LinearLayout getTopControlsRoot() {
return topControlsRoot;
}
diff --git a/app/src/main/java/org/schabi/newpipe/player/VideoPlayerImpl.java b/app/src/main/java/org/schabi/newpipe/player/VideoPlayerImpl.java
index 71fe21b6d40..76c8106be31 100644
--- a/app/src/main/java/org/schabi/newpipe/player/VideoPlayerImpl.java
+++ b/app/src/main/java/org/schabi/newpipe/player/VideoPlayerImpl.java
@@ -25,6 +25,7 @@
import android.content.*;
import android.graphics.Bitmap;
import android.graphics.PixelFormat;
+import android.graphics.Point;
import android.net.Uri;
import android.os.Build;
import android.preference.PreferenceManager;
@@ -124,7 +125,6 @@ public class VideoPlayerImpl extends VideoPlayer
private ImageButton shareButton;
private View primaryControls;
- private LinearLayout topControls;
private View secondaryControls;
private int maxGestureLength;
@@ -245,7 +245,6 @@ public void initViews(View rootView) {
this.moreOptionsButton = rootView.findViewById(R.id.moreOptionsButton);
this.primaryControls = rootView.findViewById(R.id.primaryControls);
- this.topControls = rootView.findViewById(R.id.topControls);
this.secondaryControls = rootView.findViewById(R.id.secondaryControls);
this.shareButton = rootView.findViewById(R.id.share);
@@ -285,7 +284,7 @@ private void setupElementsVisibility() {
getRootView().findViewById(R.id.metadataView).setVisibility(View.GONE);
queueButton.setVisibility(View.GONE);
moreOptionsButton.setVisibility(View.GONE);
- topControls.setOrientation(LinearLayout.HORIZONTAL);
+ getTopControlsRoot().setOrientation(LinearLayout.HORIZONTAL);
primaryControls.getLayoutParams().width = LinearLayout.LayoutParams.WRAP_CONTENT;
secondaryControls.setAlpha(1f);
secondaryControls.setVisibility(View.VISIBLE);
@@ -297,7 +296,7 @@ private void setupElementsVisibility() {
fullscreenButton.setVisibility(View.GONE);
getRootView().findViewById(R.id.metadataView).setVisibility(View.VISIBLE);
moreOptionsButton.setVisibility(View.VISIBLE);
- topControls.setOrientation(LinearLayout.VERTICAL);
+ getTopControlsRoot().setOrientation(LinearLayout.VERTICAL);
primaryControls.getLayoutParams().width = LinearLayout.LayoutParams.MATCH_PARENT;
secondaryControls.setVisibility(View.GONE);
moreOptionsButton.setImageDrawable(service.getResources().getDrawable(
@@ -507,7 +506,7 @@ public void onPlayNext() {
@Override
public void toggleFullscreen() {
- if (DEBUG) Log.d(TAG, "onFullScreenButtonClicked() called");
+ if (DEBUG) Log.d(TAG, "toggleFullscreen() called");
if (simpleExoPlayer == null || getCurrentMetadata() == null) return;
if (popupPlayerSelected()) {
@@ -535,6 +534,7 @@ public void toggleFullscreen() {
if (fragmentListener == null) return;
isFullscreen = !isFullscreen;
+ setControlsWidth();
fragmentListener.onFullscreenStateChanged(isInFullscreen());
// When user presses back button in landscape mode and in fullscreen and uses ZOOM mode
// a video can be larger than screen. Prevent it like this
@@ -595,7 +595,8 @@ public void onClick(View v) {
getControlsVisibilityHandler().removeCallbacksAndMessages(null);
animateView(getControlsRoot(), true, DEFAULT_CONTROLS_DURATION, 0, () -> {
if (getCurrentState() == STATE_PLAYING && !isSomePopupMenuVisible()) {
- hideControls(DEFAULT_CONTROLS_DURATION, DEFAULT_CONTROLS_HIDE_TIME);
+ if (v.getId() == playPauseButton.getId()) hideControls(0, 0);
+ else hideControls(DEFAULT_CONTROLS_DURATION, DEFAULT_CONTROLS_HIDE_TIME);
}
});
}
@@ -816,6 +817,8 @@ public void onPlaying() {
service.getLockManager().acquireWifiAndCpu();
service.resetNotification();
service.updateNotification(R.drawable.ic_pause_white);
+
+ service.startForeground(NOTIFICATION_ID, service.getNotBuilder().build());
}
@Override
@@ -831,6 +834,10 @@ public void onPaused() {
service.resetNotification();
service.updateNotification(R.drawable.ic_play_arrow_white);
+ // Remove running notification when user don't want music (or video in popup) to be played in background
+ if (!minimizeOnPopupEnabled() && !backgroundPlaybackEnabled() && videoPlayerSelected())
+ service.stopForeground(true);
+
getRootView().setKeepScreenOn(false);
service.getLockManager().releaseWifiAndCpu();
@@ -1033,6 +1040,7 @@ public void showControlsThenHide() {
if (queueVisible) return;
showOrHideButtons();
+ showSystemUIPartially();
super.showControlsThenHide();
}
@@ -1041,6 +1049,7 @@ public void showControls(long duration) {
if (queueVisible) return;
showOrHideButtons();
+ showSystemUIPartially();
super.showControls(duration);
}
@@ -1078,12 +1087,36 @@ private void showOrHideButtons() {
queueButton.setVisibility(View.VISIBLE);
}
+ private void showSystemUIPartially() {
+ if (isInFullscreen()) {
+ int visibility = View.SYSTEM_UI_FLAG_LAYOUT_STABLE
+ | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
+ | View.SYSTEM_UI_FLAG_FULLSCREEN;
+ getParentActivity().getWindow().getDecorView().setSystemUiVisibility(visibility);
+ }
+ }
+
@Override
public void hideSystemUIIfNeeded() {
if (fragmentListener != null)
fragmentListener.hideSystemUIIfNeeded();
}
+ private void setControlsWidth() {
+ Point size = new Point();
+ // This method will give a correct size of a usable area of a window.
+ // It doesn't include NavigationBar, notches, etc.
+ getRootView().getDisplay().getSize(size);
+
+ int width = isFullscreen ? size.x : ViewGroup.LayoutParams.MATCH_PARENT;
+ primaryControls.getLayoutParams().width = width;
+ primaryControls.requestLayout();
+ secondaryControls.getLayoutParams().width = width;
+ secondaryControls.requestLayout();
+ getBottomControlsRoot().getLayoutParams().width = width;
+ getBottomControlsRoot().requestLayout();
+ }
+
private void updatePlaybackButtons() {
if (repeatButton == null || shuffleButton == null ||
simpleExoPlayer == null || playQueue == null) return;
diff --git a/app/src/main/java/org/schabi/newpipe/player/event/CustomBottomSheetBehavior.java b/app/src/main/java/org/schabi/newpipe/player/event/CustomBottomSheetBehavior.java
index 85db3b2017c..6f4cf41de7f 100644
--- a/app/src/main/java/org/schabi/newpipe/player/event/CustomBottomSheetBehavior.java
+++ b/app/src/main/java/org/schabi/newpipe/player/event/CustomBottomSheetBehavior.java
@@ -18,27 +18,30 @@ public CustomBottomSheetBehavior(Context context, AttributeSet attrs) {
@Override
public boolean onInterceptTouchEvent(CoordinatorLayout parent, View child, MotionEvent event) {
+ // Behavior of globalVisibleRect is different on different APIs.
+ // For example, on API 19 getGlobalVisibleRect returns a filled rect of a collapsed view while on the latest API
+ // it returns empty rect in that case. So check visibility with return value too
+ boolean visible;
+ Rect rect = new Rect();
+
// Without overriding scrolling will not work in detail_content_root_layout
ViewGroup controls = child.findViewById(R.id.detail_content_root_layout);
if (controls != null) {
- Rect rect = new Rect();
- controls.getGlobalVisibleRect(rect);
- if (rect.contains((int) event.getX(), (int) event.getY())) return false;
+ visible = controls.getGlobalVisibleRect(rect);
+ if (rect.contains((int) event.getX(), (int) event.getY()) && visible) return false;
}
// Without overriding scrolling will not work on relatedStreamsLayout
ViewGroup relatedStreamsLayout = child.findViewById(R.id.relatedStreamsLayout);
if (relatedStreamsLayout != null) {
- Rect rect = new Rect();
- relatedStreamsLayout.getGlobalVisibleRect(rect);
- if (rect.contains((int) event.getX(), (int) event.getY())) return false;
+ visible = relatedStreamsLayout.getGlobalVisibleRect(rect);
+ if (rect.contains((int) event.getX(), (int) event.getY()) && visible) return false;
}
ViewGroup playQueue = child.findViewById(R.id.playQueue);
if (playQueue != null) {
- Rect rect = new Rect();
- playQueue.getGlobalVisibleRect(rect);
- if (rect.contains((int) event.getX(), (int) event.getY())) return false;
+ visible = playQueue.getGlobalVisibleRect(rect);
+ if (rect.contains((int) event.getX(), (int) event.getY()) && visible) return false;
}
return super.onInterceptTouchEvent(parent, child, event);
diff --git a/app/src/main/java/org/schabi/newpipe/player/event/PlayerGestureListener.java b/app/src/main/java/org/schabi/newpipe/player/event/PlayerGestureListener.java
index 00a511ca361..db7d8d615ee 100644
--- a/app/src/main/java/org/schabi/newpipe/player/event/PlayerGestureListener.java
+++ b/app/src/main/java/org/schabi/newpipe/player/event/PlayerGestureListener.java
@@ -139,14 +139,6 @@ private boolean onSingleTapConfirmedInMain(MotionEvent e) {
} else {
playerImpl.showControlsThenHide();
}
- if (playerImpl.isInFullscreen()) {
- int visibility = View.SYSTEM_UI_FLAG_LAYOUT_STABLE
- | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
- | View.SYSTEM_UI_FLAG_FULLSCREEN;
- playerImpl.getParentActivity().getWindow().getDecorView().setSystemUiVisibility(visibility);
- playerImpl.getParentActivity().getWindow().clearFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS);
- playerImpl.getParentActivity().getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
- }
}
return true;
}
diff --git a/app/src/main/res/layout-large-land/activity_main_player.xml b/app/src/main/res/layout-large-land/activity_main_player.xml
index 8d7d9b6398a..ff57bc2bfce 100644
--- a/app/src/main/res/layout-large-land/activity_main_player.xml
+++ b/app/src/main/res/layout-large-land/activity_main_player.xml
@@ -377,12 +377,17 @@
android:visibility="gone"
tools:visibility="visible"/>
+
+
+
+
From e0639677345af36fc1c3cc1704ebbac7ccf35d17 Mon Sep 17 00:00:00 2001
From: Avently <7953703+avently@users.noreply.github.com>
Date: Fri, 3 Jan 2020 19:19:14 +0300
Subject: [PATCH 005/398] Third block of fixes for review - audio-only streams
plays the same way as video streams - fullscreen mode for tablet with
controls on the right place - hidden controls while swiping mini player down
- mini player works better
---
.../fragments/detail/VideoDetailFragment.java | 11 +++-----
.../newpipe/player/VideoPlayerImpl.java | 26 ++++++++++++++++---
2 files changed, 27 insertions(+), 10 deletions(-)
diff --git a/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java
index 8813d139d20..3d42942ba91 100644
--- a/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java
+++ b/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java
@@ -526,12 +526,7 @@ public void onClick(View v) {
openChannel();
break;
case R.id.detail_thumbnail_root_layout:
- if (currentInfo.getVideoStreams().isEmpty()
- && currentInfo.getVideoOnlyStreams().isEmpty()) {
- openBackgroundPlayer(false);
- } else {
- openVideoPlayer();
- }
+ openVideoPlayer();
break;
case R.id.detail_title_root_layout:
toggleTitleAndDescription();
@@ -545,6 +540,7 @@ public void onClick(View v) {
if (player != null) {
player.onPlayPause();
player.hideControls(0,0);
+ showSystemUi();
}
else openVideoPlayer();
@@ -1869,9 +1865,10 @@ else if (bottomSheetState == BottomSheetBehavior.STATE_EXPANDED)
case BottomSheetBehavior.STATE_COLLAPSED:
// Re-enable clicks
setOverlayElementsClickable(true);
- if (player != null && player.isInFullscreen()) player.toggleFullscreen();
+ if (player != null && player.isInFullscreen() && player.isPlaying()) showSystemUi();
break;
case BottomSheetBehavior.STATE_DRAGGING:
+ if (player != null && player.isControlsVisible()) player.hideControls(0, 0);
break;
case BottomSheetBehavior.STATE_SETTLING:
break;
diff --git a/app/src/main/java/org/schabi/newpipe/player/VideoPlayerImpl.java b/app/src/main/java/org/schabi/newpipe/player/VideoPlayerImpl.java
index 76c8106be31..d5bb5c86d30 100644
--- a/app/src/main/java/org/schabi/newpipe/player/VideoPlayerImpl.java
+++ b/app/src/main/java/org/schabi/newpipe/player/VideoPlayerImpl.java
@@ -534,7 +534,7 @@ public void toggleFullscreen() {
if (fragmentListener == null) return;
isFullscreen = !isFullscreen;
- setControlsWidth();
+ setControlsSize();
fragmentListener.onFullscreenStateChanged(isInFullscreen());
// When user presses back button in landscape mode and in fullscreen and uses ZOOM mode
// a video can be larger than screen. Prevent it like this
@@ -1102,19 +1102,39 @@ public void hideSystemUIIfNeeded() {
fragmentListener.hideSystemUIIfNeeded();
}
- private void setControlsWidth() {
+ /*
+ * This method 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
+ * */
+ void setControlsSize() {
Point size = new Point();
+ Display display = getRootView().getDisplay();
+ if (display == null) return;
// This method will give a correct size of a usable area of a window.
// It doesn't include NavigationBar, notches, etc.
- getRootView().getDisplay().getSize(size);
+ display.getSize(size);
int width = isFullscreen ? size.x : ViewGroup.LayoutParams.MATCH_PARENT;
+ int gravity = isFullscreen ? (display.getRotation() == Surface.ROTATION_90 ? Gravity.START : Gravity.END) : Gravity.TOP;
+
primaryControls.getLayoutParams().width = width;
+ ((LinearLayout.LayoutParams) primaryControls.getLayoutParams()).gravity = gravity;
primaryControls.requestLayout();
+
secondaryControls.getLayoutParams().width = width;
+ ((LinearLayout.LayoutParams) secondaryControls.getLayoutParams()).gravity = gravity;
secondaryControls.requestLayout();
+
getBottomControlsRoot().getLayoutParams().width = width;
+ 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();
+
+ ViewGroup controlsRoot = getRootView().findViewById(R.id.playbackControlRoot);
+ controlsRoot.getLayoutParams().height = isFullscreen ? size.y : ViewGroup.LayoutParams.MATCH_PARENT;
+ controlsRoot.requestLayout();
}
private void updatePlaybackButtons() {
From a2d5314cf79d14492a52bfb55e36f21751e7d3fe Mon Sep 17 00:00:00 2001
From: Avently <7953703+avently@users.noreply.github.com>
Date: Mon, 6 Jan 2020 13:39:01 +0300
Subject: [PATCH 006/398] Fourth block of fixes for review - wrote more methods
to PlayQueue. Now it supports internal history of played items with ability
to play previous() item. Also it has equals() to check whether queues has the
same content or not - backstack in fragment is more powerful now with help of
PlayQueue's history and able to work great with playlists' PlayQueue and
SinglePlayQueue at the same time - simplified logic inside fragment. Easy to
understand. New PlayQueue will be added in backstack from only one place;
less number of setInitialData() calls - BasePlayer now able to check
PlayQueue and compare it with currently playing. And if it is the same queue
it tries to not init() it twice. It gives possibility to have a great
backstack in fragment since the same queue will not be played from two
different instances and will not be added to backstack twice with duplicated
history inside - better support of Player.STATE_IDLE - worked with layouts of
player and made them better and more universal - service will be stopped when
activity finishes by a user decision - fixed a problem related to
ChannelPlayQueue and PlaylistPlayQueue in initial start of fragment - fixed
crash in popup
---
.../newpipe/fragments/detail/StackItem.java | 6 +-
.../fragments/detail/VideoDetailFragment.java | 71 +++++++++----------
.../org/schabi/newpipe/player/BasePlayer.java | 20 +++++-
.../org/schabi/newpipe/player/MainPlayer.java | 1 +
.../newpipe/player/ServicePlayerActivity.java | 4 ++
.../newpipe/player/VideoPlayerImpl.java | 25 +++++--
.../player/event/PlayerEventListener.java | 2 +
.../newpipe/player/playqueue/PlayQueue.java | 58 ++++++++++++++-
.../activity_main_player.xml | 31 +++++---
.../main/res/layout/activity_main_player.xml | 31 +++++---
10 files changed, 184 insertions(+), 65 deletions(-)
diff --git a/app/src/main/java/org/schabi/newpipe/fragments/detail/StackItem.java b/app/src/main/java/org/schabi/newpipe/fragments/detail/StackItem.java
index 3fb7a7716d1..2e90a4fc9f7 100644
--- a/app/src/main/java/org/schabi/newpipe/fragments/detail/StackItem.java
+++ b/app/src/main/java/org/schabi/newpipe/fragments/detail/StackItem.java
@@ -7,7 +7,7 @@
class StackItem implements Serializable {
private final int serviceId;
private String title;
- private final String url;
+ private String url;
private final PlayQueue playQueue;
StackItem(int serviceId, String url, String title, PlayQueue playQueue) {
@@ -21,6 +21,10 @@ public void setTitle(String title) {
this.title = title;
}
+ public void setUrl(String url) {
+ this.url = url;
+ }
+
public int getServiceId() {
return serviceId;
}
diff --git a/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java
index 3d42942ba91..d35e27c408e 100644
--- a/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java
+++ b/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java
@@ -126,7 +126,7 @@ public class VideoDetailFragment
@State
protected PlayQueue playQueue;
@State
- int bottomSheetState = BottomSheetBehavior.STATE_HIDDEN;
+ int bottomSheetState = BottomSheetBehavior.STATE_EXPANDED;
private StreamInfo currentInfo;
private Disposable currentWorker;
@@ -398,7 +398,8 @@ public void onStop() {
public void onDestroy() {
super.onDestroy();
- unbind();
+ if (!activity.isFinishing()) unbind();
+ else stopService();
PreferenceManager.getDefaultSharedPreferences(activity)
.unregisterOnSharedPreferenceChangeListener(this);
@@ -850,26 +851,6 @@ public void onNothingSelected(AdapterView> parent) {
*/
protected final LinkedList stack = new LinkedList<>();
- public void pushToStack(int serviceId, String videoUrl, String name, PlayQueue playQueue) {
- if (DEBUG) {
- Log.d(TAG, "pushToStack() called with: serviceId = ["
- + serviceId + "], videoUrl = [" + videoUrl + "], name = [" + name + "], playQueue = [" + playQueue + "]");
- }
-
- if (stack.size() > 0
- && stack.peek().getServiceId() == serviceId
- && stack.peek().getUrl().equals(videoUrl)
- && stack.peek().getPlayQueue().getClass().equals(playQueue.getClass())) {
- Log.d(TAG, "pushToStack() called with: serviceId == peek.serviceId = ["
- + serviceId + "], videoUrl == peek.getUrl = [" + videoUrl + "]");
- return;
- } else {
- Log.d(TAG, "pushToStack() wasn't equal");
- }
-
- stack.push(new StackItem(serviceId, videoUrl, name, playQueue));
- }
-
public void setTitleToUrl(int serviceId, String videoUrl, String name) {
if (name != null && !name.isEmpty()) {
for (StackItem stackItem : stack) {
@@ -885,12 +866,17 @@ public void setTitleToUrl(int serviceId, String videoUrl, String name) {
public boolean onBackPressed() {
if (DEBUG) Log.d(TAG, "onBackPressed() called");
+ // If we are in fullscreen mode just exit from it via first back press
if (player != null && player.isInFullscreen()) {
player.onPause();
restoreDefaultOrientation();
return true;
}
+ // If we have something in history of played items we replay it here
+ if (player != null && player.getPlayQueue().previous()) {
+ return true;
+ }
// That means that we are on the start of the stack,
// return false to let the MainActivity handle the onBack
if (stack.size() <= 1) {
@@ -928,15 +914,15 @@ protected void doInitialLoadLogic() {
}
public void selectAndLoadVideo(int serviceId, String videoUrl, String name, PlayQueue playQueue) {
- boolean streamIsTheSame = videoUrl.equals(url) && currentInfo != null;
- setInitialData(serviceId, videoUrl, name, playQueue);
-
+ boolean streamIsTheSame = this.playQueue != null && this.playQueue.equals(playQueue);
// Situation when user switches from players to main player. All needed data is here, we can start watching
if (streamIsTheSame) {
- handleResult(currentInfo);
+ //TODO not sure about usefulness of this line in the case when user switches from one player to another
+ // handleResult(currentInfo);
openVideoPlayer();
return;
}
+ setInitialData(serviceId, videoUrl, name, playQueue);
startLoading(false);
}
@@ -944,7 +930,6 @@ public void prepareAndHandleInfo(final StreamInfo info, boolean scrollToTop) {
if (DEBUG) Log.d(TAG, "prepareAndHandleInfo() called with: info = ["
+ info + "], scrollToTop = [" + scrollToTop + "]");
- setInitialData(info.getServiceId(), info.getUrl(), info.getName(), new SinglePlayQueue(info));
showLoading();
initTabs();
@@ -1390,8 +1375,6 @@ public void handleResult(@NonNull StreamInfo info) {
setInitialData(info.getServiceId(), info.getOriginalUrl(), info.getName(),
playQueue == null ? new SinglePlayQueue(info) : playQueue);
- pushToStack(serviceId, url, name, playQueue);
-
if(showRelatedStreams){
if(null == relatedStreamsLayout){ //phone
pageAdapter.updateItem(RELATED_TAB_TAG, RelatedVideosFragment.getInstance(info));
@@ -1627,6 +1610,20 @@ private void showPlaybackProgress(long progress, long duration) {
// Player event listener
//////////////////////////////////////////////////////////////////////////*/
+ @Override
+ public void onQueueUpdate(PlayQueue queue) {
+ playQueue = queue;
+ // This should be the only place where we push data to stack. It will allow to have live instance of PlayQueue with actual
+ // information about deleted/added items inside Channel/Playlist queue and makes possible to have a history of played items
+ if (stack.isEmpty() || !stack.peek().getPlayQueue().equals(queue))
+ stack.push(new StackItem(serviceId, url, name, playQueue));
+
+ if (DEBUG) {
+ Log.d(TAG, "onQueueUpdate() called with: serviceId = ["
+ + serviceId + "], videoUrl = [" + url + "], name = [" + name + "], playQueue = [" + playQueue + "]");
+ }
+ }
+
@Override
public void onPlaybackUpdate(int state, int repeatMode, boolean shuffled, PlaybackParameters parameters) {
setOverlayPlayPauseImage();
@@ -1647,11 +1644,6 @@ public void onPlaybackUpdate(int state, int repeatMode, boolean shuffled, Playba
public void onProgressUpdate(int currentProgress, int duration, int bufferPercent) {
// Progress updates every second even if media is paused. It's useless until playing
if (!player.getPlayer().isPlaying() || playQueue == null) return;
-
- // Update current progress in cached playQueue because playQueue in popup and background players
- // are different instances
- playQueue.setRecovery(playQueue.getIndex(), currentProgress);
-
showPlaybackProgress(currentProgress, duration);
// We don't want to interrupt playback and don't want to see notification if player is stopped
@@ -1672,6 +1664,14 @@ else if (player.minimizeOnPopupEnabled())
@Override
public void onMetadataUpdate(StreamInfo info) {
+ if (!stack.isEmpty()) {
+ // When PlayQueue can have multiple streams (PlaylistPlayQueue or ChannelPlayQueue) every new played stream gives
+ // new title and url. StackItem contains information about first played stream. Let's update it here
+ StackItem peek = stack.peek();
+ peek.setTitle(info.getName());
+ peek.setUrl(info.getUrl());
+ }
+
if (currentInfo == info) return;
currentInfo = info;
@@ -1865,7 +1865,7 @@ else if (bottomSheetState == BottomSheetBehavior.STATE_EXPANDED)
case BottomSheetBehavior.STATE_COLLAPSED:
// Re-enable clicks
setOverlayElementsClickable(true);
- if (player != null && player.isInFullscreen() && player.isPlaying()) showSystemUi();
+ if (player != null && player.isInFullscreen()) showSystemUi();
break;
case BottomSheetBehavior.STATE_DRAGGING:
if (player != null && player.isControlsVisible()) player.hideControls(0, 0);
@@ -1873,7 +1873,6 @@ else if (bottomSheetState == BottomSheetBehavior.STATE_EXPANDED)
case BottomSheetBehavior.STATE_SETTLING:
break;
}
- Log.d(TAG, "onStateChanged: " + newState);
}
@Override public void onSlide(@NonNull View bottomSheet, float slideOffset) {
setOverlayLook(appBarLayout, behavior, slideOffset);
diff --git a/app/src/main/java/org/schabi/newpipe/player/BasePlayer.java b/app/src/main/java/org/schabi/newpipe/player/BasePlayer.java
index 2ae822d7f04..70ab82fb861 100644
--- a/app/src/main/java/org/schabi/newpipe/player/BasePlayer.java
+++ b/app/src/main/java/org/schabi/newpipe/player/BasePlayer.java
@@ -274,6 +274,16 @@ public void handleIntent(Intent intent) {
return;
}
+ boolean same = playQueue != null && playQueue.equals(queue);
+
+ // Do not re-init the same PlayQueue. Save time
+ if (same && !playQueue.isDisposed()) {
+ // Player can have state = IDLE when playback is stopped or failed and we should retry() in this case
+ if (simpleExoPlayer != null && simpleExoPlayer.getPlaybackState() == Player.STATE_IDLE)
+ simpleExoPlayer.retry();
+ return;
+ }
+
final int repeatMode = intent.getIntExtra(REPEAT_MODE, getRepeatMode());
final float playbackSpeed = intent.getFloatExtra(PLAYBACK_SPEED, getPlaybackSpeed());
final float playbackPitch = intent.getFloatExtra(PLAYBACK_PITCH, getPlaybackPitch());
@@ -284,14 +294,17 @@ public void handleIntent(Intent intent) {
if (simpleExoPlayer != null
&& queue.size() == 1
&& playQueue != null
+ && playQueue.size() == 1
&& playQueue.getItem() != null
&& queue.getItem().getUrl().equals(playQueue.getItem().getUrl())
&& queue.getItem().getRecoveryPosition() != PlayQueueItem.RECOVERY_UNSET
- ) {
+ && !same) {
simpleExoPlayer.seekTo(playQueue.getIndex(), queue.getItem().getRecoveryPosition());
return;
- } else if (intent.getBooleanExtra(RESUME_PLAYBACK, false) && isPlaybackResumeEnabled()) {
+ } else if (intent.getBooleanExtra(RESUME_PLAYBACK, false)
+ && isPlaybackResumeEnabled()
+ && !same) {
final PlayQueueItem item = queue.getItem();
if (item != null && item.getRecoveryPosition() == PlayQueueItem.RECOVERY_UNSET) {
stateLoader = recordManager.loadStreamState(item)
@@ -321,7 +334,8 @@ public void handleIntent(Intent intent) {
}
}
// Good to go...
- initPlayback(queue, repeatMode, playbackSpeed, playbackPitch, playbackSkipSilence,
+ // In a case of equal PlayQueues we can re-init old one but only when it is disposed
+ initPlayback(same ? playQueue : queue, repeatMode, playbackSpeed, playbackPitch, playbackSkipSilence,
/*playOnInit=*/true);
}
diff --git a/app/src/main/java/org/schabi/newpipe/player/MainPlayer.java b/app/src/main/java/org/schabi/newpipe/player/MainPlayer.java
index 6e5082494fb..4e3c070a508 100644
--- a/app/src/main/java/org/schabi/newpipe/player/MainPlayer.java
+++ b/app/src/main/java/org/schabi/newpipe/player/MainPlayer.java
@@ -126,6 +126,7 @@ public void stop() {
if (playerImpl.getPlayer() != null) {
playerImpl.wasPlaying = playerImpl.getPlayer().getPlayWhenReady();
+ // We can't pause the player here because it will make transition from one stream to a new stream not smooth
playerImpl.getPlayer().stop(false);
playerImpl.setRecovery();
}
diff --git a/app/src/main/java/org/schabi/newpipe/player/ServicePlayerActivity.java b/app/src/main/java/org/schabi/newpipe/player/ServicePlayerActivity.java
index c8d564557a6..1c449c77ea2 100644
--- a/app/src/main/java/org/schabi/newpipe/player/ServicePlayerActivity.java
+++ b/app/src/main/java/org/schabi/newpipe/player/ServicePlayerActivity.java
@@ -557,6 +557,10 @@ private void shareUrl(String subject, String url) {
// Binding Service Listener
////////////////////////////////////////////////////////////////////////////
+ @Override
+ public void onQueueUpdate(PlayQueue queue) {
+ }
+
@Override
public void onPlaybackUpdate(int state, int repeatMode, boolean shuffled, PlaybackParameters parameters) {
onStateChanged(state);
diff --git a/app/src/main/java/org/schabi/newpipe/player/VideoPlayerImpl.java b/app/src/main/java/org/schabi/newpipe/player/VideoPlayerImpl.java
index d5bb5c86d30..21934fb7024 100644
--- a/app/src/main/java/org/schabi/newpipe/player/VideoPlayerImpl.java
+++ b/app/src/main/java/org/schabi/newpipe/player/VideoPlayerImpl.java
@@ -281,6 +281,7 @@ protected void setupSubtitleView(@NonNull SubtitleView view,
private void setupElementsVisibility() {
if (popupPlayerSelected()) {
fullscreenButton.setVisibility(View.VISIBLE);
+ getRootView().findViewById(R.id.spaceBeforeControls).setVisibility(View.GONE);
getRootView().findViewById(R.id.metadataView).setVisibility(View.GONE);
queueButton.setVisibility(View.GONE);
moreOptionsButton.setVisibility(View.GONE);
@@ -294,10 +295,11 @@ private void setupElementsVisibility() {
openInBrowser.setVisibility(View.GONE);
} else {
fullscreenButton.setVisibility(View.GONE);
+ getRootView().findViewById(R.id.spaceBeforeControls).setVisibility(View.VISIBLE);
getRootView().findViewById(R.id.metadataView).setVisibility(View.VISIBLE);
moreOptionsButton.setVisibility(View.VISIBLE);
getTopControlsRoot().setOrientation(LinearLayout.VERTICAL);
- primaryControls.getLayoutParams().width = LinearLayout.LayoutParams.MATCH_PARENT;
+ primaryControls.getLayoutParams().width = secondaryControls.getLayoutParams().width;
secondaryControls.setVisibility(View.GONE);
moreOptionsButton.setImageDrawable(service.getResources().getDrawable(
R.drawable.ic_expand_more_white_24dp));
@@ -500,7 +502,13 @@ public void onPlayNext() {
triggerProgressUpdate();
}
- /*//////////////////////////////////////////////////////////////////////////
+ @Override
+ protected void initPlayback(@NonNull PlayQueue queue, int repeatMode, float playbackSpeed, float playbackPitch, boolean playbackSkipSilence, boolean playOnReady) {
+ super.initPlayback(queue, repeatMode, playbackSpeed, playbackPitch, playbackSkipSilence, playOnReady);
+ updateQueue(queue);
+ }
+
+ /*//////////////////////////////////////////////////////////////////////////
// Player Overrides
//////////////////////////////////////////////////////////////////////////*/
@@ -1088,7 +1096,7 @@ private void showOrHideButtons() {
}
private void showSystemUIPartially() {
- if (isInFullscreen()) {
+ if (isInFullscreen() && getParentActivity() != null) {
int visibility = View.SYSTEM_UI_FLAG_LAYOUT_STABLE
| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
| View.SYSTEM_UI_FLAG_FULLSCREEN;
@@ -1106,7 +1114,7 @@ public void hideSystemUIIfNeeded() {
* This method 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
* */
- void setControlsSize() {
+ private void setControlsSize() {
Point size = new Point();
Display display = getRootView().getDisplay();
if (display == null) return;
@@ -1479,6 +1487,15 @@ public void removeFragmentListener(PlayerServiceEventListener listener) {
}
}
+ private void updateQueue(PlayQueue queue) {
+ if (fragmentListener != null) {
+ fragmentListener.onQueueUpdate(queue);
+ }
+ if (activityListener != null) {
+ activityListener.onQueueUpdate(queue);
+ }
+ }
+
private void updateMetadata() {
if (fragmentListener != null && getCurrentMetadata() != null) {
fragmentListener.onMetadataUpdate(getCurrentMetadata().getMetadata());
diff --git a/app/src/main/java/org/schabi/newpipe/player/event/PlayerEventListener.java b/app/src/main/java/org/schabi/newpipe/player/event/PlayerEventListener.java
index 3a7b299545c..37ad9798f3a 100644
--- a/app/src/main/java/org/schabi/newpipe/player/event/PlayerEventListener.java
+++ b/app/src/main/java/org/schabi/newpipe/player/event/PlayerEventListener.java
@@ -4,8 +4,10 @@
import com.google.android.exoplayer2.PlaybackParameters;
import org.schabi.newpipe.extractor.stream.StreamInfo;
+import org.schabi.newpipe.player.playqueue.PlayQueue;
public interface PlayerEventListener {
+ void onQueueUpdate(PlayQueue queue);
void onPlaybackUpdate(int state, int repeatMode, boolean shuffled, PlaybackParameters parameters);
void onProgressUpdate(int currentProgress, int duration, int bufferPercent);
void onMetadataUpdate(StreamInfo info);
diff --git a/app/src/main/java/org/schabi/newpipe/player/playqueue/PlayQueue.java b/app/src/main/java/org/schabi/newpipe/player/playqueue/PlayQueue.java
index fcb1e28193f..12454bde9ed 100644
--- a/app/src/main/java/org/schabi/newpipe/player/playqueue/PlayQueue.java
+++ b/app/src/main/java/org/schabi/newpipe/player/playqueue/PlayQueue.java
@@ -46,17 +46,23 @@ public abstract class PlayQueue implements Serializable {
private ArrayList backup;
private ArrayList streams;
+ private ArrayList history;
@NonNull private final AtomicInteger queueIndex;
private transient BehaviorSubject eventBroadcast;
private transient Flowable broadcastReceiver;
private transient Subscription reportingReactor;
+ private transient boolean disposed;
+
PlayQueue(final int index, final List startWith) {
streams = new ArrayList<>();
streams.addAll(startWith);
+ history = new ArrayList<>();
+ history.add(streams.get(index));
queueIndex = new AtomicInteger(index);
+ disposed = false;
}
/*//////////////////////////////////////////////////////////////////////////
@@ -88,6 +94,7 @@ public void dispose() {
eventBroadcast = null;
broadcastReceiver = null;
reportingReactor = null;
+ disposed = true;
}
/**
@@ -195,6 +202,7 @@ public synchronized void setIndex(final int index) {
int newIndex = index;
if (index < 0) newIndex = 0;
if (index >= streams.size()) newIndex = isComplete() ? index % streams.size() : streams.size() - 1;
+ if (oldIndex != newIndex) history.add(streams.get(newIndex));
queueIndex.set(newIndex);
broadcast(new SelectEvent(oldIndex, newIndex));
@@ -267,6 +275,9 @@ public synchronized void error(final boolean skippable) {
if (skippable) {
queueIndex.incrementAndGet();
+ if (streams.size() > queueIndex.get()) {
+ history.add(streams.get(queueIndex.get()));
+ }
} else {
removeInternal(index);
}
@@ -292,7 +303,9 @@ private synchronized void removeInternal(final int removeIndex) {
final int backupIndex = backup.indexOf(getItem(removeIndex));
backup.remove(backupIndex);
}
- streams.remove(removeIndex);
+
+ history.remove(streams.remove(removeIndex));
+ history.add(streams.get(queueIndex.get()));
}
/**
@@ -366,6 +379,7 @@ public synchronized void shuffle() {
streams.add(0, streams.remove(newIndex));
}
queueIndex.set(0);
+ history.add(streams.get(0));
broadcast(new ReorderEvent(originIndex, queueIndex.get()));
}
@@ -393,10 +407,52 @@ public synchronized void unshuffle() {
} else {
queueIndex.set(0);
}
+ history.add(streams.get(queueIndex.get()));
broadcast(new ReorderEvent(originIndex, queueIndex.get()));
}
+ /**
+ * Selects previous played item
+ *
+ * This method removes currently playing item from history and
+ * starts playing the last item from history if it exists
+ *
+ * Returns true if history is not empty and the item can be played
+ * */
+ public synchronized boolean previous() {
+ if (history.size() <= 1) return false;
+
+ history.remove(history.size() - 1);
+
+ PlayQueueItem last = history.remove(history.size() - 1);
+ setIndex(indexOf(last));
+
+ return true;
+ }
+
+ /*
+ * Compares two PlayQueues. Useful when a user switches players but queue is the same so
+ * we don't have to do anything with new queue. This method also gives a chance to track history of items in a queue in
+ * VideoDetailFragment without duplicating items from two identical queues
+ * */
+ @Override
+ public boolean equals(@Nullable Object obj) {
+ if (!(obj instanceof PlayQueue) || getStreams().size() != ((PlayQueue) obj).getStreams().size())
+ return false;
+
+ PlayQueue other = (PlayQueue) obj;
+ for (int i = 0; i < getStreams().size(); i++) {
+ if (!getItem(i).getUrl().equals(other.getItem(i).getUrl()))
+ return false;
+ }
+
+ return true;
+ }
+
+ public boolean isDisposed() {
+ return disposed;
+ }
/*//////////////////////////////////////////////////////////////////////////
// Rx Broadcast
//////////////////////////////////////////////////////////////////////////*/
diff --git a/app/src/main/res/layout-large-land/activity_main_player.xml b/app/src/main/res/layout-large-land/activity_main_player.xml
index ff57bc2bfce..d0602ed75f6 100644
--- a/app/src/main/res/layout-large-land/activity_main_player.xml
+++ b/app/src/main/res/layout-large-land/activity_main_player.xml
@@ -141,17 +141,29 @@
android:layout_height="match_parent"
android:fitsSystemWindows="true">
+
+
+
+
+
+ android:paddingEnd="6dp"
+ android:layout_toEndOf="@id/spaceBeforeControls"
+ android:baselineAligned="false">
@@ -274,8 +284,6 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="top"
- android:paddingStart="16dp"
- android:paddingEnd="6dp"
android:visibility="invisible"
tools:ignore="RtlHardcoded"
tools:visibility="visible">
@@ -302,6 +310,8 @@
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"
@@ -365,10 +375,11 @@
android:id="@+id/fullScreenButton"
android:layout_width="40dp"
android:layout_height="40dp"
- android:paddingEnd="8dp"
- android:paddingTop="8dp"
+ android:layout_marginTop="2dp"
+ android:layout_marginEnd="2dp"
+ android:padding="6dp"
android:layout_alignParentRight="true"
- android:background="@drawable/player_top_controls_bg"
+ android:background="?attr/selectableItemBackground"
android:clickable="true"
android:focusable="true"
android:scaleType="fitCenter"
diff --git a/app/src/main/res/layout/activity_main_player.xml b/app/src/main/res/layout/activity_main_player.xml
index 1022d2e9560..bf9da748f2f 100644
--- a/app/src/main/res/layout/activity_main_player.xml
+++ b/app/src/main/res/layout/activity_main_player.xml
@@ -139,17 +139,29 @@
android:layout_height="match_parent"
android:fitsSystemWindows="true">
+
+
+
+
+
+ android:paddingEnd="6dp"
+ android:layout_toEndOf="@id/spaceBeforeControls"
+ android:baselineAligned="false">
@@ -272,8 +282,6 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="top"
- android:paddingStart="16dp"
- android:paddingEnd="6dp"
android:visibility="invisible"
tools:ignore="RtlHardcoded"
tools:visibility="visible">
@@ -300,6 +308,8 @@
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"
@@ -363,10 +373,11 @@
android:id="@+id/fullScreenButton"
android:layout_width="40dp"
android:layout_height="40dp"
- android:paddingEnd="8dp"
- android:paddingTop="8dp"
+ android:layout_marginTop="2dp"
+ android:layout_marginEnd="2dp"
+ android:padding="6dp"
android:layout_alignParentRight="true"
- android:background="@drawable/player_top_controls_bg"
+ android:background="?attr/selectableItemBackground"
android:clickable="true"
android:focusable="true"
android:scaleType="fitCenter"
From 4c57893312bf94adc25f7dd43bd577639e051035 Mon Sep 17 00:00:00 2001
From: Avently <7953703+avently@users.noreply.github.com>
Date: Wed, 8 Jan 2020 19:16:50 +0300
Subject: [PATCH 007/398] New features and fixes - added autoplay options
inside settings: always, only on wifi, never - now statusbar will be shown in
fullscreen mode - playlists, channels can be autoplayed too (if enabled) -
changed title of background activity to Play queue - fixed a crash
---
.../fragments/detail/VideoDetailFragment.java | 80 ++++++++++++-------
.../list/channel/ChannelFragment.java | 2 +-
.../list/playlist/PlaylistFragment.java | 2 +-
.../history/StatisticsPlaylistFragment.java | 2 +-
.../local/playlist/LocalPlaylistFragment.java | 2 +-
.../player/BackgroundPlayerActivity.java | 2 +-
.../newpipe/player/VideoPlayerImpl.java | 14 ++--
.../newpipe/player/helper/PlayerHelper.java | 34 ++++++++
.../org/schabi/newpipe/util/ListHelper.java | 2 +-
.../schabi/newpipe/util/NavigationHelper.java | 4 +-
.../activity_main_player.xml | 12 +--
.../main/res/layout/activity_main_player.xml | 12 +--
app/src/main/res/values/settings_keys.xml | 17 ++++
app/src/main/res/values/strings.xml | 6 ++
app/src/main/res/xml/video_audio_settings.xml | 9 +++
15 files changed, 146 insertions(+), 54 deletions(-)
diff --git a/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java
index d35e27c408e..312e4d9e552 100644
--- a/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java
+++ b/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java
@@ -330,7 +330,11 @@ public static VideoDetailFragment getInstance(int serviceId, String videoUrl, St
startService(false);
setupBroadcastReceiver();
+
settingsContentObserver = new SettingsContentObserver(new Handler(), this);
+ activity.getContentResolver().registerContentObserver(
+ android.provider.Settings.System.CONTENT_URI, true,
+ settingsContentObserver);
}
@Override
@@ -344,7 +348,6 @@ public void onPause() {
if (currentWorker != null) currentWorker.dispose();
setupBrightness(true);
- getContext().getContentResolver().unregisterContentObserver(settingsContentObserver);
PreferenceManager.getDefaultSharedPreferences(getContext())
.edit()
.putString(getString(R.string.stream_info_selected_tab_key), pageAdapter.getItemTitle(viewPager.getCurrentItem()))
@@ -356,9 +359,6 @@ public void onResume() {
super.onResume();
isFragmentStopped = false;
- getContext().getContentResolver().registerContentObserver(
- android.provider.Settings.System.CONTENT_URI, true,
- settingsContentObserver);
setupBrightness(false);
@@ -403,7 +403,8 @@ public void onDestroy() {
PreferenceManager.getDefaultSharedPreferences(activity)
.unregisterOnSharedPreferenceChangeListener(this);
- getActivity().unregisterReceiver(broadcastReceiver);
+ activity.unregisterReceiver(broadcastReceiver);
+ activity.getContentResolver().unregisterContentObserver(settingsContentObserver);
if (positionSubscriber != null) positionSubscriber.dispose();
if (currentWorker != null) currentWorker.dispose();
@@ -566,7 +567,7 @@ public boolean onLongClick(View v) {
openPopupPlayer(true);
break;
case R.id.detail_controls_download:
- NavigationHelper.openDownloads(getActivity());
+ NavigationHelper.openDownloads(activity);
break;
case R.id.overlay_thumbnail:
case R.id.overlay_metadata_layout:
@@ -874,7 +875,7 @@ public boolean onBackPressed() {
}
// If we have something in history of played items we replay it here
- if (player != null && player.getPlayQueue().previous()) {
+ if (player != null && player.getPlayQueue() != null && player.getPlayQueue().previous()) {
return true;
}
// That means that we are on the start of the stack,
@@ -1126,7 +1127,7 @@ private void openChannel() {
currentInfo.getUploaderUrl(),
currentInfo.getUploaderName());
} catch (Exception e) {
- ErrorActivity.reportUiError((AppCompatActivity) getActivity(), e);
+ ErrorActivity.reportUiError(activity, e);
}
}
}
@@ -1159,9 +1160,26 @@ private boolean isExternalPlayerEnabled() {
}
// This method overrides default behaviour when setAutoplay() is called.
- // Don't auto play if the user selected an external player
+ // Don't auto play if the user selected an external player or disabled it in settings
private boolean isAutoplayEnabled() {
- return playQueue != null && playQueue.getStreams().size() != 0 && !isExternalPlayerEnabled() && autoPlayEnabled;
+ return playQueue != null && playQueue.getStreams().size() != 0
+ && autoPlayEnabled
+ && !isExternalPlayerEnabled()
+ && isAutoplayAllowedByUser();
+ }
+
+ private boolean isAutoplayAllowedByUser () {
+ if (activity == null) return false;
+
+ switch (PlayerHelper.getAutoplayType(activity)) {
+ case PlayerHelper.AutoplayType.AUTOPLAY_TYPE_NEVER:
+ return false;
+ case PlayerHelper.AutoplayType.AUTOPLAY_TYPE_WIFI:
+ return !ListHelper.isMeteredNetwork(activity);
+ case PlayerHelper.AutoplayType.AUTOPLAY_TYPE_ALWAYS:
+ default:
+ return true;
+ }
}
private void addVideoPlayerView() {
@@ -1275,7 +1293,7 @@ public void onReceive(Context context, Intent intent) {
}
};
IntentFilter intentFilter = new IntentFilter(ACTION_SHOW_MAIN_PLAYER);
- getActivity().registerReceiver(broadcastReceiver, intentFilter);
+ activity.registerReceiver(broadcastReceiver, intentFilter);
}
@@ -1287,23 +1305,23 @@ private boolean globalScreenOrientationLocked() {
// 1: Screen orientation changes using accelerometer
// 0: Screen orientation is locked
return !(android.provider.Settings.System.getInt(
- getContext().getContentResolver(), Settings.System.ACCELEROMETER_ROTATION, 0) == 1);
+ activity.getContentResolver(), Settings.System.ACCELEROMETER_ROTATION, 0) == 1);
}
private void restoreDefaultOrientation() {
- if (player == null || !player.videoPlayerSelected()) return;
+ if (player == null || !player.videoPlayerSelected() || activity == null) return;
if (player != null && player.isInFullscreen()) player.toggleFullscreen();
// This will show systemUI and pause the player.
// User can tap on Play button and video will be in fullscreen mode again
if (globalScreenOrientationLocked()) removeVideoPlayerView();
- getActivity().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
+ activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
}
private void setupOrientation() {
- if (player == null || !player.videoPlayerSelected()) return;
+ if (player == null || !player.videoPlayerSelected() || activity == null) return;
- SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(getActivity());
+ SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(activity);
int newOrientation;
if (globalScreenOrientationLocked()) {
boolean lastOrientationWasLandscape
@@ -1314,14 +1332,14 @@ private void setupOrientation() {
} else
newOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
- if (newOrientation != getActivity().getRequestedOrientation())
- getActivity().setRequestedOrientation(newOrientation);
+ if (newOrientation != activity.getRequestedOrientation())
+ activity.setRequestedOrientation(newOrientation);
}
@Override
public void onSettingsChanged() {
- if(!globalScreenOrientationLocked())
- getActivity().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
+ if(activity != null && !globalScreenOrientationLocked())
+ activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
}
/*//////////////////////////////////////////////////////////////////////////
@@ -1515,7 +1533,7 @@ public void openDownloadDialog() {
downloadDialog.setSelectedVideoStream(selectedVideoStreamIndex);
downloadDialog.setSubtitleStreams(currentInfo.getSubtitles());
- downloadDialog.show(getActivity().getSupportFragmentManager(), "downloadDialog");
+ downloadDialog.show(activity.getSupportFragmentManager(), "downloadDialog");
} catch (Exception e) {
ErrorActivity.ErrorInfo info = ErrorActivity.ErrorInfo.make(UserAction.UI_ERROR,
ServiceList.all()
@@ -1525,10 +1543,10 @@ public void openDownloadDialog() {
.getName(), "",
R.string.could_not_setup_download_menu);
- ErrorActivity.reportError(getActivity(),
+ ErrorActivity.reportError(activity,
e,
- getActivity().getClass(),
- getActivity().findViewById(android.R.id.content), info);
+ activity.getClass(),
+ activity.findViewById(android.R.id.content), info);
}
}
@@ -1744,13 +1762,17 @@ public boolean isFragmentStopped() {
private void showSystemUi() {
if (DEBUG) Log.d(TAG, "showSystemUi() called");
- getActivity().getWindow().getDecorView().setSystemUiVisibility(0);
- getActivity().getWindow().clearFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS);
+ if (activity == null) return;
+
+ activity.getWindow().getDecorView().setSystemUiVisibility(0);
+ activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS);
}
private void hideSystemUi() {
if (DEBUG) Log.d(TAG, "hideSystemUi() called");
+ if (activity == null) return;
+
int visibility = View.SYSTEM_UI_FLAG_LAYOUT_STABLE
| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
@@ -1769,7 +1791,9 @@ public void hideSystemUIIfNeeded() {
}
private void setupBrightness(boolean save) {
- WindowManager.LayoutParams lp = getActivity().getWindow().getAttributes();
+ if (activity == null) return;
+
+ WindowManager.LayoutParams lp = activity.getWindow().getAttributes();
float brightnessLevel;
if (save) {
@@ -1787,7 +1811,7 @@ private void setupBrightness(boolean save) {
lp.screenBrightness = brightnessLevel;
}
- getActivity().getWindow().setAttributes(lp);
+ activity.getWindow().setAttributes(lp);
}
private void checkLandscape() {
diff --git a/app/src/main/java/org/schabi/newpipe/fragments/list/channel/ChannelFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/list/channel/ChannelFragment.java
index c20ff0fc2d4..832e2ff9bae 100644
--- a/app/src/main/java/org/schabi/newpipe/fragments/list/channel/ChannelFragment.java
+++ b/app/src/main/java/org/schabi/newpipe/fragments/list/channel/ChannelFragment.java
@@ -389,7 +389,7 @@ public void handleResult(@NonNull ChannelInfo result) {
monitorSubscription(result);
headerPlayAllButton.setOnClickListener(
- view -> NavigationHelper.playOnMainPlayer(activity, getPlayQueue(), false));
+ view -> NavigationHelper.playOnMainPlayer(activity, getPlayQueue(), true));
headerPopupButton.setOnClickListener(
view -> NavigationHelper.playOnPopupPlayer(activity, getPlayQueue(), false));
headerBackgroundButton.setOnClickListener(
diff --git a/app/src/main/java/org/schabi/newpipe/fragments/list/playlist/PlaylistFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/list/playlist/PlaylistFragment.java
index 6941741af4c..f3f14f746dc 100644
--- a/app/src/main/java/org/schabi/newpipe/fragments/list/playlist/PlaylistFragment.java
+++ b/app/src/main/java/org/schabi/newpipe/fragments/list/playlist/PlaylistFragment.java
@@ -295,7 +295,7 @@ public void handleResult(@NonNull final PlaylistInfo result) {
.subscribe(getPlaylistBookmarkSubscriber());
headerPlayAllButton.setOnClickListener(view ->
- NavigationHelper.playOnMainPlayer(activity, getPlayQueue(), false));
+ NavigationHelper.playOnMainPlayer(activity, getPlayQueue(), true));
headerPopupButton.setOnClickListener(view ->
NavigationHelper.playOnPopupPlayer(activity, getPlayQueue(), false));
headerBackgroundButton.setOnClickListener(view ->
diff --git a/app/src/main/java/org/schabi/newpipe/local/history/StatisticsPlaylistFragment.java b/app/src/main/java/org/schabi/newpipe/local/history/StatisticsPlaylistFragment.java
index 31ae70954e2..e40549b8803 100644
--- a/app/src/main/java/org/schabi/newpipe/local/history/StatisticsPlaylistFragment.java
+++ b/app/src/main/java/org/schabi/newpipe/local/history/StatisticsPlaylistFragment.java
@@ -310,7 +310,7 @@ public void handleResult(@NonNull List result) {
}
headerPlayAllButton.setOnClickListener(view ->
- NavigationHelper.playOnMainPlayer(activity, getPlayQueue(), false));
+ NavigationHelper.playOnMainPlayer(activity, getPlayQueue(), true));
headerPopupButton.setOnClickListener(view ->
NavigationHelper.playOnPopupPlayer(activity, getPlayQueue(), false));
headerBackgroundButton.setOnClickListener(view ->
diff --git a/app/src/main/java/org/schabi/newpipe/local/playlist/LocalPlaylistFragment.java b/app/src/main/java/org/schabi/newpipe/local/playlist/LocalPlaylistFragment.java
index 9e72838ad60..33f98614c84 100644
--- a/app/src/main/java/org/schabi/newpipe/local/playlist/LocalPlaylistFragment.java
+++ b/app/src/main/java/org/schabi/newpipe/local/playlist/LocalPlaylistFragment.java
@@ -319,7 +319,7 @@ public void handleResult(@NonNull List result) {
setVideoCount(itemListAdapter.getItemsList().size());
headerPlayAllButton.setOnClickListener(view ->
- NavigationHelper.playOnMainPlayer(activity, getPlayQueue(), false));
+ NavigationHelper.playOnMainPlayer(activity, getPlayQueue(), true));
headerPopupButton.setOnClickListener(view ->
NavigationHelper.playOnPopupPlayer(activity, getPlayQueue(), false));
headerBackgroundButton.setOnClickListener(view ->
diff --git a/app/src/main/java/org/schabi/newpipe/player/BackgroundPlayerActivity.java b/app/src/main/java/org/schabi/newpipe/player/BackgroundPlayerActivity.java
index bf3e202d2ed..5078a01b840 100644
--- a/app/src/main/java/org/schabi/newpipe/player/BackgroundPlayerActivity.java
+++ b/app/src/main/java/org/schabi/newpipe/player/BackgroundPlayerActivity.java
@@ -21,7 +21,7 @@ public String getTag() {
@Override
public String getSupportActionTitle() {
- return getResources().getString(R.string.title_activity_background_player);
+ return getResources().getString(R.string.title_activity_play_queue);
}
@Override
diff --git a/app/src/main/java/org/schabi/newpipe/player/VideoPlayerImpl.java b/app/src/main/java/org/schabi/newpipe/player/VideoPlayerImpl.java
index 21934fb7024..39a16afae3a 100644
--- a/app/src/main/java/org/schabi/newpipe/player/VideoPlayerImpl.java
+++ b/app/src/main/java/org/schabi/newpipe/player/VideoPlayerImpl.java
@@ -689,9 +689,6 @@ private static void showInstallKoreDialog(final Context context) {
@Override
public void onPlaybackSpeedClicked() {
if (videoPlayerSelected()) {
- // It hides status bar in fullscreen mode
- hideSystemUIIfNeeded();
-
PlaybackParameterDialog
.newInstance(getPlaybackSpeed(), getPlaybackPitch(), getPlaybackSkipSilence(), this)
.show(getParentActivity().getSupportFragmentManager(), null);
@@ -1097,9 +1094,7 @@ private void showOrHideButtons() {
private void showSystemUIPartially() {
if (isInFullscreen() && getParentActivity() != null) {
- int visibility = View.SYSTEM_UI_FLAG_LAYOUT_STABLE
- | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
- | View.SYSTEM_UI_FLAG_FULLSCREEN;
+ int visibility = View.SYSTEM_UI_FLAG_LAYOUT_STABLE;
getParentActivity().getWindow().getDecorView().setSystemUiVisibility(visibility);
}
}
@@ -1143,6 +1138,13 @@ private void setControlsSize() {
ViewGroup controlsRoot = getRootView().findViewById(R.id.playbackControlRoot);
controlsRoot.getLayoutParams().height = isFullscreen ? size.y : ViewGroup.LayoutParams.MATCH_PARENT;
controlsRoot.requestLayout();
+
+ int statusBarHeight = 0;
+ int resourceId = service.getResources().getIdentifier("status_bar_height_landscape", "dimen", "android");
+ if (resourceId > 0) statusBarHeight = service.getResources().getDimensionPixelSize(resourceId);
+
+ getRootView().findViewById(R.id.playbackWindowRoot).setPadding(0, isFullscreen ? statusBarHeight : 0, 0, 0);
+ getRootView().findViewById(R.id.playbackWindowRoot).requestLayout();
}
private void updatePlaybackButtons() {
diff --git a/app/src/main/java/org/schabi/newpipe/player/helper/PlayerHelper.java b/app/src/main/java/org/schabi/newpipe/player/helper/PlayerHelper.java
index 5ca02980d17..80f38afb23f 100644
--- a/app/src/main/java/org/schabi/newpipe/player/helper/PlayerHelper.java
+++ b/app/src/main/java/org/schabi/newpipe/player/helper/PlayerHelper.java
@@ -44,6 +44,9 @@
import static com.google.android.exoplayer2.ui.AspectRatioFrameLayout.RESIZE_MODE_FIT;
import static com.google.android.exoplayer2.ui.AspectRatioFrameLayout.RESIZE_MODE_ZOOM;
import static java.lang.annotation.RetentionPolicy.SOURCE;
+import static org.schabi.newpipe.player.helper.PlayerHelper.AutoplayType.AUTOPLAY_TYPE_ALWAYS;
+import static org.schabi.newpipe.player.helper.PlayerHelper.AutoplayType.AUTOPLAY_TYPE_WIFI;
+import static org.schabi.newpipe.player.helper.PlayerHelper.AutoplayType.AUTOPLAY_TYPE_NEVER;
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_NONE;
import static org.schabi.newpipe.player.helper.PlayerHelper.MinimizeMode.MINIMIZE_ON_EXIT_MODE_POPUP;
@@ -64,6 +67,15 @@ private PlayerHelper() {}
int MINIMIZE_ON_EXIT_MODE_BACKGROUND = 1;
int MINIMIZE_ON_EXIT_MODE_POPUP = 2;
}
+
+ @Retention(SOURCE)
+ @IntDef({AUTOPLAY_TYPE_ALWAYS, AUTOPLAY_TYPE_WIFI,
+ AUTOPLAY_TYPE_NEVER})
+ public @interface AutoplayType {
+ int AUTOPLAY_TYPE_ALWAYS = 0;
+ int AUTOPLAY_TYPE_WIFI = 1;
+ int AUTOPLAY_TYPE_NEVER = 2;
+ }
////////////////////////////////////////////////////////////////////////////
// Exposed helpers
////////////////////////////////////////////////////////////////////////////
@@ -202,6 +214,22 @@ public static int getMinimizeOnExitAction(@NonNull final Context context) {
}
}
+ @AutoplayType
+ public static int getAutoplayType(@NonNull final Context context) {
+ final String defaultType = context.getString(R.string.autoplay_always_key);
+ final String wifi = context.getString(R.string.autoplay_wifi_key);
+ final String never = context.getString(R.string.autoplay_never_key);
+
+ final String type = getAutoplayType(context, defaultType);
+ if (type.equals(wifi)) {
+ return AUTOPLAY_TYPE_WIFI;
+ } else if (type.equals(never)) {
+ return AUTOPLAY_TYPE_NEVER;
+ } else {
+ return AUTOPLAY_TYPE_ALWAYS;
+ }
+ }
+
@NonNull
public static SeekParameters getSeekParameters(@NonNull final Context context) {
return isUsingInexactSeek(context) ?
@@ -351,6 +379,12 @@ private static String getMinimizeOnExitAction(@NonNull final Context context,
key);
}
+ private static String getAutoplayType(@NonNull final Context context,
+ final String key) {
+ return getPreferences(context).getString(context.getString(R.string.autoplay_key),
+ key);
+ }
+
private static SinglePlayQueue getAutoQueuedSinglePlayQueue(StreamInfoItem streamInfoItem) {
SinglePlayQueue singlePlayQueue = new SinglePlayQueue(streamInfoItem);
singlePlayQueue.getItem().setAutoQueued(true);
diff --git a/app/src/main/java/org/schabi/newpipe/util/ListHelper.java b/app/src/main/java/org/schabi/newpipe/util/ListHelper.java
index eb950b1ed67..d878a2b87cb 100644
--- a/app/src/main/java/org/schabi/newpipe/util/ListHelper.java
+++ b/app/src/main/java/org/schabi/newpipe/util/ListHelper.java
@@ -445,7 +445,7 @@ private static String getResolutionLimit(Context context) {
* @param context App context
* @return {@code true} if connected to a metered network
*/
- private static boolean isMeteredNetwork(Context context)
+ public static boolean isMeteredNetwork(Context context)
{
ConnectivityManager manager = (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE);
if (manager == null || manager.getActiveNetworkInfo() == null) return false;
diff --git a/app/src/main/java/org/schabi/newpipe/util/NavigationHelper.java b/app/src/main/java/org/schabi/newpipe/util/NavigationHelper.java
index 648894cc1d7..8b867a328a9 100644
--- a/app/src/main/java/org/schabi/newpipe/util/NavigationHelper.java
+++ b/app/src/main/java/org/schabi/newpipe/util/NavigationHelper.java
@@ -116,8 +116,8 @@ public static Intent getPlayerIntent(@NonNull final Context context,
.putExtra(BasePlayer.PLAYBACK_SKIP_SILENCE, playbackSkipSilence);
}
- public static void playOnMainPlayer(final AppCompatActivity activity, final PlayQueue queue, final boolean resumePlayback) {
- playOnMainPlayer(activity.getSupportFragmentManager(), queue, resumePlayback);
+ public static void playOnMainPlayer(final AppCompatActivity activity, final PlayQueue queue, final boolean autoPlay) {
+ playOnMainPlayer(activity.getSupportFragmentManager(), queue, autoPlay);
}
public static void playOnMainPlayer(final FragmentManager fragmentManager, final PlayQueue queue, boolean autoPlay) {
diff --git a/app/src/main/res/layout-large-land/activity_main_player.xml b/app/src/main/res/layout-large-land/activity_main_player.xml
index d0602ed75f6..7fb1872cfbb 100644
--- a/app/src/main/res/layout-large-land/activity_main_player.xml
+++ b/app/src/main/res/layout-large-land/activity_main_player.xml
@@ -134,6 +134,12 @@
android:visibility="gone"
tools:visibility="visible">
+
+
-
-
+
+
-
-
@string/minimize_on_exit_popup_description
+
+ autoplay_key
+ @string/autoplay_always_key
+ autoplay_always_key
+ autoplay_wifi_key
+ autoplay_never_key
+
+ - @string/autoplay_always_key
+ - @string/autoplay_wifi_key
+ - @string/autoplay_never_key
+
+
+ - @string/autoplay_always_description
+ - @string/autoplay_wifi_description
+ - @string/autoplay_never_description
+
+
default_resolution
360p
show_higher_resolutions
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 19013322de2..3a575ae25cc 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -411,6 +411,7 @@
Conferences
%1$s/%2$s
+ Play queue
Background player
Popup player
Remove
@@ -520,6 +521,11 @@
None
Minimize to background player
Minimize to popup player
+
+ Start playback automatically — %s
+ Always
+ Only on WiFi
+ Never
List view mode
List
Grid
diff --git a/app/src/main/res/xml/video_audio_settings.xml b/app/src/main/res/xml/video_audio_settings.xml
index 0ff43ce90c4..447fa90189b 100644
--- a/app/src/main/res/xml/video_audio_settings.xml
+++ b/app/src/main/res/xml/video_audio_settings.xml
@@ -105,6 +105,15 @@
android:summary="@string/minimize_on_exit_summary"
android:title="@string/minimize_on_exit_title"/>
+
+
Date: Thu, 9 Jan 2020 18:28:06 +0300
Subject: [PATCH 008/398] Autoplay enhancement and new button at the top left
corner - added a video close button to the top left corner - autoplay will
not work if stream plays in background or popup players
---
app/src/main/AndroidManifest.xml | 4 +-
.../fragments/detail/VideoDetailFragment.java | 37 +++++++++++++------
.../newpipe/player/VideoPlayerImpl.java | 9 +++++
.../activity_main_player.xml | 14 +++++++
.../main/res/layout/activity_main_player.xml | 14 +++++++
5 files changed, 65 insertions(+), 13 deletions(-)
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 0f8339f81e0..18e42452442 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -38,9 +38,9 @@
-
+
{
if (l != ol || t != ot || r != or || b != ob) {
@@ -555,9 +560,11 @@ public void toggleFullscreen() {
if (!isInFullscreen()) {
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);
}
}
@@ -597,6 +604,8 @@ public void onClick(View v) {
} else if (v.getId() == fullscreenButton.getId()) {
toggleFullscreen();
+ } else if (v.getId() == playerCloseButton.getId()) {
+ service.sendBroadcast(new Intent(VideoDetailFragment.ACTION_HIDE_MAIN_PLAYER));
}
if (getCurrentState() != STATE_COMPLETED) {
diff --git a/app/src/main/res/layout-large-land/activity_main_player.xml b/app/src/main/res/layout-large-land/activity_main_player.xml
index 7fb1872cfbb..df0ada0b0a1 100644
--- a/app/src/main/res/layout-large-land/activity_main_player.xml
+++ b/app/src/main/res/layout-large-land/activity_main_player.xml
@@ -175,6 +175,20 @@
android:paddingLeft="2dp"
tools:ignore="RtlHardcoded">
+
+
+
+
Date: Thu, 9 Jan 2020 19:27:10 +0300
Subject: [PATCH 009/398] Changed default autoplay type to "Only on WiFi"
---
.../org/schabi/newpipe/player/helper/PlayerHelper.java | 10 +++++-----
app/src/main/res/values/settings_keys.xml | 2 +-
2 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/app/src/main/java/org/schabi/newpipe/player/helper/PlayerHelper.java b/app/src/main/java/org/schabi/newpipe/player/helper/PlayerHelper.java
index 80f38afb23f..a0152c13a89 100644
--- a/app/src/main/java/org/schabi/newpipe/player/helper/PlayerHelper.java
+++ b/app/src/main/java/org/schabi/newpipe/player/helper/PlayerHelper.java
@@ -216,17 +216,17 @@ public static int getMinimizeOnExitAction(@NonNull final Context context) {
@AutoplayType
public static int getAutoplayType(@NonNull final Context context) {
- final String defaultType = context.getString(R.string.autoplay_always_key);
- final String wifi = context.getString(R.string.autoplay_wifi_key);
+ final String defaultType = context.getString(R.string.autoplay_wifi_key);
+ final String always = context.getString(R.string.autoplay_always_key);
final String never = context.getString(R.string.autoplay_never_key);
final String type = getAutoplayType(context, defaultType);
- if (type.equals(wifi)) {
- return AUTOPLAY_TYPE_WIFI;
+ if (type.equals(always)) {
+ return AUTOPLAY_TYPE_ALWAYS;
} else if (type.equals(never)) {
return AUTOPLAY_TYPE_NEVER;
} else {
- return AUTOPLAY_TYPE_ALWAYS;
+ return AUTOPLAY_TYPE_WIFI;
}
}
diff --git a/app/src/main/res/values/settings_keys.xml b/app/src/main/res/values/settings_keys.xml
index ed540ef413d..40439745081 100644
--- a/app/src/main/res/values/settings_keys.xml
+++ b/app/src/main/res/values/settings_keys.xml
@@ -65,7 +65,7 @@
autoplay_key
- @string/autoplay_always_key
+ @string/autoplay_wifi_key
autoplay_always_key
autoplay_wifi_key
autoplay_never_key
From 421b8214cb2d630f179d0786f9a7e2090fa9d10f Mon Sep 17 00:00:00 2001
From: Avently <7953703+avently@users.noreply.github.com>
Date: Fri, 10 Jan 2020 17:32:05 +0300
Subject: [PATCH 010/398] Fixes of VideoDetailFragment
---
.../fragments/detail/VideoDetailFragment.java | 24 ++++++++++---------
.../newpipe/player/VideoPlayerImpl.java | 13 +++++-----
2 files changed, 19 insertions(+), 18 deletions(-)
diff --git a/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java
index b958a5a3f35..22db9fadc56 100644
--- a/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java
+++ b/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java
@@ -874,7 +874,7 @@ public boolean onBackPressed() {
}
StackItem currentPeek = stack.peek();
- if (currentPeek != null && currentPeek.getPlayQueue() != playQueue) {
+ if (currentPeek != null && !currentPeek.getPlayQueue().equals(playQueue)) {
// When user selected a stream but didn't start playback this stream will not be added to backStack.
// Then he press Back and the last saved item from history will show up
setupFromHistoryItem(currentPeek);
@@ -1091,8 +1091,7 @@ private void openNormalPlayer() {
startService(true);
return;
}
- if (currentInfo == null || playQueue == null)
- return;
+ if (currentInfo == null) return;
PlayQueue queue = setupPlayQueueForIntent(false);
@@ -1120,7 +1119,6 @@ private PlayQueue setupPlayQueueForIntent(boolean append) {
// Size can be 0 because queue removes bad stream automatically when error occurs
if (playQueue == null || playQueue.size() == 0)
queue = new SinglePlayQueue(currentInfo);
- this.playQueue = queue;
return queue;
}
@@ -1404,8 +1402,7 @@ public void handleResult(@NonNull StreamInfo info) {
super.handleResult(info);
currentInfo = info;
- setInitialData(info.getServiceId(), info.getOriginalUrl(), info.getName(),
- playQueue == null ? new SinglePlayQueue(info) : playQueue);
+ setInitialData(info.getServiceId(), info.getOriginalUrl(), info.getName(), playQueue);
if(showRelatedStreams){
if(null == relatedStreamsLayout){ //phone
@@ -1665,8 +1662,13 @@ public void onPlaybackUpdate(int state, int repeatMode, boolean shuffled, Playba
restoreDefaultOrientation();
break;
case BasePlayer.STATE_PLAYING:
- if (positionView.getAlpha() != 1f) animateView(positionView, true, 100);
- if (detailPositionView.getAlpha() != 1f) animateView(detailPositionView, true, 100);
+ if (positionView.getAlpha() != 1f
+ && player.getPlayQueue() != null
+ && player.getPlayQueue().getItem() != null
+ && player.getPlayQueue().getItem().getUrl().equals(url)) {
+ animateView(positionView, true, 100);
+ animateView(detailPositionView, true, 100);
+ }
setupOrientation();
break;
}
@@ -1677,7 +1679,8 @@ public void onProgressUpdate(int currentProgress, int duration, int bufferPercen
// Progress updates every second even if media is paused. It's useless until playing
if (!player.getPlayer().isPlaying() || playQueue == null) return;
- if (playQueue == player.getPlayQueue()) showPlaybackProgress(currentProgress, duration);
+ if (player.getPlayQueue().getItem().getUrl().equals(url))
+ showPlaybackProgress(currentProgress, duration);
// We don't want to interrupt playback and don't want to see notification if player is stopped
// since next lines of code will enable background playback if needed
@@ -1907,9 +1910,8 @@ else if (bottomSheetState == BottomSheetBehavior.STATE_EXPANDED)
if (player != null && player.isInFullscreen()) showSystemUi();
break;
case BottomSheetBehavior.STATE_DRAGGING:
- if (player != null && player.isControlsVisible()) player.hideControls(0, 0);
- break;
case BottomSheetBehavior.STATE_SETTLING:
+ if (player != null && player.isControlsVisible()) player.hideControls(0, 0);
break;
}
}
diff --git a/app/src/main/java/org/schabi/newpipe/player/VideoPlayerImpl.java b/app/src/main/java/org/schabi/newpipe/player/VideoPlayerImpl.java
index c773d719e8d..3bf734458f3 100644
--- a/app/src/main/java/org/schabi/newpipe/player/VideoPlayerImpl.java
+++ b/app/src/main/java/org/schabi/newpipe/player/VideoPlayerImpl.java
@@ -510,7 +510,7 @@ public void onPlayNext() {
@Override
protected void initPlayback(@NonNull PlayQueue queue, int repeatMode, float playbackSpeed, float playbackPitch, boolean playbackSkipSilence, boolean playOnReady) {
super.initPlayback(queue, repeatMode, playbackSpeed, playbackPitch, playbackSkipSilence, playOnReady);
- updateQueue(queue);
+ updateQueue();
}
/*//////////////////////////////////////////////////////////////////////////
@@ -1474,7 +1474,6 @@ private void end() {
public void setFragmentListener(PlayerServiceEventListener listener) {
fragmentListener = listener;
- updateMetadata();
updatePlayback();
triggerProgressUpdate();
}
@@ -1498,12 +1497,12 @@ public void removeFragmentListener(PlayerServiceEventListener listener) {
}
}
- private void updateQueue(PlayQueue queue) {
- if (fragmentListener != null) {
- fragmentListener.onQueueUpdate(queue);
+ private void updateQueue() {
+ if (fragmentListener != null && playQueue != null) {
+ fragmentListener.onQueueUpdate(playQueue);
}
- if (activityListener != null) {
- activityListener.onQueueUpdate(queue);
+ if (activityListener != null && playQueue != null) {
+ activityListener.onQueueUpdate(playQueue);
}
}
From 0c394b123c5dd2c480d4315c66d91d5a6faa3e6a Mon Sep 17 00:00:00 2001
From: Avently <7953703+avently@users.noreply.github.com>
Date: Mon, 13 Jan 2020 19:24:28 +0300
Subject: [PATCH 011/398] Another fix of VideoDetailFragment
---
.../fragments/detail/VideoDetailFragment.java | 22 ++++++-------------
1 file changed, 7 insertions(+), 15 deletions(-)
diff --git a/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java
index 22db9fadc56..b1929891b92 100644
--- a/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java
+++ b/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java
@@ -112,7 +112,6 @@ public class VideoDetailFragment
public static final String ACTION_SHOW_MAIN_PLAYER = "org.schabi.newpipe.fragments.VideoDetailFragment.ACTION_SHOW_MAIN_PLAYER";
public static final String ACTION_HIDE_MAIN_PLAYER = "org.schabi.newpipe.fragments.VideoDetailFragment.ACTION_HIDE_MAIN_PLAYER";
- private boolean autoPlayEnabled;
private boolean showRelatedStreams;
private boolean showComments;
private String selectedTabTag;
@@ -127,6 +126,8 @@ public class VideoDetailFragment
protected PlayQueue playQueue;
@State
int bottomSheetState = BottomSheetBehavior.STATE_EXPANDED;
+ @State
+ protected boolean autoPlayEnabled = true;
private StreamInfo currentInfo;
private Disposable currentWorker;
@@ -311,9 +312,6 @@ public static VideoDetailFragment getInstance(int serviceId, String videoUrl, St
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
- // Let's play all streams automatically
- setAutoplay(true);
-
activity.setVolumeControlStream(AudioManager.STREAM_MUSIC);
showRelatedStreams = PreferenceManager.getDefaultSharedPreferences(activity)
@@ -870,6 +868,7 @@ public boolean onBackPressed() {
if (player != null && player.isInFullscreen()) {
player.onPause();
restoreDefaultOrientation();
+ setAutoplay(false);
return true;
}
@@ -1169,8 +1168,7 @@ private boolean isExternalPlayerEnabled() {
// This method overrides default behaviour when setAutoplay() is called.
// Don't auto play if the user selected an external player or disabled it in settings
private boolean isAutoplayEnabled() {
- return playQueue != null && playQueue.getStreams().size() != 0
- && autoPlayEnabled
+ return autoPlayEnabled
&& !isExternalPlayerEnabled()
&& (player == null || player.videoPlayerSelected())
&& isAutoplayAllowedByUser();
@@ -1326,22 +1324,16 @@ private void restoreDefaultOrientation() {
if (player != null && player.isInFullscreen()) player.toggleFullscreen();
// This will show systemUI and pause the player.
// User can tap on Play button and video will be in fullscreen mode again
- if (globalScreenOrientationLocked()) removeVideoPlayerView();
activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
}
private void setupOrientation() {
if (player == null || !player.videoPlayerSelected() || activity == null) return;
- SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(activity);
int newOrientation;
- if (globalScreenOrientationLocked()) {
- boolean lastOrientationWasLandscape
- = sharedPreferences.getBoolean(getString(R.string.last_orientation_landscape_key), false);
- newOrientation = lastOrientationWasLandscape
- ? ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE
- : ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT;
- } else
+ if (globalScreenOrientationLocked())
+ newOrientation = ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE;
+ else
newOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
if (newOrientation != activity.getRequestedOrientation())
From d1609cba90006e18a0dde03f09d133aedf73e985 Mon Sep 17 00:00:00 2001
From: Avently <7953703+avently@users.noreply.github.com>
Date: Wed, 15 Jan 2020 21:32:29 +0300
Subject: [PATCH 012/398] Enhancements to background playback and media button
handling
---
.../fragments/detail/VideoDetailFragment.java | 14 +++++-----
.../org/schabi/newpipe/player/MainPlayer.java | 26 ++++++++++++++++---
.../newpipe/player/VideoPlayerImpl.java | 10 +++----
3 files changed, 32 insertions(+), 18 deletions(-)
diff --git a/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java
index b1929891b92..5493d05cc63 100644
--- a/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java
+++ b/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java
@@ -21,6 +21,7 @@
import androidx.coordinatorlayout.widget.CoordinatorLayout;
import com.google.android.exoplayer2.ExoPlaybackException;
import com.google.android.exoplayer2.PlaybackParameters;
+import com.google.android.exoplayer2.Player;
import com.google.android.material.appbar.AppBarLayout;
import com.google.android.material.bottomsheet.BottomSheetBehavior;
import com.google.android.material.tabs.TabLayout;
@@ -237,9 +238,8 @@ public void onServiceConnected(ComponentName compName, IBinder service) {
if (!player.videoPlayerSelected()) return;
- if (currentInfo == null && !wasCleared()) selectAndLoadVideo(serviceId, url, name, playQueue);
-
- if (player.getPlayQueue() != null) addVideoPlayerView();
+ // STATE_IDLE means the player is stopped
+ if (player.getPlayer() != null && player.getPlayer().getPlaybackState() != Player.STATE_IDLE) addVideoPlayerView();
// If the video is playing but orientation changed let's make the video in fullscreen again
@@ -375,7 +375,7 @@ public void onResume() {
updateFlags = 0;
}
- // Check if it was loading when the fragment was stopped/paused,
+ // Check if it was loading when the fragment was stopped/paused
if (wasLoading.getAndSet(false) && !wasCleared()) {
selectAndLoadVideo(serviceId, url, name, playQueue);
} else if (currentInfo != null) {
@@ -537,7 +537,7 @@ public void onClick(View v) {
bottomSheetBehavior.setState(BottomSheetBehavior.STATE_EXPANDED);
break;
case R.id.overlay_play_pause_button:
- if (player != null) {
+ if (player != null && player.getPlayer() != null && player.getPlayer().getPlaybackState() != Player.STATE_IDLE) {
player.onPlayPause();
player.hideControls(0,0);
showSystemUi();
@@ -900,9 +900,9 @@ public boolean onBackPressed() {
}
private void setupFromHistoryItem(StackItem item) {
+ setAutoplay(false);
hideMainPlayer();
- setAutoplay(false);
selectAndLoadVideo(
item.getServiceId(),
item.getUrl(),
@@ -1107,7 +1107,7 @@ private void hideMainPlayer() {
return;
removeVideoPlayerView();
- playerService.stop();
+ playerService.stop(isAutoplayEnabled());
playerService.getView().setVisibility(View.GONE);
}
diff --git a/app/src/main/java/org/schabi/newpipe/player/MainPlayer.java b/app/src/main/java/org/schabi/newpipe/player/MainPlayer.java
index 4e3c070a508..b7081f71ef4 100644
--- a/app/src/main/java/org/schabi/newpipe/player/MainPlayer.java
+++ b/app/src/main/java/org/schabi/newpipe/player/MainPlayer.java
@@ -113,6 +113,10 @@ private void createView() {
public int onStartCommand(Intent intent, int flags, int startId) {
if (DEBUG) Log.d(TAG, "onStartCommand() called with: intent = [" + intent +
"], flags = [" + flags + "], startId = [" + startId + "]");
+
+ if (Intent.ACTION_MEDIA_BUTTON.equals(intent.getAction()) || intent.getStringExtra(VideoPlayer.PLAY_QUEUE_KEY) != null)
+ showNotificationAndStartForeground();
+
playerImpl.handleIntent(intent);
if (playerImpl.mediaSessionManager != null) {
playerImpl.mediaSessionManager.handleMediaButtonIntent(intent);
@@ -120,15 +124,20 @@ public int onStartCommand(Intent intent, int flags, int startId) {
return START_NOT_STICKY;
}
- public void stop() {
- if (DEBUG)
- Log.d(TAG, "stop() called");
+ public void stop(boolean autoplayEnabled) {
+ if (DEBUG) Log.d(TAG, "stop() called");
if (playerImpl.getPlayer() != null) {
playerImpl.wasPlaying = playerImpl.getPlayer().getPlayWhenReady();
- // We can't pause the player here because it will make transition from one stream to a new stream not smooth
+ // Releases wifi & cpu, disables keepScreenOn, etc.
+ if (!autoplayEnabled) playerImpl.onPause();
+ // We can't just pause the player here because it will make transition from one stream to a new stream not smooth
playerImpl.getPlayer().stop(false);
playerImpl.setRecovery();
+ // 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.
+ // When autoplay enabled such notification flashing is annoying so skip this case
+ if (!autoplayEnabled) stopForeground(true);
}
}
@@ -211,6 +220,15 @@ public void removeViewFromParent() {
}
}
+ private void showNotificationAndStartForeground() {
+ resetNotification();
+ if (getBigNotRemoteView() != null)
+ getBigNotRemoteView().setProgressBar(R.id.notificationProgressBar, 100, 0, false);
+ if (getNotRemoteView() != null)
+ getNotRemoteView().setProgressBar(R.id.notificationProgressBar, 100, 0, false);
+ startForeground(NOTIFICATION_ID, getNotBuilder().build());
+ }
+
/*//////////////////////////////////////////////////////////////////////////
// Notification
//////////////////////////////////////////////////////////////////////////*/
diff --git a/app/src/main/java/org/schabi/newpipe/player/VideoPlayerImpl.java b/app/src/main/java/org/schabi/newpipe/player/VideoPlayerImpl.java
index 3bf734458f3..2da110712f7 100644
--- a/app/src/main/java/org/schabi/newpipe/player/VideoPlayerImpl.java
+++ b/app/src/main/java/org/schabi/newpipe/player/VideoPlayerImpl.java
@@ -189,12 +189,6 @@ public void handleIntent(Intent intent) {
reload();
}
- service.resetNotification();
- if (service.getBigNotRemoteView() != null)
- service.getBigNotRemoteView().setProgressBar(R.id.notificationProgressBar, 100, 0, false);
- if (service.getNotRemoteView() != null)
- service.getNotRemoteView().setProgressBar(R.id.notificationProgressBar, 100, 0, false);
- service.startForeground(NOTIFICATION_ID, service.getNotBuilder().build());
setupElementsVisibility();
if (audioPlayerSelected()) {
@@ -1167,7 +1161,7 @@ private void updatePlaybackButtons() {
public void checkLandscape() {
AppCompatActivity parent = getParentActivity();
if (parent != null && service.isLandscape() != isInFullscreen()
- && getCurrentState() != STATE_COMPLETED && videoPlayerSelected())
+ && getCurrentState() != STATE_COMPLETED && videoPlayerSelected() && !audioOnly)
toggleFullscreen();
}
@@ -1197,6 +1191,8 @@ public void useVideoSource(boolean video) {
return;
audioOnly = !video;
+ // When a user returns from background controls could be hidden but systemUI will be shown 100%. Hide it
+ if (!audioOnly && !isControlsVisible()) hideSystemUIIfNeeded();
setRecovery();
reload();
}
From 92ff98d99ac0146db45c5f2cd1b4ebc7716c07a6 Mon Sep 17 00:00:00 2001
From: Avently <7953703+avently@users.noreply.github.com>
Date: Thu, 16 Jan 2020 14:20:22 +0300
Subject: [PATCH 013/398] New logic for handling global orientation - added a
button to manually change an orientation of a video - adapted UI for an
automatic global orientation too
---
.../fragments/detail/VideoDetailFragment.java | 61 ++++++++-----------
.../org/schabi/newpipe/player/MainPlayer.java | 2 +-
.../newpipe/player/VideoPlayerImpl.java | 41 ++++++++++++-
.../event/PlayerServiceEventListener.java | 2 +
.../newpipe/player/helper/PlayerHelper.java | 8 +++
.../settings/SettingsContentObserver.java | 29 ---------
.../activity_main_player.xml | 15 +++++
.../main/res/layout/activity_main_player.xml | 15 +++++
8 files changed, 106 insertions(+), 67 deletions(-)
delete mode 100644 app/src/main/java/org/schabi/newpipe/settings/SettingsContentObserver.java
diff --git a/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java
index 5493d05cc63..cfaf0aea47d 100644
--- a/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java
+++ b/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java
@@ -4,6 +4,7 @@
import android.app.Activity;
import android.content.*;
import android.content.pm.ActivityInfo;
+import android.database.ContentObserver;
import android.graphics.Bitmap;
import android.media.AudioManager;
import android.os.Build;
@@ -69,7 +70,6 @@
import org.schabi.newpipe.player.playqueue.*;
import org.schabi.newpipe.report.ErrorActivity;
import org.schabi.newpipe.report.UserAction;
-import org.schabi.newpipe.settings.SettingsContentObserver;
import org.schabi.newpipe.util.*;
import org.schabi.newpipe.views.AnimatedProgressBar;
@@ -97,8 +97,7 @@ public class VideoDetailFragment
View.OnClickListener,
View.OnLongClickListener,
PlayerEventListener,
- PlayerServiceEventListener,
- SettingsContentObserver.OnChangeListener {
+ PlayerServiceEventListener {
public static final String AUTO_PLAY = "auto_play";
private boolean isFragmentStopped;
@@ -203,7 +202,7 @@ public class VideoDetailFragment
private TabLayout tabLayout;
private FrameLayout relatedStreamsLayout;
- private SettingsContentObserver settingsContentObserver;
+ private ContentObserver settingsContentObserver;
private ServiceConnection serviceConnection;
private boolean bounded;
private MainPlayer playerService;
@@ -329,9 +328,15 @@ public static VideoDetailFragment getInstance(int serviceId, String videoUrl, St
startService(false);
setupBroadcastReceiver();
- settingsContentObserver = new SettingsContentObserver(new Handler(), this);
+ settingsContentObserver = new ContentObserver(new Handler()) {
+ @Override
+ public void onChange(boolean selfChange) {
+ if(activity != null && !PlayerHelper.globalScreenOrientationLocked(activity))
+ activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
+ }
+ };
activity.getContentResolver().registerContentObserver(
- android.provider.Settings.System.CONTENT_URI, true,
+ Settings.System.getUriFor(Settings.System.ACCELEROMETER_ROTATION), false,
settingsContentObserver);
}
@@ -1311,13 +1316,6 @@ public void onReceive(Context context, Intent intent) {
// Orientation listener
//////////////////////////////////////////////////////////////////////////*/
- private boolean globalScreenOrientationLocked() {
- // 1: Screen orientation changes using accelerometer
- // 0: Screen orientation is locked
- return !(android.provider.Settings.System.getInt(
- activity.getContentResolver(), Settings.System.ACCELEROMETER_ROTATION, 0) == 1);
- }
-
private void restoreDefaultOrientation() {
if (player == null || !player.videoPlayerSelected() || activity == null) return;
@@ -1327,25 +1325,6 @@ private void restoreDefaultOrientation() {
activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
}
- private void setupOrientation() {
- if (player == null || !player.videoPlayerSelected() || activity == null) return;
-
- int newOrientation;
- if (globalScreenOrientationLocked())
- newOrientation = ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE;
- else
- newOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
-
- if (newOrientation != activity.getRequestedOrientation())
- activity.setRequestedOrientation(newOrientation);
- }
-
- @Override
- public void onSettingsChanged() {
- if(activity != null && !globalScreenOrientationLocked())
- activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
- }
-
/*//////////////////////////////////////////////////////////////////////////
// Contract
//////////////////////////////////////////////////////////////////////////*/
@@ -1661,7 +1640,6 @@ public void onPlaybackUpdate(int state, int repeatMode, boolean shuffled, Playba
animateView(positionView, true, 100);
animateView(detailPositionView, true, 100);
}
- setupOrientation();
break;
}
}
@@ -1742,6 +1720,15 @@ public void onFullscreenStateChanged(boolean fullscreen) {
addVideoPlayerView();
}
+ @Override
+ public void onScreenRotationButtonClicked() {
+ int newOrientation = isLandscape() ?
+ ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED
+ : ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE;
+
+ activity.setRequestedOrientation(newOrientation);
+ }
+
/*
* Will scroll down to description view after long click on moreOptionsButton
* */
@@ -1828,9 +1815,15 @@ private void checkLandscape() {
if ((!player.isPlaying() && player.getPlayQueue() != playQueue) || player.getPlayQueue() == null)
setAutoplay(true);
+ boolean orientationLocked = PlayerHelper.globalScreenOrientationLocked(activity);
// Let's give a user time to look at video information page if video is not playing
- if (player.isPlaying())
+ if (player.isPlaying()) {
player.checkLandscape();
+ } else if (orientationLocked) {
+ player.checkLandscape();
+ player.onPlay();
+ player.showControlsThenHide();
+ }
}
private boolean isLandscape() {
diff --git a/app/src/main/java/org/schabi/newpipe/player/MainPlayer.java b/app/src/main/java/org/schabi/newpipe/player/MainPlayer.java
index b7081f71ef4..63c2f195fcc 100644
--- a/app/src/main/java/org/schabi/newpipe/player/MainPlayer.java
+++ b/app/src/main/java/org/schabi/newpipe/player/MainPlayer.java
@@ -195,7 +195,7 @@ private void onClose() {
boolean isLandscape() {
// DisplayMetrics from activity context knows about MultiWindow feature while DisplayMetrics from app context doesn't
- final DisplayMetrics metrics = playerImpl.getParentActivity() != null ?
+ final DisplayMetrics metrics = playerImpl != null && playerImpl.getParentActivity() != null ?
playerImpl.getParentActivity().getResources().getDisplayMetrics()
: getResources().getDisplayMetrics();
return metrics.heightPixels < metrics.widthPixels;
diff --git a/app/src/main/java/org/schabi/newpipe/player/VideoPlayerImpl.java b/app/src/main/java/org/schabi/newpipe/player/VideoPlayerImpl.java
index 2da110712f7..66407936c80 100644
--- a/app/src/main/java/org/schabi/newpipe/player/VideoPlayerImpl.java
+++ b/app/src/main/java/org/schabi/newpipe/player/VideoPlayerImpl.java
@@ -23,12 +23,15 @@
import android.animation.AnimatorListenerAdapter;
import android.annotation.SuppressLint;
import android.content.*;
+import android.database.ContentObserver;
import android.graphics.Bitmap;
import android.graphics.PixelFormat;
import android.graphics.Point;
import android.net.Uri;
import android.os.Build;
+import android.os.Handler;
import android.preference.PreferenceManager;
+import android.provider.Settings;
import android.util.DisplayMetrics;
import android.util.Log;
import android.util.TypedValue;
@@ -88,7 +91,7 @@
public class VideoPlayerImpl extends VideoPlayer
implements View.OnLayoutChangeListener,
PlaybackParameterDialog.Callback,
- View.OnLongClickListener{
+ View.OnLongClickListener {
private static final String TAG = ".VideoPlayerImpl";
private final float MAX_GESTURE_LENGTH = 0.75f;
@@ -109,6 +112,7 @@ public class VideoPlayerImpl extends VideoPlayer
private ImageButton openInBrowser;
private ImageButton fullscreenButton;
private ImageButton playerCloseButton;
+ private ImageButton screenRotationButton;
private ImageButton playPauseButton;
private ImageButton playPreviousButton;
@@ -139,6 +143,7 @@ public class VideoPlayerImpl extends VideoPlayer
private PlayerEventListener activityListener;
private GestureDetector gestureDetector;
private SharedPreferences defaultPreferences;
+ private ContentObserver settingsContentObserver;
@NonNull
final private AudioPlaybackResolver resolver;
@@ -233,6 +238,7 @@ public void initViews(View rootView) {
this.playWithKodi = rootView.findViewById(R.id.playWithKodi);
this.openInBrowser = rootView.findViewById(R.id.openInBrowser);
this.fullscreenButton = rootView.findViewById(R.id.fullScreenButton);
+ this.screenRotationButton = rootView.findViewById(R.id.screenRotationButton);
this.playerCloseButton = rootView.findViewById(R.id.playerCloseButton);
this.playPauseButton = rootView.findViewById(R.id.playPauseButton);
@@ -277,6 +283,7 @@ protected void setupSubtitleView(@NonNull SubtitleView view,
private void setupElementsVisibility() {
if (popupPlayerSelected()) {
fullscreenButton.setVisibility(View.VISIBLE);
+ screenRotationButton.setVisibility(View.GONE);
getRootView().findViewById(R.id.spaceBeforeControls).setVisibility(View.GONE);
getRootView().findViewById(R.id.metadataView).setVisibility(View.GONE);
queueButton.setVisibility(View.GONE);
@@ -292,6 +299,7 @@ private void setupElementsVisibility() {
playerCloseButton.setVisibility(View.GONE);
} else {
fullscreenButton.setVisibility(View.GONE);
+ setupScreenRotationButton(service.isLandscape());
getRootView().findViewById(R.id.spaceBeforeControls).setVisibility(View.VISIBLE);
getRootView().findViewById(R.id.metadataView).setVisibility(View.VISIBLE);
moreOptionsButton.setVisibility(View.VISIBLE);
@@ -337,10 +345,19 @@ public void initListeners() {
moreOptionsButton.setOnLongClickListener(this);
shareButton.setOnClickListener(this);
fullscreenButton.setOnClickListener(this);
+ screenRotationButton.setOnClickListener(this);
playWithKodi.setOnClickListener(this);
openInBrowser.setOnClickListener(this);
playerCloseButton.setOnClickListener(this);
+ settingsContentObserver = new ContentObserver(new Handler()) {
+ @Override
+ public void onChange(boolean selfChange) { setupScreenRotationButton(service.isLandscape()); }
+ };
+ service.getContentResolver().registerContentObserver(
+ Settings.System.getUriFor(Settings.System.ACCELEROMETER_ROTATION), false,
+ settingsContentObserver);
+
getRootView().addOnLayoutChangeListener((view, l, t, r, b, ol, ot, or, ob) -> {
if (l != ol || t != ot || r != or || b != ob) {
// Use smaller value to be consistent between screen orientations
@@ -560,6 +577,7 @@ public void toggleFullscreen() {
channelTextView.setVisibility(View.VISIBLE);
playerCloseButton.setVisibility(View.GONE);
}
+ setupScreenRotationButton(isInFullscreen());
}
@Override
@@ -598,6 +616,9 @@ public void onClick(View v) {
} else if (v.getId() == fullscreenButton.getId()) {
toggleFullscreen();
+ } else if (v.getId() == screenRotationButton.getId()) {
+ fragmentListener.onScreenRotationButtonClicked();
+
} else if (v.getId() == playerCloseButton.getId()) {
service.sendBroadcast(new Intent(VideoDetailFragment.ACTION_HIDE_MAIN_PLAYER));
}
@@ -689,6 +710,13 @@ private static void showInstallKoreDialog(final Context context) {
builder.create().show();
}
+ private void setupScreenRotationButton(boolean landscape) {
+ boolean orientationLocked = PlayerHelper.globalScreenOrientationLocked(service);
+ screenRotationButton.setVisibility(orientationLocked && videoPlayerSelected() ? View.VISIBLE : View.GONE);
+ screenRotationButton.setImageDrawable(service.getResources().getDrawable(
+ landscape ? R.drawable.ic_fullscreen_exit_white : R.drawable.ic_fullscreen_white));
+ }
+
@Override
public void onPlaybackSpeedClicked() {
if (videoPlayerSelected()) {
@@ -880,6 +908,13 @@ public void onCompleted() {
super.onCompleted();
}
+ @Override
+ public void destroy() {
+ super.destroy();
+
+ service.getContentResolver().unregisterContentObserver(settingsContentObserver);
+ }
+
/*//////////////////////////////////////////////////////////////////////////
// Broadcast Receiver
//////////////////////////////////////////////////////////////////////////*/
@@ -1282,7 +1317,7 @@ private void initPopup() {
getLoadingPanel().setMinimumHeight(popupLayoutParams.height);
service.removeViewFromParent();
- windowManager.addView(service.getView(), popupLayoutParams);
+ windowManager.addView(getRootView(), popupLayoutParams);
if (getAspectRatioFrameLayout().getResizeMode() == AspectRatioFrameLayout.RESIZE_MODE_ZOOM)
onResizeClicked();
@@ -1313,7 +1348,7 @@ private void initPopupCloseOverlay() {
}
private void initVideoPlayer() {
- service.getView().setLayoutParams(new FrameLayout.LayoutParams(
+ getRootView().setLayoutParams(new FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT));
}
diff --git a/app/src/main/java/org/schabi/newpipe/player/event/PlayerServiceEventListener.java b/app/src/main/java/org/schabi/newpipe/player/event/PlayerServiceEventListener.java
index 7422f9442b6..eeff08b5ce2 100644
--- a/app/src/main/java/org/schabi/newpipe/player/event/PlayerServiceEventListener.java
+++ b/app/src/main/java/org/schabi/newpipe/player/event/PlayerServiceEventListener.java
@@ -5,6 +5,8 @@
public interface PlayerServiceEventListener extends PlayerEventListener {
void onFullscreenStateChanged(boolean fullscreen);
+ void onScreenRotationButtonClicked();
+
void onMoreOptionsLongClicked();
void onPlayerError(ExoPlaybackException error);
diff --git a/app/src/main/java/org/schabi/newpipe/player/helper/PlayerHelper.java b/app/src/main/java/org/schabi/newpipe/player/helper/PlayerHelper.java
index a0152c13a89..cfce6e67860 100644
--- a/app/src/main/java/org/schabi/newpipe/player/helper/PlayerHelper.java
+++ b/app/src/main/java/org/schabi/newpipe/player/helper/PlayerHelper.java
@@ -4,6 +4,7 @@
import android.content.SharedPreferences;
import android.os.Build;
import android.preference.PreferenceManager;
+import android.provider.Settings;
import androidx.annotation.IntDef;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@@ -321,6 +322,13 @@ public static void setScreenBrightness(@NonNull final Context context, final flo
setScreenBrightness(context, setScreenBrightness, System.currentTimeMillis());
}
+ public static boolean globalScreenOrientationLocked(Context context) {
+ // 1: Screen orientation changes using accelerometer
+ // 0: Screen orientation is locked
+ return !(android.provider.Settings.System.getInt(
+ context.getContentResolver(), Settings.System.ACCELEROMETER_ROTATION, 0) == 1);
+ }
+
////////////////////////////////////////////////////////////////////////////
// Private helpers
////////////////////////////////////////////////////////////////////////////
diff --git a/app/src/main/java/org/schabi/newpipe/settings/SettingsContentObserver.java b/app/src/main/java/org/schabi/newpipe/settings/SettingsContentObserver.java
deleted file mode 100644
index 534fb26c3a9..00000000000
--- a/app/src/main/java/org/schabi/newpipe/settings/SettingsContentObserver.java
+++ /dev/null
@@ -1,29 +0,0 @@
-package org.schabi.newpipe.settings;
-
-import android.database.ContentObserver;
-import android.os.Handler;
-
-public class SettingsContentObserver extends ContentObserver {
- private OnChangeListener listener;
-
- public interface OnChangeListener {
- void onSettingsChanged();
- }
-
- public SettingsContentObserver(Handler handler, OnChangeListener listener) {
- super(handler);
- this.listener = listener;
- }
-
- @Override
- public boolean deliverSelfNotifications() {
- return super.deliverSelfNotifications();
- }
-
- @Override
- public void onChange(boolean selfChange) {
- super.onChange(selfChange);
- if (listener != null)
- listener.onSettingsChanged();
- }
-}
\ No newline at end of file
diff --git a/app/src/main/res/layout-large-land/activity_main_player.xml b/app/src/main/res/layout-large-land/activity_main_player.xml
index df0ada0b0a1..16a52cdb66e 100644
--- a/app/src/main/res/layout-large-land/activity_main_player.xml
+++ b/app/src/main/res/layout-large-land/activity_main_player.xml
@@ -466,6 +466,21 @@
android:visibility="gone"
android:background="?attr/selectableItemBackground"
tools:ignore="HardcodedText,RtlHardcoded,RtlSymmetry" />
+
+
diff --git a/app/src/main/res/layout/activity_main_player.xml b/app/src/main/res/layout/activity_main_player.xml
index b00a3a4d46c..1a0fb292fcd 100644
--- a/app/src/main/res/layout/activity_main_player.xml
+++ b/app/src/main/res/layout/activity_main_player.xml
@@ -464,6 +464,21 @@
android:visibility="gone"
android:background="?attr/selectableItemBackground"
tools:ignore="HardcodedText,RtlHardcoded,RtlSymmetry" />
+
+
From cc438fdb7babde33544e2baca2f3b59cb8e10b34 Mon Sep 17 00:00:00 2001
From: Avently <7953703+avently@users.noreply.github.com>
Date: Fri, 17 Jan 2020 17:37:53 +0300
Subject: [PATCH 014/398] Player's elements positioning is better for tablet
and in multiWindow mode - status bar got a fix for situation when a phone
vendor did not provide status bar height for landscape orientation - popup
will not be init'd twice - also fixed some non-reproduceable bugs
---
.../fragments/detail/VideoDetailFragment.java | 50 ++++++++++++-------
.../newpipe/player/VideoPlayerImpl.java | 46 +++++++++++++----
.../newpipe/player/helper/PlayerHelper.java | 6 +++
.../activity_main_player.xml | 2 -
.../fragment_video_detail.xml | 3 +-
.../main/res/layout/activity_main_player.xml | 2 -
.../main/res/layout/fragment_video_detail.xml | 3 +-
7 files changed, 74 insertions(+), 38 deletions(-)
diff --git a/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java
index cfaf0aea47d..f4c79e73dd5 100644
--- a/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java
+++ b/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java
@@ -288,8 +288,8 @@ private void startService(boolean playAfterConnect) {
}
private void stopService() {
- getContext().stopService(new Intent(getContext(), MainPlayer.class));
unbind();
+ getContext().stopService(new Intent(getContext(), MainPlayer.class));
}
@@ -325,7 +325,6 @@ public static VideoDetailFragment getInstance(int serviceId, String videoUrl, St
PreferenceManager.getDefaultSharedPreferences(activity)
.registerOnSharedPreferenceChangeListener(this);
- startService(false);
setupBroadcastReceiver();
settingsContentObserver = new ContentObserver(new Handler()) {
@@ -415,6 +414,7 @@ public void onDestroy() {
positionSubscriber = null;
currentWorker = null;
disposables = null;
+ bottomSheetBehavior.setBottomSheetCallback(null);
}
@Override
@@ -688,6 +688,7 @@ protected void initListeners() {
detailControlsPopup.setOnTouchListener(getOnControlsTouchListener());
setupBottomPlayer();
+ startService(false);
}
private View.OnTouchListener getOnControlsTouchListener() {
@@ -931,8 +932,6 @@ public void selectAndLoadVideo(int serviceId, String videoUrl, String name, Play
boolean streamIsTheSame = this.playQueue != null && this.playQueue.equals(playQueue);
// Situation when user switches from players to main player. All needed data is here, we can start watching
if (streamIsTheSame) {
- //TODO not sure about usefulness of this line in the case when user switches from one player to another
- // handleResult(currentInfo);
openVideoPlayer();
return;
}
@@ -1094,17 +1093,17 @@ private void openNormalPlayer() {
if (playerService == null) {
startService(true);
return;
- }
- if (currentInfo == null) return;
+ }
+ if (currentInfo == null) return;
- PlayQueue queue = setupPlayQueueForIntent(false);
+ PlayQueue queue = setupPlayQueueForIntent(false);
- addVideoPlayerView();
- playerService.getView().setVisibility(View.GONE);
+ // Video view can have elements visible from popup, We hide it here but once it ready the view will be shown in handleIntent()
+ playerService.getView().setVisibility(View.GONE);
+ addVideoPlayerView();
- Intent playerIntent = NavigationHelper.getPlayerIntent(
- getContext(), MainPlayer.class, queue, null, true);
- activity.startService(playerIntent);
+ Intent playerIntent = NavigationHelper.getPlayerIntent(getContext(), MainPlayer.class, queue, null, true);
+ activity.startService(playerIntent);
}
private void hideMainPlayer() {
@@ -1194,7 +1193,7 @@ private boolean isAutoplayAllowedByUser () {
}
private void addVideoPlayerView() {
- if (player == null) return;
+ if (player == null || getView() == null) return;
FrameLayout viewHolder = getView().findViewById(R.id.player_placeholder);
@@ -1213,6 +1212,8 @@ private void removeVideoPlayerView() {
}
private void makeDefaultHeightForVideoPlaceholder() {
+ if (getView() == null) return;
+
FrameLayout viewHolder = getView().findViewById(R.id.player_placeholder);
viewHolder.getLayoutParams().height = FrameLayout.LayoutParams.MATCH_PARENT;
viewHolder.requestLayout();
@@ -1322,7 +1323,9 @@ private void restoreDefaultOrientation() {
if (player != null && player.isInFullscreen()) player.toggleFullscreen();
// This will show systemUI and pause the player.
// User can tap on Play button and video will be in fullscreen mode again
- activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
+ // Note for tablet: trying to avoid orientation changes since it's not easy to physically rotate the tablet every time
+ if (!PlayerHelper.isTablet(activity))
+ activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
}
/*//////////////////////////////////////////////////////////////////////////
@@ -1356,7 +1359,7 @@ public void showLoading() {
if(relatedStreamsLayout != null){
if(showRelatedStreams){
- relatedStreamsLayout.setVisibility(View.INVISIBLE);
+ relatedStreamsLayout.setVisibility(player != null && player.isInFullscreen() ? View.GONE : View.INVISIBLE);
}else{
relatedStreamsLayout.setVisibility(View.GONE);
}
@@ -1383,7 +1386,7 @@ public void handleResult(@NonNull StreamInfo info) {
getChildFragmentManager().beginTransaction()
.replace(R.id.relatedStreamsLayout, RelatedVideosFragment.getInstance(info))
.commitNow();
- relatedStreamsLayout.setVisibility(View.VISIBLE);
+ relatedStreamsLayout.setVisibility(player != null && player.isInFullscreen() ? View.GONE : View.VISIBLE);
}
}
@@ -1722,6 +1725,13 @@ public void onFullscreenStateChanged(boolean fullscreen) {
@Override
public void onScreenRotationButtonClicked() {
+ // 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() && PlayerHelper.isTablet(activity)) {
+ player.toggleFullscreen();
+ return;
+ }
+
int newOrientation = isLandscape() ?
ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED
: ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE;
@@ -1866,10 +1876,12 @@ private void setupBottomPlayer() {
final int peekHeight = getResources().getDimensionPixelSize(R.dimen.mini_player_height);
if (bottomSheetState != BottomSheetBehavior.STATE_HIDDEN) {
bottomSheetBehavior.setPeekHeight(peekHeight);
- if (bottomSheetState == BottomSheetBehavior.STATE_COLLAPSED)
- setOverlayLook(appBarLayout, behavior, 1 - MAX_OVERLAY_ALPHA);
- else if (bottomSheetState == BottomSheetBehavior.STATE_EXPANDED)
+ if (bottomSheetState == BottomSheetBehavior.STATE_COLLAPSED) {
+ overlay.setAlpha(MAX_OVERLAY_ALPHA);
+ } else if (bottomSheetState == BottomSheetBehavior.STATE_EXPANDED) {
+ overlay.setAlpha(0);
setOverlayElementsClickable(false);
+ }
}
bottomSheetBehavior.setBottomSheetCallback(new BottomSheetBehavior.BottomSheetCallback() {
diff --git a/app/src/main/java/org/schabi/newpipe/player/VideoPlayerImpl.java b/app/src/main/java/org/schabi/newpipe/player/VideoPlayerImpl.java
index 66407936c80..4c2740edc4c 100644
--- a/app/src/main/java/org/schabi/newpipe/player/VideoPlayerImpl.java
+++ b/app/src/main/java/org/schabi/newpipe/player/VideoPlayerImpl.java
@@ -1155,18 +1155,20 @@ private void setControlsSize() {
// It doesn't include NavigationBar, notches, etc.
display.getSize(size);
- int width = isFullscreen ? size.x : ViewGroup.LayoutParams.MATCH_PARENT;
+ int spaceBeforeTopControls = getRootView().findViewById(R.id.spaceBeforeControls).getWidth();
+ int widthForTopControls = isFullscreen ? size.x - spaceBeforeTopControls : ViewGroup.LayoutParams.MATCH_PARENT;
+ int widthForBottomControls = isFullscreen ? size.x : ViewGroup.LayoutParams.MATCH_PARENT;
int gravity = isFullscreen ? (display.getRotation() == Surface.ROTATION_90 ? Gravity.START : Gravity.END) : Gravity.TOP;
- primaryControls.getLayoutParams().width = width;
+ primaryControls.getLayoutParams().width = widthForTopControls;
((LinearLayout.LayoutParams) primaryControls.getLayoutParams()).gravity = gravity;
primaryControls.requestLayout();
- secondaryControls.getLayoutParams().width = width;
+ secondaryControls.getLayoutParams().width = widthForTopControls;
((LinearLayout.LayoutParams) secondaryControls.getLayoutParams()).gravity = gravity;
secondaryControls.requestLayout();
- getBottomControlsRoot().getLayoutParams().width = width;
+ getBottomControlsRoot().getLayoutParams().width = widthForBottomControls;
RelativeLayout.LayoutParams bottomParams = ((RelativeLayout.LayoutParams) getBottomControlsRoot().getLayoutParams());
bottomParams.removeRule(RelativeLayout.ALIGN_PARENT_START);
bottomParams.removeRule(RelativeLayout.ALIGN_PARENT_END);
@@ -1174,15 +1176,33 @@ private void setControlsSize() {
getBottomControlsRoot().requestLayout();
ViewGroup controlsRoot = getRootView().findViewById(R.id.playbackControlRoot);
- controlsRoot.getLayoutParams().height = isFullscreen ? size.y : ViewGroup.LayoutParams.MATCH_PARENT;
+ // In tablet navigationBar located at the bottom of the screen. And the only situation when we need to set custom height is
+ // in fullscreen mode in tablet in non-multiWindow mode. Other than that MATCH_PARENT is good
+ controlsRoot.getLayoutParams().height = isFullscreen && !isInMultiWindow() && PlayerHelper.isTablet(service)
+ ? size.y
+ : ViewGroup.LayoutParams.MATCH_PARENT;
controlsRoot.requestLayout();
+ int topPadding = isFullscreen && !isInMultiWindow() ? getStatusBarHeight() : 0;
+ getRootView().findViewById(R.id.playbackWindowRoot).setPadding(0, topPadding, 0, 0);
+ getRootView().findViewById(R.id.playbackWindowRoot).requestLayout();
+ }
+
+ private int getStatusBarHeight() {
int statusBarHeight = 0;
int resourceId = service.getResources().getIdentifier("status_bar_height_landscape", "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
+ DisplayMetrics metrics = getRootView().getResources().getDisplayMetrics();
+ statusBarHeight = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 24, metrics);
+ }
+ return statusBarHeight;
+ }
- getRootView().findViewById(R.id.playbackWindowRoot).setPadding(0, isFullscreen ? statusBarHeight : 0, 0, 0);
- getRootView().findViewById(R.id.playbackWindowRoot).requestLayout();
+ private boolean isInMultiWindow() {
+ AppCompatActivity parent = getParentActivity();
+ return Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && parent != null && parent.isInMultiWindowMode();
}
private void updatePlaybackButtons() {
@@ -1287,6 +1307,9 @@ public void onStartDrag(PlayQueueItemHolder viewHolder) {
private void initPopup() {
if (DEBUG) Log.d(TAG, "initPopup() called");
+ // Popup is already added to windowManager
+ if (getRootView().getLayoutParams() instanceof WindowManager.LayoutParams) return;
+
updateScreenSize();
final boolean popupRememberSizeAndPos = PlayerHelper.isRememberingPopupDimensions(service);
@@ -1326,6 +1349,10 @@ private void initPopup() {
@SuppressLint("RtlHardcoded")
private void initPopupCloseOverlay() {
if (DEBUG) Log.d(TAG, "initPopupCloseOverlay() called");
+
+ // closeOverlayView is already added to windowManager
+ if (closeOverlayView != null) return;
+
closeOverlayView = View.inflate(service, R.layout.player_popup_close_overlay, null);
closeOverlayButton = closeOverlayView.findViewById(R.id.closeButton);
@@ -1493,6 +1520,7 @@ public void onAnimationEnd(Animator animation) {
private void end() {
windowManager.removeView(closeOverlayView);
+ closeOverlayView = null;
service.onDestroy();
}
@@ -1653,10 +1681,6 @@ public View getCloseOverlayButton() {
return closeOverlayButton;
}
- public View getCloseOverlayView() {
- return closeOverlayView;
- }
-
public View getClosingOverlayView() {
return closingOverlayView;
}
diff --git a/app/src/main/java/org/schabi/newpipe/player/helper/PlayerHelper.java b/app/src/main/java/org/schabi/newpipe/player/helper/PlayerHelper.java
index cfce6e67860..ae1cac382d9 100644
--- a/app/src/main/java/org/schabi/newpipe/player/helper/PlayerHelper.java
+++ b/app/src/main/java/org/schabi/newpipe/player/helper/PlayerHelper.java
@@ -2,6 +2,7 @@
import android.content.Context;
import android.content.SharedPreferences;
+import android.content.res.Configuration;
import android.os.Build;
import android.preference.PreferenceManager;
import android.provider.Settings;
@@ -329,6 +330,11 @@ public static boolean globalScreenOrientationLocked(Context context) {
context.getContentResolver(), Settings.System.ACCELEROMETER_ROTATION, 0) == 1);
}
+ public static boolean isTablet(@NonNull final Context context) {
+ return (context.getResources().getConfiguration().screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK)
+ >= Configuration.SCREENLAYOUT_SIZE_LARGE;
+ }
+
////////////////////////////////////////////////////////////////////////////
// Private helpers
////////////////////////////////////////////////////////////////////////////
diff --git a/app/src/main/res/layout-large-land/activity_main_player.xml b/app/src/main/res/layout-large-land/activity_main_player.xml
index 16a52cdb66e..73a1113c694 100644
--- a/app/src/main/res/layout-large-land/activity_main_player.xml
+++ b/app/src/main/res/layout-large-land/activity_main_player.xml
@@ -161,7 +161,6 @@
android:orientation="vertical"
android:gravity="top"
android:paddingTop="4dp"
- android:paddingEnd="6dp"
android:layout_toEndOf="@id/spaceBeforeControls"
android:baselineAligned="false">
@@ -172,7 +171,6 @@
android:baselineAligned="false"
android:gravity="top"
android:paddingBottom="7dp"
- android:paddingLeft="2dp"
tools:ignore="RtlHardcoded">
diff --git a/app/src/main/res/layout/activity_main_player.xml b/app/src/main/res/layout/activity_main_player.xml
index 1a0fb292fcd..cf44d6bcb0f 100644
--- a/app/src/main/res/layout/activity_main_player.xml
+++ b/app/src/main/res/layout/activity_main_player.xml
@@ -159,7 +159,6 @@
android:orientation="vertical"
android:gravity="top"
android:paddingTop="4dp"
- android:paddingEnd="6dp"
android:layout_toEndOf="@id/spaceBeforeControls"
android:baselineAligned="false">
@@ -170,7 +169,6 @@
android:baselineAligned="false"
android:gravity="top"
android:paddingBottom="7dp"
- android:paddingLeft="2dp"
tools:ignore="RtlHardcoded">
Date: Sun, 26 Jan 2020 07:33:52 +0300
Subject: [PATCH 015/398] Hotfix
---
app/build.gradle | 2 +-
.../schabi/newpipe/fragments/detail/VideoDetailFragment.java | 1 +
app/src/main/res/layout/activity_error.xml | 1 +
3 files changed, 3 insertions(+), 1 deletion(-)
diff --git a/app/build.gradle b/app/build.gradle
index f7017a6dfae..424ed621185 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -62,7 +62,7 @@ dependencies {
exclude module: 'support-annotations'
})
- implementation 'com.github.TeamNewPipe:NewPipeExtractor:8e53fda'
+ implementation 'com.github.TeamNewPipe:NewPipeExtractor:ff61e284'
testImplementation 'junit:junit:4.12'
testImplementation 'org.mockito:mockito-core:2.23.0'
diff --git a/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java
index f4c79e73dd5..dca7126da73 100644
--- a/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java
+++ b/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java
@@ -1175,6 +1175,7 @@ private boolean isAutoplayEnabled() {
return autoPlayEnabled
&& !isExternalPlayerEnabled()
&& (player == null || player.videoPlayerSelected())
+ && bottomSheetState != BottomSheetBehavior.STATE_HIDDEN
&& isAutoplayAllowedByUser();
}
diff --git a/app/src/main/res/layout/activity_error.xml b/app/src/main/res/layout/activity_error.xml
index c47077c73de..f3fd9a9568c 100644
--- a/app/src/main/res/layout/activity_error.xml
+++ b/app/src/main/res/layout/activity_error.xml
@@ -100,6 +100,7 @@
android:id="@+id/errorView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
+ android:textIsSelectable="true"
android:typeface="monospace"/>
From f334a2740f95cd5fe093860e83483b6511b4542e Mon Sep 17 00:00:00 2001
From: Avently <7953703+avently@users.noreply.github.com>
Date: Wed, 5 Feb 2020 08:59:30 +0300
Subject: [PATCH 016/398] Mini player, ExpandableSurfaceView with ZOOM support,
popup - mini player's title, image and author information will be updated in
many situations but the main idea is that the info will be the same as
currently playing stream. If nothing played then you'll see the info about
currently opened stream in fragment. When MainPlayer service stops the info
updates too - made ExpandableSurfaceView to replace AspectRatioFrameLayout.
The reason for that is to make possible to use aspect ratio mode ZOOM. It's
impossible to show a stream inside AspectRatioFrameLayout with ZOOM mode and
to fit the video view to a screen space at the same time. Now the new view
able to do that and to show vertical videos in a slightly wide space for them
- refactored some methods to make the code more understandable - made fixes
for player view for landscape-to-landscape orientation change - added Java
docs - adapted swipe tracking inside bottom sheet - fixed PlayQueue crashes
on clearing - paddings for popup player now as small as possible
---
.../material/appbar/FlingBehavior.java | 2 +-
.../fragments/detail/VideoDetailFragment.java | 79 +++++---
.../org/schabi/newpipe/player/BasePlayer.java | 17 +-
.../org/schabi/newpipe/player/MainPlayer.java | 1 +
.../schabi/newpipe/player/VideoPlayer.java | 32 ++-
.../newpipe/player/VideoPlayerImpl.java | 184 ++++++++++++------
.../event/CustomBottomSheetBehavior.java | 24 ++-
.../newpipe/player/playqueue/PlayQueue.java | 14 +-
.../newpipe/views/ExpandableSurfaceView.java | 102 ++++++++++
.../activity_main_player.xml | 81 +++-----
.../fragment_video_detail.xml | 2 +-
.../main/res/layout/activity_main_player.xml | 81 +++-----
.../main/res/layout/fragment_video_detail.xml | 2 +-
app/src/main/res/values/dimens.xml | 9 +
14 files changed, 405 insertions(+), 225 deletions(-)
create mode 100644 app/src/main/java/org/schabi/newpipe/views/ExpandableSurfaceView.java
diff --git a/app/src/main/java/com/google/android/material/appbar/FlingBehavior.java b/app/src/main/java/com/google/android/material/appbar/FlingBehavior.java
index ff2860558fd..f1038faa173 100644
--- a/app/src/main/java/com/google/android/material/appbar/FlingBehavior.java
+++ b/app/src/main/java/com/google/android/material/appbar/FlingBehavior.java
@@ -30,7 +30,7 @@ public boolean onInterceptTouchEvent(CoordinatorLayout parent, AppBarLayout chil
ViewGroup playQueue = child.findViewById(R.id.playQueue);
if (playQueue != null) {
playQueue.getGlobalVisibleRect(playQueueRect);
- if (playQueueRect.contains((int) ev.getX(), (int) ev.getY())) {
+ if (playQueueRect.contains((int) ev.getRawX(), (int) ev.getRawY())) {
allowScroll = false;
return false;
}
diff --git a/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java
index dca7126da73..ce113a93dc6 100644
--- a/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java
+++ b/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java
@@ -5,7 +5,6 @@
import android.content.*;
import android.content.pm.ActivityInfo;
import android.database.ContentObserver;
-import android.graphics.Bitmap;
import android.media.AudioManager;
import android.os.Build;
import android.os.Bundle;
@@ -108,6 +107,7 @@ public class VideoDetailFragment
private static final int TOOLBAR_ITEMS_UPDATE_FLAG = 0x4;
private static final int COMMENTS_UPDATE_FLAG = 0x8;
private static final float MAX_OVERLAY_ALPHA = 0.9f;
+ private static final float MAX_PLAYER_HEIGHT = 0.7f;
public static final String ACTION_SHOW_MAIN_PLAYER = "org.schabi.newpipe.fragments.VideoDetailFragment.ACTION_SHOW_MAIN_PLAYER";
public static final String ACTION_HIDE_MAIN_PLAYER = "org.schabi.newpipe.fragments.VideoDetailFragment.ACTION_HIDE_MAIN_PLAYER";
@@ -235,7 +235,7 @@ public void onServiceConnected(ComponentName compName, IBinder service) {
// It will do nothing if the player is not in fullscreen mode
hideSystemUIIfNeeded();
- if (!player.videoPlayerSelected()) return;
+ if (!player.videoPlayerSelected() && !playAfterConnect) return;
// STATE_IDLE means the player is stopped
if (player.getPlayer() != null && player.getPlayer().getPlaybackState() != Player.STATE_IDLE) addVideoPlayerView();
@@ -282,6 +282,9 @@ private void stopPlayerListener() {
}
private void startService(boolean playAfterConnect) {
+ // startService() can be called concurrently and it will give a random crashes and NullPointerExceptions
+ // inside the service because the service will be bound twice. Prevent it with unbinding first
+ unbind();
getContext().startService(new Intent(getContext(), MainPlayer.class));
serviceConnection = getServiceConnection(playAfterConnect);
bind();
@@ -708,7 +711,6 @@ private View.OnTouchListener getOnControlsTouchListener() {
private void initThumbnailViews(@NonNull StreamInfo info) {
thumbnailImageView.setImageResource(R.drawable.dummy_thumbnail_dark);
- overlayThumbnailImageView.setImageResource(R.drawable.dummy_thumbnail_dark);
if (!TextUtils.isEmpty(info.getThumbnailUrl())) {
final String infoServiceName = NewPipe.getNameOfService(info.getServiceId());
@@ -718,11 +720,6 @@ public void onLoadingFailed(String imageUri, View view, FailReason failReason) {
showSnackBarError(failReason.getCause(), UserAction.LOAD_IMAGE,
infoServiceName, imageUri, R.string.could_not_load_thumbnails);
}
-
- @Override
- public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) {
- overlayThumbnailImageView.setImageBitmap(loadedImage);
- }
};
imageLoader.displayImage(info.getThumbnailUrl(), thumbnailImageView,
@@ -855,7 +852,7 @@ public void onNothingSelected(AdapterView> parent) {
*/
protected final LinkedList stack = new LinkedList<>();
- public void setTitleToUrl(int serviceId, String videoUrl, String name) {
+ /*public void setTitleToUrl(int serviceId, String videoUrl, String name) {
if (name != null && !name.isEmpty()) {
for (StackItem stackItem : stack) {
if (stack.peek().getServiceId() == serviceId
@@ -864,7 +861,7 @@ public void setTitleToUrl(int serviceId, String videoUrl, String name) {
}
}
}
- }
+ }*/
@Override
public boolean onBackPressed() {
@@ -887,7 +884,9 @@ public boolean onBackPressed() {
}
// If we have something in history of played items we replay it here
- if (player != null && player.getPlayQueue() != null && player.getPlayQueue().previous()) {
+ boolean isPreviousCanBePlayed = player != null && player.getPlayQueue() != null && player.videoPlayerSelected()
+ && player.getPlayQueue().previous();
+ if (isPreviousCanBePlayed) {
return true;
}
// That means that we are on the start of the stack,
@@ -914,6 +913,12 @@ private void setupFromHistoryItem(StackItem item) {
item.getUrl(),
!TextUtils.isEmpty(item.getTitle()) ? item.getTitle() : "",
item.getPlayQueue());
+
+ PlayQueueItem playQueueItem = item.getPlayQueue().getItem();
+ // Update title, url, uploader from the last item in the stack (it's current now)
+ boolean isPlayerStopped = player == null || player.isPlayerStopped();
+ if (playQueueItem != null && isPlayerStopped)
+ updateOverlayData(playQueueItem.getTitle(), playQueueItem.getUploader(), playQueueItem.getThumbnailUrl());
}
/*//////////////////////////////////////////////////////////////////////////
@@ -1199,7 +1204,7 @@ private void addVideoPlayerView() {
FrameLayout viewHolder = getView().findViewById(R.id.player_placeholder);
// Check if viewHolder already contains a child
- if (player.getRootView() != viewHolder) removeVideoPlayerView();
+ if (player.getRootView().getParent() != viewHolder) removeVideoPlayerView();
setHeightThumbnail();
// Prevent from re-adding a view multiple times
@@ -1250,6 +1255,11 @@ private void prepareDescription(final String descriptionHtml) {
}));
}
+ /**
+ * Method which controls the size of thumbnail and the size of main player inside a layout with thumbnail.
+ * It decides what height the player should have in both screen orientations. It knows about multiWindow feature
+ * and about videos with aspectRatio ZOOM (the height for them will be a bit higher, {@link #MAX_PLAYER_HEIGHT})
+ */
private void setHeightThumbnail() {
final DisplayMetrics metrics = getResources().getDisplayMetrics();
boolean isPortrait = metrics.heightPixels > metrics.widthPixels;
@@ -1260,11 +1270,14 @@ private void setHeightThumbnail() {
else
height = isPortrait
? (int) (metrics.widthPixels / (16.0f / 9.0f))
- : (int) (metrics.heightPixels / 2f);;
+ : (int) (metrics.heightPixels / 2f);
- thumbnailImageView.setLayoutParams(
- new FrameLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, height));
+ thumbnailImageView.setLayoutParams(new FrameLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, height));
thumbnailImageView.setMinimumHeight(height);
+ if (player != null) {
+ int maxHeight = (int) (metrics.heightPixels * MAX_PLAYER_HEIGHT);
+ player.getSurfaceView().setHeights(height, player.isInFullscreen() ? height : maxHeight);
+ }
}
private void showContent() {
@@ -1393,13 +1406,11 @@ public void handleResult(@NonNull StreamInfo info) {
animateView(thumbnailPlayButton, true, 200);
videoTitleTextView.setText(name);
- overlayTitleTextView.setText(name);
if (!TextUtils.isEmpty(info.getUploaderName())) {
uploaderTextView.setText(info.getUploaderName());
uploaderTextView.setVisibility(View.VISIBLE);
uploaderTextView.setSelected(true);
- overlayChannelTextView.setText(info.getUploaderName());
} else {
uploaderTextView.setVisibility(View.GONE);
}
@@ -1481,8 +1492,9 @@ public void handleResult(@NonNull StreamInfo info) {
setupActionBar(info);
initThumbnailViews(info);
- setTitleToUrl(info.getServiceId(), info.getUrl(), info.getName());
- setTitleToUrl(info.getServiceId(), info.getOriginalUrl(), info.getName());
+ if (player == null || player.isPlayerStopped())
+ updateOverlayData(info.getName(), info.getUploaderName(), info.getThumbnailUrl());
+
if (!info.getErrors().isEmpty()) {
showSnackBarError(info.getErrors(),
@@ -1682,7 +1694,8 @@ public void onMetadataUpdate(StreamInfo info) {
peek.setUrl(info.getUrl());
}
- if (currentInfo == info) return;
+ updateOverlayData(info.getName(), info.getUploaderName(), info.getThumbnailUrl());
+ if (currentInfo != null && info.getUrl().equals(currentInfo.getUrl())) return;
currentInfo = info;
setAutoplay(false);
@@ -1702,6 +1715,8 @@ public void onPlayerError(ExoPlaybackException error) {
public void onServiceStopped() {
unbind();
setOverlayPlayPauseImage();
+ if (currentInfo != null)
+ updateOverlayData(currentInfo.getName(), currentInfo.getUploaderName(), currentInfo.getThumbnailUrl());
}
@Override
@@ -1858,9 +1873,11 @@ private boolean wasCleared() {
private void cleanUp() {
// New beginning
stack.clear();
+ if (currentWorker != null) currentWorker.dispose();
stopService();
setInitialData(0,null,"", null);
currentInfo = null;
+ updateOverlayData(null, null, null);
}
/*//////////////////////////////////////////////////////////////////////////
@@ -1899,16 +1916,20 @@ private void setupBottomPlayer() {
// Disable click because overlay buttons located on top of buttons from the player
setOverlayElementsClickable(false);
hideSystemUIIfNeeded();
- if (isLandscape() && player != null && player.isPlaying() && !player.isInFullscreen())
- player.toggleFullscreen();
+ boolean needToExpand = isLandscape()
+ && player != null
+ && player.isPlaying()
+ && !player.isInFullscreen()
+ && player.videoPlayerSelected();
+ if (needToExpand) player.toggleFullscreen();
break;
case BottomSheetBehavior.STATE_COLLAPSED:
// Re-enable clicks
setOverlayElementsClickable(true);
- if (player != null && player.isInFullscreen()) showSystemUi();
break;
case BottomSheetBehavior.STATE_DRAGGING:
case BottomSheetBehavior.STATE_SETTLING:
+ if (player != null && player.isInFullscreen()) showSystemUi();
if (player != null && player.isControlsVisible()) player.hideControls(0, 0);
break;
}
@@ -1925,6 +1946,15 @@ private void setupBottomPlayer() {
});
}
+ private void updateOverlayData(@Nullable String title, @Nullable String uploader, @Nullable String thumbnailUrl) {
+ overlayTitleTextView.setText(!TextUtils.isEmpty(title) ? title : "");
+ overlayChannelTextView.setText(!TextUtils.isEmpty(uploader) ? uploader : "");
+ overlayThumbnailImageView.setImageResource(R.drawable.dummy_thumbnail_dark);
+ if (!TextUtils.isEmpty(thumbnailUrl))
+ imageLoader.displayImage(thumbnailUrl, overlayThumbnailImageView,
+ ImageDisplayConstants.DISPLAY_THUMBNAIL_OPTIONS, null);
+ }
+
private void setOverlayPlayPauseImage() {
boolean playing = player != null && player.getPlayer().getPlayWhenReady();
int attr = playing ? R.attr.pause : R.attr.play;
@@ -1935,7 +1965,8 @@ private void setOverlayLook(AppBarLayout appBarLayout, AppBarLayout.Behavior beh
if (behavior != null) {
overlay.setAlpha(Math.min(MAX_OVERLAY_ALPHA, 1 - slideOffset));
- behavior.setTopAndBottomOffset((int)(-appBarLayout.getTotalScrollRange() * (1 - slideOffset) / 3));
+ // These numbers are not special. They just do a cool transition
+ behavior.setTopAndBottomOffset((int)(-thumbnailImageView.getHeight() * 2 * (1 - slideOffset) / 3));
appBarLayout.requestLayout();
}
}
diff --git a/app/src/main/java/org/schabi/newpipe/player/BasePlayer.java b/app/src/main/java/org/schabi/newpipe/player/BasePlayer.java
index 70ab82fb861..815cbb8ab73 100644
--- a/app/src/main/java/org/schabi/newpipe/player/BasePlayer.java
+++ b/app/src/main/java/org/schabi/newpipe/player/BasePlayer.java
@@ -276,14 +276,6 @@ public void handleIntent(Intent intent) {
boolean same = playQueue != null && playQueue.equals(queue);
- // Do not re-init the same PlayQueue. Save time
- if (same && !playQueue.isDisposed()) {
- // Player can have state = IDLE when playback is stopped or failed and we should retry() in this case
- if (simpleExoPlayer != null && simpleExoPlayer.getPlaybackState() == Player.STATE_IDLE)
- simpleExoPlayer.retry();
- return;
- }
-
final int repeatMode = intent.getIntExtra(REPEAT_MODE, getRepeatMode());
final float playbackSpeed = intent.getFloatExtra(PLAYBACK_SPEED, getPlaybackSpeed());
final float playbackPitch = intent.getFloatExtra(PLAYBACK_PITCH, getPlaybackPitch());
@@ -298,10 +290,17 @@ public void handleIntent(Intent intent) {
&& playQueue.getItem() != null
&& queue.getItem().getUrl().equals(playQueue.getItem().getUrl())
&& queue.getItem().getRecoveryPosition() != PlayQueueItem.RECOVERY_UNSET
- && !same) {
+ && simpleExoPlayer.getPlaybackState() != Player.STATE_IDLE) {
+ // Player can have state = IDLE when playback is stopped or failed and we should retry() in this case
+ if (simpleExoPlayer.getPlaybackState() == Player.STATE_IDLE) simpleExoPlayer.retry();
simpleExoPlayer.seekTo(playQueue.getIndex(), queue.getItem().getRecoveryPosition());
return;
+ } else if (same && !playQueue.isDisposed() && simpleExoPlayer != null) {
+ // Do not re-init the same PlayQueue. Save time
+ // Player can have state = IDLE when playback is stopped or failed and we should retry() in this case
+ if (simpleExoPlayer.getPlaybackState() == Player.STATE_IDLE) simpleExoPlayer.retry();
+ return;
} else if (intent.getBooleanExtra(RESUME_PLAYBACK, false)
&& isPlaybackResumeEnabled()
&& !same) {
diff --git a/app/src/main/java/org/schabi/newpipe/player/MainPlayer.java b/app/src/main/java/org/schabi/newpipe/player/MainPlayer.java
index 63c2f195fcc..771d6d7e151 100644
--- a/app/src/main/java/org/schabi/newpipe/player/MainPlayer.java
+++ b/app/src/main/java/org/schabi/newpipe/player/MainPlayer.java
@@ -179,6 +179,7 @@ private void onClose() {
playerImpl.savePlaybackState();
playerImpl.stopActivityBinding();
+ playerImpl.removePopupFromView();
playerImpl.destroy();
}
if (notificationManager != null) notificationManager.cancel(NOTIFICATION_ID);
diff --git a/app/src/main/java/org/schabi/newpipe/player/VideoPlayer.java b/app/src/main/java/org/schabi/newpipe/player/VideoPlayer.java
index 07f485e7abc..c29cfd19c67 100644
--- a/app/src/main/java/org/schabi/newpipe/player/VideoPlayer.java
+++ b/app/src/main/java/org/schabi/newpipe/player/VideoPlayer.java
@@ -34,10 +34,7 @@
import android.os.Handler;
import android.preference.PreferenceManager;
import android.util.Log;
-import android.view.Menu;
-import android.view.MenuItem;
-import android.view.SurfaceView;
-import android.view.View;
+import android.view.*;
import android.widget.*;
import androidx.annotation.NonNull;
@@ -65,6 +62,7 @@
import org.schabi.newpipe.player.resolver.MediaSourceTag;
import org.schabi.newpipe.player.resolver.VideoPlaybackResolver;
import org.schabi.newpipe.util.AnimationUtils;
+import org.schabi.newpipe.views.ExpandableSurfaceView;
import java.util.ArrayList;
import java.util.List;
@@ -109,8 +107,7 @@ public abstract class VideoPlayer extends BasePlayer
private View rootView;
- private AspectRatioFrameLayout aspectRatioFrameLayout;
- private SurfaceView surfaceView;
+ private ExpandableSurfaceView surfaceView;
private View surfaceForeground;
private View loadingPanel;
@@ -163,7 +160,6 @@ public void setup(View rootView) {
public void initViews(View rootView) {
this.rootView = rootView;
- this.aspectRatioFrameLayout = rootView.findViewById(R.id.aspectRatioLayout);
this.surfaceView = rootView.findViewById(R.id.surfaceView);
this.surfaceForeground = rootView.findViewById(R.id.surfaceForeground);
this.loadingPanel = rootView.findViewById(R.id.loading_panel);
@@ -187,12 +183,10 @@ public void initViews(View rootView) {
setupSubtitleView(subtitleView, captionScale, captionStyle);
this.resizeView = rootView.findViewById(R.id.resizeTextView);
- resizeView.setText(PlayerHelper.resizeTypeOf(context, aspectRatioFrameLayout.getResizeMode()));
+ resizeView.setText(PlayerHelper.resizeTypeOf(context, getSurfaceView().getResizeMode()));
this.captionTextView = rootView.findViewById(R.id.captionTextView);
- //this.aspectRatioFrameLayout.setAspectRatio(16.0f / 9.0f);
-
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN)
playbackSeekBar.getThumb().setColorFilter(Color.RED, PorterDuff.Mode.SRC_IN);
this.playbackSeekBar.getProgressDrawable().setColorFilter(Color.RED, PorterDuff.Mode.MULTIPLY);
@@ -501,7 +495,7 @@ public void onVideoSizeChanged(int width, int height, int unappliedRotationDegre
if (DEBUG) {
Log.d(TAG, "onVideoSizeChanged() called with: width / height = [" + width + " / " + height + " = " + (((float) width) / height) + "], unappliedRotationDegrees = [" + unappliedRotationDegrees + "], pixelWidthHeightRatio = [" + pixelWidthHeightRatio + "]");
}
- aspectRatioFrameLayout.setAspectRatio(((float) width) / height);
+ getSurfaceView().setAspectRatio(((float) width) / height);
}
@Override
@@ -715,15 +709,15 @@ private void onCaptionClicked() {
}
void onResizeClicked() {
- if (getAspectRatioFrameLayout() != null) {
- final int currentResizeMode = getAspectRatioFrameLayout().getResizeMode();
+ if (getSurfaceView() != null) {
+ final int currentResizeMode = getSurfaceView().getResizeMode();
final int newResizeMode = nextResizeMode(currentResizeMode);
setResizeMode(newResizeMode);
}
}
protected void setResizeMode(@AspectRatioFrameLayout.ResizeMode final int resizeMode) {
- getAspectRatioFrameLayout().setResizeMode(resizeMode);
+ getSurfaceView().setResizeMode(resizeMode);
getResizeView().setText(PlayerHelper.resizeTypeOf(context, resizeMode));
}
@@ -894,11 +888,7 @@ public String getPlaybackQuality() {
return resolver.getPlaybackQuality();
}
- public AspectRatioFrameLayout getAspectRatioFrameLayout() {
- return aspectRatioFrameLayout;
- }
-
- public SurfaceView getSurfaceView() {
+ public ExpandableSurfaceView getSurfaceView() {
return surfaceView;
}
@@ -969,6 +959,10 @@ public PopupMenu getQualityPopupMenu() {
return qualityPopupMenu;
}
+ public TextView getPlaybackSpeedTextView() {
+ return playbackSpeedTextView;
+ }
+
public PopupMenu getPlaybackSpeedPopupMenu() {
return playbackSpeedPopupMenu;
}
diff --git a/app/src/main/java/org/schabi/newpipe/player/VideoPlayerImpl.java b/app/src/main/java/org/schabi/newpipe/player/VideoPlayerImpl.java
index 4c2740edc4c..72c3b71ee51 100644
--- a/app/src/main/java/org/schabi/newpipe/player/VideoPlayerImpl.java
+++ b/app/src/main/java/org/schabi/newpipe/player/VideoPlayerImpl.java
@@ -46,6 +46,7 @@
import androidx.recyclerview.widget.RecyclerView;
import com.google.android.exoplayer2.ExoPlaybackException;
import com.google.android.exoplayer2.Player;
+import com.google.android.exoplayer2.SimpleExoPlayer;
import com.google.android.exoplayer2.source.MediaSource;
import com.google.android.exoplayer2.text.CaptionStyleCompat;
import com.google.android.exoplayer2.ui.AspectRatioFrameLayout;
@@ -195,6 +196,7 @@ public void handleIntent(Intent intent) {
}
setupElementsVisibility();
+ setupElementsSize();
if (audioPlayerSelected()) {
service.removeViewFromParent();
@@ -280,11 +282,16 @@ protected void setupSubtitleView(@NonNull SubtitleView view,
}
}
+ /**
+ * 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()) {
fullscreenButton.setVisibility(View.VISIBLE);
screenRotationButton.setVisibility(View.GONE);
- getRootView().findViewById(R.id.spaceBeforeControls).setVisibility(View.GONE);
+ getResizeView().setVisibility(View.GONE);
getRootView().findViewById(R.id.metadataView).setVisibility(View.GONE);
queueButton.setVisibility(View.GONE);
moreOptionsButton.setVisibility(View.GONE);
@@ -297,14 +304,16 @@ private void setupElementsVisibility() {
playWithKodi.setVisibility(View.GONE);
openInBrowser.setVisibility(View.GONE);
playerCloseButton.setVisibility(View.GONE);
+ getTopControlsRoot().bringToFront();
+ getBottomControlsRoot().bringToFront();
} else {
fullscreenButton.setVisibility(View.GONE);
setupScreenRotationButton(service.isLandscape());
- getRootView().findViewById(R.id.spaceBeforeControls).setVisibility(View.VISIBLE);
+ getResizeView().setVisibility(View.VISIBLE);
getRootView().findViewById(R.id.metadataView).setVisibility(View.VISIBLE);
moreOptionsButton.setVisibility(View.VISIBLE);
getTopControlsRoot().setOrientation(LinearLayout.VERTICAL);
- primaryControls.getLayoutParams().width = secondaryControls.getLayoutParams().width;
+ primaryControls.getLayoutParams().width = LinearLayout.LayoutParams.MATCH_PARENT;
secondaryControls.setVisibility(View.GONE);
moreOptionsButton.setImageDrawable(service.getResources().getDrawable(
R.drawable.ic_expand_more_white_24dp));
@@ -325,6 +334,37 @@ private void setupElementsVisibility() {
animateRotation(moreOptionsButton, DEFAULT_CONTROLS_DURATION, 0);
}
+ /**
+ * Changes padding, size of elements based on player selected right now. Popup player has small padding in comparison with the
+ * main player
+ */
+ private void setupElementsSize() {
+ if (popupPlayerSelected()) {
+ int controlsPadding = service.getResources().getDimensionPixelSize(R.dimen.player_popup_controls_padding);
+ int buttonsPadding = service.getResources().getDimensionPixelSize(R.dimen.player_popup_buttons_padding);
+ getTopControlsRoot().setPaddingRelative(controlsPadding, 0, controlsPadding, 0);
+ getBottomControlsRoot().setPaddingRelative(controlsPadding, 0, controlsPadding, 0);
+ getQualityTextView().setPadding(buttonsPadding, buttonsPadding, buttonsPadding, buttonsPadding);
+ getPlaybackSpeedTextView().setPadding(buttonsPadding, buttonsPadding, buttonsPadding, buttonsPadding);
+ getQualityTextView().setPadding(buttonsPadding, buttonsPadding, buttonsPadding, buttonsPadding);
+ getCaptionTextView().setPadding(buttonsPadding, buttonsPadding, buttonsPadding, buttonsPadding);
+ getQualityTextView().setMinimumWidth(0);
+ getPlaybackSpeedTextView().setMinimumWidth(0);
+ } else if (videoPlayerSelected()) {
+ int buttonsMinWidth = service.getResources().getDimensionPixelSize(R.dimen.player_main_buttons_min_width);
+ int playerTopPadding = service.getResources().getDimensionPixelSize(R.dimen.player_main_top_padding);
+ int controlsPadding = service.getResources().getDimensionPixelSize(R.dimen.player_main_controls_padding);
+ int buttonsPadding = service.getResources().getDimensionPixelSize(R.dimen.player_main_buttons_padding);
+ getTopControlsRoot().setPaddingRelative(controlsPadding, playerTopPadding, controlsPadding, 0);
+ getBottomControlsRoot().setPaddingRelative(controlsPadding, 0, controlsPadding, 0);
+ getQualityTextView().setPadding(buttonsPadding, buttonsPadding, buttonsPadding, buttonsPadding);
+ getPlaybackSpeedTextView().setPadding(buttonsPadding, buttonsPadding, buttonsPadding, buttonsPadding);
+ getQualityTextView().setMinimumWidth(buttonsMinWidth);
+ getPlaybackSpeedTextView().setMinimumWidth(buttonsMinWidth);
+ getCaptionTextView().setPadding(buttonsPadding, buttonsPadding, buttonsPadding, buttonsPadding);
+ }
+ }
+
@Override
public void initListeners() {
super.initListeners();
@@ -357,24 +397,7 @@ public void initListeners() {
service.getContentResolver().registerContentObserver(
Settings.System.getUriFor(Settings.System.ACCELEROMETER_ROTATION), false,
settingsContentObserver);
-
- getRootView().addOnLayoutChangeListener((view, l, t, r, b, ol, ot, or, ob) -> {
- if (l != ol || t != ot || r != or || b != ob) {
- // Use smaller value to be consistent between screen orientations
- // (and to make usage easier)
- int width = r - l, height = b - t;
- int min = Math.min(width, height);
- maxGestureLength = (int) (min * MAX_GESTURE_LENGTH);
-
- if (DEBUG) Log.d(TAG, "maxGestureLength = " + maxGestureLength);
-
- volumeProgressBar.setMax(maxGestureLength);
- brightnessProgressBar.setMax(maxGestureLength);
-
- setInitialGestureValues();
- queueLayout.getLayoutParams().height = min - queueLayout.getTop();
- }
- });
+ getRootView().addOnLayoutChangeListener(this);
}
public AppCompatActivity getParentActivity() {
@@ -553,19 +576,15 @@ public void toggleFullscreen() {
intent.putExtra(Constants.KEY_URL, getVideoUrl());
intent.putExtra(Constants.KEY_TITLE, getVideoTitle());
intent.putExtra(VideoDetailFragment.AUTO_PLAY, true);
+ service.onDestroy();
context.startActivity(intent);
+ return;
} else {
if (fragmentListener == null) return;
isFullscreen = !isFullscreen;
setControlsSize();
fragmentListener.onFullscreenStateChanged(isInFullscreen());
- // When user presses back button in landscape mode and in fullscreen and uses ZOOM mode
- // a video can be larger than screen. Prevent it like this
- if (getAspectRatioFrameLayout().getResizeMode() == AspectRatioFrameLayout.RESIZE_MODE_ZOOM
- && !isInFullscreen()
- && service.isLandscape())
- onResizeClicked();
}
if (!isInFullscreen()) {
@@ -741,18 +760,28 @@ public void onDismiss(PopupMenu menu) {
}
@Override
- public void onLayoutChange(final View view, int left, int top, int right, int bottom,
- int oldLeft, int oldTop, int oldRight, int oldBottom) {
- if (popupPlayerSelected()) {
- float widthDp = Math.abs(right - left) / service.getResources().getDisplayMetrics().density;
- final int visibility = widthDp > MINIMUM_SHOW_EXTRA_WIDTH_DP ? View.VISIBLE : View.GONE;
- secondaryControls.setVisibility(visibility);
- } else if (videoPlayerSelected()
- && !isInFullscreen()
- && getAspectRatioFrameLayout().getMeasuredHeight() > service.getResources().getDisplayMetrics().heightPixels * 0.8) {
- // Resize mode is ZOOM probably. In this mode video will grow down and it will be weird.
- // So let's open it in fullscreen
- toggleFullscreen();
+ public void onLayoutChange(final View view, int l, int t, int r, int b,
+ int ol, int ot, int or, int ob) {
+ if (l != ol || t != ot || r != or || b != ob) {
+ // Use smaller value to be consistent between screen orientations
+ // (and to make usage easier)
+ int width = r - l, height = b - t;
+ int min = Math.min(width, height);
+ maxGestureLength = (int) (min * MAX_GESTURE_LENGTH);
+
+ if (DEBUG) Log.d(TAG, "maxGestureLength = " + maxGestureLength);
+
+ volumeProgressBar.setMax(maxGestureLength);
+ brightnessProgressBar.setMax(maxGestureLength);
+
+ setInitialGestureValues();
+ queueLayout.getLayoutParams().height = min - queueLayout.getTop();
+
+ if (popupPlayerSelected()) {
+ 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);
+ }
}
}
@@ -781,6 +810,11 @@ private void storeResizeMode(@AspectRatioFrameLayout.ResizeMode int resizeMode)
.apply();
}
+ private void restoreResizeMode() {
+ setResizeMode(defaultPreferences.getInt(
+ service.getString(R.string.last_resize_mode), AspectRatioFrameLayout.RESIZE_MODE_FIT));
+ }
+
@Override
protected VideoPlaybackResolver.QualityResolver getQualityResolver() {
return new VideoPlaybackResolver.QualityResolver() {
@@ -933,6 +967,7 @@ protected void setupBroadcastReceiver(IntentFilter intentFilter) {
intentFilter.addAction(ACTION_FAST_REWIND);
intentFilter.addAction(ACTION_FAST_FORWARD);
+ intentFilter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
intentFilter.addAction(Intent.ACTION_SCREEN_ON);
intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
@@ -969,6 +1004,9 @@ public void onBroadcastReceived(Intent intent) {
case ACTION_REPEAT:
onRepeatClicked();
break;
+ case Intent.ACTION_CONFIGURATION_CHANGED:
+ setControlsSize();
+ break;
case Intent.ACTION_SCREEN_ON:
shouldUpdateOnProgress = true;
// Interrupt playback only when screen turns on and user is watching video in fragment
@@ -1054,6 +1092,10 @@ public boolean popupPlayerSelected() {
return playerType == MainPlayer.PlayerType.POPUP;
}
+ public boolean isPlayerStopped() {
+ return getPlayer() == null || getPlayer().getPlaybackState() == SimpleExoPlayer.STATE_IDLE;
+ }
+
private int distanceFromCloseButton(MotionEvent popupMotionEvent) {
final int closeOverlayButtonX = closeOverlayButton.getLeft() + closeOverlayButton.getWidth() / 2;
final int closeOverlayButtonY = closeOverlayButton.getTop() + closeOverlayButton.getHeight() / 2;
@@ -1143,32 +1185,29 @@ public void hideSystemUIIfNeeded() {
fragmentListener.hideSystemUIIfNeeded();
}
- /*
- * This method 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
- * */
- private void setControlsSize() {
+ /**
+ * 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() {
Point size = new Point();
Display display = getRootView().getDisplay();
- if (display == null) return;
+ 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);
- int spaceBeforeTopControls = getRootView().findViewById(R.id.spaceBeforeControls).getWidth();
- int widthForTopControls = isFullscreen ? size.x - spaceBeforeTopControls : ViewGroup.LayoutParams.MATCH_PARENT;
- int widthForBottomControls = isFullscreen ? size.x : ViewGroup.LayoutParams.MATCH_PARENT;
+ int width = isFullscreen ? size.x : ViewGroup.LayoutParams.MATCH_PARENT;
int gravity = isFullscreen ? (display.getRotation() == Surface.ROTATION_90 ? Gravity.START : Gravity.END) : Gravity.TOP;
- primaryControls.getLayoutParams().width = widthForTopControls;
- ((LinearLayout.LayoutParams) primaryControls.getLayoutParams()).gravity = gravity;
- primaryControls.requestLayout();
-
- secondaryControls.getLayoutParams().width = widthForTopControls;
- ((LinearLayout.LayoutParams) secondaryControls.getLayoutParams()).gravity = gravity;
- secondaryControls.requestLayout();
+ getTopControlsRoot().getLayoutParams().width = width;
+ 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 = widthForBottomControls;
+ getBottomControlsRoot().getLayoutParams().width = width;
RelativeLayout.LayoutParams bottomParams = ((RelativeLayout.LayoutParams) getBottomControlsRoot().getLayoutParams());
bottomParams.removeRule(RelativeLayout.ALIGN_PARENT_START);
bottomParams.removeRule(RelativeLayout.ALIGN_PARENT_END);
@@ -1188,6 +1227,9 @@ private void setControlsSize() {
getRootView().findViewById(R.id.playbackWindowRoot).requestLayout();
}
+ /**
+ * @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;
int resourceId = service.getResources().getIdentifier("status_bar_height_landscape", "dimen", "android");
@@ -1200,6 +1242,9 @@ private int getStatusBarHeight() {
return statusBarHeight;
}
+ /**
+ * @return true if main player is attached to activity and activity inside multiWindow mode
+ */
private boolean isInMultiWindow() {
AppCompatActivity parent = getParentActivity();
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && parent != null && parent.isInMultiWindowMode();
@@ -1308,7 +1353,7 @@ private void initPopup() {
if (DEBUG) Log.d(TAG, "initPopup() called");
// Popup is already added to windowManager
- if (getRootView().getLayoutParams() instanceof WindowManager.LayoutParams) return;
+ if (isPopupHasParent()) return;
updateScreenSize();
@@ -1316,18 +1361,19 @@ private void initPopup() {
final float defaultSize = service.getResources().getDimension(R.dimen.popup_default_width);
SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(service);
popupWidth = popupRememberSizeAndPos ? sharedPreferences.getFloat(POPUP_SAVED_WIDTH, defaultSize) : defaultSize;
-
+ popupHeight = getMinimumVideoHeight(popupWidth);
final int layoutParamType = Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.O ?
WindowManager.LayoutParams.TYPE_PHONE :
WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
popupLayoutParams = new WindowManager.LayoutParams(
- (int) popupWidth, (int) getMinimumVideoHeight(popupWidth),
+ (int) popupWidth, (int) popupHeight,
layoutParamType,
IDLE_WINDOW_FLAGS,
PixelFormat.TRANSLUCENT);
popupLayoutParams.gravity = Gravity.LEFT | Gravity.TOP;
popupLayoutParams.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
+ getSurfaceView().setHeights((int) popupHeight, (int) popupHeight);
int centerX = (int) (screenWidth / 2f - popupWidth / 2f);
int centerY = (int) (screenHeight / 2f - popupHeight / 2f);
@@ -1342,8 +1388,8 @@ private void initPopup() {
service.removeViewFromParent();
windowManager.addView(getRootView(), popupLayoutParams);
- if (getAspectRatioFrameLayout().getResizeMode() == AspectRatioFrameLayout.RESIZE_MODE_ZOOM)
- onResizeClicked();
+ // Popup doesn't have aspectRatio selector, using FIT automatically
+ setResizeMode(AspectRatioFrameLayout.RESIZE_MODE_FIT);
}
@SuppressLint("RtlHardcoded")
@@ -1375,6 +1421,7 @@ private void initPopupCloseOverlay() {
}
private void initVideoPlayer() {
+ restoreResizeMode();
getRootView().setLayoutParams(new FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT));
}
@@ -1471,6 +1518,7 @@ public void updatePopupSize(int width, int height) {
popupLayoutParams.height = height;
popupWidth = width;
popupHeight = height;
+ getSurfaceView().setHeights((int) popupHeight, (int) popupHeight);
if (DEBUG) Log.d(TAG, "updatePopupSize() updated values: width = [" + width + "], height = [" + height + "]");
windowManager.updateViewLayout(getRootView(), popupLayoutParams);
@@ -1499,6 +1547,14 @@ public void closePopup() {
animateOverlayAndFinishService();
}
+ public void removePopupFromView() {
+ boolean isCloseOverlayHasParent = closeOverlayView != null && closeOverlayView.getParent() != null;
+ if (isPopupHasParent())
+ windowManager.removeView(getRootView());
+ if (isCloseOverlayHasParent)
+ windowManager.removeView(closeOverlayView);
+ }
+
private void animateOverlayAndFinishService() {
final int targetTranslationY = (int) (closeOverlayButton.getRootView().getHeight() - closeOverlayButton.getY());
@@ -1527,12 +1583,18 @@ private void end() {
}).start();
}
+ private boolean isPopupHasParent() {
+ View root = getRootView();
+ return root != null && root.getLayoutParams() instanceof WindowManager.LayoutParams && root.getParent() != null;
+ }
+
///////////////////////////////////////////////////////////////////////////
// Manipulations with listener
///////////////////////////////////////////////////////////////////////////
public void setFragmentListener(PlayerServiceEventListener listener) {
fragmentListener = listener;
+ updateMetadata();
updatePlayback();
triggerProgressUpdate();
}
diff --git a/app/src/main/java/org/schabi/newpipe/player/event/CustomBottomSheetBehavior.java b/app/src/main/java/org/schabi/newpipe/player/event/CustomBottomSheetBehavior.java
index 6f4cf41de7f..f0178853f74 100644
--- a/app/src/main/java/org/schabi/newpipe/player/event/CustomBottomSheetBehavior.java
+++ b/app/src/main/java/org/schabi/newpipe/player/event/CustomBottomSheetBehavior.java
@@ -16,6 +16,8 @@ public CustomBottomSheetBehavior(Context context, AttributeSet attrs) {
super(context, attrs);
}
+ boolean skippingInterception = false;
+
@Override
public boolean onInterceptTouchEvent(CoordinatorLayout parent, View child, MotionEvent event) {
// Behavior of globalVisibleRect is different on different APIs.
@@ -24,24 +26,40 @@ public boolean onInterceptTouchEvent(CoordinatorLayout parent, View child, Motio
boolean visible;
Rect rect = new Rect();
+ // Drop folowing when actions ends
+ if (event.getAction() == MotionEvent.ACTION_CANCEL || event.getAction() == MotionEvent.ACTION_UP)
+ skippingInterception = false;
+
+ // Found that user still swipping, continue folowing
+ if (skippingInterception) return false;
+
// Without overriding scrolling will not work in detail_content_root_layout
ViewGroup controls = child.findViewById(R.id.detail_content_root_layout);
if (controls != null) {
visible = controls.getGlobalVisibleRect(rect);
- if (rect.contains((int) event.getX(), (int) event.getY()) && visible) return false;
+ if (rect.contains((int) event.getRawX(), (int) event.getRawY()) && visible) {
+ skippingInterception = true;
+ return false;
+ }
}
// Without overriding scrolling will not work on relatedStreamsLayout
ViewGroup relatedStreamsLayout = child.findViewById(R.id.relatedStreamsLayout);
if (relatedStreamsLayout != null) {
visible = relatedStreamsLayout.getGlobalVisibleRect(rect);
- if (rect.contains((int) event.getX(), (int) event.getY()) && visible) return false;
+ if (rect.contains((int) event.getRawX(), (int) event.getRawY()) && visible) {
+ skippingInterception = true;
+ return false;
+ }
}
ViewGroup playQueue = child.findViewById(R.id.playQueue);
if (playQueue != null) {
visible = playQueue.getGlobalVisibleRect(rect);
- if (rect.contains((int) event.getX(), (int) event.getY()) && visible) return false;
+ if (rect.contains((int) event.getRawX(), (int) event.getRawY()) && visible) {
+ skippingInterception = true;
+ return false;
+ }
}
return super.onInterceptTouchEvent(parent, child, event);
diff --git a/app/src/main/java/org/schabi/newpipe/player/playqueue/PlayQueue.java b/app/src/main/java/org/schabi/newpipe/player/playqueue/PlayQueue.java
index 12454bde9ed..e739b8f33aa 100644
--- a/app/src/main/java/org/schabi/newpipe/player/playqueue/PlayQueue.java
+++ b/app/src/main/java/org/schabi/newpipe/player/playqueue/PlayQueue.java
@@ -59,7 +59,7 @@ public abstract class PlayQueue implements Serializable {
streams = new ArrayList<>();
streams.addAll(startWith);
history = new ArrayList<>();
- history.add(streams.get(index));
+ if (streams.size() > index) history.add(streams.get(index));
queueIndex = new AtomicInteger(index);
disposed = false;
@@ -305,7 +305,9 @@ private synchronized void removeInternal(final int removeIndex) {
}
history.remove(streams.remove(removeIndex));
- history.add(streams.get(queueIndex.get()));
+ if (streams.size() > queueIndex.get()) {
+ history.add(streams.get(queueIndex.get()));
+ }
}
/**
@@ -379,7 +381,9 @@ public synchronized void shuffle() {
streams.add(0, streams.remove(newIndex));
}
queueIndex.set(0);
- history.add(streams.get(0));
+ if (streams.size() > 0) {
+ history.add(streams.get(0));
+ }
broadcast(new ReorderEvent(originIndex, queueIndex.get()));
}
@@ -407,7 +411,9 @@ public synchronized void unshuffle() {
} else {
queueIndex.set(0);
}
- history.add(streams.get(queueIndex.get()));
+ if (streams.size() > queueIndex.get()) {
+ history.add(streams.get(queueIndex.get()));
+ }
broadcast(new ReorderEvent(originIndex, queueIndex.get()));
}
diff --git a/app/src/main/java/org/schabi/newpipe/views/ExpandableSurfaceView.java b/app/src/main/java/org/schabi/newpipe/views/ExpandableSurfaceView.java
new file mode 100644
index 00000000000..df012eafdc0
--- /dev/null
+++ b/app/src/main/java/org/schabi/newpipe/views/ExpandableSurfaceView.java
@@ -0,0 +1,102 @@
+package org.schabi.newpipe.views;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.SurfaceView;
+import com.google.android.exoplayer2.ui.AspectRatioFrameLayout;
+
+import static com.google.android.exoplayer2.ui.AspectRatioFrameLayout.*;
+
+public class ExpandableSurfaceView extends SurfaceView {
+ private int resizeMode = AspectRatioFrameLayout.RESIZE_MODE_FIT;
+ private int baseHeight = 0;
+ private int maxHeight = 0;
+ private float videoAspectRatio = 0f;
+ private float scaleX = 1.0f;
+ private float scaleY = 1.0f;
+
+ public ExpandableSurfaceView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+ if (videoAspectRatio == 0f) return;
+
+ int width = MeasureSpec.getSize(widthMeasureSpec);
+ 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 && verticalVideo ? maxHeight : baseHeight;
+
+ if (height == 0) return;
+
+ float viewAspectRatio = width / ((float) height);
+ float aspectDeformation = videoAspectRatio / viewAspectRatio - 1;
+ 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;
+ }
+ super.onMeasure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
+ MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY));
+ }
+
+ /**
+ * Scale view only in {@link #onLayout} to make transition for ZOOM mode as smooth as possible
+ */
+ @Override
+ protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+ setScaleX(scaleX);
+ setScaleY(scaleY);
+ }
+
+ /**
+ * @param base The height that will be used in every resize mode as a minimum height
+ * @param max The max height for vertical videos in non-FIT resize modes
+ */
+ public void setHeights(int base, int max) {
+ if (baseHeight == base && maxHeight == max) return;
+ baseHeight = base;
+ maxHeight = max;
+ requestLayout();
+ }
+
+ @AspectRatioFrameLayout.ResizeMode
+ public void setResizeMode(int newResizeMode) {
+ if (resizeMode == newResizeMode) return;
+
+ resizeMode = newResizeMode;
+ requestLayout();
+ }
+
+ @AspectRatioFrameLayout.ResizeMode
+ public int getResizeMode() {
+ return resizeMode;
+ }
+
+ public void setAspectRatio(float aspectRatio) {
+ if (videoAspectRatio == aspectRatio) return;
+
+ videoAspectRatio = aspectRatio;
+ requestLayout();
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/res/layout-large-land/activity_main_player.xml b/app/src/main/res/layout-large-land/activity_main_player.xml
index 73a1113c694..d434fe1ac2b 100644
--- a/app/src/main/res/layout-large-land/activity_main_player.xml
+++ b/app/src/main/res/layout-large-land/activity_main_player.xml
@@ -8,27 +8,18 @@
android:background="@color/black"
android:gravity="center">
-
-
-
-
-
-
+ android:layout_centerHorizontal="true"/>
-
+
-
-
-
@@ -235,11 +222,9 @@
android:id="@+id/qualityTextView"
android:layout_width="wrap_content"
android:layout_height="35dp"
- android:padding="6dp"
- android:layout_marginStart="5dp"
+ android:padding="@dimen/player_main_buttons_padding"
android:layout_marginEnd="8dp"
android:gravity="center"
- android:minWidth="50dp"
android:text="720p"
android:textColor="@android:color/white"
android:textStyle="bold"
@@ -251,11 +236,10 @@
android:id="@+id/playbackSpeed"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:padding="6dp"
+ android:padding="@dimen/player_main_buttons_padding"
android:layout_marginEnd="8dp"
android:gravity="center"
android:minHeight="35dp"
- android:minWidth="40dp"
android:textColor="@android:color/white"
android:textStyle="bold"
android:background="?attr/selectableItemBackground"
@@ -266,7 +250,7 @@
android:id="@+id/queueButton"
android:layout_width="30dp"
android:layout_height="35dp"
- android:padding="6dp"
+ android:padding="@dimen/player_main_buttons_padding"
android:layout_marginEnd="8dp"
android:clickable="true"
android:focusable="true"
@@ -280,8 +264,7 @@
android:id="@+id/moreOptionsButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:padding="8dp"
- android:layout_marginEnd="8dp"
+ android:padding="@dimen/player_main_buttons_padding"
android:clickable="true"
android:focusable="true"
android:scaleType="fitXY"
@@ -304,7 +287,7 @@
android:id="@+id/resizeTextView"
android:layout_width="wrap_content"
android:layout_height="35dp"
- android:padding="6dp"
+ android:padding="@dimen/player_main_buttons_padding"
android:layout_marginEnd="8dp"
android:gravity="center"
android:minWidth="50dp"
@@ -318,7 +301,7 @@
android:id="@+id/captionTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:padding="6dp"
+ android:padding="@dimen/player_main_buttons_padding"
android:layout_marginEnd="8dp"
android:gravity="center|left"
android:minHeight="35dp"
@@ -341,7 +324,7 @@
android:id="@+id/playWithKodi"
android:layout_width="wrap_content"
android:layout_height="35dp"
- android:padding="6dp"
+ android:padding="@dimen/player_main_buttons_padding"
android:layout_marginEnd="8dp"
android:clickable="true"
android:focusable="true"
@@ -355,7 +338,7 @@
android:id="@+id/openInBrowser"
android:layout_width="wrap_content"
android:layout_height="35dp"
- android:padding="6dp"
+ android:padding="@dimen/player_main_buttons_padding"
android:layout_marginEnd="8dp"
android:clickable="true"
android:focusable="true"
@@ -369,8 +352,7 @@
android:id="@+id/share"
android:layout_width="wrap_content"
android:layout_height="35dp"
- android:padding="6dp"
- android:layout_marginEnd="8dp"
+ android:padding="@dimen/player_main_buttons_padding"
android:clickable="true"
android:focusable="true"
android:scaleType="fitXY"
@@ -387,9 +369,7 @@
android:id="@+id/fullScreenButton"
android:layout_width="40dp"
android:layout_height="40dp"
- android:layout_marginTop="2dp"
- android:layout_marginEnd="2dp"
- android:padding="6dp"
+ android:padding="@dimen/player_main_buttons_padding"
android:layout_alignParentRight="true"
android:background="?attr/selectableItemBackground"
android:clickable="true"
@@ -413,9 +393,8 @@
android:layout_alignParentBottom="true"
android:gravity="center"
android:orientation="horizontal"
- android:paddingBottom="6dp"
- android:paddingLeft="16dp"
- android:paddingRight="16dp">
+ android:paddingLeft="@dimen/player_main_controls_padding"
+ android:paddingRight="@dimen/player_main_controls_padding">
diff --git a/app/src/main/res/layout/activity_main_player.xml b/app/src/main/res/layout/activity_main_player.xml
index cf44d6bcb0f..d631080965c 100644
--- a/app/src/main/res/layout/activity_main_player.xml
+++ b/app/src/main/res/layout/activity_main_player.xml
@@ -8,27 +8,18 @@
android:background="@color/black"
android:gravity="center">
-
-
-
-
-
-
+ android:layout_centerHorizontal="true"/>
-
+
-
-
-
@@ -233,11 +220,9 @@
android:id="@+id/qualityTextView"
android:layout_width="wrap_content"
android:layout_height="35dp"
- android:padding="6dp"
- android:layout_marginStart="5dp"
+ android:padding="@dimen/player_main_buttons_padding"
android:layout_marginEnd="8dp"
android:gravity="center"
- android:minWidth="50dp"
android:text="720p"
android:textColor="@android:color/white"
android:textStyle="bold"
@@ -249,11 +234,10 @@
android:id="@+id/playbackSpeed"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:padding="6dp"
+ android:padding="@dimen/player_main_buttons_padding"
android:layout_marginEnd="8dp"
android:gravity="center"
android:minHeight="35dp"
- android:minWidth="40dp"
android:textColor="@android:color/white"
android:textStyle="bold"
android:background="?attr/selectableItemBackground"
@@ -264,7 +248,7 @@
android:id="@+id/queueButton"
android:layout_width="30dp"
android:layout_height="35dp"
- android:padding="6dp"
+ android:padding="@dimen/player_main_buttons_padding"
android:layout_marginEnd="8dp"
android:clickable="true"
android:focusable="true"
@@ -278,8 +262,7 @@
android:id="@+id/moreOptionsButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:padding="8dp"
- android:layout_marginEnd="8dp"
+ android:padding="@dimen/player_main_buttons_padding"
android:clickable="true"
android:focusable="true"
android:scaleType="fitXY"
@@ -302,7 +285,7 @@
android:id="@+id/resizeTextView"
android:layout_width="wrap_content"
android:layout_height="35dp"
- android:padding="6dp"
+ android:padding="@dimen/player_main_buttons_padding"
android:layout_marginEnd="8dp"
android:gravity="center"
android:minWidth="50dp"
@@ -316,7 +299,7 @@
android:id="@+id/captionTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:padding="6dp"
+ android:padding="@dimen/player_main_buttons_padding"
android:layout_marginEnd="8dp"
android:gravity="center|left"
android:minHeight="35dp"
@@ -339,7 +322,7 @@
android:id="@+id/playWithKodi"
android:layout_width="wrap_content"
android:layout_height="35dp"
- android:padding="6dp"
+ android:padding="@dimen/player_main_buttons_padding"
android:layout_marginEnd="8dp"
android:clickable="true"
android:focusable="true"
@@ -353,7 +336,7 @@
android:id="@+id/openInBrowser"
android:layout_width="wrap_content"
android:layout_height="35dp"
- android:padding="6dp"
+ android:padding="@dimen/player_main_buttons_padding"
android:layout_marginEnd="8dp"
android:clickable="true"
android:focusable="true"
@@ -367,8 +350,7 @@
android:id="@+id/share"
android:layout_width="wrap_content"
android:layout_height="35dp"
- android:padding="6dp"
- android:layout_marginEnd="8dp"
+ android:padding="@dimen/player_main_buttons_padding"
android:clickable="true"
android:focusable="true"
android:scaleType="fitXY"
@@ -385,9 +367,7 @@
android:id="@+id/fullScreenButton"
android:layout_width="40dp"
android:layout_height="40dp"
- android:layout_marginTop="2dp"
- android:layout_marginEnd="2dp"
- android:padding="6dp"
+ android:padding="@dimen/player_main_buttons_padding"
android:layout_alignParentRight="true"
android:background="?attr/selectableItemBackground"
android:clickable="true"
@@ -411,9 +391,8 @@
android:layout_alignParentBottom="true"
android:gravity="center"
android:orientation="horizontal"
- android:paddingBottom="6dp"
- android:paddingLeft="16dp"
- android:paddingRight="16dp">
+ android:paddingLeft="@dimen/player_main_controls_padding"
+ android:paddingRight="@dimen/player_main_controls_padding">
diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml
index 07b71e5ee82..56928b2491e 100644
--- a/app/src/main/res/values/dimens.xml
+++ b/app/src/main/res/values/dimens.xml
@@ -24,6 +24,15 @@
2dp
4dp
8dp
+
+
+ 16dp
+ 6dp
+ 4dp
+ 6dp
+ 1dp
+ 40dp
+
180dp
150dp
From a47e6dd8c542eefe88d1ea2bd814ea57f4fe1cdf Mon Sep 17 00:00:00 2001
From: Avently <7953703+avently@users.noreply.github.com>
Date: Wed, 12 Feb 2020 22:33:23 +0300
Subject: [PATCH 017/398] AppBarLayout scrolling awesomeness, PlayQueue layout
touches interception, player's controls' margin - made scrolling in
appBarLayout awesome - PlayQueue layout was intercepting touches while it was
in GONE visibility state. Now it's not gonna happen - removed margin between
two lines of player's controls - when a user leaves the app with two back
presses the app will not stop MainPlayer service if popup or background
players play
---
.../material/appbar/FlingBehavior.java | 8 +--
.../fragments/detail/VideoDetailFragment.java | 5 +-
.../newpipe/player/VideoPlayerImpl.java | 6 +-
.../event/CustomBottomSheetBehavior.java | 61 +++++++------------
.../activity_main_player.xml | 1 -
.../fragment_video_detail.xml | 41 ++++++-------
.../main/res/layout/activity_main_player.xml | 1 -
.../main/res/layout/fragment_video_detail.xml | 48 ++++++---------
8 files changed, 69 insertions(+), 102 deletions(-)
diff --git a/app/src/main/java/com/google/android/material/appbar/FlingBehavior.java b/app/src/main/java/com/google/android/material/appbar/FlingBehavior.java
index f1038faa173..d8c5fd014ec 100644
--- a/app/src/main/java/com/google/android/material/appbar/FlingBehavior.java
+++ b/app/src/main/java/com/google/android/material/appbar/FlingBehavior.java
@@ -23,14 +23,14 @@ public FlingBehavior(Context context, AttributeSet attrs) {
}
private boolean allowScroll = true;
- private Rect playQueueRect = new Rect();
+ private Rect globalRect = new Rect();
@Override
public boolean onInterceptTouchEvent(CoordinatorLayout parent, AppBarLayout child, MotionEvent ev) {
- ViewGroup playQueue = child.findViewById(R.id.playQueue);
+ ViewGroup playQueue = child.findViewById(R.id.playQueuePanel);
if (playQueue != null) {
- playQueue.getGlobalVisibleRect(playQueueRect);
- if (playQueueRect.contains((int) ev.getRawX(), (int) ev.getRawY())) {
+ boolean visible = playQueue.getGlobalVisibleRect(globalRect);
+ if (visible && globalRect.contains((int) ev.getRawX(), (int) ev.getRawY())) {
allowScroll = false;
return false;
}
diff --git a/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java
index ce113a93dc6..6f65c34dcb9 100644
--- a/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java
+++ b/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java
@@ -403,8 +403,9 @@ public void onStop() {
public void onDestroy() {
super.onDestroy();
- if (!activity.isFinishing()) unbind();
- else stopService();
+ // Stop the service when user leaves the app with double back press if video player is selected. Otherwise unbind
+ if (activity.isFinishing() && player != null && player.videoPlayerSelected()) stopService();
+ else unbind();
PreferenceManager.getDefaultSharedPreferences(activity)
.unregisterOnSharedPreferenceChangeListener(this);
diff --git a/app/src/main/java/org/schabi/newpipe/player/VideoPlayerImpl.java b/app/src/main/java/org/schabi/newpipe/player/VideoPlayerImpl.java
index 72c3b71ee51..78f6aa38789 100644
--- a/app/src/main/java/org/schabi/newpipe/player/VideoPlayerImpl.java
+++ b/app/src/main/java/org/schabi/newpipe/player/VideoPlayerImpl.java
@@ -306,6 +306,7 @@ private void setupElementsVisibility() {
playerCloseButton.setVisibility(View.GONE);
getTopControlsRoot().bringToFront();
getBottomControlsRoot().bringToFront();
+ onQueueClosed();
} else {
fullscreenButton.setVisibility(View.GONE);
setupScreenRotationButton(service.isLandscape());
@@ -678,7 +679,10 @@ private void onQueueClicked() {
private void onQueueClosed() {
animateView(queueLayout, SLIDE_AND_ALPHA, /*visible=*/false,
- DEFAULT_CONTROLS_DURATION);
+ DEFAULT_CONTROLS_DURATION, 0, () -> {
+ // Even when queueLayout is GONE it receives touch events and ruins normal behavior of the app. This line fixes it
+ queueLayout.setTranslationY(-queueLayout.getHeight() * 5);
+ });
queueVisible = false;
}
diff --git a/app/src/main/java/org/schabi/newpipe/player/event/CustomBottomSheetBehavior.java b/app/src/main/java/org/schabi/newpipe/player/event/CustomBottomSheetBehavior.java
index f0178853f74..c7acc039079 100644
--- a/app/src/main/java/org/schabi/newpipe/player/event/CustomBottomSheetBehavior.java
+++ b/app/src/main/java/org/schabi/newpipe/player/event/CustomBottomSheetBehavior.java
@@ -4,61 +4,46 @@
import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.MotionEvent;
-import android.view.View;
import android.view.ViewGroup;
+import android.widget.FrameLayout;
+import androidx.annotation.NonNull;
import androidx.coordinatorlayout.widget.CoordinatorLayout;
import com.google.android.material.bottomsheet.BottomSheetBehavior;
import org.schabi.newpipe.R;
-public class CustomBottomSheetBehavior extends BottomSheetBehavior {
+import java.util.Arrays;
+import java.util.List;
+
+public class CustomBottomSheetBehavior extends BottomSheetBehavior {
public CustomBottomSheetBehavior(Context context, AttributeSet attrs) {
super(context, attrs);
}
- boolean skippingInterception = false;
+ boolean visible;
+ Rect globalRect = new Rect();
+ private boolean skippingInterception = false;
+ private List skipInterceptionOfElements = Arrays.asList(
+ R.id.detail_content_root_layout, R.id.relatedStreamsLayout, R.id.playQueuePanel, R.id.viewpager);
@Override
- public boolean onInterceptTouchEvent(CoordinatorLayout parent, View child, MotionEvent event) {
- // Behavior of globalVisibleRect is different on different APIs.
- // For example, on API 19 getGlobalVisibleRect returns a filled rect of a collapsed view while on the latest API
- // it returns empty rect in that case. So check visibility with return value too
- boolean visible;
- Rect rect = new Rect();
-
- // Drop folowing when actions ends
+ public boolean onInterceptTouchEvent(@NonNull CoordinatorLayout parent, @NonNull FrameLayout child, MotionEvent event) {
+ // Drop following when action ends
if (event.getAction() == MotionEvent.ACTION_CANCEL || event.getAction() == MotionEvent.ACTION_UP)
skippingInterception = false;
- // Found that user still swipping, continue folowing
+ // Found that user still swiping, continue following
if (skippingInterception) return false;
- // Without overriding scrolling will not work in detail_content_root_layout
- ViewGroup controls = child.findViewById(R.id.detail_content_root_layout);
- if (controls != null) {
- visible = controls.getGlobalVisibleRect(rect);
- if (rect.contains((int) event.getRawX(), (int) event.getRawY()) && visible) {
- skippingInterception = true;
- return false;
- }
- }
-
- // Without overriding scrolling will not work on relatedStreamsLayout
- ViewGroup relatedStreamsLayout = child.findViewById(R.id.relatedStreamsLayout);
- if (relatedStreamsLayout != null) {
- visible = relatedStreamsLayout.getGlobalVisibleRect(rect);
- if (rect.contains((int) event.getRawX(), (int) event.getRawY()) && visible) {
- skippingInterception = true;
- return false;
- }
- }
-
- ViewGroup playQueue = child.findViewById(R.id.playQueue);
- if (playQueue != null) {
- visible = playQueue.getGlobalVisibleRect(rect);
- if (rect.contains((int) event.getRawX(), (int) event.getRawY()) && visible) {
- skippingInterception = true;
- return false;
+ // Without overriding scrolling will not work when user touches these elements
+ for (Integer element : skipInterceptionOfElements) {
+ ViewGroup viewGroup = child.findViewById(element);
+ if (viewGroup != null) {
+ visible = viewGroup.getGlobalVisibleRect(globalRect);
+ if (visible && globalRect.contains((int) event.getRawX(), (int) event.getRawY())) {
+ skippingInterception = true;
+ return false;
+ }
}
}
diff --git a/app/src/main/res/layout-large-land/activity_main_player.xml b/app/src/main/res/layout-large-land/activity_main_player.xml
index d434fe1ac2b..4a4879d7f58 100644
--- a/app/src/main/res/layout-large-land/activity_main_player.xml
+++ b/app/src/main/res/layout-large-land/activity_main_player.xml
@@ -157,7 +157,6 @@
android:minHeight="50dp"
android:baselineAligned="false"
android:gravity="top"
- android:layout_marginBottom="7dp"
tools:ignore="RtlHardcoded">
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
Date: Tue, 25 Feb 2020 02:15:22 +0300
Subject: [PATCH 018/398] Vertical videos in portrait & fullscreen, UI
enhancements for tablets and phones, fixes - vertical videos now work ok in
portrait and fullscreen mode at the same time - auto pause on back press is
disabled for large tablets - large dragable area for swipe to bottom in
fullscreen mode in place of top controls - appbar will be scrolled to top
when entering in fullscreen mode
---
.../fragments/detail/VideoDetailFragment.java | 11 +--
.../newpipe/player/VideoPlayerImpl.java | 75 ++++++++++++++-----
.../player/event/PlayerGestureListener.java | 5 +-
.../activity_main_player.xml | 44 +++++------
.../main/res/layout/activity_main_player.xml | 44 +++++------
5 files changed, 112 insertions(+), 67 deletions(-)
diff --git a/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java
index 6f65c34dcb9..a946e3f9952 100644
--- a/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java
+++ b/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java
@@ -870,7 +870,7 @@ public boolean onBackPressed() {
// If we are in fullscreen mode just exit from it via first back press
if (player != null && player.isInFullscreen()) {
- player.onPause();
+ if (!PlayerHelper.isTablet(activity)) player.onPause();
restoreDefaultOrientation();
setAutoplay(false);
return true;
@@ -1699,6 +1699,7 @@ public void onMetadataUpdate(StreamInfo info) {
if (currentInfo != null && info.getUrl().equals(currentInfo.getUrl())) return;
currentInfo = info;
+ setInitialData(info.getServiceId(), info.getUrl(),info.getName(), playQueue);
setAutoplay(false);
prepareAndHandleInfo(info, true);
}
@@ -1736,6 +1737,7 @@ public void onFullscreenStateChanged(boolean fullscreen) {
}
if (relatedStreamsLayout != null) relatedStreamsLayout.setVisibility(fullscreen ? View.GONE : View.VISIBLE);
+ scrollToTop();
addVideoPlayerView();
}
@@ -1842,12 +1844,10 @@ private void checkLandscape() {
if ((!player.isPlaying() && player.getPlayQueue() != playQueue) || player.getPlayQueue() == null)
setAutoplay(true);
+ player.checkLandscape();
boolean orientationLocked = PlayerHelper.globalScreenOrientationLocked(activity);
// Let's give a user time to look at video information page if video is not playing
- if (player.isPlaying()) {
- player.checkLandscape();
- } else if (orientationLocked) {
- player.checkLandscape();
+ if (orientationLocked && !player.isPlaying()) {
player.onPlay();
player.showControlsThenHide();
}
@@ -1927,6 +1927,7 @@ private void setupBottomPlayer() {
case BottomSheetBehavior.STATE_COLLAPSED:
// Re-enable clicks
setOverlayElementsClickable(true);
+ if (player != null) player.onQueueClosed();
break;
case BottomSheetBehavior.STATE_DRAGGING:
case BottomSheetBehavior.STATE_SETTLING:
diff --git a/app/src/main/java/org/schabi/newpipe/player/VideoPlayerImpl.java b/app/src/main/java/org/schabi/newpipe/player/VideoPlayerImpl.java
index 78f6aa38789..ec490451bf7 100644
--- a/app/src/main/java/org/schabi/newpipe/player/VideoPlayerImpl.java
+++ b/app/src/main/java/org/schabi/newpipe/player/VideoPlayerImpl.java
@@ -74,9 +74,11 @@
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.*;
import static org.schabi.newpipe.player.helper.PlayerHelper.MinimizeMode.MINIMIZE_ON_EXIT_MODE_BACKGROUND;
import static org.schabi.newpipe.player.helper.PlayerHelper.getTimeString;
+import static org.schabi.newpipe.player.helper.PlayerHelper.isTablet;
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;
@@ -137,6 +139,7 @@ public class VideoPlayerImpl extends VideoPlayer
private boolean audioOnly = false;
private boolean isFullscreen = false;
+ private boolean isVerticalVideo = false;
boolean shouldUpdateOnProgress;
private MainPlayer service;
@@ -305,11 +308,13 @@ private void setupElementsVisibility() {
openInBrowser.setVisibility(View.GONE);
playerCloseButton.setVisibility(View.GONE);
getTopControlsRoot().bringToFront();
+ getTopControlsRoot().setClickable(false);
+ getTopControlsRoot().setFocusable(false);
getBottomControlsRoot().bringToFront();
onQueueClosed();
} else {
fullscreenButton.setVisibility(View.GONE);
- setupScreenRotationButton(service.isLandscape());
+ setupScreenRotationButton();
getResizeView().setVisibility(View.VISIBLE);
getRootView().findViewById(R.id.metadataView).setVisibility(View.VISIBLE);
moreOptionsButton.setVisibility(View.VISIBLE);
@@ -323,6 +328,10 @@ private void setupElementsVisibility() {
defaultPreferences.getBoolean(service.getString(R.string.show_play_with_kodi_key), false) ? View.VISIBLE : View.GONE);
openInBrowser.setVisibility(View.VISIBLE);
playerCloseButton.setVisibility(isFullscreen ? View.GONE : View.VISIBLE);
+ // Top controls have a large minHeight which is allows to drag the player down in fullscreen mode (just larger area
+ // to make easy to locate by finger)
+ getTopControlsRoot().setClickable(true);
+ getTopControlsRoot().setFocusable(true);
}
if (!isInFullscreen()) {
titleTextView.setVisibility(View.GONE);
@@ -393,7 +402,7 @@ public void initListeners() {
settingsContentObserver = new ContentObserver(new Handler()) {
@Override
- public void onChange(boolean selfChange) { setupScreenRotationButton(service.isLandscape()); }
+ public void onChange(boolean selfChange) { setupScreenRotationButton(); }
};
service.getContentResolver().registerContentObserver(
Settings.System.getUriFor(Settings.System.ACCELEROMETER_ROTATION), false,
@@ -442,6 +451,14 @@ public void onPlaybackParameterChanged(float playbackTempo, float playbackPitch,
setPlaybackParameters(playbackTempo, playbackPitch, playbackSkipSilence);
}
+ @Override
+ public void onVideoSizeChanged(int width, int height, int unappliedRotationDegrees, float pixelWidthHeightRatio) {
+ super.onVideoSizeChanged(width, height, unappliedRotationDegrees, pixelWidthHeightRatio);
+ isVerticalVideo = width < height;
+ prepareOrientation();
+ setupScreenRotationButton();
+ }
+
/*//////////////////////////////////////////////////////////////////////////
// ExoPlayer Video Listener
//////////////////////////////////////////////////////////////////////////*/
@@ -597,7 +614,7 @@ public void toggleFullscreen() {
channelTextView.setVisibility(View.VISIBLE);
playerCloseButton.setVisibility(View.GONE);
}
- setupScreenRotationButton(isInFullscreen());
+ setupScreenRotationButton();
}
@Override
@@ -637,7 +654,8 @@ public void onClick(View v) {
toggleFullscreen();
} else if (v.getId() == screenRotationButton.getId()) {
- fragmentListener.onScreenRotationButtonClicked();
+ if (!isVerticalVideo) fragmentListener.onScreenRotationButtonClicked();
+ else toggleFullscreen();
} else if (v.getId() == playerCloseButton.getId()) {
service.sendBroadcast(new Intent(VideoDetailFragment.ACTION_HIDE_MAIN_PLAYER));
@@ -667,6 +685,7 @@ public boolean onLongClick(View v) {
private void onQueueClicked() {
queueVisible = true;
+ hideSystemUIIfNeeded();
buildQueue();
updatePlaybackButtons();
@@ -677,7 +696,9 @@ private void onQueueClicked() {
itemsList.scrollToPosition(playQueue.getIndex());
}
- private void onQueueClosed() {
+ public void onQueueClosed() {
+ if (!queueVisible) return;
+
animateView(queueLayout, SLIDE_AND_ALPHA, /*visible=*/false,
DEFAULT_CONTROLS_DURATION, 0, () -> {
// Even when queueLayout is GONE it receives touch events and ruins normal behavior of the app. This line fixes it
@@ -733,11 +754,18 @@ private static void showInstallKoreDialog(final Context context) {
builder.create().show();
}
- private void setupScreenRotationButton(boolean landscape) {
+ private void setupScreenRotationButton() {
boolean orientationLocked = PlayerHelper.globalScreenOrientationLocked(service);
- screenRotationButton.setVisibility(orientationLocked && videoPlayerSelected() ? View.VISIBLE : View.GONE);
+ boolean showButton = (orientationLocked || isVerticalVideo || isTablet(service)) && videoPlayerSelected();
+ screenRotationButton.setVisibility(showButton ? View.VISIBLE : View.GONE);
screenRotationButton.setImageDrawable(service.getResources().getDrawable(
- landscape ? R.drawable.ic_fullscreen_exit_white : R.drawable.ic_fullscreen_white));
+ isInFullscreen() ? R.drawable.ic_fullscreen_exit_white : R.drawable.ic_fullscreen_white));
+ }
+
+ private void prepareOrientation() {
+ boolean orientationLocked = PlayerHelper.globalScreenOrientationLocked(service);
+ if (orientationLocked && isInFullscreen() && service.isLandscape() == isVerticalVideo && fragmentListener != null)
+ fragmentListener.onScreenRotationButtonClicked();
}
@Override
@@ -779,7 +807,7 @@ public void onLayoutChange(final View view, int l, int t, int r, int b,
brightnessProgressBar.setMax(maxGestureLength);
setInitialGestureValues();
- queueLayout.getLayoutParams().height = min - queueLayout.getTop();
+ queueLayout.getLayoutParams().height = height - queueLayout.getTop();
if (popupPlayerSelected()) {
float widthDp = Math.abs(r - l) / service.getResources().getDisplayMetrics().density;
@@ -1009,7 +1037,16 @@ public void onBroadcastReceived(Intent intent) {
onRepeatClicked();
break;
case Intent.ACTION_CONFIGURATION_CHANGED:
- setControlsSize();
+ // 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
+ boolean reportedOrientationIsLandscape = service.isLandscape();
+ 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();
break;
case Intent.ACTION_SCREEN_ON:
shouldUpdateOnProgress = true;
@@ -1201,7 +1238,7 @@ public void setControlsSize() {
// It doesn't include NavigationBar, notches, etc.
display.getSize(size);
- int width = isFullscreen ? size.x : ViewGroup.LayoutParams.MATCH_PARENT;
+ int width = isFullscreen ? (service.isLandscape() ? size.x : size.y) : ViewGroup.LayoutParams.MATCH_PARENT;
int gravity = isFullscreen ? (display.getRotation() == Surface.ROTATION_90 ? Gravity.START : Gravity.END) : Gravity.TOP;
getTopControlsRoot().getLayoutParams().width = width;
@@ -1218,10 +1255,11 @@ public void setControlsSize() {
bottomParams.addRule(gravity == Gravity.END ? RelativeLayout.ALIGN_PARENT_END : RelativeLayout.ALIGN_PARENT_START);
getBottomControlsRoot().requestLayout();
- ViewGroup controlsRoot = getRootView().findViewById(R.id.playbackControlRoot);
- // In tablet navigationBar located at the bottom of the screen. And the only situation when we need to set custom height is
- // in fullscreen mode in tablet in non-multiWindow mode. Other than that MATCH_PARENT is good
- controlsRoot.getLayoutParams().height = isFullscreen && !isInMultiWindow() && PlayerHelper.isTablet(service)
+ 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
+ boolean navBarAtTheBottom = PlayerHelper.isTablet(service) || !service.isLandscape();
+ controlsRoot.getLayoutParams().height = isFullscreen && !isInMultiWindow() && navBarAtTheBottom
? size.y
: ViewGroup.LayoutParams.MATCH_PARENT;
controlsRoot.requestLayout();
@@ -1264,9 +1302,12 @@ private void updatePlaybackButtons() {
public void checkLandscape() {
AppCompatActivity parent = getParentActivity();
- if (parent != null && service.isLandscape() != isInFullscreen()
- && getCurrentState() != STATE_COMPLETED && videoPlayerSelected() && !audioOnly)
+ boolean videoInLandscapeButNotInFullscreen = service.isLandscape() && !isInFullscreen() && videoPlayerSelected() && !audioOnly;
+ boolean playingState = getCurrentState() != STATE_COMPLETED && getCurrentState() != STATE_PAUSED;
+ if (parent != null && videoInLandscapeButNotInFullscreen && playingState)
toggleFullscreen();
+
+ setControlsSize();
}
private void buildQueue() {
diff --git a/app/src/main/java/org/schabi/newpipe/player/event/PlayerGestureListener.java b/app/src/main/java/org/schabi/newpipe/player/event/PlayerGestureListener.java
index db7d8d615ee..bb9ede4d73e 100644
--- a/app/src/main/java/org/schabi/newpipe/player/event/PlayerGestureListener.java
+++ b/app/src/main/java/org/schabi/newpipe/player/event/PlayerGestureListener.java
@@ -160,9 +160,8 @@ private boolean onScrollInMain(MotionEvent initialEvent, MotionEvent movingEvent
isMovingInMain = true;
- boolean acceptAnyArea = isVolumeGestureEnabled != isBrightnessGestureEnabled;
- boolean acceptVolumeArea = acceptAnyArea || initialEvent.getX() > playerImpl.getRootView().getWidth() / 2;
- boolean acceptBrightnessArea = acceptAnyArea || !acceptVolumeArea;
+ boolean acceptVolumeArea = initialEvent.getX() > playerImpl.getRootView().getWidth() / 2.0;
+ boolean acceptBrightnessArea = initialEvent.getX() <= playerImpl.getRootView().getWidth() / 2.0;
if (isVolumeGestureEnabled && acceptVolumeArea) {
playerImpl.getVolumeProgressBar().incrementProgressBy((int) distanceY);
diff --git a/app/src/main/res/layout-large-land/activity_main_player.xml b/app/src/main/res/layout-large-land/activity_main_player.xml
index 4a4879d7f58..d879303713f 100644
--- a/app/src/main/res/layout-large-land/activity_main_player.xml
+++ b/app/src/main/res/layout-large-land/activity_main_player.xml
@@ -12,7 +12,7 @@
android:id="@+id/surfaceView"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:layout_centerHorizontal="true"/>
+ android:layout_centerInParent="true"/>
+
+
-
-
-
+
+ android:layout_centerInParent="true"/>
+
+
-
-
-
+
Date: Sat, 29 Feb 2020 02:57:54 +0300
Subject: [PATCH 019/398] Better implementation of old code
---
.../newpipe/fragments/detail/StackItem.java | 6 +-
.../fragments/detail/VideoDetailFragment.java | 66 +++++++------------
.../org/schabi/newpipe/player/MainPlayer.java | 1 +
.../newpipe/player/VideoPlayerImpl.java | 30 +++++++--
.../event/PlayerServiceEventListener.java | 4 +-
5 files changed, 55 insertions(+), 52 deletions(-)
diff --git a/app/src/main/java/org/schabi/newpipe/fragments/detail/StackItem.java b/app/src/main/java/org/schabi/newpipe/fragments/detail/StackItem.java
index 2e90a4fc9f7..38e41b2fb4b 100644
--- a/app/src/main/java/org/schabi/newpipe/fragments/detail/StackItem.java
+++ b/app/src/main/java/org/schabi/newpipe/fragments/detail/StackItem.java
@@ -8,7 +8,7 @@ class StackItem implements Serializable {
private final int serviceId;
private String title;
private String url;
- private final PlayQueue playQueue;
+ private PlayQueue playQueue;
StackItem(int serviceId, String url, String title, PlayQueue playQueue) {
this.serviceId = serviceId;
@@ -25,6 +25,10 @@ public void setUrl(String url) {
this.url = url;
}
+ public void setPlayQueue(PlayQueue queue) {
+ this.playQueue = queue;
+ }
+
public int getServiceId() {
return serviceId;
}
diff --git a/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java
index a946e3f9952..efb997d5057 100644
--- a/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java
+++ b/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java
@@ -99,8 +99,6 @@ public class VideoDetailFragment
PlayerServiceEventListener {
public static final String AUTO_PLAY = "auto_play";
- private boolean isFragmentStopped;
-
private int updateFlags = 0;
private static final int RELATED_STREAMS_UPDATE_FLAG = 0x1;
private static final int RESOLUTIONS_MENU_UPDATE_FLAG = 0x2;
@@ -109,8 +107,10 @@ public class VideoDetailFragment
private static final float MAX_OVERLAY_ALPHA = 0.9f;
private static final float MAX_PLAYER_HEIGHT = 0.7f;
- public static final String ACTION_SHOW_MAIN_PLAYER = "org.schabi.newpipe.fragments.VideoDetailFragment.ACTION_SHOW_MAIN_PLAYER";
- public static final String ACTION_HIDE_MAIN_PLAYER = "org.schabi.newpipe.fragments.VideoDetailFragment.ACTION_HIDE_MAIN_PLAYER";
+ public static final String ACTION_SHOW_MAIN_PLAYER = "org.schabi.newpipe.VideoDetailFragment.ACTION_SHOW_MAIN_PLAYER";
+ public static final String ACTION_HIDE_MAIN_PLAYER = "org.schabi.newpipe.VideoDetailFragment.ACTION_HIDE_MAIN_PLAYER";
+ public static final String ACTION_VIDEO_FRAGMENT_RESUMED = "org.schabi.newpipe.VideoDetailFragment.ACTION_VIDEO_FRAGMENT_RESUMED";
+ public static final String ACTION_VIDEO_FRAGMENT_STOPPED = "org.schabi.newpipe.VideoDetailFragment.ACTION_VIDEO_FRAGMENT_STOPPED";
private boolean showRelatedStreams;
private boolean showComments;
@@ -233,15 +233,13 @@ public void onServiceConnected(ComponentName compName, IBinder service) {
startPlayerListener();
// It will do nothing if the player is not in fullscreen mode
- hideSystemUIIfNeeded();
+ hideSystemUiIfNeeded();
if (!player.videoPlayerSelected() && !playAfterConnect) return;
- // STATE_IDLE means the player is stopped
- if (player.getPlayer() != null && player.getPlayer().getPlaybackState() != Player.STATE_IDLE) addVideoPlayerView();
+ if (playerIsNotStopped()) addVideoPlayerView();
// If the video is playing but orientation changed let's make the video in fullscreen again
-
if (isLandscape()) checkLandscape();
else if (player.isInFullscreen()) player.toggleFullscreen();
@@ -363,7 +361,7 @@ public void onPause() {
public void onResume() {
super.onResume();
- isFragmentStopped = false;
+ activity.sendBroadcast(new Intent(ACTION_VIDEO_FRAGMENT_RESUMED));
setupBrightness(false);
@@ -383,20 +381,16 @@ public void onResume() {
}
// Check if it was loading when the fragment was stopped/paused
- if (wasLoading.getAndSet(false) && !wasCleared()) {
+ if (wasLoading.getAndSet(false) && !wasCleared())
selectAndLoadVideo(serviceId, url, name, playQueue);
- } else if (currentInfo != null) {
- updateProgressInfo(currentInfo);
- }
-
- if (player != null && player.videoPlayerSelected()) addVideoPlayerView();
}
@Override
public void onStop() {
super.onStop();
- isFragmentStopped = true;
+ if (!activity.isChangingConfigurations())
+ activity.sendBroadcast(new Intent(ACTION_VIDEO_FRAGMENT_STOPPED));
}
@Override
@@ -546,7 +540,7 @@ public void onClick(View v) {
bottomSheetBehavior.setState(BottomSheetBehavior.STATE_EXPANDED);
break;
case R.id.overlay_play_pause_button:
- if (player != null && player.getPlayer() != null && player.getPlayer().getPlaybackState() != Player.STATE_IDLE) {
+ if (playerIsNotStopped()) {
player.onPlayPause();
player.hideControls(0,0);
showSystemUi();
@@ -1632,8 +1626,14 @@ public void onQueueUpdate(PlayQueue queue) {
playQueue = queue;
// This should be the only place where we push data to stack. It will allow to have live instance of PlayQueue with actual
// information about deleted/added items inside Channel/Playlist queue and makes possible to have a history of played items
- if (stack.isEmpty() || !stack.peek().getPlayQueue().equals(queue))
+ if (stack.isEmpty() || !stack.peek().getPlayQueue().equals(queue)) {
stack.push(new StackItem(serviceId, url, name, playQueue));
+ } else if (stack.peek().getPlayQueue().equals(queue)) {
+ // On every MainPlayer service's destroy() playQueue gets disposed and no longer able to track progress.
+ // That's why we update our cached disposed queue with the new one that is active and have the same history
+ // Without that the cached playQueue will have an old recovery position
+ stack.peek().setPlayQueue(queue);
+ }
if (DEBUG) {
Log.d(TAG, "onQueueUpdate() called with: serviceId = ["
@@ -1668,21 +1668,6 @@ public void onProgressUpdate(int currentProgress, int duration, int bufferPercen
if (player.getPlayQueue().getItem().getUrl().equals(url))
showPlaybackProgress(currentProgress, duration);
-
- // We don't want to interrupt playback and don't want to see notification if player is stopped
- // since next lines of code will enable background playback if needed
- if (!player.videoPlayerSelected()) return;
-
- // This will be called when user goes to another app
- if (isFragmentStopped) {
- // Video enabled. Let's think what to do with source in background
- if (player.backgroundPlaybackEnabled())
- player.useVideoSource(false);
- else if (player.minimizeOnPopupEnabled())
- NavigationHelper.playOnPopupPlayer(activity, playQueue, true);
- else player.onPause();
- }
- else player.useVideoSource(true);
}
@Override
@@ -1731,7 +1716,7 @@ public void onFullscreenStateChanged(boolean fullscreen) {
if (parent == null) return;
if (fullscreen) {
- hideSystemUIIfNeeded();
+ hideSystemUiIfNeeded();
} else {
showSystemUi();
}
@@ -1776,11 +1761,6 @@ public void onMoreOptionsLongClicked() {
valueAnimator.start();
}
- @Override
- public boolean isFragmentStopped() {
- return isFragmentStopped;
- }
-
/*//////////////////////////////////////////////////////////////////////////
// Player related utils
//////////////////////////////////////////////////////////////////////////*/
@@ -1811,11 +1791,15 @@ private void hideSystemUi() {
}
// Listener implementation
- public void hideSystemUIIfNeeded() {
+ public void hideSystemUiIfNeeded() {
if (player != null && player.isInFullscreen() && bottomSheetBehavior.getState() == BottomSheetBehavior.STATE_EXPANDED)
hideSystemUi();
}
+ private boolean playerIsNotStopped() {
+ return player != null && player.getPlayer() != null && player.getPlayer().getPlaybackState() != Player.STATE_IDLE;
+ }
+
private void setupBrightness(boolean save) {
if (activity == null) return;
@@ -1916,7 +1900,7 @@ private void setupBottomPlayer() {
bottomSheetBehavior.setPeekHeight(peekHeight);
// Disable click because overlay buttons located on top of buttons from the player
setOverlayElementsClickable(false);
- hideSystemUIIfNeeded();
+ hideSystemUiIfNeeded();
boolean needToExpand = isLandscape()
&& player != null
&& player.isPlaying()
diff --git a/app/src/main/java/org/schabi/newpipe/player/MainPlayer.java b/app/src/main/java/org/schabi/newpipe/player/MainPlayer.java
index 771d6d7e151..61b69ac5e73 100644
--- a/app/src/main/java/org/schabi/newpipe/player/MainPlayer.java
+++ b/app/src/main/java/org/schabi/newpipe/player/MainPlayer.java
@@ -177,6 +177,7 @@ private void onClose() {
if (playerImpl != null) {
removeViewFromParent();
+ playerImpl.setRecovery();
playerImpl.savePlaybackState();
playerImpl.stopActivityBinding();
playerImpl.removePopupFromView();
diff --git a/app/src/main/java/org/schabi/newpipe/player/VideoPlayerImpl.java b/app/src/main/java/org/schabi/newpipe/player/VideoPlayerImpl.java
index ec490451bf7..4aa10fe9af2 100644
--- a/app/src/main/java/org/schabi/newpipe/player/VideoPlayerImpl.java
+++ b/app/src/main/java/org/schabi/newpipe/player/VideoPlayerImpl.java
@@ -999,6 +999,9 @@ protected void setupBroadcastReceiver(IntentFilter intentFilter) {
intentFilter.addAction(ACTION_FAST_REWIND);
intentFilter.addAction(ACTION_FAST_FORWARD);
+ intentFilter.addAction(VideoDetailFragment.ACTION_VIDEO_FRAGMENT_RESUMED);
+ intentFilter.addAction(VideoDetailFragment.ACTION_VIDEO_FRAGMENT_STOPPED);
+
intentFilter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
intentFilter.addAction(Intent.ACTION_SCREEN_ON);
intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
@@ -1036,6 +1039,24 @@ public void onBroadcastReceived(Intent intent) {
case ACTION_REPEAT:
onRepeatClicked();
break;
+ case VideoDetailFragment.ACTION_VIDEO_FRAGMENT_RESUMED:
+ useVideoSource(true);
+ break;
+ case VideoDetailFragment.ACTION_VIDEO_FRAGMENT_STOPPED:
+ // This will be called when user goes to another app
+ // We don't want to interrupt playback and don't want to see notification if player is stopped
+ // since next lines of code will enable background playback if needed
+ if (videoPlayerSelected() && isPlaying()) {
+ if (backgroundPlaybackEnabled()) {
+ useVideoSource(false);
+ } else if (minimizeOnPopupEnabled()) {
+ setRecovery();
+ NavigationHelper.playOnPopupPlayer(getParentActivity(), playQueue, true);
+ } else {
+ onPause();
+ }
+ }
+ break;
case Intent.ACTION_CONFIGURATION_CHANGED:
// 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
@@ -1223,7 +1244,7 @@ private void showSystemUIPartially() {
@Override
public void hideSystemUIIfNeeded() {
if (fragmentListener != null)
- fragmentListener.hideSystemUIIfNeeded();
+ fragmentListener.hideSystemUiIfNeeded();
}
/**
@@ -1327,12 +1348,7 @@ private void buildQueue() {
}
public void useVideoSource(boolean video) {
- // Return when: old value of audioOnly equals to the new value, audio player is selected,
- // video player is selected AND fragment is not shown
- if (playQueue == null
- || audioOnly == !video
- || audioPlayerSelected()
- || (video && videoPlayerSelected() && fragmentListener.isFragmentStopped()))
+ if (playQueue == null || audioOnly == !video || audioPlayerSelected())
return;
audioOnly = !video;
diff --git a/app/src/main/java/org/schabi/newpipe/player/event/PlayerServiceEventListener.java b/app/src/main/java/org/schabi/newpipe/player/event/PlayerServiceEventListener.java
index eeff08b5ce2..69e23f8fb9d 100644
--- a/app/src/main/java/org/schabi/newpipe/player/event/PlayerServiceEventListener.java
+++ b/app/src/main/java/org/schabi/newpipe/player/event/PlayerServiceEventListener.java
@@ -11,7 +11,5 @@ public interface PlayerServiceEventListener extends PlayerEventListener {
void onPlayerError(ExoPlaybackException error);
- boolean isFragmentStopped();
-
- void hideSystemUIIfNeeded();
+ void hideSystemUiIfNeeded();
}
\ No newline at end of file
From d87e488c236ed576675f25c3d27d815cab0e31f7 Mon Sep 17 00:00:00 2001
From: Avently <7953703+avently@users.noreply.github.com>
Date: Sat, 29 Feb 2020 22:13:07 +0300
Subject: [PATCH 020/398] Fix for a ripple effect on a button
---
.../java/org/schabi/newpipe/player/VideoPlayerImpl.java | 9 +++++++--
1 file changed, 7 insertions(+), 2 deletions(-)
diff --git a/app/src/main/java/org/schabi/newpipe/player/VideoPlayerImpl.java b/app/src/main/java/org/schabi/newpipe/player/VideoPlayerImpl.java
index 4aa10fe9af2..d026ff8cf29 100644
--- a/app/src/main/java/org/schabi/newpipe/player/VideoPlayerImpl.java
+++ b/app/src/main/java/org/schabi/newpipe/player/VideoPlayerImpl.java
@@ -320,7 +320,7 @@ private void setupElementsVisibility() {
moreOptionsButton.setVisibility(View.VISIBLE);
getTopControlsRoot().setOrientation(LinearLayout.VERTICAL);
primaryControls.getLayoutParams().width = LinearLayout.LayoutParams.MATCH_PARENT;
- secondaryControls.setVisibility(View.GONE);
+ secondaryControls.setVisibility(View.INVISIBLE);
moreOptionsButton.setImageDrawable(service.getResources().getDrawable(
R.drawable.ic_expand_more_white_24dp));
shareButton.setVisibility(View.VISIBLE);
@@ -715,7 +715,12 @@ private void onMoreOptionsClicked() {
animateRotation(moreOptionsButton, DEFAULT_CONTROLS_DURATION,
isMoreControlsVisible ? 0 : 180);
animateView(secondaryControls, SLIDE_AND_ALPHA, !isMoreControlsVisible,
- DEFAULT_CONTROLS_DURATION);
+ DEFAULT_CONTROLS_DURATION, 0,
+ () -> {
+ // Fix for a ripple effect on background drawable. When view returns from GONE state it takes more
+ // milliseconds than returning from INVISIBLE state. And the delay makes ripple background end to fast
+ if (isMoreControlsVisible) secondaryControls.setVisibility(View.INVISIBLE);
+ });
showControls(DEFAULT_CONTROLS_DURATION);
}
From 398cbe9284a10a2cf7fa9c7524edc89c26014a48 Mon Sep 17 00:00:00 2001
From: Avently <7953703+avently@users.noreply.github.com>
Date: Tue, 10 Mar 2020 12:06:38 +0300
Subject: [PATCH 021/398] Better backstack, better tablet support, switching
players confirmation, fix for background playback
---
.../fragments/detail/VideoDetailFragment.java | 118 ++++++++++++++----
.../newpipe/player/BackgroundPlayer.java | 2 +-
.../org/schabi/newpipe/player/BasePlayer.java | 4 +
.../newpipe/player/PopupVideoPlayer.java | 2 +-
.../newpipe/player/ServicePlayerActivity.java | 2 +-
.../newpipe/player/VideoPlayerImpl.java | 26 ++--
.../event/CustomBottomSheetBehavior.java | 19 +--
.../player/event/PlayerEventListener.java | 2 +-
.../newpipe/player/helper/PlayerHelper.java | 4 +
app/src/main/res/values/settings_keys.xml | 1 +
app/src/main/res/values/strings.xml | 3 +
app/src/main/res/xml/video_audio_settings.xml | 8 ++
12 files changed, 140 insertions(+), 51 deletions(-)
diff --git a/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java
index efb997d5057..0b7ffddef63 100644
--- a/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java
+++ b/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java
@@ -18,6 +18,7 @@
import androidx.annotation.DrawableRes;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import androidx.appcompat.app.AlertDialog;
import androidx.coordinatorlayout.widget.CoordinatorLayout;
import com.google.android.exoplayer2.ExoPlaybackException;
import com.google.android.exoplayer2.PlaybackParameters;
@@ -74,6 +75,7 @@
import java.io.Serializable;
import java.util.Collection;
+import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.TimeUnit;
@@ -86,6 +88,7 @@
import io.reactivex.schedulers.Schedulers;
import static org.schabi.newpipe.extractor.StreamingService.ServiceInfo.MediaCapability.COMMENTS;
+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;
@@ -237,7 +240,7 @@ public void onServiceConnected(ComponentName compName, IBinder service) {
if (!player.videoPlayerSelected() && !playAfterConnect) return;
- if (playerIsNotStopped()) addVideoPlayerView();
+ if (playerIsNotStopped() && player.videoPlayerSelected()) addVideoPlayerView();
// If the video is playing but orientation changed let's make the video in fullscreen again
if (isLandscape()) checkLandscape();
@@ -382,7 +385,7 @@ public void onResume() {
// Check if it was loading when the fragment was stopped/paused
if (wasLoading.getAndSet(false) && !wasCleared())
- selectAndLoadVideo(serviceId, url, name, playQueue);
+ startLoading(false);
}
@Override
@@ -870,16 +873,10 @@ public boolean onBackPressed() {
return true;
}
- StackItem currentPeek = stack.peek();
- if (currentPeek != null && !currentPeek.getPlayQueue().equals(playQueue)) {
- // When user selected a stream but didn't start playback this stream will not be added to backStack.
- // Then he press Back and the last saved item from history will show up
- setupFromHistoryItem(currentPeek);
- return true;
- }
-
// If we have something in history of played items we replay it here
- boolean isPreviousCanBePlayed = player != null && player.getPlayQueue() != null && player.videoPlayerSelected()
+ boolean isPreviousCanBePlayed = player != null
+ && player.getPlayQueue() != null
+ && player.videoPlayerSelected()
&& player.getPlayQueue().previous();
if (isPreviousCanBePlayed) {
return true;
@@ -903,11 +900,15 @@ private void setupFromHistoryItem(StackItem item) {
setAutoplay(false);
hideMainPlayer();
- selectAndLoadVideo(
+ setInitialData(
item.getServiceId(),
item.getUrl(),
!TextUtils.isEmpty(item.getTitle()) ? item.getTitle() : "",
item.getPlayQueue());
+ startLoading(false);
+
+ // Maybe an item was deleted in background activity
+ if (item.getPlayQueue().getItem() == null) return;
PlayQueueItem playQueueItem = item.getPlayQueue().getItem();
// Update title, url, uploader from the last item in the stack (it's current now)
@@ -936,7 +937,7 @@ public void selectAndLoadVideo(int serviceId, String videoUrl, String name, Play
return;
}
setInitialData(serviceId, videoUrl, name, playQueue);
- startLoading(false);
+ startLoading(false, true);
}
public void prepareAndHandleInfo(final StreamInfo info, boolean scrollToTop) {
@@ -965,6 +966,20 @@ public void startLoading(boolean forceLoad) {
currentInfo = null;
if (currentWorker != null) currentWorker.dispose();
+ runWorker(forceLoad, stack.isEmpty());
+ }
+
+ private void startLoading(boolean forceLoad, boolean addToBackStack) {
+ super.startLoading(false);
+
+ initTabs();
+ currentInfo = null;
+ if (currentWorker != null) currentWorker.dispose();
+
+ runWorker(forceLoad, addToBackStack);
+ }
+
+ private void runWorker(boolean forceLoad, boolean addToBackStack) {
currentWorker = ExtractorHelper.getStreamInfo(serviceId, url, forceLoad)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
@@ -973,12 +988,15 @@ public void startLoading(boolean forceLoad) {
hideMainPlayer();
handleResult(result);
showContent();
+ if (addToBackStack) {
+ if (playQueue == null) playQueue = new SinglePlayQueue(result);
+ stack.push(new StackItem(serviceId, url, name, playQueue));
+ }
if (isAutoplayEnabled()) openVideoPlayer();
}, (@NonNull Throwable throwable) -> {
isLoading.set(false);
onError(throwable);
});
-
}
private void initTabs() {
@@ -1063,7 +1081,9 @@ private void openPopupPlayer(final boolean append) {
if (append) {
NavigationHelper.enqueueOnPopupPlayer(activity, queue, false);
} else {
- NavigationHelper.playOnPopupPlayer(activity, queue, true);
+ Runnable onAllow = () -> NavigationHelper.playOnPopupPlayer(activity, queue, true);
+ if (shouldAskBeforeClearingQueue()) showClearingQueueConfirmation(onAllow);
+ else onAllow.run();
}
}
@@ -1073,7 +1093,9 @@ private void openVideoPlayer() {
VideoStream selectedVideoStream = getSelectedVideoStream();
startOnExternalPlayer(activity, currentInfo, selectedVideoStream);
} else {
- openNormalPlayer();
+ Runnable onAllow = this::openNormalPlayer;
+ if (shouldAskBeforeClearingQueue()) showClearingQueueConfirmation(onAllow);
+ else onAllow.run();
}
}
@@ -1085,7 +1107,9 @@ private void openNormalBackgroundPlayer(final boolean append) {
if (append) {
NavigationHelper.enqueueOnBackgroundPlayer(activity, queue, false);
} else {
- NavigationHelper.playOnBackgroundPlayer(activity, queue, true);
+ Runnable onAllow = () -> NavigationHelper.playOnBackgroundPlayer(activity, queue, true);
+ if (shouldAskBeforeClearingQueue()) showClearingQueueConfirmation(onAllow);
+ else onAllow.run();
}
}
@@ -1579,7 +1603,7 @@ private void updateProgressInfo(@NonNull final StreamInfo info) {
&& prefs.getBoolean(activity.getString(R.string.enable_playback_resume_key), true);
final boolean showPlaybackPosition = prefs.getBoolean(
activity.getString(R.string.enable_playback_state_lists_key), true);
- if (!playbackResumeEnabled || info.getDuration() <= 0) {
+ if (!playbackResumeEnabled) {
if (playQueue == null || playQueue.getStreams().isEmpty()
|| playQueue.getItem().getRecoveryPosition() == RECOVERY_UNSET || !showPlaybackPosition) {
positionView.setVisibility(View.INVISIBLE);
@@ -1605,7 +1629,8 @@ private void updateProgressInfo(@NonNull final StreamInfo info) {
}, e -> {
if (DEBUG) e.printStackTrace();
}, () -> {
- // OnComplete, do nothing
+ animateView(positionView, false, 0);
+ animateView(detailPositionView, false, 0);
});
}
@@ -1615,6 +1640,10 @@ private void showPlaybackProgress(long progress, long duration) {
positionView.setMax(durationSeconds);
positionView.setProgress(progressSeconds);
detailPositionView.setText(Localization.getDurationString(progressSeconds));
+ if (positionView.getVisibility() != View.VISIBLE) {
+ animateView(positionView, true, 100);
+ animateView(detailPositionView, true, 100);
+ }
}
/*//////////////////////////////////////////////////////////////////////////
@@ -1628,11 +1657,11 @@ public void onQueueUpdate(PlayQueue queue) {
// information about deleted/added items inside Channel/Playlist queue and makes possible to have a history of played items
if (stack.isEmpty() || !stack.peek().getPlayQueue().equals(queue)) {
stack.push(new StackItem(serviceId, url, name, playQueue));
- } else if (stack.peek().getPlayQueue().equals(queue)) {
+ } else if (findQueueInStack(queue) != null) {
// On every MainPlayer service's destroy() playQueue gets disposed and no longer able to track progress.
// That's why we update our cached disposed queue with the new one that is active and have the same history
// Without that the cached playQueue will have an old recovery position
- stack.peek().setPlayQueue(queue);
+ findQueueInStack(queue).setPlayQueue(queue);
}
if (DEBUG) {
@@ -1671,20 +1700,23 @@ public void onProgressUpdate(int currentProgress, int duration, int bufferPercen
}
@Override
- public void onMetadataUpdate(StreamInfo info) {
- if (!stack.isEmpty()) {
+ public void onMetadataUpdate(StreamInfo info, PlayQueue queue) {
+ StackItem item = findQueueInStack(queue);
+ if (item != null) {
// When PlayQueue can have multiple streams (PlaylistPlayQueue or ChannelPlayQueue) every new played stream gives
// new title and url. StackItem contains information about first played stream. Let's update it here
- StackItem peek = stack.peek();
- peek.setTitle(info.getName());
- peek.setUrl(info.getUrl());
+ item.setTitle(info.getName());
+ item.setUrl(info.getUrl());
}
+ // They are not equal when user watches something in popup while browsing in fragment and then changes screen orientation
+ // In that case the fragment will set itself as a service listener and will receive initial call to onMetadataUpdate()
+ if (!queue.equals(playQueue)) return;
updateOverlayData(info.getName(), info.getUploaderName(), info.getThumbnailUrl());
if (currentInfo != null && info.getUrl().equals(currentInfo.getUrl())) return;
currentInfo = info;
- setInitialData(info.getServiceId(), info.getUrl(),info.getName(), playQueue);
+ setInitialData(info.getServiceId(), info.getUrl(),info.getName(), queue);
setAutoplay(false);
prepareAndHandleInfo(info, true);
}
@@ -1852,6 +1884,37 @@ private boolean wasCleared() {
return url == null;
}
+ private StackItem findQueueInStack(PlayQueue queue) {
+ StackItem item = null;
+ Iterator iterator = stack.descendingIterator();
+ while (iterator.hasNext()) {
+ StackItem next = iterator.next();
+ if (next.getPlayQueue().equals(queue)) {
+ item = next;
+ break;
+ }
+ }
+ return item;
+ }
+
+ private boolean shouldAskBeforeClearingQueue() {
+ PlayQueue activeQueue = player != null ? player.getPlayQueue() : null;
+ // Player will have STATE_IDLE when a user pressed back button
+ return isClearingQueueConfirmationRequired(activity) && playerIsNotStopped()
+ && activeQueue != null && !activeQueue.equals(playQueue) && activeQueue.getStreams().size() > 1;
+ }
+
+ private void showClearingQueueConfirmation(Runnable onAllow) {
+ new AlertDialog.Builder(activity)
+ .setTitle(R.string.confirm_prompt)
+ .setMessage(R.string.clear_queue_confirmation_description)
+ .setNegativeButton(android.R.string.cancel, null)
+ .setPositiveButton(android.R.string.yes, (dialog, which) -> {
+ onAllow.run();
+ dialog.dismiss();
+ }).show();
+ }
+
/*
* Remove unneeded information while waiting for a next task
* */
@@ -1905,6 +1968,7 @@ private void setupBottomPlayer() {
&& player != null
&& player.isPlaying()
&& !player.isInFullscreen()
+ && !PlayerHelper.isTablet(activity)
&& player.videoPlayerSelected();
if (needToExpand) player.toggleFullscreen();
break;
diff --git a/app/src/main/java/org/schabi/newpipe/player/BackgroundPlayer.java b/app/src/main/java/org/schabi/newpipe/player/BackgroundPlayer.java
index ab07ded2273..e408f49f623 100644
--- a/app/src/main/java/org/schabi/newpipe/player/BackgroundPlayer.java
+++ b/app/src/main/java/org/schabi/newpipe/player/BackgroundPlayer.java
@@ -451,7 +451,7 @@ public void onPlaybackShutdown() {
private void updateMetadata() {
if (activityListener != null && getCurrentMetadata() != null) {
- activityListener.onMetadataUpdate(getCurrentMetadata().getMetadata());
+ activityListener.onMetadataUpdate(getCurrentMetadata().getMetadata(), playQueue);
}
}
diff --git a/app/src/main/java/org/schabi/newpipe/player/BasePlayer.java b/app/src/main/java/org/schabi/newpipe/player/BasePlayer.java
index 815cbb8ab73..490419c6466 100644
--- a/app/src/main/java/org/schabi/newpipe/player/BasePlayer.java
+++ b/app/src/main/java/org/schabi/newpipe/player/BasePlayer.java
@@ -1236,6 +1236,10 @@ public boolean isPlaying() {
return simpleExoPlayer != null && simpleExoPlayer.isPlaying();
}
+ public boolean isLoading() {
+ return simpleExoPlayer != null && simpleExoPlayer.isLoading();
+ }
+
@Player.RepeatMode
public int getRepeatMode() {
return simpleExoPlayer == null
diff --git a/app/src/main/java/org/schabi/newpipe/player/PopupVideoPlayer.java b/app/src/main/java/org/schabi/newpipe/player/PopupVideoPlayer.java
index 0a15e7169eb..22681d9ceea 100644
--- a/app/src/main/java/org/schabi/newpipe/player/PopupVideoPlayer.java
+++ b/app/src/main/java/org/schabi/newpipe/player/PopupVideoPlayer.java
@@ -673,7 +673,7 @@ public void onLoadingCancelled(String imageUri, View view) {
private void updateMetadata() {
if (activityListener != null && getCurrentMetadata() != null) {
- activityListener.onMetadataUpdate(getCurrentMetadata().getMetadata());
+ activityListener.onMetadataUpdate(getCurrentMetadata().getMetadata(), playQueue);
}
}
diff --git a/app/src/main/java/org/schabi/newpipe/player/ServicePlayerActivity.java b/app/src/main/java/org/schabi/newpipe/player/ServicePlayerActivity.java
index 1c449c77ea2..619200727d2 100644
--- a/app/src/main/java/org/schabi/newpipe/player/ServicePlayerActivity.java
+++ b/app/src/main/java/org/schabi/newpipe/player/ServicePlayerActivity.java
@@ -596,7 +596,7 @@ public void onProgressUpdate(int currentProgress, int duration, int bufferPercen
}
@Override
- public void onMetadataUpdate(StreamInfo info) {
+ public void onMetadataUpdate(StreamInfo info, PlayQueue queue) {
if (info != null) {
metadataTitle.setText(info.getName());
metadataArtist.setText(info.getUploaderName());
diff --git a/app/src/main/java/org/schabi/newpipe/player/VideoPlayerImpl.java b/app/src/main/java/org/schabi/newpipe/player/VideoPlayerImpl.java
index d026ff8cf29..efbe0645714 100644
--- a/app/src/main/java/org/schabi/newpipe/player/VideoPlayerImpl.java
+++ b/app/src/main/java/org/schabi/newpipe/player/VideoPlayerImpl.java
@@ -761,7 +761,8 @@ private static void showInstallKoreDialog(final Context context) {
private void setupScreenRotationButton() {
boolean orientationLocked = PlayerHelper.globalScreenOrientationLocked(service);
- boolean showButton = (orientationLocked || isVerticalVideo || isTablet(service)) && videoPlayerSelected();
+ boolean tabletInLandscape = isTablet(service) && service.isLandscape();
+ boolean showButton = videoPlayerSelected() && (orientationLocked || isVerticalVideo || tabletInLandscape);
screenRotationButton.setVisibility(showButton ? View.VISIBLE : View.GONE);
screenRotationButton.setImageDrawable(service.getResources().getDrawable(
isInFullscreen() ? R.drawable.ic_fullscreen_exit_white : R.drawable.ic_fullscreen_white));
@@ -1048,10 +1049,10 @@ public void onBroadcastReceived(Intent intent) {
useVideoSource(true);
break;
case VideoDetailFragment.ACTION_VIDEO_FRAGMENT_STOPPED:
- // This will be called when user goes to another app
- // We don't want to interrupt playback and don't want to see notification if player is stopped
- // since next lines of code will enable background playback if needed
- if (videoPlayerSelected() && isPlaying()) {
+ // This will be called when user goes to another app/activity, turns off a screen.
+ // We don't want to interrupt playback and don't want to see notification if player is stopped.
+ // Next lines of code will enable background playback if needed
+ if (videoPlayerSelected() && (isPlaying() || isLoading())) {
if (backgroundPlaybackEnabled()) {
useVideoSource(false);
} else if (minimizeOnPopupEnabled()) {
@@ -1076,14 +1077,15 @@ public void onBroadcastReceived(Intent intent) {
break;
case Intent.ACTION_SCREEN_ON:
shouldUpdateOnProgress = true;
- // Interrupt playback only when screen turns on and user is watching video in fragment
- if (backgroundPlaybackEnabled() && getPlayer() != null && (isPlaying() || getPlayer().isLoading()))
+ // Interrupt playback only when screen turns on and user is watching video in popup player
+ // Same action for video player will be handled in ACTION_VIDEO_FRAGMENT_RESUMED event
+ if (backgroundPlaybackEnabled() && popupPlayerSelected() && (isPlaying() || isLoading()))
useVideoSource(true);
break;
case Intent.ACTION_SCREEN_OFF:
shouldUpdateOnProgress = false;
- // Interrupt playback only when screen turns off with video working
- if (backgroundPlaybackEnabled() && getPlayer() != null && (isPlaying() || getPlayer().isLoading()))
+ // Interrupt playback only when screen turns off with popup player working
+ if (backgroundPlaybackEnabled() && popupPlayerSelected() && (isPlaying() || isLoading()))
useVideoSource(false);
break;
}
@@ -1330,7 +1332,7 @@ public void checkLandscape() {
AppCompatActivity parent = getParentActivity();
boolean videoInLandscapeButNotInFullscreen = service.isLandscape() && !isInFullscreen() && videoPlayerSelected() && !audioOnly;
boolean playingState = getCurrentState() != STATE_COMPLETED && getCurrentState() != STATE_PAUSED;
- if (parent != null && videoInLandscapeButNotInFullscreen && playingState)
+ if (parent != null && videoInLandscapeButNotInFullscreen && playingState && !PlayerHelper.isTablet(service))
toggleFullscreen();
setControlsSize();
@@ -1695,10 +1697,10 @@ private void updateQueue() {
private void updateMetadata() {
if (fragmentListener != null && getCurrentMetadata() != null) {
- fragmentListener.onMetadataUpdate(getCurrentMetadata().getMetadata());
+ fragmentListener.onMetadataUpdate(getCurrentMetadata().getMetadata(), playQueue);
}
if (activityListener != null && getCurrentMetadata() != null) {
- activityListener.onMetadataUpdate(getCurrentMetadata().getMetadata());
+ activityListener.onMetadataUpdate(getCurrentMetadata().getMetadata(), playQueue);
}
}
diff --git a/app/src/main/java/org/schabi/newpipe/player/event/CustomBottomSheetBehavior.java b/app/src/main/java/org/schabi/newpipe/player/event/CustomBottomSheetBehavior.java
index c7acc039079..9d4707666e1 100644
--- a/app/src/main/java/org/schabi/newpipe/player/event/CustomBottomSheetBehavior.java
+++ b/app/src/main/java/org/schabi/newpipe/player/event/CustomBottomSheetBehavior.java
@@ -35,14 +35,17 @@ public boolean onInterceptTouchEvent(@NonNull CoordinatorLayout parent, @NonNull
// Found that user still swiping, continue following
if (skippingInterception) return false;
- // Without overriding scrolling will not work when user touches these elements
- for (Integer element : skipInterceptionOfElements) {
- ViewGroup viewGroup = child.findViewById(element);
- if (viewGroup != null) {
- visible = viewGroup.getGlobalVisibleRect(globalRect);
- if (visible && globalRect.contains((int) event.getRawX(), (int) event.getRawY())) {
- skippingInterception = true;
- return false;
+ // Don't need to do anything if bottomSheet isn't expanded
+ if (getState() == BottomSheetBehavior.STATE_EXPANDED) {
+ // Without overriding scrolling will not work when user touches these elements
+ for (Integer element : skipInterceptionOfElements) {
+ ViewGroup viewGroup = child.findViewById(element);
+ if (viewGroup != null) {
+ visible = viewGroup.getGlobalVisibleRect(globalRect);
+ if (visible && globalRect.contains((int) event.getRawX(), (int) event.getRawY())) {
+ skippingInterception = true;
+ return false;
+ }
}
}
}
diff --git a/app/src/main/java/org/schabi/newpipe/player/event/PlayerEventListener.java b/app/src/main/java/org/schabi/newpipe/player/event/PlayerEventListener.java
index 37ad9798f3a..8741f539f60 100644
--- a/app/src/main/java/org/schabi/newpipe/player/event/PlayerEventListener.java
+++ b/app/src/main/java/org/schabi/newpipe/player/event/PlayerEventListener.java
@@ -10,6 +10,6 @@ public interface PlayerEventListener {
void onQueueUpdate(PlayQueue queue);
void onPlaybackUpdate(int state, int repeatMode, boolean shuffled, PlaybackParameters parameters);
void onProgressUpdate(int currentProgress, int duration, int bufferPercent);
- void onMetadataUpdate(StreamInfo info);
+ void onMetadataUpdate(StreamInfo info, PlayQueue queue);
void onServiceStopped();
}
diff --git a/app/src/main/java/org/schabi/newpipe/player/helper/PlayerHelper.java b/app/src/main/java/org/schabi/newpipe/player/helper/PlayerHelper.java
index ae1cac382d9..6afb5a32279 100644
--- a/app/src/main/java/org/schabi/newpipe/player/helper/PlayerHelper.java
+++ b/app/src/main/java/org/schabi/newpipe/player/helper/PlayerHelper.java
@@ -200,6 +200,10 @@ public static boolean isAutoQueueEnabled(@NonNull final Context context) {
return isAutoQueueEnabled(context, false);
}
+ public static boolean isClearingQueueConfirmationRequired(@NonNull final Context context) {
+ return getPreferences(context).getBoolean(context.getString(R.string.clear_queue_confirmation_key), false);
+ }
+
@MinimizeMode
public static int getMinimizeOnExitAction(@NonNull final Context context) {
final String defaultAction = context.getString(R.string.minimize_on_exit_none_key);
diff --git a/app/src/main/res/values/settings_keys.xml b/app/src/main/res/values/settings_keys.xml
index 40439745081..f2e957a718c 100644
--- a/app/src/main/res/values/settings_keys.xml
+++ b/app/src/main/res/values/settings_keys.xml
@@ -27,6 +27,7 @@
auto_queue_key
screen_brightness_key
screen_brightness_timestamp_key
+ clear_queue_confirmation_key
seek_duration
10000
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 3a575ae25cc..388897ffd24 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -71,6 +71,9 @@
Use fast inexact seek
Inexact seek allows the player to seek to positions faster with reduced precision
Fast-forward/-rewind seek duration
+ Ask confirmation before clearing a queue
+ After switching from one player to another your queue may be replaced
+ Queue from the active player will be replaced
Load thumbnails
Show comments
Disable to stop showing comments
diff --git a/app/src/main/res/xml/video_audio_settings.xml b/app/src/main/res/xml/video_audio_settings.xml
index 447fa90189b..88dc071d0f1 100644
--- a/app/src/main/res/xml/video_audio_settings.xml
+++ b/app/src/main/res/xml/video_audio_settings.xml
@@ -164,5 +164,13 @@
android:key="@string/seek_duration_key"
android:summary="%s"
android:title="@string/seek_duration_title"/>
+
+
+
From c796e2ae3c4d103c01dec6d172a6c6601061f682 Mon Sep 17 00:00:00 2001
From: Ethan Budd
Date: Thu, 18 Jun 2020 22:43:06 -0500
Subject: [PATCH 022/398] Fixes crash when a file is deleted then redownloaded
---
app/src/main/java/us/shandian/giga/io/StoredFileHelper.java | 1 +
1 file changed, 1 insertion(+)
diff --git a/app/src/main/java/us/shandian/giga/io/StoredFileHelper.java b/app/src/main/java/us/shandian/giga/io/StoredFileHelper.java
index ad3ceec3dfc..eba9437e1e5 100644
--- a/app/src/main/java/us/shandian/giga/io/StoredFileHelper.java
+++ b/app/src/main/java/us/shandian/giga/io/StoredFileHelper.java
@@ -315,6 +315,7 @@ public boolean equals(StoredFileHelper storage) {
return false;
if (this.isInvalid() || storage.isInvalid()) {
+ if (this.srcName == null || storage.srcName == null || this.srcType == null || storage.srcType == null) return false;
return this.srcName.equalsIgnoreCase(storage.srcName) && this.srcType.equalsIgnoreCase(storage.srcType);
}
From a7fbe05a735b2019e938f1ca60e1196881ea35a4 Mon Sep 17 00:00:00 2001
From: Avently <7953703+avently@users.noreply.github.com>
Date: Sat, 27 Jun 2020 06:25:50 +0300
Subject: [PATCH 023/398] Changes for review
---
app/src/main/AndroidManifest.xml | 3 -
.../java/org/schabi/newpipe/MainActivity.java | 9 +-
.../org/schabi/newpipe/RouterActivity.java | 9 +-
.../fragments/detail/VideoDetailFragment.java | 278 +++++-------------
.../fragments/list/search/SearchFragment.java | 6 +-
.../newpipe/player/BackgroundPlayer.java | 2 +-
.../org/schabi/newpipe/player/BasePlayer.java | 33 ++-
.../org/schabi/newpipe/player/MainPlayer.java | 4 +-
.../schabi/newpipe/player/VideoPlayer.java | 10 +-
.../newpipe/player/VideoPlayerImpl.java | 72 ++---
.../player/event/PlayerGestureListener.java | 28 +-
.../newpipe/player/helper/AudioReactor.java | 2 +-
.../newpipe/player/helper/PlayerHelper.java | 18 +-
.../newpipe/streams/OggFromWebMWriter.java | 6 +-
.../newpipe/streams/SubtitleConverter.java | 2 +-
.../schabi/newpipe/streams/WebMWriter.java | 2 +-
.../schabi/newpipe/util/NavigationHelper.java | 23 +-
.../newpipe/views/ExpandableSurfaceView.java | 4 +-
.../giga/postprocessing/Postprocessing.java | 2 +-
.../giga/ui/adapter/MissionAdapter.java | 6 +-
.../giga/ui/common/ProgressDrawable.java | 4 +-
app/src/main/res/layout/toolbar_layout.xml | 9 -
22 files changed, 182 insertions(+), 350 deletions(-)
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 18e42452442..3136774e1c2 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -38,9 +38,6 @@
-
getResultHandler(Choice choice) {
}
private void openMainPlayer(PlayQueue playQueue, Choice choice) {
- Intent intent = NavigationHelper.getPlayerIntent(this, MainActivity.class, playQueue, true);
- intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- intent.putExtra(Constants.KEY_LINK_TYPE, choice.linkType);
- intent.putExtra(Constants.KEY_URL, choice.url);
- intent.putExtra(Constants.KEY_TITLE, "");
- intent.putExtra(VideoDetailFragment.AUTO_PLAY, true);
- this.startActivity(intent);
+ NavigationHelper.playOnMainPlayer(this, playQueue, choice.linkType,
+ choice.url, "", true, true);
}
@Override
diff --git a/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java
index 0b7ffddef63..9d6d20c0dd0 100644
--- a/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java
+++ b/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java
@@ -5,7 +5,6 @@
import android.content.*;
import android.content.pm.ActivityInfo;
import android.database.ContentObserver;
-import android.media.AudioManager;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
@@ -102,11 +101,8 @@ public class VideoDetailFragment
PlayerServiceEventListener {
public static final String AUTO_PLAY = "auto_play";
- private int updateFlags = 0;
private static final int RELATED_STREAMS_UPDATE_FLAG = 0x1;
- private static final int RESOLUTIONS_MENU_UPDATE_FLAG = 0x2;
- private static final int TOOLBAR_ITEMS_UPDATE_FLAG = 0x4;
- private static final int COMMENTS_UPDATE_FLAG = 0x8;
+ private static final int COMMENTS_UPDATE_FLAG = 0x2;
private static final float MAX_OVERLAY_ALPHA = 0.9f;
private static final float MAX_PLAYER_HEIGHT = 0.7f;
@@ -115,10 +111,16 @@ public class VideoDetailFragment
public static final String ACTION_VIDEO_FRAGMENT_RESUMED = "org.schabi.newpipe.VideoDetailFragment.ACTION_VIDEO_FRAGMENT_RESUMED";
public static final String ACTION_VIDEO_FRAGMENT_STOPPED = "org.schabi.newpipe.VideoDetailFragment.ACTION_VIDEO_FRAGMENT_STOPPED";
+ private static final String COMMENTS_TAB_TAG = "COMMENTS";
+ private static final String RELATED_TAB_TAG = "NEXT VIDEO";
+ private static final String EMPTY_TAB_TAG = "EMPTY TAB";
+
private boolean showRelatedStreams;
private boolean showComments;
private String selectedTabTag;
+ private int updateFlags = 0;
+
@State
protected int serviceId = Constants.NO_SERVICE_ID;
@State
@@ -148,10 +150,6 @@ public class VideoDetailFragment
// Views
//////////////////////////////////////////////////////////////////////////*/
- private Menu menu;
-
- private Spinner spinnerToolbar;
-
private LinearLayout contentRootLayoutHiding;
private View thumbnailBackgroundButton;
@@ -195,10 +193,6 @@ public class VideoDetailFragment
private ImageButton overlayPlayPauseButton;
private ImageButton overlayCloseButton;
- private static final String COMMENTS_TAB_TAG = "COMMENTS";
- private static final String RELATED_TAB_TAG = "NEXT VIDEO";
- private static final String EMPTY_TAB_TAG = "EMPTY TAB";
-
private AppBarLayout appBarLayout;
private ViewPager viewPager;
private TabAdaptor pageAdapter;
@@ -207,7 +201,7 @@ public class VideoDetailFragment
private ContentObserver settingsContentObserver;
private ServiceConnection serviceConnection;
- private boolean bounded;
+ private boolean bound;
private MainPlayer playerService;
private VideoPlayerImpl player;
@@ -242,12 +236,18 @@ public void onServiceConnected(ComponentName compName, IBinder service) {
if (playerIsNotStopped() && player.videoPlayerSelected()) addVideoPlayerView();
- // If the video is playing but orientation changed let's make the video in fullscreen again
- if (isLandscape()) checkLandscape();
- else if (player.isInFullscreen()) player.toggleFullscreen();
+ if (isLandscape()) {
+ // If the video is playing but orientation changed let's make the video in fullscreen again
+ checkLandscape();
+ } else if (player.isFullscreen()) {
+ // Device is in portrait orientation after rotation but UI is in fullscreen.
+ // Return back to non-fullscreen state
+ player.toggleFullscreen();
+ }
- if (currentInfo != null && isAutoplayEnabled() && player.getParentActivity() == null || playAfterConnect)
+ if (playAfterConnect || (currentInfo != null && isAutoplayEnabled() && player.getParentActivity() == null)) {
openVideoPlayer();
+ }
}
};
}
@@ -259,15 +259,15 @@ private void bind() {
final boolean success = getContext().bindService(serviceIntent, serviceConnection, Context.BIND_AUTO_CREATE);
if (!success) getContext().unbindService(serviceConnection);
- bounded = success;
+ bound = success;
}
private void unbind() {
if (DEBUG) Log.d(TAG, "unbind() called");
- if (bounded) {
+ if (bound) {
getContext().unbindService(serviceConnection);
- bounded = false;
+ bound = false;
stopPlayerListener();
playerService = null;
player = null;
@@ -313,9 +313,6 @@ public static VideoDetailFragment getInstance(int serviceId, String videoUrl, St
public void
onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- setHasOptionsMenu(true);
-
- activity.setVolumeControlStream(AudioManager.STREAM_MUSIC);
showRelatedStreams = PreferenceManager.getDefaultSharedPreferences(activity)
.getBoolean(getString(R.string.show_next_video_key), true);
@@ -371,15 +368,9 @@ public void onResume() {
if (updateFlags != 0) {
if (!isLoading.get() && currentInfo != null) {
if ((updateFlags & RELATED_STREAMS_UPDATE_FLAG) != 0) startLoading(false);
- if ((updateFlags & RESOLUTIONS_MENU_UPDATE_FLAG) != 0) setupActionBar(currentInfo);
if ((updateFlags & COMMENTS_UPDATE_FLAG) != 0) startLoading(false);
}
- if ((updateFlags & TOOLBAR_ITEMS_UPDATE_FLAG) != 0
- && menu != null) {
- updateMenuItemVisibility();
- }
-
updateFlags = 0;
}
@@ -418,14 +409,6 @@ public void onDestroy() {
bottomSheetBehavior.setBottomSheetCallback(null);
}
- @Override
- public void onDestroyView() {
- if (DEBUG) Log.d(TAG, "onDestroyView() called");
- spinnerToolbar.setOnItemSelectedListener(null);
- spinnerToolbar.setAdapter(null);
- super.onDestroyView();
- }
-
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
@@ -446,13 +429,6 @@ public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, Strin
if (key.equals(getString(R.string.show_next_video_key))) {
showRelatedStreams = sharedPreferences.getBoolean(key, true);
updateFlags |= RELATED_STREAMS_UPDATE_FLAG;
- } else if (key.equals(getString(R.string.default_video_format_key))
- || key.equals(getString(R.string.default_resolution_key))
- || key.equals(getString(R.string.show_higher_resolutions_key))
- || key.equals(getString(R.string.use_external_video_player_key))) {
- updateFlags |= RESOLUTIONS_MENU_UPDATE_FLAG;
- } else if (key.equals(getString(R.string.show_play_with_kodi_key))) {
- updateFlags |= TOOLBAR_ITEMS_UPDATE_FLAG;
} else if (key.equals(getString(R.string.show_comments_key))) {
showComments = sharedPreferences.getBoolean(key, true);
updateFlags |= COMMENTS_UPDATE_FLAG;
@@ -600,8 +576,6 @@ private void toggleTitleAndDescription() {
@Override
protected void initViews(View rootView, Bundle savedInstanceState) {
super.initViews(rootView, savedInstanceState);
- spinnerToolbar = activity.findViewById(R.id.toolbar).findViewById(R.id.toolbar_spinner);
-
thumbnailBackgroundButton = rootView.findViewById(R.id.detail_thumbnail_root_layout);
thumbnailImageView = rootView.findViewById(R.id.detail_thumbnail_image_view);
thumbnailPlayButton = rootView.findViewById(R.id.detail_thumbnail_play_button);
@@ -730,116 +704,6 @@ public void onLoadingFailed(String imageUri, View view, FailReason failReason) {
}
}
-
- /*//////////////////////////////////////////////////////////////////////////
- // Menu
- //////////////////////////////////////////////////////////////////////////*/
-
- @Override
- public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
- this.menu = menu;
-
- // CAUTION set item properties programmatically otherwise it would not be accepted by
- // appcompat itemsinflater.inflate(R.menu.videoitem_detail, menu);
-
- /*inflater.inflate(R.menu.video_detail_menu, menu);
-
- updateMenuItemVisibility();
-
- ActionBar supportActionBar = activity.getSupportActionBar();
- if (supportActionBar != null) {
- supportActionBar.setDisplayHomeAsUpEnabled(true);
- supportActionBar.setDisplayShowTitleEnabled(false);
- }*/
- }
-
- private void updateMenuItemVisibility() {
- /*// show kodi if set in settings
- menu.findItem(R.id.action_play_with_kodi).setVisible(
- PreferenceManager.getDefaultSharedPreferences(activity).getBoolean(
- activity.getString(R.string.show_play_with_kodi_key), false));*/
- }
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- if (isLoading.get()) {
- // if is still loading block menu
- return true;
- }
-
- int id = item.getItemId();
- switch (id) {
- case R.id.menu_item_share: {
- if (currentInfo != null) {
- ShareUtils.shareUrl(this.getContext(), currentInfo.getName(), currentInfo.getOriginalUrl());
- }
- return true;
- }
- case R.id.menu_item_openInBrowser: {
- if (currentInfo != null) {
- ShareUtils.openUrlInBrowser(this.getContext(), currentInfo.getOriginalUrl());
- }
- return true;
- }
- case R.id.action_play_with_kodi:
- /*try {
- NavigationHelper.playWithKore(activity, Uri.parse(
- url.replace("https", "http")));
- } catch (Exception e) {
- if (DEBUG) Log.i(TAG, "Failed to start kore", e);
- showInstallKoreDialog(activity);
- }*/
- return true;
- default:
- return super.onOptionsItemSelected(item);
- }
- }
-
- /*private static void showInstallKoreDialog(final Context context) {
- final AlertDialog.Builder builder = new AlertDialog.Builder(context);
- builder.setMessage(R.string.kore_not_found)
- .setPositiveButton(R.string.install, (DialogInterface dialog, int which) ->
- NavigationHelper.installKore(context))
- .setNegativeButton(R.string.cancel, (DialogInterface dialog, int which) -> {
- });
- builder.create().show();
- }
-
- private void setupActionBarOnError(final String url) {
- if (DEBUG) Log.d(TAG, "setupActionBarHandlerOnError() called with: url = [" + url + "]");
- Log.e("-----", "missing code");
- }*/
-
- private void setupActionBar(final StreamInfo info) {
- if (DEBUG) Log.d(TAG, "setupActionBarHandler() called with: info = [" + info + "]");
- boolean isExternalPlayerEnabled = PreferenceManager.getDefaultSharedPreferences(activity)
- .getBoolean(activity.getString(R.string.use_external_video_player_key), false);
-
- sortedVideoStreams = ListHelper.getSortedStreamVideosList(
- activity,
- info.getVideoStreams(),
- info.getVideoOnlyStreams(),
- false);
- selectedVideoStreamIndex = ListHelper.getDefaultResolutionIndex(activity, sortedVideoStreams);
-
- /*final StreamItemAdapter streamsAdapter =
- new StreamItemAdapter<>(activity,
- new StreamSizeWrapper<>(sortedVideoStreams, activity), isExternalPlayerEnabled);
-
- spinnerToolbar.setAdapter(streamsAdapter);
- spinnerToolbar.setSelection(selectedVideoStreamIndex);
- spinnerToolbar.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
- @Override
- public void onItemSelected(AdapterView> parent, View view, int position, long id) {
- selectedVideoStreamIndex = position;
- }
-
- @Override
- public void onNothingSelected(AdapterView> parent) {
- }
- });*/
- }
-
/*//////////////////////////////////////////////////////////////////////////
// OwnStack
//////////////////////////////////////////////////////////////////////////*/
@@ -866,7 +730,7 @@ public boolean onBackPressed() {
if (DEBUG) Log.d(TAG, "onBackPressed() called");
// If we are in fullscreen mode just exit from it via first back press
- if (player != null && player.isInFullscreen()) {
+ if (player != null && player.isFullscreen()) {
if (!PlayerHelper.isTablet(activity)) player.onPause();
restoreDefaultOrientation();
setAutoplay(false);
@@ -874,11 +738,10 @@ public boolean onBackPressed() {
}
// If we have something in history of played items we replay it here
- boolean isPreviousCanBePlayed = player != null
+ if (player != null
&& player.getPlayQueue() != null
&& player.videoPlayerSelected()
- && player.getPlayQueue().previous();
- if (isPreviousCanBePlayed) {
+ && player.getPlayQueue().previous()) {
return true;
}
// That means that we are on the start of the stack,
@@ -930,9 +793,8 @@ protected void doInitialLoadLogic() {
}
public void selectAndLoadVideo(int serviceId, String videoUrl, String name, PlayQueue playQueue) {
- boolean streamIsTheSame = this.playQueue != null && this.playQueue.equals(playQueue);
// Situation when user switches from players to main player. All needed data is here, we can start watching
- if (streamIsTheSame) {
+ if (this.playQueue != null && this.playQueue.equals(playQueue)) {
openVideoPlayer();
return;
}
@@ -1056,7 +918,7 @@ private void openBackgroundPlayer(final boolean append) {
.getBoolean(activity.getString(R.string.use_external_audio_player_key), false);
// If a user watched video inside fullscreen mode and than chose another player return to non-fullscreen mode
- if (player != null && player.isInFullscreen()) player.toggleFullscreen();
+ if (player != null && player.isFullscreen()) player.toggleFullscreen();
if (!useExternalAudioPlayer && android.os.Build.VERSION.SDK_INT >= 16) {
openNormalBackgroundPlayer(append);
@@ -1072,18 +934,16 @@ private void openPopupPlayer(final boolean append) {
}
// See UI changes while remote playQueue changes
- if (!bounded) startService(false);
+ if (!bound) startService(false);
// If a user watched video inside fullscreen mode and than chose another player return to non-fullscreen mode
- if (player != null && player.isInFullscreen()) player.toggleFullscreen();
+ if (player != null && player.isFullscreen()) player.toggleFullscreen();
PlayQueue queue = setupPlayQueueForIntent(append);
if (append) {
NavigationHelper.enqueueOnPopupPlayer(activity, queue, false);
} else {
- Runnable onAllow = () -> NavigationHelper.playOnPopupPlayer(activity, queue, true);
- if (shouldAskBeforeClearingQueue()) showClearingQueueConfirmation(onAllow);
- else onAllow.run();
+ replaceQueueIfUserConfirms(() -> NavigationHelper.playOnPopupPlayer(activity, queue, true));
}
}
@@ -1093,27 +953,23 @@ private void openVideoPlayer() {
VideoStream selectedVideoStream = getSelectedVideoStream();
startOnExternalPlayer(activity, currentInfo, selectedVideoStream);
} else {
- Runnable onAllow = this::openNormalPlayer;
- if (shouldAskBeforeClearingQueue()) showClearingQueueConfirmation(onAllow);
- else onAllow.run();
+ replaceQueueIfUserConfirms(this::openMainPlayer);
}
}
private void openNormalBackgroundPlayer(final boolean append) {
// See UI changes while remote playQueue changes
- if (!bounded) startService(false);
+ if (!bound) startService(false);
PlayQueue queue = setupPlayQueueForIntent(append);
if (append) {
NavigationHelper.enqueueOnBackgroundPlayer(activity, queue, false);
} else {
- Runnable onAllow = () -> NavigationHelper.playOnBackgroundPlayer(activity, queue, true);
- if (shouldAskBeforeClearingQueue()) showClearingQueueConfirmation(onAllow);
- else onAllow.run();
+ replaceQueueIfUserConfirms(() -> NavigationHelper.playOnBackgroundPlayer(activity, queue, true));
}
}
- private void openNormalPlayer() {
+ private void openMainPlayer() {
if (playerService == null) {
startService(true);
return;
@@ -1144,7 +1000,7 @@ private PlayQueue setupPlayQueueForIntent(boolean append) {
PlayQueue queue = playQueue;
// Size can be 0 because queue removes bad stream automatically when error occurs
- if (playQueue == null || playQueue.size() == 0)
+ if (queue == null || queue.size() == 0)
queue = new SinglePlayQueue(currentInfo);
return queue;
@@ -1284,18 +1140,18 @@ private void setHeightThumbnail() {
boolean isPortrait = metrics.heightPixels > metrics.widthPixels;
int height;
- if (player != null && player.isInFullscreen())
+ if (player != null && player.isFullscreen())
height = isInMultiWindow() ? getView().getHeight() : activity.getWindow().getDecorView().getHeight();
else
height = isPortrait
? (int) (metrics.widthPixels / (16.0f / 9.0f))
- : (int) (metrics.heightPixels / 2f);
+ : (int) (metrics.heightPixels / 2.0f);
thumbnailImageView.setLayoutParams(new FrameLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, height));
thumbnailImageView.setMinimumHeight(height);
if (player != null) {
int maxHeight = (int) (metrics.heightPixels * MAX_PLAYER_HEIGHT);
- player.getSurfaceView().setHeights(height, player.isInFullscreen() ? height : maxHeight);
+ player.getSurfaceView().setHeights(height, player.isFullscreen() ? height : maxHeight);
}
}
@@ -1353,7 +1209,7 @@ public void onReceive(Context context, Intent intent) {
private void restoreDefaultOrientation() {
if (player == null || !player.videoPlayerSelected() || activity == null) return;
- if (player != null && player.isInFullscreen()) player.toggleFullscreen();
+ if (player != null && player.isFullscreen()) player.toggleFullscreen();
// This will show systemUI and pause the player.
// User can tap on Play button and video will be in fullscreen mode again
// Note for tablet: trying to avoid orientation changes since it's not easy to physically rotate the tablet every time
@@ -1375,7 +1231,6 @@ public void showLoading() {
contentRootLayoutHiding.setVisibility(View.INVISIBLE);
}
- //animateView(spinnerToolbar, false, 200);
animateView(thumbnailPlayButton, false, 50);
animateView(detailDurationView, false, 100);
animateView(detailPositionView, false, 100);
@@ -1392,7 +1247,7 @@ public void showLoading() {
if(relatedStreamsLayout != null){
if(showRelatedStreams){
- relatedStreamsLayout.setVisibility(player != null && player.isInFullscreen() ? View.GONE : View.INVISIBLE);
+ relatedStreamsLayout.setVisibility(player != null && player.isFullscreen() ? View.GONE : View.INVISIBLE);
}else{
relatedStreamsLayout.setVisibility(View.GONE);
}
@@ -1419,7 +1274,7 @@ public void handleResult(@NonNull StreamInfo info) {
getChildFragmentManager().beginTransaction()
.replace(R.id.relatedStreamsLayout, RelatedVideosFragment.getInstance(info))
.commitNow();
- relatedStreamsLayout.setVisibility(player != null && player.isInFullscreen() ? View.GONE : View.VISIBLE);
+ relatedStreamsLayout.setVisibility(player != null && player.isFullscreen() ? View.GONE : View.VISIBLE);
}
}
@@ -1506,9 +1361,6 @@ public void handleResult(@NonNull StreamInfo info) {
prepareDescription(info.getDescription());
updateProgressInfo(info);
-
- //animateView(spinnerToolbar, true, 500);
- setupActionBar(info);
initThumbnailViews(info);
if (player == null || player.isPlayerStopped())
@@ -1527,7 +1379,6 @@ public void handleResult(@NonNull StreamInfo info) {
case LIVE_STREAM:
case AUDIO_LIVE_STREAM:
detailControlsDownload.setVisibility(View.GONE);
- spinnerToolbar.setVisibility(View.GONE);
break;
default:
if(info.getAudioStreams().isEmpty()) detailControlsBackground.setVisibility(View.GONE);
@@ -1535,7 +1386,6 @@ public void handleResult(@NonNull StreamInfo info) {
|| !info.getVideoOnlyStreams().isEmpty()) break;
detailControlsPopup.setVisibility(View.GONE);
- spinnerToolbar.setVisibility(View.GONE);
thumbnailPlayButton.setImageResource(R.drawable.ic_headset_white_24dp);
break;
}
@@ -1629,8 +1479,8 @@ private void updateProgressInfo(@NonNull final StreamInfo info) {
}, e -> {
if (DEBUG) e.printStackTrace();
}, () -> {
- animateView(positionView, false, 0);
- animateView(detailPositionView, false, 0);
+ positionView.setVisibility(View.GONE);
+ detailPositionView.setVisibility(View.GONE);
});
}
@@ -1653,15 +1503,16 @@ private void showPlaybackProgress(long progress, long duration) {
@Override
public void onQueueUpdate(PlayQueue queue) {
playQueue = queue;
+ StackItem stackWithQueue;
// This should be the only place where we push data to stack. It will allow to have live instance of PlayQueue with actual
// information about deleted/added items inside Channel/Playlist queue and makes possible to have a history of played items
if (stack.isEmpty() || !stack.peek().getPlayQueue().equals(queue)) {
stack.push(new StackItem(serviceId, url, name, playQueue));
- } else if (findQueueInStack(queue) != null) {
+ } else if ((stackWithQueue = findQueueInStack(queue)) != null) {
// On every MainPlayer service's destroy() playQueue gets disposed and no longer able to track progress.
// That's why we update our cached disposed queue with the new one that is active and have the same history
// Without that the cached playQueue will have an old recovery position
- findQueueInStack(queue).setPlayQueue(queue);
+ stackWithQueue.setPlayQueue(queue);
}
if (DEBUG) {
@@ -1679,7 +1530,7 @@ public void onPlaybackUpdate(int state, int repeatMode, boolean shuffled, Playba
restoreDefaultOrientation();
break;
case BasePlayer.STATE_PLAYING:
- if (positionView.getAlpha() != 1f
+ if (positionView.getAlpha() != 1.0f
&& player.getPlayQueue() != null
&& player.getPlayQueue().getItem() != null
&& player.getPlayQueue().getItem().getUrl().equals(url)) {
@@ -1725,7 +1576,7 @@ public void onMetadataUpdate(StreamInfo info, PlayQueue queue) {
public void onPlayerError(ExoPlaybackException error) {
if (error.type == ExoPlaybackException.TYPE_SOURCE || error.type == ExoPlaybackException.TYPE_UNEXPECTED) {
hideMainPlayer();
- if (playerService != null && player.isInFullscreen())
+ if (playerService != null && player.isFullscreen())
player.toggleFullscreen();
}
}
@@ -1824,7 +1675,7 @@ private void hideSystemUi() {
// Listener implementation
public void hideSystemUiIfNeeded() {
- if (player != null && player.isInFullscreen() && bottomSheetBehavior.getState() == BottomSheetBehavior.STATE_EXPANDED)
+ if (player != null && player.isFullscreen() && bottomSheetBehavior.getState() == BottomSheetBehavior.STATE_EXPANDED)
hideSystemUi();
}
@@ -1897,11 +1748,19 @@ private StackItem findQueueInStack(PlayQueue queue) {
return item;
}
- private boolean shouldAskBeforeClearingQueue() {
- PlayQueue activeQueue = player != null ? player.getPlayQueue() : null;
+ private void replaceQueueIfUserConfirms(final Runnable onAllow) {
+ @Nullable final PlayQueue activeQueue = player == null ? null : player.getPlayQueue();
+
// Player will have STATE_IDLE when a user pressed back button
- return isClearingQueueConfirmationRequired(activity) && playerIsNotStopped()
- && activeQueue != null && !activeQueue.equals(playQueue) && activeQueue.getStreams().size() > 1;
+ if (isClearingQueueConfirmationRequired(activity)
+ && playerIsNotStopped()
+ && activeQueue != null
+ && !activeQueue.equals(playQueue)
+ && activeQueue.getStreams().size() > 1) {
+ showClearingQueueConfirmation(onAllow);
+ } else {
+ onAllow.run();
+ }
}
private void showClearingQueueConfirmation(Runnable onAllow) {
@@ -1964,13 +1823,13 @@ private void setupBottomPlayer() {
// Disable click because overlay buttons located on top of buttons from the player
setOverlayElementsClickable(false);
hideSystemUiIfNeeded();
- boolean needToExpand = isLandscape()
+ // Conditions when the player should be expanded to fullscreen
+ if (isLandscape()
&& player != null
&& player.isPlaying()
- && !player.isInFullscreen()
+ && !player.isFullscreen()
&& !PlayerHelper.isTablet(activity)
- && player.videoPlayerSelected();
- if (needToExpand) player.toggleFullscreen();
+ && player.videoPlayerSelected()) player.toggleFullscreen();
break;
case BottomSheetBehavior.STATE_COLLAPSED:
// Re-enable clicks
@@ -1979,7 +1838,7 @@ private void setupBottomPlayer() {
break;
case BottomSheetBehavior.STATE_DRAGGING:
case BottomSheetBehavior.STATE_SETTLING:
- if (player != null && player.isInFullscreen()) showSystemUi();
+ if (player != null && player.isFullscreen()) showSystemUi();
if (player != null && player.isControlsVisible()) player.hideControls(0, 0);
break;
}
@@ -1997,8 +1856,8 @@ private void setupBottomPlayer() {
}
private void updateOverlayData(@Nullable String title, @Nullable String uploader, @Nullable String thumbnailUrl) {
- overlayTitleTextView.setText(!TextUtils.isEmpty(title) ? title : "");
- overlayChannelTextView.setText(!TextUtils.isEmpty(uploader) ? uploader : "");
+ overlayTitleTextView.setText(TextUtils.isEmpty(title) ? "" : title);
+ overlayChannelTextView.setText(TextUtils.isEmpty(uploader) ? "" : uploader);
overlayThumbnailImageView.setImageResource(R.drawable.dummy_thumbnail_dark);
if (!TextUtils.isEmpty(thumbnailUrl))
imageLoader.displayImage(thumbnailUrl, overlayThumbnailImageView,
@@ -2006,8 +1865,7 @@ private void updateOverlayData(@Nullable String title, @Nullable String uploader
}
private void setOverlayPlayPauseImage() {
- boolean playing = player != null && player.getPlayer().getPlayWhenReady();
- int attr = playing ? R.attr.pause : R.attr.play;
+ int attr = player != null && player.getPlayer().getPlayWhenReady() ? R.attr.pause : R.attr.play;
overlayPlayPauseButton.setImageResource(ThemeHelper.resolveResourceIdFromAttr(activity, attr));
}
diff --git a/app/src/main/java/org/schabi/newpipe/fragments/list/search/SearchFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/list/search/SearchFragment.java
index f2e8aa244e6..5fd470745a4 100644
--- a/app/src/main/java/org/schabi/newpipe/fragments/list/search/SearchFragment.java
+++ b/app/src/main/java/org/schabi/newpipe/fragments/list/search/SearchFragment.java
@@ -436,16 +436,16 @@ private void showSearchOnStart() {
if (TextUtils.isEmpty(searchString) || TextUtils.isEmpty(searchEditText.getText())) {
searchToolbarContainer.setTranslationX(100);
- searchToolbarContainer.setAlpha(0f);
+ searchToolbarContainer.setAlpha(0.0f);
searchToolbarContainer.setVisibility(View.VISIBLE);
searchToolbarContainer.animate()
.translationX(0)
- .alpha(1f)
+ .alpha(1.0f)
.setDuration(200)
.setInterpolator(new DecelerateInterpolator()).start();
} else {
searchToolbarContainer.setTranslationX(0);
- searchToolbarContainer.setAlpha(1f);
+ searchToolbarContainer.setAlpha(1.0f);
searchToolbarContainer.setVisibility(View.VISIBLE);
}
}
diff --git a/app/src/main/java/org/schabi/newpipe/player/BackgroundPlayer.java b/app/src/main/java/org/schabi/newpipe/player/BackgroundPlayer.java
index e408f49f623..99b38aae7a0 100644
--- a/app/src/main/java/org/schabi/newpipe/player/BackgroundPlayer.java
+++ b/app/src/main/java/org/schabi/newpipe/player/BackgroundPlayer.java
@@ -337,7 +337,7 @@ public void onLoadingFailed(String imageUri, View view, FailReason failReason) {
@Override
public void onPrepared(boolean playWhenReady) {
super.onPrepared(playWhenReady);
- simpleExoPlayer.setVolume(1f);
+ simpleExoPlayer.setVolume(1.0f);
}
@Override
diff --git a/app/src/main/java/org/schabi/newpipe/player/BasePlayer.java b/app/src/main/java/org/schabi/newpipe/player/BasePlayer.java
index 490419c6466..c3165447382 100644
--- a/app/src/main/java/org/schabi/newpipe/player/BasePlayer.java
+++ b/app/src/main/java/org/schabi/newpipe/player/BasePlayer.java
@@ -158,7 +158,7 @@ public abstract class BasePlayer implements
// Playback
//////////////////////////////////////////////////////////////////////////*/
- protected static final float[] PLAYBACK_SPEEDS = {0.5f, 0.75f, 1f, 1.25f, 1.5f, 1.75f, 2f};
+ protected static final float[] PLAYBACK_SPEEDS = {0.5f, 0.75f, 1.0f, 1.25f, 1.5f, 1.75f, 2.0f};
protected PlayQueue playQueue;
protected PlayQueueAdapter playQueueAdapter;
@@ -227,7 +227,7 @@ public void onReceive(Context context, Intent intent) {
public void setup() {
if (simpleExoPlayer == null) {
- initPlayer(/*playOnInit=*/true);
+ initPlayer(true);
}
initListeners();
}
@@ -274,7 +274,7 @@ public void handleIntent(Intent intent) {
return;
}
- boolean same = playQueue != null && playQueue.equals(queue);
+ boolean samePlayQueue = playQueue != null && playQueue.equals(queue);
final int repeatMode = intent.getIntExtra(REPEAT_MODE, getRepeatMode());
final float playbackSpeed = intent.getFloatExtra(PLAYBACK_SPEED, getPlaybackSpeed());
@@ -282,6 +282,14 @@ public void handleIntent(Intent intent) {
final boolean playbackSkipSilence = intent.getBooleanExtra(PLAYBACK_SKIP_SILENCE,
getPlaybackSkipSilence());
+ /*
+ * There are 3 situations when playback shouldn't be started from scratch (zero timestamp):
+ * 1. User pressed on a timestamp link and the same video should be rewound to that timestamp
+ * 2. User changed a player from, for example. main to popup, or from audio to main, etc
+ * 3. User chose to resume a video based on a saved timestamp from history of played videos
+ * In those cases time will be saved because re-init of the play queue is a not an instant task
+ * and requires network calls
+ * */
// seek to timestamp if stream is already playing
if (simpleExoPlayer != null
&& queue.size() == 1
@@ -289,21 +297,20 @@ public void handleIntent(Intent intent) {
&& playQueue.size() == 1
&& playQueue.getItem() != null
&& queue.getItem().getUrl().equals(playQueue.getItem().getUrl())
- && queue.getItem().getRecoveryPosition() != PlayQueueItem.RECOVERY_UNSET
- && simpleExoPlayer.getPlaybackState() != Player.STATE_IDLE) {
+ && queue.getItem().getRecoveryPosition() != PlayQueueItem.RECOVERY_UNSET) {
// Player can have state = IDLE when playback is stopped or failed and we should retry() in this case
if (simpleExoPlayer.getPlaybackState() == Player.STATE_IDLE) simpleExoPlayer.retry();
simpleExoPlayer.seekTo(playQueue.getIndex(), queue.getItem().getRecoveryPosition());
return;
- } else if (same && !playQueue.isDisposed() && simpleExoPlayer != null) {
+ } else if (samePlayQueue && !playQueue.isDisposed() && simpleExoPlayer != null) {
// Do not re-init the same PlayQueue. Save time
// Player can have state = IDLE when playback is stopped or failed and we should retry() in this case
if (simpleExoPlayer.getPlaybackState() == Player.STATE_IDLE) simpleExoPlayer.retry();
return;
} else if (intent.getBooleanExtra(RESUME_PLAYBACK, false)
&& isPlaybackResumeEnabled()
- && !same) {
+ && !samePlayQueue) {
final PlayQueueItem item = queue.getItem();
if (item != null && item.getRecoveryPosition() == PlayQueueItem.RECOVERY_UNSET) {
stateLoader = recordManager.loadStreamState(item)
@@ -313,19 +320,16 @@ && isPlaybackResumeEnabled()
.subscribe(
state -> {
queue.setRecovery(queue.getIndex(), state.getProgressTime());
- initPlayback(queue, repeatMode, playbackSpeed, playbackPitch, playbackSkipSilence,
- /*playOnInit=*/true);
+ initPlayback(queue, repeatMode, playbackSpeed, playbackPitch, playbackSkipSilence, true);
},
error -> {
if (DEBUG) error.printStackTrace();
// In case any error we can start playback without history
- initPlayback(queue, repeatMode, playbackSpeed, playbackPitch, playbackSkipSilence,
- /*playOnInit=*/true);
+ initPlayback(queue, repeatMode, playbackSpeed, playbackPitch, playbackSkipSilence, true);
},
() -> {
// Completed but not found in history
- initPlayback(queue, repeatMode, playbackSpeed, playbackPitch, playbackSkipSilence,
- /*playOnInit=*/true);
+ initPlayback(queue, repeatMode, playbackSpeed, playbackPitch, playbackSkipSilence, true);
}
);
databaseUpdateReactor.add(stateLoader);
@@ -334,8 +338,7 @@ && isPlaybackResumeEnabled()
}
// Good to go...
// In a case of equal PlayQueues we can re-init old one but only when it is disposed
- initPlayback(same ? playQueue : queue, repeatMode, playbackSpeed, playbackPitch, playbackSkipSilence,
- /*playOnInit=*/true);
+ initPlayback(samePlayQueue ? playQueue : queue, repeatMode, playbackSpeed, playbackPitch, playbackSkipSilence, true);
}
protected void initPlayback(@NonNull final PlayQueue queue,
diff --git a/app/src/main/java/org/schabi/newpipe/player/MainPlayer.java b/app/src/main/java/org/schabi/newpipe/player/MainPlayer.java
index 61b69ac5e73..f1f9b51daa1 100644
--- a/app/src/main/java/org/schabi/newpipe/player/MainPlayer.java
+++ b/app/src/main/java/org/schabi/newpipe/player/MainPlayer.java
@@ -184,8 +184,6 @@ private void onClose() {
playerImpl.destroy();
}
if (notificationManager != null) notificationManager.cancel(NOTIFICATION_ID);
- playerImpl = null;
- lockManager = null;
stopForeground(true);
stopSelf();
@@ -197,7 +195,7 @@ private void onClose() {
boolean isLandscape() {
// DisplayMetrics from activity context knows about MultiWindow feature while DisplayMetrics from app context doesn't
- final DisplayMetrics metrics = playerImpl != null && playerImpl.getParentActivity() != null ?
+ final DisplayMetrics metrics = (playerImpl != null && playerImpl.getParentActivity() != null) ?
playerImpl.getParentActivity().getResources().getDisplayMetrics()
: getResources().getDisplayMetrics();
return metrics.heightPixels < metrics.widthPixels;
diff --git a/app/src/main/java/org/schabi/newpipe/player/VideoPlayer.java b/app/src/main/java/org/schabi/newpipe/player/VideoPlayer.java
index c29cfd19c67..632044b0660 100644
--- a/app/src/main/java/org/schabi/newpipe/player/VideoPlayer.java
+++ b/app/src/main/java/org/schabi/newpipe/player/VideoPlayer.java
@@ -797,9 +797,9 @@ public void showAndAnimateControl(final int drawableId, final boolean goneOnEnd)
if (drawableId == -1) {
if (controlAnimationView.getVisibility() == View.VISIBLE) {
controlViewAnimator = ObjectAnimator.ofPropertyValuesHolder(controlAnimationView,
- PropertyValuesHolder.ofFloat(View.ALPHA, 1f, 0f),
- PropertyValuesHolder.ofFloat(View.SCALE_X, 1.4f, 1f),
- PropertyValuesHolder.ofFloat(View.SCALE_Y, 1.4f, 1f)
+ PropertyValuesHolder.ofFloat(View.ALPHA, 1.0f, 0.0f),
+ PropertyValuesHolder.ofFloat(View.SCALE_X, 1.4f, 1.0f),
+ PropertyValuesHolder.ofFloat(View.SCALE_Y, 1.4f, 1.0f)
).setDuration(DEFAULT_CONTROLS_DURATION);
controlViewAnimator.addListener(new AnimatorListenerAdapter() {
@Override
@@ -812,8 +812,8 @@ public void onAnimationEnd(Animator animation) {
return;
}
- float scaleFrom = goneOnEnd ? 1f : 1f, scaleTo = goneOnEnd ? 1.8f : 1.4f;
- float alphaFrom = goneOnEnd ? 1f : 0f, alphaTo = goneOnEnd ? 0f : 1f;
+ float scaleFrom = goneOnEnd ? 1.0f : 1.0f, scaleTo = goneOnEnd ? 1.8f : 1.4f;
+ float alphaFrom = goneOnEnd ? 1.0f : 0.0f, alphaTo = goneOnEnd ? 0.0f : 1.0f;
controlViewAnimator = ObjectAnimator.ofPropertyValuesHolder(controlAnimationView,
diff --git a/app/src/main/java/org/schabi/newpipe/player/VideoPlayerImpl.java b/app/src/main/java/org/schabi/newpipe/player/VideoPlayerImpl.java
index efbe0645714..aad20b0adc6 100644
--- a/app/src/main/java/org/schabi/newpipe/player/VideoPlayerImpl.java
+++ b/app/src/main/java/org/schabi/newpipe/player/VideoPlayerImpl.java
@@ -270,14 +270,14 @@ protected void setupSubtitleView(@NonNull SubtitleView view,
final float captionScale,
@NonNull final CaptionStyleCompat captionStyle) {
if (popupPlayerSelected()) {
- float captionRatio = (captionScale - 1f) / 5f + 1f;
+ float captionRatio = (captionScale - 1.0f) / 5.0f + 1.0f;
view.setFractionalTextSize(SubtitleView.DEFAULT_TEXT_SIZE_FRACTION * captionRatio);
view.setApplyEmbeddedStyles(captionStyle.equals(CaptionStyleCompat.DEFAULT));
view.setStyle(captionStyle);
} else {
final DisplayMetrics metrics = context.getResources().getDisplayMetrics();
final int minimumLength = Math.min(metrics.heightPixels, metrics.widthPixels);
- final float captionRatioInverse = 20f + 4f * (1f - captionScale);
+ final float captionRatioInverse = 20f + 4f * (1.0f - captionScale);
view.setFixedTextSize(TypedValue.COMPLEX_UNIT_PX,
(float) minimumLength / captionRatioInverse);
view.setApplyEmbeddedStyles(captionStyle.equals(CaptionStyleCompat.DEFAULT));
@@ -300,7 +300,7 @@ private void setupElementsVisibility() {
moreOptionsButton.setVisibility(View.GONE);
getTopControlsRoot().setOrientation(LinearLayout.HORIZONTAL);
primaryControls.getLayoutParams().width = LinearLayout.LayoutParams.WRAP_CONTENT;
- secondaryControls.setAlpha(1f);
+ secondaryControls.setAlpha(1.0f);
secondaryControls.setVisibility(View.VISIBLE);
secondaryControls.setTranslationY(0);
shareButton.setVisibility(View.GONE);
@@ -333,7 +333,7 @@ private void setupElementsVisibility() {
getTopControlsRoot().setClickable(true);
getTopControlsRoot().setFocusable(true);
}
- if (!isInFullscreen()) {
+ if (!isFullscreen()) {
titleTextView.setVisibility(View.GONE);
channelTextView.setVisibility(View.GONE);
} else {
@@ -602,10 +602,10 @@ public void toggleFullscreen() {
isFullscreen = !isFullscreen;
setControlsSize();
- fragmentListener.onFullscreenStateChanged(isInFullscreen());
+ fragmentListener.onFullscreenStateChanged(isFullscreen());
}
- if (!isInFullscreen()) {
+ if (!isFullscreen()) {
titleTextView.setVisibility(View.GONE);
channelTextView.setVisibility(View.GONE);
playerCloseButton.setVisibility(videoPlayerSelected() ? View.VISIBLE : View.GONE);
@@ -674,7 +674,7 @@ public void onClick(View v) {
@Override
public boolean onLongClick(View v) {
- if (v.getId() == moreOptionsButton.getId() && isInFullscreen()) {
+ if (v.getId() == moreOptionsButton.getId() && isFullscreen()) {
fragmentListener.onMoreOptionsLongClicked();
hideControls(0, 0);
hideSystemUIIfNeeded();
@@ -690,7 +690,7 @@ private void onQueueClicked() {
updatePlaybackButtons();
getControlsRoot().setVisibility(View.INVISIBLE);
- animateView(queueLayout, SLIDE_AND_ALPHA, /*visible=*/true,
+ animateView(queueLayout, SLIDE_AND_ALPHA,true,
DEFAULT_CONTROLS_DURATION);
itemsList.scrollToPosition(playQueue.getIndex());
@@ -699,7 +699,7 @@ private void onQueueClicked() {
public void onQueueClosed() {
if (!queueVisible) return;
- animateView(queueLayout, SLIDE_AND_ALPHA, /*visible=*/false,
+ animateView(queueLayout, SLIDE_AND_ALPHA,false,
DEFAULT_CONTROLS_DURATION, 0, () -> {
// Even when queueLayout is GONE it receives touch events and ruins normal behavior of the app. This line fixes it
queueLayout.setTranslationY(-queueLayout.getHeight() * 5);
@@ -765,12 +765,12 @@ private void setupScreenRotationButton() {
boolean showButton = videoPlayerSelected() && (orientationLocked || isVerticalVideo || tabletInLandscape);
screenRotationButton.setVisibility(showButton ? View.VISIBLE : View.GONE);
screenRotationButton.setImageDrawable(service.getResources().getDrawable(
- isInFullscreen() ? R.drawable.ic_fullscreen_exit_white : R.drawable.ic_fullscreen_white));
+ isFullscreen() ? R.drawable.ic_fullscreen_exit_white : R.drawable.ic_fullscreen_white));
}
private void prepareOrientation() {
boolean orientationLocked = PlayerHelper.globalScreenOrientationLocked(service);
- if (orientationLocked && isInFullscreen() && service.isLandscape() == isVerticalVideo && fragmentListener != null)
+ if (orientationLocked && isFullscreen() && service.isLandscape() == isVerticalVideo && fragmentListener != null)
fragmentListener.onScreenRotationButtonClicked();
}
@@ -893,7 +893,7 @@ public void changeState(int state) {
@Override
public void onBlocked() {
super.onBlocked();
- playPauseButton.setImageResource(R.drawable.ic_pause_white);
+ playPauseButton.setImageResource(R.drawable.ic_play_arrow_white);
animatePlayButtons(false, 100);
getRootView().setKeepScreenOn(false);
@@ -1185,7 +1185,7 @@ public boolean isInsideClosingRadius(MotionEvent popupMotionEvent) {
return distanceFromCloseButton(popupMotionEvent) <= getClosingRadius();
}
- public boolean isInFullscreen() {
+ public boolean isFullscreen() {
return isFullscreen;
}
@@ -1216,8 +1216,7 @@ public void hideControls(final long duration, long delay) {
getControlsVisibilityHandler().removeCallbacksAndMessages(null);
getControlsVisibilityHandler().postDelayed(() ->
animateView(getControlsRoot(), false, duration, 0,
- this::hideSystemUIIfNeeded),
- /*delayMillis=*/delay
+ this::hideSystemUIIfNeeded), delay
);
}
@@ -1225,24 +1224,13 @@ private void showOrHideButtons() {
if (playQueue == null)
return;
- if (playQueue.getIndex() == 0)
- playPreviousButton.setVisibility(View.INVISIBLE);
- else
- playPreviousButton.setVisibility(View.VISIBLE);
-
- if (playQueue.getIndex() + 1 == playQueue.getStreams().size())
- playNextButton.setVisibility(View.INVISIBLE);
- else
- playNextButton.setVisibility(View.VISIBLE);
-
- if (playQueue.getStreams().size() <= 1 || popupPlayerSelected())
- queueButton.setVisibility(View.GONE);
- else
- queueButton.setVisibility(View.VISIBLE);
+ playPreviousButton.setVisibility(playQueue.getIndex() == 0 ? View.INVISIBLE : View.VISIBLE);
+ playNextButton.setVisibility(playQueue.getIndex() + 1 == playQueue.getStreams().size() ? View.INVISIBLE : View.VISIBLE);
+ queueButton.setVisibility(playQueue.getStreams().size() <= 1 || popupPlayerSelected() ? View.GONE : View.VISIBLE);
}
private void showSystemUIPartially() {
- if (isInFullscreen() && getParentActivity() != null) {
+ if (isFullscreen() && getParentActivity() != null) {
int visibility = View.SYSTEM_UI_FLAG_LAYOUT_STABLE;
getParentActivity().getWindow().getDecorView().setSystemUiVisibility(visibility);
}
@@ -1330,7 +1318,7 @@ private void updatePlaybackButtons() {
public void checkLandscape() {
AppCompatActivity parent = getParentActivity();
- boolean videoInLandscapeButNotInFullscreen = service.isLandscape() && !isInFullscreen() && videoPlayerSelected() && !audioOnly;
+ boolean videoInLandscapeButNotInFullscreen = service.isLandscape() && !isFullscreen() && videoPlayerSelected() && !audioOnly;
boolean playingState = getCurrentState() != STATE_COMPLETED && getCurrentState() != STATE_PAUSED;
if (parent != null && videoInLandscapeButNotInFullscreen && playingState && !PlayerHelper.isTablet(service))
toggleFullscreen();
@@ -1421,7 +1409,7 @@ private void initPopup() {
if (DEBUG) Log.d(TAG, "initPopup() called");
// Popup is already added to windowManager
- if (isPopupHasParent()) return;
+ if (popupHasParent()) return;
updateScreenSize();
@@ -1430,13 +1418,10 @@ private void initPopup() {
SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(service);
popupWidth = popupRememberSizeAndPos ? sharedPreferences.getFloat(POPUP_SAVED_WIDTH, defaultSize) : defaultSize;
popupHeight = getMinimumVideoHeight(popupWidth);
- final int layoutParamType = Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.O ?
- WindowManager.LayoutParams.TYPE_PHONE :
- WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
popupLayoutParams = new WindowManager.LayoutParams(
(int) popupWidth, (int) popupHeight,
- layoutParamType,
+ popupLayoutParamType(),
IDLE_WINDOW_FLAGS,
PixelFormat.TRANSLUCENT);
popupLayoutParams.gravity = Gravity.LEFT | Gravity.TOP;
@@ -1470,15 +1455,12 @@ private void initPopupCloseOverlay() {
closeOverlayView = View.inflate(service, R.layout.player_popup_close_overlay, null);
closeOverlayButton = closeOverlayView.findViewById(R.id.closeButton);
- final int layoutParamType = Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.O ?
- WindowManager.LayoutParams.TYPE_PHONE :
- WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
final int flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
| WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
WindowManager.LayoutParams closeOverlayLayoutParams = new WindowManager.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT,
- layoutParamType,
+ popupLayoutParamType(),
flags,
PixelFormat.TRANSLUCENT);
closeOverlayLayoutParams.gravity = Gravity.LEFT | Gravity.TOP;
@@ -1600,6 +1582,12 @@ private void updateWindowFlags(final int flags) {
windowManager.updateViewLayout(getRootView(), popupLayoutParams);
}
+ private int popupLayoutParamType() {
+ return Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.O ?
+ WindowManager.LayoutParams.TYPE_PHONE :
+ WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
+ }
+
/*//////////////////////////////////////////////////////////////////////////
// Misc
//////////////////////////////////////////////////////////////////////////*/
@@ -1617,7 +1605,7 @@ public void closePopup() {
public void removePopupFromView() {
boolean isCloseOverlayHasParent = closeOverlayView != null && closeOverlayView.getParent() != null;
- if (isPopupHasParent())
+ if (popupHasParent())
windowManager.removeView(getRootView());
if (isCloseOverlayHasParent)
windowManager.removeView(closeOverlayView);
@@ -1651,7 +1639,7 @@ private void end() {
}).start();
}
- private boolean isPopupHasParent() {
+ private boolean popupHasParent() {
View root = getRootView();
return root != null && root.getLayoutParams() instanceof WindowManager.LayoutParams && root.getParent() != null;
}
diff --git a/app/src/main/java/org/schabi/newpipe/player/event/PlayerGestureListener.java b/app/src/main/java/org/schabi/newpipe/player/event/PlayerGestureListener.java
index bb9ede4d73e..f8b4021037b 100644
--- a/app/src/main/java/org/schabi/newpipe/player/event/PlayerGestureListener.java
+++ b/app/src/main/java/org/schabi/newpipe/player/event/PlayerGestureListener.java
@@ -160,10 +160,7 @@ private boolean onScrollInMain(MotionEvent initialEvent, MotionEvent movingEvent
isMovingInMain = true;
- boolean acceptVolumeArea = initialEvent.getX() > playerImpl.getRootView().getWidth() / 2.0;
- boolean acceptBrightnessArea = initialEvent.getX() <= playerImpl.getRootView().getWidth() / 2.0;
-
- if (isVolumeGestureEnabled && acceptVolumeArea) {
+ if (isVolumeGestureEnabled && initialEvent.getX() > playerImpl.getRootView().getWidth() / 2.0) {
playerImpl.getVolumeProgressBar().incrementProgressBy((int) distanceY);
float currentProgressPercent =
(float) playerImpl.getVolumeProgressBar().getProgress() / playerImpl.getMaxGestureLength();
@@ -172,14 +169,11 @@ private boolean onScrollInMain(MotionEvent initialEvent, MotionEvent movingEvent
if (DEBUG) Log.d(TAG, "onScroll().volumeControl, currentVolume = " + currentVolume);
- final int resId =
- currentProgressPercent <= 0 ? R.drawable.ic_volume_off_white_72dp
+ playerImpl.getVolumeImageView().setImageDrawable(
+ AppCompatResources.getDrawable(service, currentProgressPercent <= 0 ? R.drawable.ic_volume_off_white_72dp
: currentProgressPercent < 0.25 ? R.drawable.ic_volume_mute_white_72dp
: currentProgressPercent < 0.75 ? R.drawable.ic_volume_down_white_72dp
- : R.drawable.ic_volume_up_white_72dp;
-
- playerImpl.getVolumeImageView().setImageDrawable(
- AppCompatResources.getDrawable(service, resId)
+ : R.drawable.ic_volume_up_white_72dp)
);
if (playerImpl.getVolumeRelativeLayout().getVisibility() != View.VISIBLE) {
@@ -188,7 +182,7 @@ private boolean onScrollInMain(MotionEvent initialEvent, MotionEvent movingEvent
if (playerImpl.getBrightnessRelativeLayout().getVisibility() == View.VISIBLE) {
playerImpl.getBrightnessRelativeLayout().setVisibility(View.GONE);
}
- } else if (isBrightnessGestureEnabled && acceptBrightnessArea) {
+ } else if (isBrightnessGestureEnabled && initialEvent.getX() <= playerImpl.getRootView().getWidth() / 2.0) {
Activity parent = playerImpl.getParentActivity();
if (parent == null) return true;
@@ -203,13 +197,11 @@ private boolean onScrollInMain(MotionEvent initialEvent, MotionEvent movingEvent
if (DEBUG) Log.d(TAG, "onScroll().brightnessControl, currentBrightness = " + currentProgressPercent);
- final int resId =
- currentProgressPercent < 0.25 ? R.drawable.ic_brightness_low_white_72dp
- : currentProgressPercent < 0.75 ? R.drawable.ic_brightness_medium_white_72dp
- : R.drawable.ic_brightness_high_white_72dp;
-
playerImpl.getBrightnessImageView().setImageDrawable(
- AppCompatResources.getDrawable(service, resId)
+ AppCompatResources.getDrawable(service,
+ currentProgressPercent < 0.25 ? R.drawable.ic_brightness_low_white_72dp
+ : currentProgressPercent < 0.75 ? R.drawable.ic_brightness_medium_white_72dp
+ : R.drawable.ic_brightness_high_white_72dp)
);
if (playerImpl.getBrightnessRelativeLayout().getVisibility() != View.VISIBLE) {
@@ -247,7 +239,7 @@ private boolean onTouchInMain(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_MOVE:
- v.getParent().requestDisallowInterceptTouchEvent(playerImpl.isInFullscreen());
+ v.getParent().requestDisallowInterceptTouchEvent(playerImpl.isFullscreen());
return true;
case MotionEvent.ACTION_UP:
v.getParent().requestDisallowInterceptTouchEvent(false);
diff --git a/app/src/main/java/org/schabi/newpipe/player/helper/AudioReactor.java b/app/src/main/java/org/schabi/newpipe/player/helper/AudioReactor.java
index 8f344390adf..ff9d0c47719 100644
--- a/app/src/main/java/org/schabi/newpipe/player/helper/AudioReactor.java
+++ b/app/src/main/java/org/schabi/newpipe/player/helper/AudioReactor.java
@@ -114,7 +114,7 @@ public void onAudioFocusChange(int focusChange) {
private void onAudioFocusGain() {
Log.d(TAG, "onAudioFocusGain() called");
player.setVolume(DUCK_AUDIO_TO);
- animateAudio(DUCK_AUDIO_TO, 1f);
+ animateAudio(DUCK_AUDIO_TO, 1.0f);
if (PlayerHelper.isResumeAfterAudioFocusGain(context)) {
player.setPlayWhenReady(true);
diff --git a/app/src/main/java/org/schabi/newpipe/player/helper/PlayerHelper.java b/app/src/main/java/org/schabi/newpipe/player/helper/PlayerHelper.java
index 6afb5a32279..82003231d42 100644
--- a/app/src/main/java/org/schabi/newpipe/player/helper/PlayerHelper.java
+++ b/app/src/main/java/org/schabi/newpipe/player/helper/PlayerHelper.java
@@ -222,14 +222,10 @@ public static int getMinimizeOnExitAction(@NonNull final Context context) {
@AutoplayType
public static int getAutoplayType(@NonNull final Context context) {
- final String defaultType = context.getString(R.string.autoplay_wifi_key);
- final String always = context.getString(R.string.autoplay_always_key);
- final String never = context.getString(R.string.autoplay_never_key);
-
- final String type = getAutoplayType(context, defaultType);
- if (type.equals(always)) {
+ final String type = getAutoplayType(context, context.getString(R.string.autoplay_wifi_key));
+ if (type.equals(context.getString(R.string.autoplay_always_key))) {
return AUTOPLAY_TYPE_ALWAYS;
- } else if (type.equals(never)) {
+ } else if (type.equals(context.getString(R.string.autoplay_never_key))) {
return AUTOPLAY_TYPE_NEVER;
} else {
return AUTOPLAY_TYPE_WIFI;
@@ -307,12 +303,12 @@ public static CaptionStyleCompat getCaptionStyle(@NonNull final Context context)
* Very small - 0.25f, Small - 0.5f, Normal - 1.0f, Large - 1.5f, Very Large - 2.0f
* */
public static float getCaptionScale(@NonNull final Context context) {
- if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) return 1f;
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) return 1.0f;
final CaptioningManager captioningManager = (CaptioningManager)
context.getSystemService(Context.CAPTIONING_SERVICE);
if (captioningManager == null || !captioningManager.isEnabled()) {
- return 1f;
+ return 1.0f;
}
return captioningManager.getFontScale();
@@ -330,8 +326,8 @@ public static void setScreenBrightness(@NonNull final Context context, final flo
public static boolean globalScreenOrientationLocked(Context context) {
// 1: Screen orientation changes using accelerometer
// 0: Screen orientation is locked
- return !(android.provider.Settings.System.getInt(
- context.getContentResolver(), Settings.System.ACCELEROMETER_ROTATION, 0) == 1);
+ return android.provider.Settings.System.getInt(
+ context.getContentResolver(), Settings.System.ACCELEROMETER_ROTATION, 0) == 0;
}
public static boolean isTablet(@NonNull final Context context) {
diff --git a/app/src/main/java/org/schabi/newpipe/streams/OggFromWebMWriter.java b/app/src/main/java/org/schabi/newpipe/streams/OggFromWebMWriter.java
index 16bffea9aa1..5a5a9e1fdaf 100644
--- a/app/src/main/java/org/schabi/newpipe/streams/OggFromWebMWriter.java
+++ b/app/src/main/java/org/schabi/newpipe/streams/OggFromWebMWriter.java
@@ -158,7 +158,7 @@ public void build() throws IOException {
switch (webm_track.kind) {
case Audio:
resolution = getSampleFrequencyFromTrack(webm_track.bMetadata);
- if (resolution == 0f) {
+ if (resolution == 0.0f) {
throw new RuntimeException("cannot get the audio sample rate");
}
break;
@@ -167,7 +167,7 @@ public void build() throws IOException {
if (webm_track.defaultDuration == 0) {
throw new RuntimeException("missing default frame time");
}
- resolution = 1000f / ((float) webm_track.defaultDuration / webm_segment.info.timecodeScale);
+ resolution = 1000.0f / ((float) webm_track.defaultDuration / webm_segment.info.timecodeScale);
break;
default:
throw new RuntimeException("not implemented");
@@ -358,7 +358,7 @@ private float getSampleFrequencyFromTrack(byte[] bMetadata) {
}
}
- return 0f;
+ return 0.0f;
}
private void clearSegmentTable() {
diff --git a/app/src/main/java/org/schabi/newpipe/streams/SubtitleConverter.java b/app/src/main/java/org/schabi/newpipe/streams/SubtitleConverter.java
index c41db437389..9c6fa977dd3 100644
--- a/app/src/main/java/org/schabi/newpipe/streams/SubtitleConverter.java
+++ b/app/src/main/java/org/schabi/newpipe/streams/SubtitleConverter.java
@@ -292,7 +292,7 @@ private static int parseTimestamp(String multiImpl) throws NumberFormatException
time += Integer.parseInt(units[0]) * 3600000;// hours
time += Integer.parseInt(units[1]) * 60000;//minutes
- time += Float.parseFloat(units[2]) * 1000f;// seconds and milliseconds (if present)
+ time += Float.parseFloat(units[2]) * 1000.0f;// seconds and milliseconds (if present)
// frames and sub-frames are ignored (not implemented)
// time += units[3] * fps;
diff --git a/app/src/main/java/org/schabi/newpipe/streams/WebMWriter.java b/app/src/main/java/org/schabi/newpipe/streams/WebMWriter.java
index 8525fabd204..fa2cc43e2f5 100644
--- a/app/src/main/java/org/schabi/newpipe/streams/WebMWriter.java
+++ b/app/src/main/java/org/schabi/newpipe/streams/WebMWriter.java
@@ -612,7 +612,7 @@ private byte[] encode(long number, boolean withLength) {
int offset = withLength ? 1 : 0;
byte[] buffer = new byte[offset + length];
- long marker = (long) Math.floor((length - 1f) / 8f);
+ long marker = (long) Math.floor((length - 1.0f) / 8.0f);
float mul = 1;
for (int i = length - 1; i >= 0; i--, mul *= 0x100) {
diff --git a/app/src/main/java/org/schabi/newpipe/util/NavigationHelper.java b/app/src/main/java/org/schabi/newpipe/util/NavigationHelper.java
index 8b867a328a9..f0fd7e41bfa 100644
--- a/app/src/main/java/org/schabi/newpipe/util/NavigationHelper.java
+++ b/app/src/main/java/org/schabi/newpipe/util/NavigationHelper.java
@@ -73,9 +73,7 @@ public static Intent getPlayerIntent(@NonNull final Context context,
if (cacheKey != null) intent.putExtra(VideoPlayer.PLAY_QUEUE_KEY, cacheKey);
if (quality != null) intent.putExtra(VideoPlayer.PLAYBACK_QUALITY, quality);
intent.putExtra(VideoPlayer.RESUME_PLAYBACK, resumePlayback);
-
- int playerType = intent.getIntExtra(VideoPlayer.PLAYER_TYPE, VideoPlayer.PLAYER_TYPE_VIDEO);
- intent.putExtra(VideoPlayer.PLAYER_TYPE, playerType);
+ intent.putExtra(VideoPlayer.PLAYER_TYPE, VideoPlayer.PLAYER_TYPE_VIDEO);
return intent;
}
@@ -122,7 +120,24 @@ public static void playOnMainPlayer(final AppCompatActivity activity, final Play
public static void playOnMainPlayer(final FragmentManager fragmentManager, final PlayQueue queue, boolean autoPlay) {
PlayQueueItem currentStream = queue.getItem();
- NavigationHelper.openVideoDetailFragment(fragmentManager, currentStream.getServiceId(), currentStream.getUrl(), currentStream.getTitle(), autoPlay, queue);
+ openVideoDetailFragment(fragmentManager, currentStream.getServiceId(), currentStream.getUrl(), currentStream.getTitle(), autoPlay, queue);
+ }
+
+ public static void playOnMainPlayer(@NonNull final Context context,
+ @NonNull final PlayQueue queue,
+ @NonNull final StreamingService.LinkType linkType,
+ @NonNull final String url,
+ @NonNull final String title,
+ final boolean autoPlay,
+ final boolean resumePlayback) {
+
+ Intent intent = getPlayerIntent(context, MainActivity.class, queue, resumePlayback);
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ intent.putExtra(Constants.KEY_LINK_TYPE, linkType);
+ intent.putExtra(Constants.KEY_URL, url);
+ intent.putExtra(Constants.KEY_TITLE, title);
+ intent.putExtra(VideoDetailFragment.AUTO_PLAY, autoPlay);
+ context.startActivity(intent);
}
public static void playOnPopupPlayer(final Context context, final PlayQueue queue, final boolean resumePlayback) {
diff --git a/app/src/main/java/org/schabi/newpipe/views/ExpandableSurfaceView.java b/app/src/main/java/org/schabi/newpipe/views/ExpandableSurfaceView.java
index df012eafdc0..f5a7df4716c 100644
--- a/app/src/main/java/org/schabi/newpipe/views/ExpandableSurfaceView.java
+++ b/app/src/main/java/org/schabi/newpipe/views/ExpandableSurfaceView.java
@@ -11,7 +11,7 @@ public class ExpandableSurfaceView extends SurfaceView {
private int resizeMode = AspectRatioFrameLayout.RESIZE_MODE_FIT;
private int baseHeight = 0;
private int maxHeight = 0;
- private float videoAspectRatio = 0f;
+ private float videoAspectRatio = 0.0f;
private float scaleX = 1.0f;
private float scaleY = 1.0f;
@@ -22,7 +22,7 @@ public ExpandableSurfaceView(Context context, AttributeSet attrs) {
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
- if (videoAspectRatio == 0f) return;
+ if (videoAspectRatio == 0.0f) return;
int width = MeasureSpec.getSize(widthMeasureSpec);
boolean verticalVideo = videoAspectRatio < 1;
diff --git a/app/src/main/java/us/shandian/giga/postprocessing/Postprocessing.java b/app/src/main/java/us/shandian/giga/postprocessing/Postprocessing.java
index 773ff92d186..bf9202a754b 100644
--- a/app/src/main/java/us/shandian/giga/postprocessing/Postprocessing.java
+++ b/app/src/main/java/us/shandian/giga/postprocessing/Postprocessing.java
@@ -89,7 +89,7 @@ public static Postprocessing getAlgorithm(@NonNull String algorithmName, String[
}
public void setTemporalDir(@NonNull File directory) {
- long rnd = (int) (Math.random() * 100000f);
+ long rnd = (int) (Math.random() * 100000.0f);
tempFile = new File(directory, rnd + "_" + System.nanoTime() + ".tmp");
}
diff --git a/app/src/main/java/us/shandian/giga/ui/adapter/MissionAdapter.java b/app/src/main/java/us/shandian/giga/ui/adapter/MissionAdapter.java
index 8420e343bad..aa7e42abcd9 100644
--- a/app/src/main/java/us/shandian/giga/ui/adapter/MissionAdapter.java
+++ b/app/src/main/java/us/shandian/giga/ui/adapter/MissionAdapter.java
@@ -198,7 +198,7 @@ public void onBindViewHolder(@NonNull ViewHolder view, @SuppressLint("RecyclerVi
} else {
h.progress.setMarquee(false);
h.status.setText("100%");
- h.progress.setProgress(1f);
+ h.progress.setProgress(1.0f);
h.size.setText(Utility.formatBytes(item.mission.length));
}
}
@@ -231,7 +231,7 @@ private void updateProgress(ViewHolderItem h) {
double progress;
if (mission.unknownLength) {
progress = Double.NaN;
- h.progress.setProgress(0f);
+ h.progress.setProgress(0.0f);
} else {
progress = done / length;
}
@@ -298,7 +298,7 @@ private void updateProgress(ViewHolderItem h) {
for (int i = 0; i < h.lastSpeed.length; i++) {
averageSpeed += h.lastSpeed[i];
}
- averageSpeed /= h.lastSpeed.length + 1f;
+ averageSpeed /= h.lastSpeed.length + 1.0f;
}
String speedStr = Utility.formatSpeed(averageSpeed);
diff --git a/app/src/main/java/us/shandian/giga/ui/common/ProgressDrawable.java b/app/src/main/java/us/shandian/giga/ui/common/ProgressDrawable.java
index 3f638d4182a..bec947540d2 100644
--- a/app/src/main/java/us/shandian/giga/ui/common/ProgressDrawable.java
+++ b/app/src/main/java/us/shandian/giga/ui/common/ProgressDrawable.java
@@ -26,7 +26,7 @@ public class ProgressDrawable extends Drawable {
public ProgressDrawable() {
mMarqueeLine = null;// marquee disabled
- mMarqueeProgress = 0f;
+ mMarqueeProgress = 0.0f;
mMarqueeSize = 0;
mMarqueeNext = 0;
}
@@ -122,7 +122,7 @@ public void onBoundsChange(Rect rect) {
}
private void setupMarquee(int width, int height) {
- mMarqueeSize = (int) ((width * 10f) / 100f);// the size is 10% of the width
+ mMarqueeSize = (int) ((width * 10.0f) / 100.0f);// the size is 10% of the width
mMarqueeLine.rewind();
mMarqueeLine.moveTo(-mMarqueeSize, -mMarqueeSize);
diff --git a/app/src/main/res/layout/toolbar_layout.xml b/app/src/main/res/layout/toolbar_layout.xml
index 5d224bda895..318d16ff560 100644
--- a/app/src/main/res/layout/toolbar_layout.xml
+++ b/app/src/main/res/layout/toolbar_layout.xml
@@ -19,15 +19,6 @@
app:popupTheme="@style/ThemeOverlay.AppCompat.ActionBar"
app:titleTextAppearance="@style/Toolbar.Title">
-
-
Date: Sun, 28 Jun 2020 13:33:08 +0200
Subject: [PATCH 024/398] Show dialog with open options in case of an
unsupported url
---
.../org/schabi/newpipe/RouterActivity.java | 42 +++++++++++--------
.../fragments/list/search/SearchFragment.java | 2 +-
app/src/main/res/values-ar/strings.xml | 2 +-
app/src/main/res/values-b+ast/strings.xml | 2 +-
.../main/res/values-b+zh+HANS+CN/strings.xml | 2 +-
app/src/main/res/values-be/strings.xml | 2 +-
app/src/main/res/values-bg/strings.xml | 2 +-
app/src/main/res/values-bn-rBD/strings.xml | 2 +-
app/src/main/res/values-ca/strings.xml | 2 +-
app/src/main/res/values-cs/strings.xml | 2 +-
app/src/main/res/values-da/strings.xml | 2 +-
app/src/main/res/values-de/strings.xml | 2 +-
app/src/main/res/values-el/strings.xml | 2 +-
app/src/main/res/values-eo/strings.xml | 2 +-
app/src/main/res/values-es/strings.xml | 2 +-
app/src/main/res/values-et/strings.xml | 2 +-
app/src/main/res/values-eu/strings.xml | 2 +-
app/src/main/res/values-fa/strings.xml | 2 +-
app/src/main/res/values-fi/strings.xml | 2 +-
app/src/main/res/values-fr/strings.xml | 2 +-
app/src/main/res/values-gl/strings.xml | 2 +-
app/src/main/res/values-he/strings.xml | 2 +-
app/src/main/res/values-hi/strings.xml | 2 +-
app/src/main/res/values-hr/strings.xml | 2 +-
app/src/main/res/values-hu/strings.xml | 2 +-
app/src/main/res/values-ia/strings.xml | 2 +-
app/src/main/res/values-in/strings.xml | 2 +-
app/src/main/res/values-it/strings.xml | 2 +-
app/src/main/res/values-ja/strings.xml | 2 +-
app/src/main/res/values-ko/strings.xml | 2 +-
app/src/main/res/values-ku/strings.xml | 2 +-
app/src/main/res/values-lt/strings.xml | 2 +-
app/src/main/res/values-mk/strings.xml | 2 +-
app/src/main/res/values-ml/strings.xml | 2 +-
app/src/main/res/values-ms/strings.xml | 2 +-
app/src/main/res/values-nb-rNO/strings.xml | 2 +-
app/src/main/res/values-ne/strings.xml | 2 +-
app/src/main/res/values-nl-rBE/strings.xml | 2 +-
app/src/main/res/values-nl/strings.xml | 2 +-
app/src/main/res/values-pa/strings.xml | 2 +-
app/src/main/res/values-pl/strings.xml | 2 +-
app/src/main/res/values-pt-rBR/strings.xml | 2 +-
app/src/main/res/values-pt/strings.xml | 2 +-
app/src/main/res/values-ro/strings.xml | 2 +-
app/src/main/res/values-ru/strings.xml | 2 +-
app/src/main/res/values-sk/strings.xml | 2 +-
app/src/main/res/values-sl/strings.xml | 2 +-
app/src/main/res/values-sq/strings.xml | 2 +-
app/src/main/res/values-sr/strings.xml | 2 +-
app/src/main/res/values-sv/strings.xml | 2 +-
app/src/main/res/values-ta/strings.xml | 2 +-
app/src/main/res/values-te/strings.xml | 2 +-
app/src/main/res/values-th/strings.xml | 2 +-
app/src/main/res/values-tr/strings.xml | 2 +-
app/src/main/res/values-uk/strings.xml | 2 +-
app/src/main/res/values-ur/strings.xml | 2 +-
app/src/main/res/values-vi/strings.xml | 2 +-
app/src/main/res/values-zh-rCN/strings.xml | 2 +-
app/src/main/res/values-zh-rHK/strings.xml | 2 +-
app/src/main/res/values-zh-rTW/strings.xml | 2 +-
app/src/main/res/values/strings.xml | 3 +-
61 files changed, 86 insertions(+), 77 deletions(-)
diff --git a/app/src/main/java/org/schabi/newpipe/RouterActivity.java b/app/src/main/java/org/schabi/newpipe/RouterActivity.java
index 39f6b217dfd..3d996f35cc0 100644
--- a/app/src/main/java/org/schabi/newpipe/RouterActivity.java
+++ b/app/src/main/java/org/schabi/newpipe/RouterActivity.java
@@ -50,6 +50,7 @@
import org.schabi.newpipe.util.ListHelper;
import org.schabi.newpipe.util.NavigationHelper;
import org.schabi.newpipe.util.PermissionHelper;
+import org.schabi.newpipe.util.ShareUtils;
import org.schabi.newpipe.util.ThemeHelper;
import org.schabi.newpipe.util.urlfinder.UrlFinder;
import org.schabi.newpipe.views.FocusOverlayView;
@@ -159,27 +160,36 @@ private void handleUrl(final String url) {
if (result) {
onSuccess();
} else {
- onError();
+ showUnsupportedUrlDialog(url);
}
- }, this::handleError));
+ }, throwable -> handleError(throwable, url)));
}
- private void handleError(final Throwable error) {
- error.printStackTrace();
+ private void handleError(final Throwable throwable, final String url) {
+ throwable.printStackTrace();
- if (error instanceof ExtractionException) {
- Toast.makeText(this, R.string.url_not_supported_toast, Toast.LENGTH_LONG).show();
+ if (throwable instanceof ExtractionException) {
+ showUnsupportedUrlDialog(url);
} else {
- ExtractorHelper.handleGeneralException(this, -1, null, error,
+ ExtractorHelper.handleGeneralException(this, -1, url, throwable,
UserAction.SOMETHING_ELSE, null);
+ finish();
}
-
- finish();
}
- private void onError() {
- Toast.makeText(this, R.string.url_not_supported_toast, Toast.LENGTH_LONG).show();
- finish();
+ private void showUnsupportedUrlDialog(final String url) {
+ final Context context = getThemeWrapperContext();
+ new AlertDialog.Builder(context)
+ .setTitle(R.string.unsupported_url)
+ .setMessage(R.string.unsupported_url_dialog_message)
+ .setIcon(ThemeHelper.resolveResourceIdFromAttr(context, R.attr.ic_share))
+ .setPositiveButton(R.string.open_in_browser,
+ (dialog, which) -> ShareUtils.openUrlInBrowser(this, url))
+ .setNegativeButton(R.string.share,
+ (dialog, which) -> ShareUtils.shareUrl(this, "", url)) // no subject
+ .setNeutralButton(R.string.cancel, null)
+ .setOnDismissListener(dialog -> finish())
+ .show();
}
protected void onSuccess() {
@@ -459,7 +469,7 @@ private void handleChoice(final String selectedChoiceKey) {
startActivity(intent);
finish();
- }, this::handleError)
+ }, throwable -> handleError(throwable, currentUrl))
);
return;
}
@@ -492,11 +502,9 @@ private void openDownloadDialog() {
downloadDialog.setSelectedVideoStream(selectedVideoStreamIndex);
downloadDialog.show(fm, "downloadDialog");
fm.executePendingTransactions();
- downloadDialog.getDialog().setOnDismissListener(dialog -> {
- finish();
- });
+ downloadDialog.getDialog().setOnDismissListener(dialog -> finish());
}, (@NonNull Throwable throwable) -> {
- onError();
+ showUnsupportedUrlDialog(currentUrl);
});
}
diff --git a/app/src/main/java/org/schabi/newpipe/fragments/list/search/SearchFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/list/search/SearchFragment.java
index 9bfead4f0ee..060a5c9c974 100644
--- a/app/src/main/java/org/schabi/newpipe/fragments/list/search/SearchFragment.java
+++ b/app/src/main/java/org/schabi/newpipe/fragments/list/search/SearchFragment.java
@@ -798,7 +798,7 @@ private void search(final String ss, final String[] cf, final String sf) {
getFragmentManager().popBackStackImmediate();
activity.startActivity(intent);
}, throwable ->
- showError(getString(R.string.url_not_supported_toast), false)));
+ showError(getString(R.string.unsupported_url), false)));
return;
}
} catch (Exception ignored) {
diff --git a/app/src/main/res/values-ar/strings.xml b/app/src/main/res/values-ar/strings.xml
index 5d2fe413a99..a6360502e2b 100644
--- a/app/src/main/res/values-ar/strings.xml
+++ b/app/src/main/res/values-ar/strings.xml
@@ -46,7 +46,7 @@
عرض خيار التشغيل بواسطة كودي
السمة
تم النشر بتاريخ %1$s
- رابط URL غير معتمد
+ رابط URL غير معتمد
استخدام مشغل صوت خارجي
استخدام مشغل فيديو خارجي
(إختبارية) إجراء التنزيلات من خلال استخدام بروكسي Tor لزيادة الخصوصية ( تشغيل الفيديو المباشر غير مدعوم حتى الأن ).
diff --git a/app/src/main/res/values-b+ast/strings.xml b/app/src/main/res/values-b+ast/strings.xml
index 247c76b3f2a..99dae05de4d 100644
--- a/app/src/main/res/values-b+ast/strings.xml
+++ b/app/src/main/res/values-b+ast/strings.xml
@@ -277,7 +277,7 @@
Tempu
Tonu
Refugar
- La URL nun se sofita
+ La URL nun se sofita
Reproduciendo en segundu planu
Reproduciendo nel mou ventanu
Atroxa llocalmente les consultes de gueta
diff --git a/app/src/main/res/values-b+zh+HANS+CN/strings.xml b/app/src/main/res/values-b+zh+HANS+CN/strings.xml
index fa6f9fe25a9..40f246e4e4c 100644
--- a/app/src/main/res/values-b+zh+HANS+CN/strings.xml
+++ b/app/src/main/res/values-b+zh+HANS+CN/strings.xml
@@ -29,7 +29,7 @@
黑色
下载
下一个
- 不支持的 URL
+ 不支持的 URL
外观
其他
全部
diff --git a/app/src/main/res/values-be/strings.xml b/app/src/main/res/values-be/strings.xml
index fbd7a99c0cf..c8f026ab9b5 100644
--- a/app/src/main/res/values-be/strings.xml
+++ b/app/src/main/res/values-be/strings.xml
@@ -85,7 +85,7 @@
\"Наступнае\" и \"Прапанаванае\" відэа
\"Зацісніце, каб дадаць\"
Паказаць падказку пры націсканні \"У акне\" ці \"У фоне\" на старонцы звестак аб відэа
- URL не падтрымліваецца
+ URL не падтрымліваецца
Краіна кантэнту па змаўчанні
Сэрвіс
Мова кантэнту па змаўчанні
diff --git a/app/src/main/res/values-bg/strings.xml b/app/src/main/res/values-bg/strings.xml
index 400c8d28026..0d41f31866f 100644
--- a/app/src/main/res/values-bg/strings.xml
+++ b/app/src/main/res/values-bg/strings.xml
@@ -68,7 +68,7 @@
Следващ клип
Показвай „следващ“ и „подобни“
Показвай съвет „задръж за добавяне“
- Непознат URL
+ Непознат URL
Език на съдържанието по подразбиране
Плейър
Поведение
diff --git a/app/src/main/res/values-bn-rBD/strings.xml b/app/src/main/res/values-bn-rBD/strings.xml
index 6ad5e7ad0ef..8da0ba0ac7f 100644
--- a/app/src/main/res/values-bn-rBD/strings.xml
+++ b/app/src/main/res/values-bn-rBD/strings.xml
@@ -49,7 +49,7 @@
ডাউনলোড
পরবর্তী ভিডিও
পরবর্তী এবং অনুরূপ ভিডিওগুলি দেখাও
- URL সমর্থিত নয়
+ URL সমর্থিত নয়
কন্টেন্ট এর জন্য পছন্দসই ভাষা
ভিডিও এবং অডিও
পপআপ
diff --git a/app/src/main/res/values-ca/strings.xml b/app/src/main/res/values-ca/strings.xml
index d77c6a63a8e..abb65418dca 100644
--- a/app/src/main/res/values-ca/strings.xml
+++ b/app/src/main/res/values-ca/strings.xml
@@ -281,7 +281,7 @@
Emmagatzema les cerques localment
Crea un historial de vídeos visualitzats
Reprèn automàticament
- Aquest URL no és compatible
+ Aquest URL no és compatible
Informe d\'error
Més tard
Filtra
diff --git a/app/src/main/res/values-cs/strings.xml b/app/src/main/res/values-cs/strings.xml
index 20b9a8bc4b6..91e1d88dae9 100644
--- a/app/src/main/res/values-cs/strings.xml
+++ b/app/src/main/res/values-cs/strings.xml
@@ -35,7 +35,7 @@
Stáhnout
Další
Zobrazovat \'další\' a \'podobná\' videa
- URL není podporováno
+ URL není podporováno
Preferovaný jazyk obsahu
Video a zvuk
Vzhled
diff --git a/app/src/main/res/values-da/strings.xml b/app/src/main/res/values-da/strings.xml
index 91ca1040f9b..3cc1cef30a0 100644
--- a/app/src/main/res/values-da/strings.xml
+++ b/app/src/main/res/values-da/strings.xml
@@ -92,7 +92,7 @@
Vis \'Næste\' og \'Lignende\' videoer
Vis \"Hold for at tilføje\"-tip
Vis et tip når der trykkes på baggrunds- eller pop op-knappen på siden med videodetaljer
- Denne webadresse er ikke understøttet
+ Denne webadresse er ikke understøttet
Standardland for indhold
Tjeneste
Standardsprog for indhold
diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml
index 4f5c6e01850..8704adc84cd 100644
--- a/app/src/main/res/values-de/strings.xml
+++ b/app/src/main/res/values-de/strings.xml
@@ -28,7 +28,7 @@
Herunterladen
Nächste
„Nächste“ und „Ähnliche“ Videos anzeigen
- Nicht unterstützte URL
+ Nicht unterstützte URL
Video & Audio
Bevorzugte Sprache des Inhalts
Video-Vorschaubild
diff --git a/app/src/main/res/values-el/strings.xml b/app/src/main/res/values-el/strings.xml
index ed5a6b29983..ca14bcd3111 100644
--- a/app/src/main/res/values-el/strings.xml
+++ b/app/src/main/res/values-el/strings.xml
@@ -35,7 +35,7 @@
Λήψη
Επόμενο
Εμφάνιση \"Επόμενου\" και \"Σχετικών\" βίντεο
- Δεν υποστηρίζεται η διεύθυνση URL
+ Δεν υποστηρίζεται η διεύθυνση URL
Προεπιλεγμένη γλώσσα περιεχομένου
Βίντεο & Ήχος
Εμφάνιση
diff --git a/app/src/main/res/values-eo/strings.xml b/app/src/main/res/values-eo/strings.xml
index c7ea0df181d..930a27e77b8 100644
--- a/app/src/main/res/values-eo/strings.xml
+++ b/app/src/main/res/values-eo/strings.xml
@@ -25,7 +25,7 @@
Luma
Elŝuti
Vica filmeto
- Ligilo ne subtenita
+ Ligilo ne subtenita
Preferata enhavlingvo
Filmeto kaj sono
Apero
diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml
index db9c65046a6..e8ad132f0ab 100644
--- a/app/src/main/res/values-es/strings.xml
+++ b/app/src/main/res/values-es/strings.xml
@@ -27,7 +27,7 @@
Formato de audio predeterminado
Descargar
Siguiente
- No se admite el URL
+ No se admite el URL
Usar reproductor de vídeo externo
Usar reproductor de audio externo
Tema
diff --git a/app/src/main/res/values-et/strings.xml b/app/src/main/res/values-et/strings.xml
index a32d26af291..383c16e891a 100644
--- a/app/src/main/res/values-et/strings.xml
+++ b/app/src/main/res/values-et/strings.xml
@@ -84,7 +84,7 @@
Kuva \'järgmine\' ja \'sarnased\' videod
Kuva vihjet \"lisamiseks hoia\"
Kuva vihje, kui videoandmete lehel vajutatakse tausta või hüpikakna nupule
- Mitte toetatud URL
+ Mitte toetatud URL
Sisu vaikimisi riik
Teenus
Sisu vaikimisi keel
diff --git a/app/src/main/res/values-eu/strings.xml b/app/src/main/res/values-eu/strings.xml
index 635e89d9574..2a20817a229 100644
--- a/app/src/main/res/values-eu/strings.xml
+++ b/app/src/main/res/values-eu/strings.xml
@@ -25,7 +25,7 @@
Deskargatu
Hurrengoa
Erakutsi \'hurrengo\' eta \'antzeko\' bideoak
- URLak ez du euskarririk
+ URLak ez du euskarririk
Edukiaren hizkuntz lehenetsia
Bideoa eta Audioa
Erreproduzitu
diff --git a/app/src/main/res/values-fa/strings.xml b/app/src/main/res/values-fa/strings.xml
index ca78bc8ddb9..4aa8757a863 100644
--- a/app/src/main/res/values-fa/strings.xml
+++ b/app/src/main/res/values-fa/strings.xml
@@ -38,7 +38,7 @@
بارگیری
بعدی
نماش ویدیوهای «بعدی» و «مشابه»
- نشانی پشتیبانی نشده
+ نشانی پشتیبانی نشده
زبان محتوای ترجیحی
ویدیو و صدا
ظاهر
diff --git a/app/src/main/res/values-fi/strings.xml b/app/src/main/res/values-fi/strings.xml
index 44ffc5126df..a351d20633a 100644
--- a/app/src/main/res/values-fi/strings.xml
+++ b/app/src/main/res/values-fi/strings.xml
@@ -67,7 +67,7 @@
Lataus
Seuraava video
Näytä seuraavia ja samankaltaisia videoita
- URL ei tueta
+ URL ei tueta
Oletus-sisällon kieli
Soitin
Käyttäytyminen
diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml
index dc4ca619e14..f9234794780 100644
--- a/app/src/main/res/values-fr/strings.xml
+++ b/app/src/main/res/values-fr/strings.xml
@@ -27,7 +27,7 @@
Télécharger
Suivant
Afficher les vidéos « Suivantes » et « Similaires »
- URL non pris en charge
+ URL non pris en charge
Vidéo et audio
Autre
Miniature d’aperçu vidéo
diff --git a/app/src/main/res/values-gl/strings.xml b/app/src/main/res/values-gl/strings.xml
index 8450d60c814..9c6ac9a8d7a 100644
--- a/app/src/main/res/values-gl/strings.xml
+++ b/app/src/main/res/values-gl/strings.xml
@@ -90,7 +90,7 @@
Mostrar vídeos «seguintes» e «semellantes»
Mostrar a suxestión «Manteña presionado para engadir á cola»
Mostrar unha suxestión ao premer o botón de segundo plano ou o de popup na páxina de detalles do vídeo
- Este URL non está soportado
+ Este URL non está soportado
País predeterminado para o contido
Servizo
Reprodutor
diff --git a/app/src/main/res/values-he/strings.xml b/app/src/main/res/values-he/strings.xml
index 512c46ad394..bf339a360b7 100644
--- a/app/src/main/res/values-he/strings.xml
+++ b/app/src/main/res/values-he/strings.xml
@@ -54,7 +54,7 @@
הורדה
הבא
להציג סרטונים דומים ובאים בתור
- כתובת לא נתמכת
+ כתובת לא נתמכת
שפת התוכן המועדפת
סרטונים ושמע
חלון צף
diff --git a/app/src/main/res/values-hi/strings.xml b/app/src/main/res/values-hi/strings.xml
index ad1f3f5fced..58095e006e0 100644
--- a/app/src/main/res/values-hi/strings.xml
+++ b/app/src/main/res/values-hi/strings.xml
@@ -96,7 +96,7 @@
\'अगला\' और \'पहले समान\' वीडियो दिखाए
\"जोड़ने के लिए पकड़ें रहे\" दिखाए
जब बैकग्राउंड और पॉपअप बटन विडियो के विवरण पन्ने में दबाई जाए तो tip को दिखाए
- ये वाला URL इसमें नहीं चलेगा
+ ये वाला URL इसमें नहीं चलेगा
डिफ़ॉल्ट विषय की भाषा
प्लेयर
चाल चलन
diff --git a/app/src/main/res/values-hr/strings.xml b/app/src/main/res/values-hr/strings.xml
index 95703bdd2f0..35c0a625393 100644
--- a/app/src/main/res/values-hr/strings.xml
+++ b/app/src/main/res/values-hr/strings.xml
@@ -68,7 +68,7 @@
Preuzmi
Sljedeće
Prikaži \'Sljedeće\' i \'Slične\' videozapise
- URL nije podržan
+ URL nije podržan
Zadani jezik sadržaja
Video i zvuk
Skočni prozor
diff --git a/app/src/main/res/values-hu/strings.xml b/app/src/main/res/values-hu/strings.xml
index 6b6f1c1ed2f..53f7a64f535 100644
--- a/app/src/main/res/values-hu/strings.xml
+++ b/app/src/main/res/values-hu/strings.xml
@@ -26,7 +26,7 @@
Alapértelmezett hang formátum
Letöltés
Következő
- Nem támogatott webcím
+ Nem támogatott webcím
Külső videólejátszó használata
Külső hanglejátszó használata
Válaszd ki a hangfájlok letöltési helyét
diff --git a/app/src/main/res/values-ia/strings.xml b/app/src/main/res/values-ia/strings.xml
index 150046340b9..25eb5c65ed0 100644
--- a/app/src/main/res/values-ia/strings.xml
+++ b/app/src/main/res/values-ia/strings.xml
@@ -66,7 +66,7 @@
Sequente
Reproduction automatic
Monstrar le videos sequente e simile
- URL non supportate
+ URL non supportate
Pais predefinite del contentos
Servicio
Lingua predefinite del contento
diff --git a/app/src/main/res/values-in/strings.xml b/app/src/main/res/values-in/strings.xml
index c567b447994..70dc31fa830 100644
--- a/app/src/main/res/values-in/strings.xml
+++ b/app/src/main/res/values-in/strings.xml
@@ -34,7 +34,7 @@
Unduh
Berikutnya
Tampilkan video \'Berikutnya\' dan \'Serupa\'
- URL tidak didukung
+ URL tidak didukung
Bahasa konten
Video & Audio
Tampilan
diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml
index 06348d427ab..ae1b97f4f0f 100644
--- a/app/src/main/res/values-it/strings.xml
+++ b/app/src/main/res/values-it/strings.xml
@@ -27,7 +27,7 @@
Scarica
Prossimo
Mostra video \"Prossimo\" e \"Simili\"
- URL non supportato
+ URL non supportato
Lingua Predefinita per Contenuti
Video e Audio
Copertina di anteprima video
diff --git a/app/src/main/res/values-ja/strings.xml b/app/src/main/res/values-ja/strings.xml
index d9506c77001..d4d6c27ee7c 100644
--- a/app/src/main/res/values-ja/strings.xml
+++ b/app/src/main/res/values-ja/strings.xml
@@ -26,7 +26,7 @@
保存
次
「次の動画」と「関連動画」を表示
- URLは使用できません
+ URLは使用できません
優先言語
動画と音声
%1$s ビュー
diff --git a/app/src/main/res/values-ko/strings.xml b/app/src/main/res/values-ko/strings.xml
index 190c13b7171..680462cd051 100644
--- a/app/src/main/res/values-ko/strings.xml
+++ b/app/src/main/res/values-ko/strings.xml
@@ -27,7 +27,7 @@
다운로드
다음
다음/유사한 비디오 표시
- 지원하지 않는 URL입니다
+ 지원하지 않는 URL입니다
기본 컨텐츠 언어
비디오 & 오디오
비디오 미리보기 썸네일
diff --git a/app/src/main/res/values-ku/strings.xml b/app/src/main/res/values-ku/strings.xml
index cf04b973228..f83e26a0541 100644
--- a/app/src/main/res/values-ku/strings.xml
+++ b/app/src/main/res/values-ku/strings.xml
@@ -81,7 +81,7 @@
داگرتن
دواتر
پیشاندانی ’دواتر’ و ڤیدیۆ ’هاوشێوەکان’
- بەستەرەکە پشتگیری نەکراوە
+ بەستەرەکە پشتگیری نەکراوە
وڵاتی بنەڕەتی
خزمەتگوزاری
کارپێکەر
diff --git a/app/src/main/res/values-lt/strings.xml b/app/src/main/res/values-lt/strings.xml
index fb05da09c28..562fce75c7b 100644
--- a/app/src/main/res/values-lt/strings.xml
+++ b/app/src/main/res/values-lt/strings.xml
@@ -56,7 +56,7 @@
Atsisiųsti
Kitas vaizdo įrašas
Rodyti kitus panašius vaizdo įrašus
- URL nepalaikoma
+ URL nepalaikoma
Numatytoji tūrinio kalba
Vaizdas ir garsas
Iššokantis langas
diff --git a/app/src/main/res/values-mk/strings.xml b/app/src/main/res/values-mk/strings.xml
index 660148f01cb..95614bd56d2 100644
--- a/app/src/main/res/values-mk/strings.xml
+++ b/app/src/main/res/values-mk/strings.xml
@@ -85,7 +85,7 @@
Прикажи „следни“ и „слични“ видеа
Прикажи „задржи за прикачување“
Покажи совет при притискање на позадината или кога скок копчето е притиснато на видео \"Детали:\"
- Неподдржана URL врска
+ Неподдржана URL врска
Земја на прикажани видеа
Услуга
Стандарден јазик на содржина
diff --git a/app/src/main/res/values-ml/strings.xml b/app/src/main/res/values-ml/strings.xml
index aa5362b8003..227ec25f401 100644
--- a/app/src/main/res/values-ml/strings.xml
+++ b/app/src/main/res/values-ml/strings.xml
@@ -366,7 +366,7 @@
സ്ഥിര കന്റെന്റ് ഭാഷ
സേവനം
സ്ഥിര കന്റെന്റ് രാജ്യം
- അനുയോജ്യമല്ലാത്ത URL
+ അനുയോജ്യമല്ലാത്ത URL
പോപ്പപ്പ്/ബാക്ക്ഗ്രൗണ്ട് ബട്ടൺ അമർത്തുമ്പോൾ \"വിശദാംശങ്ങൾ\" എന്ന ടിപ് കാണിക്കും
\"ഹോൾഡ് ടു അപ്പെൻഡ്\" എന്ന ടിപ് കാണിക്കുക
\'അടുത്ത\' , \'സമാനമായ\' വീഡിയോകൾ കാണിക്കുക
diff --git a/app/src/main/res/values-ms/strings.xml b/app/src/main/res/values-ms/strings.xml
index 1944877f818..c9c24174fd2 100644
--- a/app/src/main/res/values-ms/strings.xml
+++ b/app/src/main/res/values-ms/strings.xml
@@ -92,7 +92,7 @@
Paparkan video \'Seterusnya\' dan \'Berkaitan\'
Tunjukkan tip \"Pegang untuk menambahkan\"
Tunjukkan tip apabila butang latar belakang atau popup ditekan pada halaman butiran video
- URL tidak disokong
+ URL tidak disokong
Negara kandungan utama
Perkhidmatan
Bahasa kandungan utama
diff --git a/app/src/main/res/values-nb-rNO/strings.xml b/app/src/main/res/values-nb-rNO/strings.xml
index e6e3198e578..d80b3249c66 100644
--- a/app/src/main/res/values-nb-rNO/strings.xml
+++ b/app/src/main/res/values-nb-rNO/strings.xml
@@ -35,7 +35,7 @@
Last ned
Neste
Vis \"Neste\" og \"Lignende\" -videoer
- Nettadressen støttes ikke
+ Nettadressen støttes ikke
Foretrukket innholdsspråk
Video og lyd
Utseende
diff --git a/app/src/main/res/values-ne/strings.xml b/app/src/main/res/values-ne/strings.xml
index f91ae04527e..6c47e793877 100644
--- a/app/src/main/res/values-ne/strings.xml
+++ b/app/src/main/res/values-ne/strings.xml
@@ -94,7 +94,7 @@
\'अर्को\' र \'समान\' भिडियो देखाउन
\"होल्ड संलग्न गर्न\" टिप देखाउन
पृष्ठभूमि वा भिडियो मा पपअप बटन थिच्दा टिप देखाउन \"विवरण:\"
- असमर्थित URL
+ असमर्थित URL
पूर्वनिर्धारित सामग्री देश
सेवा
पूर्वनिर्धारित सामग्री भाषा
diff --git a/app/src/main/res/values-nl-rBE/strings.xml b/app/src/main/res/values-nl-rBE/strings.xml
index a80cec9cc60..813831a6b2c 100644
--- a/app/src/main/res/values-nl-rBE/strings.xml
+++ b/app/src/main/res/values-nl-rBE/strings.xml
@@ -85,7 +85,7 @@
Toont ‘Volgende’ en ‘Vergelijkbare’ video’s
Toont tip ‘Ingedrukt houden voor toe te voegen’
Toont tip wanneer dat den achtergrond- of pop-upknop wordt ingedrukt op de videogegevenspagina
- URL wordt niet ondersteund
+ URL wordt niet ondersteund
Standaardinhoudsland
Dienst
Standaardtaal voor inhoud
diff --git a/app/src/main/res/values-nl/strings.xml b/app/src/main/res/values-nl/strings.xml
index 67677799f93..c14770100ca 100644
--- a/app/src/main/res/values-nl/strings.xml
+++ b/app/src/main/res/values-nl/strings.xml
@@ -26,7 +26,7 @@
Standaardaudioformaat
Downloaden
Volgende
- URL wordt niet ondersteund
+ URL wordt niet ondersteund
‘volgende’ en ‘vergelijkbare’ video’s weergeven
Standaardtaal voor inhoud
Externe videospeler gebruiken
diff --git a/app/src/main/res/values-pa/strings.xml b/app/src/main/res/values-pa/strings.xml
index 6a84b99a42b..c1892d02ce8 100644
--- a/app/src/main/res/values-pa/strings.xml
+++ b/app/src/main/res/values-pa/strings.xml
@@ -85,7 +85,7 @@
\'ਅੱਗੇ\' ਅਤੇ \'ਸਮਾਨਅੰਤਰ\' ਵੀਡੀਓ ਦਿਖਾਓ
\"Hold to append\" ਸੁਝਾਅ ਦਿਖਾਓ
ਵੀਡੀਓ ਵੇਰਵੇ ਪੰਨੇ ਤੇ ਬੈਕਗ੍ਰਾਉਂਡ ਜਾਂ ਪੌਪ-ਅਪ ਬਟਨ ਦਬਾਉਣ ਤੇ ਸੰਕੇਤ ਦਿਖਾਓ
- ਅਣ-ਸਹਾਇਕ URL
+ ਅਣ-ਸਹਾਇਕ URL
ਮੂਲ ਦੇਸ਼ Content
ਸੇਵਾ
ਪਲੇਯਰ
diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml
index 0f029e001da..e2f06f7b381 100644
--- a/app/src/main/res/values-pl/strings.xml
+++ b/app/src/main/res/values-pl/strings.xml
@@ -38,7 +38,7 @@
Pobrane
Dalej
Pokaż \"następne\" i \"podobne\" filmy
- Nieobsługiwany adres URL
+ Nieobsługiwany adres URL
Domyślny język treści
Wideo i audio
Wygląd
diff --git a/app/src/main/res/values-pt-rBR/strings.xml b/app/src/main/res/values-pt-rBR/strings.xml
index 16293c5288d..faf714f830b 100644
--- a/app/src/main/res/values-pt-rBR/strings.xml
+++ b/app/src/main/res/values-pt-rBR/strings.xml
@@ -69,7 +69,7 @@
Permita acesso ao armazenamento primeiramente
Tema
Publicado em %1$s
- Link não suportado
+ Link não suportado
Ao vivo
Downloads
Downloads
diff --git a/app/src/main/res/values-pt/strings.xml b/app/src/main/res/values-pt/strings.xml
index 3a2a9d4d86c..fa026c70331 100644
--- a/app/src/main/res/values-pt/strings.xml
+++ b/app/src/main/res/values-pt/strings.xml
@@ -29,7 +29,7 @@
Transferir
Seguinte
Mostrar vídeos \'Seguintes\' e \'Semelhantes\'
- URL não suportado
+ URL não suportado
Idioma do conteúdo predefinido
Vídeo e áudio
Miniatura de pré-visualização de vídeo
diff --git a/app/src/main/res/values-ro/strings.xml b/app/src/main/res/values-ro/strings.xml
index 2d08addb9ad..dfe732d5f80 100644
--- a/app/src/main/res/values-ro/strings.xml
+++ b/app/src/main/res/values-ro/strings.xml
@@ -36,7 +36,7 @@
Descărcați
Următorul
Arată videoclipurile care urmează și similare
- URL nesuportat
+ URL nesuportat
Limba dorită a conținutului
Video & Audio
Aspect
diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml
index 2670da7eb24..0bd9da4e7b9 100644
--- a/app/src/main/res/values-ru/strings.xml
+++ b/app/src/main/res/values-ru/strings.xml
@@ -26,7 +26,7 @@
Формат аудио по умолчанию
Скачать
Следующее
- URL не поддерживается
+ URL не поддерживается
\"Следующее\" и похожие видео
Язык контента по умолчанию
Видео и аудио
diff --git a/app/src/main/res/values-sk/strings.xml b/app/src/main/res/values-sk/strings.xml
index 17ba3f3f3b1..69fa424ae9e 100644
--- a/app/src/main/res/values-sk/strings.xml
+++ b/app/src/main/res/values-sk/strings.xml
@@ -35,7 +35,7 @@
Prevziať
Ďalšie
Ukázať \'Ďalšie\' a \'Podobné\' videá
- URL nie je podporovaná
+ URL nie je podporovaná
Preferovaný jazyk obsahu
Video & zvuk
Vzhľad
diff --git a/app/src/main/res/values-sl/strings.xml b/app/src/main/res/values-sl/strings.xml
index c1cc8d963dc..189cf86fe6d 100644
--- a/app/src/main/res/values-sl/strings.xml
+++ b/app/src/main/res/values-sl/strings.xml
@@ -28,7 +28,7 @@
Prejem
Naslednji video
Pokaži naslednji video in podobne posnetke
- Zapis naslova URL ni podprt.
+ Zapis naslova URL ni podprt.
Privzeti jezik vsebine
Video in Zvok
Sličica predogleda videa
diff --git a/app/src/main/res/values-sq/strings.xml b/app/src/main/res/values-sq/strings.xml
index 1d3614bf18e..16dcd196e4e 100644
--- a/app/src/main/res/values-sq/strings.xml
+++ b/app/src/main/res/values-sq/strings.xml
@@ -546,7 +546,7 @@
Zgjidhni instancat tuaja të preferuara të PeerTube
Instancat PeerTube
Shteti i parazgjedhur i përmbajtjes
- URL e pambështetur
+ URL e pambështetur
Trego ndihmën kur shtypet sfondi ose butoni i popup në \"Detajet:\" e videos
Trego ndihmën \"Mbaje shtypur për ta shtuar në listë\"
Trego \'Tjetra\' dhe videot \'E ngjashme\'
diff --git a/app/src/main/res/values-sr/strings.xml b/app/src/main/res/values-sr/strings.xml
index 1cd4d2baa9e..af00028799e 100644
--- a/app/src/main/res/values-sr/strings.xml
+++ b/app/src/main/res/values-sr/strings.xml
@@ -26,7 +26,7 @@
Подразумевани формат звука
Преузми
Следећи видео
- УРЛ није подржан
+ УРЛ није подржан
Прикажи следећи и слични видео
Подразумевани језик садржаја
Видео и аудио
diff --git a/app/src/main/res/values-sv/strings.xml b/app/src/main/res/values-sv/strings.xml
index 3a83b8676e6..d97baaac0eb 100644
--- a/app/src/main/res/values-sv/strings.xml
+++ b/app/src/main/res/values-sv/strings.xml
@@ -52,7 +52,7 @@
Ladda ned
Nästa
Visa \'Nästa\' och \'Liknande\' videor
- Webbadressen stöds inte
+ Webbadressen stöds inte
Standard innehållsspråk
Video & Ljud
Popup-ruta
diff --git a/app/src/main/res/values-ta/strings.xml b/app/src/main/res/values-ta/strings.xml
index 52ef33abe0b..257b39b75dc 100644
--- a/app/src/main/res/values-ta/strings.xml
+++ b/app/src/main/res/values-ta/strings.xml
@@ -119,7 +119,7 @@
"தொலைபேசி அழைப்பு போன்ற குறுக்கீடுகளுக்கு பிறகு தொடரவும் "
\'அடுத்து\' மற்றும் \'ஒப்பான\' காணொளிகலை காண்பி
தேடப்பட்ட வாக்கியத்தை அமைவிடத்தில் சேமிக்கவும்
- ஆதரிக்கப்படாத URL
+ ஆதரிக்கப்படாத URL
இயல்புநிலை தகவல்களின் நாடு
பிழைதிருத்து
உள்ளடக்கம்
diff --git a/app/src/main/res/values-te/strings.xml b/app/src/main/res/values-te/strings.xml
index 1f2fd4ce192..1f344bf2331 100644
--- a/app/src/main/res/values-te/strings.xml
+++ b/app/src/main/res/values-te/strings.xml
@@ -46,7 +46,7 @@
తదుపరి వీడియో
తదుపరి వీడియో మరియు ఇలాంటి వీడియో
చిట్కాను అనుబంధించడానికి హోల్డ్ను చూపు
- Url మద్దతు లేదు
+ Url మద్దతు లేదు
డిఫాల్ట్ భాష
ప్లేయర్
ప్రవర్తన
diff --git a/app/src/main/res/values-th/strings.xml b/app/src/main/res/values-th/strings.xml
index 7910a29c7ba..20999eb9a22 100644
--- a/app/src/main/res/values-th/strings.xml
+++ b/app/src/main/res/values-th/strings.xml
@@ -91,7 +91,7 @@
แสดงวิดีโอ \'ถัดไป\' และ \'ที่คล้ายกัน\'
แสดงเคล็ดลับ \"แตะค้างเพื่อเพิ่ม\"
แสดงเคล็ดลับเมื่อกดปุ่มพื้นหลังหรือป๊อปอัพในหน้ารายละเอียดวิดีโอ
- URL ที่ไม่สนับสนุน
+ URL ที่ไม่สนับสนุน
ประเทศเริ่มต้นของเนื้อหา
บริการ
ภาษาของเนื้อหาเริ่มต้น
diff --git a/app/src/main/res/values-tr/strings.xml b/app/src/main/res/values-tr/strings.xml
index cbfe624f838..3ceebd47157 100644
--- a/app/src/main/res/values-tr/strings.xml
+++ b/app/src/main/res/values-tr/strings.xml
@@ -37,7 +37,7 @@
İndir
Sonraki
\'Sonraki\' ve \'Benzer\' videoları göster
- Desteklenmeyen URL
+ Desteklenmeyen URL
Öntanımlı içerik dili
Ses
Video ve ses
diff --git a/app/src/main/res/values-uk/strings.xml b/app/src/main/res/values-uk/strings.xml
index 594a6e224e4..798821e992e 100644
--- a/app/src/main/res/values-uk/strings.xml
+++ b/app/src/main/res/values-uk/strings.xml
@@ -37,7 +37,7 @@
Завантажити
Наступне
Показувати \"Наступне\" і \"Схожі\" відео
- URL не підтримується
+ URL не підтримується
Переважна мова контенту
Відео та Аудіо
Зовнішній вигляд
diff --git a/app/src/main/res/values-ur/strings.xml b/app/src/main/res/values-ur/strings.xml
index d222022d6a6..9f0989424ee 100644
--- a/app/src/main/res/values-ur/strings.xml
+++ b/app/src/main/res/values-ur/strings.xml
@@ -85,7 +85,7 @@
\'اگلی\' اور \'ملتی جلتی\' ویڈیوز دکھائیں
’’شامل کرنے کے لئے پکڑیں‘‘ اشارہ دکھائیں
ویڈیو تفصیلات کے صفحے پر جب پس منظر یا پاپ اپ بٹن دبائے جانے پر ٹپ دکھائیں
- غیر موافق URL
+ غیر موافق URL
مشمولات کا طے شدہ ملک
خدمت
پلیئر
diff --git a/app/src/main/res/values-vi/strings.xml b/app/src/main/res/values-vi/strings.xml
index a16c93013ee..0e64d2857d4 100644
--- a/app/src/main/res/values-vi/strings.xml
+++ b/app/src/main/res/values-vi/strings.xml
@@ -53,7 +53,7 @@
Tải về
Tiếp theo
Hiển thị video \"Tiếp theo\" và \"Tương tự\"
- URL không được hỗ trợ
+ URL không được hỗ trợ
Hiển thị
Khác
Phát ở chế độ nền
diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml
index 604ad060528..92aea3d64f7 100644
--- a/app/src/main/res/values-zh-rCN/strings.xml
+++ b/app/src/main/res/values-zh-rCN/strings.xml
@@ -29,7 +29,7 @@
黑色
下载
下一个
- 不支持的 URL
+ 不支持的 URL
外观
其他
全部
diff --git a/app/src/main/res/values-zh-rHK/strings.xml b/app/src/main/res/values-zh-rHK/strings.xml
index c0686701235..d9893b8a2a4 100644
--- a/app/src/main/res/values-zh-rHK/strings.xml
+++ b/app/src/main/res/values-zh-rHK/strings.xml
@@ -28,7 +28,7 @@
下載
下一部影片
顯示下一部及相關的影片
- 不支援此網址
+ 不支援此網址
預設內容語言
影片及聲音
外觀
diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml
index b5e4fcbdfa0..4fd15e95ecf 100644
--- a/app/src/main/res/values-zh-rTW/strings.xml
+++ b/app/src/main/res/values-zh-rTW/strings.xml
@@ -32,7 +32,7 @@
下載
下一個
顯示「下一部」與「相關」的影片
- 不支援此網址
+ 不支援此網址
預設內容語言
影片和音訊
外觀
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index f2e79a79b39..1e8a6b049e3 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -106,7 +106,8 @@
Show \'Next\' and \'Similar\' videos
Show \"Hold to append\" tip
Show tip when pressing the background or the popup button in video \"Details:\"
- Unsupported URL
+ Unsupported URL
+ NewPipe could not recognize the provided url. Open it with another method?
Default content country
Service
Default content language
From b2164ce5fcc3111d8cd1f503657524aceaee30c7 Mon Sep 17 00:00:00 2001
From: Avently <7953703+avently@users.noreply.github.com>
Date: Sun, 12 Jul 2020 03:59:47 +0300
Subject: [PATCH 025/398] Marked many (too many) variables as final
---
.../material/appbar/FlingBehavior.java | 6 +-
.../java/org/schabi/newpipe/MainActivity.java | 9 +-
.../newpipe/fragments/detail/StackItem.java | 2 +-
.../fragments/detail/VideoDetailFragment.java | 282 +++++++++---------
.../org/schabi/newpipe/player/BasePlayer.java | 2 +-
.../org/schabi/newpipe/player/MainPlayer.java | 14 +-
.../newpipe/player/ServicePlayerActivity.java | 2 +-
.../newpipe/player/VideoPlayerImpl.java | 121 ++++----
.../event/CustomBottomSheetBehavior.java | 8 +-
.../player/event/PlayerGestureListener.java | 31 +-
.../newpipe/player/playqueue/PlayQueue.java | 17 +-
.../schabi/newpipe/util/NavigationHelper.java | 65 ++--
.../newpipe/views/ExpandableSurfaceView.java | 13 +-
13 files changed, 297 insertions(+), 275 deletions(-)
diff --git a/app/src/main/java/com/google/android/material/appbar/FlingBehavior.java b/app/src/main/java/com/google/android/material/appbar/FlingBehavior.java
index d8c5fd014ec..95137414eef 100644
--- a/app/src/main/java/com/google/android/material/appbar/FlingBehavior.java
+++ b/app/src/main/java/com/google/android/material/appbar/FlingBehavior.java
@@ -23,13 +23,13 @@ public FlingBehavior(Context context, AttributeSet attrs) {
}
private boolean allowScroll = true;
- private Rect globalRect = new Rect();
+ private final Rect globalRect = new Rect();
@Override
public boolean onInterceptTouchEvent(CoordinatorLayout parent, AppBarLayout child, MotionEvent ev) {
- ViewGroup playQueue = child.findViewById(R.id.playQueuePanel);
+ final ViewGroup playQueue = child.findViewById(R.id.playQueuePanel);
if (playQueue != null) {
- boolean visible = playQueue.getGlobalVisibleRect(globalRect);
+ final boolean visible = playQueue.getGlobalVisibleRect(globalRect);
if (visible && globalRect.contains((int) ev.getRawX(), (int) ev.getRawY())) {
allowScroll = false;
return false;
diff --git a/app/src/main/java/org/schabi/newpipe/MainActivity.java b/app/src/main/java/org/schabi/newpipe/MainActivity.java
index f630036619e..2fb5d616a53 100644
--- a/app/src/main/java/org/schabi/newpipe/MainActivity.java
+++ b/app/src/main/java/org/schabi/newpipe/MainActivity.java
@@ -45,7 +45,6 @@
import com.google.android.material.navigation.NavigationView;
import org.schabi.newpipe.extractor.NewPipe;
-import org.schabi.newpipe.extractor.ServiceList;
import org.schabi.newpipe.extractor.StreamingService;
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
import org.schabi.newpipe.extractor.services.peertube.PeertubeInstance;
@@ -453,21 +452,21 @@ protected void onNewIntent(Intent intent) {
public void onBackPressed() {
if (DEBUG) Log.d(TAG, "onBackPressed() called");
- FrameLayout bottomSheetLayout = findViewById(R.id.fragment_player_holder);
- BottomSheetBehavior bottomSheetBehavior = BottomSheetBehavior.from(bottomSheetLayout);
+ final FrameLayout bottomSheetLayout = findViewById(R.id.fragment_player_holder);
+ final BottomSheetBehavior bottomSheetBehavior = BottomSheetBehavior.from(bottomSheetLayout);
final int sheetState = bottomSheetBehavior.getState();
// In case bottomSheet is not visible on the screen or collapsed we can assume that the user interacts with a fragment
// inside fragment_holder so all back presses should be handled by it
if (sheetState == BottomSheetBehavior.STATE_HIDDEN || sheetState == BottomSheetBehavior.STATE_COLLAPSED) {
- Fragment fragment = getSupportFragmentManager().findFragmentById(R.id.fragment_holder);
+ final Fragment fragment = getSupportFragmentManager().findFragmentById(R.id.fragment_holder);
// If current fragment implements BackPressable (i.e. can/wanna handle back press) delegate the back press to it
if (fragment instanceof BackPressable) {
if (((BackPressable) fragment).onBackPressed()) return;
}
} else {
- Fragment fragmentPlayer = getSupportFragmentManager().findFragmentById(R.id.fragment_player_holder);
+ final Fragment fragmentPlayer = getSupportFragmentManager().findFragmentById(R.id.fragment_player_holder);
// If current fragment implements BackPressable (i.e. can/wanna handle back press) delegate the back press to it
if (fragmentPlayer instanceof BackPressable) {
if (!((BackPressable) fragmentPlayer).onBackPressed())
diff --git a/app/src/main/java/org/schabi/newpipe/fragments/detail/StackItem.java b/app/src/main/java/org/schabi/newpipe/fragments/detail/StackItem.java
index 38e41b2fb4b..ca96b5f967d 100644
--- a/app/src/main/java/org/schabi/newpipe/fragments/detail/StackItem.java
+++ b/app/src/main/java/org/schabi/newpipe/fragments/detail/StackItem.java
@@ -10,7 +10,7 @@ class StackItem implements Serializable {
private String url;
private PlayQueue playQueue;
- StackItem(int serviceId, String url, String title, PlayQueue playQueue) {
+ StackItem(final int serviceId, final String url, final String title, final PlayQueue playQueue) {
this.serviceId = serviceId;
this.url = url;
this.title = title;
diff --git a/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java
index 9d6d20c0dd0..060f95b68b7 100644
--- a/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java
+++ b/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java
@@ -73,10 +73,7 @@
import org.schabi.newpipe.views.AnimatedProgressBar;
import java.io.Serializable;
-import java.util.Collection;
-import java.util.Iterator;
-import java.util.LinkedList;
-import java.util.List;
+import java.util.*;
import java.util.concurrent.TimeUnit;
import icepick.State;
@@ -143,7 +140,7 @@ public class VideoDetailFragment
private List sortedVideoStreams;
private int selectedVideoStreamIndex = -1;
- private BottomSheetBehavior bottomSheetBehavior;
+ private BottomSheetBehavior bottomSheetBehavior;
private BroadcastReceiver broadcastReceiver;
/*//////////////////////////////////////////////////////////////////////////
@@ -194,7 +191,7 @@ public class VideoDetailFragment
private ImageButton overlayCloseButton;
private AppBarLayout appBarLayout;
- private ViewPager viewPager;
+ private ViewPager viewPager;
private TabAdaptor pageAdapter;
private TabLayout tabLayout;
private FrameLayout relatedStreamsLayout;
@@ -210,19 +207,19 @@ public class VideoDetailFragment
// Service management
//////////////////////////////////////////////////////////////////////////*/
- private ServiceConnection getServiceConnection(boolean playAfterConnect) {
+ private ServiceConnection getServiceConnection(final boolean playAfterConnect) {
return new ServiceConnection() {
@Override
- public void onServiceDisconnected(ComponentName name) {
+ public void onServiceDisconnected(final ComponentName name) {
if (DEBUG) Log.d(TAG, "Player service is disconnected");
unbind();
}
@Override
- public void onServiceConnected(ComponentName compName, IBinder service) {
+ public void onServiceConnected(final ComponentName compName, final IBinder service) {
if (DEBUG) Log.d(TAG, "Player service is connected");
- MainPlayer.LocalBinder localBinder = (MainPlayer.LocalBinder) service;
+ final MainPlayer.LocalBinder localBinder = (MainPlayer.LocalBinder) service;
playerService = localBinder.getService();
player = localBinder.getPlayer();
@@ -255,18 +252,16 @@ public void onServiceConnected(ComponentName compName, IBinder service) {
private void bind() {
if (DEBUG) Log.d(TAG, "bind() called");
- Intent serviceIntent = new Intent(getContext(), MainPlayer.class);
- final boolean success = getContext().bindService(serviceIntent, serviceConnection, Context.BIND_AUTO_CREATE);
-
- if (!success) getContext().unbindService(serviceConnection);
- bound = success;
+ final Intent serviceIntent = new Intent(getContext(), MainPlayer.class);
+ bound = requireContext().bindService(serviceIntent, serviceConnection, Context.BIND_AUTO_CREATE);
+ if (!bound) requireContext().unbindService(serviceConnection);
}
private void unbind() {
if (DEBUG) Log.d(TAG, "unbind() called");
if (bound) {
- getContext().unbindService(serviceConnection);
+ requireContext().unbindService(serviceConnection);
bound = false;
stopPlayerListener();
playerService = null;
@@ -286,20 +281,20 @@ private void startService(boolean playAfterConnect) {
// startService() can be called concurrently and it will give a random crashes and NullPointerExceptions
// inside the service because the service will be bound twice. Prevent it with unbinding first
unbind();
- getContext().startService(new Intent(getContext(), MainPlayer.class));
+ requireContext().startService(new Intent(getContext(), MainPlayer.class));
serviceConnection = getServiceConnection(playAfterConnect);
bind();
}
private void stopService() {
unbind();
- getContext().stopService(new Intent(getContext(), MainPlayer.class));
+ requireContext().stopService(new Intent(getContext(), MainPlayer.class));
}
/*////////////////////////////////////////////////////////////////////////*/
- public static VideoDetailFragment getInstance(int serviceId, String videoUrl, String name, PlayQueue playQueue) {
+ public static VideoDetailFragment getInstance(final int serviceId, final String videoUrl, final String name, final PlayQueue playQueue) {
VideoDetailFragment instance = new VideoDetailFragment();
instance.setInitialData(serviceId, videoUrl, name, playQueue);
return instance;
@@ -330,8 +325,8 @@ public static VideoDetailFragment getInstance(int serviceId, String videoUrl, St
settingsContentObserver = new ContentObserver(new Handler()) {
@Override
- public void onChange(boolean selfChange) {
- if(activity != null && !PlayerHelper.globalScreenOrientationLocked(activity))
+ public void onChange(final boolean selfChange) {
+ if (activity != null && !PlayerHelper.globalScreenOrientationLocked(activity))
activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
}
};
@@ -402,10 +397,9 @@ public void onDestroy() {
if (positionSubscriber != null) positionSubscriber.dispose();
if (currentWorker != null) currentWorker.dispose();
- if (disposables != null) disposables.clear();
+ disposables.clear();
positionSubscriber = null;
currentWorker = null;
- disposables = null;
bottomSheetBehavior.setBottomSheetCallback(null);
}
@@ -521,10 +515,9 @@ public void onClick(View v) {
case R.id.overlay_play_pause_button:
if (playerIsNotStopped()) {
player.onPlayPause();
- player.hideControls(0,0);
+ player.hideControls(0, 0);
showSystemUi();
- }
- else openVideoPlayer();
+ } else openVideoPlayer();
setOverlayPlayPauseImage();
break;
@@ -754,12 +747,13 @@ public boolean onBackPressed() {
// Remove top
stack.pop();
// Get stack item from the new top
+ assert stack.peek() != null;
setupFromHistoryItem(stack.peek());
return true;
}
- private void setupFromHistoryItem(StackItem item) {
+ private void setupFromHistoryItem(final StackItem item) {
setAutoplay(false);
hideMainPlayer();
@@ -773,9 +767,9 @@ private void setupFromHistoryItem(StackItem item) {
// Maybe an item was deleted in background activity
if (item.getPlayQueue().getItem() == null) return;
- PlayQueueItem playQueueItem = item.getPlayQueue().getItem();
+ final PlayQueueItem playQueueItem = item.getPlayQueue().getItem();
// Update title, url, uploader from the last item in the stack (it's current now)
- boolean isPlayerStopped = player == null || player.isPlayerStopped();
+ final boolean isPlayerStopped = player == null || player.isPlayerStopped();
if (playQueueItem != null && isPlayerStopped)
updateOverlayData(playQueueItem.getTitle(), playQueueItem.getUploader(), playQueueItem.getThumbnailUrl());
}
@@ -792,7 +786,7 @@ protected void doInitialLoadLogic() {
else prepareAndHandleInfo(currentInfo, false);
}
- public void selectAndLoadVideo(int serviceId, String videoUrl, String name, PlayQueue playQueue) {
+ public void selectAndLoadVideo(final int serviceId, final String videoUrl, final String name, final PlayQueue playQueue) {
// Situation when user switches from players to main player. All needed data is here, we can start watching
if (this.playQueue != null && this.playQueue.equals(playQueue)) {
openVideoPlayer();
@@ -802,7 +796,7 @@ public void selectAndLoadVideo(int serviceId, String videoUrl, String name, Play
startLoading(false, true);
}
- public void prepareAndHandleInfo(final StreamInfo info, boolean scrollToTop) {
+ public void prepareAndHandleInfo(final StreamInfo info, final boolean scrollToTop) {
if (DEBUG) Log.d(TAG, "prepareAndHandleInfo() called with: info = ["
+ info + "], scrollToTop = [" + scrollToTop + "]");
@@ -821,7 +815,7 @@ protected void prepareAndLoadInfo() {
}
@Override
- public void startLoading(boolean forceLoad) {
+ public void startLoading(final boolean forceLoad) {
super.startLoading(forceLoad);
initTabs();
@@ -831,7 +825,7 @@ public void startLoading(boolean forceLoad) {
runWorker(forceLoad, stack.isEmpty());
}
- private void startLoading(boolean forceLoad, boolean addToBackStack) {
+ private void startLoading(final boolean forceLoad, final boolean addToBackStack) {
super.startLoading(false);
initTabs();
@@ -841,7 +835,7 @@ private void startLoading(boolean forceLoad, boolean addToBackStack) {
runWorker(forceLoad, addToBackStack);
}
- private void runWorker(boolean forceLoad, boolean addToBackStack) {
+ private void runWorker(final boolean forceLoad, final boolean addToBackStack) {
currentWorker = ExtractorHelper.getStreamInfo(serviceId, url, forceLoad)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
@@ -867,26 +861,26 @@ private void initTabs() {
}
pageAdapter.clearAllItems();
- if(shouldShowComments()){
+ if (shouldShowComments()) {
pageAdapter.addFragment(CommentsFragment.getInstance(serviceId, url, name), COMMENTS_TAB_TAG);
}
- if(showRelatedStreams && null == relatedStreamsLayout){
+ if (showRelatedStreams && null == relatedStreamsLayout) {
//temp empty fragment. will be updated in handleResult
pageAdapter.addFragment(new Fragment(), RELATED_TAB_TAG);
}
- if(pageAdapter.getCount() == 0){
+ if (pageAdapter.getCount() == 0) {
pageAdapter.addFragment(new EmptyFragment(), EMPTY_TAB_TAG);
}
pageAdapter.notifyDataSetUpdate();
- if(pageAdapter.getCount() < 2){
+ if (pageAdapter.getCount() < 2) {
tabLayout.setVisibility(View.GONE);
- }else{
- int position = pageAdapter.getItemPositionByTitle(selectedTabTag);
- if(position != -1) viewPager.setCurrentItem(position);
+ } else {
+ final int position = pageAdapter.getItemPositionByTitle(selectedTabTag);
+ if (position != -1) viewPager.setCurrentItem(position);
tabLayout.setVisibility(View.VISIBLE);
}
}
@@ -911,10 +905,10 @@ public void scrollToTop() {
//////////////////////////////////////////////////////////////////////////*/
private void openBackgroundPlayer(final boolean append) {
- AudioStream audioStream = currentInfo.getAudioStreams()
+ final AudioStream audioStream = currentInfo.getAudioStreams()
.get(ListHelper.getDefaultAudioFormat(activity, currentInfo.getAudioStreams()));
- boolean useExternalAudioPlayer = PreferenceManager.getDefaultSharedPreferences(activity)
+ final boolean useExternalAudioPlayer = PreferenceManager.getDefaultSharedPreferences(activity)
.getBoolean(activity.getString(R.string.use_external_audio_player_key), false);
// If a user watched video inside fullscreen mode and than chose another player return to non-fullscreen mode
@@ -939,7 +933,7 @@ private void openPopupPlayer(final boolean append) {
// If a user watched video inside fullscreen mode and than chose another player return to non-fullscreen mode
if (player != null && player.isFullscreen()) player.toggleFullscreen();
- PlayQueue queue = setupPlayQueueForIntent(append);
+ final PlayQueue queue = setupPlayQueueForIntent(append);
if (append) {
NavigationHelper.enqueueOnPopupPlayer(activity, queue, false);
} else {
@@ -950,7 +944,8 @@ private void openPopupPlayer(final boolean append) {
private void openVideoPlayer() {
if (PreferenceManager.getDefaultSharedPreferences(activity)
.getBoolean(this.getString(R.string.use_external_video_player_key), false)) {
- VideoStream selectedVideoStream = getSelectedVideoStream();
+ final VideoStream selectedVideoStream = getSelectedVideoStream();
+ if (selectedVideoStream == null) return;
startOnExternalPlayer(activity, currentInfo, selectedVideoStream);
} else {
replaceQueueIfUserConfirms(this::openMainPlayer);
@@ -961,7 +956,7 @@ private void openNormalBackgroundPlayer(final boolean append) {
// See UI changes while remote playQueue changes
if (!bound) startService(false);
- PlayQueue queue = setupPlayQueueForIntent(append);
+ final PlayQueue queue = setupPlayQueueForIntent(append);
if (append) {
NavigationHelper.enqueueOnBackgroundPlayer(activity, queue, false);
} else {
@@ -971,18 +966,18 @@ private void openNormalBackgroundPlayer(final boolean append) {
private void openMainPlayer() {
if (playerService == null) {
- startService(true);
- return;
+ startService(true);
+ return;
}
if (currentInfo == null) return;
- PlayQueue queue = setupPlayQueueForIntent(false);
+ final PlayQueue queue = setupPlayQueueForIntent(false);
// Video view can have elements visible from popup, We hide it here but once it ready the view will be shown in handleIntent()
- playerService.getView().setVisibility(View.GONE);
+ Objects.requireNonNull(playerService.getView()).setVisibility(View.GONE);
addVideoPlayerView();
- Intent playerIntent = NavigationHelper.getPlayerIntent(getContext(), MainPlayer.class, queue, null, true);
+ final Intent playerIntent = NavigationHelper.getPlayerIntent(requireContext(), MainPlayer.class, queue, null, true);
activity.startService(playerIntent);
}
@@ -995,7 +990,7 @@ private void hideMainPlayer() {
playerService.getView().setVisibility(View.GONE);
}
- private PlayQueue setupPlayQueueForIntent(boolean append) {
+ private PlayQueue setupPlayQueueForIntent(final boolean append) {
if (append) return new SinglePlayQueue(currentInfo);
PlayQueue queue = playQueue;
@@ -1026,7 +1021,7 @@ private void openChannel() {
// Utils
//////////////////////////////////////////////////////////////////////////*/
- public void setAutoplay(boolean autoplay) {
+ public void setAutoplay(final boolean autoplay) {
this.autoPlayEnabled = autoplay;
}
@@ -1059,7 +1054,7 @@ private boolean isAutoplayEnabled() {
&& isAutoplayAllowedByUser();
}
- private boolean isAutoplayAllowedByUser () {
+ private boolean isAutoplayAllowedByUser() {
if (activity == null) return false;
switch (PlayerHelper.getAutoplayType(activity)) {
@@ -1076,7 +1071,7 @@ private boolean isAutoplayAllowedByUser () {
private void addVideoPlayerView() {
if (player == null || getView() == null) return;
- FrameLayout viewHolder = getView().findViewById(R.id.player_placeholder);
+ final FrameLayout viewHolder = getView().findViewById(R.id.player_placeholder);
// Check if viewHolder already contains a child
if (player.getRootView().getParent() != viewHolder) removeVideoPlayerView();
@@ -1095,7 +1090,7 @@ private void removeVideoPlayerView() {
private void makeDefaultHeightForVideoPlaceholder() {
if (getView() == null) return;
- FrameLayout viewHolder = getView().findViewById(R.id.player_placeholder);
+ final FrameLayout viewHolder = getView().findViewById(R.id.player_placeholder);
viewHolder.getLayoutParams().height = FrameLayout.LayoutParams.MATCH_PARENT;
viewHolder.requestLayout();
}
@@ -1113,7 +1108,7 @@ private void prepareDescription(final String descriptionHtml) {
disposables.add(Single.just(descriptionHtml)
.map((@io.reactivex.annotations.NonNull String description) -> {
- Spanned parsedDescription;
+ final Spanned parsedDescription;
if (Build.VERSION.SDK_INT >= 24) {
parsedDescription = Html.fromHtml(description, 0);
} else {
@@ -1137,11 +1132,11 @@ private void prepareDescription(final String descriptionHtml) {
*/
private void setHeightThumbnail() {
final DisplayMetrics metrics = getResources().getDisplayMetrics();
- boolean isPortrait = metrics.heightPixels > metrics.widthPixels;
+ final boolean isPortrait = metrics.heightPixels > metrics.widthPixels;
- int height;
+ final int height;
if (player != null && player.isFullscreen())
- height = isInMultiWindow() ? getView().getHeight() : activity.getWindow().getDecorView().getHeight();
+ height = isInMultiWindow() ? Objects.requireNonNull(getView()).getHeight() : activity.getWindow().getDecorView().getHeight();
else
height = isPortrait
? (int) (metrics.widthPixels / (16.0f / 9.0f))
@@ -1150,7 +1145,7 @@ private void setHeightThumbnail() {
thumbnailImageView.setLayoutParams(new FrameLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, height));
thumbnailImageView.setMinimumHeight(height);
if (player != null) {
- int maxHeight = (int) (metrics.heightPixels * MAX_PLAYER_HEIGHT);
+ final int maxHeight = (int) (metrics.heightPixels * MAX_PLAYER_HEIGHT);
player.getSurfaceView().setHeights(height, player.isFullscreen() ? height : maxHeight);
}
}
@@ -1159,7 +1154,7 @@ private void showContent() {
contentRootLayoutHiding.setVisibility(View.VISIBLE);
}
- protected void setInitialData(int serviceId, String url, String name, PlayQueue playQueue) {
+ protected void setInitialData(final int serviceId, final String url, final String name, final PlayQueue playQueue) {
this.serviceId = serviceId;
this.url = url;
this.name = !TextUtils.isEmpty(name) ? name : "";
@@ -1188,9 +1183,9 @@ private void setupBroadcastReceiver() {
broadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
- if(intent.getAction().equals(ACTION_SHOW_MAIN_PLAYER)) {
+ if (intent.getAction().equals(ACTION_SHOW_MAIN_PLAYER)) {
bottomSheetBehavior.setState(BottomSheetBehavior.STATE_EXPANDED);
- } else if(intent.getAction().equals(ACTION_HIDE_MAIN_PLAYER)) {
+ } else if (intent.getAction().equals(ACTION_HIDE_MAIN_PLAYER)) {
bottomSheetBehavior.setState(BottomSheetBehavior.STATE_HIDDEN);
}
}
@@ -1227,7 +1222,7 @@ public void showLoading() {
super.showLoading();
//if data is already cached, transition from VISIBLE -> INVISIBLE -> VISIBLE is not required
- if(!ExtractorHelper.isCached(serviceId, url, InfoItem.InfoType.STREAM)){
+ if (!ExtractorHelper.isCached(serviceId, url, InfoItem.InfoType.STREAM)) {
contentRootLayoutHiding.setVisibility(View.INVISIBLE);
}
@@ -1245,10 +1240,10 @@ public void showLoading() {
videoTitleToggleArrow.setVisibility(View.GONE);
videoTitleRoot.setClickable(false);
- if(relatedStreamsLayout != null){
- if(showRelatedStreams){
+ if (relatedStreamsLayout != null) {
+ if (showRelatedStreams) {
relatedStreamsLayout.setVisibility(player != null && player.isFullscreen() ? View.GONE : View.INVISIBLE);
- }else{
+ } else {
relatedStreamsLayout.setVisibility(View.GONE);
}
}
@@ -1266,11 +1261,11 @@ public void handleResult(@NonNull StreamInfo info) {
currentInfo = info;
setInitialData(info.getServiceId(), info.getOriginalUrl(), info.getName(), playQueue);
- if(showRelatedStreams){
- if(null == relatedStreamsLayout){ //phone
+ if (showRelatedStreams) {
+ if (null == relatedStreamsLayout) { //phone
pageAdapter.updateItem(RELATED_TAB_TAG, RelatedVideosFragment.getInstance(info));
pageAdapter.notifyDataSetUpdate();
- }else{ //tablet
+ } else { //tablet
getChildFragmentManager().beginTransaction()
.replace(R.id.relatedStreamsLayout, RelatedVideosFragment.getInstance(info))
.commitNow();
@@ -1359,6 +1354,12 @@ public void handleResult(@NonNull StreamInfo info) {
videoUploadDateView.setVisibility(View.GONE);
}
+ sortedVideoStreams = ListHelper.getSortedStreamVideosList(
+ activity,
+ info.getVideoStreams(),
+ info.getVideoOnlyStreams(),
+ false);
+ selectedVideoStreamIndex = ListHelper.getDefaultResolutionIndex(activity, sortedVideoStreams);
prepareDescription(info.getDescription());
updateProgressInfo(info);
initThumbnailViews(info);
@@ -1381,7 +1382,7 @@ public void handleResult(@NonNull StreamInfo info) {
detailControlsDownload.setVisibility(View.GONE);
break;
default:
- if(info.getAudioStreams().isEmpty()) detailControlsBackground.setVisibility(View.GONE);
+ if (info.getAudioStreams().isEmpty()) detailControlsBackground.setVisibility(View.GONE);
if (!info.getVideoStreams().isEmpty()
|| !info.getVideoOnlyStreams().isEmpty()) break;
@@ -1393,28 +1394,28 @@ public void handleResult(@NonNull StreamInfo info) {
public void openDownloadDialog() {
- try {
- DownloadDialog downloadDialog = DownloadDialog.newInstance(currentInfo);
- downloadDialog.setVideoStreams(sortedVideoStreams);
- downloadDialog.setAudioStreams(currentInfo.getAudioStreams());
- downloadDialog.setSelectedVideoStream(selectedVideoStreamIndex);
- downloadDialog.setSubtitleStreams(currentInfo.getSubtitles());
-
- downloadDialog.show(activity.getSupportFragmentManager(), "downloadDialog");
- } catch (Exception e) {
- ErrorActivity.ErrorInfo info = ErrorActivity.ErrorInfo.make(UserAction.UI_ERROR,
- ServiceList.all()
- .get(currentInfo
- .getServiceId())
- .getServiceInfo()
- .getName(), "",
- R.string.could_not_setup_download_menu);
-
- ErrorActivity.reportError(activity,
- e,
- activity.getClass(),
- activity.findViewById(android.R.id.content), info);
- }
+ try {
+ final DownloadDialog downloadDialog = DownloadDialog.newInstance(currentInfo);
+ downloadDialog.setVideoStreams(sortedVideoStreams);
+ downloadDialog.setAudioStreams(currentInfo.getAudioStreams());
+ downloadDialog.setSelectedVideoStream(selectedVideoStreamIndex);
+ downloadDialog.setSubtitleStreams(currentInfo.getSubtitles());
+
+ downloadDialog.show(activity.getSupportFragmentManager(), "downloadDialog");
+ } catch (Exception e) {
+ final ErrorActivity.ErrorInfo info = ErrorActivity.ErrorInfo.make(UserAction.UI_ERROR,
+ ServiceList.all()
+ .get(currentInfo
+ .getServiceId())
+ .getServiceInfo()
+ .getName(), "",
+ R.string.could_not_setup_download_menu);
+
+ ErrorActivity.reportError(activity,
+ e,
+ activity.getClass(),
+ activity.findViewById(android.R.id.content), info);
+ }
}
/*//////////////////////////////////////////////////////////////////////////
@@ -1428,7 +1429,7 @@ protected boolean onError(Throwable exception) {
else if (exception instanceof ContentNotAvailableException) {
showError(getString(R.string.content_not_available), false);
} else {
- int errorId = exception instanceof YoutubeStreamExtractor.DecryptException
+ final int errorId = exception instanceof YoutubeStreamExtractor.DecryptException
? R.string.youtube_signature_decryption_error
: exception instanceof ParsingException
? R.string.parsing_error
@@ -1484,7 +1485,7 @@ private void updateProgressInfo(@NonNull final StreamInfo info) {
});
}
- private void showPlaybackProgress(long progress, long duration) {
+ private void showPlaybackProgress(final long progress, final long duration) {
final int progressSeconds = (int) TimeUnit.MILLISECONDS.toSeconds(progress);
final int durationSeconds = (int) TimeUnit.MILLISECONDS.toSeconds(duration);
positionView.setMax(durationSeconds);
@@ -1501,9 +1502,9 @@ private void showPlaybackProgress(long progress, long duration) {
//////////////////////////////////////////////////////////////////////////*/
@Override
- public void onQueueUpdate(PlayQueue queue) {
+ public void onQueueUpdate(final PlayQueue queue) {
playQueue = queue;
- StackItem stackWithQueue;
+ final StackItem stackWithQueue;
// This should be the only place where we push data to stack. It will allow to have live instance of PlayQueue with actual
// information about deleted/added items inside Channel/Playlist queue and makes possible to have a history of played items
if (stack.isEmpty() || !stack.peek().getPlayQueue().equals(queue)) {
@@ -1522,7 +1523,7 @@ public void onQueueUpdate(PlayQueue queue) {
}
@Override
- public void onPlaybackUpdate(int state, int repeatMode, boolean shuffled, PlaybackParameters parameters) {
+ public void onPlaybackUpdate(final int state, final int repeatMode, final boolean shuffled, final PlaybackParameters parameters) {
setOverlayPlayPauseImage();
switch (state) {
@@ -1542,7 +1543,7 @@ public void onPlaybackUpdate(int state, int repeatMode, boolean shuffled, Playba
}
@Override
- public void onProgressUpdate(int currentProgress, int duration, int bufferPercent) {
+ public void onProgressUpdate(final int currentProgress, final int duration, final int bufferPercent) {
// Progress updates every second even if media is paused. It's useless until playing
if (!player.getPlayer().isPlaying() || playQueue == null) return;
@@ -1551,8 +1552,8 @@ public void onProgressUpdate(int currentProgress, int duration, int bufferPercen
}
@Override
- public void onMetadataUpdate(StreamInfo info, PlayQueue queue) {
- StackItem item = findQueueInStack(queue);
+ public void onMetadataUpdate(final StreamInfo info, final PlayQueue queue) {
+ final StackItem item = findQueueInStack(queue);
if (item != null) {
// When PlayQueue can have multiple streams (PlaylistPlayQueue or ChannelPlayQueue) every new played stream gives
// new title and url. StackItem contains information about first played stream. Let's update it here
@@ -1567,13 +1568,13 @@ public void onMetadataUpdate(StreamInfo info, PlayQueue queue) {
if (currentInfo != null && info.getUrl().equals(currentInfo.getUrl())) return;
currentInfo = info;
- setInitialData(info.getServiceId(), info.getUrl(),info.getName(), queue);
+ setInitialData(info.getServiceId(), info.getUrl(), info.getName(), queue);
setAutoplay(false);
prepareAndHandleInfo(info, true);
}
@Override
- public void onPlayerError(ExoPlaybackException error) {
+ public void onPlayerError(final ExoPlaybackException error) {
if (error.type == ExoPlaybackException.TYPE_SOURCE || error.type == ExoPlaybackException.TYPE_UNEXPECTED) {
hideMainPlayer();
if (playerService != null && player.isFullscreen())
@@ -1590,12 +1591,12 @@ public void onServiceStopped() {
}
@Override
- public void onFullscreenStateChanged(boolean fullscreen) {
+ public void onFullscreenStateChanged(final boolean fullscreen) {
if (playerService.getView() == null || player.getParentActivity() == null)
return;
- View view = playerService.getView();
- ViewGroup parent = (ViewGroup) view.getParent();
+ final View view = playerService.getView();
+ final ViewGroup parent = (ViewGroup) view.getParent();
if (parent == null) return;
if (fullscreen) {
@@ -1619,7 +1620,7 @@ public void onScreenRotationButtonClicked() {
return;
}
- int newOrientation = isLandscape() ?
+ final int newOrientation = isLandscape() ?
ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED
: ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE;
@@ -1627,13 +1628,13 @@ public void onScreenRotationButtonClicked() {
}
/*
- * Will scroll down to description view after long click on moreOptionsButton
- * */
+ * Will scroll down to description view after long click on moreOptionsButton
+ * */
@Override
public void onMoreOptionsLongClicked() {
- CoordinatorLayout.LayoutParams params = (CoordinatorLayout.LayoutParams) appBarLayout.getLayoutParams();
- AppBarLayout.Behavior behavior = (AppBarLayout.Behavior) params.getBehavior();
- ValueAnimator valueAnimator = ValueAnimator.ofInt(0, -getView().findViewById(R.id.player_placeholder).getHeight());
+ final CoordinatorLayout.LayoutParams params = (CoordinatorLayout.LayoutParams) appBarLayout.getLayoutParams();
+ final AppBarLayout.Behavior behavior = (AppBarLayout.Behavior) params.getBehavior();
+ final ValueAnimator valueAnimator = ValueAnimator.ofInt(0, -getView().findViewById(R.id.player_placeholder).getHeight());
valueAnimator.setInterpolator(new DecelerateInterpolator());
valueAnimator.addUpdateListener(animation -> {
behavior.setTopAndBottomOffset((int) animation.getAnimatedValue());
@@ -1662,7 +1663,7 @@ private void hideSystemUi() {
if (activity == null) return;
- 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_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_FULLSCREEN
@@ -1683,12 +1684,10 @@ private boolean playerIsNotStopped() {
return player != null && player.getPlayer() != null && player.getPlayer().getPlaybackState() != Player.STATE_IDLE;
}
- private void setupBrightness(boolean save) {
+ private void setupBrightness(final boolean save) {
if (activity == null) return;
- WindowManager.LayoutParams lp = activity.getWindow().getAttributes();
- float brightnessLevel;
-
+ final WindowManager.LayoutParams lp = activity.getWindow().getAttributes();
if (save) {
// Save current brightness level
PlayerHelper.setScreenBrightness(activity, lp.screenBrightness);
@@ -1698,7 +1697,7 @@ private void setupBrightness(boolean save) {
lp.screenBrightness = -1;
} else {
// Restore already saved brightness level
- brightnessLevel = PlayerHelper.getScreenBrightness(activity);
+ final float brightnessLevel = PlayerHelper.getScreenBrightness(activity);
if (brightnessLevel <= 0.0f && brightnessLevel > 1.0f)
return;
@@ -1712,7 +1711,7 @@ private void checkLandscape() {
setAutoplay(true);
player.checkLandscape();
- boolean orientationLocked = PlayerHelper.globalScreenOrientationLocked(activity);
+ 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()) {
player.onPlay();
@@ -1729,17 +1728,17 @@ private boolean isInMultiWindow() {
}
/*
- * Means that the player fragment was swiped away via BottomSheetLayout and is empty but ready for any new actions. See cleanUp()
- * */
+ * Means that the player fragment was swiped away via BottomSheetLayout and is empty but ready for any new actions. See cleanUp()
+ * */
private boolean wasCleared() {
return url == null;
}
- private StackItem findQueueInStack(PlayQueue queue) {
+ private StackItem findQueueInStack(final PlayQueue queue) {
StackItem item = null;
- Iterator iterator = stack.descendingIterator();
+ final Iterator iterator = stack.descendingIterator();
while (iterator.hasNext()) {
- StackItem next = iterator.next();
+ final StackItem next = iterator.next();
if (next.getPlayQueue().equals(queue)) {
item = next;
break;
@@ -1763,7 +1762,7 @@ && playerIsNotStopped()
}
}
- private void showClearingQueueConfirmation(Runnable onAllow) {
+ private void showClearingQueueConfirmation(final Runnable onAllow) {
new AlertDialog.Builder(activity)
.setTitle(R.string.confirm_prompt)
.setMessage(R.string.clear_queue_confirmation_description)
@@ -1775,14 +1774,14 @@ private void showClearingQueueConfirmation(Runnable onAllow) {
}
/*
- * Remove unneeded information while waiting for a next task
- * */
+ * Remove unneeded information while waiting for a next task
+ * */
private void cleanUp() {
// New beginning
stack.clear();
if (currentWorker != null) currentWorker.dispose();
stopService();
- setInitialData(0,null,"", null);
+ setInitialData(0, null, "", null);
currentInfo = null;
updateOverlayData(null, null, null);
}
@@ -1792,10 +1791,10 @@ private void cleanUp() {
//////////////////////////////////////////////////////////////////////////*/
private void setupBottomPlayer() {
- CoordinatorLayout.LayoutParams params = (CoordinatorLayout.LayoutParams) appBarLayout.getLayoutParams();
- AppBarLayout.Behavior behavior = (AppBarLayout.Behavior) params.getBehavior();
+ final CoordinatorLayout.LayoutParams params = (CoordinatorLayout.LayoutParams) appBarLayout.getLayoutParams();
+ final AppBarLayout.Behavior behavior = (AppBarLayout.Behavior) params.getBehavior();
- FrameLayout bottomSheetLayout = activity.findViewById(R.id.fragment_player_holder);
+ final FrameLayout bottomSheetLayout = activity.findViewById(R.id.fragment_player_holder);
bottomSheetBehavior = BottomSheetBehavior.from(bottomSheetLayout);
bottomSheetBehavior.setState(bottomSheetState);
final int peekHeight = getResources().getDimensionPixelSize(R.dimen.mini_player_height);
@@ -1810,7 +1809,8 @@ private void setupBottomPlayer() {
}
bottomSheetBehavior.setBottomSheetCallback(new BottomSheetBehavior.BottomSheetCallback() {
- @Override public void onStateChanged(@NonNull View bottomSheet, int newState) {
+ @Override
+ public void onStateChanged(@NonNull final View bottomSheet, final int newState) {
bottomSheetState = newState;
switch (newState) {
@@ -1843,7 +1843,9 @@ private void setupBottomPlayer() {
break;
}
}
- @Override public void onSlide(@NonNull View bottomSheet, float slideOffset) {
+
+ @Override
+ public void onSlide(@NonNull final View bottomSheet, final float slideOffset) {
setOverlayLook(appBarLayout, behavior, slideOffset);
}
});
@@ -1855,31 +1857,31 @@ private void setupBottomPlayer() {
});
}
- private void updateOverlayData(@Nullable String title, @Nullable String uploader, @Nullable String thumbnailUrl) {
+ private void updateOverlayData(@Nullable final String title, @Nullable final String uploader, @Nullable final String thumbnailUrl) {
overlayTitleTextView.setText(TextUtils.isEmpty(title) ? "" : title);
overlayChannelTextView.setText(TextUtils.isEmpty(uploader) ? "" : uploader);
overlayThumbnailImageView.setImageResource(R.drawable.dummy_thumbnail_dark);
if (!TextUtils.isEmpty(thumbnailUrl))
imageLoader.displayImage(thumbnailUrl, overlayThumbnailImageView,
- ImageDisplayConstants.DISPLAY_THUMBNAIL_OPTIONS, null);
+ ImageDisplayConstants.DISPLAY_THUMBNAIL_OPTIONS, null);
}
private void setOverlayPlayPauseImage() {
- int attr = player != null && player.getPlayer().getPlayWhenReady() ? R.attr.pause : R.attr.play;
+ final int attr = player != null && player.getPlayer().getPlayWhenReady() ? R.attr.pause : R.attr.play;
overlayPlayPauseButton.setImageResource(ThemeHelper.resolveResourceIdFromAttr(activity, attr));
}
- private void setOverlayLook(AppBarLayout appBarLayout, AppBarLayout.Behavior behavior, float slideOffset) {
+ private void setOverlayLook(final AppBarLayout appBarLayout, final AppBarLayout.Behavior behavior, final float slideOffset) {
if (behavior != null) {
overlay.setAlpha(Math.min(MAX_OVERLAY_ALPHA, 1 - slideOffset));
// These numbers are not special. They just do a cool transition
- behavior.setTopAndBottomOffset((int)(-thumbnailImageView.getHeight() * 2 * (1 - slideOffset) / 3));
+ behavior.setTopAndBottomOffset((int) (-thumbnailImageView.getHeight() * 2 * (1 - slideOffset) / 3));
appBarLayout.requestLayout();
}
}
- private void setOverlayElementsClickable(boolean enable) {
+ private void setOverlayElementsClickable(final boolean enable) {
overlayThumbnailImageView.setClickable(enable);
overlayThumbnailImageView.setLongClickable(enable);
overlayMetadata.setClickable(enable);
diff --git a/app/src/main/java/org/schabi/newpipe/player/BasePlayer.java b/app/src/main/java/org/schabi/newpipe/player/BasePlayer.java
index c3165447382..634ce777930 100644
--- a/app/src/main/java/org/schabi/newpipe/player/BasePlayer.java
+++ b/app/src/main/java/org/schabi/newpipe/player/BasePlayer.java
@@ -274,7 +274,7 @@ public void handleIntent(Intent intent) {
return;
}
- boolean samePlayQueue = playQueue != null && playQueue.equals(queue);
+ final boolean samePlayQueue = playQueue != null && playQueue.equals(queue);
final int repeatMode = intent.getIntExtra(REPEAT_MODE, getRepeatMode());
final float playbackSpeed = intent.getFloatExtra(PLAYBACK_SPEED, getPlaybackSpeed());
diff --git a/app/src/main/java/org/schabi/newpipe/player/MainPlayer.java b/app/src/main/java/org/schabi/newpipe/player/MainPlayer.java
index f1f9b51daa1..5bfa4732ec7 100644
--- a/app/src/main/java/org/schabi/newpipe/player/MainPlayer.java
+++ b/app/src/main/java/org/schabi/newpipe/player/MainPlayer.java
@@ -102,7 +102,7 @@ public void onCreate() {
}
private void createView() {
- View layout = View.inflate(this, R.layout.activity_main_player, null);
+ final View layout = View.inflate(this, R.layout.activity_main_player, null);
playerImpl = new VideoPlayerImpl(this);
playerImpl.setup(layout);
@@ -124,7 +124,7 @@ public int onStartCommand(Intent intent, int flags, int startId) {
return START_NOT_STICKY;
}
- public void stop(boolean autoplayEnabled) {
+ public void stop(final boolean autoplayEnabled) {
if (DEBUG) Log.d(TAG, "stop() called");
if (playerImpl.getPlayer() != null) {
@@ -212,7 +212,7 @@ public void removeViewFromParent() {
if (getView().getParent() != null) {
if (playerImpl.getParentActivity() != null) {
// This means view was added to fragment
- ViewGroup parent = (ViewGroup) getView().getParent();
+ final ViewGroup parent = (ViewGroup) getView().getParent();
parent.removeView(getView());
} else
// This means view was added by windowManager for popup player
@@ -244,7 +244,7 @@ private NotificationCompat.Builder createNotification() {
setupNotification(notRemoteView);
setupNotification(bigNotRemoteView);
- NotificationCompat.Builder builder = new NotificationCompat.Builder(this, getString(R.string.notification_channel_id))
+ final NotificationCompat.Builder builder = new NotificationCompat.Builder(this, getString(R.string.notification_channel_id))
.setOngoing(true)
.setSmallIcon(R.drawable.ic_newpipe_triangle_white)
.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
@@ -254,7 +254,7 @@ private NotificationCompat.Builder createNotification() {
return builder;
}
- private void setupNotification(RemoteViews remoteViews) {
+ private void setupNotification(final RemoteViews remoteViews) {
// Don't show anything until player is playing
if (playerImpl == null) return;
@@ -298,7 +298,7 @@ private void setupNotification(RemoteViews remoteViews) {
*
* @param drawableId if != -1, sets the drawable with that id on the play/pause button
*/
- synchronized void updateNotification(int drawableId) {
+ synchronized void updateNotification(final int drawableId) {
//if (DEBUG) Log.d(TAG, "updateNotification() called with: drawableId = [" + drawableId + "]");
if (notBuilder == null) return;
if (drawableId != -1) {
@@ -329,7 +329,7 @@ private void setRepeatModeIcon(final RemoteViews remoteViews, final int repeatMo
}
private Intent getIntentForNotification() {
- Intent intent;
+ final Intent intent;
if (playerImpl.audioPlayerSelected() || playerImpl.popupPlayerSelected()) {
// Means we play in popup or audio only. Let's show BackgroundPlayerActivity
intent = NavigationHelper.getBackgroundPlayerActivityIntent(getApplicationContext());
diff --git a/app/src/main/java/org/schabi/newpipe/player/ServicePlayerActivity.java b/app/src/main/java/org/schabi/newpipe/player/ServicePlayerActivity.java
index 619200727d2..9b5838a401c 100644
--- a/app/src/main/java/org/schabi/newpipe/player/ServicePlayerActivity.java
+++ b/app/src/main/java/org/schabi/newpipe/player/ServicePlayerActivity.java
@@ -186,7 +186,7 @@ protected void onDestroy() {
}
Intent getSwitchIntent(final Class clazz, final MainPlayer.PlayerType playerType) {
- Intent intent = NavigationHelper.getPlayerIntent(
+ final Intent intent = NavigationHelper.getPlayerIntent(
getApplicationContext(),
clazz,
this.player.getPlayQueue(),
diff --git a/app/src/main/java/org/schabi/newpipe/player/VideoPlayerImpl.java b/app/src/main/java/org/schabi/newpipe/player/VideoPlayerImpl.java
index aad20b0adc6..6c184376366 100644
--- a/app/src/main/java/org/schabi/newpipe/player/VideoPlayerImpl.java
+++ b/app/src/main/java/org/schabi/newpipe/player/VideoPlayerImpl.java
@@ -97,7 +97,7 @@ public class VideoPlayerImpl extends VideoPlayer
View.OnLongClickListener {
private static final String TAG = ".VideoPlayerImpl";
- private final float MAX_GESTURE_LENGTH = 0.75f;
+ private static final float MAX_GESTURE_LENGTH = 0.75f;
private TextView titleTextView;
private TextView channelTextView;
@@ -142,11 +142,11 @@ public class VideoPlayerImpl extends VideoPlayer
private boolean isVerticalVideo = false;
boolean shouldUpdateOnProgress;
- private MainPlayer service;
+ private final MainPlayer service;
private PlayerServiceEventListener fragmentListener;
private PlayerEventListener activityListener;
private GestureDetector gestureDetector;
- private SharedPreferences defaultPreferences;
+ private final SharedPreferences defaultPreferences;
private ContentObserver settingsContentObserver;
@NonNull
final private AudioPlaybackResolver resolver;
@@ -184,7 +184,7 @@ public class VideoPlayerImpl extends VideoPlayer
public void handleIntent(Intent intent) {
if (intent.getStringExtra(VideoPlayer.PLAY_QUEUE_KEY) == null) return;
- MainPlayer.PlayerType oldPlayerType = playerType;
+ final MainPlayer.PlayerType oldPlayerType = playerType;
choosePlayerTypeFromIntent(intent);
audioOnly = audioPlayerSelected();
@@ -350,8 +350,8 @@ private void setupElementsVisibility() {
*/
private void setupElementsSize() {
if (popupPlayerSelected()) {
- int controlsPadding = service.getResources().getDimensionPixelSize(R.dimen.player_popup_controls_padding);
- int buttonsPadding = service.getResources().getDimensionPixelSize(R.dimen.player_popup_buttons_padding);
+ final int controlsPadding = service.getResources().getDimensionPixelSize(R.dimen.player_popup_controls_padding);
+ final int buttonsPadding = service.getResources().getDimensionPixelSize(R.dimen.player_popup_buttons_padding);
getTopControlsRoot().setPaddingRelative(controlsPadding, 0, controlsPadding, 0);
getBottomControlsRoot().setPaddingRelative(controlsPadding, 0, controlsPadding, 0);
getQualityTextView().setPadding(buttonsPadding, buttonsPadding, buttonsPadding, buttonsPadding);
@@ -361,10 +361,10 @@ private void setupElementsSize() {
getQualityTextView().setMinimumWidth(0);
getPlaybackSpeedTextView().setMinimumWidth(0);
} else if (videoPlayerSelected()) {
- int buttonsMinWidth = service.getResources().getDimensionPixelSize(R.dimen.player_main_buttons_min_width);
- int playerTopPadding = service.getResources().getDimensionPixelSize(R.dimen.player_main_top_padding);
- int controlsPadding = service.getResources().getDimensionPixelSize(R.dimen.player_main_controls_padding);
- int buttonsPadding = service.getResources().getDimensionPixelSize(R.dimen.player_main_buttons_padding);
+ final int buttonsMinWidth = service.getResources().getDimensionPixelSize(R.dimen.player_main_buttons_min_width);
+ final int playerTopPadding = service.getResources().getDimensionPixelSize(R.dimen.player_main_top_padding);
+ final int controlsPadding = service.getResources().getDimensionPixelSize(R.dimen.player_main_controls_padding);
+ final int buttonsPadding = service.getResources().getDimensionPixelSize(R.dimen.player_main_buttons_padding);
getTopControlsRoot().setPaddingRelative(controlsPadding, playerTopPadding, controlsPadding, 0);
getBottomControlsRoot().setPaddingRelative(controlsPadding, 0, controlsPadding, 0);
getQualityTextView().setPadding(buttonsPadding, buttonsPadding, buttonsPadding, buttonsPadding);
@@ -379,7 +379,7 @@ private void setupElementsSize() {
public void initListeners() {
super.initListeners();
- PlayerGestureListener listener = new PlayerGestureListener(this, service);
+ final PlayerGestureListener listener = new PlayerGestureListener(this, service);
gestureDetector = new GestureDetector(context, listener);
getRootView().setOnTouchListener(listener);
@@ -415,7 +415,7 @@ public AppCompatActivity getParentActivity() {
if (getRootView() == null || getRootView().getParent() == null || !(getRootView().getParent() instanceof ViewGroup))
return null;
- ViewGroup parent = (ViewGroup) getRootView().getParent();
+ final ViewGroup parent = (ViewGroup) getRootView().getParent();
return (AppCompatActivity) parent.getContext();
}
@@ -509,7 +509,7 @@ public void onPlaybackShutdown() {
}
@Override
- public void onUpdateProgress(int currentProgress, int duration, int bufferPercent) {
+ public void onUpdateProgress(final int currentProgress, final int duration, final int bufferPercent) {
super.onUpdateProgress(currentProgress, duration, bufferPercent);
updateProgress(currentProgress, duration, bufferPercent);
@@ -560,7 +560,8 @@ public void onPlayNext() {
}
@Override
- protected void initPlayback(@NonNull PlayQueue queue, int repeatMode, float playbackSpeed, float playbackPitch, boolean playbackSkipSilence, boolean playOnReady) {
+ protected void initPlayback(@NonNull PlayQueue queue, int repeatMode, float playbackSpeed,
+ float playbackPitch, boolean playbackSkipSilence, boolean playOnReady) {
super.initPlayback(queue, repeatMode, playbackSpeed, playbackPitch, playbackSkipSilence, playOnReady);
updateQueue();
}
@@ -760,16 +761,16 @@ private static void showInstallKoreDialog(final Context context) {
}
private void setupScreenRotationButton() {
- boolean orientationLocked = PlayerHelper.globalScreenOrientationLocked(service);
- boolean tabletInLandscape = isTablet(service) && service.isLandscape();
- boolean showButton = videoPlayerSelected() && (orientationLocked || isVerticalVideo || tabletInLandscape);
+ final boolean orientationLocked = PlayerHelper.globalScreenOrientationLocked(service);
+ final boolean tabletInLandscape = isTablet(service) && service.isLandscape();
+ final boolean showButton = videoPlayerSelected() && (orientationLocked || isVerticalVideo || tabletInLandscape);
screenRotationButton.setVisibility(showButton ? View.VISIBLE : View.GONE);
screenRotationButton.setImageDrawable(service.getResources().getDrawable(
isFullscreen() ? R.drawable.ic_fullscreen_exit_white : R.drawable.ic_fullscreen_white));
}
private void prepareOrientation() {
- boolean orientationLocked = PlayerHelper.globalScreenOrientationLocked(service);
+ final boolean orientationLocked = PlayerHelper.globalScreenOrientationLocked(service);
if (orientationLocked && isFullscreen() && service.isLandscape() == isVerticalVideo && fragmentListener != null)
fragmentListener.onScreenRotationButtonClicked();
}
@@ -1068,8 +1069,8 @@ public void onBroadcastReceived(Intent intent) {
// 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
- boolean reportedOrientationIsLandscape = service.isLandscape();
- boolean actualOrientationIsLandscape = context.getResources().getConfiguration().orientation == ORIENTATION_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
@@ -1130,7 +1131,7 @@ private void setInitialGestureValues() {
}
}
- private void choosePlayerTypeFromIntent(Intent intent) {
+ private void choosePlayerTypeFromIntent(final Intent intent) {
// If you want to open popup from the app just include Constants.POPUP_ONLY into an extra
if (intent.getIntExtra(PLAYER_TYPE, PLAYER_TYPE_VIDEO) == PLAYER_TYPE_AUDIO) {
playerType = MainPlayer.PlayerType.AUDIO;
@@ -1165,12 +1166,12 @@ public boolean isPlayerStopped() {
return getPlayer() == null || getPlayer().getPlaybackState() == SimpleExoPlayer.STATE_IDLE;
}
- private int distanceFromCloseButton(MotionEvent popupMotionEvent) {
+ private int distanceFromCloseButton(final MotionEvent popupMotionEvent) {
final int closeOverlayButtonX = closeOverlayButton.getLeft() + closeOverlayButton.getWidth() / 2;
final int closeOverlayButtonY = closeOverlayButton.getTop() + closeOverlayButton.getHeight() / 2;
- float fingerX = popupLayoutParams.x + popupMotionEvent.getX();
- float fingerY = popupLayoutParams.y + popupMotionEvent.getY();
+ final float fingerX = popupLayoutParams.x + popupMotionEvent.getX();
+ final float fingerY = popupLayoutParams.y + popupMotionEvent.getY();
return (int) Math.sqrt(Math.pow(closeOverlayButtonX - fingerX, 2) + Math.pow(closeOverlayButtonY - fingerY, 2));
}
@@ -1181,7 +1182,7 @@ private float getClosingRadius() {
return buttonRadius * 1.2f;
}
- public boolean isInsideClosingRadius(MotionEvent popupMotionEvent) {
+ public boolean isInsideClosingRadius(final MotionEvent popupMotionEvent) {
return distanceFromCloseButton(popupMotionEvent) <= getClosingRadius();
}
@@ -1199,7 +1200,7 @@ public void showControlsThenHide() {
}
@Override
- public void showControls(long duration) {
+ public void showControls(final long duration) {
if (queueVisible) return;
showOrHideButtons();
@@ -1208,7 +1209,7 @@ public void showControls(long duration) {
}
@Override
- public void hideControls(final long duration, long delay) {
+ public void hideControls(final long duration, final long delay) {
if (DEBUG) Log.d(TAG, "hideControls() called with: delay = [" + delay + "]");
showOrHideButtons();
@@ -1231,7 +1232,7 @@ private void showOrHideButtons() {
private void showSystemUIPartially() {
if (isFullscreen() && getParentActivity() != null) {
- int visibility = View.SYSTEM_UI_FLAG_LAYOUT_STABLE;
+ final int visibility = View.SYSTEM_UI_FLAG_LAYOUT_STABLE;
getParentActivity().getWindow().getDecorView().setSystemUiVisibility(visibility);
}
}
@@ -1247,40 +1248,40 @@ public void hideSystemUIIfNeeded() {
* NavigationBar and notches but not under them. Tablets have only bottom NavigationBar
*/
public void setControlsSize() {
- Point size = new Point();
- Display display = getRootView().getDisplay();
+ 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);
- int width = isFullscreen ? (service.isLandscape() ? size.x : size.y) : ViewGroup.LayoutParams.MATCH_PARENT;
- int gravity = isFullscreen ? (display.getRotation() == Surface.ROTATION_90 ? Gravity.START : Gravity.END) : Gravity.TOP;
+ final int width = isFullscreen ? (service.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;
- RelativeLayout.LayoutParams topParams = ((RelativeLayout.LayoutParams) getTopControlsRoot().getLayoutParams());
+ 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;
- RelativeLayout.LayoutParams bottomParams = ((RelativeLayout.LayoutParams) getBottomControlsRoot().getLayoutParams());
+ 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();
- ViewGroup controlsRoot = getRootView().findViewById(R.id.playbackWindowRoot);
+ 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
- boolean navBarAtTheBottom = PlayerHelper.isTablet(service) || !service.isLandscape();
+ final boolean navBarAtTheBottom = PlayerHelper.isTablet(service) || !service.isLandscape();
controlsRoot.getLayoutParams().height = isFullscreen && !isInMultiWindow() && navBarAtTheBottom
? size.y
: ViewGroup.LayoutParams.MATCH_PARENT;
controlsRoot.requestLayout();
- int topPadding = isFullscreen && !isInMultiWindow() ? getStatusBarHeight() : 0;
+ final int topPadding = isFullscreen && !isInMultiWindow() ? getStatusBarHeight() : 0;
getRootView().findViewById(R.id.playbackWindowRoot).setPadding(0, topPadding, 0, 0);
getRootView().findViewById(R.id.playbackWindowRoot).requestLayout();
}
@@ -1290,11 +1291,11 @@ public void setControlsSize() {
*/
private int getStatusBarHeight() {
int statusBarHeight = 0;
- int resourceId = service.getResources().getIdentifier("status_bar_height_landscape", "dimen", "android");
+ final int resourceId = service.getResources().getIdentifier("status_bar_height_landscape", "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
- DisplayMetrics metrics = getRootView().getResources().getDisplayMetrics();
+ final DisplayMetrics metrics = getRootView().getResources().getDisplayMetrics();
statusBarHeight = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 24, metrics);
}
return statusBarHeight;
@@ -1304,7 +1305,7 @@ private int getStatusBarHeight() {
* @return true if main player is attached to activity and activity inside multiWindow mode
*/
private boolean isInMultiWindow() {
- AppCompatActivity parent = getParentActivity();
+ final AppCompatActivity parent = getParentActivity();
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && parent != null && parent.isInMultiWindowMode();
}
@@ -1317,9 +1318,9 @@ private void updatePlaybackButtons() {
}
public void checkLandscape() {
- AppCompatActivity parent = getParentActivity();
- boolean videoInLandscapeButNotInFullscreen = service.isLandscape() && !isFullscreen() && videoPlayerSelected() && !audioOnly;
- boolean playingState = getCurrentState() != STATE_COMPLETED && getCurrentState() != STATE_PAUSED;
+ final AppCompatActivity parent = getParentActivity();
+ final boolean videoInLandscapeButNotInFullscreen = service.isLandscape() && !isFullscreen() && videoPlayerSelected() && !audioOnly;
+ final boolean playingState = getCurrentState() != STATE_COMPLETED && getCurrentState() != STATE_PAUSED;
if (parent != null && videoInLandscapeButNotInFullscreen && playingState && !PlayerHelper.isTablet(service))
toggleFullscreen();
@@ -1342,7 +1343,7 @@ private void buildQueue() {
itemsListCloseButton.setOnClickListener(view -> onQueueClosed());
}
- public void useVideoSource(boolean video) {
+ public void useVideoSource(final boolean video) {
if (playQueue == null || audioOnly == !video || audioPlayerSelected())
return;
@@ -1415,7 +1416,7 @@ private void initPopup() {
final boolean popupRememberSizeAndPos = PlayerHelper.isRememberingPopupDimensions(service);
final float defaultSize = service.getResources().getDimension(R.dimen.popup_default_width);
- SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(service);
+ final SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(service);
popupWidth = popupRememberSizeAndPos ? sharedPreferences.getFloat(POPUP_SAVED_WIDTH, defaultSize) : defaultSize;
popupHeight = getMinimumVideoHeight(popupWidth);
@@ -1428,8 +1429,8 @@ private void initPopup() {
popupLayoutParams.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
getSurfaceView().setHeights((int) popupHeight, (int) popupHeight);
- int centerX = (int) (screenWidth / 2f - popupWidth / 2f);
- int centerY = (int) (screenHeight / 2f - popupHeight / 2f);
+ final int centerX = (int) (screenWidth / 2f - popupWidth / 2f);
+ final int centerY = (int) (screenHeight / 2f - popupHeight / 2f);
popupLayoutParams.x = popupRememberSizeAndPos ? sharedPreferences.getInt(POPUP_SAVED_X, centerX) : centerX;
popupLayoutParams.y = popupRememberSizeAndPos ? sharedPreferences.getInt(POPUP_SAVED_Y, centerY) : centerY;
@@ -1458,7 +1459,7 @@ private void initPopupCloseOverlay() {
final int flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
| WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
- WindowManager.LayoutParams closeOverlayLayoutParams = new WindowManager.LayoutParams(
+ final WindowManager.LayoutParams closeOverlayLayoutParams = new WindowManager.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT,
popupLayoutParamType(),
flags,
@@ -1523,19 +1524,19 @@ public boolean checkPopupPositionBounds(final float boundaryWidth, final float b
}
public void savePositionAndSize() {
- SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(service);
+ final SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(service);
sharedPreferences.edit().putInt(POPUP_SAVED_X, popupLayoutParams.x).apply();
sharedPreferences.edit().putInt(POPUP_SAVED_Y, popupLayoutParams.y).apply();
sharedPreferences.edit().putFloat(POPUP_SAVED_WIDTH, popupLayoutParams.width).apply();
}
- private float getMinimumVideoHeight(float width) {
+ private float getMinimumVideoHeight(final float width) {
//if (DEBUG) Log.d(TAG, "getMinimumVideoHeight() called with: width = [" + width + "], returned: " + height);
return width / (16.0f / 9.0f); // Respect the 16:9 ratio that most videos have
}
public void updateScreenSize() {
- DisplayMetrics metrics = new DisplayMetrics();
+ final DisplayMetrics metrics = new DisplayMetrics();
windowManager.getDefaultDisplay().getMetrics(metrics);
screenWidth = metrics.widthPixels;
@@ -1604,7 +1605,7 @@ public void closePopup() {
}
public void removePopupFromView() {
- boolean isCloseOverlayHasParent = closeOverlayView != null && closeOverlayView.getParent() != null;
+ final boolean isCloseOverlayHasParent = closeOverlayView != null && closeOverlayView.getParent() != null;
if (popupHasParent())
windowManager.removeView(getRootView());
if (isCloseOverlayHasParent)
@@ -1640,7 +1641,7 @@ private void end() {
}
private boolean popupHasParent() {
- View root = getRootView();
+ final View root = getRootView();
return root != null && root.getLayoutParams() instanceof WindowManager.LayoutParams && root.getParent() != null;
}
@@ -1648,27 +1649,27 @@ private boolean popupHasParent() {
// Manipulations with listener
///////////////////////////////////////////////////////////////////////////
- public void setFragmentListener(PlayerServiceEventListener listener) {
+ public void setFragmentListener(final PlayerServiceEventListener listener) {
fragmentListener = listener;
updateMetadata();
updatePlayback();
triggerProgressUpdate();
}
- public void removeFragmentListener(PlayerServiceEventListener listener) {
+ public void removeFragmentListener(final PlayerServiceEventListener listener) {
if (fragmentListener == listener) {
fragmentListener = null;
}
}
- /*package-private*/ void setActivityListener(PlayerEventListener listener) {
+ void setActivityListener(final PlayerEventListener listener) {
activityListener = listener;
updateMetadata();
updatePlayback();
triggerProgressUpdate();
}
- /*package-private*/ void removeActivityListener(PlayerEventListener listener) {
+ void removeActivityListener(final PlayerEventListener listener) {
if (activityListener == listener) {
activityListener = null;
}
@@ -1703,7 +1704,7 @@ private void updatePlayback() {
}
}
- private void updateProgress(int currentProgress, int duration, int bufferPercent) {
+ private void updateProgress(final int currentProgress, final int duration, final int bufferPercent) {
if (fragmentListener != null) {
fragmentListener.onProgressUpdate(currentProgress, duration, bufferPercent);
}
@@ -1787,11 +1788,11 @@ public float getPopupHeight() {
return popupHeight;
}
- public void setPopupWidth(float width) {
+ public void setPopupWidth(final float width) {
popupWidth = width;
}
- public void setPopupHeight(float height) {
+ public void setPopupHeight(final float height) {
popupHeight = height;
}
diff --git a/app/src/main/java/org/schabi/newpipe/player/event/CustomBottomSheetBehavior.java b/app/src/main/java/org/schabi/newpipe/player/event/CustomBottomSheetBehavior.java
index 9d4707666e1..24ef5dffc85 100644
--- a/app/src/main/java/org/schabi/newpipe/player/event/CustomBottomSheetBehavior.java
+++ b/app/src/main/java/org/schabi/newpipe/player/event/CustomBottomSheetBehavior.java
@@ -16,14 +16,14 @@
public class CustomBottomSheetBehavior extends BottomSheetBehavior {
- public CustomBottomSheetBehavior(Context context, AttributeSet attrs) {
+ public CustomBottomSheetBehavior(final Context context, final AttributeSet attrs) {
super(context, attrs);
}
boolean visible;
Rect globalRect = new Rect();
private boolean skippingInterception = false;
- private List skipInterceptionOfElements = Arrays.asList(
+ private final List skipInterceptionOfElements = Arrays.asList(
R.id.detail_content_root_layout, R.id.relatedStreamsLayout, R.id.playQueuePanel, R.id.viewpager);
@Override
@@ -38,8 +38,8 @@ public boolean onInterceptTouchEvent(@NonNull CoordinatorLayout parent, @NonNull
// Don't need to do anything if bottomSheet isn't expanded
if (getState() == BottomSheetBehavior.STATE_EXPANDED) {
// Without overriding scrolling will not work when user touches these elements
- for (Integer element : skipInterceptionOfElements) {
- ViewGroup viewGroup = child.findViewById(element);
+ for (final Integer element : skipInterceptionOfElements) {
+ final ViewGroup viewGroup = child.findViewById(element);
if (viewGroup != null) {
visible = viewGroup.getGlobalVisibleRect(globalRect);
if (visible && globalRect.contains((int) event.getRawX(), (int) event.getRawY())) {
diff --git a/app/src/main/java/org/schabi/newpipe/player/event/PlayerGestureListener.java b/app/src/main/java/org/schabi/newpipe/player/event/PlayerGestureListener.java
index f8b4021037b..8e4a5c2ac78 100644
--- a/app/src/main/java/org/schabi/newpipe/player/event/PlayerGestureListener.java
+++ b/app/src/main/java/org/schabi/newpipe/player/event/PlayerGestureListener.java
@@ -20,8 +20,8 @@ public class PlayerGestureListener extends GestureDetector.SimpleOnGestureListen
private static final String TAG = ".PlayerGestureListener";
private static final boolean DEBUG = BasePlayer.DEBUG;
- private VideoPlayerImpl playerImpl;
- private MainPlayer service;
+ private final VideoPlayerImpl playerImpl;
+ private final MainPlayer service;
private int initialPopupX, initialPopupY;
@@ -29,7 +29,7 @@ public class PlayerGestureListener extends GestureDetector.SimpleOnGestureListen
private boolean isResizing;
- private int tossFlingVelocity;
+ private final int tossFlingVelocity;
private final boolean isVolumeGestureEnabled;
private final boolean isBrightnessGestureEnabled;
@@ -114,9 +114,9 @@ public boolean onTouch(View v, MotionEvent event) {
//////////////////////////////////////////////////////////////////////////*/
private boolean onDoubleTapInMain(MotionEvent e) {
- if (e.getX() > playerImpl.getRootView().getWidth() * 2 / 3) {
+ if (e.getX() > playerImpl.getRootView().getWidth() * 2.0 / 3.0) {
playerImpl.onFastForward();
- } else if (e.getX() < playerImpl.getRootView().getWidth() / 3) {
+ } else if (e.getX() < playerImpl.getRootView().getWidth() / 3.0) {
playerImpl.onFastRewind();
} else {
playerImpl.getPlayPauseButton().performClick();
@@ -143,7 +143,8 @@ private boolean onSingleTapConfirmedInMain(MotionEvent e) {
return true;
}
- private boolean onScrollInMain(MotionEvent initialEvent, MotionEvent movingEvent, float distanceX, float distanceY) {
+ private boolean onScrollInMain(final MotionEvent initialEvent, final MotionEvent movingEvent,
+ final float distanceX, final float distanceY) {
if (!isVolumeGestureEnabled && !isBrightnessGestureEnabled) return false;
//noinspection PointlessBooleanExpression
@@ -162,9 +163,9 @@ private boolean onScrollInMain(MotionEvent initialEvent, MotionEvent movingEvent
if (isVolumeGestureEnabled && initialEvent.getX() > playerImpl.getRootView().getWidth() / 2.0) {
playerImpl.getVolumeProgressBar().incrementProgressBy((int) distanceY);
- float currentProgressPercent =
+ final float currentProgressPercent =
(float) playerImpl.getVolumeProgressBar().getProgress() / playerImpl.getMaxGestureLength();
- int currentVolume = (int) (maxVolume * currentProgressPercent);
+ final int currentVolume = (int) (maxVolume * currentProgressPercent);
playerImpl.getAudioReactor().setVolume(currentVolume);
if (DEBUG) Log.d(TAG, "onScroll().volumeControl, currentVolume = " + currentVolume);
@@ -183,15 +184,15 @@ private boolean onScrollInMain(MotionEvent initialEvent, MotionEvent movingEvent
playerImpl.getBrightnessRelativeLayout().setVisibility(View.GONE);
}
} else if (isBrightnessGestureEnabled && initialEvent.getX() <= playerImpl.getRootView().getWidth() / 2.0) {
- Activity parent = playerImpl.getParentActivity();
+ final Activity parent = playerImpl.getParentActivity();
if (parent == null) return true;
- Window window = parent.getWindow();
+ final Window window = parent.getWindow();
playerImpl.getBrightnessProgressBar().incrementProgressBy((int) distanceY);
- float currentProgressPercent =
+ final float currentProgressPercent =
(float) playerImpl.getBrightnessProgressBar().getProgress() / playerImpl.getMaxGestureLength();
- WindowManager.LayoutParams layoutParams = window.getAttributes();
+ final WindowManager.LayoutParams layoutParams = window.getAttributes();
layoutParams.screenBrightness = currentProgressPercent;
window.setAttributes(layoutParams);
@@ -306,8 +307,10 @@ private boolean onScrollInPopup(MotionEvent initialEvent, MotionEvent movingEven
isMovingInPopup = true;
- float diffX = (int) (movingEvent.getRawX() - initialEvent.getRawX()), posX = (int) (initialPopupX + diffX);
- float diffY = (int) (movingEvent.getRawY() - initialEvent.getRawY()), posY = (int) (initialPopupY + diffY);
+ final float diffX = (int) (movingEvent.getRawX() - initialEvent.getRawX());
+ float posX = (int) (initialPopupX + diffX);
+ final float diffY = (int) (movingEvent.getRawY() - initialEvent.getRawY());
+ float posY = (int) (initialPopupY + diffY);
if (posX > (playerImpl.getScreenWidth() - playerImpl.getPopupWidth())) posX = (int) (playerImpl.getScreenWidth() - playerImpl.getPopupWidth());
else if (posX < 0) posX = 0;
diff --git a/app/src/main/java/org/schabi/newpipe/player/playqueue/PlayQueue.java b/app/src/main/java/org/schabi/newpipe/player/playqueue/PlayQueue.java
index e739b8f33aa..482b361000c 100644
--- a/app/src/main/java/org/schabi/newpipe/player/playqueue/PlayQueue.java
+++ b/app/src/main/java/org/schabi/newpipe/player/playqueue/PlayQueue.java
@@ -46,7 +46,7 @@ public abstract class PlayQueue implements Serializable {
private ArrayList backup;
private ArrayList streams;
- private ArrayList history;
+ private final ArrayList history;
@NonNull private final AtomicInteger queueIndex;
private transient BehaviorSubject eventBroadcast;
@@ -132,7 +132,7 @@ public PlayQueueItem getItem() {
* Returns the item at the given index.
* May throw {@link IndexOutOfBoundsException}.
* */
- public PlayQueueItem getItem(int index) {
+ public PlayQueueItem getItem(final int index) {
if (index < 0 || index >= streams.size() || streams.get(index) == null) return null;
return streams.get(index);
}
@@ -235,7 +235,7 @@ public synchronized void append(@NonNull final PlayQueueItem... items) {
* Will emit a {@link AppendEvent} on any given context.
* */
public synchronized void append(@NonNull final List items) {
- List itemList = new ArrayList<>(items);
+ final List itemList = new ArrayList<>(items);
if (isShuffled()) {
backup.addAll(itemList);
@@ -300,8 +300,7 @@ private synchronized void removeInternal(final int removeIndex) {
}
if (backup != null) {
- final int backupIndex = backup.indexOf(getItem(removeIndex));
- backup.remove(backupIndex);
+ backup.remove(getItem(removeIndex));
}
history.remove(streams.remove(removeIndex));
@@ -332,7 +331,7 @@ public synchronized void move(final int source, final int target) {
queueIndex.incrementAndGet();
}
- PlayQueueItem playQueueItem = streams.remove(source);
+ final PlayQueueItem playQueueItem = streams.remove(source);
playQueueItem.setAutoQueued(false);
streams.add(target, playQueueItem);
broadcast(new MoveEvent(source, target));
@@ -431,7 +430,7 @@ public synchronized boolean previous() {
history.remove(history.size() - 1);
- PlayQueueItem last = history.remove(history.size() - 1);
+ final PlayQueueItem last = history.remove(history.size() - 1);
setIndex(indexOf(last));
return true;
@@ -443,11 +442,11 @@ public synchronized boolean previous() {
* VideoDetailFragment without duplicating items from two identical queues
* */
@Override
- public boolean equals(@Nullable Object obj) {
+ public boolean equals(@Nullable final Object obj) {
if (!(obj instanceof PlayQueue) || getStreams().size() != ((PlayQueue) obj).getStreams().size())
return false;
- PlayQueue other = (PlayQueue) obj;
+ final PlayQueue other = (PlayQueue) obj;
for (int i = 0; i < getStreams().size(); i++) {
if (!getItem(i).getUrl().equals(other.getItem(i).getUrl()))
return false;
diff --git a/app/src/main/java/org/schabi/newpipe/util/NavigationHelper.java b/app/src/main/java/org/schabi/newpipe/util/NavigationHelper.java
index f0fd7e41bfa..e897e827fc4 100644
--- a/app/src/main/java/org/schabi/newpipe/util/NavigationHelper.java
+++ b/app/src/main/java/org/schabi/newpipe/util/NavigationHelper.java
@@ -114,13 +114,25 @@ public static Intent getPlayerIntent(@NonNull final Context context,
.putExtra(BasePlayer.PLAYBACK_SKIP_SILENCE, playbackSkipSilence);
}
- public static void playOnMainPlayer(final AppCompatActivity activity, final PlayQueue queue, final boolean autoPlay) {
+ public static void playOnMainPlayer(
+ final AppCompatActivity activity,
+ final PlayQueue queue,
+ final boolean autoPlay) {
playOnMainPlayer(activity.getSupportFragmentManager(), queue, autoPlay);
}
- public static void playOnMainPlayer(final FragmentManager fragmentManager, final PlayQueue queue, boolean autoPlay) {
- PlayQueueItem currentStream = queue.getItem();
- openVideoDetailFragment(fragmentManager, currentStream.getServiceId(), currentStream.getUrl(), currentStream.getTitle(), autoPlay, queue);
+ public static void playOnMainPlayer(
+ final FragmentManager fragmentManager,
+ final PlayQueue queue,
+ final boolean autoPlay) {
+ final PlayQueueItem currentStream = queue.getItem();
+ openVideoDetailFragment(
+ fragmentManager,
+ currentStream.getServiceId(),
+ currentStream.getUrl(),
+ currentStream.getTitle(),
+ autoPlay,
+ queue);
}
public static void playOnMainPlayer(@NonNull final Context context,
@@ -131,7 +143,7 @@ public static void playOnMainPlayer(@NonNull final Context context,
final boolean autoPlay,
final boolean resumePlayback) {
- Intent intent = getPlayerIntent(context, MainActivity.class, queue, resumePlayback);
+ final Intent intent = getPlayerIntent(context, MainActivity.class, queue, resumePlayback);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.putExtra(Constants.KEY_LINK_TYPE, linkType);
intent.putExtra(Constants.KEY_URL, url);
@@ -147,14 +159,14 @@ public static void playOnPopupPlayer(final Context context, final PlayQueue queu
}
Toast.makeText(context, R.string.popup_playing_toast, Toast.LENGTH_SHORT).show();
- Intent intent = getPlayerIntent(context, MainPlayer.class, queue, resumePlayback);
+ final Intent intent = getPlayerIntent(context, MainPlayer.class, queue, resumePlayback);
intent.putExtra(VideoPlayer.PLAYER_TYPE, VideoPlayer.PLAYER_TYPE_POPUP);
startService(context, intent);
}
public static void playOnBackgroundPlayer(final Context context, final PlayQueue queue, final boolean resumePlayback) {
Toast.makeText(context, R.string.background_player_playing_toast, Toast.LENGTH_SHORT).show();
- Intent intent = getPlayerIntent(context, MainPlayer.class, queue, resumePlayback);
+ final Intent intent = getPlayerIntent(context, MainPlayer.class, queue, resumePlayback);
intent.putExtra(VideoPlayer.PLAYER_TYPE, VideoPlayer.PLAYER_TYPE_AUDIO);
startService(context, intent);
}
@@ -170,7 +182,7 @@ public static void enqueueOnPopupPlayer(final Context context, final PlayQueue q
}
Toast.makeText(context, R.string.popup_playing_append, Toast.LENGTH_SHORT).show();
- Intent intent = getPlayerEnqueueIntent(context, MainPlayer.class, queue, selectOnAppend, resumePlayback);
+ final Intent intent = getPlayerEnqueueIntent(context, MainPlayer.class, queue, selectOnAppend, resumePlayback);
intent.putExtra(VideoPlayer.PLAYER_TYPE, VideoPlayer.PLAYER_TYPE_POPUP);
startService(context, intent);
}
@@ -179,9 +191,9 @@ public static void enqueueOnBackgroundPlayer(final Context context, final PlayQu
enqueueOnBackgroundPlayer(context, queue, false, resumePlayback);
}
- public static void enqueueOnBackgroundPlayer(final Context context, final PlayQueue queue, boolean selectOnAppend, final boolean resumePlayback) {
+ public static void enqueueOnBackgroundPlayer(final Context context, final PlayQueue queue, final boolean selectOnAppend, final boolean resumePlayback) {
Toast.makeText(context, R.string.background_player_append, Toast.LENGTH_SHORT).show();
- Intent intent = getPlayerEnqueueIntent(context, MainPlayer.class, queue, selectOnAppend, resumePlayback);
+ final Intent intent = getPlayerEnqueueIntent(context, MainPlayer.class, queue, selectOnAppend, resumePlayback);
intent.putExtra(VideoPlayer.PLAYER_TYPE, VideoPlayer.PLAYER_TYPE_AUDIO);
startService(context, intent);
}
@@ -307,25 +319,31 @@ public static void openVideoDetailFragment(FragmentManager fragmentManager, int
openVideoDetailFragment(fragmentManager, serviceId, url, title, true, null);
}
- public static void openVideoDetailFragment(FragmentManager fragmentManager, int serviceId, String url, String title, boolean autoPlay, PlayQueue playQueue) {
- Fragment fragment = fragmentManager.findFragmentById(R.id.fragment_player_holder);
+ public static void openVideoDetailFragment(
+ FragmentManager fragmentManager,
+ int serviceId,
+ String url,
+ String title,
+ boolean autoPlay,
+ PlayQueue playQueue) {
+ final Fragment fragment = fragmentManager.findFragmentById(R.id.fragment_player_holder);
if (title == null) title = "";
if (fragment instanceof VideoDetailFragment && fragment.isVisible()) {
- expandMainPlayer(fragment.getActivity());
- VideoDetailFragment detailFragment = (VideoDetailFragment) fragment;
+ expandMainPlayer(fragment.requireActivity());
+ final VideoDetailFragment detailFragment = (VideoDetailFragment) fragment;
detailFragment.setAutoplay(autoPlay);
detailFragment.selectAndLoadVideo(serviceId, url, title, playQueue);
detailFragment.scrollToTop();
return;
}
- VideoDetailFragment instance = VideoDetailFragment.getInstance(serviceId, url, title, playQueue);
+ final VideoDetailFragment instance = VideoDetailFragment.getInstance(serviceId, url, title, playQueue);
instance.setAutoplay(autoPlay);
defaultTransaction(fragmentManager)
.replace(R.id.fragment_player_holder, instance)
- .runOnCommit(() -> expandMainPlayer(instance.getActivity()))
+ .runOnCommit(() -> expandMainPlayer(instance.requireActivity()))
.commit();
}
@@ -335,9 +353,9 @@ public static void expandMainPlayer(Context context) {
}
public static void openChannelFragment(
- FragmentManager fragmentManager,
- int serviceId,
- String url,
+ final FragmentManager fragmentManager,
+ final int serviceId,
+ final String url,
String name) {
if (name == null) name = "";
defaultTransaction(fragmentManager)
@@ -525,7 +543,7 @@ public static Intent getIntentByLink(Context context, StreamingService service,
case STREAM:
rIntent.putExtra(VideoDetailFragment.AUTO_PLAY,
PreferenceManager.getDefaultSharedPreferences(context)
- .getBoolean(context.getString(R.string.autoplay_through_intent_key), false));
+ .getBoolean(context.getString(R.string.autoplay_through_intent_key), false));
break;
}
@@ -558,6 +576,7 @@ private static void installApp(Context context, String packageName) {
/**
* Start an activity to install Kore
+ *
* @param context the context
*/
public static void installKore(Context context) {
@@ -566,13 +585,13 @@ public static void installKore(Context context) {
/**
* Start Kore app to show a video on Kodi
- *
+ *
* For a list of supported urls see the
*
- * Kore source code
+ * Kore source code
* .
*
- * @param context the context to use
+ * @param context the context to use
* @param videoURL the url to the video
*/
public static void playWithKore(Context context, Uri videoURL) {
diff --git a/app/src/main/java/org/schabi/newpipe/views/ExpandableSurfaceView.java b/app/src/main/java/org/schabi/newpipe/views/ExpandableSurfaceView.java
index f5a7df4716c..3d69e9cdc70 100644
--- a/app/src/main/java/org/schabi/newpipe/views/ExpandableSurfaceView.java
+++ b/app/src/main/java/org/schabi/newpipe/views/ExpandableSurfaceView.java
@@ -25,14 +25,14 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
if (videoAspectRatio == 0.0f) return;
int width = MeasureSpec.getSize(widthMeasureSpec);
- boolean verticalVideo = videoAspectRatio < 1;
+ 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 && verticalVideo ? maxHeight : baseHeight;
if (height == 0) return;
- float viewAspectRatio = width / ((float) height);
- float aspectDeformation = videoAspectRatio / viewAspectRatio - 1;
+ final float viewAspectRatio = width / ((float) height);
+ final float aspectDeformation = videoAspectRatio / viewAspectRatio - 1;
scaleX = 1.0f;
scaleY = 1.0f;
@@ -73,15 +73,14 @@ protected void onLayout(boolean changed, int left, int top, int right, int botto
* @param base The height that will be used in every resize mode as a minimum height
* @param max The max height for vertical videos in non-FIT resize modes
*/
- public void setHeights(int base, int max) {
+ public void setHeights(final int base, final int max) {
if (baseHeight == base && maxHeight == max) return;
baseHeight = base;
maxHeight = max;
requestLayout();
}
- @AspectRatioFrameLayout.ResizeMode
- public void setResizeMode(int newResizeMode) {
+ public void setResizeMode(@AspectRatioFrameLayout.ResizeMode final int newResizeMode) {
if (resizeMode == newResizeMode) return;
resizeMode = newResizeMode;
@@ -93,7 +92,7 @@ public int getResizeMode() {
return resizeMode;
}
- public void setAspectRatio(float aspectRatio) {
+ public void setAspectRatio(final float aspectRatio) {
if (videoAspectRatio == aspectRatio) return;
videoAspectRatio = aspectRatio;
From bff238774ec3a92fe84289d300e7c476b0e9daab Mon Sep 17 00:00:00 2001
From: Avently <7953703+avently@users.noreply.github.com>
Date: Mon, 13 Jul 2020 23:28:39 +0300
Subject: [PATCH 026/398] Small fixes of issues
---
.../fragments/detail/VideoDetailFragment.java | 9 ++-------
.../schabi/newpipe/player/VideoPlayerImpl.java | 17 +++++++++--------
.../player/event/PlayerGestureListener.java | 8 ++++++--
.../layout-large-land/activity_main_player.xml | 18 +++++++-----------
.../main/res/layout/activity_main_player.xml | 4 ++--
5 files changed, 26 insertions(+), 30 deletions(-)
diff --git a/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java
index ce6bd72f531..396363d312f 100644
--- a/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java
+++ b/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java
@@ -470,11 +470,6 @@ public void onSharedPreferenceChanged(final SharedPreferences sharedPreferences,
@Override
public void onSaveInstanceState(final Bundle outState) {
super.onSaveInstanceState(outState);
-
- // Check if the next video label and video is visible,
- // if it is, include the two elements in the next check
- int nextCount = currentInfo != null && currentInfo.getNextVideo() != null ? 2 : 0;
-
if (!isLoading.get() && currentInfo != null && isVisible()) {
outState.putSerializable(INFO_KEY, currentInfo);
}
@@ -947,12 +942,12 @@ private void runWorker(final boolean forceLoad, final boolean addToBackStack) {
getString(R.string.show_age_restricted_content), false)) {
hideAgeRestrictedContent();
} else {
- currentInfo = result;
handleResult(result);
showContent();
if (addToBackStack) {
if (playQueue == null) playQueue = new SinglePlayQueue(result);
- stack.push(new StackItem(serviceId, url, name, playQueue));
+ if (stack.isEmpty() || !stack.peek().getPlayQueue().equals(playQueue))
+ stack.push(new StackItem(serviceId, url, name, playQueue));
}
if (isAutoplayEnabled()) openVideoPlayer();
}
diff --git a/app/src/main/java/org/schabi/newpipe/player/VideoPlayerImpl.java b/app/src/main/java/org/schabi/newpipe/player/VideoPlayerImpl.java
index 1b72d7a9679..d102a93ec3d 100644
--- a/app/src/main/java/org/schabi/newpipe/player/VideoPlayerImpl.java
+++ b/app/src/main/java/org/schabi/newpipe/player/VideoPlayerImpl.java
@@ -351,6 +351,7 @@ private void setupElementsVisibility() {
titleTextView.setVisibility(View.VISIBLE);
channelTextView.setVisibility(View.VISIBLE);
}
+ setMuteButton(muteButton, isMuted());
animateRotation(moreOptionsButton, DEFAULT_CONTROLS_DURATION, 0);
}
@@ -960,12 +961,12 @@ public void changeState(int state) {
@Override
public void onBlocked() {
super.onBlocked();
- playPauseButton.setImageResource(R.drawable.exo_controls_play);
+ playPauseButton.setImageResource(R.drawable.ic_play_arrow_white_24dp);
animatePlayButtons(false, 100);
getRootView().setKeepScreenOn(false);
service.resetNotification();
- service.updateNotification(R.drawable.exo_controls_play);
+ service.updateNotification(R.drawable.ic_play_arrow_white_24dp);
}
@Override
@@ -974,14 +975,14 @@ public void onBuffering() {
getRootView().setKeepScreenOn(true);
service.resetNotification();
- service.updateNotification(R.drawable.exo_controls_play);
+ service.updateNotification(R.drawable.ic_play_arrow_white_24dp);
}
@Override
public void onPlaying() {
super.onPlaying();
animateView(playPauseButton, AnimationUtils.Type.SCALE_AND_ALPHA, false, 80, 0, () -> {
- playPauseButton.setImageResource(R.drawable.exo_controls_pause);
+ playPauseButton.setImageResource(R.drawable.ic_pause_white_24dp);
animatePlayButtons(true, 200);
playPauseButton.requestFocus();
});
@@ -991,7 +992,7 @@ public void onPlaying() {
getRootView().setKeepScreenOn(true);
service.resetNotification();
- service.updateNotification(R.drawable.exo_controls_pause);
+ service.updateNotification(R.drawable.ic_pause_white_24dp);
service.startForeground(NOTIFICATION_ID, service.getNotBuilder().build());
}
@@ -1000,7 +1001,7 @@ public void onPlaying() {
public void onPaused() {
super.onPaused();
animateView(playPauseButton, AnimationUtils.Type.SCALE_AND_ALPHA, false, 80, 0, () -> {
- playPauseButton.setImageResource(R.drawable.exo_controls_play);
+ playPauseButton.setImageResource(R.drawable.ic_play_arrow_white_24dp);
animatePlayButtons(true, 200);
playPauseButton.requestFocus();
});
@@ -1008,7 +1009,7 @@ public void onPaused() {
updateWindowFlags(IDLE_WINDOW_FLAGS);
service.resetNotification();
- service.updateNotification(R.drawable.exo_controls_play);
+ service.updateNotification(R.drawable.ic_play_arrow_white_24dp);
// Remove running notification when user don't want music (or video in popup) to be played in background
if (!minimizeOnPopupEnabled() && !backgroundPlaybackEnabled() && videoPlayerSelected())
@@ -1024,7 +1025,7 @@ public void onPausedSeek() {
getRootView().setKeepScreenOn(true);
service.resetNotification();
- service.updateNotification(R.drawable.exo_controls_play);
+ service.updateNotification(R.drawable.ic_play_arrow_white_24dp);
}
diff --git a/app/src/main/java/org/schabi/newpipe/player/event/PlayerGestureListener.java b/app/src/main/java/org/schabi/newpipe/player/event/PlayerGestureListener.java
index d7bc3a6a0be..559a4d02b4c 100644
--- a/app/src/main/java/org/schabi/newpipe/player/event/PlayerGestureListener.java
+++ b/app/src/main/java/org/schabi/newpipe/player/event/PlayerGestureListener.java
@@ -175,7 +175,11 @@ private boolean onScrollInMain(final MotionEvent initialEvent, final MotionEvent
isMovingInMain = true;
- if (isVolumeGestureEnabled && initialEvent.getX() > playerImpl.getRootView().getWidth() / 2.0) {
+ boolean acceptAnyArea = isVolumeGestureEnabled != isBrightnessGestureEnabled;
+ boolean acceptVolumeArea = acceptAnyArea
+ || initialEvent.getX() > playerImpl.getRootView().getWidth() / 2.0;
+
+ if (isVolumeGestureEnabled && acceptVolumeArea) {
playerImpl.getVolumeProgressBar().incrementProgressBy((int) distanceY);
final float currentProgressPercent =
(float) playerImpl.getVolumeProgressBar().getProgress() / playerImpl.getMaxGestureLength();
@@ -197,7 +201,7 @@ private boolean onScrollInMain(final MotionEvent initialEvent, final MotionEvent
if (playerImpl.getBrightnessRelativeLayout().getVisibility() == View.VISIBLE) {
playerImpl.getBrightnessRelativeLayout().setVisibility(View.GONE);
}
- } else if (isBrightnessGestureEnabled && initialEvent.getX() <= playerImpl.getRootView().getWidth() / 2.0) {
+ } else {
final Activity parent = playerImpl.getParentActivity();
if (parent == null) return true;
diff --git a/app/src/main/res/layout-large-land/activity_main_player.xml b/app/src/main/res/layout-large-land/activity_main_player.xml
index 1ee2538c04c..1a4e6b4e475 100644
--- a/app/src/main/res/layout-large-land/activity_main_player.xml
+++ b/app/src/main/res/layout-large-land/activity_main_player.xml
@@ -42,7 +42,6 @@
android:id="@+id/playQueuePanel"
android:layout_width="380dp"
android:layout_alignParentEnd="true"
- android:layout_alignParentRight="true"
android:layout_height="match_parent"
android:visibility="gone"
android:background="?attr/queue_background_color"
@@ -58,9 +57,7 @@
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_centerVertical="true"
- android:layout_alignParentRight="true"
android:layout_alignParentEnd="true"
- android:layout_marginRight="40dp"
android:layout_marginEnd="40dp"
android:padding="10dp"
android:clickable="true"
@@ -88,7 +85,6 @@
android:src="@drawable/exo_controls_repeat_off"
android:background="?android:selectableItemBackground"
tools:ignore="ContentDescription,RtlHardcoded"/>
-
@@ -223,9 +218,10 @@
diff --git a/app/src/main/res/layout-large-land/activity_main_player.xml b/app/src/main/res/layout-large-land/activity_main_player.xml
index 26a2ebc8bb2..92288933b06 100644
--- a/app/src/main/res/layout-large-land/activity_main_player.xml
+++ b/app/src/main/res/layout-large-land/activity_main_player.xml
@@ -217,7 +217,6 @@
+ android:visibility="gone"
+ tools:visibility="visible"/>
-
@@ -504,7 +503,7 @@
app:srcCompat="@drawable/ic_pause_white_24dp"
tools:ignore="ContentDescription"/>
-
@@ -660,7 +659,6 @@
-
@@ -504,7 +504,7 @@
app:srcCompat="@drawable/ic_pause_white_24dp"
tools:ignore="ContentDescription"/>
-
diff --git a/app/src/main/res/layout/activity_player_queue_control.xml b/app/src/main/res/layout/activity_player_queue_control.xml
index c5b8e574339..c5d3b0eb8cc 100644
--- a/app/src/main/res/layout/activity_player_queue_control.xml
+++ b/app/src/main/res/layout/activity_player_queue_control.xml
@@ -184,7 +184,7 @@
app:srcCompat="@drawable/ic_repeat_white_24dp"
tools:ignore="ContentDescription"/>
-
-
Date: Sat, 18 Jul 2020 10:16:35 +0200
Subject: [PATCH 031/398] Added translation using Weblate (Neapolitan)
---
app/src/main/res/values-nap/strings.xml | 2 ++
1 file changed, 2 insertions(+)
create mode 100644 app/src/main/res/values-nap/strings.xml
diff --git a/app/src/main/res/values-nap/strings.xml b/app/src/main/res/values-nap/strings.xml
new file mode 100644
index 00000000000..a6b3daec935
--- /dev/null
+++ b/app/src/main/res/values-nap/strings.xml
@@ -0,0 +1,2 @@
+
+
\ No newline at end of file
From c7ccf9bab84041e00c95c16f42e744b72e85c4eb Mon Sep 17 00:00:00 2001
From: Avently <7953703+avently@users.noreply.github.com>
Date: Tue, 21 Jul 2020 01:43:49 +0300
Subject: [PATCH 032/398] AndroidTvUtils -> DeviceUtils
---
.../java/org/schabi/newpipe/MainActivity.java | 6 +++---
.../org/schabi/newpipe/RouterActivity.java | 4 ++--
.../newpipe/download/DownloadActivity.java | 4 ++--
.../fragments/detail/VideoDetailFragment.java | 12 +++++------
.../fragments/list/search/SearchFragment.java | 4 ++--
.../holder/CommentsMiniInfoItemHolder.java | 4 ++--
.../subscription/dialog/FeedGroupDialog.kt | 4 ++--
.../newpipe/player/MainVideoPlayer.java | 10 +++++-----
.../newpipe/player/VideoPlayerImpl.java | 11 +++++-----
.../newpipe/player/helper/PlayerHelper.java | 7 -------
.../newpipe/settings/SettingsActivity.java | 4 ++--
.../{AndroidTvUtils.java => DeviceUtils.java} | 20 +++++++++++++------
.../newpipe/views/FocusAwareSeekBar.java | 4 ++--
13 files changed, 47 insertions(+), 47 deletions(-)
rename app/src/main/java/org/schabi/newpipe/util/{AndroidTvUtils.java => DeviceUtils.java} (81%)
diff --git a/app/src/main/java/org/schabi/newpipe/MainActivity.java b/app/src/main/java/org/schabi/newpipe/MainActivity.java
index ad574150331..fb1ca234217 100644
--- a/app/src/main/java/org/schabi/newpipe/MainActivity.java
+++ b/app/src/main/java/org/schabi/newpipe/MainActivity.java
@@ -68,7 +68,7 @@
import org.schabi.newpipe.player.event.OnKeyDownListener;
import org.schabi.newpipe.player.playqueue.PlayQueue;
import org.schabi.newpipe.report.ErrorActivity;
-import org.schabi.newpipe.util.AndroidTvUtils;
+import org.schabi.newpipe.util.DeviceUtils;
import org.schabi.newpipe.util.Constants;
import org.schabi.newpipe.util.KioskTranslator;
import org.schabi.newpipe.util.Localization;
@@ -144,7 +144,7 @@ && getSupportFragmentManager().getBackStackEntryCount() == 0) {
ErrorActivity.reportUiError(this, e);
}
- if (AndroidTvUtils.isTv(this)) {
+ if (DeviceUtils.isTv(this)) {
FocusOverlayView.setupFocusObserver(this);
}
}
@@ -545,7 +545,7 @@ public void onBackPressed() {
Log.d(TAG, "onBackPressed() called");
}
- if (AndroidTvUtils.isTv(this)) {
+ if (DeviceUtils.isTv(this)) {
View drawerPanel = findViewById(R.id.navigation);
if (drawer.isDrawerOpen(drawerPanel)) {
drawer.closeDrawers();
diff --git a/app/src/main/java/org/schabi/newpipe/RouterActivity.java b/app/src/main/java/org/schabi/newpipe/RouterActivity.java
index 423e88b76fc..e9e166c22b6 100644
--- a/app/src/main/java/org/schabi/newpipe/RouterActivity.java
+++ b/app/src/main/java/org/schabi/newpipe/RouterActivity.java
@@ -44,7 +44,7 @@
import org.schabi.newpipe.player.playqueue.PlaylistPlayQueue;
import org.schabi.newpipe.player.playqueue.SinglePlayQueue;
import org.schabi.newpipe.report.UserAction;
-import org.schabi.newpipe.util.AndroidTvUtils;
+import org.schabi.newpipe.util.DeviceUtils;
import org.schabi.newpipe.util.Constants;
import org.schabi.newpipe.util.ExtractorHelper;
import org.schabi.newpipe.util.ListHelper;
@@ -347,7 +347,7 @@ private void showDialog(final List choices) {
alertDialog.show();
- if (AndroidTvUtils.isTv(this)) {
+ if (DeviceUtils.isTv(this)) {
FocusOverlayView.setupFocusObserver(alertDialog);
}
}
diff --git a/app/src/main/java/org/schabi/newpipe/download/DownloadActivity.java b/app/src/main/java/org/schabi/newpipe/download/DownloadActivity.java
index e46ded40d42..5415c4ff853 100644
--- a/app/src/main/java/org/schabi/newpipe/download/DownloadActivity.java
+++ b/app/src/main/java/org/schabi/newpipe/download/DownloadActivity.java
@@ -13,7 +13,7 @@
import androidx.appcompat.widget.Toolbar;
import org.schabi.newpipe.R;
-import org.schabi.newpipe.util.AndroidTvUtils;
+import org.schabi.newpipe.util.DeviceUtils;
import org.schabi.newpipe.util.ThemeHelper;
import org.schabi.newpipe.views.FocusOverlayView;
@@ -57,7 +57,7 @@ public void onGlobalLayout() {
}
});
- if (AndroidTvUtils.isTv(this)) {
+ if (DeviceUtils.isTv(this)) {
FocusOverlayView.setupFocusObserver(this);
}
}
diff --git a/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java
index a87864a63a6..5310570c8d3 100644
--- a/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java
+++ b/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java
@@ -92,7 +92,7 @@
import org.schabi.newpipe.player.playqueue.SinglePlayQueue;
import org.schabi.newpipe.report.ErrorActivity;
import org.schabi.newpipe.report.UserAction;
-import org.schabi.newpipe.util.AndroidTvUtils;
+import org.schabi.newpipe.util.DeviceUtils;
import org.schabi.newpipe.util.Constants;
import org.schabi.newpipe.util.ExtractorHelper;
import org.schabi.newpipe.util.ImageDisplayConstants;
@@ -767,7 +767,7 @@ protected void initViews(final View rootView, final Bundle savedInstanceState) {
thumbnailBackgroundButton.requestFocus();
- if (AndroidTvUtils.isTv(getContext())) {
+ if (DeviceUtils.isTv(getContext())) {
// remove ripple effects from detail controls
final int transparent = getResources().getColor(R.color.transparent_background_color);
detailControlsAddToPlaylist.setBackgroundColor(transparent);
@@ -880,7 +880,7 @@ public boolean onBackPressed() {
// If we are in fullscreen mode just exit from it via first back press
if (player != null && player.isFullscreen()) {
- if (!PlayerHelper.isTablet(activity)) {
+ if (!DeviceUtils.isTablet(activity)) {
player.onPause();
}
restoreDefaultOrientation();
@@ -1449,7 +1449,7 @@ private void restoreDefaultOrientation() {
// User can tap on Play button and video will be in fullscreen mode again
// Note for tablet: trying to avoid orientation changes since it's not easy
// to physically rotate the tablet every time
- if (!PlayerHelper.isTablet(activity)) {
+ if (!DeviceUtils.isTablet(activity)) {
activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
}
}
@@ -1945,7 +1945,7 @@ public void onScreenRotationButtonClicked() {
// 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() && PlayerHelper.isTablet(activity)) {
+ if (isLandscape() && DeviceUtils.isTablet(activity)) {
player.toggleFullscreen();
return;
}
@@ -2185,7 +2185,7 @@ public void onStateChanged(@NonNull final View bottomSheet, final int newState)
&& player != null
&& player.isPlaying()
&& !player.isFullscreen()
- && !PlayerHelper.isTablet(activity)
+ && !DeviceUtils.isTablet(activity)
&& player.videoPlayerSelected()) {
player.toggleFullscreen();
}
diff --git a/app/src/main/java/org/schabi/newpipe/fragments/list/search/SearchFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/list/search/SearchFragment.java
index 33ab001c764..12abc29aedd 100644
--- a/app/src/main/java/org/schabi/newpipe/fragments/list/search/SearchFragment.java
+++ b/app/src/main/java/org/schabi/newpipe/fragments/list/search/SearchFragment.java
@@ -48,7 +48,7 @@
import org.schabi.newpipe.local.history.HistoryRecordManager;
import org.schabi.newpipe.report.ErrorActivity;
import org.schabi.newpipe.report.UserAction;
-import org.schabi.newpipe.util.AndroidTvUtils;
+import org.schabi.newpipe.util.DeviceUtils;
import org.schabi.newpipe.util.AnimationUtils;
import org.schabi.newpipe.util.Constants;
import org.schabi.newpipe.util.ExtractorHelper;
@@ -525,7 +525,7 @@ private void initSearchListeners() {
if (isSuggestionsEnabled && errorPanelRoot.getVisibility() != View.VISIBLE) {
showSuggestionsPanel();
}
- if (AndroidTvUtils.isTv(getContext())) {
+ if (DeviceUtils.isTv(getContext())) {
showKeyboardSearch();
}
});
diff --git a/app/src/main/java/org/schabi/newpipe/info_list/holder/CommentsMiniInfoItemHolder.java b/app/src/main/java/org/schabi/newpipe/info_list/holder/CommentsMiniInfoItemHolder.java
index 863273a88e8..613ff4b6ff6 100644
--- a/app/src/main/java/org/schabi/newpipe/info_list/holder/CommentsMiniInfoItemHolder.java
+++ b/app/src/main/java/org/schabi/newpipe/info_list/holder/CommentsMiniInfoItemHolder.java
@@ -15,7 +15,7 @@
import org.schabi.newpipe.info_list.InfoItemBuilder;
import org.schabi.newpipe.local.history.HistoryRecordManager;
import org.schabi.newpipe.report.ErrorActivity;
-import org.schabi.newpipe.util.AndroidTvUtils;
+import org.schabi.newpipe.util.DeviceUtils;
import org.schabi.newpipe.util.CommentTextOnTouchListener;
import org.schabi.newpipe.util.ImageDisplayConstants;
import org.schabi.newpipe.util.Localization;
@@ -126,7 +126,7 @@ public void updateFromItem(final InfoItem infoItem,
itemView.setOnLongClickListener(view -> {
- if (AndroidTvUtils.isTv(itemBuilder.getContext())) {
+ if (DeviceUtils.isTv(itemBuilder.getContext())) {
openCommentAuthor(item);
} else {
ShareUtils.copyToClipboard(itemBuilder.getContext(), commentText);
diff --git a/app/src/main/java/org/schabi/newpipe/local/subscription/dialog/FeedGroupDialog.kt b/app/src/main/java/org/schabi/newpipe/local/subscription/dialog/FeedGroupDialog.kt
index 66387d29852..80036cd4a5c 100644
--- a/app/src/main/java/org/schabi/newpipe/local/subscription/dialog/FeedGroupDialog.kt
+++ b/app/src/main/java/org/schabi/newpipe/local/subscription/dialog/FeedGroupDialog.kt
@@ -40,7 +40,7 @@ import org.schabi.newpipe.local.subscription.dialog.FeedGroupDialogViewModel.Dia
import org.schabi.newpipe.local.subscription.item.EmptyPlaceholderItem
import org.schabi.newpipe.local.subscription.item.PickerIconItem
import org.schabi.newpipe.local.subscription.item.PickerSubscriptionItem
-import org.schabi.newpipe.util.AndroidTvUtils
+import org.schabi.newpipe.util.DeviceUtils
import org.schabi.newpipe.util.ThemeHelper
class FeedGroupDialog : DialogFragment(), BackPressable {
@@ -237,7 +237,7 @@ class FeedGroupDialog : DialogFragment(), BackPressable {
}
toolbar_search_edit_text.setOnClickListener {
- if (AndroidTvUtils.isTv(context)) {
+ if (DeviceUtils.isTv(context)) {
showKeyboardSearch()
}
}
diff --git a/app/src/main/java/org/schabi/newpipe/player/MainVideoPlayer.java b/app/src/main/java/org/schabi/newpipe/player/MainVideoPlayer.java
index 51e159469a9..f8788768538 100644
--- a/app/src/main/java/org/schabi/newpipe/player/MainVideoPlayer.java
+++ b/app/src/main/java/org/schabi/newpipe/player/MainVideoPlayer.java
@@ -80,7 +80,7 @@
import org.schabi.newpipe.player.playqueue.PlayQueueItemTouchCallback;
import org.schabi.newpipe.player.resolver.MediaSourceTag;
import org.schabi.newpipe.player.resolver.VideoPlaybackResolver;
-import org.schabi.newpipe.util.AndroidTvUtils;
+import org.schabi.newpipe.util.DeviceUtils;
import org.schabi.newpipe.util.AnimationUtils;
import org.schabi.newpipe.util.KoreUtil;
import org.schabi.newpipe.util.ListHelper;
@@ -179,7 +179,7 @@ public void onChange(final boolean selfChange) {
final String orientKey = getString(R.string.last_orientation_landscape_key);
final boolean lastOrientationWasLandscape = defaultPreferences
- .getBoolean(orientKey, AndroidTvUtils.isTv(getApplicationContext()));
+ .getBoolean(orientKey, DeviceUtils.isTv(getApplicationContext()));
setLandscape(lastOrientationWasLandscape);
} else {
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
@@ -191,7 +191,7 @@ public void onChange(final boolean selfChange) {
Settings.System.getUriFor(Settings.System.ACCELEROMETER_ROTATION),
false, rotationObserver);
- if (AndroidTvUtils.isTv(this)) {
+ if (DeviceUtils.isTv(this)) {
FocusOverlayView.setupFocusObserver(this);
}
}
@@ -223,7 +223,7 @@ public boolean onKeyDown(final int keyCode, final KeyEvent event) {
default:
break;
case KeyEvent.KEYCODE_BACK:
- if (AndroidTvUtils.isTv(getApplicationContext())
+ if (DeviceUtils.isTv(getApplicationContext())
&& playerImpl.isControlsVisible()) {
playerImpl.hideControls(0, 0);
hideSystemUi();
@@ -272,7 +272,7 @@ protected void onResume() {
final String orientKey = getString(R.string.last_orientation_landscape_key);
boolean lastOrientationWasLandscape = defaultPreferences
- .getBoolean(orientKey, AndroidTvUtils.isTv(getApplicationContext()));
+ .getBoolean(orientKey, DeviceUtils.isTv(getApplicationContext()));
setLandscape(lastOrientationWasLandscape);
}
diff --git a/app/src/main/java/org/schabi/newpipe/player/VideoPlayerImpl.java b/app/src/main/java/org/schabi/newpipe/player/VideoPlayerImpl.java
index ec01ef11e75..fd3f38ab7ae 100644
--- a/app/src/main/java/org/schabi/newpipe/player/VideoPlayerImpl.java
+++ b/app/src/main/java/org/schabi/newpipe/player/VideoPlayerImpl.java
@@ -94,7 +94,7 @@
import org.schabi.newpipe.player.resolver.AudioPlaybackResolver;
import org.schabi.newpipe.player.resolver.MediaSourceTag;
import org.schabi.newpipe.player.resolver.VideoPlaybackResolver;
-import org.schabi.newpipe.util.AndroidTvUtils;
+import org.schabi.newpipe.util.DeviceUtils;
import org.schabi.newpipe.util.AnimationUtils;
import org.schabi.newpipe.util.Constants;
import org.schabi.newpipe.util.KoreUtil;
@@ -117,7 +117,6 @@
import static org.schabi.newpipe.player.MainPlayer.NOTIFICATION_ID;
import static org.schabi.newpipe.player.helper.PlayerHelper.MinimizeMode.MINIMIZE_ON_EXIT_MODE_BACKGROUND;
import static org.schabi.newpipe.player.helper.PlayerHelper.getTimeString;
-import static org.schabi.newpipe.player.helper.PlayerHelper.isTablet;
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;
@@ -481,7 +480,7 @@ public boolean onKeyDown(final int keyCode) {
default:
break;
case KeyEvent.KEYCODE_BACK:
- if (AndroidTvUtils.isTv(service) && isControlsVisible()) {
+ if (DeviceUtils.isTv(service) && isControlsVisible()) {
hideControls(0, 0);
hideSystemUIIfNeeded();
return true;
@@ -930,7 +929,7 @@ private static void showInstallKoreDialog(final Context context) {
private void setupScreenRotationButton() {
final boolean orientationLocked = PlayerHelper.globalScreenOrientationLocked(service);
- final boolean tabletInLandscape = isTablet(service) && service.isLandscape();
+ final boolean tabletInLandscape = DeviceUtils.isTablet(service) && service.isLandscape();
final boolean showButton = videoPlayerSelected()
&& (orientationLocked || isVerticalVideo || tabletInLandscape);
screenRotationButton.setVisibility(showButton ? View.VISIBLE : View.GONE);
@@ -1542,7 +1541,7 @@ public void setControlsSize() {
// 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 = PlayerHelper.isTablet(service) || !service.isLandscape();
+ final boolean navBarAtTheBottom = DeviceUtils.isTablet(service) || !service.isLandscape();
controlsRoot.getLayoutParams().height = isFullscreen && !isInMultiWindow()
&& navBarAtTheBottom ? size.y : ViewGroup.LayoutParams.MATCH_PARENT;
controlsRoot.requestLayout();
@@ -1612,7 +1611,7 @@ && videoPlayerSelected()
if (parent != null
&& videoInLandscapeButNotInFullscreen
&& playingState
- && !PlayerHelper.isTablet(service)) {
+ && !DeviceUtils.isTablet(service)) {
toggleFullscreen();
}
diff --git a/app/src/main/java/org/schabi/newpipe/player/helper/PlayerHelper.java b/app/src/main/java/org/schabi/newpipe/player/helper/PlayerHelper.java
index bd681ec44c8..58732bda2a9 100644
--- a/app/src/main/java/org/schabi/newpipe/player/helper/PlayerHelper.java
+++ b/app/src/main/java/org/schabi/newpipe/player/helper/PlayerHelper.java
@@ -362,13 +362,6 @@ public static boolean globalScreenOrientationLocked(final Context context) {
context.getContentResolver(), Settings.System.ACCELEROMETER_ROTATION, 0) == 0;
}
- public static boolean isTablet(@NonNull final Context context) {
- return (context
- .getResources()
- .getConfiguration().screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK)
- >= Configuration.SCREENLAYOUT_SIZE_LARGE;
- }
-
////////////////////////////////////////////////////////////////////////////
// Private helpers
////////////////////////////////////////////////////////////////////////////
diff --git a/app/src/main/java/org/schabi/newpipe/settings/SettingsActivity.java b/app/src/main/java/org/schabi/newpipe/settings/SettingsActivity.java
index 18cbece6fb4..26a33917ffd 100644
--- a/app/src/main/java/org/schabi/newpipe/settings/SettingsActivity.java
+++ b/app/src/main/java/org/schabi/newpipe/settings/SettingsActivity.java
@@ -13,7 +13,7 @@
import androidx.preference.PreferenceFragmentCompat;
import org.schabi.newpipe.R;
-import org.schabi.newpipe.util.AndroidTvUtils;
+import org.schabi.newpipe.util.DeviceUtils;
import org.schabi.newpipe.util.ThemeHelper;
import org.schabi.newpipe.views.FocusOverlayView;
@@ -62,7 +62,7 @@ protected void onCreate(final Bundle savedInstanceBundle) {
.commit();
}
- if (AndroidTvUtils.isTv(this)) {
+ if (DeviceUtils.isTv(this)) {
FocusOverlayView.setupFocusObserver(this);
}
}
diff --git a/app/src/main/java/org/schabi/newpipe/util/AndroidTvUtils.java b/app/src/main/java/org/schabi/newpipe/util/DeviceUtils.java
similarity index 81%
rename from app/src/main/java/org/schabi/newpipe/util/AndroidTvUtils.java
rename to app/src/main/java/org/schabi/newpipe/util/DeviceUtils.java
index db2ab4aa709..0afa0663c99 100644
--- a/app/src/main/java/org/schabi/newpipe/util/AndroidTvUtils.java
+++ b/app/src/main/java/org/schabi/newpipe/util/DeviceUtils.java
@@ -8,22 +8,23 @@
import android.os.Build;
import android.view.KeyEvent;
+import androidx.annotation.NonNull;
import org.schabi.newpipe.App;
import static android.content.Context.BATTERY_SERVICE;
import static android.content.Context.UI_MODE_SERVICE;
-public final class AndroidTvUtils {
+public final class DeviceUtils {
private static final String AMAZON_FEATURE_FIRE_TV = "amazon.hardware.fire_tv";
private static Boolean isTV = null;
- private AndroidTvUtils() {
+ private DeviceUtils() {
}
public static boolean isTv(final Context context) {
- if (AndroidTvUtils.isTV != null) {
- return AndroidTvUtils.isTV;
+ if (isTV != null) {
+ return isTV;
}
PackageManager pm = App.getApp().getPackageManager();
@@ -48,8 +49,15 @@ public static boolean isTv(final Context context) {
isTv = isTv || pm.hasSystemFeature(PackageManager.FEATURE_LEANBACK);
}
- AndroidTvUtils.isTV = isTv;
- return AndroidTvUtils.isTV;
+ DeviceUtils.isTV = isTv;
+ return DeviceUtils.isTV;
+ }
+
+ public static boolean isTablet(@NonNull final Context context) {
+ return (context
+ .getResources()
+ .getConfiguration().screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK)
+ >= Configuration.SCREENLAYOUT_SIZE_LARGE;
}
public static boolean isConfirmKey(final int keyCode) {
diff --git a/app/src/main/java/org/schabi/newpipe/views/FocusAwareSeekBar.java b/app/src/main/java/org/schabi/newpipe/views/FocusAwareSeekBar.java
index 6dbcded485e..a50d5a64ca8 100644
--- a/app/src/main/java/org/schabi/newpipe/views/FocusAwareSeekBar.java
+++ b/app/src/main/java/org/schabi/newpipe/views/FocusAwareSeekBar.java
@@ -26,7 +26,7 @@
import androidx.appcompat.widget.AppCompatSeekBar;
-import org.schabi.newpipe.util.AndroidTvUtils;
+import org.schabi.newpipe.util.DeviceUtils;
/**
* SeekBar, adapted for directional navigation. It emulates touch-related callbacks
@@ -60,7 +60,7 @@ public void setOnSeekBarChangeListener(final OnSeekBarChangeListener l) {
@Override
public boolean onKeyDown(final int keyCode, final KeyEvent event) {
- if (!isInTouchMode() && AndroidTvUtils.isConfirmKey(keyCode)) {
+ if (!isInTouchMode() && DeviceUtils.isConfirmKey(keyCode)) {
releaseTrack();
}
From 77cd3182f10f616eba93768fbefd9001de09d22f Mon Sep 17 00:00:00 2001
From: Avently <7953703+avently@users.noreply.github.com>
Date: Tue, 21 Jul 2020 01:53:59 +0300
Subject: [PATCH 033/398] Removed unused line
---
.../main/java/org/schabi/newpipe/player/helper/PlayerHelper.java | 1 -
1 file changed, 1 deletion(-)
diff --git a/app/src/main/java/org/schabi/newpipe/player/helper/PlayerHelper.java b/app/src/main/java/org/schabi/newpipe/player/helper/PlayerHelper.java
index 58732bda2a9..0a4dd83ac4f 100644
--- a/app/src/main/java/org/schabi/newpipe/player/helper/PlayerHelper.java
+++ b/app/src/main/java/org/schabi/newpipe/player/helper/PlayerHelper.java
@@ -2,7 +2,6 @@
import android.content.Context;
import android.content.SharedPreferences;
-import android.content.res.Configuration;
import android.os.Build;
import android.preference.PreferenceManager;
import android.provider.Settings;
From 3ecbbea7cbcb5feba59e543835b4ff3edbf55edf Mon Sep 17 00:00:00 2001
From: Avently <7953703+avently@users.noreply.github.com>
Date: Wed, 22 Jul 2020 01:20:30 +0300
Subject: [PATCH 034/398] Better TV support, icons, activity_main refactoring -
on Android TV you'll be able to navigate with D-pad in main fragment and in
the player. But not between them for now - play/pause/next/previous buttons
are smaller now - replaced ic_list with previous version of it -
activity_main looks better which helps with Android TV support
---
.../fragments/detail/VideoDetailFragment.java | 10 +++---
.../schabi/newpipe/player/VideoPlayer.java | 2 +-
.../newpipe/player/VideoPlayerImpl.java | 15 +--------
.../main/res/drawable/ic_list_black_24dp.xml | 11 ++++---
.../main/res/drawable/ic_list_white_24dp.xml | 12 +++----
.../activity_main_player.xml | 18 ++++++-----
app/src/main/res/layout/activity_main.xml | 31 +++++++------------
.../main/res/layout/activity_main_player.xml | 18 ++++++-----
.../layout/activity_player_queue_control.xml | 8 ++---
app/src/main/res/values/strings.xml | 2 +-
10 files changed, 53 insertions(+), 74 deletions(-)
diff --git a/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java
index 5310570c8d3..a83acd47648 100644
--- a/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java
+++ b/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java
@@ -570,10 +570,6 @@ protected void onRestoreInstanceState(@NonNull final Bundle savedState) {
@Override
public void onClick(final View v) {
- if (isLoading.get() || currentInfo == null) {
- return;
- }
-
switch (v.getId()) {
case R.id.detail_controls_background:
openBackgroundPlayer(false);
@@ -2168,6 +2164,7 @@ private void setupBottomPlayer() {
@Override
public void onStateChanged(@NonNull final View bottomSheet, final int newState) {
bottomSheetState = newState;
+ ViewGroup mainFragment = requireActivity().findViewById(R.id.fragment_holder);
switch (newState) {
case BottomSheetBehavior.STATE_HIDDEN:
@@ -2175,6 +2172,7 @@ public void onStateChanged(@NonNull final View bottomSheet, final int newState)
cleanUp();
break;
case BottomSheetBehavior.STATE_EXPANDED:
+ mainFragment.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
bottomSheetBehavior.setPeekHeight(peekHeight);
// Disable click because overlay buttons located on top of buttons
// from the player
@@ -2191,6 +2189,8 @@ public void onStateChanged(@NonNull final View bottomSheet, final int newState)
}
break;
case BottomSheetBehavior.STATE_COLLAPSED:
+ mainFragment.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
+ mainFragment.requestFocus();
// Re-enable clicks
setOverlayElementsClickable(true);
if (player != null) {
@@ -2236,7 +2236,7 @@ private void updateOverlayData(@Nullable final String title,
}
private void setOverlayPlayPauseImage() {
- final int attr = player != null && player.getPlayer().getPlayWhenReady()
+ final int attr = player != null && player.isPlaying()
? R.attr.ic_pause
: R.attr.ic_play_arrow;
overlayPlayPauseButton.setImageResource(
diff --git a/app/src/main/java/org/schabi/newpipe/player/VideoPlayer.java b/app/src/main/java/org/schabi/newpipe/player/VideoPlayer.java
index 51f9f3ca2b6..e621f9f33e4 100644
--- a/app/src/main/java/org/schabi/newpipe/player/VideoPlayer.java
+++ b/app/src/main/java/org/schabi/newpipe/player/VideoPlayer.java
@@ -204,7 +204,7 @@ public void initViews(final View view) {
final CaptionStyleCompat captionStyle = PlayerHelper.getCaptionStyle(context);
setupSubtitleView(subtitleView, captionScale, captionStyle);
- this.resizeView = view.findViewById(R.id.resizeTextView);
+ this.resizeView = view.findViewById(R.id.resizeTextView);
resizeView.setText(PlayerHelper
.resizeTypeOf(context, getSurfaceView().getResizeMode()));
diff --git a/app/src/main/java/org/schabi/newpipe/player/VideoPlayerImpl.java b/app/src/main/java/org/schabi/newpipe/player/VideoPlayerImpl.java
index fd3f38ab7ae..4eea23a0b88 100644
--- a/app/src/main/java/org/schabi/newpipe/player/VideoPlayerImpl.java
+++ b/app/src/main/java/org/schabi/newpipe/player/VideoPlayerImpl.java
@@ -22,8 +22,6 @@
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.annotation.SuppressLint;
-import android.content.Context;
-import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
@@ -60,7 +58,6 @@
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
-import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.content.res.AppCompatResources;
import androidx.recyclerview.widget.ItemTouchHelper;
@@ -892,7 +889,7 @@ private void onPlayWithKodiClicked() {
if (DEBUG) {
Log.i(TAG, "Failed to start kore", e);
}
- showInstallKoreDialog(getParentActivity());
+ KoreUtil.showInstallKoreDialog(getParentActivity());
}
}
@@ -917,16 +914,6 @@ private void showHideKodiButton() {
? View.VISIBLE : View.GONE);
}
- private static void showInstallKoreDialog(final Context context) {
- final AlertDialog.Builder builder = new AlertDialog.Builder(context);
- builder.setMessage(R.string.kore_not_found)
- .setPositiveButton(R.string.install, (DialogInterface dialog, int which) ->
- NavigationHelper.installKore(context))
- .setNegativeButton(R.string.cancel, (DialogInterface dialog, int which) -> {
- });
- builder.create().show();
- }
-
private void setupScreenRotationButton() {
final boolean orientationLocked = PlayerHelper.globalScreenOrientationLocked(service);
final boolean tabletInLandscape = DeviceUtils.isTablet(service) && service.isLandscape();
diff --git a/app/src/main/res/drawable/ic_list_black_24dp.xml b/app/src/main/res/drawable/ic_list_black_24dp.xml
index 7020c1c569e..4c2fb88349a 100644
--- a/app/src/main/res/drawable/ic_list_black_24dp.xml
+++ b/app/src/main/res/drawable/ic_list_black_24dp.xml
@@ -1,8 +1,9 @@
-
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+
diff --git a/app/src/main/res/drawable/ic_list_white_24dp.xml b/app/src/main/res/drawable/ic_list_white_24dp.xml
index c9ae060174a..f47037629f0 100644
--- a/app/src/main/res/drawable/ic_list_white_24dp.xml
+++ b/app/src/main/res/drawable/ic_list_white_24dp.xml
@@ -1,9 +1,5 @@
-
-
+
+
diff --git a/app/src/main/res/layout-large-land/activity_main_player.xml b/app/src/main/res/layout-large-land/activity_main_player.xml
index 92288933b06..91627f2d4e5 100644
--- a/app/src/main/res/layout-large-land/activity_main_player.xml
+++ b/app/src/main/res/layout-large-land/activity_main_player.xml
@@ -247,9 +247,12 @@
-
-
-
+ android:layout_height="match_parent">
+
-
-
-
+ android:id="@+id/fragment_player_holder"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_gravity="center_horizontal"
+ app:behavior_hideable="true"
+ app:behavior_peekHeight="0dp"
+ app:layout_behavior="org.schabi.newpipe.player.event.CustomBottomSheetBehavior">
-
-
+
diff --git a/app/src/main/res/layout/activity_main_player.xml b/app/src/main/res/layout/activity_main_player.xml
index e4a1e7c0c39..fabb46bcc26 100644
--- a/app/src/main/res/layout/activity_main_player.xml
+++ b/app/src/main/res/layout/activity_main_player.xml
@@ -250,9 +250,12 @@
-
Use fast inexact seek
Inexact seek allows the player to seek to positions faster with reduced precision. Seeking for 5, 15 or 25 seconds doesn\'t work with this.
Fast-forward/-rewind seek duration
- Ask confirmation before clearing a queue
+ Ask for confirmation before clearing a queue
After switching from one player to another your queue may be replaced
Queue from the active player will be replaced
Load thumbnails
From 7aa8a5c368e0142ff0008c9c0c7c876477b8935f Mon Sep 17 00:00:00 2001
From: Avently <7953703+avently@users.noreply.github.com>
Date: Wed, 22 Jul 2020 02:20:58 +0300
Subject: [PATCH 035/398] Fixed a situation when background playback could use
a video stream instead of an audio stream
---
.../fragments/detail/VideoDetailFragment.java | 4 +-
.../newpipe/player/VideoPlayerImpl.java | 42 ++++++++++++-------
2 files changed, 30 insertions(+), 16 deletions(-)
diff --git a/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java
index a83acd47648..c920a103ad7 100644
--- a/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java
+++ b/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java
@@ -2164,10 +2164,10 @@ private void setupBottomPlayer() {
@Override
public void onStateChanged(@NonNull final View bottomSheet, final int newState) {
bottomSheetState = newState;
- ViewGroup mainFragment = requireActivity().findViewById(R.id.fragment_holder);
-
+ final ViewGroup mainFragment = requireActivity().findViewById(R.id.fragment_holder);
switch (newState) {
case BottomSheetBehavior.STATE_HIDDEN:
+ mainFragment.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
bottomSheetBehavior.setPeekHeight(0);
cleanUp();
break;
diff --git a/app/src/main/java/org/schabi/newpipe/player/VideoPlayerImpl.java b/app/src/main/java/org/schabi/newpipe/player/VideoPlayerImpl.java
index 4eea23a0b88..435396fd692 100644
--- a/app/src/main/java/org/schabi/newpipe/player/VideoPlayerImpl.java
+++ b/app/src/main/java/org/schabi/newpipe/player/VideoPlayerImpl.java
@@ -187,6 +187,7 @@ public class VideoPlayerImpl extends VideoPlayer
private boolean audioOnly = false;
private boolean isFullscreen = false;
private boolean isVerticalVideo = false;
+ private boolean fragmentIsVisible = false;
boolean shouldUpdateOnProgress;
int timesNotificationUpdated;
@@ -1224,28 +1225,22 @@ public void onBroadcastReceived(final Intent intent) {
break;
case ACTION_PLAY_PAUSE:
onPlayPause();
+ if (!fragmentIsVisible) {
+ // Ensure that we have audio-only stream playing when a user
+ // started to play from notification's play button from outside of the app
+ onFragmentStopped();
+ }
break;
case ACTION_REPEAT:
onRepeatClicked();
break;
case VideoDetailFragment.ACTION_VIDEO_FRAGMENT_RESUMED:
+ fragmentIsVisible = true;
useVideoSource(true);
break;
case VideoDetailFragment.ACTION_VIDEO_FRAGMENT_STOPPED:
- // This will be called when user goes to another app/activity, turns off a screen.
- // We don't want to interrupt playback and don't want to see notification
- // if player is stopped.
- // Next lines of code will enable background playback if needed
- if (videoPlayerSelected() && (isPlaying() || isLoading())) {
- if (backgroundPlaybackEnabled()) {
- useVideoSource(false);
- } else if (minimizeOnPopupEnabled()) {
- setRecovery();
- NavigationHelper.playOnPopupPlayer(getParentActivity(), playQueue, true);
- } else {
- onPause();
- }
- }
+ fragmentIsVisible = false;
+ onFragmentStopped();
break;
case Intent.ACTION_CONFIGURATION_CHANGED:
assureCorrectAppLanguage(service);
@@ -1998,6 +1993,7 @@ private boolean popupHasParent() {
public void setFragmentListener(final PlayerServiceEventListener listener) {
fragmentListener = listener;
+ fragmentIsVisible = true;
updateMetadata();
updatePlayback();
triggerProgressUpdate();
@@ -2072,6 +2068,24 @@ void stopActivityBinding() {
}
}
+ /**
+ * This will be called when a user goes to another app/activity, turns off a screen.
+ * We don't want to interrupt playback and don't want to see notification so
+ * next lines of code will enable audio-only playback only if needed
+ * */
+ private void onFragmentStopped() {
+ if (videoPlayerSelected() && (isPlaying() || isLoading())) {
+ if (backgroundPlaybackEnabled()) {
+ useVideoSource(false);
+ } else if (minimizeOnPopupEnabled()) {
+ setRecovery();
+ NavigationHelper.playOnPopupPlayer(getParentActivity(), playQueue, true);
+ } else {
+ onPause();
+ }
+ }
+ }
+
///////////////////////////////////////////////////////////////////////////
// Getters
///////////////////////////////////////////////////////////////////////////
From 91a0257c8f1a4b190936bc933ed18f8ee081d876 Mon Sep 17 00:00:00 2001
From: Avently <7953703+avently@users.noreply.github.com>
Date: Wed, 22 Jul 2020 17:19:32 +0300
Subject: [PATCH 036/398] Fixes for Android API <21
---
.../schabi/newpipe/player/VideoPlayerImpl.java | 18 +++++++++---------
.../fragment_video_detail.xml | 2 +-
.../main/res/layout/fragment_video_detail.xml | 2 +-
3 files changed, 11 insertions(+), 11 deletions(-)
diff --git a/app/src/main/java/org/schabi/newpipe/player/VideoPlayerImpl.java b/app/src/main/java/org/schabi/newpipe/player/VideoPlayerImpl.java
index 435396fd692..70642481e29 100644
--- a/app/src/main/java/org/schabi/newpipe/player/VideoPlayerImpl.java
+++ b/app/src/main/java/org/schabi/newpipe/player/VideoPlayerImpl.java
@@ -370,7 +370,7 @@ private void setupElementsVisibility() {
getTopControlsRoot().setOrientation(LinearLayout.VERTICAL);
primaryControls.getLayoutParams().width = LinearLayout.LayoutParams.MATCH_PARENT;
secondaryControls.setVisibility(View.INVISIBLE);
- moreOptionsButton.setImageDrawable(service.getResources().getDrawable(
+ moreOptionsButton.setImageDrawable(AppCompatResources.getDrawable(service,
R.drawable.ic_expand_more_white_24dp));
shareButton.setVisibility(View.VISIBLE);
showHideKodiButton();
@@ -921,9 +921,9 @@ private void setupScreenRotationButton() {
final boolean showButton = videoPlayerSelected()
&& (orientationLocked || isVerticalVideo || tabletInLandscape);
screenRotationButton.setVisibility(showButton ? View.VISIBLE : View.GONE);
- screenRotationButton.setImageDrawable(service.getResources().getDrawable(isFullscreen()
- ? R.drawable.ic_fullscreen_exit_white_24dp
- : R.drawable.ic_fullscreen_white_24dp));
+ screenRotationButton.setImageDrawable(AppCompatResources.getDrawable(service, isFullscreen()
+ ? R.drawable.ic_fullscreen_exit_white_24dp
+ : R.drawable.ic_fullscreen_white_24dp));
}
private void prepareOrientation() {
@@ -1077,7 +1077,7 @@ public void onBlocked() {
getRootView().setKeepScreenOn(false);
service.resetNotification();
- service.updateNotification(R.drawable.ic_play_arrow_white_24dp);
+ service.updateNotification(R.drawable.exo_controls_play);
}
@Override
@@ -1086,7 +1086,7 @@ public void onBuffering() {
getRootView().setKeepScreenOn(true);
service.resetNotification();
- service.updateNotification(R.drawable.ic_play_arrow_white_24dp);
+ service.updateNotification(R.drawable.exo_controls_play);
}
@Override
@@ -1103,7 +1103,7 @@ public void onPlaying() {
getRootView().setKeepScreenOn(true);
service.resetNotification();
- service.updateNotification(R.drawable.ic_pause_white_24dp);
+ service.updateNotification(R.drawable.exo_controls_pause);
service.startForeground(NOTIFICATION_ID, service.getNotBuilder().build());
}
@@ -1120,7 +1120,7 @@ public void onPaused() {
updateWindowFlags(IDLE_WINDOW_FLAGS);
service.resetNotification();
- service.updateNotification(R.drawable.ic_play_arrow_white_24dp);
+ service.updateNotification(R.drawable.exo_controls_play);
// Remove running notification when user don't want music (or video in popup)
// to be played in background
@@ -1138,7 +1138,7 @@ public void onPausedSeek() {
getRootView().setKeepScreenOn(true);
service.resetNotification();
- service.updateNotification(R.drawable.ic_play_arrow_white_24dp);
+ service.updateNotification(R.drawable.exo_controls_play);
}
diff --git a/app/src/main/res/layout-large-land/fragment_video_detail.xml b/app/src/main/res/layout-large-land/fragment_video_detail.xml
index 192993c820e..e2a611b08fc 100644
--- a/app/src/main/res/layout-large-land/fragment_video_detail.xml
+++ b/app/src/main/res/layout-large-land/fragment_video_detail.xml
@@ -675,7 +675,7 @@
android:layout_marginRight="2dp"
android:padding="10dp"
android:scaleType="center"
- android:src="?attr/ic_play_arrow"
+ app:srcCompat="?attr/ic_play_arrow"
android:background="?attr/selectableItemBackground"
tools:ignore="ContentDescription,RtlHardcoded"/>
diff --git a/app/src/main/res/layout/fragment_video_detail.xml b/app/src/main/res/layout/fragment_video_detail.xml
index cc1f2564669..1dd5a713516 100644
--- a/app/src/main/res/layout/fragment_video_detail.xml
+++ b/app/src/main/res/layout/fragment_video_detail.xml
@@ -648,7 +648,7 @@
android:layout_marginRight="2dp"
android:padding="10dp"
android:scaleType="center"
- android:src="?attr/ic_play_arrow"
+ app:srcCompat="?attr/ic_play_arrow"
android:background="?attr/selectableItemBackground"
tools:ignore="ContentDescription,RtlHardcoded"/>
From a1200a5fff3316e4a1fcf121d1229c483539ef02 Mon Sep 17 00:00:00 2001
From: Ajeje Brazorf
Date: Wed, 22 Jul 2020 19:15:35 +0200
Subject: [PATCH 037/398] Added translation using Weblate (Sardinian)
---
app/src/main/res/values-sc/strings.xml | 2 ++
1 file changed, 2 insertions(+)
create mode 100644 app/src/main/res/values-sc/strings.xml
diff --git a/app/src/main/res/values-sc/strings.xml b/app/src/main/res/values-sc/strings.xml
new file mode 100644
index 00000000000..a6b3daec935
--- /dev/null
+++ b/app/src/main/res/values-sc/strings.xml
@@ -0,0 +1,2 @@
+
+
\ No newline at end of file
From 7c79d421e8928d0596e13ab043b87f2fd3946a3a Mon Sep 17 00:00:00 2001
From: Avently <7953703+avently@users.noreply.github.com>
Date: Fri, 24 Jul 2020 00:43:09 +0300
Subject: [PATCH 038/398] Quality selector for external playback and better
fullscreen mode for old devices
---
.../fragments/detail/VideoDetailFragment.java | 41 ++++++++++++-------
.../newpipe/player/VideoPlayerImpl.java | 4 +-
2 files changed, 30 insertions(+), 15 deletions(-)
diff --git a/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java
index c920a103ad7..be7d0316a3e 100644
--- a/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java
+++ b/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java
@@ -370,7 +370,7 @@ private void stopService(final Context context) {
/*////////////////////////////////////////////////////////////////////////*/
public static VideoDetailFragment getInstance(final int serviceId, final String videoUrl,
- final String name, final PlayQueue playQueue) {
+ final String name, final PlayQueue playQueue) {
VideoDetailFragment instance = new VideoDetailFragment();
instance.setInitialData(serviceId, videoUrl, name, playQueue);
return instance;
@@ -1142,11 +1142,7 @@ private void openPopupPlayer(final boolean append) {
private void openVideoPlayer() {
if (PreferenceManager.getDefaultSharedPreferences(activity)
.getBoolean(this.getString(R.string.use_external_video_player_key), false)) {
- final VideoStream selectedVideoStream = getSelectedVideoStream();
- if (selectedVideoStream == null) {
- return;
- }
- startOnExternalPlayer(activity, currentInfo, selectedVideoStream);
+ showExternalPlaybackDialog();
} else {
replaceQueueIfUserConfirms(this::openMainPlayer);
}
@@ -1302,12 +1298,6 @@ private void makeDefaultHeightForVideoPlaceholder() {
viewHolder.requestLayout();
}
-
- @Nullable
- private VideoStream getSelectedVideoStream() {
- return sortedVideoStreams != null ? sortedVideoStreams.get(selectedVideoStreamIndex) : null;
- }
-
private void prepareDescription(final Description description) {
if (description == null || TextUtils.isEmpty(description.getContent())
|| description == Description.emptyDescription) {
@@ -2113,8 +2103,7 @@ && playerIsNotStopped()
private void showClearingQueueConfirmation(final Runnable onAllow) {
new AlertDialog.Builder(activity)
- .setTitle(R.string.confirm_prompt)
- .setMessage(R.string.clear_queue_confirmation_description)
+ .setTitle(R.string.clear_queue_confirmation_description)
.setNegativeButton(android.R.string.cancel, null)
.setPositiveButton(android.R.string.yes, (dialog, which) -> {
onAllow.run();
@@ -2122,6 +2111,30 @@ private void showClearingQueueConfirmation(final Runnable onAllow) {
}).show();
}
+ private void showExternalPlaybackDialog() {
+ if (sortedVideoStreams == null) {
+ return;
+ }
+ CharSequence[] resolutions = new CharSequence[sortedVideoStreams.size()];
+ for (int i = 0; i < sortedVideoStreams.size(); i++) {
+ resolutions[i] = sortedVideoStreams.get(i).getResolution();
+ }
+ AlertDialog.Builder builder = new AlertDialog.Builder(activity)
+ .setNegativeButton(android.R.string.cancel, null)
+ .setNeutralButton(R.string.open_in_browser, (dialog, i) ->
+ ShareUtils.openUrlInBrowser(requireActivity(), url)
+ );
+ // Maybe there are no video streams available, show just `open in browser` button
+ if (resolutions.length > 0) {
+ builder.setSingleChoiceItems(resolutions, selectedVideoStreamIndex, (dialog, i) -> {
+ dialog.dismiss();
+ startOnExternalPlayer(activity, currentInfo, sortedVideoStreams.get(i));
+ }
+ );
+ }
+ builder.show();
+ }
+
/*
* Remove unneeded information while waiting for a next task
* */
diff --git a/app/src/main/java/org/schabi/newpipe/player/VideoPlayerImpl.java b/app/src/main/java/org/schabi/newpipe/player/VideoPlayerImpl.java
index 70642481e29..0c5bfd8f692 100644
--- a/app/src/main/java/org/schabi/newpipe/player/VideoPlayerImpl.java
+++ b/app/src/main/java/org/schabi/newpipe/player/VideoPlayerImpl.java
@@ -1463,7 +1463,9 @@ private void showOrHideButtons() {
private void showSystemUIPartially() {
if (isFullscreen() && getParentActivity() != null) {
- 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_HIDE_NAVIGATION;
getParentActivity().getWindow().getDecorView().setSystemUiVisibility(visibility);
}
}
From 08db1d59e57d5c0db46911e2894b85b7c1de613e Mon Sep 17 00:00:00 2001
From: Avently <7953703+avently@users.noreply.github.com>
Date: Sat, 25 Jul 2020 04:14:29 +0300
Subject: [PATCH 039/398] Android TV: ability to select all buttons in the main
player, as well as in the main fragment
---
.../fragments/detail/VideoDetailFragment.java | 37 ++++-
.../newpipe/player/VideoPlayerImpl.java | 28 ++--
.../newpipe/views/FocusOverlayView.java | 15 +-
.../activity_main_player.xml | 153 +++++++++---------
.../fragment_video_detail.xml | 3 +
.../main/res/layout/activity_main_player.xml | 148 +++++++++--------
6 files changed, 216 insertions(+), 168 deletions(-)
diff --git a/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java
index be7d0316a3e..1d83094dc15 100644
--- a/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java
+++ b/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java
@@ -34,6 +34,7 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog;
+import androidx.appcompat.widget.Toolbar;
import androidx.coordinatorlayout.widget.CoordinatorLayout;
import com.google.android.exoplayer2.ExoPlaybackException;
import com.google.android.exoplayer2.PlaybackParameters;
@@ -2154,6 +2155,30 @@ private void cleanUp() {
// Bottom mini player
//////////////////////////////////////////////////////////////////////////*/
+ /**
+ * That's for Android TV support. Move focus from main fragment to the player or back
+ * based on what is currently selected
+ * @param toMain if true than the main fragment will be focused or the player otherwise
+ * */
+ private void moveFocusToMainFragment(final boolean toMain) {
+ final ViewGroup mainFragment = requireActivity().findViewById(R.id.fragment_holder);
+ // Hamburger button steels a focus even under bottomSheet
+ final Toolbar toolbar = requireActivity().findViewById(R.id.toolbar);
+ final int afterDescendants = ViewGroup.FOCUS_AFTER_DESCENDANTS;
+ final int blockDescendants = ViewGroup.FOCUS_BLOCK_DESCENDANTS;
+ if (toMain) {
+ mainFragment.setDescendantFocusability(afterDescendants);
+ toolbar.setDescendantFocusability(afterDescendants);
+ ((ViewGroup) requireView()).setDescendantFocusability(blockDescendants);
+ mainFragment.requestFocus();
+ } else {
+ mainFragment.setDescendantFocusability(blockDescendants);
+ toolbar.setDescendantFocusability(blockDescendants);
+ ((ViewGroup) requireView()).setDescendantFocusability(afterDescendants);
+ thumbnailBackgroundButton.requestFocus();
+ }
+ }
+
private void setupBottomPlayer() {
final CoordinatorLayout.LayoutParams params =
(CoordinatorLayout.LayoutParams) appBarLayout.getLayoutParams();
@@ -2177,15 +2202,17 @@ private void setupBottomPlayer() {
@Override
public void onStateChanged(@NonNull final View bottomSheet, final int newState) {
bottomSheetState = newState;
- final ViewGroup mainFragment = requireActivity().findViewById(R.id.fragment_holder);
+
switch (newState) {
case BottomSheetBehavior.STATE_HIDDEN:
- mainFragment.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
+ moveFocusToMainFragment(true);
+
bottomSheetBehavior.setPeekHeight(0);
cleanUp();
break;
case BottomSheetBehavior.STATE_EXPANDED:
- mainFragment.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
+ moveFocusToMainFragment(false);
+
bottomSheetBehavior.setPeekHeight(peekHeight);
// Disable click because overlay buttons located on top of buttons
// from the player
@@ -2202,8 +2229,8 @@ public void onStateChanged(@NonNull final View bottomSheet, final int newState)
}
break;
case BottomSheetBehavior.STATE_COLLAPSED:
- mainFragment.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
- mainFragment.requestFocus();
+ moveFocusToMainFragment(true);
+
// Re-enable clicks
setOverlayElementsClickable(true);
if (player != null) {
diff --git a/app/src/main/java/org/schabi/newpipe/player/VideoPlayerImpl.java b/app/src/main/java/org/schabi/newpipe/player/VideoPlayerImpl.java
index 0c5bfd8f692..8a4f7fdc576 100644
--- a/app/src/main/java/org/schabi/newpipe/player/VideoPlayerImpl.java
+++ b/app/src/main/java/org/schabi/newpipe/player/VideoPlayerImpl.java
@@ -480,7 +480,6 @@ public boolean onKeyDown(final int keyCode) {
case KeyEvent.KEYCODE_BACK:
if (DeviceUtils.isTv(service) && isControlsVisible()) {
hideControls(0, 0);
- hideSystemUIIfNeeded();
return true;
}
break;
@@ -499,7 +498,9 @@ public boolean onKeyDown(final int keyCode) {
}
if (!isControlsVisible()) {
- playPauseButton.requestFocus();
+ if (!queueVisible) {
+ playPauseButton.requestFocus();
+ }
showControlsThenHide();
showSystemUIPartially();
return true;
@@ -805,7 +806,7 @@ public void onClick(final View v) {
if (v.getId() == playPauseButton.getId()) {
hideControls(0, 0);
} else {
- safeHideControls(DEFAULT_CONTROLS_DURATION, DEFAULT_CONTROLS_HIDE_TIME);
+ hideControls(DEFAULT_CONTROLS_DURATION, DEFAULT_CONTROLS_HIDE_TIME);
}
}
});
@@ -830,6 +831,7 @@ private void onQueueClicked() {
updatePlaybackButtons();
getControlsRoot().setVisibility(View.INVISIBLE);
+ queueLayout.requestFocus();
animateView(queueLayout, SLIDE_AND_ALPHA, true,
DEFAULT_CONTROLS_DURATION);
@@ -848,6 +850,7 @@ public void onQueueClosed() {
queueLayout.setTranslationY(-queueLayout.getHeight() * 5);
});
queueVisible = false;
+ playPauseButton.requestFocus();
}
private void onMoreOptionsClicked() {
@@ -1095,7 +1098,9 @@ public void onPlaying() {
animateView(playPauseButton, AnimationUtils.Type.SCALE_AND_ALPHA, false, 80, 0, () -> {
playPauseButton.setImageResource(R.drawable.ic_pause_white_24dp);
animatePlayButtons(true, 200);
- playPauseButton.requestFocus();
+ if (!queueVisible) {
+ playPauseButton.requestFocus();
+ }
});
updateWindowFlags(ONGOING_PLAYBACK_WINDOW_FLAGS);
@@ -1114,7 +1119,9 @@ public void onPaused() {
animateView(playPauseButton, AnimationUtils.Type.SCALE_AND_ALPHA, false, 80, 0, () -> {
playPauseButton.setImageResource(R.drawable.ic_play_arrow_white_24dp);
animatePlayButtons(true, 200);
- playPauseButton.requestFocus();
+ if (!queueVisible) {
+ playPauseButton.requestFocus();
+ }
});
updateWindowFlags(IDLE_WINDOW_FLAGS);
@@ -1401,12 +1408,10 @@ public boolean isFullscreen() {
return isFullscreen;
}
- @Override
public void showControlsThenHide() {
- if (queueVisible) {
- return;
+ if (DEBUG) {
+ Log.d(TAG, "showControlsThenHide() called");
}
-
showOrHideButtons();
showSystemUIPartially();
super.showControlsThenHide();
@@ -1414,10 +1419,9 @@ public void showControlsThenHide() {
@Override
public void showControls(final long duration) {
- if (queueVisible) {
- return;
+ if (DEBUG) {
+ Log.d(TAG, "showControls() called with: duration = [" + duration + "]");
}
-
showOrHideButtons();
showSystemUIPartially();
super.showControls(duration);
diff --git a/app/src/main/java/org/schabi/newpipe/views/FocusOverlayView.java b/app/src/main/java/org/schabi/newpipe/views/FocusOverlayView.java
index 1c868f66a7d..b23f98d7975 100644
--- a/app/src/main/java/org/schabi/newpipe/views/FocusOverlayView.java
+++ b/app/src/main/java/org/schabi/newpipe/views/FocusOverlayView.java
@@ -38,6 +38,7 @@
import android.view.Window;
import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import androidx.appcompat.view.WindowCallbackWrapper;
@@ -113,7 +114,9 @@ private void updateRect() {
if (focusedView != null) {
focusedView.getGlobalVisibleRect(focusRect);
- } else {
+ }
+
+ if (shouldClearFocusRect(focusedView, focusRect)) {
focusRect.setEmpty();
}
@@ -184,6 +187,16 @@ public void setAlpha(final int alpha) {
public void setColorFilter(final ColorFilter colorFilter) {
}
+ /*
+ * When any view in the player looses it's focus (after setVisibility(GONE)) the focus gets
+ * added to the whole fragment which has a width and height equal to the window frame.
+ * The easiest way to avoid the unneeded frame is to skip highlighting of rect that is
+ * equal to the overlayView bounds
+ * */
+ private boolean shouldClearFocusRect(@Nullable final View focusedView, final Rect focusedRect) {
+ return focusedView == null || focusedRect.equals(getBounds());
+ }
+
public static void setupFocusObserver(final Dialog dialog) {
Rect displayRect = new Rect();
diff --git a/app/src/main/res/layout-large-land/activity_main_player.xml b/app/src/main/res/layout-large-land/activity_main_player.xml
index 91627f2d4e5..46edda8b78e 100644
--- a/app/src/main/res/layout-large-land/activity_main_player.xml
+++ b/app/src/main/res/layout-large-land/activity_main_player.xml
@@ -38,81 +38,6 @@
tools:ignore="ContentDescription"
tools:visibility="visible"/>
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
@@ -431,6 +358,7 @@
android:paddingBottom="4dp"
android:paddingTop="8dp"
tools:progress="25"
+ android:nextFocusDown="@id/screenRotationButton"
tools:secondaryProgress="50"/>
@@ -522,6 +451,80 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -602,6 +604,7 @@
android:alpha="0.9"
android:paddingLeft="@dimen/video_item_search_padding"
android:paddingRight="@dimen/video_item_search_padding"
+ android:descendantFocusability="blocksDescendants"
android:background="?attr/windowBackground" >
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Date: Sat, 25 Jul 2020 07:00:53 +0300
Subject: [PATCH 040/398] Another part of UI improvements for Android TV -
focus will be hidden right after start of a video; fullscreen works like this
too - back button will not needed to be pressed one more time like before -
prev & next buttons for playqueue will be hidden with play/pause button
before video be ready to play
---
.../fragments/detail/VideoDetailFragment.java | 3 ++-
.../java/org/schabi/newpipe/player/MainPlayer.java | 3 +++
.../org/schabi/newpipe/player/VideoPlayerImpl.java | 7 +++++--
.../res/layout-large-land/fragment_video_detail.xml | 12 ++++++------
4 files changed, 16 insertions(+), 9 deletions(-)
diff --git a/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java
index 1d83094dc15..6c459ffe9bd 100644
--- a/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java
+++ b/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java
@@ -2158,8 +2158,9 @@ private void cleanUp() {
/**
* That's for Android TV support. Move focus from main fragment to the player or back
* based on what is currently selected
+ *
* @param toMain if true than the main fragment will be focused or the player otherwise
- * */
+ */
private void moveFocusToMainFragment(final boolean toMain) {
final ViewGroup mainFragment = requireActivity().findViewById(R.id.fragment_holder);
// Hamburger button steels a focus even under bottomSheet
diff --git a/app/src/main/java/org/schabi/newpipe/player/MainPlayer.java b/app/src/main/java/org/schabi/newpipe/player/MainPlayer.java
index 53296d915a5..703be346ecf 100644
--- a/app/src/main/java/org/schabi/newpipe/player/MainPlayer.java
+++ b/app/src/main/java/org/schabi/newpipe/player/MainPlayer.java
@@ -163,6 +163,9 @@ public void stop(final boolean autoplayEnabled) {
// from one stream to a new stream not smooth
playerImpl.getPlayer().stop(false);
playerImpl.setRecovery();
+ // 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);
// 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.
diff --git a/app/src/main/java/org/schabi/newpipe/player/VideoPlayerImpl.java b/app/src/main/java/org/schabi/newpipe/player/VideoPlayerImpl.java
index 8a4f7fdc576..d2eb591f408 100644
--- a/app/src/main/java/org/schabi/newpipe/player/VideoPlayerImpl.java
+++ b/app/src/main/java/org/schabi/newpipe/player/VideoPlayerImpl.java
@@ -253,9 +253,12 @@ public void handleIntent(final Intent intent) {
getRootView().setVisibility(View.VISIBLE);
initPopup();
initPopupCloseOverlay();
+ playPauseButton.requestFocus();
} else {
getRootView().setVisibility(View.VISIBLE);
initVideoPlayer();
+ // Android TV: without it focus will frame the whole player
+ playPauseButton.requestFocus();
}
onPlay();
@@ -1057,10 +1060,10 @@ public int getOverrideResolutionIndex(final List sortedVideos,
private void animatePlayButtons(final boolean show, final int duration) {
animateView(playPauseButton, AnimationUtils.Type.SCALE_AND_ALPHA, show, duration);
- if (playQueue.getIndex() > 0) {
+ if (playQueue.getIndex() > 0 || !show) {
animateView(playPreviousButton, AnimationUtils.Type.SCALE_AND_ALPHA, show, duration);
}
- if (playQueue.getIndex() + 1 < playQueue.getStreams().size()) {
+ if (playQueue.getIndex() + 1 < playQueue.getStreams().size() || !show) {
animateView(playNextButton, AnimationUtils.Type.SCALE_AND_ALPHA, show, duration);
}
diff --git a/app/src/main/res/layout-large-land/fragment_video_detail.xml b/app/src/main/res/layout-large-land/fragment_video_detail.xml
index 95d2f3c00f0..f69832b810e 100644
--- a/app/src/main/res/layout-large-land/fragment_video_detail.xml
+++ b/app/src/main/res/layout-large-land/fragment_video_detail.xml
@@ -153,12 +153,12 @@
tools:visibility="visible" />
-
+
From 5293d17e32afa13386ce2e90db4455532c1bc487 Mon Sep 17 00:00:00 2001
From: Avently <7953703+avently@users.noreply.github.com>
Date: Sat, 25 Jul 2020 09:39:42 +0300
Subject: [PATCH 041/398] Removed unused files, translations, styles, settings
key
---
app/src/main/AndroidManifest.xml | 23 +-
.../newpipe/player/BackgroundPlayer.java | 684 --------
.../org/schabi/newpipe/player/MainPlayer.java | 2 +-
.../newpipe/player/MainVideoPlayer.java | 1478 -----------------
.../newpipe/player/PopupVideoPlayer.java | 1315 ---------------
.../player/PopupVideoPlayerActivity.java | 72 -
.../newpipe/player/VideoPlayerImpl.java | 2 +-
.../player/event/PlayerGestureListener.java | 4 +-
app/src/main/res/layout/player_popup.xml | 299 ----
.../res/layout/player_popup_notification.xml | 88 -
.../main/res/menu/menu_play_queue_popup.xml | 10 -
app/src/main/res/menu/menu_videooptions.xml | 22 -
app/src/main/res/values-ar/strings.xml | 2 -
.../main/res/values-b+zh+HANS+CN/strings.xml | 2 -
app/src/main/res/values-be/strings.xml | 2 -
app/src/main/res/values-bg/strings.xml | 2 -
app/src/main/res/values-ca/strings.xml | 2 -
app/src/main/res/values-ckb/strings.xml | 2 -
app/src/main/res/values-cs/strings.xml | 2 -
app/src/main/res/values-da/strings.xml | 2 -
app/src/main/res/values-de/strings.xml | 2 -
app/src/main/res/values-el/strings.xml | 2 -
app/src/main/res/values-eo/strings.xml | 2 -
app/src/main/res/values-es/strings.xml | 2 -
app/src/main/res/values-et/strings.xml | 2 -
app/src/main/res/values-eu/strings.xml | 2 -
app/src/main/res/values-fa/strings.xml | 2 -
app/src/main/res/values-fi/strings.xml | 2 -
app/src/main/res/values-fr/strings.xml | 2 -
app/src/main/res/values-gl/strings.xml | 2 -
app/src/main/res/values-he/strings.xml | 2 -
app/src/main/res/values-hi/strings.xml | 2 -
app/src/main/res/values-hr/strings.xml | 2 -
app/src/main/res/values-hu/strings.xml | 1 -
app/src/main/res/values-in/strings.xml | 2 -
app/src/main/res/values-it/strings.xml | 2 -
app/src/main/res/values-ja/strings.xml | 2 -
app/src/main/res/values-ko/strings.xml | 2 -
app/src/main/res/values-ku/strings.xml | 2 -
app/src/main/res/values-lt/strings.xml | 2 -
app/src/main/res/values-mk/strings.xml | 2 -
app/src/main/res/values-ml/strings.xml | 2 -
app/src/main/res/values-ms/strings.xml | 2 -
app/src/main/res/values-nb-rNO/strings.xml | 2 -
app/src/main/res/values-ne/strings.xml | 2 -
app/src/main/res/values-nl-rBE/strings.xml | 2 -
app/src/main/res/values-nl/strings.xml | 2 -
app/src/main/res/values-pa/strings.xml | 2 -
app/src/main/res/values-pl/strings.xml | 2 -
app/src/main/res/values-pt-rBR/strings.xml | 2 -
app/src/main/res/values-pt/strings.xml | 2 -
app/src/main/res/values-ro/strings.xml | 2 -
app/src/main/res/values-ru/strings.xml | 2 -
app/src/main/res/values-sk/strings.xml | 2 -
app/src/main/res/values-sl/strings.xml | 2 -
app/src/main/res/values-sq/strings.xml | 2 -
app/src/main/res/values-sr/strings.xml | 2 -
app/src/main/res/values-sv/strings.xml | 2 -
app/src/main/res/values-th/strings.xml | 2 -
app/src/main/res/values-tr/strings.xml | 2 -
app/src/main/res/values-uk/strings.xml | 2 -
app/src/main/res/values-ur/strings.xml | 2 -
app/src/main/res/values-v28/styles.xml | 8 -
app/src/main/res/values-vi/strings.xml | 2 -
app/src/main/res/values-zh-rCN/strings.xml | 2 -
app/src/main/res/values-zh-rTW/strings.xml | 2 -
app/src/main/res/values/settings_keys.xml | 2 -
app/src/main/res/values/strings.xml | 2 -
app/src/main/res/values/styles.xml | 1 -
69 files changed, 5 insertions(+), 4112 deletions(-)
delete mode 100644 app/src/main/java/org/schabi/newpipe/player/BackgroundPlayer.java
delete mode 100644 app/src/main/java/org/schabi/newpipe/player/MainVideoPlayer.java
delete mode 100644 app/src/main/java/org/schabi/newpipe/player/PopupVideoPlayer.java
delete mode 100644 app/src/main/java/org/schabi/newpipe/player/PopupVideoPlayerActivity.java
delete mode 100644 app/src/main/res/layout/player_popup.xml
delete mode 100644 app/src/main/res/layout/player_popup_notification.xml
delete mode 100644 app/src/main/res/menu/menu_play_queue_popup.xml
delete mode 100644 app/src/main/res/menu/menu_videooptions.xml
delete mode 100644 app/src/main/res/values-v28/styles.xml
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 60a7f3cb847..16ed422e0e3 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -42,11 +42,6 @@
-
-
-
@@ -57,25 +52,9 @@
-
-
-
-
-
-
diff --git a/app/src/main/java/org/schabi/newpipe/player/BackgroundPlayer.java b/app/src/main/java/org/schabi/newpipe/player/BackgroundPlayer.java
deleted file mode 100644
index a75ea7de86e..00000000000
--- a/app/src/main/java/org/schabi/newpipe/player/BackgroundPlayer.java
+++ /dev/null
@@ -1,684 +0,0 @@
-/*
- * Copyright 2017 Mauricio Colli
- * BackgroundPlayer.java is part of NewPipe
- *
- * License: GPL-3.0+
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
-package org.schabi.newpipe.player;
-
-import android.app.NotificationManager;
-import android.app.PendingIntent;
-import android.app.Service;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.SharedPreferences;
-import android.content.res.Resources;
-import android.graphics.Bitmap;
-import android.os.Build;
-import android.os.IBinder;
-import android.preference.PreferenceManager;
-import android.util.Log;
-import android.view.View;
-import android.widget.RemoteViews;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import androidx.annotation.RequiresApi;
-import androidx.core.app.NotificationCompat;
-
-import com.google.android.exoplayer2.PlaybackParameters;
-import com.google.android.exoplayer2.Player;
-import com.google.android.exoplayer2.source.MediaSource;
-import com.nostra13.universalimageloader.core.assist.FailReason;
-
-import org.schabi.newpipe.BuildConfig;
-import org.schabi.newpipe.R;
-import org.schabi.newpipe.extractor.stream.StreamInfo;
-import org.schabi.newpipe.player.event.PlayerEventListener;
-import org.schabi.newpipe.player.playqueue.PlayQueueItem;
-import org.schabi.newpipe.player.resolver.AudioPlaybackResolver;
-import org.schabi.newpipe.player.resolver.MediaSourceTag;
-import org.schabi.newpipe.util.BitmapUtils;
-import org.schabi.newpipe.util.NavigationHelper;
-import org.schabi.newpipe.util.ThemeHelper;
-
-import static org.schabi.newpipe.player.helper.PlayerHelper.getTimeString;
-import static org.schabi.newpipe.util.Localization.assureCorrectAppLanguage;
-
-/**
- * Service Background Player implementing {@link VideoPlayer}.
- *
- * @author mauriciocolli
- */
-public final class BackgroundPlayer extends Service {
- public static final String ACTION_CLOSE
- = "org.schabi.newpipe.player.BackgroundPlayer.CLOSE";
- public static final String ACTION_PLAY_PAUSE
- = "org.schabi.newpipe.player.BackgroundPlayer.PLAY_PAUSE";
- public static final String ACTION_REPEAT
- = "org.schabi.newpipe.player.BackgroundPlayer.REPEAT";
- public static final String ACTION_PLAY_NEXT
- = "org.schabi.newpipe.player.BackgroundPlayer.ACTION_PLAY_NEXT";
- public static final String ACTION_PLAY_PREVIOUS
- = "org.schabi.newpipe.player.BackgroundPlayer.ACTION_PLAY_PREVIOUS";
- public static final String ACTION_FAST_REWIND
- = "org.schabi.newpipe.player.BackgroundPlayer.ACTION_FAST_REWIND";
- public static final String ACTION_FAST_FORWARD
- = "org.schabi.newpipe.player.BackgroundPlayer.ACTION_FAST_FORWARD";
-
- public static final String SET_IMAGE_RESOURCE_METHOD = "setImageResource";
- private static final String TAG = "BackgroundPlayer";
- private static final boolean DEBUG = BasePlayer.DEBUG;
- private static final int NOTIFICATION_ID = 123789;
- private static final int NOTIFICATION_UPDATES_BEFORE_RESET = 60;
- private BasePlayerImpl basePlayerImpl;
-
- /*//////////////////////////////////////////////////////////////////////////
- // Service-Activity Binder
- //////////////////////////////////////////////////////////////////////////*/
- private SharedPreferences sharedPreferences;
-
- /*//////////////////////////////////////////////////////////////////////////
- // Notification
- //////////////////////////////////////////////////////////////////////////*/
- private PlayerEventListener activityListener;
- private IBinder mBinder;
- private NotificationManager notificationManager;
- private NotificationCompat.Builder notBuilder;
- private RemoteViews notRemoteView;
- private RemoteViews bigNotRemoteView;
- private boolean shouldUpdateOnProgress;
- private int timesNotificationUpdated;
-
- /*//////////////////////////////////////////////////////////////////////////
- // Service's LifeCycle
- //////////////////////////////////////////////////////////////////////////*/
-
- @Override
- public void onCreate() {
- if (DEBUG) {
- Log.d(TAG, "onCreate() called");
- }
- notificationManager = ((NotificationManager) getSystemService(NOTIFICATION_SERVICE));
- sharedPreferences = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
- assureCorrectAppLanguage(this);
- ThemeHelper.setTheme(this);
- basePlayerImpl = new BasePlayerImpl(this);
- basePlayerImpl.setup();
-
- mBinder = new PlayerServiceBinder(basePlayerImpl);
- shouldUpdateOnProgress = true;
- }
-
- @Override
- public int onStartCommand(final Intent intent, final int flags, final int startId) {
- if (DEBUG) {
- Log.d(TAG, "onStartCommand() called with: intent = [" + intent + "], "
- + "flags = [" + flags + "], startId = [" + startId + "]");
- }
- basePlayerImpl.handleIntent(intent);
- if (basePlayerImpl.mediaSessionManager != null) {
- basePlayerImpl.mediaSessionManager.handleMediaButtonIntent(intent);
- }
- return START_NOT_STICKY;
- }
-
- @Override
- public void onDestroy() {
- if (DEBUG) {
- Log.d(TAG, "destroy() called");
- }
- onClose();
- }
-
- @Override
- protected void attachBaseContext(final Context base) {
- super.attachBaseContext(AudioServiceLeakFix.preventLeakOf(base));
- }
-
- @Override
- public IBinder onBind(final Intent intent) {
- return mBinder;
- }
-
- /*//////////////////////////////////////////////////////////////////////////
- // Actions
- //////////////////////////////////////////////////////////////////////////*/
- private void onClose() {
- if (DEBUG) {
- Log.d(TAG, "onClose() called");
- }
-
- if (basePlayerImpl != null) {
- basePlayerImpl.savePlaybackState();
- basePlayerImpl.stopActivityBinding();
- basePlayerImpl.destroy();
- }
- if (notificationManager != null) {
- notificationManager.cancel(NOTIFICATION_ID);
- }
- mBinder = null;
- basePlayerImpl = null;
-
- stopForeground(true);
- stopSelf();
- }
-
- private void onScreenOnOff(final boolean on) {
- if (DEBUG) {
- Log.d(TAG, "onScreenOnOff() called with: on = [" + on + "]");
- }
- shouldUpdateOnProgress = on;
- basePlayerImpl.triggerProgressUpdate();
- if (on) {
- basePlayerImpl.startProgressLoop();
- } else {
- basePlayerImpl.stopProgressLoop();
- }
- }
-
- /*//////////////////////////////////////////////////////////////////////////
- // Notification
- //////////////////////////////////////////////////////////////////////////*/
-
- private void resetNotification() {
- notBuilder = createNotification();
- timesNotificationUpdated = 0;
- }
-
- private NotificationCompat.Builder createNotification() {
- notRemoteView = new RemoteViews(BuildConfig.APPLICATION_ID,
- R.layout.player_background_notification);
- bigNotRemoteView = new RemoteViews(BuildConfig.APPLICATION_ID,
- R.layout.player_background_notification_expanded);
-
- setupNotification(notRemoteView);
- setupNotification(bigNotRemoteView);
-
- NotificationCompat.Builder builder = new NotificationCompat
- .Builder(this, getString(R.string.notification_channel_id))
- .setOngoing(true)
- .setSmallIcon(R.drawable.ic_newpipe_triangle_white)
- .setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
- .setCustomContentView(notRemoteView)
- .setCustomBigContentView(bigNotRemoteView);
-
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
- setLockScreenThumbnail(builder);
- }
-
- if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN) {
- builder.setPriority(NotificationCompat.PRIORITY_MAX);
- }
- return builder;
- }
-
- @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
- private void setLockScreenThumbnail(final NotificationCompat.Builder builder) {
- boolean isLockScreenThumbnailEnabled = sharedPreferences.getBoolean(
- getString(R.string.enable_lock_screen_video_thumbnail_key), true);
-
- if (isLockScreenThumbnailEnabled) {
- basePlayerImpl.mediaSessionManager.setLockScreenArt(
- builder,
- getCenteredThumbnailBitmap()
- );
- } else {
- basePlayerImpl.mediaSessionManager.clearLockScreenArt(builder);
- }
- }
-
- @Nullable
- private Bitmap getCenteredThumbnailBitmap() {
- final int screenWidth = Resources.getSystem().getDisplayMetrics().widthPixels;
- final int screenHeight = Resources.getSystem().getDisplayMetrics().heightPixels;
-
- return BitmapUtils.centerCrop(basePlayerImpl.getThumbnail(), screenWidth, screenHeight);
- }
-
- private void setupNotification(final RemoteViews remoteViews) {
- if (basePlayerImpl == null) {
- return;
- }
-
- remoteViews.setTextViewText(R.id.notificationSongName, basePlayerImpl.getVideoTitle());
- remoteViews.setTextViewText(R.id.notificationArtist, basePlayerImpl.getUploaderName());
-
- remoteViews.setOnClickPendingIntent(R.id.notificationPlayPause,
- PendingIntent.getBroadcast(this, NOTIFICATION_ID,
- new Intent(ACTION_PLAY_PAUSE), PendingIntent.FLAG_UPDATE_CURRENT));
- remoteViews.setOnClickPendingIntent(R.id.notificationStop,
- PendingIntent.getBroadcast(this, NOTIFICATION_ID,
- new Intent(ACTION_CLOSE), PendingIntent.FLAG_UPDATE_CURRENT));
- remoteViews.setOnClickPendingIntent(R.id.notificationRepeat,
- PendingIntent.getBroadcast(this, NOTIFICATION_ID,
- new Intent(ACTION_REPEAT), PendingIntent.FLAG_UPDATE_CURRENT));
-
- // Starts background player activity -- attempts to unlock lockscreen
- final Intent intent = NavigationHelper.getBackgroundPlayerActivityIntent(this);
- remoteViews.setOnClickPendingIntent(R.id.notificationContent,
- PendingIntent.getActivity(this, NOTIFICATION_ID, intent,
- PendingIntent.FLAG_UPDATE_CURRENT));
-
- if (basePlayerImpl.playQueue != null && basePlayerImpl.playQueue.size() > 1) {
- remoteViews.setInt(R.id.notificationFRewind, SET_IMAGE_RESOURCE_METHOD,
- R.drawable.exo_controls_previous);
- remoteViews.setInt(R.id.notificationFForward, SET_IMAGE_RESOURCE_METHOD,
- R.drawable.exo_controls_next);
- remoteViews.setOnClickPendingIntent(R.id.notificationFRewind,
- PendingIntent.getBroadcast(this, NOTIFICATION_ID,
- new Intent(ACTION_PLAY_PREVIOUS), PendingIntent.FLAG_UPDATE_CURRENT));
- remoteViews.setOnClickPendingIntent(R.id.notificationFForward,
- PendingIntent.getBroadcast(this, NOTIFICATION_ID,
- new Intent(ACTION_PLAY_NEXT), PendingIntent.FLAG_UPDATE_CURRENT));
- } else {
- remoteViews.setInt(R.id.notificationFRewind, SET_IMAGE_RESOURCE_METHOD,
- R.drawable.exo_controls_rewind);
- remoteViews.setInt(R.id.notificationFForward, SET_IMAGE_RESOURCE_METHOD,
- R.drawable.exo_controls_fastforward);
- remoteViews.setOnClickPendingIntent(R.id.notificationFRewind,
- PendingIntent.getBroadcast(this, NOTIFICATION_ID,
- new Intent(ACTION_FAST_REWIND), PendingIntent.FLAG_UPDATE_CURRENT));
- remoteViews.setOnClickPendingIntent(R.id.notificationFForward,
- PendingIntent.getBroadcast(this, NOTIFICATION_ID,
- new Intent(ACTION_FAST_FORWARD), PendingIntent.FLAG_UPDATE_CURRENT));
- }
-
- setRepeatModeIcon(remoteViews, basePlayerImpl.getRepeatMode());
- }
-
- /**
- * Updates the notification, and the play/pause button in it.
- * Used for changes on the remoteView
- *
- * @param drawableId if != -1, sets the drawable with that id on the play/pause button
- */
- private synchronized void updateNotification(final int drawableId) {
-// if (DEBUG) {
-// Log.d(TAG, "updateNotification() called with: drawableId = [" + drawableId + "]");
-// }
- if (notBuilder == null) {
- return;
- }
- if (drawableId != -1) {
- if (notRemoteView != null) {
- notRemoteView.setImageViewResource(R.id.notificationPlayPause, drawableId);
- }
- if (bigNotRemoteView != null) {
- bigNotRemoteView.setImageViewResource(R.id.notificationPlayPause, drawableId);
- }
- }
- notificationManager.notify(NOTIFICATION_ID, notBuilder.build());
- timesNotificationUpdated++;
- }
-
- /*//////////////////////////////////////////////////////////////////////////
- // Utils
- //////////////////////////////////////////////////////////////////////////*/
-
- private void setRepeatModeIcon(final RemoteViews remoteViews, final int repeatMode) {
- switch (repeatMode) {
- case Player.REPEAT_MODE_OFF:
- remoteViews.setInt(R.id.notificationRepeat, SET_IMAGE_RESOURCE_METHOD,
- R.drawable.exo_controls_repeat_off);
- break;
- case Player.REPEAT_MODE_ONE:
- remoteViews.setInt(R.id.notificationRepeat, SET_IMAGE_RESOURCE_METHOD,
- R.drawable.exo_controls_repeat_one);
- break;
- case Player.REPEAT_MODE_ALL:
- remoteViews.setInt(R.id.notificationRepeat, SET_IMAGE_RESOURCE_METHOD,
- R.drawable.exo_controls_repeat_all);
- break;
- }
- }
- //////////////////////////////////////////////////////////////////////////
-
- protected class BasePlayerImpl extends BasePlayer {
- @NonNull
- private final AudioPlaybackResolver resolver;
- private int cachedDuration;
- private String cachedDurationString;
-
- BasePlayerImpl(final Context context) {
- super(context);
- this.resolver = new AudioPlaybackResolver(context, dataSource);
- }
-
- @Override
- public void initPlayer(final boolean playOnReady) {
- super.initPlayer(playOnReady);
- }
-
- @Override
- public void handleIntent(final Intent intent) {
- super.handleIntent(intent);
-
- resetNotification();
- if (bigNotRemoteView != null) {
- bigNotRemoteView.setProgressBar(R.id.notificationProgressBar, 100, 0, false);
- }
- if (notRemoteView != null) {
- notRemoteView.setProgressBar(R.id.notificationProgressBar, 100, 0, false);
- }
- startForeground(NOTIFICATION_ID, notBuilder.build());
- }
-
- /*//////////////////////////////////////////////////////////////////////////
- // Thumbnail Loading
- //////////////////////////////////////////////////////////////////////////*/
-
- private void updateNotificationThumbnail() {
- if (basePlayerImpl == null) {
- return;
- }
- if (notRemoteView != null) {
- notRemoteView.setImageViewBitmap(R.id.notificationCover,
- basePlayerImpl.getThumbnail());
- }
- if (bigNotRemoteView != null) {
- bigNotRemoteView.setImageViewBitmap(R.id.notificationCover,
- basePlayerImpl.getThumbnail());
- }
- }
-
- @Override
- public void onLoadingComplete(final String imageUri, final View view,
- final Bitmap loadedImage) {
- super.onLoadingComplete(imageUri, view, loadedImage);
- resetNotification();
- updateNotificationThumbnail();
- updateNotification(-1);
- }
-
- @Override
- public void onLoadingFailed(final String imageUri, final View view,
- final FailReason failReason) {
- super.onLoadingFailed(imageUri, view, failReason);
- resetNotification();
- updateNotificationThumbnail();
- updateNotification(-1);
- }
-
- /*//////////////////////////////////////////////////////////////////////////
- // States Implementation
- //////////////////////////////////////////////////////////////////////////*/
-
- @Override
- public void onPrepared(final boolean playWhenReady) {
- super.onPrepared(playWhenReady);
- }
-
- @Override
- public void onShuffleClicked() {
- super.onShuffleClicked();
- updatePlayback();
- }
-
- @Override
- public void onMuteUnmuteButtonClicked() {
- super.onMuteUnmuteButtonClicked();
- updatePlayback();
- }
-
- @Override
- public void onUpdateProgress(final int currentProgress, final int duration,
- final int bufferPercent) {
- updateProgress(currentProgress, duration, bufferPercent);
-
- if (!shouldUpdateOnProgress) {
- return;
- }
- if (timesNotificationUpdated > NOTIFICATION_UPDATES_BEFORE_RESET) {
- resetNotification();
-
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O /*Oreo*/) {
- updateNotificationThumbnail();
- }
- }
- if (bigNotRemoteView != null) {
- if (cachedDuration != duration) {
- cachedDuration = duration;
- cachedDurationString = getTimeString(duration);
- }
- bigNotRemoteView.setProgressBar(R.id.notificationProgressBar, duration,
- currentProgress, false);
- bigNotRemoteView.setTextViewText(R.id.notificationTime,
- getTimeString(currentProgress) + " / " + cachedDurationString);
- }
- if (notRemoteView != null) {
- notRemoteView.setProgressBar(R.id.notificationProgressBar, duration,
- currentProgress, false);
- }
- updateNotification(-1);
- }
-
- @Override
- public void onPlayPrevious() {
- super.onPlayPrevious();
- triggerProgressUpdate();
- }
-
- @Override
- public void onPlayNext() {
- super.onPlayNext();
- triggerProgressUpdate();
- }
-
- @Override
- public void destroy() {
- super.destroy();
- if (notRemoteView != null) {
- notRemoteView.setImageViewBitmap(R.id.notificationCover, null);
- }
- if (bigNotRemoteView != null) {
- bigNotRemoteView.setImageViewBitmap(R.id.notificationCover, null);
- }
- }
-
- /*//////////////////////////////////////////////////////////////////////////
- // ExoPlayer Listener
- //////////////////////////////////////////////////////////////////////////*/
-
- @Override
- public void onPlaybackParametersChanged(final PlaybackParameters playbackParameters) {
- super.onPlaybackParametersChanged(playbackParameters);
- updatePlayback();
- }
-
- @Override
- public void onLoadingChanged(final boolean isLoading) {
- // Disable default behavior
- }
-
- @Override
- public void onRepeatModeChanged(final int i) {
- resetNotification();
- updateNotification(-1);
- updatePlayback();
- }
-
- /*//////////////////////////////////////////////////////////////////////////
- // Playback Listener
- //////////////////////////////////////////////////////////////////////////*/
-
- protected void onMetadataChanged(@NonNull final MediaSourceTag tag) {
- super.onMetadataChanged(tag);
- resetNotification();
- updateNotificationThumbnail();
- updateNotification(-1);
- updateMetadata();
- }
-
- @Override
- @Nullable
- public MediaSource sourceOf(final PlayQueueItem item, final StreamInfo info) {
- return resolver.resolve(info);
- }
-
- @Override
- public void onPlaybackShutdown() {
- super.onPlaybackShutdown();
- onClose();
- }
-
- /*//////////////////////////////////////////////////////////////////////////
- // Activity Event Listener
- //////////////////////////////////////////////////////////////////////////*/
-
- /*package-private*/ void setActivityListener(final PlayerEventListener listener) {
- activityListener = listener;
- updateMetadata();
- updatePlayback();
- triggerProgressUpdate();
- }
-
- /*package-private*/ void removeActivityListener(final PlayerEventListener listener) {
- if (activityListener == listener) {
- activityListener = null;
- }
- }
-
- private void updateMetadata() {
- if (activityListener != null && getCurrentMetadata() != null) {
- activityListener.onMetadataUpdate(getCurrentMetadata().getMetadata(), playQueue);
- }
- }
-
- private void updatePlayback() {
- if (activityListener != null && simpleExoPlayer != null && playQueue != null) {
- activityListener.onPlaybackUpdate(currentState, getRepeatMode(),
- playQueue.isShuffled(), getPlaybackParameters());
- }
- }
-
- private void updateProgress(final int currentProgress, final int duration,
- final int bufferPercent) {
- if (activityListener != null) {
- activityListener.onProgressUpdate(currentProgress, duration, bufferPercent);
- }
- }
-
- private void stopActivityBinding() {
- if (activityListener != null) {
- activityListener.onServiceStopped();
- activityListener = null;
- }
- }
-
- /*//////////////////////////////////////////////////////////////////////////
- // Broadcast Receiver
- //////////////////////////////////////////////////////////////////////////*/
-
- @Override
- protected void setupBroadcastReceiver(final IntentFilter intentFltr) {
- super.setupBroadcastReceiver(intentFltr);
- intentFltr.addAction(ACTION_CLOSE);
- intentFltr.addAction(ACTION_PLAY_PAUSE);
- intentFltr.addAction(ACTION_REPEAT);
- intentFltr.addAction(ACTION_PLAY_PREVIOUS);
- intentFltr.addAction(ACTION_PLAY_NEXT);
- intentFltr.addAction(ACTION_FAST_REWIND);
- intentFltr.addAction(ACTION_FAST_FORWARD);
-
- intentFltr.addAction(Intent.ACTION_SCREEN_ON);
- intentFltr.addAction(Intent.ACTION_SCREEN_OFF);
-
- intentFltr.addAction(Intent.ACTION_HEADSET_PLUG);
- }
-
- @Override
- public void onBroadcastReceived(final Intent intent) {
- super.onBroadcastReceived(intent);
- if (intent == null || intent.getAction() == null) {
- return;
- }
- if (DEBUG) {
- Log.d(TAG, "onBroadcastReceived() called with: intent = [" + intent + "]");
- }
- switch (intent.getAction()) {
- case ACTION_CLOSE:
- onClose();
- break;
- case ACTION_PLAY_PAUSE:
- onPlayPause();
- break;
- case ACTION_REPEAT:
- onRepeatClicked();
- break;
- case ACTION_PLAY_NEXT:
- onPlayNext();
- break;
- case ACTION_PLAY_PREVIOUS:
- onPlayPrevious();
- break;
- case ACTION_FAST_FORWARD:
- onFastForward();
- break;
- case ACTION_FAST_REWIND:
- onFastRewind();
- break;
- case Intent.ACTION_SCREEN_ON:
- onScreenOnOff(true);
- break;
- case Intent.ACTION_SCREEN_OFF:
- onScreenOnOff(false);
- break;
- }
- }
-
- /*//////////////////////////////////////////////////////////////////////////
- // States
- //////////////////////////////////////////////////////////////////////////*/
-
- @Override
- public void changeState(final int state) {
- super.changeState(state);
- updatePlayback();
- }
-
- @Override
- public void onPlaying() {
- super.onPlaying();
- resetNotification();
- updateNotificationThumbnail();
- updateNotification(R.drawable.exo_controls_pause);
- }
-
- @Override
- public void onPaused() {
- super.onPaused();
- resetNotification();
- updateNotificationThumbnail();
- updateNotification(R.drawable.exo_controls_play);
- }
-
- @Override
- public void onCompleted() {
- super.onCompleted();
- resetNotification();
- if (bigNotRemoteView != null) {
- bigNotRemoteView.setProgressBar(R.id.notificationProgressBar, 100, 100, false);
- }
- if (notRemoteView != null) {
- notRemoteView.setProgressBar(R.id.notificationProgressBar, 100, 100, false);
- }
- updateNotificationThumbnail();
- updateNotification(R.drawable.ic_replay_white_24dp);
- }
- }
-}
diff --git a/app/src/main/java/org/schabi/newpipe/player/MainPlayer.java b/app/src/main/java/org/schabi/newpipe/player/MainPlayer.java
index 703be346ecf..d3bb90660c6 100644
--- a/app/src/main/java/org/schabi/newpipe/player/MainPlayer.java
+++ b/app/src/main/java/org/schabi/newpipe/player/MainPlayer.java
@@ -1,6 +1,6 @@
/*
* Copyright 2017 Mauricio Colli
- * BackgroundPlayer.java is part of NewPipe
+ * Part of NewPipe
*
* License: GPL-3.0+
* This program is free software: you can redistribute it and/or modify
diff --git a/app/src/main/java/org/schabi/newpipe/player/MainVideoPlayer.java b/app/src/main/java/org/schabi/newpipe/player/MainVideoPlayer.java
deleted file mode 100644
index f8788768538..00000000000
--- a/app/src/main/java/org/schabi/newpipe/player/MainVideoPlayer.java
+++ /dev/null
@@ -1,1478 +0,0 @@
-/*
- * Copyright 2017 Mauricio Colli
- * Copyright 2019 Eltex ltd
- * MainVideoPlayer.java is part of NewPipe
- *
- * License: GPL-3.0+
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
-package org.schabi.newpipe.player;
-
-import android.content.Context;
-import android.content.Intent;
-import android.content.SharedPreferences;
-import android.content.pm.ActivityInfo;
-import android.content.res.Configuration;
-import android.database.ContentObserver;
-import android.graphics.Color;
-import android.graphics.drawable.ColorDrawable;
-import android.media.AudioManager;
-import android.net.Uri;
-import android.os.Build;
-import android.os.Bundle;
-import android.os.Handler;
-import android.preference.PreferenceManager;
-import android.provider.Settings;
-import android.util.DisplayMetrics;
-import android.util.Log;
-import android.util.TypedValue;
-import android.view.DisplayCutout;
-import android.view.GestureDetector;
-import android.view.KeyEvent;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.WindowInsets;
-import android.view.WindowManager;
-import android.widget.Button;
-import android.widget.ImageButton;
-import android.widget.ImageView;
-import android.widget.PopupMenu;
-import android.widget.ProgressBar;
-import android.widget.RelativeLayout;
-import android.widget.SeekBar;
-import android.widget.TextView;
-import android.widget.Toast;
-
-import androidx.annotation.ColorInt;
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import androidx.appcompat.app.AppCompatActivity;
-import androidx.appcompat.content.res.AppCompatResources;
-import androidx.core.app.ActivityCompat;
-import androidx.recyclerview.widget.ItemTouchHelper;
-import androidx.recyclerview.widget.RecyclerView;
-
-import com.google.android.exoplayer2.Player;
-import com.google.android.exoplayer2.text.CaptionStyleCompat;
-import com.google.android.exoplayer2.ui.AspectRatioFrameLayout;
-import com.google.android.exoplayer2.ui.SubtitleView;
-
-import org.schabi.newpipe.R;
-import org.schabi.newpipe.extractor.stream.VideoStream;
-import org.schabi.newpipe.fragments.OnScrollBelowItemsListener;
-import org.schabi.newpipe.player.helper.PlaybackParameterDialog;
-import org.schabi.newpipe.player.helper.PlayerHelper;
-import org.schabi.newpipe.player.playqueue.PlayQueueItem;
-import org.schabi.newpipe.player.playqueue.PlayQueueItemBuilder;
-import org.schabi.newpipe.player.playqueue.PlayQueueItemHolder;
-import org.schabi.newpipe.player.playqueue.PlayQueueItemTouchCallback;
-import org.schabi.newpipe.player.resolver.MediaSourceTag;
-import org.schabi.newpipe.player.resolver.VideoPlaybackResolver;
-import org.schabi.newpipe.util.DeviceUtils;
-import org.schabi.newpipe.util.AnimationUtils;
-import org.schabi.newpipe.util.KoreUtil;
-import org.schabi.newpipe.util.ListHelper;
-import org.schabi.newpipe.util.NavigationHelper;
-import org.schabi.newpipe.util.PermissionHelper;
-import org.schabi.newpipe.util.ShareUtils;
-import org.schabi.newpipe.util.StateSaver;
-import org.schabi.newpipe.util.ThemeHelper;
-import org.schabi.newpipe.views.FocusOverlayView;
-
-import java.util.List;
-import java.util.Queue;
-import java.util.UUID;
-
-import static org.schabi.newpipe.player.BasePlayer.STATE_PLAYING;
-import static org.schabi.newpipe.player.VideoPlayer.DEFAULT_CONTROLS_DURATION;
-import static org.schabi.newpipe.player.VideoPlayer.DEFAULT_CONTROLS_HIDE_TIME;
-import static org.schabi.newpipe.player.VideoPlayer.DPAD_CONTROLS_HIDE_TIME;
-import static org.schabi.newpipe.util.AnimationUtils.Type.SCALE_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.animateView;
-import static org.schabi.newpipe.util.Localization.assureCorrectAppLanguage;
-import static org.schabi.newpipe.util.StateSaver.KEY_SAVED_STATE;
-
-/**
- * Activity Player implementing {@link VideoPlayer}.
- *
- * @author mauriciocolli
- */
-public final class MainVideoPlayer extends AppCompatActivity
- implements StateSaver.WriteRead, PlaybackParameterDialog.Callback {
- private static final String TAG = ".MainVideoPlayer";
- private static final boolean DEBUG = BasePlayer.DEBUG;
-
- private GestureDetector gestureDetector;
-
- private VideoPlayerImpl playerImpl;
-
- private SharedPreferences defaultPreferences;
-
- @Nullable
- private PlayerState playerState;
- private boolean isInMultiWindow;
- private boolean isBackPressed;
-
- private ContentObserver rotationObserver;
-
- /*//////////////////////////////////////////////////////////////////////////
- // Activity LifeCycle
- //////////////////////////////////////////////////////////////////////////*/
-
- @Override
- protected void onCreate(@Nullable final Bundle savedInstanceState) {
- assureCorrectAppLanguage(this);
- super.onCreate(savedInstanceState);
- if (DEBUG) {
- Log.d(TAG, "onCreate() called with: "
- + "savedInstanceState = [" + savedInstanceState + "]");
- }
- defaultPreferences = PreferenceManager.getDefaultSharedPreferences(this);
- ThemeHelper.setTheme(this);
- getWindow().setBackgroundDrawable(new ColorDrawable(Color.BLACK));
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
- getWindow().setStatusBarColor(Color.BLACK);
- }
- setVolumeControlStream(AudioManager.STREAM_MUSIC);
-
- WindowManager.LayoutParams lp = getWindow().getAttributes();
- lp.screenBrightness = PlayerHelper.getScreenBrightness(getApplicationContext());
- getWindow().setAttributes(lp);
-
- hideSystemUi();
- setContentView(R.layout.activity_main_player);
-
- playerImpl = new VideoPlayerImpl(this);
- playerImpl.setup(findViewById(android.R.id.content));
-
- if (savedInstanceState != null && savedInstanceState.get(KEY_SAVED_STATE) != null) {
- return; // We have saved states, stop here to restore it
- }
-
- final Intent intent = getIntent();
- if (intent != null) {
- playerImpl.handleIntent(intent);
- } else {
- Toast.makeText(this, R.string.general_error, Toast.LENGTH_SHORT).show();
- finish();
- }
-
- rotationObserver = new ContentObserver(new Handler()) {
- @Override
- public void onChange(final boolean selfChange) {
- super.onChange(selfChange);
- if (globalScreenOrientationLocked()) {
- final String orientKey = getString(R.string.last_orientation_landscape_key);
-
- final boolean lastOrientationWasLandscape = defaultPreferences
- .getBoolean(orientKey, DeviceUtils.isTv(getApplicationContext()));
- setLandscape(lastOrientationWasLandscape);
- } else {
- setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
- }
- }
- };
-
- getContentResolver().registerContentObserver(
- Settings.System.getUriFor(Settings.System.ACCELEROMETER_ROTATION),
- false, rotationObserver);
-
- if (DeviceUtils.isTv(this)) {
- FocusOverlayView.setupFocusObserver(this);
- }
- }
-
- @Override
- protected void onRestoreInstanceState(@NonNull final Bundle bundle) {
- if (DEBUG) {
- Log.d(TAG, "onRestoreInstanceState() called");
- }
- super.onRestoreInstanceState(bundle);
- StateSaver.tryToRestore(bundle, this);
- }
-
- @Override
- protected void onNewIntent(final Intent intent) {
- if (DEBUG) {
- Log.d(TAG, "onNewIntent() called with: intent = [" + intent + "]");
- }
- super.onNewIntent(intent);
- if (intent != null) {
- playerState = null;
- playerImpl.handleIntent(intent);
- }
- }
-
- @Override
- public boolean onKeyDown(final int keyCode, final KeyEvent event) {
- switch (event.getKeyCode()) {
- default:
- break;
- case KeyEvent.KEYCODE_BACK:
- if (DeviceUtils.isTv(getApplicationContext())
- && playerImpl.isControlsVisible()) {
- playerImpl.hideControls(0, 0);
- hideSystemUi();
- return true;
- }
- break;
- case KeyEvent.KEYCODE_DPAD_UP:
- case KeyEvent.KEYCODE_DPAD_LEFT:
- case KeyEvent.KEYCODE_DPAD_DOWN:
- case KeyEvent.KEYCODE_DPAD_RIGHT:
- case KeyEvent.KEYCODE_DPAD_CENTER:
- View playerRoot = playerImpl.getRootView();
- View controls = playerImpl.getControlsRoot();
- if (playerRoot.hasFocus() && !controls.hasFocus()) {
- // do not interfere with focus in playlist etc.
- return super.onKeyDown(keyCode, event);
- }
-
- if (playerImpl.getCurrentState() == BasePlayer.STATE_BLOCKED) {
- return true;
- }
-
- if (!playerImpl.isControlsVisible()) {
- playerImpl.playPauseButton.requestFocus();
- playerImpl.showControlsThenHide();
- showSystemUi();
- return true;
- } else {
- playerImpl.hideControls(DEFAULT_CONTROLS_DURATION, DPAD_CONTROLS_HIDE_TIME);
- }
- break;
- }
-
- return super.onKeyDown(keyCode, event);
- }
-
- @Override
- protected void onResume() {
- if (DEBUG) {
- Log.d(TAG, "onResume() called");
- }
- assureCorrectAppLanguage(this);
- super.onResume();
-
- if (globalScreenOrientationLocked()) {
- final String orientKey = getString(R.string.last_orientation_landscape_key);
-
- boolean lastOrientationWasLandscape = defaultPreferences
- .getBoolean(orientKey, DeviceUtils.isTv(getApplicationContext()));
- setLandscape(lastOrientationWasLandscape);
- }
-
- final int lastResizeMode = defaultPreferences.getInt(
- getString(R.string.last_resize_mode), AspectRatioFrameLayout.RESIZE_MODE_FIT);
- playerImpl.setResizeMode(lastResizeMode);
-
- // Upon going in or out of multiwindow mode, isInMultiWindow will always be false,
- // since the first onResume needs to restore the player.
- // Subsequent onResume calls while multiwindow mode remains the same and the player is
- // prepared should be ignored.
- if (isInMultiWindow) {
- return;
- }
- isInMultiWindow = isInMultiWindow();
-
- if (playerState != null) {
- playerImpl.setPlaybackQuality(playerState.getPlaybackQuality());
- playerImpl.initPlayback(playerState.getPlayQueue(), playerState.getRepeatMode(),
- playerState.getPlaybackSpeed(), playerState.getPlaybackPitch(),
- playerState.isPlaybackSkipSilence(), playerState.wasPlaying(),
- playerImpl.isMuted());
- }
- }
-
- @Override
- public void onConfigurationChanged(final Configuration newConfig) {
- super.onConfigurationChanged(newConfig);
- assureCorrectAppLanguage(this);
-
- if (playerImpl.isSomePopupMenuVisible()) {
- playerImpl.getQualityPopupMenu().dismiss();
- playerImpl.getPlaybackSpeedPopupMenu().dismiss();
- }
- }
-
- @Override
- public void onBackPressed() {
- super.onBackPressed();
- isBackPressed = true;
- }
-
- @Override
- protected void onSaveInstanceState(final Bundle outState) {
- if (DEBUG) {
- Log.d(TAG, "onSaveInstanceState() called");
- }
- super.onSaveInstanceState(outState);
- if (playerImpl == null) {
- return;
- }
-
- playerImpl.setRecovery();
- if (!playerImpl.gotDestroyed()) {
- playerState = createPlayerState();
- }
- StateSaver.tryToSave(isChangingConfigurations(), null, outState, this);
- }
-
- @Override
- protected void onStop() {
- if (DEBUG) {
- Log.d(TAG, "onStop() called");
- }
- super.onStop();
- PlayerHelper.setScreenBrightness(getApplicationContext(),
- getWindow().getAttributes().screenBrightness);
-
- if (playerImpl == null) {
- return;
- }
- if (!isBackPressed) {
- playerImpl.minimize();
- }
- playerState = createPlayerState();
- playerImpl.destroy();
-
- if (rotationObserver != null) {
- getContentResolver().unregisterContentObserver(rotationObserver);
- }
-
- isInMultiWindow = false;
- isBackPressed = false;
- }
-
- @Override
- protected void attachBaseContext(final Context newBase) {
- super.attachBaseContext(AudioServiceLeakFix.preventLeakOf(newBase));
- }
-
- @Override
- protected void onPause() {
- playerImpl.savePlaybackState();
- super.onPause();
- }
-
- /*//////////////////////////////////////////////////////////////////////////
- // State Saving
- //////////////////////////////////////////////////////////////////////////*/
-
- private PlayerState createPlayerState() {
- return new PlayerState(playerImpl.getPlayQueue(), playerImpl.getRepeatMode(),
- playerImpl.getPlaybackSpeed(), playerImpl.getPlaybackPitch(),
- playerImpl.getPlaybackQuality(), playerImpl.getPlaybackSkipSilence(),
- playerImpl.isPlaying());
- }
-
- @Override
- public String generateSuffix() {
- return "." + UUID.randomUUID().toString() + ".player";
- }
-
- @Override
- public void writeTo(final Queue