1 /* 2 * Copyright (C) 2013 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 com.android.server.audio; 18 19 import android.annotation.NonNull; 20 import android.annotation.Nullable; 21 import android.content.pm.UserProperties; 22 import android.media.AudioAttributes; 23 import android.media.AudioFocusInfo; 24 import android.media.AudioManager; 25 import android.media.IAudioFocusDispatcher; 26 import android.os.IBinder; 27 import android.os.UserHandle; 28 import android.util.Log; 29 30 import com.android.internal.annotations.GuardedBy; 31 import com.android.server.LocalServices; 32 import com.android.server.audio.MediaFocusControl.AudioFocusDeathHandler; 33 import com.android.server.pm.UserManagerInternal; 34 35 import java.io.PrintWriter; 36 import java.util.List; 37 38 /** 39 * @hide 40 * Class to handle all the information about a user of audio focus. The lifecycle of each 41 * instance is managed by android.media.MediaFocusControl, from its addition to the audio focus 42 * stack, or the map of focus owners for an external focus policy, to its release. 43 */ 44 public class FocusRequester { 45 46 // on purpose not using this classe's name, as it will only be used from MediaFocusControl 47 private static final String TAG = "FocusRequester"; 48 private static final boolean DEBUG = false; 49 50 private AudioFocusDeathHandler mDeathHandler; // may be null 51 private IAudioFocusDispatcher mFocusDispatcher; // may be null 52 private final IBinder mSourceRef; // may be null 53 private final @NonNull String mClientId; 54 private final @NonNull String mPackageName; 55 private final int mCallingUid; 56 private final MediaFocusControl mFocusController; // never null 57 private final int mSdkTarget; 58 59 /** 60 * the audio focus gain request that caused the addition of this object in the focus stack. 61 */ 62 private final int mFocusGainRequest; 63 /** 64 * the flags associated with the gain request that qualify the type of grant (e.g. accepting 65 * delay vs grant must be immediate) 66 */ 67 private final int mGrantFlags; 68 /** 69 * the audio focus loss received my mFocusDispatcher, is AudioManager.AUDIOFOCUS_NONE if 70 * it never lost focus. 71 */ 72 private int mFocusLossReceived; 73 /** 74 * whether this focus owner listener was notified when it lost focus 75 */ 76 private boolean mFocusLossWasNotified; 77 /** 78 * whether this focus owner has already lost focus, but is being faded out until focus loss 79 * dispatch occurs. It's in "limbo" mode: has lost focus but not released yet until notified 80 */ 81 boolean mFocusLossFadeLimbo; 82 /** 83 * the audio attributes associated with the focus request 84 */ 85 private final @NonNull AudioAttributes mAttributes; 86 87 /** 88 * Class constructor 89 * @param aa 90 * @param focusRequest 91 * @param grantFlags 92 * @param afl 93 * @param source 94 * @param id 95 * @param hdlr 96 * @param pn 97 * @param uid 98 * @param ctlr cannot be null 99 */ FocusRequester(@onNull AudioAttributes aa, int focusRequest, int grantFlags, IAudioFocusDispatcher afl, IBinder source, @NonNull String id, AudioFocusDeathHandler hdlr, @NonNull String pn, int uid, @NonNull MediaFocusControl ctlr, int sdk)100 FocusRequester(@NonNull AudioAttributes aa, int focusRequest, int grantFlags, 101 IAudioFocusDispatcher afl, IBinder source, @NonNull String id, 102 AudioFocusDeathHandler hdlr, @NonNull String pn, int uid, 103 @NonNull MediaFocusControl ctlr, int sdk) { 104 mAttributes = aa; 105 mFocusDispatcher = afl; 106 mSourceRef = source; 107 mClientId = id; 108 mDeathHandler = hdlr; 109 mPackageName = pn; 110 mCallingUid = uid; 111 mFocusGainRequest = focusRequest; 112 mGrantFlags = grantFlags; 113 mFocusLossReceived = AudioManager.AUDIOFOCUS_NONE; 114 mFocusLossWasNotified = true; 115 mFocusLossFadeLimbo = false; 116 mFocusController = ctlr; 117 mSdkTarget = sdk; 118 } 119 FocusRequester(AudioFocusInfo afi, IAudioFocusDispatcher afl, IBinder source, AudioFocusDeathHandler hdlr, @NonNull MediaFocusControl ctlr)120 FocusRequester(AudioFocusInfo afi, IAudioFocusDispatcher afl, 121 IBinder source, AudioFocusDeathHandler hdlr, @NonNull MediaFocusControl ctlr) { 122 mAttributes = afi.getAttributes(); 123 mClientId = afi.getClientId(); 124 mPackageName = afi.getPackageName(); 125 mCallingUid = afi.getClientUid(); 126 mFocusGainRequest = afi.getGainRequest(); 127 mFocusLossReceived = AudioManager.AUDIOFOCUS_NONE; 128 mFocusLossWasNotified = true; 129 mFocusLossFadeLimbo = false; 130 mGrantFlags = afi.getFlags(); 131 mSdkTarget = afi.getSdkTarget(); 132 133 mFocusDispatcher = afl; 134 mSourceRef = source; 135 mDeathHandler = hdlr; 136 mFocusController = ctlr; 137 } 138 hasSameClient(String otherClient)139 boolean hasSameClient(String otherClient) { 140 return mClientId.compareTo(otherClient) == 0; 141 } 142 isLockedFocusOwner()143 boolean isLockedFocusOwner() { 144 return ((mGrantFlags & AudioManager.AUDIOFOCUS_FLAG_LOCK) != 0); 145 } 146 147 /** 148 * @return true if the focus requester is scheduled to receive a focus loss 149 */ isInFocusLossLimbo()150 boolean isInFocusLossLimbo() { 151 return mFocusLossFadeLimbo; 152 } 153 hasSameBinder(IBinder ib)154 boolean hasSameBinder(IBinder ib) { 155 return (mSourceRef != null) && mSourceRef.equals(ib); 156 } 157 hasSameDispatcher(IAudioFocusDispatcher fd)158 boolean hasSameDispatcher(IAudioFocusDispatcher fd) { 159 return (mFocusDispatcher != null) && mFocusDispatcher.equals(fd); 160 } 161 getPackageName()162 @NonNull String getPackageName() { 163 return mPackageName; 164 } 165 hasSamePackage(@onNull String pack)166 boolean hasSamePackage(@NonNull String pack) { 167 return mPackageName.compareTo(pack) == 0; 168 } 169 hasSameUid(int uid)170 boolean hasSameUid(int uid) { 171 return mCallingUid == uid; 172 } 173 isAlwaysVisibleUser()174 boolean isAlwaysVisibleUser() { 175 final UserManagerInternal umi = LocalServices.getService(UserManagerInternal.class); 176 final UserProperties properties = umi.getUserProperties(UserHandle.getUserId(mCallingUid)); 177 return properties != null && properties.getAlwaysVisible(); 178 } 179 getClientUid()180 int getClientUid() { 181 return mCallingUid; 182 } 183 getClientId()184 String getClientId() { 185 return mClientId; 186 } 187 getGainRequest()188 int getGainRequest() { 189 return mFocusGainRequest; 190 } 191 getGrantFlags()192 int getGrantFlags() { 193 return mGrantFlags; 194 } 195 getAudioAttributes()196 @NonNull AudioAttributes getAudioAttributes() { 197 return mAttributes; 198 } 199 getSdkTarget()200 int getSdkTarget() { 201 return mSdkTarget; 202 } 203 focusChangeToString(int focus)204 private static String focusChangeToString(int focus) { 205 switch(focus) { 206 case AudioManager.AUDIOFOCUS_NONE: 207 return "none"; 208 case AudioManager.AUDIOFOCUS_GAIN: 209 return "GAIN"; 210 case AudioManager.AUDIOFOCUS_GAIN_TRANSIENT: 211 return "GAIN_TRANSIENT"; 212 case AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK: 213 return "GAIN_TRANSIENT_MAY_DUCK"; 214 case AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE: 215 return "GAIN_TRANSIENT_EXCLUSIVE"; 216 case AudioManager.AUDIOFOCUS_LOSS: 217 return "LOSS"; 218 case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT: 219 return "LOSS_TRANSIENT"; 220 case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK: 221 return "LOSS_TRANSIENT_CAN_DUCK"; 222 default: 223 return "[invalid focus change" + focus + "]"; 224 } 225 } 226 focusGainToString()227 private String focusGainToString() { 228 return focusChangeToString(mFocusGainRequest); 229 } 230 focusLossToString()231 private String focusLossToString() { 232 return focusChangeToString(mFocusLossReceived); 233 } 234 flagsToString(int flags)235 private static String flagsToString(int flags) { 236 String msg = new String(); 237 if ((flags & AudioManager.AUDIOFOCUS_FLAG_DELAY_OK) != 0) { 238 msg += "DELAY_OK"; 239 } 240 if ((flags & AudioManager.AUDIOFOCUS_FLAG_LOCK) != 0) { 241 if (!msg.isEmpty()) { msg += "|"; } 242 msg += "LOCK"; 243 } 244 if ((flags & AudioManager.AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS) != 0) { 245 if (!msg.isEmpty()) { msg += "|"; } 246 msg += "PAUSES_ON_DUCKABLE_LOSS"; 247 } 248 return msg; 249 } 250 dump(PrintWriter pw)251 void dump(PrintWriter pw) { 252 pw.println(" source:" + mSourceRef 253 + " -- pack: " + mPackageName 254 + " -- client: " + mClientId 255 + " -- gain: " + focusGainToString() 256 + " -- flags: " + flagsToString(mGrantFlags) 257 + " -- loss: " + focusLossToString() 258 + " -- notified: " + mFocusLossWasNotified 259 + " -- limbo" + mFocusLossFadeLimbo 260 + " -- uid: " + mCallingUid 261 + " -- attr: " + mAttributes 262 + " -- sdk:" + mSdkTarget); 263 } 264 265 /** 266 * Clear all references, except for instances in "loss limbo" due to the current fade out 267 * for which there will be an attempt to be clear after the loss has been notified 268 */ maybeRelease()269 void maybeRelease() { 270 if (!mFocusLossFadeLimbo) { 271 release(); 272 } 273 } 274 release()275 void release() { 276 final IBinder srcRef = mSourceRef; 277 final AudioFocusDeathHandler deathHdlr = mDeathHandler; 278 try { 279 if (srcRef != null && deathHdlr != null) { 280 srcRef.unlinkToDeath(deathHdlr, 0); 281 } 282 } catch (java.util.NoSuchElementException e) { } 283 mDeathHandler = null; 284 mFocusDispatcher = null; 285 } 286 287 @Override finalize()288 protected void finalize() throws Throwable { 289 release(); 290 super.finalize(); 291 } 292 293 /** 294 * For a given audio focus gain request, return the audio focus loss type that will result 295 * from it, taking into account any previous focus loss. 296 * @param gainRequest 297 * @return the audio focus loss type that matches the gain request 298 */ focusLossForGainRequest(int gainRequest)299 private int focusLossForGainRequest(int gainRequest) { 300 switch(gainRequest) { 301 case AudioManager.AUDIOFOCUS_GAIN: 302 switch(mFocusLossReceived) { 303 case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK: 304 case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT: 305 case AudioManager.AUDIOFOCUS_LOSS: 306 case AudioManager.AUDIOFOCUS_NONE: 307 return AudioManager.AUDIOFOCUS_LOSS; 308 } 309 case AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE: 310 case AudioManager.AUDIOFOCUS_GAIN_TRANSIENT: 311 switch(mFocusLossReceived) { 312 case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK: 313 case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT: 314 case AudioManager.AUDIOFOCUS_NONE: 315 return AudioManager.AUDIOFOCUS_LOSS_TRANSIENT; 316 case AudioManager.AUDIOFOCUS_LOSS: 317 return AudioManager.AUDIOFOCUS_LOSS; 318 } 319 case AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK: 320 switch(mFocusLossReceived) { 321 case AudioManager.AUDIOFOCUS_NONE: 322 case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK: 323 return AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK; 324 case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT: 325 return AudioManager.AUDIOFOCUS_LOSS_TRANSIENT; 326 case AudioManager.AUDIOFOCUS_LOSS: 327 return AudioManager.AUDIOFOCUS_LOSS; 328 } 329 default: 330 Log.e(TAG, "focusLossForGainRequest() for invalid focus request "+ gainRequest); 331 return AudioManager.AUDIOFOCUS_NONE; 332 } 333 } 334 335 /** 336 * Handle the loss of focus resulting from a given focus gain. 337 * @param focusGain the focus gain from which the loss of focus is resulting 338 * @param frWinner the new focus owner 339 * @return true if the focus loss is definitive, false otherwise. 340 */ 341 @GuardedBy("MediaFocusControl.mAudioFocusLock") handleFocusLossFromGain(int focusGain, final FocusRequester frWinner, boolean forceDuck)342 boolean handleFocusLossFromGain(int focusGain, final FocusRequester frWinner, boolean forceDuck) 343 { 344 if (DEBUG) { 345 Log.i(TAG, "handleFocusLossFromGain for " + mClientId + " gain:" + focusGain); 346 } 347 final int focusLoss = focusLossForGainRequest(focusGain); 348 handleFocusLoss(focusLoss, frWinner, forceDuck); 349 return (focusLoss == AudioManager.AUDIOFOCUS_LOSS); 350 } 351 352 @GuardedBy("MediaFocusControl.mAudioFocusLock") handleFocusGain(int focusGain)353 void handleFocusGain(int focusGain) { 354 try { 355 mFocusLossReceived = AudioManager.AUDIOFOCUS_NONE; 356 mFocusLossFadeLimbo = false; 357 mFocusController.notifyExtPolicyFocusGrant_syncAf(toAudioFocusInfo(), 358 AudioManager.AUDIOFOCUS_REQUEST_GRANTED); 359 final IAudioFocusDispatcher fd = mFocusDispatcher; 360 if (fd != null) { 361 if (DEBUG) { 362 Log.v(TAG, "dispatching " + focusChangeToString(focusGain) + " to " 363 + mClientId); 364 } 365 if (mFocusLossWasNotified) { 366 fd.dispatchAudioFocusChange(focusGain, mClientId); 367 } 368 } 369 mFocusController.restoreVShapedPlayers(this); 370 } catch (android.os.RemoteException e) { 371 Log.e(TAG, "Failure to signal gain of audio focus due to: ", e); 372 } 373 } 374 375 @GuardedBy("MediaFocusControl.mAudioFocusLock") handleFocusGainFromRequest(int focusRequestResult)376 void handleFocusGainFromRequest(int focusRequestResult) { 377 if (focusRequestResult == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) { 378 mFocusController.restoreVShapedPlayers(this); 379 } 380 } 381 382 @GuardedBy("MediaFocusControl.mAudioFocusLock") handleFocusLoss(int focusLoss, @Nullable final FocusRequester frWinner, boolean forceDuck)383 void handleFocusLoss(int focusLoss, @Nullable final FocusRequester frWinner, boolean forceDuck) 384 { 385 if (DEBUG) { 386 Log.i(TAG, "handleFocusLoss for " + mClientId + " loss:" + focusLoss); 387 } 388 try { 389 if (focusLoss != mFocusLossReceived) { 390 mFocusLossReceived = focusLoss; 391 mFocusLossWasNotified = false; 392 // before dispatching a focus loss, check if the following conditions are met: 393 // 1/ the framework is not supposed to notify the focus loser on a DUCK loss 394 // (i.e. it has a focus controller that implements a ducking policy) 395 // 2/ it is a DUCK loss 396 // 3/ the focus loser isn't flagged as pausing in a DUCK loss 397 // if they are, do not notify the focus loser 398 if (!mFocusController.mustNotifyFocusOwnerOnDuck() 399 && mFocusLossReceived == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK 400 && (mGrantFlags 401 & AudioManager.AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS) == 0) { 402 if (DEBUG) { 403 Log.v(TAG, "NOT dispatching " + focusChangeToString(mFocusLossReceived) 404 + " to " + mClientId + ", to be handled externally"); 405 } 406 mFocusController.notifyExtPolicyFocusLoss_syncAf( 407 toAudioFocusInfo(), false /* wasDispatched */); 408 return; 409 } 410 411 // check enforcement by the framework 412 boolean handled = false; 413 if (frWinner != null) { 414 handled = frameworkHandleFocusLoss(focusLoss, frWinner, forceDuck); 415 } 416 417 if (handled) { 418 if (DEBUG) { 419 Log.v(TAG, "NOT dispatching " + focusChangeToString(mFocusLossReceived) 420 + " to " + mClientId + ", response handled by framework"); 421 } 422 mFocusController.notifyExtPolicyFocusLoss_syncAf( 423 toAudioFocusInfo(), false /* wasDispatched */); 424 return; // with mFocusLossWasNotified = false 425 } 426 427 final IAudioFocusDispatcher fd = mFocusDispatcher; 428 if (fd != null) { 429 if (DEBUG) { 430 Log.v(TAG, "dispatching " + focusChangeToString(mFocusLossReceived) + " to " 431 + mClientId); 432 } 433 mFocusController.notifyExtPolicyFocusLoss_syncAf( 434 toAudioFocusInfo(), true /* wasDispatched */); 435 mFocusLossWasNotified = true; 436 fd.dispatchAudioFocusChange(mFocusLossReceived, mClientId); 437 } else if (DEBUG) { 438 Log.i(TAG, "NOT dispatching " + focusChangeToString(mFocusLossReceived) 439 + " to " + mClientId + " no IAudioFocusDispatcher"); 440 } 441 } 442 } catch (android.os.RemoteException e) { 443 Log.e(TAG, "Failure to signal loss of audio focus due to:", e); 444 } 445 } 446 447 /** 448 * Let the framework handle the focus loss if possible 449 * @param focusLoss 450 * @param frWinner 451 * @param forceDuck 452 * @return true if the framework handled the focus loss 453 */ 454 @GuardedBy("MediaFocusControl.mAudioFocusLock") frameworkHandleFocusLoss(int focusLoss, @NonNull final FocusRequester frWinner, boolean forceDuck)455 private boolean frameworkHandleFocusLoss(int focusLoss, @NonNull final FocusRequester frWinner, 456 boolean forceDuck) { 457 if (frWinner.mCallingUid == this.mCallingUid) { 458 // the focus change is within the same app, so let the dispatching 459 // happen as if the framework was not involved. 460 return false; 461 } 462 463 if (focusLoss == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK) { 464 if (!MediaFocusControl.ENFORCE_DUCKING) { 465 return false; 466 } 467 468 // candidate for enforcement by the framework 469 if (!forceDuck && ((mGrantFlags 470 & AudioManager.AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS) != 0)) { 471 // the focus loser declared it would pause instead of duck, let it 472 // handle it (the framework doesn't pause for apps) 473 Log.v(TAG, "not ducking uid " + this.mCallingUid + " - flags"); 474 return false; 475 } 476 if (!forceDuck && (MediaFocusControl.ENFORCE_DUCKING_FOR_NEW 477 && this.getSdkTarget() <= MediaFocusControl.DUCKING_IN_APP_SDK_LEVEL)) { 478 // legacy behavior, apps used to be notified when they should be ducking 479 Log.v(TAG, "not ducking uid " + this.mCallingUid + " - old SDK"); 480 return false; 481 } 482 483 return mFocusController.duckPlayers(frWinner, /*loser*/ this, forceDuck); 484 } 485 486 if (focusLoss == AudioManager.AUDIOFOCUS_LOSS) { 487 if (!MediaFocusControl.ENFORCE_FADEOUT_FOR_FOCUS_LOSS) { 488 return false; 489 } 490 491 // candidate for fade-out before a receiving a loss 492 boolean playersAreFaded = mFocusController.fadeOutPlayers(frWinner, /* loser */ this); 493 if (playersAreFaded) { 494 // active players are being faded out, delay the dispatch of focus loss 495 // mark this instance as being faded so it's not released yet as the focus loss 496 // will be dispatched later, it is now in limbo mode 497 mFocusLossFadeLimbo = true; 498 mFocusController.postDelayedLossAfterFade(this, 499 mFocusController.getFadeOutDurationOnFocusLossMillis( 500 this.getAudioAttributes())); 501 return true; 502 } 503 } 504 505 return false; 506 } 507 dispatchFocusChange(int focusChange)508 int dispatchFocusChange(int focusChange) { 509 final IAudioFocusDispatcher fd = mFocusDispatcher; 510 if (fd == null) { 511 if (MediaFocusControl.DEBUG) { Log.e(TAG, "dispatchFocusChange: no focus dispatcher"); } 512 return AudioManager.AUDIOFOCUS_REQUEST_FAILED; 513 } 514 if (focusChange == AudioManager.AUDIOFOCUS_NONE) { 515 if (MediaFocusControl.DEBUG) { Log.v(TAG, "dispatchFocusChange: AUDIOFOCUS_NONE"); } 516 return AudioManager.AUDIOFOCUS_REQUEST_FAILED; 517 } else if ((focusChange == AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK 518 || focusChange == AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE 519 || focusChange == AudioManager.AUDIOFOCUS_GAIN_TRANSIENT 520 || focusChange == AudioManager.AUDIOFOCUS_GAIN) 521 && (mFocusGainRequest != focusChange)){ 522 Log.w(TAG, "focus gain was requested with " + mFocusGainRequest 523 + ", dispatching " + focusChange); 524 } else if (focusChange == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK 525 || focusChange == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT 526 || focusChange == AudioManager.AUDIOFOCUS_LOSS) { 527 mFocusLossReceived = focusChange; 528 } 529 try { 530 fd.dispatchAudioFocusChange(focusChange, mClientId); 531 } catch (android.os.RemoteException e) { 532 Log.e(TAG, "dispatchFocusChange: error talking to focus listener " + mClientId, e); 533 return AudioManager.AUDIOFOCUS_REQUEST_FAILED; 534 } 535 return AudioManager.AUDIOFOCUS_REQUEST_GRANTED; 536 } 537 538 @GuardedBy("MediaFocusControl.mAudioFocusLock") dispatchFocusChangeWithFadeLocked(int focusChange, List<FocusRequester> otherActiveFrs)539 int dispatchFocusChangeWithFadeLocked(int focusChange, List<FocusRequester> otherActiveFrs) { 540 if (focusChange == AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK 541 || focusChange == AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE 542 || focusChange == AudioManager.AUDIOFOCUS_GAIN_TRANSIENT 543 || focusChange == AudioManager.AUDIOFOCUS_GAIN) { 544 mFocusLossFadeLimbo = false; 545 mFocusController.restoreVShapedPlayers(this); 546 } else if (focusChange == AudioManager.AUDIOFOCUS_LOSS 547 && mFocusController.shouldEnforceFade()) { 548 for (int index = 0; index < otherActiveFrs.size(); index++) { 549 // candidate for fade-out before a receiving a loss 550 if (mFocusController.fadeOutPlayers(otherActiveFrs.get(index), /* loser= */ this)) { 551 // active players are being faded out, delay the dispatch of focus loss 552 // mark this instance as being faded so it's not released yet as the focus loss 553 // will be dispatched later, it is now in limbo mode 554 mFocusLossFadeLimbo = true; 555 mFocusController.postDelayedLossAfterFade(this, 556 mFocusController.getFadeOutDurationOnFocusLossMillis( 557 this.getAudioAttributes())); 558 return AudioManager.AUDIOFOCUS_REQUEST_DELAYED; 559 } 560 } 561 } 562 return dispatchFocusChange(focusChange); 563 } 564 dispatchFocusResultFromExtPolicy(int requestResult)565 void dispatchFocusResultFromExtPolicy(int requestResult) { 566 final IAudioFocusDispatcher fd = mFocusDispatcher; 567 if (fd == null) { 568 if (MediaFocusControl.DEBUG) { 569 Log.e(TAG, "dispatchFocusResultFromExtPolicy: no focus dispatcher"); 570 } 571 return; 572 } 573 if (DEBUG) { 574 Log.v(TAG, "dispatching result" + requestResult + " to " + mClientId); 575 } 576 try { 577 fd.dispatchFocusResultFromExtPolicy(requestResult, mClientId); 578 } catch (android.os.RemoteException e) { 579 Log.e(TAG, "dispatchFocusResultFromExtPolicy: error talking to focus listener" 580 + mClientId, e); 581 } 582 } 583 toAudioFocusInfo()584 AudioFocusInfo toAudioFocusInfo() { 585 return new AudioFocusInfo(mAttributes, mCallingUid, mClientId, mPackageName, 586 mFocusGainRequest, mFocusLossReceived, mGrantFlags, mSdkTarget); 587 } 588 } 589