Merge "Fix unable to cleanup a removed display"
This commit is contained in:
committed by
Android (Google) Code Review
commit
42617d031a
@@ -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);
|
||||
// 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
|
||||
// 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);
|
||||
stack.setWindowingMode(windowingMode);
|
||||
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
|
||||
// default to let stack inherited the windowing mode from the new display.
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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--;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user