Merge "Clean-up change transition when cancelled before anim starts"

This commit is contained in:
TreeHugger Robot
2019-02-09 06:09:22 +00:00
committed by Android (Google) Code Review
3 changed files with 114 additions and 23 deletions

View File

@@ -143,7 +143,7 @@ class AppWindowThumbnail implements Animatable {
void destroy() {
mSurfaceAnimator.cancelAnimation();
mSurfaceControl.remove();
getPendingTransaction().remove(mSurfaceControl);
}
/**

View File

@@ -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);
}
}

View File

@@ -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();