# MediaButtonReceiver

Artifact: [androidx.media3:media3-session](https://developer.android.com/jetpack/androidx/releases/media3) [View Source](https://cs.android.com/search?q=file:androidx/media3/session/MediaButtonReceiver.java+class:androidx.media3.session.MediaButtonReceiver)

*** ** * ** ***

<br />

```
@UnstableApi
public class MediaButtonReceiver extends BroadcastReceiver
```

<br />

|---|---|---|
| [java.lang.Object](https://developer.android.com/reference/java/lang/Object.html) |||
| ↳ | [android.content.BroadcastReceiver](https://developer.android.com/reference/android/content/BroadcastReceiver.html) ||
|   | ↳ | [androidx.media3.session.MediaButtonReceiver](https://developer.android.com/reference/androidx/media3/session/MediaButtonReceiver) |

*** ** * ** ***

A media button receiver receives hardware media playback button intent, such as those sent by wired and wireless headsets.

You can add this MediaButtonReceiver to your app by adding it directly to your AndroidManifest.xml:

```
<receiver
    android:name="androidx.media3.session.MediaButtonReceiver"
    android:exported="true">
  <intent-filter>
    <action android:name="android.intent.action.MEDIA_BUTTON" />
  </intent-filter>
</receiver>
```

Apps that add this receiver to the manifest, must implement `https://developer.android.com/reference/androidx/media3/session/MediaSession.Callback#onPlaybackResumption(androidx.media3.session.MediaSession,androidx.media3.session.MediaSession.ControllerInfo)` or active automatic playback resumption (Note: If you choose to make this receiver start your own service that is not a `https://developer.android.com/reference/androidx/media3/session/MediaSessionService` or `https://developer.android.com/reference/androidx/media3/session/MediaLibraryService`, then you need to fulfill all requirements around starting a service in the foreground on all API levels your app should properly work on).

## Service discovery

This class assumes you have a `https://developer.android.com/reference/android/app/Service.html` in your app's manifest that controls media playback via a `https://developer.android.com/reference/androidx/media3/session/MediaSession`. Once a key event is received by this receiver, it tries to find a `https://developer.android.com/reference/android/app/Service.html` that can handle the action `https://developer.android.com/reference/android/content/Intent.html#ACTION_MEDIA_BUTTON`, `https://developer.android.com/reference/androidx/media3/session/MediaSessionService#SERVICE_INTERFACE()` or `https://developer.android.com/reference/androidx/media3/session/MediaLibraryService#SERVICE_INTERFACE()`. If an appropriate service is found, this class starts the service as a foreground service and sends the key event to the service by an `https://developer.android.com/reference/android/content/Intent.html` with action `https://developer.android.com/reference/android/content/Intent.html#ACTION_MEDIA_BUTTON`. If neither one is available or more than one valid service is found for one of the actions, an `https://developer.android.com/reference/java/lang/IllegalStateException.html` is thrown.

### Service handling ACTION_MEDIA_BUTTON

A service can receive a key event by including an intent filter that handles ` android.intent.action.MEDIA_BUTTON`.

```
<service android:name="com.example.android.MediaPlaybackService" >
  <intent-filter>
    <action android:name="android.intent.action.MEDIA_BUTTON" />
  </intent-filter>
</service>
```

### Service handling action `https://developer.android.com/reference/androidx/media3/session/MediaSessionService` or `https://developer.android.com/reference/androidx/media3/session/MediaLibraryService`

If you are using a `https://developer.android.com/reference/androidx/media3/session/MediaSessionService` or `https://developer.android.com/reference/androidx/media3/session/MediaLibraryService`, the service interface name is already used as the intent action. In this case, no further configuration is required.

```
<service android:name="com.example.android.MediaPlaybackService" >
  <intent-filter>
    <action android:name="androidx.media3.session.MediaLibraryService" />
  </intent-filter>
</service>
```

## Summary

| ### Public constructors |
|---|
| `https://developer.android.com/reference/androidx/media3/session/MediaButtonReceiver#MediaButtonReceiver()()` |

| ### Public methods |
|---|---|
| `void` | `https://developer.android.com/reference/androidx/media3/session/MediaButtonReceiver#onReceive(android.content.Context,android.content.Intent)(https://developer.android.com/reference/android/content/Context.html context, @https://developer.android.com/reference/androidx/annotation/Nullable https://developer.android.com/reference/android/content/Intent.html intent)` Apps can override this method if the default behaviour doesn't match their needs. |

| ### Protected methods |
|---|---|
| `final void` | `@https://developer.android.com/reference/androidx/media3/common/util/UnstableApi https://developer.android.com/reference/androidx/media3/session/MediaButtonReceiver#handleIntentAndMaybeStartTheService(android.content.Context,android.content.Intent)( https://developer.android.com/reference/android/content/Context.html context, @https://developer.android.com/reference/androidx/annotation/Nullable https://developer.android.com/reference/android/content/Intent.html intent )` Handles the intent and starts the service if `https://developer.android.com/reference/androidx/media3/session/MediaButtonReceiver#shouldStartForegroundService(android.content.Context,android.content.Intent)` indicates to do so. |
| `void` | `@https://developer.android.com/reference/androidx/annotation/RequiresApi(value = 31) [onForegroundServiceStartNotAllowedException](https://developer.android.com/reference/androidx/media3/session/MediaButtonReceiver#onForegroundServiceStartNotAllowedException(android.content.Intent,android.app.ForegroundServiceStartNotAllowedException))( https://developer.android.com/reference/android/content/Intent.html intent, https://developer.android.com/reference/android/app/ForegroundServiceStartNotAllowedException.html e )` **This method is deprecated.** Use `https://developer.android.com/reference/androidx/media3/session/MediaButtonReceiver#onForegroundServiceStartNotAllowedException(android.content.Context,android.content.Intent,android.app.ForegroundServiceStartNotAllowedException)` instead. <br /> |
| `void` | `@https://developer.android.com/reference/androidx/annotation/RequiresApi(value = 31) https://developer.android.com/reference/androidx/media3/session/MediaButtonReceiver#onForegroundServiceStartNotAllowedException(android.content.Context,android.content.Intent,android.app.ForegroundServiceStartNotAllowedException)( https://developer.android.com/reference/android/content/Context.html context, https://developer.android.com/reference/android/content/Intent.html intent, https://developer.android.com/reference/android/app/ForegroundServiceStartNotAllowedException.html e )` This method is called when an exception is thrown when calling `https://developer.android.com/reference/android/content/Context.html#startForegroundService(android.content.Intent)` as a result of receiving a media button event. |
| `boolean` | `https://developer.android.com/reference/androidx/media3/session/MediaButtonReceiver#shouldStartForegroundService(android.content.Context,android.content.Intent)(https://developer.android.com/reference/android/content/Context.html context, https://developer.android.com/reference/android/content/Intent.html intent)` Returns whether to start the `https://developer.android.com/reference/android/content/Intent.html#getComponent()` into the foreground. |

### Inherited methods

From [android.content.BroadcastReceiver](https://developer.android.com/reference/android/content/BroadcastReceiver.html) `final void` `https://developer.android.com/reference/android/content/BroadcastReceiver.html#abortBroadcast()()` `final void` `https://developer.android.com/reference/android/content/BroadcastReceiver.html#clearAbortBroadcast()()` `final boolean` `https://developer.android.com/reference/android/content/BroadcastReceiver.html#getAbortBroadcast()()` `final boolean` `https://developer.android.com/reference/android/content/BroadcastReceiver.html#getDebugUnregister()()` `final int` `https://developer.android.com/reference/android/content/BroadcastReceiver.html#getResultCode()()` `final https://developer.android.com/reference/java/lang/String.html` `https://developer.android.com/reference/android/content/BroadcastReceiver.html#getResultData()()` `final https://developer.android.com/reference/android/os/Bundle.html` `https://developer.android.com/reference/android/content/BroadcastReceiver.html#getResultExtras(boolean)(boolean makeMap)` `https://developer.android.com/reference/java/lang/String.html` `https://developer.android.com/reference/android/content/BroadcastReceiver.html#getSentFromPackage()()` `int` `https://developer.android.com/reference/android/content/BroadcastReceiver.html#getSentFromUid()()` `final https://developer.android.com/reference/android/content/BroadcastReceiver.PendingResult.html` `https://developer.android.com/reference/android/content/BroadcastReceiver.html#goAsync()()` `final boolean` `https://developer.android.com/reference/android/content/BroadcastReceiver.html#isInitialStickyBroadcast()()` `final boolean` `https://developer.android.com/reference/android/content/BroadcastReceiver.html#isOrderedBroadcast()()` `https://developer.android.com/reference/android/os/IBinder.html` `https://developer.android.com/reference/android/content/BroadcastReceiver.html#peekService(android.content.Context, android.content.Intent)(https://developer.android.com/reference/android/content/Context.html myContext, https://developer.android.com/reference/android/content/Intent.html service)` `final void` `https://developer.android.com/reference/android/content/BroadcastReceiver.html#setDebugUnregister(boolean)(boolean debug)` `final void` `https://developer.android.com/reference/android/content/BroadcastReceiver.html#setOrderedHint(boolean)(boolean isOrdered)` `final void` `https://developer.android.com/reference/android/content/BroadcastReceiver.html#setResult(int, java.lang.String, android.os.Bundle)(int code, https://developer.android.com/reference/java/lang/String.html data, https://developer.android.com/reference/android/os/Bundle.html extras)` `final void` `https://developer.android.com/reference/android/content/BroadcastReceiver.html#setResultCode(int)(int code)` `final void` `https://developer.android.com/reference/android/content/BroadcastReceiver.html#setResultData(java.lang.String)(https://developer.android.com/reference/java/lang/String.html data)` `final void` `https://developer.android.com/reference/android/content/BroadcastReceiver.html#setResultExtras(android.os.Bundle)(https://developer.android.com/reference/android/os/Bundle.html extras)`

## Public constructors

### MediaButtonReceiver

```
public MediaButtonReceiver()
```

## Public methods

### onReceive

```
public void onReceive(Context context, @Nullable Intent intent)
```

Apps can override this method if the default behaviour doesn't match their needs. When doing that, an app would eventually call `https://developer.android.com/reference/androidx/media3/session/MediaButtonReceiver#handleIntentAndMaybeStartTheService(android.content.Context,android.content.Intent)` to continue the process to start the service. If you are not calling this method, then using this class probably is not needed. Instead, a custom implementation of `https://developer.android.com/reference/android/content/BroadcastReceiver.html` can be provided in the manifest for the action `https://developer.android.com/reference/android/content/Intent.html#ACTION_MEDIA_BUTTON`.

The recommended approach is to use this receiver without overriding this method, but instead use `https://developer.android.com/reference/androidx/media3/session/MediaButtonReceiver#shouldStartForegroundService(android.content.Context,android.content.Intent)` to indicate whether to start the service or not. When overriding this method, we can't provide further support because the strongly recommended way to handle the intent is using the default implementation.

## Protected methods

### handleIntentAndMaybeStartTheService

```
@UnstableApi
protected final void handleIntentAndMaybeStartTheService(
    Context context,
    @Nullable Intent intent
)
```

Handles the intent and starts the service if `https://developer.android.com/reference/androidx/media3/session/MediaButtonReceiver#shouldStartForegroundService(android.content.Context,android.content.Intent)` indicates to do so.

| Parameters |
|---|---|
| `https://developer.android.com/reference/android/content/Context.html context` | The context. |
| `@https://developer.android.com/reference/androidx/annotation/Nullable https://developer.android.com/reference/android/content/Intent.html intent` | The intent. |

### onForegroundServiceStartNotAllowedException

```
@RequiresApi(value = 31)
protected void [onForegroundServiceStartNotAllowedException](https://developer.android.com/reference/androidx/media3/session/MediaButtonReceiver#onForegroundServiceStartNotAllowedException(android.content.Intent,android.app.ForegroundServiceStartNotAllowedException))(
    Intent intent,
    ForegroundServiceStartNotAllowedException e
)
```

> [!CAUTION]
> **This method is deprecated.**   
>
> Use `https://developer.android.com/reference/androidx/media3/session/MediaButtonReceiver#onForegroundServiceStartNotAllowedException(android.content.Context,android.content.Intent,android.app.ForegroundServiceStartNotAllowedException)` instead.

### onForegroundServiceStartNotAllowedException

```
@RequiresApi(value = 31)
protected void onForegroundServiceStartNotAllowedException(
    Context context,
    Intent intent,
    ForegroundServiceStartNotAllowedException e
)
```

This method is called when an exception is thrown when calling `https://developer.android.com/reference/android/content/Context.html#startForegroundService(android.content.Intent)` as a result of receiving a media button event.

By default, this method only logs the exception and it can be safely overridden. Apps that find that such a media button event has been legitimately sent, may choose to override this method and take the opportunity to post a notification from where the user journey can continue.

This exception can be thrown if a broadcast media button event is received and a media service is found in the manifest that is registered to handle `https://developer.android.com/reference/android/content/Intent.html#ACTION_MEDIA_BUTTON`. If this happens on API 31+ and the app is in the background then an exception is thrown.

A media button intent is only required to be sent to this receiver for a Bluetooth media button event that wants to restart the service. In such a case the app gets an exemption and is allowed to start the foreground service. In this case this method will never be called.

In all other cases of attempting to start a Media3 service or to send a media button event, apps must use a `https://developer.android.com/reference/androidx/media3/session/MediaBrowser` or `https://developer.android.com/reference/androidx/media3/session/MediaController` to bind to the service instead of broadcasting an intent.

| Parameters |
|---|---|
| `https://developer.android.com/reference/android/content/Context.html context` | The broadcast receiver's `https://developer.android.com/reference/android/content/Context.html` |
| `https://developer.android.com/reference/android/content/Intent.html intent` | The intent that was used `https://developer.android.com/reference/android/content/Context.html#startForegroundService(android.content.Intent)`. |
| `https://developer.android.com/reference/android/app/ForegroundServiceStartNotAllowedException.html e` | The exception thrown by the system and caught by this broadcast receiver. |

### shouldStartForegroundService

```
protected boolean shouldStartForegroundService(Context context, Intent intent)
```

Returns whether to start the `https://developer.android.com/reference/android/content/Intent.html#getComponent()` into the foreground.

Returns true by default. Apps can override this method to decide to not start a service when receiving an event with `https://developer.android.com/reference/android/view/KeyEvent.html#KEYCODE_MEDIA_PLAY` or `https://developer.android.com/reference/android/view/KeyEvent.html#KEYCODE_MEDIA_PLAY_PAUSE` that should be suppressed.

Note: Once the service is started into the foreground by the receiver, the app must start playback to get into the foreground or the system will crash the service with a ` ForegroundServiceDidNotStartInTimeException` or an `https://developer.android.com/reference/java/lang/IllegalStateException.html`.

| Parameters |
|---|---|
| `https://developer.android.com/reference/android/content/Context.html context` | The `https://developer.android.com/reference/android/content/Context.html` that `https://developer.android.com/reference/androidx/media3/session/MediaButtonReceiver#onReceive(android.content.Context,android.content.Intent)`. |
| `https://developer.android.com/reference/android/content/Intent.html intent` | The intent that will be used by `https://developer.android.com/reference/android/content/Context.html#startForegroundService(android.content.Intent)`. |

| Returns |
|---|---|
| `boolean` | true if the service should be `https://developer.android.com/reference/androidx/core/content/ContextCompat#startForegroundService(android.content.Context,android.content.Intent)`. If false is returned the service is not started and the receiver call is a no-op. |