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.app.AppOpsManager; 21 import android.content.Context; 22 import android.media.AudioAttributes; 23 import android.media.AudioFocusInfo; 24 import android.media.AudioManager; 25 import android.media.AudioSystem; 26 import android.media.IAudioFocusDispatcher; 27 import android.media.audiopolicy.AudioPolicy; 28 import android.media.audiopolicy.IAudioPolicyCallback; 29 import android.os.Binder; 30 import android.os.Build; 31 import android.os.IBinder; 32 import android.os.RemoteException; 33 import android.util.Log; 34 35 import java.io.PrintWriter; 36 import java.util.ArrayList; 37 import java.util.Date; 38 import java.util.HashMap; 39 import java.util.Iterator; 40 import java.util.Map.Entry; 41 import java.util.Set; 42 import java.util.Stack; 43 import java.text.DateFormat; 44 45 /** 46 * @hide 47 * 48 */ 49 public class MediaFocusControl implements PlayerFocusEnforcer { 50 51 private static final String TAG = "MediaFocusControl"; 52 static final boolean DEBUG = false; 53 54 /** 55 * set to true so the framework enforces ducking itself, without communicating to apps 56 * that they lost focus for most use cases. 57 */ 58 static final boolean ENFORCE_DUCKING = true; 59 /** 60 * set to true to the framework enforces ducking itself only with apps above a given SDK 61 * target level. Is ignored if ENFORCE_DUCKING is false. 62 */ 63 static final boolean ENFORCE_DUCKING_FOR_NEW = true; 64 /** 65 * the SDK level (included) up to which the framework doesn't enforce ducking itself. Is ignored 66 * if ENFORCE_DUCKING_FOR_NEW is false; 67 */ 68 // automatic ducking was introduced for Android O 69 static final int DUCKING_IN_APP_SDK_LEVEL = Build.VERSION_CODES.N_MR1; 70 /** 71 * set to true so the framework enforces muting media/game itself when the device is ringing 72 * or in a call. 73 */ 74 static final boolean ENFORCE_MUTING_FOR_RING_OR_CALL = true; 75 76 private final Context mContext; 77 private final AppOpsManager mAppOps; 78 private PlayerFocusEnforcer mFocusEnforcer; // never null 79 80 private boolean mRingOrCallActive = false; 81 82 protected MediaFocusControl(Context cntxt, PlayerFocusEnforcer pfe) { 83 mContext = cntxt; 84 mAppOps = (AppOpsManager)mContext.getSystemService(Context.APP_OPS_SERVICE); 85 mFocusEnforcer = pfe; 86 } 87 88 protected void dump(PrintWriter pw) { 89 pw.println("\nMediaFocusControl dump time: " 90 + DateFormat.getTimeInstance().format(new Date())); 91 dumpFocusStack(pw); 92 } 93 94 //================================================================= 95 // PlayerFocusEnforcer implementation 96 @Override 97 public boolean duckPlayers(FocusRequester winner, FocusRequester loser) { 98 return mFocusEnforcer.duckPlayers(winner, loser); 99 } 100 101 @Override 102 public void unduckPlayers(FocusRequester winner) { 103 mFocusEnforcer.unduckPlayers(winner); 104 } 105 106 @Override 107 public void mutePlayersForCall(int[] usagesToMute) { 108 mFocusEnforcer.mutePlayersForCall(usagesToMute); 109 } 110 111 @Override 112 public void unmutePlayersForCall() { 113 mFocusEnforcer.unmutePlayersForCall(); 114 } 115 116 //========================================================================================== 117 // AudioFocus 118 //========================================================================================== 119 120 private final static Object mAudioFocusLock = new Object(); 121 122 /** 123 * Discard the current audio focus owner. 124 * Notify top of audio focus stack that it lost focus (regardless of possibility to reassign 125 * focus), remove it from the stack, and clear the remote control display. 126 */ 127 protected void discardAudioFocusOwner() { 128 synchronized(mAudioFocusLock) { 129 if (!mFocusStack.empty()) { 130 // notify the current focus owner it lost focus after removing it from stack 131 final FocusRequester exFocusOwner = mFocusStack.pop(); 132 exFocusOwner.handleFocusLoss(AudioManager.AUDIOFOCUS_LOSS, null); 133 exFocusOwner.release(); 134 } 135 } 136 } 137 138 /** 139 * Called synchronized on mAudioFocusLock 140 */ 141 private void notifyTopOfAudioFocusStack() { 142 // notify the top of the stack it gained focus 143 if (!mFocusStack.empty()) { 144 if (canReassignAudioFocus()) { 145 mFocusStack.peek().handleFocusGain(AudioManager.AUDIOFOCUS_GAIN); 146 } 147 } 148 } 149 150 /** 151 * Focus is requested, propagate the associated loss throughout the stack. 152 * @param focusGain the new focus gain that will later be added at the top of the stack 153 */ 154 private void propagateFocusLossFromGain_syncAf(int focusGain, final FocusRequester fr) { 155 // going through the audio focus stack to signal new focus, traversing order doesn't 156 // matter as all entries respond to the same external focus gain 157 Iterator<FocusRequester> stackIterator = mFocusStack.iterator(); 158 while(stackIterator.hasNext()) { 159 stackIterator.next().handleExternalFocusGain(focusGain, fr); 160 } 161 } 162 163 private final Stack<FocusRequester> mFocusStack = new Stack<FocusRequester>(); 164 165 /** 166 * Helper function: 167 * Display in the log the current entries in the audio focus stack 168 */ 169 private void dumpFocusStack(PrintWriter pw) { 170 pw.println("\nAudio Focus stack entries (last is top of stack):"); 171 synchronized(mAudioFocusLock) { 172 Iterator<FocusRequester> stackIterator = mFocusStack.iterator(); 173 while(stackIterator.hasNext()) { 174 stackIterator.next().dump(pw); 175 } 176 pw.println("\n"); 177 if (mFocusPolicy == null) { 178 pw.println("No external focus policy\n"); 179 } else { 180 pw.println("External focus policy: "+ mFocusPolicy + ", focus owners:\n"); 181 dumpExtFocusPolicyFocusOwners(pw); 182 } 183 } 184 pw.println("\n"); 185 pw.println(" Notify on duck: " + mNotifyFocusOwnerOnDuck + "\n"); 186 pw.println(" In ring or call: " + mRingOrCallActive + "\n"); 187 } 188 189 /** 190 * Helper function: 191 * Called synchronized on mAudioFocusLock 192 * Remove a focus listener from the focus stack. 193 * @param clientToRemove the focus listener 194 * @param signal if true and the listener was at the top of the focus stack, i.e. it was holding 195 * focus, notify the next item in the stack it gained focus. 196 */ 197 private void removeFocusStackEntry(String clientToRemove, boolean signal, 198 boolean notifyFocusFollowers) { 199 // is the current top of the focus stack abandoning focus? (because of request, not death) 200 if (!mFocusStack.empty() && mFocusStack.peek().hasSameClient(clientToRemove)) 201 { 202 //Log.i(TAG, " removeFocusStackEntry() removing top of stack"); 203 FocusRequester fr = mFocusStack.pop(); 204 fr.release(); 205 if (notifyFocusFollowers) { 206 final AudioFocusInfo afi = fr.toAudioFocusInfo(); 207 afi.clearLossReceived(); 208 notifyExtPolicyFocusLoss_syncAf(afi, false); 209 } 210 if (signal) { 211 // notify the new top of the stack it gained focus 212 notifyTopOfAudioFocusStack(); 213 } 214 } else { 215 // focus is abandoned by a client that's not at the top of the stack, 216 // no need to update focus. 217 // (using an iterator on the stack so we can safely remove an entry after having 218 // evaluated it, traversal order doesn't matter here) 219 Iterator<FocusRequester> stackIterator = mFocusStack.iterator(); 220 while(stackIterator.hasNext()) { 221 FocusRequester fr = stackIterator.next(); 222 if(fr.hasSameClient(clientToRemove)) { 223 Log.i(TAG, "AudioFocus removeFocusStackEntry(): removing entry for " 224 + clientToRemove); 225 stackIterator.remove(); 226 // stack entry not used anymore, clear references 227 fr.release(); 228 } 229 } 230 } 231 } 232 233 /** 234 * Helper function: 235 * Called synchronized on mAudioFocusLock 236 * Remove focus listeners from the focus stack for a particular client when it has died. 237 */ 238 private void removeFocusStackEntryOnDeath(IBinder cb) { 239 // is the owner of the audio focus part of the client to remove? 240 boolean isTopOfStackForClientToRemove = !mFocusStack.isEmpty() && 241 mFocusStack.peek().hasSameBinder(cb); 242 // (using an iterator on the stack so we can safely remove an entry after having 243 // evaluated it, traversal order doesn't matter here) 244 Iterator<FocusRequester> stackIterator = mFocusStack.iterator(); 245 while(stackIterator.hasNext()) { 246 FocusRequester fr = stackIterator.next(); 247 if(fr.hasSameBinder(cb)) { 248 Log.i(TAG, "AudioFocus removeFocusStackEntryOnDeath(): removing entry for " + cb); 249 stackIterator.remove(); 250 // stack entry not used anymore, clear references 251 fr.release(); 252 } 253 } 254 if (isTopOfStackForClientToRemove) { 255 // we removed an entry at the top of the stack: 256 // notify the new top of the stack it gained focus. 257 notifyTopOfAudioFocusStack(); 258 } 259 } 260 261 /** 262 * Helper function for external focus policy: 263 * Called synchronized on mAudioFocusLock 264 * Remove focus listeners from the list of potential focus owners for a particular client when 265 * it has died. 266 */ 267 private void removeFocusEntryForExtPolicy(IBinder cb) { 268 if (mFocusOwnersForFocusPolicy.isEmpty()) { 269 return; 270 } 271 boolean released = false; 272 final Set<Entry<String, FocusRequester>> owners = mFocusOwnersForFocusPolicy.entrySet(); 273 final Iterator<Entry<String, FocusRequester>> ownerIterator = owners.iterator(); 274 while (ownerIterator.hasNext()) { 275 final Entry<String, FocusRequester> owner = ownerIterator.next(); 276 final FocusRequester fr = owner.getValue(); 277 if (fr.hasSameBinder(cb)) { 278 ownerIterator.remove(); 279 fr.release(); 280 notifyExtFocusPolicyFocusAbandon_syncAf(fr.toAudioFocusInfo()); 281 break; 282 } 283 } 284 } 285 286 /** 287 * Helper function: 288 * Returns true if the system is in a state where the focus can be reevaluated, false otherwise. 289 * The implementation guarantees that a state where focus cannot be immediately reassigned 290 * implies that an "locked" focus owner is at the top of the focus stack. 291 * Modifications to the implementation that break this assumption will cause focus requests to 292 * misbehave when honoring the AudioManager.AUDIOFOCUS_FLAG_DELAY_OK flag. 293 */ 294 private boolean canReassignAudioFocus() { 295 // focus requests are rejected during a phone call or when the phone is ringing 296 // this is equivalent to IN_VOICE_COMM_FOCUS_ID having the focus 297 if (!mFocusStack.isEmpty() && isLockedFocusOwner(mFocusStack.peek())) { 298 return false; 299 } 300 return true; 301 } 302 303 private boolean isLockedFocusOwner(FocusRequester fr) { 304 return (fr.hasSameClient(AudioSystem.IN_VOICE_COMM_FOCUS_ID) || fr.isLockedFocusOwner()); 305 } 306 307 /** 308 * Helper function 309 * Pre-conditions: focus stack is not empty, there is one or more locked focus owner 310 * at the top of the focus stack 311 * Push the focus requester onto the audio focus stack at the first position immediately 312 * following the locked focus owners. 313 * @return {@link AudioManager#AUDIOFOCUS_REQUEST_GRANTED} or 314 * {@link AudioManager#AUDIOFOCUS_REQUEST_DELAYED} 315 */ 316 private int pushBelowLockedFocusOwners(FocusRequester nfr) { 317 int lastLockedFocusOwnerIndex = mFocusStack.size(); 318 for (int index = mFocusStack.size()-1; index >= 0; index--) { 319 if (isLockedFocusOwner(mFocusStack.elementAt(index))) { 320 lastLockedFocusOwnerIndex = index; 321 } 322 } 323 if (lastLockedFocusOwnerIndex == mFocusStack.size()) { 324 // this should not happen, but handle it and log an error 325 Log.e(TAG, "No exclusive focus owner found in propagateFocusLossFromGain_syncAf()", 326 new Exception()); 327 // no exclusive owner, push at top of stack, focus is granted, propagate change 328 propagateFocusLossFromGain_syncAf(nfr.getGainRequest(), nfr); 329 mFocusStack.push(nfr); 330 return AudioManager.AUDIOFOCUS_REQUEST_GRANTED; 331 } else { 332 mFocusStack.insertElementAt(nfr, lastLockedFocusOwnerIndex); 333 return AudioManager.AUDIOFOCUS_REQUEST_DELAYED; 334 } 335 } 336 337 /** 338 * Inner class to monitor audio focus client deaths, and remove them from the audio focus 339 * stack if necessary. 340 */ 341 protected class AudioFocusDeathHandler implements IBinder.DeathRecipient { 342 private IBinder mCb; // To be notified of client's death 343 344 AudioFocusDeathHandler(IBinder cb) { 345 mCb = cb; 346 } 347 348 public void binderDied() { 349 synchronized(mAudioFocusLock) { 350 if (mFocusPolicy != null) { 351 removeFocusEntryForExtPolicy(mCb); 352 } else { 353 removeFocusStackEntryOnDeath(mCb); 354 } 355 } 356 } 357 } 358 359 /** 360 * Indicates whether to notify an audio focus owner when it loses focus 361 * with {@link AudioManager#AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK} if it will only duck. 362 * This variable being false indicates an AudioPolicy has been registered and has signaled 363 * it will handle audio ducking. 364 */ 365 private boolean mNotifyFocusOwnerOnDuck = true; 366 367 protected void setDuckingInExtPolicyAvailable(boolean available) { 368 mNotifyFocusOwnerOnDuck = !available; 369 } 370 371 boolean mustNotifyFocusOwnerOnDuck() { return mNotifyFocusOwnerOnDuck; } 372 373 private ArrayList<IAudioPolicyCallback> mFocusFollowers = new ArrayList<IAudioPolicyCallback>(); 374 375 void addFocusFollower(IAudioPolicyCallback ff) { 376 if (ff == null) { 377 return; 378 } 379 synchronized(mAudioFocusLock) { 380 boolean found = false; 381 for (IAudioPolicyCallback pcb : mFocusFollowers) { 382 if (pcb.asBinder().equals(ff.asBinder())) { 383 found = true; 384 break; 385 } 386 } 387 if (found) { 388 return; 389 } else { 390 mFocusFollowers.add(ff); 391 notifyExtPolicyCurrentFocusAsync(ff); 392 } 393 } 394 } 395 396 void removeFocusFollower(IAudioPolicyCallback ff) { 397 if (ff == null) { 398 return; 399 } 400 synchronized(mAudioFocusLock) { 401 for (IAudioPolicyCallback pcb : mFocusFollowers) { 402 if (pcb.asBinder().equals(ff.asBinder())) { 403 mFocusFollowers.remove(pcb); 404 break; 405 } 406 } 407 } 408 } 409 410 private IAudioPolicyCallback mFocusPolicy = null; 411 412 // Since we don't have a stack of focus owners when using an external focus policy, we keep 413 // track of all the focus requesters in this map, with their clientId as the key. This is 414 // used both for focus dispatch and death handling 415 private HashMap<String, FocusRequester> mFocusOwnersForFocusPolicy = 416 new HashMap<String, FocusRequester>(); 417 418 void setFocusPolicy(IAudioPolicyCallback policy) { 419 if (policy == null) { 420 return; 421 } 422 synchronized (mAudioFocusLock) { 423 mFocusPolicy = policy; 424 } 425 } 426 427 void unsetFocusPolicy(IAudioPolicyCallback policy) { 428 if (policy == null) { 429 return; 430 } 431 synchronized (mAudioFocusLock) { 432 if (mFocusPolicy == policy) { 433 mFocusPolicy = null; 434 } 435 } 436 } 437 438 /** 439 * @param pcb non null 440 */ 441 void notifyExtPolicyCurrentFocusAsync(IAudioPolicyCallback pcb) { 442 final IAudioPolicyCallback pcb2 = pcb; 443 final Thread thread = new Thread() { 444 @Override 445 public void run() { 446 synchronized(mAudioFocusLock) { 447 if (mFocusStack.isEmpty()) { 448 return; 449 } 450 try { 451 pcb2.notifyAudioFocusGrant(mFocusStack.peek().toAudioFocusInfo(), 452 // top of focus stack always has focus 453 AudioManager.AUDIOFOCUS_REQUEST_GRANTED); 454 } catch (RemoteException e) { 455 Log.e(TAG, "Can't call notifyAudioFocusGrant() on IAudioPolicyCallback " 456 + pcb2.asBinder(), e); 457 } 458 } 459 } 460 }; 461 thread.start(); 462 } 463 464 /** 465 * Called synchronized on mAudioFocusLock 466 */ 467 void notifyExtPolicyFocusGrant_syncAf(AudioFocusInfo afi, int requestResult) { 468 for (IAudioPolicyCallback pcb : mFocusFollowers) { 469 try { 470 // oneway 471 pcb.notifyAudioFocusGrant(afi, requestResult); 472 } catch (RemoteException e) { 473 Log.e(TAG, "Can't call notifyAudioFocusGrant() on IAudioPolicyCallback " 474 + pcb.asBinder(), e); 475 } 476 } 477 } 478 479 /** 480 * Called synchronized on mAudioFocusLock 481 */ 482 void notifyExtPolicyFocusLoss_syncAf(AudioFocusInfo afi, boolean wasDispatched) { 483 for (IAudioPolicyCallback pcb : mFocusFollowers) { 484 try { 485 // oneway 486 pcb.notifyAudioFocusLoss(afi, wasDispatched); 487 } catch (RemoteException e) { 488 Log.e(TAG, "Can't call notifyAudioFocusLoss() on IAudioPolicyCallback " 489 + pcb.asBinder(), e); 490 } 491 } 492 } 493 494 /** 495 * Called synchronized on mAudioFocusLock 496 * @param afi 497 * @param requestResult 498 * @return true if the external audio focus policy (if any) is handling the focus request 499 */ 500 boolean notifyExtFocusPolicyFocusRequest_syncAf(AudioFocusInfo afi, int requestResult, 501 IAudioFocusDispatcher fd, IBinder cb) { 502 if (mFocusPolicy == null) { 503 return false; 504 } 505 if (DEBUG) { 506 Log.v(TAG, "notifyExtFocusPolicyFocusRequest client="+afi.getClientId() 507 + " dispatcher=" + fd); 508 } 509 final FocusRequester existingFr = mFocusOwnersForFocusPolicy.get(afi.getClientId()); 510 if (existingFr != null) { 511 if (!existingFr.hasSameDispatcher(fd)) { 512 existingFr.release(); 513 final AudioFocusDeathHandler hdlr = new AudioFocusDeathHandler(cb); 514 mFocusOwnersForFocusPolicy.put(afi.getClientId(), 515 new FocusRequester(afi, fd, cb, hdlr, this)); 516 } 517 } else if (requestResult == AudioManager.AUDIOFOCUS_REQUEST_GRANTED 518 || requestResult == AudioManager.AUDIOFOCUS_REQUEST_DELAYED) { 519 // new focus (future) focus owner to keep track of 520 final AudioFocusDeathHandler hdlr = new AudioFocusDeathHandler(cb); 521 mFocusOwnersForFocusPolicy.put(afi.getClientId(), 522 new FocusRequester(afi, fd, cb, hdlr, this)); 523 } 524 try { 525 //oneway 526 mFocusPolicy.notifyAudioFocusRequest(afi, requestResult); 527 } catch (RemoteException e) { 528 Log.e(TAG, "Can't call notifyAudioFocusRequest() on IAudioPolicyCallback " 529 + mFocusPolicy.asBinder(), e); 530 } 531 return true; 532 } 533 534 /** 535 * Called synchronized on mAudioFocusLock 536 * @param afi 537 * @param requestResult 538 * @return true if the external audio focus policy (if any) is handling the focus request 539 */ 540 boolean notifyExtFocusPolicyFocusAbandon_syncAf(AudioFocusInfo afi) { 541 if (mFocusPolicy == null) { 542 return false; 543 } 544 final FocusRequester fr = mFocusOwnersForFocusPolicy.remove(afi.getClientId()); 545 if (fr != null) { 546 fr.release(); 547 } 548 try { 549 //oneway 550 mFocusPolicy.notifyAudioFocusAbandon(afi); 551 } catch (RemoteException e) { 552 Log.e(TAG, "Can't call notifyAudioFocusAbandon() on IAudioPolicyCallback " 553 + mFocusPolicy.asBinder(), e); 554 } 555 return true; 556 } 557 558 /** see AudioManager.dispatchFocusChange(AudioFocusInfo afi, int focusChange, AudioPolicy ap) */ 559 int dispatchFocusChange(AudioFocusInfo afi, int focusChange) { 560 if (DEBUG) { 561 Log.v(TAG, "dispatchFocusChange " + focusChange + " to afi client=" 562 + afi.getClientId()); 563 } 564 synchronized (mAudioFocusLock) { 565 if (mFocusPolicy == null) { 566 if (DEBUG) { Log.v(TAG, "> failed: no focus policy" ); } 567 return AudioManager.AUDIOFOCUS_REQUEST_FAILED; 568 } 569 final FocusRequester fr = mFocusOwnersForFocusPolicy.get(afi.getClientId()); 570 if (fr == null) { 571 if (DEBUG) { Log.v(TAG, "> failed: no such focus requester known" ); } 572 return AudioManager.AUDIOFOCUS_REQUEST_FAILED; 573 } 574 return fr.dispatchFocusChange(focusChange); 575 } 576 } 577 578 private void dumpExtFocusPolicyFocusOwners(PrintWriter pw) { 579 final Set<Entry<String, FocusRequester>> owners = mFocusOwnersForFocusPolicy.entrySet(); 580 final Iterator<Entry<String, FocusRequester>> ownerIterator = owners.iterator(); 581 while (ownerIterator.hasNext()) { 582 final Entry<String, FocusRequester> owner = ownerIterator.next(); 583 final FocusRequester fr = owner.getValue(); 584 fr.dump(pw); 585 } 586 } 587 588 protected int getCurrentAudioFocus() { 589 synchronized(mAudioFocusLock) { 590 if (mFocusStack.empty()) { 591 return AudioManager.AUDIOFOCUS_NONE; 592 } else { 593 return mFocusStack.peek().getGainRequest(); 594 } 595 } 596 } 597 598 /** 599 * Delay after entering ringing or call mode after which the framework will mute streams 600 * that are still playing. 601 */ 602 private static final int RING_CALL_MUTING_ENFORCEMENT_DELAY_MS = 100; 603 604 /** 605 * Usages to mute when the device rings or is in a call 606 */ 607 private final static int[] USAGES_TO_MUTE_IN_RING_OR_CALL = 608 { AudioAttributes.USAGE_MEDIA, AudioAttributes.USAGE_GAME }; 609 610 /** 611 * Return the volume ramp time expected before playback with the given AudioAttributes would 612 * start after gaining audio focus. 613 * @param attr attributes of the sound about to start playing 614 * @return time in ms 615 */ 616 protected static int getFocusRampTimeMs(int focusGain, AudioAttributes attr) { 617 switch (attr.getUsage()) { 618 case AudioAttributes.USAGE_MEDIA: 619 case AudioAttributes.USAGE_GAME: 620 return 1000; 621 case AudioAttributes.USAGE_ALARM: 622 case AudioAttributes.USAGE_NOTIFICATION_RINGTONE: 623 case AudioAttributes.USAGE_ASSISTANT: 624 case AudioAttributes.USAGE_ASSISTANCE_ACCESSIBILITY: 625 case AudioAttributes.USAGE_ASSISTANCE_NAVIGATION_GUIDANCE: 626 return 700; 627 case AudioAttributes.USAGE_VOICE_COMMUNICATION: 628 case AudioAttributes.USAGE_VOICE_COMMUNICATION_SIGNALLING: 629 case AudioAttributes.USAGE_NOTIFICATION: 630 case AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_REQUEST: 631 case AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_INSTANT: 632 case AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_DELAYED: 633 case AudioAttributes.USAGE_NOTIFICATION_EVENT: 634 case AudioAttributes.USAGE_ASSISTANCE_SONIFICATION: 635 return 500; 636 case AudioAttributes.USAGE_UNKNOWN: 637 default: 638 return 0; 639 } 640 } 641 642 /** @see AudioManager#requestAudioFocus(AudioManager.OnAudioFocusChangeListener, int, int, int) */ 643 protected int requestAudioFocus(AudioAttributes aa, int focusChangeHint, IBinder cb, 644 IAudioFocusDispatcher fd, String clientId, String callingPackageName, int flags, 645 int sdk) { 646 Log.i(TAG, " AudioFocus requestAudioFocus() from uid/pid " + Binder.getCallingUid() 647 + "/" + Binder.getCallingPid() 648 + " clientId=" + clientId 649 + " req=" + focusChangeHint 650 + " flags=0x" + Integer.toHexString(flags)); 651 // we need a valid binder callback for clients 652 if (!cb.pingBinder()) { 653 Log.e(TAG, " AudioFocus DOA client for requestAudioFocus(), aborting."); 654 return AudioManager.AUDIOFOCUS_REQUEST_FAILED; 655 } 656 657 if (mAppOps.noteOp(AppOpsManager.OP_TAKE_AUDIO_FOCUS, Binder.getCallingUid(), 658 callingPackageName) != AppOpsManager.MODE_ALLOWED) { 659 return AudioManager.AUDIOFOCUS_REQUEST_FAILED; 660 } 661 662 synchronized(mAudioFocusLock) { 663 boolean enteringRingOrCall = !mRingOrCallActive 664 & (AudioSystem.IN_VOICE_COMM_FOCUS_ID.compareTo(clientId) == 0); 665 if (enteringRingOrCall) { mRingOrCallActive = true; } 666 667 final AudioFocusInfo afiForExtPolicy; 668 if (mFocusPolicy != null) { 669 // construct AudioFocusInfo as it will be communicated to audio focus policy 670 afiForExtPolicy = new AudioFocusInfo(aa, Binder.getCallingUid(), 671 clientId, callingPackageName, focusChangeHint, 0 /*lossReceived*/, 672 flags, sdk); 673 } else { 674 afiForExtPolicy = null; 675 } 676 677 // handle delayed focus 678 boolean focusGrantDelayed = false; 679 if (!canReassignAudioFocus()) { 680 if ((flags & AudioManager.AUDIOFOCUS_FLAG_DELAY_OK) == 0) { 681 final int result = AudioManager.AUDIOFOCUS_REQUEST_FAILED; 682 notifyExtFocusPolicyFocusRequest_syncAf(afiForExtPolicy, result, fd, cb); 683 return result; 684 } else { 685 // request has AUDIOFOCUS_FLAG_DELAY_OK: focus can't be 686 // granted right now, so the requester will be inserted in the focus stack 687 // to receive focus later 688 focusGrantDelayed = true; 689 } 690 } 691 692 // external focus policy: delay request for focus gain? 693 final int resultWithExtPolicy = AudioManager.AUDIOFOCUS_REQUEST_DELAYED; 694 if (notifyExtFocusPolicyFocusRequest_syncAf( 695 afiForExtPolicy, resultWithExtPolicy, fd, cb)) { 696 // stop handling focus request here as it is handled by external audio focus policy 697 return resultWithExtPolicy; 698 } 699 700 // handle the potential premature death of the new holder of the focus 701 // (premature death == death before abandoning focus) 702 // Register for client death notification 703 AudioFocusDeathHandler afdh = new AudioFocusDeathHandler(cb); 704 705 try { 706 cb.linkToDeath(afdh, 0); 707 } catch (RemoteException e) { 708 // client has already died! 709 Log.w(TAG, "AudioFocus requestAudioFocus() could not link to "+cb+" binder death"); 710 return AudioManager.AUDIOFOCUS_REQUEST_FAILED; 711 } 712 713 if (!mFocusStack.empty() && mFocusStack.peek().hasSameClient(clientId)) { 714 // if focus is already owned by this client and the reason for acquiring the focus 715 // hasn't changed, don't do anything 716 final FocusRequester fr = mFocusStack.peek(); 717 if (fr.getGainRequest() == focusChangeHint && fr.getGrantFlags() == flags) { 718 // unlink death handler so it can be gc'ed. 719 // linkToDeath() creates a JNI global reference preventing collection. 720 cb.unlinkToDeath(afdh, 0); 721 notifyExtPolicyFocusGrant_syncAf(fr.toAudioFocusInfo(), 722 AudioManager.AUDIOFOCUS_REQUEST_GRANTED); 723 return AudioManager.AUDIOFOCUS_REQUEST_GRANTED; 724 } 725 // the reason for the audio focus request has changed: remove the current top of 726 // stack and respond as if we had a new focus owner 727 if (!focusGrantDelayed) { 728 mFocusStack.pop(); 729 // the entry that was "popped" is the same that was "peeked" above 730 fr.release(); 731 } 732 } 733 734 // focus requester might already be somewhere below in the stack, remove it 735 removeFocusStackEntry(clientId, false /* signal */, false /*notifyFocusFollowers*/); 736 737 final FocusRequester nfr = new FocusRequester(aa, focusChangeHint, flags, fd, cb, 738 clientId, afdh, callingPackageName, Binder.getCallingUid(), this, sdk); 739 if (focusGrantDelayed) { 740 // focusGrantDelayed being true implies we can't reassign focus right now 741 // which implies the focus stack is not empty. 742 final int requestResult = pushBelowLockedFocusOwners(nfr); 743 if (requestResult != AudioManager.AUDIOFOCUS_REQUEST_FAILED) { 744 notifyExtPolicyFocusGrant_syncAf(nfr.toAudioFocusInfo(), requestResult); 745 } 746 return requestResult; 747 } else { 748 // propagate the focus change through the stack 749 if (!mFocusStack.empty()) { 750 propagateFocusLossFromGain_syncAf(focusChangeHint, nfr); 751 } 752 753 // push focus requester at the top of the audio focus stack 754 mFocusStack.push(nfr); 755 nfr.handleFocusGainFromRequest(AudioManager.AUDIOFOCUS_REQUEST_GRANTED); 756 } 757 notifyExtPolicyFocusGrant_syncAf(nfr.toAudioFocusInfo(), 758 AudioManager.AUDIOFOCUS_REQUEST_GRANTED); 759 760 if (ENFORCE_MUTING_FOR_RING_OR_CALL & enteringRingOrCall) { 761 runAudioCheckerForRingOrCallAsync(true/*enteringRingOrCall*/); 762 } 763 }//synchronized(mAudioFocusLock) 764 765 return AudioManager.AUDIOFOCUS_REQUEST_GRANTED; 766 } 767 768 /** 769 * @see AudioManager#abandonAudioFocus(AudioManager.OnAudioFocusChangeListener, AudioAttributes) 770 * */ 771 protected int abandonAudioFocus(IAudioFocusDispatcher fl, String clientId, AudioAttributes aa, 772 String callingPackageName) { 773 // AudioAttributes are currently ignored, to be used for zones 774 Log.i(TAG, " AudioFocus abandonAudioFocus() from uid/pid " + Binder.getCallingUid() 775 + "/" + Binder.getCallingPid() 776 + " clientId=" + clientId); 777 try { 778 // this will take care of notifying the new focus owner if needed 779 synchronized(mAudioFocusLock) { 780 // external focus policy? 781 if (mFocusPolicy != null) { 782 final AudioFocusInfo afi = new AudioFocusInfo(aa, Binder.getCallingUid(), 783 clientId, callingPackageName, 0 /*gainRequest*/, 0 /*lossReceived*/, 784 0 /*flags*/, 0 /* sdk n/a here*/); 785 if (notifyExtFocusPolicyFocusAbandon_syncAf(afi)) { 786 return AudioManager.AUDIOFOCUS_REQUEST_GRANTED; 787 } 788 } 789 790 boolean exitingRingOrCall = mRingOrCallActive 791 & (AudioSystem.IN_VOICE_COMM_FOCUS_ID.compareTo(clientId) == 0); 792 if (exitingRingOrCall) { mRingOrCallActive = false; } 793 794 removeFocusStackEntry(clientId, true /*signal*/, true /*notifyFocusFollowers*/); 795 796 if (ENFORCE_MUTING_FOR_RING_OR_CALL & exitingRingOrCall) { 797 runAudioCheckerForRingOrCallAsync(false/*enteringRingOrCall*/); 798 } 799 } 800 } catch (java.util.ConcurrentModificationException cme) { 801 // Catching this exception here is temporary. It is here just to prevent 802 // a crash seen when the "Silent" notification is played. This is believed to be fixed 803 // but this try catch block is left just to be safe. 804 Log.e(TAG, "FATAL EXCEPTION AudioFocus abandonAudioFocus() caused " + cme); 805 cme.printStackTrace(); 806 } 807 808 return AudioManager.AUDIOFOCUS_REQUEST_GRANTED; 809 } 810 811 812 protected void unregisterAudioFocusClient(String clientId) { 813 synchronized(mAudioFocusLock) { 814 removeFocusStackEntry(clientId, false, true /*notifyFocusFollowers*/); 815 } 816 } 817 818 private void runAudioCheckerForRingOrCallAsync(final boolean enteringRingOrCall) { 819 new Thread() { 820 public void run() { 821 if (enteringRingOrCall) { 822 try { 823 Thread.sleep(RING_CALL_MUTING_ENFORCEMENT_DELAY_MS); 824 } catch (InterruptedException e) { 825 e.printStackTrace(); 826 } 827 } 828 synchronized (mAudioFocusLock) { 829 // since the new thread starting running the state could have changed, so 830 // we need to check again mRingOrCallActive, not enteringRingOrCall 831 if (mRingOrCallActive) { 832 mFocusEnforcer.mutePlayersForCall(USAGES_TO_MUTE_IN_RING_OR_CALL); 833 } else { 834 mFocusEnforcer.unmutePlayersForCall(); 835 } 836 } 837 } 838 }.start(); 839 } 840 } 841