2424import org .schabi .newpipe .player .playqueue .PlayQueue ;
2525import org .schabi .newpipe .util .NavigationHelper ;
2626
27+ import java .util .Optional ;
28+ import java .util .function .Consumer ;
29+
2730public final class PlayerHolder {
2831
2932 private PlayerHolder () {
@@ -45,7 +48,16 @@ public static synchronized PlayerHolder getInstance() {
4548 private final PlayerServiceConnection serviceConnection = new PlayerServiceConnection ();
4649 private boolean bound ;
4750 @ Nullable private PlayerService playerService ;
48- @ Nullable private Player player ;
51+
52+ private Optional <Player > getPlayer () {
53+ return Optional .ofNullable (playerService )
54+ .flatMap (s -> Optional .ofNullable (s .getPlayer ()));
55+ }
56+
57+ private Optional <PlayQueue > getPlayQueue () {
58+ // player play queue might be null e.g. while player is starting
59+ return getPlayer ().flatMap (p -> Optional .ofNullable (p .getPlayQueue ()));
60+ }
4961
5062 /**
5163 * Returns the current {@link PlayerType} of the {@link PlayerService} service,
@@ -55,21 +67,15 @@ public static synchronized PlayerHolder getInstance() {
5567 */
5668 @ Nullable
5769 public PlayerType getType () {
58- if (player == null ) {
59- return null ;
60- }
61- return player .getPlayerType ();
70+ return getPlayer ().map (Player ::getPlayerType ).orElse (null );
6271 }
6372
6473 public boolean isPlaying () {
65- if (player == null ) {
66- return false ;
67- }
68- return player .isPlaying ();
74+ return getPlayer ().map (Player ::isPlaying ).orElse (false );
6975 }
7076
7177 public boolean isPlayerOpen () {
72- return player != null ;
78+ return getPlayer (). isPresent () ;
7379 }
7480
7581 /**
@@ -78,26 +84,19 @@ public boolean isPlayerOpen() {
7884 * @return true only if the player is open and its play queue is ready (i.e. it is not null)
7985 */
8086 public boolean isPlayQueueReady () {
81- return player != null && player . getPlayQueue () != null ;
87+ return getPlayQueue (). isPresent () ;
8288 }
8389
8490 public boolean isBound () {
8591 return bound ;
8692 }
8793
8894 public int getQueueSize () {
89- if (player == null || player .getPlayQueue () == null ) {
90- // player play queue might be null e.g. while player is starting
91- return 0 ;
92- }
93- return player .getPlayQueue ().size ();
95+ return getPlayQueue ().map (PlayQueue ::size ).orElse (0 );
9496 }
9597
9698 public int getQueuePosition () {
97- if (player == null || player .getPlayQueue () == null ) {
98- return 0 ;
99- }
100- return player .getPlayQueue ().getIndex ();
99+ return getPlayQueue ().map (PlayQueue ::getIndex ).orElse (0 );
101100 }
102101
103102 public void setListener (@ Nullable final PlayerServiceExtendedEventListener newListener ) {
@@ -108,9 +107,10 @@ public void setListener(@Nullable final PlayerServiceExtendedEventListener newLi
108107 }
109108
110109 // Force reload data from service
111- if (player != null ) {
112- listener .onServiceConnected (player , playerService , false );
110+ if (playerService != null ) {
111+ listener .onServiceConnected (playerService );
113112 startPlayerListener ();
113+ // ^ will call listener.onPlayerConnected() down the line if there is an active player
114114 }
115115 }
116116
@@ -181,11 +181,12 @@ public void onServiceConnected(final ComponentName compName, final IBinder servi
181181 final PlayerService .LocalBinder localBinder = (PlayerService .LocalBinder ) service ;
182182
183183 playerService = localBinder .getService ();
184- player = localBinder .getPlayer ();
185184 if (listener != null ) {
186- listener .onServiceConnected (player , playerService , playAfterConnect );
185+ listener .onServiceConnected (playerService );
186+ getPlayer ().ifPresent (p -> listener .onPlayerConnected (p , playAfterConnect ));
187187 }
188188 startPlayerListener ();
189+ // ^ will call listener.onPlayerConnected() down the line if there is an active player
189190
190191 // notify the main activity that binding the service has completed, so that it can
191192 // open the bottom mini-player
@@ -229,25 +230,32 @@ private void unbind(final Context context) {
229230 bound = false ;
230231 stopPlayerListener ();
231232 playerService = null ;
232- player = null ;
233233 if (listener != null ) {
234+ listener .onPlayerDisconnected ();
234235 listener .onServiceDisconnected ();
235236 }
236237 }
237238 }
238239
239240 private void startPlayerListener () {
240- if (player != null ) {
241- player .setFragmentListener (internalListener );
241+ if (playerService != null ) {
242+ // setting the player listener will take care of calling relevant callbacks if the
243+ // player in the service is (not) already active, also see playerStateListener below
244+ playerService .setPlayerListener (playerStateListener );
242245 }
246+ getPlayer ().ifPresent (p -> p .setFragmentListener (internalListener ));
243247 }
244248
245249 private void stopPlayerListener () {
246- if (player != null ) {
247- player . removeFragmentListener ( internalListener );
250+ if (playerService != null ) {
251+ playerService . setPlayerListener ( null );
248252 }
253+ getPlayer ().ifPresent (p -> p .removeFragmentListener (internalListener ));
249254 }
250255
256+ /**
257+ * This listener will be held by the players created by {@link PlayerService}.
258+ */
251259 private final PlayerServiceEventListener internalListener =
252260 new PlayerServiceEventListener () {
253261 @ Override
@@ -334,4 +342,23 @@ public void onServiceStopped() {
334342 unbind (getCommonContext ());
335343 }
336344 };
345+
346+ /**
347+ * This listener will be held by bound {@link PlayerService}s to notify of the player starting
348+ * or stopping. This is necessary since the service outlives the player e.g. to answer Android
349+ * Auto media browser queries.
350+ */
351+ private final Consumer <Player > playerStateListener = (@ Nullable final Player player ) -> {
352+ if (listener != null ) {
353+ if (player == null ) {
354+ // player.fragmentListener=null is already done by player.stopActivityBinding(),
355+ // which is called by player.destroy(), which is in turn called by PlayerService
356+ // before setting its player to null
357+ listener .onPlayerDisconnected ();
358+ } else {
359+ listener .onPlayerConnected (player , serviceConnection .playAfterConnect );
360+ player .setFragmentListener (internalListener );
361+ }
362+ }
363+ };
337364}
0 commit comments