diff --git a/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java index 63077e92d..2dd24fabf 100644 --- a/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java +++ b/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java @@ -234,10 +234,9 @@ public final class VideoDetailFragment // Service management //////////////////////////////////////////////////////////////////////////*/ @Override - public void onServiceConnected(final Player connectedPlayer, - final PlayerService connectedPlayerService, + public void onServiceConnected(final PlayerService connectedPlayerService, final boolean playAfterConnect) { - player = connectedPlayer; + player = connectedPlayerService.getPlayer(); playerService = connectedPlayerService; // It will do nothing if the player is not in fullscreen mode diff --git a/app/src/main/java/org/schabi/newpipe/player/PlayQueueActivity.java b/app/src/main/java/org/schabi/newpipe/player/PlayQueueActivity.java index 195baecbd..e936b9f45 100644 --- a/app/src/main/java/org/schabi/newpipe/player/PlayQueueActivity.java +++ b/app/src/main/java/org/schabi/newpipe/player/PlayQueueActivity.java @@ -217,11 +217,16 @@ public final class PlayQueueActivity extends AppCompatActivity } @Override - public void onServiceConnected(final ComponentName name, final IBinder service) { + public void onServiceConnected(final ComponentName name, final IBinder binder) { Log.d(TAG, "Player service is connected"); - if (service instanceof PlayerService.LocalBinder) { - player = ((PlayerService.LocalBinder) service).getPlayer(); + if (binder instanceof PlayerService.LocalBinder localBinder) { + final @Nullable PlayerService s = localBinder.getService(); + if (s == null) { + player = null; + } else { + player = s.getPlayer(); + } } if (player == null || player.getPlayQueue() == null || player.exoPlayerIsNull()) { diff --git a/app/src/main/java/org/schabi/newpipe/player/PlayerService.java b/app/src/main/java/org/schabi/newpipe/player/PlayerService.java index e7abf4320..924a0e251 100644 --- a/app/src/main/java/org/schabi/newpipe/player/PlayerService.java +++ b/app/src/main/java/org/schabi/newpipe/player/PlayerService.java @@ -28,6 +28,8 @@ import android.os.Binder; import android.os.IBinder; import android.util.Log; +import androidx.annotation.Nullable; + import org.schabi.newpipe.player.mediasession.MediaSessionPlayerUi; import org.schabi.newpipe.player.notification.NotificationPlayerUi; import org.schabi.newpipe.util.ThemeHelper; @@ -36,7 +38,9 @@ import java.lang.ref.WeakReference; /** - * One service for all players. + * One background service for our player. Even though the player has multiple UIs + * (e.g. the audio-only UI, the main UI, the pulldown-menu UI), + * this allows us to keep playing even when switching between the different UIs. */ public final class PlayerService extends Service { private static final String TAG = PlayerService.class.getSimpleName(); @@ -46,6 +50,9 @@ public final class PlayerService extends Service { private final IBinder mBinder = new PlayerService.LocalBinder(this); + public Player getPlayer() { + return player; + } /*////////////////////////////////////////////////////////////////////////// // Service's LifeCycle @@ -167,6 +174,9 @@ public final class PlayerService extends Service { return mBinder; } + /** Allows us this {@link org.schabi.newpipe.player.PlayerService} over the Service boundary + * back to our {@link org.schabi.newpipe.player.helper.PlayerHolder}. + */ public static class LocalBinder extends Binder { private final WeakReference playerService; @@ -174,12 +184,11 @@ public final class PlayerService extends Service { this.playerService = new WeakReference<>(playerService); } - public PlayerService getService() { + /** Get the PlayerService object itself. + * @return this + * */ + public @Nullable PlayerService getService() { return playerService.get(); } - - public Player getPlayer() { - return playerService.get().player; - } } } diff --git a/app/src/main/java/org/schabi/newpipe/player/event/PlayerServiceExtendedEventListener.java b/app/src/main/java/org/schabi/newpipe/player/event/PlayerServiceExtendedEventListener.java index 8effe2f0e..9e8c7cf76 100644 --- a/app/src/main/java/org/schabi/newpipe/player/event/PlayerServiceExtendedEventListener.java +++ b/app/src/main/java/org/schabi/newpipe/player/event/PlayerServiceExtendedEventListener.java @@ -1,11 +1,9 @@ package org.schabi.newpipe.player.event; import org.schabi.newpipe.player.PlayerService; -import org.schabi.newpipe.player.Player; public interface PlayerServiceExtendedEventListener extends PlayerServiceEventListener { - void onServiceConnected(Player player, - PlayerService playerService, + void onServiceConnected(PlayerService playerService, boolean playAfterConnect); void onServiceDisconnected(); } 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 24939c1d8..70a1da6a7 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 @@ -43,6 +43,7 @@ public final class PlayerHolder { private final PlayerServiceConnection serviceConnection = new PlayerServiceConnection(); private boolean bound; + @Nullable private PlayerService playerService; @Nullable private Player player; @@ -108,13 +109,16 @@ public final class PlayerHolder { // Force reload data from service if (player != null) { - listener.onServiceConnected(player, playerService, false); - startPlayerListener(); + listener.onServiceConnected(playerService, false); + player.setFragmentListener(internalListener); } } - // helper to handle context in common place as using the same - // context to bind/unbind a service is crucial + /** Helper to handle context in common place as using the same + * context to bind/unbind a service is crucial. + * + * @return the common context + * */ private Context getCommonContext() { return App.getInstance(); } @@ -131,7 +135,7 @@ public final class PlayerHolder { // bound twice. Prevent it with unbinding first unbind(context); ContextCompat.startForegroundService(context, new Intent(context, PlayerService.class)); - serviceConnection.doPlayAfterConnect(playAfterConnect); + serviceConnection.playAfterConnect = playAfterConnect; bind(context); } @@ -145,10 +149,6 @@ public final class PlayerHolder { private boolean playAfterConnect = false; - public void doPlayAfterConnect(final boolean playAfterConnection) { - this.playAfterConnect = playAfterConnection; - } - @Override public void onServiceDisconnected(final ComponentName compName) { if (DEBUG) { @@ -167,14 +167,21 @@ public final class PlayerHolder { final PlayerService.LocalBinder localBinder = (PlayerService.LocalBinder) service; playerService = localBinder.getService(); - player = localBinder.getPlayer(); + player = playerService != null ? playerService.getPlayer() : null; + if (listener != null) { - listener.onServiceConnected(player, playerService, playAfterConnect); + listener.onServiceConnected(playerService, playAfterConnect); + } + if (player != null) { + player.setFragmentListener(internalListener); } - startPlayerListener(); } } + /** Connect to (and if needed start) the {@link PlayerService} + * and bind {@link PlayerServiceConnection} to it. + * @param context common holder context + * */ private void bind(final Context context) { if (DEBUG) { Log.d(TAG, "bind() called"); @@ -196,7 +203,9 @@ public final class PlayerHolder { if (bound) { context.unbindService(serviceConnection); bound = false; - stopPlayerListener(); + if (player != null) { + player.removeFragmentListener(internalListener); + } playerService = null; player = null; if (listener != null) { @@ -205,18 +214,6 @@ public final class PlayerHolder { } } - private void startPlayerListener() { - if (player != null) { - player.setFragmentListener(internalListener); - } - } - - private void stopPlayerListener() { - if (player != null) { - player.removeFragmentListener(internalListener); - } - } - private final PlayerServiceEventListener internalListener = new PlayerServiceEventListener() { @Override