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
396 lines
16 KiB
Java
396 lines
16 KiB
Java
/*
|
|
* Copyright (C) 2020 The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
package com.android.settings.display;
|
|
|
|
import static android.provider.Settings.System.SCREEN_OFF_TIMEOUT;
|
|
|
|
import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
|
|
|
|
import static com.google.common.truth.Truth.assertThat;
|
|
|
|
import static org.mockito.ArgumentMatchers.any;
|
|
import static org.mockito.ArgumentMatchers.anyInt;
|
|
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;
|
|
import static org.mockito.Mockito.when;
|
|
|
|
import android.app.KeyguardManager;
|
|
import android.app.admin.DevicePolicyManager;
|
|
import android.content.ContentResolver;
|
|
import android.content.Context;
|
|
import android.content.Intent;
|
|
import android.content.pm.PackageManager;
|
|
import android.content.pm.ResolveInfo;
|
|
import android.content.pm.ServiceInfo;
|
|
import android.content.res.Resources;
|
|
import android.platform.test.annotations.RequiresFlagsEnabled;
|
|
import android.platform.test.flag.junit.CheckFlagsRule;
|
|
import android.platform.test.flag.junit.DeviceFlagsValueProvider;
|
|
import android.provider.SearchIndexableResource;
|
|
import android.provider.Settings;
|
|
|
|
import androidx.preference.PreferenceScreen;
|
|
|
|
import com.android.settings.R;
|
|
import com.android.settings.flags.Flags;
|
|
import com.android.settings.testutils.FakeFeatureFactory;
|
|
import com.android.settingslib.RestrictedLockUtils;
|
|
import com.android.settingslib.widget.CandidateInfo;
|
|
import com.android.settingslib.widget.FooterPreference;
|
|
|
|
import org.junit.Before;
|
|
import org.junit.Rule;
|
|
import org.junit.Test;
|
|
import org.junit.runner.RunWith;
|
|
import org.mockito.Mock;
|
|
import org.mockito.MockitoAnnotations;
|
|
import org.robolectric.RobolectricTestRunner;
|
|
import org.robolectric.Shadows;
|
|
import org.robolectric.annotation.Config;
|
|
import org.robolectric.shadows.ShadowKeyguardManager;
|
|
|
|
import java.util.List;
|
|
|
|
@RunWith(RobolectricTestRunner.class)
|
|
@Config(shadows = {
|
|
com.android.settings.testutils.shadow.ShadowFragment.class,
|
|
ShadowKeyguardManager.class
|
|
})
|
|
public class ScreenTimeoutSettingsTest {
|
|
|
|
@Rule
|
|
public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
|
|
|
|
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;
|
|
private ContentResolver mContentResolver;
|
|
private Resources mResources;
|
|
|
|
@Mock
|
|
private PreferenceScreen mPreferenceScreen;
|
|
|
|
@Mock
|
|
AdaptiveSleepPermissionPreferenceController mPermissionPreferenceController;
|
|
|
|
@Mock
|
|
AdaptiveSleepPreferenceController mAdaptiveSleepPreferenceController;
|
|
|
|
@Mock
|
|
AdaptiveSleepCameraStatePreferenceController mAdaptiveSleepCameraStatePreferenceController;
|
|
|
|
@Mock
|
|
AdaptiveSleepBatterySaverPreferenceController mAdaptiveSleepBatterySaverPreferenceController;
|
|
|
|
@Mock
|
|
FooterPreference mDisableOptionsPreference;
|
|
|
|
@Mock
|
|
FooterPreference mPowerConsumptionPreference;
|
|
|
|
@Mock
|
|
DevicePolicyManager mDevicePolicyManager;
|
|
|
|
@Mock
|
|
private PackageManager mPackageManager;
|
|
|
|
@Before
|
|
public void setup() {
|
|
MockitoAnnotations.initMocks(this);
|
|
FakeFeatureFactory.setupForTest();
|
|
mContext = spy(getApplicationContext());
|
|
mSettings = spy(new ScreenTimeoutSettings());
|
|
mSettings.mContext = mContext;
|
|
mContentResolver = mContext.getContentResolver();
|
|
mResources = spy(mContext.getResources());
|
|
|
|
doReturn(mPackageManager).when(mContext).getPackageManager();
|
|
when(mPackageManager.getAttentionServicePackageName()).thenReturn("some.package");
|
|
when(mPackageManager.checkPermission(any(), any())).thenReturn(
|
|
PackageManager.PERMISSION_GRANTED);
|
|
final ResolveInfo attentionServiceResolveInfo = new ResolveInfo();
|
|
attentionServiceResolveInfo.serviceInfo = new ServiceInfo();
|
|
when(mPackageManager.resolveService(isA(Intent.class), anyInt())).thenReturn(
|
|
attentionServiceResolveInfo);
|
|
|
|
doReturn(TIMEOUT_ENTRIES).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);
|
|
|
|
doReturn(null).when(mContext).getSystemService(DevicePolicyManager.class);
|
|
doReturn(mResources).when(mContext).getResources();
|
|
|
|
doReturn(mResources).when(mSettings).getResources();
|
|
doReturn(mContext).when(mSettings).getContext();
|
|
doReturn(mPreferenceScreen).when(mSettings).getPreferenceScreen();
|
|
|
|
mSettings.mAdaptiveSleepController = mAdaptiveSleepPreferenceController;
|
|
mSettings.mAdaptiveSleepPermissionController = mPermissionPreferenceController;
|
|
mSettings.mAdaptiveSleepCameraStatePreferenceController =
|
|
mAdaptiveSleepCameraStatePreferenceController;
|
|
mSettings.mAdaptiveSleepBatterySaverPreferenceController =
|
|
mAdaptiveSleepBatterySaverPreferenceController;
|
|
}
|
|
|
|
@Test
|
|
public void searchIndexProvider_shouldIndexResource() {
|
|
final List<SearchIndexableResource> indexRes =
|
|
ScreenTimeoutSettings.SEARCH_INDEX_DATA_PROVIDER.getXmlResourcesToIndex(
|
|
mContext, true /* enabled */);
|
|
|
|
assertThat(indexRes).isNotNull();
|
|
assertThat(indexRes.get(0).xmlResId).isEqualTo(mSettings.getPreferenceScreenResId());
|
|
}
|
|
|
|
@Test
|
|
public void getDefaultKey_returnCurrentTimeout() {
|
|
long timeout = Long.parseLong(TIMEOUT_VALUES[1]);
|
|
Settings.System.putLong(mContentResolver, SCREEN_OFF_TIMEOUT, timeout);
|
|
|
|
String key = mSettings.getDefaultKey();
|
|
|
|
assertThat(key).isEqualTo(TIMEOUT_VALUES[1]);
|
|
}
|
|
|
|
@Test
|
|
public void updateCandidates_screenAttentionAvailable_showAdaptiveSleepPreference() {
|
|
mSettings.updateCandidates();
|
|
|
|
verify(mSettings.mAdaptiveSleepController).addToScreen(mPreferenceScreen);
|
|
}
|
|
|
|
@Test
|
|
public void updateCandidates_screenAttentionNotAvailable_doNotShowAdaptiveSleepPreference() {
|
|
doReturn(false).when(mResources).getBoolean(
|
|
com.android.internal.R.bool.config_adaptive_sleep_available);
|
|
|
|
mSettings.updateCandidates();
|
|
|
|
verify(mSettings.mAdaptiveSleepController, never()).addToScreen(mPreferenceScreen);
|
|
}
|
|
|
|
@Test
|
|
public void updateCandidates_AttentionServiceNotInstalled_doNoShowAdaptiveSleepPreference() {
|
|
when(mPackageManager.resolveService(isA(Intent.class), anyInt())).thenReturn(null);
|
|
|
|
verify(mSettings.mAdaptiveSleepController, never()).addToScreen(mPreferenceScreen);
|
|
}
|
|
|
|
@Test
|
|
public void updateCandidates_enforcedAdmin_showDisabledByAdminPreference() {
|
|
mSettings.mAdmin = new RestrictedLockUtils.EnforcedAdmin();
|
|
mSettings.mDisableOptionsPreference = mDisableOptionsPreference;
|
|
mSettings.mPowerConsumptionPreference = mPowerConsumptionPreference;
|
|
doNothing().when(mSettings).setupDisabledFooterPreference();
|
|
doNothing().when(mSettings).setupPowerConsumptionFooterPreference();
|
|
|
|
mSettings.updateCandidates();
|
|
|
|
verify(mPreferenceScreen, atLeast(1)).addPreference(mDisableOptionsPreference);
|
|
verify(mPreferenceScreen, never()).addPreference(mPowerConsumptionPreference);
|
|
}
|
|
|
|
@Test
|
|
public void updateCandidates_withoutAdmin_showPowerConsumptionPreference() {
|
|
mSettings.mAdmin = null;
|
|
mSettings.mDisableOptionsPreference = mDisableOptionsPreference;
|
|
mSettings.mPowerConsumptionPreference = mPowerConsumptionPreference;
|
|
doNothing().when(mSettings).setupDisabledFooterPreference();
|
|
doNothing().when(mSettings).setupPowerConsumptionFooterPreference();
|
|
|
|
mSettings.updateCandidates();
|
|
|
|
verify(mPreferenceScreen, never()).addPreference(mDisableOptionsPreference);
|
|
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<? extends CandidateInfo> 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<? extends CandidateInfo> 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<? extends CandidateInfo> 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<? extends CandidateInfo> 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<? extends CandidateInfo> 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]);
|
|
|
|
long timeout = Settings.System.getLong(mContentResolver, SCREEN_OFF_TIMEOUT,
|
|
30000 /* default */);
|
|
|
|
assertThat(Long.toString(timeout)).isEqualTo(TIMEOUT_VALUES[0]);
|
|
}
|
|
|
|
@Test
|
|
@RequiresFlagsEnabled(Flags.FLAG_PROTECT_SCREEN_TIMEOUT_WITH_AUTH)
|
|
public void onClick_whenUserAlreadyAuthenticated_buttonChecked() {
|
|
String key = "222";
|
|
String defaultKey = "1";
|
|
mSettings.setDefaultKey(defaultKey);
|
|
CandidateInfo info = new ScreenTimeoutSettings.TimeoutCandidateInfo("label", key, false);
|
|
ScreenTimeoutSettings.ProtectedSelectorWithWidgetPreference pref =
|
|
new ScreenTimeoutSettings.ProtectedSelectorWithWidgetPreference(
|
|
mContext, info.getKey(), mSettings);
|
|
mSettings.bindPreference(pref, info.getKey(), info, defaultKey);
|
|
mSettings.setUserAuthenticated(true);
|
|
|
|
pref.onClick();
|
|
|
|
assertThat(mSettings.getDefaultKey()).isEqualTo(key);
|
|
}
|
|
|
|
@Test
|
|
@RequiresFlagsEnabled(Flags.FLAG_PROTECT_SCREEN_TIMEOUT_WITH_AUTH)
|
|
public void onClick_whenButtonAlreadyChecked_noAuthNeeded() {
|
|
String key = "222";
|
|
mSettings.setDefaultKey(key);
|
|
CandidateInfo info = new ScreenTimeoutSettings.TimeoutCandidateInfo("label", key, false);
|
|
ScreenTimeoutSettings.ProtectedSelectorWithWidgetPreference pref =
|
|
new ScreenTimeoutSettings.ProtectedSelectorWithWidgetPreference(
|
|
mContext, info.getKey(), mSettings);
|
|
mSettings.bindPreference(pref, info.getKey(), info, key);
|
|
mSettings.setUserAuthenticated(false);
|
|
setAuthPassesAutomatically();
|
|
|
|
pref.onClick();
|
|
|
|
assertThat(mSettings.isUserAuthenticated()).isFalse();
|
|
}
|
|
|
|
@Test
|
|
@RequiresFlagsEnabled(Flags.FLAG_PROTECT_SCREEN_TIMEOUT_WITH_AUTH)
|
|
public void onClick_whenReducingTimeout_noAuthNeeded() {
|
|
String key = "1";
|
|
String defaultKey = "222";
|
|
mSettings.setDefaultKey(defaultKey);
|
|
CandidateInfo info = new ScreenTimeoutSettings.TimeoutCandidateInfo("label", key, false);
|
|
ScreenTimeoutSettings.ProtectedSelectorWithWidgetPreference pref =
|
|
new ScreenTimeoutSettings.ProtectedSelectorWithWidgetPreference(
|
|
mContext, info.getKey(), mSettings);
|
|
mSettings.bindPreference(pref, info.getKey(), info, defaultKey);
|
|
mSettings.setUserAuthenticated(false);
|
|
setAuthPassesAutomatically();
|
|
|
|
pref.onClick();
|
|
|
|
assertThat(mSettings.isUserAuthenticated()).isFalse();
|
|
assertThat(mSettings.getDefaultKey()).isEqualTo(key);
|
|
}
|
|
|
|
@Test
|
|
@RequiresFlagsEnabled(Flags.FLAG_PROTECT_SCREEN_TIMEOUT_WITH_AUTH)
|
|
public void onClick_whenIncreasingTimeout_authNeeded() {
|
|
String key = "222";
|
|
String defaultKey = "1";
|
|
mSettings.setDefaultKey(defaultKey);
|
|
CandidateInfo info = new ScreenTimeoutSettings.TimeoutCandidateInfo("label", key, false);
|
|
ScreenTimeoutSettings.ProtectedSelectorWithWidgetPreference pref =
|
|
new ScreenTimeoutSettings.ProtectedSelectorWithWidgetPreference(
|
|
mContext, info.getKey(), mSettings);
|
|
mSettings.bindPreference(pref, info.getKey(), info, defaultKey);
|
|
mSettings.setUserAuthenticated(false);
|
|
setAuthPassesAutomatically();
|
|
|
|
pref.onClick();
|
|
|
|
assertThat(mSettings.getDefaultKey()).isEqualTo(key);
|
|
assertThat(mSettings.isUserAuthenticated()).isTrue();
|
|
}
|
|
|
|
private void setAuthPassesAutomatically() {
|
|
Shadows.shadowOf(mContext.getSystemService(KeyguardManager.class))
|
|
.setIsKeyguardSecure(false);
|
|
}
|
|
}
|