1 /* 2 * Copyright (C) 2016 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.systemui.doze; 18 19 import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FINGERPRINT; 20 import static android.hardware.biometrics.Flags.screenOffUnlockUdfps; 21 22 import static com.android.systemui.doze.DozeLog.REASON_SENSOR_QUICK_PICKUP; 23 import static com.android.systemui.doze.DozeLog.REASON_SENSOR_UDFPS_LONG_PRESS; 24 import static com.android.systemui.plugins.SensorManagerPlugin.Sensor.TYPE_WAKE_DISPLAY; 25 import static com.android.systemui.plugins.SensorManagerPlugin.Sensor.TYPE_WAKE_LOCK_SCREEN; 26 27 import android.annotation.AnyThread; 28 import android.content.res.Resources; 29 import android.database.ContentObserver; 30 import android.hardware.Sensor; 31 import android.hardware.SensorManager; 32 import android.hardware.TriggerEvent; 33 import android.hardware.TriggerEventListener; 34 import android.hardware.biometrics.BiometricAuthenticator; 35 import android.hardware.display.AmbientDisplayConfiguration; 36 import android.net.Uri; 37 import android.os.Handler; 38 import android.os.SystemClock; 39 import android.os.UserHandle; 40 import android.provider.Settings; 41 import android.text.TextUtils; 42 import android.util.IndentingPrintWriter; 43 import android.view.Display; 44 45 import androidx.annotation.NonNull; 46 import androidx.annotation.VisibleForTesting; 47 48 import com.android.internal.R; 49 import com.android.internal.logging.UiEvent; 50 import com.android.internal.logging.UiEventLogger; 51 import com.android.internal.logging.UiEventLoggerImpl; 52 import com.android.systemui.Flags; 53 import com.android.systemui.biometrics.AuthController; 54 import com.android.systemui.plugins.SensorManagerPlugin; 55 import com.android.systemui.statusbar.phone.DozeParameters; 56 import com.android.systemui.statusbar.policy.DevicePostureController; 57 import com.android.systemui.user.domain.interactor.SelectedUserInteractor; 58 import com.android.systemui.util.sensors.AsyncSensorManager; 59 import com.android.systemui.util.sensors.ProximitySensor; 60 import com.android.systemui.util.settings.SecureSettings; 61 import com.android.systemui.util.wakelock.WakeLock; 62 63 import java.io.PrintWriter; 64 import java.util.Arrays; 65 import java.util.Collection; 66 import java.util.HashMap; 67 import java.util.List; 68 import java.util.Map; 69 import java.util.Objects; 70 import java.util.function.Consumer; 71 72 /** 73 * Tracks and registers/unregisters sensors while the device is dozing based on the config 74 * provided by {@link AmbientDisplayConfiguration} and parameters provided by {@link DozeParameters} 75 * 76 * Sensors registration depends on: 77 * - sensor existence/availability 78 * - user configuration (some can be toggled on/off via settings) 79 * - use of the proximity sensor (sometimes prox cannot be registered in certain display states) 80 * - touch state 81 * - device posture 82 * 83 * Sensors will trigger the provided Callback's {@link Callback#onSensorPulse} method. 84 * These sensors include: 85 * - pickup gesture 86 * - single and double tap gestures 87 * - udfps long-press gesture 88 * - reach and presence gestures 89 * - quick pickup gesture (low-threshold pickup gesture) 90 * 91 * This class also registers a ProximitySensor that reports near/far events and will 92 * trigger callbacks on the provided {@link mProxCallback}. 93 */ 94 public class DozeSensors { 95 private static final String TAG = "DozeSensors"; 96 private static final UiEventLogger UI_EVENT_LOGGER = new UiEventLoggerImpl(); 97 private static final String KEY_DOZE_PULSE_ON_AUTH = "doze_pulse_on_auth"; 98 99 private final AsyncSensorManager mSensorManager; 100 private final AmbientDisplayConfiguration mConfig; 101 private final WakeLock mWakeLock; 102 private final DozeLog mDozeLog; 103 private final SecureSettings mSecureSettings; 104 private final DevicePostureController mDevicePostureController; 105 private final AuthController mAuthController; 106 private final SelectedUserInteractor mSelectedUserInteractor; 107 private final boolean mScreenOffUdfpsEnabled; 108 109 // Sensors 110 @VisibleForTesting 111 protected TriggerSensor[] mTriggerSensors; 112 private final ProximitySensor mProximitySensor; 113 114 // Sensor callbacks 115 private final Callback mSensorCallback; // receives callbacks on registered sensor events 116 private final Consumer<Boolean> mProxCallback; // receives callbacks on near/far updates 117 118 private final Handler mHandler = new Handler(); 119 private long mDebounceFrom; 120 private boolean mSettingRegistered; 121 private boolean mListening; 122 private boolean mListeningTouchScreenSensors; 123 private boolean mListeningProxSensors; 124 private boolean mListeningAodOnlySensors; 125 private boolean mUdfpsEnrolled; 126 127 @DevicePostureController.DevicePostureInt 128 private int mDevicePosture; 129 130 // whether to only register sensors that use prox when the display state is dozing or off 131 private boolean mSelectivelyRegisterProxSensors; 132 133 @VisibleForTesting 134 public enum DozeSensorsUiEvent implements UiEventLogger.UiEventEnum { 135 @UiEvent(doc = "User performs pickup gesture that activates the ambient display") 136 ACTION_AMBIENT_GESTURE_PICKUP(459); 137 138 private final int mId; 139 DozeSensorsUiEvent(int id)140 DozeSensorsUiEvent(int id) { 141 mId = id; 142 } 143 144 @Override getId()145 public int getId() { 146 return mId; 147 } 148 } 149 DozeSensors( Resources resources, AsyncSensorManager sensorManager, DozeParameters dozeParameters, AmbientDisplayConfiguration config, WakeLock wakeLock, Callback sensorCallback, Consumer<Boolean> proxCallback, DozeLog dozeLog, ProximitySensor proximitySensor, SecureSettings secureSettings, AuthController authController, DevicePostureController devicePostureController, SelectedUserInteractor selectedUserInteractor )150 DozeSensors( 151 Resources resources, 152 AsyncSensorManager sensorManager, 153 DozeParameters dozeParameters, 154 AmbientDisplayConfiguration config, 155 WakeLock wakeLock, 156 Callback sensorCallback, 157 Consumer<Boolean> proxCallback, 158 DozeLog dozeLog, 159 ProximitySensor proximitySensor, 160 SecureSettings secureSettings, 161 AuthController authController, 162 DevicePostureController devicePostureController, 163 SelectedUserInteractor selectedUserInteractor 164 ) { 165 mSensorManager = sensorManager; 166 mConfig = config; 167 mWakeLock = wakeLock; 168 mProxCallback = proxCallback; 169 mSecureSettings = secureSettings; 170 mSensorCallback = sensorCallback; 171 mDozeLog = dozeLog; 172 mProximitySensor = proximitySensor; 173 mProximitySensor.setTag(TAG); 174 mSelectivelyRegisterProxSensors = dozeParameters.getSelectivelyRegisterSensorsUsingProx(); 175 mListeningProxSensors = !mSelectivelyRegisterProxSensors; 176 mSelectedUserInteractor = selectedUserInteractor; 177 mScreenOffUdfpsEnabled = 178 config.screenOffUdfpsEnabled(mSelectedUserInteractor.getSelectedUserId()); 179 mDevicePostureController = devicePostureController; 180 mDevicePosture = mDevicePostureController.getDevicePosture(); 181 mAuthController = authController; 182 183 mUdfpsEnrolled = 184 mAuthController.isUdfpsEnrolled(mSelectedUserInteractor.getSelectedUserId()); 185 mAuthController.addCallback(mAuthControllerCallback); 186 mTriggerSensors = new TriggerSensor[] { 187 new TriggerSensor( 188 mSensorManager.getDefaultSensor(Sensor.TYPE_SIGNIFICANT_MOTION), 189 null /* setting */, 190 dozeParameters.getPulseOnSigMotion(), 191 DozeLog.PULSE_REASON_SENSOR_SIGMOTION, 192 false /* touchCoords */, 193 false /* touchscreen */ 194 ), 195 new TriggerSensor( 196 mSensorManager.getDefaultSensor(Sensor.TYPE_PICK_UP_GESTURE), 197 Settings.Secure.DOZE_PICK_UP_GESTURE, 198 resources.getBoolean( 199 R.bool.config_dozePickupGestureEnabled) /* settingDef */, 200 config.dozePickupSensorAvailable(), 201 DozeLog.REASON_SENSOR_PICKUP, false /* touchCoords */, 202 false /* touchscreen */, 203 false /* ignoresSetting */, 204 false /* requires prox */, 205 true /* immediatelyReRegister */, 206 false /* requiresAod */ 207 ), 208 new TriggerSensor( 209 findSensor(config.doubleTapSensorType()), 210 Settings.Secure.DOZE_DOUBLE_TAP_GESTURE, 211 true /* configured */, 212 DozeLog.REASON_SENSOR_DOUBLE_TAP, 213 dozeParameters.doubleTapReportsTouchCoordinates(), 214 true /* touchscreen */ 215 ), 216 new TriggerSensor( 217 findSensors(config.tapSensorTypeMapping()), 218 Settings.Secure.DOZE_TAP_SCREEN_GESTURE, 219 true /* settingDef */, 220 true /* configured */, 221 DozeLog.REASON_SENSOR_TAP, 222 true /* reports touch coordinates */, 223 true /* touchscreen */, 224 false /* ignoresSetting */, 225 dozeParameters.singleTapUsesProx(mDevicePosture) /* requiresProx */, 226 true /* immediatelyReRegister */, 227 mDevicePosture, 228 false 229 ), 230 new TriggerSensor( 231 findSensor(config.longPressSensorType()), 232 Settings.Secure.DOZE_PULSE_ON_LONG_PRESS, 233 false /* settingDef */, 234 true /* configured */, 235 DozeLog.PULSE_REASON_SENSOR_LONG_PRESS, 236 true /* reports touch coordinates */, 237 true /* touchscreen */, 238 false /* ignoresSetting */, 239 dozeParameters.longPressUsesProx() /* requiresProx */, 240 true /* immediatelyReRegister */, 241 false /* requiresAod */ 242 ), 243 new TriggerSensor( 244 findSensor(config.udfpsLongPressSensorType()), 245 KEY_DOZE_PULSE_ON_AUTH, 246 true /* settingDef */, 247 udfpsLongPressConfigured(), 248 DozeLog.REASON_SENSOR_UDFPS_LONG_PRESS, 249 true /* reports touch coordinates */, 250 true /* touchscreen */, 251 false /* ignoresSetting */, 252 dozeParameters.longPressUsesProx(), 253 screenOffUnlockUdfps() /* immediatelyReRegister */, 254 !screenOffUnlockUdfps() /* requiresAod */ 255 ), 256 new PluginSensor( 257 new SensorManagerPlugin.Sensor(TYPE_WAKE_DISPLAY), 258 Settings.Secure.DOZE_WAKE_DISPLAY_GESTURE, 259 mConfig.wakeScreenGestureAvailable() 260 && mConfig.alwaysOnEnabled( 261 mSelectedUserInteractor.getSelectedUserId()), 262 DozeLog.REASON_SENSOR_WAKE_UP_PRESENCE, 263 false /* reports touch coordinates */, 264 false /* touchscreen */ 265 ), 266 new PluginSensor( 267 new SensorManagerPlugin.Sensor(TYPE_WAKE_LOCK_SCREEN), 268 Settings.Secure.DOZE_WAKE_LOCK_SCREEN_GESTURE, 269 mConfig.wakeScreenGestureAvailable(), 270 DozeLog.PULSE_REASON_SENSOR_WAKE_REACH, 271 false /* reports touch coordinates */, 272 false /* touchscreen */, 273 mConfig.getWakeLockScreenDebounce() 274 ), 275 new TriggerSensor( 276 findSensor(config.quickPickupSensorType()), 277 Settings.Secure.DOZE_QUICK_PICKUP_GESTURE, 278 true /* setting default */, 279 quickPickUpConfigured(), 280 DozeLog.REASON_SENSOR_QUICK_PICKUP, 281 false /* requiresTouchCoordinates */, 282 false /* requiresTouchscreen */, 283 false /* ignoresSetting */, 284 false /* requiresProx */, 285 true /* immediatelyReRegister */, 286 false /* requiresAod */ 287 ), 288 }; 289 setProxListening(false); // Don't immediately start listening when we register. 290 mProximitySensor.register( 291 proximityEvent -> { 292 if (proximityEvent != null) { 293 mProxCallback.accept(!proximityEvent.getBelow()); 294 } 295 }); 296 297 mDevicePostureController.addCallback(mDevicePostureCallback); 298 } 299 udfpsLongPressConfigured()300 private boolean udfpsLongPressConfigured() { 301 return mUdfpsEnrolled 302 && (mConfig.alwaysOnEnabled(mSelectedUserInteractor.getSelectedUserId()) 303 || mScreenOffUdfpsEnabled); 304 } 305 quickPickUpConfigured()306 private boolean quickPickUpConfigured() { 307 return mUdfpsEnrolled 308 && mConfig.quickPickupSensorEnabled(mSelectedUserInteractor.getSelectedUserId()); 309 } 310 311 /** 312 * Unregister all sensors and callbacks. 313 */ destroy()314 public void destroy() { 315 // Unregisters everything, which is enough to allow gc. 316 for (TriggerSensor triggerSensor : mTriggerSensors) { 317 triggerSensor.setListening(false); 318 } 319 mProximitySensor.destroy(); 320 321 mDevicePostureController.removeCallback(mDevicePostureCallback); 322 mAuthController.removeCallback(mAuthControllerCallback); 323 } 324 325 /** 326 * Temporarily disable some sensors to avoid turning on the device while the user is 327 * turning it off. 328 */ requestTemporaryDisable()329 public void requestTemporaryDisable() { 330 mDebounceFrom = SystemClock.uptimeMillis(); 331 } 332 findSensor(String type)333 private Sensor findSensor(String type) { 334 return findSensor(mSensorManager, type, null); 335 } 336 337 @NonNull findSensors(@onNull String[] types)338 private Sensor[] findSensors(@NonNull String[] types) { 339 Sensor[] sensorMap = new Sensor[DevicePostureController.SUPPORTED_POSTURES_SIZE]; 340 341 // Map of sensorType => Sensor, so we reuse the same sensor if it's the same between 342 // postures 343 Map<String, Sensor> typeToSensorMap = new HashMap<>(); 344 for (int i = 0; i < types.length; i++) { 345 String sensorType = types[i]; 346 if (!typeToSensorMap.containsKey(sensorType)) { 347 typeToSensorMap.put(sensorType, findSensor(sensorType)); 348 } 349 sensorMap[i] = typeToSensorMap.get(sensorType); 350 } 351 352 return sensorMap; 353 } 354 355 /** 356 * Utility method to find a {@link Sensor} for the supplied string type and string name. 357 * 358 * Return the first sensor in the list that matches the specified inputs. Ignores type or name 359 * if the input is null or empty. 360 * 361 * @param type sensorType 362 * @parm name sensorName, to differentiate between sensors with the same type 363 */ findSensor(SensorManager sensorManager, String type, String name)364 public static Sensor findSensor(SensorManager sensorManager, String type, String name) { 365 final boolean isNameSpecified = !TextUtils.isEmpty(name); 366 final boolean isTypeSpecified = !TextUtils.isEmpty(type); 367 if (isNameSpecified || isTypeSpecified) { 368 final List<Sensor> sensors = sensorManager.getSensorList(Sensor.TYPE_ALL); 369 for (Sensor sensor : sensors) { 370 if ((!isNameSpecified || name.equals(sensor.getName())) 371 && (!isTypeSpecified || type.equals(sensor.getStringType()))) { 372 return sensor; 373 } 374 } 375 } 376 return null; 377 } 378 379 /** 380 * If sensors should be registered and sending signals. 381 */ setListening(boolean listen, boolean includeTouchScreenSensors, boolean includeAodOnlySensors)382 public void setListening(boolean listen, boolean includeTouchScreenSensors, 383 boolean includeAodOnlySensors) { 384 if (mListening == listen && mListeningTouchScreenSensors == includeTouchScreenSensors 385 && mListeningAodOnlySensors == includeAodOnlySensors) { 386 return; 387 } 388 mListening = listen; 389 mListeningTouchScreenSensors = includeTouchScreenSensors; 390 mListeningAodOnlySensors = includeAodOnlySensors; 391 updateListening(); 392 } 393 394 /** 395 * If sensors should be registered and sending signals. 396 */ setListeningWithPowerState(boolean listen, boolean includeTouchScreenSensors, boolean includeAodRequiringSensors, boolean lowPowerStateOrOff)397 public void setListeningWithPowerState(boolean listen, boolean includeTouchScreenSensors, 398 boolean includeAodRequiringSensors, boolean lowPowerStateOrOff) { 399 final boolean shouldRegisterProxSensors = 400 !mSelectivelyRegisterProxSensors || lowPowerStateOrOff; 401 if (mListening == listen 402 && mListeningTouchScreenSensors == includeTouchScreenSensors 403 && mListeningProxSensors == shouldRegisterProxSensors 404 && mListeningAodOnlySensors == includeAodRequiringSensors 405 ) { 406 return; 407 } 408 mListening = listen; 409 mListeningTouchScreenSensors = includeTouchScreenSensors; 410 mListeningProxSensors = shouldRegisterProxSensors; 411 mListeningAodOnlySensors = includeAodRequiringSensors; 412 updateListening(); 413 } 414 415 /** 416 * Registers/unregisters sensors based on internal state. 417 */ updateListening()418 private void updateListening() { 419 boolean anyListening = false; 420 for (TriggerSensor s : mTriggerSensors) { 421 boolean listen = mListening 422 && (!s.mRequiresTouchscreen || mListeningTouchScreenSensors) 423 && (!s.mRequiresProx || mListeningProxSensors) 424 && (!s.mRequiresAod || mListeningAodOnlySensors); 425 426 //AOD might be turned off in visual because of BetterySaver or isAlwaysOnSuppressed(), 427 //but AOD isn't really turned off, in these cases, udfpsLongPressSensor should be 428 //unregistered. 429 if (!mListeningAodOnlySensors && KEY_DOZE_PULSE_ON_AUTH.equals(s.mSetting)) { 430 if (mConfig.alwaysOnEnabled(mSelectedUserInteractor.getSelectedUserId()) 431 && !mConfig.screenOffUdfpsEnabled( 432 mSelectedUserInteractor.getSelectedUserId())) { 433 listen = false; 434 } 435 } 436 437 s.setListening(listen); 438 if (listen) { 439 anyListening = true; 440 } 441 } 442 443 if (!anyListening) { 444 if (Flags.registerContentObserversAsync()) { 445 mSecureSettings.unregisterContentObserverAsync(mSettingsObserver); 446 } else { 447 mSecureSettings.unregisterContentObserverSync(mSettingsObserver); 448 } 449 } else if (!mSettingRegistered) { 450 for (TriggerSensor s : mTriggerSensors) { 451 s.registerSettingsObserver(mSettingsObserver); 452 } 453 } 454 mSettingRegistered = anyListening; 455 } 456 457 /** Set the listening state of only the sensors that require the touchscreen. */ setTouchscreenSensorsListening(boolean listening)458 public void setTouchscreenSensorsListening(boolean listening) { 459 for (TriggerSensor sensor : mTriggerSensors) { 460 if (sensor.mRequiresTouchscreen) { 461 sensor.setListening(listening); 462 } 463 } 464 } 465 onUserSwitched()466 public void onUserSwitched() { 467 for (TriggerSensor s : mTriggerSensors) { 468 s.updateListening(); 469 } 470 } 471 onScreenState(int state)472 void onScreenState(int state) { 473 mProximitySensor.setSecondarySafe( 474 state == Display.STATE_DOZE 475 || state == Display.STATE_DOZE_SUSPEND 476 || state == Display.STATE_OFF); 477 } 478 setProxListening(boolean listen)479 public void setProxListening(boolean listen) { 480 if (mProximitySensor.isRegistered() && listen) { 481 mProximitySensor.alertListeners(); 482 } else { 483 if (listen) { 484 mProximitySensor.resume(); 485 } else { 486 mProximitySensor.pause(); 487 } 488 } 489 } 490 491 private final ContentObserver mSettingsObserver = new ContentObserver(mHandler) { 492 @Override 493 public void onChange(boolean selfChange, Collection<Uri> uris, int flags, int userId) { 494 if (userId != mSelectedUserInteractor.getSelectedUserId()) { 495 return; 496 } 497 for (TriggerSensor s : mTriggerSensors) { 498 s.updateListening(); 499 } 500 } 501 }; 502 503 /** Ignore the setting value of only the sensors that require the touchscreen. */ ignoreTouchScreenSensorsSettingInterferingWithDocking(boolean ignore)504 public void ignoreTouchScreenSensorsSettingInterferingWithDocking(boolean ignore) { 505 for (TriggerSensor sensor : mTriggerSensors) { 506 if (sensor.mRequiresTouchscreen) { 507 sensor.ignoreSetting(ignore); 508 } 509 } 510 } 511 512 /** Dump current state */ dump(PrintWriter pw)513 public void dump(PrintWriter pw) { 514 pw.println("mListening=" + mListening); 515 pw.println("mDevicePosture=" 516 + DevicePostureController.devicePostureToString(mDevicePosture)); 517 pw.println("mListeningTouchScreenSensors=" + mListeningTouchScreenSensors); 518 pw.println("mSelectivelyRegisterProxSensors=" + mSelectivelyRegisterProxSensors); 519 pw.println("mListeningProxSensors=" + mListeningProxSensors); 520 pw.println("mScreenOffUdfpsEnabled=" + mScreenOffUdfpsEnabled); 521 pw.println("mUdfpsEnrolled=" + mUdfpsEnrolled); 522 IndentingPrintWriter idpw = new IndentingPrintWriter(pw); 523 idpw.increaseIndent(); 524 for (TriggerSensor s : mTriggerSensors) { 525 idpw.println("Sensor: " + s.toString()); 526 } 527 idpw.println("ProxSensor: " + mProximitySensor.toString()); 528 } 529 530 /** 531 * @return true if prox is currently near, false if far or null if unknown. 532 */ isProximityCurrentlyNear()533 public Boolean isProximityCurrentlyNear() { 534 return mProximitySensor.isNear(); 535 } 536 537 @VisibleForTesting 538 class TriggerSensor extends TriggerEventListener { 539 @NonNull final Sensor[] mSensors; // index = posture, value = sensor 540 boolean mConfigured; 541 final int mPulseReason; 542 private final String mSetting; 543 private final boolean mReportsTouchCoordinates; 544 private final boolean mSettingDefault; 545 private final boolean mRequiresTouchscreen; 546 private final boolean mRequiresProx; 547 548 // Whether the sensor should only register if the device is in AOD 549 private final boolean mRequiresAod; 550 551 // Whether to immediately re-register this sensor after the sensor is triggered. 552 // If false, the sensor registration will be updated on the next AOD state transition. 553 private final boolean mImmediatelyReRegister; 554 555 protected boolean mRequested; 556 protected boolean mRegistered; 557 protected boolean mDisabled; 558 protected boolean mIgnoresSetting; 559 private @DevicePostureController.DevicePostureInt int mPosture; 560 TriggerSensor( Sensor sensor, String setting, boolean configured, int pulseReason, boolean reportsTouchCoordinates, boolean requiresTouchscreen )561 TriggerSensor( 562 Sensor sensor, 563 String setting, 564 boolean configured, 565 int pulseReason, 566 boolean reportsTouchCoordinates, 567 boolean requiresTouchscreen 568 ) { 569 this( 570 sensor, 571 setting, 572 true /* settingDef */, 573 configured, 574 pulseReason, 575 reportsTouchCoordinates, 576 requiresTouchscreen, 577 false /* ignoresSetting */, 578 false /* requiresProx */, 579 true /* immediatelyReRegister */, 580 false 581 ); 582 } 583 TriggerSensor( Sensor sensor, String setting, boolean settingDef, boolean configured, int pulseReason, boolean reportsTouchCoordinates, boolean requiresTouchscreen, boolean ignoresSetting, boolean requiresProx, boolean immediatelyReRegister, boolean requiresAod )584 TriggerSensor( 585 Sensor sensor, 586 String setting, 587 boolean settingDef, 588 boolean configured, 589 int pulseReason, 590 boolean reportsTouchCoordinates, 591 boolean requiresTouchscreen, 592 boolean ignoresSetting, 593 boolean requiresProx, 594 boolean immediatelyReRegister, 595 boolean requiresAod 596 ) { 597 this( 598 new Sensor[]{ sensor }, 599 setting, 600 settingDef, 601 configured, 602 pulseReason, 603 reportsTouchCoordinates, 604 requiresTouchscreen, 605 ignoresSetting, 606 requiresProx, 607 immediatelyReRegister, 608 DevicePostureController.DEVICE_POSTURE_UNKNOWN, 609 requiresAod 610 ); 611 } 612 TriggerSensor( @onNull Sensor[] sensors, String setting, boolean settingDef, boolean configured, int pulseReason, boolean reportsTouchCoordinates, boolean requiresTouchscreen, boolean ignoresSetting, boolean requiresProx, boolean immediatelyReRegister, @DevicePostureController.DevicePostureInt int posture, boolean requiresAod )613 TriggerSensor( 614 @NonNull Sensor[] sensors, 615 String setting, 616 boolean settingDef, 617 boolean configured, 618 int pulseReason, 619 boolean reportsTouchCoordinates, 620 boolean requiresTouchscreen, 621 boolean ignoresSetting, 622 boolean requiresProx, 623 boolean immediatelyReRegister, 624 @DevicePostureController.DevicePostureInt int posture, 625 boolean requiresAod 626 ) { 627 mSensors = sensors; 628 mSetting = setting; 629 mSettingDefault = settingDef; 630 mConfigured = configured; 631 mPulseReason = pulseReason; 632 mReportsTouchCoordinates = reportsTouchCoordinates; 633 mRequiresTouchscreen = requiresTouchscreen; 634 mIgnoresSetting = ignoresSetting; 635 mRequiresProx = requiresProx; 636 mRequiresAod = requiresAod; 637 mPosture = posture; 638 mImmediatelyReRegister = immediatelyReRegister; 639 } 640 641 /** 642 * @return true if the sensor changed based for the new posture 643 */ setPosture(@evicePostureController.DevicePostureInt int posture)644 public boolean setPosture(@DevicePostureController.DevicePostureInt int posture) { 645 if (mPosture == posture 646 || mSensors.length < 2 647 || posture >= mSensors.length) { 648 return false; 649 } 650 651 Sensor oldSensor = mSensors[mPosture]; 652 Sensor newSensor = mSensors[posture]; 653 if (Objects.equals(oldSensor, newSensor)) { 654 mPosture = posture; 655 // uses the same sensor for the new posture 656 return false; 657 } 658 659 // cancel the previous sensor: 660 if (mRegistered) { 661 final boolean rt = mSensorManager.cancelTriggerSensor(this, oldSensor); 662 mDozeLog.traceSensorUnregisterAttempt(oldSensor.toString(), rt, "posture changed"); 663 mRegistered = false; 664 } 665 666 // update the new sensor: 667 mPosture = posture; 668 updateListening(); 669 mDozeLog.tracePostureChanged(mPosture, "DozeSensors swap " 670 + "{" + oldSensor + "} => {" + newSensor + "}, mRegistered=" + mRegistered); 671 return true; 672 } 673 setListening(boolean listen)674 public void setListening(boolean listen) { 675 if (mRequested == listen) return; 676 mRequested = listen; 677 updateListening(); 678 } 679 setDisabled(boolean disabled)680 public void setDisabled(boolean disabled) { 681 if (mDisabled == disabled) return; 682 mDisabled = disabled; 683 updateListening(); 684 } 685 ignoreSetting(boolean ignored)686 public void ignoreSetting(boolean ignored) { 687 if (mIgnoresSetting == ignored) return; 688 mIgnoresSetting = ignored; 689 updateListening(); 690 } 691 692 /** 693 * Update configured state. 694 */ setConfigured(boolean configured)695 public void setConfigured(boolean configured) { 696 if (mConfigured == configured) return; 697 mConfigured = configured; 698 updateListening(); 699 } 700 updateListening()701 public void updateListening() { 702 final Sensor sensor = mSensors[mPosture]; 703 704 if (!mConfigured || sensor == null) return; 705 if (mRequested && !mDisabled && (enabledBySetting() || mIgnoresSetting)) { 706 if (!mRegistered) { 707 mRegistered = mSensorManager.requestTriggerSensor(this, sensor); 708 mDozeLog.traceSensorRegisterAttempt(sensor.toString(), mRegistered); 709 } else { 710 mDozeLog.traceSkipRegisterSensor(sensor.toString()); 711 } 712 } else if (mRegistered) { 713 final boolean rt = mSensorManager.cancelTriggerSensor(this, sensor); 714 mDozeLog.traceSensorUnregisterAttempt(sensor.toString(), rt); 715 mRegistered = false; 716 } 717 } 718 enabledBySetting()719 protected boolean enabledBySetting() { 720 if (!mConfig.enabled(mSelectedUserInteractor.getSelectedUserId())) { 721 return false; 722 } else if (TextUtils.isEmpty(mSetting)) { 723 return true; 724 } 725 return mSecureSettings.getIntForUser(mSetting, mSettingDefault ? 1 : 0, 726 mSelectedUserInteractor.getSelectedUserId()) != 0; 727 } 728 729 @Override toString()730 public String toString() { 731 StringBuilder sb = new StringBuilder(); 732 sb.append("{") 733 .append("mRegistered=").append(mRegistered) 734 .append(", mRequested=").append(mRequested) 735 .append(", mDisabled=").append(mDisabled) 736 .append(", mConfigured=").append(mConfigured) 737 .append(", mIgnoresSetting=").append(mIgnoresSetting) 738 .append(", mSensors=").append(Arrays.toString(mSensors)); 739 if (mSensors.length > 2) { 740 sb.append(", mPosture=") 741 .append(DevicePostureController.devicePostureToString(mDevicePosture)); 742 } 743 return sb.append("}").toString(); 744 } 745 746 @Override 747 @AnyThread onTrigger(TriggerEvent event)748 public void onTrigger(TriggerEvent event) { 749 final Sensor sensor = mSensors[mPosture]; 750 mDozeLog.traceSensor(mPulseReason); 751 mHandler.post(mWakeLock.wrap(() -> { 752 if (sensor != null && sensor.getType() == Sensor.TYPE_PICK_UP_GESTURE) { 753 UI_EVENT_LOGGER.log(DozeSensorsUiEvent.ACTION_AMBIENT_GESTURE_PICKUP); 754 } 755 756 mRegistered = false; 757 float screenX = -1; 758 float screenY = -1; 759 if (mReportsTouchCoordinates && event.values.length >= 2) { 760 screenX = event.values[0]; 761 screenY = event.values[1]; 762 } 763 mSensorCallback.onSensorPulse(mPulseReason, screenX, screenY, event.values); 764 if (!mRegistered && mImmediatelyReRegister) { 765 updateListening(); 766 } 767 })); 768 } 769 registerSettingsObserver(ContentObserver settingsObserver)770 public void registerSettingsObserver(ContentObserver settingsObserver) { 771 if (mConfigured && !TextUtils.isEmpty(mSetting)) { 772 if (Flags.registerContentObserversAsync()) { 773 mSecureSettings.registerContentObserverForUserAsync( 774 mSetting, mSettingsObserver, UserHandle.USER_ALL); 775 } else { 776 mSecureSettings.registerContentObserverForUserSync( 777 mSetting, mSettingsObserver, UserHandle.USER_ALL); 778 } 779 } 780 } 781 triggerEventToString(TriggerEvent event)782 protected String triggerEventToString(TriggerEvent event) { 783 if (event == null) return null; 784 final StringBuilder sb = new StringBuilder("SensorEvent[") 785 .append(event.timestamp).append(',') 786 .append(event.sensor.getName()); 787 if (event.values != null) { 788 for (int i = 0; i < event.values.length; i++) { 789 sb.append(',').append(event.values[i]); 790 } 791 } 792 return sb.append(']').toString(); 793 } 794 } 795 796 /** 797 * A Sensor that is injected via plugin. 798 */ 799 @VisibleForTesting 800 class PluginSensor extends TriggerSensor implements SensorManagerPlugin.SensorEventListener { 801 802 final SensorManagerPlugin.Sensor mPluginSensor; 803 private long mDebounce; 804 PluginSensor(SensorManagerPlugin.Sensor sensor, String setting, boolean configured, int pulseReason, boolean reportsTouchCoordinates, boolean requiresTouchscreen)805 PluginSensor(SensorManagerPlugin.Sensor sensor, String setting, boolean configured, 806 int pulseReason, boolean reportsTouchCoordinates, boolean requiresTouchscreen) { 807 this(sensor, setting, configured, pulseReason, reportsTouchCoordinates, 808 requiresTouchscreen, 0L /* debounce */); 809 } 810 PluginSensor(SensorManagerPlugin.Sensor sensor, String setting, boolean configured, int pulseReason, boolean reportsTouchCoordinates, boolean requiresTouchscreen, long debounce)811 PluginSensor(SensorManagerPlugin.Sensor sensor, String setting, boolean configured, 812 int pulseReason, boolean reportsTouchCoordinates, boolean requiresTouchscreen, 813 long debounce) { 814 super(null, setting, configured, pulseReason, reportsTouchCoordinates, 815 requiresTouchscreen); 816 mPluginSensor = sensor; 817 mDebounce = debounce; 818 } 819 820 @Override updateListening()821 public void updateListening() { 822 if (!mConfigured) return; 823 AsyncSensorManager asyncSensorManager = (AsyncSensorManager) mSensorManager; 824 if (mRequested && !mDisabled && (enabledBySetting() || mIgnoresSetting) 825 && !mRegistered) { 826 asyncSensorManager.registerPluginListener(mPluginSensor, this); 827 mRegistered = true; 828 mDozeLog.tracePluginSensorUpdate(true /* registered */); 829 } else if (mRegistered) { 830 asyncSensorManager.unregisterPluginListener(mPluginSensor, this); 831 mRegistered = false; 832 mDozeLog.tracePluginSensorUpdate(false /* registered */); 833 } 834 } 835 836 @Override toString()837 public String toString() { 838 return new StringBuilder("{mRegistered=").append(mRegistered) 839 .append(", mRequested=").append(mRequested) 840 .append(", mDisabled=").append(mDisabled) 841 .append(", mConfigured=").append(mConfigured) 842 .append(", mIgnoresSetting=").append(mIgnoresSetting) 843 .append(", mSensor=").append(mPluginSensor).append("}").toString(); 844 } 845 triggerEventToString(SensorManagerPlugin.SensorEvent event)846 private String triggerEventToString(SensorManagerPlugin.SensorEvent event) { 847 if (event == null) return null; 848 final StringBuilder sb = new StringBuilder("PluginTriggerEvent[") 849 .append(event.getSensor()).append(',') 850 .append(event.getVendorType()); 851 if (event.getValues() != null) { 852 for (int i = 0; i < event.getValues().length; i++) { 853 sb.append(',').append(event.getValues()[i]); 854 } 855 } 856 return sb.append(']').toString(); 857 } 858 859 @Override onSensorChanged(SensorManagerPlugin.SensorEvent event)860 public void onSensorChanged(SensorManagerPlugin.SensorEvent event) { 861 mDozeLog.traceSensor(mPulseReason); 862 mHandler.post(mWakeLock.wrap(() -> { 863 final long now = SystemClock.uptimeMillis(); 864 if (now < mDebounceFrom + mDebounce) { 865 mDozeLog.traceSensorEventDropped(mPulseReason, "debounce"); 866 return; 867 } 868 mSensorCallback.onSensorPulse(mPulseReason, -1, -1, event.getValues()); 869 })); 870 } 871 } 872 873 private final DevicePostureController.Callback mDevicePostureCallback = posture -> { 874 if (mDevicePosture == posture) { 875 return; 876 } 877 mDevicePosture = posture; 878 879 for (TriggerSensor triggerSensor : mTriggerSensors) { 880 triggerSensor.setPosture(mDevicePosture); 881 } 882 }; 883 884 private final AuthController.Callback mAuthControllerCallback = new AuthController.Callback() { 885 @Override 886 public void onAllAuthenticatorsRegistered(@BiometricAuthenticator.Modality int modality) { 887 if (modality == TYPE_FINGERPRINT) { 888 updateUdfpsEnrolled(); 889 } 890 } 891 892 @Override 893 public void onEnrollmentsChanged(@BiometricAuthenticator.Modality int modality) { 894 if (modality == TYPE_FINGERPRINT) { 895 updateUdfpsEnrolled(); 896 } 897 } 898 899 private void updateUdfpsEnrolled() { 900 mUdfpsEnrolled = mAuthController.isUdfpsEnrolled( 901 mSelectedUserInteractor.getSelectedUserId()); 902 for (TriggerSensor sensor : mTriggerSensors) { 903 if (REASON_SENSOR_QUICK_PICKUP == sensor.mPulseReason) { 904 sensor.setConfigured(quickPickUpConfigured()); 905 } else if (REASON_SENSOR_UDFPS_LONG_PRESS == sensor.mPulseReason) { 906 sensor.setConfigured(udfpsLongPressConfigured()); 907 } 908 } 909 } 910 }; 911 912 public interface Callback { 913 914 /** 915 * Called when a sensor requests a pulse 916 * @param pulseReason Requesting sensor, e.g. {@link DozeLog#REASON_SENSOR_PICKUP} 917 * @param screenX the location on the screen where the sensor fired or -1 918 * if the sensor doesn't support reporting screen locations. 919 * @param screenY the location on the screen where the sensor fired or -1 920 * @param rawValues raw values array from the event. 921 */ onSensorPulse(int pulseReason, float screenX, float screenY, float[] rawValues)922 void onSensorPulse(int pulseReason, float screenX, float screenY, float[] rawValues); 923 } 924 } 925