diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json index 891c82d2c1666..0e8388b7e8f3f 100644 --- a/data/etc/services.core.protolog.json +++ b/data/etc/services.core.protolog.json @@ -2485,6 +2485,12 @@ "group": "WM_ERROR", "at": "com\/android\/server\/wm\/WindowManagerService.java" }, + "323235828": { + "message": "Delaying app transition for recents animation to finish", + "level": "VERBOSE", + "group": "WM_DEBUG_APP_TRANSITIONS", + "at": "com\/android\/server\/wm\/AppTransitionController.java" + }, "327461496": { "message": "Complete pause: %s", "level": "VERBOSE", diff --git a/services/core/java/com/android/server/wm/AppTransitionController.java b/services/core/java/com/android/server/wm/AppTransitionController.java index 701fc9441acb8..cb6559715c558 100644 --- a/services/core/java/com/android/server/wm/AppTransitionController.java +++ b/services/core/java/com/android/server/wm/AppTransitionController.java @@ -68,6 +68,7 @@ import static com.android.server.wm.AppTransition.isNormalTransit; import static com.android.server.wm.NonAppWindowAnimationAdapter.shouldAttachNavBarToApp; import static com.android.server.wm.NonAppWindowAnimationAdapter.shouldStartNonAppWindowAnimationsForKeyguardExit; import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_APP_TRANSITION; +import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_RECENTS; import static com.android.server.wm.WallpaperAnimationAdapter.shouldStartWallpaperAnimation; import static com.android.server.wm.WindowContainer.AnimationFlags.PARENTS; import static com.android.server.wm.WindowManagerDebugConfig.SHOW_LIGHT_TRANSACTIONS; @@ -1142,13 +1143,17 @@ public class AppTransitionController { if (activity == null) { continue; } + if (activity.isAnimating(PARENTS, ANIMATION_TYPE_RECENTS)) { + ProtoLog.v(WM_DEBUG_APP_TRANSITIONS, + "Delaying app transition for recents animation to finish"); + return false; + } ProtoLog.v(WM_DEBUG_APP_TRANSITIONS, "Check opening app=%s: allDrawn=%b startingDisplayed=%b " + "startingMoved=%b isRelaunching()=%b startingWindow=%s", activity, activity.allDrawn, activity.startingDisplayed, activity.startingMoved, activity.isRelaunching(), activity.mStartingWindow); - final boolean allDrawn = activity.allDrawn && !activity.isRelaunching(); if (!allDrawn && !activity.startingDisplayed && !activity.startingMoved) { return false; diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java index c7bc51356c765..b10c4eb892ac2 100644 --- a/services/core/java/com/android/server/wm/WindowContainer.java +++ b/services/core/java/com/android/server/wm/WindowContainer.java @@ -1584,6 +1584,14 @@ class WindowContainer extends ConfigurationContainer< return true; } + void forAllWindowContainers(Consumer callback) { + callback.accept(this); + final int count = mChildren.size(); + for (int i = 0; i < count; i++) { + mChildren.get(i).forAllWindowContainers(callback); + } + } + /** * For all windows at or below this container call the callback. * @param callback Calls the {@link ToBooleanFunction#apply} method for each window found and diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 7b77fd0683cde..363c0ebad16ba 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -118,6 +118,7 @@ import static com.android.server.wm.DisplayContent.IME_TARGET_CONTROL; import static com.android.server.wm.DisplayContent.IME_TARGET_LAYERING; import static com.android.server.wm.RootWindowContainer.MATCH_ATTACHED_TASK_OR_RECENT_TASKS; import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_ALL; +import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_APP_TRANSITION; import static com.android.server.wm.WindowContainer.AnimationFlags.CHILDREN; import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG; @@ -3050,13 +3051,22 @@ public class WindowManagerService extends IWindowManager.Stub } } + void cleanupRecentsAnimation(@RecentsAnimationController.ReorderMode int reorderMode) { if (mRecentsAnimationController != null) { final RecentsAnimationController controller = mRecentsAnimationController; mRecentsAnimationController = null; controller.cleanupAnimation(reorderMode); - // TODO(mult-display): currently only default display support recents animation. - getDefaultDisplayContentLocked().mAppTransition.updateBooster(); + // TODO(multi-display): currently only default display support recents animation. + // Cancel any existing app transition animation running in the legacy transition + // framework. + final DisplayContent dc = getDefaultDisplayContentLocked(); + dc.mAppTransition.freeze(); + dc.forAllWindowContainers((wc) -> { + if (wc.isAnimating(TRANSITION, ANIMATION_TYPE_APP_TRANSITION)) { + wc.cancelAnimation(); + } + }); } } 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 eb6395b461201..35921585d56fe 100644 --- a/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java @@ -39,8 +39,10 @@ import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentat import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyInt; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing; 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.spyOn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify; +import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_RECENTS; import static com.android.server.wm.WindowContainer.POSITION_TOP; import static org.junit.Assert.assertEquals; @@ -48,7 +50,9 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; import android.graphics.Rect; import android.os.Binder; @@ -376,7 +380,7 @@ public class AppTransitionTests extends WindowTestsBase { doReturn(false).when(dc).onDescendantOrientationChanged(any()); final WindowState exitingAppWindow = createWindow(null /* parent */, TYPE_BASE_APPLICATION, dc, "exiting app"); - final ActivityRecord exitingActivity= exitingAppWindow.mActivityRecord; + final ActivityRecord exitingActivity = exitingAppWindow.mActivityRecord; // Wait until everything in animation handler get executed to prevent the exiting window // from being removed during WindowSurfacePlacer Traversal. waitUntilHandlersIdle(); @@ -404,6 +408,41 @@ public class AppTransitionTests extends WindowTestsBase { assertTrue(runner.mCancelled); } + @Test + public void testDelayWhileRecents() { + final DisplayContent dc = createNewDisplay(Display.STATE_ON); + doReturn(false).when(dc).onDescendantOrientationChanged(any()); + final Task task = createTask(dc); + + // Simulate activity1 launches activity2. + final ActivityRecord activity1 = createActivityRecord(task); + activity1.setVisible(true); + activity1.mVisibleRequested = false; + activity1.allDrawn = true; + final ActivityRecord activity2 = createActivityRecord(task); + activity2.setVisible(false); + activity2.mVisibleRequested = true; + activity2.allDrawn = true; + + dc.mClosingApps.add(activity1); + dc.mOpeningApps.add(activity2); + dc.prepareAppTransition(TRANSIT_OPEN); + assertTrue(dc.mAppTransition.containsTransitRequest(TRANSIT_OPEN)); + + // Wait until everything in animation handler get executed to prevent the exiting window + // from being removed during WindowSurfacePlacer Traversal. + waitUntilHandlersIdle(); + + // Start recents + doReturn(true).when(task) + .isSelfAnimating(anyInt(), eq(ANIMATION_TYPE_RECENTS)); + + dc.mAppTransitionController.handleAppTransitionReady(); + + verify(activity1, never()).commitVisibility(anyBoolean(), anyBoolean(), anyBoolean()); + verify(activity2, never()).commitVisibility(anyBoolean(), anyBoolean(), anyBoolean()); + } + @Test public void testGetAnimationStyleResId() { // Verify getAnimationStyleResId will return as LayoutParams.windowAnimations when without