Loading services/core/java/com/android/server/wm/WindowManagerService.java +26 −25 Original line number Diff line number Diff line Loading @@ -2627,27 +2627,32 @@ public class WindowManagerService extends IWindowManager.Stub transit = WindowManagerPolicy.TRANSIT_PREVIEW_DONE; } if (win.isWinVisibleLw() && win.mDisplayContent.okToAnimate()) { String reason = null; if (win.isWinVisibleLw() && winAnimator.applyAnimationLocked(transit, false)) { if (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. } else if (win.isExitAnimationRunningSelfOrParent()) { reason = "animating"; win.mAnimatingExit = true; } else if (win.mDisplayContent.okToAnimate() && win.mDisplayContent.mWallpaperController.isWallpaperTarget(win) } else if (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. // 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; } else { } 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 Loading @@ -2655,10 +2660,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); } Loading services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java +32 −0 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading @@ -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; Loading Loading @@ -173,6 +179,32 @@ public class WindowManagerServiceTests extends WindowTestsBase { verify(mWm.mAtmService.mTaskSupervisor).wakeUp(anyString()); } @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()); Loading Loading
services/core/java/com/android/server/wm/WindowManagerService.java +26 −25 Original line number Diff line number Diff line Loading @@ -2627,27 +2627,32 @@ public class WindowManagerService extends IWindowManager.Stub transit = WindowManagerPolicy.TRANSIT_PREVIEW_DONE; } if (win.isWinVisibleLw() && win.mDisplayContent.okToAnimate()) { String reason = null; if (win.isWinVisibleLw() && winAnimator.applyAnimationLocked(transit, false)) { if (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. } else if (win.isExitAnimationRunningSelfOrParent()) { reason = "animating"; win.mAnimatingExit = true; } else if (win.mDisplayContent.okToAnimate() && win.mDisplayContent.mWallpaperController.isWallpaperTarget(win) } else if (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. // 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; } else { } 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 Loading @@ -2655,10 +2660,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); } Loading
services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java +32 −0 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading @@ -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; Loading Loading @@ -173,6 +179,32 @@ public class WindowManagerServiceTests extends WindowTestsBase { verify(mWm.mAtmService.mTaskSupervisor).wakeUp(anyString()); } @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()); Loading