diff options
| author | 2024-08-22 18:13:47 +0000 | |
|---|---|---|
| committer | 2024-10-01 23:56:13 +0000 | |
| commit | c51a772b76456efb1b3d7d72c08a09f26cdd1941 (patch) | |
| tree | a8f1880a5c38a8736bcfcbacddbb8d86f74093ae | |
| parent | 7cc648a95219e30106ab9772a276691a5f3d0ba2 (diff) | |
Update native input display interactive on power group changes
Utilize Notifier's onGroupWakefulnessChangeStarted to inform native
input manager of a power group's (and therefore, displays')
interactivity.
Add method to DisplayManagerInternal to be able to get the display IDs
for a given display/power group, so that we may know which displays need
to be updated.
Flag: com.android.server.power.feature.flags.per_display_wake_by_touch
Bug: 360916082
Test: atest CtsInputTestCases NotifierTest DisplayManagerServiceTest
Change-Id: Ifd733c4a14ad7a3b7e9bf39abb18ea9f9f04841c
8 files changed, 241 insertions, 2 deletions
diff --git a/core/java/android/hardware/display/DisplayManagerInternal.java b/core/java/android/hardware/display/DisplayManagerInternal.java index 73b5d947c0fe..e5980972d590 100644 --- a/core/java/android/hardware/display/DisplayManagerInternal.java +++ b/core/java/android/hardware/display/DisplayManagerInternal.java @@ -431,6 +431,17 @@ public abstract class DisplayManagerInternal { */ public abstract IntArray getDisplayGroupIds(); + + /** + * Get all display ids belonging to the display group with given id. + */ + public abstract int[] getDisplayIdsForGroup(int groupId); + + /** + * Get the mapping of display group ids to the display ids that belong to them. + */ + public abstract SparseArray<int[]> getDisplayIdsByGroupsIds(); + /** * Get all available display ids. */ diff --git a/services/core/java/com/android/server/display/DisplayGroup.java b/services/core/java/com/android/server/display/DisplayGroup.java index 2dcd5ccaf557..f73b66c78fce 100644 --- a/services/core/java/com/android/server/display/DisplayGroup.java +++ b/services/core/java/com/android/server/display/DisplayGroup.java @@ -87,4 +87,14 @@ public class DisplayGroup { int getIdLocked(int index) { return mDisplays.get(index).getDisplayIdLocked(); } + + /** Returns the IDs of the {@link LogicalDisplay}s belonging to the DisplayGroup. */ + int[] getIdsLocked() { + final int numDisplays = mDisplays.size(); + final int[] displayIds = new int[numDisplays]; + for (int i = 0; i < numDisplays; i++) { + displayIds[i] = mDisplays.get(i).getDisplayIdLocked(); + } + return displayIds; + } } diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java index 67e2ca2b312c..d25b51d6434c 100644 --- a/services/core/java/com/android/server/display/DisplayManagerService.java +++ b/services/core/java/com/android/server/display/DisplayManagerService.java @@ -5575,6 +5575,20 @@ public final class DisplayManagerService extends SystemService { } @Override + public int[] getDisplayIdsForGroup(int groupId) { + synchronized (mSyncRoot) { + return mLogicalDisplayMapper.getDisplayIdsForGroupLocked(groupId); + } + } + + @Override + public SparseArray<int[]> getDisplayIdsByGroupsIds() { + synchronized (mSyncRoot) { + return mLogicalDisplayMapper.getDisplayIdsByGroupIdLocked(); + } + } + + @Override public IntArray getDisplayIds() { IntArray displayIds = new IntArray(); synchronized (mSyncRoot) { diff --git a/services/core/java/com/android/server/display/LogicalDisplayMapper.java b/services/core/java/com/android/server/display/LogicalDisplayMapper.java index c3f6a5285ae3..bcb600d0f91c 100644 --- a/services/core/java/com/android/server/display/LogicalDisplayMapper.java +++ b/services/core/java/com/android/server/display/LogicalDisplayMapper.java @@ -344,6 +344,23 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener { return displayIds; } + public int[] getDisplayIdsForGroupLocked(int groupId) { + DisplayGroup displayGroup = mDisplayGroups.get(groupId); + if (displayGroup == null) { + return new int[]{}; + } + return displayGroup.getIdsLocked(); + } + + public SparseArray<int[]> getDisplayIdsByGroupIdLocked() { + SparseArray<int[]> displayIdsByGroupIds = new SparseArray<>(); + for (int i = 0; i < mDisplayGroups.size(); i++) { + int groupId = mDisplayGroups.get(i).getGroupId(); + displayIdsByGroupIds.put(groupId, getDisplayIdsForGroupLocked(groupId)); + } + return displayIdsByGroupIds; + } + public void forEachLocked(Consumer<LogicalDisplay> consumer) { forEachLocked(consumer, /* includeDisabled= */ true); } diff --git a/services/core/java/com/android/server/power/Notifier.java b/services/core/java/com/android/server/power/Notifier.java index 0cdf537b3455..4fae798f0cef 100644 --- a/services/core/java/com/android/server/power/Notifier.java +++ b/services/core/java/com/android/server/power/Notifier.java @@ -164,6 +164,7 @@ public class Notifier { } private final SparseArray<Interactivity> mInteractivityByGroupId = new SparseArray<>(); + private SparseBooleanArray mDisplayInteractivities = new SparseBooleanArray(); // The current global interactive state. This is set as soon as an interactive state // transition begins so as to capture the reason that it happened. At some point @@ -690,6 +691,42 @@ public class Notifier { } /** + * Update the interactivities of the displays in given DisplayGroup. + * + * @param groupId The group id of the DisplayGroup to update display interactivities for. + */ + private void updateDisplayInteractivities(int groupId, boolean interactive) { + final int[] displayIds = mDisplayManagerInternal.getDisplayIdsForGroup(groupId); + for (int displayId : displayIds) { + mDisplayInteractivities.put(displayId, interactive); + } + + } + + private void resetDisplayInteractivities() { + final SparseArray<int[]> displaysByGroupId = + mDisplayManagerInternal.getDisplayIdsByGroupsIds(); + SparseBooleanArray newDisplayInteractivities = new SparseBooleanArray(); + for (int i = 0; i < displaysByGroupId.size(); i++) { + final int groupId = displaysByGroupId.keyAt(i); + for (int displayId : displaysByGroupId.get(i)) { + // If we already know display interactivity, use that + if (mDisplayInteractivities.indexOfKey(displayId) > 0) { + newDisplayInteractivities.put( + displayId, mDisplayInteractivities.get(displayId)); + } else { // If display is new to Notifier, use the power group's interactive value + final Interactivity groupInteractivity = mInteractivityByGroupId.get(groupId); + // If group Interactivity hasn't been initialized, assume group is interactive + final boolean groupInteractive = + groupInteractivity == null || groupInteractivity.isInteractive; + newDisplayInteractivities.put(displayId, groupInteractive); + } + } + } + mDisplayInteractivities = newDisplayInteractivities; + } + + /** * Called when an individual PowerGroup changes wakefulness. */ public void onGroupWakefulnessChangeStarted(int groupId, int wakefulness, int changeReason, @@ -717,6 +754,12 @@ public class Notifier { handleEarlyInteractiveChange(groupId); mWakefulnessSessionObserver.onWakefulnessChangeStarted(groupId, wakefulness, changeReason, eventTime); + + // Update input on which displays are interactive + if (mFlags.isPerDisplayWakeByTouchEnabled()) { + updateDisplayInteractivities(groupId, isInteractive); + mInputManagerInternal.setDisplayInteractivities(mDisplayInteractivities); + } } } @@ -731,6 +774,16 @@ public class Notifier { } /** + * Called when a PowerGroup has been changed. + */ + public void onGroupChanged() { + if (mFlags.isPerDisplayWakeByTouchEnabled()) { + resetDisplayInteractivities(); + mInputManagerInternal.setDisplayInteractivities(mDisplayInteractivities); + } + } + + /** * Called when there has been user activity. */ public void onUserActivity(int displayGroupId, @PowerManager.UserActivityEvent int event, diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java index e0539647d061..21ab7812e604 100644 --- a/services/core/java/com/android/server/power/PowerManagerService.java +++ b/services/core/java/com/android/server/power/PowerManagerService.java @@ -125,7 +125,6 @@ import com.android.internal.util.DumpUtils; import com.android.internal.util.FrameworkStatsLog; import com.android.internal.util.LatencyTracker; import com.android.internal.util.Preconditions; -import com.android.server.crashrecovery.CrashRecoveryHelper; import com.android.server.EventLogTags; import com.android.server.LockGuard; import com.android.server.ServiceThread; @@ -133,6 +132,7 @@ import com.android.server.SystemService; import com.android.server.UiThread; import com.android.server.Watchdog; import com.android.server.am.BatteryStatsService; +import com.android.server.crashrecovery.CrashRecoveryHelper; import com.android.server.display.feature.DeviceConfigParameterProvider; import com.android.server.lights.LightsManager; import com.android.server.lights.LogicalLight; @@ -2445,6 +2445,8 @@ public final class PowerManagerService extends SystemService mClock.uptimeMillis()); } else if (event == DisplayGroupPowerChangeListener.DISPLAY_GROUP_REMOVED) { mNotifier.onGroupRemoved(groupId); + } else if (event == DisplayGroupPowerChangeListener.DISPLAY_GROUP_CHANGED) { + mNotifier.onGroupChanged(); } if (oldWakefulness != newWakefulness) { diff --git a/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java b/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java index 255dcb083518..342c87a6b5f6 100644 --- a/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java +++ b/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java @@ -37,6 +37,7 @@ import static com.android.server.display.config.DisplayDeviceConfigTestUtilsKt.c import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertWithMessage; +import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotEquals; @@ -1524,6 +1525,47 @@ public class DisplayManagerServiceTest { } @Test + public void testGetDisplayIdsForGroup() throws Exception { + DisplayManagerService displayManager = new DisplayManagerService(mContext, mBasicInjector); + displayManager.onBootPhase(SystemService.PHASE_BOOT_COMPLETED); + DisplayManagerInternal localService = displayManager.new LocalService(); + LogicalDisplayMapper logicalDisplayMapper = displayManager.getLogicalDisplayMapper(); + // Create display 1 + FakeDisplayDevice displayDevice1 = + createFakeDisplayDevice(displayManager, new float[]{60f}, Display.TYPE_INTERNAL); + LogicalDisplay display1 = logicalDisplayMapper.getDisplayLocked(displayDevice1); + final int groupId1 = display1.getDisplayInfoLocked().displayGroupId; + // Create display 2 + FakeDisplayDevice displayDevice2 = + createFakeDisplayDevice(displayManager, new float[]{60f}, Display.TYPE_INTERNAL); + LogicalDisplay display2 = logicalDisplayMapper.getDisplayLocked(displayDevice2); + final int groupId2 = display2.getDisplayInfoLocked().displayGroupId; + // Both displays should be in the same display group + assertEquals(groupId1, groupId2); + final int[] expectedDisplayIds = new int[]{ + display1.getDisplayIdLocked(), display2.getDisplayIdLocked()}; + + final int[] displayIds = localService.getDisplayIdsForGroup(groupId1); + + assertArrayEquals(expectedDisplayIds, displayIds); + } + + @Test + public void testGetDisplayIdsForUnknownGroup() throws Exception { + final int unknownDisplayGroupId = 999; + DisplayManagerService displayManager = new DisplayManagerService(mContext, mBasicInjector); + displayManager.onBootPhase(SystemService.PHASE_BOOT_COMPLETED); + DisplayManagerInternal localService = displayManager.new LocalService(); + LogicalDisplayMapper logicalDisplayMapper = displayManager.getLogicalDisplayMapper(); + // Verify that display manager does not have display group + assertNull(logicalDisplayMapper.getDisplayGroupLocked(unknownDisplayGroupId)); + + final int[] displayIds = localService.getDisplayIdsForGroup(unknownDisplayGroupId); + + assertEquals(0, displayIds.length); + } + + @Test public void testCreateVirtualDisplay_isValidProjection_notValid() throws RemoteException { when(mMockAppToken.asBinder()).thenReturn(mMockAppToken); diff --git a/services/tests/powerservicetests/src/com/android/server/power/NotifierTest.java b/services/tests/powerservicetests/src/com/android/server/power/NotifierTest.java index 07029268661e..a1db18232c09 100644 --- a/services/tests/powerservicetests/src/com/android/server/power/NotifierTest.java +++ b/services/tests/powerservicetests/src/com/android/server/power/NotifierTest.java @@ -268,7 +268,7 @@ public class NotifierTest { } @Test - public void testOnGlobalWakefulnessChangeStarted() throws Exception { + public void testOnGlobalWakefulnessChangeStarted() { createNotifier(); // GIVEN system is currently non-interactive when(mPowerManagerFlags.isPerDisplayWakeByTouchEnabled()).thenReturn(false); @@ -294,6 +294,96 @@ public class NotifierTest { } @Test + public void testOnGroupWakefulnessChangeStarted_newPowerGroup_perDisplayWakeDisabled() { + createNotifier(); + // GIVEN power group is not yet known to Notifier and per-display wake by touch is disabled + final int groupId = 123; + final int changeReason = PowerManager.WAKE_REASON_TAP; + when(mPowerManagerFlags.isPerDisplayWakeByTouchEnabled()).thenReturn(false); + + // WHEN a power group wakefulness change starts + mNotifier.onGroupWakefulnessChangeStarted( + groupId, WAKEFULNESS_AWAKE, changeReason, /* eventTime= */ 999); + mTestLooper.dispatchAll(); + + // THEN window manager policy is informed that device has started waking up + verify(mPolicy).startedWakingUp(groupId, changeReason); + verify(mDisplayManagerInternal, never()).getDisplayIds(); + verify(mInputManagerInternal, never()).setDisplayInteractivities(any()); + } + + @Test + public void testOnGroupWakefulnessChangeStarted_interactivityNoChange_perDisplayWakeDisabled() { + createNotifier(); + // GIVEN power group is not interactive and per-display wake by touch is disabled + final int groupId = 234; + final int changeReason = PowerManager.GO_TO_SLEEP_REASON_TIMEOUT; + when(mPowerManagerFlags.isPerDisplayWakeByTouchEnabled()).thenReturn(false); + mNotifier.onGroupWakefulnessChangeStarted( + groupId, WAKEFULNESS_ASLEEP, changeReason, /* eventTime= */ 999); + mTestLooper.dispatchAll(); + verify(mPolicy, times(1)).startedGoingToSleep(groupId, changeReason); + + // WHEN a power wakefulness change to not interactive starts + mNotifier.onGroupWakefulnessChangeStarted( + groupId, WAKEFULNESS_ASLEEP, changeReason, /* eventTime= */ 999); + mTestLooper.dispatchAll(); + + // THEN policy is only informed once of non-interactive wakefulness change + verify(mPolicy, times(1)).startedGoingToSleep(groupId, changeReason); + verify(mDisplayManagerInternal, never()).getDisplayIds(); + verify(mInputManagerInternal, never()).setDisplayInteractivities(any()); + } + + @Test + public void testOnGroupWakefulnessChangeStarted_interactivityChange_perDisplayWakeDisabled() { + createNotifier(); + // GIVEN power group is not interactive and per-display wake by touch is disabled + final int groupId = 345; + final int firstChangeReason = PowerManager.GO_TO_SLEEP_REASON_TIMEOUT; + when(mPowerManagerFlags.isPerDisplayWakeByTouchEnabled()).thenReturn(false); + mNotifier.onGroupWakefulnessChangeStarted( + groupId, WAKEFULNESS_ASLEEP, firstChangeReason, /* eventTime= */ 999); + mTestLooper.dispatchAll(); + + // WHEN a power wakefulness change to interactive starts + final int secondChangeReason = PowerManager.WAKE_REASON_TAP; + mNotifier.onGroupWakefulnessChangeStarted( + groupId, WAKEFULNESS_AWAKE, secondChangeReason, /* eventTime= */ 999); + mTestLooper.dispatchAll(); + + // THEN policy is informed of the change + verify(mPolicy).startedWakingUp(groupId, secondChangeReason); + verify(mDisplayManagerInternal, never()).getDisplayIds(); + verify(mInputManagerInternal, never()).setDisplayInteractivities(any()); + } + + @Test + public void testOnGroupWakefulnessChangeStarted_perDisplayWakeByTouchEnabled() { + createNotifier(); + // GIVEN per-display wake by touch flag is enabled + when(mPowerManagerFlags.isPerDisplayWakeByTouchEnabled()).thenReturn(true); + final int groupId = 456; + final int displayId1 = 1001; + final int displayId2 = 1002; + final int[] displays = new int[]{displayId1, displayId2}; + when(mDisplayManagerInternal.getDisplayIds()).thenReturn(IntArray.wrap(displays)); + when(mDisplayManagerInternal.getDisplayIdsForGroup(groupId)).thenReturn(displays); + final int changeReason = PowerManager.WAKE_REASON_TAP; + + // WHEN power group wakefulness change started + mNotifier.onGroupWakefulnessChangeStarted( + groupId, WAKEFULNESS_AWAKE, changeReason, /* eventTime= */ 999); + mTestLooper.dispatchAll(); + + // THEN native input manager is updated that the displays are interactive + final SparseBooleanArray expectedDisplayInteractivities = new SparseBooleanArray(); + expectedDisplayInteractivities.put(displayId1, true); + expectedDisplayInteractivities.put(displayId2, true); + verify(mInputManagerInternal).setDisplayInteractivities(expectedDisplayInteractivities); + } + + @Test public void testOnWakeLockListener_RemoteException_NoRethrow() throws RemoteException { when(mPowerManagerFlags.improveWakelockLatency()).thenReturn(true); createNotifier(); |