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

Commit 2ef151d3 authored by Galia Peycheva's avatar Galia Peycheva Committed by Android (Google) Code Review
Browse files

Merge "Add specific z-ordering between PiP, Dream and Assistant" into rvc-dev

parents ec2c313a 7ecd6efa
Loading
Loading
Loading
Loading
+73 −41
Original line number Diff line number Diff line
@@ -123,6 +123,10 @@ final class TaskDisplayArea extends DisplayArea<ActivityStack> {
    private final RootWindowContainer.FindTaskResult
            mTmpFindTaskResult = new RootWindowContainer.FindTaskResult();

    // Indicates whether the Assistant should show on top of the Dream (respectively, above
    // everything else on screen). Otherwise, it will be put under always-on-top stacks.
    private final boolean mAssistantOnTopOfDream;

    /**
     * If this is the same as {@link #getFocusedStack} then the activity on the top of the focused
     * stack has been resumed. If stacks are changing position this will hold the old stack until
@@ -148,6 +152,9 @@ final class TaskDisplayArea extends DisplayArea<ActivityStack> {
        mDisplayContent = displayContent;
        mRootWindowContainer = service.mRoot;
        mAtmService = service.mAtmService;

        mAssistantOnTopOfDream = mWmService.mContext.getResources().getBoolean(
                    com.android.internal.R.bool.config_assistantOnTopOfDream);
    }

    /**
@@ -327,55 +334,80 @@ final class TaskDisplayArea extends DisplayArea<ActivityStack> {
    }

    /**
     * When stack is added or repositioned, find a proper position for it.
     * This will make sure that pinned stack always stays on top.
     * @param requestedPosition Position requested by caller.
     * @param stack Stack to be added or positioned.
     * @param adding Flag indicates whether we're adding a new stack or positioning an existing.
     * @return The proper position for the stack.
     * Assigns a priority number to stack types. This priority defines an order between the types
     * of stacks that are added to the task display area.
     *
     * Higher priority number indicates that the stack should have a higher z-order.
     *
     * @return the priority of the stack
     */
    private int findPositionForStack(int requestedPosition, ActivityStack stack,
            boolean adding) {
        if (stack.isActivityTypeDream()) {
            return POSITION_TOP;
        }

        if (stack.inPinnedWindowingMode()) {
            return POSITION_TOP;
        }

        final int topChildPosition = mChildren.size() - 1;
        int belowAlwaysOnTopPosition = POSITION_BOTTOM;
        for (int i = topChildPosition; i >= 0; --i) {
            // Since a stack could be repositioned while being one of the child, return
            // current index if that's the same stack we are positioning and it is always on
            // top.
            final boolean sameStack = mChildren.get(i) == stack;
            if ((sameStack && stack.isAlwaysOnTop())
                    || (!sameStack && !mChildren.get(i).isAlwaysOnTop())) {
                belowAlwaysOnTopPosition = i;
                break;
            }
    private int getPriority(ActivityStack stack) {
        if (mAssistantOnTopOfDream && stack.isActivityTypeAssistant()) return 4;
        if (stack.isActivityTypeDream()) return 3;
        if (stack.inPinnedWindowingMode()) return 2;
        if (stack.isAlwaysOnTop()) return 1;
        return 0;
    }

        // The max possible position we can insert the stack at.
        int maxPosition = POSITION_TOP;
        // The min possible position we can insert the stack at.
    private int findMinPositionForStack(ActivityStack stack) {
        int minPosition = POSITION_BOTTOM;
        for (int i = 0; i < mChildren.size(); ++i) {
            if (getPriority(getStackAt(i)) < getPriority(stack)) {
                minPosition = i;
            } else {
                break;
            }
        }

        if (stack.isAlwaysOnTop()) {
            if (hasPinnedTask()) {
                // Always-on-top stacks go below the pinned stack.
                maxPosition = mChildren.indexOf(mRootPinnedTask) - 1;
            // Since a stack could be repositioned while still being one of the children, we check
            // if this always-on-top stack already exists and if so, set the minPosition to its
            // previous position.
            final int currentIndex = getIndexOf(stack);
            if (currentIndex > minPosition) {
                minPosition = currentIndex;
            }
            // Always-on-top stacks need to be above all other stacks.
            minPosition = belowAlwaysOnTopPosition
                    != POSITION_BOTTOM ? belowAlwaysOnTopPosition : topChildPosition;
        } else {
            // Other stacks need to be below the always-on-top stacks.
            maxPosition = belowAlwaysOnTopPosition
                    != POSITION_BOTTOM ? belowAlwaysOnTopPosition : 0;
        }
        return minPosition;
    }

    private int findMaxPositionForStack(ActivityStack stack) {
        for (int i = mChildren.size() - 1; i >= 0; --i) {
            final ActivityStack curr = getStackAt(i);
            // Since a stack could be repositioned while still being one of the children, we check
            // if 'curr' is the same stack and skip it if so
            final boolean sameStack = curr == stack;
            if (getPriority(curr) <= getPriority(stack) && !sameStack) {
                return i;
            }
        }
        return 0;
    }

    /**
     * When stack is added or repositioned, find a proper position for it.
     *
     * The order is defined as:
     *  - Dream is on top of everything
     *  - PiP is directly below the Dream
     *  - always-on-top stacks are directly below PiP; new always-on-top stacks are added above
     *    existing ones
     *  - other non-always-on-top stacks come directly below always-on-top stacks; new
     *    non-always-on-top stacks are added directly below always-on-top stacks and above existing
     *    non-always-on-top stacks
     *  - if {@link #mAssistantOnTopOfDream} is enabled, then Assistant is on top of everything
     *    (including the Dream); otherwise, it is a normal non-always-on-top stack
     *
     * @param requestedPosition Position requested by caller.
     * @param stack Stack to be added or positioned.
     * @param adding Flag indicates whether we're adding a new stack or positioning an existing.
     * @return The proper position for the stack.
     */
    private int findPositionForStack(int requestedPosition, ActivityStack stack, boolean adding) {
        // The max possible position we can insert the stack at.
        int maxPosition = findMaxPositionForStack(stack);
        // The min possible position we can insert the stack at.
        int minPosition = findMinPositionForStack(stack);

        // Cap the requested position to something reasonable for the previous position check
        // below.
+24 −0
Original line number Diff line number Diff line
@@ -16,6 +16,8 @@

package com.android.server.wm;

import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_DREAM;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
@@ -270,6 +272,28 @@ public class ActivityDisplayTests extends ActivityTestsBase {
        anotherAlwaysOnTopStack.setWindowingMode(WINDOWING_MODE_FREEFORM);
        assertTrue(anotherAlwaysOnTopStack.isAlwaysOnTop());
        assertEquals(anotherAlwaysOnTopStack, taskDisplayArea.getStackAt(topPosition - 1));

        final ActivityStack dreamStack = taskDisplayArea.createStack(
                WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_DREAM, true /* onTop */);
        assertEquals(taskDisplayArea, dreamStack.getDisplayArea());
        assertTrue(dreamStack.isAlwaysOnTop());
        topPosition = taskDisplayArea.getStackCount() - 1;
        // Ensure dream shows above all activities, including PiP
        assertEquals(dreamStack, taskDisplayArea.getTopStack());
        assertEquals(pinnedStack, taskDisplayArea.getStackAt(topPosition - 1));

        final ActivityStack assistStack = taskDisplayArea.createStack(
                WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_ASSISTANT, true /* onTop */);
        assertEquals(taskDisplayArea, assistStack.getDisplayArea());
        assertFalse(assistStack.isAlwaysOnTop());
        topPosition = taskDisplayArea.getStackCount() - 1;

        // Ensure Assistant shows as a non-always-on-top activity when config_assistantOnTopOfDream
        // is false and on top of everything when true.
        final boolean isAssistantOnTop = mContext.getResources()
                .getBoolean(com.android.internal.R.bool.config_assistantOnTopOfDream);
        assertEquals(assistStack, taskDisplayArea.getStackAt(
                    isAssistantOnTop ? topPosition : topPosition - 4));
    }

    @Test
+42 −15
Original line number Diff line number Diff line
@@ -471,12 +471,27 @@ public class ActivityStackTests extends ActivityTestsBase {
        assertEquals(STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT,
                splitScreenSecondary2.getVisibility(null /* starting */));

        // Assistant stack shouldn't be visible behind translucent split-screen stack
        // Assistant stack shouldn't be visible behind translucent split-screen stack,
        // unless it is configured to show on top of everything.
        doReturn(false).when(assistantStack).isTranslucent(any());
        doReturn(true).when(splitScreenPrimary).isTranslucent(any());
        doReturn(true).when(splitScreenSecondary2).isTranslucent(any());
        splitScreenSecondary2.moveToFront("testShouldBeVisible_SplitScreen");
        splitScreenPrimary.moveToFront("testShouldBeVisible_SplitScreen");

        if (isAssistantOnTop()) {
            assertTrue(assistantStack.shouldBeVisible(null /* starting */));
            assertFalse(splitScreenPrimary.shouldBeVisible(null /* starting */));
            assertFalse(splitScreenSecondary2.shouldBeVisible(null /* starting */));
            assertEquals(STACK_VISIBILITY_VISIBLE,
                    assistantStack.getVisibility(null /* starting */));
            assertEquals(STACK_VISIBILITY_INVISIBLE,
                    splitScreenPrimary.getVisibility(null /* starting */));
            assertEquals(STACK_VISIBILITY_INVISIBLE,
                    splitScreenSecondary.getVisibility(null /* starting */));
            assertEquals(STACK_VISIBILITY_INVISIBLE,
                    splitScreenSecondary2.getVisibility(null /* starting */));
        } else {
            assertFalse(assistantStack.shouldBeVisible(null /* starting */));
            assertTrue(splitScreenPrimary.shouldBeVisible(null /* starting */));
            assertTrue(splitScreenSecondary2.shouldBeVisible(null /* starting */));
@@ -489,6 +504,7 @@ public class ActivityStackTests extends ActivityTestsBase {
            assertEquals(STACK_VISIBILITY_VISIBLE,
                    splitScreenSecondary2.getVisibility(null /* starting */));
        }
    }

    @Test
    public void testGetVisibility_MultiLevel() {
@@ -927,10 +943,16 @@ public class ActivityStackTests extends ActivityTestsBase {

        splitScreenSecondary.moveToFront("testSplitScreenMoveToFront");

        if (isAssistantOnTop()) {
            assertFalse(splitScreenPrimary.shouldBeVisible(null /* starting */));
            assertFalse(splitScreenSecondary.shouldBeVisible(null /* starting */));
            assertTrue(assistantStack.shouldBeVisible(null /* starting */));
        } else {
            assertTrue(splitScreenPrimary.shouldBeVisible(null /* starting */));
            assertTrue(splitScreenSecondary.shouldBeVisible(null /* starting */));
            assertFalse(assistantStack.shouldBeVisible(null /* starting */));
        }
    }

    private ActivityStack createStandardStackForVisibilityTest(int windowingMode,
            boolean translucent) {
@@ -1344,6 +1366,11 @@ public class ActivityStackTests extends ActivityTestsBase {
                anyBoolean());
    }

    private boolean isAssistantOnTop() {
        return mContext.getResources().getBoolean(
                com.android.internal.R.bool.config_assistantOnTopOfDream);
    }

    private void verifyShouldSleepActivities(boolean focusedStack,
            boolean keyguardGoingAway, boolean displaySleeping, boolean expected) {
        final DisplayContent display = mock(DisplayContent.class);