Update controls after addToDisplay/relayout before dispatching insets

A window might request to control insets before it is added to WM and
expect the first dispatched WindowInsets as requested.

The first insets state returned from addToDisplay or relayout might be
not expected if the window just become thecontrol target in the
function.

With this CL, WM can return controls from addToDisplay and relayout, so
that the client can apply controls immediately, and update controlled
insets sources before dispatching the insets to the view hierarchy. This
enaures the insets dispatched are up-to-date.

Fix: 150756571
Test: atest WindowInsetsControllerTests RelayoutPerfTest
            WindowAddRemovePerfTest
Change-Id: Ib78c24beb7af5a54ad78935c3ddb260ef9645212
diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java
index 5f3732a..7d8a56e 100644
--- a/services/core/java/com/android/server/wm/Session.java
+++ b/services/core/java/com/android/server/wm/Session.java
@@ -51,6 +51,7 @@
 import android.view.IWindowSession;
 import android.view.IWindowSessionCallback;
 import android.view.InputChannel;
+import android.view.InsetsSourceControl;
 import android.view.InsetsState;
 import android.view.SurfaceControl;
 import android.view.SurfaceSession;
@@ -158,10 +159,10 @@
             int viewVisibility, int displayId, Rect outFrame, Rect outContentInsets,
             Rect outStableInsets,
             DisplayCutout.ParcelableWrapper outDisplayCutout, InputChannel outInputChannel,
-            InsetsState outInsetsState) {
+            InsetsState outInsetsState, InsetsSourceControl[] outActiveControls) {
         return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId, outFrame,
                 outContentInsets, outStableInsets, outDisplayCutout, outInputChannel,
-                outInsetsState);
+                outInsetsState, outActiveControls);
     }
 
     @Override
@@ -171,7 +172,7 @@
         return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId,
                 new Rect() /* outFrame */, outContentInsets, outStableInsets,
                 new DisplayCutout.ParcelableWrapper() /* cutout */, null /* outInputChannel */,
-                outInsetsState);
+                outInsetsState, null);
     }
 
     @Override
@@ -191,7 +192,8 @@
             Rect outStableInsets, Rect outBackdropFrame,
             DisplayCutout.ParcelableWrapper cutout, MergedConfiguration mergedConfiguration,
             SurfaceControl outSurfaceControl, InsetsState outInsetsState,
-            Point outSurfaceSize, SurfaceControl outBLASTSurfaceControl) {
+            InsetsSourceControl[] outActiveControls, Point outSurfaceSize,
+            SurfaceControl outBLASTSurfaceControl) {
         if (false) Slog.d(TAG_WM, ">>>>>> ENTERED relayout from "
                 + Binder.getCallingPid());
         Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, mRelayoutTag);
@@ -199,8 +201,8 @@
                 requestedWidth, requestedHeight, viewFlags, flags, frameNumber,
                 outFrame, outContentInsets, outVisibleInsets,
                 outStableInsets, outBackdropFrame, cutout,
-                mergedConfiguration, outSurfaceControl, outInsetsState, outSurfaceSize,
-                outBLASTSurfaceControl);
+                mergedConfiguration, outSurfaceControl, outInsetsState, outActiveControls,
+                outSurfaceSize, outBLASTSurfaceControl);
         Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
         if (false) Slog.d(TAG_WM, "<<<<<< EXITING relayout to "
                 + Binder.getCallingPid());
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotSurface.java b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
index eb005e0..f6ed2a9 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
@@ -68,6 +68,7 @@
 import android.util.Slog;
 import android.view.DisplayCutout;
 import android.view.IWindowSession;
+import android.view.InsetsSourceControl;
 import android.view.InsetsState;
 import android.view.Surface;
 import android.view.SurfaceControl;
@@ -164,6 +165,7 @@
         final Rect tmpContentInsets = new Rect();
         final Rect tmpStableInsets = new Rect();
         final InsetsState mTmpInsetsState = new InsetsState();
+        final InsetsSourceControl[] mTempControls = new InsetsSourceControl[0];
         final MergedConfiguration tmpMergedConfiguration = new MergedConfiguration();
         final TaskDescription taskDescription = new TaskDescription();
         taskDescription.setBackgroundColor(WHITE);
@@ -231,8 +233,8 @@
         }
         try {
             final int res = session.addToDisplay(window, window.mSeq, layoutParams,
-                    View.GONE, activity.getDisplayContent().getDisplayId(), tmpFrame, tmpRect, tmpRect,
-                    tmpCutout, null, mTmpInsetsState);
+                    View.GONE, activity.getDisplayContent().getDisplayId(), tmpFrame, tmpRect,
+                    tmpRect, tmpCutout, null, mTmpInsetsState, mTempControls);
             if (res < 0) {
                 Slog.w(TAG, "Failed to add snapshot starting window res=" + res);
                 return null;
@@ -249,7 +251,7 @@
             session.relayout(window, window.mSeq, layoutParams, -1, -1, View.VISIBLE, 0, -1,
                     tmpFrame, tmpContentInsets, tmpRect, tmpStableInsets, tmpRect,
                     tmpCutout, tmpMergedConfiguration, surfaceControl, mTmpInsetsState,
-                    sTmpSurfaceSize, sTmpSurfaceControl);
+                    mTempControls, sTmpSurfaceSize, sTmpSurfaceControl);
         } catch (RemoteException e) {
             // Local call.
         }
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 3cbb85b..9d4af5a 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -227,6 +227,7 @@
 import android.view.InputDevice;
 import android.view.InputEvent;
 import android.view.InputWindowHandle;
+import android.view.InsetsSourceControl;
 import android.view.InsetsState;
 import android.view.KeyEvent;
 import android.view.MagnificationSpec;
@@ -1356,7 +1357,7 @@
             LayoutParams attrs, int viewVisibility, int displayId, Rect outFrame,
             Rect outContentInsets, Rect outStableInsets,
             DisplayCutout.ParcelableWrapper outDisplayCutout, InputChannel outInputChannel,
-            InsetsState outInsetsState) {
+            InsetsState outInsetsState, InsetsSourceControl[] outActiveControls) {
         int[] appOp = new int[1];
         final boolean isRoundedCornerOverlay = (attrs.privateFlags
                 & PRIVATE_FLAG_IS_ROUNDED_CORNERS_OVERLAY) != 0;
@@ -1643,8 +1644,7 @@
                     outStableInsets, outDisplayCutout)) {
                 res |= WindowManagerGlobal.ADD_FLAG_ALWAYS_CONSUME_SYSTEM_BARS;
             }
-            outInsetsState.set(win.getInsetsState(),
-                    win.mClient instanceof IWindow.Stub /* copySource */);
+            outInsetsState.set(win.getInsetsState(), win.isClientLocal());
 
             if (mInTouchMode) {
                 res |= WindowManagerGlobal.ADD_FLAG_IN_TOUCH_MODE;
@@ -1678,6 +1678,8 @@
             }
             displayContent.getInputMonitor().updateInputWindowsLw(false /*force*/);
 
+            getInsetsSourceControls(win, outActiveControls);
+
             ProtoLog.v(WM_DEBUG_ADD_REMOVE, "addWindow: New client %s"
                     + ": window=%s Callers=%s", client.asBinder(), win, Debug.getCallers(5));
 
@@ -2080,7 +2082,8 @@
             Rect outVisibleInsets, Rect outStableInsets, Rect outBackdropFrame,
             DisplayCutout.ParcelableWrapper outCutout, MergedConfiguration mergedConfiguration,
             SurfaceControl outSurfaceControl, InsetsState outInsetsState,
-            Point outSurfaceSize, SurfaceControl outBLASTSurfaceControl) {
+            InsetsSourceControl[] outActiveControls, Point outSurfaceSize,
+            SurfaceControl outBLASTSurfaceControl) {
         int result = 0;
         boolean configChanged;
         final int pid = Binder.getCallingPid();
@@ -2375,8 +2378,8 @@
                     outStableInsets);
             outCutout.set(win.getWmDisplayCutout().getDisplayCutout());
             outBackdropFrame.set(win.getBackdropFrame(win.getFrameLw()));
-            outInsetsState.set(win.getInsetsState(),
-                    win.mClient instanceof IWindow.Stub /* copySource */);
+            outInsetsState.set(win.getInsetsState(), win.isClientLocal());
+            getInsetsSourceControls(win, outActiveControls);
             if (DEBUG) {
                 Slog.v(TAG_WM, "Relayout given client " + client.asBinder()
                         + ", requestedWidth=" + requestedWidth
@@ -2413,6 +2416,21 @@
         return result;
     }
 
+    private void getInsetsSourceControls(WindowState win, InsetsSourceControl[] outControls) {
+        if (outControls != null) {
+            final InsetsSourceControl[] controls =
+                    win.getDisplayContent().getInsetsStateController().getControlsForDispatch(win);
+            Arrays.fill(outControls, null);
+            if (controls != null) {
+                final int length = Math.min(controls.length, outControls.length);
+                for (int i = 0; i < length; i++) {
+                    outControls[i] = win.isClientLocal()
+                            ? new InsetsSourceControl(controls[i]) : controls[i];
+                }
+            }
+        }
+    }
+
     private boolean tryStartExitingAnimation(WindowState win, WindowStateAnimator winAnimator,
             boolean focusMayChange) {
         // Try starting an animation; if there isn't one, we
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 8e7585a..eb0a100 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -3477,6 +3477,10 @@
         Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
     }
 
+    boolean isClientLocal() {
+        return mClient instanceof IWindow.Stub;
+    }
+
     void updateLocationInParentDisplayIfNeeded() {
         final int embeddedDisplayContentsSize = mEmbeddedDisplayContents.size();
         // If there is any embedded display which is re-parented to this window, we need to