diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 60a7f3cb8..16ed422e0 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 a75ea7de8..000000000 --- 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 703be346e..d3bb90660 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 f87887685..000000000 --- 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 objectsToSave) { - if (objectsToSave == null) { - return; - } - objectsToSave.add(playerState); - } - - @Override - @SuppressWarnings("unchecked") - public void readFrom(@NonNull final Queue savedObjects) { - playerState = (PlayerState) savedObjects.poll(); - } - - /*////////////////////////////////////////////////////////////////////////// - // View - //////////////////////////////////////////////////////////////////////////*/ - - private void showSystemUi() { - if (DEBUG) { - Log.d(TAG, "showSystemUi() called"); - } - if (playerImpl != null && playerImpl.queueVisible) { - return; - } - - final int visibility = View.SYSTEM_UI_FLAG_LAYOUT_STABLE - | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN - | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION; - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - @ColorInt final int systenUiColor = - ActivityCompat.getColor(getApplicationContext(), R.color.video_overlay_color); - getWindow().setStatusBarColor(systenUiColor); - getWindow().setNavigationBarColor(systenUiColor); - } - - getWindow().getDecorView().setSystemUiVisibility(visibility); - 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; - } - getWindow().getDecorView().setSystemUiVisibility(visibility); - } - getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, - WindowManager.LayoutParams.FLAG_FULLSCREEN); - } - - private void toggleOrientation() { - setLandscape(!isLandscape()); - defaultPreferences.edit() - .putBoolean(getString(R.string.last_orientation_landscape_key), !isLandscape()) - .apply(); - } - - private boolean isLandscape() { - return getResources().getDisplayMetrics().heightPixels - < getResources().getDisplayMetrics().widthPixels; - } - - private void setLandscape(final boolean v) { - setRequestedOrientation(v - ? ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE - : ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT); - } - - private boolean globalScreenOrientationLocked() { - // 1: Screen orientation changes using accelerometer - // 0: Screen orientation is locked - return !(android.provider.Settings.System - .getInt(getContentResolver(), Settings.System.ACCELEROMETER_ROTATION, 0) == 1); - } - - protected void setRepeatModeButton(final ImageButton imageButton, final int repeatMode) { - switch (repeatMode) { - case Player.REPEAT_MODE_OFF: - imageButton.setImageResource(R.drawable.exo_controls_repeat_off); - break; - case Player.REPEAT_MODE_ONE: - imageButton.setImageResource(R.drawable.exo_controls_repeat_one); - break; - case Player.REPEAT_MODE_ALL: - imageButton.setImageResource(R.drawable.exo_controls_repeat_all); - break; - } - } - - protected void setShuffleButton(final ImageButton shuffleButton, final boolean shuffled) { - final int shuffleAlpha = shuffled ? 255 : 77; - shuffleButton.setImageAlpha(shuffleAlpha); - } - - protected void setMuteButton(final ImageButton muteButton, final boolean isMuted) { - muteButton.setImageDrawable(AppCompatResources.getDrawable(getApplicationContext(), isMuted - ? R.drawable.ic_volume_off_white_24dp : R.drawable.ic_volume_up_white_24dp)); - } - - - private boolean isInMultiWindow() { - return Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && isInMultiWindowMode(); - } - - //////////////////////////////////////////////////////////////////////////// - // Playback Parameters Listener - //////////////////////////////////////////////////////////////////////////// - - @Override - public void onPlaybackParameterChanged(final float playbackTempo, final float playbackPitch, - final boolean playbackSkipSilence) { - if (playerImpl != null) { - playerImpl.setPlaybackParameters(playbackTempo, playbackPitch, playbackSkipSilence); - } - } - - /////////////////////////////////////////////////////////////////////////// - - @SuppressWarnings({"unused", "WeakerAccess"}) - private class VideoPlayerImpl extends VideoPlayer { - private static final float MAX_GESTURE_LENGTH = 0.75f; - - private TextView titleTextView; - private TextView channelTextView; - private RelativeLayout volumeRelativeLayout; - private ProgressBar volumeProgressBar; - private ImageView volumeImageView; - private RelativeLayout brightnessRelativeLayout; - private ProgressBar brightnessProgressBar; - private ImageView brightnessImageView; - private ImageButton queueButton; - private ImageButton repeatButton; - private ImageButton shuffleButton; - - private ImageButton playPauseButton; - private ImageButton playPreviousButton; - private ImageButton playNextButton; - private Button closeButton; - - private RelativeLayout queueLayout; - private ImageButton itemsListCloseButton; - private RecyclerView itemsList; - private ItemTouchHelper itemTouchHelper; - - private boolean queueVisible; - - private ImageButton moreOptionsButton; - private ImageButton kodiButton; - private ImageButton shareButton; - private ImageButton toggleOrientationButton; - private ImageButton switchPopupButton; - private ImageButton switchBackgroundButton; - private ImageButton muteButton; - - private RelativeLayout windowRootLayout; - private View secondaryControls; - - private int maxGestureLength; - - VideoPlayerImpl(final Context context) { - super("VideoPlayerImpl" + MainVideoPlayer.TAG, context); - } - - @Override - public void initViews(final View view) { - super.initViews(view); - this.titleTextView = view.findViewById(R.id.titleTextView); - this.channelTextView = view.findViewById(R.id.channelTextView); - this.volumeRelativeLayout = view.findViewById(R.id.volumeRelativeLayout); - this.volumeProgressBar = view.findViewById(R.id.volumeProgressBar); - this.volumeImageView = view.findViewById(R.id.volumeImageView); - this.brightnessRelativeLayout = view.findViewById(R.id.brightnessRelativeLayout); - this.brightnessProgressBar = view.findViewById(R.id.brightnessProgressBar); - this.brightnessImageView = view.findViewById(R.id.brightnessImageView); - this.queueButton = view.findViewById(R.id.queueButton); - this.repeatButton = view.findViewById(R.id.repeatButton); - this.shuffleButton = view.findViewById(R.id.shuffleButton); - - this.playPauseButton = view.findViewById(R.id.playPauseButton); - this.playPreviousButton = view.findViewById(R.id.playPreviousButton); - this.playNextButton = view.findViewById(R.id.playNextButton); - this.closeButton = view.findViewById(R.id.closeButton); - - this.moreOptionsButton = view.findViewById(R.id.moreOptionsButton); - this.secondaryControls = view.findViewById(R.id.secondaryControls); - this.kodiButton = view.findViewById(R.id.playWithKodi); - this.shareButton = view.findViewById(R.id.share); - this.toggleOrientationButton = view.findViewById(R.id.toggleOrientation); - this.switchBackgroundButton = view.findViewById(R.id.switchBackground); - this.muteButton = view.findViewById(R.id.switchMute); - this.switchPopupButton = view.findViewById(R.id.switchPopup); - - this.queueLayout = findViewById(R.id.playQueuePanel); - this.itemsListCloseButton = findViewById(R.id.playQueueClose); - this.itemsList = findViewById(R.id.playQueue); - - titleTextView.setSelected(true); - channelTextView.setSelected(true); - - getRootView().setKeepScreenOn(true); - } - - @Override - protected void setupSubtitleView(@NonNull final SubtitleView view, - final float captionScale, - @NonNull final CaptionStyleCompat captionStyle) { - final DisplayMetrics metrics = context.getResources().getDisplayMetrics(); - final int minimumLength = Math.min(metrics.heightPixels, metrics.widthPixels); - final float captionRatioInverse = 20f + 4f * (1f - captionScale); - view.setFixedTextSize(TypedValue.COMPLEX_UNIT_PX, - (float) minimumLength / captionRatioInverse); - view.setApplyEmbeddedStyles(captionStyle.equals(CaptionStyleCompat.DEFAULT)); - view.setStyle(captionStyle); - } - - @Override - public void initListeners() { - super.initListeners(); - - PlayerGestureListener listener = new PlayerGestureListener(); - gestureDetector = new GestureDetector(context, listener); - gestureDetector.setIsLongpressEnabled(false); - getRootView().setOnTouchListener(listener); - - queueButton.setOnClickListener(this); - repeatButton.setOnClickListener(this); - shuffleButton.setOnClickListener(this); - - playPauseButton.setOnClickListener(this); - playPreviousButton.setOnClickListener(this); - playNextButton.setOnClickListener(this); - closeButton.setOnClickListener(this); - - moreOptionsButton.setOnClickListener(this); - kodiButton.setOnClickListener(this); - shareButton.setOnClickListener(this); - toggleOrientationButton.setOnClickListener(this); - switchBackgroundButton.setOnClickListener(this); - muteButton.setOnClickListener(this); - switchPopupButton.setOnClickListener(this); - - 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; - int height = b - t; - maxGestureLength = (int) (Math.min(width, height) * MAX_GESTURE_LENGTH); - - if (DEBUG) { - Log.d(TAG, "maxGestureLength = " + maxGestureLength); - } - - volumeProgressBar.setMax(maxGestureLength); - brightnessProgressBar.setMax(maxGestureLength); - - setInitialGestureValues(); - } - }); - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { - queueLayout.setOnApplyWindowInsetsListener(new View.OnApplyWindowInsetsListener() { - @Override - public WindowInsets onApplyWindowInsets(final View view, - final WindowInsets windowInsets) { - final DisplayCutout cutout = windowInsets.getDisplayCutout(); - if (cutout != null) { - view.setPadding(cutout.getSafeInsetLeft(), cutout.getSafeInsetTop(), - cutout.getSafeInsetRight(), cutout.getSafeInsetBottom()); - } - return windowInsets; - } - }); - } - } - - public void minimize() { - switch (PlayerHelper.getMinimizeOnExitAction(context)) { - case PlayerHelper.MinimizeMode.MINIMIZE_ON_EXIT_MODE_BACKGROUND: - onPlayBackgroundButtonClicked(); - break; - case PlayerHelper.MinimizeMode.MINIMIZE_ON_EXIT_MODE_POPUP: - toggleFullscreen(); - break; - case PlayerHelper.MinimizeMode.MINIMIZE_ON_EXIT_MODE_NONE: - default: - // No action - break; - } - } - - /*////////////////////////////////////////////////////////////////////////// - // ExoPlayer Video Listener - //////////////////////////////////////////////////////////////////////////*/ - - @Override - public void onRepeatModeChanged(final int i) { - super.onRepeatModeChanged(i); - updatePlaybackButtons(); - } - - @Override - public void onShuffleClicked() { - super.onShuffleClicked(); - updatePlaybackButtons(); - } - - /*////////////////////////////////////////////////////////////////////////// - // Playback Listener - //////////////////////////////////////////////////////////////////////////*/ - - protected void onMetadataChanged(@NonNull final MediaSourceTag tag) { - super.onMetadataChanged(tag); - - // show kodi button if it supports the current service and it is enabled in settings - final boolean showKodiButton = - KoreUtil.isServiceSupportedByKore(tag.getMetadata().getServiceId()) - && PreferenceManager.getDefaultSharedPreferences(context) - .getBoolean(context.getString(R.string.show_play_with_kodi_key), false); - kodiButton.setVisibility(showKodiButton ? View.VISIBLE : View.GONE); - - titleTextView.setText(tag.getMetadata().getName()); - channelTextView.setText(tag.getMetadata().getUploaderName()); - } - - @Override - public void onPlaybackShutdown() { - super.onPlaybackShutdown(); - finish(); - } - - public void onKodiShare() { - onPause(); - try { - NavigationHelper.playWithKore(context, Uri.parse(playerImpl.getVideoUrl())); - } catch (Exception e) { - if (DEBUG) { - Log.i(TAG, "Failed to start kore", e); - } - KoreUtil.showInstallKoreDialog(context); - } - } - - /*////////////////////////////////////////////////////////////////////////// - // Player Overrides - //////////////////////////////////////////////////////////////////////////*/ - - @Override - public void toggleFullscreen() { - super.toggleFullscreen(); - - if (DEBUG) { - Log.d(TAG, "onFullScreenButtonClicked() called"); - } - if (simpleExoPlayer == null) { - return; - } - - if (!PermissionHelper.isPopupEnabled(context)) { - PermissionHelper.showPopupEnablementToast(context); - return; - } - - setRecovery(); - final Intent intent = NavigationHelper.getPlayerIntent( - context, - PopupVideoPlayer.class, - this.getPlayQueue(), - this.getRepeatMode(), - this.getPlaybackSpeed(), - this.getPlaybackPitch(), - this.getPlaybackSkipSilence(), - this.getPlaybackQuality(), - false, - !isPlaying(), - isMuted() - ); - context.startService(intent); - - ((View) getControlAnimationView().getParent()).setVisibility(View.GONE); - destroy(); - finish(); - } - - public void onPlayBackgroundButtonClicked() { - if (DEBUG) { - Log.d(TAG, "onPlayBackgroundButtonClicked() called"); - } - if (playerImpl.getPlayer() == null) { - return; - } - - setRecovery(); - final Intent intent = NavigationHelper.getPlayerIntent( - context, - BackgroundPlayer.class, - this.getPlayQueue(), - this.getRepeatMode(), - this.getPlaybackSpeed(), - this.getPlaybackPitch(), - this.getPlaybackSkipSilence(), - this.getPlaybackQuality(), - false, - !isPlaying(), - isMuted() - ); - context.startService(intent); - - ((View) getControlAnimationView().getParent()).setVisibility(View.GONE); - destroy(); - finish(); - } - - @Override - public void onMuteUnmuteButtonClicked() { - super.onMuteUnmuteButtonClicked(); - setMuteButton(muteButton, playerImpl.isMuted()); - } - - - @Override - public void onClick(final View v) { - super.onClick(v); - if (v.getId() == playPauseButton.getId()) { - onPlayPause(); - } else if (v.getId() == playPreviousButton.getId()) { - onPlayPrevious(); - } else if (v.getId() == playNextButton.getId()) { - onPlayNext(); - } else if (v.getId() == queueButton.getId()) { - onQueueClicked(); - return; - } else if (v.getId() == repeatButton.getId()) { - onRepeatClicked(); - return; - } else if (v.getId() == shuffleButton.getId()) { - onShuffleClicked(); - return; - } else if (v.getId() == moreOptionsButton.getId()) { - onMoreOptionsClicked(); - } else if (v.getId() == shareButton.getId()) { - onShareClicked(); - } else if (v.getId() == toggleOrientationButton.getId()) { - onScreenRotationClicked(); - } else if (v.getId() == switchPopupButton.getId()) { - toggleFullscreen(); - } else if (v.getId() == switchBackgroundButton.getId()) { - onPlayBackgroundButtonClicked(); - } else if (v.getId() == muteButton.getId()) { - onMuteUnmuteButtonClicked(); - } else if (v.getId() == closeButton.getId()) { - onPlaybackShutdown(); - return; - } else if (v.getId() == kodiButton.getId()) { - onKodiShare(); - } - - if (getCurrentState() != STATE_COMPLETED) { - getControlsVisibilityHandler().removeCallbacksAndMessages(null); - animateView(getControlsRoot(), true, DEFAULT_CONTROLS_DURATION, 0, () -> { - if (getCurrentState() == STATE_PLAYING && !isSomePopupMenuVisible()) { - safeHideControls(DEFAULT_CONTROLS_DURATION, DEFAULT_CONTROLS_HIDE_TIME); - } - }); - } - } - - private void onQueueClicked() { - queueVisible = true; - hideSystemUi(); - - buildQueue(); - updatePlaybackButtons(); - - getControlsRoot().setVisibility(View.INVISIBLE); - animateView(queueLayout, SLIDE_AND_ALPHA, true, DEFAULT_CONTROLS_DURATION); - - itemsList.scrollToPosition(playQueue.getIndex()); - } - - private void onQueueClosed() { - animateView(queueLayout, SLIDE_AND_ALPHA, false, DEFAULT_CONTROLS_DURATION); - queueVisible = false; - } - - private void onMoreOptionsClicked() { - if (DEBUG) { - Log.d(TAG, "onMoreOptionsClicked() called"); - } - - final boolean isMoreControlsVisible - = secondaryControls.getVisibility() == View.VISIBLE; - - animateRotation(moreOptionsButton, DEFAULT_CONTROLS_DURATION, - isMoreControlsVisible ? 0 : 180); - animateView(secondaryControls, SLIDE_AND_ALPHA, !isMoreControlsVisible, - DEFAULT_CONTROLS_DURATION); - showControls(DEFAULT_CONTROLS_DURATION); - setMuteButton(muteButton, playerImpl.isMuted()); - } - - private void onShareClicked() { - // share video at the current time (youtube.com/watch?v=ID&t=SECONDS) - ShareUtils.shareUrl(MainVideoPlayer.this, playerImpl.getVideoTitle(), - playerImpl.getVideoUrl() - + "&t=" + playerImpl.getPlaybackSeekBar().getProgress() / 1000); - } - - private void onScreenRotationClicked() { - if (DEBUG) { - Log.d(TAG, "onScreenRotationClicked() called"); - } - toggleOrientation(); - showControlsThenHide(); - } - - @Override - public void onPlaybackSpeedClicked() { - PlaybackParameterDialog - .newInstance(getPlaybackSpeed(), - getPlaybackPitch(), - getPlaybackSkipSilence(), - MainVideoPlayer.this) - .show(getSupportFragmentManager(), TAG); - } - - @Override - public void onStopTrackingTouch(final SeekBar seekBar) { - super.onStopTrackingTouch(seekBar); - if (wasPlaying()) { - showControlsThenHide(); - } - } - - @Override - public void onDismiss(final PopupMenu menu) { - super.onDismiss(menu); - if (isPlaying()) { - hideControls(DEFAULT_CONTROLS_DURATION, 0); - } - hideSystemUi(); - } - - @Override - protected int nextResizeMode(final int currentResizeMode) { - final int newResizeMode; - switch (currentResizeMode) { - case AspectRatioFrameLayout.RESIZE_MODE_FIT: - newResizeMode = AspectRatioFrameLayout.RESIZE_MODE_FILL; - break; - case AspectRatioFrameLayout.RESIZE_MODE_FILL: - newResizeMode = AspectRatioFrameLayout.RESIZE_MODE_ZOOM; - break; - default: - newResizeMode = AspectRatioFrameLayout.RESIZE_MODE_FIT; - break; - } - - storeResizeMode(newResizeMode); - return newResizeMode; - } - - private void storeResizeMode(@AspectRatioFrameLayout.ResizeMode final int resizeMode) { - defaultPreferences.edit() - .putInt(getString(R.string.last_resize_mode), resizeMode) - .apply(); - } - - @Override - protected VideoPlaybackResolver.QualityResolver getQualityResolver() { - return new VideoPlaybackResolver.QualityResolver() { - @Override - public int getDefaultResolutionIndex(final List sortedVideos) { - return ListHelper.getDefaultResolutionIndex(context, sortedVideos); - } - - @Override - public int getOverrideResolutionIndex(final List sortedVideos, - final String playbackQuality) { - return ListHelper.getResolutionIndex(context, sortedVideos, playbackQuality); - } - }; - } - - /*////////////////////////////////////////////////////////////////////////// - // States - //////////////////////////////////////////////////////////////////////////*/ - - private void animatePlayButtons(final boolean show, final int duration) { - animateView(playPauseButton, AnimationUtils.Type.SCALE_AND_ALPHA, show, duration); - animateView(playPreviousButton, AnimationUtils.Type.SCALE_AND_ALPHA, show, duration); - animateView(playNextButton, AnimationUtils.Type.SCALE_AND_ALPHA, show, duration); - } - - @Override - public void onBlocked() { - super.onBlocked(); - playPauseButton.setImageResource(R.drawable.ic_pause_white_24dp); - animatePlayButtons(false, 100); - animateView(closeButton, false, DEFAULT_CONTROLS_DURATION); - getRootView().setKeepScreenOn(true); - } - - @Override - public void onBuffering() { - super.onBuffering(); - getRootView().setKeepScreenOn(true); - } - - @Override - public void onPlaying() { - super.onPlaying(); - animateView(playPauseButton, AnimationUtils.Type.SCALE_AND_ALPHA, false, 80, 0, () -> { - playPauseButton.setImageResource(R.drawable.ic_pause_white_24dp); - animatePlayButtons(true, 200); - playPauseButton.requestFocus(); - animateView(closeButton, false, DEFAULT_CONTROLS_DURATION); - }); - - getRootView().setKeepScreenOn(true); - } - - @Override - public void onPaused() { - super.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(); - animateView(closeButton, false, DEFAULT_CONTROLS_DURATION); - }); - - showSystemUi(); - getRootView().setKeepScreenOn(false); - } - - @Override - public void onPausedSeek() { - super.onPausedSeek(); - animatePlayButtons(false, 100); - getRootView().setKeepScreenOn(true); - } - - - @Override - public void onCompleted() { - animateView(playPauseButton, AnimationUtils.Type.SCALE_AND_ALPHA, false, 0, 0, () -> { - playPauseButton.setImageResource(R.drawable.ic_replay_white_24dp); - animatePlayButtons(true, DEFAULT_CONTROLS_DURATION); - animateView(closeButton, true, DEFAULT_CONTROLS_DURATION); - }); - getRootView().setKeepScreenOn(false); - super.onCompleted(); - } - - /*////////////////////////////////////////////////////////////////////////// - // Utils - //////////////////////////////////////////////////////////////////////////*/ - - private void setInitialGestureValues() { - if (getAudioReactor() != null) { - final float currentVolumeNormalized - = (float) getAudioReactor().getVolume() / getAudioReactor().getMaxVolume(); - volumeProgressBar.setProgress( - (int) (volumeProgressBar.getMax() * currentVolumeNormalized)); - } - - float screenBrightness = getWindow().getAttributes().screenBrightness; - if (screenBrightness < 0) { - screenBrightness = Settings.System.getInt(getContentResolver(), - Settings.System.SCREEN_BRIGHTNESS, 0) / 255.0f; - } - - brightnessProgressBar.setProgress( - (int) (brightnessProgressBar.getMax() * screenBrightness)); - - if (DEBUG) { - Log.d(TAG, "setInitialGestureValues: volumeProgressBar.getProgress() [" - + volumeProgressBar.getProgress() + "] " - + "brightnessProgressBar.getProgress() [" - + brightnessProgressBar.getProgress() + "]"); - } - } - - @Override - public void showControlsThenHide() { - if (queueVisible) { - return; - } - - super.showControlsThenHide(); - } - - @Override - public void showControls(final long duration) { - if (queueVisible) { - return; - } - - super.showControls(duration); - } - - @Override - public void safeHideControls(final long duration, final long delay) { - if (DEBUG) { - Log.d(TAG, "safeHideControls() called with: delay = [" + delay + "]"); - } - - View controlsRoot = getControlsRoot(); - if (controlsRoot.isInTouchMode()) { - getControlsVisibilityHandler().removeCallbacksAndMessages(null); - getControlsVisibilityHandler().postDelayed(() -> - animateView(controlsRoot, false, duration, 0, - MainVideoPlayer.this::hideSystemUi), delay); - } - } - - @Override - public void hideControls(final long duration, final long delay) { - if (DEBUG) { - Log.d(TAG, "hideControls() called with: delay = [" + delay + "]"); - } - getControlsVisibilityHandler().removeCallbacksAndMessages(null); - getControlsVisibilityHandler().postDelayed(() -> - animateView(getControlsRoot(), false, duration, 0, - MainVideoPlayer.this::hideSystemUi), - /*delayMillis=*/delay - ); - } - - @Override - public void hideSystemUIIfNeeded() { } - - private void updatePlaybackButtons() { - if (repeatButton == null || shuffleButton == null - || simpleExoPlayer == null || playQueue == null) { - return; - } - - setRepeatModeButton(repeatButton, getRepeatMode()); - setShuffleButton(shuffleButton, playQueue.isShuffled()); - } - - 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()); - } - - private OnScrollBelowItemsListener getQueueScrollListener() { - return new OnScrollBelowItemsListener() { - @Override - public void onScrolledDown(final 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(final int sourceIndex, final int targetIndex) { - if (playQueue != null) { - playQueue.move(sourceIndex, targetIndex); - } - } - - @Override - public void onSwiped(final int index) { - if (index != -1) { - playQueue.remove(index); - } - } - }; - } - - private PlayQueueItemBuilder.OnSelectedListener getOnSelectedListener() { - return new PlayQueueItemBuilder.OnSelectedListener() { - @Override - public void selected(final PlayQueueItem item, final View view) { - onSelected(item); - } - - @Override - public void held(final PlayQueueItem item, final View view) { - final int index = playQueue.indexOf(item); - if (index != -1) { - playQueue.remove(index); - } - } - - @Override - public void onStartDrag(final PlayQueueItemHolder viewHolder) { - if (itemTouchHelper != null) { - itemTouchHelper.startDrag(viewHolder); - } - } - }; - } - - /////////////////////////////////////////////////////////////////////////// - // Getters - /////////////////////////////////////////////////////////////////////////// - - public TextView getTitleTextView() { - return titleTextView; - } - - public TextView getChannelTextView() { - return channelTextView; - } - - 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 getRepeatButton() { - return repeatButton; - } - - public ImageButton getMuteButton() { - return muteButton; - } - - public ImageButton getPlayPauseButton() { - return playPauseButton; - } - - public int getMaxGestureLength() { - return maxGestureLength; - } - } - - private class PlayerGestureListener extends GestureDetector.SimpleOnGestureListener - implements View.OnTouchListener { - private static final int MOVEMENT_THRESHOLD = 40; - - private final boolean isVolumeGestureEnabled = PlayerHelper - .isVolumeGestureEnabled(getApplicationContext()); - private final boolean isBrightnessGestureEnabled = PlayerHelper - .isBrightnessGestureEnabled(getApplicationContext()); - - private final int maxVolume = playerImpl.getAudioReactor().getMaxVolume(); - - private boolean isMoving; - - @Override - public boolean onDoubleTap(final MotionEvent e) { - if (DEBUG) { - Log.d(TAG, "onDoubleTap() called with: " - + "e = [" + e + "], " - + "rawXy = " + e.getRawX() + ", " + e.getRawY() + ", " - + "xy = " + e.getX() + ", " + e.getY()); - } - - 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; - } - - @Override - public boolean onSingleTapConfirmed(final 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 { - playerImpl.playPauseButton.requestFocus(); - playerImpl.showControlsThenHide(); - showSystemUi(); - } - - return true; - } - - @Override - public boolean onDown(final MotionEvent e) { - if (DEBUG) { - Log.d(TAG, "onDown() called with: e = [" + e + "]"); - } - - return super.onDown(e); - } - - @Override - public boolean onScroll(final MotionEvent initialEvent, final MotionEvent movingEvent, - final float distanceX, final float distanceY) { - if (!isVolumeGestureEnabled && !isBrightnessGestureEnabled) { - return false; - } - - final boolean isTouchingStatusBar = initialEvent.getY() < getStatusBarHeight(); - final boolean isTouchingNavigationBar = initialEvent.getY() - > playerImpl.getRootView().getHeight() - getNavigationBarHeight(); - if (isTouchingStatusBar || isTouchingNavigationBar) { - return false; - } - -// if (DEBUG) { -// 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 (!isMoving && (insideThreshold || Math.abs(distanceX) > Math.abs(distanceY)) - || playerImpl.getCurrentState() == BasePlayer.STATE_COMPLETED) { - return false; - } - - isMoving = 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_24dp - : currentProgressPercent < 0.25 - ? R.drawable.ic_volume_mute_white_24dp - : currentProgressPercent < 0.75 - ? R.drawable.ic_volume_down_white_24dp - : R.drawable.ic_volume_up_white_24dp; - - playerImpl.getVolumeImageView().setImageDrawable( - AppCompatResources.getDrawable(getApplicationContext(), 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) { - playerImpl.getBrightnessProgressBar().incrementProgressBy((int) distanceY); - float currentProgressPercent - = (float) playerImpl.getBrightnessProgressBar().getProgress() - / playerImpl.getMaxGestureLength(); - WindowManager.LayoutParams layoutParams = getWindow().getAttributes(); - layoutParams.screenBrightness = currentProgressPercent; - getWindow().setAttributes(layoutParams); - - if (DEBUG) { - Log.d(TAG, "onScroll().brightnessControl, currentBrightness = " - + currentProgressPercent); - } - - final int resId = currentProgressPercent < 0.25 - ? R.drawable.ic_brightness_low_white_24dp - : currentProgressPercent < 0.75 - ? R.drawable.ic_brightness_medium_white_24dp - : R.drawable.ic_brightness_high_white_24dp; - - playerImpl.getBrightnessImageView().setImageDrawable( - AppCompatResources.getDrawable(getApplicationContext(), 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 int getNavigationBarHeight() { - int resId = getResources().getIdentifier("navigation_bar_height", "dimen", "android"); - if (resId > 0) { - return getResources().getDimensionPixelSize(resId); - } - return 0; - } - - private int getStatusBarHeight() { - int resId = getResources().getIdentifier("status_bar_height", "dimen", "android"); - if (resId > 0) { - return getResources().getDimensionPixelSize(resId); - } - return 0; - } - - private void onScrollEnd() { - 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); - } - } - - @Override - public boolean onTouch(final View v, final MotionEvent event) { -// if (DEBUG) { -// Log.d(TAG, "onTouch() called with: v = [" + v + "], event = [" + event + "]"); -// } - gestureDetector.onTouchEvent(event); - if (event.getAction() == MotionEvent.ACTION_UP && isMoving) { - isMoving = false; - onScrollEnd(); - } - return true; - } - - } -} diff --git a/app/src/main/java/org/schabi/newpipe/player/PopupVideoPlayer.java b/app/src/main/java/org/schabi/newpipe/player/PopupVideoPlayer.java deleted file mode 100644 index bffcaa6d1..000000000 --- a/app/src/main/java/org/schabi/newpipe/player/PopupVideoPlayer.java +++ /dev/null @@ -1,1315 +0,0 @@ -/* - * Copyright 2017 Mauricio Colli - * PopupVideoPlayer.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.animation.Animator; -import android.animation.AnimatorListenerAdapter; -import android.annotation.SuppressLint; -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.Configuration; -import android.graphics.Bitmap; -import android.graphics.PixelFormat; -import android.os.Build; -import android.os.IBinder; -import android.preference.PreferenceManager; -import android.util.DisplayMetrics; -import android.util.Log; -import android.view.GestureDetector; -import android.view.Gravity; -import android.view.MotionEvent; -import android.view.View; -import android.view.ViewConfiguration; -import android.view.ViewGroup; -import android.view.WindowManager; -import android.view.animation.AnticipateInterpolator; -import android.widget.ImageButton; -import android.widget.ImageView; -import android.widget.PopupMenu; -import android.widget.RemoteViews; -import android.widget.SeekBar; -import android.widget.TextView; - -import androidx.annotation.NonNull; -import androidx.core.app.NotificationCompat; - -import com.google.android.exoplayer2.C; -import com.google.android.exoplayer2.PlaybackParameters; -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 com.google.android.material.floatingactionbutton.FloatingActionButton; -import com.nostra13.universalimageloader.core.assist.FailReason; - -import org.schabi.newpipe.BuildConfig; -import org.schabi.newpipe.R; -import org.schabi.newpipe.extractor.stream.VideoStream; -import org.schabi.newpipe.player.event.PlayerEventListener; -import org.schabi.newpipe.player.helper.PlayerHelper; -import org.schabi.newpipe.player.resolver.MediaSourceTag; -import org.schabi.newpipe.player.resolver.VideoPlaybackResolver; -import org.schabi.newpipe.util.ListHelper; -import org.schabi.newpipe.util.NavigationHelper; -import org.schabi.newpipe.util.ThemeHelper; - -import java.util.List; - -import static org.schabi.newpipe.player.BasePlayer.STATE_PLAYING; -import static org.schabi.newpipe.player.VideoPlayer.DEFAULT_CONTROLS_DURATION; -import static org.schabi.newpipe.player.VideoPlayer.DEFAULT_CONTROLS_HIDE_TIME; -import static org.schabi.newpipe.util.AnimationUtils.animateView; -import static org.schabi.newpipe.util.Localization.assureCorrectAppLanguage; - -/** - * Service Popup Player implementing {@link VideoPlayer}. - * - * @author mauriciocolli - */ -public final class PopupVideoPlayer extends Service { - public static final String ACTION_CLOSE = "org.schabi.newpipe.player.PopupVideoPlayer.CLOSE"; - public static final String ACTION_PLAY_PAUSE - = "org.schabi.newpipe.player.PopupVideoPlayer.PLAY_PAUSE"; - public static final String ACTION_REPEAT = "org.schabi.newpipe.player.PopupVideoPlayer.REPEAT"; - private static final String TAG = ".PopupVideoPlayer"; - private static final boolean DEBUG = BasePlayer.DEBUG; - private static final int NOTIFICATION_ID = 40028922; - private static final String POPUP_SAVED_WIDTH = "popup_saved_width"; - private static final String POPUP_SAVED_X = "popup_saved_x"; - private static final String POPUP_SAVED_Y = "popup_saved_y"; - - private static final int MINIMUM_SHOW_EXTRA_WIDTH_DP = 300; - - private static final int IDLE_WINDOW_FLAGS = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE - | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM; - private static final int ONGOING_PLAYBACK_WINDOW_FLAGS = IDLE_WINDOW_FLAGS - | WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON; - - private WindowManager windowManager; - private WindowManager.LayoutParams popupLayoutParams; - private GestureDetector popupGestureDetector; - - private View closeOverlayView; - private FloatingActionButton closeOverlayButton; - - private int tossFlingVelocity; - - private float screenWidth; - private float screenHeight; - private float popupWidth; - private float popupHeight; - - private float minimumWidth; - private float minimumHeight; - private float maximumWidth; - private float maximumHeight; - - private NotificationManager notificationManager; - private NotificationCompat.Builder notBuilder; - private RemoteViews notRemoteView; - - private VideoPlayerImpl playerImpl; - private boolean isPopupClosing = false; - - /*////////////////////////////////////////////////////////////////////////// - // Service-Activity Binder - //////////////////////////////////////////////////////////////////////////*/ - - private PlayerEventListener activityListener; - private IBinder mBinder; - - /*////////////////////////////////////////////////////////////////////////// - // Service LifeCycle - //////////////////////////////////////////////////////////////////////////*/ - - @Override - public void onCreate() { - assureCorrectAppLanguage(this); - windowManager = (WindowManager) getSystemService(WINDOW_SERVICE); - notificationManager = ((NotificationManager) getSystemService(NOTIFICATION_SERVICE)); - - playerImpl = new VideoPlayerImpl(this); - ThemeHelper.setTheme(this); - - mBinder = new PlayerServiceBinder(playerImpl); - } - - @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 + "]"); - } - if (playerImpl.getPlayer() == null) { - initPopup(); - initPopupCloseOverlay(); - } - - playerImpl.handleIntent(intent); - - return START_NOT_STICKY; - } - - @Override - public void onConfigurationChanged(final Configuration newConfig) { - assureCorrectAppLanguage(this); - if (DEBUG) { - Log.d(TAG, "onConfigurationChanged() called with: " - + "newConfig = [" + newConfig + "]"); - } - updateScreenSize(); - updatePopupSize(popupLayoutParams.width, -1); - checkPopupPositionBounds(); - } - - @Override - public void onDestroy() { - if (DEBUG) { - Log.d(TAG, "onDestroy() called"); - } - closePopup(); - } - - @Override - protected void attachBaseContext(final Context base) { - super.attachBaseContext(AudioServiceLeakFix.preventLeakOf(base)); - } - - @Override - public IBinder onBind(final Intent intent) { - return mBinder; - } - - /*////////////////////////////////////////////////////////////////////////// - // Init - //////////////////////////////////////////////////////////////////////////*/ - - @SuppressLint("RtlHardcoded") - private void initPopup() { - if (DEBUG) { - Log.d(TAG, "initPopup() called"); - } - View rootView = View.inflate(this, R.layout.player_popup, null); - playerImpl.setup(rootView); - - tossFlingVelocity = PlayerHelper.getTossFlingVelocity(this); - - updateScreenSize(); - - final boolean popupRememberSizeAndPos = PlayerHelper.isRememberingPopupDimensions(this); - final float defaultSize = getResources().getDimension(R.dimen.popup_default_width); - SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this); - 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(); - - PopupWindowGestureListener listener = new PopupWindowGestureListener(); - popupGestureDetector = new GestureDetector(this, listener); - rootView.setOnTouchListener(listener); - - playerImpl.getLoadingPanel().setMinimumWidth(popupLayoutParams.width); - playerImpl.getLoadingPanel().setMinimumHeight(popupLayoutParams.height); - windowManager.addView(rootView, popupLayoutParams); - } - - @SuppressLint("RtlHardcoded") - private void initPopupCloseOverlay() { - if (DEBUG) { - Log.d(TAG, "initPopupCloseOverlay() called"); - } - closeOverlayView = View.inflate(this, 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); - } - - /*////////////////////////////////////////////////////////////////////////// - // Notification - //////////////////////////////////////////////////////////////////////////*/ - - private void resetNotification() { - notBuilder = createNotification(); - } - - private NotificationCompat.Builder createNotification() { - notRemoteView = new RemoteViews(BuildConfig.APPLICATION_ID, - R.layout.player_popup_notification); - - notRemoteView.setTextViewText(R.id.notificationSongName, playerImpl.getVideoTitle()); - notRemoteView.setTextViewText(R.id.notificationArtist, playerImpl.getUploaderName()); - notRemoteView.setImageViewBitmap(R.id.notificationCover, playerImpl.getThumbnail()); - - notRemoteView.setOnClickPendingIntent(R.id.notificationPlayPause, - PendingIntent.getBroadcast(this, NOTIFICATION_ID, new Intent(ACTION_PLAY_PAUSE), - PendingIntent.FLAG_UPDATE_CURRENT)); - notRemoteView.setOnClickPendingIntent(R.id.notificationStop, - PendingIntent.getBroadcast(this, NOTIFICATION_ID, new Intent(ACTION_CLOSE), - PendingIntent.FLAG_UPDATE_CURRENT)); - notRemoteView.setOnClickPendingIntent(R.id.notificationRepeat, - PendingIntent.getBroadcast(this, NOTIFICATION_ID, new Intent(ACTION_REPEAT), - PendingIntent.FLAG_UPDATE_CURRENT)); - - // Starts popup player activity -- attempts to unlock lockscreen - final Intent intent = NavigationHelper.getBackgroundPlayerActivityIntent(this); - notRemoteView.setOnClickPendingIntent(R.id.notificationContent, - PendingIntent.getActivity(this, NOTIFICATION_ID, intent, - PendingIntent.FLAG_UPDATE_CURRENT)); - - setRepeatModeRemote(notRemoteView, playerImpl.getRepeatMode()); - - 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) - .setContent(notRemoteView); - if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN) { - builder.setPriority(NotificationCompat.PRIORITY_MAX); - } - return builder; - } - - /** - * 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 void updateNotification(final int drawableId) { - if (DEBUG) { - Log.d(TAG, "updateNotification() called with: drawableId = [" + drawableId + "]"); - } - if (notBuilder == null || notRemoteView == null) { - return; - } - if (drawableId != -1) { - notRemoteView.setImageViewResource(R.id.notificationPlayPause, drawableId); - } - notificationManager.notify(NOTIFICATION_ID, notBuilder.build()); - } - - /*////////////////////////////////////////////////////////////////////////// - // Misc - //////////////////////////////////////////////////////////////////////////*/ - - public void closePopup() { - if (DEBUG) { - Log.d(TAG, "closePopup() called, isPopupClosing = " + isPopupClosing); - } - if (isPopupClosing) { - return; - } - isPopupClosing = true; - - if (playerImpl != null) { - playerImpl.savePlaybackState(); - if (playerImpl.getRootView() != null) { - windowManager.removeView(playerImpl.getRootView()); - } - playerImpl.setRootView(null); - playerImpl.stopActivityBinding(); - playerImpl.destroy(); - playerImpl = null; - } - - mBinder = null; - if (notificationManager != null) { - notificationManager.cancel(NOTIFICATION_ID); - } - - 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(final Animator animation) { - end(); - } - - @Override - public void onAnimationEnd(final Animator animation) { - end(); - } - - private void end() { - windowManager.removeView(closeOverlayView); - - stopForeground(true); - stopSelf(); - } - }).start(); - } - - /*////////////////////////////////////////////////////////////////////////// - // Utils - //////////////////////////////////////////////////////////////////////////*/ - - /** - * @see #checkPopupPositionBounds(float, float) - * @return if the popup was out of bounds and have been moved back to it - */ - @SuppressWarnings("UnusedReturnValue") - private 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. - *

- * - * @param boundaryWidth width of the boundary - * @param boundaryHeight height of the boundary - * @return if the popup was out of bounds and have been moved back to it - */ - private 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; - } - - private void savePositionAndSize() { - SharedPreferences sharedPreferences = PreferenceManager - .getDefaultSharedPreferences(PopupVideoPlayer.this); - 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(final float width) { - final float height = width / (16.0f / 9.0f); // Respect the 16:9 ratio that most videos have -// if (DEBUG) { -// Log.d(TAG, "getMinimumVideoHeight() called with: width = [" + width + "], " -// + "returned: " + height); -// } - return height; - } - - private 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 = getResources().getDimension(R.dimen.popup_default_width); - popupHeight = getMinimumVideoHeight(popupWidth); - - minimumWidth = getResources().getDimension(R.dimen.popup_minimum_width); - minimumHeight = getMinimumVideoHeight(minimumWidth); - - maximumWidth = screenWidth; - maximumHeight = screenHeight; - } - - private void updatePopupSize(final int width, final int height) { - if (playerImpl == null) { - return; - } - if (DEBUG) { - Log.d(TAG, "updatePopupSize() called with: " - + "width = [" + width + "], height = [" + height + "]"); - } - - final int actualWidth = (int) (width > maximumWidth ? maximumWidth - : width < minimumWidth ? minimumWidth : width); - - final int actualHeight; - if (height == -1) { - actualHeight = (int) getMinimumVideoHeight(width); - } else { - actualHeight = (int) (height > maximumHeight ? maximumHeight - : height < minimumHeight ? minimumHeight : height); - } - - popupLayoutParams.width = actualWidth; - popupLayoutParams.height = actualHeight; - popupWidth = actualWidth; - popupHeight = actualHeight; - - if (DEBUG) { - Log.d(TAG, "updatePopupSize() updated values: " - + "width = [" + actualWidth + "], height = [" + actualHeight + "]"); - } - windowManager.updateViewLayout(playerImpl.getRootView(), popupLayoutParams); - } - - protected void setRepeatModeRemote(final RemoteViews remoteViews, final int repeatMode) { - final String methodName = "setImageResource"; - - if (remoteViews == null) { - return; - } - - switch (repeatMode) { - case Player.REPEAT_MODE_OFF: - remoteViews.setInt(R.id.notificationRepeat, methodName, - R.drawable.exo_controls_repeat_off); - break; - case Player.REPEAT_MODE_ONE: - remoteViews.setInt(R.id.notificationRepeat, methodName, - R.drawable.exo_controls_repeat_one); - break; - case Player.REPEAT_MODE_ALL: - remoteViews.setInt(R.id.notificationRepeat, methodName, - R.drawable.exo_controls_repeat_all); - break; - } - } - - private void updateWindowFlags(final int flags) { - if (popupLayoutParams == null || windowManager == null || playerImpl == null) { - return; - } - - popupLayoutParams.flags = flags; - windowManager.updateViewLayout(playerImpl.getRootView(), popupLayoutParams); - } - /////////////////////////////////////////////////////////////////////////// - - protected class VideoPlayerImpl extends VideoPlayer implements View.OnLayoutChangeListener { - private TextView resizingIndicator; - private ImageButton fullScreenButton; - private ImageView videoPlayPause; - - private View extraOptionsView; - private View closingOverlayView; - - VideoPlayerImpl(final Context context) { - super("VideoPlayerImpl" + PopupVideoPlayer.TAG, context); - } - - @Override - public void handleIntent(final Intent intent) { - super.handleIntent(intent); - - resetNotification(); - startForeground(NOTIFICATION_ID, notBuilder.build()); - } - - @Override - public void initViews(final View rootView) { - super.initViews(rootView); - resizingIndicator = rootView.findViewById(R.id.resizing_indicator); - fullScreenButton = rootView.findViewById(R.id.fullScreenButton); - fullScreenButton.setOnClickListener(v -> toggleFullscreen()); - videoPlayPause = rootView.findViewById(R.id.videoPlayPause); - - extraOptionsView = rootView.findViewById(R.id.extraOptionsView); - closingOverlayView = rootView.findViewById(R.id.closingOverlay); - rootView.addOnLayoutChangeListener(this); - } - - @Override - public void initListeners() { - super.initListeners(); - videoPlayPause.setOnClickListener(v -> onPlayPause()); - } - - @Override - protected void setupSubtitleView(@NonNull final SubtitleView view, final float captionScale, - @NonNull final CaptionStyleCompat captionStyle) { - float captionRatio = (captionScale - 1f) / 5f + 1f; - view.setFractionalTextSize(SubtitleView.DEFAULT_TEXT_SIZE_FRACTION * captionRatio); - view.setApplyEmbeddedStyles(captionStyle.equals(CaptionStyleCompat.DEFAULT)); - view.setStyle(captionStyle); - } - - @Override - @SuppressWarnings("checkstyle:ParameterNumber") - public void onLayoutChange(final View view, final int left, final int top, final int right, - final int bottom, final int oldLeft, final int oldTop, - final int oldRight, final int oldBottom) { - float widthDp = Math.abs(right - left) / getResources().getDisplayMetrics().density; - final int visibility = widthDp > MINIMUM_SHOW_EXTRA_WIDTH_DP ? View.VISIBLE : View.GONE; - extraOptionsView.setVisibility(visibility); - } - - @Override - public void destroy() { - if (notRemoteView != null) { - notRemoteView.setImageViewBitmap(R.id.notificationCover, null); - } - super.destroy(); - } - - @Override - public void toggleFullscreen() { - super.toggleFullscreen(); - - if (DEBUG) { - Log.d(TAG, "onFullScreenButtonClicked() called"); - } - - setRecovery(); - final Intent intent = NavigationHelper.getPlayerIntent( - context, - MainVideoPlayer.class, - this.getPlayQueue(), - this.getRepeatMode(), - this.getPlaybackSpeed(), - this.getPlaybackPitch(), - this.getPlaybackSkipSilence(), - this.getPlaybackQuality(), - false, - !isPlaying(), - isMuted() - ); - intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - context.startActivity(intent); - closePopup(); - } - - @Override - public void onDismiss(final PopupMenu menu) { - super.onDismiss(menu); - if (isPlaying()) { - hideControls(500, 0); - } - } - - @Override - protected int nextResizeMode(final int resizeMode) { - if (resizeMode == AspectRatioFrameLayout.RESIZE_MODE_FILL) { - return AspectRatioFrameLayout.RESIZE_MODE_FIT; - } else { - return AspectRatioFrameLayout.RESIZE_MODE_FILL; - } - } - - @Override - public void onStopTrackingTouch(final SeekBar seekBar) { - super.onStopTrackingTouch(seekBar); - if (wasPlaying()) { - hideControls(100, 0); - } - } - - @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); - super.onUpdateProgress(currentProgress, duration, bufferPercent); - } - - @Override - protected VideoPlaybackResolver.QualityResolver getQualityResolver() { - return new VideoPlaybackResolver.QualityResolver() { - @Override - public int getDefaultResolutionIndex(final List sortedVideos) { - return ListHelper.getPopupDefaultResolutionIndex(context, sortedVideos); - } - - @Override - public int getOverrideResolutionIndex(final List sortedVideos, - final String playbackQuality) { - return ListHelper.getPopupResolutionIndex(context, sortedVideos, - playbackQuality); - } - }; - } - - /*////////////////////////////////////////////////////////////////////////// - // Thumbnail Loading - //////////////////////////////////////////////////////////////////////////*/ - - @Override - public void onLoadingComplete(final String imageUri, final View view, - final Bitmap loadedImage) { - super.onLoadingComplete(imageUri, view, loadedImage); - if (playerImpl == null) { - return; - } - // rebuild notification here since remote view does not release bitmaps, - // causing memory leaks - resetNotification(); - updateNotification(-1); - } - - @Override - public void onLoadingFailed(final String imageUri, final View view, - final FailReason failReason) { - super.onLoadingFailed(imageUri, view, failReason); - resetNotification(); - updateNotification(-1); - } - - @Override - public void onLoadingCancelled(final String imageUri, final View view) { - super.onLoadingCancelled(imageUri, view); - resetNotification(); - updateNotification(-1); - } - - /*////////////////////////////////////////////////////////////////////////// - // 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(), simpleExoPlayer.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; - } - } - - /*////////////////////////////////////////////////////////////////////////// - // ExoPlayer Video Listener - //////////////////////////////////////////////////////////////////////////*/ - - @Override - public void onRepeatModeChanged(final int i) { - super.onRepeatModeChanged(i); - setRepeatModeRemote(notRemoteView, i); - updatePlayback(); - resetNotification(); - updateNotification(-1); - } - - @Override - public void onPlaybackParametersChanged(final PlaybackParameters playbackParameters) { - super.onPlaybackParametersChanged(playbackParameters); - updatePlayback(); - } - - /*////////////////////////////////////////////////////////////////////////// - // Playback Listener - //////////////////////////////////////////////////////////////////////////*/ - - protected void onMetadataChanged(@NonNull final MediaSourceTag tag) { - super.onMetadataChanged(tag); - resetNotification(); - updateNotification(-1); - updateMetadata(); - } - - @Override - public void onPlaybackShutdown() { - super.onPlaybackShutdown(); - closePopup(); - } - - /*////////////////////////////////////////////////////////////////////////// - // Broadcast Receiver - //////////////////////////////////////////////////////////////////////////*/ - - @Override - protected void setupBroadcastReceiver(final IntentFilter intentFltr) { - super.setupBroadcastReceiver(intentFltr); - if (DEBUG) { - Log.d(TAG, "setupBroadcastReceiver() called with: " - + "intentFilter = [" + intentFltr + "]"); - } - intentFltr.addAction(ACTION_CLOSE); - intentFltr.addAction(ACTION_PLAY_PAUSE); - intentFltr.addAction(ACTION_REPEAT); - - intentFltr.addAction(Intent.ACTION_SCREEN_ON); - intentFltr.addAction(Intent.ACTION_SCREEN_OFF); - } - - @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: - closePopup(); - break; - case ACTION_PLAY_PAUSE: - onPlayPause(); - break; - case ACTION_REPEAT: - onRepeatClicked(); - break; - case Intent.ACTION_SCREEN_ON: - enableVideoRenderer(true); - break; - case Intent.ACTION_SCREEN_OFF: - enableVideoRenderer(false); - break; - } - } - - /*////////////////////////////////////////////////////////////////////////// - // States - //////////////////////////////////////////////////////////////////////////*/ - - @Override - public void changeState(final int state) { - super.changeState(state); - updatePlayback(); - } - - @Override - public void onBlocked() { - super.onBlocked(); - resetNotification(); - updateNotification(R.drawable.exo_controls_play); - } - - @Override - public void onPlaying() { - super.onPlaying(); - - updateWindowFlags(ONGOING_PLAYBACK_WINDOW_FLAGS); - - resetNotification(); - updateNotification(R.drawable.exo_controls_pause); - - videoPlayPause.setBackgroundResource(R.drawable.exo_controls_pause); - hideControls(DEFAULT_CONTROLS_DURATION, DEFAULT_CONTROLS_HIDE_TIME); - - startForeground(NOTIFICATION_ID, notBuilder.build()); - } - - @Override - public void onBuffering() { - super.onBuffering(); - resetNotification(); - updateNotification(R.drawable.exo_controls_play); - } - - @Override - public void onPaused() { - super.onPaused(); - - updateWindowFlags(IDLE_WINDOW_FLAGS); - - resetNotification(); - updateNotification(R.drawable.exo_controls_play); - videoPlayPause.setBackgroundResource(R.drawable.exo_controls_play); - - stopForeground(false); - } - - @Override - public void onPausedSeek() { - super.onPausedSeek(); - resetNotification(); - updateNotification(R.drawable.exo_controls_play); - - videoPlayPause.setBackgroundResource(R.drawable.exo_controls_play); - } - - @Override - public void onCompleted() { - super.onCompleted(); - - updateWindowFlags(IDLE_WINDOW_FLAGS); - - resetNotification(); - updateNotification(R.drawable.ic_replay_white_24dp); - videoPlayPause.setBackgroundResource(R.drawable.ic_replay_white_24dp); - - stopForeground(false); - } - - @Override - public void showControlsThenHide() { - videoPlayPause.setVisibility(View.VISIBLE); - super.showControlsThenHide(); - } - - public void showControls(final long duration) { - videoPlayPause.setVisibility(View.VISIBLE); - super.showControls(duration); - } - - public void hideControls(final long duration, final long delay) { - super.hideControlsAndButton(duration, delay, videoPlayPause); - } - - @Override - public void hideSystemUIIfNeeded() { } - - /*////////////////////////////////////////////////////////////////////////// - // Utils - //////////////////////////////////////////////////////////////////////////*/ - - /*package-private*/ void enableVideoRenderer(final boolean enable) { - final int videoRendererIndex = getRendererIndex(C.TRACK_TYPE_VIDEO); - if (videoRendererIndex != RENDERER_UNAVAILABLE) { - trackSelector.setParameters(trackSelector.buildUponParameters() - .setRendererDisabled(videoRendererIndex, !enable)); - } - } - - /*////////////////////////////////////////////////////////////////////////// - // Getters - //////////////////////////////////////////////////////////////////////////*/ - - @SuppressWarnings("WeakerAccess") - public TextView getResizingIndicator() { - return resizingIndicator; - } - - public View getClosingOverlayView() { - return closingOverlayView; - } - } - - private class PopupWindowGestureListener extends GestureDetector.SimpleOnGestureListener - implements View.OnTouchListener { - private int initialPopupX; - private int initialPopupY; - private boolean isMoving; - private boolean isResizing; - - //initial co-ordinates and distance between fingers - private double initPointerDistance = -1; - private float initFirstPointerX = -1; - private float initFirstPointerY = -1; - private float initSecPointerX = -1; - private float initSecPointerY = -1; - - - @Override - public boolean onDoubleTap(final MotionEvent e) { - if (DEBUG) { - Log.d(TAG, "onDoubleTap() called with: e = [" + e + "], " - + "rawXy = " + e.getRawX() + ", " + e.getRawY() - + ", xy = " + e.getX() + ", " + e.getY()); - } - if (playerImpl == null || !playerImpl.isPlaying()) { - return false; - } - - playerImpl.hideControls(0, 0); - - if (e.getX() > popupWidth / 2) { - playerImpl.onFastForward(); - } else { - playerImpl.onFastRewind(); - } - - return true; - } - - @Override - public boolean onSingleTapConfirmed(final MotionEvent e) { - if (DEBUG) { - Log.d(TAG, "onSingleTapConfirmed() called with: e = [" + e + "]"); - } - if (playerImpl == null || playerImpl.getPlayer() == null) { - return false; - } - if (playerImpl.isControlsVisible()) { - playerImpl.hideControls(100, 100); - } else { - playerImpl.showControlsThenHide(); - - } - return true; - } - - @Override - public boolean onDown(final MotionEvent e) { - if (DEBUG) { - Log.d(TAG, "onDown() called with: e = [" + 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). - checkPopupPositionBounds(closeOverlayView.getWidth(), closeOverlayView.getHeight()); - - initialPopupX = popupLayoutParams.x; - initialPopupY = popupLayoutParams.y; - popupWidth = popupLayoutParams.width; - popupHeight = popupLayoutParams.height; - return super.onDown(e); - } - - @Override - public void onLongPress(final MotionEvent e) { - if (DEBUG) { - Log.d(TAG, "onLongPress() called with: e = [" + e + "]"); - } - updateScreenSize(); - checkPopupPositionBounds(); - updatePopupSize((int) screenWidth, -1); - } - - @Override - public boolean onScroll(final MotionEvent initialEvent, final MotionEvent movingEvent, - final float distanceX, final float distanceY) { - if (isResizing || playerImpl == null) { - return super.onScroll(initialEvent, movingEvent, distanceX, distanceY); - } - - if (!isMoving) { - animateView(closeOverlayButton, true, 200); - } - - isMoving = true; - - float diffX = (int) (movingEvent.getRawX() - initialEvent.getRawX()); - float posX = (int) (initialPopupX + diffX); - float diffY = (int) (movingEvent.getRawY() - initialEvent.getRawY()); - float posY = (int) (initialPopupY + diffY); - - if (posX > (screenWidth - popupWidth)) { - posX = (int) (screenWidth - popupWidth); - } else if (posX < 0) { - posX = 0; - } - - if (posY > (screenHeight - popupHeight)) { - posY = (int) (screenHeight - popupHeight); - } else if (posY < 0) { - posY = 0; - } - - popupLayoutParams.x = (int) posX; - popupLayoutParams.y = (int) posY; - - final View closingOverlayView = playerImpl.getClosingOverlayView(); - if (isInsideClosingRadius(movingEvent)) { - if (closingOverlayView.getVisibility() == View.GONE) { - animateView(closingOverlayView, true, 250); - } - } else { - if (closingOverlayView.getVisibility() == View.VISIBLE) { - animateView(closingOverlayView, false, 0); - } - } - -// if (DEBUG) { -// 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 = [" + popupWidth + " x " + popupHeight + "]"); -// } - windowManager.updateViewLayout(playerImpl.getRootView(), popupLayoutParams); - return true; - } - - private void onScrollEnd(final MotionEvent event) { - if (DEBUG) { - Log.d(TAG, "onScrollEnd() called"); - } - if (playerImpl == null) { - return; - } - if (playerImpl.isControlsVisible() && playerImpl.getCurrentState() == STATE_PLAYING) { - playerImpl.hideControls(DEFAULT_CONTROLS_DURATION, DEFAULT_CONTROLS_HIDE_TIME); - } - - if (isInsideClosingRadius(event)) { - closePopup(); - } else { - animateView(playerImpl.getClosingOverlayView(), false, 0); - - if (!isPopupClosing) { - animateView(closeOverlayButton, false, 200); - } - } - } - - @Override - public boolean onFling(final MotionEvent e1, final MotionEvent e2, - final float velocityX, final float velocityY) { - if (DEBUG) { - Log.d(TAG, "Fling velocity: dX=[" + velocityX + "], dY=[" + 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) { - popupLayoutParams.x = (int) velocityX; - } - if (absVelocityY > tossFlingVelocity) { - popupLayoutParams.y = (int) velocityY; - } - checkPopupPositionBounds(); - windowManager.updateViewLayout(playerImpl.getRootView(), popupLayoutParams); - return true; - } - return false; - } - - @Override - public boolean onTouch(final View v, final MotionEvent event) { - popupGestureDetector.onTouchEvent(event); - if (playerImpl == null) { - return false; - } - if (event.getPointerCount() == 2 && !isMoving && !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); - - //record co-ordinates of fingers - initFirstPointerX = event.getX(0); - initFirstPointerY = event.getY(0); - initSecPointerX = event.getX(1); - initSecPointerY = event.getY(1); - //record distance between fingers - initPointerDistance = Math.hypot(initFirstPointerX - initSecPointerX, - initFirstPointerY - initSecPointerY); - - isResizing = true; - } - - if (event.getAction() == MotionEvent.ACTION_MOVE && !isMoving && 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 (isMoving) { - isMoving = false; - onScrollEnd(event); - } - - if (isResizing) { - isResizing = false; - - initPointerDistance = -1; - initFirstPointerX = -1; - initFirstPointerY = -1; - initSecPointerX = -1; - initSecPointerY = -1; - - animateView(playerImpl.getResizingIndicator(), false, 100, 0); - playerImpl.changeState(playerImpl.getCurrentState()); - } - - if (!isPopupClosing) { - savePositionAndSize(); - } - } - - v.performClick(); - return true; - } - - private boolean handleMultiDrag(final MotionEvent event) { - if (initPointerDistance != -1 && event.getPointerCount() == 2) { - // get the movements of the fingers - double firstPointerMove = Math.hypot(event.getX(0) - initFirstPointerX, - event.getY(0) - initFirstPointerY); - double secPointerMove = Math.hypot(event.getX(1) - initSecPointerX, - event.getY(1) - initSecPointerY); - - // minimum threshold beyond which pinch gesture will work - int minimumMove = ViewConfiguration.get(PopupVideoPlayer.this).getScaledTouchSlop(); - - if (Math.max(firstPointerMove, secPointerMove) > minimumMove) { - // calculate current distance between the pointers - double currentPointerDistance = - Math.hypot(event.getX(0) - event.getX(1), - event.getY(0) - event.getY(1)); - - // change co-ordinates of popup so the center stays at the same position - double newWidth = (popupWidth * currentPointerDistance / initPointerDistance); - initPointerDistance = currentPointerDistance; - popupLayoutParams.x += (popupWidth - newWidth) / 2; - - checkPopupPositionBounds(); - updateScreenSize(); - - updatePopupSize((int) Math.min(screenWidth, newWidth), -1); - return true; - } - } - return false; - } - - /*////////////////////////////////////////////////////////////////////////// - // Utils - //////////////////////////////////////////////////////////////////////////*/ - - 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(); - - 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; - } - - private boolean isInsideClosingRadius(final MotionEvent popupMotionEvent) { - return distanceFromCloseButton(popupMotionEvent) <= getClosingRadius(); - } - } -} diff --git a/app/src/main/java/org/schabi/newpipe/player/PopupVideoPlayerActivity.java b/app/src/main/java/org/schabi/newpipe/player/PopupVideoPlayerActivity.java deleted file mode 100644 index 7c5813bc4..000000000 --- a/app/src/main/java/org/schabi/newpipe/player/PopupVideoPlayerActivity.java +++ /dev/null @@ -1,72 +0,0 @@ -package org.schabi.newpipe.player; - -import android.content.Intent; -import android.view.Menu; -import android.view.MenuItem; - -import org.schabi.newpipe.R; - -import static org.schabi.newpipe.player.PopupVideoPlayer.ACTION_CLOSE; - -public final class PopupVideoPlayerActivity extends ServicePlayerActivity { - - private static final String TAG = "PopupVideoPlayerActivity"; - - @Override - public String getTag() { - return TAG; - } - - @Override - public String getSupportActionTitle() { - return getResources().getString(R.string.title_activity_popup_player); - } - - @Override - public Intent getBindIntent() { - return new Intent(this, PopupVideoPlayer.class); - } - - @Override - public void startPlayerListener() { - if (player != null && player instanceof PopupVideoPlayer.VideoPlayerImpl) { - ((PopupVideoPlayer.VideoPlayerImpl) player).setActivityListener(this); - } - } - - @Override - public void stopPlayerListener() { - if (player != null && player instanceof PopupVideoPlayer.VideoPlayerImpl) { - ((PopupVideoPlayer.VideoPlayerImpl) player).removeActivityListener(this); - } - } - - @Override - public int getPlayerOptionMenuResource() { - return R.menu.menu_play_queue_popup; - } - - @Override - public boolean onPlayerOptionSelected(final MenuItem item) { - if (item.getItemId() == R.id.action_switch_background) { - this.player.setRecovery(); - getApplicationContext().sendBroadcast(getPlayerShutdownIntent()); - getApplicationContext().startService( - getSwitchIntent(MainPlayer.class, MainPlayer.PlayerType.AUDIO) - .putExtra(BasePlayer.START_PAUSED, !this.player.isPlaying()) - ); - return true; - } - return false; - } - - @Override - public void setupMenu(final Menu menu) { - - } - - //@Override - public Intent getPlayerShutdownIntent() { - return new Intent(ACTION_CLOSE); - } -} 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 d2eb591f4..0f98b2296 100644 --- a/app/src/main/java/org/schabi/newpipe/player/VideoPlayerImpl.java +++ b/app/src/main/java/org/schabi/newpipe/player/VideoPlayerImpl.java @@ -1,6 +1,6 @@ /* * Copyright 2017 Mauricio Colli - * PopupVideoPlayer.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/event/PlayerGestureListener.java b/app/src/main/java/org/schabi/newpipe/player/event/PlayerGestureListener.java index 9eb56ff84..e37a3a930 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 @@ -213,7 +213,7 @@ public class PlayerGestureListener return false; } - /*if (DEBUG && false) Log.d(TAG, "MainVideoPlayer.onScroll = " + + /*if (DEBUG && false) Log.d(TAG, "onScrollInMain = " + ", e1.getRaw = [" + initialEvent.getRawX() + ", " + initialEvent.getRawY() + "]" + ", e2.getRaw = [" + movingEvent.getRawX() + ", " + movingEvent.getRawY() + "]" + ", distanceXy = [" + distanceX + ", " + distanceY + "]");*/ @@ -431,7 +431,7 @@ public class PlayerGestureListener } // if (DEBUG) { -// Log.d(TAG, "PopupVideoPlayer.onScroll = " +// Log.d(TAG, "onScrollInPopup = " // + "e1.getRaw = [" + initialEvent.getRawX() + ", " // + initialEvent.getRawY() + "], " // + "e1.getX,Y = [" + initialEvent.getX() + ", " diff --git a/app/src/main/res/layout/player_popup.xml b/app/src/main/res/layout/player_popup.xml deleted file mode 100644 index 1ca07ca10..000000000 --- a/app/src/main/res/layout/player_popup.xml +++ /dev/null @@ -1,299 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/layout/player_popup_notification.xml b/app/src/main/res/layout/player_popup_notification.xml deleted file mode 100644 index e8b077ecc..000000000 --- a/app/src/main/res/layout/player_popup_notification.xml +++ /dev/null @@ -1,88 +0,0 @@ - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/menu/menu_play_queue_popup.xml b/app/src/main/res/menu/menu_play_queue_popup.xml deleted file mode 100644 index dd5177da9..000000000 --- a/app/src/main/res/menu/menu_play_queue_popup.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - - diff --git a/app/src/main/res/menu/menu_videooptions.xml b/app/src/main/res/menu/menu_videooptions.xml deleted file mode 100644 index f153ad31c..000000000 --- a/app/src/main/res/menu/menu_videooptions.xml +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - - diff --git a/app/src/main/res/values-ar/strings.xml b/app/src/main/res/values-ar/strings.xml index 2d007a043..d8ab4f6cd 100644 --- a/app/src/main/res/values-ar/strings.xml +++ b/app/src/main/res/values-ar/strings.xml @@ -227,8 +227,6 @@ الشائعة أفضل 50 جديد وساخن - مشغل الخلفية - المشغل المنبثق حذف التفاصيل الإعدادات الصوتية 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 40712041e..5bae06248 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 @@ -273,8 +273,6 @@ 无法播放此串流 发生无法恢复播放器错误 恢复播放器错误 - 后台播放 - 悬浮窗播放器 移除 详情 音频设置 diff --git a/app/src/main/res/values-be/strings.xml b/app/src/main/res/values-be/strings.xml index fbd7a99c0..7088a324f 100644 --- a/app/src/main/res/values-be/strings.xml +++ b/app/src/main/res/values-be/strings.xml @@ -314,8 +314,6 @@ Трэнды Топ 50 Новае і гарачае - У фоне - У акне Выдаліць Падрабязнасці Налады аўдыё diff --git a/app/src/main/res/values-bg/strings.xml b/app/src/main/res/values-bg/strings.xml index 400c8d280..e37a124a6 100644 --- a/app/src/main/res/values-bg/strings.xml +++ b/app/src/main/res/values-bg/strings.xml @@ -307,8 +307,6 @@ Набиращи популярност Топ 50 Ново и горещо - Във фонов режим - В прозорец Премахни Детайли Аудио настройки diff --git a/app/src/main/res/values-ca/strings.xml b/app/src/main/res/values-ca/strings.xml index d77c6a63a..726851fb4 100644 --- a/app/src/main/res/values-ca/strings.xml +++ b/app/src/main/res/values-ca/strings.xml @@ -259,8 +259,6 @@ Quiosc Tendències Els millors 50 - Reproductor en rerefons - Reproductor emergent Afegeix a la cua de reproducció en rerefons Afegeix a la cua de reproducció emergent Reprodueix aquí diff --git a/app/src/main/res/values-ckb/strings.xml b/app/src/main/res/values-ckb/strings.xml index c913207cc..203391c36 100644 --- a/app/src/main/res/values-ckb/strings.xml +++ b/app/src/main/res/values-ckb/strings.xml @@ -188,7 +188,6 @@ ڕووكار گۆڕین بۆ سەرەکی دەقە بنچینەییەکان لە خزمەتگوزارییەکانەوە لە بابەتی پەخشەکاندا دیار دەبن - کارپێکەری پەنجەرەی بچووک داگرتن ژێرنووسەکان بەستەر هەڵەیە @@ -601,7 +600,6 @@ دواین کارپێکراو ناتوانرێ لیستی داگرتن دابنرێ هێنانەوە/هاوردەکردن - کارپێکەری پاشبنەما وەشانی نوێی داوانامە بەردەستە! وێنۆچکەی خشتەی کارپێکردن گۆڕدرا. هێنانەوەی پەڕەی کەسی SoundCloud بەدانانی بەستەر یاخوود ئایدی: diff --git a/app/src/main/res/values-cs/strings.xml b/app/src/main/res/values-cs/strings.xml index f18da7ba0..c92727e7b 100644 --- a/app/src/main/res/values-cs/strings.xml +++ b/app/src/main/res/values-cs/strings.xml @@ -234,8 +234,6 @@ otevření ve vyskakovacím okně Trendy Top 50 Nové & hot - Přehrávač na pozadí - Přehrávač v okně Odebrat Podrobnosti Nastavení zvuku diff --git a/app/src/main/res/values-da/strings.xml b/app/src/main/res/values-da/strings.xml index 91ca1040f..2217f37e0 100644 --- a/app/src/main/res/values-da/strings.xml +++ b/app/src/main/res/values-da/strings.xml @@ -315,8 +315,6 @@ Populært lige nu Top 50 Nyt og populært - Baggrundsafspiller - Pop op-afspiller Fjern Detaljer Lydindstillinger diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index 20c4e3286..3dd629323 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -225,8 +225,6 @@ Abonnement-Seite Feed-Seite Kanal-Seite - Wiedergabe im Hintergrund - Pop-up Player Details Top 50 Nicht behebbarer Wiedergabefehler aufgetreten diff --git a/app/src/main/res/values-el/strings.xml b/app/src/main/res/values-el/strings.xml index ed5a6b299..cd29ee996 100644 --- a/app/src/main/res/values-el/strings.xml +++ b/app/src/main/res/values-el/strings.xml @@ -307,8 +307,6 @@ Αυτό θα παρακάμψει τις τρέχουσες ρυθμίσεις σας. Θέλετε επίσης να εισάγετε ρυθμίσεις; Περίπτερο - Συσκευή αναπαραγωγής Παρασκηνίου - Συσκευή αναπαραγωγής Αναδυόμενου παραθύρου Αφαίρεση Λεπτομέρειες Ρυθμίσεις ήχου diff --git a/app/src/main/res/values-eo/strings.xml b/app/src/main/res/values-eo/strings.xml index f219ee2e8..9144dfe58 100644 --- a/app/src/main/res/values-eo/strings.xml +++ b/app/src/main/res/values-eo/strings.xml @@ -162,8 +162,6 @@ Ne povis ludi tion torenton Neatendebla eraro de ludilo okazis Reakiri el eraro de la ludilo - Fona ludilo - Ŝprucfenestra ludilo Retiri Detalado Sonaj parametroj diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index cbff74f70..8c412f8de 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -230,8 +230,6 @@ No se pudo reproducir este stream Se produjo un error irrecuperable del reproductor Recuperándose del error del reproductor - Reproductor en segundo plano - Reproductor emergente Quitar Detalles Configuración de audio diff --git a/app/src/main/res/values-et/strings.xml b/app/src/main/res/values-et/strings.xml index a32d26af2..0bf400e19 100644 --- a/app/src/main/res/values-et/strings.xml +++ b/app/src/main/res/values-et/strings.xml @@ -295,8 +295,6 @@ Trendid "Top 50 " Uus ja kuum - Taustapleier - Hüpikpleier Eemalda Üksikasjad Heli seaded diff --git a/app/src/main/res/values-eu/strings.xml b/app/src/main/res/values-eu/strings.xml index db02eaedc..3bd40df14 100644 --- a/app/src/main/res/values-eu/strings.xml +++ b/app/src/main/res/values-eu/strings.xml @@ -243,8 +243,6 @@ Joerak Lehen 50ak Berria eta arrakastatsua - Bigarren planoko erreproduzigailua - Laster-leiho erreproduzigailua Kendu Xehetasunak Audio ezarpenak diff --git a/app/src/main/res/values-fa/strings.xml b/app/src/main/res/values-fa/strings.xml index 8f40e68ff..0dbe5f978 100644 --- a/app/src/main/res/values-fa/strings.xml +++ b/app/src/main/res/values-fa/strings.xml @@ -258,7 +258,6 @@ محبوب ۵۰ ویدئوی برتر جدید و داغ - پخش‌کننده پس‌زمینه حذف جزئیات تنظیمات صدا @@ -371,7 +370,6 @@ قرار دادن در صف پخش به صورت تصویر در تصویر خطای عدم احیای پخش‌کننده رخ داد در حال احیا از خطای پخش‌کننده - پخش‌کننده تصویر در تصویر در صف پخش پس‌زمینه قرار بده در صف پخش تصویر در تصویر قرار بده شروع پخش در اینجا diff --git a/app/src/main/res/values-fi/strings.xml b/app/src/main/res/values-fi/strings.xml index d325f7ee4..c65af0bfd 100644 --- a/app/src/main/res/values-fi/strings.xml +++ b/app/src/main/res/values-fi/strings.xml @@ -230,8 +230,6 @@ Tätä suoratoistosisältöä ei voitu toistaa Palautuskelvoton soittimen virhe Palaudutaan soittimen virheestä - Taustasoitin - Ponnahdusikkunasoitin Poista Yksityiskohdat Ääniasetukset diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index 0d14f1390..1239c8abb 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -224,8 +224,6 @@ Impossible de lire ce flux Une erreur irrécupérable du lecteur est survenue Pas encore d’abonnements de chaîne - Lecteur en arrière-plan - Lecteur flottant Retirer Détails Paramètres audios diff --git a/app/src/main/res/values-gl/strings.xml b/app/src/main/res/values-gl/strings.xml index 8450d60c8..18178d4fd 100644 --- a/app/src/main/res/values-gl/strings.xml +++ b/app/src/main/res/values-gl/strings.xml @@ -341,8 +341,6 @@ Tendencias Top 50 Novo e popular - Reprodutor en segundo plano - Reprodutor «popup» Eliminar Detalles Opcións de audio diff --git a/app/src/main/res/values-he/strings.xml b/app/src/main/res/values-he/strings.xml index 0ac642b19..0091ba022 100644 --- a/app/src/main/res/values-he/strings.xml +++ b/app/src/main/res/values-he/strings.xml @@ -243,8 +243,6 @@ החמים 50 המובילים חדש וחם - נגן רקע - נגן צף הסרה פרטים אפשרויות שמע diff --git a/app/src/main/res/values-hi/strings.xml b/app/src/main/res/values-hi/strings.xml index ad1f3f5fc..1f5a033dc 100644 --- a/app/src/main/res/values-hi/strings.xml +++ b/app/src/main/res/values-hi/strings.xml @@ -232,8 +232,6 @@ kiosk टॉप 50 नया और गरम - पृष्ठभूमि प्लेयर - पॉपअप प्लेयर निकाले विवरण जोड़ने के लिए पकड़ें रहे diff --git a/app/src/main/res/values-hr/strings.xml b/app/src/main/res/values-hr/strings.xml index 4512e265b..f413fe5d9 100644 --- a/app/src/main/res/values-hr/strings.xml +++ b/app/src/main/res/values-hr/strings.xml @@ -234,8 +234,6 @@ U trendu Vrh 50 Novo i popularno - Pozadinski player - Skočni reproduktor Ukloni Detalji Postavke zvuka diff --git a/app/src/main/res/values-hu/strings.xml b/app/src/main/res/values-hu/strings.xml index 1dcfb9413..3848987bb 100644 --- a/app/src/main/res/values-hu/strings.xml +++ b/app/src/main/res/values-hu/strings.xml @@ -296,7 +296,6 @@ Felkapott Top 50 Új és friss - Felugró ablak lejátszó Eltávolítás Részletek Hang beállítások diff --git a/app/src/main/res/values-in/strings.xml b/app/src/main/res/values-in/strings.xml index cc976ecff..f103d2641 100644 --- a/app/src/main/res/values-in/strings.xml +++ b/app/src/main/res/values-in/strings.xml @@ -270,8 +270,6 @@ Trending Top 50 Baru & panas - Pemutar latar belakang - Pemutar popup Hapus Detail Pengaturan Audio diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml index 0b2b3b44b..d6582ef36 100644 --- a/app/src/main/res/values-it/strings.xml +++ b/app/src/main/res/values-it/strings.xml @@ -231,8 +231,6 @@ Impossibile riprodurre questo flusso Si è verificato un errore irreversibile Ripristino dell\'errore del lettore multimediale - Riproduzione in Sottofondo - Lettore Popup Rimuovi Dettagli Impostazioni Audio diff --git a/app/src/main/res/values-ja/strings.xml b/app/src/main/res/values-ja/strings.xml index f66930a0c..f9c3bb9e6 100644 --- a/app/src/main/res/values-ja/strings.xml +++ b/app/src/main/res/values-ja/strings.xml @@ -216,7 +216,6 @@ Kiosk 人気 トップ50 - ポップアップ再生 削除 詳細 音声の設定 @@ -241,7 +240,6 @@ 有効な ZIP ファイルではありません 警告: すべてのファイルをインポートできませんでした。 これにより、現在の設定が上書きされます。 - バックグラウンド再生 ここから再生を開始 バックグラウンドで連続再生を開始 ドロワーを開く diff --git a/app/src/main/res/values-ko/strings.xml b/app/src/main/res/values-ko/strings.xml index 78550ca5e..532dda837 100644 --- a/app/src/main/res/values-ko/strings.xml +++ b/app/src/main/res/values-ko/strings.xml @@ -230,8 +230,6 @@ 인기 급상승 탑 50 신작 & 뜨는 동영상 - 백그라운드 플레이어 - 팝업 플레이어 제거 상세 정보 오디오 설정 diff --git a/app/src/main/res/values-ku/strings.xml b/app/src/main/res/values-ku/strings.xml index 47c46cc49..0bafd4b32 100644 --- a/app/src/main/res/values-ku/strings.xml +++ b/app/src/main/res/values-ku/strings.xml @@ -252,7 +252,6 @@ دواین کارپێکراو زۆرترین کارپێکردن ناوەڕۆکی پەڕەی سەرەکی - کارپێکەری پەنجەرەی بچووک لادان وردەکارییەکان ڕێکخستنەکانی دەنگ @@ -434,7 +433,6 @@ پڕبینەرەکان باشترین 50 نوێ & چالاک - کارپێکەری پاشبنەما پەنجەت داگرە بۆ ڕیزنەبوون ڕیزنەبوون لە پاشبنەما ڕیزنەبوون لە پەنجەرەی بچووک diff --git a/app/src/main/res/values-lt/strings.xml b/app/src/main/res/values-lt/strings.xml index fb05da09c..d9806e326 100644 --- a/app/src/main/res/values-lt/strings.xml +++ b/app/src/main/res/values-lt/strings.xml @@ -267,8 +267,6 @@ Tendencijos Top 50 Nauja ir karšta - Foninis grotuvas - Langelio rėžimo grotuvas Pašalinti Detalės Garso nustatymai diff --git a/app/src/main/res/values-mk/strings.xml b/app/src/main/res/values-mk/strings.xml index 660148f01..71f02b892 100644 --- a/app/src/main/res/values-mk/strings.xml +++ b/app/src/main/res/values-mk/strings.xml @@ -290,8 +290,6 @@ Популарни Топ 50 Нови и жешки - Позадински плеер - Подпрозорче Одстрани Детали Звучни поставки diff --git a/app/src/main/res/values-ml/strings.xml b/app/src/main/res/values-ml/strings.xml index bc27edaa4..67cb36731 100644 --- a/app/src/main/res/values-ml/strings.xml +++ b/app/src/main/res/values-ml/strings.xml @@ -79,8 +79,6 @@ ഓഡിയോ ക്രമീകരണങ്ങൾ വിശദാംശങ്ങൾ നീക്കം ചെയ്യുക - പോപ്-അപ് പ്ലെയർ - ബാക്ക്ഗ്രൗണ്ട് പ്ലേയർ സമ്മേളനങ്ങൾ ഏറ്റവും ഇഷ്ടപ്പെട്ടത് സമീപകാലത്ത് ചേർത്തത് diff --git a/app/src/main/res/values-ms/strings.xml b/app/src/main/res/values-ms/strings.xml index 1944877f8..069c33450 100644 --- a/app/src/main/res/values-ms/strings.xml +++ b/app/src/main/res/values-ms/strings.xml @@ -328,8 +328,6 @@ Top 50 Baru & panas Persidangan - Pemain latar belakang - Pemain popup Hapuskan Butiran Tetapan Audio diff --git a/app/src/main/res/values-nb-rNO/strings.xml b/app/src/main/res/values-nb-rNO/strings.xml index 6adb1c9f8..52e9653f1 100644 --- a/app/src/main/res/values-nb-rNO/strings.xml +++ b/app/src/main/res/values-nb-rNO/strings.xml @@ -222,8 +222,6 @@ Kiosk Topp 50 Nytt og hett - Bakgrunnsavspiller - Oppsprettsavspiller Fjern Detaljer Lydinnstillinger diff --git a/app/src/main/res/values-ne/strings.xml b/app/src/main/res/values-ne/strings.xml index aac2a27ae..2a3cb7d9c 100644 --- a/app/src/main/res/values-ne/strings.xml +++ b/app/src/main/res/values-ne/strings.xml @@ -334,8 +334,6 @@ शीर्ष 50 नयाँ र तात्तातो सम्मेलनहरु - प्ले लाममा - पपअप प्लयेर हटाउ विवरण अडियो सेटिङहरू diff --git a/app/src/main/res/values-nl-rBE/strings.xml b/app/src/main/res/values-nl-rBE/strings.xml index a80cec9cc..66843542c 100644 --- a/app/src/main/res/values-nl-rBE/strings.xml +++ b/app/src/main/res/values-nl-rBE/strings.xml @@ -291,8 +291,6 @@ Populair Top 50 Nieuw en populair - Achtergrondspeler - Pop-upspeler Verwijderen Details Audio-instellingen diff --git a/app/src/main/res/values-nl/strings.xml b/app/src/main/res/values-nl/strings.xml index ca4539a60..24ad14eeb 100644 --- a/app/src/main/res/values-nl/strings.xml +++ b/app/src/main/res/values-nl/strings.xml @@ -231,8 +231,6 @@ Populair Top 50 Nieuw en populair - Achtergrondspeler - Pop-upspeler Verwijderen Details Audio-instellingen diff --git a/app/src/main/res/values-pa/strings.xml b/app/src/main/res/values-pa/strings.xml index 6a84b99a4..95608ba7a 100644 --- a/app/src/main/res/values-pa/strings.xml +++ b/app/src/main/res/values-pa/strings.xml @@ -299,8 +299,6 @@ ਰੁਝਾਨ ਵਿੱਚ ਟੌਪ 50 ਨਵਾਂ ਅਤੇ ਗਰਮਾ-ਗਰਮ - ਬੈਕਗ੍ਰਾਉਂਡ ਪਲੇਅਰ - ਪੌਪ-ਅਪ ਪਲੇਅਰ ਹਟਾਓ ਵੇਰਵੇ ਆਡੀਓ ਸੈਟਿੰਗਾਂ diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml index deef7afbd..22ef12114 100644 --- a/app/src/main/res/values-pl/strings.xml +++ b/app/src/main/res/values-pl/strings.xml @@ -240,8 +240,6 @@ Najpopularniejsze 50 najlepszych Nowe i gorące - Odtwarzanie w tle - Odtwarzacz w trybie okienkowym Usuń Szczegóły Ustawienia dźwięku diff --git a/app/src/main/res/values-pt-rBR/strings.xml b/app/src/main/res/values-pt-rBR/strings.xml index a0a62ca91..d15b5c54a 100644 --- a/app/src/main/res/values-pt-rBR/strings.xml +++ b/app/src/main/res/values-pt-rBR/strings.xml @@ -231,8 +231,6 @@ Este vídeo não pôde ser reproduzido Ocorreu um erro irrecuperável no player Recuperando do erro do player - Player em segundo plano - Player Popup Remover Detalhes Configurações de áudio diff --git a/app/src/main/res/values-pt/strings.xml b/app/src/main/res/values-pt/strings.xml index a52946dbd..e807d44c5 100644 --- a/app/src/main/res/values-pt/strings.xml +++ b/app/src/main/res/values-pt/strings.xml @@ -225,8 +225,6 @@ Tendências Top 50 Tendências - Reprodutor em segundo plano - Reprodutor \'popup\' Remover Detalhes Definições de áudio diff --git a/app/src/main/res/values-ro/strings.xml b/app/src/main/res/values-ro/strings.xml index 2d08addb9..7c7850bc1 100644 --- a/app/src/main/res/values-ro/strings.xml +++ b/app/src/main/res/values-ro/strings.xml @@ -286,8 +286,6 @@ pentru a deschide în mod pop-up Nici-un fişier ZIP valid Avertisment: Nu se pot importa fişierele. Acest lucru o să vă reseteze setup-ul curent. - Player în fundal - Player popup Şterge Detalii Setări Audio diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index 913475d8e..e8e14692d 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -242,8 +242,6 @@ Показать подсказку при нажатии \"В окне\" или \"В фоне\" на странице сведений о видео [Неизвестно] Восстановление после ошибки плеера - В фоне - В окне Зажмите, чтобы добавить в очередь В очередь в фоне В очередь в окне diff --git a/app/src/main/res/values-sk/strings.xml b/app/src/main/res/values-sk/strings.xml index 3352c81f8..b1ef016af 100644 --- a/app/src/main/res/values-sk/strings.xml +++ b/app/src/main/res/values-sk/strings.xml @@ -276,8 +276,6 @@ Trendy Top 50 Nové & horúce - Prehrávač na pozadí - Prehrávač v mini okne Odstrániť Podrobnosti Nastavenie zvuku diff --git a/app/src/main/res/values-sl/strings.xml b/app/src/main/res/values-sl/strings.xml index c1cc8d963..2586a5106 100644 --- a/app/src/main/res/values-sl/strings.xml +++ b/app/src/main/res/values-sl/strings.xml @@ -280,8 +280,6 @@ odpiranje v pojavnem načinu Izbor kanala Najboljših 50 Novo in vroče - Ozadnji predvajalnik - Pojavni predvajalnik Odstrani Podrobnosti Nastavitve zvoka diff --git a/app/src/main/res/values-sq/strings.xml b/app/src/main/res/values-sq/strings.xml index 278e27371..c796efadf 100644 --- a/app/src/main/res/values-sq/strings.xml +++ b/app/src/main/res/values-sq/strings.xml @@ -226,8 +226,6 @@ Aranzhimet Audio Detaje Hiq - Luajtësi popup - Luajtësi në sfond Konferencat Më të pëlqyerat Të shtuara së fundmi diff --git a/app/src/main/res/values-sr/strings.xml b/app/src/main/res/values-sr/strings.xml index 1cd4d2baa..87e631aee 100644 --- a/app/src/main/res/values-sr/strings.xml +++ b/app/src/main/res/values-sr/strings.xml @@ -233,8 +233,6 @@ У тренду Топ 50 Ново и вруће - Позадински плејер - Искачући плејер Уклони Детаљи Поставке звука diff --git a/app/src/main/res/values-sv/strings.xml b/app/src/main/res/values-sv/strings.xml index 23be5276b..cc613d2de 100644 --- a/app/src/main/res/values-sv/strings.xml +++ b/app/src/main/res/values-sv/strings.xml @@ -232,8 +232,6 @@ Trend Topp 50 Aktuellt - Bakgrundsspelare - Popup-spelare Ta bort Detaljer Ljudinställningar diff --git a/app/src/main/res/values-th/strings.xml b/app/src/main/res/values-th/strings.xml index 7910a29c7..952044208 100644 --- a/app/src/main/res/values-th/strings.xml +++ b/app/src/main/res/values-th/strings.xml @@ -311,8 +311,6 @@ 50 อันดับแรก ใหม่และมาแรง การประชุม - เครื่องเล่นพื้นหลัง - เครื่องเล่นป๊อปอัพ เอาออก รายละเอียด การตั้งค่าเสียง diff --git a/app/src/main/res/values-tr/strings.xml b/app/src/main/res/values-tr/strings.xml index bc4808f59..141331c68 100644 --- a/app/src/main/res/values-tr/strings.xml +++ b/app/src/main/res/values-tr/strings.xml @@ -228,8 +228,6 @@ Popüler En iyi 50 En yeniler ve popülerler - Arkaplan oynatıcı - Açılır pencere oynatıcı Kaldır Ayrıntılar Ses Ayarları diff --git a/app/src/main/res/values-uk/strings.xml b/app/src/main/res/values-uk/strings.xml index 20e9dbde1..efaf1270a 100644 --- a/app/src/main/res/values-uk/strings.xml +++ b/app/src/main/res/values-uk/strings.xml @@ -289,8 +289,6 @@ Це перезапише ваші поточні налаштування. Кіоски Набуває популярності - Програвач у тлі - Програвач у вікні Видалити Утримуйте, щоб додати в чергу Додати до фону diff --git a/app/src/main/res/values-ur/strings.xml b/app/src/main/res/values-ur/strings.xml index 5609902e3..10b1c5524 100644 --- a/app/src/main/res/values-ur/strings.xml +++ b/app/src/main/res/values-ur/strings.xml @@ -288,8 +288,6 @@ رجحان میں اوّل 50 نیا اور تازہ - پس منظر پلیئر - پوپ اپ پلیئر ہٹائیں تفصیلات آڈیو کی ترتیبات diff --git a/app/src/main/res/values-v28/styles.xml b/app/src/main/res/values-v28/styles.xml deleted file mode 100644 index 92c2d9214..000000000 --- a/app/src/main/res/values-v28/styles.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - diff --git a/app/src/main/res/values-vi/strings.xml b/app/src/main/res/values-vi/strings.xml index 1795dd607..d77d1564c 100644 --- a/app/src/main/res/values-vi/strings.xml +++ b/app/src/main/res/values-vi/strings.xml @@ -307,8 +307,6 @@ Trang chủ Xu hướng Mới & hot - Trình phát nền - Trình phát popup Tẩy xoá Chi tiết Cài đặt âm thanh diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index 8b87e9b10..76fb80795 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -273,8 +273,6 @@ 无法播放此串流 发生无法恢复播放器错误 恢复播放器错误 - 后台播放 - 悬浮窗播放器 移除 详情 音频设置 diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml index b71d64a1f..0a10f68a0 100644 --- a/app/src/main/res/values-zh-rTW/strings.xml +++ b/app/src/main/res/values-zh-rTW/strings.xml @@ -252,8 +252,6 @@ 動向 前 50 最新和熱門 - 背景播放 - 懸浮視窗播放 移除 詳細資訊 音訊設定 diff --git a/app/src/main/res/values/settings_keys.xml b/app/src/main/res/values/settings_keys.xml index cdb8293af..bce920722 100644 --- a/app/src/main/res/values/settings_keys.xml +++ b/app/src/main/res/values/settings_keys.xml @@ -144,8 +144,6 @@ @string/audio_webm_key - last_orientation_landscape_key - last_resize_mode diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 2da2a9b1c..be856ef01 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -429,8 +429,6 @@ %1$s/%2$s Play queue - Background player - Popup player Remove Details Audio Settings diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index 9018a2d2a..9a81d01e1 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -330,5 +330,4 @@ @null -