blob: d023bd7827ff1a610bb929c98f8c5d00eb87fea8 [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 Trivid9fef5c2017-12-28 15:25:35 -080035import com.android.internal.annotations.GuardedBy;
36
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -070037import java.io.PrintWriter;
38import java.util.ArrayList;
Jean-Michel Trivi545fcf82015-04-07 09:45:35 -070039import java.util.Date;
Jean-Michel Trivi126cf032017-04-02 23:19:02 -070040import java.util.HashMap;
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -070041import java.util.Iterator;
Jean-Michel Trivid9fef5c2017-12-28 15:25:35 -080042import java.util.LinkedList;
43import java.util.List;
Jean-Michel Trivi126cf032017-04-02 23:19:02 -070044import java.util.Map.Entry;
45import java.util.Set;
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -070046import java.util.Stack;
Jean-Michel Trivi545fcf82015-04-07 09:45:35 -070047import java.text.DateFormat;
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -070048
49/**
50 * @hide
51 *
52 */
Jean-Michel Trivi99489cc2017-01-25 19:08:49 -080053public class MediaFocusControl implements PlayerFocusEnforcer {
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -070054
55 private static final String TAG = "MediaFocusControl";
Jean-Michel Trivi126cf032017-04-02 23:19:02 -070056 static final boolean DEBUG = false;
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -070057
Jean-Michel Trivi99489cc2017-01-25 19:08:49 -080058 /**
59 * set to true so the framework enforces ducking itself, without communicating to apps
Jean-Michel Trivi952f2342017-03-06 16:16:56 -080060 * that they lost focus for most use cases.
Jean-Michel Trivi99489cc2017-01-25 19:08:49 -080061 */
Jean-Michel Trivi952f2342017-03-06 16:16:56 -080062 static final boolean ENFORCE_DUCKING = true;
Jean-Michel Trivi62b86342017-02-04 15:33:47 -080063 /**
Jean-Michel Trivi461922f2017-04-25 15:23:17 -070064 * set to true to the framework enforces ducking itself only with apps above a given SDK
65 * target level. Is ignored if ENFORCE_DUCKING is false.
66 */
67 static final boolean ENFORCE_DUCKING_FOR_NEW = true;
68 /**
69 * the SDK level (included) up to which the framework doesn't enforce ducking itself. Is ignored
70 * if ENFORCE_DUCKING_FOR_NEW is false;
71 */
72 // automatic ducking was introduced for Android O
73 static final int DUCKING_IN_APP_SDK_LEVEL = Build.VERSION_CODES.N_MR1;
74 /**
Jean-Michel Trivi62b86342017-02-04 15:33:47 -080075 * set to true so the framework enforces muting media/game itself when the device is ringing
76 * or in a call.
77 */
78 static final boolean ENFORCE_MUTING_FOR_RING_OR_CALL = true;
Jean-Michel Trivi99489cc2017-01-25 19:08:49 -080079
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -070080 private final Context mContext;
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -070081 private final AppOpsManager mAppOps;
Jean-Michel Trivi99489cc2017-01-25 19:08:49 -080082 private PlayerFocusEnforcer mFocusEnforcer; // never null
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -070083
Jean-Michel Trivi62b86342017-02-04 15:33:47 -080084 private boolean mRingOrCallActive = false;
85
Jean-Michel Trivie2d8aae2018-01-30 15:09:47 -080086 private final Object mExtFocusChangeLock = new Object();
87 @GuardedBy("mExtFocusChangeLock")
88 private long mExtFocusChangeCounter;
89
Jean-Michel Trivi99489cc2017-01-25 19:08:49 -080090 protected MediaFocusControl(Context cntxt, PlayerFocusEnforcer pfe) {
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -070091 mContext = cntxt;
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -070092 mAppOps = (AppOpsManager)mContext.getSystemService(Context.APP_OPS_SERVICE);
Jean-Michel Trivi99489cc2017-01-25 19:08:49 -080093 mFocusEnforcer = pfe;
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -070094 }
95
Jean-Michel Trivi73673ab2013-08-06 10:42:45 -070096 protected void dump(PrintWriter pw) {
Jean-Michel Trivi545fcf82015-04-07 09:45:35 -070097 pw.println("\nMediaFocusControl dump time: "
98 + DateFormat.getTimeInstance().format(new Date()));
Jean-Michel Trivi73673ab2013-08-06 10:42:45 -070099 dumpFocusStack(pw);
Jean-Michel Trivi0b67b9f2017-10-05 12:19:23 -0700100 pw.println("\n");
101 // log
102 mEventLogger.dump(pw);
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700103 }
104
Jean-Michel Trivi99489cc2017-01-25 19:08:49 -0800105 //=================================================================
106 // PlayerFocusEnforcer implementation
107 @Override
Jean-Michel Trivi9228af62018-01-05 17:06:17 -0800108 public boolean duckPlayers(FocusRequester winner, FocusRequester loser, boolean forceDuck) {
109 return mFocusEnforcer.duckPlayers(winner, loser, forceDuck);
Jean-Michel Trivi99489cc2017-01-25 19:08:49 -0800110 }
111
112 @Override
113 public void unduckPlayers(FocusRequester winner) {
114 mFocusEnforcer.unduckPlayers(winner);
115 }
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700116
Jean-Michel Trivi62b86342017-02-04 15:33:47 -0800117 @Override
118 public void mutePlayersForCall(int[] usagesToMute) {
119 mFocusEnforcer.mutePlayersForCall(usagesToMute);
120 }
121
122 @Override
123 public void unmutePlayersForCall() {
124 mFocusEnforcer.unmutePlayersForCall();
125 }
126
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700127 //==========================================================================================
128 // AudioFocus
129 //==========================================================================================
130
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700131 private final static Object mAudioFocusLock = new Object();
132
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700133 /**
Jean-Michel Trivi0b67b9f2017-10-05 12:19:23 -0700134 * Arbitrary maximum size of audio focus stack to prevent apps OOM'ing this process.
135 */
136 private static final int MAX_STACK_SIZE = 100;
137
138 private static final AudioEventLogger mEventLogger = new AudioEventLogger(50,
139 "focus commands as seen by MediaFocusControl");
140
141 /**
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700142 * Discard the current audio focus owner.
143 * Notify top of audio focus stack that it lost focus (regardless of possibility to reassign
144 * focus), remove it from the stack, and clear the remote control display.
145 */
146 protected void discardAudioFocusOwner() {
147 synchronized(mAudioFocusLock) {
Jean-Michel Trivicbb212f2013-07-30 15:09:33 -0700148 if (!mFocusStack.empty()) {
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700149 // notify the current focus owner it lost focus after removing it from stack
Jean-Michel Trivi83283f22013-07-29 18:09:41 -0700150 final FocusRequester exFocusOwner = mFocusStack.pop();
Jean-Michel Trivi9228af62018-01-05 17:06:17 -0800151 exFocusOwner.handleFocusLoss(AudioManager.AUDIOFOCUS_LOSS, null,
152 false /*forceDuck*/);
Jean-Michel Trivi83283f22013-07-29 18:09:41 -0700153 exFocusOwner.release();
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700154 }
155 }
156 }
157
Jean-Michel Trivid9fef5c2017-12-28 15:25:35 -0800158 @GuardedBy("mAudioFocusLock")
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700159 private void notifyTopOfAudioFocusStack() {
160 // notify the top of the stack it gained focus
Jean-Michel Trivicbb212f2013-07-30 15:09:33 -0700161 if (!mFocusStack.empty()) {
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700162 if (canReassignAudioFocus()) {
Jean-Michel Trivi00bf4b12013-07-26 17:19:32 -0700163 mFocusStack.peek().handleFocusGain(AudioManager.AUDIOFOCUS_GAIN);
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700164 }
165 }
166 }
167
Jean-Michel Trivicbb212f2013-07-30 15:09:33 -0700168 /**
169 * Focus is requested, propagate the associated loss throughout the stack.
Jean-Michel Trivid9fef5c2017-12-28 15:25:35 -0800170 * Will also remove entries in the stack that have just received a definitive loss of focus.
Jean-Michel Trivicbb212f2013-07-30 15:09:33 -0700171 * @param focusGain the new focus gain that will later be added at the top of the stack
172 */
Jean-Michel Trivid9fef5c2017-12-28 15:25:35 -0800173 @GuardedBy("mAudioFocusLock")
Jean-Michel Trivi9228af62018-01-05 17:06:17 -0800174 private void propagateFocusLossFromGain_syncAf(int focusGain, final FocusRequester fr,
175 boolean forceDuck) {
Jean-Michel Trivid9fef5c2017-12-28 15:25:35 -0800176 final List<String> clientsToRemove = new LinkedList<String>();
Jean-Michel Trivicbb212f2013-07-30 15:09:33 -0700177 // going through the audio focus stack to signal new focus, traversing order doesn't
178 // matter as all entries respond to the same external focus gain
Jean-Michel Trivid9fef5c2017-12-28 15:25:35 -0800179 for (FocusRequester focusLoser : mFocusStack) {
180 final boolean isDefinitiveLoss =
Jean-Michel Trivi9228af62018-01-05 17:06:17 -0800181 focusLoser.handleFocusLossFromGain(focusGain, fr, forceDuck);
Jean-Michel Trivid9fef5c2017-12-28 15:25:35 -0800182 if (isDefinitiveLoss) {
183 clientsToRemove.add(focusLoser.getClientId());
184 }
185 }
186 for (String clientToRemove : clientsToRemove) {
187 removeFocusStackEntry(clientToRemove, false /*signal*/,
188 true /*notifyFocusFollowers*/);
Jean-Michel Trivicbb212f2013-07-30 15:09:33 -0700189 }
190 }
191
Jean-Michel Trivi83283f22013-07-29 18:09:41 -0700192 private final Stack<FocusRequester> mFocusStack = new Stack<FocusRequester>();
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700193
194 /**
195 * Helper function:
196 * Display in the log the current entries in the audio focus stack
197 */
198 private void dumpFocusStack(PrintWriter pw) {
199 pw.println("\nAudio Focus stack entries (last is top of stack):");
200 synchronized(mAudioFocusLock) {
Jean-Michel Trivi83283f22013-07-29 18:09:41 -0700201 Iterator<FocusRequester> stackIterator = mFocusStack.iterator();
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700202 while(stackIterator.hasNext()) {
Jean-Michel Trivi83283f22013-07-29 18:09:41 -0700203 stackIterator.next().dump(pw);
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700204 }
Jean-Michel Trivi126cf032017-04-02 23:19:02 -0700205 pw.println("\n");
206 if (mFocusPolicy == null) {
207 pw.println("No external focus policy\n");
208 } else {
209 pw.println("External focus policy: "+ mFocusPolicy + ", focus owners:\n");
210 dumpExtFocusPolicyFocusOwners(pw);
211 }
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700212 }
Jean-Michel Trivi62b86342017-02-04 15:33:47 -0800213 pw.println("\n");
214 pw.println(" Notify on duck: " + mNotifyFocusOwnerOnDuck + "\n");
215 pw.println(" In ring or call: " + mRingOrCallActive + "\n");
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700216 }
217
218 /**
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700219 * Remove a focus listener from the focus stack.
220 * @param clientToRemove the focus listener
221 * @param signal if true and the listener was at the top of the focus stack, i.e. it was holding
222 * focus, notify the next item in the stack it gained focus.
223 */
Jean-Michel Trivid9fef5c2017-12-28 15:25:35 -0800224 @GuardedBy("mAudioFocusLock")
Jean-Michel Trivi0212be52014-11-24 14:43:10 -0800225 private void removeFocusStackEntry(String clientToRemove, boolean signal,
226 boolean notifyFocusFollowers) {
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700227 // is the current top of the focus stack abandoning focus? (because of request, not death)
Jean-Michel Trivi83283f22013-07-29 18:09:41 -0700228 if (!mFocusStack.empty() && mFocusStack.peek().hasSameClient(clientToRemove))
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700229 {
230 //Log.i(TAG, " removeFocusStackEntry() removing top of stack");
Jean-Michel Trivi83283f22013-07-29 18:09:41 -0700231 FocusRequester fr = mFocusStack.pop();
232 fr.release();
Jean-Michel Trivi0212be52014-11-24 14:43:10 -0800233 if (notifyFocusFollowers) {
234 final AudioFocusInfo afi = fr.toAudioFocusInfo();
235 afi.clearLossReceived();
236 notifyExtPolicyFocusLoss_syncAf(afi, false);
237 }
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700238 if (signal) {
239 // notify the new top of the stack it gained focus
240 notifyTopOfAudioFocusStack();
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700241 }
242 } else {
243 // focus is abandoned by a client that's not at the top of the stack,
244 // no need to update focus.
245 // (using an iterator on the stack so we can safely remove an entry after having
246 // evaluated it, traversal order doesn't matter here)
Jean-Michel Trivi83283f22013-07-29 18:09:41 -0700247 Iterator<FocusRequester> stackIterator = mFocusStack.iterator();
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700248 while(stackIterator.hasNext()) {
RoboErik01fe6612014-02-13 14:19:04 -0800249 FocusRequester fr = stackIterator.next();
Jean-Michel Trivi83283f22013-07-29 18:09:41 -0700250 if(fr.hasSameClient(clientToRemove)) {
Jean-Michel Trivi00bf4b12013-07-26 17:19:32 -0700251 Log.i(TAG, "AudioFocus removeFocusStackEntry(): removing entry for "
Jean-Michel Trivi83283f22013-07-29 18:09:41 -0700252 + clientToRemove);
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700253 stackIterator.remove();
Jean-Michel Trivie8987722016-07-07 15:38:32 -0700254 // stack entry not used anymore, clear references
Jean-Michel Trivi83283f22013-07-29 18:09:41 -0700255 fr.release();
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700256 }
257 }
258 }
259 }
260
261 /**
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700262 * Remove focus listeners from the focus stack for a particular client when it has died.
263 */
Jean-Michel Trivid9fef5c2017-12-28 15:25:35 -0800264 @GuardedBy("mAudioFocusLock")
Jean-Michel Trivie8987722016-07-07 15:38:32 -0700265 private void removeFocusStackEntryOnDeath(IBinder cb) {
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700266 // is the owner of the audio focus part of the client to remove?
267 boolean isTopOfStackForClientToRemove = !mFocusStack.isEmpty() &&
Jean-Michel Trivi83283f22013-07-29 18:09:41 -0700268 mFocusStack.peek().hasSameBinder(cb);
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700269 // (using an iterator on the stack so we can safely remove an entry after having
270 // evaluated it, traversal order doesn't matter here)
Jean-Michel Trivi83283f22013-07-29 18:09:41 -0700271 Iterator<FocusRequester> stackIterator = mFocusStack.iterator();
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700272 while(stackIterator.hasNext()) {
RoboErik01fe6612014-02-13 14:19:04 -0800273 FocusRequester fr = stackIterator.next();
Jean-Michel Trivi83283f22013-07-29 18:09:41 -0700274 if(fr.hasSameBinder(cb)) {
Jean-Michel Trivie8987722016-07-07 15:38:32 -0700275 Log.i(TAG, "AudioFocus removeFocusStackEntryOnDeath(): removing entry for " + cb);
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700276 stackIterator.remove();
Jean-Michel Trivie8987722016-07-07 15:38:32 -0700277 // stack entry not used anymore, clear references
278 fr.release();
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700279 }
280 }
281 if (isTopOfStackForClientToRemove) {
282 // we removed an entry at the top of the stack:
283 // notify the new top of the stack it gained focus.
284 notifyTopOfAudioFocusStack();
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700285 }
286 }
287
288 /**
Jean-Michel Trivi126cf032017-04-02 23:19:02 -0700289 * Helper function for external focus policy:
Jean-Michel Trivi126cf032017-04-02 23:19:02 -0700290 * Remove focus listeners from the list of potential focus owners for a particular client when
291 * it has died.
292 */
Jean-Michel Trivid9fef5c2017-12-28 15:25:35 -0800293 @GuardedBy("mAudioFocusLock")
Jean-Michel Trivi126cf032017-04-02 23:19:02 -0700294 private void removeFocusEntryForExtPolicy(IBinder cb) {
295 if (mFocusOwnersForFocusPolicy.isEmpty()) {
296 return;
297 }
298 boolean released = false;
299 final Set<Entry<String, FocusRequester>> owners = mFocusOwnersForFocusPolicy.entrySet();
300 final Iterator<Entry<String, FocusRequester>> ownerIterator = owners.iterator();
301 while (ownerIterator.hasNext()) {
302 final Entry<String, FocusRequester> owner = ownerIterator.next();
303 final FocusRequester fr = owner.getValue();
304 if (fr.hasSameBinder(cb)) {
305 ownerIterator.remove();
306 fr.release();
307 notifyExtFocusPolicyFocusAbandon_syncAf(fr.toAudioFocusInfo());
308 break;
309 }
310 }
311 }
312
313 /**
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700314 * Helper function:
315 * 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 -0800316 * The implementation guarantees that a state where focus cannot be immediately reassigned
Jean-Michel Trivi958876f2014-11-16 15:40:22 -0800317 * implies that an "locked" focus owner is at the top of the focus stack.
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -0800318 * Modifications to the implementation that break this assumption will cause focus requests to
319 * misbehave when honoring the AudioManager.AUDIOFOCUS_FLAG_DELAY_OK flag.
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700320 */
321 private boolean canReassignAudioFocus() {
322 // focus requests are rejected during a phone call or when the phone is ringing
323 // this is equivalent to IN_VOICE_COMM_FOCUS_ID having the focus
Jean-Michel Trivi958876f2014-11-16 15:40:22 -0800324 if (!mFocusStack.isEmpty() && isLockedFocusOwner(mFocusStack.peek())) {
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700325 return false;
326 }
327 return true;
328 }
329
Jean-Michel Trivi958876f2014-11-16 15:40:22 -0800330 private boolean isLockedFocusOwner(FocusRequester fr) {
John Spurlock61560172015-02-06 19:46:04 -0500331 return (fr.hasSameClient(AudioSystem.IN_VOICE_COMM_FOCUS_ID) || fr.isLockedFocusOwner());
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -0800332 }
333
334 /**
335 * Helper function
Jean-Michel Trivi958876f2014-11-16 15:40:22 -0800336 * Pre-conditions: focus stack is not empty, there is one or more locked focus owner
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -0800337 * at the top of the focus stack
338 * Push the focus requester onto the audio focus stack at the first position immediately
Jean-Michel Trivi958876f2014-11-16 15:40:22 -0800339 * following the locked focus owners.
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -0800340 * @return {@link AudioManager#AUDIOFOCUS_REQUEST_GRANTED} or
341 * {@link AudioManager#AUDIOFOCUS_REQUEST_DELAYED}
342 */
Jean-Michel Trivid9fef5c2017-12-28 15:25:35 -0800343 @GuardedBy("mAudioFocusLock")
Jean-Michel Trivi958876f2014-11-16 15:40:22 -0800344 private int pushBelowLockedFocusOwners(FocusRequester nfr) {
345 int lastLockedFocusOwnerIndex = mFocusStack.size();
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -0800346 for (int index = mFocusStack.size()-1; index >= 0; index--) {
Jean-Michel Trivi958876f2014-11-16 15:40:22 -0800347 if (isLockedFocusOwner(mFocusStack.elementAt(index))) {
348 lastLockedFocusOwnerIndex = index;
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -0800349 }
350 }
Jean-Michel Trivi958876f2014-11-16 15:40:22 -0800351 if (lastLockedFocusOwnerIndex == mFocusStack.size()) {
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -0800352 // this should not happen, but handle it and log an error
353 Log.e(TAG, "No exclusive focus owner found in propagateFocusLossFromGain_syncAf()",
354 new Exception());
355 // no exclusive owner, push at top of stack, focus is granted, propagate change
Jean-Michel Trivi9228af62018-01-05 17:06:17 -0800356 propagateFocusLossFromGain_syncAf(nfr.getGainRequest(), nfr, false /*forceDuck*/);
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -0800357 mFocusStack.push(nfr);
358 return AudioManager.AUDIOFOCUS_REQUEST_GRANTED;
359 } else {
Jean-Michel Trivi958876f2014-11-16 15:40:22 -0800360 mFocusStack.insertElementAt(nfr, lastLockedFocusOwnerIndex);
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -0800361 return AudioManager.AUDIOFOCUS_REQUEST_DELAYED;
362 }
363 }
364
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700365 /**
366 * Inner class to monitor audio focus client deaths, and remove them from the audio focus
367 * stack if necessary.
368 */
Jean-Michel Trivi83283f22013-07-29 18:09:41 -0700369 protected class AudioFocusDeathHandler implements IBinder.DeathRecipient {
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700370 private IBinder mCb; // To be notified of client's death
371
372 AudioFocusDeathHandler(IBinder cb) {
373 mCb = cb;
374 }
375
376 public void binderDied() {
377 synchronized(mAudioFocusLock) {
Jean-Michel Trivi126cf032017-04-02 23:19:02 -0700378 if (mFocusPolicy != null) {
379 removeFocusEntryForExtPolicy(mCb);
380 } else {
381 removeFocusStackEntryOnDeath(mCb);
382 }
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700383 }
384 }
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700385 }
386
Jean-Michel Trivi0212be52014-11-24 14:43:10 -0800387 /**
388 * Indicates whether to notify an audio focus owner when it loses focus
389 * with {@link AudioManager#AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK} if it will only duck.
390 * This variable being false indicates an AudioPolicy has been registered and has signaled
391 * it will handle audio ducking.
392 */
393 private boolean mNotifyFocusOwnerOnDuck = true;
394
395 protected void setDuckingInExtPolicyAvailable(boolean available) {
396 mNotifyFocusOwnerOnDuck = !available;
397 }
398
399 boolean mustNotifyFocusOwnerOnDuck() { return mNotifyFocusOwnerOnDuck; }
400
401 private ArrayList<IAudioPolicyCallback> mFocusFollowers = new ArrayList<IAudioPolicyCallback>();
402
403 void addFocusFollower(IAudioPolicyCallback ff) {
404 if (ff == null) {
405 return;
406 }
407 synchronized(mAudioFocusLock) {
408 boolean found = false;
409 for (IAudioPolicyCallback pcb : mFocusFollowers) {
410 if (pcb.asBinder().equals(ff.asBinder())) {
411 found = true;
412 break;
413 }
414 }
415 if (found) {
416 return;
417 } else {
418 mFocusFollowers.add(ff);
Jean-Michel Trivi60fd0842015-03-13 10:11:28 -0700419 notifyExtPolicyCurrentFocusAsync(ff);
Jean-Michel Trivi0212be52014-11-24 14:43:10 -0800420 }
421 }
422 }
423
424 void removeFocusFollower(IAudioPolicyCallback ff) {
425 if (ff == null) {
426 return;
427 }
428 synchronized(mAudioFocusLock) {
429 for (IAudioPolicyCallback pcb : mFocusFollowers) {
430 if (pcb.asBinder().equals(ff.asBinder())) {
431 mFocusFollowers.remove(pcb);
432 break;
433 }
434 }
435 }
436 }
437
Jean-Michel Trivi126cf032017-04-02 23:19:02 -0700438 private IAudioPolicyCallback mFocusPolicy = null;
439
440 // Since we don't have a stack of focus owners when using an external focus policy, we keep
441 // track of all the focus requesters in this map, with their clientId as the key. This is
442 // used both for focus dispatch and death handling
443 private HashMap<String, FocusRequester> mFocusOwnersForFocusPolicy =
444 new HashMap<String, FocusRequester>();
445
446 void setFocusPolicy(IAudioPolicyCallback policy) {
447 if (policy == null) {
448 return;
449 }
450 synchronized (mAudioFocusLock) {
451 mFocusPolicy = policy;
452 }
453 }
454
455 void unsetFocusPolicy(IAudioPolicyCallback policy) {
456 if (policy == null) {
457 return;
458 }
459 synchronized (mAudioFocusLock) {
460 if (mFocusPolicy == policy) {
461 mFocusPolicy = null;
462 }
463 }
464 }
465
Jean-Michel Trivi0212be52014-11-24 14:43:10 -0800466 /**
Jean-Michel Trivi60fd0842015-03-13 10:11:28 -0700467 * @param pcb non null
468 */
469 void notifyExtPolicyCurrentFocusAsync(IAudioPolicyCallback pcb) {
470 final IAudioPolicyCallback pcb2 = pcb;
471 final Thread thread = new Thread() {
472 @Override
473 public void run() {
474 synchronized(mAudioFocusLock) {
475 if (mFocusStack.isEmpty()) {
476 return;
477 }
478 try {
479 pcb2.notifyAudioFocusGrant(mFocusStack.peek().toAudioFocusInfo(),
480 // top of focus stack always has focus
481 AudioManager.AUDIOFOCUS_REQUEST_GRANTED);
482 } catch (RemoteException e) {
483 Log.e(TAG, "Can't call notifyAudioFocusGrant() on IAudioPolicyCallback "
484 + pcb2.asBinder(), e);
485 }
486 }
487 }
488 };
489 thread.start();
490 }
491
492 /**
Jean-Michel Trivi0212be52014-11-24 14:43:10 -0800493 * Called synchronized on mAudioFocusLock
494 */
495 void notifyExtPolicyFocusGrant_syncAf(AudioFocusInfo afi, int requestResult) {
496 for (IAudioPolicyCallback pcb : mFocusFollowers) {
497 try {
498 // oneway
499 pcb.notifyAudioFocusGrant(afi, requestResult);
500 } catch (RemoteException e) {
Jean-Michel Trivi60fd0842015-03-13 10:11:28 -0700501 Log.e(TAG, "Can't call notifyAudioFocusGrant() on IAudioPolicyCallback "
Jean-Michel Trivi0212be52014-11-24 14:43:10 -0800502 + pcb.asBinder(), e);
503 }
504 }
505 }
506
507 /**
508 * Called synchronized on mAudioFocusLock
509 */
510 void notifyExtPolicyFocusLoss_syncAf(AudioFocusInfo afi, boolean wasDispatched) {
511 for (IAudioPolicyCallback pcb : mFocusFollowers) {
512 try {
513 // oneway
514 pcb.notifyAudioFocusLoss(afi, wasDispatched);
515 } catch (RemoteException e) {
Jean-Michel Trivi60fd0842015-03-13 10:11:28 -0700516 Log.e(TAG, "Can't call notifyAudioFocusLoss() on IAudioPolicyCallback "
Jean-Michel Trivi0212be52014-11-24 14:43:10 -0800517 + pcb.asBinder(), e);
518 }
519 }
520 }
521
Jean-Michel Trivi126cf032017-04-02 23:19:02 -0700522 /**
523 * Called synchronized on mAudioFocusLock
524 * @param afi
525 * @param requestResult
526 * @return true if the external audio focus policy (if any) is handling the focus request
527 */
Jean-Michel Trivie2d8aae2018-01-30 15:09:47 -0800528 boolean notifyExtFocusPolicyFocusRequest_syncAf(AudioFocusInfo afi,
Jean-Michel Trivi126cf032017-04-02 23:19:02 -0700529 IAudioFocusDispatcher fd, IBinder cb) {
530 if (mFocusPolicy == null) {
531 return false;
532 }
533 if (DEBUG) {
534 Log.v(TAG, "notifyExtFocusPolicyFocusRequest client="+afi.getClientId()
535 + " dispatcher=" + fd);
536 }
Jean-Michel Trivie2d8aae2018-01-30 15:09:47 -0800537 synchronized (mExtFocusChangeLock) {
538 afi.setGen(mExtFocusChangeCounter++);
539 }
Jean-Michel Trivi126cf032017-04-02 23:19:02 -0700540 final FocusRequester existingFr = mFocusOwnersForFocusPolicy.get(afi.getClientId());
541 if (existingFr != null) {
542 if (!existingFr.hasSameDispatcher(fd)) {
543 existingFr.release();
544 final AudioFocusDeathHandler hdlr = new AudioFocusDeathHandler(cb);
545 mFocusOwnersForFocusPolicy.put(afi.getClientId(),
546 new FocusRequester(afi, fd, cb, hdlr, this));
547 }
Jean-Michel Trivie2d8aae2018-01-30 15:09:47 -0800548 } else {
Jean-Michel Trivi126cf032017-04-02 23:19:02 -0700549 // new focus (future) focus owner to keep track of
550 final AudioFocusDeathHandler hdlr = new AudioFocusDeathHandler(cb);
551 mFocusOwnersForFocusPolicy.put(afi.getClientId(),
552 new FocusRequester(afi, fd, cb, hdlr, this));
553 }
554 try {
555 //oneway
Jean-Michel Trivie2d8aae2018-01-30 15:09:47 -0800556 mFocusPolicy.notifyAudioFocusRequest(afi, AudioManager.AUDIOFOCUS_REQUEST_GRANTED);
557 return true;
Jean-Michel Trivi126cf032017-04-02 23:19:02 -0700558 } catch (RemoteException e) {
559 Log.e(TAG, "Can't call notifyAudioFocusRequest() on IAudioPolicyCallback "
560 + mFocusPolicy.asBinder(), e);
561 }
Jean-Michel Trivie2d8aae2018-01-30 15:09:47 -0800562 return false;
563 }
564
565 void setFocusRequestResultFromExtPolicy(AudioFocusInfo afi, int requestResult) {
566 synchronized (mExtFocusChangeLock) {
567 if (afi.getGen() > mExtFocusChangeCounter) {
568 return;
569 }
570 }
571 final FocusRequester fr = mFocusOwnersForFocusPolicy.get(afi.getClientId());
572 if (fr != null) {
573 fr.dispatchFocusResultFromExtPolicy(requestResult);
574 }
Jean-Michel Trivi126cf032017-04-02 23:19:02 -0700575 }
576
577 /**
578 * Called synchronized on mAudioFocusLock
579 * @param afi
580 * @param requestResult
581 * @return true if the external audio focus policy (if any) is handling the focus request
582 */
583 boolean notifyExtFocusPolicyFocusAbandon_syncAf(AudioFocusInfo afi) {
584 if (mFocusPolicy == null) {
585 return false;
586 }
587 final FocusRequester fr = mFocusOwnersForFocusPolicy.remove(afi.getClientId());
588 if (fr != null) {
589 fr.release();
590 }
591 try {
592 //oneway
593 mFocusPolicy.notifyAudioFocusAbandon(afi);
594 } catch (RemoteException e) {
595 Log.e(TAG, "Can't call notifyAudioFocusAbandon() on IAudioPolicyCallback "
596 + mFocusPolicy.asBinder(), e);
597 }
598 return true;
599 }
600
601 /** see AudioManager.dispatchFocusChange(AudioFocusInfo afi, int focusChange, AudioPolicy ap) */
602 int dispatchFocusChange(AudioFocusInfo afi, int focusChange) {
603 if (DEBUG) {
604 Log.v(TAG, "dispatchFocusChange " + focusChange + " to afi client="
605 + afi.getClientId());
606 }
607 synchronized (mAudioFocusLock) {
608 if (mFocusPolicy == null) {
609 if (DEBUG) { Log.v(TAG, "> failed: no focus policy" ); }
610 return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
611 }
Jean-Michel Trivie2d8aae2018-01-30 15:09:47 -0800612 final FocusRequester fr;
613 if (focusChange == AudioManager.AUDIOFOCUS_LOSS) {
614 fr = mFocusOwnersForFocusPolicy.remove(afi.getClientId());
615 } else {
616 fr = mFocusOwnersForFocusPolicy.get(afi.getClientId());
617 }
Jean-Michel Trivi126cf032017-04-02 23:19:02 -0700618 if (fr == null) {
619 if (DEBUG) { Log.v(TAG, "> failed: no such focus requester known" ); }
620 return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
621 }
622 return fr.dispatchFocusChange(focusChange);
623 }
624 }
625
626 private void dumpExtFocusPolicyFocusOwners(PrintWriter pw) {
627 final Set<Entry<String, FocusRequester>> owners = mFocusOwnersForFocusPolicy.entrySet();
628 final Iterator<Entry<String, FocusRequester>> ownerIterator = owners.iterator();
629 while (ownerIterator.hasNext()) {
630 final Entry<String, FocusRequester> owner = ownerIterator.next();
631 final FocusRequester fr = owner.getValue();
632 fr.dump(pw);
633 }
634 }
635
Jean-Michel Trivi23805662013-07-31 14:19:18 -0700636 protected int getCurrentAudioFocus() {
637 synchronized(mAudioFocusLock) {
638 if (mFocusStack.empty()) {
639 return AudioManager.AUDIOFOCUS_NONE;
640 } else {
641 return mFocusStack.peek().getGainRequest();
642 }
643 }
644 }
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700645
Jean-Michel Trivi99489cc2017-01-25 19:08:49 -0800646 /**
Jean-Michel Trivi62b86342017-02-04 15:33:47 -0800647 * Delay after entering ringing or call mode after which the framework will mute streams
648 * that are still playing.
649 */
650 private static final int RING_CALL_MUTING_ENFORCEMENT_DELAY_MS = 100;
651
652 /**
653 * Usages to mute when the device rings or is in a call
654 */
655 private final static int[] USAGES_TO_MUTE_IN_RING_OR_CALL =
656 { AudioAttributes.USAGE_MEDIA, AudioAttributes.USAGE_GAME };
657
658 /**
Jean-Michel Trivi99489cc2017-01-25 19:08:49 -0800659 * Return the volume ramp time expected before playback with the given AudioAttributes would
660 * start after gaining audio focus.
661 * @param attr attributes of the sound about to start playing
662 * @return time in ms
663 */
Jean-Michel Trividce82ab2017-02-07 16:02:33 -0800664 protected static int getFocusRampTimeMs(int focusGain, AudioAttributes attr) {
Jean-Michel Trivi99489cc2017-01-25 19:08:49 -0800665 switch (attr.getUsage()) {
666 case AudioAttributes.USAGE_MEDIA:
667 case AudioAttributes.USAGE_GAME:
668 return 1000;
669 case AudioAttributes.USAGE_ALARM:
670 case AudioAttributes.USAGE_NOTIFICATION_RINGTONE:
671 case AudioAttributes.USAGE_ASSISTANT:
672 case AudioAttributes.USAGE_ASSISTANCE_ACCESSIBILITY:
673 case AudioAttributes.USAGE_ASSISTANCE_NAVIGATION_GUIDANCE:
674 return 700;
675 case AudioAttributes.USAGE_VOICE_COMMUNICATION:
676 case AudioAttributes.USAGE_VOICE_COMMUNICATION_SIGNALLING:
677 case AudioAttributes.USAGE_NOTIFICATION:
678 case AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_REQUEST:
679 case AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_INSTANT:
680 case AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_DELAYED:
681 case AudioAttributes.USAGE_NOTIFICATION_EVENT:
682 case AudioAttributes.USAGE_ASSISTANCE_SONIFICATION:
683 return 500;
684 case AudioAttributes.USAGE_UNKNOWN:
685 default:
686 return 0;
687 }
688 }
689
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -0800690 /** @see AudioManager#requestAudioFocus(AudioManager.OnAudioFocusChangeListener, int, int, int) */
691 protected int requestAudioFocus(AudioAttributes aa, int focusChangeHint, IBinder cb,
Jean-Michel Trivi461922f2017-04-25 15:23:17 -0700692 IAudioFocusDispatcher fd, String clientId, String callingPackageName, int flags,
Jean-Michel Trivi9228af62018-01-05 17:06:17 -0800693 int sdk, boolean forceDuck) {
Jean-Michel Trivi0b67b9f2017-10-05 12:19:23 -0700694 mEventLogger.log((new AudioEventLogger.StringEvent(
695 "requestAudioFocus() from uid/pid " + Binder.getCallingUid()
696 + "/" + Binder.getCallingPid()
697 + " clientId=" + clientId + " callingPack=" + callingPackageName
698 + " req=" + focusChangeHint
699 + " flags=0x" + Integer.toHexString(flags)
700 + " sdk=" + sdk))
701 .printLog(TAG));
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700702 // we need a valid binder callback for clients
703 if (!cb.pingBinder()) {
704 Log.e(TAG, " AudioFocus DOA client for requestAudioFocus(), aborting.");
705 return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
706 }
707
708 if (mAppOps.noteOp(AppOpsManager.OP_TAKE_AUDIO_FOCUS, Binder.getCallingUid(),
709 callingPackageName) != AppOpsManager.MODE_ALLOWED) {
710 return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
711 }
712
713 synchronized(mAudioFocusLock) {
Jean-Michel Trivi0b67b9f2017-10-05 12:19:23 -0700714 if (mFocusStack.size() > MAX_STACK_SIZE) {
715 Log.e(TAG, "Max AudioFocus stack size reached, failing requestAudioFocus()");
716 return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
717 }
718
Jean-Michel Trivi62b86342017-02-04 15:33:47 -0800719 boolean enteringRingOrCall = !mRingOrCallActive
720 & (AudioSystem.IN_VOICE_COMM_FOCUS_ID.compareTo(clientId) == 0);
721 if (enteringRingOrCall) { mRingOrCallActive = true; }
722
Jean-Michel Trivi126cf032017-04-02 23:19:02 -0700723 final AudioFocusInfo afiForExtPolicy;
724 if (mFocusPolicy != null) {
725 // construct AudioFocusInfo as it will be communicated to audio focus policy
726 afiForExtPolicy = new AudioFocusInfo(aa, Binder.getCallingUid(),
727 clientId, callingPackageName, focusChangeHint, 0 /*lossReceived*/,
Jean-Michel Trivi461922f2017-04-25 15:23:17 -0700728 flags, sdk);
Jean-Michel Trivi126cf032017-04-02 23:19:02 -0700729 } else {
730 afiForExtPolicy = null;
731 }
732
733 // handle delayed focus
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -0800734 boolean focusGrantDelayed = false;
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700735 if (!canReassignAudioFocus()) {
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -0800736 if ((flags & AudioManager.AUDIOFOCUS_FLAG_DELAY_OK) == 0) {
Jean-Michel Trivie2d8aae2018-01-30 15:09:47 -0800737 return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -0800738 } else {
739 // request has AUDIOFOCUS_FLAG_DELAY_OK: focus can't be
740 // granted right now, so the requester will be inserted in the focus stack
741 // to receive focus later
742 focusGrantDelayed = true;
743 }
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700744 }
745
Jean-Michel Trivie2d8aae2018-01-30 15:09:47 -0800746 // external focus policy?
Jean-Michel Trivi126cf032017-04-02 23:19:02 -0700747 if (notifyExtFocusPolicyFocusRequest_syncAf(
Jean-Michel Trivie2d8aae2018-01-30 15:09:47 -0800748 afiForExtPolicy, fd, cb)) {
Jean-Michel Trivi126cf032017-04-02 23:19:02 -0700749 // stop handling focus request here as it is handled by external audio focus policy
Jean-Michel Trivie2d8aae2018-01-30 15:09:47 -0800750 return AudioManager.AUDIOFOCUS_REQUEST_WAITING_FOR_EXT_POLICY;
Jean-Michel Trivi126cf032017-04-02 23:19:02 -0700751 }
752
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700753 // handle the potential premature death of the new holder of the focus
754 // (premature death == death before abandoning focus)
755 // Register for client death notification
756 AudioFocusDeathHandler afdh = new AudioFocusDeathHandler(cb);
Jean-Michel Trivie8987722016-07-07 15:38:32 -0700757
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700758 try {
759 cb.linkToDeath(afdh, 0);
760 } catch (RemoteException e) {
761 // client has already died!
762 Log.w(TAG, "AudioFocus requestAudioFocus() could not link to "+cb+" binder death");
763 return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
764 }
765
Jean-Michel Trivi83283f22013-07-29 18:09:41 -0700766 if (!mFocusStack.empty() && mFocusStack.peek().hasSameClient(clientId)) {
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700767 // if focus is already owned by this client and the reason for acquiring the focus
768 // hasn't changed, don't do anything
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -0800769 final FocusRequester fr = mFocusStack.peek();
770 if (fr.getGainRequest() == focusChangeHint && fr.getGrantFlags() == flags) {
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700771 // unlink death handler so it can be gc'ed.
772 // linkToDeath() creates a JNI global reference preventing collection.
773 cb.unlinkToDeath(afdh, 0);
Jean-Michel Trivi0212be52014-11-24 14:43:10 -0800774 notifyExtPolicyFocusGrant_syncAf(fr.toAudioFocusInfo(),
775 AudioManager.AUDIOFOCUS_REQUEST_GRANTED);
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700776 return AudioManager.AUDIOFOCUS_REQUEST_GRANTED;
777 }
778 // the reason for the audio focus request has changed: remove the current top of
779 // stack and respond as if we had a new focus owner
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -0800780 if (!focusGrantDelayed) {
781 mFocusStack.pop();
782 // the entry that was "popped" is the same that was "peeked" above
783 fr.release();
784 }
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700785 }
786
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700787 // focus requester might already be somewhere below in the stack, remove it
Jean-Michel Trivi0212be52014-11-24 14:43:10 -0800788 removeFocusStackEntry(clientId, false /* signal */, false /*notifyFocusFollowers*/);
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700789
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -0800790 final FocusRequester nfr = new FocusRequester(aa, focusChangeHint, flags, fd, cb,
Jean-Michel Trivi461922f2017-04-25 15:23:17 -0700791 clientId, afdh, callingPackageName, Binder.getCallingUid(), this, sdk);
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -0800792 if (focusGrantDelayed) {
793 // focusGrantDelayed being true implies we can't reassign focus right now
794 // which implies the focus stack is not empty.
Jean-Michel Trivi0212be52014-11-24 14:43:10 -0800795 final int requestResult = pushBelowLockedFocusOwners(nfr);
796 if (requestResult != AudioManager.AUDIOFOCUS_REQUEST_FAILED) {
797 notifyExtPolicyFocusGrant_syncAf(nfr.toAudioFocusInfo(), requestResult);
798 }
799 return requestResult;
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -0800800 } else {
801 // propagate the focus change through the stack
802 if (!mFocusStack.empty()) {
Jean-Michel Trivi9228af62018-01-05 17:06:17 -0800803 propagateFocusLossFromGain_syncAf(focusChangeHint, nfr, forceDuck);
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -0800804 }
Jean-Michel Trivicbb212f2013-07-30 15:09:33 -0700805
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -0800806 // push focus requester at the top of the audio focus stack
807 mFocusStack.push(nfr);
Jean-Michel Trivi270f1c92017-05-05 11:43:31 -0700808 nfr.handleFocusGainFromRequest(AudioManager.AUDIOFOCUS_REQUEST_GRANTED);
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -0800809 }
Jean-Michel Trivi0212be52014-11-24 14:43:10 -0800810 notifyExtPolicyFocusGrant_syncAf(nfr.toAudioFocusInfo(),
811 AudioManager.AUDIOFOCUS_REQUEST_GRANTED);
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700812
Jean-Michel Trivi62b86342017-02-04 15:33:47 -0800813 if (ENFORCE_MUTING_FOR_RING_OR_CALL & enteringRingOrCall) {
814 runAudioCheckerForRingOrCallAsync(true/*enteringRingOrCall*/);
815 }
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700816 }//synchronized(mAudioFocusLock)
817
818 return AudioManager.AUDIOFOCUS_REQUEST_GRANTED;
819 }
820
Jean-Michel Trivi958876f2014-11-16 15:40:22 -0800821 /**
822 * @see AudioManager#abandonAudioFocus(AudioManager.OnAudioFocusChangeListener, AudioAttributes)
823 * */
Jean-Michel Trivi126cf032017-04-02 23:19:02 -0700824 protected int abandonAudioFocus(IAudioFocusDispatcher fl, String clientId, AudioAttributes aa,
825 String callingPackageName) {
Jean-Michel Trivi0b67b9f2017-10-05 12:19:23 -0700826 // AudioAttributes are currently ignored, to be used for zones / a11y
827 mEventLogger.log((new AudioEventLogger.StringEvent(
828 "abandonAudioFocus() from uid/pid " + Binder.getCallingUid()
829 + "/" + Binder.getCallingPid()
830 + " clientId=" + clientId))
831 .printLog(TAG));
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700832 try {
833 // this will take care of notifying the new focus owner if needed
834 synchronized(mAudioFocusLock) {
Jean-Michel Trivi126cf032017-04-02 23:19:02 -0700835 // external focus policy?
836 if (mFocusPolicy != null) {
837 final AudioFocusInfo afi = new AudioFocusInfo(aa, Binder.getCallingUid(),
838 clientId, callingPackageName, 0 /*gainRequest*/, 0 /*lossReceived*/,
Jean-Michel Trivi461922f2017-04-25 15:23:17 -0700839 0 /*flags*/, 0 /* sdk n/a here*/);
Jean-Michel Trivi126cf032017-04-02 23:19:02 -0700840 if (notifyExtFocusPolicyFocusAbandon_syncAf(afi)) {
841 return AudioManager.AUDIOFOCUS_REQUEST_GRANTED;
842 }
843 }
844
Jean-Michel Trivi62b86342017-02-04 15:33:47 -0800845 boolean exitingRingOrCall = mRingOrCallActive
846 & (AudioSystem.IN_VOICE_COMM_FOCUS_ID.compareTo(clientId) == 0);
847 if (exitingRingOrCall) { mRingOrCallActive = false; }
848
Jean-Michel Trivi0212be52014-11-24 14:43:10 -0800849 removeFocusStackEntry(clientId, true /*signal*/, true /*notifyFocusFollowers*/);
Jean-Michel Trivi62b86342017-02-04 15:33:47 -0800850
851 if (ENFORCE_MUTING_FOR_RING_OR_CALL & exitingRingOrCall) {
852 runAudioCheckerForRingOrCallAsync(false/*enteringRingOrCall*/);
853 }
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700854 }
855 } catch (java.util.ConcurrentModificationException cme) {
856 // Catching this exception here is temporary. It is here just to prevent
857 // a crash seen when the "Silent" notification is played. This is believed to be fixed
858 // but this try catch block is left just to be safe.
859 Log.e(TAG, "FATAL EXCEPTION AudioFocus abandonAudioFocus() caused " + cme);
860 cme.printStackTrace();
861 }
862
863 return AudioManager.AUDIOFOCUS_REQUEST_GRANTED;
864 }
865
866
867 protected void unregisterAudioFocusClient(String clientId) {
868 synchronized(mAudioFocusLock) {
Jean-Michel Trivi0212be52014-11-24 14:43:10 -0800869 removeFocusStackEntry(clientId, false, true /*notifyFocusFollowers*/);
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700870 }
871 }
872
Jean-Michel Trivi62b86342017-02-04 15:33:47 -0800873 private void runAudioCheckerForRingOrCallAsync(final boolean enteringRingOrCall) {
874 new Thread() {
875 public void run() {
876 if (enteringRingOrCall) {
877 try {
878 Thread.sleep(RING_CALL_MUTING_ENFORCEMENT_DELAY_MS);
879 } catch (InterruptedException e) {
880 e.printStackTrace();
881 }
882 }
883 synchronized (mAudioFocusLock) {
884 // since the new thread starting running the state could have changed, so
885 // we need to check again mRingOrCallActive, not enteringRingOrCall
886 if (mRingOrCallActive) {
887 mFocusEnforcer.mutePlayersForCall(USAGES_TO_MUTE_IN_RING_OR_CALL);
888 } else {
889 mFocusEnforcer.unmutePlayersForCall();
890 }
891 }
892 }
893 }.start();
894 }
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700895}