Class ServiceMediaApi

java.lang.Object
android.support.v4.media.session.MediaSessionCompat.Callback
com.jwplayer.pub.api.background.ServiceMediaApi

public class ServiceMediaApi extends android.support.v4.media.session.MediaSessionCompat.Callback
Transport behaviour and notification buttons for background audio. Subclass and pass to MediaServiceController.Builder.serviceMediaApi(ServiceMediaApi) (or MediaServiceController.enable(androidx.appcompat.app.AppCompatActivity, com.jwplayer.pub.api.JWPlayer, com.jwplayer.pub.api.background.ServiceMediaApi)) to change what the notification, lock screen and media buttons do: onPlay(), onPause(), onSeekTo(long), onSkipToNext(), onSkipToPrevious(), onStop(), onSkipToQueueItem(long), onFastForward() and onRewind() are called, and getNotificationCapabilities() decides which transport controls are offered.

To add buttons to the notification, override getNotificationButtons(Context) and onNotificationButtonClick(String):


 public List<NotificationButton> getNotificationButtons(Context context) {
     List<NotificationButton> buttons = new ArrayList<>(super.getNotificationButtons(context));
     buttons.add(new NotificationButton.Builder("like", R.drawable.ic_like, "Like").build());
     return buttons;
 }

 public void onNotificationButtonClick(String id) {
     if ("like".equals(id)) { ... }
 }
 

Existing overrides of addNotificationActions(Context, NotificationCompat.Builder) and getCompactActions() keep working; see those methods for what carries over.

MediaSessionCompat.Callback.onMediaButtonEvent(Intent) is called for media keys the SDK does not handle itself (anything other than play, pause, play/pause, headset hook, next, previous, skip forward and back, fast-forward, rewind and stop), when a subclass overrides it. The rest of the MediaSessionCompat.Callback base class is kept only for source compatibility; it is not registered with a legacy session.

  • Field Details

    • mPlayer

      protected final JWPlayer mPlayer
  • Constructor Details

    • ServiceMediaApi

      public ServiceMediaApi(JWPlayer player)
    • ServiceMediaApi

      protected ServiceMediaApi(JWPlayer player, BGAFactory factory)
  • Method Details

    • onPause

      public void onPause()
      Overrides:
      onPause in class android.support.v4.media.session.MediaSessionCompat.Callback
    • onPlay

      public void onPlay()
      Overrides:
      onPlay in class android.support.v4.media.session.MediaSessionCompat.Callback
    • onSeekTo

      public void onSeekTo(long pos)
      Overrides:
      onSeekTo in class android.support.v4.media.session.MediaSessionCompat.Callback
    • onSkipToNext

      public void onSkipToNext()
      Overrides:
      onSkipToNext in class android.support.v4.media.session.MediaSessionCompat.Callback
    • onSkipToPrevious

      public void onSkipToPrevious()
      Overrides:
      onSkipToPrevious in class android.support.v4.media.session.MediaSessionCompat.Callback
    • onStop

      public void onStop()
      Called for Stop while playing or buffering. A Stop that arrives while paused (from dismissing the notification, a Bluetooth or car Stop button, or a media controller) does not call this: the content stays loaded, as it did before, and playback can be resumed.
      Overrides:
      onStop in class android.support.v4.media.session.MediaSessionCompat.Callback
    • onSkipToQueueItem

      public void onSkipToQueueItem(long id)
      Overrides:
      onSkipToQueueItem in class android.support.v4.media.session.MediaSessionCompat.Callback
    • onFastForward

      public void onFastForward()
      Overrides:
      onFastForward in class android.support.v4.media.session.MediaSessionCompat.Callback
    • onRewind

      public void onRewind()
      Overrides:
      onRewind in class android.support.v4.media.session.MediaSessionCompat.Callback
    • getPlayer

      public JWPlayer getPlayer()
    • getNotificationCapabilities

      public long getNotificationCapabilities()
    • getNotificationButtons

      @NonNull public List<NotificationButton> getNotificationButtons(@NonNull android.content.Context context)
      The buttons on the notification, in order, transport controls included.

      The default returns the actions added by addNotificationActions(Context, NotificationCompat.Builder), with the compact view from getCompactActions(): previous, play or pause, and next, following getNotificationCapabilities(), or whatever a subclass that overrides those methods adds. To add buttons, call super and append to the list it returns. When the list is built with NotificationButtons (or is empty) and has no play/pause, play/pause is added first while the player offers it, so an empty list gives a notification with play/pause only. The plain result of an addNotificationActions override is rendered exactly as given, as before.

      Called on the main thread whenever the player state, playlist item or metadata changes, and after invalidateNotificationButtons(), so the list can follow the state (a "like" button that disables itself, say). Give the same button the same id each time.

      At most 10 custom buttons are used; the rest are dropped with a warning. In practice 3 to 5 is the most the system shows: extra buttons may not appear at all, depending on the Android version and the device. Android 12 and below show at most 5 actions in the expanded notification, built-in controls and an automatically added play/pause (placed first) included; later ones are dropped, so put the important buttons first. On Android 13 and later, the system media controls lay out the buttons themselves, ignore the compact view, and do not show disabled buttons.

    • onNotificationButtonClick

      public void onNotificationButtonClick(@NonNull String buttonId)
      Called on the main thread when a button from getNotificationButtons(Context) is tapped. Not called for a disabled button, nor for an action added by addNotificationActions(android.content.Context, androidx.core.app.NotificationCompat.Builder), whose own PendingIntent is sent instead. Does nothing by default.
    • invalidateNotificationButtons

      public void invalidateNotificationButtons()
      Asks for getNotificationButtons(Context) to be read again, when the buttons depend on something other than the player state. Safe from any thread, including from onNotificationButtonClick: the buttons are read again shortly after, on the main thread. A call made on the main thread from inside getNotificationButtons is ignored, since that read already sees the new state. Does nothing while this api is not backing background audio.
    • getCompactActions

      @Deprecated public int[] getCompactActions()
      Deprecated.
      Give buttons a NotificationButton.Builder.compactViewIndex(int) in getNotificationButtons(Context) instead. Still honoured for the actions from addNotificationActions(android.content.Context, androidx.core.app.NotificationCompat.Builder): the first three entries are used, and each index, into those actions in the order they were added, puts that action at that position in the compact view. An override is honoured exactly; with the default, play/pause is always in the compact view.
    • addNotificationActions

      @Deprecated public void addNotificationActions(android.content.Context context, androidx.core.app.NotificationCompat.Builder builder)
      Deprecated.
      Override getNotificationButtons(Context) instead. Still honoured: the SDK calls this on a scratch builder each time it reads the buttons, and turns each added action into a button with the same icon and title, in the same order. Tapping it sends the action's own PendingIntent, as before; an action with a null intent is shown but does nothing. An action whose intent is getActionIntent(android.content.Context, int) for a media key becomes the native control for that key. In the notification itself the action's intent is fired directly, as before; from the lock screen, Android 13+ system controls, Bluetooth or Auto the SDK sends it on the user's behalf.

      An override runs on the main thread on every relevant player event (state, item, metadata changes), so keep it cheap and free of side effects, and return the same PendingIntents each time (same request code, no FLAG_CANCEL_CURRENT): the SDK identifies an action by its intent and title, so a new intent per call makes the button look new on every refresh. The actions are rendered exactly as added, play/pause only if you add it. Android 12 and below show at most 5 actions in the expanded notification; later ones are dropped, so put the important ones first.

      Limits: only the actions carry over; everything else set on the builder (text, style, colour, large icon, ...) is ignored, since the notification is built from the media session. The icon must be a drawable resource; an action with any other icon is skipped. Below Android 13 the notification's own buttons fire the intent directly, so an Activity intent opens as before. Android 13+ system media controls, the lock screen, Bluetooth and Auto press the button through the media session instead, and the SDK sends the intent for the user: Android blocks an Activity PendingIntent started that way while the app is in the background (verified on Android 15). Use a broadcast intent, or the onNotificationButtonClick(String) callback, for actions that must work there; a service intent is subject to Android 8+ background start limits when the app is not in the foreground.

    • getActionIntent

      public android.app.PendingIntent getActionIntent(android.content.Context context, int mediaKeyEvent)
      A PendingIntent that sends mediaKeyEvent to the background-audio service, as if a media button had been pressed. Inside addNotificationActions(android.content.Context, androidx.core.app.NotificationCompat.Builder), an action with this intent becomes the native control for that key. Works while background audio is active: it is a plain service start, which Android 8+ refuses for an app in the background with no foreground service. It is deliberately not a foreground-service start: a key that does not start playback (pause, next while paused) would leave the service unpromoted and the app would crash after the foreground-start timeout.