Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8f852c19 authored by jainrachit's avatar jainrachit
Browse files

[1/n] Add WCT for setting safe region bounds for letterboxing

- Apply the safe region bounds on a WindowContainer.

Bug: 380132497
Flag: com.android.window.flags.safe_region_letterboxing
Test: atest WindowContainerTransactionTests
Change-Id: Ic3008ce64549eb44ff0ba536e98e76db9191a76c
parent 41f92097
Loading
Loading
Loading
Loading
+61 −1
Original line number Diff line number Diff line
@@ -445,6 +445,27 @@ public final class WindowContainerTransaction implements Parcelable {
        return this;
    }

    /**
     * Sets a given safe region {@code Rect} on the {@code container}. Set {@code null} to reset
     * safe region bounds. When a safe region is set on a WindowContainer, the activities which
     * need to be within a safe region will be letterboxed within the set safe region bounds.
     * <p>Note that if the position of the WindowContainer changes, the caller needs to update the
     * safe region bounds.
     *
     * @param container        The window container that the safe region bounds are set on
     * @param safeRegionBounds The rect for the safe region bounds which are absolute in nature.
     * @hide
     */
    @NonNull
    @FlaggedApi(Flags.FLAG_SAFE_REGION_LETTERBOXING)
    public WindowContainerTransaction setSafeRegionBounds(
            @NonNull WindowContainerToken container,
            @Nullable Rect safeRegionBounds) {
        mHierarchyOps.add(
                HierarchyOp.createForSetSafeRegionBounds(container.asBinder(), safeRegionBounds));
        return this;
    }

    /*
     * ===========================================================================================
     * Hierarchy updates (create/destroy/reorder/reparent containers)
@@ -1597,6 +1618,7 @@ public final class WindowContainerTransaction implements Parcelable {
        public static final int HIERARCHY_OP_TYPE_SET_DISABLE_LAUNCH_ADJACENT = 23;
        public static final int HIERARCHY_OP_TYPE_REMOVE_ROOT_TASK = 24;
        public static final int HIERARCHY_OP_TYPE_APP_COMPAT_REACHABILITY = 25;
        public static final int HIERARCHY_OP_TYPE_SET_SAFE_REGION_BOUNDS = 26;

        @IntDef(prefix = {"HIERARCHY_OP_TYPE_"}, value = {
                HIERARCHY_OP_TYPE_REPARENT,
@@ -1625,6 +1647,7 @@ public final class WindowContainerTransaction implements Parcelable {
                HIERARCHY_OP_TYPE_SET_DISABLE_LAUNCH_ADJACENT,
                HIERARCHY_OP_TYPE_REMOVE_ROOT_TASK,
                HIERARCHY_OP_TYPE_APP_COMPAT_REACHABILITY,
                HIERARCHY_OP_TYPE_SET_SAFE_REGION_BOUNDS,
        })
        @Retention(RetentionPolicy.SOURCE)
        public @interface HierarchyOpType {
@@ -1710,6 +1733,9 @@ public final class WindowContainerTransaction implements Parcelable {

        private boolean mLaunchAdjacentDisabled;

        @Nullable
        private Rect mSafeRegionBounds;

        /** Creates a hierarchy operation for reparenting a container within the hierarchy. */
        @NonNull
        public static HierarchyOp createForReparent(
@@ -1873,6 +1899,17 @@ public final class WindowContainerTransaction implements Parcelable {
                    .build();
        }

        /** Creates a hierarchy op for setting the safe region bounds. */
        @NonNull
        @FlaggedApi(Flags.FLAG_SAFE_REGION_LETTERBOXING)
        public static HierarchyOp createForSetSafeRegionBounds(@NonNull IBinder container,
                @Nullable Rect safeRegionBounds) {
            return new Builder(HIERARCHY_OP_TYPE_SET_SAFE_REGION_BOUNDS)
                    .setContainer(container)
                    .setSafeRegionBounds(safeRegionBounds)
                    .build();
        }

        /** Only creates through {@link Builder}. */
        private HierarchyOp(@HierarchyOpType int type) {
            mType = type;
@@ -1903,6 +1940,7 @@ public final class WindowContainerTransaction implements Parcelable {
            mIsTrimmableFromRecents = copy.mIsTrimmableFromRecents;
            mExcludeInsetsTypes = copy.mExcludeInsetsTypes;
            mLaunchAdjacentDisabled = copy.mLaunchAdjacentDisabled;
            mSafeRegionBounds = copy.mSafeRegionBounds;
        }

        private HierarchyOp(@NonNull Parcel in) {
@@ -1930,6 +1968,7 @@ public final class WindowContainerTransaction implements Parcelable {
            mIsTrimmableFromRecents = in.readBoolean();
            mExcludeInsetsTypes = in.readInt();
            mLaunchAdjacentDisabled = in.readBoolean();
            mSafeRegionBounds = in.readTypedObject(Rect.CREATOR);
        }

        @HierarchyOpType
@@ -2051,6 +2090,12 @@ public final class WindowContainerTransaction implements Parcelable {
            return mLaunchAdjacentDisabled;
        }

        /** Denotes the safe region bounds */
        @Nullable
        public Rect getSafeRegionBounds() {
            return mSafeRegionBounds;
        }

        /** Gets a string representation of a hierarchy-op type. */
        public static String hopToString(@HierarchyOpType int type) {
            switch (type) {
@@ -2084,6 +2129,7 @@ public final class WindowContainerTransaction implements Parcelable {
                case HIERARCHY_OP_TYPE_RESTORE_BACK_NAVIGATION: return "restoreBackNav";
                case HIERARCHY_OP_TYPE_SET_EXCLUDE_INSETS_TYPES: return "setExcludeInsetsTypes";
                case HIERARCHY_OP_TYPE_SET_KEYGUARD_STATE: return "setKeyguardState";
                case HIERARCHY_OP_TYPE_SET_SAFE_REGION_BOUNDS: return "setSafeRegionBounds";
                default: return "HOP(" + type + ")";
            }
        }
@@ -2184,6 +2230,11 @@ public final class WindowContainerTransaction implements Parcelable {
                    sb.append("container= ").append(mContainer)
                            .append(" isTrimmable= ")
                            .append(mIsTrimmableFromRecents);
                    break;
                case HIERARCHY_OP_TYPE_SET_SAFE_REGION_BOUNDS:
                    sb.append("container= ").append(mContainer)
                            .append(" safeRegionBounds= ")
                            .append(mSafeRegionBounds);
                default:
                    sb.append("container=").append(mContainer)
                            .append(" reparent=").append(mReparent)
@@ -2220,6 +2271,7 @@ public final class WindowContainerTransaction implements Parcelable {
            dest.writeBoolean(mIsTrimmableFromRecents);
            dest.writeInt(mExcludeInsetsTypes);
            dest.writeBoolean(mLaunchAdjacentDisabled);
            dest.writeTypedObject(mSafeRegionBounds, flags);
        }

        @Override
@@ -2305,6 +2357,9 @@ public final class WindowContainerTransaction implements Parcelable {

            private boolean mLaunchAdjacentDisabled;

            @Nullable
            private Rect mSafeRegionBounds;

            Builder(@HierarchyOpType int type) {
                mType = type;
            }
@@ -2426,6 +2481,11 @@ public final class WindowContainerTransaction implements Parcelable {
                return this;
            }

            Builder setSafeRegionBounds(Rect safeRegionBounds) {
                mSafeRegionBounds = safeRegionBounds;
                return this;
            }

            @NonNull
            HierarchyOp build() {
                final HierarchyOp hierarchyOp = new HierarchyOp(mType);
@@ -2456,7 +2516,7 @@ public final class WindowContainerTransaction implements Parcelable {
                hierarchyOp.mIsTrimmableFromRecents = mIsTrimmableFromRecents;
                hierarchyOp.mExcludeInsetsTypes = mExcludeInsetsTypes;
                hierarchyOp.mLaunchAdjacentDisabled = mLaunchAdjacentDisabled;

                hierarchyOp.mSafeRegionBounds = mSafeRegionBounds;
                return hierarchyOp;
            }
        }
+152 −0
Original line number Diff line number Diff line
@@ -36,8 +36,10 @@ import static org.mockito.Mockito.atLeast;
import static org.mockito.Mockito.times;

import android.content.Intent;
import android.graphics.Rect;
import android.os.Binder;
import android.os.Bundle;
import android.platform.test.annotations.EnableFlags;
import android.platform.test.annotations.Presubmit;
import android.window.WindowContainerToken;
import android.window.WindowContainerTransaction;
@@ -46,6 +48,8 @@ import android.window.WindowContainerTransaction.HierarchyOp;
import androidx.annotation.NonNull;
import androidx.test.filters.SmallTest;

import com.android.window.flags.Flags;

import org.junit.Test;
import org.junit.runner.RunWith;

@@ -62,6 +66,8 @@ import java.util.List;
@Presubmit
@RunWith(WindowTestRunner.class)
public class WindowContainerTransactionTests extends WindowTestsBase {
    private final Rect mSafeRegionBounds = new Rect(50, 50, 200, 300);

    @Test
    public void testRemoveTask() {
        final Task rootTask = createTask(mDisplayContent);
@@ -208,6 +214,152 @@ public class WindowContainerTransactionTests extends WindowTestsBase {
        assertEquals(WINDOWING_MODE_FULLSCREEN, taskToMove.getWindowingMode());
    }

    @Test
    @EnableFlags(Flags.FLAG_SAFE_REGION_LETTERBOXING)
    public void testSetSafeRegionBoundsOnTaskDisplayArea() {
        final Task rootTask = createTask(mDisplayContent);
        final Task task = createTaskInRootTask(rootTask, 0 /* userId */);
        final ActivityRecord activity = createActivityRecord(mDisplayContent, task);
        final TaskDisplayArea taskDisplayArea = mDisplayContent.getDefaultTaskDisplayArea();

        final WindowContainerTransaction wct = new WindowContainerTransaction();
        final WindowContainerToken token = taskDisplayArea.mRemoteToken.toWindowContainerToken();
        // Set safe region bounds on the task display area
        wct.setSafeRegionBounds(token, mSafeRegionBounds);
        applyTransaction(wct);

        assertEquals(activity.getSafeRegionBounds(), mSafeRegionBounds);
        assertEquals(task.getSafeRegionBounds(), mSafeRegionBounds);
        assertEquals(rootTask.getSafeRegionBounds(), mSafeRegionBounds);
        assertEquals(taskDisplayArea.getSafeRegionBounds(), mSafeRegionBounds);
    }

    @Test
    @EnableFlags(Flags.FLAG_SAFE_REGION_LETTERBOXING)
    public void testSetSafeRegionBoundsOnRootTask() {
        final Task rootTask = createTask(mDisplayContent);
        final Task task = createTaskInRootTask(rootTask, 0 /* userId */);
        final ActivityRecord activity = createActivityRecord(mDisplayContent, task);
        final TaskDisplayArea taskDisplayArea = mDisplayContent.getDefaultTaskDisplayArea();

        final WindowContainerTransaction wct = new WindowContainerTransaction();
        final WindowContainerToken token = rootTask.mRemoteToken.toWindowContainerToken();
        // Set safe region bounds on the root task
        wct.setSafeRegionBounds(token, mSafeRegionBounds);
        applyTransaction(wct);

        assertEquals(activity.getSafeRegionBounds(), mSafeRegionBounds);
        assertEquals(task.getSafeRegionBounds(), mSafeRegionBounds);
        assertEquals(rootTask.getSafeRegionBounds(), mSafeRegionBounds);
        assertNull(taskDisplayArea.getSafeRegionBounds());
    }

    @Test
    @EnableFlags(Flags.FLAG_SAFE_REGION_LETTERBOXING)
    public void testSetSafeRegionBoundsOnTask() {
        final Task rootTask = createTask(mDisplayContent);
        final Task task = createTaskInRootTask(rootTask, 0 /* userId */);
        final ActivityRecord activity = createActivityRecord(mDisplayContent, task);
        final TaskDisplayArea taskDisplayArea = mDisplayContent.getDefaultTaskDisplayArea();

        final WindowContainerTransaction wct = new WindowContainerTransaction();
        final WindowContainerToken token = task.mRemoteToken.toWindowContainerToken();
        // Set safe region bounds on the task
        wct.setSafeRegionBounds(token, mSafeRegionBounds);
        applyTransaction(wct);

        assertEquals(activity.getSafeRegionBounds(), mSafeRegionBounds);
        assertEquals(task.getSafeRegionBounds(), mSafeRegionBounds);
        assertNull(rootTask.getSafeRegionBounds());
        assertNull(taskDisplayArea.getSafeRegionBounds());
    }

    @Test
    @EnableFlags(Flags.FLAG_SAFE_REGION_LETTERBOXING)
    public void testSetSafeRegionBoundsOnTask_resetSafeRegionBounds() {
        final Task rootTask = createTask(mDisplayContent);
        final Task task = createTaskInRootTask(rootTask, 0 /* userId */);
        final ActivityRecord activity = createActivityRecord(mDisplayContent, task);
        final TaskDisplayArea taskDisplayArea = mDisplayContent.getDefaultTaskDisplayArea();

        final WindowContainerTransaction wct = new WindowContainerTransaction();
        final WindowContainerToken token = task.mRemoteToken.toWindowContainerToken();
        // Set safe region bounds on the task
        wct.setSafeRegionBounds(token, mSafeRegionBounds);
        applyTransaction(wct);

        assertEquals(activity.getSafeRegionBounds(), mSafeRegionBounds);
        assertEquals(task.getSafeRegionBounds(), mSafeRegionBounds);
        assertNull(rootTask.getSafeRegionBounds());
        assertNull(taskDisplayArea.getSafeRegionBounds());

        // Reset safe region bounds on the task
        wct.setSafeRegionBounds(token, /* safeRegionBounds */null);
        applyTransaction(wct);

        assertNull(activity.getSafeRegionBounds());
        assertNull(task.getSafeRegionBounds());
        assertNull(rootTask.getSafeRegionBounds());
        assertNull(taskDisplayArea.getSafeRegionBounds());
    }

    @Test
    @EnableFlags(Flags.FLAG_SAFE_REGION_LETTERBOXING)
    public void testSetSafeRegionBoundsOnRootTaskAndTask() {
        final Task rootTask = createTask(mDisplayContent);
        final Task task = createTaskInRootTask(rootTask, 0 /* userId */);
        final ActivityRecord activity = createActivityRecord(mDisplayContent, task);
        final TaskDisplayArea taskDisplayArea = mDisplayContent.getDefaultTaskDisplayArea();

        final WindowContainerTransaction wct = new WindowContainerTransaction();
        final WindowContainerToken token = rootTask.mRemoteToken.toWindowContainerToken();
        // Set safe region bounds on the root task
        wct.setSafeRegionBounds(token, mSafeRegionBounds);
        // Set different safe region bounds on task
        final Rect tempSafeRegionBounds = new Rect(30, 30, 200, 200);
        wct.setSafeRegionBounds(task.mRemoteToken.toWindowContainerToken(), tempSafeRegionBounds);
        applyTransaction(wct);

        assertEquals(activity.getSafeRegionBounds(), tempSafeRegionBounds);
        assertEquals(task.getSafeRegionBounds(), tempSafeRegionBounds);
        assertEquals(rootTask.getSafeRegionBounds(), mSafeRegionBounds);
        assertNull(taskDisplayArea.getSafeRegionBounds());
    }

    @Test
    @EnableFlags(Flags.FLAG_SAFE_REGION_LETTERBOXING)
    public void testSetSafeRegionBoundsOnRootTaskAndTask_resetSafeRegionBoundsOnTask() {
        final Task rootTask = createTask(mDisplayContent);
        final Task task = createTaskInRootTask(rootTask, 0 /* userId */);
        final ActivityRecord activity = createActivityRecord(mDisplayContent, task);
        final TaskDisplayArea taskDisplayArea = mDisplayContent.getDefaultTaskDisplayArea();

        final WindowContainerTransaction wct = new WindowContainerTransaction();
        final WindowContainerToken token = rootTask.mRemoteToken.toWindowContainerToken();
        // Set safe region bounds on the root task
        wct.setSafeRegionBounds(token, mSafeRegionBounds);
        // Set different safe region bounds on task
        final Rect mTmpSafeRegionBounds = new Rect(30, 30, 200, 200);
        wct.setSafeRegionBounds(task.mRemoteToken.toWindowContainerToken(), mTmpSafeRegionBounds);
        applyTransaction(wct);

        // Task and activity will use different safe region bounds
        assertEquals(activity.getSafeRegionBounds(), mTmpSafeRegionBounds);
        assertEquals(task.getSafeRegionBounds(), mTmpSafeRegionBounds);
        assertEquals(rootTask.getSafeRegionBounds(), mSafeRegionBounds);
        assertNull(taskDisplayArea.getSafeRegionBounds());

        // Reset safe region bounds on task
        wct.setSafeRegionBounds(task.mRemoteToken.toWindowContainerToken(),
                /* safeRegionBounds */null);
        applyTransaction(wct);

        assertEquals(activity.getSafeRegionBounds(), mSafeRegionBounds);
        assertEquals(task.getSafeRegionBounds(), mSafeRegionBounds);
        assertEquals(rootTask.getSafeRegionBounds(), mSafeRegionBounds);
        assertNull(taskDisplayArea.getSafeRegionBounds());
    }

    @Test
    public void testDesktopMode_moveTaskToFront() {
        final TestDesktopOrganizer desktopOrganizer = new TestDesktopOrganizer(mAtm);