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

This commit is contained in:
Jean-Michel Trivi
2017-05-01 06:33:01 +00:00
committed by Android (Google) Code Review
4 changed files with 127 additions and 16 deletions

View File

@@ -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);
}

View File

@@ -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);
}

View File

@@ -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);
}

View File

@@ -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. Lets 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 doesnt 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 didnt 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,
* its 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 dont 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