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

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

Merge "Fix unable to cleanup a removed display"

parents c96b8345 402b440f
Loading
Loading
Loading
Loading
+36 −14
Original line number Diff line number Diff line
@@ -1031,29 +1031,50 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack>

    void remove() {
        final boolean destroyContentOnRemoval = shouldDestroyContentOnRemove();
        ActivityStack lastReparentedStack = null;
        mPreferredTopFocusableStack = null;

        // Stacks could be reparented from the removed display to other display. While
        // reparenting the last stack of the removed display, the remove display is ready to be
        // released (no more ActivityStack). But, we cannot release it at that moment or the
        // related WindowContainer and WindowContainerController will also be removed. So, we
        // set display as removed after reparenting stack finished.
        for (int i = mStacks.size() - 1; i >= 0; --i) {
            final ActivityStack stack = mStacks.get(i);
        final ActivityDisplay toDisplay = mSupervisor.getDefaultDisplay();
        mSupervisor.beginDeferResume();
        try {
            int numStacks = mStacks.size();
            // Keep the order from bottom to top.
            for (int stackNdx = 0; stackNdx < numStacks; stackNdx++) {
                final ActivityStack stack = mStacks.get(stackNdx);
                // Always finish non-standard type stacks.
                if (destroyContentOnRemoval || !stack.isActivityTypeStandardOrUndefined()) {
                    stack.finishAllActivitiesLocked(true /* immediately */);
                } else {
                // If default display is in split-window mode, set windowing mode of the stack to
                // split-screen secondary. Otherwise, set the windowing mode to undefined by
                    // If default display is in split-window mode, set windowing mode of the stack
                    // to split-screen secondary. Otherwise, set the windowing mode to undefined by
                    // default to let stack inherited the windowing mode from the new display.
                int windowingMode = mSupervisor.getDefaultDisplay().hasSplitScreenPrimaryStack()
                        ? WINDOWING_MODE_SPLIT_SCREEN_SECONDARY : WINDOWING_MODE_UNDEFINED;
                mSupervisor.moveStackToDisplayLocked(stack.mStackId, DEFAULT_DISPLAY, true);
                    final int windowingMode = toDisplay.hasSplitScreenPrimaryStack()
                            ? WINDOWING_MODE_SPLIT_SCREEN_SECONDARY
                            : WINDOWING_MODE_UNDEFINED;
                    stack.reparent(toDisplay, true /* onTop */, true /* displayRemoved */);
                    stack.setWindowingMode(windowingMode);
                    lastReparentedStack = stack;
                }
                // Stacks may be removed from this display. Ensure each stack will be processed and
                // the loop will end.
                stackNdx -= numStacks - mStacks.size();
                numStacks = mStacks.size();
            }
        } finally {
            mSupervisor.endDeferResume();
        }
        mRemoved = true;

        // Only update focus/visibility for the last one because there may be many stacks are
        // reparented and the intermediate states are unnecessary.
        if (lastReparentedStack != null) {
            lastReparentedStack.postReparent();
        }
        releaseSelfIfNeeded();

        if (!mAllSleepTokens.isEmpty()) {
@@ -1091,7 +1112,8 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack>
                || mDisplayId == mSupervisor.mService.mVr2dDisplayId;
    }

    private boolean shouldDestroyContentOnRemove() {
    @VisibleForTesting
    boolean shouldDestroyContentOnRemove() {
        return mDisplay.getRemoveMode() == REMOVE_MODE_DESTROY_CONTENT;
    }

+10 −2
Original line number Diff line number Diff line
@@ -738,7 +738,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
    }

    /** Adds the stack to specified display and calls WindowManager to do the same. */
    void reparent(ActivityDisplay activityDisplay, boolean onTop) {
    void reparent(ActivityDisplay activityDisplay, boolean onTop, boolean displayRemoved) {
        // TODO: We should probably resolve the windowing mode for the stack on the new display here
        // so that it end up in a compatible mode in the new display. e.g. split-screen secondary.
        removeFromDisplay();
@@ -747,6 +747,13 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
        mTmpRect2.setEmpty();
        mWindowContainerController.reparent(activityDisplay.mDisplayId, mTmpRect2, onTop);
        postAddToDisplay(activityDisplay, mTmpRect2.isEmpty() ? null : mTmpRect2, onTop);
        if (!displayRemoved) {
            postReparent();
        }
    }

    /** Resume next focusable stack after reparenting to another display. */
    void postReparent() {
        adjustFocusToNextFocusableStack("reparent", true /* allowFocusSelf */);
        mStackSupervisor.resumeFocusedStacksTopActivitiesLocked();
        // Update visibility of activities before notifying WM. This way it won't try to resize
@@ -1162,7 +1169,8 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
    }

    final boolean isAttached() {
        return getParent() != null;
        final ActivityDisplay display = getDisplay();
        return display != null && !display.isRemoved();
    }

    /**
+3 −3
Original line number Diff line number Diff line
@@ -3173,7 +3173,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
                    + " to its current displayId=" + displayId);
        }

        stack.reparent(activityDisplay, onTop);
        stack.reparent(activityDisplay, onTop, false /* displayRemoved */);
        // TODO(multi-display): resize stacks properly if moved from split-screen.
    }

@@ -4568,14 +4568,14 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
    /**
     * Begin deferring resume to avoid duplicate resumes in one pass.
     */
    private void beginDeferResume() {
    void beginDeferResume() {
        mDeferResumeCount++;
    }

    /**
     * End deferring resume and determine if resume can be called.
     */
    private void endDeferResume() {
    void endDeferResume() {
        mDeferResumeCount--;
    }

+39 −0
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

package com.android.server.wm;

import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
@@ -27,7 +28,12 @@ import static com.android.server.wm.ActivityStackSupervisor.ON_TOP;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;

import android.platform.test.annotations.Presubmit;

@@ -120,6 +126,39 @@ public class ActivityDisplayTests extends ActivityTestsBase {
        assertTrue(stack2.isFocusedStackOnDisplay());
    }

    /**
     * Verifies {@link ActivityDisplay#remove} should not resume home stack on the removing display.
     */
    @Test
    public void testNotResumeHomeStackOnRemovingDisplay() {
        // Create a display which supports system decoration and allows reparenting stacks to
        // another display when the display is removed.
        final ActivityDisplay display = spy(createNewActivityDisplay());
        doReturn(false).when(display).shouldDestroyContentOnRemove();
        doReturn(true).when(display).supportsSystemDecorations();
        mSupervisor.addChild(display, ActivityDisplay.POSITION_TOP);

        // Put home stack on the display.
        final ActivityStack homeStack = display.createStack(
                WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, ON_TOP);
        final TaskRecord task = new TaskBuilder(mSupervisor).setStack(homeStack).build();
        new ActivityBuilder(mService).setTask(task).build();
        display.removeChild(homeStack);
        final ActivityStack spiedHomeStack = spy(homeStack);
        display.addChild(spiedHomeStack, ActivityDisplay.POSITION_TOP);
        reset(spiedHomeStack);

        // Put a finishing standard activity which will be reparented.
        final ActivityStack stack = createFullscreenStackWithSimpleActivityAt(display);
        stack.topRunningActivityLocked().makeFinishingLocked();

        display.remove();

        // The removed display should have no focused stack and its home stack should never resume.
        assertNull(display.getFocusedStack());
        verify(spiedHomeStack, never()).resumeTopActivityUncheckedLocked(any(), any());
    }

    private ActivityStack createFullscreenStackWithSimpleActivityAt(ActivityDisplay display) {
        final ActivityStack fullscreenStack = display.createStack(
                WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, ON_TOP);