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