Merge "Fix index out of bounds when removing deferred containers" into rvc-dev am: 8da7870ba5 am: c69836c81e

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/12035041

Change-Id: Ic8d5effbb9fb4e6692bd7430894e9021c663f1b5
This commit is contained in:
TreeHugger Robot
2020-06-30 03:50:34 +00:00
committed by Automerger Merge Worker
6 changed files with 50 additions and 43 deletions

View File

@@ -3146,11 +3146,11 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
} }
@Override @Override
boolean checkCompleteDeferredRemoval() { boolean handleCompleteDeferredRemoval() {
if (mIsExiting) { if (mIsExiting) {
removeIfPossible(); removeIfPossible();
} }
return super.checkCompleteDeferredRemoval(); return super.handleCompleteDeferredRemoval();
} }
void onRemovedFromDisplay() { void onRemovedFromDisplay() {

View File

@@ -86,7 +86,6 @@ import static com.android.server.wm.TaskProto.ACTIVITY_TYPE;
import static com.android.server.wm.TaskProto.ANIMATING_BOUNDS; import static com.android.server.wm.TaskProto.ANIMATING_BOUNDS;
import static com.android.server.wm.TaskProto.BOUNDS; import static com.android.server.wm.TaskProto.BOUNDS;
import static com.android.server.wm.TaskProto.CREATED_BY_ORGANIZER; import static com.android.server.wm.TaskProto.CREATED_BY_ORGANIZER;
import static com.android.server.wm.TaskProto.DEFER_REMOVAL;
import static com.android.server.wm.TaskProto.DISPLAY_ID; import static com.android.server.wm.TaskProto.DISPLAY_ID;
import static com.android.server.wm.TaskProto.FILLS_PARENT; import static com.android.server.wm.TaskProto.FILLS_PARENT;
import static com.android.server.wm.TaskProto.LAST_NON_FULLSCREEN_BOUNDS; import static com.android.server.wm.TaskProto.LAST_NON_FULLSCREEN_BOUNDS;
@@ -248,11 +247,6 @@ class ActivityStack extends Task {
private Rect mTmpRect = new Rect(); private Rect mTmpRect = new Rect();
private Rect mTmpRect2 = new Rect(); private Rect mTmpRect2 = new Rect();
/** Detach this stack from its display when animation completes. */
// TODO: maybe tie this to WindowContainer#removeChild some how...
// TODO: This is no longer set. Okay to remove or was the set removed by accident?
private boolean mDeferRemoval;
// If this is true, we are in the bounds animating mode. The task will be down or upscaled to // If this is true, we are in the bounds animating mode. The task will be down or upscaled to
// perfectly fit the region it would have been cropped to. We may also avoid certain logic we // perfectly fit the region it would have been cropped to. We may also avoid certain logic we
// would otherwise apply while resizing, while resizing in the bounds animating mode. // would otherwise apply while resizing, while resizing in the bounds animating mode.
@@ -3232,9 +3226,6 @@ class ActivityStack extends Task {
@Override @Override
void dump(PrintWriter pw, String prefix, boolean dumpAll) { void dump(PrintWriter pw, String prefix, boolean dumpAll) {
if (mDeferRemoval) {
pw.println(prefix + "mDeferRemoval=true");
}
super.dump(pw, prefix, dumpAll); super.dump(pw, prefix, dumpAll);
if (!mExitingActivities.isEmpty()) { if (!mExitingActivities.isEmpty()) {
pw.println(); pw.println();
@@ -3304,15 +3295,12 @@ class ActivityStack extends Task {
} }
/** Returns true if a removal action is still being deferred. */ /** Returns true if a removal action is still being deferred. */
boolean checkCompleteDeferredRemoval() { boolean handleCompleteDeferredRemoval() {
if (isAnimating(TRANSITION | CHILDREN)) { if (isAnimating(TRANSITION | CHILDREN)) {
return true; return true;
} }
if (mDeferRemoval) {
removeImmediately();
}
return super.checkCompleteDeferredRemoval(); return super.handleCompleteDeferredRemoval();
} }
public DisplayInfo getDisplayInfo() { public DisplayInfo getDisplayInfo() {
@@ -3380,7 +3368,6 @@ class ActivityStack extends Task {
mLastNonFullscreenBounds.dumpDebug(proto, LAST_NON_FULLSCREEN_BOUNDS); mLastNonFullscreenBounds.dumpDebug(proto, LAST_NON_FULLSCREEN_BOUNDS);
} }
proto.write(DEFER_REMOVAL, mDeferRemoval);
proto.write(ANIMATING_BOUNDS, mBoundsAnimating); proto.write(ANIMATING_BOUNDS, mBoundsAnimating);
if (mSurfaceControl != null) { if (mSurfaceControl != null) {

View File

@@ -2739,6 +2739,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
@Override @Override
void removeImmediately() { void removeImmediately() {
mRemovingDisplay = true; mRemovingDisplay = true;
mDeferredRemoval = false;
try { try {
if (mParentWindow != null) { if (mParentWindow != null) {
mParentWindow.removeEmbeddedDisplayContent(this); mParentWindow.removeEmbeddedDisplayContent(this);
@@ -2771,31 +2772,14 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
/** Returns true if a removal action is still being deferred. */ /** Returns true if a removal action is still being deferred. */
@Override @Override
boolean checkCompleteDeferredRemoval() { boolean handleCompleteDeferredRemoval() {
boolean stillDeferringRemoval = false; final boolean stillDeferringRemoval = super.handleCompleteDeferredRemoval();
for (int i = getChildCount() - 1; i >= 0; --i) {
final DisplayChildWindowContainer child = getChildAt(i);
stillDeferringRemoval |= child.checkCompleteDeferredRemoval();
if (getChildCount() == 0) {
// If this display is pending to be removed because it contains an activity with
// {@link ActivityRecord#mIsExiting} is true, this display may be removed when
// completing the removal of the last activity from
// {@link ActivityRecord#checkCompleteDeferredRemoval}.
return false;
}
}
if (!stillDeferringRemoval && mDeferredRemoval) { if (!stillDeferringRemoval && mDeferredRemoval) {
removeImmediately(); removeImmediately();
return false; return false;
} }
return true; return stillDeferringRemoval;
}
/** @return 'true' if removal of this display content is deferred due to active animation. */
boolean isRemovalDeferred() {
return mDeferredRemoval;
} }
void adjustForImeIfNeeded() { void adjustForImeIfNeeded() {

View File

@@ -990,9 +990,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
} }
// Remove all deferred displays stacks, tasks, and activities. // Remove all deferred displays stacks, tasks, and activities.
for (int displayNdx = mChildren.size() - 1; displayNdx >= 0; --displayNdx) { handleCompleteDeferredRemoval();
mChildren.get(displayNdx).checkCompleteDeferredRemoval();
}
forAllDisplays(dc -> { forAllDisplays(dc -> {
dc.getInputMonitor().updateInputWindowsLw(true /*force*/); dc.getInputMonitor().updateInputWindowsLw(true /*force*/);

View File

@@ -1044,13 +1044,25 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
return mChildren.peekLast(); return mChildren.peekLast();
} }
/** Returns true if there is still a removal being deferred */ /**
boolean checkCompleteDeferredRemoval() { * Removes the containers which were deferred.
*
* @return {@code true} if there is still a removal being deferred.
*/
boolean handleCompleteDeferredRemoval() {
boolean stillDeferringRemoval = false; boolean stillDeferringRemoval = false;
for (int i = mChildren.size() - 1; i >= 0; --i) { for (int i = mChildren.size() - 1; i >= 0; --i) {
final WindowContainer wc = mChildren.get(i); final WindowContainer wc = mChildren.get(i);
stillDeferringRemoval |= wc.checkCompleteDeferredRemoval(); stillDeferringRemoval |= wc.handleCompleteDeferredRemoval();
if (!hasChild()) {
// All child containers of current level could be removed from a removal of
// descendant. E.g. if a display is pending to be removed because it contains an
// activity with {@link ActivityRecord#mIsExiting} is true, the display may be
// removed when completing the removal of the last activity from
// {@link ActivityRecord#checkCompleteDeferredRemoval}.
return false;
}
} }
return stillDeferringRemoval; return stillDeferringRemoval;

View File

@@ -27,6 +27,7 @@ import static android.window.DisplayAreaOrganizer.FEATURE_DEFAULT_TASK_CONTAINER
import static com.android.dx.mockito.inline.extended.ExtendedMockito.any; import static com.android.dx.mockito.inline.extended.ExtendedMockito.any;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyFloat; import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyFloat;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyInt;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.eq; import static com.android.dx.mockito.inline.extended.ExtendedMockito.eq;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock; import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
@@ -824,6 +825,31 @@ public class WindowContainerTests extends WindowTestsBase {
assertEquals(newDc, activity.mDisplayContent); assertEquals(newDc, activity.mDisplayContent);
} }
@Test
public void testHandleCompleteDeferredRemoval() {
final DisplayContent displayContent = createNewDisplay();
// Do not reparent activity to default display when removing the display.
doReturn(true).when(displayContent).shouldDestroyContentOnRemove();
final ActivityRecord r = new ActivityTestsBase.StackBuilder(mWm.mRoot)
.setDisplay(displayContent).build().getTopMostActivity();
// Add a window and make the activity animating so the removal of activity is deferred.
createWindow(null, TYPE_BASE_APPLICATION, r, "win");
doReturn(true).when(r).isAnimating(anyInt(), anyInt());
displayContent.remove();
// Ensure that ActivityRecord#onRemovedFromDisplay is called.
r.destroyed("test");
// The removal is deferred, so the activity is still in the display.
assertEquals(r, displayContent.getTopMostActivity());
// Assume the animation is done so the deferred removal can continue.
doReturn(false).when(r).isAnimating(anyInt(), anyInt());
assertFalse(displayContent.handleCompleteDeferredRemoval());
assertFalse(displayContent.hasChild());
assertFalse(r.hasChild());
}
@Test @Test
public void testTaskCanApplyAnimation() { public void testTaskCanApplyAnimation() {
final ActivityStack stack = createTaskStackOnDisplay(mDisplayContent); final ActivityStack stack = createTaskStackOnDisplay(mDisplayContent);