From 6558794d265ba8f20958c1e3e1644bcfce22773f Mon Sep 17 00:00:00 2001 From: Stypox Date: Tue, 18 Feb 2025 17:36:43 +0100 Subject: [PATCH] Try to bind to PlayerService when MainActivity starts Fixes mini-player not appearing on app start if the player service is already playing something. The PlayerService (and the player) may be started from an external intent that does not involve the MainActivity (e.g. RouterActivity or Android Auto's media browser interface). This PR tries to bind to the PlayerService as soon as the MainActivity starts, but only does so in a passive way, i.e. if the service is not already running it is not started. Once the connection between PlayerHolder and PlayerService is setup, the ACTION_PLAYER_STARTED broadcast is sent to MainActivity so that it can setup the bottom mini-player. Another important thing this commit does is to check whether the player is open before actually adding the mini-player view, since the PlayerService could be bound even without a running player (e.g. Android Auto's media browser is being used). This is a consequence of commit "Drop some assumptions on how PlayerService is started and reused". --- .../java/org/schabi/newpipe/MainActivity.java | 7 ++++- .../newpipe/player/helper/PlayerHolder.java | 30 +++++++++++++++---- 2 files changed, 31 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/org/schabi/newpipe/MainActivity.java b/app/src/main/java/org/schabi/newpipe/MainActivity.java index 354e06587..bbfc98f61 100644 --- a/app/src/main/java/org/schabi/newpipe/MainActivity.java +++ b/app/src/main/java/org/schabi/newpipe/MainActivity.java @@ -848,7 +848,8 @@ public class MainActivity extends AppCompatActivity { @Override public void onReceive(final Context context, final Intent intent) { if (Objects.equals(intent.getAction(), - VideoDetailFragment.ACTION_PLAYER_STARTED)) { + VideoDetailFragment.ACTION_PLAYER_STARTED) + && PlayerHolder.getInstance().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. @@ -860,6 +861,10 @@ public class MainActivity extends AppCompatActivity { final IntentFilter intentFilter = new IntentFilter(); intentFilter.addAction(VideoDetailFragment.ACTION_PLAYER_STARTED); registerReceiver(broadcastReceiver, intentFilter); + + // 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.getInstance().tryBindIfNeeded(this); } } diff --git a/app/src/main/java/org/schabi/newpipe/player/helper/PlayerHolder.java b/app/src/main/java/org/schabi/newpipe/player/helper/PlayerHolder.java index 7263afccd..b9afaa7c7 100644 --- a/app/src/main/java/org/schabi/newpipe/player/helper/PlayerHolder.java +++ b/app/src/main/java/org/schabi/newpipe/player/helper/PlayerHolder.java @@ -22,6 +22,7 @@ import org.schabi.newpipe.player.PlayerType; import org.schabi.newpipe.player.event.PlayerServiceEventListener; import org.schabi.newpipe.player.event.PlayerServiceExtendedEventListener; import org.schabi.newpipe.player.playqueue.PlayQueue; +import org.schabi.newpipe.util.NavigationHelper; public final class PlayerHolder { @@ -121,6 +122,9 @@ public final class PlayerHolder { public void startService(final boolean playAfterConnect, final PlayerServiceExtendedEventListener newListener) { + if (DEBUG) { + Log.d(TAG, "startService() called with playAfterConnect=" + playAfterConnect); + } final Context context = getCommonContext(); setListener(newListener); if (bound) { @@ -182,6 +186,10 @@ public final class PlayerHolder { listener.onServiceConnected(player, playerService, playAfterConnect); } startPlayerListener(); + + // notify the main activity that binding the service has completed, so that it can + // open the bottom mini-player + NavigationHelper.sendPlayerStartedEvent(localBinder.getService()); } } @@ -189,16 +197,28 @@ public final class PlayerHolder { if (DEBUG) { Log.d(TAG, "bind() called"); } - - final Intent serviceIntent = new Intent(context, PlayerService.class); - serviceIntent.setAction(PlayerService.BIND_PLAYER_HOLDER_ACTION); - bound = context.bindService(serviceIntent, serviceConnection, - Context.BIND_AUTO_CREATE); + // BIND_AUTO_CREATE starts the service if it's not already running + bound = bind(context, Context.BIND_AUTO_CREATE); if (!bound) { context.unbindService(serviceConnection); } } + public void tryBindIfNeeded(final Context context) { + if (!bound) { + // flags=0 means the service will not be started if it does not already exist. In this + // case the return value is not useful, as a value of "true" does not really indicate + // that the service is going to be bound. + bind(context, 0); + } + } + + private boolean bind(final Context context, final int flags) { + final Intent serviceIntent = new Intent(context, PlayerService.class); + serviceIntent.setAction(PlayerService.BIND_PLAYER_HOLDER_ACTION); + return context.bindService(serviceIntent, serviceConnection, flags); + } + private void unbind(final Context context) { if (DEBUG) { Log.d(TAG, "unbind() called");