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

Commit ec397364 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Fix unused new stack when bring existing activity to front"

parents 71b9bd81 fd4a0500
Loading
Loading
Loading
Loading
+4 −2
Original line number Diff line number Diff line
@@ -81,6 +81,7 @@ import static android.content.res.Configuration.UI_MODE_TYPE_VR_HEADSET;
import static android.os.Build.VERSION_CODES.HONEYCOMB;
import static android.os.Build.VERSION_CODES.O;
import static android.os.Process.SYSTEM_UID;
import static android.view.Display.INVALID_DISPLAY;
import static android.view.WindowManagerPolicyConstants.NAV_BAR_LEFT;

import static com.android.server.am.ActivityTaskManagerDebugConfig.DEBUG_CONFIGURATION;
@@ -2212,12 +2213,13 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
    }

    /**
     * @return display id to which this record is attached, -1 if not attached.
     * @return display id to which this record is attached,
     *         {@link android.view.Display#INVALID_DISPLAY} if not attached.
     */
    int getDisplayId() {
        final ActivityStack stack = getStack();
        if (stack == null) {
            return -1;
            return INVALID_DISPLAY;
        }
        return stack.mDisplayId;
    }
+15 −2
Original line number Diff line number Diff line
@@ -2466,7 +2466,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
        }
        if (displayId != INVALID_DISPLAY && canLaunchOnDisplay(r, displayId)) {
            if (r != null) {
                stack = (T) getValidLaunchStackOnDisplay(displayId, r, options);
                stack = (T) getValidLaunchStackOnDisplay(displayId, r, candidateTask, options);
                if (stack != null) {
                    return stack;
                }
@@ -2531,10 +2531,11 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
     * If there is no such stack, new dynamic stack can be created.
     * @param displayId Target display.
     * @param r Activity that should be launched there.
     * @param candidateTask The possible task the activity might be put in.
     * @return Existing stack if there is a valid one, new dynamic stack if it is valid or null.
     */
    ActivityStack getValidLaunchStackOnDisplay(int displayId, @NonNull ActivityRecord r,
            @Nullable ActivityOptions options) {
            @Nullable TaskRecord candidateTask, @Nullable ActivityOptions options) {
        final ActivityDisplay activityDisplay = getActivityDisplayOrCreateLocked(displayId);
        if (activityDisplay == null) {
            throw new IllegalArgumentException(
@@ -2545,6 +2546,13 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
            return null;
        }

        // If {@code r} is already in target display and its task is the same as the candidate task,
        // the intention should be getting a launch stack for the reusable activity, so we can use
        // the existing stack.
        if (r.getDisplayId() == displayId && r.getTask() == candidateTask) {
            return candidateTask.getStack();
        }

        // Return the topmost valid stack on the display.
        for (int i = activityDisplay.getChildCount() - 1; i >= 0; --i) {
            final ActivityStack stack = activityDisplay.getChildAt(i);
@@ -2565,6 +2573,11 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
        return null;
    }

    ActivityStack getValidLaunchStackOnDisplay(int displayId, @NonNull ActivityRecord r,
            @Nullable ActivityOptions options) {
        return getValidLaunchStackOnDisplay(displayId, r, null /* candidateTask */, options);
    }

    // TODO: Can probably be consolidated into getLaunchStack()...
    private boolean isValidLaunchStack(ActivityStack stack, int displayId, ActivityRecord r) {
        switch (stack.getActivityType()) {
+57 −13
Original line number Diff line number Diff line
@@ -37,6 +37,7 @@ import static android.content.Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED;
import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_TASK;

import static com.android.server.am.ActivityDisplay.POSITION_BOTTOM;
import static com.android.server.am.ActivityDisplay.POSITION_TOP;
import static com.android.server.am.ActivityTaskManagerService.ANIMATE;

import static org.junit.Assert.assertEquals;
@@ -562,23 +563,13 @@ public class ActivityStarterTests extends ActivityTestsBase {
                false /* mockGetLaunchStack */);

        // Create a secondary display at bottom.
        final TestActivityDisplay secondaryDisplay = spy(addNewActivityDisplayAt(POSITION_BOTTOM));
        final TestActivityDisplay secondaryDisplay = spy(createNewActivityDisplay());
        mSupervisor.addChild(secondaryDisplay, POSITION_BOTTOM);
        final ActivityStack stack = secondaryDisplay.createStack(WINDOWING_MODE_FULLSCREEN,
                ACTIVITY_TYPE_STANDARD, true /* onTop */);

        // Create an activity record on the top of secondary display.
        final ComponentName componentName = ComponentName.createRelative(
                DEFAULT_COMPONENT_PACKAGE_NAME,
                DEFAULT_COMPONENT_PACKAGE_NAME + ".ReusableActivity");
        final TaskRecord taskRecord = new TaskBuilder(mSupervisor)
                .setComponent(componentName)
                .setStack(stack)
                .build();
        final ActivityRecord topActivityOnSecondaryDisplay = new ActivityBuilder(mService)
                .setComponent(componentName)
                .setLaunchMode(LAUNCH_SINGLE_TASK)
                .setTask(taskRecord)
                .build();
        final ActivityRecord topActivityOnSecondaryDisplay = createSingleTaskActivityOn(stack);

        // Put an activity on default display as the top focused activity.
        new ActivityBuilder(mService).setCreateTask(true).build();
@@ -599,6 +590,59 @@ public class ActivityStarterTests extends ActivityTestsBase {
        verify(secondaryDisplay, times(1)).createStack(anyInt(), anyInt(), anyBoolean());
    }

    /**
     * This test ensures that when starting an existing non-top single task activity on secondary
     * display which is the top focused display, it should bring the task to front without creating
     * unused stack.
     */
    @Test
    public void testBringTaskToFrontOnSecondaryDisplay() {
        final ActivityStarter starter = prepareStarter(FLAG_ACTIVITY_NEW_TASK,
                false /* mockGetLaunchStack */);

        // Create a secondary display with an activity.
        final TestActivityDisplay secondaryDisplay = spy(createNewActivityDisplay());
        mSupervisor.addChild(secondaryDisplay, POSITION_TOP);
        final ActivityRecord singleTaskActivity = createSingleTaskActivityOn(
                secondaryDisplay.createStack(WINDOWING_MODE_FULLSCREEN,
                        ACTIVITY_TYPE_STANDARD, false /* onTop */));

        // Create another activity on top of the secondary display.
        final ActivityStack topStack = secondaryDisplay.createStack(WINDOWING_MODE_FULLSCREEN,
                ACTIVITY_TYPE_STANDARD, true /* onTop */);
        final TaskRecord topTask = new TaskBuilder(mSupervisor).setStack(topStack).build();
        new ActivityBuilder(mService).setTask(topTask).build();

        // Start activity with the same intent as {@code singleTaskActivity} on secondary display.
        final ActivityOptions options = ActivityOptions.makeBasic()
                .setLaunchDisplayId(secondaryDisplay.mDisplayId);
        final int result = starter.setReason("testBringTaskToFrontOnSecondaryDisplay")
                .setIntent(singleTaskActivity.intent)
                .setActivityOptions(options.toBundle())
                .execute();

        // Ensure result is moving existing task to front.
        assertEquals(START_TASK_TO_FRONT, result);

        // Ensure secondary display only creates two stacks.
        verify(secondaryDisplay, times(2)).createStack(anyInt(), anyInt(), anyBoolean());
    }

    private ActivityRecord createSingleTaskActivityOn(ActivityStack stack) {
        final ComponentName componentName = ComponentName.createRelative(
                DEFAULT_COMPONENT_PACKAGE_NAME,
                DEFAULT_COMPONENT_PACKAGE_NAME + ".SingleTaskActivity");
        final TaskRecord taskRecord = new TaskBuilder(mSupervisor)
                .setComponent(componentName)
                .setStack(stack)
                .build();
        return new ActivityBuilder(mService)
                .setComponent(componentName)
                .setLaunchMode(LAUNCH_SINGLE_TASK)
                .setTask(taskRecord)
                .build();
    }

    /**
     * This test ensures that a reused top activity in the top focused stack is able to be
     * reparented to another display.