Merge "Introduce new window insets launch flag"
diff --git a/core/java/android/view/InsetsAnimationControlImpl.java b/core/java/android/view/InsetsAnimationControlImpl.java
index ce71b07..7c1465b 100644
--- a/core/java/android/view/InsetsAnimationControlImpl.java
+++ b/core/java/android/view/InsetsAnimationControlImpl.java
@@ -161,8 +161,9 @@
     private Insets getInsetsFromState(InsetsState state, Rect frame,
             @Nullable @InsetSide SparseIntArray typeSideMap) {
         return state.calculateInsets(frame, false /* isScreenRound */,
-                false /* alwaysConsumerNavBar */, null /* displayCutout */, typeSideMap)
-                .getInsets(mTypes);
+                false /* alwaysConsumerNavBar */, null /* displayCutout */,
+                null /* legacyContentInsets */, null /* legacyStableInsets */, typeSideMap)
+               .getInsets(mTypes);
     }
 
     private Insets sanitize(Insets insets) {
diff --git a/core/java/android/view/InsetsController.java b/core/java/android/view/InsetsController.java
index c2ade76..4b1d1ec 100644
--- a/core/java/android/view/InsetsController.java
+++ b/core/java/android/view/InsetsController.java
@@ -56,6 +56,9 @@
 
     private final Runnable mAnimCallback;
 
+    private final Rect mLastLegacyContentInsets = new Rect();
+    private final Rect mLastLegacyStableInsets = new Rect();
+
     public InsetsController(ViewRootImpl viewRoot) {
         mViewRoot = viewRoot;
         mAnimCallback = () -> {
@@ -70,6 +73,7 @@
             }
             WindowInsets insets = state.calculateInsets(mFrame, mLastInsets.isRound(),
                     mLastInsets.shouldAlwaysConsumeNavBar(), mLastInsets.getDisplayCutout(),
+                    mLastLegacyContentInsets, mLastLegacyStableInsets,
                     null /* typeSideMap */);
             mViewRoot.mView.dispatchWindowInsetsAnimationProgress(insets);
         };
@@ -102,8 +106,12 @@
      */
     @VisibleForTesting
     public WindowInsets calculateInsets(boolean isScreenRound,
-            boolean alwaysConsumeNavBar, DisplayCutout cutout) {
+            boolean alwaysConsumeNavBar, DisplayCutout cutout, Rect legacyContentInsets,
+            Rect legacyStableInsets) {
+        mLastLegacyContentInsets.set(legacyContentInsets);
+        mLastLegacyStableInsets.set(legacyStableInsets);
         mLastInsets = mState.calculateInsets(mFrame, isScreenRound, alwaysConsumeNavBar, cutout,
+                legacyContentInsets, legacyStableInsets,
                 null /* typeSideMap */);
         return mLastInsets;
     }
diff --git a/core/java/android/view/InsetsState.java b/core/java/android/view/InsetsState.java
index cf8c0707..529776e 100644
--- a/core/java/android/view/InsetsState.java
+++ b/core/java/android/view/InsetsState.java
@@ -16,6 +16,7 @@
 
 package android.view;
 
+import static android.view.ViewRootImpl.NEW_INSETS_MODE_IME;
 import static android.view.WindowInsets.Type.indexOf;
 
 import android.annotation.IntDef;
@@ -119,11 +120,17 @@
      */
     public WindowInsets calculateInsets(Rect frame, boolean isScreenRound,
             boolean alwaysConsumeNavBar, DisplayCutout cutout,
+            @Nullable Rect legacyContentInsets, @Nullable Rect legacyStableInsets,
             @Nullable @InsetSide SparseIntArray typeSideMap) {
         Insets[] typeInsetsMap = new Insets[Type.SIZE];
         Insets[] typeMaxInsetsMap = new Insets[Type.SIZE];
         final Rect relativeFrame = new Rect(frame);
         final Rect relativeFrameMax = new Rect(frame);
+        if (ViewRootImpl.sNewInsetsMode == NEW_INSETS_MODE_IME
+                && legacyContentInsets != null && legacyStableInsets != null) {
+            WindowInsets.assignCompatInsets(typeInsetsMap, legacyContentInsets);
+            WindowInsets.assignCompatInsets(typeMaxInsetsMap, legacyStableInsets);
+        }
         for (int type = FIRST_TYPE; type <= LAST_TYPE; type++) {
             InsetsSource source = mSources.get(type);
             if (source == null) {
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index a1aa06e..2131e6d 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -16,6 +16,7 @@
 
 package android.view;
 
+import static android.view.ViewRootImpl.NEW_INSETS_MODE_FULL;
 import static android.view.accessibility.AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED;
 
 import static java.lang.Math.max;
@@ -5123,7 +5124,7 @@
 
             sAcceptZeroSizeDragShadow = targetSdkVersion < Build.VERSION_CODES.P;
 
-            sBrokenInsetsDispatch = !ViewRootImpl.USE_NEW_INSETS
+            sBrokenInsetsDispatch = ViewRootImpl.sNewInsetsMode != NEW_INSETS_MODE_FULL
                     || targetSdkVersion < Build.VERSION_CODES.Q;
 
             sCompatibilityDone = true;
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 27d4ea4..a031b70 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -163,13 +163,16 @@
     private static final boolean MT_RENDERER_AVAILABLE = true;
 
     /**
-     * If set to true, the view system will switch from using rectangles retrieved from window to
+     * If set to 2, the view system will switch from using rectangles retrieved from window to
      * dispatch to the view hierarchy to using {@link InsetsController}, that derives the insets
      * directly from the full configuration, enabling richer information about the insets state, as
      * well as new APIs to control it frame-by-frame, and synchronize animations with it.
      * <p>
-     * Only switch this to true once the new insets system is productionized and the old APIs are
+     * Only set this to 2 once the new insets system is productionized and the old APIs are
      * fully migrated over.
+     * <p>
+     * If set to 1, this will switch to a mode where we only use the new approach for IME, but not
+     * for the status/navigation bar.
      */
     private static final String USE_NEW_INSETS_PROPERTY = "persist.wm.new_insets";
 
@@ -177,8 +180,26 @@
      * @see #USE_NEW_INSETS_PROPERTY
      * @hide
      */
-    public static final boolean USE_NEW_INSETS =
-            SystemProperties.getBoolean(USE_NEW_INSETS_PROPERTY, false);
+    public static final int sNewInsetsMode =
+            SystemProperties.getInt(USE_NEW_INSETS_PROPERTY, 0);
+
+    /**
+     * @see #USE_NEW_INSETS_PROPERTY
+     * @hide
+     */
+    public static final int NEW_INSETS_MODE_NONE = 0;
+
+    /**
+     * @see #USE_NEW_INSETS_PROPERTY
+     * @hide
+     */
+    public static final int NEW_INSETS_MODE_IME = 1;
+
+    /**
+     * @see #USE_NEW_INSETS_PROPERTY
+     * @hide
+     */
+    public static final int NEW_INSETS_MODE_FULL = 2;
 
     /**
      * Set this system property to true to force the view hierarchy to render
@@ -1367,7 +1388,7 @@
     }
 
     void notifyInsetsChanged() {
-        if (!USE_NEW_INSETS) {
+        if (sNewInsetsMode == NEW_INSETS_MODE_NONE) {
             return;
         }
         mApplyInsetsRequested = true;
@@ -1855,10 +1876,11 @@
             }
             contentInsets = ensureInsetsNonNegative(contentInsets, "content");
             stableInsets = ensureInsetsNonNegative(stableInsets, "stable");
-            if (USE_NEW_INSETS) {
+            if (sNewInsetsMode != NEW_INSETS_MODE_NONE) {
                 mLastWindowInsets = mInsetsController.calculateInsets(
                         mContext.getResources().getConfiguration().isScreenRound(),
-                        mAttachInfo.mAlwaysConsumeNavBar, displayCutout);
+                        mAttachInfo.mAlwaysConsumeNavBar, displayCutout,
+                        contentInsets, stableInsets);
             } else {
                 mLastWindowInsets = new WindowInsets(contentInsets, stableInsets,
                         mContext.getResources().getConfiguration().isScreenRound(),
diff --git a/core/java/android/view/WindowInsets.java b/core/java/android/view/WindowInsets.java
index 9ac0ca9..e808830 100644
--- a/core/java/android/view/WindowInsets.java
+++ b/core/java/android/view/WindowInsets.java
@@ -217,7 +217,10 @@
         return typeInsetMap;
     }
 
-    private static void assignCompatInsets(Insets[] typeInsetMap, Rect insets) {
+    /**
+     * @hide
+     */
+    static void assignCompatInsets(Insets[] typeInsetMap, Rect insets) {
         typeInsetMap[indexOf(TOP_BAR)] = Insets.of(0, insets.top, 0, 0);
         typeInsetMap[indexOf(SIDE_BARS)] = Insets.of(insets.left, 0, insets.right, insets.bottom);
     }
diff --git a/core/tests/coretests/src/android/view/InsetsStateTest.java b/core/tests/coretests/src/android/view/InsetsStateTest.java
index 9857b7a..2db2f5f 100644
--- a/core/tests/coretests/src/android/view/InsetsStateTest.java
+++ b/core/tests/coretests/src/android/view/InsetsStateTest.java
@@ -60,7 +60,7 @@
         mState.getSource(TYPE_IME).setVisible(true);
         SparseIntArray typeSideMap = new SparseIntArray();
         WindowInsets insets = mState.calculateInsets(new Rect(0, 0, 100, 300), false, false,
-                DisplayCutout.NO_CUTOUT, typeSideMap);
+                DisplayCutout.NO_CUTOUT, null, null, typeSideMap);
         assertEquals(Insets.of(0, 100, 0, 100), insets.getSystemWindowInsets());
         assertEquals(Insets.of(0, 100, 0, 100), insets.getInsets(Type.all()));
         assertEquals(INSET_SIDE_TOP, typeSideMap.get(TYPE_TOP_BAR));
@@ -76,7 +76,7 @@
         mState.getSource(TYPE_IME).setFrame(new Rect(0, 100, 100, 300));
         mState.getSource(TYPE_IME).setVisible(true);
         WindowInsets insets = mState.calculateInsets(new Rect(0, 0, 100, 300), false, false,
-                DisplayCutout.NO_CUTOUT, null);
+                DisplayCutout.NO_CUTOUT, null, null, null);
         assertEquals(100, insets.getStableInsetBottom());
         assertEquals(Insets.of(0, 0, 0, 100), insets.getMaxInsets(Type.all()));
         assertEquals(Insets.of(0, 0, 0, 200), insets.getSystemWindowInsets());
@@ -92,7 +92,7 @@
         mState.getSource(TYPE_NAVIGATION_BAR).setFrame(new Rect(80, 0, 100, 300));
         mState.getSource(TYPE_NAVIGATION_BAR).setVisible(true);
         WindowInsets insets = mState.calculateInsets(new Rect(0, 0, 100, 300), false, false,
-                DisplayCutout.NO_CUTOUT, null);
+                DisplayCutout.NO_CUTOUT, null, null, null);
         assertEquals(Insets.of(0, 100, 20, 0), insets.getSystemWindowInsets());
         assertEquals(Insets.of(0, 100, 0, 0), insets.getInsets(Type.topBar()));
         assertEquals(Insets.of(0, 0, 20, 0), insets.getInsets(Type.sideBars()));
@@ -106,7 +106,7 @@
         mState.getSource(TYPE_IME).setVisible(true);
         mState.removeSource(TYPE_IME);
         WindowInsets insets = mState.calculateInsets(new Rect(0, 0, 100, 300), false, false,
-                DisplayCutout.NO_CUTOUT, null);
+                DisplayCutout.NO_CUTOUT, null, null, null);
         assertEquals(0, insets.getSystemWindowInsetBottom());
     }
 
diff --git a/core/tests/coretests/src/android/view/WindowInsetsTest.java b/core/tests/coretests/src/android/view/WindowInsetsTest.java
index 15a96a1..d57fa8f 100644
--- a/core/tests/coretests/src/android/view/WindowInsetsTest.java
+++ b/core/tests/coretests/src/android/view/WindowInsetsTest.java
@@ -18,7 +18,7 @@
 
 import static android.view.WindowInsets.Type.ime;
 import static android.view.WindowInsets.Type.sideBars;
-
+import static android.view.WindowInsets.Type.topBar;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
 
@@ -54,6 +54,7 @@
         assertTrue(new WindowInsets((Rect) null).isConsumed());
     }
 
+    // TODO: Move this to CTS once API made public
     @Test
     public void typeMap() {
         Builder b = new WindowInsets.Builder();
@@ -62,4 +63,14 @@
         WindowInsets insets = b.build();
         assertEquals(300, insets.getSystemWindowInsets().bottom);
     }
+
+    // TODO: Move this to CTS once API made public
+    @Test
+    public void compatInsets() {
+        Builder b = new WindowInsets.Builder();
+        b.setSystemWindowInsets(Insets.of(0, 50, 30, 10));
+        WindowInsets insets = b.build();
+        assertEquals(Insets.of(0, 50, 0, 0), insets.getInsets(topBar()));
+        assertEquals(Insets.of(0, 0, 30, 10), insets.getInsets(sideBars()));
+    }
 }
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 6527ca0..8026a04 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -30,11 +30,14 @@
 import static android.view.Display.DEFAULT_DISPLAY;
 import static android.view.Display.FLAG_PRIVATE;
 import static android.view.InsetsState.TYPE_IME;
+import static android.view.InsetsState.TYPE_NAVIGATION_BAR;
+import static android.view.InsetsState.TYPE_TOP_BAR;
 import static android.view.Surface.ROTATION_0;
 import static android.view.Surface.ROTATION_180;
 import static android.view.Surface.ROTATION_270;
 import static android.view.Surface.ROTATION_90;
 import static android.view.View.GONE;
+import static android.view.ViewRootImpl.NEW_INSETS_MODE_FULL;
 import static android.view.WindowManager.DOCKED_BOTTOM;
 import static android.view.WindowManager.DOCKED_INVALID;
 import static android.view.WindowManager.DOCKED_TOP;
@@ -164,6 +167,7 @@
 import android.view.SurfaceControl.Transaction;
 import android.view.SurfaceSession;
 import android.view.View;
+import android.view.ViewRootImpl;
 import android.view.WindowManager;
 import android.view.WindowManagerPolicyConstants.PointerEventListener;
 
@@ -1051,6 +1055,11 @@
      */
     void setInsetProvider(@InternalInsetType int type, WindowState win,
             @Nullable TriConsumer<DisplayFrames, WindowState, Rect> frameProvider) {
+        if (ViewRootImpl.sNewInsetsMode != NEW_INSETS_MODE_FULL) {
+            if (type == TYPE_TOP_BAR || type == TYPE_NAVIGATION_BAR) {
+                return;
+            }
+        }
         mInsetsStateController.getSourceProvider(type).setWindow(win, frameProvider);
     }
 
diff --git a/services/core/java/com/android/server/wm/InsetsSourceProvider.java b/services/core/java/com/android/server/wm/InsetsSourceProvider.java
index d6f1616..e49e4c0 100644
--- a/services/core/java/com/android/server/wm/InsetsSourceProvider.java
+++ b/services/core/java/com/android/server/wm/InsetsSourceProvider.java
@@ -16,6 +16,8 @@
 
 package com.android.server.wm;
 
+import static android.view.ViewRootImpl.NEW_INSETS_MODE_NONE;
+
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.graphics.Rect;
@@ -159,7 +161,7 @@
     }
 
     boolean isClientVisible() {
-        return !ViewRootImpl.USE_NEW_INSETS || mClientVisible;
+        return ViewRootImpl.sNewInsetsMode == NEW_INSETS_MODE_NONE || mClientVisible;
     }
 
     private class ControlAdapter implements AnimationAdapter {
diff --git a/services/core/java/com/android/server/wm/InsetsStateController.java b/services/core/java/com/android/server/wm/InsetsStateController.java
index bc01f7c..32dbe96 100644
--- a/services/core/java/com/android/server/wm/InsetsStateController.java
+++ b/services/core/java/com/android/server/wm/InsetsStateController.java
@@ -19,6 +19,9 @@
 import static android.view.InsetsState.TYPE_IME;
 import static android.view.InsetsState.TYPE_NAVIGATION_BAR;
 import static android.view.InsetsState.TYPE_TOP_BAR;
+import static android.view.ViewRootImpl.NEW_INSETS_MODE_FULL;
+import static android.view.ViewRootImpl.NEW_INSETS_MODE_NONE;
+import static android.view.ViewRootImpl.sNewInsetsMode;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -160,7 +163,7 @@
     }
 
     private void onControlChanged(int type, @Nullable WindowState win) {
-        if (!ViewRootImpl.USE_NEW_INSETS) {
+        if (sNewInsetsMode == NEW_INSETS_MODE_NONE) {
             return;
         }
         final WindowState previous = mTypeWinControlMap.get(type);