Loading services/core/java/com/android/server/wm/TaskSnapshotController.java +1 −1 Original line number Original line Diff line number Diff line Loading @@ -220,7 +220,7 @@ class TaskSnapshotController extends AbsAppSnapshotController<Task, TaskSnapshot } } final WindowState imeWindow = task.getDisplayContent().mInputMethodWindow; final WindowState imeWindow = task.getDisplayContent().mInputMethodWindow; ScreenCapture.ScreenshotHardwareBuffer imeBuffer = null; ScreenCapture.ScreenshotHardwareBuffer imeBuffer = null; if (imeWindow != null && imeWindow.isWinVisibleLw()) { if (imeWindow != null && imeWindow.isVisible()) { final Rect bounds = imeWindow.getParentFrame(); final Rect bounds = imeWindow.getParentFrame(); bounds.offsetTo(0, 0); bounds.offsetTo(0, 0); imeBuffer = ScreenCapture.captureLayersExcluding(imeWindow.getSurfaceControl(), imeBuffer = ScreenCapture.captureLayersExcluding(imeWindow.getSurfaceControl(), Loading services/core/java/com/android/server/wm/TransitionController.java +15 −0 Original line number Original line Diff line number Diff line Loading @@ -108,6 +108,12 @@ class TransitionController { */ */ private final ArrayList<Transition> mPlayingTransitions = new ArrayList<>(); private final ArrayList<Transition> mPlayingTransitions = new ArrayList<>(); /** * The windows that request to be invisible while it is in transition. After the transition * is finished and the windows are no longer animating, their surfaces will be destroyed. */ final ArrayList<WindowState> mAnimatingExitWindows = new ArrayList<>(); final Lock mRunningLock = new Lock(); final Lock mRunningLock = new Lock(); private final IBinder.DeathRecipient mTransitionPlayerDeath; private final IBinder.DeathRecipient mTransitionPlayerDeath; Loading Loading @@ -664,6 +670,15 @@ class TransitionController { mPlayingTransitions.remove(record); mPlayingTransitions.remove(record); updateRunningRemoteAnimation(record, false /* isPlaying */); updateRunningRemoteAnimation(record, false /* isPlaying */); record.finishTransition(); record.finishTransition(); for (int i = mAnimatingExitWindows.size() - 1; i >= 0; i--) { final WindowState w = mAnimatingExitWindows.get(i); if (w.mAnimatingExit && w.mHasSurface && !w.inTransition()) { w.onExitAnimationDone(); } if (!w.mAnimatingExit || !w.mHasSurface) { mAnimatingExitWindows.remove(i); } } mRunningLock.doNotifyLocked(); mRunningLock.doNotifyLocked(); // Run state-validation checks when no transitions are active anymore. // Run state-validation checks when no transitions are active anymore. if (!inTransition()) { if (!inTransition()) { Loading services/core/java/com/android/server/wm/WindowManagerService.java +20 −32 Original line number Original line Diff line number Diff line Loading @@ -2426,7 +2426,7 @@ public class WindowManagerService extends IWindowManager.Stub if (wallpaperMayMove) { if (wallpaperMayMove) { displayContent.mWallpaperController.adjustWallpaperWindows(); displayContent.mWallpaperController.adjustWallpaperWindows(); } } focusMayChange = tryStartExitingAnimation(win, winAnimator, focusMayChange); tryStartExitingAnimation(win, winAnimator); } } } } Loading Loading @@ -2611,8 +2611,7 @@ public class WindowManagerService extends IWindowManager.Stub } } } } private boolean tryStartExitingAnimation(WindowState win, WindowStateAnimator winAnimator, private void tryStartExitingAnimation(WindowState win, WindowStateAnimator winAnimator) { boolean focusMayChange) { // Try starting an animation; if there isn't one, we // Try starting an animation; if there isn't one, we // can destroy the surface right away. // can destroy the surface right away. int transit = WindowManagerPolicy.TRANSIT_EXIT; int transit = WindowManagerPolicy.TRANSIT_EXIT; Loading @@ -2620,39 +2619,30 @@ public class WindowManagerService extends IWindowManager.Stub transit = WindowManagerPolicy.TRANSIT_PREVIEW_DONE; transit = WindowManagerPolicy.TRANSIT_PREVIEW_DONE; } } if (win.isWinVisibleLw() && win.mDisplayContent.okToAnimate()) { if (win.isVisible() && win.isDisplayed() && win.mDisplayContent.okToAnimate()) { String reason = null; String reason = null; if (winAnimator.applyAnimationLocked(transit, false)) { if (winAnimator.applyAnimationLocked(transit, false)) { // This is a WMCore-driven window animation. // This is a WMCore-driven window animation. reason = "applyAnimation"; reason = "applyAnimation"; focusMayChange = true; } else if (win.isSelfAnimating(0 /* flags */, ANIMATION_TYPE_WINDOW_ANIMATION)) { win.mAnimatingExit = true; // This is already animating via a WMCore-driven window animation. } else if ( reason = "selfAnimating"; // This is already animating via a WMCore-driven window animation } else { win.isSelfAnimating(0 /* flags */, ANIMATION_TYPE_WINDOW_ANIMATION) if (win.mTransitionController.isShellTransitionsEnabled()) { // Or already animating as part of a legacy app-transition // Already animating as part of a shell-transition. Currently this only handles || win.isAnimating(PARENTS | TRANSITION, // activity window because other types should be WMCore-driven. ANIMATION_TYPE_APP_TRANSITION | ANIMATION_TYPE_RECENTS) if ((win.mActivityRecord != null && win.mActivityRecord.inTransition())) { // Or already animating as part of a shell-transition. win.mTransitionController.mAnimatingExitWindows.add(win); || (win.inTransition() reason = "inTransition"; // Filter out non-app windows since transitions don't animate those } // (but may still "wait" on them for readiness) } else if (win.isAnimating(PARENTS | TRANSITION, && (win.mActivityRecord != null || win.mIsWallpaper))) { ANIMATION_TYPE_APP_TRANSITION | ANIMATION_TYPE_RECENTS)) { // TODO(b/247005789): set mAnimatingExit somewhere in shell-transitions setup. // Already animating as part of a legacy app-transition. reason = "animating"; reason = "inLegacyTransition"; 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) { if (reason != null) { win.mAnimatingExit = true; ProtoLog.d(WM_DEBUG_ANIM, ProtoLog.d(WM_DEBUG_ANIM, "Set animatingExit: reason=startExitingAnimation/%s win=%s", reason, win); "Set animatingExit: reason=startExitingAnimation/%s win=%s", reason, win); } } Loading @@ -2668,8 +2658,6 @@ public class WindowManagerService extends IWindowManager.Stub if (mAccessibilityController.hasCallbacks()) { if (mAccessibilityController.hasCallbacks()) { mAccessibilityController.onWindowTransition(win, transit); mAccessibilityController.onWindowTransition(win, transit); } } return focusMayChange; } } private int createSurfaceControl(SurfaceControl outSurfaceControl, int result, private int createSurfaceControl(SurfaceControl outSurfaceControl, int result, Loading services/core/java/com/android/server/wm/WindowState.java +3 −13 Original line number Original line Diff line number Diff line Loading @@ -1921,16 +1921,6 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP return !isWallpaper || mToken.isVisibleRequested(); return !isWallpaper || mToken.isVisibleRequested(); } } /** * Is this window visible, ignoring its app token? It is not visible if there is no surface, * or we are in the process of running an exit animation that will remove the surface. */ // TODO: Can we consolidate this with #isVisible() or have a more appropriate name for this? boolean isWinVisibleLw() { return (mActivityRecord == null || mActivityRecord.isVisibleRequested() || mActivityRecord.isAnimating(TRANSITION | PARENTS)) && isVisible(); } /** /** * The same as isVisible(), but follows the current hidden state of the associated app token, * The same as isVisible(), but follows the current hidden state of the associated app token, * not the pending requested hidden state. * not the pending requested hidden state. Loading Loading @@ -2530,7 +2520,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP } } // If we are not currently running the exit animation, we need to see about starting one // If we are not currently running the exit animation, we need to see about starting one wasVisible = isWinVisibleLw(); wasVisible = isVisible(); if (keepVisibleDeadWindow) { if (keepVisibleDeadWindow) { ProtoLog.v(WM_DEBUG_ADD_REMOVE, ProtoLog.v(WM_DEBUG_ADD_REMOVE, Loading @@ -2556,7 +2546,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP // look weird if its orientation is changed. // look weird if its orientation is changed. && !inRelaunchingActivity(); && !inRelaunchingActivity(); if (wasVisible) { if (wasVisible && isDisplayed()) { final int transit = (!startingWindow) ? TRANSIT_EXIT : TRANSIT_PREVIEW_DONE; final int transit = (!startingWindow) ? TRANSIT_EXIT : TRANSIT_PREVIEW_DONE; // Try starting an animation. // Try starting an animation. Loading Loading @@ -3111,7 +3101,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP * interacts with it. * interacts with it. */ */ private boolean shouldKeepVisibleDeadAppWindow() { private boolean shouldKeepVisibleDeadAppWindow() { if (!isWinVisibleLw() || mActivityRecord == null || !mActivityRecord.isClientVisible()) { if (!isVisible() || mActivityRecord == null || !mActivityRecord.isClientVisible()) { // Not a visible app window or the app isn't dead. // Not a visible app window or the app isn't dead. return false; return false; } } Loading services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java +21 −10 Original line number Original line Diff line number Diff line Loading @@ -49,12 +49,12 @@ import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify; Loading Loading @@ -91,7 +91,6 @@ import com.android.compatibility.common.util.AdoptShellPermissionsRule; import org.junit.Rule; import org.junit.Rule; import org.junit.Test; import org.junit.Test; import org.junit.rules.ExpectedException; import org.junit.runner.RunWith; import org.junit.runner.RunWith; /** /** Loading @@ -103,9 +102,6 @@ import org.junit.runner.RunWith; @RunWith(WindowTestRunner.class) @RunWith(WindowTestRunner.class) public class WindowManagerServiceTests extends WindowTestsBase { public class WindowManagerServiceTests extends WindowTestsBase { @Rule public ExpectedException mExpectedException = ExpectedException.none(); @Rule @Rule public AdoptShellPermissionsRule mAdoptShellPermissionsRule = new AdoptShellPermissionsRule( public AdoptShellPermissionsRule mAdoptShellPermissionsRule = new AdoptShellPermissionsRule( InstrumentationRegistry.getInstrumentation().getUiAutomation(), InstrumentationRegistry.getInstrumentation().getUiAutomation(), Loading Loading @@ -198,16 +194,20 @@ public class WindowManagerServiceTests extends WindowTestsBase { public void testRelayoutExitingWindow() { public void testRelayoutExitingWindow() { final WindowState win = createWindow(null, TYPE_BASE_APPLICATION, "appWin"); final WindowState win = createWindow(null, TYPE_BASE_APPLICATION, "appWin"); final WindowSurfaceController surfaceController = mock(WindowSurfaceController.class); final WindowSurfaceController surfaceController = mock(WindowSurfaceController.class); doReturn(true).when(surfaceController).hasSurface(); spyOn(win); doReturn(true).when(win).isAnimationRunningSelfOrParent(); win.mWinAnimator.mSurfaceController = surfaceController; win.mWinAnimator.mSurfaceController = surfaceController; win.mWinAnimator.mDrawState = WindowStateAnimator.HAS_DRAWN; doReturn(true).when(surfaceController).hasSurface(); spyOn(win.mTransitionController); doReturn(true).when(win.mTransitionController).isShellTransitionsEnabled(); doReturn(true).when(win.mTransitionController).inTransition( eq(win.mActivityRecord)); win.mViewVisibility = View.VISIBLE; win.mViewVisibility = View.VISIBLE; win.mHasSurface = true; win.mHasSurface = true; win.mActivityRecord.mAppStopped = true; win.mActivityRecord.mAppStopped = true; win.mActivityRecord.setVisibleRequested(false); win.mActivityRecord.setVisible(false); mWm.mWindowMap.put(win.mClient.asBinder(), win); mWm.mWindowMap.put(win.mClient.asBinder(), win); spyOn(mWm.mWindowPlacerLocked); // Skip unnecessary operations of relayout. doNothing().when(mWm.mWindowPlacerLocked).performSurfacePlacement(anyBoolean()); final int w = 100; final int w = 100; final int h = 200; final int h = 200; final ClientWindowFrames outFrames = new ClientWindowFrames(); final ClientWindowFrames outFrames = new ClientWindowFrames(); Loading @@ -216,6 +216,17 @@ public class WindowManagerServiceTests extends WindowTestsBase { final InsetsState outInsetsState = new InsetsState(); final InsetsState outInsetsState = new InsetsState(); final InsetsSourceControl.Array outControls = new InsetsSourceControl.Array(); final InsetsSourceControl.Array outControls = new InsetsSourceControl.Array(); final Bundle outBundle = new Bundle(); final Bundle outBundle = new Bundle(); mWm.relayoutWindow(win.mSession, win.mClient, win.mAttrs, w, h, View.GONE, 0, 0, 0, outFrames, outConfig, outSurfaceControl, outInsetsState, outControls, outBundle); // The window is in transition, so its destruction is deferred. assertTrue(win.mAnimatingExit); assertFalse(win.mDestroying); assertTrue(win.mTransitionController.mAnimatingExitWindows.contains(win)); win.mAnimatingExit = false; win.mViewVisibility = View.VISIBLE; win.mActivityRecord.setVisibleRequested(false); win.mActivityRecord.setVisible(false); mWm.relayoutWindow(win.mSession, win.mClient, win.mAttrs, w, h, View.GONE, 0, 0, 0, mWm.relayoutWindow(win.mSession, win.mClient, win.mAttrs, w, h, View.GONE, 0, 0, 0, outFrames, outConfig, outSurfaceControl, outInsetsState, outControls, outBundle); outFrames, outConfig, outSurfaceControl, outInsetsState, outControls, outBundle); // Because the window is already invisible, it doesn't need to apply exiting animation // Because the window is already invisible, it doesn't need to apply exiting animation Loading Loading
services/core/java/com/android/server/wm/TaskSnapshotController.java +1 −1 Original line number Original line Diff line number Diff line Loading @@ -220,7 +220,7 @@ class TaskSnapshotController extends AbsAppSnapshotController<Task, TaskSnapshot } } final WindowState imeWindow = task.getDisplayContent().mInputMethodWindow; final WindowState imeWindow = task.getDisplayContent().mInputMethodWindow; ScreenCapture.ScreenshotHardwareBuffer imeBuffer = null; ScreenCapture.ScreenshotHardwareBuffer imeBuffer = null; if (imeWindow != null && imeWindow.isWinVisibleLw()) { if (imeWindow != null && imeWindow.isVisible()) { final Rect bounds = imeWindow.getParentFrame(); final Rect bounds = imeWindow.getParentFrame(); bounds.offsetTo(0, 0); bounds.offsetTo(0, 0); imeBuffer = ScreenCapture.captureLayersExcluding(imeWindow.getSurfaceControl(), imeBuffer = ScreenCapture.captureLayersExcluding(imeWindow.getSurfaceControl(), Loading
services/core/java/com/android/server/wm/TransitionController.java +15 −0 Original line number Original line Diff line number Diff line Loading @@ -108,6 +108,12 @@ class TransitionController { */ */ private final ArrayList<Transition> mPlayingTransitions = new ArrayList<>(); private final ArrayList<Transition> mPlayingTransitions = new ArrayList<>(); /** * The windows that request to be invisible while it is in transition. After the transition * is finished and the windows are no longer animating, their surfaces will be destroyed. */ final ArrayList<WindowState> mAnimatingExitWindows = new ArrayList<>(); final Lock mRunningLock = new Lock(); final Lock mRunningLock = new Lock(); private final IBinder.DeathRecipient mTransitionPlayerDeath; private final IBinder.DeathRecipient mTransitionPlayerDeath; Loading Loading @@ -664,6 +670,15 @@ class TransitionController { mPlayingTransitions.remove(record); mPlayingTransitions.remove(record); updateRunningRemoteAnimation(record, false /* isPlaying */); updateRunningRemoteAnimation(record, false /* isPlaying */); record.finishTransition(); record.finishTransition(); for (int i = mAnimatingExitWindows.size() - 1; i >= 0; i--) { final WindowState w = mAnimatingExitWindows.get(i); if (w.mAnimatingExit && w.mHasSurface && !w.inTransition()) { w.onExitAnimationDone(); } if (!w.mAnimatingExit || !w.mHasSurface) { mAnimatingExitWindows.remove(i); } } mRunningLock.doNotifyLocked(); mRunningLock.doNotifyLocked(); // Run state-validation checks when no transitions are active anymore. // Run state-validation checks when no transitions are active anymore. if (!inTransition()) { if (!inTransition()) { Loading
services/core/java/com/android/server/wm/WindowManagerService.java +20 −32 Original line number Original line Diff line number Diff line Loading @@ -2426,7 +2426,7 @@ public class WindowManagerService extends IWindowManager.Stub if (wallpaperMayMove) { if (wallpaperMayMove) { displayContent.mWallpaperController.adjustWallpaperWindows(); displayContent.mWallpaperController.adjustWallpaperWindows(); } } focusMayChange = tryStartExitingAnimation(win, winAnimator, focusMayChange); tryStartExitingAnimation(win, winAnimator); } } } } Loading Loading @@ -2611,8 +2611,7 @@ public class WindowManagerService extends IWindowManager.Stub } } } } private boolean tryStartExitingAnimation(WindowState win, WindowStateAnimator winAnimator, private void tryStartExitingAnimation(WindowState win, WindowStateAnimator winAnimator) { boolean focusMayChange) { // Try starting an animation; if there isn't one, we // Try starting an animation; if there isn't one, we // can destroy the surface right away. // can destroy the surface right away. int transit = WindowManagerPolicy.TRANSIT_EXIT; int transit = WindowManagerPolicy.TRANSIT_EXIT; Loading @@ -2620,39 +2619,30 @@ public class WindowManagerService extends IWindowManager.Stub transit = WindowManagerPolicy.TRANSIT_PREVIEW_DONE; transit = WindowManagerPolicy.TRANSIT_PREVIEW_DONE; } } if (win.isWinVisibleLw() && win.mDisplayContent.okToAnimate()) { if (win.isVisible() && win.isDisplayed() && win.mDisplayContent.okToAnimate()) { String reason = null; String reason = null; if (winAnimator.applyAnimationLocked(transit, false)) { if (winAnimator.applyAnimationLocked(transit, false)) { // This is a WMCore-driven window animation. // This is a WMCore-driven window animation. reason = "applyAnimation"; reason = "applyAnimation"; focusMayChange = true; } else if (win.isSelfAnimating(0 /* flags */, ANIMATION_TYPE_WINDOW_ANIMATION)) { win.mAnimatingExit = true; // This is already animating via a WMCore-driven window animation. } else if ( reason = "selfAnimating"; // This is already animating via a WMCore-driven window animation } else { win.isSelfAnimating(0 /* flags */, ANIMATION_TYPE_WINDOW_ANIMATION) if (win.mTransitionController.isShellTransitionsEnabled()) { // Or already animating as part of a legacy app-transition // Already animating as part of a shell-transition. Currently this only handles || win.isAnimating(PARENTS | TRANSITION, // activity window because other types should be WMCore-driven. ANIMATION_TYPE_APP_TRANSITION | ANIMATION_TYPE_RECENTS) if ((win.mActivityRecord != null && win.mActivityRecord.inTransition())) { // Or already animating as part of a shell-transition. win.mTransitionController.mAnimatingExitWindows.add(win); || (win.inTransition() reason = "inTransition"; // Filter out non-app windows since transitions don't animate those } // (but may still "wait" on them for readiness) } else if (win.isAnimating(PARENTS | TRANSITION, && (win.mActivityRecord != null || win.mIsWallpaper))) { ANIMATION_TYPE_APP_TRANSITION | ANIMATION_TYPE_RECENTS)) { // TODO(b/247005789): set mAnimatingExit somewhere in shell-transitions setup. // Already animating as part of a legacy app-transition. reason = "animating"; reason = "inLegacyTransition"; 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) { if (reason != null) { win.mAnimatingExit = true; ProtoLog.d(WM_DEBUG_ANIM, ProtoLog.d(WM_DEBUG_ANIM, "Set animatingExit: reason=startExitingAnimation/%s win=%s", reason, win); "Set animatingExit: reason=startExitingAnimation/%s win=%s", reason, win); } } Loading @@ -2668,8 +2658,6 @@ public class WindowManagerService extends IWindowManager.Stub if (mAccessibilityController.hasCallbacks()) { if (mAccessibilityController.hasCallbacks()) { mAccessibilityController.onWindowTransition(win, transit); mAccessibilityController.onWindowTransition(win, transit); } } return focusMayChange; } } private int createSurfaceControl(SurfaceControl outSurfaceControl, int result, private int createSurfaceControl(SurfaceControl outSurfaceControl, int result, Loading
services/core/java/com/android/server/wm/WindowState.java +3 −13 Original line number Original line Diff line number Diff line Loading @@ -1921,16 +1921,6 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP return !isWallpaper || mToken.isVisibleRequested(); return !isWallpaper || mToken.isVisibleRequested(); } } /** * Is this window visible, ignoring its app token? It is not visible if there is no surface, * or we are in the process of running an exit animation that will remove the surface. */ // TODO: Can we consolidate this with #isVisible() or have a more appropriate name for this? boolean isWinVisibleLw() { return (mActivityRecord == null || mActivityRecord.isVisibleRequested() || mActivityRecord.isAnimating(TRANSITION | PARENTS)) && isVisible(); } /** /** * The same as isVisible(), but follows the current hidden state of the associated app token, * The same as isVisible(), but follows the current hidden state of the associated app token, * not the pending requested hidden state. * not the pending requested hidden state. Loading Loading @@ -2530,7 +2520,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP } } // If we are not currently running the exit animation, we need to see about starting one // If we are not currently running the exit animation, we need to see about starting one wasVisible = isWinVisibleLw(); wasVisible = isVisible(); if (keepVisibleDeadWindow) { if (keepVisibleDeadWindow) { ProtoLog.v(WM_DEBUG_ADD_REMOVE, ProtoLog.v(WM_DEBUG_ADD_REMOVE, Loading @@ -2556,7 +2546,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP // look weird if its orientation is changed. // look weird if its orientation is changed. && !inRelaunchingActivity(); && !inRelaunchingActivity(); if (wasVisible) { if (wasVisible && isDisplayed()) { final int transit = (!startingWindow) ? TRANSIT_EXIT : TRANSIT_PREVIEW_DONE; final int transit = (!startingWindow) ? TRANSIT_EXIT : TRANSIT_PREVIEW_DONE; // Try starting an animation. // Try starting an animation. Loading Loading @@ -3111,7 +3101,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP * interacts with it. * interacts with it. */ */ private boolean shouldKeepVisibleDeadAppWindow() { private boolean shouldKeepVisibleDeadAppWindow() { if (!isWinVisibleLw() || mActivityRecord == null || !mActivityRecord.isClientVisible()) { if (!isVisible() || mActivityRecord == null || !mActivityRecord.isClientVisible()) { // Not a visible app window or the app isn't dead. // Not a visible app window or the app isn't dead. return false; return false; } } Loading
services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java +21 −10 Original line number Original line Diff line number Diff line Loading @@ -49,12 +49,12 @@ import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify; Loading Loading @@ -91,7 +91,6 @@ import com.android.compatibility.common.util.AdoptShellPermissionsRule; import org.junit.Rule; import org.junit.Rule; import org.junit.Test; import org.junit.Test; import org.junit.rules.ExpectedException; import org.junit.runner.RunWith; import org.junit.runner.RunWith; /** /** Loading @@ -103,9 +102,6 @@ import org.junit.runner.RunWith; @RunWith(WindowTestRunner.class) @RunWith(WindowTestRunner.class) public class WindowManagerServiceTests extends WindowTestsBase { public class WindowManagerServiceTests extends WindowTestsBase { @Rule public ExpectedException mExpectedException = ExpectedException.none(); @Rule @Rule public AdoptShellPermissionsRule mAdoptShellPermissionsRule = new AdoptShellPermissionsRule( public AdoptShellPermissionsRule mAdoptShellPermissionsRule = new AdoptShellPermissionsRule( InstrumentationRegistry.getInstrumentation().getUiAutomation(), InstrumentationRegistry.getInstrumentation().getUiAutomation(), Loading Loading @@ -198,16 +194,20 @@ public class WindowManagerServiceTests extends WindowTestsBase { public void testRelayoutExitingWindow() { public void testRelayoutExitingWindow() { final WindowState win = createWindow(null, TYPE_BASE_APPLICATION, "appWin"); final WindowState win = createWindow(null, TYPE_BASE_APPLICATION, "appWin"); final WindowSurfaceController surfaceController = mock(WindowSurfaceController.class); final WindowSurfaceController surfaceController = mock(WindowSurfaceController.class); doReturn(true).when(surfaceController).hasSurface(); spyOn(win); doReturn(true).when(win).isAnimationRunningSelfOrParent(); win.mWinAnimator.mSurfaceController = surfaceController; win.mWinAnimator.mSurfaceController = surfaceController; win.mWinAnimator.mDrawState = WindowStateAnimator.HAS_DRAWN; doReturn(true).when(surfaceController).hasSurface(); spyOn(win.mTransitionController); doReturn(true).when(win.mTransitionController).isShellTransitionsEnabled(); doReturn(true).when(win.mTransitionController).inTransition( eq(win.mActivityRecord)); win.mViewVisibility = View.VISIBLE; win.mViewVisibility = View.VISIBLE; win.mHasSurface = true; win.mHasSurface = true; win.mActivityRecord.mAppStopped = true; win.mActivityRecord.mAppStopped = true; win.mActivityRecord.setVisibleRequested(false); win.mActivityRecord.setVisible(false); mWm.mWindowMap.put(win.mClient.asBinder(), win); mWm.mWindowMap.put(win.mClient.asBinder(), win); spyOn(mWm.mWindowPlacerLocked); // Skip unnecessary operations of relayout. doNothing().when(mWm.mWindowPlacerLocked).performSurfacePlacement(anyBoolean()); final int w = 100; final int w = 100; final int h = 200; final int h = 200; final ClientWindowFrames outFrames = new ClientWindowFrames(); final ClientWindowFrames outFrames = new ClientWindowFrames(); Loading @@ -216,6 +216,17 @@ public class WindowManagerServiceTests extends WindowTestsBase { final InsetsState outInsetsState = new InsetsState(); final InsetsState outInsetsState = new InsetsState(); final InsetsSourceControl.Array outControls = new InsetsSourceControl.Array(); final InsetsSourceControl.Array outControls = new InsetsSourceControl.Array(); final Bundle outBundle = new Bundle(); final Bundle outBundle = new Bundle(); mWm.relayoutWindow(win.mSession, win.mClient, win.mAttrs, w, h, View.GONE, 0, 0, 0, outFrames, outConfig, outSurfaceControl, outInsetsState, outControls, outBundle); // The window is in transition, so its destruction is deferred. assertTrue(win.mAnimatingExit); assertFalse(win.mDestroying); assertTrue(win.mTransitionController.mAnimatingExitWindows.contains(win)); win.mAnimatingExit = false; win.mViewVisibility = View.VISIBLE; win.mActivityRecord.setVisibleRequested(false); win.mActivityRecord.setVisible(false); mWm.relayoutWindow(win.mSession, win.mClient, win.mAttrs, w, h, View.GONE, 0, 0, 0, mWm.relayoutWindow(win.mSession, win.mClient, win.mAttrs, w, h, View.GONE, 0, 0, 0, outFrames, outConfig, outSurfaceControl, outInsetsState, outControls, outBundle); outFrames, outConfig, outSurfaceControl, outInsetsState, outControls, outBundle); // Because the window is already invisible, it doesn't need to apply exiting animation // Because the window is already invisible, it doesn't need to apply exiting animation Loading