1 /*
2  * Copyright (C) 2021 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.server.uwb;
18 
19 import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
20 
21 import static org.junit.Assert.assertEquals;
22 import static org.mockito.ArgumentMatchers.any;
23 import static org.mockito.ArgumentMatchers.anyBoolean;
24 import static org.mockito.ArgumentMatchers.anyInt;
25 import static org.mockito.ArgumentMatchers.anyLong;
26 import static org.mockito.ArgumentMatchers.anyString;
27 import static org.mockito.ArgumentMatchers.eq;
28 import static org.mockito.Mockito.validateMockitoUsage;
29 import static org.mockito.Mockito.when;
30 import static org.mockito.Mockito.withSettings;
31 
32 import android.app.test.MockAnswerUtil;
33 import android.content.Context;
34 import android.content.res.Resources;
35 import android.os.Handler;
36 import android.os.test.TestLooper;
37 import android.provider.DeviceConfig;
38 
39 import com.android.dx.mockito.inline.extended.ExtendedMockito;
40 import com.android.server.uwb.DeviceConfigFacade.PoseSourceType;
41 import com.android.uwb.resources.R;
42 
43 import org.junit.After;
44 import org.junit.Before;
45 import org.junit.Test;
46 import org.mockito.ArgumentCaptor;
47 import org.mockito.Mock;
48 import org.mockito.MockitoAnnotations;
49 import org.mockito.MockitoSession;
50 
51 public class DeviceConfigFacadeTest {
52     @Mock private Resources mResources;
53     @Mock private Context mContext;
54 
55     final ArgumentCaptor<DeviceConfig.OnPropertiesChangedListener>
56             mOnPropertiesChangedListenerCaptor =
57             ArgumentCaptor.forClass(DeviceConfig.OnPropertiesChangedListener.class);
58 
59     private DeviceConfigFacade mDeviceConfigFacade;
60     private TestLooper mLooper = new TestLooper();
61     private MockitoSession mSession;
62 
63     /**
64      * Setup the mocks and an instance of DeviceConfig before each test.
65      */
66     @Before
setUp()67     public void setUp() throws Exception {
68         MockitoAnnotations.initMocks(this);
69         // static mocking
70         mSession = ExtendedMockito.mockitoSession()
71                 .mockStatic(DeviceConfig.class, withSettings().lenient())
72                 .startMocking();
73         // Have DeviceConfig return the default value passed in.
74         when(DeviceConfig.getBoolean(anyString(), anyString(), anyBoolean()))
75                 .then(new MockAnswerUtil.AnswerWithArguments() {
76                     public boolean answer(String namespace, String field, boolean def) {
77                         return def;
78                     }
79                 });
80         when(DeviceConfig.getInt(anyString(), anyString(), anyInt()))
81                 .then(new MockAnswerUtil.AnswerWithArguments() {
82                     public int answer(String namespace, String field, int def) {
83                         return def;
84                     }
85                 });
86         when(DeviceConfig.getLong(anyString(), anyString(), anyLong()))
87                 .then(new MockAnswerUtil.AnswerWithArguments() {
88                     public long answer(String namespace, String field, long def) {
89                         return def;
90                     }
91                 });
92         when(DeviceConfig.getString(anyString(), anyString(), anyString()))
93                 .then(new MockAnswerUtil.AnswerWithArguments() {
94                     public String answer(String namespace, String field, String def) {
95                         return def;
96                     }
97                 });
98 
99         when(mResources.getBoolean(R.bool.enable_filters)).thenReturn(true);
100         when(mResources.getBoolean(R.bool.enable_primer_est_elevation)).thenReturn(true);
101         when(mResources.getBoolean(R.bool.enable_primer_aoa)).thenReturn(true);
102         when(mResources.getInteger(R.integer.filter_distance_inliers_percent))
103                 .thenReturn(1);
104         when(mResources.getInteger(R.integer.filter_distance_window))
105                 .thenReturn(2);
106         when(mResources.getInteger(R.integer.filter_angle_inliers_percent))
107                 .thenReturn(3);
108         when(mResources.getInteger(R.integer.filter_angle_window))
109                 .thenReturn(4);
110         when(mResources.getInteger(R.integer.primer_fov_degrees))
111                 .thenReturn(5);
112         when(mResources.getString(R.string.pose_source_type))
113                 .thenReturn("ROTATION_VECTOR");
114         when(mResources.getInteger(R.integer.prediction_timeout_seconds))
115                 .thenReturn(6);
116         when(mResources.getBoolean(R.bool.enable_azimuth_mirroring)).thenReturn(true);
117         when(mResources.getBoolean(R.bool.predict_rear_azimuths)).thenReturn(true);
118         when(mResources.getInteger(R.integer.mirror_detection_window))
119                 .thenReturn(7);
120         when(mResources.getInteger(R.integer.front_mirror_dps))
121                 .thenReturn(8);
122         when(mResources.getInteger(R.integer.back_mirror_dps))
123                 .thenReturn(9);
124         when(mResources.getInteger(R.integer.mirror_score_std_degrees))
125                 .thenReturn(10);
126         when(mResources.getInteger(R.integer.back_noise_influence_percent))
127                 .thenReturn(11);
128 
129         // Setup the default values for the Advertising profile and Rx data packet parameters.
130         when(mResources.getInteger(R.integer.advertise_aoa_criteria_angle))
131                 .thenReturn(5);
132         when(mResources.getInteger(R.integer.advertise_time_threshold_millis))
133                 .thenReturn(2000);
134         when(mResources.getInteger(R.integer.advertise_array_size_to_check))
135                 .thenReturn(12);
136         when(mResources.getInteger(R.integer.advertise_array_start_index_to_cal_variance))
137                 .thenReturn(3);
138         when(mResources.getInteger(R.integer.advertise_array_end_index_to_cal_variance))
139                 .thenReturn(7);
140         when(mResources.getInteger(R.integer.advertise_trusted_variance_value))
141                 .thenReturn(12);
142         when(mResources.getInteger(R.integer.rx_data_max_packets_to_store))
143                 .thenReturn(10);
144         when(mResources.getBoolean(R.bool.background_ranging_enabled))
145                 .thenReturn(false);
146         when(mResources.getBoolean(R.bool.ranging_error_streak_timer_enabled))
147                 .thenReturn(true);
148         when(mResources.getBoolean(R.bool.ccc_ranging_stopped_params_send_enabled))
149                 .thenReturn(false);
150         when(mResources.getBoolean(R.bool.ccc_absolute_uwb_initiation_time_enabled))
151                 .thenReturn(false);
152         when(mResources.getBoolean(R.bool.location_use_for_country_code_enabled))
153                 .thenReturn(true);
154         when(mResources.getBoolean(R.bool.uwb_disabled_until_first_toggle))
155                 .thenReturn(false);
156         when(mResources.getBoolean(R.bool.persistent_cache_use_for_country_code_enabled))
157                 .thenReturn(false);
158         when(mResources.getBoolean(R.bool.hw_idle_turn_off_enabled))
159                 .thenReturn(false);
160         when(mResources.getBoolean(R.bool.is_antenna_mode_config_supported))
161                 .thenReturn(false);
162 
163         when(mContext.getResources()).thenReturn(mResources);
164 
165         mDeviceConfigFacade = new DeviceConfigFacade(new Handler(mLooper.getLooper()),
166                 mContext);
167         verify(() -> DeviceConfig.addOnPropertiesChangedListener(anyString(), any(),
168                 mOnPropertiesChangedListenerCaptor.capture()));
169     }
170 
171     /**
172      * Called after each test
173      */
174     @After
cleanup()175     public void cleanup() {
176         validateMockitoUsage();
177         mSession.finishMocking();
178     }
179 
180     /**
181      * Verifies that default values are set correctly
182      */
183     @Test
testDefaultValue()184     public void testDefaultValue() throws Exception {
185         assertEquals(DeviceConfigFacade.DEFAULT_RANGING_RESULT_LOG_INTERVAL_MS,
186                 mDeviceConfigFacade.getRangingResultLogIntervalMs());
187         assertEquals(false, mDeviceConfigFacade.isDeviceErrorBugreportEnabled());
188         assertEquals(false, mDeviceConfigFacade.isSessionInitErrorBugreportEnabled());
189         assertEquals(DeviceConfigFacade.DEFAULT_BUG_REPORT_MIN_INTERVAL_MS,
190                 mDeviceConfigFacade.getBugReportMinIntervalMs());
191 
192         assertEquals(true, mDeviceConfigFacade.isEnableFilters());
193         assertEquals(true, mDeviceConfigFacade.isEnablePrimerEstElevation());
194         assertEquals(true, mDeviceConfigFacade.isEnablePrimerAoA());
195         assertEquals(true, mDeviceConfigFacade.isEnableBackAzimuth());
196         assertEquals(true, mDeviceConfigFacade.isEnableBackAzimuthMasking());
197 
198         assertEquals(1, mDeviceConfigFacade.getFilterDistanceInliersPercent());
199         assertEquals(2, mDeviceConfigFacade.getFilterDistanceWindow());
200         assertEquals(3, mDeviceConfigFacade.getFilterAngleInliersPercent());
201         assertEquals(4, mDeviceConfigFacade.getFilterAngleWindow());
202         assertEquals(5, mDeviceConfigFacade.getPrimerFovDegree());
203         assertEquals(PoseSourceType.ROTATION_VECTOR, mDeviceConfigFacade.getPoseSourceType());
204         assertEquals(6, mDeviceConfigFacade.getPredictionTimeoutSeconds());
205         assertEquals(7, mDeviceConfigFacade.getBackAzimuthWindow());
206         assertEquals(
207                 Math.toRadians(8),
208                 mDeviceConfigFacade.getFrontAzimuthRadiansPerSecond(),
209                 0.001);
210         assertEquals(
211                 Math.toRadians(9),
212                 mDeviceConfigFacade.getBackAzimuthRadiansPerSecond(),
213                 0.001);
214         assertEquals(
215                 Math.toRadians(10),
216                 mDeviceConfigFacade.getMirrorScoreStdRadians(),
217                 0.001);
218         assertEquals(
219                 11 / 100F,
220                 mDeviceConfigFacade.getBackNoiseInfluenceCoeff(),
221                 0.001);
222 
223         // true because FOV is 5: within limits.
224         assertEquals(true, mDeviceConfigFacade.isEnablePrimerFov());
225 
226         // Check the default values for the Advertising profile and Rx packet parameters.
227         assertEquals(5, mDeviceConfigFacade.getAdvertiseAoaCriteriaAngle());
228         assertEquals(2000, mDeviceConfigFacade.getAdvertiseTimeThresholdMillis());
229         assertEquals(12, mDeviceConfigFacade.getAdvertiseArraySizeToCheck());
230         assertEquals(3, mDeviceConfigFacade.getAdvertiseArrayStartIndexToCalVariance());
231         assertEquals(7, mDeviceConfigFacade.getAdvertiseArrayEndIndexToCalVariance());
232         assertEquals(12, mDeviceConfigFacade.getAdvertiseTrustedVarianceValue());
233         assertEquals(10, mDeviceConfigFacade.getRxDataMaxPacketsToStore());
234         assertEquals(false, mDeviceConfigFacade.isBackgroundRangingEnabled());
235         assertEquals(true, mDeviceConfigFacade.isRangingErrorStreakTimerEnabled());
236         assertEquals(false, mDeviceConfigFacade.isCccRangingStoppedParamsSendEnabled());
237         assertEquals(false, mDeviceConfigFacade.isCccAbsoluteUwbInitiationTimeEnabled());
238         assertEquals(true, mDeviceConfigFacade.isLocationUseForCountryCodeEnabled());
239         assertEquals(false, mDeviceConfigFacade.isUwbDisabledUntilFirstToggle());
240         assertEquals(false, mDeviceConfigFacade.isPersistentCacheUseForCountryCodeEnabled());
241         assertEquals(false, mDeviceConfigFacade.isHwIdleTurnOffEnabled());
242         assertEquals(false, mDeviceConfigFacade.isAntennaModeConfigSupported());
243     }
244 
245     /**
246      * Verifies that all fields are updated properly.
247      */
248     @Test
testFieldUpdates()249     public void testFieldUpdates() throws Exception {
250         // These are interwoven (change then check, repeated) to make sure that copypasta
251         //  errors didn't cause two values to get flipped.
252 
253         // Simulate updating the fields, make sure the corresponding call is updated.
254         when(DeviceConfig.getInt(anyString(), eq("ranging_result_log_interval_ms"),
255                 anyInt())).thenReturn(4000);
256         mOnPropertiesChangedListenerCaptor.getValue().onPropertiesChanged(null);
257         assertEquals(4000, mDeviceConfigFacade.getRangingResultLogIntervalMs());
258 
259         when(DeviceConfig.getBoolean(anyString(), eq("device_error_bugreport_enabled"),
260                 anyBoolean())).thenReturn(true);
261         mOnPropertiesChangedListenerCaptor.getValue().onPropertiesChanged(null);
262         assertEquals(true, mDeviceConfigFacade.isDeviceErrorBugreportEnabled());
263 
264         when(DeviceConfig.getBoolean(anyString(), eq("session_init_error_bugreport_enabled"),
265                 anyBoolean())).thenReturn(true);
266         mOnPropertiesChangedListenerCaptor.getValue().onPropertiesChanged(null);
267         assertEquals(true, mDeviceConfigFacade.isSessionInitErrorBugreportEnabled());
268 
269         when(DeviceConfig.getInt(anyString(), eq("bug_report_min_interval_ms"),
270                 anyInt())).thenReturn(10 * 3600_000);
271         mOnPropertiesChangedListenerCaptor.getValue().onPropertiesChanged(null);
272         assertEquals(10 * 3600_000, mDeviceConfigFacade.getBugReportMinIntervalMs());
273 
274         when(DeviceConfig.getBoolean(anyString(), eq("enable_filters"),
275                 anyBoolean())).thenReturn(false);
276         mOnPropertiesChangedListenerCaptor.getValue().onPropertiesChanged(null);
277         assertEquals(false, mDeviceConfigFacade.isEnableFilters());
278 
279         when(DeviceConfig.getBoolean(anyString(), eq("enable_primer_est_elevation"),
280                 anyBoolean())).thenReturn(false);
281         mOnPropertiesChangedListenerCaptor.getValue().onPropertiesChanged(null);
282         assertEquals(false, mDeviceConfigFacade.isEnablePrimerEstElevation());
283 
284         when(DeviceConfig.getBoolean(anyString(), eq("enable_primer_aoa"),
285                 anyBoolean())).thenReturn(false);
286         mOnPropertiesChangedListenerCaptor.getValue().onPropertiesChanged(null);
287         assertEquals(false, mDeviceConfigFacade.isEnablePrimerAoA());
288 
289         when(DeviceConfig.getBoolean(anyString(), eq("enable_azimuth_mirroring"),
290                 anyBoolean())).thenReturn(false);
291         mOnPropertiesChangedListenerCaptor.getValue().onPropertiesChanged(null);
292         assertEquals(false, mDeviceConfigFacade.isEnableBackAzimuth());
293 
294         when(DeviceConfig.getBoolean(anyString(), eq("predict_rear_azimuths"),
295                 anyBoolean())).thenReturn(false);
296         mOnPropertiesChangedListenerCaptor.getValue().onPropertiesChanged(null);
297         assertEquals(false, mDeviceConfigFacade.isEnableBackAzimuthMasking());
298 
299         when(DeviceConfig.getInt(anyString(), eq("filter_distance_inliers_percent"),
300                 anyInt())).thenReturn(6);
301         mOnPropertiesChangedListenerCaptor.getValue().onPropertiesChanged(null);
302         assertEquals(6, mDeviceConfigFacade.getFilterDistanceInliersPercent());
303 
304         when(DeviceConfig.getInt(anyString(), eq("filter_distance_window"),
305                 anyInt())).thenReturn(7);
306         mOnPropertiesChangedListenerCaptor.getValue().onPropertiesChanged(null);
307         assertEquals(7, mDeviceConfigFacade.getFilterDistanceWindow());
308 
309         when(DeviceConfig.getInt(anyString(), eq("filter_angle_inliers_percent"),
310                 anyInt())).thenReturn(8);
311         mOnPropertiesChangedListenerCaptor.getValue().onPropertiesChanged(null);
312         assertEquals(8, mDeviceConfigFacade.getFilterAngleInliersPercent());
313 
314         when(DeviceConfig.getInt(anyString(), eq("filter_angle_window"),
315                 anyInt())).thenReturn(9);
316         mOnPropertiesChangedListenerCaptor.getValue().onPropertiesChanged(null);
317         assertEquals(9, mDeviceConfigFacade.getFilterAngleWindow());
318 
319         when(DeviceConfig.getInt(anyString(), eq("primer_fov_degrees"),
320                 anyInt())).thenReturn(0);
321         when(DeviceConfig.getString(anyString(), eq("pose_source_type"),
322                 anyString())).thenReturn("NONE");
323         when(DeviceConfig.getInt(anyString(), eq("prediction_timeout_seconds"),
324                 anyInt())).thenReturn(5);
325 
326         when(DeviceConfig.getInt(anyString(), eq("advertise_aoa_criteria_angle"), anyInt()))
327                 .thenReturn(20);
328         when(DeviceConfig.getInt(anyString(), eq("advertise_time_threshold_millis"), anyInt()))
329                 .thenReturn(3000);
330         when(DeviceConfig.getInt(anyString(), eq("advertise_array_size_to_check"), anyInt()))
331                 .thenReturn(15);
332         when(DeviceConfig.getInt(anyString(), eq("advertise_array_start_index_to_cal_variance"),
333                 anyInt())).thenReturn(3);
334         when(DeviceConfig.getInt(anyString(), eq("advertise_array_end_index_to_cal_variance"),
335                 anyInt())).thenReturn(7);
336         when(DeviceConfig.getInt(anyString(), eq("advertise_trusted_variance_value"), anyInt()))
337                 .thenReturn(12);
338         when(DeviceConfig.getInt(anyString(), eq("rx_data_max_packets_to_store"),
339                 anyInt())).thenReturn(20);
340         when(DeviceConfig.getBoolean(anyString(), eq("background_ranging_enabled"),
341                 anyBoolean())).thenReturn(true);
342         when(DeviceConfig.getBoolean(anyString(), eq("ranging_error_streak_timer_enabled"),
343                 anyBoolean())).thenReturn(false);
344         when(DeviceConfig.getBoolean(anyString(), eq("ccc_ranging_stopped_params_send_enabled"),
345                 anyBoolean())).thenReturn(true);
346         when(DeviceConfig.getBoolean(anyString(), eq("ccc_absolute_uwb_initiation_time_enabled"),
347                 anyBoolean())).thenReturn(true);
348         when(DeviceConfig.getBoolean(anyString(), eq("location_use_for_country_code_enabled"),
349                 anyBoolean())).thenReturn(false);
350         when(DeviceConfig.getBoolean(anyString(), eq("uwb_disabled_until_first_toggle"),
351                 anyBoolean())).thenReturn(true);
352         when(DeviceConfig.getBoolean(anyString(),
353                 eq("persistent_cache_use_for_country_code_enabled"),
354                 anyBoolean())).thenReturn(true);
355         when(DeviceConfig.getBoolean(anyString(), eq("hw_idle_turn_off_enabled"),
356                 anyBoolean())).thenReturn(true);
357         when(DeviceConfig.getBoolean(anyString(), eq("is_antenna_mode_config_supported"),
358                 anyBoolean())).thenReturn(true);
359 
360         mOnPropertiesChangedListenerCaptor.getValue().onPropertiesChanged(null);
361         assertEquals(0, mDeviceConfigFacade.getPrimerFovDegree());
362         // false because FOV is 0.
363         assertEquals(false, mDeviceConfigFacade.isEnablePrimerFov());
364 
365         assertEquals(20, mDeviceConfigFacade.getAdvertiseAoaCriteriaAngle());
366         assertEquals(3000, mDeviceConfigFacade.getAdvertiseTimeThresholdMillis());
367         assertEquals(15, mDeviceConfigFacade.getAdvertiseArraySizeToCheck());
368         assertEquals(3, mDeviceConfigFacade.getAdvertiseArrayStartIndexToCalVariance());
369         assertEquals(7 , mDeviceConfigFacade.getAdvertiseArrayEndIndexToCalVariance());
370         assertEquals(12, mDeviceConfigFacade.getAdvertiseTrustedVarianceValue());
371         assertEquals(20, mDeviceConfigFacade.getRxDataMaxPacketsToStore());
372         assertEquals(true, mDeviceConfigFacade.isBackgroundRangingEnabled());
373         assertEquals(false, mDeviceConfigFacade.isRangingErrorStreakTimerEnabled());
374         assertEquals(true, mDeviceConfigFacade.isCccRangingStoppedParamsSendEnabled());
375         assertEquals(true, mDeviceConfigFacade.isCccAbsoluteUwbInitiationTimeEnabled());
376         assertEquals(false, mDeviceConfigFacade.isLocationUseForCountryCodeEnabled());
377         assertEquals(true, mDeviceConfigFacade.isUwbDisabledUntilFirstToggle());
378         assertEquals(true, mDeviceConfigFacade.isPersistentCacheUseForCountryCodeEnabled());
379         assertEquals(true, mDeviceConfigFacade.isHwIdleTurnOffEnabled());
380         assertEquals(true, mDeviceConfigFacade.isAntennaModeConfigSupported());
381         when(DeviceConfig.getString(anyString(), eq("pose_source_type"),
382                 anyString())).thenReturn("NONE");
383         mOnPropertiesChangedListenerCaptor.getValue().onPropertiesChanged(null);
384         assertEquals(PoseSourceType.NONE, mDeviceConfigFacade.getPoseSourceType());
385 
386         when(DeviceConfig.getInt(anyString(), eq("prediction_timeout_seconds"),
387                 anyInt())).thenReturn(5);
388         mOnPropertiesChangedListenerCaptor.getValue().onPropertiesChanged(null);
389         assertEquals(5, mDeviceConfigFacade.getPredictionTimeoutSeconds());
390 
391         when(DeviceConfig.getInt(anyString(), eq("mirror_detection_window"),
392                 anyInt())).thenReturn(11);
393         mOnPropertiesChangedListenerCaptor.getValue().onPropertiesChanged(null);
394         assertEquals(11, mDeviceConfigFacade.getBackAzimuthWindow());
395 
396         when(DeviceConfig.getInt(anyString(), eq("front_mirror_dps"),
397                 anyInt())).thenReturn(12);
398         when(DeviceConfig.getInt(anyString(), eq("back_mirror_dps"),
399                 anyInt())).thenReturn(13);
400         when(DeviceConfig.getInt(anyString(), eq("mirror_score_std_degrees"),
401                 anyInt())).thenReturn(14);
402         when(DeviceConfig.getInt(anyString(), eq("back_noise_influence_percent"),
403                 anyInt())).thenReturn(15);
404 
405         mOnPropertiesChangedListenerCaptor.getValue().onPropertiesChanged(null);
406         assertEquals(
407                 Math.toRadians(12),
408                 mDeviceConfigFacade.getFrontAzimuthRadiansPerSecond(),
409                 0.001);
410         assertEquals(
411                 Math.toRadians(13),
412                 mDeviceConfigFacade.getBackAzimuthRadiansPerSecond(),
413                 0.001);
414         assertEquals(
415                 Math.toRadians(14),
416                 mDeviceConfigFacade.getMirrorScoreStdRadians(),
417                 0.001);
418         assertEquals(
419                 15 / 100F,
420                 mDeviceConfigFacade.getBackNoiseInfluenceCoeff(),
421                 0.001);
422     }
423 }
424