diff --git a/demos/session/src/main/AndroidManifest.xml b/demos/session/src/main/AndroidManifest.xml index f86bcd86bb..e94b527e83 100644 --- a/demos/session/src/main/AndroidManifest.xml +++ b/demos/session/src/main/AndroidManifest.xml @@ -45,6 +45,7 @@ diff --git a/libraries/session/src/main/java/androidx/media3/session/MediaNotificationManager.java b/libraries/session/src/main/java/androidx/media3/session/MediaNotificationManager.java index 6376ba641d..75c168f575 100644 --- a/libraries/session/src/main/java/androidx/media3/session/MediaNotificationManager.java +++ b/libraries/session/src/main/java/androidx/media3/session/MediaNotificationManager.java @@ -19,13 +19,17 @@ import static androidx.media3.common.util.Assertions.checkStateNotNull; import android.app.Notification; import android.content.Intent; +import android.content.pm.ServiceInfo; import android.os.Bundle; import android.os.Handler; import android.os.Looper; +import androidx.annotation.DoNotInline; import androidx.annotation.Nullable; +import androidx.annotation.RequiresApi; import androidx.core.app.NotificationManagerCompat; import androidx.core.content.ContextCompat; import androidx.media3.common.Player; +import androidx.media3.common.util.Log; import androidx.media3.common.util.Util; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; @@ -44,6 +48,8 @@ import java.util.concurrent.TimeoutException; */ /* package */ final class MediaNotificationManager { + private static final String TAG = "MediaNtfMng"; + private final MediaSessionService mediaSessionService; private final MediaNotification.Provider mediaNotificationProvider; private final MediaNotification.ActionFactory actionFactory; @@ -170,8 +176,12 @@ import java.util.concurrent.TimeoutException; Player player = session.getPlayer(); if (player.getPlayWhenReady() && canStartPlayback(player)) { ContextCompat.startForegroundService(mediaSessionService, startSelfIntent); - mediaSessionService.startForeground( - mediaNotification.notificationId, mediaNotification.notification); + if (Util.SDK_INT >= 29) { + Api29.startForeground(mediaSessionService, mediaNotification); + } else { + mediaSessionService.startForeground( + mediaNotification.notificationId, mediaNotification.notification); + } } else { maybeStopForegroundService(/* removeNotifications= */ false); notificationManagerCompat.notify( @@ -251,4 +261,29 @@ import java.util.concurrent.TimeoutException; mediaSessionService.onUpdateNotification(session); } } + + @RequiresApi(29) + private static class Api29 { + + @DoNotInline + public static void startForeground( + MediaSessionService mediaSessionService, MediaNotification mediaNotification) { + try { + // startForeground() will throw if the service's foregroundServiceType is not defined in the + // manifest to include mediaPlayback. + mediaSessionService.startForeground( + mediaNotification.notificationId, + mediaNotification.notification, + ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK); + } catch (RuntimeException e) { + Log.e( + TAG, + "The service must be declared with a foregroundServiceType that includes " + + " mediaPlayback"); + throw e; + } + } + + private Api29() {} + } } diff --git a/libraries/session/src/main/java/androidx/media3/session/MediaSessionService.java b/libraries/session/src/main/java/androidx/media3/session/MediaSessionService.java index e6fd108f64..41b3445330 100644 --- a/libraries/session/src/main/java/androidx/media3/session/MediaSessionService.java +++ b/libraries/session/src/main/java/androidx/media3/session/MediaSessionService.java @@ -60,7 +60,9 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; *

To extend this class, declare the intent filter in your {@code AndroidManifest.xml}: * *

{@code
- * 
+ * 
  *   
  *     
  *   
@@ -85,9 +87,11 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
  *
  * 

Service Lifecycle

* - *

A media session service is a bound service. When a {@link MediaController} is created for the - * service, the controller binds to the service. {@link #onGetSession(ControllerInfo)} will be - * called from {@link #onBind(Intent)}. + *

A media session service is a bound service and its foreground + * service type must include mediaPlayback. When a {@link MediaController} is created + * for the service, the controller binds to the service. {@link #onGetSession(ControllerInfo)} will + * be called from {@link #onBind(Intent)}. * *

After binding, the session's {@link MediaSession.SessionCallback#onConnect(MediaSession, * MediaSession.ControllerInfo)} will be called to accept or reject the connection request from the diff --git a/libraries/test_session_current/src/main/AndroidManifest.xml b/libraries/test_session_current/src/main/AndroidManifest.xml index 71c443bf25..457b099fd8 100644 --- a/libraries/test_session_current/src/main/AndroidManifest.xml +++ b/libraries/test_session_current/src/main/AndroidManifest.xml @@ -81,6 +81,7 @@ @@ -89,6 +90,7 @@ @@ -96,6 +98,7 @@