Skip to content

Commit bff51c2

Browse files
committed
Post dummy notification then close player service on invalid intent
This should solve "Context.startForegroundService() did not then call Service.startForeground()" according to #12489 (comment)
1 parent a0fcf18 commit bff51c2

2 files changed

Lines changed: 53 additions & 34 deletions

File tree

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

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
import org.schabi.newpipe.player.mediabrowser.MediaBrowserPlaybackPreparer;
4141
import org.schabi.newpipe.player.mediasession.MediaSessionPlayerUi;
4242
import org.schabi.newpipe.player.notification.NotificationPlayerUi;
43+
import org.schabi.newpipe.player.notification.NotificationUtil;
4344
import org.schabi.newpipe.util.ThemeHelper;
4445

4546
import java.lang.ref.WeakReference;
@@ -156,23 +157,22 @@ public int onStartCommand(final Intent intent, final int flags, final int startI
156157
}
157158
}
158159

159-
if (Intent.ACTION_MEDIA_BUTTON.equals(intent.getAction())
160-
&& (player == null || player.getPlayQueue() == null)) {
161-
/*
162-
No need to process media button's actions if the player is not working, otherwise
163-
the player service would strangely start with nothing to play
164-
Stop the service in this case, which will be removed from the foreground and its
165-
notification cancelled in its destruction
166-
*/
160+
if (player == null) {
161+
// No need to process media button's actions or other system intents if the player is
162+
// not running. However, since the current intent might have been issued by the system
163+
// with `startForegroundService()` (for unknown reasons), we need to ensure that we post
164+
// a (dummy) foreground notification, otherwise we'd incur in
165+
// "Context.startForegroundService() did not then call Service.startForeground()". Then
166+
// we stop the service again.
167+
Log.d(TAG, "onStartCommand() got a useless intent, closing the service");
168+
NotificationUtil.startForegroundWithDummyNotification(this);
167169
destroyPlayerAndStopService();
168170
return START_NOT_STICKY;
169171
}
170172

171-
if (player != null) {
172-
player.handleIntent(intent);
173-
player.UIs().get(MediaSessionPlayerUi.class)
174-
.ifPresent(ui -> ui.handleMediaButtonIntent(intent));
175-
}
173+
player.handleIntent(intent);
174+
player.UIs().get(MediaSessionPlayerUi.class)
175+
.ifPresent(ui -> ui.handleMediaButtonIntent(intent));
176176

177177
return START_NOT_STICKY;
178178
}

app/src/main/java/org/schabi/newpipe/player/notification/NotificationUtil.java

Lines changed: 40 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@
55
import static org.schabi.newpipe.player.notification.NotificationConstants.ACTION_CLOSE;
66

77
import android.annotation.SuppressLint;
8+
import android.app.Notification;
89
import android.app.PendingIntent;
10+
import android.content.Context;
911
import android.content.Intent;
1012
import android.content.pm.ServiceInfo;
1113
import android.graphics.Bitmap;
@@ -23,6 +25,7 @@
2325
import org.schabi.newpipe.MainActivity;
2426
import org.schabi.newpipe.R;
2527
import org.schabi.newpipe.player.Player;
28+
import org.schabi.newpipe.player.PlayerService;
2629
import org.schabi.newpipe.player.mediasession.MediaSessionPlayerUi;
2730
import org.schabi.newpipe.util.NavigationHelper;
2831

@@ -89,12 +92,9 @@ private synchronized NotificationCompat.Builder createNotification() {
8992
Log.d(TAG, "createNotification()");
9093
}
9194
notificationManager = NotificationManagerCompat.from(player.getContext());
92-
final NotificationCompat.Builder builder =
93-
new NotificationCompat.Builder(player.getContext(),
94-
player.getContext().getString(R.string.notification_channel_id));
95-
final MediaStyle mediaStyle = new MediaStyle();
9695

9796
// setup media style (compact notification slots and media session)
97+
final MediaStyle mediaStyle = new MediaStyle();
9898
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) {
9999
// notification actions are ignored on Android 13+, and are replaced by code in
100100
// MediaSessionPlayerUi
@@ -107,18 +107,9 @@ private synchronized NotificationCompat.Builder createNotification() {
107107
.ifPresent(mediaStyle::setMediaSession);
108108

109109
// setup notification builder
110-
builder.setStyle(mediaStyle)
111-
.setPriority(NotificationCompat.PRIORITY_HIGH)
112-
.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
113-
.setCategory(NotificationCompat.CATEGORY_TRANSPORT)
114-
.setShowWhen(false)
115-
.setSmallIcon(R.drawable.ic_newpipe_triangle_white)
116-
.setColor(ContextCompat.getColor(player.getContext(),
117-
R.color.dark_background_color))
110+
final var builder = setupNotificationBuilder(player.getContext(), mediaStyle)
118111
.setColorized(player.getPrefs().getBoolean(
119-
player.getContext().getString(R.string.notification_colorize_key), true))
120-
.setDeleteIntent(PendingIntentCompat.getBroadcast(player.getContext(),
121-
NOTIFICATION_ID, new Intent(ACTION_CLOSE), FLAG_UPDATE_CURRENT, false));
112+
player.getContext().getString(R.string.notification_colorize_key), true));
122113

123114
// set the initial value for the video thumbnail, updatable with updateNotificationThumbnail
124115
setLargeIcon(builder);
@@ -167,17 +158,17 @@ public boolean shouldUpdateBufferingSlot() {
167158
&& notificationBuilder.mActions.get(2).actionIntent != null);
168159
}
169160

161+
public static void startForegroundWithDummyNotification(final PlayerService service) {
162+
final var builder = setupNotificationBuilder(service, new MediaStyle());
163+
startForeground(service, builder.build());
164+
}
165+
170166
public void createNotificationAndStartForeground() {
171167
if (notificationBuilder == null) {
172168
notificationBuilder = createNotification();
173169
}
174170
updateNotification();
175-
176-
// ServiceInfo constants are not used below Android Q, so 0 is set here
177-
final int serviceType = Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q
178-
? ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK : 0;
179-
ServiceCompat.startForeground(player.getService(), NOTIFICATION_ID,
180-
notificationBuilder.build(), serviceType);
171+
startForeground(player.getService(), notificationBuilder.build());
181172
}
182173

183174
public void cancelNotificationAndStopForeground() {
@@ -191,6 +182,34 @@ public void cancelNotificationAndStopForeground() {
191182
}
192183

193184

185+
/////////////////////////////////////////////////////
186+
// STATIC FUNCTIONS IN COMMON BETWEEN DUMMY AND REAL NOTIFICATION
187+
/////////////////////////////////////////////////////
188+
189+
private static NotificationCompat.Builder setupNotificationBuilder(final Context context,
190+
final MediaStyle style) {
191+
return new NotificationCompat.Builder(context,
192+
context.getString(R.string.notification_channel_id))
193+
.setStyle(style)
194+
.setPriority(NotificationCompat.PRIORITY_HIGH)
195+
.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
196+
.setCategory(NotificationCompat.CATEGORY_TRANSPORT)
197+
.setShowWhen(false)
198+
.setSmallIcon(R.drawable.ic_newpipe_triangle_white)
199+
.setColor(ContextCompat.getColor(context, R.color.dark_background_color))
200+
.setDeleteIntent(PendingIntentCompat.getBroadcast(context,
201+
NOTIFICATION_ID, new Intent(ACTION_CLOSE), FLAG_UPDATE_CURRENT, false));
202+
}
203+
204+
private static void startForeground(final PlayerService service,
205+
final Notification notification) {
206+
// ServiceInfo constants are not used below Android Q, so 0 is set here
207+
final int serviceType = Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q
208+
? ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK : 0;
209+
ServiceCompat.startForeground(service, NOTIFICATION_ID, notification, serviceType);
210+
}
211+
212+
194213
/////////////////////////////////////////////////////
195214
// ACTIONS
196215
/////////////////////////////////////////////////////

0 commit comments

Comments
 (0)