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