Merge "[Ongoing Call] Remove the call chip when #onEntryCleanUp is called." into sc-qpr1-dev
diff --git a/services/core/java/com/android/server/audio/FadeOutManager.java b/services/core/java/com/android/server/audio/FadeOutManager.java
index bb627e5..00cb280 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 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 @@
         }
     }
 
+    /**
+     * 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 @@
         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 e6c4abfa..9548ada 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 @@
     @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 @@
                 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 @@
      */
     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 @@
                             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 a13b2eb..b94cea4 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 @@
 
     @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);
     }
 
     //=================================================================