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 android.content.Context; 20 import android.os.Handler; 21 import android.provider.DeviceConfig; 22 import android.util.Log; 23 24 import com.android.uwb.resources.R; 25 26 /** 27 * This class allows getting all configurable flags from DeviceConfig. 28 */ 29 public class DeviceConfigFacade { 30 private static final String LOG_TAG = DeviceConfigFacade.class.getSimpleName(); 31 32 /** 33 */ 34 private static final int MAX_FOV = 180; 35 36 public static final int DEFAULT_RANGING_RESULT_LOG_INTERVAL_MS = 5_000; 37 private static final int MS_IN_HOUR = 60 * 60 * 1000; 38 public static final int DEFAULT_BUG_REPORT_MIN_INTERVAL_MS = 24 * MS_IN_HOUR; 39 private static final String TAG = "DeviceConfigFacadeUwb"; 40 41 public enum PoseSourceType { 42 NONE, 43 ROTATION_VECTOR, 44 GYRO, 45 SIXDOF, 46 DOUBLE_INTEGRATE, 47 } 48 49 private final Context mContext; 50 51 // Cached values of fields updated via updateDeviceConfigFlags() 52 private int mRangingResultLogIntervalMs; 53 private boolean mDeviceErrorBugreportEnabled; 54 private boolean mSessionInitErrorBugreportEnabled; 55 private int mBugReportMinIntervalMs; 56 private boolean mEnableFilters; 57 private int mFilterDistanceInliersPercent; 58 private int mFilterDistanceWindow; 59 private int mFilterAngleInliersPercent; 60 private int mFilterAngleWindow; 61 private PoseSourceType mPoseSourceType; 62 private boolean mEnablePrimerEstElevation; 63 private boolean mEnablePrimerAoA; 64 private boolean mEnablePrimerFov; 65 private int mPrimerFovDegree; 66 private boolean mEnableBackAzimuth; 67 private boolean mEnableBackAzimuthMasking; 68 private int mBackAzimuthWindow; 69 private float mFrontAzimuthRadiansPerSecond; 70 private float mBackAzimuthRadiansPerSecond; 71 private float mMirrorScoreStdRadians; 72 private float mBackNoiseInfluenceCoeff; 73 private int mPredictionTimeoutSeconds; 74 75 // Config parameters related to Advertising Profile. 76 private int mAdvertiseAoaCriteriaAngle; 77 private int mAdvertiseTimeThresholdMillis; 78 private int mAdvertiseArraySizeToCheck; 79 private int mAdvertiseArrayStartIndexToCalVariance; 80 private int mAdvertiseArrayEndIndexToCalVariance; 81 private int mAdvertiseTrustedVarianceValue; 82 83 // Config parameters related to Rx/Tx data packets. 84 private int mRxDataMaxPacketsToStore; 85 // Flag to enable unlimited background ranging. 86 private boolean mBackgroundRangingEnabled; 87 // Flag to disable error streak timer when a session is ongoing. 88 private boolean mRangingErrorStreakTimerEnabled; 89 DeviceConfigFacade(Handler handler, Context context)90 public DeviceConfigFacade(Handler handler, Context context) { 91 mContext = context; 92 93 updateDeviceConfigFlags(); 94 DeviceConfig.addOnPropertiesChangedListener( 95 DeviceConfig.NAMESPACE_UWB, 96 command -> handler.post(command), 97 properties -> { 98 updateDeviceConfigFlags(); 99 }); 100 } 101 updateDeviceConfigFlags()102 private void updateDeviceConfigFlags() { 103 String poseSourceName; 104 mRangingResultLogIntervalMs = DeviceConfig.getInt(DeviceConfig.NAMESPACE_UWB, 105 "ranging_result_log_interval_ms", DEFAULT_RANGING_RESULT_LOG_INTERVAL_MS); 106 mDeviceErrorBugreportEnabled = DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_UWB, 107 "device_error_bugreport_enabled", false); 108 mSessionInitErrorBugreportEnabled = DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_UWB, 109 "session_init_error_bugreport_enabled", false); 110 mBugReportMinIntervalMs = DeviceConfig.getInt(DeviceConfig.NAMESPACE_UWB, 111 "bug_report_min_interval_ms", DEFAULT_BUG_REPORT_MIN_INTERVAL_MS); 112 113 // Default values come from the overlay file (config.xml). 114 mEnableFilters = DeviceConfig.getBoolean( 115 DeviceConfig.NAMESPACE_UWB, 116 "enable_filters", 117 mContext.getResources().getBoolean(R.bool.enable_filters) 118 ); 119 mFilterDistanceInliersPercent = DeviceConfig.getInt( 120 DeviceConfig.NAMESPACE_UWB, 121 "filter_distance_inliers_percent", 122 mContext.getResources().getInteger(R.integer.filter_distance_inliers_percent) 123 ); 124 mFilterDistanceWindow = DeviceConfig.getInt( 125 DeviceConfig.NAMESPACE_UWB, 126 "filter_distance_window", 127 mContext.getResources().getInteger(R.integer.filter_distance_window) 128 ); 129 mFilterAngleInliersPercent = DeviceConfig.getInt( 130 DeviceConfig.NAMESPACE_UWB, 131 "filter_angle_inliers_percent", 132 mContext.getResources().getInteger(R.integer.filter_angle_inliers_percent) 133 ); 134 mFilterAngleWindow = DeviceConfig.getInt( 135 DeviceConfig.NAMESPACE_UWB, 136 "filter_angle_window", 137 mContext.getResources().getInteger(R.integer.filter_angle_window) 138 ); 139 poseSourceName = DeviceConfig.getString( 140 DeviceConfig.NAMESPACE_UWB, 141 "pose_source_type", 142 mContext.getResources().getString(R.string.pose_source_type) 143 ); 144 mEnablePrimerEstElevation = DeviceConfig.getBoolean( 145 DeviceConfig.NAMESPACE_UWB, 146 "enable_primer_est_elevation", 147 mContext.getResources().getBoolean(R.bool.enable_primer_est_elevation) 148 ); 149 mEnablePrimerAoA = DeviceConfig.getBoolean( 150 DeviceConfig.NAMESPACE_UWB, 151 "enable_primer_aoa", 152 mContext.getResources().getBoolean(R.bool.enable_primer_aoa) 153 ); 154 mPrimerFovDegree = DeviceConfig.getInt( 155 DeviceConfig.NAMESPACE_UWB, 156 "primer_fov_degrees", 157 mContext.getResources().getInteger(R.integer.primer_fov_degrees) 158 ); 159 mPredictionTimeoutSeconds = DeviceConfig.getInt( 160 DeviceConfig.NAMESPACE_UWB, 161 "prediction_timeout_seconds", 162 mContext.getResources().getInteger(R.integer.prediction_timeout_seconds) 163 ); 164 mEnableBackAzimuth = DeviceConfig.getBoolean( 165 DeviceConfig.NAMESPACE_UWB, 166 "enable_azimuth_mirroring", 167 mContext.getResources().getBoolean(R.bool.enable_azimuth_mirroring) 168 ); 169 mEnableBackAzimuthMasking = DeviceConfig.getBoolean( 170 DeviceConfig.NAMESPACE_UWB, 171 "predict_rear_azimuths", 172 mContext.getResources().getBoolean(R.bool.predict_rear_azimuths) 173 ); 174 mBackAzimuthWindow = DeviceConfig.getInt( 175 DeviceConfig.NAMESPACE_UWB, 176 "mirror_detection_window", 177 mContext.getResources().getInteger(R.integer.mirror_detection_window) 178 ); 179 int frontAzimuthDegreesPerSecond = DeviceConfig.getInt( 180 DeviceConfig.NAMESPACE_UWB, 181 "front_mirror_dps", 182 mContext.getResources().getInteger(R.integer.front_mirror_dps) 183 ); 184 int backAzimuthDegreesPerSecond = DeviceConfig.getInt( 185 DeviceConfig.NAMESPACE_UWB, 186 "back_mirror_dps", 187 mContext.getResources().getInteger(R.integer.back_mirror_dps) 188 ); 189 int mirrorScoreStdDegrees = DeviceConfig.getInt( 190 DeviceConfig.NAMESPACE_UWB, 191 "mirror_score_std_degrees", 192 mContext.getResources().getInteger(R.integer.mirror_score_std_degrees) 193 ); 194 int backNoiseInfluencePercent = DeviceConfig.getInt( 195 DeviceConfig.NAMESPACE_UWB, 196 "back_noise_influence_percent", 197 mContext.getResources().getInteger(R.integer.back_noise_influence_percent) 198 ); 199 200 // Read the Advertising profile config parameters. 201 mAdvertiseAoaCriteriaAngle = DeviceConfig.getInt( 202 DeviceConfig.NAMESPACE_UWB, 203 "advertise_aoa_criteria_angle", 204 mContext.getResources().getInteger(R.integer.advertise_aoa_criteria_angle) 205 ); 206 mAdvertiseTimeThresholdMillis = DeviceConfig.getInt( 207 DeviceConfig.NAMESPACE_UWB, 208 "advertise_time_threshold_millis", 209 mContext.getResources().getInteger(R.integer.advertise_time_threshold_millis) 210 ); 211 mAdvertiseArraySizeToCheck = DeviceConfig.getInt( 212 DeviceConfig.NAMESPACE_UWB, 213 "advertise_array_size_to_check", 214 mContext.getResources().getInteger(R.integer.advertise_array_size_to_check) 215 ); 216 mAdvertiseArrayStartIndexToCalVariance = DeviceConfig.getInt( 217 DeviceConfig.NAMESPACE_UWB, 218 "advertise_array_start_index_to_cal_variance", 219 mContext.getResources().getInteger( 220 R.integer.advertise_array_start_index_to_cal_variance) 221 ); 222 mAdvertiseArrayEndIndexToCalVariance = DeviceConfig.getInt( 223 DeviceConfig.NAMESPACE_UWB, 224 "advertise_array_end_index_to_cal_variance", 225 mContext.getResources().getInteger( 226 R.integer.advertise_array_end_index_to_cal_variance) 227 ); 228 mAdvertiseTrustedVarianceValue = DeviceConfig.getInt( 229 DeviceConfig.NAMESPACE_UWB, 230 "advertise_trusted_variance_value", 231 mContext.getResources().getInteger(R.integer.advertise_trusted_variance_value) 232 ); 233 234 // Rx data packets. 235 mRxDataMaxPacketsToStore = DeviceConfig.getInt( 236 DeviceConfig.NAMESPACE_UWB, 237 "rx_data_max_packets_to_store", 238 mContext.getResources().getInteger(R.integer.rx_data_max_packets_to_store) 239 ); 240 241 mBackgroundRangingEnabled = DeviceConfig.getBoolean( 242 DeviceConfig.NAMESPACE_UWB, 243 "background_ranging_enabled", 244 mContext.getResources().getBoolean(R.bool.background_ranging_enabled) 245 ); 246 247 mRangingErrorStreakTimerEnabled = DeviceConfig.getBoolean( 248 DeviceConfig.NAMESPACE_UWB, 249 "ranging_error_streak_timer_enabled", 250 mContext.getResources().getBoolean(R.bool.ranging_error_streak_timer_enabled) 251 ); 252 253 // A little parsing and cleanup: 254 mFrontAzimuthRadiansPerSecond = (float) Math.toRadians(frontAzimuthDegreesPerSecond); 255 mBackAzimuthRadiansPerSecond = (float) Math.toRadians(backAzimuthDegreesPerSecond); 256 mMirrorScoreStdRadians = (float) Math.toRadians(mirrorScoreStdDegrees); 257 mBackNoiseInfluenceCoeff = backNoiseInfluencePercent / 100F; 258 try { 259 mPoseSourceType = PoseSourceType.valueOf(poseSourceName); 260 } catch (IllegalArgumentException e) { 261 mPoseSourceType = PoseSourceType.ROTATION_VECTOR; 262 Log.e(LOG_TAG, "UWB pose source '" + poseSourceName + "' defined in flags or" 263 + "overlay file is invalid. Defaulting to " + mPoseSourceType.name()); 264 } 265 mEnablePrimerFov = mPrimerFovDegree > 0 && mPrimerFovDegree < MAX_FOV; 266 } 267 268 /** 269 * Gets ranging result logging interval in ms 270 */ 271 public int getRangingResultLogIntervalMs() { 272 return mRangingResultLogIntervalMs; 273 } 274 275 /** 276 * Gets the feature flag for reporting device error 277 */ 278 public boolean isDeviceErrorBugreportEnabled() { 279 return mDeviceErrorBugreportEnabled; 280 } 281 282 /** 283 * Gets the feature flag for reporting session init error 284 */ 285 public boolean isSessionInitErrorBugreportEnabled() { 286 return mSessionInitErrorBugreportEnabled; 287 } 288 289 /** 290 * Gets minimum wait time between two bug report captures 291 */ 292 public int getBugReportMinIntervalMs() { 293 return mBugReportMinIntervalMs; 294 } 295 296 /** 297 * Gets the flag for enabling UWB filtering. 298 */ 299 public boolean isEnableFilters() { 300 return mEnableFilters; 301 } 302 303 /** 304 * Gets the percentage (0-100) of inliers to be used in the distance filter cut. 305 */ 306 public int getFilterDistanceInliersPercent() { 307 return mFilterDistanceInliersPercent; 308 } 309 310 /** 311 * Gets the size of the distance filter moving window. 312 */ 313 public int getFilterDistanceWindow() { 314 return mFilterDistanceWindow; 315 } 316 317 /** 318 * Gets the percentage (0-100) of inliers to be used inthe angle filter cut. 319 */ 320 public int getFilterAngleInliersPercent() { 321 return mFilterAngleInliersPercent; 322 } 323 324 /** 325 * Gets the size of the angle filter moving window. 326 */ 327 public int getFilterAngleWindow() { 328 return mFilterAngleWindow; 329 } 330 331 /** 332 * Gets the type of pose source that should be used by default. 333 */ 334 public PoseSourceType getPoseSourceType() { 335 return mPoseSourceType; 336 } 337 338 /** 339 * Gets the flag that enables the elevation estimation primer. 340 */ 341 public boolean isEnablePrimerEstElevation() { 342 return mEnablePrimerEstElevation; 343 } 344 345 /** 346 * Gets the flag that enables the primer that converts AoA to spherical coordinates. 347 */ 348 public boolean isEnablePrimerAoA() { 349 return mEnablePrimerAoA; 350 } 351 352 /** 353 * Gets a value indicating if the FOV primer should be enabled. 354 */ 355 public boolean isEnablePrimerFov() { 356 return mEnablePrimerFov; 357 } 358 359 /** 360 * Gets the configured field of view. 361 */ 362 public int getPrimerFovDegree() { 363 return mPrimerFovDegree; 364 } 365 366 /** 367 * Gets how long to replace reports with an error status with predicted reports in seconds. 368 */ 369 public int getPredictionTimeoutSeconds() { 370 return mPredictionTimeoutSeconds; 371 } 372 373 /** 374 * Gets the flag that enables back-azimuth detection. 375 */ 376 public boolean isEnableBackAzimuth() { 377 return mEnableBackAzimuth; 378 } 379 380 /** 381 * Gets the flag that causes rear azimuth values to be replaced with predictions. 382 */ 383 public boolean isEnableBackAzimuthMasking() { 384 return mEnableBackAzimuthMasking; 385 } 386 387 /** 388 * Gets the size of the back-azimuth detection window. 389 */ 390 public int getBackAzimuthWindow() { 391 return mBackAzimuthWindow; 392 } 393 394 /** 395 * Gets minimum correlation rate required to assume azimuth readings are coming from the front. 396 */ 397 public float getFrontAzimuthRadiansPerSecond() { 398 return mFrontAzimuthRadiansPerSecond; 399 } 400 401 /** 402 * Gets minimum correlation rate required to assume azimuth readings are coming from the back. 403 */ 404 public float getBackAzimuthRadiansPerSecond() { 405 return mBackAzimuthRadiansPerSecond; 406 } 407 408 /** 409 * Gets the standard deviation of the mirror detection bell curve. 410 */ 411 public float getMirrorScoreStdRadians() { 412 return mMirrorScoreStdRadians; 413 } 414 415 /** 416 * Gets a coefficient of how much noise adds to the back-facing mirroring score. 417 */ 418 public float getBackNoiseInfluenceCoeff() { 419 return mBackNoiseInfluenceCoeff; 420 } 421 422 /** 423 * Gets the Advertising Profile AoA Criteria Angle. 424 */ 425 public int getAdvertiseAoaCriteriaAngle() { 426 return mAdvertiseAoaCriteriaAngle; 427 } 428 429 /** 430 * Gets the Advertising profile time threshold (for the received Owr Aoa Measurements). 431 */ 432 public int getAdvertiseTimeThresholdMillis() { 433 return mAdvertiseTimeThresholdMillis; 434 } 435 436 /** 437 * Gets the Advertising profile Array Size (of the stored values from Owr Aoa Measurements). 438 */ 439 public int getAdvertiseArraySizeToCheck() { 440 return mAdvertiseArraySizeToCheck; 441 } 442 443 /** 444 * Gets the Advertising profile Array Start Index (of the stored values from Owr Aoa 445 * Measurements), which we will use to calculate Variance. 446 */ 447 public int getAdvertiseArrayStartIndexToCalVariance() { 448 return mAdvertiseArrayStartIndexToCalVariance; 449 } 450 451 /** 452 * Gets the Advertising profile Array End Index (of the stored values from Owr Aoa 453 * Measurements), which we will use to calculate Variance. 454 */ 455 public int getAdvertiseArrayEndIndexToCalVariance() { 456 return mAdvertiseArrayEndIndexToCalVariance; 457 } 458 459 /** 460 * Gets the Advertising profile Trusted Variance Value (the threshold within which computed 461 * variance from the Owr Aoa Measurements is acceptable). 462 */ 463 public int getAdvertiseTrustedVarianceValue() { 464 return mAdvertiseTrustedVarianceValue; 465 } 466 467 /** 468 * Gets the max number of Rx data packets (received on a UWB session from the remote device), 469 * to be stored in the UWB framework. 470 */ 471 public int getRxDataMaxPacketsToStore() { 472 return mRxDataMaxPacketsToStore; 473 } 474 475 /** 476 * Returns whether background ranging is enabled or not. 477 * If enabled: 478 * * Background 3p apps are allowed to open new ranging sessions 479 * * When previously foreground 3p apps moves to background, sessions are not terminated 480 */ 481 public boolean isBackgroundRangingEnabled() { 482 return mBackgroundRangingEnabled; 483 } 484 485 /** 486 * Returns whether ranging error streak timer is enabled or not. 487 * If disabled, session would not be automatically stopped if there is no peer available. 488 */ 489 public boolean isRangingErrorStreakTimerEnabled() { 490 return mRangingErrorStreakTimerEnabled; 491 } 492 } 493