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