blob: 206834e9adc4d7c2e8a49f087ed495c985385bcd [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 Trivifa9a6982013-06-27 16:22:58 -070019import android.app.AppOpsManager;
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -070020import android.content.Context;
John Spurlock61560172015-02-06 19:46:04 -050021import android.media.AudioAttributes;
22import android.media.AudioFocusInfo;
23import android.media.AudioManager;
24import android.media.AudioSystem;
25import android.media.IAudioFocusDispatcher;
Jean-Michel Trivi0212be52014-11-24 14:43:10 -080026import android.media.audiopolicy.IAudioPolicyCallback;
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -070027import android.os.Binder;
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -070028import android.os.IBinder;
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -070029import android.os.RemoteException;
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -070030import android.util.Log;
John Spurlock61560172015-02-06 19:46:04 -050031
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -070032import java.io.PrintWriter;
33import java.util.ArrayList;
Jean-Michel Trivi545fcf82015-04-07 09:45:35 -070034import java.util.Date;
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -070035import java.util.Iterator;
36import java.util.Stack;
Jean-Michel Trivi545fcf82015-04-07 09:45:35 -070037import java.text.DateFormat;
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -070038
39/**
40 * @hide
41 *
42 */
Jean-Michel Trivid4de20d2015-11-04 14:45:54 -080043public class MediaFocusControl {
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -070044
45 private static final String TAG = "MediaFocusControl";
46
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -070047 private final Context mContext;
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -070048 private final AppOpsManager mAppOps;
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -070049
Jean-Michel Trivid4de20d2015-11-04 14:45:54 -080050 protected MediaFocusControl(Context cntxt) {
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -070051 mContext = cntxt;
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -070052 mAppOps = (AppOpsManager)mContext.getSystemService(Context.APP_OPS_SERVICE);
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -070053 }
54
Jean-Michel Trivi73673ab2013-08-06 10:42:45 -070055 protected void dump(PrintWriter pw) {
Jean-Michel Trivi545fcf82015-04-07 09:45:35 -070056 pw.println("\nMediaFocusControl dump time: "
57 + DateFormat.getTimeInstance().format(new Date()));
Jean-Michel Trivi73673ab2013-08-06 10:42:45 -070058 dumpFocusStack(pw);
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -070059 }
60
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -070061
62 //==========================================================================================
63 // AudioFocus
64 //==========================================================================================
65
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -070066 private final static Object mAudioFocusLock = new Object();
67
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -070068 /**
69 * Discard the current audio focus owner.
70 * Notify top of audio focus stack that it lost focus (regardless of possibility to reassign
71 * focus), remove it from the stack, and clear the remote control display.
72 */
73 protected void discardAudioFocusOwner() {
74 synchronized(mAudioFocusLock) {
Jean-Michel Trivicbb212f2013-07-30 15:09:33 -070075 if (!mFocusStack.empty()) {
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -070076 // notify the current focus owner it lost focus after removing it from stack
Jean-Michel Trivi83283f22013-07-29 18:09:41 -070077 final FocusRequester exFocusOwner = mFocusStack.pop();
Jean-Michel Trivi00bf4b12013-07-26 17:19:32 -070078 exFocusOwner.handleFocusLoss(AudioManager.AUDIOFOCUS_LOSS);
Jean-Michel Trivi83283f22013-07-29 18:09:41 -070079 exFocusOwner.release();
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -070080 }
81 }
82 }
83
Jean-Michel Trivi0212be52014-11-24 14:43:10 -080084 /**
85 * Called synchronized on mAudioFocusLock
86 */
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -070087 private void notifyTopOfAudioFocusStack() {
88 // notify the top of the stack it gained focus
Jean-Michel Trivicbb212f2013-07-30 15:09:33 -070089 if (!mFocusStack.empty()) {
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -070090 if (canReassignAudioFocus()) {
Jean-Michel Trivi00bf4b12013-07-26 17:19:32 -070091 mFocusStack.peek().handleFocusGain(AudioManager.AUDIOFOCUS_GAIN);
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -070092 }
93 }
94 }
95
Jean-Michel Trivicbb212f2013-07-30 15:09:33 -070096 /**
97 * Focus is requested, propagate the associated loss throughout the stack.
98 * @param focusGain the new focus gain that will later be added at the top of the stack
99 */
100 private void propagateFocusLossFromGain_syncAf(int focusGain) {
101 // going through the audio focus stack to signal new focus, traversing order doesn't
102 // matter as all entries respond to the same external focus gain
103 Iterator<FocusRequester> stackIterator = mFocusStack.iterator();
104 while(stackIterator.hasNext()) {
105 stackIterator.next().handleExternalFocusGain(focusGain);
106 }
107 }
108
Jean-Michel Trivi83283f22013-07-29 18:09:41 -0700109 private final Stack<FocusRequester> mFocusStack = new Stack<FocusRequester>();
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700110
111 /**
112 * Helper function:
113 * Display in the log the current entries in the audio focus stack
114 */
115 private void dumpFocusStack(PrintWriter pw) {
116 pw.println("\nAudio Focus stack entries (last is top of stack):");
117 synchronized(mAudioFocusLock) {
Jean-Michel Trivi83283f22013-07-29 18:09:41 -0700118 Iterator<FocusRequester> stackIterator = mFocusStack.iterator();
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700119 while(stackIterator.hasNext()) {
Jean-Michel Trivi83283f22013-07-29 18:09:41 -0700120 stackIterator.next().dump(pw);
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700121 }
122 }
Jean-Michel Trivi0212be52014-11-24 14:43:10 -0800123 pw.println("\n Notify on duck: " + mNotifyFocusOwnerOnDuck +"\n");
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700124 }
125
126 /**
127 * Helper function:
128 * Called synchronized on mAudioFocusLock
129 * Remove a focus listener from the focus stack.
130 * @param clientToRemove the focus listener
131 * @param signal if true and the listener was at the top of the focus stack, i.e. it was holding
132 * focus, notify the next item in the stack it gained focus.
133 */
Jean-Michel Trivi0212be52014-11-24 14:43:10 -0800134 private void removeFocusStackEntry(String clientToRemove, boolean signal,
135 boolean notifyFocusFollowers) {
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700136 // is the current top of the focus stack abandoning focus? (because of request, not death)
Jean-Michel Trivi83283f22013-07-29 18:09:41 -0700137 if (!mFocusStack.empty() && mFocusStack.peek().hasSameClient(clientToRemove))
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700138 {
139 //Log.i(TAG, " removeFocusStackEntry() removing top of stack");
Jean-Michel Trivi83283f22013-07-29 18:09:41 -0700140 FocusRequester fr = mFocusStack.pop();
141 fr.release();
Jean-Michel Trivi0212be52014-11-24 14:43:10 -0800142 if (notifyFocusFollowers) {
143 final AudioFocusInfo afi = fr.toAudioFocusInfo();
144 afi.clearLossReceived();
145 notifyExtPolicyFocusLoss_syncAf(afi, false);
146 }
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700147 if (signal) {
148 // notify the new top of the stack it gained focus
149 notifyTopOfAudioFocusStack();
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700150 }
151 } else {
152 // focus is abandoned by a client that's not at the top of the stack,
153 // no need to update focus.
154 // (using an iterator on the stack so we can safely remove an entry after having
155 // evaluated it, traversal order doesn't matter here)
Jean-Michel Trivi83283f22013-07-29 18:09:41 -0700156 Iterator<FocusRequester> stackIterator = mFocusStack.iterator();
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700157 while(stackIterator.hasNext()) {
RoboErik01fe6612014-02-13 14:19:04 -0800158 FocusRequester fr = stackIterator.next();
Jean-Michel Trivi83283f22013-07-29 18:09:41 -0700159 if(fr.hasSameClient(clientToRemove)) {
Jean-Michel Trivi00bf4b12013-07-26 17:19:32 -0700160 Log.i(TAG, "AudioFocus removeFocusStackEntry(): removing entry for "
Jean-Michel Trivi83283f22013-07-29 18:09:41 -0700161 + clientToRemove);
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700162 stackIterator.remove();
Jean-Michel Trivie8987722016-07-07 15:38:32 -0700163 // stack entry not used anymore, clear references
Jean-Michel Trivi83283f22013-07-29 18:09:41 -0700164 fr.release();
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700165 }
166 }
167 }
168 }
169
170 /**
171 * Helper function:
172 * Called synchronized on mAudioFocusLock
173 * Remove focus listeners from the focus stack for a particular client when it has died.
174 */
Jean-Michel Trivie8987722016-07-07 15:38:32 -0700175 private void removeFocusStackEntryOnDeath(IBinder cb) {
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700176 // is the owner of the audio focus part of the client to remove?
177 boolean isTopOfStackForClientToRemove = !mFocusStack.isEmpty() &&
Jean-Michel Trivi83283f22013-07-29 18:09:41 -0700178 mFocusStack.peek().hasSameBinder(cb);
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700179 // (using an iterator on the stack so we can safely remove an entry after having
180 // evaluated it, traversal order doesn't matter here)
Jean-Michel Trivi83283f22013-07-29 18:09:41 -0700181 Iterator<FocusRequester> stackIterator = mFocusStack.iterator();
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700182 while(stackIterator.hasNext()) {
RoboErik01fe6612014-02-13 14:19:04 -0800183 FocusRequester fr = stackIterator.next();
Jean-Michel Trivi83283f22013-07-29 18:09:41 -0700184 if(fr.hasSameBinder(cb)) {
Jean-Michel Trivie8987722016-07-07 15:38:32 -0700185 Log.i(TAG, "AudioFocus removeFocusStackEntryOnDeath(): removing entry for " + cb);
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700186 stackIterator.remove();
Jean-Michel Trivie8987722016-07-07 15:38:32 -0700187 // stack entry not used anymore, clear references
188 fr.release();
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700189 }
190 }
191 if (isTopOfStackForClientToRemove) {
192 // we removed an entry at the top of the stack:
193 // notify the new top of the stack it gained focus.
194 notifyTopOfAudioFocusStack();
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700195 }
196 }
197
198 /**
199 * Helper function:
200 * 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 -0800201 * The implementation guarantees that a state where focus cannot be immediately reassigned
Jean-Michel Trivi958876f2014-11-16 15:40:22 -0800202 * implies that an "locked" focus owner is at the top of the focus stack.
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -0800203 * Modifications to the implementation that break this assumption will cause focus requests to
204 * misbehave when honoring the AudioManager.AUDIOFOCUS_FLAG_DELAY_OK flag.
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700205 */
206 private boolean canReassignAudioFocus() {
207 // focus requests are rejected during a phone call or when the phone is ringing
208 // this is equivalent to IN_VOICE_COMM_FOCUS_ID having the focus
Jean-Michel Trivi958876f2014-11-16 15:40:22 -0800209 if (!mFocusStack.isEmpty() && isLockedFocusOwner(mFocusStack.peek())) {
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700210 return false;
211 }
212 return true;
213 }
214
Jean-Michel Trivi958876f2014-11-16 15:40:22 -0800215 private boolean isLockedFocusOwner(FocusRequester fr) {
John Spurlock61560172015-02-06 19:46:04 -0500216 return (fr.hasSameClient(AudioSystem.IN_VOICE_COMM_FOCUS_ID) || fr.isLockedFocusOwner());
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -0800217 }
218
219 /**
220 * Helper function
Jean-Michel Trivi958876f2014-11-16 15:40:22 -0800221 * Pre-conditions: focus stack is not empty, there is one or more locked focus owner
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -0800222 * at the top of the focus stack
223 * Push the focus requester onto the audio focus stack at the first position immediately
Jean-Michel Trivi958876f2014-11-16 15:40:22 -0800224 * following the locked focus owners.
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -0800225 * @return {@link AudioManager#AUDIOFOCUS_REQUEST_GRANTED} or
226 * {@link AudioManager#AUDIOFOCUS_REQUEST_DELAYED}
227 */
Jean-Michel Trivi958876f2014-11-16 15:40:22 -0800228 private int pushBelowLockedFocusOwners(FocusRequester nfr) {
229 int lastLockedFocusOwnerIndex = mFocusStack.size();
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -0800230 for (int index = mFocusStack.size()-1; index >= 0; index--) {
Jean-Michel Trivi958876f2014-11-16 15:40:22 -0800231 if (isLockedFocusOwner(mFocusStack.elementAt(index))) {
232 lastLockedFocusOwnerIndex = index;
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -0800233 }
234 }
Jean-Michel Trivi958876f2014-11-16 15:40:22 -0800235 if (lastLockedFocusOwnerIndex == mFocusStack.size()) {
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -0800236 // this should not happen, but handle it and log an error
237 Log.e(TAG, "No exclusive focus owner found in propagateFocusLossFromGain_syncAf()",
238 new Exception());
239 // no exclusive owner, push at top of stack, focus is granted, propagate change
240 propagateFocusLossFromGain_syncAf(nfr.getGainRequest());
241 mFocusStack.push(nfr);
242 return AudioManager.AUDIOFOCUS_REQUEST_GRANTED;
243 } else {
Jean-Michel Trivi958876f2014-11-16 15:40:22 -0800244 mFocusStack.insertElementAt(nfr, lastLockedFocusOwnerIndex);
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -0800245 return AudioManager.AUDIOFOCUS_REQUEST_DELAYED;
246 }
247 }
248
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700249 /**
250 * Inner class to monitor audio focus client deaths, and remove them from the audio focus
251 * stack if necessary.
252 */
Jean-Michel Trivi83283f22013-07-29 18:09:41 -0700253 protected class AudioFocusDeathHandler implements IBinder.DeathRecipient {
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700254 private IBinder mCb; // To be notified of client's death
255
256 AudioFocusDeathHandler(IBinder cb) {
257 mCb = cb;
258 }
259
260 public void binderDied() {
261 synchronized(mAudioFocusLock) {
Jean-Michel Trivie8987722016-07-07 15:38:32 -0700262 removeFocusStackEntryOnDeath(mCb);
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700263 }
264 }
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700265 }
266
Jean-Michel Trivi0212be52014-11-24 14:43:10 -0800267 /**
268 * Indicates whether to notify an audio focus owner when it loses focus
269 * with {@link AudioManager#AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK} if it will only duck.
270 * This variable being false indicates an AudioPolicy has been registered and has signaled
271 * it will handle audio ducking.
272 */
273 private boolean mNotifyFocusOwnerOnDuck = true;
274
275 protected void setDuckingInExtPolicyAvailable(boolean available) {
276 mNotifyFocusOwnerOnDuck = !available;
277 }
278
279 boolean mustNotifyFocusOwnerOnDuck() { return mNotifyFocusOwnerOnDuck; }
280
281 private ArrayList<IAudioPolicyCallback> mFocusFollowers = new ArrayList<IAudioPolicyCallback>();
282
283 void addFocusFollower(IAudioPolicyCallback ff) {
284 if (ff == null) {
285 return;
286 }
287 synchronized(mAudioFocusLock) {
288 boolean found = false;
289 for (IAudioPolicyCallback pcb : mFocusFollowers) {
290 if (pcb.asBinder().equals(ff.asBinder())) {
291 found = true;
292 break;
293 }
294 }
295 if (found) {
296 return;
297 } else {
298 mFocusFollowers.add(ff);
Jean-Michel Trivi60fd0842015-03-13 10:11:28 -0700299 notifyExtPolicyCurrentFocusAsync(ff);
Jean-Michel Trivi0212be52014-11-24 14:43:10 -0800300 }
301 }
302 }
303
304 void removeFocusFollower(IAudioPolicyCallback ff) {
305 if (ff == null) {
306 return;
307 }
308 synchronized(mAudioFocusLock) {
309 for (IAudioPolicyCallback pcb : mFocusFollowers) {
310 if (pcb.asBinder().equals(ff.asBinder())) {
311 mFocusFollowers.remove(pcb);
312 break;
313 }
314 }
315 }
316 }
317
318 /**
Jean-Michel Trivi60fd0842015-03-13 10:11:28 -0700319 * @param pcb non null
320 */
321 void notifyExtPolicyCurrentFocusAsync(IAudioPolicyCallback pcb) {
322 final IAudioPolicyCallback pcb2 = pcb;
323 final Thread thread = new Thread() {
324 @Override
325 public void run() {
326 synchronized(mAudioFocusLock) {
327 if (mFocusStack.isEmpty()) {
328 return;
329 }
330 try {
331 pcb2.notifyAudioFocusGrant(mFocusStack.peek().toAudioFocusInfo(),
332 // top of focus stack always has focus
333 AudioManager.AUDIOFOCUS_REQUEST_GRANTED);
334 } catch (RemoteException e) {
335 Log.e(TAG, "Can't call notifyAudioFocusGrant() on IAudioPolicyCallback "
336 + pcb2.asBinder(), e);
337 }
338 }
339 }
340 };
341 thread.start();
342 }
343
344 /**
Jean-Michel Trivi0212be52014-11-24 14:43:10 -0800345 * Called synchronized on mAudioFocusLock
346 */
347 void notifyExtPolicyFocusGrant_syncAf(AudioFocusInfo afi, int requestResult) {
348 for (IAudioPolicyCallback pcb : mFocusFollowers) {
349 try {
350 // oneway
351 pcb.notifyAudioFocusGrant(afi, requestResult);
352 } catch (RemoteException e) {
Jean-Michel Trivi60fd0842015-03-13 10:11:28 -0700353 Log.e(TAG, "Can't call notifyAudioFocusGrant() on IAudioPolicyCallback "
Jean-Michel Trivi0212be52014-11-24 14:43:10 -0800354 + pcb.asBinder(), e);
355 }
356 }
357 }
358
359 /**
360 * Called synchronized on mAudioFocusLock
361 */
362 void notifyExtPolicyFocusLoss_syncAf(AudioFocusInfo afi, boolean wasDispatched) {
363 for (IAudioPolicyCallback pcb : mFocusFollowers) {
364 try {
365 // oneway
366 pcb.notifyAudioFocusLoss(afi, wasDispatched);
367 } catch (RemoteException e) {
Jean-Michel Trivi60fd0842015-03-13 10:11:28 -0700368 Log.e(TAG, "Can't call notifyAudioFocusLoss() on IAudioPolicyCallback "
Jean-Michel Trivi0212be52014-11-24 14:43:10 -0800369 + pcb.asBinder(), e);
370 }
371 }
372 }
373
Jean-Michel Trivi23805662013-07-31 14:19:18 -0700374 protected int getCurrentAudioFocus() {
375 synchronized(mAudioFocusLock) {
376 if (mFocusStack.empty()) {
377 return AudioManager.AUDIOFOCUS_NONE;
378 } else {
379 return mFocusStack.peek().getGainRequest();
380 }
381 }
382 }
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700383
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -0800384 /** @see AudioManager#requestAudioFocus(AudioManager.OnAudioFocusChangeListener, int, int, int) */
385 protected int requestAudioFocus(AudioAttributes aa, int focusChangeHint, IBinder cb,
386 IAudioFocusDispatcher fd, String clientId, String callingPackageName, int flags) {
Jean-Michel Trivi40399052015-11-23 15:17:33 -0800387 Log.i(TAG, " AudioFocus requestAudioFocus() from uid/pid " + Binder.getCallingUid()
388 + "/" + Binder.getCallingPid()
389 + " clientId=" + clientId
390 + " req=" + focusChangeHint
391 + " flags=0x" + Integer.toHexString(flags));
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700392 // we need a valid binder callback for clients
393 if (!cb.pingBinder()) {
394 Log.e(TAG, " AudioFocus DOA client for requestAudioFocus(), aborting.");
395 return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
396 }
397
398 if (mAppOps.noteOp(AppOpsManager.OP_TAKE_AUDIO_FOCUS, Binder.getCallingUid(),
399 callingPackageName) != AppOpsManager.MODE_ALLOWED) {
400 return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
401 }
402
403 synchronized(mAudioFocusLock) {
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -0800404 boolean focusGrantDelayed = false;
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700405 if (!canReassignAudioFocus()) {
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -0800406 if ((flags & AudioManager.AUDIOFOCUS_FLAG_DELAY_OK) == 0) {
407 return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
408 } else {
409 // request has AUDIOFOCUS_FLAG_DELAY_OK: focus can't be
410 // granted right now, so the requester will be inserted in the focus stack
411 // to receive focus later
412 focusGrantDelayed = true;
413 }
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700414 }
415
416 // handle the potential premature death of the new holder of the focus
417 // (premature death == death before abandoning focus)
418 // Register for client death notification
419 AudioFocusDeathHandler afdh = new AudioFocusDeathHandler(cb);
Jean-Michel Trivie8987722016-07-07 15:38:32 -0700420
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700421 try {
422 cb.linkToDeath(afdh, 0);
423 } catch (RemoteException e) {
424 // client has already died!
425 Log.w(TAG, "AudioFocus requestAudioFocus() could not link to "+cb+" binder death");
426 return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
427 }
428
Jean-Michel Trivi83283f22013-07-29 18:09:41 -0700429 if (!mFocusStack.empty() && mFocusStack.peek().hasSameClient(clientId)) {
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700430 // if focus is already owned by this client and the reason for acquiring the focus
431 // hasn't changed, don't do anything
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -0800432 final FocusRequester fr = mFocusStack.peek();
433 if (fr.getGainRequest() == focusChangeHint && fr.getGrantFlags() == flags) {
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700434 // unlink death handler so it can be gc'ed.
435 // linkToDeath() creates a JNI global reference preventing collection.
436 cb.unlinkToDeath(afdh, 0);
Jean-Michel Trivi0212be52014-11-24 14:43:10 -0800437 notifyExtPolicyFocusGrant_syncAf(fr.toAudioFocusInfo(),
438 AudioManager.AUDIOFOCUS_REQUEST_GRANTED);
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700439 return AudioManager.AUDIOFOCUS_REQUEST_GRANTED;
440 }
441 // the reason for the audio focus request has changed: remove the current top of
442 // stack and respond as if we had a new focus owner
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -0800443 if (!focusGrantDelayed) {
444 mFocusStack.pop();
445 // the entry that was "popped" is the same that was "peeked" above
446 fr.release();
447 }
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700448 }
449
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700450 // focus requester might already be somewhere below in the stack, remove it
Jean-Michel Trivi0212be52014-11-24 14:43:10 -0800451 removeFocusStackEntry(clientId, false /* signal */, false /*notifyFocusFollowers*/);
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700452
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -0800453 final FocusRequester nfr = new FocusRequester(aa, focusChangeHint, flags, fd, cb,
Jean-Michel Trivi0212be52014-11-24 14:43:10 -0800454 clientId, afdh, callingPackageName, Binder.getCallingUid(), this);
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -0800455 if (focusGrantDelayed) {
456 // focusGrantDelayed being true implies we can't reassign focus right now
457 // which implies the focus stack is not empty.
Jean-Michel Trivi0212be52014-11-24 14:43:10 -0800458 final int requestResult = pushBelowLockedFocusOwners(nfr);
459 if (requestResult != AudioManager.AUDIOFOCUS_REQUEST_FAILED) {
460 notifyExtPolicyFocusGrant_syncAf(nfr.toAudioFocusInfo(), requestResult);
461 }
462 return requestResult;
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -0800463 } else {
464 // propagate the focus change through the stack
465 if (!mFocusStack.empty()) {
466 propagateFocusLossFromGain_syncAf(focusChangeHint);
467 }
Jean-Michel Trivicbb212f2013-07-30 15:09:33 -0700468
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -0800469 // push focus requester at the top of the audio focus stack
470 mFocusStack.push(nfr);
471 }
Jean-Michel Trivi0212be52014-11-24 14:43:10 -0800472 notifyExtPolicyFocusGrant_syncAf(nfr.toAudioFocusInfo(),
473 AudioManager.AUDIOFOCUS_REQUEST_GRANTED);
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700474
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700475 }//synchronized(mAudioFocusLock)
476
477 return AudioManager.AUDIOFOCUS_REQUEST_GRANTED;
478 }
479
Jean-Michel Trivi958876f2014-11-16 15:40:22 -0800480 /**
481 * @see AudioManager#abandonAudioFocus(AudioManager.OnAudioFocusChangeListener, AudioAttributes)
482 * */
483 protected int abandonAudioFocus(IAudioFocusDispatcher fl, String clientId, AudioAttributes aa) {
484 // AudioAttributes are currently ignored, to be used for zones
Jean-Michel Trivi40399052015-11-23 15:17:33 -0800485 Log.i(TAG, " AudioFocus abandonAudioFocus() from uid/pid " + Binder.getCallingUid()
486 + "/" + Binder.getCallingPid()
487 + " clientId=" + clientId);
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700488 try {
489 // this will take care of notifying the new focus owner if needed
490 synchronized(mAudioFocusLock) {
Jean-Michel Trivi0212be52014-11-24 14:43:10 -0800491 removeFocusStackEntry(clientId, true /*signal*/, true /*notifyFocusFollowers*/);
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700492 }
493 } catch (java.util.ConcurrentModificationException cme) {
494 // Catching this exception here is temporary. It is here just to prevent
495 // a crash seen when the "Silent" notification is played. This is believed to be fixed
496 // but this try catch block is left just to be safe.
497 Log.e(TAG, "FATAL EXCEPTION AudioFocus abandonAudioFocus() caused " + cme);
498 cme.printStackTrace();
499 }
500
501 return AudioManager.AUDIOFOCUS_REQUEST_GRANTED;
502 }
503
504
505 protected void unregisterAudioFocusClient(String clientId) {
506 synchronized(mAudioFocusLock) {
Jean-Michel Trivi0212be52014-11-24 14:43:10 -0800507 removeFocusStackEntry(clientId, false, true /*notifyFocusFollowers*/);
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700508 }
509 }
510
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700511}