Each dimmer can only have one dim layer at a time.

Only allow each Dimmer to control one dim layer at a time.
This is to make sure that there's only one dim per Task, Stack,
or NonAppWindowContainer.

Fixes: 72812390
Test: Open multiple dialogs on top of each other in one app.
Dim will remain the same and not get darker for each dialog.
Test: DimmerTests

Change-Id: I21ebbfb06fa6aefa8a66c5991d86fe22610a8859
diff --git a/services/core/java/com/android/server/wm/Dimmer.java b/services/core/java/com/android/server/wm/Dimmer.java
index b435605..1e7cb24 100644
--- a/services/core/java/com/android/server/wm/Dimmer.java
+++ b/services/core/java/com/android/server/wm/Dimmer.java
@@ -16,7 +16,6 @@
 
 package com.android.server.wm;
 
-import android.util.ArrayMap;
 import android.view.SurfaceControl;
 import android.graphics.Rect;
 
@@ -124,14 +123,13 @@
         }
     }
 
-    @VisibleForTesting
-    ArrayMap<WindowContainer, DimState> mDimLayerUsers = new ArrayMap<>();
-
     /**
      * The {@link WindowContainer} that our Dim's are bounded to. We may be dimming on behalf of the
      * host, some controller of it, or one of the hosts children.
      */
     private WindowContainer mHost;
+    private WindowContainer mLastRequestedDimContainer;
+    private DimState mDimState;
 
     Dimmer(WindowContainer host) {
         mHost = host;
@@ -146,29 +144,32 @@
     }
 
     /**
-     * Retreive the DimState for a given child of the host.
+     * Retrieve the DimState, creating one if it doesn't exist.
      */
     private DimState getDimState(WindowContainer container) {
-        DimState state = mDimLayerUsers.get(container);
-        if (state == null) {
+        if (mDimState == null) {
             final SurfaceControl ctl = makeDimLayer();
-            state = new DimState(ctl);
+            mDimState = new DimState(ctl);
             /**
              * See documentation on {@link #dimAbove} to understand lifecycle management of Dim's
              * via state resetting for Dim's with containers.
              */
             if (container == null) {
-                state.mDontReset = true;
+                mDimState.mDontReset = true;
             }
-            mDimLayerUsers.put(container, state);
         }
-        return state;
+
+        mLastRequestedDimContainer = container;
+        return mDimState;
     }
 
     private void dim(SurfaceControl.Transaction t, WindowContainer container, int relativeLayer,
             float alpha) {
         final DimState d = getDimState(container);
         if (container != null) {
+            // The dim method is called from WindowState.prepareSurfaces(), which is always called
+            // in the correct Z from lowest Z to highest. This ensures that the dim layer is always
+            // relative to the highest Z layer with a dim.
             t.setRelativeLayer(d.mDimLayer, container.getSurfaceControl(), relativeLayer);
         } else {
             t.setLayer(d.mDimLayer, Integer.MAX_VALUE);
@@ -237,11 +238,8 @@
      * a chance to request dims to continue.
      */
     void resetDimStates() {
-        for (int i = mDimLayerUsers.size() - 1; i >= 0; i--) {
-            final DimState state = mDimLayerUsers.valueAt(i);
-            if (!state.mDontReset) {
-                state.mDimming = false;
-            }
+        if (mDimState != null && !mDimState.mDontReset) {
+            mDimState.mDimming = false;
         }
     }
 
@@ -254,30 +252,25 @@
      * @return true if any Dims were updated.
      */
     boolean updateDims(SurfaceControl.Transaction t, Rect bounds) {
-        boolean didSomething = false;
-        for (int i = mDimLayerUsers.size() - 1; i >= 0; i--) {
-            DimState state = mDimLayerUsers.valueAt(i);
-            WindowContainer container = mDimLayerUsers.keyAt(i);
-
-            // TODO: We want to animate the addition and removal of Dim's instead of immediately
-            // acting. When we do this we need to take care to account for the "Replacing Windows"
-            // case (and seamless dim transfer).
-            if (!state.mDimming) {
-                mDimLayerUsers.removeAt(i);
-                startDimExit(container, state.mSurfaceAnimator, t);
-            } else {
-                didSomething = true;
-                // TODO: Once we use geometry from hierarchy this falls away.
-                t.setSize(state.mDimLayer, bounds.width(), bounds.height());
-                t.setPosition(state.mDimLayer, bounds.left, bounds.top);
-                if (!state.isVisible) {
-                    state.isVisible = true;
-                    t.show(state.mDimLayer);
-                    startDimEnter(container, state.mSurfaceAnimator, t);
-                }
-            }
+        if (mDimState == null) {
+            return false;
         }
-        return didSomething;
+
+        if (!mDimState.mDimming) {
+            startDimExit(mLastRequestedDimContainer, mDimState.mSurfaceAnimator, t);
+            mDimState = null;
+            return false;
+        } else {
+            // TODO: Once we use geometry from hierarchy this falls away.
+            t.setSize(mDimState.mDimLayer, bounds.width(), bounds.height());
+            t.setPosition(mDimState.mDimLayer, bounds.left, bounds.top);
+            if (!mDimState.isVisible) {
+                mDimState.isVisible = true;
+                t.show(mDimState.mDimLayer);
+                startDimEnter(mLastRequestedDimContainer, mDimState.mSurfaceAnimator, t);
+            }
+            return true;
+        }
     }
 
     private void startDimEnter(WindowContainer container, SurfaceAnimator animator,