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