Loading services/core/java/com/android/server/wm/DeferredDisplayUpdater.java +44 −1 Original line number Diff line number Diff line Loading @@ -23,6 +23,7 @@ import static com.android.internal.protolog.WmProtoLogGroups.WM_DEBUG_WINDOW_TRA import static com.android.server.wm.ActivityTaskManagerService.POWER_MODE_REASON_CHANGE_DISPLAY; import static com.android.server.wm.utils.DisplayInfoOverrides.WM_OVERRIDE_FIELDS; import static com.android.server.wm.utils.DisplayInfoOverrides.copyDisplayInfoFields; import static com.android.window.flags.Flags.ensureWallpaperDrawnOnDisplaySwitch; import android.annotation.NonNull; import android.annotation.Nullable; Loading @@ -38,9 +39,12 @@ import android.window.WindowContainerTransaction; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.display.BrightnessSynchronizer; import com.android.internal.protolog.ProtoLog; import com.android.server.wm.Transition.ReadyCondition; import com.android.server.wm.utils.DisplayInfoOverrides.DisplayInfoFieldsUpdater; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Objects; /** Loading Loading @@ -76,6 +80,8 @@ class DeferredDisplayUpdater { "Screen unblock: wait for transition"; private static final int WAIT_FOR_TRANSITION_TIMEOUT = 1000; private static final String READY_CONDITION_KEYGUARD_DRAWN = "keyguard_drawn"; private final DisplayContent mDisplayContent; @NonNull Loading Loading @@ -104,6 +110,12 @@ class DeferredDisplayUpdater { private boolean mInPhysicalDisplayChangeTransition; /** True if we are waiting for the IKeyguardDrawnCallback which will eventually invoke * {@link DeferredDisplayUpdater#waitForTransition(Message)}} */ private boolean mPendingKeyguardDrawing; private final List<ReadyCondition> mWaitingForKeyguardDrawnConditions = new ArrayList<>(); /** The message to notify PhoneWindowManager#finishWindowsDrawn. */ @Nullable private Message mScreenUnblocker; Loading Loading @@ -298,6 +310,14 @@ class DeferredDisplayUpdater { mDisplayContent.mTransitionController.requestStartTransition(transition, /* startTask= */ null, /* remoteTransition= */ null, displayChange); if (mPendingKeyguardDrawing && ensureWallpaperDrawnOnDisplaySwitch()) { // Keyguard hasn't reported that it has drawn yet, defer readiness until it draws final ReadyCondition condition = new ReadyCondition(READY_CONDITION_KEYGUARD_DRAWN, /* newTrackerOnly= */ false); transition.mReadyTracker.add(condition); mWaitingForKeyguardDrawnConditions.add(condition); } final DisplayAreaInfo newDisplayAreaInfo = mDisplayContent.getDisplayAreaInfo(); final boolean startedRemoteChange = mDisplayContent.mRemoteDisplayChangeController Loading @@ -315,8 +335,12 @@ class DeferredDisplayUpdater { mDisplayContent.mAtmService.mWindowOrganizerController.applyTransaction( wct); } if (ensureWallpaperDrawnOnDisplaySwitch()) { transition.setReady(mDisplayContent, /* ready= */ true); } else { transition.setAllReady(); } } private boolean isPhysicalDisplayUpdated(@Nullable DisplayInfo first, @Nullable DisplayInfo second) { Loading Loading @@ -346,6 +370,13 @@ class DeferredDisplayUpdater { */ void onDisplaySwitching(boolean switching) { mShouldWaitForTransitionWhenScreenOn = switching; mPendingKeyguardDrawing = switching; if (!switching) { // Reset keyguard drawn in case for some reason we haven't received the callback // and the screen is already fully switched on here onKeyguardDrawn(); } } /** Loading @@ -359,6 +390,10 @@ class DeferredDisplayUpdater { /** Returns {@code true} if the transition will control when to turn on the screen. */ boolean waitForTransition(@NonNull Message screenUnblocker) { // waitForTransition() is called by PhoneWindowManager after receiving keyguard // drawn callback, so mark keyguard as drawn onKeyguardDrawn(); if (!mShouldWaitForTransitionWhenScreenOn) { return false; } Loading @@ -373,6 +408,14 @@ class DeferredDisplayUpdater { return true; } private void onKeyguardDrawn() { mPendingKeyguardDrawing = false; for (int i = 0; i < mWaitingForKeyguardDrawnConditions.size(); i++) { mWaitingForKeyguardDrawnConditions.get(i).meet(); } mWaitingForKeyguardDrawnConditions.clear(); } /** * Continues the screen unblocking flow, could be called either on a binder thread as * a result of surface transaction presented listener or from {@link WindowManagerService#mH} Loading services/tests/wmtests/src/com/android/server/wm/DisplayContentDeferredUpdateTests.java +176 −6 Original line number Diff line number Diff line Loading @@ -37,12 +37,16 @@ import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.when; import android.os.Message; import android.platform.test.annotations.DisableFlags; import android.platform.test.annotations.EnableFlags; import android.platform.test.annotations.Presubmit; import android.view.DisplayInfo; import android.window.ITransitionPlayer; import androidx.test.filters.SmallTest; import com.android.server.LocalServices; import com.android.server.wm.RemoteDisplayChangeController.ContinueRemoteDisplayChangeCallback; import com.android.server.wm.TransitionController.OnStartCollect; import org.junit.Before; Loading @@ -69,6 +73,8 @@ public class DisplayContentDeferredUpdateTests extends WindowTestsBase { private DisplayContent mSecondaryDisplayContent; private final BLASTSyncEngine mSyncEngine = mock(BLASTSyncEngine.class); private final Message mScreenUnblocker = mock(Message.class); private final Message mSecondaryScreenUnblocker = mock(Message.class); Loading @@ -81,7 +87,7 @@ public class DisplayContentDeferredUpdateTests extends WindowTestsBase { mockTransitionsController(); mockRemoteDisplayChangeController(mDisplayContent); mockRemoteDisplayChangeController(mDisplayContent, /* finishImmediately= */ true); performInitialDisplayUpdate(mDisplayContent); mWmInternal = LocalServices.getService(WindowManagerInternal.class); Loading Loading @@ -184,6 +190,129 @@ public class DisplayContentDeferredUpdateTests extends WindowTestsBase { assertThat(mDisplayContent.getDisplayInfo().uniqueId).isEqualTo("old"); } @Test public void testDisplaySwitching_remoteDisplayChangePending_transitionIsNotReady() { performPhysicalDisplaySwitch(); startCollectingTheLastTransition(); // Transition should not be ready as there is a pending remote display change final Transition transition = captureRequestedTransition().getValue(); assertThat(transition.allReady()).isFalse(); } @Test @DisableFlags(com.android.window.flags.Flags.FLAG_ENSURE_WALLPAPER_DRAWN_ON_DISPLAY_SWITCH) public void testDisplaySwitching_wallpaperFlagDisabled_remoteDisplayChangeFinished_transitionIsReady() { performPhysicalDisplaySwitch(); startCollectingTheLastTransition(); finishRemoteDisplayChange(mDisplayContent); // Transition should be ready as remote display change is completed final Transition transition = captureRequestedTransition().getValue(); assertThat(transition.allReady()).isTrue(); } @Test @EnableFlags(com.android.window.flags.Flags.FLAG_ENSURE_WALLPAPER_DRAWN_ON_DISPLAY_SWITCH) public void testDisplaySwitching_remoteDisplayChangeFinished_transitionIsNotReady() { performPhysicalDisplaySwitch(); startCollectingTheLastTransition(); finishRemoteDisplayChange(mDisplayContent); // Transition should not be ready as keyguard is not drawn yet final Transition transition = captureRequestedTransition().getValue(); assertThat(transition.allReady()).isFalse(); } @Test @EnableFlags(com.android.window.flags.Flags.FLAG_ENSURE_WALLPAPER_DRAWN_ON_DISPLAY_SWITCH) public void testDisplaySwitching_keyguardDrawn_transitionIsNotReady() { performPhysicalDisplaySwitch(); startCollectingTheLastTransition(); signalKeyguardIsDrawn(); // Transition should not be ready as remote display change is not finished final Transition transition = captureRequestedTransition().getValue(); assertThat(transition.allReady()).isFalse(); } @Test @EnableFlags(com.android.window.flags.Flags.FLAG_ENSURE_WALLPAPER_DRAWN_ON_DISPLAY_SWITCH) public void testDisplaySwitching_remoteDisplayChangeFinishedThenKeyguardDrawn_transitionIsReady() { performPhysicalDisplaySwitch(); startCollectingTheLastTransition(); finishRemoteDisplayChange(mDisplayContent); signalKeyguardIsDrawn(); // Transition should be ready as both remote display change // and keyguard drawing are completed final Transition transition = captureRequestedTransition().getValue(); assertThat(transition.allReady()).isTrue(); } @Test @EnableFlags(com.android.window.flags.Flags.FLAG_ENSURE_WALLPAPER_DRAWN_ON_DISPLAY_SWITCH) public void testDisplaySwitching_keyguardDrawnThenRemoteDisplayChangeFinished_transitionIsReady() { performPhysicalDisplaySwitch(); startCollectingTheLastTransition(); signalKeyguardIsDrawn(); finishRemoteDisplayChange(mDisplayContent); // Transition should be ready as both remote display change // and keyguard drawing are completed final Transition transition = captureRequestedTransition().getValue(); assertThat(transition.allReady()).isTrue(); } @Test @EnableFlags(com.android.window.flags.Flags.FLAG_ENSURE_WALLPAPER_DRAWN_ON_DISPLAY_SWITCH) public void testDisplaySwitching_keyguardDrawnBeforeTransitionThenRemoteDisplayChangeFinished_transitionIsReady() { performPhysicalDisplaySwitch(); signalKeyguardIsDrawn(); startCollectingTheLastTransition(); finishRemoteDisplayChange(mDisplayContent); // Transition should be ready as both remote display change // and keyguard drawing are completed final Transition transition = captureRequestedTransition().getValue(); assertThat(transition.allReady()).isTrue(); } @Test @EnableFlags(com.android.window.flags.Flags.FLAG_ENSURE_WALLPAPER_DRAWN_ON_DISPLAY_SWITCH) public void testDisplaySwitching_keyguardWasNotDrawn_secondSwitchingIsNormal_transitionIsReady() { performPhysicalDisplaySwitch(); startCollectingTheLastTransition(); finishRemoteDisplayChange(mDisplayContent); mDisplayContent.mDisplayUpdater.onDisplaySwitching(/* switching= */ false); // Here we finished remote display change & display switching, but keyguard drawn callback // was not invoked. Let's verify that we still handle the next display change correctly. clearInvocations(mDisplayContent.mRemoteDisplayChangeController); mockRemoteDisplayChangeController(mDisplayContent, /* finishImmediately= */ false); mDisplayContent.mDisplayUpdater.onDisplaySwitching(/* switching= */ true); mUniqueId = "new2"; mDisplayContent.requestDisplayUpdate(mock(Runnable.class)); startCollectingTheLastTransition(); signalKeyguardIsDrawn(); finishRemoteDisplayChange(mDisplayContent); // Transition should be ready as both remote display change // and keyguard drawing are completed final Transition transition = captureRequestedTransition().getValue(); assertThat(transition.allReady()).isTrue(); } @Test public void testTwoDisplayUpdates_transitionStarted_displayUpdated() { mUniqueId = "old"; Loading Loading @@ -319,26 +448,44 @@ public class DisplayContentDeferredUpdateTests extends WindowTestsBase { mSecondaryDisplayContent = createNewDisplay(); when(mSecondaryScreenUnblocker.getTarget()).thenReturn(mWm.mH); doReturn(true).when(mSecondaryDisplayContent).getLastHasContent(); mockRemoteDisplayChangeController(mSecondaryDisplayContent); mockRemoteDisplayChangeController(mSecondaryDisplayContent, /* finishImmediately= */ true); performInitialDisplayUpdate(mSecondaryDisplayContent); } private void mockTransitionsController() { spyOn(mDisplayContent.mTransitionController); mDisplayContent.mTransitionController.setSyncEngine(mSyncEngine); when(mDisplayContent.mTransitionController.isShellTransitionsEnabled()) .thenReturn(true); doReturn(mock(Transition.class)).when(mDisplayContent.mTransitionController) .createTransition(anyInt(), anyInt()); final ITransitionPlayer player = new ITransitionPlayer.Default(); mDisplayContent.mTransitionController.registerTransitionPlayer(player, /* playerProc= */ null); doReturn(true).when(mDisplayContent.mTransitionController) .startCollectOrQueue(any(), any()); } private void mockRemoteDisplayChangeController(DisplayContent displayContent) { private void mockRemoteDisplayChangeController(DisplayContent displayContent, boolean finishImmediately) { spyOn(displayContent.mRemoteDisplayChangeController); doReturn(true).when(displayContent.mRemoteDisplayChangeController) doAnswer(invocation -> { if (finishImmediately) { final ContinueRemoteDisplayChangeCallback callback = invocation.getArgument(invocation.getArguments().length - 1); callback.onContinueRemoteDisplayChange(null); } return true; }).when(displayContent.mRemoteDisplayChangeController) .performRemoteDisplayChange(anyInt(), anyInt(), any(), any()); } private void finishRemoteDisplayChange(DisplayContent displayContent) { ArgumentCaptor<ContinueRemoteDisplayChangeCallback> callbackCaptor = ArgumentCaptor.forClass(ContinueRemoteDisplayChangeCallback.class); verify(displayContent.mRemoteDisplayChangeController) .performRemoteDisplayChange(anyInt(), anyInt(), any(), callbackCaptor.capture()); callbackCaptor.getValue().onContinueRemoteDisplayChange(null); } private ArgumentCaptor<OnStartCollect> captureStartTransitionCollection() { ArgumentCaptor<OnStartCollect> callbackCaptor = ArgumentCaptor.forClass(OnStartCollect.class); Loading @@ -364,6 +511,29 @@ public class DisplayContentDeferredUpdateTests extends WindowTestsBase { } } private void performPhysicalDisplaySwitch() { mockRemoteDisplayChangeController(mDisplayContent, /* finishImmediately= */ false); mDisplayContent.mDisplayUpdater.onDisplaySwitching(/* switching= */ true); mUniqueId = "new"; mDisplayContent.requestDisplayUpdate(mock(Runnable.class)); } private void signalKeyguardIsDrawn() { // waitForTransition call signals that keyguard is drawn mDisplayContent.mDisplayUpdater.waitForTransition(mScreenUnblocker); } private void startCollectingTheLastTransition() { ArgumentCaptor<OnStartCollect> callbackCaptor = ArgumentCaptor.forClass(OnStartCollect.class); ArgumentCaptor<Transition> transitionCaptor = ArgumentCaptor.forClass(Transition.class); verify(mDisplayContent.mTransitionController, atLeast(1)) .startCollectOrQueue(transitionCaptor.capture(), callbackCaptor.capture()); transitionCaptor.getValue().startCollecting(/* timeoutMs= */ 0); captureStartTransitionCollection().getValue().onCollectStarted(/* deferred= */ true); } private void performInitialDisplayUpdate(DisplayContent displayContent) { mColorMode = 0; mLogicalDensityDpi = 400; Loading Loading
services/core/java/com/android/server/wm/DeferredDisplayUpdater.java +44 −1 Original line number Diff line number Diff line Loading @@ -23,6 +23,7 @@ import static com.android.internal.protolog.WmProtoLogGroups.WM_DEBUG_WINDOW_TRA import static com.android.server.wm.ActivityTaskManagerService.POWER_MODE_REASON_CHANGE_DISPLAY; import static com.android.server.wm.utils.DisplayInfoOverrides.WM_OVERRIDE_FIELDS; import static com.android.server.wm.utils.DisplayInfoOverrides.copyDisplayInfoFields; import static com.android.window.flags.Flags.ensureWallpaperDrawnOnDisplaySwitch; import android.annotation.NonNull; import android.annotation.Nullable; Loading @@ -38,9 +39,12 @@ import android.window.WindowContainerTransaction; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.display.BrightnessSynchronizer; import com.android.internal.protolog.ProtoLog; import com.android.server.wm.Transition.ReadyCondition; import com.android.server.wm.utils.DisplayInfoOverrides.DisplayInfoFieldsUpdater; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Objects; /** Loading Loading @@ -76,6 +80,8 @@ class DeferredDisplayUpdater { "Screen unblock: wait for transition"; private static final int WAIT_FOR_TRANSITION_TIMEOUT = 1000; private static final String READY_CONDITION_KEYGUARD_DRAWN = "keyguard_drawn"; private final DisplayContent mDisplayContent; @NonNull Loading Loading @@ -104,6 +110,12 @@ class DeferredDisplayUpdater { private boolean mInPhysicalDisplayChangeTransition; /** True if we are waiting for the IKeyguardDrawnCallback which will eventually invoke * {@link DeferredDisplayUpdater#waitForTransition(Message)}} */ private boolean mPendingKeyguardDrawing; private final List<ReadyCondition> mWaitingForKeyguardDrawnConditions = new ArrayList<>(); /** The message to notify PhoneWindowManager#finishWindowsDrawn. */ @Nullable private Message mScreenUnblocker; Loading Loading @@ -298,6 +310,14 @@ class DeferredDisplayUpdater { mDisplayContent.mTransitionController.requestStartTransition(transition, /* startTask= */ null, /* remoteTransition= */ null, displayChange); if (mPendingKeyguardDrawing && ensureWallpaperDrawnOnDisplaySwitch()) { // Keyguard hasn't reported that it has drawn yet, defer readiness until it draws final ReadyCondition condition = new ReadyCondition(READY_CONDITION_KEYGUARD_DRAWN, /* newTrackerOnly= */ false); transition.mReadyTracker.add(condition); mWaitingForKeyguardDrawnConditions.add(condition); } final DisplayAreaInfo newDisplayAreaInfo = mDisplayContent.getDisplayAreaInfo(); final boolean startedRemoteChange = mDisplayContent.mRemoteDisplayChangeController Loading @@ -315,8 +335,12 @@ class DeferredDisplayUpdater { mDisplayContent.mAtmService.mWindowOrganizerController.applyTransaction( wct); } if (ensureWallpaperDrawnOnDisplaySwitch()) { transition.setReady(mDisplayContent, /* ready= */ true); } else { transition.setAllReady(); } } private boolean isPhysicalDisplayUpdated(@Nullable DisplayInfo first, @Nullable DisplayInfo second) { Loading Loading @@ -346,6 +370,13 @@ class DeferredDisplayUpdater { */ void onDisplaySwitching(boolean switching) { mShouldWaitForTransitionWhenScreenOn = switching; mPendingKeyguardDrawing = switching; if (!switching) { // Reset keyguard drawn in case for some reason we haven't received the callback // and the screen is already fully switched on here onKeyguardDrawn(); } } /** Loading @@ -359,6 +390,10 @@ class DeferredDisplayUpdater { /** Returns {@code true} if the transition will control when to turn on the screen. */ boolean waitForTransition(@NonNull Message screenUnblocker) { // waitForTransition() is called by PhoneWindowManager after receiving keyguard // drawn callback, so mark keyguard as drawn onKeyguardDrawn(); if (!mShouldWaitForTransitionWhenScreenOn) { return false; } Loading @@ -373,6 +408,14 @@ class DeferredDisplayUpdater { return true; } private void onKeyguardDrawn() { mPendingKeyguardDrawing = false; for (int i = 0; i < mWaitingForKeyguardDrawnConditions.size(); i++) { mWaitingForKeyguardDrawnConditions.get(i).meet(); } mWaitingForKeyguardDrawnConditions.clear(); } /** * Continues the screen unblocking flow, could be called either on a binder thread as * a result of surface transaction presented listener or from {@link WindowManagerService#mH} Loading
services/tests/wmtests/src/com/android/server/wm/DisplayContentDeferredUpdateTests.java +176 −6 Original line number Diff line number Diff line Loading @@ -37,12 +37,16 @@ import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.when; import android.os.Message; import android.platform.test.annotations.DisableFlags; import android.platform.test.annotations.EnableFlags; import android.platform.test.annotations.Presubmit; import android.view.DisplayInfo; import android.window.ITransitionPlayer; import androidx.test.filters.SmallTest; import com.android.server.LocalServices; import com.android.server.wm.RemoteDisplayChangeController.ContinueRemoteDisplayChangeCallback; import com.android.server.wm.TransitionController.OnStartCollect; import org.junit.Before; Loading @@ -69,6 +73,8 @@ public class DisplayContentDeferredUpdateTests extends WindowTestsBase { private DisplayContent mSecondaryDisplayContent; private final BLASTSyncEngine mSyncEngine = mock(BLASTSyncEngine.class); private final Message mScreenUnblocker = mock(Message.class); private final Message mSecondaryScreenUnblocker = mock(Message.class); Loading @@ -81,7 +87,7 @@ public class DisplayContentDeferredUpdateTests extends WindowTestsBase { mockTransitionsController(); mockRemoteDisplayChangeController(mDisplayContent); mockRemoteDisplayChangeController(mDisplayContent, /* finishImmediately= */ true); performInitialDisplayUpdate(mDisplayContent); mWmInternal = LocalServices.getService(WindowManagerInternal.class); Loading Loading @@ -184,6 +190,129 @@ public class DisplayContentDeferredUpdateTests extends WindowTestsBase { assertThat(mDisplayContent.getDisplayInfo().uniqueId).isEqualTo("old"); } @Test public void testDisplaySwitching_remoteDisplayChangePending_transitionIsNotReady() { performPhysicalDisplaySwitch(); startCollectingTheLastTransition(); // Transition should not be ready as there is a pending remote display change final Transition transition = captureRequestedTransition().getValue(); assertThat(transition.allReady()).isFalse(); } @Test @DisableFlags(com.android.window.flags.Flags.FLAG_ENSURE_WALLPAPER_DRAWN_ON_DISPLAY_SWITCH) public void testDisplaySwitching_wallpaperFlagDisabled_remoteDisplayChangeFinished_transitionIsReady() { performPhysicalDisplaySwitch(); startCollectingTheLastTransition(); finishRemoteDisplayChange(mDisplayContent); // Transition should be ready as remote display change is completed final Transition transition = captureRequestedTransition().getValue(); assertThat(transition.allReady()).isTrue(); } @Test @EnableFlags(com.android.window.flags.Flags.FLAG_ENSURE_WALLPAPER_DRAWN_ON_DISPLAY_SWITCH) public void testDisplaySwitching_remoteDisplayChangeFinished_transitionIsNotReady() { performPhysicalDisplaySwitch(); startCollectingTheLastTransition(); finishRemoteDisplayChange(mDisplayContent); // Transition should not be ready as keyguard is not drawn yet final Transition transition = captureRequestedTransition().getValue(); assertThat(transition.allReady()).isFalse(); } @Test @EnableFlags(com.android.window.flags.Flags.FLAG_ENSURE_WALLPAPER_DRAWN_ON_DISPLAY_SWITCH) public void testDisplaySwitching_keyguardDrawn_transitionIsNotReady() { performPhysicalDisplaySwitch(); startCollectingTheLastTransition(); signalKeyguardIsDrawn(); // Transition should not be ready as remote display change is not finished final Transition transition = captureRequestedTransition().getValue(); assertThat(transition.allReady()).isFalse(); } @Test @EnableFlags(com.android.window.flags.Flags.FLAG_ENSURE_WALLPAPER_DRAWN_ON_DISPLAY_SWITCH) public void testDisplaySwitching_remoteDisplayChangeFinishedThenKeyguardDrawn_transitionIsReady() { performPhysicalDisplaySwitch(); startCollectingTheLastTransition(); finishRemoteDisplayChange(mDisplayContent); signalKeyguardIsDrawn(); // Transition should be ready as both remote display change // and keyguard drawing are completed final Transition transition = captureRequestedTransition().getValue(); assertThat(transition.allReady()).isTrue(); } @Test @EnableFlags(com.android.window.flags.Flags.FLAG_ENSURE_WALLPAPER_DRAWN_ON_DISPLAY_SWITCH) public void testDisplaySwitching_keyguardDrawnThenRemoteDisplayChangeFinished_transitionIsReady() { performPhysicalDisplaySwitch(); startCollectingTheLastTransition(); signalKeyguardIsDrawn(); finishRemoteDisplayChange(mDisplayContent); // Transition should be ready as both remote display change // and keyguard drawing are completed final Transition transition = captureRequestedTransition().getValue(); assertThat(transition.allReady()).isTrue(); } @Test @EnableFlags(com.android.window.flags.Flags.FLAG_ENSURE_WALLPAPER_DRAWN_ON_DISPLAY_SWITCH) public void testDisplaySwitching_keyguardDrawnBeforeTransitionThenRemoteDisplayChangeFinished_transitionIsReady() { performPhysicalDisplaySwitch(); signalKeyguardIsDrawn(); startCollectingTheLastTransition(); finishRemoteDisplayChange(mDisplayContent); // Transition should be ready as both remote display change // and keyguard drawing are completed final Transition transition = captureRequestedTransition().getValue(); assertThat(transition.allReady()).isTrue(); } @Test @EnableFlags(com.android.window.flags.Flags.FLAG_ENSURE_WALLPAPER_DRAWN_ON_DISPLAY_SWITCH) public void testDisplaySwitching_keyguardWasNotDrawn_secondSwitchingIsNormal_transitionIsReady() { performPhysicalDisplaySwitch(); startCollectingTheLastTransition(); finishRemoteDisplayChange(mDisplayContent); mDisplayContent.mDisplayUpdater.onDisplaySwitching(/* switching= */ false); // Here we finished remote display change & display switching, but keyguard drawn callback // was not invoked. Let's verify that we still handle the next display change correctly. clearInvocations(mDisplayContent.mRemoteDisplayChangeController); mockRemoteDisplayChangeController(mDisplayContent, /* finishImmediately= */ false); mDisplayContent.mDisplayUpdater.onDisplaySwitching(/* switching= */ true); mUniqueId = "new2"; mDisplayContent.requestDisplayUpdate(mock(Runnable.class)); startCollectingTheLastTransition(); signalKeyguardIsDrawn(); finishRemoteDisplayChange(mDisplayContent); // Transition should be ready as both remote display change // and keyguard drawing are completed final Transition transition = captureRequestedTransition().getValue(); assertThat(transition.allReady()).isTrue(); } @Test public void testTwoDisplayUpdates_transitionStarted_displayUpdated() { mUniqueId = "old"; Loading Loading @@ -319,26 +448,44 @@ public class DisplayContentDeferredUpdateTests extends WindowTestsBase { mSecondaryDisplayContent = createNewDisplay(); when(mSecondaryScreenUnblocker.getTarget()).thenReturn(mWm.mH); doReturn(true).when(mSecondaryDisplayContent).getLastHasContent(); mockRemoteDisplayChangeController(mSecondaryDisplayContent); mockRemoteDisplayChangeController(mSecondaryDisplayContent, /* finishImmediately= */ true); performInitialDisplayUpdate(mSecondaryDisplayContent); } private void mockTransitionsController() { spyOn(mDisplayContent.mTransitionController); mDisplayContent.mTransitionController.setSyncEngine(mSyncEngine); when(mDisplayContent.mTransitionController.isShellTransitionsEnabled()) .thenReturn(true); doReturn(mock(Transition.class)).when(mDisplayContent.mTransitionController) .createTransition(anyInt(), anyInt()); final ITransitionPlayer player = new ITransitionPlayer.Default(); mDisplayContent.mTransitionController.registerTransitionPlayer(player, /* playerProc= */ null); doReturn(true).when(mDisplayContent.mTransitionController) .startCollectOrQueue(any(), any()); } private void mockRemoteDisplayChangeController(DisplayContent displayContent) { private void mockRemoteDisplayChangeController(DisplayContent displayContent, boolean finishImmediately) { spyOn(displayContent.mRemoteDisplayChangeController); doReturn(true).when(displayContent.mRemoteDisplayChangeController) doAnswer(invocation -> { if (finishImmediately) { final ContinueRemoteDisplayChangeCallback callback = invocation.getArgument(invocation.getArguments().length - 1); callback.onContinueRemoteDisplayChange(null); } return true; }).when(displayContent.mRemoteDisplayChangeController) .performRemoteDisplayChange(anyInt(), anyInt(), any(), any()); } private void finishRemoteDisplayChange(DisplayContent displayContent) { ArgumentCaptor<ContinueRemoteDisplayChangeCallback> callbackCaptor = ArgumentCaptor.forClass(ContinueRemoteDisplayChangeCallback.class); verify(displayContent.mRemoteDisplayChangeController) .performRemoteDisplayChange(anyInt(), anyInt(), any(), callbackCaptor.capture()); callbackCaptor.getValue().onContinueRemoteDisplayChange(null); } private ArgumentCaptor<OnStartCollect> captureStartTransitionCollection() { ArgumentCaptor<OnStartCollect> callbackCaptor = ArgumentCaptor.forClass(OnStartCollect.class); Loading @@ -364,6 +511,29 @@ public class DisplayContentDeferredUpdateTests extends WindowTestsBase { } } private void performPhysicalDisplaySwitch() { mockRemoteDisplayChangeController(mDisplayContent, /* finishImmediately= */ false); mDisplayContent.mDisplayUpdater.onDisplaySwitching(/* switching= */ true); mUniqueId = "new"; mDisplayContent.requestDisplayUpdate(mock(Runnable.class)); } private void signalKeyguardIsDrawn() { // waitForTransition call signals that keyguard is drawn mDisplayContent.mDisplayUpdater.waitForTransition(mScreenUnblocker); } private void startCollectingTheLastTransition() { ArgumentCaptor<OnStartCollect> callbackCaptor = ArgumentCaptor.forClass(OnStartCollect.class); ArgumentCaptor<Transition> transitionCaptor = ArgumentCaptor.forClass(Transition.class); verify(mDisplayContent.mTransitionController, atLeast(1)) .startCollectOrQueue(transitionCaptor.capture(), callbackCaptor.capture()); transitionCaptor.getValue().startCollecting(/* timeoutMs= */ 0); captureStartTransitionCollection().getValue().onCollectStarted(/* deferred= */ true); } private void performInitialDisplayUpdate(DisplayContent displayContent) { mColorMode = 0; mLogicalDensityDpi = 400; Loading