• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2013 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.server.audio;
18 
19 import static com.android.server.utils.EventLogger.Event.ALOGE;
20 import static com.android.server.utils.EventLogger.Event.ALOGW;
21 
22 import android.annotation.NonNull;
23 import android.annotation.Nullable;
24 import android.content.pm.UserProperties;
25 import android.media.AudioAttributes;
26 import android.media.AudioFocusInfo;
27 import android.media.AudioManager;
28 import android.media.IAudioFocusDispatcher;
29 import android.os.IBinder;
30 import android.os.RemoteException;
31 import android.os.UserHandle;
32 import android.util.Log;
33 
34 import com.android.internal.annotations.GuardedBy;
35 import com.android.server.LocalServices;
36 import com.android.server.audio.MediaFocusControl.AudioFocusDeathHandler;
37 import com.android.server.pm.UserManagerInternal;
38 import com.android.server.utils.EventLogger;
39 
40 import java.io.PrintWriter;
41 import java.util.List;
42 
43 /**
44  * @hide
45  * Class to handle all the information about a user of audio focus. The lifecycle of each
46  * instance is managed by android.media.MediaFocusControl, from its addition to the audio focus
47  * stack, or the map of focus owners for an external focus policy, to its release.
48  */
49 public class FocusRequester {
50 
51     // on purpose not using this classe's name, as it will only be used from MediaFocusControl
52     private static final String TAG = "FocusRequester";
53     private static final boolean DEBUG = false;
54 
55     private AudioFocusDeathHandler mDeathHandler; // may be null
56     private IAudioFocusDispatcher mFocusDispatcher; // may be null
57     private final IBinder mSourceRef; // may be null
58     private final @NonNull String mClientId;
59     private final @NonNull String mPackageName;
60     private final int mCallingUid;
61     private final MediaFocusControl mFocusController; // never null
62     private final int mSdkTarget;
63 
64     /**
65      * the audio focus gain request that caused the addition of this object in the focus stack.
66      */
67     private final int mFocusGainRequest;
68     /**
69      * the flags associated with the gain request that qualify the type of grant (e.g. accepting
70      * delay vs grant must be immediate)
71      */
72     private final int mGrantFlags;
73     /**
74      * the audio focus loss received my mFocusDispatcher, is AudioManager.AUDIOFOCUS_NONE if
75      *  it never lost focus.
76      */
77     private int mFocusLossReceived;
78     /**
79      * whether this focus owner listener was notified when it lost focus
80      */
81     private boolean mFocusLossWasNotified;
82     /**
83      * whether this focus owner has already lost focus, but is being faded out until focus loss
84      * dispatch occurs. It's in "limbo" mode: has lost focus but not released yet until notified
85      */
86     boolean mFocusLossFadeLimbo;
87     /**
88      * the audio attributes associated with the focus request
89      */
90     private final @NonNull AudioAttributes mAttributes;
91 
92     private final EventLogger mEventLogger;
93 
94     /**
95      * Class constructor
96      * @param aa
97      * @param focusRequest
98      * @param grantFlags
99      * @param afl
100      * @param source
101      * @param id
102      * @param hdlr
103      * @param pn
104      * @param uid
105      * @param ctlr cannot be null
106      */
FocusRequester(@onNull AudioAttributes aa, int focusRequest, int grantFlags, IAudioFocusDispatcher afl, IBinder source, @NonNull String id, AudioFocusDeathHandler hdlr, @NonNull String pn, int uid, @NonNull MediaFocusControl ctlr, int sdk, EventLogger eventLogger)107     FocusRequester(@NonNull AudioAttributes aa, int focusRequest, int grantFlags,
108             IAudioFocusDispatcher afl, IBinder source, @NonNull String id,
109             AudioFocusDeathHandler hdlr, @NonNull String pn, int uid,
110             @NonNull MediaFocusControl ctlr, int sdk, EventLogger eventLogger) {
111         mAttributes = aa;
112         mFocusDispatcher = afl;
113         mSourceRef = source;
114         mClientId = id;
115         mDeathHandler = hdlr;
116         mPackageName = pn;
117         mCallingUid = uid;
118         mFocusGainRequest = focusRequest;
119         mGrantFlags = grantFlags;
120         mFocusLossReceived = AudioManager.AUDIOFOCUS_NONE;
121         mFocusLossWasNotified = true;
122         mFocusLossFadeLimbo = false;
123         mFocusController = ctlr;
124         mSdkTarget = sdk;
125         mEventLogger = eventLogger;
126     }
127 
FocusRequester(AudioFocusInfo afi, IAudioFocusDispatcher afl, IBinder source, AudioFocusDeathHandler hdlr, @NonNull MediaFocusControl ctlr, EventLogger eventLogger)128     FocusRequester(AudioFocusInfo afi, IAudioFocusDispatcher afl,
129              IBinder source, AudioFocusDeathHandler hdlr, @NonNull MediaFocusControl ctlr,
130              EventLogger eventLogger) {
131         mAttributes = afi.getAttributes();
132         mClientId = afi.getClientId();
133         mPackageName = afi.getPackageName();
134         mCallingUid = afi.getClientUid();
135         mFocusGainRequest = afi.getGainRequest();
136         mFocusLossReceived = AudioManager.AUDIOFOCUS_NONE;
137         mFocusLossWasNotified = true;
138         mFocusLossFadeLimbo = false;
139         mGrantFlags = afi.getFlags();
140         mSdkTarget = afi.getSdkTarget();
141 
142         mFocusDispatcher = afl;
143         mSourceRef = source;
144         mDeathHandler = hdlr;
145         mFocusController = ctlr;
146         mEventLogger = eventLogger;
147     }
148 
hasSameClient(String otherClient)149     boolean hasSameClient(String otherClient) {
150         return mClientId.compareTo(otherClient) == 0;
151     }
152 
isLockedFocusOwner()153     boolean isLockedFocusOwner() {
154         return ((mGrantFlags & AudioManager.AUDIOFOCUS_FLAG_LOCK) != 0);
155     }
156 
157     /**
158      * @return true if the focus requester is scheduled to receive a focus loss
159      */
isInFocusLossLimbo()160     boolean isInFocusLossLimbo() {
161         return mFocusLossFadeLimbo;
162     }
163 
hasSameBinder(IBinder ib)164     boolean hasSameBinder(IBinder ib) {
165         return (mSourceRef != null) && mSourceRef.equals(ib);
166     }
167 
hasSameDispatcher(IAudioFocusDispatcher fd)168     boolean hasSameDispatcher(IAudioFocusDispatcher fd) {
169         return (mFocusDispatcher != null) && mFocusDispatcher.equals(fd);
170     }
171 
getPackageName()172     @NonNull String getPackageName() {
173         return mPackageName;
174     }
175 
hasSamePackage(@onNull String pack)176     boolean hasSamePackage(@NonNull String pack) {
177         return mPackageName.compareTo(pack) == 0;
178     }
179 
hasSameUid(int uid)180     boolean hasSameUid(int uid) {
181         return mCallingUid == uid;
182     }
183 
isAlwaysVisibleUser()184     boolean isAlwaysVisibleUser() {
185         final UserManagerInternal umi = LocalServices.getService(UserManagerInternal.class);
186         final UserProperties properties = umi.getUserProperties(UserHandle.getUserId(mCallingUid));
187         return properties != null && properties.getAlwaysVisible();
188     }
189 
getClientUid()190     int getClientUid() {
191         return mCallingUid;
192     }
193 
getClientId()194     String getClientId() {
195         return mClientId;
196     }
197 
getGainRequest()198     int getGainRequest() {
199         return mFocusGainRequest;
200     }
201 
getGrantFlags()202     int getGrantFlags() {
203         return mGrantFlags;
204     }
205 
getAudioAttributes()206     @NonNull AudioAttributes getAudioAttributes() {
207         return mAttributes;
208     }
209 
getSdkTarget()210     int getSdkTarget() {
211         return mSdkTarget;
212     }
213 
focusChangeToString(int focus)214     private static String focusChangeToString(int focus) {
215         switch(focus) {
216             case AudioManager.AUDIOFOCUS_NONE:
217                 return "none";
218             case AudioManager.AUDIOFOCUS_GAIN:
219                 return "GAIN";
220             case AudioManager.AUDIOFOCUS_GAIN_TRANSIENT:
221                 return "GAIN_TRANSIENT";
222             case AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK:
223                 return "GAIN_TRANSIENT_MAY_DUCK";
224             case AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE:
225                 return "GAIN_TRANSIENT_EXCLUSIVE";
226             case AudioManager.AUDIOFOCUS_LOSS:
227                 return "LOSS";
228             case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
229                 return "LOSS_TRANSIENT";
230             case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:
231                 return "LOSS_TRANSIENT_CAN_DUCK";
232             default:
233                 return "[invalid focus change" + focus + "]";
234         }
235     }
236 
focusGainToString()237     private String focusGainToString() {
238         return focusChangeToString(mFocusGainRequest);
239     }
240 
focusLossToString()241     private String focusLossToString() {
242         return focusChangeToString(mFocusLossReceived);
243     }
244 
flagsToString(int flags)245     private static String flagsToString(int flags) {
246         String msg = new String();
247         if ((flags & AudioManager.AUDIOFOCUS_FLAG_DELAY_OK) != 0) {
248             msg += "DELAY_OK";
249         }
250         if ((flags & AudioManager.AUDIOFOCUS_FLAG_LOCK) != 0)     {
251             if (!msg.isEmpty()) { msg += "|"; }
252             msg += "LOCK";
253         }
254         if ((flags & AudioManager.AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS) != 0) {
255             if (!msg.isEmpty()) { msg += "|"; }
256             msg += "PAUSES_ON_DUCKABLE_LOSS";
257         }
258         return msg;
259     }
260 
dump(PrintWriter pw)261     void dump(PrintWriter pw) {
262         pw.println("  source:" + mSourceRef
263                 + " -- pack: " + mPackageName
264                 + " -- client: " + mClientId
265                 + " -- gain: " + focusGainToString()
266                 + " -- flags: " + flagsToString(mGrantFlags)
267                 + " -- loss: " + focusLossToString()
268                 + " -- notified: " + mFocusLossWasNotified
269                 + " -- limbo" + mFocusLossFadeLimbo
270                 + " -- uid: " + mCallingUid
271                 + " -- attr: " + mAttributes
272                 + " -- sdk:" + mSdkTarget);
273     }
274 
275     /**
276      * Clear all references, except for instances in "loss limbo" due to the current fade out
277      * for which there will be an attempt to be clear after the loss has been notified
278      */
maybeRelease()279     void maybeRelease() {
280         if (!mFocusLossFadeLimbo) {
281             release();
282         }
283     }
284 
release()285     void release() {
286         final IBinder srcRef = mSourceRef;
287         final AudioFocusDeathHandler deathHdlr = mDeathHandler;
288         try {
289             if (srcRef != null && deathHdlr != null) {
290                 srcRef.unlinkToDeath(deathHdlr, 0);
291             }
292         } catch (java.util.NoSuchElementException e) { }
293         mDeathHandler = null;
294         mFocusDispatcher = null;
295     }
296 
297     @Override
finalize()298     protected void finalize() throws Throwable {
299         release();
300         super.finalize();
301     }
302 
303     /**
304      * For a given audio focus gain request, return the audio focus loss type that will result
305      * from it, taking into account any previous focus loss.
306      * @param gainRequest
307      * @return the audio focus loss type that matches the gain request
308      */
focusLossForGainRequest(int gainRequest)309     private int focusLossForGainRequest(int gainRequest) {
310         switch(gainRequest) {
311             case AudioManager.AUDIOFOCUS_GAIN:
312                 switch(mFocusLossReceived) {
313                     case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:
314                     case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
315                     case AudioManager.AUDIOFOCUS_LOSS:
316                     case AudioManager.AUDIOFOCUS_NONE:
317                         return AudioManager.AUDIOFOCUS_LOSS;
318                 }
319             case AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE:
320             case AudioManager.AUDIOFOCUS_GAIN_TRANSIENT:
321                 switch(mFocusLossReceived) {
322                     case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:
323                     case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
324                     case AudioManager.AUDIOFOCUS_NONE:
325                         return AudioManager.AUDIOFOCUS_LOSS_TRANSIENT;
326                     case AudioManager.AUDIOFOCUS_LOSS:
327                         return AudioManager.AUDIOFOCUS_LOSS;
328                 }
329             case AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK:
330                 switch(mFocusLossReceived) {
331                     case AudioManager.AUDIOFOCUS_NONE:
332                     case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:
333                         return AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK;
334                     case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
335                         return AudioManager.AUDIOFOCUS_LOSS_TRANSIENT;
336                     case AudioManager.AUDIOFOCUS_LOSS:
337                         return AudioManager.AUDIOFOCUS_LOSS;
338                 }
339             default:
340                 Log.e(TAG, "focusLossForGainRequest() for invalid focus request "+ gainRequest);
341                         return AudioManager.AUDIOFOCUS_NONE;
342         }
343     }
344 
345     /**
346      * Handle the loss of focus resulting from a given focus gain.
347      * @param focusGain the focus gain from which the loss of focus is resulting
348      * @param frWinner the new focus owner
349      * @return true if the focus loss is definitive, false otherwise.
350      */
351     @GuardedBy("MediaFocusControl.mAudioFocusLock")
handleFocusLossFromGain(int focusGain, final FocusRequester frWinner, boolean forceDuck)352     boolean handleFocusLossFromGain(int focusGain, final FocusRequester frWinner, boolean forceDuck)
353     {
354         if (DEBUG) {
355             Log.i(TAG, "handleFocusLossFromGain for " + mClientId + " gain:" + focusGain);
356         }
357         final int focusLoss = focusLossForGainRequest(focusGain);
358         handleFocusLoss(focusLoss, frWinner, forceDuck);
359         return (focusLoss == AudioManager.AUDIOFOCUS_LOSS);
360     }
361 
362     @GuardedBy("MediaFocusControl.mAudioFocusLock")
handleFocusGain(int focusGain)363     void handleFocusGain(int focusGain) {
364         try {
365             mFocusLossReceived = AudioManager.AUDIOFOCUS_NONE;
366             mFocusLossFadeLimbo = false;
367             mFocusController.notifyExtPolicyFocusGrant_syncAf(toAudioFocusInfo(),
368                     AudioManager.AUDIOFOCUS_REQUEST_GRANTED);
369             final IAudioFocusDispatcher fd = mFocusDispatcher;
370             if (fd != null && mFocusLossWasNotified) {
371                 if (DEBUG) {
372                     Log.v(TAG, "dispatching " + focusChangeToString(focusGain) + " to "
373                         + mClientId);
374                 }
375                 fd.dispatchAudioFocusChange(focusGain, mClientId);
376                 mEventLogger.enqueue(new FocusRequestEvent(
377                         this, focusGain, "handleGain"));
378             } else if (mFocusLossWasNotified) {
379                 mEventLogger.enqueue(new FocusRequestEvent(
380                         this, focusGain, "handleGain no listener").printSlog(ALOGW, TAG));
381             }
382             mFocusController.restoreVShapedPlayers(this);
383         } catch (RemoteException e) {
384             mEventLogger.enqueue(new FocusRequestEvent(
385                     this, focusGain, "handleGain exc: " + e).printSlog(ALOGE, TAG));
386         }
387     }
388 
389     @GuardedBy("MediaFocusControl.mAudioFocusLock")
handleFocusGainFromRequest(int focusRequestResult)390     void handleFocusGainFromRequest(int focusRequestResult) {
391         if (focusRequestResult == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
392             mFocusController.restoreVShapedPlayers(this);
393         }
394     }
395 
396     @GuardedBy("MediaFocusControl.mAudioFocusLock")
handleFocusLoss(int focusLoss, @Nullable final FocusRequester frWinner, boolean forceDuck)397     void handleFocusLoss(int focusLoss, @Nullable final FocusRequester frWinner, boolean forceDuck)
398     {
399         if (DEBUG) {
400             Log.i(TAG, "handleFocusLoss for " + mClientId + " loss:" + focusLoss);
401         }
402         if (focusLoss != mFocusLossReceived) {
403             mFocusLossReceived = focusLoss;
404             mFocusLossWasNotified = false;
405             // before dispatching a focus loss, check if the following conditions are met:
406             // 1/ the framework is not supposed to notify the focus loser on a DUCK loss
407             //    (i.e. it has a focus controller that implements a ducking policy)
408             // 2/ it is a DUCK loss
409             // 3/ the focus loser isn't flagged as pausing in a DUCK loss
410             // if they are, do not notify the focus loser
411             if (!mFocusController.mustNotifyFocusOwnerOnDuck()
412                     && mFocusLossReceived == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK
413                     && (mGrantFlags
414                             & AudioManager.AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS) == 0) {
415                 if (DEBUG) {
416                     Log.v(TAG, "NOT dispatching " + focusChangeToString(mFocusLossReceived)
417                             + " to " + mClientId + ", to be handled externally");
418                 }
419                 mFocusController.notifyExtPolicyFocusLoss_syncAf(
420                         toAudioFocusInfo(), false /* wasDispatched */);
421                 return;
422             }
423 
424             // check enforcement by the framework
425             boolean handled = false;
426             if (frWinner != null) {
427                 handled = frameworkHandleFocusLoss(focusLoss, frWinner, forceDuck);
428             }
429 
430             if (handled) {
431                 if (DEBUG) {
432                     Log.v(TAG, "NOT dispatching " + focusChangeToString(mFocusLossReceived)
433                             + " to " + mClientId + ", response handled by framework");
434                 }
435                 mFocusController.notifyExtPolicyFocusLoss_syncAf(
436                         toAudioFocusInfo(), false /* wasDispatched */);
437                 return; // with mFocusLossWasNotified = false
438             }
439 
440             final IAudioFocusDispatcher fd = mFocusDispatcher;
441             if (fd != null) {
442                 if (DEBUG) {
443                     Log.v(TAG, "dispatching " + focusChangeToString(mFocusLossReceived) + " to "
444                         + mClientId);
445                 }
446                 mFocusController.notifyExtPolicyFocusLoss_syncAf(
447                         toAudioFocusInfo(), true /* wasDispatched */);
448                 mFocusLossWasNotified = true;
449                 try {
450                     fd.dispatchAudioFocusChange(mFocusLossReceived, mClientId);
451                     mEventLogger.enqueue(new FocusRequestEvent(
452                                 this, mFocusLossReceived, "handleLoss"));
453                 } catch (RemoteException e) {
454                     mEventLogger.enqueue(new FocusRequestEvent(
455                                 this, mFocusLossReceived, "handleLoss failed exc: " + e)
456                             .printSlog(ALOGE,TAG));
457                 }
458             } else {
459                 mEventLogger.enqueue(new FocusRequestEvent(
460                             this, mFocusLossReceived, "handleLoss failed no listener")
461                         .printSlog(ALOGE, TAG));
462             }
463         }
464     }
465 
466     /**
467      * Let the framework handle the focus loss if possible
468      * @param focusLoss
469      * @param frWinner
470      * @param forceDuck
471      * @return true if the framework handled the focus loss
472      */
473     @GuardedBy("MediaFocusControl.mAudioFocusLock")
frameworkHandleFocusLoss(int focusLoss, @NonNull final FocusRequester frWinner, boolean forceDuck)474     private boolean frameworkHandleFocusLoss(int focusLoss, @NonNull final FocusRequester frWinner,
475                                              boolean forceDuck) {
476         if (frWinner.mCallingUid == this.mCallingUid) {
477             // the focus change is within the same app, so let the dispatching
478             // happen as if the framework was not involved.
479             return false;
480         }
481 
482         if (focusLoss == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK) {
483             if (!MediaFocusControl.ENFORCE_DUCKING) {
484                 return false;
485             }
486 
487             // candidate for enforcement by the framework
488             if (!forceDuck && ((mGrantFlags
489                     & AudioManager.AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS) != 0)) {
490                 // the focus loser declared it would pause instead of duck, let it
491                 // handle it (the framework doesn't pause for apps)
492                 Log.v(TAG, "not ducking uid " + this.mCallingUid + " - flags");
493                 return false;
494             }
495             if (!forceDuck && (MediaFocusControl.ENFORCE_DUCKING_FOR_NEW
496                     && this.getSdkTarget() <= MediaFocusControl.DUCKING_IN_APP_SDK_LEVEL)) {
497                 // legacy behavior, apps used to be notified when they should be ducking
498                 Log.v(TAG, "not ducking uid " + this.mCallingUid + " - old SDK");
499                 return false;
500             }
501 
502             return mFocusController.duckPlayers(frWinner, /*loser*/ this, forceDuck);
503         }
504 
505         if (focusLoss == AudioManager.AUDIOFOCUS_LOSS) {
506             if (!MediaFocusControl.ENFORCE_FADEOUT_FOR_FOCUS_LOSS) {
507                 return false;
508             }
509 
510             // candidate for fade-out before a receiving a loss
511             boolean playersAreFaded =  mFocusController.fadeOutPlayers(frWinner, /* loser */ this);
512             if (playersAreFaded) {
513                 // active players are being faded out, delay the dispatch of focus loss
514                 // mark this instance as being faded so it's not released yet as the focus loss
515                 // will be dispatched later, it is now in limbo mode
516                 mFocusLossFadeLimbo = true;
517                 mFocusController.postDelayedLossAfterFade(this,
518                         mFocusController.getFadeOutDurationOnFocusLossMillis(
519                                 this.getAudioAttributes()));
520                 return true;
521             }
522         }
523 
524         return false;
525     }
526 
dispatchFocusChange(int focusChange, String reason)527     int dispatchFocusChange(int focusChange, String reason) {
528         final IAudioFocusDispatcher fd = mFocusDispatcher;
529         if (fd == null) {
530             if (MediaFocusControl.DEBUG) { Log.e(TAG, "dispatchFocusChange: no focus dispatcher"); }
531             return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
532         }
533         if (focusChange == AudioManager.AUDIOFOCUS_NONE) {
534             if (MediaFocusControl.DEBUG) { Log.v(TAG, "dispatchFocusChange: AUDIOFOCUS_NONE"); }
535             return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
536         } else if ((focusChange == AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK
537                 || focusChange == AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE
538                 || focusChange == AudioManager.AUDIOFOCUS_GAIN_TRANSIENT
539                 || focusChange == AudioManager.AUDIOFOCUS_GAIN)
540                 && (mFocusGainRequest != focusChange)){
541             Log.w(TAG, "focus gain was requested with " + mFocusGainRequest
542                     + ", dispatching " + focusChange);
543         } else if (focusChange == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK
544                 || focusChange == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT
545                 || focusChange == AudioManager.AUDIOFOCUS_LOSS) {
546             mFocusLossReceived = focusChange;
547         }
548         try {
549             fd.dispatchAudioFocusChange(focusChange, mClientId);
550             mEventLogger.enqueue(new FocusRequestEvent(this,
551                         focusChange, "dispatch: "  + reason));
552         } catch (RemoteException e) {
553             mEventLogger.enqueue(new FocusRequestEvent(
554                         this, focusChange, "dispatch failed: " + e).printSlog(ALOGE, TAG));
555             return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
556         }
557         return AudioManager.AUDIOFOCUS_REQUEST_GRANTED;
558     }
559 
560     @GuardedBy("MediaFocusControl.mAudioFocusLock")
dispatchFocusChangeWithFadeLocked(int focusChange, List<FocusRequester> otherActiveFrs)561     int dispatchFocusChangeWithFadeLocked(int focusChange, List<FocusRequester> otherActiveFrs) {
562         if (focusChange == AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK
563                 || focusChange == AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE
564                 || focusChange == AudioManager.AUDIOFOCUS_GAIN_TRANSIENT
565                 || focusChange == AudioManager.AUDIOFOCUS_GAIN) {
566             mFocusLossFadeLimbo = false;
567             mFocusController.restoreVShapedPlayers(this);
568         } else if (focusChange == AudioManager.AUDIOFOCUS_LOSS
569                 && mFocusController.shouldEnforceFade()) {
570             for (int index = 0; index < otherActiveFrs.size(); index++) {
571                 // candidate for fade-out before a receiving a loss
572                 if (mFocusController.fadeOutPlayers(otherActiveFrs.get(index), /* loser= */ this)) {
573                     // active players are being faded out, delay the dispatch of focus loss
574                     // mark this instance as being faded so it's not released yet as the focus loss
575                     // will be dispatched later, it is now in limbo mode
576                     mFocusLossFadeLimbo = true;
577                     mFocusController.postDelayedLossAfterFade(this,
578                             mFocusController.getFadeOutDurationOnFocusLossMillis(
579                                     this.getAudioAttributes()));
580                     return AudioManager.AUDIOFOCUS_REQUEST_DELAYED;
581                 }
582             }
583         }
584         return dispatchFocusChange(focusChange, "focus with fade");
585     }
586 
dispatchFocusResultFromExtPolicy(int requestResult)587     void dispatchFocusResultFromExtPolicy(int requestResult) {
588         final IAudioFocusDispatcher fd = mFocusDispatcher;
589         if (fd == null) {
590             if (MediaFocusControl.DEBUG) {
591                 Log.e(TAG, "dispatchFocusResultFromExtPolicy: no focus dispatcher");
592             }
593             return;
594         }
595         if (DEBUG) {
596             Log.v(TAG, "dispatching result" + requestResult + " to " + mClientId);
597         }
598         try {
599             fd.dispatchFocusResultFromExtPolicy(requestResult, mClientId);
600         } catch (RemoteException e) {
601             Log.e(TAG, "dispatchFocusResultFromExtPolicy: error talking to focus listener"
602                     + mClientId, e);
603         }
604     }
605 
toAudioFocusInfo()606     AudioFocusInfo toAudioFocusInfo() {
607         return new AudioFocusInfo(mAttributes, mCallingUid, mClientId, mPackageName,
608                 mFocusGainRequest, mFocusLossReceived, mGrantFlags, mSdkTarget);
609     }
610 
611     static class FocusRequestEvent extends EventLogger.Event {
612         private final String mClientId;
613         private final int mUid;
614         private final String  mPackageName;
615         private final int mCode;
616         private final String mDescription;
617 
FocusRequestEvent(FocusRequester fr, String description)618         public FocusRequestEvent(FocusRequester fr, String description) {
619             this(fr, -1, description);
620         }
621 
FocusRequestEvent(FocusRequester fr, int code, String description)622         public FocusRequestEvent(FocusRequester fr, int code, String description) {
623             mClientId = fr.getClientId();
624             mUid = fr.getClientUid();
625             mPackageName = fr.getPackageName();
626             mCode = code;
627             mDescription = description != null ? description : "";
628         }
629         @Override
eventToString()630         public String eventToString() {
631             return "focus owner: " + mClientId + " in uid: " + mUid
632                 + " pack: " + mPackageName
633                 + ((mCode != -1) ? " code: " + mCode : "")
634                 + " event: " + mDescription;
635         }
636     }
637 
638 }
639