• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.datetime;
18 
19 import static android.app.time.Capabilities.CAPABILITY_NOT_APPLICABLE;
20 import static android.app.time.Capabilities.CAPABILITY_NOT_SUPPORTED;
21 import static android.app.time.Capabilities.CAPABILITY_POSSESSED;
22 import static android.app.time.DetectorStatusTypes.DETECTION_ALGORITHM_STATUS_NOT_SUPPORTED;
23 import static android.app.time.DetectorStatusTypes.DETECTION_ALGORITHM_STATUS_RUNNING;
24 import static android.app.time.DetectorStatusTypes.DETECTOR_STATUS_RUNNING;
25 import static android.app.time.LocationTimeZoneAlgorithmStatus.PROVIDER_STATUS_NOT_PRESENT;
26 import static android.app.time.LocationTimeZoneAlgorithmStatus.PROVIDER_STATUS_NOT_READY;
27 
28 import static com.android.settings.core.BasePreferenceController.DISABLED_DEPENDENT_SETTING;
29 
30 import static com.google.common.truth.Truth.assertThat;
31 
32 import static org.mockito.ArgumentMatchers.any;
33 import static org.mockito.Mockito.never;
34 import static org.mockito.Mockito.spy;
35 import static org.mockito.Mockito.verify;
36 import static org.mockito.Mockito.when;
37 
38 import android.app.time.Capabilities.CapabilityState;
39 import android.app.time.LocationTimeZoneAlgorithmStatus;
40 import android.app.time.TelephonyTimeZoneAlgorithmStatus;
41 import android.app.time.TimeManager;
42 import android.app.time.TimeZoneCapabilities;
43 import android.app.time.TimeZoneCapabilitiesAndConfig;
44 import android.app.time.TimeZoneConfiguration;
45 import android.app.time.TimeZoneDetectorStatus;
46 import android.content.Context;
47 import android.os.UserHandle;
48 
49 import androidx.preference.SwitchPreference;
50 
51 import com.android.settings.R;
52 import com.android.settings.core.InstrumentedPreferenceFragment;
53 
54 import org.junit.Before;
55 import org.junit.Test;
56 import org.junit.runner.RunWith;
57 import org.mockito.Answers;
58 import org.mockito.Mock;
59 import org.mockito.MockitoAnnotations;
60 import org.robolectric.RobolectricTestRunner;
61 import org.robolectric.RuntimeEnvironment;
62 import org.robolectric.annotation.Config;
63 
64 @RunWith(RobolectricTestRunner.class)
65 @Config(shadows = {
66         com.android.settings.testutils.shadow.ShadowFragment.class,
67 })
68 public class LocationTimeZoneDetectionPreferenceControllerTest {
69 
70     @Mock
71     private TimeManager mTimeManager;
72     private Context mContext;
73     private SwitchPreference mPreference;
74     private LocationTimeZoneDetectionPreferenceController mController;
75     @Mock(answer = Answers.RETURNS_DEEP_STUBS)
76     private InstrumentedPreferenceFragment mFragment;
77 
78     @Before
setUp()79     public void setUp() {
80         MockitoAnnotations.initMocks(this);
81         mContext = spy(RuntimeEnvironment.application);
82         when(mContext.getSystemService(TimeManager.class)).thenReturn(mTimeManager);
83         mController = new LocationTimeZoneDetectionPreferenceController(mContext);
84         mController.setFragment(mFragment);
85 
86         mPreference = new SwitchPreference(mContext);
87         mPreference.setKey("location_time_zone_detection");
88     }
89 
90     @Test
setChecked_withTrue_shouldUpdateSetting_whenLocationIsEnabled()91     public void setChecked_withTrue_shouldUpdateSetting_whenLocationIsEnabled() {
92         boolean useLocationEnabled = true;
93         TimeZoneCapabilitiesAndConfig capabilitiesAndConfig =
94                 createTimeZoneCapabilitiesAndConfig(useLocationEnabled, CAPABILITY_POSSESSED);
95         when(mTimeManager.getTimeZoneCapabilitiesAndConfig()).thenReturn(capabilitiesAndConfig);
96 
97         // Simulate the UI being clicked.
98         mController.setChecked(true);
99 
100         // Verify the TimeManager was updated with the UI value.
101         TimeZoneConfiguration expectedConfiguration = new TimeZoneConfiguration.Builder()
102                 .setGeoDetectionEnabled(true)
103                 .build();
104         verify(mTimeManager).updateTimeZoneConfiguration(expectedConfiguration);
105     }
106 
107     @Test
isNotSliceable()108     public void isNotSliceable() {
109         assertThat(mController.isSliceable()).isFalse();
110     }
111 
112     @Test
setChecked_withTrue_shouldDoNothing_whenLocationIsDisabled()113     public void setChecked_withTrue_shouldDoNothing_whenLocationIsDisabled() {
114         boolean useLocationEnabled = false;
115         TimeZoneCapabilitiesAndConfig capabilitiesAndConfig =
116                 createTimeZoneCapabilitiesAndConfig(useLocationEnabled, CAPABILITY_POSSESSED);
117         when(mTimeManager.getTimeZoneCapabilitiesAndConfig()).thenReturn(capabilitiesAndConfig);
118 
119         // Simulate the UI being clicked.
120         mController.setChecked(true);
121 
122         // Verify the TimeManager was not updated.
123         verify(mTimeManager, never()).updateTimeZoneConfiguration(any());
124     }
125 
126     @Test
toggleOff_automaticTimeZone_disablesLocationToggle()127     public void toggleOff_automaticTimeZone_disablesLocationToggle() {
128         TimeZoneCapabilitiesAndConfig capabilitiesAndConfig =
129                 createTimeZoneCapabilitiesAndConfig(/* useLocationEnabled= */ true,
130                         CAPABILITY_POSSESSED, /* setAutoDetectionEnabled= */ false);
131         when(mTimeManager.getTimeZoneCapabilitiesAndConfig()).thenReturn(capabilitiesAndConfig);
132 
133         assertThat(mController.getAvailabilityStatus()).isEqualTo(DISABLED_DEPENDENT_SETTING);
134     }
135 
136     @Test
setChecked_withFalse_shouldUpdateSetting()137     public void setChecked_withFalse_shouldUpdateSetting() {
138         boolean useLocationEnabled = false;
139         TimeZoneCapabilitiesAndConfig capabilitiesAndConfig =
140                 createTimeZoneCapabilitiesAndConfig(useLocationEnabled, CAPABILITY_POSSESSED);
141         when(mTimeManager.getTimeZoneCapabilitiesAndConfig()).thenReturn(capabilitiesAndConfig);
142 
143         // Simulate the UI being clicked.
144         mController.setChecked(false);
145 
146         // Verify the TimeManager was updated with the UI value.
147         TimeZoneConfiguration expectedConfiguration = new TimeZoneConfiguration.Builder()
148                 .setGeoDetectionEnabled(false)
149                 .build();
150         verify(mTimeManager).updateTimeZoneConfiguration(expectedConfiguration);
151     }
152 
153     @Test
testLocationTimeZoneDetection_supported_shouldBeShown()154     public void testLocationTimeZoneDetection_supported_shouldBeShown() {
155         boolean useLocationEnabled = false;
156         TimeZoneCapabilitiesAndConfig capabilitiesAndConfig =
157                 createTimeZoneCapabilitiesAndConfig(useLocationEnabled, CAPABILITY_POSSESSED);
158         when(mTimeManager.getTimeZoneCapabilitiesAndConfig()).thenReturn(capabilitiesAndConfig);
159 
160         assertThat(mController.isAvailable()).isTrue();
161     }
162 
163     @Test
testLocationTimeZoneDetection_unsupported_shouldNotBeShown()164     public void testLocationTimeZoneDetection_unsupported_shouldNotBeShown() {
165         boolean useLocationEnabled = false;
166         TimeZoneCapabilitiesAndConfig capabilitiesAndConfig = createTimeZoneCapabilitiesAndConfig(
167                 useLocationEnabled, CAPABILITY_NOT_SUPPORTED);
168         when(mTimeManager.getTimeZoneCapabilitiesAndConfig()).thenReturn(capabilitiesAndConfig);
169 
170         assertThat(mController.isAvailable()).isFalse();
171     }
172 
173     /**
174      * Tests that the summary is set in just one of many cases. Exhaustive testing would be brittle.
175      */
176     @Test
testLocationTimeZoneDetection_summary_geoDetectionEnabled()177     public void testLocationTimeZoneDetection_summary_geoDetectionEnabled() {
178         boolean useLocationEnabled = false;
179         TimeZoneCapabilitiesAndConfig capabilitiesAndConfig =
180                 createTimeZoneCapabilitiesAndConfig(useLocationEnabled, CAPABILITY_POSSESSED);
181 
182         when(mTimeManager.getTimeZoneCapabilitiesAndConfig()).thenReturn(capabilitiesAndConfig);
183         assertThat(mController.getSummary()).isEqualTo(
184                 mContext.getString(R.string.location_time_zone_detection_auto_is_on));
185     }
186 
187     @Test
testLocationTimeZoneDetection_toggleIsOn_whenGeoDetectionEnabledAnsMlsIsOff()188     public void testLocationTimeZoneDetection_toggleIsOn_whenGeoDetectionEnabledAnsMlsIsOff() {
189         boolean useLocationEnabled = false;
190         TimeZoneCapabilitiesAndConfig capabilitiesAndConfig = createTimeZoneCapabilitiesAndConfig(
191                 useLocationEnabled, CAPABILITY_NOT_APPLICABLE);
192 
193         when(mTimeManager.getTimeZoneCapabilitiesAndConfig()).thenReturn(capabilitiesAndConfig);
194 
195         assertThat(mController.isChecked()).isTrue();
196         assertThat(mController.getSummary()).isEqualTo(
197                 mContext.getString(R.string.location_app_permission_summary_location_off));
198     }
199 
createTimeZoneCapabilitiesAndConfig( boolean useLocationEnabled, @CapabilityState int configureGeoDetectionEnabledCapability)200     private static TimeZoneCapabilitiesAndConfig createTimeZoneCapabilitiesAndConfig(
201             boolean useLocationEnabled,
202             @CapabilityState int configureGeoDetectionEnabledCapability) {
203         return createTimeZoneCapabilitiesAndConfig(useLocationEnabled,
204                 configureGeoDetectionEnabledCapability, /* setAutoDetectionEnabled= */ true);
205     }
206 
createTimeZoneCapabilitiesAndConfig( boolean useLocationEnabled, @CapabilityState int configureGeoDetectionEnabledCapability, boolean setAutoDetectionEnabled)207     private static TimeZoneCapabilitiesAndConfig createTimeZoneCapabilitiesAndConfig(
208             boolean useLocationEnabled,
209             @CapabilityState int configureGeoDetectionEnabledCapability,
210             boolean setAutoDetectionEnabled) {
211         // Create a status that matches the user's capability state.
212         LocationTimeZoneAlgorithmStatus locationAlgorithmStatus;
213         switch (configureGeoDetectionEnabledCapability) {
214             case CAPABILITY_NOT_SUPPORTED:
215                 locationAlgorithmStatus = new LocationTimeZoneAlgorithmStatus(
216                         DETECTION_ALGORITHM_STATUS_NOT_SUPPORTED,
217                         PROVIDER_STATUS_NOT_PRESENT, null, PROVIDER_STATUS_NOT_PRESENT, null);
218                 break;
219             case CAPABILITY_NOT_APPLICABLE:
220             case CAPABILITY_POSSESSED:
221                 locationAlgorithmStatus = new LocationTimeZoneAlgorithmStatus(
222                         DETECTION_ALGORITHM_STATUS_RUNNING,
223                         PROVIDER_STATUS_NOT_READY, null, PROVIDER_STATUS_NOT_READY, null);
224                 break;
225             default:
226                 throw new AssertionError(
227                         "Unsupported capability state: " + configureGeoDetectionEnabledCapability);
228         }
229         TimeZoneDetectorStatus status = new TimeZoneDetectorStatus(DETECTOR_STATUS_RUNNING,
230                 new TelephonyTimeZoneAlgorithmStatus(DETECTION_ALGORITHM_STATUS_RUNNING),
231                 locationAlgorithmStatus);
232 
233         UserHandle arbitraryUserHandle = UserHandle.of(123);
234         TimeZoneCapabilities capabilities = new TimeZoneCapabilities.Builder(arbitraryUserHandle)
235                 .setConfigureAutoDetectionEnabledCapability(CAPABILITY_POSSESSED)
236                 .setUseLocationEnabled(useLocationEnabled)
237                 .setConfigureGeoDetectionEnabledCapability(configureGeoDetectionEnabledCapability)
238                 .setSetManualTimeZoneCapability(CAPABILITY_NOT_APPLICABLE)
239                 .setConfigureNotificationsEnabledCapability(CAPABILITY_POSSESSED)
240                 .build();
241 
242         TimeZoneConfiguration configuration = new TimeZoneConfiguration.Builder()
243                 .setAutoDetectionEnabled(setAutoDetectionEnabled)
244                 .setGeoDetectionEnabled(true)
245                 .setNotificationsEnabled(true)
246                 .build();
247 
248         return new TimeZoneCapabilitiesAndConfig(status, capabilities, configuration);
249     }
250 }
251