1/*
2 * Copyright (C) 2017 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.media;
18
19import android.annotation.NonNull;
20import android.annotation.Nullable;
21import android.annotation.SystemApi;
22import android.annotation.TestApi;
23import android.media.AudioManager.OnAudioFocusChangeListener;
24import android.os.Bundle;
25import android.os.Handler;
26import android.os.Looper;
27
28/**
29 * A class to encapsulate information about an audio focus request.
30 * An {@code AudioFocusRequest} instance is built by {@link Builder}, and is used to
31 * request and abandon audio focus, respectively
32 * with {@link AudioManager#requestAudioFocus(AudioFocusRequest)} and
33 * {@link AudioManager#abandonAudioFocusRequest(AudioFocusRequest)}.
34 *
35 * <h3>What is audio focus?</h3>
36 * <p>Audio focus is a concept introduced in API 8. It is used to convey the fact that a user can
37 * only focus on a single audio stream at a time, e.g. listening to music or a podcast, but not
38 * both at the same time. In some cases, multiple audio streams can be playing at the same time,
39 * but there is only one the user would really listen to (focus on), while the other plays in
40 * the background. An example of this is driving directions being spoken while music plays at
41 * a reduced volume (a.k.a. ducking).
42 * <p>When an application requests audio focus, it expresses its intention to “own” audio focus to
43 * play audio. Let’s review the different types of focus requests, the return value after a request,
44 * and the responses to a loss.
45 * <p class="note">Note: applications should not play anything until granted focus.</p>
46 *
47 * <h3>The different types of focus requests</h3>
48 * <p>There are four focus request types. A successful focus request with each will yield different
49 * behaviors by the system and the other application that previously held audio focus.
50 * <ul>
51 * <li>{@link AudioManager#AUDIOFOCUS_GAIN} expresses the fact that your application is now the
52 * sole source of audio that the user is listening to. The duration of the audio playback is
53 * unknown, and is possibly very long: after the user finishes interacting with your application,
54 * (s)he doesn’t expect another audio stream to resume. Examples of uses of this focus gain are
55 * for music playback, for a game or a video player.</li>
56 *
57 * <li>{@link AudioManager#AUDIOFOCUS_GAIN_TRANSIENT} is for a situation when you know your
58 * application is temporarily grabbing focus from the current owner, but the user expects playback
59 * to go back to where it was once your application no longer requires audio focus. An example is
60 * for playing an alarm, or during a VoIP call. The playback is known to be finite: the alarm will
61 * time-out or be dismissed, the VoIP call has a beginning and an end. When any of those events
62 * ends, and if the user was listening to music when it started, the user expects music to resume,
63 * but didn’t wish to listen to both at the same time.</li>
64 *
65 * <li>{@link AudioManager#AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK}: this focus request type is similar
66 * to {@code AUDIOFOCUS_GAIN_TRANSIENT} for the temporary aspect of the focus request, but it also
67 * expresses the fact during the time you own focus, you allow another application to keep playing
68 * at a reduced volume, “ducked”. Examples are when playing driving directions or notifications,
69 * it’s ok for music to keep playing, but not loud enough that it would prevent the directions to
70 * be hard to understand. A typical attenuation by the “ducked” application is a factor of 0.2f
71 * (or -14dB), that can for instance be applied with {@code MediaPlayer.setVolume(0.2f)} when
72 * using this class for playback.</li>
73 *
74 * <li>{@link AudioManager#AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE} is also for a temporary request,
75 * but also expresses that your application expects the device to not play anything else. This is
76 * typically used if you are doing audio recording or speech recognition, and don’t want for
77 * examples notifications to be played by the system during that time.</li>
78 * </ul>
79 *
80 * <p>An {@code AudioFocusRequest} instance always contains one of the four types of requests
81 * explained above. It is passed when building an {@code AudioFocusRequest} instance with its
82 * builder in the {@link Builder} constructor
83 * {@link AudioFocusRequest.Builder#AudioFocusRequest.Builder(int)}, or
84 * with {@link AudioFocusRequest.Builder#setFocusGain(int)} after copying an existing instance with
85 * {@link AudioFocusRequest.Builder#AudioFocusRequest.Builder(AudioFocusRequest)}.
86 *
87 * <h3>Qualifying your focus request</h3>
88 * <h4>Use case requiring a focus request</h4>
89 * <p>Any focus request is qualified by the {@link AudioAttributes}
90 * (see {@link Builder#setAudioAttributes(AudioAttributes)}) that describe the audio use case that
91 * will follow the request (once it's successful or granted). It is recommended to use the
92 * same {@code AudioAttributes} for the request as the attributes you are using for audio/media
93 * playback.
94 * <br>If no attributes are set, default attributes of {@link AudioAttributes#USAGE_MEDIA} are used.
95 *
96 * <h4>Delayed focus</h4>
97 * <p>Audio focus can be "locked" by the system for a number of reasons: during a phone call, when
98 * the car to which the device is connected plays an emergency message... To support these
99 * situations, the application can request to be notified when its request is fulfilled, by flagging
100 * its request as accepting delayed focus, with {@link Builder#setAcceptsDelayedFocusGain(boolean)}.
101 * <br>If focus is requested while being locked by the system,
102 * {@link AudioManager#requestAudioFocus(AudioFocusRequest)} will return
103 * {@link AudioManager#AUDIOFOCUS_REQUEST_DELAYED}. When focus isn't locked anymore, the focus
104 * listener set with {@link Builder#setOnAudioFocusChangeListener(OnAudioFocusChangeListener)}
105 * or with {@link Builder#setOnAudioFocusChangeListener(OnAudioFocusChangeListener, Handler)} will
106 * be called to notify the application it now owns audio focus.
107 *
108 * <h4>Pausing vs ducking</h4>
109 * <p>When an application requested audio focus with
110 * {@link AudioManager#AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK}, the system will duck the current focus
111 * owner.
112 * <p class="note">Note: this behavior is <b>new for Android O</b>, whereas applications targeting
113 * SDK level up to API 25 had to implement the ducking themselves when they received a focus
114 * loss of {@link AudioManager#AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK}.
115 * <p>But ducking is not always the behavior expected by the user. A typical example is when the
116 * device plays driving directions while the user is listening to an audio book or podcast, and
117 * expects the audio playback to pause, instead of duck, as it is hard to understand a navigation
118 * prompt and spoken content at the same time. Therefore the system will not automatically duck
119 * when it detects it would be ducking spoken content: such content is detected when the
120 * {@code AudioAttributes} of the player are qualified by
121 * {@link AudioAttributes#CONTENT_TYPE_SPEECH}. Refer for instance to
122 * {@link AudioAttributes.Builder#setContentType(int)} and
123 * {@link MediaPlayer#setAudioAttributes(AudioAttributes)} if you are writing a media playback
124 * application for audio book, podcasts... Since the system will not automatically duck applications
125 * that play speech, it calls their focus listener instead to notify them of
126 * {@link AudioManager#AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK}, so they can pause instead. Note that
127 * this behavior is independent of the use of {@code AudioFocusRequest}, but tied to the use
128 * of {@code AudioAttributes}.
129 * <p>If your application requires pausing instead of ducking for any other reason than playing
130 * speech, you can also declare so with {@link Builder#setWillPauseWhenDucked(boolean)}, which will
131 * cause the system to call your focus listener instead of automatically ducking.
132 *
133 * <h4>Example</h4>
134 * <p>The example below covers the following steps to be found in any application that would play
135 * audio, and use audio focus. Here we play an audio book, and our application is intended to pause
136 * rather than duck when it loses focus. These steps consist in:
137 * <ul>
138 * <li>Creating {@code AudioAttributes} to be used for the playback and the focus request.</li>
139 * <li>Configuring and creating the {@code AudioFocusRequest} instance that defines the intended
140 *     focus behaviors.</li>
141 * <li>Requesting audio focus and checking the return code to see if playback can happen right
142 *     away, or is delayed.</li>
143 * <li>Implementing a focus change listener to respond to focus gains and losses.</li>
144 * </ul>
145 * <p>
146 * <pre class="prettyprint">
147 * // initialization of the audio attributes and focus request
148 * mAudioManager = (AudioManager) Context.getSystemService(Context.AUDIO_SERVICE);
149 * mPlaybackAttributes = new AudioAttributes.Builder()
150 *         .setUsage(AudioAttributes.USAGE_MEDIA)
151 *         .setContentType(AudioAttributes.CONTENT_TYPE_SPEECH)
152 *         .build();
153 * mFocusRequest = new AudioFocusRequest.Builder(AudioManager.AUDIOFOCUS_GAIN)
154 *         .setAudioAttributes(mPlaybackAttributes)
155 *         .setAcceptsDelayedFocusGain(true)
156 *         .setWillPauseWhenDucked(true)
157 *         .setOnAudioFocusChangeListener(this, mMyHandler)
158 *         .build();
159 * mMediaPlayer = new MediaPlayer();
160 * mMediaPlayer.setAudioAttributes(mPlaybackAttributes);
161 * final Object mFocusLock = new Object();
162 *
163 * boolean mPlaybackDelayed = false;
164 *
165 * // requesting audio focus
166 * int res = mAudioManager.requestAudioFocus(mFocusRequest);
167 * synchronized (mFocusLock) {
168 *     if (res == AudioManager.AUDIOFOCUS_REQUEST_FAILED) {
169 *         mPlaybackDelayed = false;
170 *     } else if (res == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
171 *         mPlaybackDelayed = false;
172 *         playbackNow();
173 *     } else if (res == AudioManager.AUDIOFOCUS_REQUEST_DELAYED) {
174 *        mPlaybackDelayed = true;
175 *     }
176 * }
177 *
178 * // implementation of the OnAudioFocusChangeListener
179 * &#64;Override
180 * public void onAudioFocusChange(int focusChange) {
181 *     switch (focusChange) {
182 *         case AudioManager.AUDIOFOCUS_GAIN:
183 *             if (mPlaybackDelayed || mResumeOnFocusGain) {
184 *                 synchronized (mFocusLock) {
185 *                     mPlaybackDelayed = false;
186 *                     mResumeOnFocusGain = false;
187 *                 }
188 *                 playbackNow();
189 *             }
190 *             break;
191 *         case AudioManager.AUDIOFOCUS_LOSS:
192 *             synchronized (mFocusLock) {
193 *                 // this is not a transient loss, we shouldn't automatically resume for now
194 *                 mResumeOnFocusGain = false;
195 *                 mPlaybackDelayed = false;
196 *             }
197 *             pausePlayback();
198 *             break;
199 *         case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
200 *         case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:
201 *             // we handle all transient losses the same way because we never duck audio books
202 *             synchronized (mFocusLock) {
203 *                 // we should only resume if playback was interrupted
204 *                 mResumeOnFocusGain = mMediaPlayer.isPlaying();
205 *                 mPlaybackDelayed = false;
206 *             }
207 *             pausePlayback();
208 *             break;
209 *     }
210 * }
211 *
212 * // Important:
213 * // Also set "mResumeOnFocusGain" to false when the user pauses or stops playback: this way your
214 * // application doesn't automatically restart when it gains focus, even though the user had
215 * // stopped it.
216 * </pre>
217 */
218
219public final class AudioFocusRequest {
220
221    // default attributes for the request when not specified
222    private final static AudioAttributes FOCUS_DEFAULT_ATTR = new AudioAttributes.Builder()
223            .setUsage(AudioAttributes.USAGE_MEDIA).build();
224
225    /** @hide */
226    public static final String KEY_ACCESSIBILITY_FORCE_FOCUS_DUCKING = "a11y_force_ducking";
227
228    private final OnAudioFocusChangeListener mFocusListener; // may be null
229    private final Handler mListenerHandler;                  // may be null
230    private final AudioAttributes mAttr;                     // never null
231    private final int mFocusGain;
232    private final int mFlags;
233
234    private AudioFocusRequest(OnAudioFocusChangeListener listener, Handler handler,
235            AudioAttributes attr, int focusGain, int flags) {
236        mFocusListener = listener;
237        mListenerHandler = handler;
238        mFocusGain = focusGain;
239        mAttr = attr;
240        mFlags = flags;
241    }
242
243    /**
244     * @hide
245     * Checks whether a focus gain constant is a valid value for an audio focus request.
246     * @param focusGain value to check
247     * @return true if focusGain is a valid value for an audio focus request.
248     */
249    final static boolean isValidFocusGain(int focusGain) {
250        switch (focusGain) {
251            case AudioManager.AUDIOFOCUS_GAIN:
252            case AudioManager.AUDIOFOCUS_GAIN_TRANSIENT:
253            case AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK:
254            case AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE:
255                return true;
256            default:
257                return false;
258        }
259    }
260
261    /**
262     * @hide
263     * Returns the focus change listener set for this {@code AudioFocusRequest}.
264     * @return null if no {@link AudioManager.OnAudioFocusChangeListener} was set.
265     */
266    @TestApi
267    public @Nullable OnAudioFocusChangeListener getOnAudioFocusChangeListener() {
268        return mFocusListener;
269    }
270
271    /**
272     * @hide
273     * Returns the {@link Handler} to be used for the focus change listener.
274     * @return the same {@code Handler} set in.
275     *   {@link Builder#setOnAudioFocusChangeListener(OnAudioFocusChangeListener, Handler)}, or null
276     *   if no listener was set.
277     */
278    public @Nullable Handler getOnAudioFocusChangeListenerHandler() {
279        return mListenerHandler;
280    }
281
282    /**
283     * Returns the {@link AudioAttributes} set for this {@code AudioFocusRequest}, or the default
284     * attributes if none were set.
285     * @return non-null {@link AudioAttributes}.
286     */
287    public @NonNull AudioAttributes getAudioAttributes() {
288        return mAttr;
289    }
290
291    /**
292     * Returns the type of audio focus request configured for this {@code AudioFocusRequest}.
293     * @return one of {@link AudioManager#AUDIOFOCUS_GAIN},
294     * {@link AudioManager#AUDIOFOCUS_GAIN_TRANSIENT},
295     * {@link AudioManager#AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK}, and
296     * {@link AudioManager#AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE}.
297     */
298    public int getFocusGain() {
299        return mFocusGain;
300    }
301
302    /**
303     * Returns whether the application that would use this {@code AudioFocusRequest} would pause
304     * when it is requested to duck.
305     * @return the duck/pause behavior.
306     */
307    public boolean willPauseWhenDucked() {
308        return (mFlags & AudioManager.AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS)
309                == AudioManager.AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS;
310    }
311
312    /**
313     * Returns whether the application that would use this {@code AudioFocusRequest} supports
314     * a focus gain granted after a temporary request failure.
315     * @return whether delayed focus gain is supported.
316     */
317    public boolean acceptsDelayedFocusGain() {
318        return (mFlags & AudioManager.AUDIOFOCUS_FLAG_DELAY_OK)
319                == AudioManager.AUDIOFOCUS_FLAG_DELAY_OK;
320    }
321
322    /**
323     * @hide
324     * Returns whether audio focus will be locked (i.e. focus cannot change) as a result of this
325     * focus request being successful.
326     * @return whether this request will lock focus.
327     */
328    @SystemApi
329    public boolean locksFocus() {
330        return (mFlags & AudioManager.AUDIOFOCUS_FLAG_LOCK)
331                == AudioManager.AUDIOFOCUS_FLAG_LOCK;
332    }
333
334    int getFlags() {
335        return mFlags;
336    }
337
338    /**
339     * Builder class for {@link AudioFocusRequest} objects.
340     * <p>See {@link AudioFocusRequest} for an example of building an instance with this builder.
341     * <br>The default values for the instance to be built are:
342     * <table>
343     * <tr><td>focus listener and handler</td><td>none</td></tr>
344     * <tr><td>{@code AudioAttributes}</td><td>attributes with usage set to
345     *     {@link AudioAttributes#USAGE_MEDIA}</td></tr>
346     * <tr><td>pauses on duck</td><td>false</td></tr>
347     * <tr><td>supports delayed focus grant</td><td>false</td></tr>
348     * </table>
349     */
350    public static final class Builder {
351        private OnAudioFocusChangeListener mFocusListener;
352        private Handler mListenerHandler;
353        private AudioAttributes mAttr = FOCUS_DEFAULT_ATTR;
354        private int mFocusGain;
355        private boolean mPausesOnDuck = false;
356        private boolean mDelayedFocus = false;
357        private boolean mFocusLocked = false;
358        private boolean mA11yForceDucking = false;
359
360        /**
361         * Constructs a new {@code Builder}, and specifies how audio focus
362         * will be requested. Valid values for focus requests are
363         * {@link AudioManager#AUDIOFOCUS_GAIN}, {@link AudioManager#AUDIOFOCUS_GAIN_TRANSIENT},
364         * {@link AudioManager#AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK}, and
365         * {@link AudioManager#AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE}.
366         * <p>By default there is no focus change listener, delayed focus is not supported, ducking
367         * is suitable for the application, and the <code>AudioAttributes</code>
368         * have a usage of {@link AudioAttributes#USAGE_MEDIA}.
369         * @param focusGain the type of audio focus gain that will be requested
370         * @throws IllegalArgumentException thrown when an invalid focus gain type is used
371         */
372        public Builder(int focusGain) {
373            setFocusGain(focusGain);
374        }
375
376        /**
377         * Constructs a new {@code Builder} with all the properties of the {@code AudioFocusRequest}
378         * passed as parameter.
379         * Use this method when you want a new request to differ only by some properties.
380         * @param requestToCopy the non-null {@code AudioFocusRequest} to build a duplicate from.
381         * @throws IllegalArgumentException thrown when a null {@code AudioFocusRequest} is used.
382         */
383        public Builder(@NonNull AudioFocusRequest requestToCopy) {
384            if (requestToCopy == null) {
385                throw new IllegalArgumentException("Illegal null AudioFocusRequest");
386            }
387            mAttr = requestToCopy.mAttr;
388            mFocusListener = requestToCopy.mFocusListener;
389            mListenerHandler = requestToCopy.mListenerHandler;
390            mFocusGain = requestToCopy.mFocusGain;
391            mPausesOnDuck = requestToCopy.willPauseWhenDucked();
392            mDelayedFocus = requestToCopy.acceptsDelayedFocusGain();
393        }
394
395        /**
396         * Sets the type of focus gain that will be requested.
397         * Use this method to replace the focus gain when building a request by modifying an
398         * existing {@code AudioFocusRequest} instance.
399         * @param focusGain the type of audio focus gain that will be requested.
400         * @return this {@code Builder} instance
401         * @throws IllegalArgumentException thrown when an invalid focus gain type is used
402         */
403        public @NonNull Builder setFocusGain(int focusGain) {
404            if (!isValidFocusGain(focusGain)) {
405                throw new IllegalArgumentException("Illegal audio focus gain type " + focusGain);
406            }
407            mFocusGain = focusGain;
408            return this;
409        }
410
411        /**
412         * Sets the listener called when audio focus changes after being requested with
413         *   {@link AudioManager#requestAudioFocus(AudioFocusRequest)}, and until being abandoned
414         *   with {@link AudioManager#abandonAudioFocusRequest(AudioFocusRequest)}.
415         *   Note that only focus changes (gains and losses) affecting the focus owner are reported,
416         *   not gains and losses of other focus requesters in the system.<br>
417         *   Notifications are delivered on the {@link Looper} associated with the one of
418         *   the creation of the {@link AudioManager} used to request focus
419         *   (see {@link AudioManager#requestAudioFocus(AudioFocusRequest)}).
420         * @param listener the listener receiving the focus change notifications.
421         * @return this {@code Builder} instance.
422         * @throws NullPointerException thrown when a null focus listener is used.
423         */
424        public @NonNull Builder setOnAudioFocusChangeListener(
425                @NonNull OnAudioFocusChangeListener listener) {
426            if (listener == null) {
427                throw new NullPointerException("Illegal null focus listener");
428            }
429            mFocusListener = listener;
430            mListenerHandler = null;
431            return this;
432        }
433
434        /**
435         * @hide
436         * Internal listener setter, no null checks on listener nor handler
437         * @param listener
438         * @param handler
439         * @return this {@code Builder} instance.
440         */
441        @NonNull Builder setOnAudioFocusChangeListenerInt(
442                OnAudioFocusChangeListener listener, Handler handler) {
443            mFocusListener = listener;
444            mListenerHandler = handler;
445            return this;
446        }
447
448        /**
449         * Sets the listener called when audio focus changes after being requested with
450         *   {@link AudioManager#requestAudioFocus(AudioFocusRequest)}, and until being abandoned
451         *   with {@link AudioManager#abandonAudioFocusRequest(AudioFocusRequest)}.
452         *   Note that only focus changes (gains and losses) affecting the focus owner are reported,
453         *   not gains and losses of other focus requesters in the system.
454         * @param listener the listener receiving the focus change notifications.
455         * @param handler the {@link Handler} for the thread on which to execute
456         *   the notifications.
457         * @return this {@code Builder} instance.
458         * @throws NullPointerException thrown when a null focus listener or handler is used.
459         */
460        public @NonNull Builder setOnAudioFocusChangeListener(
461                @NonNull OnAudioFocusChangeListener listener, @NonNull Handler handler) {
462            if (listener == null || handler == null) {
463                throw new NullPointerException("Illegal null focus listener or handler");
464            }
465            mFocusListener = listener;
466            mListenerHandler = handler;
467            return this;
468        }
469
470        /**
471         * Sets the {@link AudioAttributes} to be associated with the focus request, and which
472         * describe the use case for which focus is requested.
473         * As the focus requests typically precede audio playback, this information is used on
474         * certain platforms to declare the subsequent playback use case. It is therefore good
475         * practice to use in this method the same {@code AudioAttributes} as used for
476         * playback, see for example {@link MediaPlayer#setAudioAttributes(AudioAttributes)} in
477         * {@code MediaPlayer} or {@link AudioTrack.Builder#setAudioAttributes(AudioAttributes)}
478         * in {@code AudioTrack}.
479         * @param attributes the {@link AudioAttributes} for the focus request.
480         * @return this {@code Builder} instance.
481         * @throws NullPointerException thrown when using null for the attributes.
482         */
483        public @NonNull Builder setAudioAttributes(@NonNull AudioAttributes attributes) {
484            if (attributes == null) {
485                throw new NullPointerException("Illegal null AudioAttributes");
486            }
487            mAttr = attributes;
488            return this;
489        }
490
491        /**
492         * Declare the intended behavior of the application with regards to audio ducking.
493         * See more details in the {@link AudioFocusRequest} class documentation.
494         * @param pauseOnDuck use {@code true} if the application intends to pause audio playback
495         *    when losing focus with {@link AudioManager#AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK}.
496         *    If {@code true}, note that you must also set a focus listener to receive such an
497         *    event, with
498         *    {@link #setOnAudioFocusChangeListener(OnAudioFocusChangeListener, Handler)}.
499         * @return this {@code Builder} instance.
500         */
501        public @NonNull Builder setWillPauseWhenDucked(boolean pauseOnDuck) {
502            mPausesOnDuck = pauseOnDuck;
503            return this;
504        }
505
506        /**
507         * Marks this focus request as compatible with delayed focus.
508         * See more details about delayed focus in the {@link AudioFocusRequest} class
509         * documentation.
510         * @param acceptsDelayedFocusGain use {@code true} if the application supports delayed
511         *    focus. If {@code true}, note that you must also set a focus listener to be notified
512         *    of delayed focus gain, with
513         *    {@link #setOnAudioFocusChangeListener(OnAudioFocusChangeListener, Handler)}.
514         * @return this {@code Builder} instance
515         */
516        public @NonNull Builder setAcceptsDelayedFocusGain(boolean acceptsDelayedFocusGain) {
517            mDelayedFocus = acceptsDelayedFocusGain;
518            return this;
519        }
520
521        /**
522         * @hide
523         * Marks this focus request as locking audio focus so granting is temporarily disabled.
524         * This feature can only be used by owners of a registered
525         * {@link android.media.audiopolicy.AudioPolicy} in
526         * {@link AudioManager#requestAudioFocus(AudioFocusRequest, android.media.audiopolicy.AudioPolicy)}.
527         * Setting to false is the same as the default behavior.
528         * @param focusLocked true when locking focus
529         * @return this {@code Builder} instance
530         */
531        @SystemApi
532        public @NonNull Builder setLocksFocus(boolean focusLocked) {
533            mFocusLocked = focusLocked;
534            return this;
535        }
536
537        /**
538         * Marks this focus request as forcing ducking, regardless of the conditions in which
539         * the system would or would not enforce ducking.
540         * Forcing ducking will only be honored when requesting AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK
541         * with an {@link AudioAttributes} usage of
542         * {@link AudioAttributes#USAGE_ASSISTANCE_ACCESSIBILITY}, coming from an accessibility
543         * service, and will be ignored otherwise.
544         * @param forceDucking {@code true} to force ducking
545         * @return this {@code Builder} instance
546         */
547        public @NonNull Builder setForceDucking(boolean forceDucking) {
548            mA11yForceDucking = forceDucking;
549            return this;
550        }
551
552        /**
553         * Builds a new {@code AudioFocusRequest} instance combining all the information gathered
554         * by this {@code Builder}'s configuration methods.
555         * @return the {@code AudioFocusRequest} instance qualified by all the properties set
556         *   on this {@code Builder}.
557         * @throws IllegalStateException thrown when attempting to build a focus request that is set
558         *    to accept delayed focus, or to pause on duck, but no focus change listener was set.
559         */
560        public AudioFocusRequest build() {
561            if ((mDelayedFocus || mPausesOnDuck) && (mFocusListener == null)) {
562                throw new IllegalStateException(
563                        "Can't use delayed focus or pause on duck without a listener");
564            }
565            if (mA11yForceDucking) {
566                final Bundle extraInfo;
567                if (mAttr.getBundle() == null) {
568                    extraInfo = new Bundle();
569                } else {
570                    extraInfo = mAttr.getBundle();
571                }
572                // checking of usage and focus request is done server side
573                extraInfo.putBoolean(KEY_ACCESSIBILITY_FORCE_FOCUS_DUCKING, true);
574                mAttr = new AudioAttributes.Builder(mAttr).addBundle(extraInfo).build();
575            }
576            final int flags = 0
577                    | (mDelayedFocus ? AudioManager.AUDIOFOCUS_FLAG_DELAY_OK : 0)
578                    | (mPausesOnDuck ? AudioManager.AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS : 0)
579                    | (mFocusLocked  ? AudioManager.AUDIOFOCUS_FLAG_LOCK : 0);
580            return new AudioFocusRequest(mFocusListener, mListenerHandler,
581                    mAttr, mFocusGain, flags);
582        }
583    }
584}
585