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