blob: c5f563c7a43c1f0c0f91c919b2b33aaf1cc06188 [file] [log] [blame]
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07001/*
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
John Spurlock61560172015-02-06 19:46:04 -050017package com.android.server.audio;
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -070018
Jean-Michel Trivi126cf032017-04-02 23:19:02 -070019import android.annotation.NonNull;
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -070020import android.app.AppOpsManager;
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -070021import android.content.Context;
John Spurlock61560172015-02-06 19:46:04 -050022import android.media.AudioAttributes;
23import android.media.AudioFocusInfo;
24import android.media.AudioManager;
25import android.media.AudioSystem;
26import android.media.IAudioFocusDispatcher;
Jean-Michel Trivi126cf032017-04-02 23:19:02 -070027import android.media.audiopolicy.AudioPolicy;
Jean-Michel Trivi0212be52014-11-24 14:43:10 -080028import android.media.audiopolicy.IAudioPolicyCallback;
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -070029import android.os.Binder;
Jean-Michel Trivi461922f2017-04-25 15:23:17 -070030import android.os.Build;
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -070031import android.os.IBinder;
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -070032import android.os.RemoteException;
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -070033import android.util.Log;
John Spurlock61560172015-02-06 19:46:04 -050034
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -070035import java.io.PrintWriter;
36import java.util.ArrayList;
Jean-Michel Trivi545fcf82015-04-07 09:45:35 -070037import java.util.Date;
Jean-Michel Trivi126cf032017-04-02 23:19:02 -070038import java.util.HashMap;
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -070039import java.util.Iterator;
Jean-Michel Trivi126cf032017-04-02 23:19:02 -070040import java.util.Map.Entry;
41import java.util.Set;
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -070042import java.util.Stack;
Jean-Michel Trivi545fcf82015-04-07 09:45:35 -070043import java.text.DateFormat;
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -070044
45/**
46 * @hide
47 *
48 */
Jean-Michel Trivi99489cc2017-01-25 19:08:49 -080049public class MediaFocusControl implements PlayerFocusEnforcer {
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -070050
51 private static final String TAG = "MediaFocusControl";
Jean-Michel Trivi126cf032017-04-02 23:19:02 -070052 static final boolean DEBUG = false;
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -070053
Jean-Michel Trivi99489cc2017-01-25 19:08:49 -080054 /**
55 * set to true so the framework enforces ducking itself, without communicating to apps
Jean-Michel Trivi952f2342017-03-06 16:16:56 -080056 * that they lost focus for most use cases.
Jean-Michel Trivi99489cc2017-01-25 19:08:49 -080057 */
Jean-Michel Trivi952f2342017-03-06 16:16:56 -080058 static final boolean ENFORCE_DUCKING = true;
Jean-Michel Trivi62b86342017-02-04 15:33:47 -080059 /**
Jean-Michel Trivi461922f2017-04-25 15:23:17 -070060 * 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 /**
Jean-Michel Trivi62b86342017-02-04 15:33:47 -080071 * 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;
Jean-Michel Trivi99489cc2017-01-25 19:08:49 -080075
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -070076 private final Context mContext;
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -070077 private final AppOpsManager mAppOps;
Jean-Michel Trivi99489cc2017-01-25 19:08:49 -080078 private PlayerFocusEnforcer mFocusEnforcer; // never null
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -070079
Jean-Michel Trivi62b86342017-02-04 15:33:47 -080080 private boolean mRingOrCallActive = false;
81
Jean-Michel Trivi99489cc2017-01-25 19:08:49 -080082 protected MediaFocusControl(Context cntxt, PlayerFocusEnforcer pfe) {
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -070083 mContext = cntxt;
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -070084 mAppOps = (AppOpsManager)mContext.getSystemService(Context.APP_OPS_SERVICE);
Jean-Michel Trivi99489cc2017-01-25 19:08:49 -080085 mFocusEnforcer = pfe;
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -070086 }
87
Jean-Michel Trivi73673ab2013-08-06 10:42:45 -070088 protected void dump(PrintWriter pw) {
Jean-Michel Trivi545fcf82015-04-07 09:45:35 -070089 pw.println("\nMediaFocusControl dump time: "
90 + DateFormat.getTimeInstance().format(new Date()));
Jean-Michel Trivi73673ab2013-08-06 10:42:45 -070091 dumpFocusStack(pw);
Jean-Michel Trivi0b67b9f2017-10-05 12:19:23 -070092 pw.println("\n");
93 // log
94 mEventLogger.dump(pw);
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -070095 }
96
Jean-Michel Trivi99489cc2017-01-25 19:08:49 -080097 //=================================================================
98 // PlayerFocusEnforcer implementation
99 @Override
100 public boolean duckPlayers(FocusRequester winner, FocusRequester loser) {
101 return mFocusEnforcer.duckPlayers(winner, loser);
102 }
103
104 @Override
105 public void unduckPlayers(FocusRequester winner) {
106 mFocusEnforcer.unduckPlayers(winner);
107 }
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700108
Jean-Michel Trivi62b86342017-02-04 15:33:47 -0800109 @Override
110 public void mutePlayersForCall(int[] usagesToMute) {
111 mFocusEnforcer.mutePlayersForCall(usagesToMute);
112 }
113
114 @Override
115 public void unmutePlayersForCall() {
116 mFocusEnforcer.unmutePlayersForCall();
117 }
118
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700119 //==========================================================================================
120 // AudioFocus
121 //==========================================================================================
122
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700123 private final static Object mAudioFocusLock = new Object();
124
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700125 /**
Jean-Michel Trivi0b67b9f2017-10-05 12:19:23 -0700126 * Arbitrary maximum size of audio focus stack to prevent apps OOM'ing this process.
127 */
128 private static final int MAX_STACK_SIZE = 100;
129
130 private static final AudioEventLogger mEventLogger = new AudioEventLogger(50,
131 "focus commands as seen by MediaFocusControl");
132
133 /**
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700134 * Discard the current audio focus owner.
135 * Notify top of audio focus stack that it lost focus (regardless of possibility to reassign
136 * focus), remove it from the stack, and clear the remote control display.
137 */
138 protected void discardAudioFocusOwner() {
139 synchronized(mAudioFocusLock) {
Jean-Michel Trivicbb212f2013-07-30 15:09:33 -0700140 if (!mFocusStack.empty()) {
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700141 // notify the current focus owner it lost focus after removing it from stack
Jean-Michel Trivi83283f22013-07-29 18:09:41 -0700142 final FocusRequester exFocusOwner = mFocusStack.pop();
Jean-Michel Trivi99489cc2017-01-25 19:08:49 -0800143 exFocusOwner.handleFocusLoss(AudioManager.AUDIOFOCUS_LOSS, null);
Jean-Michel Trivi83283f22013-07-29 18:09:41 -0700144 exFocusOwner.release();
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700145 }
146 }
147 }
148
Jean-Michel Trivi0212be52014-11-24 14:43:10 -0800149 /**
150 * Called synchronized on mAudioFocusLock
151 */
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700152 private void notifyTopOfAudioFocusStack() {
153 // notify the top of the stack it gained focus
Jean-Michel Trivicbb212f2013-07-30 15:09:33 -0700154 if (!mFocusStack.empty()) {
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700155 if (canReassignAudioFocus()) {
Jean-Michel Trivi00bf4b12013-07-26 17:19:32 -0700156 mFocusStack.peek().handleFocusGain(AudioManager.AUDIOFOCUS_GAIN);
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700157 }
158 }
159 }
160
Jean-Michel Trivicbb212f2013-07-30 15:09:33 -0700161 /**
162 * Focus is requested, propagate the associated loss throughout the stack.
163 * @param focusGain the new focus gain that will later be added at the top of the stack
164 */
Jean-Michel Trivi99489cc2017-01-25 19:08:49 -0800165 private void propagateFocusLossFromGain_syncAf(int focusGain, final FocusRequester fr) {
Jean-Michel Trivicbb212f2013-07-30 15:09:33 -0700166 // going through the audio focus stack to signal new focus, traversing order doesn't
167 // matter as all entries respond to the same external focus gain
168 Iterator<FocusRequester> stackIterator = mFocusStack.iterator();
169 while(stackIterator.hasNext()) {
Jean-Michel Trivi99489cc2017-01-25 19:08:49 -0800170 stackIterator.next().handleExternalFocusGain(focusGain, fr);
Jean-Michel Trivicbb212f2013-07-30 15:09:33 -0700171 }
172 }
173
Jean-Michel Trivi83283f22013-07-29 18:09:41 -0700174 private final Stack<FocusRequester> mFocusStack = new Stack<FocusRequester>();
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700175
176 /**
177 * Helper function:
178 * Display in the log the current entries in the audio focus stack
179 */
180 private void dumpFocusStack(PrintWriter pw) {
181 pw.println("\nAudio Focus stack entries (last is top of stack):");
182 synchronized(mAudioFocusLock) {
Jean-Michel Trivi83283f22013-07-29 18:09:41 -0700183 Iterator<FocusRequester> stackIterator = mFocusStack.iterator();
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700184 while(stackIterator.hasNext()) {
Jean-Michel Trivi83283f22013-07-29 18:09:41 -0700185 stackIterator.next().dump(pw);
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700186 }
Jean-Michel Trivi126cf032017-04-02 23:19:02 -0700187 pw.println("\n");
188 if (mFocusPolicy == null) {
189 pw.println("No external focus policy\n");
190 } else {
191 pw.println("External focus policy: "+ mFocusPolicy + ", focus owners:\n");
192 dumpExtFocusPolicyFocusOwners(pw);
193 }
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700194 }
Jean-Michel Trivi62b86342017-02-04 15:33:47 -0800195 pw.println("\n");
196 pw.println(" Notify on duck: " + mNotifyFocusOwnerOnDuck + "\n");
197 pw.println(" In ring or call: " + mRingOrCallActive + "\n");
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700198 }
199
200 /**
201 * Helper function:
202 * Called synchronized on mAudioFocusLock
203 * Remove a focus listener from the focus stack.
204 * @param clientToRemove the focus listener
205 * @param signal if true and the listener was at the top of the focus stack, i.e. it was holding
206 * focus, notify the next item in the stack it gained focus.
207 */
Jean-Michel Trivi0212be52014-11-24 14:43:10 -0800208 private void removeFocusStackEntry(String clientToRemove, boolean signal,
209 boolean notifyFocusFollowers) {
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700210 // is the current top of the focus stack abandoning focus? (because of request, not death)
Jean-Michel Trivi83283f22013-07-29 18:09:41 -0700211 if (!mFocusStack.empty() && mFocusStack.peek().hasSameClient(clientToRemove))
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700212 {
213 //Log.i(TAG, " removeFocusStackEntry() removing top of stack");
Jean-Michel Trivi83283f22013-07-29 18:09:41 -0700214 FocusRequester fr = mFocusStack.pop();
215 fr.release();
Jean-Michel Trivi0212be52014-11-24 14:43:10 -0800216 if (notifyFocusFollowers) {
217 final AudioFocusInfo afi = fr.toAudioFocusInfo();
218 afi.clearLossReceived();
219 notifyExtPolicyFocusLoss_syncAf(afi, false);
220 }
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700221 if (signal) {
222 // notify the new top of the stack it gained focus
223 notifyTopOfAudioFocusStack();
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700224 }
225 } else {
226 // focus is abandoned by a client that's not at the top of the stack,
227 // no need to update focus.
228 // (using an iterator on the stack so we can safely remove an entry after having
229 // evaluated it, traversal order doesn't matter here)
Jean-Michel Trivi83283f22013-07-29 18:09:41 -0700230 Iterator<FocusRequester> stackIterator = mFocusStack.iterator();
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700231 while(stackIterator.hasNext()) {
RoboErik01fe6612014-02-13 14:19:04 -0800232 FocusRequester fr = stackIterator.next();
Jean-Michel Trivi83283f22013-07-29 18:09:41 -0700233 if(fr.hasSameClient(clientToRemove)) {
Jean-Michel Trivi00bf4b12013-07-26 17:19:32 -0700234 Log.i(TAG, "AudioFocus removeFocusStackEntry(): removing entry for "
Jean-Michel Trivi83283f22013-07-29 18:09:41 -0700235 + clientToRemove);
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700236 stackIterator.remove();
Jean-Michel Trivie8987722016-07-07 15:38:32 -0700237 // stack entry not used anymore, clear references
Jean-Michel Trivi83283f22013-07-29 18:09:41 -0700238 fr.release();
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700239 }
240 }
241 }
242 }
243
244 /**
245 * Helper function:
246 * Called synchronized on mAudioFocusLock
247 * Remove focus listeners from the focus stack for a particular client when it has died.
248 */
Jean-Michel Trivie8987722016-07-07 15:38:32 -0700249 private void removeFocusStackEntryOnDeath(IBinder cb) {
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700250 // is the owner of the audio focus part of the client to remove?
251 boolean isTopOfStackForClientToRemove = !mFocusStack.isEmpty() &&
Jean-Michel Trivi83283f22013-07-29 18:09:41 -0700252 mFocusStack.peek().hasSameBinder(cb);
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700253 // (using an iterator on the stack so we can safely remove an entry after having
254 // evaluated it, traversal order doesn't matter here)
Jean-Michel Trivi83283f22013-07-29 18:09:41 -0700255 Iterator<FocusRequester> stackIterator = mFocusStack.iterator();
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700256 while(stackIterator.hasNext()) {
RoboErik01fe6612014-02-13 14:19:04 -0800257 FocusRequester fr = stackIterator.next();
Jean-Michel Trivi83283f22013-07-29 18:09:41 -0700258 if(fr.hasSameBinder(cb)) {
Jean-Michel Trivie8987722016-07-07 15:38:32 -0700259 Log.i(TAG, "AudioFocus removeFocusStackEntryOnDeath(): removing entry for " + cb);
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700260 stackIterator.remove();
Jean-Michel Trivie8987722016-07-07 15:38:32 -0700261 // stack entry not used anymore, clear references
262 fr.release();
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700263 }
264 }
265 if (isTopOfStackForClientToRemove) {
266 // we removed an entry at the top of the stack:
267 // notify the new top of the stack it gained focus.
268 notifyTopOfAudioFocusStack();
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700269 }
270 }
271
272 /**
Jean-Michel Trivi126cf032017-04-02 23:19:02 -0700273 * Helper function for external focus policy:
274 * Called synchronized on mAudioFocusLock
275 * Remove focus listeners from the list of potential focus owners for a particular client when
276 * it has died.
277 */
278 private void removeFocusEntryForExtPolicy(IBinder cb) {
279 if (mFocusOwnersForFocusPolicy.isEmpty()) {
280 return;
281 }
282 boolean released = false;
283 final Set<Entry<String, FocusRequester>> owners = mFocusOwnersForFocusPolicy.entrySet();
284 final Iterator<Entry<String, FocusRequester>> ownerIterator = owners.iterator();
285 while (ownerIterator.hasNext()) {
286 final Entry<String, FocusRequester> owner = ownerIterator.next();
287 final FocusRequester fr = owner.getValue();
288 if (fr.hasSameBinder(cb)) {
289 ownerIterator.remove();
290 fr.release();
291 notifyExtFocusPolicyFocusAbandon_syncAf(fr.toAudioFocusInfo());
292 break;
293 }
294 }
295 }
296
297 /**
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700298 * Helper function:
299 * Returns true if the system is in a state where the focus can be reevaluated, false otherwise.
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -0800300 * The implementation guarantees that a state where focus cannot be immediately reassigned
Jean-Michel Trivi958876f2014-11-16 15:40:22 -0800301 * implies that an "locked" focus owner is at the top of the focus stack.
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -0800302 * Modifications to the implementation that break this assumption will cause focus requests to
303 * misbehave when honoring the AudioManager.AUDIOFOCUS_FLAG_DELAY_OK flag.
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700304 */
305 private boolean canReassignAudioFocus() {
306 // focus requests are rejected during a phone call or when the phone is ringing
307 // this is equivalent to IN_VOICE_COMM_FOCUS_ID having the focus
Jean-Michel Trivi958876f2014-11-16 15:40:22 -0800308 if (!mFocusStack.isEmpty() && isLockedFocusOwner(mFocusStack.peek())) {
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700309 return false;
310 }
311 return true;
312 }
313
Jean-Michel Trivi958876f2014-11-16 15:40:22 -0800314 private boolean isLockedFocusOwner(FocusRequester fr) {
John Spurlock61560172015-02-06 19:46:04 -0500315 return (fr.hasSameClient(AudioSystem.IN_VOICE_COMM_FOCUS_ID) || fr.isLockedFocusOwner());
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -0800316 }
317
318 /**
319 * Helper function
Jean-Michel Trivi958876f2014-11-16 15:40:22 -0800320 * Pre-conditions: focus stack is not empty, there is one or more locked focus owner
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -0800321 * at the top of the focus stack
322 * Push the focus requester onto the audio focus stack at the first position immediately
Jean-Michel Trivi958876f2014-11-16 15:40:22 -0800323 * following the locked focus owners.
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -0800324 * @return {@link AudioManager#AUDIOFOCUS_REQUEST_GRANTED} or
325 * {@link AudioManager#AUDIOFOCUS_REQUEST_DELAYED}
326 */
Jean-Michel Trivi958876f2014-11-16 15:40:22 -0800327 private int pushBelowLockedFocusOwners(FocusRequester nfr) {
328 int lastLockedFocusOwnerIndex = mFocusStack.size();
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -0800329 for (int index = mFocusStack.size()-1; index >= 0; index--) {
Jean-Michel Trivi958876f2014-11-16 15:40:22 -0800330 if (isLockedFocusOwner(mFocusStack.elementAt(index))) {
331 lastLockedFocusOwnerIndex = index;
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -0800332 }
333 }
Jean-Michel Trivi958876f2014-11-16 15:40:22 -0800334 if (lastLockedFocusOwnerIndex == mFocusStack.size()) {
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -0800335 // this should not happen, but handle it and log an error
336 Log.e(TAG, "No exclusive focus owner found in propagateFocusLossFromGain_syncAf()",
337 new Exception());
338 // no exclusive owner, push at top of stack, focus is granted, propagate change
Jean-Michel Trivi99489cc2017-01-25 19:08:49 -0800339 propagateFocusLossFromGain_syncAf(nfr.getGainRequest(), nfr);
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -0800340 mFocusStack.push(nfr);
341 return AudioManager.AUDIOFOCUS_REQUEST_GRANTED;
342 } else {
Jean-Michel Trivi958876f2014-11-16 15:40:22 -0800343 mFocusStack.insertElementAt(nfr, lastLockedFocusOwnerIndex);
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -0800344 return AudioManager.AUDIOFOCUS_REQUEST_DELAYED;
345 }
346 }
347
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700348 /**
349 * Inner class to monitor audio focus client deaths, and remove them from the audio focus
350 * stack if necessary.
351 */
Jean-Michel Trivi83283f22013-07-29 18:09:41 -0700352 protected class AudioFocusDeathHandler implements IBinder.DeathRecipient {
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700353 private IBinder mCb; // To be notified of client's death
354
355 AudioFocusDeathHandler(IBinder cb) {
356 mCb = cb;
357 }
358
359 public void binderDied() {
360 synchronized(mAudioFocusLock) {
Jean-Michel Trivi126cf032017-04-02 23:19:02 -0700361 if (mFocusPolicy != null) {
362 removeFocusEntryForExtPolicy(mCb);
363 } else {
364 removeFocusStackEntryOnDeath(mCb);
365 }
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700366 }
367 }
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700368 }
369
Jean-Michel Trivi0212be52014-11-24 14:43:10 -0800370 /**
371 * Indicates whether to notify an audio focus owner when it loses focus
372 * with {@link AudioManager#AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK} if it will only duck.
373 * This variable being false indicates an AudioPolicy has been registered and has signaled
374 * it will handle audio ducking.
375 */
376 private boolean mNotifyFocusOwnerOnDuck = true;
377
378 protected void setDuckingInExtPolicyAvailable(boolean available) {
379 mNotifyFocusOwnerOnDuck = !available;
380 }
381
382 boolean mustNotifyFocusOwnerOnDuck() { return mNotifyFocusOwnerOnDuck; }
383
384 private ArrayList<IAudioPolicyCallback> mFocusFollowers = new ArrayList<IAudioPolicyCallback>();
385
386 void addFocusFollower(IAudioPolicyCallback ff) {
387 if (ff == null) {
388 return;
389 }
390 synchronized(mAudioFocusLock) {
391 boolean found = false;
392 for (IAudioPolicyCallback pcb : mFocusFollowers) {
393 if (pcb.asBinder().equals(ff.asBinder())) {
394 found = true;
395 break;
396 }
397 }
398 if (found) {
399 return;
400 } else {
401 mFocusFollowers.add(ff);
Jean-Michel Trivi60fd0842015-03-13 10:11:28 -0700402 notifyExtPolicyCurrentFocusAsync(ff);
Jean-Michel Trivi0212be52014-11-24 14:43:10 -0800403 }
404 }
405 }
406
407 void removeFocusFollower(IAudioPolicyCallback ff) {
408 if (ff == null) {
409 return;
410 }
411 synchronized(mAudioFocusLock) {
412 for (IAudioPolicyCallback pcb : mFocusFollowers) {
413 if (pcb.asBinder().equals(ff.asBinder())) {
414 mFocusFollowers.remove(pcb);
415 break;
416 }
417 }
418 }
419 }
420
Jean-Michel Trivi126cf032017-04-02 23:19:02 -0700421 private IAudioPolicyCallback mFocusPolicy = null;
422
423 // Since we don't have a stack of focus owners when using an external focus policy, we keep
424 // track of all the focus requesters in this map, with their clientId as the key. This is
425 // used both for focus dispatch and death handling
426 private HashMap<String, FocusRequester> mFocusOwnersForFocusPolicy =
427 new HashMap<String, FocusRequester>();
428
429 void setFocusPolicy(IAudioPolicyCallback policy) {
430 if (policy == null) {
431 return;
432 }
433 synchronized (mAudioFocusLock) {
434 mFocusPolicy = policy;
435 }
436 }
437
438 void unsetFocusPolicy(IAudioPolicyCallback policy) {
439 if (policy == null) {
440 return;
441 }
442 synchronized (mAudioFocusLock) {
443 if (mFocusPolicy == policy) {
444 mFocusPolicy = null;
445 }
446 }
447 }
448
Jean-Michel Trivi0212be52014-11-24 14:43:10 -0800449 /**
Jean-Michel Trivi60fd0842015-03-13 10:11:28 -0700450 * @param pcb non null
451 */
452 void notifyExtPolicyCurrentFocusAsync(IAudioPolicyCallback pcb) {
453 final IAudioPolicyCallback pcb2 = pcb;
454 final Thread thread = new Thread() {
455 @Override
456 public void run() {
457 synchronized(mAudioFocusLock) {
458 if (mFocusStack.isEmpty()) {
459 return;
460 }
461 try {
462 pcb2.notifyAudioFocusGrant(mFocusStack.peek().toAudioFocusInfo(),
463 // top of focus stack always has focus
464 AudioManager.AUDIOFOCUS_REQUEST_GRANTED);
465 } catch (RemoteException e) {
466 Log.e(TAG, "Can't call notifyAudioFocusGrant() on IAudioPolicyCallback "
467 + pcb2.asBinder(), e);
468 }
469 }
470 }
471 };
472 thread.start();
473 }
474
475 /**
Jean-Michel Trivi0212be52014-11-24 14:43:10 -0800476 * Called synchronized on mAudioFocusLock
477 */
478 void notifyExtPolicyFocusGrant_syncAf(AudioFocusInfo afi, int requestResult) {
479 for (IAudioPolicyCallback pcb : mFocusFollowers) {
480 try {
481 // oneway
482 pcb.notifyAudioFocusGrant(afi, requestResult);
483 } catch (RemoteException e) {
Jean-Michel Trivi60fd0842015-03-13 10:11:28 -0700484 Log.e(TAG, "Can't call notifyAudioFocusGrant() on IAudioPolicyCallback "
Jean-Michel Trivi0212be52014-11-24 14:43:10 -0800485 + pcb.asBinder(), e);
486 }
487 }
488 }
489
490 /**
491 * Called synchronized on mAudioFocusLock
492 */
493 void notifyExtPolicyFocusLoss_syncAf(AudioFocusInfo afi, boolean wasDispatched) {
494 for (IAudioPolicyCallback pcb : mFocusFollowers) {
495 try {
496 // oneway
497 pcb.notifyAudioFocusLoss(afi, wasDispatched);
498 } catch (RemoteException e) {
Jean-Michel Trivi60fd0842015-03-13 10:11:28 -0700499 Log.e(TAG, "Can't call notifyAudioFocusLoss() on IAudioPolicyCallback "
Jean-Michel Trivi0212be52014-11-24 14:43:10 -0800500 + pcb.asBinder(), e);
501 }
502 }
503 }
504
Jean-Michel Trivi126cf032017-04-02 23:19:02 -0700505 /**
506 * Called synchronized on mAudioFocusLock
507 * @param afi
508 * @param requestResult
509 * @return true if the external audio focus policy (if any) is handling the focus request
510 */
511 boolean notifyExtFocusPolicyFocusRequest_syncAf(AudioFocusInfo afi, int requestResult,
512 IAudioFocusDispatcher fd, IBinder cb) {
513 if (mFocusPolicy == null) {
514 return false;
515 }
516 if (DEBUG) {
517 Log.v(TAG, "notifyExtFocusPolicyFocusRequest client="+afi.getClientId()
518 + " dispatcher=" + fd);
519 }
520 final FocusRequester existingFr = mFocusOwnersForFocusPolicy.get(afi.getClientId());
521 if (existingFr != null) {
522 if (!existingFr.hasSameDispatcher(fd)) {
523 existingFr.release();
524 final AudioFocusDeathHandler hdlr = new AudioFocusDeathHandler(cb);
525 mFocusOwnersForFocusPolicy.put(afi.getClientId(),
526 new FocusRequester(afi, fd, cb, hdlr, this));
527 }
528 } else if (requestResult == AudioManager.AUDIOFOCUS_REQUEST_GRANTED
529 || requestResult == AudioManager.AUDIOFOCUS_REQUEST_DELAYED) {
530 // new focus (future) focus owner to keep track of
531 final AudioFocusDeathHandler hdlr = new AudioFocusDeathHandler(cb);
532 mFocusOwnersForFocusPolicy.put(afi.getClientId(),
533 new FocusRequester(afi, fd, cb, hdlr, this));
534 }
535 try {
536 //oneway
537 mFocusPolicy.notifyAudioFocusRequest(afi, requestResult);
538 } catch (RemoteException e) {
539 Log.e(TAG, "Can't call notifyAudioFocusRequest() on IAudioPolicyCallback "
540 + mFocusPolicy.asBinder(), e);
541 }
542 return true;
543 }
544
545 /**
546 * Called synchronized on mAudioFocusLock
547 * @param afi
548 * @param requestResult
549 * @return true if the external audio focus policy (if any) is handling the focus request
550 */
551 boolean notifyExtFocusPolicyFocusAbandon_syncAf(AudioFocusInfo afi) {
552 if (mFocusPolicy == null) {
553 return false;
554 }
555 final FocusRequester fr = mFocusOwnersForFocusPolicy.remove(afi.getClientId());
556 if (fr != null) {
557 fr.release();
558 }
559 try {
560 //oneway
561 mFocusPolicy.notifyAudioFocusAbandon(afi);
562 } catch (RemoteException e) {
563 Log.e(TAG, "Can't call notifyAudioFocusAbandon() on IAudioPolicyCallback "
564 + mFocusPolicy.asBinder(), e);
565 }
566 return true;
567 }
568
569 /** see AudioManager.dispatchFocusChange(AudioFocusInfo afi, int focusChange, AudioPolicy ap) */
570 int dispatchFocusChange(AudioFocusInfo afi, int focusChange) {
571 if (DEBUG) {
572 Log.v(TAG, "dispatchFocusChange " + focusChange + " to afi client="
573 + afi.getClientId());
574 }
575 synchronized (mAudioFocusLock) {
576 if (mFocusPolicy == null) {
577 if (DEBUG) { Log.v(TAG, "> failed: no focus policy" ); }
578 return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
579 }
580 final FocusRequester fr = mFocusOwnersForFocusPolicy.get(afi.getClientId());
581 if (fr == null) {
582 if (DEBUG) { Log.v(TAG, "> failed: no such focus requester known" ); }
583 return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
584 }
585 return fr.dispatchFocusChange(focusChange);
586 }
587 }
588
589 private void dumpExtFocusPolicyFocusOwners(PrintWriter pw) {
590 final Set<Entry<String, FocusRequester>> owners = mFocusOwnersForFocusPolicy.entrySet();
591 final Iterator<Entry<String, FocusRequester>> ownerIterator = owners.iterator();
592 while (ownerIterator.hasNext()) {
593 final Entry<String, FocusRequester> owner = ownerIterator.next();
594 final FocusRequester fr = owner.getValue();
595 fr.dump(pw);
596 }
597 }
598
Jean-Michel Trivi23805662013-07-31 14:19:18 -0700599 protected int getCurrentAudioFocus() {
600 synchronized(mAudioFocusLock) {
601 if (mFocusStack.empty()) {
602 return AudioManager.AUDIOFOCUS_NONE;
603 } else {
604 return mFocusStack.peek().getGainRequest();
605 }
606 }
607 }
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700608
Jean-Michel Trivi99489cc2017-01-25 19:08:49 -0800609 /**
Jean-Michel Trivi62b86342017-02-04 15:33:47 -0800610 * Delay after entering ringing or call mode after which the framework will mute streams
611 * that are still playing.
612 */
613 private static final int RING_CALL_MUTING_ENFORCEMENT_DELAY_MS = 100;
614
615 /**
616 * Usages to mute when the device rings or is in a call
617 */
618 private final static int[] USAGES_TO_MUTE_IN_RING_OR_CALL =
619 { AudioAttributes.USAGE_MEDIA, AudioAttributes.USAGE_GAME };
620
621 /**
Jean-Michel Trivi99489cc2017-01-25 19:08:49 -0800622 * Return the volume ramp time expected before playback with the given AudioAttributes would
623 * start after gaining audio focus.
624 * @param attr attributes of the sound about to start playing
625 * @return time in ms
626 */
Jean-Michel Trividce82ab2017-02-07 16:02:33 -0800627 protected static int getFocusRampTimeMs(int focusGain, AudioAttributes attr) {
Jean-Michel Trivi99489cc2017-01-25 19:08:49 -0800628 switch (attr.getUsage()) {
629 case AudioAttributes.USAGE_MEDIA:
630 case AudioAttributes.USAGE_GAME:
631 return 1000;
632 case AudioAttributes.USAGE_ALARM:
633 case AudioAttributes.USAGE_NOTIFICATION_RINGTONE:
634 case AudioAttributes.USAGE_ASSISTANT:
635 case AudioAttributes.USAGE_ASSISTANCE_ACCESSIBILITY:
636 case AudioAttributes.USAGE_ASSISTANCE_NAVIGATION_GUIDANCE:
637 return 700;
638 case AudioAttributes.USAGE_VOICE_COMMUNICATION:
639 case AudioAttributes.USAGE_VOICE_COMMUNICATION_SIGNALLING:
640 case AudioAttributes.USAGE_NOTIFICATION:
641 case AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_REQUEST:
642 case AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_INSTANT:
643 case AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_DELAYED:
644 case AudioAttributes.USAGE_NOTIFICATION_EVENT:
645 case AudioAttributes.USAGE_ASSISTANCE_SONIFICATION:
646 return 500;
647 case AudioAttributes.USAGE_UNKNOWN:
648 default:
649 return 0;
650 }
651 }
652
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -0800653 /** @see AudioManager#requestAudioFocus(AudioManager.OnAudioFocusChangeListener, int, int, int) */
654 protected int requestAudioFocus(AudioAttributes aa, int focusChangeHint, IBinder cb,
Jean-Michel Trivi461922f2017-04-25 15:23:17 -0700655 IAudioFocusDispatcher fd, String clientId, String callingPackageName, int flags,
656 int sdk) {
Jean-Michel Trivi0b67b9f2017-10-05 12:19:23 -0700657 mEventLogger.log((new AudioEventLogger.StringEvent(
658 "requestAudioFocus() from uid/pid " + Binder.getCallingUid()
659 + "/" + Binder.getCallingPid()
660 + " clientId=" + clientId + " callingPack=" + callingPackageName
661 + " req=" + focusChangeHint
662 + " flags=0x" + Integer.toHexString(flags)
663 + " sdk=" + sdk))
664 .printLog(TAG));
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700665 // we need a valid binder callback for clients
666 if (!cb.pingBinder()) {
667 Log.e(TAG, " AudioFocus DOA client for requestAudioFocus(), aborting.");
668 return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
669 }
670
671 if (mAppOps.noteOp(AppOpsManager.OP_TAKE_AUDIO_FOCUS, Binder.getCallingUid(),
672 callingPackageName) != AppOpsManager.MODE_ALLOWED) {
673 return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
674 }
675
676 synchronized(mAudioFocusLock) {
Jean-Michel Trivi0b67b9f2017-10-05 12:19:23 -0700677 if (mFocusStack.size() > MAX_STACK_SIZE) {
678 Log.e(TAG, "Max AudioFocus stack size reached, failing requestAudioFocus()");
679 return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
680 }
681
Jean-Michel Trivi62b86342017-02-04 15:33:47 -0800682 boolean enteringRingOrCall = !mRingOrCallActive
683 & (AudioSystem.IN_VOICE_COMM_FOCUS_ID.compareTo(clientId) == 0);
684 if (enteringRingOrCall) { mRingOrCallActive = true; }
685
Jean-Michel Trivi126cf032017-04-02 23:19:02 -0700686 final AudioFocusInfo afiForExtPolicy;
687 if (mFocusPolicy != null) {
688 // construct AudioFocusInfo as it will be communicated to audio focus policy
689 afiForExtPolicy = new AudioFocusInfo(aa, Binder.getCallingUid(),
690 clientId, callingPackageName, focusChangeHint, 0 /*lossReceived*/,
Jean-Michel Trivi461922f2017-04-25 15:23:17 -0700691 flags, sdk);
Jean-Michel Trivi126cf032017-04-02 23:19:02 -0700692 } else {
693 afiForExtPolicy = null;
694 }
695
696 // handle delayed focus
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -0800697 boolean focusGrantDelayed = false;
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700698 if (!canReassignAudioFocus()) {
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -0800699 if ((flags & AudioManager.AUDIOFOCUS_FLAG_DELAY_OK) == 0) {
Jean-Michel Trivi126cf032017-04-02 23:19:02 -0700700 final int result = AudioManager.AUDIOFOCUS_REQUEST_FAILED;
701 notifyExtFocusPolicyFocusRequest_syncAf(afiForExtPolicy, result, fd, cb);
702 return result;
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -0800703 } else {
704 // request has AUDIOFOCUS_FLAG_DELAY_OK: focus can't be
705 // granted right now, so the requester will be inserted in the focus stack
706 // to receive focus later
707 focusGrantDelayed = true;
708 }
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700709 }
710
Jean-Michel Trivi126cf032017-04-02 23:19:02 -0700711 // external focus policy: delay request for focus gain?
712 final int resultWithExtPolicy = AudioManager.AUDIOFOCUS_REQUEST_DELAYED;
713 if (notifyExtFocusPolicyFocusRequest_syncAf(
714 afiForExtPolicy, resultWithExtPolicy, fd, cb)) {
715 // stop handling focus request here as it is handled by external audio focus policy
716 return resultWithExtPolicy;
717 }
718
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700719 // handle the potential premature death of the new holder of the focus
720 // (premature death == death before abandoning focus)
721 // Register for client death notification
722 AudioFocusDeathHandler afdh = new AudioFocusDeathHandler(cb);
Jean-Michel Trivie8987722016-07-07 15:38:32 -0700723
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700724 try {
725 cb.linkToDeath(afdh, 0);
726 } catch (RemoteException e) {
727 // client has already died!
728 Log.w(TAG, "AudioFocus requestAudioFocus() could not link to "+cb+" binder death");
729 return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
730 }
731
Jean-Michel Trivi83283f22013-07-29 18:09:41 -0700732 if (!mFocusStack.empty() && mFocusStack.peek().hasSameClient(clientId)) {
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700733 // if focus is already owned by this client and the reason for acquiring the focus
734 // hasn't changed, don't do anything
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -0800735 final FocusRequester fr = mFocusStack.peek();
736 if (fr.getGainRequest() == focusChangeHint && fr.getGrantFlags() == flags) {
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700737 // unlink death handler so it can be gc'ed.
738 // linkToDeath() creates a JNI global reference preventing collection.
739 cb.unlinkToDeath(afdh, 0);
Jean-Michel Trivi0212be52014-11-24 14:43:10 -0800740 notifyExtPolicyFocusGrant_syncAf(fr.toAudioFocusInfo(),
741 AudioManager.AUDIOFOCUS_REQUEST_GRANTED);
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700742 return AudioManager.AUDIOFOCUS_REQUEST_GRANTED;
743 }
744 // the reason for the audio focus request has changed: remove the current top of
745 // stack and respond as if we had a new focus owner
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -0800746 if (!focusGrantDelayed) {
747 mFocusStack.pop();
748 // the entry that was "popped" is the same that was "peeked" above
749 fr.release();
750 }
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700751 }
752
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700753 // focus requester might already be somewhere below in the stack, remove it
Jean-Michel Trivi0212be52014-11-24 14:43:10 -0800754 removeFocusStackEntry(clientId, false /* signal */, false /*notifyFocusFollowers*/);
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700755
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -0800756 final FocusRequester nfr = new FocusRequester(aa, focusChangeHint, flags, fd, cb,
Jean-Michel Trivi461922f2017-04-25 15:23:17 -0700757 clientId, afdh, callingPackageName, Binder.getCallingUid(), this, sdk);
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -0800758 if (focusGrantDelayed) {
759 // focusGrantDelayed being true implies we can't reassign focus right now
760 // which implies the focus stack is not empty.
Jean-Michel Trivi0212be52014-11-24 14:43:10 -0800761 final int requestResult = pushBelowLockedFocusOwners(nfr);
762 if (requestResult != AudioManager.AUDIOFOCUS_REQUEST_FAILED) {
763 notifyExtPolicyFocusGrant_syncAf(nfr.toAudioFocusInfo(), requestResult);
764 }
765 return requestResult;
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -0800766 } else {
767 // propagate the focus change through the stack
768 if (!mFocusStack.empty()) {
Jean-Michel Trivi99489cc2017-01-25 19:08:49 -0800769 propagateFocusLossFromGain_syncAf(focusChangeHint, nfr);
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -0800770 }
Jean-Michel Trivicbb212f2013-07-30 15:09:33 -0700771
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -0800772 // push focus requester at the top of the audio focus stack
773 mFocusStack.push(nfr);
Jean-Michel Trivi270f1c92017-05-05 11:43:31 -0700774 nfr.handleFocusGainFromRequest(AudioManager.AUDIOFOCUS_REQUEST_GRANTED);
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -0800775 }
Jean-Michel Trivi0212be52014-11-24 14:43:10 -0800776 notifyExtPolicyFocusGrant_syncAf(nfr.toAudioFocusInfo(),
777 AudioManager.AUDIOFOCUS_REQUEST_GRANTED);
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700778
Jean-Michel Trivi62b86342017-02-04 15:33:47 -0800779 if (ENFORCE_MUTING_FOR_RING_OR_CALL & enteringRingOrCall) {
780 runAudioCheckerForRingOrCallAsync(true/*enteringRingOrCall*/);
781 }
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700782 }//synchronized(mAudioFocusLock)
783
784 return AudioManager.AUDIOFOCUS_REQUEST_GRANTED;
785 }
786
Jean-Michel Trivi958876f2014-11-16 15:40:22 -0800787 /**
788 * @see AudioManager#abandonAudioFocus(AudioManager.OnAudioFocusChangeListener, AudioAttributes)
789 * */
Jean-Michel Trivi126cf032017-04-02 23:19:02 -0700790 protected int abandonAudioFocus(IAudioFocusDispatcher fl, String clientId, AudioAttributes aa,
791 String callingPackageName) {
Jean-Michel Trivi0b67b9f2017-10-05 12:19:23 -0700792 // AudioAttributes are currently ignored, to be used for zones / a11y
793 mEventLogger.log((new AudioEventLogger.StringEvent(
794 "abandonAudioFocus() from uid/pid " + Binder.getCallingUid()
795 + "/" + Binder.getCallingPid()
796 + " clientId=" + clientId))
797 .printLog(TAG));
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700798 try {
799 // this will take care of notifying the new focus owner if needed
800 synchronized(mAudioFocusLock) {
Jean-Michel Trivi126cf032017-04-02 23:19:02 -0700801 // external focus policy?
802 if (mFocusPolicy != null) {
803 final AudioFocusInfo afi = new AudioFocusInfo(aa, Binder.getCallingUid(),
804 clientId, callingPackageName, 0 /*gainRequest*/, 0 /*lossReceived*/,
Jean-Michel Trivi461922f2017-04-25 15:23:17 -0700805 0 /*flags*/, 0 /* sdk n/a here*/);
Jean-Michel Trivi126cf032017-04-02 23:19:02 -0700806 if (notifyExtFocusPolicyFocusAbandon_syncAf(afi)) {
807 return AudioManager.AUDIOFOCUS_REQUEST_GRANTED;
808 }
809 }
810
Jean-Michel Trivi62b86342017-02-04 15:33:47 -0800811 boolean exitingRingOrCall = mRingOrCallActive
812 & (AudioSystem.IN_VOICE_COMM_FOCUS_ID.compareTo(clientId) == 0);
813 if (exitingRingOrCall) { mRingOrCallActive = false; }
814
Jean-Michel Trivi0212be52014-11-24 14:43:10 -0800815 removeFocusStackEntry(clientId, true /*signal*/, true /*notifyFocusFollowers*/);
Jean-Michel Trivi62b86342017-02-04 15:33:47 -0800816
817 if (ENFORCE_MUTING_FOR_RING_OR_CALL & exitingRingOrCall) {
818 runAudioCheckerForRingOrCallAsync(false/*enteringRingOrCall*/);
819 }
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700820 }
821 } catch (java.util.ConcurrentModificationException cme) {
822 // Catching this exception here is temporary. It is here just to prevent
823 // a crash seen when the "Silent" notification is played. This is believed to be fixed
824 // but this try catch block is left just to be safe.
825 Log.e(TAG, "FATAL EXCEPTION AudioFocus abandonAudioFocus() caused " + cme);
826 cme.printStackTrace();
827 }
828
829 return AudioManager.AUDIOFOCUS_REQUEST_GRANTED;
830 }
831
832
833 protected void unregisterAudioFocusClient(String clientId) {
834 synchronized(mAudioFocusLock) {
Jean-Michel Trivi0212be52014-11-24 14:43:10 -0800835 removeFocusStackEntry(clientId, false, true /*notifyFocusFollowers*/);
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700836 }
837 }
838
Jean-Michel Trivi62b86342017-02-04 15:33:47 -0800839 private void runAudioCheckerForRingOrCallAsync(final boolean enteringRingOrCall) {
840 new Thread() {
841 public void run() {
842 if (enteringRingOrCall) {
843 try {
844 Thread.sleep(RING_CALL_MUTING_ENFORCEMENT_DELAY_MS);
845 } catch (InterruptedException e) {
846 e.printStackTrace();
847 }
848 }
849 synchronized (mAudioFocusLock) {
850 // since the new thread starting running the state could have changed, so
851 // we need to check again mRingOrCallActive, not enteringRingOrCall
852 if (mRingOrCallActive) {
853 mFocusEnforcer.mutePlayersForCall(USAGES_TO_MUTE_IN_RING_OR_CALL);
854 } else {
855 mFocusEnforcer.unmutePlayersForCall();
856 }
857 }
858 }
859 }.start();
860 }
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700861}