mirror of
https://github.com/TeamNewPipe/NewPipe
synced 2025-08-29 13:47:55 +00:00
PlayerHolder: use object class to implement singleton pattern
This commit is contained in:
parent
cc3ecd4169
commit
38ed1da79e
@ -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);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user