diff options
3 files changed, 72 insertions, 5 deletions
diff --git a/services/core/java/com/android/server/wm/AppTransition.java b/services/core/java/com/android/server/wm/AppTransition.java index e053ff338a25..0915caedd6bc 100644 --- a/services/core/java/com/android/server/wm/AppTransition.java +++ b/services/core/java/com/android/server/wm/AppTransition.java @@ -452,6 +452,13 @@ public class AppTransition implements Dump { void freeze() { final int transit = mNextAppTransition; + // The RemoteAnimationControl didn't register AppTransitionListener and + // only initialized the finish and timeout callback when goodToGo(). + // So cancel the remote animation here to prevent the animation can't do + // finish after transition state cleared. + if (mRemoteAnimationController != null) { + mRemoteAnimationController.cancelAnimation("freeze"); + } setAppTransition(TRANSIT_UNSET, 0 /* flags */); clear(); setReady(); diff --git a/services/core/java/com/android/server/wm/RemoteAnimationController.java b/services/core/java/com/android/server/wm/RemoteAnimationController.java index 5f95691d5307..b4bfedda94c7 100644 --- a/services/core/java/com/android/server/wm/RemoteAnimationController.java +++ b/services/core/java/com/android/server/wm/RemoteAnimationController.java @@ -132,7 +132,7 @@ class RemoteAnimationController implements DeathRecipient { sendRunningRemoteAnimation(true); } - private void cancelAnimation(String reason) { + void cancelAnimation(String reason) { if (DEBUG_REMOTE_ANIMATIONS) Slog.d(TAG, "cancelAnimation(): reason=" + reason); synchronized (mService.getWindowManagerLock()) { if (mCanceled) { diff --git a/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java index 5fc7f44588e1..5a72a584b122 100644 --- a/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java @@ -18,30 +18,40 @@ package com.android.server.wm; import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; +import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION; import static android.view.WindowManager.TRANSIT_ACTIVITY_CLOSE; import static android.view.WindowManager.TRANSIT_ACTIVITY_OPEN; import static android.view.WindowManager.TRANSIT_CRASHING_ACTIVITY_CLOSE; import static android.view.WindowManager.TRANSIT_KEYGUARD_GOING_AWAY; import static android.view.WindowManager.TRANSIT_KEYGUARD_UNOCCLUDE; + import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; + import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyBoolean; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing; import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; + import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import android.graphics.Rect; +import android.os.IBinder; +import android.os.RemoteException; import android.platform.test.annotations.Presubmit; import android.view.Display; - -import org.junit.Before; -import org.junit.Test; +import android.view.IRemoteAnimationFinishedCallback; +import android.view.IRemoteAnimationRunner; +import android.view.RemoteAnimationAdapter; +import android.view.RemoteAnimationTarget; import androidx.test.filters.FlakyTest; import androidx.test.filters.SmallTest; +import org.junit.Before; +import org.junit.Test; + /** * Test class for {@link AppTransition}. * @@ -51,7 +61,6 @@ import androidx.test.filters.SmallTest; @SmallTest @Presubmit public class AppTransitionTests extends WindowTestsBase { - private DisplayContent mDc; @Before @@ -181,4 +190,55 @@ public class AppTransitionTests extends WindowTestsBase { getInstrumentation().getTargetContext(), -1)); } + @Test + public void testCancelRemoteAnimationWhenFreeze() { + final DisplayContent dc = createNewDisplay(Display.STATE_ON); + final WindowState exitingAppWindow = createWindow(null /* parent */, TYPE_BASE_APPLICATION, + dc, "exiting app"); + final AppWindowToken exitingAppToken = exitingAppWindow.mAppToken; + // Wait until everything in animation handler get executed to prevent the exiting window + // from being removed during WindowSurfacePlacer Traversal. + waitUntilHandlersIdle(); + + // Set a remote animator. + final TestRemoteAnimationRunner runner = new TestRemoteAnimationRunner(); + final RemoteAnimationAdapter adapter = new RemoteAnimationAdapter( + runner, 100, 50, true /* changeNeedsSnapshot */); + // RemoteAnimationController will tracking RemoteAnimationAdapter's caller with calling pid. + adapter.setCallingPid(123); + + // Simulate activity finish flows to prepare app transition & set visibility, + // make sure transition is set as expected. + dc.prepareAppTransition(TRANSIT_ACTIVITY_CLOSE, + false /* alwaysKeepCurrent */, 0 /* flags */, false /* forceOverride */); + assertEquals(TRANSIT_ACTIVITY_CLOSE, dc.mAppTransition.getAppTransition()); + dc.mAppTransition.overridePendingAppTransitionRemote(adapter); + exitingAppToken.setVisibility(false, false); + assertTrue(dc.mClosingApps.size() > 0); + + // Make sure window is in animating stage before freeze, and cancel after freeze. + assertTrue(dc.isAppAnimating()); + assertFalse(runner.mCancelled); + dc.mAppTransition.freeze(); + assertFalse(dc.isAppAnimating()); + assertTrue(runner.mCancelled); + } + + private class TestRemoteAnimationRunner implements IRemoteAnimationRunner { + boolean mCancelled = false; + @Override + public void onAnimationStart(RemoteAnimationTarget[] apps, + IRemoteAnimationFinishedCallback finishedCallback) throws RemoteException { + } + + @Override + public void onAnimationCancelled() { + mCancelled = true; + } + + @Override + public IBinder asBinder() { + return null; + } + } } |