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