2828import android .os .IBinder ;
2929import android .util .Log ;
3030
31+ import org .schabi .newpipe .ktx .BundleKt ;
3132import org .schabi .newpipe .player .mediasession .MediaSessionPlayerUi ;
3233import org .schabi .newpipe .player .notification .NotificationPlayerUi ;
3334import org .schabi .newpipe .util .ThemeHelper ;
4142public final class PlayerService extends Service {
4243 private static final String TAG = PlayerService .class .getSimpleName ();
4344 private static final boolean DEBUG = Player .DEBUG ;
45+ public static final String SHOULD_START_FOREGROUND_EXTRA = "should_start_foreground_extra" ;
4446
4547 private Player player ;
4648
@@ -59,35 +61,39 @@ public void onCreate() {
5961 assureCorrectAppLanguage (this );
6062 ThemeHelper .setTheme (this );
6163
62- player = new Player (this );
63- /*
64- Create the player notification and start immediately the service in foreground,
65- otherwise if nothing is played or initializing the player and its components (especially
66- loading stream metadata) takes a lot of time, the app would crash on Android 8+ as the
67- service would never be put in the foreground while we said to the system we would do so
68- */
69- player .UIs ().get (NotificationPlayerUi .class )
70- .ifPresent (NotificationPlayerUi ::createNotificationAndStartForeground );
64+ // Note: you might be tempted to create the player instance and call startForeground here,
65+ // but be aware that the Android system might start the service just to perform media
66+ // queries. In those cases creating a player instance is a waste of resources, and calling
67+ // startForeground means creating a useless empty notification. In case it's really needed
68+ // the player instance can be created here, but startForeground() should definitely not be
69+ // called here unless the service is actually starting in the foreground, to avoid the
70+ // useless notification.
7171 }
7272
7373 @ Override
7474 public int onStartCommand (final Intent intent , final int flags , final int startId ) {
7575 if (DEBUG ) {
7676 Log .d (TAG , "onStartCommand() called with: intent = [" + intent
77+ + "], extras = [" + BundleKt .toDebugString (intent .getExtras ())
7778 + "], flags = [" + flags + "], startId = [" + startId + "]" );
7879 }
7980
80- /*
81- Be sure that the player notification is set and the service is started in foreground,
82- otherwise, the app may crash on Android 8+ as the service would never be put in the
83- foreground while we said to the system we would do so
84- The service is always requested to be started in foreground, so always creating a
85- notification if there is no one already and starting the service in foreground should
86- not create any issues
87- If the service is already started in foreground, requesting it to be started shouldn't
88- do anything
89- */
90- if (player != null ) {
81+ // All internal NewPipe intents used to interact with the player, that are sent to the
82+ // PlayerService using startForegroundService(), will have SHOULD_START_FOREGROUND_EXTRA,
83+ // to ensure startForeground() is called (otherwise Android will force-crash the app).
84+ if (intent .getBooleanExtra (SHOULD_START_FOREGROUND_EXTRA , false )) {
85+ if (player == null ) {
86+ // make sure the player exists, in case the service was resumed
87+ player = new Player (this );
88+ }
89+
90+ // Be sure that the player notification is set and the service is started in foreground,
91+ // otherwise, the app may crash on Android 8+ as the service would never be put in the
92+ // foreground while we said to the system we would do so. The service is always
93+ // requested to be started in foreground, so always creating a notification if there is
94+ // no one already and starting the service in foreground should not create any issues.
95+ // If the service is already started in foreground, requesting it to be started
96+ // shouldn't do anything.
9197 player .UIs ().get (NotificationPlayerUi .class )
9298 .ifPresent (NotificationPlayerUi ::createNotificationAndStartForeground );
9399 }
0 commit comments