diff --git a/core/java/android/window/WindowContainerTransaction.java b/core/java/android/window/WindowContainerTransaction.java index 346aa3336c126..35c959493f230 100644 --- a/core/java/android/window/WindowContainerTransaction.java +++ b/core/java/android/window/WindowContainerTransaction.java @@ -31,6 +31,7 @@ import android.os.IBinder; import android.os.Parcel; import android.os.Parcelable; import android.util.ArrayMap; +import android.view.InsetsState; import android.view.SurfaceControl; import java.util.ArrayList; @@ -588,6 +589,56 @@ public final class WindowContainerTransaction implements Parcelable { return this; } + /** + * Adds a given {@code Rect} as a rect insets provider on the {@code receiverWindowContainer}. + * This will trigger a change of insets for all the children in the subtree of + * {@code receiverWindowContainer}. + * + * @param receiverWindowContainer the window container which the insets provider need to be + * added to + * @param insetsProviderFrame the frame that will be added as Insets provider + * @param insetsTypes types of insets the rect provides + * @hide + */ + @NonNull + public WindowContainerTransaction addRectInsetsProvider( + @NonNull WindowContainerToken receiverWindowContainer, + @NonNull Rect insetsProviderFrame, + @InsetsState.InternalInsetsType int[] insetsTypes) { + final HierarchyOp hierarchyOp = + new HierarchyOp.Builder( + HierarchyOp.HIERARCHY_OP_TYPE_ADD_RECT_INSETS_PROVIDER) + .setContainer(receiverWindowContainer.asBinder()) + .setInsetsProviderFrame(insetsProviderFrame) + .setInsetsTypes(insetsTypes) + .build(); + mHierarchyOps.add(hierarchyOp); + return this; + } + + /** + * Removes the insets provider for the given types from the + * {@code receiverWindowContainer}. This will trigger a change of insets for all the children + * in the subtree of {@code receiverWindowContainer}. + * + * @param receiverWindowContainer the window container which the insets-override-provider has + * to be removed from + * @param insetsTypes types of insets that have to be removed + * @hide + */ + @NonNull + public WindowContainerTransaction removeInsetsProvider( + @NonNull WindowContainerToken receiverWindowContainer, + @InsetsState.InternalInsetsType int[] insetsTypes) { + final HierarchyOp hierarchyOp = + new HierarchyOp.Builder(HierarchyOp.HIERARCHY_OP_TYPE_REMOVE_INSETS_PROVIDER) + .setContainer(receiverWindowContainer.asBinder()) + .setInsetsTypes(insetsTypes) + .build(); + mHierarchyOps.add(hierarchyOp); + return this; + } + /** * When this {@link WindowContainerTransaction} failed to finish on the server side, it will * trigger callback with this {@param errorCallbackToken}. @@ -993,6 +1044,8 @@ public final class WindowContainerTransaction implements Parcelable { public static final int HIERARCHY_OP_TYPE_SET_ADJACENT_TASK_FRAGMENTS = 13; public static final int HIERARCHY_OP_TYPE_START_SHORTCUT = 14; public static final int HIERARCHY_OP_TYPE_RESTORE_TRANSIENT_ORDER = 15; + public static final int HIERARCHY_OP_TYPE_ADD_RECT_INSETS_PROVIDER = 16; + public static final int HIERARCHY_OP_TYPE_REMOVE_INSETS_PROVIDER = 17; // The following key(s) are for use with mLaunchOptions: // When launching a task (eg. from recents), this is the taskId to be launched. @@ -1012,6 +1065,10 @@ public final class WindowContainerTransaction implements Parcelable { @Nullable private IBinder mReparent; + private @InsetsState.InternalInsetsType int[] mInsetsTypes; + + private Rect mInsetsProviderFrame; + // Moves/reparents to top of parent when {@code true}, otherwise moves/reparents to bottom. private boolean mToTop; @@ -1130,6 +1187,8 @@ public final class WindowContainerTransaction implements Parcelable { mType = copy.mType; mContainer = copy.mContainer; mReparent = copy.mReparent; + mInsetsTypes = copy.mInsetsTypes; + mInsetsProviderFrame = copy.mInsetsProviderFrame; mToTop = copy.mToTop; mReparentTopOnly = copy.mReparentTopOnly; mMoveAdjacentTogether = copy.mMoveAdjacentTogether; @@ -1146,6 +1205,12 @@ public final class WindowContainerTransaction implements Parcelable { mType = in.readInt(); mContainer = in.readStrongBinder(); mReparent = in.readStrongBinder(); + mInsetsTypes = in.createIntArray(); + if (in.readInt() != 0) { + mInsetsProviderFrame = Rect.CREATOR.createFromParcel(in); + } else { + mInsetsProviderFrame = null; + } mToTop = in.readBoolean(); mReparentTopOnly = in.readBoolean(); mMoveAdjacentTogether = in.readBoolean(); @@ -1171,6 +1236,15 @@ public final class WindowContainerTransaction implements Parcelable { return mReparent; } + @Nullable + public @InsetsState.InternalInsetsType int[] getInsetsTypes() { + return mInsetsTypes; + } + + public Rect getInsetsProviderFrame() { + return mInsetsProviderFrame; + } + @NonNull public IBinder getContainer() { return mContainer; @@ -1276,6 +1350,13 @@ public final class WindowContainerTransaction implements Parcelable { case HIERARCHY_OP_TYPE_START_SHORTCUT: return "{StartShortcut: options=" + mLaunchOptions + " info=" + mShortcutInfo + "}"; + case HIERARCHY_OP_TYPE_ADD_RECT_INSETS_PROVIDER: + return "{addRectInsetsProvider: container=" + mContainer + + " insetsProvidingFrame=" + mInsetsProviderFrame + + " insetsType=" + Arrays.toString(mInsetsTypes) + "}"; + case HIERARCHY_OP_TYPE_REMOVE_INSETS_PROVIDER: + return "{removeLocalInsetsProvider: container=" + mContainer + + " insetsType=" + Arrays.toString(mInsetsTypes) + "}"; default: return "{mType=" + mType + " container=" + mContainer + " reparent=" + mReparent + " mToTop=" + mToTop @@ -1289,6 +1370,13 @@ public final class WindowContainerTransaction implements Parcelable { dest.writeInt(mType); dest.writeStrongBinder(mContainer); dest.writeStrongBinder(mReparent); + dest.writeIntArray(mInsetsTypes); + if (mInsetsProviderFrame != null) { + dest.writeInt(1); + mInsetsProviderFrame.writeToParcel(dest, 0); + } else { + dest.writeInt(0); + } dest.writeBoolean(mToTop); dest.writeBoolean(mReparentTopOnly); dest.writeBoolean(mMoveAdjacentTogether); @@ -1328,6 +1416,10 @@ public final class WindowContainerTransaction implements Parcelable { @Nullable private IBinder mReparent; + private int[] mInsetsTypes; + + private Rect mInsetsProviderFrame; + private boolean mToTop; private boolean mReparentTopOnly; @@ -1369,6 +1461,16 @@ public final class WindowContainerTransaction implements Parcelable { return this; } + Builder setInsetsTypes(int[] insetsTypes) { + mInsetsTypes = insetsTypes; + return this; + } + + Builder setInsetsProviderFrame(Rect insetsProviderFrame) { + mInsetsProviderFrame = insetsProviderFrame; + return this; + } + Builder setToTop(boolean toTop) { mToTop = toTop; return this; @@ -1430,6 +1532,8 @@ public final class WindowContainerTransaction implements Parcelable { hierarchyOp.mActivityTypes = mActivityTypes != null ? Arrays.copyOf(mActivityTypes, mActivityTypes.length) : null; + hierarchyOp.mInsetsTypes = mInsetsTypes; + hierarchyOp.mInsetsProviderFrame = mInsetsProviderFrame; hierarchyOp.mToTop = mToTop; hierarchyOp.mReparentTopOnly = mReparentTopOnly; hierarchyOp.mMoveAdjacentTogether = mMoveAdjacentTogether; diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java index c70a40c3b5fcc..ce27d739e1b16 100644 --- a/services/core/java/com/android/server/wm/WindowOrganizerController.java +++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java @@ -21,11 +21,13 @@ import static android.app.ActivityManager.isStartResultSuccessful; import static android.view.Display.DEFAULT_DISPLAY; import static android.window.WindowContainerTransaction.Change.CHANGE_BOUNDS_TRANSACTION; import static android.window.WindowContainerTransaction.Change.CHANGE_BOUNDS_TRANSACTION_RECT; +import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_ADD_RECT_INSETS_PROVIDER; import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_CHILDREN_TASKS_REPARENT; import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_CREATE_TASK_FRAGMENT; import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_DELETE_TASK_FRAGMENT; import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_LAUNCH_TASK; import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_PENDING_INTENT; +import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_REMOVE_INSETS_PROVIDER; import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_REORDER; import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_REPARENT; import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_REPARENT_ACTIVITY_TO_TASK_FRAGMENT; @@ -895,6 +897,17 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub taskDisplayArea.moveRootTaskBehindRootTask(thisTask.getRootTask(), restoreAt); break; } + case HIERARCHY_OP_TYPE_ADD_RECT_INSETS_PROVIDER: + final Rect insetsProviderWindowContainer = hop.getInsetsProviderFrame(); + final WindowContainer receiverWindowContainer = + WindowContainer.fromBinder(hop.getContainer()); + receiverWindowContainer.addLocalRectInsetsSourceProvider( + insetsProviderWindowContainer, hop.getInsetsTypes()); + break; + case HIERARCHY_OP_TYPE_REMOVE_INSETS_PROVIDER: + WindowContainer.fromBinder(hop.getContainer()) + .removeLocalInsetsSourceProvider(hop.getInsetsTypes()); + break; } return effects; } diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java index 4d5fb6dc58134..25d7334a529c2 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java @@ -30,6 +30,7 @@ import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; import static android.content.res.Configuration.SCREEN_HEIGHT_DP_UNDEFINED; import static android.content.res.Configuration.SCREEN_WIDTH_DP_UNDEFINED; +import static android.view.InsetsState.ITYPE_LOCAL_NAVIGATION_BAR_1; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing; @@ -610,6 +611,50 @@ public class WindowOrganizerTests extends WindowTestsBase { assertEquals(ACTIVITY_TYPE_UNDEFINED, info1.topActivityType); } + @Test + public void testAddRectInsetsProvider() { + final Task rootTask = createTask(mDisplayContent); + + final Task navigationBarInsetsReceiverTask = createTaskInRootTask(rootTask, 0); + navigationBarInsetsReceiverTask.getConfiguration().windowConfiguration.setBounds(new Rect( + 0, 200, 1080, 700)); + + final Rect navigationBarInsetsProviderRect = new Rect(0, 0, 1080, 200); + + final WindowContainerTransaction wct = new WindowContainerTransaction(); + wct.addRectInsetsProvider(navigationBarInsetsReceiverTask.mRemoteToken + .toWindowContainerToken(), navigationBarInsetsProviderRect, + new int[]{ITYPE_LOCAL_NAVIGATION_BAR_1}); + mWm.mAtmService.mWindowOrganizerController.applyTransaction(wct); + + assertThat(navigationBarInsetsReceiverTask.mLocalInsetsSourceProviders + .valueAt(0).getSource().getType()).isEqualTo(ITYPE_LOCAL_NAVIGATION_BAR_1); + } + + @Test + public void testRemoveInsetsProvider() { + final Task rootTask = createTask(mDisplayContent); + + final Task navigationBarInsetsReceiverTask = createTaskInRootTask(rootTask, 0); + navigationBarInsetsReceiverTask.getConfiguration().windowConfiguration.setBounds(new Rect( + 0, 200, 1080, 700)); + + final Rect navigationBarInsetsProviderRect = new Rect(0, 0, 1080, 200); + + final WindowContainerTransaction wct = new WindowContainerTransaction(); + wct.addRectInsetsProvider(navigationBarInsetsReceiverTask.mRemoteToken + .toWindowContainerToken(), navigationBarInsetsProviderRect, + new int[]{ITYPE_LOCAL_NAVIGATION_BAR_1}); + mWm.mAtmService.mWindowOrganizerController.applyTransaction(wct); + + final WindowContainerTransaction wct2 = new WindowContainerTransaction(); + wct2.removeInsetsProvider(navigationBarInsetsReceiverTask.mRemoteToken + .toWindowContainerToken(), new int[]{ITYPE_LOCAL_NAVIGATION_BAR_1}); + mWm.mAtmService.mWindowOrganizerController.applyTransaction(wct2); + + assertThat(navigationBarInsetsReceiverTask.mLocalInsetsSourceProviders.size()).isEqualTo(0); + } + @UseTestDisplay @Test public void testTaskInfoCallback() {