Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit cfcb4312 authored by Jean-Michel Trivi's avatar Jean-Michel Trivi
Browse files

AudioFocusRequest: longer code sample, javadoc fixes

Test: make -j offline-sdk-docs
Bug: 38124458
Change-Id: I18e83175f6919fd6afeae9475c00eded829cb96a
parent 9289faa1
Loading
Loading
Loading
Loading
+103 −37
Original line number Diff line number Diff line
@@ -40,7 +40,7 @@ import android.os.Looper;
 * <p>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.
 * <br><b>Note:<b> applications should not play anything until granted focus.
 * <p class="note">Note: applications should not play anything until granted focus.</p>
 *
 * <h3>The different types of focus requests</h3>
 * <p>There are four focus request types. A successful focus request with each will yield different
@@ -77,9 +77,10 @@ import android.os.Looper;
 *
 * <p>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)}.
 *
 * <h3>Qualifying your focus request</h3>
 * <h4>Use case requiring a focus request</h4>
@@ -105,10 +106,11 @@ import android.os.Looper;
 * <h4>Pausing vs ducking</h4>
 * <p>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 <b>new for Android O<b>, whereas applications targeting SDK
 * up to API 25, applications had to implement the ducking themselves when they received a focus
 * owner.
 * <p class="note">Note: this behavior is <b>new for Android O</b>, 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}.
 * <br>But ducking is not always the behavior expected by the user. A typical example is when the
 * <p>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.
 *
 * <h4>Example</h4>
 * <p>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:
 * <ul>
 * <li>Creating {@code AudioAttributes} to be used for the playback and the focus request.</li>
 * <li>Configuring and creating the {@code AudioFocusRequest} instance that defines the intended
 *     focus behaviors.</li>
 * <li>Requesting audio focus and checking the return code to see if playback can happen right
 *     away, or is delayed.</li>
 * <li>Implementing a focus change listener to respond to focus gains and losses.</li>
 * </ul>
 * <p>
 * <pre class="prettyprint">
 * // 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
 * &#64;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.
 * </pre>
 */

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.
     * <p> Here is an example where {@code Builder} is used to define the
     * {@link AudioFocusRequest} for requesting audio focus:
     *
     * <pre class="prettyprint">
     * 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();
     * }
     * </pre>
     *
     * <p>See {@link AudioFocusRequest} for an example of building an instance with this builder.
     * <br>The default values for the instance to be built are:
     * <table>
     * <tr><td>focus listener and handler</td><td>none</td></tr>
     * <tr><td>{@code AudioAttributes}</td><td>attributes with usage set to
     *     {@link AudioAttributes#USAGE_MEDIA}</td></tr>
     * <tr><td>pauses on duck</td><td>false</td></tr>
     * <tr><td>supports delayed focus grant</td><td>false</td></tr>
     * </table>
     */
    public static final class Builder {
        private OnAudioFocusChangeListener mFocusListener;