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