diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java index 999428a5f35b3..b142141898331 100644 --- a/services/core/java/com/android/server/policy/PhoneWindowManager.java +++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java @@ -4524,6 +4524,18 @@ public class PhoneWindowManager implements WindowManagerPolicy { mCameraGestureTriggered = false; } + // Called on the PowerManager's Notifier thread. + @Override + public void onPowerGroupWakefulnessChanged(int groupId, int wakefulness, + @PowerManager.GoToSleepReason int pmSleepReason, int globalWakefulness) { + if (wakefulness != globalWakefulness + && wakefulness != PowerManagerInternal.WAKEFULNESS_AWAKE + && groupId == Display.DEFAULT_DISPLAY_GROUP + && mKeyguardDelegate != null) { + mKeyguardDelegate.doKeyguardTimeout(null); + } + } + // Called on the PowerManager's Notifier thread. @Override public void startedWakingUp(@PowerManager.WakeReason int pmWakeReason) { diff --git a/services/core/java/com/android/server/policy/WindowManagerPolicy.java b/services/core/java/com/android/server/policy/WindowManagerPolicy.java index 4571cf3952870..7ca09ab5154f4 100644 --- a/services/core/java/com/android/server/policy/WindowManagerPolicy.java +++ b/services/core/java/com/android/server/policy/WindowManagerPolicy.java @@ -772,6 +772,20 @@ public interface WindowManagerPolicy extends WindowManagerPolicyConstants { */ public void finishedGoingToSleep(@PowerManager.GoToSleepReason int pmSleepReason); + /** + * Called when a particular PowerGroup has changed wakefulness. + * + * @param groupId The id of the PowerGroup. + * @param wakefulness One of PowerManagerInternal.WAKEFULNESS_* indicating the wake state for + * the group + * @param pmSleepReason One of PowerManager.GO_TO_SLEEP_REASON_*, detailing the reason this + * group is going to sleep. + * @param globalWakefulness The global wakefulness, which may or may not match that of this + * group. One of PowerManagerInternal.WAKEFULNESS_* + */ + void onPowerGroupWakefulnessChanged(int groupId, int wakefulness, + @PowerManager.GoToSleepReason int pmSleepReason, int globalWakefulness); + /** * Called when the display is about to turn on to show content. * When waking up, this method will be called once after the call to wakingUp(). diff --git a/services/core/java/com/android/server/power/Notifier.java b/services/core/java/com/android/server/power/Notifier.java index 77d63100032ce..aede4b1e2f5d2 100644 --- a/services/core/java/com/android/server/power/Notifier.java +++ b/services/core/java/com/android/server/power/Notifier.java @@ -552,6 +552,15 @@ public class Notifier { } } + /** + * Called when an individual PowerGroup changes wakefulness. + */ + public void onPowerGroupWakefulnessChanged(int groupId, int groupWakefulness, int changeReason, + int globalWakefulness) { + mHandler.post(() -> mPolicy.onPowerGroupWakefulnessChanged(groupId, groupWakefulness, + changeReason, globalWakefulness)); + } + /** * Called when there has been user activity. */ diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java index c04d6082877ae..57f13829b557e 100644 --- a/services/core/java/com/android/server/power/PowerManagerService.java +++ b/services/core/java/com/android/server/power/PowerManagerService.java @@ -674,6 +674,8 @@ public final class PowerManagerService extends SystemService } mDirty |= DIRTY_DISPLAY_GROUP_WAKEFULNESS; updateGlobalWakefulnessLocked(eventTime, reason, uid, opUid, opPackageName, details); + mNotifier.onPowerGroupWakefulnessChanged(groupId, wakefulness, reason, + getGlobalWakefulnessLocked()); updatePowerStateLocked(); } } diff --git a/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java index 89450ffbc11d3..9f5e79db84c89 100644 --- a/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java @@ -1696,6 +1696,99 @@ public class PowerManagerServiceTest { assertThat(mService.getLocalServiceInstance().getLastWakeup()).isEqualTo(initialWakeData); } + @Test + public void testMultiDisplay_onlyOneDisplaySleeps_onWakefulnessChangedEventFires() { + createService(); + startSystem(); + assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE); + forceSleep(); + assertThat(mService.getWakefulnessLocked(Display.DEFAULT_DISPLAY_GROUP)).isEqualTo( + WAKEFULNESS_ASLEEP); + + verify(mNotifierMock).onPowerGroupWakefulnessChanged(eq(Display.DEFAULT_DISPLAY_GROUP), + eq(WAKEFULNESS_ASLEEP), anyInt(), eq(WAKEFULNESS_ASLEEP)); + } + + @Test + public void testMultiDisplay_bothDisplaysSleep_onWakefulnessChangedEventFiresCorrectly() { + final int nonDefaultDisplayGroupId = Display.DEFAULT_DISPLAY_GROUP + 1; + final int nonDefaultDisplay = Display.DEFAULT_DISPLAY + 1; + final AtomicReference listener = + new AtomicReference<>(); + doAnswer((Answer) invocation -> { + listener.set(invocation.getArgument(0)); + return null; + }).when(mDisplayManagerInternalMock).registerDisplayGroupListener(any()); + final DisplayInfo info = new DisplayInfo(); + info.displayGroupId = nonDefaultDisplayGroupId; + when(mDisplayManagerInternalMock.getDisplayInfo(nonDefaultDisplay)).thenReturn(info); + + createService(); + startSystem(); + + assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE); + listener.get().onDisplayGroupAdded(nonDefaultDisplayGroupId); + + mService.setWakefulnessLocked(nonDefaultDisplayGroupId, WAKEFULNESS_ASLEEP, 0, 0, 0, 0, + null, null); + mService.setWakefulnessLocked(Display.DEFAULT_DISPLAY_GROUP, WAKEFULNESS_ASLEEP, 0, 0, 0, 0, + null, null); + + assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_ASLEEP); + assertThat(mService.getWakefulnessLocked(Display.DEFAULT_DISPLAY_GROUP)).isEqualTo( + WAKEFULNESS_ASLEEP); + assertThat(mService.getWakefulnessLocked(nonDefaultDisplayGroupId)).isEqualTo( + WAKEFULNESS_ASLEEP); + + verify(mNotifierMock).onPowerGroupWakefulnessChanged(eq(nonDefaultDisplayGroupId), + eq(WAKEFULNESS_ASLEEP), anyInt(), eq(WAKEFULNESS_AWAKE)); + verify(mNotifierMock).onPowerGroupWakefulnessChanged(eq(Display.DEFAULT_DISPLAY_GROUP), + eq(WAKEFULNESS_ASLEEP), anyInt(), eq(WAKEFULNESS_ASLEEP)); + } + + @Test + public void testMultiDisplay_separateWakeStates_onWakefulnessChangedEventFiresCorrectly() { + final int nonDefaultDisplayGroupId = Display.DEFAULT_DISPLAY_GROUP + 1; + final int nonDefaultDisplay = Display.DEFAULT_DISPLAY + 1; + final AtomicReference listener = + new AtomicReference<>(); + doAnswer((Answer) invocation -> { + listener.set(invocation.getArgument(0)); + return null; + }).when(mDisplayManagerInternalMock).registerDisplayGroupListener(any()); + final DisplayInfo info = new DisplayInfo(); + info.displayGroupId = nonDefaultDisplayGroupId; + when(mDisplayManagerInternalMock.getDisplayInfo(nonDefaultDisplay)).thenReturn(info); + + createService(); + startSystem(); + + assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE); + listener.get().onDisplayGroupAdded(nonDefaultDisplayGroupId); + + final String pkg = mContextSpy.getOpPackageName(); + final Binder token = new Binder(); + final String tag = + "testMultiDisplay_separateWakeStates_onWakefulnessChangedEventFiresCorrectly"; + mService.getBinderServiceInstance().acquireWakeLock(token, + PowerManager.SCREEN_BRIGHT_WAKE_LOCK, tag, pkg, + null /* workSource */, null /* historyTag */, nonDefaultDisplay, null); + + forceSleep(); + + // The wakelock should have kept the second display awake, and we should notify that the + // default display went to sleep. + assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE); + assertThat(mService.getWakefulnessLocked(Display.DEFAULT_DISPLAY_GROUP)).isEqualTo( + WAKEFULNESS_ASLEEP); + assertThat(mService.getWakefulnessLocked(nonDefaultDisplayGroupId)).isEqualTo( + WAKEFULNESS_AWAKE); + verify(mNotifierMock).onPowerGroupWakefulnessChanged(eq(Display.DEFAULT_DISPLAY_GROUP), + eq(WAKEFULNESS_ASLEEP), anyInt(), eq(WAKEFULNESS_AWAKE)); + verify(mNotifierMock, never()).onPowerGroupWakefulnessChanged( + eq(nonDefaultDisplayGroupId), anyInt(), anyInt(), anyInt()); + } + @Test public void testGetFullPowerSavePolicy_returnsStateMachineResult() { createService(); diff --git a/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java b/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java index f570005f99ccd..ea98b6b17e838 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java +++ b/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java @@ -130,6 +130,11 @@ class TestWindowManagerPolicy implements WindowManagerPolicy { public void finishedGoingToSleep(@GoToSleepReason int sleepReason) { } + @Override + public void onPowerGroupWakefulnessChanged(int groupId, int wakefulness, + @GoToSleepReason int pmSleepReason, int globalWakefulness) { + } + @Override public void screenTurningOn(int displayId, ScreenOnListener screenOnListener) { }