Exclude launcher from app transition animation while recents is running.
Changed approach to handle conflict between app transition and recents. In order to fix flicker which happens when recents and app transition start in a short time, we delayed app transition while recents was running. However this approach brought side effects such as b/232984498. When recents starts, we just want to wait that the launcher activitiy finishes rendering and commit its visibility without animation. Added a flag DisplayContent#mExcludeLauncherFromAnimation flag, so that we can now explicity declare whether we want to apply animation on the launcher or not. Bug: 223499269 Bug: 231711212 Bug: 232984498 Test: atest com.android.server.wm.AppTransitionTests Test: atest AppTransitionTest + manual tests Test 1 1. Launch Gmail app 2. Click icon on the bottom tab (e.g. Chat) 3. Swipe up from the bottom (immediately after step 2) 4. Verify closing animation only plays once Test 2 1. Launch "Google TV" 2. Play a trailer 3. Full screen and PIP mode switch twice 4. Verify PIP window is shown Test 3 1. Change phone to portlait mode 2. Launch Photo app 3. Swipe up from the bottom 4. Verify no rotation animation on the launcher Test 4 1. Install 3P launcher and set it default. 2. Launch Gmail app 3. Swipe up to go back home 4. Launch Chrome app 5. Swipe up and hold to go to overview. 6. Scroll to Gmail app and click. 7. Verify Gmail app is launched without delay. Change-Id: I0ccb99479684d17453ce57e8797024c0cd233ac3
This commit is contained in:
@@ -1879,12 +1879,6 @@
|
||||
"group": "WM_DEBUG_STATES",
|
||||
"at": "com\/android\/server\/wm\/TaskFragment.java"
|
||||
},
|
||||
"-240296576": {
|
||||
"message": "handleAppTransitionReady: displayId=%d appTransition={%s} openingApps=[%s] closingApps=[%s] transit=%s",
|
||||
"level": "VERBOSE",
|
||||
"group": "WM_DEBUG_APP_TRANSITIONS",
|
||||
"at": "com\/android\/server\/wm\/AppTransitionController.java"
|
||||
},
|
||||
"-237664290": {
|
||||
"message": "Pause the recording session on display %s",
|
||||
"level": "VERBOSE",
|
||||
@@ -1987,6 +1981,12 @@
|
||||
"group": "WM_DEBUG_CONTENT_RECORDING",
|
||||
"at": "com\/android\/server\/wm\/ContentRecorder.java"
|
||||
},
|
||||
"-134793542": {
|
||||
"message": "handleAppTransitionReady: displayId=%d appTransition={%s} excludeLauncherFromAnimation=%b openingApps=[%s] closingApps=[%s] transit=%s",
|
||||
"level": "VERBOSE",
|
||||
"group": "WM_DEBUG_APP_TRANSITIONS",
|
||||
"at": "com\/android\/server\/wm\/AppTransitionController.java"
|
||||
},
|
||||
"-134091882": {
|
||||
"message": "Screenshotting Activity %s",
|
||||
"level": "VERBOSE",
|
||||
@@ -2491,12 +2491,6 @@
|
||||
"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",
|
||||
|
||||
@@ -76,6 +76,7 @@ import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME
|
||||
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
|
||||
|
||||
import android.annotation.IntDef;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.os.Trace;
|
||||
import android.util.ArrayMap;
|
||||
@@ -145,7 +146,8 @@ public class AppTransitionController {
|
||||
* Returns the currently visible window that is associated with the wallpaper in case we are
|
||||
* transitioning from an activity with a wallpaper to one without.
|
||||
*/
|
||||
private @Nullable WindowState getOldWallpaper() {
|
||||
@Nullable
|
||||
private WindowState getOldWallpaper() {
|
||||
final WindowState wallpaperTarget = mWallpaperControllerLocked.getWallpaperTarget();
|
||||
final @TransitionType int firstTransit =
|
||||
mDisplayContent.mAppTransition.getFirstAppTransition();
|
||||
@@ -165,6 +167,16 @@ public class AppTransitionController {
|
||||
? null : wallpaperTarget;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private static ArraySet<ActivityRecord> getAppsForAnimation(
|
||||
@NonNull ArraySet<ActivityRecord> apps, boolean excludeLauncherFromAnimation) {
|
||||
final ArraySet<ActivityRecord> appsForAnimation = new ArraySet<>(apps);
|
||||
if (excludeLauncherFromAnimation) {
|
||||
appsForAnimation.removeIf(ConfigurationContainer::isActivityTypeHome);
|
||||
}
|
||||
return appsForAnimation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle application transition for given display.
|
||||
*/
|
||||
@@ -214,18 +226,29 @@ public class AppTransitionController {
|
||||
mWallpaperControllerLocked.adjustWallpaperWindowsForAppTransitionIfNeeded(
|
||||
mDisplayContent.mOpeningApps);
|
||||
|
||||
final @TransitionOldType int transit = getTransitCompatType(
|
||||
mDisplayContent.mAppTransition, mDisplayContent.mOpeningApps,
|
||||
mDisplayContent.mClosingApps, mDisplayContent.mChangingContainers,
|
||||
// Remove launcher from app transition animation while recents is running. Recents animation
|
||||
// is managed outside of app transition framework, so we just need to commit visibility.
|
||||
final boolean excludeLauncherFromAnimation =
|
||||
mDisplayContent.mOpeningApps.stream().anyMatch(
|
||||
(app) -> app.isAnimating(PARENTS, ANIMATION_TYPE_RECENTS))
|
||||
|| mDisplayContent.mClosingApps.stream().anyMatch(
|
||||
(app) -> app.isAnimating(PARENTS, ANIMATION_TYPE_RECENTS));
|
||||
final ArraySet<ActivityRecord> openingAppsForAnimation = getAppsForAnimation(
|
||||
mDisplayContent.mOpeningApps, excludeLauncherFromAnimation);
|
||||
final ArraySet<ActivityRecord> closingAppsForAnimation = getAppsForAnimation(
|
||||
mDisplayContent.mClosingApps, excludeLauncherFromAnimation);
|
||||
|
||||
@TransitionOldType final int transit = getTransitCompatType(
|
||||
mDisplayContent.mAppTransition, openingAppsForAnimation, closingAppsForAnimation,
|
||||
mDisplayContent.mChangingContainers,
|
||||
mWallpaperControllerLocked.getWallpaperTarget(), getOldWallpaper(),
|
||||
mDisplayContent.mSkipAppTransitionAnimation);
|
||||
mDisplayContent.mSkipAppTransitionAnimation = false;
|
||||
|
||||
ProtoLog.v(WM_DEBUG_APP_TRANSITIONS,
|
||||
"handleAppTransitionReady: displayId=%d appTransition={%s}"
|
||||
+ " openingApps=[%s] closingApps=[%s] transit=%s",
|
||||
mDisplayContent.mDisplayId,
|
||||
appTransition.toString(),
|
||||
+ " excludeLauncherFromAnimation=%b openingApps=[%s] closingApps=[%s] transit=%s",
|
||||
mDisplayContent.mDisplayId, appTransition.toString(), excludeLauncherFromAnimation,
|
||||
mDisplayContent.mOpeningApps, mDisplayContent.mClosingApps,
|
||||
AppTransition.appTransitionOldToString(transit));
|
||||
|
||||
@@ -233,13 +256,15 @@ public class AppTransitionController {
|
||||
// what will control the animation theme. If all closing windows are obscured, then there is
|
||||
// no need to do an animation. This is the case, for example, when this transition is being
|
||||
// done behind a dream window.
|
||||
final ArraySet<Integer> activityTypes = collectActivityTypes(mDisplayContent.mOpeningApps,
|
||||
mDisplayContent.mClosingApps, mDisplayContent.mChangingContainers);
|
||||
final ActivityRecord animLpActivity = findAnimLayoutParamsToken(transit, activityTypes);
|
||||
final ArraySet<Integer> activityTypes = collectActivityTypes(openingAppsForAnimation,
|
||||
closingAppsForAnimation, mDisplayContent.mChangingContainers);
|
||||
final ActivityRecord animLpActivity = findAnimLayoutParamsToken(transit, activityTypes,
|
||||
openingAppsForAnimation, closingAppsForAnimation,
|
||||
mDisplayContent.mChangingContainers);
|
||||
final ActivityRecord topOpeningApp =
|
||||
getTopApp(mDisplayContent.mOpeningApps, false /* ignoreHidden */);
|
||||
getTopApp(openingAppsForAnimation, false /* ignoreHidden */);
|
||||
final ActivityRecord topClosingApp =
|
||||
getTopApp(mDisplayContent.mClosingApps, false /* ignoreHidden */);
|
||||
getTopApp(closingAppsForAnimation, false /* ignoreHidden */);
|
||||
final ActivityRecord topChangingApp =
|
||||
getTopApp(mDisplayContent.mChangingContainers, false /* ignoreHidden */);
|
||||
final WindowManager.LayoutParams animLp = getAnimLp(animLpActivity);
|
||||
@@ -251,14 +276,14 @@ public class AppTransitionController {
|
||||
overrideWithRemoteAnimationIfSet(animLpActivity, transit, activityTypes);
|
||||
}
|
||||
|
||||
final boolean voiceInteraction = containsVoiceInteraction(mDisplayContent.mClosingApps)
|
||||
|| containsVoiceInteraction(mDisplayContent.mOpeningApps);
|
||||
final boolean voiceInteraction = containsVoiceInteraction(closingAppsForAnimation)
|
||||
|| containsVoiceInteraction(openingAppsForAnimation);
|
||||
|
||||
final int layoutRedo;
|
||||
mService.mSurfaceAnimationRunner.deferStartingAnimations();
|
||||
try {
|
||||
applyAnimations(mDisplayContent.mOpeningApps, mDisplayContent.mClosingApps, transit,
|
||||
animLp, voiceInteraction);
|
||||
applyAnimations(openingAppsForAnimation, closingAppsForAnimation, transit, animLp,
|
||||
voiceInteraction);
|
||||
handleClosingApps();
|
||||
handleOpeningApps();
|
||||
handleChangingApps(transit);
|
||||
@@ -310,7 +335,7 @@ public class AppTransitionController {
|
||||
* case we are transitioning from an activity with a wallpaper to one
|
||||
* without. Otherwise null.
|
||||
*/
|
||||
static @TransitionOldType int getTransitCompatType(AppTransition appTransition,
|
||||
@TransitionOldType static int getTransitCompatType(AppTransition appTransition,
|
||||
ArraySet<ActivityRecord> openingApps, ArraySet<ActivityRecord> closingApps,
|
||||
ArraySet<WindowContainer> changingContainers, @Nullable WindowState wallpaperTarget,
|
||||
@Nullable WindowState oldWallpaper, boolean skipAppTransitionAnimation) {
|
||||
@@ -341,8 +366,8 @@ public class AppTransitionController {
|
||||
if (skipAppTransitionAnimation) {
|
||||
return WindowManager.TRANSIT_OLD_UNSET;
|
||||
}
|
||||
final @TransitionFlags int flags = appTransition.getTransitFlags();
|
||||
final @TransitionType int firstTransit = appTransition.getFirstAppTransition();
|
||||
@TransitionFlags final int flags = appTransition.getTransitFlags();
|
||||
@TransitionType final int firstTransit = appTransition.getFirstAppTransition();
|
||||
|
||||
// Special transitions
|
||||
// TODO(new-app-transitions): Revisit if those can be rewritten by using flags.
|
||||
@@ -720,11 +745,9 @@ public class AppTransitionController {
|
||||
*/
|
||||
@Nullable
|
||||
private ActivityRecord findAnimLayoutParamsToken(@TransitionOldType int transit,
|
||||
ArraySet<Integer> activityTypes) {
|
||||
ArraySet<Integer> activityTypes, ArraySet<ActivityRecord> openingApps,
|
||||
ArraySet<ActivityRecord> closingApps, ArraySet<WindowContainer> changingApps) {
|
||||
ActivityRecord result;
|
||||
final ArraySet<ActivityRecord> closingApps = mDisplayContent.mClosingApps;
|
||||
final ArraySet<ActivityRecord> openingApps = mDisplayContent.mOpeningApps;
|
||||
final ArraySet<WindowContainer> changingApps = mDisplayContent.mChangingContainers;
|
||||
|
||||
// Remote animations always win, but fullscreen tokens override non-fullscreen tokens.
|
||||
result = lookForHighestTokenWithFilter(closingApps, openingApps, changingApps,
|
||||
@@ -1152,11 +1175,6 @@ 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",
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
package com.android.server.wm;
|
||||
|
||||
import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
|
||||
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
|
||||
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
|
||||
import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
|
||||
import static android.view.WindowManager.TRANSIT_CHANGE;
|
||||
@@ -25,6 +27,7 @@ import static android.view.WindowManager.TRANSIT_KEYGUARD_GOING_AWAY;
|
||||
import static android.view.WindowManager.TRANSIT_KEYGUARD_OCCLUDE;
|
||||
import static android.view.WindowManager.TRANSIT_KEYGUARD_UNOCCLUDE;
|
||||
import static android.view.WindowManager.TRANSIT_NONE;
|
||||
import static android.view.WindowManager.TRANSIT_OLD_ACTIVITY_OPEN;
|
||||
import static android.view.WindowManager.TRANSIT_OLD_CRASHING_ACTIVITY_CLOSE;
|
||||
import static android.view.WindowManager.TRANSIT_OLD_KEYGUARD_GOING_AWAY;
|
||||
import static android.view.WindowManager.TRANSIT_OLD_TASK_CHANGE_WINDOWING_MODE;
|
||||
@@ -409,38 +412,50 @@ public class AppTransitionTests extends WindowTestsBase {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDelayWhileRecents() {
|
||||
public void testExcludeLauncher() {
|
||||
final DisplayContent dc = createNewDisplay(Display.STATE_ON);
|
||||
doReturn(false).when(dc).onDescendantOrientationChanged(any());
|
||||
final Task task = createTask(dc);
|
||||
|
||||
// Simulate activity1 launches activity2.
|
||||
// Simulate activity1 launches activity2
|
||||
final ActivityRecord activity1 = createActivityRecord(task);
|
||||
activity1.setVisible(true);
|
||||
activity1.mVisibleRequested = false;
|
||||
activity1.allDrawn = true;
|
||||
dc.mClosingApps.add(activity1);
|
||||
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));
|
||||
|
||||
// Simulate start recents
|
||||
final ActivityRecord homeActivity = createActivityRecord(dc, WINDOWING_MODE_FULLSCREEN,
|
||||
ACTIVITY_TYPE_HOME);
|
||||
homeActivity.setVisible(false);
|
||||
homeActivity.mVisibleRequested = true;
|
||||
homeActivity.allDrawn = true;
|
||||
dc.mOpeningApps.add(homeActivity);
|
||||
dc.prepareAppTransition(TRANSIT_NONE);
|
||||
doReturn(true).when(task)
|
||||
.isSelfAnimating(anyInt(), eq(ANIMATION_TYPE_RECENTS));
|
||||
|
||||
// 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());
|
||||
verify(activity1).commitVisibility(eq(false), anyBoolean(), anyBoolean());
|
||||
verify(activity1).applyAnimation(any(), eq(TRANSIT_OLD_ACTIVITY_OPEN), eq(false),
|
||||
anyBoolean(), any());
|
||||
verify(activity2).commitVisibility(eq(true), anyBoolean(), anyBoolean());
|
||||
verify(activity2).applyAnimation(any(), eq(TRANSIT_OLD_ACTIVITY_OPEN), eq(true),
|
||||
anyBoolean(), any());
|
||||
verify(homeActivity).commitVisibility(eq(true), anyBoolean(), anyBoolean());
|
||||
verify(homeActivity, never()).applyAnimation(any(), anyInt(), anyBoolean(), anyBoolean(),
|
||||
any());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
Reference in New Issue
Block a user