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

Commit 63faf790 authored by Gaurav Bhola's avatar Gaurav Bhola Committed by Android (Google) Code Review
Browse files

Merge "Handle alwaysOnTop in DisplayAreas."

parents d4f1bf15 335c2629
Loading
Loading
Loading
Loading
+54 −0
Original line number Diff line number Diff line
@@ -669,6 +669,39 @@ public final class WindowContainerTransaction implements Parcelable {

    }

    /**
     * Sets/removes the always on top flag for this {@code windowContainer}. See
     * {@link com.android.server.wm.ConfigurationContainer#setAlwaysOnTop(boolean)}.
     * Please note that this method is only intended to be used for a
     * {@link com.android.server.wm.DisplayArea}.
     *
     * <p>
     *     Setting always on top to {@code True} will also make the {@code windowContainer} to move
     *     to the top.
     * </p>
     * <p>
     *     Setting always on top to {@code False} will make this {@code windowContainer} to move
     *     below the other always on top sibling containers.
     * </p>
     *
     * @param windowContainer the container which the flag need to be updated for.
     * @param alwaysOnTop denotes whether or not always on top flag should be set.
     * @hide
     */
    @NonNull
    public WindowContainerTransaction setAlwaysOnTop(
            @NonNull WindowContainerToken windowContainer,
            boolean alwaysOnTop) {
        final HierarchyOp hierarchyOp =
                new HierarchyOp.Builder(
                        HierarchyOp.HIERARCHY_OP_TYPE_SET_ALWAYS_ON_TOP)
                        .setContainer(windowContainer.asBinder())
                        .setAlwaysOnTop(alwaysOnTop)
                        .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}.
@@ -1078,6 +1111,7 @@ public final class WindowContainerTransaction implements Parcelable {
        public static final int HIERARCHY_OP_TYPE_ADD_RECT_INSETS_PROVIDER = 16;
        public static final int HIERARCHY_OP_TYPE_REMOVE_INSETS_PROVIDER = 17;
        public static final int HIERARCHY_OP_TYPE_REQUEST_FOCUS_ON_TASK_FRAGMENT = 18;
        public static final int HIERARCHY_OP_TYPE_SET_ALWAYS_ON_TOP = 19;

        // The following key(s) are for use with mLaunchOptions:
        // When launching a task (eg. from recents), this is the taskId to be launched.
@@ -1128,6 +1162,8 @@ public final class WindowContainerTransaction implements Parcelable {
        @Nullable
        private ShortcutInfo mShortcutInfo;

        private boolean mAlwaysOnTop;

        public static HierarchyOp createForReparent(
                @NonNull IBinder container, @Nullable IBinder reparent, boolean toTop) {
            return new HierarchyOp.Builder(HIERARCHY_OP_TYPE_REPARENT)
@@ -1225,6 +1261,7 @@ public final class WindowContainerTransaction implements Parcelable {
            mTaskFragmentCreationOptions = copy.mTaskFragmentCreationOptions;
            mPendingIntent = copy.mPendingIntent;
            mShortcutInfo = copy.mShortcutInfo;
            mAlwaysOnTop = copy.mAlwaysOnTop;
        }

        protected HierarchyOp(Parcel in) {
@@ -1246,6 +1283,7 @@ public final class WindowContainerTransaction implements Parcelable {
            mTaskFragmentCreationOptions = in.readTypedObject(TaskFragmentCreationParams.CREATOR);
            mPendingIntent = in.readTypedObject(PendingIntent.CREATOR);
            mShortcutInfo = in.readTypedObject(ShortcutInfo.CREATOR);
            mAlwaysOnTop = in.readBoolean();
        }

        public int getType() {
@@ -1311,6 +1349,10 @@ public final class WindowContainerTransaction implements Parcelable {
            return mActivityIntent;
        }

        public boolean isAlwaysOnTop() {
            return mAlwaysOnTop;
        }

        @Nullable
        public TaskFragmentCreationParams getTaskFragmentCreationOptions() {
            return mTaskFragmentCreationOptions;
@@ -1379,6 +1421,9 @@ public final class WindowContainerTransaction implements Parcelable {
                            + " insetsType=" + Arrays.toString(mInsetsTypes) + "}";
                case HIERARCHY_OP_TYPE_REQUEST_FOCUS_ON_TASK_FRAGMENT:
                    return "{requestFocusOnTaskFragment: container=" + mContainer + "}";
                case HIERARCHY_OP_TYPE_SET_ALWAYS_ON_TOP:
                    return "{setAlwaysOnTop: container=" + mContainer
                            + " alwaysOnTop=" + mAlwaysOnTop + "}";
                default:
                    return "{mType=" + mType + " container=" + mContainer + " reparent=" + mReparent
                            + " mToTop=" + mToTop
@@ -1408,6 +1453,7 @@ public final class WindowContainerTransaction implements Parcelable {
            dest.writeTypedObject(mTaskFragmentCreationOptions, flags);
            dest.writeTypedObject(mPendingIntent, flags);
            dest.writeTypedObject(mShortcutInfo, flags);
            dest.writeBoolean(mAlwaysOnTop);
        }

        @Override
@@ -1466,6 +1512,8 @@ public final class WindowContainerTransaction implements Parcelable {
            @Nullable
            private ShortcutInfo mShortcutInfo;

            private boolean mAlwaysOnTop;

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

            Builder setAlwaysOnTop(boolean alwaysOnTop) {
                mAlwaysOnTop = alwaysOnTop;
                return this;
            }

            Builder setTaskFragmentCreationOptions(
                    @Nullable TaskFragmentCreationParams taskFragmentCreationOptions) {
                mTaskFragmentCreationOptions = taskFragmentCreationOptions;
@@ -1553,6 +1606,7 @@ public final class WindowContainerTransaction implements Parcelable {
                hierarchyOp.mLaunchOptions = mLaunchOptions;
                hierarchyOp.mActivityIntent = mActivityIntent;
                hierarchyOp.mPendingIntent = mPendingIntent;
                hierarchyOp.mAlwaysOnTop = mAlwaysOnTop;
                hierarchyOp.mTaskFragmentCreationOptions = mTaskFragmentCreationOptions;
                hierarchyOp.mShortcutInfo = mShortcutInfo;

+29 −0
Original line number Diff line number Diff line
@@ -207,6 +207,23 @@ public class DisplayArea<T extends WindowContainer> extends WindowContainer<T> {
        return false;
    }

    @Override
    public void setAlwaysOnTop(boolean alwaysOnTop) {
        if (isAlwaysOnTop() == alwaysOnTop) {
            return;
        }
        super.setAlwaysOnTop(alwaysOnTop);
        // positionChildAtTop() must be called even when always on top gets turned off because
        // we need to make sure that the display area is moved from among always on top containers
        // to below other always on top containers. Since the position the display area should be
        // inserted into is calculated properly in {@link DisplayContent#getTopInsertPosition()}
        // in both cases, we can just request that the root task is put at top here.
        if (getParent().asDisplayArea() != null) {
            getParent().asDisplayArea().positionChildAt(POSITION_TOP, this,
                    false /* includingParents */);
        }
    }

    boolean getIgnoreOrientationRequest() {
        // Adding an exception for when ignoreOrientationRequest is overridden at runtime for all
        // DisplayArea-s. For example, this is needed for the Kids Mode since many Kids apps aren't
@@ -234,6 +251,18 @@ public class DisplayArea<T extends WindowContainer> extends WindowContainer<T> {
        // The min possible position we can insert the child at.
        int minPosition = findMinPositionForChildDisplayArea(child);

        // Place all non-always-on-top containers below always-on-top ones.
        int alwaysOnTopCount = 0;
        for (int i = minPosition; i <= maxPosition; i++) {
            if (mChildren.get(i).isAlwaysOnTop()) {
                alwaysOnTopCount++;
            }
        }
        if (child.isAlwaysOnTop()) {
            minPosition = maxPosition - alwaysOnTopCount + 1;
        } else {
            maxPosition -= alwaysOnTopCount;
        }
        return Math.max(Math.min(requestPosition, maxPosition), minPosition);
    }

+13 −0
Original line number Diff line number Diff line
@@ -37,6 +37,7 @@ import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_RESTORE_TRANSIENT_ORDER;
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_SET_ADJACENT_ROOTS;
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_SET_ADJACENT_TASK_FRAGMENTS;
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_SET_ALWAYS_ON_TOP;
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_SET_LAUNCH_ADJACENT_FLAG_ROOT;
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_SET_LAUNCH_ROOT;
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_START_ACTIVITY_IN_TASK_FRAGMENT;
@@ -1068,6 +1069,18 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
                WindowContainer.fromBinder(hop.getContainer())
                        .removeLocalInsetsSourceProvider(hop.getInsetsTypes());
                break;
            case HIERARCHY_OP_TYPE_SET_ALWAYS_ON_TOP:
                final WindowContainer container = WindowContainer.fromBinder(hop.getContainer());
                if (container == null || container.asDisplayArea() == null
                        || !container.isAttached()) {
                    Slog.e(TAG, "Attempt to operate on unknown or detached display area: "
                            + container);
                    break;
                }
                container.setAlwaysOnTop(hop.isAlwaysOnTop());
                effects |= TRANSACT_EFFECTS_LIFECYCLE;
                break;

        }
        return effects;
    }
+64 −5
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

package com.android.server.wm;

import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
@@ -399,9 +400,9 @@ public class DisplayAreaTest extends WindowTestsBase {
                parentBounds.right / 2, parentBounds.bottom);
        final Rect childBounds2 = new Rect(parentBounds.right / 2, parentBounds.top,
                parentBounds.right, parentBounds.bottom);
        TestDisplayArea parentDa = new TestDisplayArea(mWm, parentBounds);
        TestDisplayArea childDa1 = new TestDisplayArea(mWm, childBounds1);
        TestDisplayArea childDa2 = new TestDisplayArea(mWm, childBounds2);
        TestDisplayArea parentDa = new TestDisplayArea(mWm, parentBounds, "Parent");
        TestDisplayArea childDa1 = new TestDisplayArea(mWm, childBounds1, "Child1");
        TestDisplayArea childDa2 = new TestDisplayArea(mWm, childBounds2, "Child2");
        parentDa.addChild(childDa1, 0);
        parentDa.addChild(childDa2, 1);

@@ -619,9 +620,67 @@ public class DisplayAreaTest extends WindowTestsBase {
        controller.registerOrganizer(mockDisplayAreaOrganizer, FEATURE_VENDOR_FIRST);
    }

    @Test
    public void testSetAlwaysOnTop_movesDisplayAreaToTop() {
        final Rect bounds = new Rect(0, 0, 100, 100);
        DisplayArea<WindowContainer> parent = new TestDisplayArea(mWm, bounds, "Parent");
        parent.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
        DisplayArea<WindowContainer> child1 = new TestDisplayArea(mWm, bounds, "Child1");
        child1.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
        DisplayArea<WindowContainer> child2 = new TestDisplayArea(mWm, bounds, "Child2");
        child2.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
        parent.addChild(child2, 0);
        parent.addChild(child1, 1);

        child2.setAlwaysOnTop(true);

        assertEquals(parent.getChildAt(1), child2);
        assertThat(child2.isAlwaysOnTop()).isTrue();
    }

    @Test
    public void testDisplayAreaRequestsTopPosition_alwaysOnTopSiblingExists_doesNotMoveToTop() {
        final Rect bounds = new Rect(0, 0, 100, 100);
        DisplayArea<WindowContainer> parent = new TestDisplayArea(mWm, bounds, "Parent");
        parent.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
        DisplayArea<WindowContainer> alwaysOnTopChild = new TestDisplayArea(mWm, bounds,
                "AlwaysOnTopChild");
        alwaysOnTopChild.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
        DisplayArea<WindowContainer> child = new TestDisplayArea(mWm, bounds, "Child");
        child.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
        parent.addChild(alwaysOnTopChild, 0);
        parent.addChild(child, 1);
        alwaysOnTopChild.setAlwaysOnTop(true);

        parent.positionChildAt(POSITION_TOP, child, false /* includingParents */);

        assertEquals(parent.getChildAt(1), alwaysOnTopChild);
        assertEquals(parent.getChildAt(0), child);
    }

    @Test
    public void testAlwaysOnTopDisplayArea_requestsNonTopLocation_doesNotMove() {
        final Rect bounds = new Rect(0, 0, 100, 100);
        DisplayArea<WindowContainer> parent = new TestDisplayArea(mWm, bounds, "Parent");
        parent.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
        DisplayArea<WindowContainer> alwaysOnTopChild = new TestDisplayArea(mWm, bounds,
                "AlwaysOnTopChild");
        alwaysOnTopChild.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
        DisplayArea<WindowContainer> child = new TestDisplayArea(mWm, bounds, "Child");
        child.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
        parent.addChild(alwaysOnTopChild, 0);
        parent.addChild(child, 1);
        alwaysOnTopChild.setAlwaysOnTop(true);

        parent.positionChildAt(POSITION_BOTTOM, alwaysOnTopChild, false /* includingParents */);

        assertEquals(parent.getChildAt(1), alwaysOnTopChild);
        assertEquals(parent.getChildAt(0), child);
    }

    private static class TestDisplayArea<T extends WindowContainer> extends DisplayArea<T> {
        private TestDisplayArea(WindowManagerService wms, Rect bounds) {
            super(wms, ANY, "half display area");
        private TestDisplayArea(WindowManagerService wms, Rect bounds, String name) {
            super(wms, ANY, name);
            setBounds(bounds);
        }