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