Merge "Clean-up change transition when cancelled before anim starts"
This commit is contained in:
committed by
Android (Google) Code Review
commit
e1fa5a85e9
@@ -143,7 +143,7 @@ class AppWindowThumbnail implements Animatable {
|
||||
|
||||
void destroy() {
|
||||
mSurfaceAnimator.cancelAnimation();
|
||||
mSurfaceControl.remove();
|
||||
getPendingTransaction().remove(mSurfaceControl);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1275,7 +1275,19 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree
|
||||
void onDisplayChanged(DisplayContent dc) {
|
||||
DisplayContent prevDc = mDisplayContent;
|
||||
super.onDisplayChanged(dc);
|
||||
if (prevDc != null && prevDc.mFocusedApp == this) {
|
||||
if (prevDc == null) {
|
||||
return;
|
||||
}
|
||||
if (prevDc.mChangingApps.contains(this)) {
|
||||
// This gets called *after* the AppWindowToken has been reparented to the new display.
|
||||
// That reparenting resulted in this window changing modes (eg. FREEFORM -> FULLSCREEN),
|
||||
// so this token is now "frozen" while waiting for the animation to start on prevDc
|
||||
// (which will be cancelled since the window is no-longer a child). However, since this
|
||||
// is no longer a child of prevDc, this won't be notified of the cancelled animation,
|
||||
// so we need to cancel the change transition here.
|
||||
clearChangeLeash(getPendingTransaction(), true /* cancel */);
|
||||
}
|
||||
if (prevDc.mFocusedApp == this) {
|
||||
prevDc.setFocusedApp(null);
|
||||
final TaskStack stack = dc.getTopStack();
|
||||
if (stack != null) {
|
||||
@@ -1584,7 +1596,10 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree
|
||||
}
|
||||
|
||||
private boolean shouldStartChangeTransition(int prevWinMode, int newWinMode) {
|
||||
if (!isVisible() || getDisplayContent().mAppTransition.isTransitionSet()) {
|
||||
if (mWmService.mDisableTransitionAnimation
|
||||
|| !isVisible()
|
||||
|| getDisplayContent().mAppTransition.isTransitionSet()
|
||||
|| getSurfaceControl() == null) {
|
||||
return false;
|
||||
}
|
||||
// Only do an animation into and out-of freeform mode for now. Other mode
|
||||
@@ -2561,9 +2576,7 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree
|
||||
return;
|
||||
} else if (mTransitChangeLeash != null) {
|
||||
// unparent mTransitChangeLeash for clean-up
|
||||
t.hide(mTransitChangeLeash);
|
||||
t.reparent(mTransitChangeLeash, null);
|
||||
mTransitChangeLeash = null;
|
||||
clearChangeLeash(t, false /* cancel */);
|
||||
}
|
||||
|
||||
if (mAnimatingAppWindowTokenRegistry != null) {
|
||||
@@ -2659,15 +2672,36 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree
|
||||
return super.isSelfAnimating();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param cancel {@code true} if clearing the leash due to cancelling instead of transferring
|
||||
* to another leash.
|
||||
*/
|
||||
private void clearChangeLeash(Transaction t, boolean cancel) {
|
||||
if (mTransitChangeLeash == null) {
|
||||
return;
|
||||
}
|
||||
if (cancel) {
|
||||
clearThumbnail();
|
||||
SurfaceControl sc = getSurfaceControl();
|
||||
SurfaceControl parentSc = getParentSurfaceControl();
|
||||
// Don't reparent if surface is getting destroyed
|
||||
if (parentSc != null && sc != null) {
|
||||
t.reparent(sc, getParentSurfaceControl());
|
||||
}
|
||||
}
|
||||
t.hide(mTransitChangeLeash);
|
||||
t.reparent(mTransitChangeLeash, null);
|
||||
mTransitChangeLeash = null;
|
||||
if (cancel) {
|
||||
onAnimationLeashDestroyed(t);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
void cancelAnimation() {
|
||||
cancelAnimationOnly();
|
||||
clearThumbnail();
|
||||
if (mTransitChangeLeash != null) {
|
||||
getPendingTransaction().hide(mTransitChangeLeash);
|
||||
getPendingTransaction().reparent(mTransitChangeLeash, null);
|
||||
mTransitChangeLeash = null;
|
||||
}
|
||||
clearChangeLeash(getPendingTransaction(), true /* cancel */);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -3003,7 +3037,9 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree
|
||||
void removeFromPendingTransition() {
|
||||
if (isWaitingForTransitionStart() && mDisplayContent != null) {
|
||||
mDisplayContent.mOpeningApps.remove(this);
|
||||
mDisplayContent.mChangingApps.remove(this);
|
||||
if (mDisplayContent.mChangingApps.remove(this)) {
|
||||
clearChangeLeash(getPendingTransaction(), true /* cancel */);
|
||||
}
|
||||
mDisplayContent.mClosingApps.remove(this);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,24 +16,29 @@
|
||||
|
||||
package com.android.server.wm;
|
||||
|
||||
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
|
||||
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
|
||||
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
|
||||
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
|
||||
import static android.view.WindowManager.TRANSIT_TASK_CHANGE_WINDOWING_MODE;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import android.graphics.Rect;
|
||||
import android.os.IBinder;
|
||||
import android.view.Display;
|
||||
import android.view.IRemoteAnimationFinishedCallback;
|
||||
import android.view.IRemoteAnimationRunner;
|
||||
import android.view.RemoteAnimationAdapter;
|
||||
import android.view.RemoteAnimationDefinition;
|
||||
import android.view.RemoteAnimationTarget;
|
||||
|
||||
import androidx.test.filters.FlakyTest;
|
||||
import androidx.test.filters.SmallTest;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
@@ -49,14 +54,20 @@ public class AppChangeTransitionTests extends WindowTestsBase {
|
||||
private Task mTask;
|
||||
private WindowTestUtils.TestAppWindowToken mToken;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
mStack = createTaskStackOnDisplay(mDisplayContent);
|
||||
public void setUpOnDisplay(DisplayContent dc) {
|
||||
mStack = createTaskStackOnDisplay(WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_STANDARD, dc);
|
||||
mTask = createTaskInStack(mStack, 0 /* userId */);
|
||||
mToken = WindowTestUtils.createTestAppWindowToken(mDisplayContent);
|
||||
mToken = WindowTestUtils.createTestAppWindowToken(dc);
|
||||
mToken.mSkipOnParentChanged = false;
|
||||
|
||||
mTask.addChild(mToken, 0);
|
||||
|
||||
// Set a remote animator with snapshot disabled. Snapshots don't work in wmtests.
|
||||
RemoteAnimationDefinition definition = new RemoteAnimationDefinition();
|
||||
RemoteAnimationAdapter adapter =
|
||||
new RemoteAnimationAdapter(new TestRemoteAnimationRunner(), 10, 1, false);
|
||||
definition.addRemoteAnimation(TRANSIT_TASK_CHANGE_WINDOWING_MODE, adapter);
|
||||
dc.registerRemoteAnimations(definition);
|
||||
}
|
||||
|
||||
class TestRemoteAnimationRunner implements IRemoteAnimationRunner {
|
||||
@@ -85,14 +96,58 @@ public class AppChangeTransitionTests extends WindowTestsBase {
|
||||
|
||||
@Test
|
||||
public void testModeChangeRemoteAnimatorNoSnapshot() {
|
||||
RemoteAnimationDefinition definition = new RemoteAnimationDefinition();
|
||||
RemoteAnimationAdapter adapter =
|
||||
new RemoteAnimationAdapter(new TestRemoteAnimationRunner(), 10, 1, false);
|
||||
definition.addRemoteAnimation(TRANSIT_TASK_CHANGE_WINDOWING_MODE, adapter);
|
||||
mDisplayContent.registerRemoteAnimations(definition);
|
||||
// setup currently defaults to no snapshot.
|
||||
setUpOnDisplay(mDisplayContent);
|
||||
|
||||
mTask.setWindowingMode(WINDOWING_MODE_FREEFORM);
|
||||
assertEquals(1, mDisplayContent.mChangingApps.size());
|
||||
|
||||
// Verify we are in a change transition, but without a snapshot.
|
||||
// Though, the test will actually have crashed by now if a snapshot is attempted.
|
||||
assertNull(mToken.getThumbnail());
|
||||
assertTrue(mToken.isInChangeTransition());
|
||||
|
||||
waitUntilHandlersIdle();
|
||||
mToken.removeImmediately();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCancelPendingChangeOnRemove() {
|
||||
// setup currently defaults to no snapshot.
|
||||
setUpOnDisplay(mDisplayContent);
|
||||
|
||||
mTask.setWindowingMode(WINDOWING_MODE_FREEFORM);
|
||||
assertEquals(1, mDisplayContent.mChangingApps.size());
|
||||
assertTrue(mToken.isInChangeTransition());
|
||||
|
||||
// Removing the app-token from the display should clean-up the
|
||||
// the change leash.
|
||||
mDisplayContent.removeAppToken(mToken.token);
|
||||
assertEquals(0, mDisplayContent.mChangingApps.size());
|
||||
assertFalse(mToken.isInChangeTransition());
|
||||
|
||||
waitUntilHandlersIdle();
|
||||
mToken.removeImmediately();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNoChangeWhenMoveDisplay() {
|
||||
mDisplayContent.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
|
||||
final DisplayContent dc1 = createNewDisplay(Display.STATE_ON);
|
||||
dc1.setWindowingMode(WINDOWING_MODE_FREEFORM);
|
||||
setUpOnDisplay(dc1);
|
||||
|
||||
assertEquals(WINDOWING_MODE_FREEFORM, mTask.getWindowingMode());
|
||||
|
||||
// Reparenting to a display with different windowing mode may trigger
|
||||
// a change transition internally, but it should be cleaned-up once
|
||||
// the display change is complete.
|
||||
mStack.reparent(mDisplayContent.getDisplayId(), new Rect(), true);
|
||||
|
||||
assertEquals(WINDOWING_MODE_FULLSCREEN, mTask.getWindowingMode());
|
||||
|
||||
// Make sure we're not waiting for a change animation (no leash)
|
||||
assertFalse(mToken.isInChangeTransition());
|
||||
assertNull(mToken.getThumbnail());
|
||||
|
||||
waitUntilHandlersIdle();
|
||||
|
||||
Reference in New Issue
Block a user