diff options
3 files changed, 75 insertions, 8 deletions
diff --git a/services/core/java/com/android/server/audio/FadeOutManager.java b/services/core/java/com/android/server/audio/FadeOutManager.java index bb627e5a21fb..00cb280236d7 100644 --- a/services/core/java/com/android/server/audio/FadeOutManager.java +++ b/services/core/java/com/android/server/audio/FadeOutManager.java @@ -36,7 +36,16 @@ public final class FadeOutManager { public static final String TAG = "AudioService.FadeOutManager"; + /** duration of the fade out curve */ /*package*/ static final long FADE_OUT_DURATION_MS = 2000; + /** + * delay after which a faded out player will be faded back in. This will be heard by the user + * only in the case of unmuting players that didn't respect audio focus and didn't stop/pause + * when their app lost focus. + * This is the amount of time between the app being notified of + * the focus loss (when its muted by the fade out), and the time fade in (to unmute) starts + */ + /*package*/ static final long DELAY_FADE_IN_OFFENDERS_MS = 2000; private static final boolean DEBUG = PlaybackActivityMonitor.DEBUG; @@ -148,6 +157,11 @@ public final class FadeOutManager { } } + /** + * Remove the app for the given UID from the list of faded out apps, unfade out its players + * @param uid the uid for the app to unfade out + * @param players map of current available players (so we can get an APC from piid) + */ synchronized void unfadeOutUid(int uid, HashMap<Integer, AudioPlaybackConfiguration> players) { Log.i(TAG, "unfadeOutUid() uid:" + uid); final FadedOutApp fa = mFadedApps.remove(uid); @@ -157,12 +171,6 @@ public final class FadeOutManager { fa.removeUnfadeAll(players); } - synchronized void forgetUid(int uid) { - //Log.v(TAG, "forget() uid:" + uid); - //mFadedApps.remove(uid); - // TODO unfade all players later in case they are reused or the app continued to play - } - // pre-condition: apc.getPlayerState() == AudioPlaybackConfiguration.PLAYER_STATE_STARTED // see {@link PlaybackActivityMonitor#playerEvent} synchronized void checkFade(@NonNull AudioPlaybackConfiguration apc) { diff --git a/services/core/java/com/android/server/audio/MediaFocusControl.java b/services/core/java/com/android/server/audio/MediaFocusControl.java index e6c4abfa2086..9548ada14b8e 100644 --- a/services/core/java/com/android/server/audio/MediaFocusControl.java +++ b/services/core/java/com/android/server/audio/MediaFocusControl.java @@ -131,6 +131,11 @@ public class MediaFocusControl implements PlayerFocusEnforcer { @Override public void restoreVShapedPlayers(@NonNull FocusRequester winner) { mFocusEnforcer.restoreVShapedPlayers(winner); + // remove scheduled events to unfade out offending players (if any) corresponding to + // this uid, as we're removing any effects of muting/ducking/fade out now + mFocusHandler.removeEqualMessages(MSL_L_FORGET_UID, + new ForgetFadeUidInfo(winner.getClientUid())); + } @Override @@ -1182,6 +1187,13 @@ public class MediaFocusControl implements PlayerFocusEnforcer { mFocusHandler.obtainMessage(MSG_L_FOCUS_LOSS_AFTER_FADE, focusLoser), FadeOutManager.FADE_OUT_DURATION_MS); } + + private void postForgetUidLater(int uid) { + mFocusHandler.sendMessageDelayed( + mFocusHandler.obtainMessage(MSL_L_FORGET_UID, new ForgetFadeUidInfo(uid)), + FadeOutManager.DELAY_FADE_IN_OFFENDERS_MS); + } + //================================================================= // Message handling private Handler mFocusHandler; @@ -1196,6 +1208,8 @@ public class MediaFocusControl implements PlayerFocusEnforcer { */ private static final int MSG_L_FOCUS_LOSS_AFTER_FADE = 1; + private static final int MSL_L_FORGET_UID = 2; + private void initFocusThreading() { mFocusThread = new HandlerThread(TAG); mFocusThread.start(); @@ -1213,15 +1227,56 @@ public class MediaFocusControl implements PlayerFocusEnforcer { if (loser.isInFocusLossLimbo()) { loser.dispatchFocusChange(AudioManager.AUDIOFOCUS_LOSS); loser.release(); - mFocusEnforcer.forgetUid(loser.getClientUid()); + postForgetUidLater(loser.getClientUid()); } } break; + + case MSL_L_FORGET_UID: + final int uid = ((ForgetFadeUidInfo) msg.obj).mUid; + if (DEBUG) { + Log.d(TAG, "MSL_L_FORGET_UID uid=" + uid); + } + mFocusEnforcer.forgetUid(uid); + break; default: break; } } }; + } + /** + * Class to associate a UID with a scheduled event to "forget" a UID for the fade out behavior. + * Having a class with an equals() override allows using Handler.removeEqualsMessage() to + * unschedule events when needed. Here we need to unschedule the "unfading out" == "forget uid" + * whenever a new, more recent, focus related event happens before this one is handled. + */ + private static final class ForgetFadeUidInfo { + private final int mUid; + + ForgetFadeUidInfo(int uid) { + mUid = uid; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + final ForgetFadeUidInfo f = (ForgetFadeUidInfo) o; + if (f.mUid != mUid) { + return false; + } + return true; + } + + @Override + public int hashCode() { + return mUid; + } } } diff --git a/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java b/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java index a13b2eb344d9..b94cea4d5d40 100644 --- a/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java +++ b/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java @@ -747,7 +747,11 @@ public final class PlaybackActivityMonitor @Override public void forgetUid(int uid) { - mFadingManager.forgetUid(uid); + final HashMap<Integer, AudioPlaybackConfiguration> players; + synchronized (mPlayerLock) { + players = (HashMap<Integer, AudioPlaybackConfiguration>) mPlayers.clone(); + } + mFadingManager.unfadeOutUid(uid, players); } //================================================================= |