Merge "Use and reparent the task's dim" into main
diff --git a/core/java/android/window/flags/windowing_frontend.aconfig b/core/java/android/window/flags/windowing_frontend.aconfig
index 7f48c42..76989f9 100644
--- a/core/java/android/window/flags/windowing_frontend.aconfig
+++ b/core/java/android/window/flags/windowing_frontend.aconfig
@@ -180,6 +180,17 @@
 }
 
 flag {
+  name: "use_tasks_dim_only"
+  namespace: "windowing_frontend"
+  description: "Only use the task's dim and reparent it to the display area when needed instead of coordinating multiple dimmers"
+  bug: "352522056"
+  is_fixed_read_only: true
+  metadata {
+    purpose: PURPOSE_BUGFIX
+  }
+}
+
+flag {
     name: "release_snapshot_aggressively"
     namespace: "windowing_frontend"
     description: "Actively release task snapshot memory"
diff --git a/services/core/java/com/android/server/wm/Dimmer.java b/services/core/java/com/android/server/wm/Dimmer.java
index 7c31177..2d1eb41 100644
--- a/services/core/java/com/android/server/wm/Dimmer.java
+++ b/services/core/java/com/android/server/wm/Dimmer.java
@@ -28,7 +28,13 @@
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.protolog.ProtoLog;
+import com.android.window.flags.Flags;
 
+
+/**
+ * Utility class for use by a WindowContainer implementation to add "DimLayer" support, that is
+ * black layers of varying opacity at various Z-levels which create the effect of a Dim.
+ */
 class Dimmer {
 
     /**
@@ -122,8 +128,10 @@
         /**
          * Set the parameters to prepare the dim to be relative parented to the dimming container
          */
-        void prepareReparent(@NonNull WindowContainer<?> relativeParent, int relativeLayer) {
+        void prepareReparent(@NonNull WindowContainer<?> geometryParent,
+                @NonNull WindowContainer<?> relativeParent, int relativeLayer) {
             mAnimationHelper.setRequestedRelativeParent(relativeParent, relativeLayer);
+            mAnimationHelper.setRequestedGeometryParent(geometryParent);
         }
 
         /**
@@ -138,7 +146,8 @@
          * Whether anyone is currently requesting the dim
          */
         boolean isDimming() {
-            return mLastRequestedDimContainer != null;
+            return mLastRequestedDimContainer != null
+                    && (mHostContainer.isVisibleRequested() || !Flags.useTasksDimOnly());
         }
 
         private SurfaceControl makeDimLayer() {
@@ -208,13 +217,15 @@
      * the child of the host should call adjustRelativeLayer and {@link Dimmer#adjustAppearance} to
      * continue dimming. Indeed, this method won't be able to keep dimming or get a new DimState
      * without also adjusting the appearance.
+     * @param geometryParent    The container that defines the geometry of the dim
      * @param dimmingContainer      The container which to dim above. Should be a child of the host.
      * @param relativeLayer  The position of the dim wrt the container
      */
-    public void adjustRelativeLayer(@NonNull WindowContainer<?> dimmingContainer,
+    public void adjustPosition(@NonNull WindowContainer<?> geometryParent,
+                                    @NonNull WindowContainer<?> dimmingContainer,
                                     int relativeLayer) {
         if (mDimState != null) {
-            mDimState.prepareReparent(dimmingContainer, relativeLayer);
+            mDimState.prepareReparent(geometryParent, dimmingContainer, relativeLayer);
         }
     }
 
@@ -236,7 +247,9 @@
             return false;
         } else {
             // Someone is dimming, show the requested changes
-            mDimState.adjustSurfaceLayout(t);
+            if (!Flags.useTasksDimOnly()) {
+                mDimState.adjustSurfaceLayout(t);
+            }
             final WindowState ws = mDimState.mLastRequestedDimContainer.asWindowState();
             if (!mDimState.mIsVisible && ws != null && ws.mActivityRecord != null
                     && ws.mActivityRecord.mStartingData != null) {
@@ -263,6 +276,7 @@
         return mDimState != null ? mDimState.mDimSurface : null;
     }
 
+    @Deprecated
     Rect getDimBounds() {
         return mDimState != null ? mDimState.mDimBounds : null;
     }
diff --git a/services/core/java/com/android/server/wm/DimmerAnimationHelper.java b/services/core/java/com/android/server/wm/DimmerAnimationHelper.java
index df1549e..3dba57f 100644
--- a/services/core/java/com/android/server/wm/DimmerAnimationHelper.java
+++ b/services/core/java/com/android/server/wm/DimmerAnimationHelper.java
@@ -26,6 +26,7 @@
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.util.Log;
 import android.util.proto.ProtoOutputStream;
 import android.view.SurfaceControl;
@@ -48,6 +49,7 @@
         private float mAlpha = -1f;
         private int mBlurRadius = -1;
         private WindowContainer<?> mDimmingContainer = null;
+        private WindowContainer<?> mGeometryParent = null;
         private int mRelativeLayer = -1;
         private static final float EPSILON = 0.0001f;
 
@@ -103,6 +105,11 @@
         mRequestedProperties.mRelativeLayer = relativeLayer;
     }
 
+    // Sets the requested layer to reparent the dim to without applying it immediately
+    void setRequestedGeometryParent(WindowContainer<?> geometryParent) {
+        mRequestedProperties.mGeometryParent = geometryParent;
+    }
+
     // Sets a requested change without applying it immediately
     void setRequestedAppearance(float alpha, int blurRadius) {
         mRequestedProperties.mAlpha = alpha;
@@ -129,7 +136,9 @@
         }
 
         dim.ensureVisible(t);
-        relativeReparent(dim.mDimSurface,
+        reparent(dim.mDimSurface,
+                mRequestedProperties.mGeometryParent != mCurrentProperties.mGeometryParent
+                        ? mRequestedProperties.mGeometryParent.getSurfaceControl() : null,
                 mRequestedProperties.mDimmingContainer.getSurfaceControl(),
                 mRequestedProperties.mRelativeLayer, t);
 
@@ -214,11 +223,17 @@
     }
 
     /**
-     * Change the relative parent of this dim layer
+     * Change the geometry and relative parent of this dim layer
      */
-    void relativeReparent(@NonNull SurfaceControl dimLayer, @NonNull SurfaceControl relativeParent,
-                          int relativePosition, @NonNull SurfaceControl.Transaction t) {
+    void reparent(@NonNull SurfaceControl dimLayer,
+                  @Nullable SurfaceControl newGeometryParent,
+                  @NonNull SurfaceControl relativeParent,
+                  int relativePosition,
+                  @NonNull SurfaceControl.Transaction t) {
         try {
+            if (newGeometryParent != null) {
+                t.reparent(dimLayer, newGeometryParent);
+            }
             t.setRelativeLayer(dimLayer, relativeParent, relativePosition);
         } catch (NullPointerException e) {
             Log.w(TAG, "Tried to change parent of dim " + dimLayer + " after remove", e);
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 259ca83..74adeb9 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -3201,6 +3201,14 @@
         return "Task=" + mTaskId;
     }
 
+    WindowContainer<?> getDimmerParent() {
+        if (!inMultiWindowMode() && isTranslucentForTransition()) {
+            return getRootDisplayArea();
+        }
+        return this;
+    }
+
+    @Deprecated
     @Override
     Dimmer getDimmer() {
         // If the window is in multi-window mode, we want to dim at the Task level to ensure the dim
diff --git a/services/core/java/com/android/server/wm/TaskFragment.java b/services/core/java/com/android/server/wm/TaskFragment.java
index 750394d..c83b280 100644
--- a/services/core/java/com/android/server/wm/TaskFragment.java
+++ b/services/core/java/com/android/server/wm/TaskFragment.java
@@ -3102,6 +3102,7 @@
         return forAllWindows(getDimBehindWindow, true);
     }
 
+    @Deprecated
     @Override
     Dimmer getDimmer() {
         // If this is in an embedded TaskFragment and we want the dim applies on the TaskFragment.
diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java
index cf5a1e6..358adc3 100644
--- a/services/core/java/com/android/server/wm/Transition.java
+++ b/services/core/java/com/android/server/wm/Transition.java
@@ -463,14 +463,26 @@
 
     boolean canApplyDim(@NonNull Task task) {
         if (mTransientLaunches == null) return true;
-        final Dimmer dimmer = task.getDimmer();
-        if (dimmer == null) {
-            return false;
-        }
-        if (dimmer.hostIsTask()) {
+        if (Flags.useTasksDimOnly()) {
+            WindowContainer<?> dimmerParent = task.getDimmerParent();
+            if (dimmerParent == null) {
+                return false;
+            }
             // Always allow to dim if the host only affects its task.
-            return true;
+            if (dimmerParent.asTask() == task) {
+                return true;
+            }
+        } else {
+            final Dimmer dimmer = task.getDimmer();
+            if (dimmer == null) {
+                return false;
+            }
+            if (dimmer.hostIsTask()) {
+                // Always allow to dim if the host only affects its task.
+                return true;
+            }
         }
+
         // The dimmer host of a translucent task can be a display, then it is not in transient-hide.
         for (int i = mTransientLaunches.size() - 1; i >= 0; --i) {
             // The transient task is usually the task of recents/home activity.
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index eb1a80b..64f9c01 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -107,11 +107,10 @@
 import android.window.IWindowContainerToken;
 import android.window.WindowContainerToken;
 
-import com.android.internal.R;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.graphics.ColorUtils;
-import com.android.internal.protolog.common.LogLevel;
 import com.android.internal.protolog.ProtoLog;
+import com.android.internal.protolog.common.LogLevel;
 import com.android.internal.util.ToBooleanFunction;
 import com.android.server.wm.SurfaceAnimator.Animatable;
 import com.android.server.wm.SurfaceAnimator.AnimationType;
@@ -3765,6 +3764,7 @@
         }, true /* traverseTopToBottom */);
     }
 
+    @Deprecated
     Dimmer getDimmer() {
         if (mParent == null) {
             return null;
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 240978a..164994c 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -103,6 +103,7 @@
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ANIM;
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_APP_TRANSITIONS;
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_BACK_PREVIEW;
+import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_DIMMER;
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_FOCUS;
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_FOCUS_LIGHT;
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ORIENTATION;
@@ -5195,9 +5196,10 @@
     }
 
     private void applyDims() {
+        Task task = getTask();
         if (((mAttrs.flags & FLAG_DIM_BEHIND) != 0 || shouldDrawBlurBehind())
                 && mWinAnimator.getShown()
-                && !mHidden && mTransitionController.canApplyDim(getTask())) {
+                && !mHidden && mTransitionController.canApplyDim(task)) {
             // Only show the Dimmer when the following is satisfied:
             // 1. The window has the flag FLAG_DIM_BEHIND or blur behind is requested
             // 2. The WindowToken is not hidden so dims aren't shown when the window is exiting.
@@ -5210,10 +5212,31 @@
             // If the window is visible from surface flinger perspective (mWinAnimator.getShown())
             // but not window manager visible (!isVisibleNow()), it can still be the parent of the
             // dim, but can not create a new surface or continue a dim alone.
-            if (isVisibleNow()) {
-                getDimmer().adjustAppearance(this, dimAmount, blurRadius);
+            Dimmer dimmer;
+            WindowContainer<?> geometryParent = task;
+            if (Flags.useTasksDimOnly()) {
+                if (task != null) {
+                    geometryParent = task.getDimmerParent();
+                    dimmer = task.mDimmer;
+                } else {
+                    RootDisplayArea displayArea = getRootDisplayArea();
+                    geometryParent = displayArea;
+                    dimmer = displayArea != null ? displayArea.getDimmer() : null;
+                }
+                if (dimmer == null) {
+                    ProtoLog.e(WM_DEBUG_DIMMER, "WindowState %s does not have task or"
+                            + " display area for dimming", this);
+                    return;
+                }
+            } else {
+                dimmer = getDimmer();
             }
-            getDimmer().adjustRelativeLayer(this, -1 /* relativeLayer */);
+
+            if (isVisibleNow()) {
+                dimmer.adjustAppearance(this, dimAmount, blurRadius);
+            }
+            dimmer.adjustPosition(geometryParent,
+                    this /* relativeParent */, -1 /* relativeLayer */);
         }
     }
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/DimmerTests.java b/services/tests/wmtests/src/com/android/server/wm/DimmerTests.java
index 08f1dff..771e290 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DimmerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DimmerTests.java
@@ -32,11 +32,13 @@
 
 import android.graphics.Rect;
 import android.platform.test.annotations.Presubmit;
+import android.platform.test.annotations.RequiresFlagsDisabled;
 import android.view.SurfaceControl;
 import android.view.SurfaceSession;
 
 import com.android.server.testutils.StubTransaction;
 import com.android.server.wm.utils.MockAnimationAdapter;
+import com.android.window.flags.Flags;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -142,11 +144,12 @@
     }
 
     @Test
+    @RequiresFlagsDisabled(Flags.FLAG_USE_TASKS_DIM_ONLY)
     public void testUpdateDimsAppliesCrop() {
         mHost.addChild(mChild, 0);
 
         mDimmer.adjustAppearance(mChild, 1, 1);
-        mDimmer.adjustRelativeLayer(mChild, -1);
+        mDimmer.adjustPosition(mChild, mChild, -1);
 
         int width = 100;
         int height = 300;
@@ -163,7 +166,7 @@
         final int blur = 50;
         mHost.addChild(mChild, 0);
         mDimmer.adjustAppearance(mChild, alpha, blur);
-        mDimmer.adjustRelativeLayer(mChild, -1);
+        mDimmer.adjustPosition(mChild, mChild, -1);
         SurfaceControl dimLayer = mDimmer.getDimLayer();
 
         assertNotNull("Dimmer should have created a surface", dimLayer);
@@ -184,12 +187,12 @@
         final int blur = 50;
         // Dim once
         mDimmer.adjustAppearance(mChild, alpha, blur);
-        mDimmer.adjustRelativeLayer(mChild, -1);
+        mDimmer.adjustPosition(mChild, mChild, -1);
         SurfaceControl dimLayer = mDimmer.getDimLayer();
         mDimmer.updateDims(mTransaction);
         // Reset, and don't dim
         mDimmer.resetDimStates();
-        mDimmer.adjustRelativeLayer(mChild, -1);
+        mDimmer.adjustPosition(mChild, mChild, -1);
         mDimmer.updateDims(mTransaction);
         verify(mTransaction).show(dimLayer);
         verify(mTransaction).remove(dimLayer);
@@ -203,24 +206,25 @@
         final int blur = 20;
         // Dim once
         mDimmer.adjustAppearance(mChild, alpha, blur);
-        mDimmer.adjustRelativeLayer(mChild, -1);
+        mDimmer.adjustPosition(mChild, mChild, -1);
         SurfaceControl dimLayer = mDimmer.getDimLayer();
         mDimmer.updateDims(mTransaction);
         // Reset and dim again
         mDimmer.resetDimStates();
         mDimmer.adjustAppearance(mChild, alpha, blur);
-        mDimmer.adjustRelativeLayer(mChild, -1);
+        mDimmer.adjustPosition(mChild, mChild, -1);
         mDimmer.updateDims(mTransaction);
         verify(mTransaction).show(dimLayer);
         verify(mTransaction, never()).remove(dimLayer);
     }
 
     @Test
+    @RequiresFlagsDisabled(Flags.FLAG_USE_TASKS_DIM_ONLY)
     public void testDimUpdateWhileDimming() {
         mHost.addChild(mChild, 0);
         final float alpha = 0.8f;
         mDimmer.adjustAppearance(mChild, alpha, 20);
-        mDimmer.adjustRelativeLayer(mChild, -1);
+        mDimmer.adjustPosition(mChild, mChild, -1);
         final Rect bounds = mDimmer.getDimBounds();
 
         SurfaceControl dimLayer = mDimmer.getDimLayer();
@@ -240,7 +244,7 @@
     public void testRemoveDimImmediately() {
         mHost.addChild(mChild, 0);
         mDimmer.adjustAppearance(mChild, 1, 2);
-        mDimmer.adjustRelativeLayer(mChild, -1);
+        mDimmer.adjustPosition(mChild, mChild, -1);
         SurfaceControl dimLayer = mDimmer.getDimLayer();
         mDimmer.updateDims(mTransaction);
         verify(mTransaction, times(1)).show(dimLayer);
@@ -265,18 +269,18 @@
 
         mDimmer.resetDimStates();
         mDimmer.adjustAppearance(mChild, 0.1f, 0);
-        mDimmer.adjustRelativeLayer(mChild, -1);
+        mDimmer.adjustPosition(mChild, mChild, -1);
         SurfaceControl dimLayer = mDimmer.getDimLayer();
         mDimmer.updateDims(mTransaction);
 
         mDimmer.resetDimStates();
         mDimmer.adjustAppearance(mChild, 0.2f, 0);
-        mDimmer.adjustRelativeLayer(mChild, -1);
+        mDimmer.adjustPosition(mChild, mChild, -1);
         mDimmer.updateDims(mTransaction);
 
         mDimmer.resetDimStates();
         mDimmer.adjustAppearance(mChild, 0.3f, 0);
-        mDimmer.adjustRelativeLayer(mChild, -1);
+        mDimmer.adjustPosition(mChild, mChild, -1);
         mDimmer.updateDims(mTransaction);
 
         verify(mTransaction).setAlpha(dimLayer, 0.2f);
@@ -296,18 +300,18 @@
 
         mDimmer.resetDimStates();
         mDimmer.adjustAppearance(mChild, 0.2f, 0);
-        mDimmer.adjustRelativeLayer(mChild, -1);
+        mDimmer.adjustPosition(mChild, mChild, -1);
         SurfaceControl dimLayer = mDimmer.getDimLayer();
         mDimmer.updateDims(mTransaction);
 
         mDimmer.resetDimStates();
         mDimmer.adjustAppearance(mChild, 0.1f, 0);
-        mDimmer.adjustRelativeLayer(mChild, -1);
+        mDimmer.adjustPosition(mChild, mChild, -1);
         mDimmer.updateDims(mTransaction);
 
         mDimmer.resetDimStates();
         mDimmer.adjustAppearance(mChild, 0f, 0);
-        mDimmer.adjustRelativeLayer(mChild, -1);
+        mDimmer.adjustPosition(mChild, mChild, -1);
         mDimmer.updateDims(mTransaction);
 
         mDimmer.resetDimStates();
@@ -326,13 +330,13 @@
         mHost.addChild(second, 1);
 
         mDimmer.adjustAppearance(first, 0.5f, 0);
-        mDimmer.adjustRelativeLayer(first, -1);
+        mDimmer.adjustPosition(mChild, first, -1);
         SurfaceControl dimLayer = mDimmer.getDimLayer();
         mDimmer.updateDims(mTransaction);
 
         mDimmer.resetDimStates();
         mDimmer.adjustAppearance(second, 0.9f, 0);
-        mDimmer.adjustRelativeLayer(second, -1);
+        mDimmer.adjustPosition(mChild, second, -1);
         mDimmer.updateDims(mTransaction);
 
         verify(sTestAnimation, times(2)).startAnimation(
@@ -354,10 +358,10 @@
         mHost.addChild(second, 1);
 
         mDimmer.adjustAppearance(first, 0.5f, 0);
-        mDimmer.adjustRelativeLayer(first, -1);
+        mDimmer.adjustPosition(mChild, first, -1);
         SurfaceControl dimLayer = mDimmer.getDimLayer();
         mDimmer.adjustAppearance(second, 0.9f, 0);
-        mDimmer.adjustRelativeLayer(second, -1);
+        mDimmer.adjustPosition(mChild, second, -1);
         mDimmer.updateDims(mTransaction);
 
         verify(sTestAnimation, times(1)).startAnimation(