diff --git a/app/src/main/java/org/schabi/newpipe/MainActivity.java b/app/src/main/java/org/schabi/newpipe/MainActivity.java index 157511c9f..19ae63220 100644 --- a/app/src/main/java/org/schabi/newpipe/MainActivity.java +++ b/app/src/main/java/org/schabi/newpipe/MainActivity.java @@ -849,7 +849,7 @@ public class MainActivity extends AppCompatActivity { return; } - if (PlayerHolder.Companion.getInstance().isPlayerOpen()) { + if (PlayerHolder.INSTANCE.isPlayerOpen()) { // if the player is already open, no need for a broadcast receiver openMiniPlayerIfMissing(); } else { @@ -859,7 +859,7 @@ public class MainActivity extends AppCompatActivity { public void onReceive(final Context context, final Intent intent) { if (Objects.equals(intent.getAction(), VideoDetailFragment.ACTION_PLAYER_STARTED) - && PlayerHolder.Companion.getInstance().isPlayerOpen()) { + && PlayerHolder.INSTANCE.isPlayerOpen()) { openMiniPlayerIfMissing(); // At this point the player is added 100%, we can unregister. Other actions // are useless since the fragment will not be removed after that. @@ -874,7 +874,7 @@ public class MainActivity extends AppCompatActivity { // If the PlayerHolder is not bound yet, but the service is running, try to bind to it. // Once the connection is established, the ACTION_PLAYER_STARTED will be sent. - PlayerHolder.Companion.getInstance().tryBindIfNeeded(this); + PlayerHolder.INSTANCE.tryBindIfNeeded(this); } } diff --git a/app/src/main/java/org/schabi/newpipe/RouterActivity.java b/app/src/main/java/org/schabi/newpipe/RouterActivity.java index 27ae603c7..262006243 100644 --- a/app/src/main/java/org/schabi/newpipe/RouterActivity.java +++ b/app/src/main/java/org/schabi/newpipe/RouterActivity.java @@ -701,7 +701,7 @@ public class RouterActivity extends AppCompatActivity { } // ...the player is not running or in normal Video-mode/type - final PlayerType playerType = PlayerHolder.Companion.getInstance().getType(); + final PlayerType playerType = PlayerHolder.INSTANCE.getType(); return playerType == null || playerType == PlayerType.MAIN; } diff --git a/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.kt b/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.kt index d94f17e2f..888843ec6 100644 --- a/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.kt +++ b/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.kt @@ -100,7 +100,7 @@ import org.schabi.newpipe.player.PlayerType import org.schabi.newpipe.player.event.OnKeyDownListener import org.schabi.newpipe.player.event.PlayerServiceExtendedEventListener import org.schabi.newpipe.player.helper.PlayerHelper -import org.schabi.newpipe.player.helper.PlayerHolder.Companion.getInstance +import org.schabi.newpipe.player.helper.PlayerHolder import org.schabi.newpipe.player.playqueue.PlayQueue import org.schabi.newpipe.player.playqueue.SinglePlayQueue import org.schabi.newpipe.player.playqueue.events.PlayQueueEvent @@ -212,7 +212,6 @@ class VideoDetailFragment : private var settingsContentObserver: ContentObserver? = null private var playerService: PlayerService? = null private var player: Player? = null - private val playerHolder = getInstance() /*////////////////////////////////////////////////////////////////////////// // Service management @@ -367,9 +366,9 @@ class VideoDetailFragment : // Stop the service when user leaves the app with double back press // if video player is selected. Otherwise unbind if (activity.isFinishing() && this.isPlayerAvailable && player!!.videoPlayerSelected()) { - playerHolder.stopService() + PlayerHolder.stopService() } else { - playerHolder.setListener(null) + PlayerHolder.setListener(null) } PreferenceManager.getDefaultSharedPreferences(activity) @@ -768,10 +767,10 @@ class VideoDetailFragment : ) setupBottomPlayer() - if (!playerHolder.isBound) { + if (!PlayerHolder.isBound) { setHeightThumbnail() } else { - playerHolder.startService(false, this) + PlayerHolder.startService(false, this) } } @@ -1175,7 +1174,7 @@ class VideoDetailFragment : // See UI changes while remote playQueue changes if (!this.isPlayerAvailable) { - playerHolder.startService(false, this) + PlayerHolder.startService(false, this) } else { // FIXME Workaround #7427 player!!.setRecovery() @@ -1245,7 +1244,7 @@ class VideoDetailFragment : private fun openNormalBackgroundPlayer(append: Boolean) { // See UI changes while remote playQueue changes if (!this.isPlayerAvailable) { - playerHolder.startService(false, this) + PlayerHolder.startService(false, this) } val queue = setupPlayQueueForIntent(append) @@ -1263,7 +1262,7 @@ class VideoDetailFragment : private fun openMainPlayer() { if (noPlayerServiceAvailable()) { - playerHolder.startService(autoPlayEnabled, this) + PlayerHolder.startService(autoPlayEnabled, this) return } if (currentInfo == null) { @@ -1298,7 +1297,7 @@ class VideoDetailFragment : playerService!!.stopForImmediateReusing() root.ifPresent(Consumer { view: View -> view.setVisibility(View.GONE) }) } else { - playerHolder.stopService() + PlayerHolder.stopService() } } @@ -1551,8 +1550,8 @@ class VideoDetailFragment : bottomSheetBehavior!!.setState(BottomSheetBehavior.STATE_COLLAPSED) } // Rebound to the service if it was closed via notification or mini player - if (!playerHolder.isBound) { - playerHolder.startService( + if (!PlayerHolder.isBound) { + PlayerHolder.startService( false, this@VideoDetailFragment ) } @@ -2472,7 +2471,7 @@ class VideoDetailFragment : if (currentWorker != null) { currentWorker!!.dispose() } - playerHolder.stopService() + PlayerHolder.stopService() setInitialData(0, null, "", null) currentInfo = null updateOverlayData(null, null, mutableListOf()) diff --git a/app/src/main/java/org/schabi/newpipe/info_list/dialog/InfoItemDialog.java b/app/src/main/java/org/schabi/newpipe/info_list/dialog/InfoItemDialog.java index 55d49b145..cbaae2834 100644 --- a/app/src/main/java/org/schabi/newpipe/info_list/dialog/InfoItemDialog.java +++ b/app/src/main/java/org/schabi/newpipe/info_list/dialog/InfoItemDialog.java @@ -252,7 +252,7 @@ public final class InfoItemDialog { * @return the current {@link Builder} instance */ public Builder addEnqueueEntriesIfNeeded() { - final PlayerHolder holder = PlayerHolder.Companion.getInstance(); + final PlayerHolder holder = PlayerHolder.INSTANCE; if (holder.isPlayQueueReady()) { addEntry(StreamDialogDefaultEntry.ENQUEUE); diff --git a/app/src/main/java/org/schabi/newpipe/player/helper/PlayerHolder.kt b/app/src/main/java/org/schabi/newpipe/player/helper/PlayerHolder.kt index b3196aeb5..06b4f8bba 100644 --- a/app/src/main/java/org/schabi/newpipe/player/helper/PlayerHolder.kt +++ b/app/src/main/java/org/schabi/newpipe/player/helper/PlayerHolder.kt @@ -22,12 +22,19 @@ import org.schabi.newpipe.player.playqueue.PlayQueue import org.schabi.newpipe.util.NavigationHelper import java.util.function.Consumer -class PlayerHolder private constructor() { +private val DEBUG = MainActivity.DEBUG +private val TAG: String = PlayerHolder::class.java.getSimpleName() + +/** + * Singleton that manages a `PlayerService` + * and can be used to control the player instance through the service. + */ +object PlayerHolder { private var listener: PlayerServiceExtendedEventListener? = null - private val serviceConnection = PlayerServiceConnection() var isBound: Boolean = false private set + private var playerService: PlayerService? = null private val player: Player? @@ -110,7 +117,7 @@ class PlayerHolder private constructor() { val intent = Intent(context, PlayerService::class.java) intent.putExtra(PlayerService.SHOULD_START_FOREGROUND_EXTRA, true) ContextCompat.startForegroundService(context, intent) - serviceConnection.doPlayAfterConnect(playAfterConnect) + PlayerServiceConnection.doPlayAfterConnect(playAfterConnect) bind(context) } @@ -126,7 +133,7 @@ class PlayerHolder private constructor() { context.stopService(Intent(context, PlayerService::class.java)) } - internal inner class PlayerServiceConnection : ServiceConnection { + internal object PlayerServiceConnection : ServiceConnection { internal var playAfterConnect = false /** @@ -185,7 +192,7 @@ class PlayerHolder private constructor() { // BIND_AUTO_CREATE starts the service if it's not already running this.isBound = bind(context, Context.BIND_AUTO_CREATE) if (!this.isBound) { - context.unbindService(serviceConnection) + context.unbindService(PlayerServiceConnection) } } @@ -201,7 +208,7 @@ class PlayerHolder private constructor() { private fun bind(context: Context, flags: Int): Boolean { val serviceIntent = Intent(context, PlayerService::class.java) serviceIntent.setAction(PlayerService.BIND_PLAYER_HOLDER_ACTION) - return context.bindService(serviceIntent, serviceConnection, flags) + return context.bindService(serviceIntent, PlayerServiceConnection, flags) } private fun unbind(context: Context) { @@ -210,7 +217,7 @@ class PlayerHolder private constructor() { } if (this.isBound) { - context.unbindService(serviceConnection) + context.unbindService(PlayerServiceConnection) this.isBound = false stopPlayerListener() playerService = null @@ -223,18 +230,18 @@ class PlayerHolder private constructor() { // setting the player listener will take care of calling relevant callbacks if the // player in the service is (not) already active, also see playerStateListener below playerService?.setPlayerListener(playerStateListener) - this.player?.setFragmentListener(internalListener) + this.player?.setFragmentListener(HolderPlayerServiceEventListener) } private fun stopPlayerListener() { playerService?.setPlayerListener(null) - this.player?.removeFragmentListener(internalListener) + this.player?.removeFragmentListener(HolderPlayerServiceEventListener) } /** * This listener will be held by the players created by [PlayerService]. */ - private val internalListener: PlayerServiceEventListener = object : PlayerServiceEventListener { + private object HolderPlayerServiceEventListener : PlayerServiceEventListener { override fun onViewCreated() { listener?.onViewCreated() } @@ -307,26 +314,11 @@ class PlayerHolder private constructor() { // before setting its player to null l.onPlayerDisconnected() } else { - l.onPlayerConnected(player, serviceConnection.playAfterConnect) + l.onPlayerConnected(player, PlayerServiceConnection.playAfterConnect) // reset the value of playAfterConnect: if it was true before, it is now "consumed" - serviceConnection.playAfterConnect = false; - player.setFragmentListener(internalListener) + PlayerServiceConnection.playAfterConnect = false + player.setFragmentListener(HolderPlayerServiceEventListener) } } } - - companion object { - private var instance: PlayerHolder? = null - - @Synchronized - fun getInstance(): PlayerHolder { - if (instance == null) { - instance = PlayerHolder() - } - return instance!! - } - - private val DEBUG = MainActivity.DEBUG - private val TAG: String = PlayerHolder::class.java.getSimpleName() - } } diff --git a/app/src/main/java/org/schabi/newpipe/ui/components/items/stream/StreamMenu.kt b/app/src/main/java/org/schabi/newpipe/ui/components/items/stream/StreamMenu.kt index 26d385518..7619515e7 100644 --- a/app/src/main/java/org/schabi/newpipe/ui/components/items/stream/StreamMenu.kt +++ b/app/src/main/java/org/schabi/newpipe/ui/components/items/stream/StreamMenu.kt @@ -28,10 +28,9 @@ fun StreamMenu( ) { val context = LocalContext.current val streamViewModel = viewModel() - val playerHolder = PlayerHolder.Companion.getInstance() DropdownMenu(expanded = expanded, onDismissRequest = onDismissRequest) { - if (playerHolder.isPlayQueueReady) { + if (PlayerHolder.isPlayQueueReady) { DropdownMenuItem( text = { Text(text = stringResource(R.string.enqueue_stream)) }, onClick = { @@ -42,7 +41,7 @@ fun StreamMenu( } ) - if (playerHolder.queuePosition < playerHolder.queueSize - 1) { + if (PlayerHolder.queuePosition < PlayerHolder.queueSize - 1) { DropdownMenuItem( text = { Text(text = stringResource(R.string.enqueue_next_stream)) }, onClick = { diff --git a/app/src/main/java/org/schabi/newpipe/util/NavigationHelper.java b/app/src/main/java/org/schabi/newpipe/util/NavigationHelper.java index 9d8d3c3b2..c71836609 100644 --- a/app/src/main/java/org/schabi/newpipe/util/NavigationHelper.java +++ b/app/src/main/java/org/schabi/newpipe/util/NavigationHelper.java @@ -200,7 +200,7 @@ public final class NavigationHelper { } public static void enqueueOnPlayer(final Context context, final PlayQueue queue) { - PlayerType playerType = PlayerHolder.Companion.getInstance().getType(); + PlayerType playerType = PlayerHolder.INSTANCE.getType(); if (playerType == null) { Log.e(TAG, "Enqueueing but no player is open; defaulting to background player"); playerType = PlayerType.AUDIO; @@ -211,7 +211,7 @@ public final class NavigationHelper { /* ENQUEUE NEXT */ public static void enqueueNextOnPlayer(final Context context, final PlayQueue queue) { - PlayerType playerType = PlayerHolder.Companion.getInstance().getType(); + PlayerType playerType = PlayerHolder.INSTANCE.getType(); if (playerType == null) { Log.e(TAG, "Enqueueing next but no player is open; defaulting to background player"); playerType = PlayerType.AUDIO; @@ -421,13 +421,13 @@ public final class NavigationHelper { final boolean switchingPlayers) { final boolean autoPlay; - @Nullable final PlayerType playerType = PlayerHolder.Companion.getInstance().getType(); + @Nullable final PlayerType playerType = PlayerHolder.INSTANCE.getType(); if (playerType == null) { // no player open autoPlay = PlayerHelper.isAutoplayAllowedByUser(context); } else if (switchingPlayers) { // switching player to main player - autoPlay = PlayerHolder.Companion.getInstance().isPlaying(); // keep play/pause state + autoPlay = PlayerHolder.INSTANCE.isPlaying(); // keep play/pause state } else if (playerType == PlayerType.MAIN) { // opening new stream while already playing in main player autoPlay = PlayerHelper.isAutoplayAllowedByUser(context);