Skip to content

Commit dd29b73

Browse files
committed
Properly stop PlayerService
This commit is a consequence of the commit "Drop some assumptions on how PlayerService is started and reused". Since the assumptions on how the PlayerService is started and reused have changed, we also need to adapt the way it is stopped. This means allowing the service to remain alive even after the player is destroyed, in case the system is still accessing PlayerService e.g. through the media browser interface. The foreground service needs to be stopped and the notification removed in any case.
1 parent b63961f commit dd29b73

File tree

4 files changed

+40
-7
lines changed

4 files changed

+40
-7
lines changed

app/src/main/java/org/schabi/newpipe/player/Player.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -657,7 +657,7 @@ public void onPlaybackShutdown() {
657657
Log.d(TAG, "onPlaybackShutdown() called");
658658
}
659659
// destroys the service, which in turn will destroy the player
660-
service.stopService();
660+
service.destroyPlayerAndStopService();
661661
}
662662

663663
public void smoothStopForImmediateReusing() {
@@ -729,7 +729,7 @@ private void onBroadcastReceived(final Intent intent) {
729729
pause();
730730
break;
731731
case ACTION_CLOSE:
732-
service.stopService();
732+
service.destroyPlayerAndStopService();
733733
break;
734734
case ACTION_PLAY_PAUSE:
735735
playPause();

app/src/main/java/org/schabi/newpipe/player/PlayerService.java

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232

3333
import androidx.annotation.NonNull;
3434
import androidx.annotation.Nullable;
35+
import androidx.core.app.ServiceCompat;
3536
import androidx.media.MediaBrowserServiceCompat;
3637

3738
import com.google.android.exoplayer2.ext.mediasession.MediaSessionConnector;
@@ -150,7 +151,7 @@ public int onStartCommand(final Intent intent, final int flags, final int startI
150151
Stop the service in this case, which will be removed from the foreground and its
151152
notification cancelled in its destruction
152153
*/
153-
stopSelf();
154+
destroyPlayerAndStopService();
154155
return START_NOT_STICKY;
155156
}
156157

@@ -197,7 +198,6 @@ public void onDestroy() {
197198
cleanup();
198199

199200
mediaBrowserPlaybackPreparer.dispose();
200-
mediaSession.setActive(false);
201201
mediaSession.release();
202202
mediaBrowserImpl.dispose();
203203
}
@@ -207,11 +207,36 @@ private void cleanup() {
207207
player.destroy();
208208
player = null;
209209
}
210+
211+
// Should already be handled by MediaSessionPlayerUi, but just to be sure.
212+
mediaSession.setActive(false);
213+
214+
// Should already be handled by NotificationUtil.cancelNotificationAndStopForeground() in
215+
// NotificationPlayerUi, but let's make sure that the foreground service is stopped.
216+
ServiceCompat.stopForeground(this, ServiceCompat.STOP_FOREGROUND_REMOVE);
210217
}
211218

212-
public void stopService() {
219+
/**
220+
* Destroys the player and allows the player instance to be garbage collected. Sets the media
221+
* session to inactive. Stops the foreground service and removes the player notification
222+
* associated with it. Tries to stop the {@link PlayerService} completely, but this step will
223+
* have no effect in case some service connection still uses the service (e.g. the Android Auto
224+
* system accesses the media browser even when no player is running).
225+
*/
226+
public void destroyPlayerAndStopService() {
227+
if (DEBUG) {
228+
Log.d(TAG, "destroyPlayerAndStopService() called");
229+
}
230+
213231
cleanup();
214-
stopSelf();
232+
233+
// This only really stops the service if there are no other service connections (see docs):
234+
// for example the (Android Auto) media browser binder will block stopService().
235+
// This is why we also stopForeground() above, to make sure the notification is removed.
236+
// If we were to call stopSelf(), then the service would be surely stopped (regardless of
237+
// other service connections), but this would be a waste of resources since the service
238+
// would be immediately restarted by those same connections to perform the queries.
239+
stopService(new Intent(this, PlayerService.class));
215240
}
216241

217242
@Override

app/src/main/java/org/schabi/newpipe/player/helper/PlayerHolder.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,8 +138,16 @@ public void startService(final boolean playAfterConnect,
138138
}
139139

140140
public void stopService() {
141+
if (DEBUG) {
142+
Log.d(TAG, "stopService() called");
143+
}
144+
if (playerService != null) {
145+
playerService.destroyPlayerAndStopService();
146+
}
141147
final Context context = getCommonContext();
142148
unbind(context);
149+
// destroyPlayerAndStopService() already runs the next line of code, but run it again just
150+
// to make sure to stop the service even if playerService is null by any chance.
143151
context.stopService(new Intent(context, PlayerService.class));
144152
}
145153

app/src/main/java/org/schabi/newpipe/player/ui/PopupPlayerUi.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -382,7 +382,7 @@ public void onAnimationEnd(final Animator animation) {
382382
private void end() {
383383
windowManager.removeView(closeOverlayBinding.getRoot());
384384
closeOverlayBinding = null;
385-
player.getService().stopService();
385+
player.getService().destroyPlayerAndStopService();
386386
}
387387
}).start();
388388
}

0 commit comments

Comments
 (0)