From b615394f34564651bfef521cda066761045d0578 Mon Sep 17 00:00:00 2001 From: Issei Suzuki Date: Wed, 24 Mar 2021 17:48:25 +0100 Subject: [PATCH] Let keyguard (un)occlude animation run even when no activity exists. Keyguard (un)occlude transition can be executed even before the occluding app becomes ready. Normally we skip to run remote animation for such cases since nothing to animate, however, KeyguardService uses IRemoteAnimationRunner#onAnimationStart as a signal to update its internal state, so WindowManager has to trigger the binder call. Bug: 175687166 Bug: 182975035 Test: atest AppTransitionControllerTest Change-Id: I190f2cf750f849b8aafdb43642cb03e5382f50d5 --- data/etc/services.core.protolog.json | 6 + .../com/android/server/wm/AppTransition.java | 8 +- .../server/wm/AppTransitionController.java | 35 +++--- .../server/wm/RemoteAnimationController.java | 11 +- .../wm/AppTransitionControllerTest.java | 112 +++++++++++++++++- 5 files changed, 146 insertions(+), 26 deletions(-) diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json index efeaf238ac845..2fcd73539b047 100644 --- a/data/etc/services.core.protolog.json +++ b/data/etc/services.core.protolog.json @@ -1825,6 +1825,12 @@ "group": "WM_DEBUG_IME", "at": "com\/android\/server\/wm\/InsetsSourceProvider.java" }, + "35398067": { + "message": "goodToGo(): onAnimationStart, transit=%s, apps=%d, wallpapers=%d, nonApps=%d", + "level": "DEBUG", + "group": "WM_DEBUG_REMOTE_ANIMATIONS", + "at": "com\/android\/server\/wm\/RemoteAnimationController.java" + }, "38267433": { "message": "Attempted to reset replacing window on non-existing app token %s", "level": "WARN", diff --git a/services/core/java/com/android/server/wm/AppTransition.java b/services/core/java/com/android/server/wm/AppTransition.java index 99289e0139b0b..394ae7e94b72d 100644 --- a/services/core/java/com/android/server/wm/AppTransition.java +++ b/services/core/java/com/android/server/wm/AppTransition.java @@ -1679,11 +1679,15 @@ public class AppTransition implements Dump { || transit == TRANSIT_OLD_KEYGUARD_GOING_AWAY_ON_WALLPAPER; } - static boolean isKeyguardTransitOld(@TransitionOldType int transit) { - return isKeyguardGoingAwayTransitOld(transit) || transit == TRANSIT_OLD_KEYGUARD_OCCLUDE + static boolean isKeyguardOccludeTransitOld(@TransitionOldType int transit) { + return transit == TRANSIT_OLD_KEYGUARD_OCCLUDE || transit == TRANSIT_OLD_KEYGUARD_UNOCCLUDE; } + static boolean isKeyguardTransitOld(@TransitionOldType int transit) { + return isKeyguardGoingAwayTransitOld(transit) || isKeyguardOccludeTransitOld(transit); + } + static boolean isTaskTransitOld(@TransitionOldType int transit) { return isTaskOpenTransitOld(transit) || transit == TRANSIT_OLD_TASK_CLOSE diff --git a/services/core/java/com/android/server/wm/AppTransitionController.java b/services/core/java/com/android/server/wm/AppTransitionController.java index 9ca7eca07dc69..019e7bb4ca6b3 100644 --- a/services/core/java/com/android/server/wm/AppTransitionController.java +++ b/services/core/java/com/android/server/wm/AppTransitionController.java @@ -69,7 +69,6 @@ import static com.android.server.wm.WindowManagerDebugConfig.SHOW_LIGHT_TRANSACT import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; -import android.annotation.NonNull; import android.annotation.Nullable; import android.os.Trace; import android.util.ArrayMap; @@ -429,43 +428,37 @@ public class AppTransitionController { return mainWindow != null ? mainWindow.mAttrs : null; } - RemoteAnimationAdapter getRemoteAnimationOverride(@NonNull WindowContainer container, + RemoteAnimationAdapter getRemoteAnimationOverride(@Nullable WindowContainer container, @TransitionOldType int transit, ArraySet activityTypes) { - final RemoteAnimationDefinition definition = container.getRemoteAnimationDefinition(); - if (definition != null) { - final RemoteAnimationAdapter adapter = definition.getAdapter(transit, activityTypes); - if (adapter != null) { - return adapter; + if (container != null) { + final RemoteAnimationDefinition definition = container.getRemoteAnimationDefinition(); + if (definition != null) { + final RemoteAnimationAdapter adapter = definition.getAdapter(transit, + activityTypes); + if (adapter != null) { + return adapter; + } } } - if (mRemoteAnimationDefinition != null) { - final RemoteAnimationAdapter adapter = mRemoteAnimationDefinition.getAdapter( - transit, activityTypes); - if (adapter != null) { - return adapter; - } - } - return null; + return mRemoteAnimationDefinition != null + ? mRemoteAnimationDefinition.getAdapter(transit, activityTypes) + : null; } /** * Overrides the pending transition with the remote animation defined for the transition in the * set of defined remote animations in the app window token. */ - private void overrideWithRemoteAnimationIfSet(ActivityRecord animLpActivity, + private void overrideWithRemoteAnimationIfSet(@Nullable ActivityRecord animLpActivity, @TransitionOldType int transit, ArraySet activityTypes) { if (transit == TRANSIT_OLD_CRASHING_ACTIVITY_CLOSE) { // The crash transition has higher priority than any involved remote animations. return; } - if (animLpActivity == null) { - return; - } final RemoteAnimationAdapter adapter = getRemoteAnimationOverride(animLpActivity, transit, activityTypes); if (adapter != null) { - animLpActivity.getDisplayContent().mAppTransition.overridePendingAppTransitionRemote( - adapter); + mDisplayContent.mAppTransition.overridePendingAppTransitionRemote(adapter); } } diff --git a/services/core/java/com/android/server/wm/RemoteAnimationController.java b/services/core/java/com/android/server/wm/RemoteAnimationController.java index f851e3559def2..67bc7af6dc287 100644 --- a/services/core/java/com/android/server/wm/RemoteAnimationController.java +++ b/services/core/java/com/android/server/wm/RemoteAnimationController.java @@ -121,7 +121,10 @@ class RemoteAnimationController implements DeathRecipient { // Create the app targets final RemoteAnimationTarget[] appTargets = createAppAnimations(); - if (appTargets.length == 0) { + if (appTargets.length == 0 && !AppTransition.isKeyguardOccludeTransitOld(transit)) { + // Keyguard occlude transition can be executed before the occluding activity becomes + // visible. Even in this case, KeyguardService expects to receive binder call, so we + // don't cancel remote animation. ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "goodToGo(): No apps to animate, mPendingAnimations=%d", mPendingAnimations.size()); @@ -133,12 +136,16 @@ class RemoteAnimationController implements DeathRecipient { // Create the remote wallpaper animation targets (if any) final RemoteAnimationTarget[] wallpaperTargets = createWallpaperAnimations(); - // TODO(bc-unlock): Create the remote non app animation targets (if any) + // Create the remote non app animation targets (if any) final RemoteAnimationTarget[] nonAppTargets = createNonAppWindowAnimations(transit); mService.mAnimator.addAfterPrepareSurfacesRunnable(() -> { try { linkToDeathOfRunner(); + ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "goodToGo(): onAnimationStart," + + " transit=%s, apps=%d, wallpapers=%d, nonApps=%d", + AppTransition.appTransitionOldToString(transit), appTargets.length, + wallpaperTargets.length, nonAppTargets.length); mRemoteAnimationAdapter.getRunner().onAnimationStart(transit, appTargets, wallpaperTargets, nonAppTargets, mFinishedCallback); } catch (RemoteException e) { diff --git a/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java index 678defe36566a..57cf865268efa 100644 --- a/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java @@ -23,17 +23,27 @@ import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION; import static android.view.WindowManager.TRANSIT_CHANGE; import static android.view.WindowManager.TRANSIT_CLOSE; import static android.view.WindowManager.TRANSIT_OLD_ACTIVITY_OPEN; +import static android.view.WindowManager.TRANSIT_OLD_KEYGUARD_UNOCCLUDE; import static android.view.WindowManager.TRANSIT_OLD_TASK_CHANGE_WINDOWING_MODE; import static android.view.WindowManager.TRANSIT_OLD_TASK_OPEN; import static android.view.WindowManager.TRANSIT_OPEN; 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 static org.mockito.Mockito.doCallRealMethod; +import android.os.Binder; +import android.os.IBinder; +import android.os.RemoteException; import android.platform.test.annotations.Presubmit; import android.util.ArraySet; +import android.view.IRemoteAnimationFinishedCallback; +import android.view.IRemoteAnimationRunner; +import android.view.RemoteAnimationAdapter; +import android.view.RemoteAnimationDefinition; +import android.view.RemoteAnimationTarget; import android.view.WindowManager; import androidx.test.filters.FlakyTest; @@ -426,4 +436,104 @@ public class AppTransitionControllerTest extends WindowTestsBase { AppTransitionController.getAnimationTargets( opening, closing, false /* visible */)); } -} + + static class TestRemoteAnimationRunner implements IRemoteAnimationRunner { + @Override + public void onAnimationStart(int transit, RemoteAnimationTarget[] apps, + RemoteAnimationTarget[] wallpapers, RemoteAnimationTarget[] nonApps, + IRemoteAnimationFinishedCallback finishedCallback) throws RemoteException { + } + + @Override + public void onAnimationCancelled() throws RemoteException { + } + + @Override + public IBinder asBinder() { + return new Binder(); + } + } + + @Test + public void testGetRemoteAnimationOverrideEmpty() { + final ActivityRecord activity = createActivityRecord(mDisplayContent); + assertNull(mAppTransitionController.getRemoteAnimationOverride(activity, + TRANSIT_OLD_ACTIVITY_OPEN, new ArraySet())); + } + + @Test + public void testGetRemoteAnimationOverrideWindowContainer() { + final ActivityRecord activity = createActivityRecord(mDisplayContent); + final RemoteAnimationDefinition definition = new RemoteAnimationDefinition(); + final RemoteAnimationAdapter adapter = new RemoteAnimationAdapter( + new TestRemoteAnimationRunner(), 10, 1); + definition.addRemoteAnimation(TRANSIT_OLD_ACTIVITY_OPEN, adapter); + activity.registerRemoteAnimations(definition); + + assertEquals(adapter, + mAppTransitionController.getRemoteAnimationOverride( + activity, TRANSIT_OLD_ACTIVITY_OPEN, new ArraySet())); + assertNull(mAppTransitionController.getRemoteAnimationOverride( + null, TRANSIT_OLD_ACTIVITY_OPEN, new ArraySet())); + } + + @Test + public void testGetRemoteAnimationOverrideTransitionController() { + final ActivityRecord activity = createActivityRecord(mDisplayContent); + final RemoteAnimationDefinition definition = new RemoteAnimationDefinition(); + final RemoteAnimationAdapter adapter = new RemoteAnimationAdapter( + new TestRemoteAnimationRunner(), 10, 1); + definition.addRemoteAnimation(TRANSIT_OLD_ACTIVITY_OPEN, adapter); + mAppTransitionController.registerRemoteAnimations(definition); + + assertEquals(adapter, + mAppTransitionController.getRemoteAnimationOverride( + activity, TRANSIT_OLD_ACTIVITY_OPEN, new ArraySet())); + assertEquals(adapter, + mAppTransitionController.getRemoteAnimationOverride( + null, TRANSIT_OLD_ACTIVITY_OPEN, new ArraySet())); + } + + @Test + public void testGetRemoteAnimationOverrideBoth() { + final ActivityRecord activity = createActivityRecord(mDisplayContent); + final RemoteAnimationDefinition definition1 = new RemoteAnimationDefinition(); + final RemoteAnimationAdapter adapter1 = new RemoteAnimationAdapter( + new TestRemoteAnimationRunner(), 10, 1); + definition1.addRemoteAnimation(TRANSIT_OLD_ACTIVITY_OPEN, adapter1); + activity.registerRemoteAnimations(definition1); + + final RemoteAnimationDefinition definition2 = new RemoteAnimationDefinition(); + final RemoteAnimationAdapter adapter2 = new RemoteAnimationAdapter( + new TestRemoteAnimationRunner(), 10, 1); + definition2.addRemoteAnimation(TRANSIT_OLD_KEYGUARD_UNOCCLUDE, adapter2); + mAppTransitionController.registerRemoteAnimations(definition2); + + assertEquals(adapter2, + mAppTransitionController.getRemoteAnimationOverride( + activity, TRANSIT_OLD_KEYGUARD_UNOCCLUDE, new ArraySet())); + assertEquals(adapter2, + mAppTransitionController.getRemoteAnimationOverride( + null, TRANSIT_OLD_KEYGUARD_UNOCCLUDE, new ArraySet())); + } + + @Test + public void testGetRemoteAnimationOverrideWindowContainerHasPriority() { + final ActivityRecord activity = createActivityRecord(mDisplayContent); + final RemoteAnimationDefinition definition1 = new RemoteAnimationDefinition(); + final RemoteAnimationAdapter adapter1 = new RemoteAnimationAdapter( + new TestRemoteAnimationRunner(), 10, 1); + definition1.addRemoteAnimation(TRANSIT_OLD_ACTIVITY_OPEN, adapter1); + activity.registerRemoteAnimations(definition1); + + final RemoteAnimationDefinition definition2 = new RemoteAnimationDefinition(); + final RemoteAnimationAdapter adapter2 = new RemoteAnimationAdapter( + new TestRemoteAnimationRunner(), 10, 1); + definition2.addRemoteAnimation(TRANSIT_OLD_ACTIVITY_OPEN, adapter2); + mAppTransitionController.registerRemoteAnimations(definition2); + + assertEquals(adapter1, + mAppTransitionController.getRemoteAnimationOverride( + activity, TRANSIT_OLD_ACTIVITY_OPEN, new ArraySet())); + } +} \ No newline at end of file