1 /*
2  * Copyright (C) 2020 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.settings.display;
18 
19 import static android.provider.Settings.System.SCREEN_OFF_TIMEOUT;
20 
21 import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
22 
23 import static com.google.common.truth.Truth.assertThat;
24 
25 import static org.mockito.ArgumentMatchers.any;
26 import static org.mockito.ArgumentMatchers.anyInt;
27 import static org.mockito.ArgumentMatchers.isA;
28 import static org.mockito.Mockito.atLeast;
29 import static org.mockito.Mockito.doNothing;
30 import static org.mockito.Mockito.doReturn;
31 import static org.mockito.Mockito.never;
32 import static org.mockito.Mockito.spy;
33 import static org.mockito.Mockito.verify;
34 import static org.mockito.Mockito.when;
35 
36 import android.app.KeyguardManager;
37 import android.app.admin.DevicePolicyManager;
38 import android.content.ContentResolver;
39 import android.content.Context;
40 import android.content.Intent;
41 import android.content.pm.PackageManager;
42 import android.content.pm.ResolveInfo;
43 import android.content.pm.ServiceInfo;
44 import android.content.res.Resources;
45 import android.platform.test.annotations.RequiresFlagsEnabled;
46 import android.platform.test.flag.junit.CheckFlagsRule;
47 import android.platform.test.flag.junit.DeviceFlagsValueProvider;
48 import android.provider.SearchIndexableResource;
49 import android.provider.Settings;
50 
51 import androidx.preference.PreferenceScreen;
52 
53 import com.android.settings.R;
54 import com.android.settings.flags.Flags;
55 import com.android.settings.testutils.FakeFeatureFactory;
56 import com.android.settingslib.RestrictedLockUtils;
57 import com.android.settingslib.widget.CandidateInfo;
58 import com.android.settingslib.widget.FooterPreference;
59 
60 import org.junit.Before;
61 import org.junit.Rule;
62 import org.junit.Test;
63 import org.junit.runner.RunWith;
64 import org.mockito.Mock;
65 import org.mockito.MockitoAnnotations;
66 import org.robolectric.RobolectricTestRunner;
67 import org.robolectric.Shadows;
68 import org.robolectric.annotation.Config;
69 import org.robolectric.shadows.ShadowKeyguardManager;
70 
71 import java.util.List;
72 
73 @RunWith(RobolectricTestRunner.class)
74 @Config(shadows = {
75         com.android.settings.testutils.shadow.ShadowFragment.class,
76         ShadowKeyguardManager.class
77 })
78 public class ScreenTimeoutSettingsTest {
79 
80     @Rule
81     public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
82 
83     private static final String[] TIMEOUT_ENTRIES = new String[]{"15 secs", "30 secs"};
84     private static final String[] TIMEOUT_VALUES = new String[]{"15000", "30000"};
85 
86     private ScreenTimeoutSettings mSettings;
87     private Context mContext;
88     private ContentResolver mContentResolver;
89     private Resources mResources;
90 
91     @Mock
92     private PreferenceScreen mPreferenceScreen;
93 
94     @Mock
95     AdaptiveSleepPermissionPreferenceController mPermissionPreferenceController;
96 
97     @Mock
98     AdaptiveSleepPreferenceController mAdaptiveSleepPreferenceController;
99 
100     @Mock
101     AdaptiveSleepCameraStatePreferenceController mAdaptiveSleepCameraStatePreferenceController;
102 
103     @Mock
104     AdaptiveSleepBatterySaverPreferenceController mAdaptiveSleepBatterySaverPreferenceController;
105 
106     @Mock
107     FooterPreference mDisableOptionsPreference;
108 
109     @Mock
110     FooterPreference mPowerConsumptionPreference;
111 
112     @Mock
113     private PackageManager mPackageManager;
114 
115     @Before
setup()116     public void setup() {
117         MockitoAnnotations.initMocks(this);
118         FakeFeatureFactory.setupForTest();
119         mContext = spy(getApplicationContext());
120         mSettings = spy(new ScreenTimeoutSettings());
121         mSettings.mContext = mContext;
122         mContentResolver = mContext.getContentResolver();
123         mResources = spy(mContext.getResources());
124 
125         doReturn(mPackageManager).when(mContext).getPackageManager();
126         when(mPackageManager.getAttentionServicePackageName()).thenReturn("some.package");
127         when(mPackageManager.checkPermission(any(), any())).thenReturn(
128                 PackageManager.PERMISSION_GRANTED);
129         final ResolveInfo attentionServiceResolveInfo = new ResolveInfo();
130         attentionServiceResolveInfo.serviceInfo = new ServiceInfo();
131         when(mPackageManager.resolveService(isA(Intent.class), anyInt())).thenReturn(
132                 attentionServiceResolveInfo);
133 
134         doReturn(TIMEOUT_ENTRIES).when(mResources).getStringArray(R.array.screen_timeout_entries);
135         doReturn(TIMEOUT_VALUES).when(mResources).getStringArray(R.array.screen_timeout_entries);
136         doReturn(true).when(mResources).getBoolean(
137                 com.android.internal.R.bool.config_adaptive_sleep_available);
138 
139         doReturn(null).when(mContext).getSystemService(DevicePolicyManager.class);
140         doReturn(mResources).when(mContext).getResources();
141 
142         doReturn(mResources).when(mSettings).getResources();
143         doReturn(mContext).when(mSettings).getContext();
144         doReturn(mPreferenceScreen).when(mSettings).getPreferenceScreen();
145 
146         mSettings.mAdaptiveSleepController = mAdaptiveSleepPreferenceController;
147         mSettings.mAdaptiveSleepPermissionController = mPermissionPreferenceController;
148         mSettings.mAdaptiveSleepCameraStatePreferenceController =
149                 mAdaptiveSleepCameraStatePreferenceController;
150         mSettings.mAdaptiveSleepBatterySaverPreferenceController =
151                 mAdaptiveSleepBatterySaverPreferenceController;
152     }
153 
154     @Test
searchIndexProvider_shouldIndexResource()155     public void searchIndexProvider_shouldIndexResource() {
156         final List<SearchIndexableResource> indexRes =
157                 ScreenTimeoutSettings.SEARCH_INDEX_DATA_PROVIDER.getXmlResourcesToIndex(
158                         mContext, true /* enabled */);
159 
160         assertThat(indexRes).isNotNull();
161         assertThat(indexRes.get(0).xmlResId).isEqualTo(mSettings.getPreferenceScreenResId());
162     }
163 
164     @Test
getDefaultKey_returnCurrentTimeout()165     public void getDefaultKey_returnCurrentTimeout() {
166         long timeout = Long.parseLong(TIMEOUT_VALUES[1]);
167         Settings.System.putLong(mContentResolver, SCREEN_OFF_TIMEOUT, timeout);
168 
169         String key = mSettings.getDefaultKey();
170 
171         assertThat(key).isEqualTo(TIMEOUT_VALUES[1]);
172     }
173 
174     @Test
updateCandidates_screenAttentionAvailable_showAdaptiveSleepPreference()175     public void updateCandidates_screenAttentionAvailable_showAdaptiveSleepPreference() {
176         mSettings.updateCandidates();
177 
178         verify(mSettings.mAdaptiveSleepController).addToScreen(mPreferenceScreen);
179     }
180 
181     @Test
updateCandidates_screenAttentionNotAvailable_doNotShowAdaptiveSleepPreference()182     public void updateCandidates_screenAttentionNotAvailable_doNotShowAdaptiveSleepPreference() {
183         doReturn(false).when(mResources).getBoolean(
184                 com.android.internal.R.bool.config_adaptive_sleep_available);
185 
186         mSettings.updateCandidates();
187 
188         verify(mSettings.mAdaptiveSleepController, never()).addToScreen(mPreferenceScreen);
189     }
190 
191     @Test
updateCandidates_AttentionServiceNotInstalled_doNoShowAdaptiveSleepPreference()192     public void updateCandidates_AttentionServiceNotInstalled_doNoShowAdaptiveSleepPreference() {
193         when(mPackageManager.resolveService(isA(Intent.class), anyInt())).thenReturn(null);
194 
195         verify(mSettings.mAdaptiveSleepController, never()).addToScreen(mPreferenceScreen);
196     }
197 
198     @Test
updateCandidates_enforcedAdmin_showDisabledByAdminPreference()199     public void updateCandidates_enforcedAdmin_showDisabledByAdminPreference() {
200         mSettings.mAdmin = new RestrictedLockUtils.EnforcedAdmin();
201         mSettings.mDisableOptionsPreference = mDisableOptionsPreference;
202         mSettings.mPowerConsumptionPreference = mPowerConsumptionPreference;
203         doNothing().when(mSettings).setupDisabledFooterPreference();
204         doNothing().when(mSettings).setupPowerConsumptionFooterPreference();
205 
206         mSettings.updateCandidates();
207 
208         verify(mPreferenceScreen, atLeast(1)).addPreference(mDisableOptionsPreference);
209         verify(mPreferenceScreen, never()).addPreference(mPowerConsumptionPreference);
210     }
211 
212     @Test
updateCandidates_withoutAdmin_showPowerConsumptionPreference()213     public void updateCandidates_withoutAdmin_showPowerConsumptionPreference() {
214         mSettings.mAdmin = null;
215         mSettings.mDisableOptionsPreference = mDisableOptionsPreference;
216         mSettings.mPowerConsumptionPreference = mPowerConsumptionPreference;
217         doNothing().when(mSettings).setupDisabledFooterPreference();
218         doNothing().when(mSettings).setupPowerConsumptionFooterPreference();
219 
220         mSettings.updateCandidates();
221 
222         verify(mPreferenceScreen, never()).addPreference(mDisableOptionsPreference);
223         verify(mPreferenceScreen, atLeast(1)).addPreference(mPowerConsumptionPreference);
224     }
225 
226     @Test
setDefaultKey_controlCurrentScreenTimeout()227     public void setDefaultKey_controlCurrentScreenTimeout() {
228         mSettings.setDefaultKey(TIMEOUT_VALUES[0]);
229 
230         long timeout = Settings.System.getLong(mContentResolver, SCREEN_OFF_TIMEOUT,
231                 30000 /* default */);
232 
233         assertThat(Long.toString(timeout)).isEqualTo(TIMEOUT_VALUES[0]);
234     }
235 
236     @Test
237     @RequiresFlagsEnabled(Flags.FLAG_PROTECT_SCREEN_TIMEOUT_WITH_AUTH)
onClick_whenUserAlreadyAuthenticated_buttonChecked()238     public void onClick_whenUserAlreadyAuthenticated_buttonChecked() {
239         String key = "222";
240         String defaultKey = "1";
241         mSettings.setDefaultKey(defaultKey);
242         CandidateInfo info = new ScreenTimeoutSettings.TimeoutCandidateInfo("label", key, false);
243         ScreenTimeoutSettings.ProtectedSelectorWithWidgetPreference pref =
244                 new ScreenTimeoutSettings.ProtectedSelectorWithWidgetPreference(
245                         mContext, info.getKey(), mSettings);
246         mSettings.bindPreference(pref, info.getKey(), info, defaultKey);
247         mSettings.setUserAuthenticated(true);
248 
249         pref.onClick();
250 
251         assertThat(mSettings.getDefaultKey()).isEqualTo(key);
252     }
253 
254     @Test
255     @RequiresFlagsEnabled(Flags.FLAG_PROTECT_SCREEN_TIMEOUT_WITH_AUTH)
onClick_whenButtonAlreadyChecked_noAuthNeeded()256     public void onClick_whenButtonAlreadyChecked_noAuthNeeded() {
257         String key = "222";
258         mSettings.setDefaultKey(key);
259         CandidateInfo info = new ScreenTimeoutSettings.TimeoutCandidateInfo("label", key, false);
260         ScreenTimeoutSettings.ProtectedSelectorWithWidgetPreference pref =
261                 new ScreenTimeoutSettings.ProtectedSelectorWithWidgetPreference(
262                         mContext, info.getKey(), mSettings);
263         mSettings.bindPreference(pref, info.getKey(), info, key);
264         mSettings.setUserAuthenticated(false);
265         setAuthPassesAutomatically();
266 
267         pref.onClick();
268 
269         assertThat(mSettings.isUserAuthenticated()).isFalse();
270     }
271 
272     @Test
273     @RequiresFlagsEnabled(Flags.FLAG_PROTECT_SCREEN_TIMEOUT_WITH_AUTH)
onClick_whenReducingTimeout_noAuthNeeded()274     public void onClick_whenReducingTimeout_noAuthNeeded() {
275         String key = "1";
276         String defaultKey = "222";
277         mSettings.setDefaultKey(defaultKey);
278         CandidateInfo info = new ScreenTimeoutSettings.TimeoutCandidateInfo("label", key, false);
279         ScreenTimeoutSettings.ProtectedSelectorWithWidgetPreference pref =
280                 new ScreenTimeoutSettings.ProtectedSelectorWithWidgetPreference(
281                         mContext, info.getKey(), mSettings);
282         mSettings.bindPreference(pref, info.getKey(), info, defaultKey);
283         mSettings.setUserAuthenticated(false);
284         setAuthPassesAutomatically();
285 
286         pref.onClick();
287 
288         assertThat(mSettings.isUserAuthenticated()).isFalse();
289         assertThat(mSettings.getDefaultKey()).isEqualTo(key);
290     }
291 
292     @Test
293     @RequiresFlagsEnabled(Flags.FLAG_PROTECT_SCREEN_TIMEOUT_WITH_AUTH)
onClick_whenIncreasingTimeout_authNeeded()294     public void onClick_whenIncreasingTimeout_authNeeded() {
295         String key = "222";
296         String defaultKey = "1";
297         mSettings.setDefaultKey(defaultKey);
298         CandidateInfo info = new ScreenTimeoutSettings.TimeoutCandidateInfo("label", key, false);
299         ScreenTimeoutSettings.ProtectedSelectorWithWidgetPreference pref =
300                 new ScreenTimeoutSettings.ProtectedSelectorWithWidgetPreference(
301                         mContext, info.getKey(), mSettings);
302         mSettings.bindPreference(pref, info.getKey(), info, defaultKey);
303         mSettings.setUserAuthenticated(false);
304         setAuthPassesAutomatically();
305 
306         pref.onClick();
307 
308         assertThat(mSettings.getDefaultKey()).isEqualTo(key);
309         assertThat(mSettings.isUserAuthenticated()).isTrue();
310     }
311 
setAuthPassesAutomatically()312     private void setAuthPassesAutomatically() {
313         Shadows.shadowOf(mContext.getSystemService(KeyguardManager.class))
314                 .setIsKeyguardSecure(false);
315     }
316 }
317