blob: cc18114120eb47bc32dff3a0205862032b9029b6 [file] [log] [blame]
Jean-Michel Trivi83283f22013-07-29 18:09:41 -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 Trivi83283f22013-07-29 18:09:41 -070018
Jean-Michel Trivi0212be52014-11-24 14:43:10 -080019import android.annotation.NonNull;
John Spurlock61560172015-02-06 19:46:04 -050020import android.media.AudioAttributes;
21import android.media.AudioFocusInfo;
22import android.media.AudioManager;
23import android.media.IAudioFocusDispatcher;
Jean-Michel Trivi83283f22013-07-29 18:09:41 -070024import android.os.IBinder;
25import android.util.Log;
26
John Spurlock61560172015-02-06 19:46:04 -050027import com.android.server.audio.MediaFocusControl.AudioFocusDeathHandler;
28
Jean-Michel Trivi83283f22013-07-29 18:09:41 -070029import java.io.PrintWriter;
30
31/**
32 * @hide
33 * Class to handle all the information about a user of audio focus. The lifecycle of each
34 * instance is managed by android.media.MediaFocusControl, from its addition to the audio focus
35 * stack to its release.
36 */
John Spurlock61560172015-02-06 19:46:04 -050037public class FocusRequester {
Jean-Michel Trivi83283f22013-07-29 18:09:41 -070038
Jean-Michel Trivi83283f22013-07-29 18:09:41 -070039 // on purpose not using this classe's name, as it will only be used from MediaFocusControl
40 private static final String TAG = "MediaFocusControl";
Jean-Michel Trivicbb212f2013-07-30 15:09:33 -070041 private static final boolean DEBUG = false;
Jean-Michel Trivi83283f22013-07-29 18:09:41 -070042
Jean-Michel Trivie8987722016-07-07 15:38:32 -070043 private AudioFocusDeathHandler mDeathHandler; // may be null
44 private IAudioFocusDispatcher mFocusDispatcher; // may be null
45 private final IBinder mSourceRef; // may be null
Jean-Michel Trivi83283f22013-07-29 18:09:41 -070046 private final String mClientId;
47 private final String mPackageName;
48 private final int mCallingUid;
Jean-Michel Trivi0212be52014-11-24 14:43:10 -080049 private final MediaFocusControl mFocusController; // never null
Jean-Michel Trivi83283f22013-07-29 18:09:41 -070050 /**
51 * the audio focus gain request that caused the addition of this object in the focus stack.
52 */
53 private final int mFocusGainRequest;
54 /**
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -080055 * the flags associated with the gain request that qualify the type of grant (e.g. accepting
56 * delay vs grant must be immediate)
57 */
58 private final int mGrantFlags;
59 /**
Jean-Michel Trivi23805662013-07-31 14:19:18 -070060 * the audio focus loss received my mFocusDispatcher, is AudioManager.AUDIOFOCUS_NONE if
Jean-Michel Trivi83283f22013-07-29 18:09:41 -070061 * it never lost focus.
62 */
63 private int mFocusLossReceived;
64 /**
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -080065 * the audio attributes associated with the focus request
Jean-Michel Trivi83283f22013-07-29 18:09:41 -070066 */
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -080067 private final AudioAttributes mAttributes;
Jean-Michel Trivi83283f22013-07-29 18:09:41 -070068
Jean-Michel Trivi0212be52014-11-24 14:43:10 -080069 /**
70 * Class constructor
71 * @param aa
72 * @param focusRequest
73 * @param grantFlags
74 * @param afl
75 * @param source
76 * @param id
77 * @param hdlr
78 * @param pn
79 * @param uid
80 * @param ctlr cannot be null
81 */
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -080082 FocusRequester(AudioAttributes aa, int focusRequest, int grantFlags,
Jean-Michel Trivi83283f22013-07-29 18:09:41 -070083 IAudioFocusDispatcher afl, IBinder source, String id, AudioFocusDeathHandler hdlr,
Jean-Michel Trivi0212be52014-11-24 14:43:10 -080084 String pn, int uid, @NonNull MediaFocusControl ctlr) {
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -080085 mAttributes = aa;
Jean-Michel Trivi83283f22013-07-29 18:09:41 -070086 mFocusDispatcher = afl;
87 mSourceRef = source;
88 mClientId = id;
89 mDeathHandler = hdlr;
90 mPackageName = pn;
91 mCallingUid = uid;
92 mFocusGainRequest = focusRequest;
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -080093 mGrantFlags = grantFlags;
Jean-Michel Trivi23805662013-07-31 14:19:18 -070094 mFocusLossReceived = AudioManager.AUDIOFOCUS_NONE;
Jean-Michel Trivi0212be52014-11-24 14:43:10 -080095 mFocusController = ctlr;
Jean-Michel Trivi83283f22013-07-29 18:09:41 -070096 }
97
98
Jean-Michel Trivi83283f22013-07-29 18:09:41 -070099 boolean hasSameClient(String otherClient) {
100 try {
101 return mClientId.compareTo(otherClient) == 0;
102 } catch (NullPointerException e) {
103 return false;
104 }
105 }
106
Jean-Michel Trivi958876f2014-11-16 15:40:22 -0800107 boolean isLockedFocusOwner() {
108 return ((mGrantFlags & AudioManager.AUDIOFOCUS_FLAG_LOCK) != 0);
109 }
110
Jean-Michel Trivi83283f22013-07-29 18:09:41 -0700111 boolean hasSameBinder(IBinder ib) {
112 return (mSourceRef != null) && mSourceRef.equals(ib);
113 }
114
115 boolean hasSamePackage(String pack) {
116 try {
117 return mPackageName.compareTo(pack) == 0;
118 } catch (NullPointerException e) {
119 return false;
120 }
121 }
122
123 boolean hasSameUid(int uid) {
124 return mCallingUid == uid;
125 }
126
Jean-Michel Trivi958876f2014-11-16 15:40:22 -0800127 String getClientId() {
128 return mClientId;
129 }
Jean-Michel Trivi83283f22013-07-29 18:09:41 -0700130
131 int getGainRequest() {
132 return mFocusGainRequest;
133 }
134
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -0800135 int getGrantFlags() {
136 return mGrantFlags;
137 }
138
139 AudioAttributes getAudioAttributes() {
140 return mAttributes;
Jean-Michel Trivi83283f22013-07-29 18:09:41 -0700141 }
142
143
144 private static String focusChangeToString(int focus) {
145 switch(focus) {
Jean-Michel Trivi23805662013-07-31 14:19:18 -0700146 case AudioManager.AUDIOFOCUS_NONE:
Jean-Michel Trivi83283f22013-07-29 18:09:41 -0700147 return "none";
148 case AudioManager.AUDIOFOCUS_GAIN:
149 return "GAIN";
150 case AudioManager.AUDIOFOCUS_GAIN_TRANSIENT:
151 return "GAIN_TRANSIENT";
152 case AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK:
153 return "GAIN_TRANSIENT_MAY_DUCK";
Jean-Michel Trivi23805662013-07-31 14:19:18 -0700154 case AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE:
155 return "GAIN_TRANSIENT_EXCLUSIVE";
Jean-Michel Trivi83283f22013-07-29 18:09:41 -0700156 case AudioManager.AUDIOFOCUS_LOSS:
157 return "LOSS";
158 case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
159 return "LOSS_TRANSIENT";
160 case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:
161 return "LOSS_TRANSIENT_CAN_DUCK";
162 default:
163 return "[invalid focus change" + focus + "]";
164 }
165 }
166
167 private String focusGainToString() {
168 return focusChangeToString(mFocusGainRequest);
169 }
170
171 private String focusLossToString() {
172 return focusChangeToString(mFocusLossReceived);
173 }
174
Jean-Michel Trivi958876f2014-11-16 15:40:22 -0800175 private static String flagsToString(int flags) {
176 String msg = new String();
Jean-Michel Trivi0212be52014-11-24 14:43:10 -0800177 if ((flags & AudioManager.AUDIOFOCUS_FLAG_DELAY_OK) != 0) {
178 msg += "DELAY_OK";
179 }
180 if ((flags & AudioManager.AUDIOFOCUS_FLAG_LOCK) != 0) {
181 if (!msg.isEmpty()) { msg += "|"; }
182 msg += "LOCK";
183 }
184 if ((flags & AudioManager.AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS) != 0) {
185 if (!msg.isEmpty()) { msg += "|"; }
186 msg += "PAUSES_ON_DUCKABLE_LOSS";
187 }
Jean-Michel Trivi958876f2014-11-16 15:40:22 -0800188 return msg;
189 }
190
Jean-Michel Trivi83283f22013-07-29 18:09:41 -0700191 void dump(PrintWriter pw) {
192 pw.println(" source:" + mSourceRef
193 + " -- pack: " + mPackageName
194 + " -- client: " + mClientId
195 + " -- gain: " + focusGainToString()
Jean-Michel Trivi958876f2014-11-16 15:40:22 -0800196 + " -- flags: " + flagsToString(mGrantFlags)
Jean-Michel Trivi83283f22013-07-29 18:09:41 -0700197 + " -- loss: " + focusLossToString()
198 + " -- uid: " + mCallingUid
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -0800199 + " -- attr: " + mAttributes);
Jean-Michel Trivi83283f22013-07-29 18:09:41 -0700200 }
201
202
203 void release() {
204 try {
205 if (mSourceRef != null && mDeathHandler != null) {
206 mSourceRef.unlinkToDeath(mDeathHandler, 0);
207 mDeathHandler = null;
Jean-Michel Trivie8987722016-07-07 15:38:32 -0700208 mFocusDispatcher = null;
Jean-Michel Trivi83283f22013-07-29 18:09:41 -0700209 }
210 } catch (java.util.NoSuchElementException e) {
211 Log.e(TAG, "FocusRequester.release() hit ", e);
212 }
213 }
214
215 @Override
216 protected void finalize() throws Throwable {
217 release();
218 super.finalize();
219 }
220
221 /**
222 * For a given audio focus gain request, return the audio focus loss type that will result
Jean-Michel Trivi53e6e282013-07-30 14:21:34 -0700223 * from it, taking into account any previous focus loss.
Jean-Michel Trivi83283f22013-07-29 18:09:41 -0700224 * @param gainRequest
225 * @return the audio focus loss type that matches the gain request
226 */
227 private int focusLossForGainRequest(int gainRequest) {
Jean-Michel Trivi53e6e282013-07-30 14:21:34 -0700228 switch(gainRequest) {
229 case AudioManager.AUDIOFOCUS_GAIN:
230 switch(mFocusLossReceived) {
231 case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:
232 case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
233 case AudioManager.AUDIOFOCUS_LOSS:
Jean-Michel Trivi23805662013-07-31 14:19:18 -0700234 case AudioManager.AUDIOFOCUS_NONE:
Jean-Michel Trivi53e6e282013-07-30 14:21:34 -0700235 return AudioManager.AUDIOFOCUS_LOSS;
236 }
Jean-Michel Trivi23805662013-07-31 14:19:18 -0700237 case AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE:
Jean-Michel Trivi53e6e282013-07-30 14:21:34 -0700238 case AudioManager.AUDIOFOCUS_GAIN_TRANSIENT:
239 switch(mFocusLossReceived) {
240 case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:
241 case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
Jean-Michel Trivi23805662013-07-31 14:19:18 -0700242 case AudioManager.AUDIOFOCUS_NONE:
Jean-Michel Trivi53e6e282013-07-30 14:21:34 -0700243 return AudioManager.AUDIOFOCUS_LOSS_TRANSIENT;
244 case AudioManager.AUDIOFOCUS_LOSS:
245 return AudioManager.AUDIOFOCUS_LOSS;
246 }
247 case AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK:
248 switch(mFocusLossReceived) {
Jean-Michel Trivi23805662013-07-31 14:19:18 -0700249 case AudioManager.AUDIOFOCUS_NONE:
Jean-Michel Trivi53e6e282013-07-30 14:21:34 -0700250 case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:
Jean-Michel Trivicbb212f2013-07-30 15:09:33 -0700251 return AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK;
Jean-Michel Trivi53e6e282013-07-30 14:21:34 -0700252 case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
253 return AudioManager.AUDIOFOCUS_LOSS_TRANSIENT;
254 case AudioManager.AUDIOFOCUS_LOSS:
255 return AudioManager.AUDIOFOCUS_LOSS;
256 }
257 default:
258 Log.e(TAG, "focusLossForGainRequest() for invalid focus request "+ gainRequest);
Jean-Michel Trivi23805662013-07-31 14:19:18 -0700259 return AudioManager.AUDIOFOCUS_NONE;
Jean-Michel Trivi53e6e282013-07-30 14:21:34 -0700260 }
Jean-Michel Trivi83283f22013-07-29 18:09:41 -0700261 }
262
Jean-Michel Trivi0212be52014-11-24 14:43:10 -0800263 /**
264 * Called synchronized on MediaFocusControl.mAudioFocusLock
265 */
Jean-Michel Trivi83283f22013-07-29 18:09:41 -0700266 void handleExternalFocusGain(int focusGain) {
Jean-Michel Trivicbb212f2013-07-30 15:09:33 -0700267 int focusLoss = focusLossForGainRequest(focusGain);
268 handleFocusLoss(focusLoss);
Jean-Michel Trivi83283f22013-07-29 18:09:41 -0700269 }
270
Jean-Michel Trivi0212be52014-11-24 14:43:10 -0800271 /**
272 * Called synchronized on MediaFocusControl.mAudioFocusLock
273 */
Jean-Michel Trivi83283f22013-07-29 18:09:41 -0700274 void handleFocusGain(int focusGain) {
275 try {
Jean-Michel Trivi0212be52014-11-24 14:43:10 -0800276 mFocusLossReceived = AudioManager.AUDIOFOCUS_NONE;
277 mFocusController.notifyExtPolicyFocusGrant_syncAf(toAudioFocusInfo(),
278 AudioManager.AUDIOFOCUS_REQUEST_GRANTED);
Jean-Michel Trivie8987722016-07-07 15:38:32 -0700279 final IAudioFocusDispatcher fd = mFocusDispatcher;
280 if (fd != null) {
Jean-Michel Trivicbb212f2013-07-30 15:09:33 -0700281 if (DEBUG) {
282 Log.v(TAG, "dispatching " + focusChangeToString(focusGain) + " to "
283 + mClientId);
284 }
Jean-Michel Trivie8987722016-07-07 15:38:32 -0700285 fd.dispatchAudioFocusChange(focusGain, mClientId);
Jean-Michel Trivicbb212f2013-07-30 15:09:33 -0700286 }
Jean-Michel Trivi83283f22013-07-29 18:09:41 -0700287 } catch (android.os.RemoteException e) {
288 Log.e(TAG, "Failure to signal gain of audio focus due to: ", e);
289 }
290 }
291
Jean-Michel Trivi0212be52014-11-24 14:43:10 -0800292 /**
293 * Called synchronized on MediaFocusControl.mAudioFocusLock
294 */
Jean-Michel Trivi83283f22013-07-29 18:09:41 -0700295 void handleFocusLoss(int focusLoss) {
296 try {
Jean-Michel Trivicbb212f2013-07-30 15:09:33 -0700297 if (focusLoss != mFocusLossReceived) {
Jean-Michel Trivi0212be52014-11-24 14:43:10 -0800298 mFocusLossReceived = focusLoss;
299 // before dispatching a focus loss, check if the following conditions are met:
300 // 1/ the framework is not supposed to notify the focus loser on a DUCK loss
301 // 2/ it is a DUCK loss
302 // 3/ the focus loser isn't flagged as pausing in a DUCK loss
303 // if they are, do not notify the focus loser
304 if (!mFocusController.mustNotifyFocusOwnerOnDuck()
305 && mFocusLossReceived == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK
306 && (mGrantFlags
307 & AudioManager.AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS) == 0) {
308 if (DEBUG) {
309 Log.v(TAG, "NOT dispatching " + focusChangeToString(mFocusLossReceived)
310 + " to " + mClientId + ", to be handled externally");
311 }
312 mFocusController.notifyExtPolicyFocusLoss_syncAf(
313 toAudioFocusInfo(), false /* wasDispatched */);
314 return;
315 }
Jean-Michel Trivie8987722016-07-07 15:38:32 -0700316 final IAudioFocusDispatcher fd = mFocusDispatcher;
317 if (fd != null) {
Jean-Michel Trivicbb212f2013-07-30 15:09:33 -0700318 if (DEBUG) {
Jean-Michel Trivi0212be52014-11-24 14:43:10 -0800319 Log.v(TAG, "dispatching " + focusChangeToString(mFocusLossReceived) + " to "
Jean-Michel Trivicbb212f2013-07-30 15:09:33 -0700320 + mClientId);
321 }
Jean-Michel Trivi0212be52014-11-24 14:43:10 -0800322 mFocusController.notifyExtPolicyFocusLoss_syncAf(
323 toAudioFocusInfo(), true /* wasDispatched */);
Jean-Michel Trivie8987722016-07-07 15:38:32 -0700324 fd.dispatchAudioFocusChange(mFocusLossReceived, mClientId);
Jean-Michel Trivicbb212f2013-07-30 15:09:33 -0700325 }
Jean-Michel Trivicbb212f2013-07-30 15:09:33 -0700326 }
Jean-Michel Trivi83283f22013-07-29 18:09:41 -0700327 } catch (android.os.RemoteException e) {
328 Log.e(TAG, "Failure to signal loss of audio focus due to:", e);
329 }
330 }
331
Jean-Michel Trivi0212be52014-11-24 14:43:10 -0800332 AudioFocusInfo toAudioFocusInfo() {
333 return new AudioFocusInfo(mAttributes, mClientId, mPackageName,
334 mFocusGainRequest, mFocusLossReceived, mGrantFlags);
335 }
Jean-Michel Trivi83283f22013-07-29 18:09:41 -0700336}