summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Riddle Hsu <riddlehsu@google.com> 2022-08-12 23:17:11 -0600
committer Riddle Hsu <riddlehsu@google.com> 2022-08-16 06:46:22 +0000
commitc9ac64da54ce23cfc44e779cf63f71b0266d150c (patch)
treeed0efdd363858e429b4c728166112de8b67ffff5
parent9de781b8a4549ed0a2477959bf8c60ae47325a74 (diff)
Do not set mAnimatingExit on invisible window
With shell transition, WS#isExitAnimationRunningSelfOrParent of an activity window can be true if the display is running change transition (e.g. rotation). But there won't be a WS#onExitAnimationDone to consume the flag, because shell transition doesn't use AR#onAnimationFinished, also the activity may not be included in the transition participants. So instead of adding workaround to call WS#cleanupAnimatingExitWindow for all windows after every transition, if the window is already invisible, its surface can be directly destroyed. That would also solve some cases in legacy transition which were handled by the workaround. Fixes: 242285965 Test: WindowManagerServiceTests#testRelayoutExitingWindow Change-Id: Ifa1fd03c968710af0350439ecc3563b32d218e26
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java51
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java32
2 files changed, 58 insertions, 25 deletions
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 296390a57bcc..0f76dfe7250b 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -2614,27 +2614,32 @@ public class WindowManagerService extends IWindowManager.Stub
transit = WindowManagerPolicy.TRANSIT_PREVIEW_DONE;
}
- String reason = null;
- if (win.isWinVisibleLw() && winAnimator.applyAnimationLocked(transit, false)) {
- reason = "applyAnimation";
- focusMayChange = true;
- win.mAnimatingExit = true;
- } else if (win.mDisplayContent.okToAnimate() && win.isExitAnimationRunningSelfOrParent()) {
- // Currently in a hide animation... turn this into
- // an exit.
- win.mAnimatingExit = true;
- } else if (win.mDisplayContent.okToAnimate()
- && win.mDisplayContent.mWallpaperController.isWallpaperTarget(win)
- && win.mAttrs.type != TYPE_NOTIFICATION_SHADE) {
- reason = "isWallpaperTarget";
- // If the wallpaper is currently behind this app window, we need to change both of them
- // inside of a transaction to avoid artifacts.
- // For NotificationShade, sysui is in charge of running window animation and it updates
- // the client view visibility only after both NotificationShade and the wallpaper are
- // hidden. So we don't need to care about exit animation, but can destroy its surface
- // immediately.
- win.mAnimatingExit = true;
- } else {
+ if (win.isWinVisibleLw() && win.mDisplayContent.okToAnimate()) {
+ String reason = null;
+ if (winAnimator.applyAnimationLocked(transit, false)) {
+ reason = "applyAnimation";
+ focusMayChange = true;
+ win.mAnimatingExit = true;
+ } else if (win.isExitAnimationRunningSelfOrParent()) {
+ reason = "animating";
+ win.mAnimatingExit = true;
+ } else if (win.mDisplayContent.mWallpaperController.isWallpaperTarget(win)
+ && win.mAttrs.type != TYPE_NOTIFICATION_SHADE) {
+ reason = "isWallpaperTarget";
+ // If the wallpaper is currently behind this app window, they should be updated
+ // in a transaction to avoid artifacts.
+ // For NotificationShade, sysui is in charge of running window animation and it
+ // updates the client view visibility only after both NotificationShade and the
+ // wallpaper are hidden. So the exit animation is not needed and can destroy its
+ // surface immediately.
+ win.mAnimatingExit = true;
+ }
+ if (reason != null) {
+ ProtoLog.d(WM_DEBUG_ANIM,
+ "Set animatingExit: reason=startExitingAnimation/%s win=%s", reason, win);
+ }
+ }
+ if (!win.mAnimatingExit) {
boolean stopped = win.mActivityRecord == null || win.mActivityRecord.mAppStopped;
// We set mDestroying=true so ActivityRecord#notifyAppStopped in-to destroy surfaces
// will later actually destroy the surface if we do not do so here. Normally we leave
@@ -2642,10 +2647,6 @@ public class WindowManagerService extends IWindowManager.Stub
win.mDestroying = true;
win.destroySurface(false, stopped);
}
- if (reason != null) {
- ProtoLog.d(WM_DEBUG_ANIM, "Set animatingExit: reason=startExitingAnimation/%s win=%s",
- reason, win);
- }
if (mAccessibilityController.hasCallbacks()) {
mAccessibilityController.onWindowTransition(win, transit);
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java
index 14737e0a6f19..8adb89f3187e 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java
@@ -24,6 +24,7 @@ import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.WindowManager.LayoutParams.INVALID_WINDOW_TYPE;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG;
+import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG;
import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
@@ -43,6 +44,7 @@ import static com.android.server.wm.LetterboxConfiguration.LETTERBOX_BACKGROUND_
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
@@ -55,16 +57,20 @@ import static org.mockito.Mockito.when;
import android.content.pm.PackageManager;
import android.graphics.Rect;
import android.os.Binder;
+import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.UserHandle;
import android.platform.test.annotations.Presubmit;
+import android.util.MergedConfiguration;
import android.view.IWindowSessionCallback;
import android.view.InsetsSourceControl;
import android.view.InsetsState;
import android.view.InsetsVisibilities;
+import android.view.SurfaceControl;
import android.view.View;
import android.view.WindowManager;
+import android.window.ClientWindowFrames;
import android.window.WindowContainerToken;
import androidx.test.filters.SmallTest;
@@ -174,6 +180,32 @@ public class WindowManagerServiceTests extends WindowTestsBase {
}
@Test
+ public void testRelayoutExitingWindow() {
+ final WindowState win = createWindow(null, TYPE_BASE_APPLICATION, "appWin");
+ final WindowSurfaceController surfaceController = mock(WindowSurfaceController.class);
+ doReturn(true).when(surfaceController).hasSurface();
+ spyOn(win);
+ doReturn(true).when(win).isExitAnimationRunningSelfOrParent();
+ win.mWinAnimator.mSurfaceController = surfaceController;
+ win.mViewVisibility = View.VISIBLE;
+ win.mHasSurface = true;
+ win.mActivityRecord.mAppStopped = true;
+ win.mActivityRecord.mVisibleRequested = false;
+ win.mActivityRecord.setVisible(false);
+ mWm.mWindowMap.put(win.mClient.asBinder(), win);
+ final int w = 100;
+ final int h = 200;
+ mWm.relayoutWindow(win.mSession, win.mClient, win.mAttrs, w, h, View.GONE, 0,
+ new ClientWindowFrames(), new MergedConfiguration(), new SurfaceControl(),
+ new InsetsState(), new InsetsSourceControl[0], new Bundle());
+ // Because the window is already invisible, it doesn't need to apply exiting animation
+ // and WMS#tryStartExitingAnimation() will destroy the surface directly.
+ assertFalse(win.mAnimatingExit);
+ assertFalse(win.mHasSurface);
+ assertNull(win.mWinAnimator.mSurfaceController);
+ }
+
+ @Test
public void testMoveWindowTokenToDisplay_NullToken_DoNothing() {
mWm.moveWindowTokenToDisplay(null, mDisplayContent.getDisplayId());