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.app.StatusBarManager.SESSION_KEYGUARD; 20 21 import static com.android.systemui.doze.DozeMachine.State.DOZE_SUSPEND_TRIGGERS; 22 import static com.android.systemui.doze.DozeMachine.State.FINISH; 23 import static com.android.systemui.doze.DozeMachine.State.UNINITIALIZED; 24 25 import android.annotation.Nullable; 26 import android.content.BroadcastReceiver; 27 import android.content.Context; 28 import android.content.Intent; 29 import android.content.IntentFilter; 30 import android.hardware.display.AmbientDisplayConfiguration; 31 import android.os.SystemClock; 32 import android.text.format.Formatter; 33 import android.util.IndentingPrintWriter; 34 import android.util.Log; 35 import android.view.Display; 36 37 import androidx.annotation.NonNull; 38 39 import com.android.internal.annotations.VisibleForTesting; 40 import com.android.internal.logging.InstanceId; 41 import com.android.internal.logging.UiEvent; 42 import com.android.internal.logging.UiEventLogger; 43 import com.android.systemui.biometrics.AuthController; 44 import com.android.systemui.broadcast.BroadcastDispatcher; 45 import com.android.systemui.dock.DockManager; 46 import com.android.systemui.doze.DozeMachine.State; 47 import com.android.systemui.doze.dagger.DozeScope; 48 import com.android.systemui.log.SessionTracker; 49 import com.android.systemui.settings.UserTracker; 50 import com.android.systemui.statusbar.phone.DozeParameters; 51 import com.android.systemui.statusbar.policy.DevicePostureController; 52 import com.android.systemui.statusbar.policy.KeyguardStateController; 53 import com.android.systemui.user.domain.interactor.SelectedUserInteractor; 54 import com.android.systemui.util.Assert; 55 import com.android.systemui.util.sensors.AsyncSensorManager; 56 import com.android.systemui.util.sensors.ProximityCheck; 57 import com.android.systemui.util.sensors.ProximitySensor; 58 import com.android.systemui.util.settings.SecureSettings; 59 import com.android.systemui.util.wakelock.WakeLock; 60 61 import java.io.PrintWriter; 62 import java.util.Optional; 63 import java.util.function.Consumer; 64 65 import javax.inject.Inject; 66 67 /** 68 * Handles triggers for ambient state changes. 69 */ 70 @DozeScope 71 public class DozeTriggers implements DozeMachine.Part { 72 73 private static final String TAG = "DozeTriggers"; 74 private static final boolean DEBUG = DozeService.DEBUG; 75 76 /** adb shell am broadcast -a com.android.systemui.doze.pulse com.android.systemui */ 77 private static final String PULSE_ACTION = "com.android.systemui.doze.pulse"; 78 79 /** 80 * Last value sent by the wake-display sensor. 81 * Assuming that the screen should start on. 82 */ 83 private static boolean sWakeDisplaySensorState = true; 84 85 private static final int PROXIMITY_TIMEOUT_DELAY_MS = 500; 86 87 private final Context mContext; 88 private final SessionTracker mSessionTracker; 89 private DozeMachine mMachine; 90 private final DozeLog mDozeLog; 91 private final DozeSensors mDozeSensors; 92 private final DozeHost mDozeHost; 93 private final AmbientDisplayConfiguration mConfig; 94 private final DozeParameters mDozeParameters; 95 private final AsyncSensorManager mSensorManager; 96 private final WakeLock mWakeLock; 97 private final boolean mAllowPulseTriggers; 98 private final TriggerReceiver mBroadcastReceiver = new TriggerReceiver(); 99 private final DockEventListener mDockEventListener = new DockEventListener(); 100 private final DockManager mDockManager; 101 private final ProximityCheck mProxCheck; 102 private final BroadcastDispatcher mBroadcastDispatcher; 103 private final AuthController mAuthController; 104 private final KeyguardStateController mKeyguardStateController; 105 private final UserTracker mUserTracker; 106 private final SelectedUserInteractor mSelectedUserInteractor; 107 private final UiEventLogger mUiEventLogger; 108 109 private long mNotificationPulseTime; 110 private Runnable mAodInterruptRunnable; 111 112 /** see {@link #onProximityFar} prox for callback */ 113 private boolean mWantProxSensor; 114 private boolean mWantTouchScreenSensors; 115 private boolean mWantSensors; 116 private boolean mInAod; 117 118 private final UserTracker.Callback mUserChangedCallback = 119 new UserTracker.Callback() { 120 @Override 121 public void onUserChanged(int newUser, @NonNull Context userContext) { 122 mDozeSensors.onUserSwitched(); 123 } 124 }; 125 126 @VisibleForTesting 127 public enum DozingUpdateUiEvent implements UiEventLogger.UiEventEnum { 128 @UiEvent(doc = "Dozing updated due to notification.") 129 DOZING_UPDATE_NOTIFICATION(433), 130 131 @UiEvent(doc = "Dozing updated due to sigmotion.") 132 DOZING_UPDATE_SIGMOTION(434), 133 134 @UiEvent(doc = "Dozing updated because sensor was picked up.") 135 DOZING_UPDATE_SENSOR_PICKUP(435), 136 137 @UiEvent(doc = "Dozing updated because sensor was double tapped.") 138 DOZING_UPDATE_SENSOR_DOUBLE_TAP(436), 139 140 @UiEvent(doc = "Dozing updated because sensor was long squeezed.") 141 DOZING_UPDATE_SENSOR_LONG_SQUEEZE(437), 142 143 @UiEvent(doc = "Dozing updated due to docking.") 144 DOZING_UPDATE_DOCKING(438), 145 146 @UiEvent(doc = "Dozing updated because sensor woke up.") 147 DOZING_UPDATE_SENSOR_WAKEUP(439), 148 149 @UiEvent(doc = "Dozing updated because sensor woke up the lockscreen.") 150 DOZING_UPDATE_SENSOR_WAKE_LOCKSCREEN(440), 151 152 @UiEvent(doc = "Dozing updated because sensor was tapped.") 153 DOZING_UPDATE_SENSOR_TAP(441), 154 155 @UiEvent(doc = "Dozing updated because on display auth was triggered from AOD.") 156 DOZING_UPDATE_AUTH_TRIGGERED(657), 157 158 @UiEvent(doc = "Dozing updated because quick pickup sensor woke up.") 159 DOZING_UPDATE_QUICK_PICKUP(708), 160 161 @UiEvent(doc = "Dozing updated - sensor wakeup timed out (from quick pickup or presence)") 162 DOZING_UPDATE_WAKE_TIMEOUT(794); 163 164 private final int mId; 165 DozingUpdateUiEvent(int id)166 DozingUpdateUiEvent(int id) { 167 mId = id; 168 } 169 170 @Override getId()171 public int getId() { 172 return mId; 173 } 174 fromReason(int reason)175 static DozingUpdateUiEvent fromReason(int reason) { 176 switch (reason) { 177 case 1: return DOZING_UPDATE_NOTIFICATION; 178 case 2: return DOZING_UPDATE_SIGMOTION; 179 case 3: return DOZING_UPDATE_SENSOR_PICKUP; 180 case 4: return DOZING_UPDATE_SENSOR_DOUBLE_TAP; 181 case 5: return DOZING_UPDATE_SENSOR_LONG_SQUEEZE; 182 case 6: return DOZING_UPDATE_DOCKING; 183 case 7: return DOZING_UPDATE_SENSOR_WAKEUP; 184 case 8: return DOZING_UPDATE_SENSOR_WAKE_LOCKSCREEN; 185 case 9: return DOZING_UPDATE_SENSOR_TAP; 186 case 10: return DOZING_UPDATE_AUTH_TRIGGERED; 187 case 11: return DOZING_UPDATE_QUICK_PICKUP; 188 default: return null; 189 } 190 } 191 } 192 193 @Inject DozeTriggers(Context context, DozeHost dozeHost, AmbientDisplayConfiguration config, DozeParameters dozeParameters, AsyncSensorManager sensorManager, WakeLock wakeLock, DockManager dockManager, ProximitySensor proximitySensor, ProximityCheck proxCheck, DozeLog dozeLog, BroadcastDispatcher broadcastDispatcher, SecureSettings secureSettings, AuthController authController, UiEventLogger uiEventLogger, SessionTracker sessionTracker, KeyguardStateController keyguardStateController, DevicePostureController devicePostureController, UserTracker userTracker, SelectedUserInteractor selectedUserInteractor)194 public DozeTriggers(Context context, DozeHost dozeHost, 195 AmbientDisplayConfiguration config, 196 DozeParameters dozeParameters, AsyncSensorManager sensorManager, 197 WakeLock wakeLock, DockManager dockManager, 198 ProximitySensor proximitySensor, 199 ProximityCheck proxCheck, 200 DozeLog dozeLog, BroadcastDispatcher broadcastDispatcher, 201 SecureSettings secureSettings, AuthController authController, 202 UiEventLogger uiEventLogger, 203 SessionTracker sessionTracker, 204 KeyguardStateController keyguardStateController, 205 DevicePostureController devicePostureController, 206 UserTracker userTracker, 207 SelectedUserInteractor selectedUserInteractor) { 208 mContext = context; 209 mDozeHost = dozeHost; 210 mConfig = config; 211 mDozeParameters = dozeParameters; 212 mSensorManager = sensorManager; 213 mWakeLock = wakeLock; 214 mAllowPulseTriggers = true; 215 mSessionTracker = sessionTracker; 216 217 mDozeSensors = new DozeSensors(mContext.getResources(), mSensorManager, dozeParameters, 218 config, wakeLock, this::onSensor, this::onProximityFar, dozeLog, proximitySensor, 219 secureSettings, authController, devicePostureController, selectedUserInteractor); 220 mDockManager = dockManager; 221 mProxCheck = proxCheck; 222 mDozeLog = dozeLog; 223 mBroadcastDispatcher = broadcastDispatcher; 224 mAuthController = authController; 225 mUiEventLogger = uiEventLogger; 226 mKeyguardStateController = keyguardStateController; 227 mUserTracker = userTracker; 228 mSelectedUserInteractor = selectedUserInteractor; 229 } 230 231 @Override setDozeMachine(DozeMachine dozeMachine)232 public void setDozeMachine(DozeMachine dozeMachine) { 233 mMachine = dozeMachine; 234 } 235 236 @Override destroy()237 public void destroy() { 238 mDozeSensors.destroy(); 239 mProxCheck.destroy(); 240 } 241 onNotification(Runnable onPulseSuppressedListener)242 private void onNotification(Runnable onPulseSuppressedListener) { 243 if (DozeMachine.DEBUG) { 244 Log.d(TAG, "requestNotificationPulse"); 245 } 246 if (!sWakeDisplaySensorState) { 247 Log.d(TAG, "Wake display false. Pulse denied."); 248 runIfNotNull(onPulseSuppressedListener); 249 mDozeLog.tracePulseDropped("wakeDisplaySensor"); 250 return; 251 } 252 mNotificationPulseTime = SystemClock.elapsedRealtime(); 253 if (!mConfig.pulseOnNotificationEnabled(mSelectedUserInteractor.getSelectedUserId())) { 254 runIfNotNull(onPulseSuppressedListener); 255 mDozeLog.tracePulseDropped("pulseOnNotificationsDisabled"); 256 return; 257 } 258 if (mDozeHost.isAlwaysOnSuppressed()) { 259 runIfNotNull(onPulseSuppressedListener); 260 mDozeLog.tracePulseDropped("dozeSuppressed"); 261 return; 262 } 263 requestPulse(DozeLog.PULSE_REASON_NOTIFICATION, false /* performedProxCheck */, 264 onPulseSuppressedListener); 265 mDozeLog.traceNotificationPulse(); 266 } 267 onSideFingerprintAcquisitionStarted()268 private void onSideFingerprintAcquisitionStarted() { 269 requestPulse(DozeLog.PULSE_REASON_FINGERPRINT_ACTIVATED, false, null); 270 } 271 runIfNotNull(Runnable runnable)272 private static void runIfNotNull(Runnable runnable) { 273 if (runnable != null) { 274 runnable.run(); 275 } 276 } 277 proximityCheckThenCall(Consumer<Boolean> callback, boolean alreadyPerformedProxCheck, int reason)278 private void proximityCheckThenCall(Consumer<Boolean> callback, 279 boolean alreadyPerformedProxCheck, 280 int reason) { 281 Boolean cachedProxNear = mDozeSensors.isProximityCurrentlyNear(); 282 if (alreadyPerformedProxCheck) { 283 callback.accept(null); 284 } else if (cachedProxNear != null) { 285 callback.accept(cachedProxNear); 286 } else { 287 final long start = SystemClock.uptimeMillis(); 288 mProxCheck.check(PROXIMITY_TIMEOUT_DELAY_MS, near -> { 289 final long end = SystemClock.uptimeMillis(); 290 mDozeLog.traceProximityResult( 291 near != null && near, 292 end - start, 293 reason); 294 callback.accept(near); 295 mWakeLock.release(TAG); 296 }); 297 mWakeLock.acquire(TAG); 298 } 299 } 300 301 @VisibleForTesting onSensor(int pulseReason, float screenX, float screenY, float[] rawValues)302 void onSensor(int pulseReason, float screenX, float screenY, float[] rawValues) { 303 boolean isDoubleTap = pulseReason == DozeLog.REASON_SENSOR_DOUBLE_TAP; 304 boolean isTap = pulseReason == DozeLog.REASON_SENSOR_TAP; 305 boolean isPickup = pulseReason == DozeLog.REASON_SENSOR_PICKUP; 306 boolean isLongPress = pulseReason == DozeLog.PULSE_REASON_SENSOR_LONG_PRESS; 307 boolean isWakeOnPresence = pulseReason == DozeLog.REASON_SENSOR_WAKE_UP_PRESENCE; 308 boolean isWakeOnReach = pulseReason == DozeLog.PULSE_REASON_SENSOR_WAKE_REACH; 309 boolean isUdfpsLongPress = pulseReason == DozeLog.REASON_SENSOR_UDFPS_LONG_PRESS; 310 boolean isQuickPickup = pulseReason == DozeLog.REASON_SENSOR_QUICK_PICKUP; 311 boolean isWakeDisplayEvent = isQuickPickup || ((isWakeOnPresence || isWakeOnReach) 312 && rawValues != null && rawValues.length > 0 && rawValues[0] != 0); 313 314 if (isWakeOnPresence) { 315 onWakeScreen(isWakeDisplayEvent, 316 mMachine.isExecutingTransition() ? null : mMachine.getState(), 317 pulseReason); 318 } else if (isLongPress) { 319 requestPulse(pulseReason, true /* alreadyPerformedProxCheck */, 320 null /* onPulseSuppressedListener */); 321 } else if (isWakeOnReach || isQuickPickup) { 322 if (isWakeDisplayEvent) { 323 requestPulse(pulseReason, true /* alreadyPerformedProxCheck */, 324 null /* onPulseSuppressedListener */); 325 } 326 } else { 327 proximityCheckThenCall((isNear) -> { 328 if (isNear != null && isNear) { 329 // In pocket, drop event. 330 mDozeLog.traceSensorEventDropped(pulseReason, "prox reporting near"); 331 return; 332 } 333 if (isDoubleTap || isTap) { 334 mDozeHost.onSlpiTap(screenX, screenY); 335 gentleWakeUp(pulseReason); 336 } else if (isPickup) { 337 if (shouldDropPickupEvent()) { 338 mDozeLog.traceSensorEventDropped(pulseReason, "keyguard occluded"); 339 return; 340 } 341 gentleWakeUp(pulseReason); 342 } else if (isUdfpsLongPress) { 343 if (canPulse(mMachine.getState(), true)) { 344 mDozeLog.d("updfsLongPress - setting aodInterruptRunnable to run when " 345 + "the display is on"); 346 // Since the gesture won't be received by the UDFPS view, we need to 347 // manually inject an event once the display is ON 348 mAodInterruptRunnable = () -> 349 mAuthController.onAodInterrupt((int) screenX, (int) screenY, 350 rawValues[3] /* major */, rawValues[4] /* minor */); 351 } else { 352 mDozeLog.d("udfpsLongPress - Not sending aodInterrupt. " 353 + "Unsupported doze state."); 354 } 355 requestPulse(DozeLog.REASON_SENSOR_UDFPS_LONG_PRESS, true, null); 356 } else { 357 mDozeHost.extendPulse(pulseReason); 358 } 359 }, true /* alreadyPerformedProxCheck */, pulseReason); 360 } 361 362 if (isPickup && !shouldDropPickupEvent()) { 363 final long timeSinceNotification = 364 SystemClock.elapsedRealtime() - mNotificationPulseTime; 365 final boolean withinVibrationThreshold = 366 timeSinceNotification < mDozeParameters.getPickupVibrationThreshold(); 367 mDozeLog.tracePickupWakeUp(withinVibrationThreshold); 368 } 369 } 370 371 private boolean shouldDropPickupEvent() { 372 return mKeyguardStateController.isOccluded(); 373 } 374 375 private void gentleWakeUp(@DozeLog.Reason int reason) { 376 // Log screen wake up reason (lift/pickup, tap, double-tap) 377 Optional.ofNullable(DozingUpdateUiEvent.fromReason(reason)) 378 .ifPresent(uiEventEnum -> mUiEventLogger.log(uiEventEnum, getKeyguardSessionId())); 379 if (mDozeParameters.getDisplayNeedsBlanking()) { 380 // Let's prepare the display to wake-up by drawing black. 381 // This will cover the hardware wake-up sequence, where the display 382 // becomes black for a few frames. 383 mDozeHost.setAodDimmingScrim(1f); 384 } 385 mMachine.wakeUp(reason); 386 } 387 onProximityFar(boolean far)388 private void onProximityFar(boolean far) { 389 // Proximity checks are asynchronous and the user might have interacted with the phone 390 // when a new event is arriving. This means that a state transition might have happened 391 // and the proximity check is now obsolete. 392 if (mMachine.isExecutingTransition()) { 393 mDozeLog.d("onProximityFar called during transition. Ignoring sensor response."); 394 return; 395 } 396 397 final boolean near = !far; 398 final DozeMachine.State state = mMachine.getState(); 399 final boolean paused = (state == DozeMachine.State.DOZE_AOD_PAUSED); 400 final boolean pausing = (state == DozeMachine.State.DOZE_AOD_PAUSING); 401 final boolean aod = (state == DozeMachine.State.DOZE_AOD); 402 403 if (state == DozeMachine.State.DOZE_PULSING 404 || state == DozeMachine.State.DOZE_PULSING_BRIGHT) { 405 mDozeLog.traceSetIgnoreTouchWhilePulsing(near); 406 mDozeHost.onIgnoreTouchWhilePulsing(near); 407 } 408 409 if (far && (paused || pausing)) { 410 mDozeLog.d("Prox FAR, unpausing AOD"); 411 mMachine.requestState(DozeMachine.State.DOZE_AOD); 412 } else if (near && aod) { 413 mDozeLog.d("Prox NEAR, starting pausing AOD countdown"); 414 mMachine.requestState(DozeMachine.State.DOZE_AOD_PAUSING); 415 } 416 } 417 418 /** 419 * When a wake screen event is received from a sensor 420 * @param wake {@code true} when it's time to wake up, {@code false} when we should sleep. 421 * @param state The current state, or null if the state could not be determined due to enqueued 422 * transitions. 423 */ onWakeScreen(boolean wake, @Nullable DozeMachine.State state, int reason)424 private void onWakeScreen(boolean wake, @Nullable DozeMachine.State state, int reason) { 425 mDozeLog.traceWakeDisplay(wake, reason); 426 sWakeDisplaySensorState = wake; 427 428 if (wake) { 429 proximityCheckThenCall((isNear) -> { 430 if (isNear != null && isNear) { 431 // In pocket, drop event. 432 return; 433 } 434 if (state == DozeMachine.State.DOZE) { 435 mMachine.requestState(DozeMachine.State.DOZE_AOD); 436 // Log sensor triggered 437 Optional.ofNullable(DozingUpdateUiEvent.fromReason(reason)) 438 .ifPresent(uiEventEnum -> 439 mUiEventLogger.log(uiEventEnum, getKeyguardSessionId())); 440 } 441 }, false /* alreadyPerformedProxCheck */, reason); 442 } else { 443 boolean paused = (state == DozeMachine.State.DOZE_AOD_PAUSED); 444 boolean pausing = (state == DozeMachine.State.DOZE_AOD_PAUSING); 445 446 if (!pausing && !paused) { 447 mMachine.requestState(DozeMachine.State.DOZE); 448 // log wake timeout 449 mUiEventLogger.log(DozingUpdateUiEvent.DOZING_UPDATE_WAKE_TIMEOUT); 450 } 451 } 452 } 453 454 @Override transitionTo(DozeMachine.State oldState, DozeMachine.State newState)455 public void transitionTo(DozeMachine.State oldState, DozeMachine.State newState) { 456 if (oldState == DOZE_SUSPEND_TRIGGERS && (newState != FINISH 457 && newState != UNINITIALIZED)) { 458 // Register callbacks that were unregistered when we switched to 459 // DOZE_SUSPEND_TRIGGERS state. 460 registerCallbacks(); 461 } 462 switch (newState) { 463 case INITIALIZED: 464 mAodInterruptRunnable = null; 465 sWakeDisplaySensorState = true; 466 registerCallbacks(); 467 mDozeSensors.requestTemporaryDisable(); 468 break; 469 case DOZE: 470 mAodInterruptRunnable = null; 471 mWantProxSensor = false; 472 mWantSensors = true; 473 mWantTouchScreenSensors = true; 474 mInAod = false; 475 break; 476 case DOZE_AOD: 477 mAodInterruptRunnable = null; 478 mWantProxSensor = true; 479 mWantSensors = true; 480 mWantTouchScreenSensors = true; 481 mInAod = true; 482 if (!sWakeDisplaySensorState) { 483 onWakeScreen(false, newState, DozeLog.REASON_SENSOR_WAKE_UP_PRESENCE); 484 } 485 break; 486 case DOZE_AOD_PAUSED: 487 case DOZE_AOD_PAUSING: 488 mWantProxSensor = true; 489 break; 490 case DOZE_PULSING: 491 case DOZE_PULSING_BRIGHT: 492 mWantProxSensor = true; 493 mWantTouchScreenSensors = false; 494 break; 495 case DOZE_AOD_DOCKED: 496 mWantProxSensor = false; 497 mWantTouchScreenSensors = false; 498 break; 499 case DOZE_PULSE_DONE: 500 mDozeSensors.requestTemporaryDisable(); 501 break; 502 case DOZE_SUSPEND_TRIGGERS: 503 case FINISH: 504 stopListeningToAllTriggers(); 505 break; 506 default: 507 } 508 mDozeSensors.setListening(mWantSensors, mWantTouchScreenSensors, mInAod); 509 } 510 registerCallbacks()511 private void registerCallbacks() { 512 mBroadcastReceiver.register(mBroadcastDispatcher); 513 mDockManager.addListener(mDockEventListener); 514 mDozeHost.addCallback(mHostCallback); 515 mUserTracker.addCallback(mUserChangedCallback, mContext.getMainExecutor()); 516 } 517 unregisterCallbacks()518 private void unregisterCallbacks() { 519 mBroadcastReceiver.unregister(mBroadcastDispatcher); 520 mDozeHost.removeCallback(mHostCallback); 521 mDockManager.removeListener(mDockEventListener); 522 mUserTracker.removeCallback(mUserChangedCallback); 523 } 524 stopListeningToAllTriggers()525 private void stopListeningToAllTriggers() { 526 unregisterCallbacks(); 527 mDozeSensors.setListening(false, false, false); 528 mDozeSensors.setProxListening(false); 529 mWantSensors = false; 530 mWantProxSensor = false; 531 mWantTouchScreenSensors = false; 532 mInAod = false; 533 } 534 535 @Override onScreenState(int state)536 public void onScreenState(int state) { 537 mDozeSensors.onScreenState(state); 538 final boolean lowPowerStateOrOff = state == Display.STATE_DOZE 539 || state == Display.STATE_DOZE_SUSPEND || state == Display.STATE_OFF; 540 mDozeSensors.setProxListening(mWantProxSensor && lowPowerStateOrOff); 541 mDozeSensors.setListeningWithPowerState(mWantSensors, mWantTouchScreenSensors, 542 mInAod, lowPowerStateOrOff); 543 544 if (mAodInterruptRunnable != null && state == Display.STATE_ON) { 545 mAodInterruptRunnable.run(); 546 mAodInterruptRunnable = null; 547 } 548 } 549 requestPulse(final int reason, boolean performedProxCheck, Runnable onPulseSuppressedListener)550 private void requestPulse(final int reason, boolean performedProxCheck, 551 Runnable onPulseSuppressedListener) { 552 Assert.isMainThread(); 553 mDozeHost.extendPulse(reason); 554 555 // we can't determine the dozing state if we're currently transitioning 556 final DozeMachine.State dozeState = 557 mMachine.isExecutingTransition() ? null : mMachine.getState(); 558 559 // When already pulsing we're allowed to show the wallpaper directly without 560 // requesting a new pulse. 561 if (dozeState == DozeMachine.State.DOZE_PULSING 562 && reason == DozeLog.PULSE_REASON_SENSOR_WAKE_REACH) { 563 mMachine.requestState(DozeMachine.State.DOZE_PULSING_BRIGHT); 564 return; 565 } 566 567 // When already in pulsing, we can show the new Notification without requesting a new pulse. 568 if (dozeState == State.DOZE_PULSING && reason == DozeLog.PULSE_REASON_NOTIFICATION) { 569 return; 570 } 571 572 if (!mAllowPulseTriggers || mDozeHost.isPulsePending() 573 || !canPulse(dozeState, performedProxCheck)) { 574 if (!mAllowPulseTriggers) { 575 mDozeLog.tracePulseDropped("requestPulse - !mAllowPulseTriggers"); 576 } else if (mDozeHost.isPulsePending()) { 577 mDozeLog.tracePulseDropped("requestPulse - pulsePending"); 578 } else if (!canPulse(dozeState, performedProxCheck)) { 579 mDozeLog.tracePulseDropped("requestPulse - dozeState cannot pulse", dozeState); 580 } 581 runIfNotNull(onPulseSuppressedListener); 582 return; 583 } 584 585 mDozeHost.setPulsePending(true); 586 proximityCheckThenCall((isNear) -> { 587 if (isNear != null && isNear) { 588 // in pocket, abort pulse 589 mDozeLog.tracePulseDropped("requestPulse - inPocket"); 590 mDozeHost.setPulsePending(false); 591 runIfNotNull(onPulseSuppressedListener); 592 } else { 593 // not in pocket, continue pulsing 594 final boolean isPulsePending = mDozeHost.isPulsePending(); 595 mDozeHost.setPulsePending(false); 596 if (!isPulsePending || mDozeHost.isPulsingBlocked() 597 || !canPulse(dozeState, performedProxCheck)) { 598 if (!isPulsePending) { 599 mDozeLog.tracePulseDropped("continuePulseRequest - pulse no longer" 600 + " pending, pulse was cancelled before it could start" 601 + " transitioning to pulsing state."); 602 } else if (mDozeHost.isPulsingBlocked()) { 603 mDozeLog.tracePulseDropped("continuePulseRequest - pulsingBlocked"); 604 } else if (!canPulse(dozeState, performedProxCheck)) { 605 mDozeLog.tracePulseDropped("continuePulseRequest" 606 + " - doze state cannot pulse", dozeState); 607 } 608 runIfNotNull(onPulseSuppressedListener); 609 return; 610 } 611 612 mMachine.requestPulse(reason); 613 } 614 }, !mDozeParameters.getProxCheckBeforePulse() || performedProxCheck, reason); 615 616 // Logs request pulse reason on AOD screen. 617 Optional.ofNullable(DozingUpdateUiEvent.fromReason(reason)) 618 .ifPresent(uiEventEnum -> mUiEventLogger.log(uiEventEnum, getKeyguardSessionId())); 619 } 620 canPulse(DozeMachine.State dozeState, boolean pulsePerformedProximityCheck)621 private boolean canPulse(DozeMachine.State dozeState, boolean pulsePerformedProximityCheck) { 622 final boolean dozePausedOrPausing = dozeState == State.DOZE_AOD_PAUSED 623 || dozeState == State.DOZE_AOD_PAUSING; 624 return dozeState == DozeMachine.State.DOZE 625 || dozeState == DozeMachine.State.DOZE_AOD 626 || dozeState == DozeMachine.State.DOZE_AOD_DOCKED 627 || (dozePausedOrPausing && pulsePerformedProximityCheck); 628 } 629 630 @Nullable getKeyguardSessionId()631 private InstanceId getKeyguardSessionId() { 632 return mSessionTracker.getSessionId(SESSION_KEYGUARD); 633 } 634 635 @Override dump(PrintWriter pw)636 public void dump(PrintWriter pw) { 637 pw.println(" mAodInterruptRunnable=" + mAodInterruptRunnable); 638 639 pw.print(" notificationPulseTime="); 640 pw.println(Formatter.formatShortElapsedTime(mContext, mNotificationPulseTime)); 641 642 pw.println(" DozeHost#isPulsePending=" + mDozeHost.isPulsePending()); 643 pw.println("DozeSensors:"); 644 IndentingPrintWriter idpw = new IndentingPrintWriter(pw); 645 idpw.increaseIndent(); 646 mDozeSensors.dump(idpw); 647 } 648 649 private class TriggerReceiver extends BroadcastReceiver { 650 private boolean mRegistered; 651 652 @Override onReceive(Context context, Intent intent)653 public void onReceive(Context context, Intent intent) { 654 if (PULSE_ACTION.equals(intent.getAction())) { 655 if (DozeMachine.DEBUG) Log.d(TAG, "Received pulse intent"); 656 requestPulse(DozeLog.PULSE_REASON_INTENT, false, /* performedProxCheck */ 657 null /* onPulseSuppressedListener */); 658 } 659 } 660 register(BroadcastDispatcher broadcastDispatcher)661 public void register(BroadcastDispatcher broadcastDispatcher) { 662 if (mRegistered) { 663 return; 664 } 665 IntentFilter filter = new IntentFilter(PULSE_ACTION); 666 broadcastDispatcher.registerReceiver(this, filter); 667 mRegistered = true; 668 } 669 unregister(BroadcastDispatcher broadcastDispatcher)670 public void unregister(BroadcastDispatcher broadcastDispatcher) { 671 if (!mRegistered) { 672 return; 673 } 674 broadcastDispatcher.unregisterReceiver(this); 675 mRegistered = false; 676 } 677 } 678 679 private class DockEventListener implements DockManager.DockEventListener { 680 @Override onEvent(int event)681 public void onEvent(int event) { 682 if (DEBUG) Log.d(TAG, "dock event = " + event); 683 switch (event) { 684 case DockManager.STATE_DOCKED: 685 case DockManager.STATE_DOCKED_HIDE: 686 mDozeSensors.ignoreTouchScreenSensorsSettingInterferingWithDocking(true); 687 break; 688 case DockManager.STATE_NONE: 689 mDozeSensors.ignoreTouchScreenSensorsSettingInterferingWithDocking(false); 690 break; 691 default: 692 // no-op 693 } 694 } 695 } 696 697 private DozeHost.Callback mHostCallback = new DozeHost.Callback() { 698 @Override 699 public void onNotificationAlerted(Runnable onPulseSuppressedListener) { 700 onNotification(onPulseSuppressedListener); 701 } 702 703 @Override 704 public void onSideFingerprintAcquisitionStarted() { 705 DozeTriggers.this.onSideFingerprintAcquisitionStarted(); 706 } 707 }; 708 } 709