• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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