From 7f5e1f6e8b7598096fb68a3c778672537eb9d171 Mon Sep 17 00:00:00 2001 From: Sunny Shao Date: Mon, 10 Mar 2025 06:52:28 +0000 Subject: [PATCH] Customize Max Screen Timeout Make it possible to customize the maximum screen timeout. Added a configurable max timeout value which, if provided, will limit the predefined timeout values. Leverage code from aosp. Flag: EXEMPT bugfix Bug: 309512299 Test: atest ScreenTimeoutSettingsTest Change-Id: Ibb180c89489fe890f1929bdefd5ced87a9566f07 --- res/values/config.xml | 5 ++ .../display/ScreenTimeoutSettings.java | 41 ++++++--- .../display/ScreenTimeoutSettingsTest.java | 85 ++++++++++++++++++- 3 files changed, 118 insertions(+), 13 deletions(-) diff --git a/res/values/config.xml b/res/values/config.xml index c20f08035c2..4b380446540 100644 --- a/res/values/config.xml +++ b/res/values/config.xml @@ -849,6 +849,11 @@ false + + + false diff --git a/src/com/android/settings/display/ScreenTimeoutSettings.java b/src/com/android/settings/display/ScreenTimeoutSettings.java index d4ca48ebfb7..b00dfec4d9d 100644 --- a/src/com/android/settings/display/ScreenTimeoutSettings.java +++ b/src/com/android/settings/display/ScreenTimeoutSettings.java @@ -127,8 +127,6 @@ public class ScreenTimeoutSettings extends RadioButtonPickerFragment super.onAttach(context); mContext = context; mDevicePolicyManager = mContext.getSystemService(DevicePolicyManager.class); - mInitialEntries = getResources().getStringArray(R.array.screen_timeout_entries); - mInitialValues = getResources().getStringArray(R.array.screen_timeout_values); mAdaptiveSleepPermissionController = new AdaptiveSleepPermissionPreferenceController(context); mAdaptiveSleepCameraStatePreferenceController = @@ -153,10 +151,14 @@ public class ScreenTimeoutSettings extends RadioButtonPickerFragment @Override protected List getCandidates() { + mInitialEntries = getResources().getStringArray(R.array.screen_timeout_entries); + mInitialValues = getResources().getStringArray(R.array.screen_timeout_values); + final List candidates = new ArrayList<>(); final long maxTimeout = getMaxScreenTimeout(getContext()); if (mInitialValues != null) { for (int i = 0; i < mInitialValues.length; ++i) { + // Truncate mInitialEntries/Values so that they do not exceed maxTimeout if (Long.parseLong(mInitialValues[i].toString()) <= maxTimeout) { candidates.add( new TimeoutCandidateInfo( @@ -211,7 +213,7 @@ public class ScreenTimeoutSettings extends RadioButtonPickerFragment for (CandidateInfo info : candidateList) { ProtectedSelectorWithWidgetPreference pref = new ProtectedSelectorWithWidgetPreference( - getPrefContext(), info.getKey(), this); + getContext(), info.getKey(), this); bindPreference(pref, info.getKey(), info, defaultKey); screen.addPreference(pref); } @@ -219,12 +221,17 @@ public class ScreenTimeoutSettings extends RadioButtonPickerFragment final long selectedTimeout = getTimeoutFromKey(defaultKey); final long maxTimeout = getMaxScreenTimeout(getContext()); if (!candidateList.isEmpty() && (selectedTimeout > maxTimeout)) { - // The selected time out value is longer than the max timeout allowed by the admin. - // Select the largest value from the list by default. + // The selected time out value is longer than the max timeout allowed by the + // admin/configuration. The list of candidates is already truncated so that + // no value exceeds the max timeout value. + // Select the largest value from the candidates list by default. + int lastIndex = candidateList.size() - 1; final ProtectedSelectorWithWidgetPreference preferenceWithLargestTimeout = (ProtectedSelectorWithWidgetPreference) - screen.getPreference(candidateList.size() - 1); + screen.getPreference(lastIndex); preferenceWithLargestTimeout.setChecked(true); + // Update the system screen timeout setting to match the UI + setCurrentSystemScreenTimeout(getContext(), candidateList.get(lastIndex).getKey()); } mPrivacyPreference = new FooterPreference(mContext); @@ -338,7 +345,11 @@ public class ScreenTimeoutSettings extends RadioButtonPickerFragment return R.string.help_url_adaptive_sleep; } + // Get the maximum screen timeout as governed by admin and/or configuration. + // Returns the lowest timeout (admin/config) or Long.MAX_VALUE. private Long getMaxScreenTimeout(Context context) { + Long adminMaxTimeout = Long.MAX_VALUE; + Long configMaxTimeout = Long.MAX_VALUE; if (context == null) { return Long.MAX_VALUE; } @@ -346,11 +357,21 @@ public class ScreenTimeoutSettings extends RadioButtonPickerFragment if (dpm == null) { return Long.MAX_VALUE; } - mAdmin = RestrictedLockUtilsInternal.checkIfMaximumTimeToLockIsSet(context); - if (mAdmin != null) { - return dpm.getMaximumTimeToLock(null /* admin */, UserHandle.myUserId()); + if (mAdmin == null) { // Don't overwrite mocked mAdmin + mAdmin = RestrictedLockUtilsInternal.checkIfMaximumTimeToLockIsSet(context); } - return Long.MAX_VALUE; + if (mAdmin != null) { + // Get the admin max screen timeout + adminMaxTimeout = dpm.getMaximumTimeToLock(null /* admin */, UserHandle.myUserId()); + } + try { + // Get the configurable max screen timeout + configMaxTimeout = Long.valueOf( + context.getResources().getInteger(R.integer.config_max_screen_timeout)); + } catch (Resources.NotFoundException e) { + // Do nothing + } + return Math.min(adminMaxTimeout, configMaxTimeout); } private String getCurrentSystemScreenTimeout(Context context) { diff --git a/tests/robotests/src/com/android/settings/display/ScreenTimeoutSettingsTest.java b/tests/robotests/src/com/android/settings/display/ScreenTimeoutSettingsTest.java index 1a6a1128068..c50547dbb0b 100644 --- a/tests/robotests/src/com/android/settings/display/ScreenTimeoutSettingsTest.java +++ b/tests/robotests/src/com/android/settings/display/ScreenTimeoutSettingsTest.java @@ -28,6 +28,7 @@ import static org.mockito.ArgumentMatchers.isA; import static org.mockito.Mockito.atLeast; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; @@ -80,8 +81,10 @@ public class ScreenTimeoutSettingsTest { @Rule public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule(); - private static final String[] TIMEOUT_ENTRIES = new String[]{"15 secs", "30 secs"}; - private static final String[] TIMEOUT_VALUES = new String[]{"15000", "30000"}; + private static final String[] TIMEOUT_ENTRIES = + new String[]{"15 secs", "30 secs", "1 min", "2 min", "5 min"}; + private static final String[] TIMEOUT_VALUES = + new String[]{"15000", "30000", "60000", "120000", "300000"}; private ScreenTimeoutSettings mSettings; private Context mContext; @@ -109,6 +112,9 @@ public class ScreenTimeoutSettingsTest { @Mock FooterPreference mPowerConsumptionPreference; + @Mock + DevicePolicyManager mDevicePolicyManager; + @Mock private PackageManager mPackageManager; @@ -132,7 +138,7 @@ public class ScreenTimeoutSettingsTest { attentionServiceResolveInfo); doReturn(TIMEOUT_ENTRIES).when(mResources).getStringArray(R.array.screen_timeout_entries); - doReturn(TIMEOUT_VALUES).when(mResources).getStringArray(R.array.screen_timeout_entries); + doReturn(TIMEOUT_VALUES).when(mResources).getStringArray(R.array.screen_timeout_values); doReturn(true).when(mResources).getBoolean( com.android.internal.R.bool.config_adaptive_sleep_available); @@ -223,6 +229,79 @@ public class ScreenTimeoutSettingsTest { verify(mPreferenceScreen, atLeast(1)).addPreference(mPowerConsumptionPreference); } + @Test + public void getCandidates_enforcedAdmin_timeoutIsLimited() { + mSettings.mAdmin = new RestrictedLockUtils.EnforcedAdmin(); + mSettings.mDisableOptionsPreference = mDisableOptionsPreference; + doNothing().when(mSettings).setupDisabledFooterPreference(); + doReturn(mDevicePolicyManager).when(mContext).getSystemService(DevicePolicyManager.class); + // Admin-enforced max timeout of 30000 + when(mDevicePolicyManager.getMaximumTimeToLock(any(), anyInt())).thenReturn(30000L); + // No configured max timeout + doThrow(new Resources.NotFoundException("Invalid resource")).when(mResources) + .getInteger(R.integer.config_max_screen_timeout); + + List candidates = mSettings.getCandidates(); + + // Assert that candidates are truncated at the admin-controlled timeout + assertThat(candidates.size()).isEqualTo(2); + assertThat(candidates.get(candidates.size() - 1).getKey()).isEqualTo(TIMEOUT_VALUES[1]); + } + + @Test + public void getCandidates_configuredMaxTimeout_65000_timeoutIsLimited() { + when(mContext.getSystemService(DevicePolicyManager.class)).thenCallRealMethod(); + doReturn(65000).when(mResources).getInteger(R.integer.config_max_screen_timeout); + + List candidates = mSettings.getCandidates(); + + // Assert that candidates are truncated at the highest timeout that is below the max timeout + assertThat(candidates.size()).isEqualTo(3); + assertThat(candidates.get(candidates.size() - 1).getKey()).isEqualTo(TIMEOUT_VALUES[2]); + } + + @Test + public void getCandidates_configuredAndAdminEnforcedMaxTimeout_lowestTimeoutIsApplied() { + mSettings.mAdmin = new RestrictedLockUtils.EnforcedAdmin(); + mSettings.mDisableOptionsPreference = mDisableOptionsPreference; + doNothing().when(mSettings).setupDisabledFooterPreference(); + doReturn(mDevicePolicyManager).when(mContext).getSystemService(DevicePolicyManager.class); + // Admin-enforced max timeout of 30000 + when(mDevicePolicyManager.getMaximumTimeToLock(any(), anyInt())).thenReturn(30000L); + // Configured max timeout of 120000 + doReturn(120000).when(mResources).getInteger(R.integer.config_max_screen_timeout); + + List candidates = mSettings.getCandidates(); + + // Assert that candidates are truncated at the lowest of the two timeouts + assertThat(candidates.size()).isEqualTo(2); + assertThat(candidates.get(candidates.size() - 1).getKey()).isEqualTo(TIMEOUT_VALUES[1]); + } + + @Test + public void getCandidates_configuredMaxTimeout_300000_timeoutIsNotLimited() { + when(mContext.getSystemService(DevicePolicyManager.class)).thenCallRealMethod(); + doReturn(300000).when(mResources).getInteger(R.integer.config_max_screen_timeout); + + List candidates = mSettings.getCandidates(); + + // Assert that candidates are not truncated if configured max timeout is higher than the + // highest available timeout + assertThat(candidates.size()).isEqualTo(TIMEOUT_VALUES.length); + } + + @Test + public void getCandidates_configuredMaxTimeout_notSet_timeoutIsNotLimited() { + when(mContext.getSystemService(DevicePolicyManager.class)).thenCallRealMethod(); + doThrow(new Resources.NotFoundException("Invalid resource")).when(mResources) + .getInteger(R.integer.config_max_screen_timeout); + + List candidates = mSettings.getCandidates(); + + // Assert that candidates are not truncated if there is no configured max timeout + assertThat(candidates.size()).isEqualTo(TIMEOUT_VALUES.length); + } + @Test public void setDefaultKey_controlCurrentScreenTimeout() { mSettings.setDefaultKey(TIMEOUT_VALUES[0]);