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 149 when(mContext.getResources()).thenReturn(mResources); 150 151 mDeviceConfigFacade = new DeviceConfigFacade(new Handler(mLooper.getLooper()), 152 mContext); 153 verify(() -> DeviceConfig.addOnPropertiesChangedListener(anyString(), any(), 154 mOnPropertiesChangedListenerCaptor.capture())); 155 } 156 157 /** 158 * Called after each test 159 */ 160 @After cleanup()161 public void cleanup() { 162 validateMockitoUsage(); 163 mSession.finishMocking(); 164 } 165 166 /** 167 * Verifies that default values are set correctly 168 */ 169 @Test testDefaultValue()170 public void testDefaultValue() throws Exception { 171 assertEquals(DeviceConfigFacade.DEFAULT_RANGING_RESULT_LOG_INTERVAL_MS, 172 mDeviceConfigFacade.getRangingResultLogIntervalMs()); 173 assertEquals(false, mDeviceConfigFacade.isDeviceErrorBugreportEnabled()); 174 assertEquals(false, mDeviceConfigFacade.isSessionInitErrorBugreportEnabled()); 175 assertEquals(DeviceConfigFacade.DEFAULT_BUG_REPORT_MIN_INTERVAL_MS, 176 mDeviceConfigFacade.getBugReportMinIntervalMs()); 177 178 assertEquals(true, mDeviceConfigFacade.isEnableFilters()); 179 assertEquals(true, mDeviceConfigFacade.isEnablePrimerEstElevation()); 180 assertEquals(true, mDeviceConfigFacade.isEnablePrimerAoA()); 181 assertEquals(true, mDeviceConfigFacade.isEnableBackAzimuth()); 182 assertEquals(true, mDeviceConfigFacade.isEnableBackAzimuthMasking()); 183 184 assertEquals(1, mDeviceConfigFacade.getFilterDistanceInliersPercent()); 185 assertEquals(2, mDeviceConfigFacade.getFilterDistanceWindow()); 186 assertEquals(3, mDeviceConfigFacade.getFilterAngleInliersPercent()); 187 assertEquals(4, mDeviceConfigFacade.getFilterAngleWindow()); 188 assertEquals(5, mDeviceConfigFacade.getPrimerFovDegree()); 189 assertEquals(PoseSourceType.ROTATION_VECTOR, mDeviceConfigFacade.getPoseSourceType()); 190 assertEquals(6, mDeviceConfigFacade.getPredictionTimeoutSeconds()); 191 assertEquals(7, mDeviceConfigFacade.getBackAzimuthWindow()); 192 assertEquals( 193 Math.toRadians(8), 194 mDeviceConfigFacade.getFrontAzimuthRadiansPerSecond(), 195 0.001); 196 assertEquals( 197 Math.toRadians(9), 198 mDeviceConfigFacade.getBackAzimuthRadiansPerSecond(), 199 0.001); 200 assertEquals( 201 Math.toRadians(10), 202 mDeviceConfigFacade.getMirrorScoreStdRadians(), 203 0.001); 204 assertEquals( 205 11 / 100F, 206 mDeviceConfigFacade.getBackNoiseInfluenceCoeff(), 207 0.001); 208 209 // true because FOV is 5: within limits. 210 assertEquals(true, mDeviceConfigFacade.isEnablePrimerFov()); 211 212 // Check the default values for the Advertising profile and Rx packet parameters. 213 assertEquals(5, mDeviceConfigFacade.getAdvertiseAoaCriteriaAngle()); 214 assertEquals(2000, mDeviceConfigFacade.getAdvertiseTimeThresholdMillis()); 215 assertEquals(12, mDeviceConfigFacade.getAdvertiseArraySizeToCheck()); 216 assertEquals(3, mDeviceConfigFacade.getAdvertiseArrayStartIndexToCalVariance()); 217 assertEquals(7, mDeviceConfigFacade.getAdvertiseArrayEndIndexToCalVariance()); 218 assertEquals(12, mDeviceConfigFacade.getAdvertiseTrustedVarianceValue()); 219 assertEquals(10, mDeviceConfigFacade.getRxDataMaxPacketsToStore()); 220 assertEquals(false, mDeviceConfigFacade.isBackgroundRangingEnabled()); 221 assertEquals(true, mDeviceConfigFacade.isRangingErrorStreakTimerEnabled()); 222 } 223 224 /** 225 * Verifies that all fields are updated properly. 226 */ 227 @Test testFieldUpdates()228 public void testFieldUpdates() throws Exception { 229 // These are interwoven (change then check, repeated) to make sure that copypasta 230 // errors didn't cause two values to get flipped. 231 232 // Simulate updating the fields, make sure the corresponding call is updated. 233 when(DeviceConfig.getInt(anyString(), eq("ranging_result_log_interval_ms"), 234 anyInt())).thenReturn(4000); 235 mOnPropertiesChangedListenerCaptor.getValue().onPropertiesChanged(null); 236 assertEquals(4000, mDeviceConfigFacade.getRangingResultLogIntervalMs()); 237 238 when(DeviceConfig.getBoolean(anyString(), eq("device_error_bugreport_enabled"), 239 anyBoolean())).thenReturn(true); 240 mOnPropertiesChangedListenerCaptor.getValue().onPropertiesChanged(null); 241 assertEquals(true, mDeviceConfigFacade.isDeviceErrorBugreportEnabled()); 242 243 when(DeviceConfig.getInt(anyString(), eq("bug_report_min_interval_ms"), 244 anyInt())).thenReturn(10 * 3600_000); 245 mOnPropertiesChangedListenerCaptor.getValue().onPropertiesChanged(null); 246 assertEquals(10 * 3600_000, mDeviceConfigFacade.getBugReportMinIntervalMs()); 247 248 when(DeviceConfig.getBoolean(anyString(), eq("enable_filters"), 249 anyBoolean())).thenReturn(false); 250 mOnPropertiesChangedListenerCaptor.getValue().onPropertiesChanged(null); 251 assertEquals(false, mDeviceConfigFacade.isEnableFilters()); 252 253 when(DeviceConfig.getBoolean(anyString(), eq("enable_primer_est_elevation"), 254 anyBoolean())).thenReturn(false); 255 mOnPropertiesChangedListenerCaptor.getValue().onPropertiesChanged(null); 256 assertEquals(false, mDeviceConfigFacade.isEnablePrimerEstElevation()); 257 258 when(DeviceConfig.getBoolean(anyString(), eq("enable_primer_aoa"), 259 anyBoolean())).thenReturn(false); 260 mOnPropertiesChangedListenerCaptor.getValue().onPropertiesChanged(null); 261 assertEquals(false, mDeviceConfigFacade.isEnablePrimerAoA()); 262 263 when(DeviceConfig.getBoolean(anyString(), eq("enable_azimuth_mirroring"), 264 anyBoolean())).thenReturn(false); 265 mOnPropertiesChangedListenerCaptor.getValue().onPropertiesChanged(null); 266 assertEquals(false, mDeviceConfigFacade.isEnableBackAzimuth()); 267 268 when(DeviceConfig.getBoolean(anyString(), eq("predict_rear_azimuths"), 269 anyBoolean())).thenReturn(false); 270 mOnPropertiesChangedListenerCaptor.getValue().onPropertiesChanged(null); 271 assertEquals(false, mDeviceConfigFacade.isEnableBackAzimuthMasking()); 272 273 when(DeviceConfig.getInt(anyString(), eq("filter_distance_inliers_percent"), 274 anyInt())).thenReturn(6); 275 mOnPropertiesChangedListenerCaptor.getValue().onPropertiesChanged(null); 276 assertEquals(6, mDeviceConfigFacade.getFilterDistanceInliersPercent()); 277 278 when(DeviceConfig.getInt(anyString(), eq("filter_distance_window"), 279 anyInt())).thenReturn(7); 280 mOnPropertiesChangedListenerCaptor.getValue().onPropertiesChanged(null); 281 assertEquals(7, mDeviceConfigFacade.getFilterDistanceWindow()); 282 283 when(DeviceConfig.getInt(anyString(), eq("filter_angle_inliers_percent"), 284 anyInt())).thenReturn(8); 285 mOnPropertiesChangedListenerCaptor.getValue().onPropertiesChanged(null); 286 assertEquals(8, mDeviceConfigFacade.getFilterAngleInliersPercent()); 287 288 when(DeviceConfig.getInt(anyString(), eq("filter_angle_window"), 289 anyInt())).thenReturn(9); 290 mOnPropertiesChangedListenerCaptor.getValue().onPropertiesChanged(null); 291 assertEquals(9, mDeviceConfigFacade.getFilterAngleWindow()); 292 293 when(DeviceConfig.getInt(anyString(), eq("primer_fov_degrees"), 294 anyInt())).thenReturn(0); 295 when(DeviceConfig.getString(anyString(), eq("pose_source_type"), 296 anyString())).thenReturn("NONE"); 297 when(DeviceConfig.getInt(anyString(), eq("prediction_timeout_seconds"), 298 anyInt())).thenReturn(5); 299 300 when(DeviceConfig.getInt(anyString(), eq("advertise_aoa_criteria_angle"), anyInt())) 301 .thenReturn(20); 302 when(DeviceConfig.getInt(anyString(), eq("advertise_time_threshold_millis"), anyInt())) 303 .thenReturn(3000); 304 when(DeviceConfig.getInt(anyString(), eq("advertise_array_size_to_check"), anyInt())) 305 .thenReturn(15); 306 when(DeviceConfig.getInt(anyString(), eq("advertise_array_start_index_to_cal_variance"), 307 anyInt())).thenReturn(3); 308 when(DeviceConfig.getInt(anyString(), eq("advertise_array_end_index_to_cal_variance"), 309 anyInt())).thenReturn(7); 310 when(DeviceConfig.getInt(anyString(), eq("advertise_trusted_variance_value"), anyInt())) 311 .thenReturn(12); 312 when(DeviceConfig.getInt(anyString(), eq("rx_data_max_packets_to_store"), 313 anyInt())).thenReturn(20); 314 when(DeviceConfig.getBoolean(anyString(), eq("background_ranging_enabled"), 315 anyBoolean())).thenReturn(true); 316 when(DeviceConfig.getBoolean(anyString(), eq("ranging_error_streak_timer_enabled"), 317 anyBoolean())).thenReturn(false); 318 319 mOnPropertiesChangedListenerCaptor.getValue().onPropertiesChanged(null); 320 assertEquals(0, mDeviceConfigFacade.getPrimerFovDegree()); 321 // false because FOV is 0. 322 assertEquals(false, mDeviceConfigFacade.isEnablePrimerFov()); 323 324 assertEquals(20, mDeviceConfigFacade.getAdvertiseAoaCriteriaAngle()); 325 assertEquals(3000, mDeviceConfigFacade.getAdvertiseTimeThresholdMillis()); 326 assertEquals(15, mDeviceConfigFacade.getAdvertiseArraySizeToCheck()); 327 assertEquals(3, mDeviceConfigFacade.getAdvertiseArrayStartIndexToCalVariance()); 328 assertEquals(7 , mDeviceConfigFacade.getAdvertiseArrayEndIndexToCalVariance()); 329 assertEquals(12, mDeviceConfigFacade.getAdvertiseTrustedVarianceValue()); 330 assertEquals(20, mDeviceConfigFacade.getRxDataMaxPacketsToStore()); 331 assertEquals(true, mDeviceConfigFacade.isBackgroundRangingEnabled()); 332 assertEquals(false, mDeviceConfigFacade.isRangingErrorStreakTimerEnabled()); 333 when(DeviceConfig.getString(anyString(), eq("pose_source_type"), 334 anyString())).thenReturn("NONE"); 335 mOnPropertiesChangedListenerCaptor.getValue().onPropertiesChanged(null); 336 assertEquals(PoseSourceType.NONE, mDeviceConfigFacade.getPoseSourceType()); 337 338 when(DeviceConfig.getInt(anyString(), eq("prediction_timeout_seconds"), 339 anyInt())).thenReturn(5); 340 mOnPropertiesChangedListenerCaptor.getValue().onPropertiesChanged(null); 341 assertEquals(5, mDeviceConfigFacade.getPredictionTimeoutSeconds()); 342 343 when(DeviceConfig.getInt(anyString(), eq("mirror_detection_window"), 344 anyInt())).thenReturn(11); 345 mOnPropertiesChangedListenerCaptor.getValue().onPropertiesChanged(null); 346 assertEquals(11, mDeviceConfigFacade.getBackAzimuthWindow()); 347 348 when(DeviceConfig.getInt(anyString(), eq("front_mirror_dps"), 349 anyInt())).thenReturn(12); 350 when(DeviceConfig.getInt(anyString(), eq("back_mirror_dps"), 351 anyInt())).thenReturn(13); 352 when(DeviceConfig.getInt(anyString(), eq("mirror_score_std_degrees"), 353 anyInt())).thenReturn(14); 354 when(DeviceConfig.getInt(anyString(), eq("back_noise_influence_percent"), 355 anyInt())).thenReturn(15); 356 357 mOnPropertiesChangedListenerCaptor.getValue().onPropertiesChanged(null); 358 assertEquals( 359 Math.toRadians(12), 360 mDeviceConfigFacade.getFrontAzimuthRadiansPerSecond(), 361 0.001); 362 assertEquals( 363 Math.toRadians(13), 364 mDeviceConfigFacade.getBackAzimuthRadiansPerSecond(), 365 0.001); 366 assertEquals( 367 Math.toRadians(14), 368 mDeviceConfigFacade.getMirrorScoreStdRadians(), 369 0.001); 370 assertEquals( 371 15 / 100F, 372 mDeviceConfigFacade.getBackNoiseInfluenceCoeff(), 373 0.001); 374 } 375 } 376