summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Issei Suzuki <issei@google.com> 2022-04-27 15:37:03 +0000
committer Issei Suzuki <issei@google.com> 2022-11-02 12:53:29 +0000
commit67db8072d322e64f8e372636a864016b2d4913f4 (patch)
tree61e783635762bf08f4ee9e39992af371f4c57919
parent1bbb6923934b1e2bb4869e35a6bf7e4a0b16afa0 (diff)
Suppress app transition while recents is running
This fixes conflict between app transition and recents animation in the following scenario. 1) App transition animation finishes after app closing animation, which is controlled by recents, finishes. During the app closing animation, recents makes the closing app surface invisible, but app transition animation overrides it to visible again. This causes a flicker. 2) App transition starts during recents animation. When a user launches an activity, and immediately after that, swipes up the screen to close the app. Or a user launches an ChooserActivity on top of other activity, and swipes up to move back to home. While recents is running, we assume animation on tasks is controlled by recents, and visibility is commited without animation after recents animation finishes. However starting app transition during recents breaks this assumption, which ends up with playing one more unexpected closing animation (so users see closing animation twice). This change also obsolute the logic which exludes launcher activity from app transition while recents animation is running, since app transition is delayed until recents animation finishes. Bug: 223499269 Bug: 231669960 Bug: 232060413 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. Launch photo app. 2. Take screenshot. 3. Hit share icon to share the screenshot. 4. Swipe up from the bottom. 5. Verify photo app closes. Change-Id: I264b0daf1118b75fae481f0251ed50b556f27c5f
-rw-r--r--data/etc/services.core.protolog.json18
-rw-r--r--services/core/java/com/android/server/wm/AppTransitionController.java57
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java37
3 files changed, 42 insertions, 70 deletions
diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json
index 31e2abe0bb85..f047905f18b6 100644
--- a/data/etc/services.core.protolog.json
+++ b/data/etc/services.core.protolog.json
@@ -1921,6 +1921,12 @@
"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",
@@ -2023,12 +2029,6 @@
"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",
@@ -2569,6 +2569,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 9c95e31cc5f5..29b64171692a 100644
--- a/services/core/java/com/android/server/wm/AppTransitionController.java
+++ b/services/core/java/com/android/server/wm/AppTransitionController.java
@@ -80,7 +80,6 @@ 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.graphics.Rect;
import android.os.Trace;
@@ -172,16 +171,6 @@ 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.
*/
@@ -231,45 +220,32 @@ public class AppTransitionController {
mWallpaperControllerLocked.adjustWallpaperWindowsForAppTransitionIfNeeded(
mDisplayContent.mOpeningApps);
- // 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,
+ mDisplayContent.mAppTransition, mDisplayContent.mOpeningApps,
+ mDisplayContent.mClosingApps, mDisplayContent.mChangingContainers,
mWallpaperControllerLocked.getWallpaperTarget(), getOldWallpaper(),
mDisplayContent.mSkipAppTransitionAnimation);
mDisplayContent.mSkipAppTransitionAnimation = false;
ProtoLog.v(WM_DEBUG_APP_TRANSITIONS,
"handleAppTransitionReady: displayId=%d appTransition={%s}"
- + " excludeLauncherFromAnimation=%b openingApps=[%s] closingApps=[%s] transit=%s",
- mDisplayContent.mDisplayId, appTransition.toString(), excludeLauncherFromAnimation,
- mDisplayContent.mOpeningApps, mDisplayContent.mClosingApps,
- AppTransition.appTransitionOldToString(transit));
+ + " openingApps=[%s] closingApps=[%s] transit=%s",
+ mDisplayContent.mDisplayId, appTransition.toString(), mDisplayContent.mOpeningApps,
+ mDisplayContent.mClosingApps, AppTransition.appTransitionOldToString(transit));
// Find the layout params of the top-most application window in the tokens, which is
// 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(openingAppsForAnimation,
- closingAppsForAnimation, mDisplayContent.mChangingContainers);
+ final ArraySet<Integer> activityTypes = collectActivityTypes(mDisplayContent.mOpeningApps,
+ mDisplayContent.mClosingApps, mDisplayContent.mChangingContainers);
final ActivityRecord animLpActivity = findAnimLayoutParamsToken(transit, activityTypes,
- openingAppsForAnimation, closingAppsForAnimation,
+ mDisplayContent.mOpeningApps, mDisplayContent.mClosingApps,
mDisplayContent.mChangingContainers);
final ActivityRecord topOpeningApp =
- getTopApp(openingAppsForAnimation, false /* ignoreHidden */);
+ getTopApp(mDisplayContent.mOpeningApps, false /* ignoreHidden */);
final ActivityRecord topClosingApp =
- getTopApp(closingAppsForAnimation, false /* ignoreHidden */);
+ getTopApp(mDisplayContent.mClosingApps, false /* ignoreHidden */);
final ActivityRecord topChangingApp =
getTopApp(mDisplayContent.mChangingContainers, false /* ignoreHidden */);
final WindowManager.LayoutParams animLp = getAnimLp(animLpActivity);
@@ -281,14 +257,14 @@ public class AppTransitionController {
overrideWithRemoteAnimationIfSet(animLpActivity, transit, activityTypes);
}
- final boolean voiceInteraction = containsVoiceInteraction(closingAppsForAnimation)
- || containsVoiceInteraction(openingAppsForAnimation);
+ final boolean voiceInteraction = containsVoiceInteraction(mDisplayContent.mClosingApps)
+ || containsVoiceInteraction(mDisplayContent.mOpeningApps);
final int layoutRedo;
mService.mSurfaceAnimationRunner.deferStartingAnimations();
try {
- applyAnimations(openingAppsForAnimation, closingAppsForAnimation, transit, animLp,
- voiceInteraction);
+ applyAnimations(mDisplayContent.mOpeningApps, mDisplayContent.mClosingApps, transit,
+ animLp, voiceInteraction);
handleClosingApps();
handleOpeningApps();
handleChangingApps(transit);
@@ -1226,6 +1202,11 @@ 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",
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 f61effa284ef..b80d9495afeb 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java
@@ -16,8 +16,6 @@
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;
@@ -27,7 +25,6 @@ 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;
@@ -412,50 +409,38 @@ public class AppTransitionTests extends WindowTestsBase {
}
@Test
- public void testExcludeLauncher() {
+ 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
+ // 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);
-
- // 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));
+ 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).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());
+ verify(activity1, never()).commitVisibility(anyBoolean(), anyBoolean(), anyBoolean());
+ verify(activity2, never()).commitVisibility(anyBoolean(), anyBoolean(), anyBoolean());
}
@Test