diff --git a/media/java/android/media/AudioFocusRequest.java b/media/java/android/media/AudioFocusRequest.java index b1dc3ad13f12f..9841815a52d19 100644 --- a/media/java/android/media/AudioFocusRequest.java +++ b/media/java/android/media/AudioFocusRequest.java @@ -40,7 +40,7 @@ import android.os.Looper; *
When an application requests audio focus, it expresses its intention to “own” audio focus to
* play audio. Let’s review the different types of focus requests, the return value after a request,
* and the responses to a loss.
- *
Note: applications should not play anything until granted focus.
+ *
Note: applications should not play anything until granted focus.
* *There are four focus request types. A successful focus request with each will yield different @@ -77,9 +77,10 @@ import android.os.Looper; * *
An {@code AudioFocusRequest} instance always contains one of the four types of requests * explained above. It is passed when building an {@code AudioFocusRequest} instance with its - * builder in the {@link Builder} constructor {@link Builder#Builder(int)}, or with - * {@link Builder#setFocusGain(int)} after copying an existing instance with - * {@link Builder#Builder(AudioFocusRequest)}. + * builder in the {@link Builder} constructor + * {@link AudioFocusRequest.Builder#AudioFocusRequest.Builder(int)}, or + * with {@link AudioFocusRequest.Builder#setFocusGain(int)} after copying an existing instance with + * {@link AudioFocusRequest.Builder#AudioFocusRequest.Builder(AudioFocusRequest)}. * *
When an application requested audio focus with * {@link AudioManager#AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK}, the system will duck the current focus - * owner. Note that this behavior is new for Android O, whereas applications targeting SDK - * up to API 25, applications had to implement the ducking themselves when they received a focus + * owner. + *
Note: this behavior is new for Android O, whereas applications targeting
+ * SDK level up to API 25 had to implement the ducking themselves when they received a focus
* loss of {@link AudioManager#AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK}.
- *
But ducking is not always the behavior expected by the user. A typical example is when the
+ *
But ducking is not always the behavior expected by the user. A typical example is when the * device plays driving directions while the user is listening to an audio book or podcast, and * expects the audio playback to pause, instead of duck, as it is hard to understand a navigation * prompt and spoken content at the same time. Therefore the system will not automatically duck @@ -126,7 +128,92 @@ import android.os.Looper; * speech, you can also declare so with {@link Builder#setWillPauseWhenDucked(boolean)}, which will * cause the system to call your focus listener instead of automatically ducking. * + *
The example below covers the following steps to be found in any application that would play + * audio, and use audio focus. Here we play an audio book, and our application is intended to pause + * rather than duck when it loses focus. These steps consist in: + *
+ *
+ * // initialization of the audio attributes and focus request
+ * mAudioManager = (AudioManager) Context.getSystemService(Context.AUDIO_SERVICE);
+ * mPlaybackAttributes = new AudioAttributes.Builder()
+ * .setUsage(AudioAttributes.USAGE_MEDIA)
+ * .setContentType(AudioAttributes.CONTENT_TYPE_SPEECH)
+ * .build();
+ * mFocusRequest = new AudioFocusRequest.Builder(AudioManager.AUDIOFOCUS_GAIN)
+ * .setAudioAttributes(mPlaybackAttributes)
+ * .setAcceptsDelayedFocusGain(true)
+ * .setWillPauseWhenDucked(true)
+ * .setOnAudioFocusChangeListener(this, mMyHandler)
+ * .build();
+ * mMediaPlayer = new MediaPlayer();
+ * mMediaPlayer.setAudioAttributes(mPlaybackAttributes);
+ * final Object mFocusLock = new Object();
+ *
+ * boolean mPlaybackDelayed = false;
+ *
+ * // requesting audio focus
+ * int res = mAudioManager.requestAudioFocus(mFocusRequest);
+ * synchronized (mFocusLock) {
+ * if (res == AUDIOFOCUS_REQUEST_FAILED) {
+ * mPlaybackDelayed = false;
+ * } else if (res == AUDIOFOCUS_REQUEST_GRANTED) {
+ * mPlaybackDelayed = false;
+ * playbackNow();
+ * } else if (res == AUDIOFOCUS_REQUEST_DELAYED) {
+ * mPlaybackDelayed = true;
+ * }
+ * }
+ *
+ * // implementation of the OnAudioFocusChangeListener
+ * @Override
+ * public void onAudioFocusChange(int focusChange) {
+ * switch (focusChange) {
+ * case AudioManager.AUDIOFOCUS_GAIN:
+ * if (mPlaybackDelayed || mResumeOnFocusGain) {
+ * synchronized (mFocusLock) {
+ * mPlaybackDelayed = false;
+ * mResumeOnFocusGain = false;
+ * }
+ * playbackNow();
+ * }
+ * break;
+ * case AudioManager.AUDIOFOCUS_LOSS:
+ * synchronized (mFocusLock) {
+ * // this is not a transient loss, we shouldn't automatically resume for now
+ * mResumeOnFocusGain = false;
+ * mPlaybackDelayed = false;
+ * }
+ * pausePlayback();
+ * break;
+ * case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
+ * case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:
+ * // we handle all transient losses the same way because we never duck audio books
+ * synchronized (mFocusLock) {
+ * // we should only resume if playback was interrupted
+ * mResumeOnFocusGain = mMediaPlayer.isPlaying();
+ * mPlaybackDelayed = false;
+ * }
+ * pausePlayback();
+ * break;
+ * }
+ * }
+ *
+ * // Important:
+ * // Also set "mResumeOnFocusGain" to false when the user pauses or stops playback: this way your
+ * // application doesn't automatically restart when it gains focus, even though the user had
+ * // stopped it.
+ *
*/
+
public final class AudioFocusRequest {
// default attributes for the request when not specified
@@ -244,36 +331,15 @@ public final class AudioFocusRequest {
/**
* Builder class for {@link AudioFocusRequest} objects.
- * Here is an example where {@code Builder} is used to define the - * {@link AudioFocusRequest} for requesting audio focus: - * - *
- * mAudioManager = (AudioManager) Context.getSystemService(Context.AUDIO_SERVICE);
- * mPlaybackAttributes = new AudioAttributes.Builder()
- * .setUsage(AudioAttributes.USAGE_GAME)
- * .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
- * .build();
- * mFocusRequest = new AudioFocusRequest.Builder(AudioManager.AUDIOFOCUS_GAIN)
- * .setAudioAttributes(mPlaybackAttributes)
- * .setAcceptsDelayedFocusGain(true)
- * .setOnAudioFocusChangeListener(mMyFocusListener, mMyHandler)
- * .build();
- * mMediaPlayer = new MediaPlayer();
- * ...
- * mMediaPlayer.setAudioAttributes(mPlaybackAttributes);
- * ...
- * boolean mPlaybackAuthorized = true;;
- * int res = mAudioManager.requestAudioFocus(mFocusRequest);
- * if (res == AUDIOFOCUS_REQUEST_FAILED) {
- * mPlaybackAuthorized = false;
- * cancelPlayback();
- * } else if (res == AUDIOFOCUS_REQUEST_DELAYED) {
- * playbackDelayed();
- * } else { // res == AUDIOFOCUS_REQUEST_GRANTED
- * playbackNow();
- * }
- *
- *
+ * See {@link AudioFocusRequest} for an example of building an instance with this builder.
+ *
The default values for the instance to be built are:
+ *
| focus listener and handler | none |
| {@code AudioAttributes} | attributes with usage set to + * {@link AudioAttributes#USAGE_MEDIA} |
| pauses on duck | false |
| supports delayed focus grant | false |