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