Loading services/core/java/com/android/server/wm/PresentationController.java +0 −10 Original line number Diff line number Diff line Loading @@ -56,11 +56,6 @@ class PresentationController { ProtoLog.v(WmProtoLogGroups.WM_DEBUG_PRESENTATION, "Presentation added to display %d: %s", win.getDisplayId(), win); mPresentingDisplayIds.add(win.getDisplayId()); if (enablePresentationForConnectedDisplays()) { // A presentation hides all activities behind on the same display. win.mDisplayContent.ensureActivitiesVisible(/*starting=*/ null, /*notifyClients=*/ true); } win.mWmService.mDisplayManagerInternal.onPresentation(displayId, /*isShown=*/ true); } Loading @@ -76,11 +71,6 @@ class PresentationController { if (displayIdIndex != -1) { mPresentingDisplayIds.remove(displayIdIndex); } if (enablePresentationForConnectedDisplays()) { // A presentation hides all activities behind on the same display. win.mDisplayContent.ensureActivitiesVisible(/*starting=*/ null, /*notifyClients=*/ true); } win.mWmService.mDisplayManagerInternal.onPresentation(displayId, /*isShown=*/ false); } } services/core/java/com/android/server/wm/WindowManagerService.java +23 −2 Original line number Diff line number Diff line Loading @@ -157,6 +157,7 @@ import static com.android.server.wm.WindowManagerServiceDumpProto.POLICY; import static com.android.server.wm.WindowManagerServiceDumpProto.ROOT_WINDOW_CONTAINER; import static com.android.server.wm.WindowManagerServiceDumpProto.WINDOW_FRAMES_VALID; import static com.android.window.flags.Flags.enableDisplayFocusInShellTransitions; import static com.android.window.flags.Flags.enablePresentationForConnectedDisplays; import static com.android.window.flags.Flags.multiCrop; import static com.android.window.flags.Flags.setScPropertiesInClient; Loading Loading @@ -1820,9 +1821,29 @@ public class WindowManagerService extends IWindowManager.Stub final boolean hideSystemAlertWindows = shouldHideNonSystemOverlayWindow(win); win.setForceHideNonSystemOverlayWindowIfNeeded(hideSystemAlertWindows); // Only a presentation window needs a transition because its visibility affets the // lifecycle of apps below (b/390481865). if (enablePresentationForConnectedDisplays() && win.isPresentation()) { Transition transition = null; if (!win.mTransitionController.isCollecting()) { transition = win.mTransitionController.createAndStartCollecting(TRANSIT_OPEN); } win.mTransitionController.collect(win.mToken); res |= addWindowInner(win, displayPolicy, activity, displayContent, outInsetsState, outAttachedFrame, outActiveControls, client, outSizeCompatScale, attrs); // A presentation hides all activities behind on the same display. win.mDisplayContent.ensureActivitiesVisible(/*starting=*/ null, /*notifyClients=*/ true); win.mTransitionController.getCollectingTransition().setReady(win.mToken, true); if (transition != null) { win.mTransitionController.requestStartTransition(transition, null, null /* remoteTransition */, null /* displayChange */); } } else { res |= addWindowInner(win, displayPolicy, activity, displayContent, outInsetsState, outAttachedFrame, outActiveControls, client, outSizeCompatScale, attrs); } } Binder.restoreCallingIdentity(origId); Loading services/core/java/com/android/server/wm/WindowState.java +29 −10 Original line number Diff line number Diff line Loading @@ -95,6 +95,7 @@ import static android.view.WindowManager.LayoutParams.TYPE_TOAST; import static android.view.WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY; import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER; import static android.view.WindowManager.LayoutParams.isSystemAlertWindowType; import static android.view.WindowManager.TRANSIT_CLOSE; import static android.view.WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME; import static android.view.WindowManagerPolicyConstants.TYPE_LAYER_MULTIPLIER; import static android.view.WindowManagerPolicyConstants.TYPE_LAYER_OFFSET; Loading Loading @@ -182,6 +183,7 @@ import static com.android.server.wm.WindowStateProto.UNRESTRICTED_KEEP_CLEAR_ARE import static com.android.server.wm.WindowStateProto.VIEW_VISIBILITY; import static com.android.server.wm.WindowStateProto.WINDOW_CONTAINER; import static com.android.server.wm.WindowStateProto.WINDOW_FRAMES; import static com.android.window.flags.Flags.enablePresentationForConnectedDisplays; import static com.android.window.flags.Flags.surfaceTrustedOverlay; import android.annotation.CallSuper; Loading Loading @@ -2297,11 +2299,6 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP dc.updateImeInputAndControlTarget(null); } final int type = mAttrs.type; if (isPresentation()) { mWmService.mPresentationController.onPresentationRemoved(this); } // Check if window provides non decor insets before clearing its provided insets. final boolean windowProvidesDisplayDecorInsets = providesDisplayDecorInsets(); Loading Loading @@ -2442,11 +2439,33 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP } } // Only a presentation window needs a transition because its visibility affets the // lifecycle of apps below (b/390481865). if (enablePresentationForConnectedDisplays() && isPresentation()) { Transition transition = null; if (!mTransitionController.isCollecting()) { transition = mTransitionController.createAndStartCollecting(TRANSIT_CLOSE); } mTransitionController.collect(mToken); mAnimatingExit = true; mRemoveOnExit = true; mToken.setVisibleRequested(false); mWmService.mPresentationController.onPresentationRemoved(this); // A presentation hides all activities behind on the same display. mDisplayContent.ensureActivitiesVisible(/*starting=*/ null, /*notifyClients=*/ true); mTransitionController.getCollectingTransition().setReady(mToken, true); if (transition != null) { mTransitionController.requestStartTransition(transition, null, null /* remoteTransition */, null /* displayChange */); } } else { removeImmediately(); mWmService.updateFocusedWindowLocked(isFocused() ? UPDATE_FOCUS_REMOVING_FOCUS : UPDATE_FOCUS_NORMAL, true /*updateInputWindows*/); } } finally { Binder.restoreCallingIdentity(origId); } Loading services/tests/wmtests/src/com/android/server/wm/PresentationControllerTests.java +48 −5 Original line number Diff line number Diff line Loading @@ -17,14 +17,18 @@ package com.android.server.wm; import static android.view.Display.FLAG_PRESENTATION; import static android.view.WindowManager.TRANSIT_CLOSE; import static android.view.WindowManager.TRANSIT_OPEN; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; import static com.android.window.flags.Flags.FLAG_ENABLE_PRESENTATION_FOR_CONNECTED_DISPLAYS; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.eq; import android.annotation.NonNull; import android.graphics.Rect; import android.os.UserHandle; import android.os.UserManager; Loading @@ -41,6 +45,7 @@ import android.view.WindowManagerGlobal; import androidx.test.filters.SmallTest; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; Loading @@ -53,9 +58,16 @@ import org.junit.runner.RunWith; @RunWith(WindowTestRunner.class) public class PresentationControllerTests extends WindowTestsBase { TestTransitionPlayer mPlayer; @Before public void setUp() { mPlayer = registerTestTransitionPlayer(); } @EnableFlags(FLAG_ENABLE_PRESENTATION_FOR_CONNECTED_DISPLAYS) @Test public void testPresentationHidesActivitiesBehind() { public void testPresentationShowAndHide() { final DisplayInfo displayInfo = new DisplayInfo(); displayInfo.copyFrom(mDisplayInfo); displayInfo.flags = FLAG_PRESENTATION; Loading @@ -64,7 +76,6 @@ public class PresentationControllerTests extends WindowTestsBase { doReturn(dc).when(mWm.mRoot).getDisplayContentOrCreate(displayId); final ActivityRecord activity = createActivityRecord(createTask(dc)); assertTrue(activity.isVisible()); doReturn(true).when(() -> UserManager.isVisibleBackgroundUsersEnabled()); final int uid = 100000; // uid for non-system user final Session session = createTestSession(mAtm, 1234 /* pid */, uid); Loading @@ -72,16 +83,48 @@ public class PresentationControllerTests extends WindowTestsBase { doReturn(false).when(mWm.mUmInternal).isUserVisible(eq(userId), eq(displayId)); final WindowManager.LayoutParams params = new WindowManager.LayoutParams( WindowManager.LayoutParams.TYPE_PRESENTATION); final IWindow clientWindow = new TestIWindow(); // Show a Presentation window, which requests the activity to be stopped. final int result = mWm.addWindow(session, clientWindow, params, View.VISIBLE, displayId, userId, WindowInsets.Type.defaultVisible(), null, new InsetsState(), new InsetsSourceControl.Array(), new Rect(), new float[1]); assertTrue(result >= WindowManagerGlobal.ADD_OKAY); assertFalse(activity.isVisibleRequested()); assertTrue(activity.isVisible()); final WindowState window = mWm.windowForClientLocked(session, clientWindow, false); window.mHasSurface = true; final Transition addTransition = window.mTransitionController.getCollectingTransition(); assertEquals(TRANSIT_OPEN, addTransition.mType); assertTrue(addTransition.isInTransition(window)); assertTrue(addTransition.isInTransition(activity)); // Completing the transition makes the activity invisible. completeTransition(addTransition, /*abortSync=*/ true); assertFalse(activity.isVisible()); final WindowState window = mWm.windowForClientLocked(session, clientWindow, false); window.removeImmediately(); // Remove a Presentation window, which requests the activity to be resumed back. window.removeIfPossible(); final Transition removeTransition = window.mTransitionController.getCollectingTransition(); assertEquals(TRANSIT_CLOSE, removeTransition.mType); assertTrue(removeTransition.isInTransition(window)); assertTrue(removeTransition.isInTransition(activity)); assertTrue(activity.isVisibleRequested()); assertFalse(activity.isVisible()); // Completing the transition makes the activity visible. completeTransition(removeTransition, /*abortSync=*/ false); assertTrue(activity.isVisible()); } private void completeTransition(@NonNull Transition transition, boolean abortSync) { final ActionChain chain = ActionChain.testFinish(transition); if (abortSync) { // Forcefully finishing the active sync for testing purpose. mWm.mSyncEngine.abort(transition.getSyncId()); } else { transition.onTransactionReady(transition.getSyncId(), mTransaction); } transition.finishTransition(chain); } } Loading
services/core/java/com/android/server/wm/PresentationController.java +0 −10 Original line number Diff line number Diff line Loading @@ -56,11 +56,6 @@ class PresentationController { ProtoLog.v(WmProtoLogGroups.WM_DEBUG_PRESENTATION, "Presentation added to display %d: %s", win.getDisplayId(), win); mPresentingDisplayIds.add(win.getDisplayId()); if (enablePresentationForConnectedDisplays()) { // A presentation hides all activities behind on the same display. win.mDisplayContent.ensureActivitiesVisible(/*starting=*/ null, /*notifyClients=*/ true); } win.mWmService.mDisplayManagerInternal.onPresentation(displayId, /*isShown=*/ true); } Loading @@ -76,11 +71,6 @@ class PresentationController { if (displayIdIndex != -1) { mPresentingDisplayIds.remove(displayIdIndex); } if (enablePresentationForConnectedDisplays()) { // A presentation hides all activities behind on the same display. win.mDisplayContent.ensureActivitiesVisible(/*starting=*/ null, /*notifyClients=*/ true); } win.mWmService.mDisplayManagerInternal.onPresentation(displayId, /*isShown=*/ false); } }
services/core/java/com/android/server/wm/WindowManagerService.java +23 −2 Original line number Diff line number Diff line Loading @@ -157,6 +157,7 @@ import static com.android.server.wm.WindowManagerServiceDumpProto.POLICY; import static com.android.server.wm.WindowManagerServiceDumpProto.ROOT_WINDOW_CONTAINER; import static com.android.server.wm.WindowManagerServiceDumpProto.WINDOW_FRAMES_VALID; import static com.android.window.flags.Flags.enableDisplayFocusInShellTransitions; import static com.android.window.flags.Flags.enablePresentationForConnectedDisplays; import static com.android.window.flags.Flags.multiCrop; import static com.android.window.flags.Flags.setScPropertiesInClient; Loading Loading @@ -1820,9 +1821,29 @@ public class WindowManagerService extends IWindowManager.Stub final boolean hideSystemAlertWindows = shouldHideNonSystemOverlayWindow(win); win.setForceHideNonSystemOverlayWindowIfNeeded(hideSystemAlertWindows); // Only a presentation window needs a transition because its visibility affets the // lifecycle of apps below (b/390481865). if (enablePresentationForConnectedDisplays() && win.isPresentation()) { Transition transition = null; if (!win.mTransitionController.isCollecting()) { transition = win.mTransitionController.createAndStartCollecting(TRANSIT_OPEN); } win.mTransitionController.collect(win.mToken); res |= addWindowInner(win, displayPolicy, activity, displayContent, outInsetsState, outAttachedFrame, outActiveControls, client, outSizeCompatScale, attrs); // A presentation hides all activities behind on the same display. win.mDisplayContent.ensureActivitiesVisible(/*starting=*/ null, /*notifyClients=*/ true); win.mTransitionController.getCollectingTransition().setReady(win.mToken, true); if (transition != null) { win.mTransitionController.requestStartTransition(transition, null, null /* remoteTransition */, null /* displayChange */); } } else { res |= addWindowInner(win, displayPolicy, activity, displayContent, outInsetsState, outAttachedFrame, outActiveControls, client, outSizeCompatScale, attrs); } } Binder.restoreCallingIdentity(origId); Loading
services/core/java/com/android/server/wm/WindowState.java +29 −10 Original line number Diff line number Diff line Loading @@ -95,6 +95,7 @@ import static android.view.WindowManager.LayoutParams.TYPE_TOAST; import static android.view.WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY; import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER; import static android.view.WindowManager.LayoutParams.isSystemAlertWindowType; import static android.view.WindowManager.TRANSIT_CLOSE; import static android.view.WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME; import static android.view.WindowManagerPolicyConstants.TYPE_LAYER_MULTIPLIER; import static android.view.WindowManagerPolicyConstants.TYPE_LAYER_OFFSET; Loading Loading @@ -182,6 +183,7 @@ import static com.android.server.wm.WindowStateProto.UNRESTRICTED_KEEP_CLEAR_ARE import static com.android.server.wm.WindowStateProto.VIEW_VISIBILITY; import static com.android.server.wm.WindowStateProto.WINDOW_CONTAINER; import static com.android.server.wm.WindowStateProto.WINDOW_FRAMES; import static com.android.window.flags.Flags.enablePresentationForConnectedDisplays; import static com.android.window.flags.Flags.surfaceTrustedOverlay; import android.annotation.CallSuper; Loading Loading @@ -2297,11 +2299,6 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP dc.updateImeInputAndControlTarget(null); } final int type = mAttrs.type; if (isPresentation()) { mWmService.mPresentationController.onPresentationRemoved(this); } // Check if window provides non decor insets before clearing its provided insets. final boolean windowProvidesDisplayDecorInsets = providesDisplayDecorInsets(); Loading Loading @@ -2442,11 +2439,33 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP } } // Only a presentation window needs a transition because its visibility affets the // lifecycle of apps below (b/390481865). if (enablePresentationForConnectedDisplays() && isPresentation()) { Transition transition = null; if (!mTransitionController.isCollecting()) { transition = mTransitionController.createAndStartCollecting(TRANSIT_CLOSE); } mTransitionController.collect(mToken); mAnimatingExit = true; mRemoveOnExit = true; mToken.setVisibleRequested(false); mWmService.mPresentationController.onPresentationRemoved(this); // A presentation hides all activities behind on the same display. mDisplayContent.ensureActivitiesVisible(/*starting=*/ null, /*notifyClients=*/ true); mTransitionController.getCollectingTransition().setReady(mToken, true); if (transition != null) { mTransitionController.requestStartTransition(transition, null, null /* remoteTransition */, null /* displayChange */); } } else { removeImmediately(); mWmService.updateFocusedWindowLocked(isFocused() ? UPDATE_FOCUS_REMOVING_FOCUS : UPDATE_FOCUS_NORMAL, true /*updateInputWindows*/); } } finally { Binder.restoreCallingIdentity(origId); } Loading
services/tests/wmtests/src/com/android/server/wm/PresentationControllerTests.java +48 −5 Original line number Diff line number Diff line Loading @@ -17,14 +17,18 @@ package com.android.server.wm; import static android.view.Display.FLAG_PRESENTATION; import static android.view.WindowManager.TRANSIT_CLOSE; import static android.view.WindowManager.TRANSIT_OPEN; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; import static com.android.window.flags.Flags.FLAG_ENABLE_PRESENTATION_FOR_CONNECTED_DISPLAYS; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.eq; import android.annotation.NonNull; import android.graphics.Rect; import android.os.UserHandle; import android.os.UserManager; Loading @@ -41,6 +45,7 @@ import android.view.WindowManagerGlobal; import androidx.test.filters.SmallTest; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; Loading @@ -53,9 +58,16 @@ import org.junit.runner.RunWith; @RunWith(WindowTestRunner.class) public class PresentationControllerTests extends WindowTestsBase { TestTransitionPlayer mPlayer; @Before public void setUp() { mPlayer = registerTestTransitionPlayer(); } @EnableFlags(FLAG_ENABLE_PRESENTATION_FOR_CONNECTED_DISPLAYS) @Test public void testPresentationHidesActivitiesBehind() { public void testPresentationShowAndHide() { final DisplayInfo displayInfo = new DisplayInfo(); displayInfo.copyFrom(mDisplayInfo); displayInfo.flags = FLAG_PRESENTATION; Loading @@ -64,7 +76,6 @@ public class PresentationControllerTests extends WindowTestsBase { doReturn(dc).when(mWm.mRoot).getDisplayContentOrCreate(displayId); final ActivityRecord activity = createActivityRecord(createTask(dc)); assertTrue(activity.isVisible()); doReturn(true).when(() -> UserManager.isVisibleBackgroundUsersEnabled()); final int uid = 100000; // uid for non-system user final Session session = createTestSession(mAtm, 1234 /* pid */, uid); Loading @@ -72,16 +83,48 @@ public class PresentationControllerTests extends WindowTestsBase { doReturn(false).when(mWm.mUmInternal).isUserVisible(eq(userId), eq(displayId)); final WindowManager.LayoutParams params = new WindowManager.LayoutParams( WindowManager.LayoutParams.TYPE_PRESENTATION); final IWindow clientWindow = new TestIWindow(); // Show a Presentation window, which requests the activity to be stopped. final int result = mWm.addWindow(session, clientWindow, params, View.VISIBLE, displayId, userId, WindowInsets.Type.defaultVisible(), null, new InsetsState(), new InsetsSourceControl.Array(), new Rect(), new float[1]); assertTrue(result >= WindowManagerGlobal.ADD_OKAY); assertFalse(activity.isVisibleRequested()); assertTrue(activity.isVisible()); final WindowState window = mWm.windowForClientLocked(session, clientWindow, false); window.mHasSurface = true; final Transition addTransition = window.mTransitionController.getCollectingTransition(); assertEquals(TRANSIT_OPEN, addTransition.mType); assertTrue(addTransition.isInTransition(window)); assertTrue(addTransition.isInTransition(activity)); // Completing the transition makes the activity invisible. completeTransition(addTransition, /*abortSync=*/ true); assertFalse(activity.isVisible()); final WindowState window = mWm.windowForClientLocked(session, clientWindow, false); window.removeImmediately(); // Remove a Presentation window, which requests the activity to be resumed back. window.removeIfPossible(); final Transition removeTransition = window.mTransitionController.getCollectingTransition(); assertEquals(TRANSIT_CLOSE, removeTransition.mType); assertTrue(removeTransition.isInTransition(window)); assertTrue(removeTransition.isInTransition(activity)); assertTrue(activity.isVisibleRequested()); assertFalse(activity.isVisible()); // Completing the transition makes the activity visible. completeTransition(removeTransition, /*abortSync=*/ false); assertTrue(activity.isVisible()); } private void completeTransition(@NonNull Transition transition, boolean abortSync) { final ActionChain chain = ActionChain.testFinish(transition); if (abortSync) { // Forcefully finishing the active sync for testing purpose. mWm.mSyncEngine.abort(transition.getSyncId()); } else { transition.onTransactionReady(transition.getSyncId(), mTransaction); } transition.finishTransition(chain); } }