summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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());