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

Commit 5642a655 authored by Jean-Michel Trivi's avatar Jean-Michel Trivi Committed by android-build-merger
Browse files

Merge "AudioFocusRequest: more docs, listener without handler" into oc-dev

am: 128f8aa8

Change-Id: If1ef13a45277b91589b292d8e88af539ee720d03
parents 0e2ddda9 128f8aa8
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -21004,6 +21004,7 @@ package android.media {
    method public android.media.AudioFocusRequest.Builder setAcceptsDelayedFocusGain(boolean);
    method public android.media.AudioFocusRequest.Builder setAudioAttributes(android.media.AudioAttributes);
    method public android.media.AudioFocusRequest.Builder setFocusGain(int);
    method public android.media.AudioFocusRequest.Builder setOnAudioFocusChangeListener(android.media.AudioManager.OnAudioFocusChangeListener);
    method public android.media.AudioFocusRequest.Builder setOnAudioFocusChangeListener(android.media.AudioManager.OnAudioFocusChangeListener, android.os.Handler);
    method public android.media.AudioFocusRequest.Builder setWillPauseWhenDucked(boolean);
  }
+1 −0
Original line number Diff line number Diff line
@@ -22814,6 +22814,7 @@ package android.media {
    method public android.media.AudioFocusRequest.Builder setAudioAttributes(android.media.AudioAttributes);
    method public android.media.AudioFocusRequest.Builder setFocusGain(int);
    method public android.media.AudioFocusRequest.Builder setLocksFocus(boolean);
    method public android.media.AudioFocusRequest.Builder setOnAudioFocusChangeListener(android.media.AudioManager.OnAudioFocusChangeListener);
    method public android.media.AudioFocusRequest.Builder setOnAudioFocusChangeListener(android.media.AudioManager.OnAudioFocusChangeListener, android.os.Handler);
    method public android.media.AudioFocusRequest.Builder setWillPauseWhenDucked(boolean);
  }
+1 −0
Original line number Diff line number Diff line
@@ -21112,6 +21112,7 @@ package android.media {
    method public android.media.AudioFocusRequest.Builder setAcceptsDelayedFocusGain(boolean);
    method public android.media.AudioFocusRequest.Builder setAudioAttributes(android.media.AudioAttributes);
    method public android.media.AudioFocusRequest.Builder setFocusGain(int);
    method public android.media.AudioFocusRequest.Builder setOnAudioFocusChangeListener(android.media.AudioManager.OnAudioFocusChangeListener);
    method public android.media.AudioFocusRequest.Builder setOnAudioFocusChangeListener(android.media.AudioManager.OnAudioFocusChangeListener, android.os.Handler);
    method public android.media.AudioFocusRequest.Builder setWillPauseWhenDucked(boolean);
  }
+124 −16
Original line number Diff line number Diff line
@@ -29,14 +29,104 @@ import android.os.Looper;
 * request and abandon audio focus, respectively
 * with {@link AudioManager#requestAudioFocus(AudioFocusRequest)} and
 * {@link AudioManager#abandonAudioFocusRequest(AudioFocusRequest)}.
 * <p>In the context of describing audio focus, the term "ducking" is used. It describes a temporary
 * lowering of the audio level of an application in response to another application playing audio
 * concurrently. An example is during the playback of driving directions,
 * a user listening to music expects the music to "duck" during the playback of the message
 * announcing directions.
 *
 * <h3>What is audio focus?</h3>
 * <p>Audio focus is a concept introduced in API 8. It is used to convey the fact that a user can
 * only focus on a single audio stream at a time, e.g. listening to music or a podcast, but not
 * both at the same time. In some cases, multiple audio streams can be playing at the same time,
 * but there is only one the user would really listen to (focus on), while the other plays in
 * the background. An example of this is driving directions being spoken while music plays at
 * a reduced volume (a.k.a. ducking).
 * <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.
 *
 * <h3>The different types of focus requests</h3>
 * <p>There are four focus request types. A successful focus request with each will yield different
 * behaviors by the system and the other application that previously held audio focus.
 * <ul>
 * <li>{@link AudioManager#AUDIOFOCUS_GAIN} expresses the fact that your application is now the
 * sole source of audio that the user is listening to. The duration of the audio playback is
 * unknown, and is possibly very long: after the user finishes interacting with your application,
 * (s)he doesn’t expect another audio stream to resume. Examples of uses of this focus gain are
 * for music playback, for a game or a video player.</li>
 *
 * <li>{@link AudioManager#AUDIOFOCUS_GAIN_TRANSIENT} is for a situation when you know your
 * application is temporarily grabbing focus from the current owner, but the user expects playback
 * to go back to where it was once your application no longer requires audio focus. An example is
 * for playing an alarm, or during a VoIP call. The playback is known to be finite: the alarm will
 * time-out or be dismissed, the VoIP call has a beginning and an end. When any of those events
 * ends, and if the user was listening to music when it started, the user expects music to resume,
 * but didn’t wish to listen to both at the same time.</li>
 *
 * <li>{@link AudioManager#AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK}: this focus request type is similar
 * to {@code AUDIOFOCUS_GAIN_TRANSIENT} for the temporary aspect of the focus request, but it also
 * expresses the fact during the time you own focus, you allow another application to keep playing
 * at a reduced volume, “ducked”. Examples are when playing driving directions or notifications,
 * it’s ok for music to keep playing, but not loud enough that it would prevent the directions to
 * be hard to understand. A typical attenuation by the “ducked” application is a factor of 0.2f
 * (or -14dB), that can for instance be applied with {@code MediaPlayer.setVolume(0.2f)} when
 * using this class for playback.</li>
 *
 * <li>{@link AudioManager#AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE} is also for a temporary request,
 * but also expresses that your application expects the device to not play anything else. This is
 * typically used if you are doing audio recording or speech recognition, and don’t want for
 * examples notifications to be played by the system during that time.</li>
 * </ul>
 *
 * <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)}.
 *
 * <h3>Qualifying your focus request</h3>
 * <h4>Use case requiring a focus request</h4>
 * <p>Any focus request is qualified by the {@link AudioAttributes}
 * (see {@link Builder#setAudioAttributes(AudioAttributes)}) that describe the audio use case that
 * will follow the request (once it's successful or granted). It is recommended to use the
 * same {@code AudioAttributes} for the request as the attributes you are using for audio/media
 * playback.
 * <br>If no attributes are set, default attributes of {@link AudioAttributes#USAGE_MEDIA} are used.
 *
 * <h4>Delayed focus</h4>
 * <p>Audio focus can be "locked" by the system for a number of reasons: during a phone call, when
 * the car to which the device is connected plays an emergency message... To support these
 * situations, the application can request to be notified when its request is fulfilled, by flagging
 * its request as accepting delayed focus, with {@link Builder#setAcceptsDelayedFocusGain(boolean)}.
 * <br>If focus is requested while being locked by the system,
 * {@link AudioManager#requestAudioFocus(AudioFocusRequest)} will return
 * {@link AudioManager#AUDIOFOCUS_REQUEST_DELAYED}. When focus isn't locked anymore, the focus
 * listener set with {@link Builder#setOnAudioFocusChangeListener(OnAudioFocusChangeListener)}
 * or with {@link Builder#setOnAudioFocusChangeListener(OnAudioFocusChangeListener, Handler)} will
 * be called to notify the application it now owns audio focus.
 *
 * <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
 * 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
 * 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
 * when it detects it would be ducking spoken content: such content is detected when the
 * {@code AudioAttributes} of the player are qualified by
 * {@link AudioAttributes#CONTENT_TYPE_SPEECH}. Refer for instance to
 * {@link AudioAttributes.Builder#setContentType(int)} and
 * {@link MediaPlayer#setAudioAttributes(AudioAttributes)} if you are writing a media playback
 * application for audio book, podcasts... Since the system will not automatically duck applications
 * that play speech, it calls their focus listener instead to notify them of
 * {@link AudioManager#AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK}, so they can pause instead. Note that
 * this behavior is independent of the use of {@code AudioFocusRequest}, but tied to the use
 * of {@code AudioAttributes}.
 * <p>If your application requires pausing instead of ducking for any other reason than playing
 * 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.
 *
 */
// TODO use this class to provide more documentation about audio focus and the new behaviors
//      describe up to N, and after.
public final class AudioFocusRequest {

    // default attributes for the request when not specified
@@ -245,6 +335,27 @@ public final class AudioFocusRequest {
            return this;
        }

        /**
         * Sets the listener called when audio focus changes after being requested with
         *   {@link AudioManager#requestAudioFocus(AudioFocusRequest)}, and until being abandoned
         *   with {@link AudioManager#abandonAudioFocusRequest(AudioFocusRequest)}.
         *   Note that only focus changes (gains and losses) affecting the focus owner are reported,
         *   not gains and losses of other focus requesters in the system.<br>
         *   Notifications are delivered on the main {@link Looper}.
         * @param listener the listener receiving the focus change notifications.
         * @return this {@code Builder} instance.
         * @throws NullPointerException thrown when a null focus listener is used.
         */
        public @NonNull Builder setOnAudioFocusChangeListener(
                @NonNull OnAudioFocusChangeListener listener) {
            if (listener == null) {
                throw new NullPointerException("Illegal null focus listener");
            }
            mFocusListener = listener;
            mListenerHandler = null;
            return this;
        }

        /**
         * Sets the listener called when audio focus changes after being requested with
         *   {@link AudioManager#requestAudioFocus(AudioFocusRequest)}, and until being abandoned
@@ -253,17 +364,14 @@ public final class AudioFocusRequest {
         *   not gains and losses of other focus requesters in the system.
         * @param listener the listener receiving the focus change notifications.
         * @param handler the {@link Handler} for the thread on which to execute
         *   the notifications. If {@code null}, the {@code Handler} associated with the main
         *   {@link Looper} will be used.
         *   the notifications.
         * @return this {@code Builder} instance.
         * @throws IllegalArgumentException thrown when a non-null handler is used with a null
         *   listener.
         * @throws NullPointerException thrown when a null focus listener or handler is used.
         */
        public @NonNull Builder setOnAudioFocusChangeListener(
                @Nullable OnAudioFocusChangeListener listener, @Nullable Handler handler) {
            if (listener == null && handler != null) {
                throw new IllegalArgumentException(
                        "Illegal non-null handler without a focus listener");
                @NonNull OnAudioFocusChangeListener listener, @NonNull Handler handler) {
            if (listener == null || handler == null) {
                throw new NullPointerException("Illegal null focus listener or handler");
            }
            mFocusListener = listener;
            mListenerHandler = handler;
@@ -272,7 +380,7 @@ public final class AudioFocusRequest {

        /**
         * Sets the {@link AudioAttributes} to be associated with the focus request, and which
         * describe the use case describing why focus is requested.
         * describe the use case for which focus is requested.
         * As the focus requests typically precede audio playback, this information is used on
         * certain platforms to declare the subsequent playback use case. It is therefore good
         * practice to use in this method the same {@code AudioAttributes} as used for