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 17 package android.media; 18 19 import android.annotation.NonNull; 20 import android.annotation.Nullable; 21 import android.annotation.SystemApi; 22 import android.annotation.TestApi; 23 import android.media.AudioManager.OnAudioFocusChangeListener; 24 import android.os.Bundle; 25 import android.os.Handler; 26 import 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#Builder(int)}, or 84 * with {@link AudioFocusRequest.Builder#setFocusGain(int)} after copying an existing instance with 85 * {@link AudioFocusRequest.Builder#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 * @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 219 public 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 @Nullable OnAudioFocusChangeListener mFocusListener; 229 private final @Nullable Handler mListenerHandler; 230 private final @NonNull AudioAttributes mAttr; 231 private final int mFocusGain; 232 private final int mFlags; 233 AudioFocusRequest(OnAudioFocusChangeListener listener, Handler handler, AudioAttributes attr, int focusGain, int flags)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 */ isValidFocusGain(int focusGain)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 getOnAudioFocusChangeListener()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 */ getOnAudioFocusChangeListenerHandler()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 */ getAudioAttributes()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 */ getFocusGain()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 */ willPauseWhenDucked()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 */ acceptsDelayedFocusGain()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 locksFocus()329 public boolean locksFocus() { 330 return (mFlags & AudioManager.AUDIOFOCUS_FLAG_LOCK) 331 == AudioManager.AUDIOFOCUS_FLAG_LOCK; 332 } 333 getFlags()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 */ Builder(int focusGain)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 */ Builder(@onNull AudioFocusRequest requestToCopy)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 */ setFocusGain(int focusGain)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 */ setOnAudioFocusChangeListener( @onNull OnAudioFocusChangeListener listener)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 */ setOnAudioFocusChangeListenerInt( OnAudioFocusChangeListener listener, Handler handler)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 */ setOnAudioFocusChangeListener( @onNull OnAudioFocusChangeListener listener, @NonNull Handler handler)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 */ setAudioAttributes(@onNull AudioAttributes attributes)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 */ setWillPauseWhenDucked(boolean pauseOnDuck)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 */ setAcceptsDelayedFocusGain(boolean acceptsDelayedFocusGain)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 setLocksFocus(boolean focusLocked)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 */ setForceDucking(boolean forceDucking)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 */ build()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