blob: 6199a0deb31ff6528c79895e778fb213fed6f102 [file] [log] [blame]
Adrian Roosff2c4562016-11-03 12:13:36 -07001/*
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
17package com.android.systemui.doze;
18
Lucas Dupinb7fd1eb2019-03-28 12:05:17 -070019import android.annotation.Nullable;
Adrian Roos6023ccb2017-06-28 16:22:02 +020020import android.app.AlarmManager;
Adrian Roosff2c4562016-11-03 12:13:36 -070021import android.app.UiModeManager;
22import android.content.BroadcastReceiver;
23import android.content.Context;
24import android.content.Intent;
25import android.content.IntentFilter;
26import android.content.res.Configuration;
27import android.hardware.Sensor;
28import android.hardware.SensorEvent;
29import android.hardware.SensorEventListener;
30import android.hardware.SensorManager;
Issei Suzukica19e6e2019-02-26 12:39:11 +010031import android.hardware.display.AmbientDisplayConfiguration;
Steven Wude353052019-03-12 13:49:23 -040032import android.metrics.LogMaker;
Adrian Roosff2c4562016-11-03 12:13:36 -070033import android.os.Handler;
34import android.os.SystemClock;
35import android.os.UserHandle;
36import android.text.format.Formatter;
37import android.util.Log;
38
lpeter8a5f4702019-01-18 16:53:07 +080039import com.android.internal.annotations.VisibleForTesting;
Steven Wude353052019-03-12 13:49:23 -040040import com.android.internal.logging.MetricsLogger;
41import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
Adrian Roosff2c4562016-11-03 12:13:36 -070042import com.android.internal.util.Preconditions;
Steven Wude353052019-03-12 13:49:23 -040043import com.android.systemui.Dependency;
Lucas Dupinf40bd8f2019-08-07 15:55:00 -070044import com.android.systemui.R;
lpeter8a5f4702019-01-18 16:53:07 +080045import com.android.systemui.dock.DockManager;
Adrian Roosff2c4562016-11-03 12:13:36 -070046import com.android.systemui.statusbar.phone.DozeParameters;
47import com.android.systemui.util.Assert;
Adrian Roosc1b50322017-02-27 21:07:58 +010048import com.android.systemui.util.wakelock.WakeLock;
Adrian Roosff2c4562016-11-03 12:13:36 -070049
50import java.io.PrintWriter;
Adrian Roosd32b3662017-06-27 14:48:50 +020051import java.util.function.IntConsumer;
Adrian Roosff2c4562016-11-03 12:13:36 -070052
53/**
54 * Handles triggers for ambient state changes.
55 */
56public class DozeTriggers implements DozeMachine.Part {
57
58 private static final String TAG = "DozeTriggers";
Adrian Roos67cca742017-04-13 16:52:51 -070059 private static final boolean DEBUG = DozeService.DEBUG;
Adrian Roosff2c4562016-11-03 12:13:36 -070060
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
Lucas Dupin1ae6cf92018-12-14 18:06:38 -080064 /**
65 * Last value sent by the wake-display sensor.
66 * Assuming that the screen should start on.
67 */
68 private static boolean sWakeDisplaySensorState = true;
69
Adrian Roosff2c4562016-11-03 12:13:36 -070070 private final Context mContext;
71 private final DozeMachine mMachine;
72 private final DozeSensors mDozeSensors;
73 private final DozeHost mDozeHost;
74 private final AmbientDisplayConfiguration mConfig;
75 private final DozeParameters mDozeParameters;
76 private final SensorManager mSensorManager;
77 private final Handler mHandler;
Adrian Roosc1b50322017-02-27 21:07:58 +010078 private final WakeLock mWakeLock;
Adrian Roosf9d13f62016-11-08 15:42:20 -080079 private final boolean mAllowPulseTriggers;
Adrian Roosff2c4562016-11-03 12:13:36 -070080 private final UiModeManager mUiModeManager;
81 private final TriggerReceiver mBroadcastReceiver = new TriggerReceiver();
lpeter8a5f4702019-01-18 16:53:07 +080082 private final DockEventListener mDockEventListener = new DockEventListener();
83 private final DockManager mDockManager;
Adrian Roosff2c4562016-11-03 12:13:36 -070084
85 private long mNotificationPulseTime;
86 private boolean mPulsePending;
87
Steven Wude353052019-03-12 13:49:23 -040088 private final MetricsLogger mMetricsLogger = Dependency.get(MetricsLogger.class);
Adrian Roosff2c4562016-11-03 12:13:36 -070089
90 public DozeTriggers(Context context, DozeMachine machine, DozeHost dozeHost,
Adrian Roos6023ccb2017-06-28 16:22:02 +020091 AlarmManager alarmManager, AmbientDisplayConfiguration config,
Adrian Roosff2c4562016-11-03 12:13:36 -070092 DozeParameters dozeParameters, SensorManager sensorManager, Handler handler,
lpeter8a5f4702019-01-18 16:53:07 +080093 WakeLock wakeLock, boolean allowPulseTriggers, DockManager dockManager) {
Adrian Roosff2c4562016-11-03 12:13:36 -070094 mContext = context;
95 mMachine = machine;
96 mDozeHost = dozeHost;
97 mConfig = config;
98 mDozeParameters = dozeParameters;
99 mSensorManager = sensorManager;
100 mHandler = handler;
101 mWakeLock = wakeLock;
Adrian Roosf9d13f62016-11-08 15:42:20 -0800102 mAllowPulseTriggers = allowPulseTriggers;
Adrian Roos6023ccb2017-06-28 16:22:02 +0200103 mDozeSensors = new DozeSensors(context, alarmManager, mSensorManager, dozeParameters,
Lucas Dupinb2d9f482018-11-16 18:55:13 -0800104 config, wakeLock, this::onSensor, this::onProximityFar,
Adrian Roos2f5a3852018-04-23 17:48:08 +0200105 dozeParameters.getPolicy());
Adrian Roosff2c4562016-11-03 12:13:36 -0700106 mUiModeManager = mContext.getSystemService(UiModeManager.class);
lpeter8a5f4702019-01-18 16:53:07 +0800107 mDockManager = dockManager;
Adrian Roosff2c4562016-11-03 12:13:36 -0700108 }
109
Selim Cinek65c96f22019-07-25 20:09:04 -0700110 private void onNotification(Runnable onPulseSuppressedListener) {
Dave Mankoff15bbec62019-06-27 15:17:42 -0400111 if (DozeMachine.DEBUG) {
112 Log.d(TAG, "requestNotificationPulse");
113 }
114 if (!sWakeDisplaySensorState) {
115 Log.d(TAG, "Wake display false. Pulse denied.");
Selim Cinek65c96f22019-07-25 20:09:04 -0700116 runIfNotNull(onPulseSuppressedListener);
Lucas Dupinc0b81112019-07-25 18:56:12 -0700117 DozeLog.tracePulseDropped(mContext, "wakeDisplaySensor");
Dave Mankoff15bbec62019-06-27 15:17:42 -0400118 return;
119 }
Adrian Roosff2c4562016-11-03 12:13:36 -0700120 mNotificationPulseTime = SystemClock.elapsedRealtime();
Dave Mankoff15bbec62019-06-27 15:17:42 -0400121 if (!mConfig.pulseOnNotificationEnabled(UserHandle.USER_CURRENT)) {
Selim Cinek65c96f22019-07-25 20:09:04 -0700122 runIfNotNull(onPulseSuppressedListener);
Lucas Dupinc0b81112019-07-25 18:56:12 -0700123 DozeLog.tracePulseDropped(mContext, "pulseOnNotificationsDisabled");
Dave Mankoff15bbec62019-06-27 15:17:42 -0400124 return;
125 }
Selim Cinek65c96f22019-07-25 20:09:04 -0700126 requestPulse(DozeLog.PULSE_REASON_NOTIFICATION, false /* performedProxCheck */,
127 onPulseSuppressedListener);
Adrian Roos181c3202016-11-07 13:24:31 -0800128 DozeLog.traceNotificationPulse(mContext);
Adrian Roosff2c4562016-11-03 12:13:36 -0700129 }
130
Selim Cinek65c96f22019-07-25 20:09:04 -0700131 private static void runIfNotNull(Runnable runnable) {
132 if (runnable != null) {
133 runnable.run();
134 }
135 }
136
Adrian Roosd32b3662017-06-27 14:48:50 +0200137 private void proximityCheckThenCall(IntConsumer callback,
138 boolean alreadyPerformedProxCheck,
Lucas Dupin323f9ff2018-08-27 16:55:56 -0700139 int reason) {
Adrian Roos70da03a2017-07-24 16:42:57 +0200140 Boolean cachedProxFar = mDozeSensors.isProximityCurrentlyFar();
Adrian Roosd32b3662017-06-27 14:48:50 +0200141 if (alreadyPerformedProxCheck) {
142 callback.accept(ProximityCheck.RESULT_NOT_CHECKED);
Adrian Roos70da03a2017-07-24 16:42:57 +0200143 } else if (cachedProxFar != null) {
144 callback.accept(cachedProxFar ? ProximityCheck.RESULT_FAR : ProximityCheck.RESULT_NEAR);
Adrian Roosd32b3662017-06-27 14:48:50 +0200145 } else {
146 final long start = SystemClock.uptimeMillis();
147 new ProximityCheck() {
148 @Override
149 public void onProximityResult(int result) {
150 final long end = SystemClock.uptimeMillis();
151 DozeLog.traceProximityResult(mContext, result == RESULT_NEAR,
Lucas Dupin323f9ff2018-08-27 16:55:56 -0700152 end - start, reason);
Adrian Roosd32b3662017-06-27 14:48:50 +0200153 callback.accept(result);
154 }
155 }.check();
156 }
157 }
158
lpeter8a5f4702019-01-18 16:53:07 +0800159 @VisibleForTesting
Lucas Dupinf40bd8f2019-08-07 15:55:00 -0700160 void onSensor(int pulseReason, float screenX, float screenY, float[] rawValues) {
Lucas Dupin3d053532019-01-29 12:35:22 -0800161 boolean isDoubleTap = pulseReason == DozeLog.REASON_SENSOR_DOUBLE_TAP;
162 boolean isTap = pulseReason == DozeLog.REASON_SENSOR_TAP;
163 boolean isPickup = pulseReason == DozeLog.REASON_SENSOR_PICKUP;
Adrian Roosd0963a02017-05-15 14:33:37 -0700164 boolean isLongPress = pulseReason == DozeLog.PULSE_REASON_SENSOR_LONG_PRESS;
Lucas Dupinb2d9f482018-11-16 18:55:13 -0800165 boolean isWakeDisplay = pulseReason == DozeLog.REASON_SENSOR_WAKE_UP;
Lucas Dupinde64ee02018-12-21 14:45:12 -0800166 boolean isWakeLockScreen = pulseReason == DozeLog.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN;
Lucas Dupinb2d9f482018-11-16 18:55:13 -0800167 boolean wakeEvent = rawValues != null && rawValues.length > 0 && rawValues[0] != 0;
Adrian Roosff2c4562016-11-03 12:13:36 -0700168
Lucas Dupinb2d9f482018-11-16 18:55:13 -0800169 if (isWakeDisplay) {
Lucas Dupinb7fd1eb2019-03-28 12:05:17 -0700170 onWakeScreen(wakeEvent, mMachine.isExecutingTransition() ? null : mMachine.getState());
Lucas Dupin8a13aa72019-02-22 12:45:21 -0800171 } else if (isLongPress) {
Lucas Dupinf40bd8f2019-08-07 15:55:00 -0700172 requestPulse(pulseReason, true /* alreadyPerformedProxCheck */,
173 null /* onPulseSupressedListener */);
Lucas Dupin8a13aa72019-02-22 12:45:21 -0800174 } else if (isWakeLockScreen) {
175 if (wakeEvent) {
Lucas Dupinf40bd8f2019-08-07 15:55:00 -0700176 requestPulse(pulseReason, true /* alreadyPerformedProxCheck */,
Selim Cinek65c96f22019-07-25 20:09:04 -0700177 null /* onPulseSupressedListener */);
Lucas Dupin8a13aa72019-02-22 12:45:21 -0800178 }
Lucas Dupin4359b552018-08-09 15:07:54 -0700179 } else {
Adrian Roosd32b3662017-06-27 14:48:50 +0200180 proximityCheckThenCall((result) -> {
181 if (result == ProximityCheck.RESULT_NEAR) {
182 // In pocket, drop event.
183 return;
184 }
Lucas Dupind43bf702019-01-15 13:40:42 -0800185 if (isDoubleTap || isTap) {
186 if (screenX != -1 && screenY != -1) {
187 mDozeHost.onSlpiTap(screenX, screenY);
188 }
Lucas Dupined5b7a92019-03-20 11:00:27 -0700189 gentleWakeUp(pulseReason);
Lucas Dupinb2d9f482018-11-16 18:55:13 -0800190 } else if (isPickup) {
Lucas Dupined5b7a92019-03-20 11:00:27 -0700191 gentleWakeUp(pulseReason);
Adrian Roosd32b3662017-06-27 14:48:50 +0200192 } else {
Lucas Dupin5f00fa52019-03-27 22:46:53 -0700193 mDozeHost.extendPulse(pulseReason);
Adrian Roosd32b3662017-06-27 14:48:50 +0200194 }
Lucas Dupinf40bd8f2019-08-07 15:55:00 -0700195 }, true /* alreadyPerformedProxCheck */, pulseReason);
Adrian Roosed85e582017-04-27 15:09:28 -0700196 }
197
198 if (isPickup) {
Adrian Roosff2c4562016-11-03 12:13:36 -0700199 final long timeSinceNotification =
200 SystemClock.elapsedRealtime() - mNotificationPulseTime;
201 final boolean withinVibrationThreshold =
202 timeSinceNotification < mDozeParameters.getPickupVibrationThreshold();
Lucas Dupin4359b552018-08-09 15:07:54 -0700203 DozeLog.tracePickupWakeUp(mContext, withinVibrationThreshold);
Adrian Roosff2c4562016-11-03 12:13:36 -0700204 }
205 }
206
Lucas Dupined5b7a92019-03-20 11:00:27 -0700207 private void gentleWakeUp(int reason) {
208 // Log screen wake up reason (lift/pickup, tap, double-tap)
209 mMetricsLogger.write(new LogMaker(MetricsEvent.DOZING)
210 .setType(MetricsEvent.TYPE_UPDATE)
211 .setSubtype(reason));
212 if (mDozeParameters.getDisplayNeedsBlanking()) {
213 // Let's prepare the display to wake-up by drawing black.
214 // This will cover the hardware wake-up sequence, where the display
215 // becomes black for a few frames.
Lucas Dupin34306c32019-07-16 11:56:53 -0700216 mDozeHost.setAodDimmingScrim(1f);
Lucas Dupined5b7a92019-03-20 11:00:27 -0700217 }
218 mMachine.wakeUp();
219 }
220
Adrian Roos67cca742017-04-13 16:52:51 -0700221 private void onProximityFar(boolean far) {
Lucas Dupin1946b312019-03-21 14:48:23 -0700222 // Proximity checks are asynchronous and the user might have interacted with the phone
223 // when a new event is arriving. This means that a state transition might have happened
224 // and the proximity check is now obsolete.
225 if (mMachine.isExecutingTransition()) {
226 Log.w(TAG, "onProximityFar called during transition. Ignoring sensor response.");
227 return;
228 }
229
Adrian Roos67cca742017-04-13 16:52:51 -0700230 final boolean near = !far;
Adrian Roos6023ccb2017-06-28 16:22:02 +0200231 final DozeMachine.State state = mMachine.getState();
Adrian Roosc7fd6962017-09-06 16:46:46 +0200232 final boolean paused = (state == DozeMachine.State.DOZE_AOD_PAUSED);
233 final boolean pausing = (state == DozeMachine.State.DOZE_AOD_PAUSING);
234 final boolean aod = (state == DozeMachine.State.DOZE_AOD);
Adrian Roos6023ccb2017-06-28 16:22:02 +0200235
Lucas Dupin5f00fa52019-03-27 22:46:53 -0700236 if (state == DozeMachine.State.DOZE_PULSING
237 || state == DozeMachine.State.DOZE_PULSING_BRIGHT) {
Adrian Roosa6c03f82017-07-26 16:20:30 +0200238 boolean ignoreTouch = near;
Dave Mankoff15bbec62019-06-27 15:17:42 -0400239 if (DEBUG) {
240 Log.i(TAG, "Prox changed, ignore touch = " + ignoreTouch);
241 }
Adrian Roosa6c03f82017-07-26 16:20:30 +0200242 mDozeHost.onIgnoreTouchWhilePulsing(ignoreTouch);
Adrian Roos67cca742017-04-13 16:52:51 -0700243 }
Lucas Dupin65104382018-12-04 11:53:42 -0800244
Adrian Roosc7fd6962017-09-06 16:46:46 +0200245 if (far && (paused || pausing)) {
Dave Mankoff15bbec62019-06-27 15:17:42 -0400246 if (DEBUG) {
247 Log.i(TAG, "Prox FAR, unpausing AOD");
248 }
Adrian Roos67cca742017-04-13 16:52:51 -0700249 mMachine.requestState(DozeMachine.State.DOZE_AOD);
Adrian Roos6023ccb2017-06-28 16:22:02 +0200250 } else if (near && aod) {
Dave Mankoff15bbec62019-06-27 15:17:42 -0400251 if (DEBUG) {
252 Log.i(TAG, "Prox NEAR, pausing AOD");
253 }
Adrian Roos6023ccb2017-06-28 16:22:02 +0200254 mMachine.requestState(DozeMachine.State.DOZE_AOD_PAUSING);
Adrian Roos67cca742017-04-13 16:52:51 -0700255 }
256 }
257
Lucas Dupinb7fd1eb2019-03-28 12:05:17 -0700258 /**
259 * When a wake screen event is received from a sensor
260 * @param wake {@code true} when it's time to wake up, {@code false} when we should sleep.
261 * @param state The current state, or null if the state could not be determined due to enqueued
262 * transitions.
263 */
264 private void onWakeScreen(boolean wake, @Nullable DozeMachine.State state) {
Lucas Dupinb2d9f482018-11-16 18:55:13 -0800265 DozeLog.traceWakeDisplay(wake);
Lucas Dupin1ae6cf92018-12-14 18:06:38 -0800266 sWakeDisplaySensorState = wake;
Lucas Dupin323f9ff2018-08-27 16:55:56 -0700267
268 if (wake) {
269 proximityCheckThenCall((result) -> {
270 if (result == ProximityCheck.RESULT_NEAR) {
271 // In pocket, drop event.
272 return;
273 }
Lucas Dupin5131f512019-02-01 12:57:19 -0800274 if (state == DozeMachine.State.DOZE) {
Lucas Dupin323f9ff2018-08-27 16:55:56 -0700275 mMachine.requestState(DozeMachine.State.DOZE_AOD);
Steven Wucef2d5d2019-04-23 13:27:33 -0400276 // Logs AOD open due to sensor wake up.
277 mMetricsLogger.write(new LogMaker(MetricsEvent.DOZING)
278 .setType(MetricsEvent.TYPE_OPEN)
279 .setSubtype(DozeLog.REASON_SENSOR_WAKE_UP));
Lucas Dupin323f9ff2018-08-27 16:55:56 -0700280 }
Lucas Dupinf40bd8f2019-08-07 15:55:00 -0700281 }, true /* alreadyPerformedProxCheck */, DozeLog.REASON_SENSOR_WAKE_UP);
Lucas Dupin323f9ff2018-08-27 16:55:56 -0700282 } else {
Lucas Dupinb7fd1eb2019-03-28 12:05:17 -0700283 boolean paused = (state == DozeMachine.State.DOZE_AOD_PAUSED);
284 boolean pausing = (state == DozeMachine.State.DOZE_AOD_PAUSING);
Lucas Dupin323f9ff2018-08-27 16:55:56 -0700285 if (!pausing && !paused) {
Lucas Dupin65104382018-12-04 11:53:42 -0800286 mMachine.requestState(DozeMachine.State.DOZE);
Steven Wucef2d5d2019-04-23 13:27:33 -0400287 // Logs AOD close due to sensor wake up.
288 mMetricsLogger.write(new LogMaker(MetricsEvent.DOZING)
289 .setType(MetricsEvent.TYPE_CLOSE)
290 .setSubtype(DozeLog.REASON_SENSOR_WAKE_UP));
Lucas Dupin323f9ff2018-08-27 16:55:56 -0700291 }
292 }
293 }
294
Adrian Roosff2c4562016-11-03 12:13:36 -0700295 @Override
296 public void transitionTo(DozeMachine.State oldState, DozeMachine.State newState) {
297 switch (newState) {
298 case INITIALIZED:
299 mBroadcastReceiver.register(mContext);
300 mDozeHost.addCallback(mHostCallback);
lpeterac798f22019-02-12 15:15:22 +0800301 if (mDockManager != null) {
302 mDockManager.addListener(mDockEventListener);
303 }
Lucas Dupin8a13aa72019-02-22 12:45:21 -0800304 mDozeSensors.requestTemporaryDisable();
Adrian Roosff2c4562016-11-03 12:13:36 -0700305 checkTriggersAtInit();
306 break;
307 case DOZE:
308 case DOZE_AOD:
Adrian Roos67cca742017-04-13 16:52:51 -0700309 mDozeSensors.setProxListening(newState != DozeMachine.State.DOZE);
Adrian Roose3ac6f82017-06-30 16:15:22 +0200310 mDozeSensors.setListening(true);
Lucas Dupinfac2e8e2019-06-27 16:10:19 -0700311 mDozeSensors.setPaused(false);
Lucas Dupin1ae6cf92018-12-14 18:06:38 -0800312 if (newState == DozeMachine.State.DOZE_AOD && !sWakeDisplaySensorState) {
Lucas Dupin5131f512019-02-01 12:57:19 -0800313 onWakeScreen(false, newState);
Lucas Dupin1ae6cf92018-12-14 18:06:38 -0800314 }
Adrian Roosff2c4562016-11-03 12:13:36 -0700315 break;
Adrian Roos5f7bee42017-06-27 18:49:23 +0200316 case DOZE_AOD_PAUSED:
Adrian Roos6023ccb2017-06-28 16:22:02 +0200317 case DOZE_AOD_PAUSING:
Adrian Roos5f7bee42017-06-27 18:49:23 +0200318 mDozeSensors.setProxListening(true);
Lucas Dupinfac2e8e2019-06-27 16:10:19 -0700319 mDozeSensors.setPaused(true);
Adrian Roos5f7bee42017-06-27 18:49:23 +0200320 break;
Adrian Roos67cca742017-04-13 16:52:51 -0700321 case DOZE_PULSING:
Lucas Dupin5f00fa52019-03-27 22:46:53 -0700322 case DOZE_PULSING_BRIGHT:
Adrian Roos98d31982017-08-02 20:50:16 +0200323 mDozeSensors.setTouchscreenSensorsListening(false);
Adrian Roos67cca742017-04-13 16:52:51 -0700324 mDozeSensors.setProxListening(true);
Lucas Dupinfac2e8e2019-06-27 16:10:19 -0700325 mDozeSensors.setPaused(false);
Adrian Roos67cca742017-04-13 16:52:51 -0700326 break;
Lucas Dupin8a13aa72019-02-22 12:45:21 -0800327 case DOZE_PULSE_DONE:
328 mDozeSensors.requestTemporaryDisable();
Lucas Dupin3174c662019-07-15 15:49:54 -0700329 // A pulse will temporarily disable sensors that require a touch screen.
330 // Let's make sure that they are re-enabled when the pulse is over.
331 mDozeSensors.updateListening();
Lucas Dupin8a13aa72019-02-22 12:45:21 -0800332 break;
Adrian Roosff2c4562016-11-03 12:13:36 -0700333 case FINISH:
334 mBroadcastReceiver.unregister(mContext);
335 mDozeHost.removeCallback(mHostCallback);
lpeterac798f22019-02-12 15:15:22 +0800336 if (mDockManager != null) {
337 mDockManager.removeListener(mDockEventListener);
338 }
Adrian Roosff2c4562016-11-03 12:13:36 -0700339 mDozeSensors.setListening(false);
Adrian Roos67cca742017-04-13 16:52:51 -0700340 mDozeSensors.setProxListening(false);
Adrian Roosff2c4562016-11-03 12:13:36 -0700341 break;
342 default:
343 }
344 }
345
346 private void checkTriggersAtInit() {
Adrian Roosf2d545e2017-07-05 16:45:42 +0200347 if (mUiModeManager.getCurrentModeType() == Configuration.UI_MODE_TYPE_CAR
Adrian Roos710a0b12017-07-07 19:02:34 +0200348 || mDozeHost.isBlockingDoze()
Adrian Roosf2d545e2017-07-05 16:45:42 +0200349 || !mDozeHost.isProvisioned()) {
350 mMachine.requestState(DozeMachine.State.FINISH);
Adrian Roosff2c4562016-11-03 12:13:36 -0700351 }
352 }
353
Selim Cinek65c96f22019-07-25 20:09:04 -0700354 private void requestPulse(final int reason, boolean performedProxCheck,
355 Runnable onPulseSuppressedListener) {
Adrian Roosff2c4562016-11-03 12:13:36 -0700356 Assert.isMainThread();
Lucas Dupin5f00fa52019-03-27 22:46:53 -0700357 mDozeHost.extendPulse(reason);
358
359 // When already pulsing we're allowed to show the wallpaper directly without
360 // requesting a new pulse.
361 if (mMachine.getState() == DozeMachine.State.DOZE_PULSING
362 && reason == DozeLog.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN) {
363 mMachine.requestState(DozeMachine.State.DOZE_PULSING_BRIGHT);
364 return;
365 }
366
Adrian Roosf9d13f62016-11-08 15:42:20 -0800367 if (mPulsePending || !mAllowPulseTriggers || !canPulse()) {
Adrian Roosd35d4ca2017-04-19 14:31:03 -0700368 if (mAllowPulseTriggers) {
369 DozeLog.tracePulseDropped(mContext, mPulsePending, mMachine.getState(),
370 mDozeHost.isPulsingBlocked());
371 }
Selim Cinek65c96f22019-07-25 20:09:04 -0700372 runIfNotNull(onPulseSuppressedListener);
Adrian Roosff2c4562016-11-03 12:13:36 -0700373 return;
374 }
375
376 mPulsePending = true;
Adrian Roosd32b3662017-06-27 14:48:50 +0200377 proximityCheckThenCall((result) -> {
378 if (result == ProximityCheck.RESULT_NEAR) {
379 // in pocket, abort pulse
Lucas Dupinc0b81112019-07-25 18:56:12 -0700380 DozeLog.tracePulseDropped(mContext, "inPocket");
Adrian Roosd32b3662017-06-27 14:48:50 +0200381 mPulsePending = false;
Selim Cinek65c96f22019-07-25 20:09:04 -0700382 runIfNotNull(onPulseSuppressedListener);
Adrian Roosd32b3662017-06-27 14:48:50 +0200383 } else {
384 // not in pocket, continue pulsing
Adrian Roosff2c4562016-11-03 12:13:36 -0700385 continuePulseRequest(reason);
386 }
Adrian Roosd32b3662017-06-27 14:48:50 +0200387 }, !mDozeParameters.getProxCheckBeforePulse() || performedProxCheck, reason);
Steven Wude353052019-03-12 13:49:23 -0400388
389 // Logs request pulse reason on AOD screen.
390 mMetricsLogger.write(new LogMaker(MetricsEvent.DOZING)
391 .setType(MetricsEvent.TYPE_UPDATE).setSubtype(reason));
Adrian Roosff2c4562016-11-03 12:13:36 -0700392 }
393
394 private boolean canPulse() {
395 return mMachine.getState() == DozeMachine.State.DOZE
396 || mMachine.getState() == DozeMachine.State.DOZE_AOD;
397 }
398
399 private void continuePulseRequest(int reason) {
400 mPulsePending = false;
401 if (mDozeHost.isPulsingBlocked() || !canPulse()) {
Adrian Roosd35d4ca2017-04-19 14:31:03 -0700402 DozeLog.tracePulseDropped(mContext, mPulsePending, mMachine.getState(),
403 mDozeHost.isPulsingBlocked());
Adrian Roosff2c4562016-11-03 12:13:36 -0700404 return;
405 }
Adrian Roosd7b9d102017-04-28 15:42:58 -0700406 mMachine.requestPulse(reason);
Adrian Roosff2c4562016-11-03 12:13:36 -0700407 }
408
409 @Override
410 public void dump(PrintWriter pw) {
411 pw.print(" notificationPulseTime=");
412 pw.println(Formatter.formatShortElapsedTime(mContext, mNotificationPulseTime));
413
414 pw.print(" pulsePending="); pw.println(mPulsePending);
415 pw.println("DozeSensors:");
416 mDozeSensors.dump(pw);
417 }
418
Lucas Dupin1946d872019-09-09 14:06:55 -0700419 /**
420 * @see DozeSensors.ProxSensor
421 */
Adrian Roosff2c4562016-11-03 12:13:36 -0700422 private abstract class ProximityCheck implements SensorEventListener, Runnable {
423 private static final int TIMEOUT_DELAY_MS = 500;
424
425 protected static final int RESULT_UNKNOWN = 0;
426 protected static final int RESULT_NEAR = 1;
427 protected static final int RESULT_FAR = 2;
Adrian Roosd32b3662017-06-27 14:48:50 +0200428 protected static final int RESULT_NOT_CHECKED = 3;
Adrian Roosff2c4562016-11-03 12:13:36 -0700429
430 private boolean mRegistered;
431 private boolean mFinished;
432 private float mMaxRange;
Lucas Dupin1946d872019-09-09 14:06:55 -0700433 private boolean mUsingBrightnessSensor;
Adrian Roosff2c4562016-11-03 12:13:36 -0700434
435 protected abstract void onProximityResult(int result);
436
437 public void check() {
438 Preconditions.checkState(!mFinished && !mRegistered);
Lucas Dupinf40bd8f2019-08-07 15:55:00 -0700439 Sensor sensor = DozeSensors.findSensorWithType(mSensorManager,
440 mContext.getString(R.string.doze_brightness_sensor_type));
Lucas Dupin1946d872019-09-09 14:06:55 -0700441 mUsingBrightnessSensor = sensor != null;
Lucas Dupinf40bd8f2019-08-07 15:55:00 -0700442 if (sensor == null) {
443 sensor = mSensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY);
444 }
Adrian Roosff2c4562016-11-03 12:13:36 -0700445 if (sensor == null) {
446 if (DozeMachine.DEBUG) Log.d(TAG, "ProxCheck: No sensor found");
447 finishWithResult(RESULT_UNKNOWN);
448 return;
449 }
450 mDozeSensors.setDisableSensorsInterferingWithProximity(true);
451
452 mMaxRange = sensor.getMaximumRange();
453 mSensorManager.registerListener(this, sensor, SensorManager.SENSOR_DELAY_NORMAL, 0,
454 mHandler);
455 mHandler.postDelayed(this, TIMEOUT_DELAY_MS);
Lucas Dupinee4c9b72019-02-18 17:04:58 -0800456 mWakeLock.acquire(TAG);
Adrian Roosff2c4562016-11-03 12:13:36 -0700457 mRegistered = true;
458 }
459
Lucas Dupin1946d872019-09-09 14:06:55 -0700460 /**
461 * @see DozeSensors.ProxSensor#onSensorChanged(SensorEvent)
462 */
Adrian Roosff2c4562016-11-03 12:13:36 -0700463 @Override
464 public void onSensorChanged(SensorEvent event) {
465 if (event.values.length == 0) {
466 if (DozeMachine.DEBUG) Log.d(TAG, "ProxCheck: Event has no values!");
467 finishWithResult(RESULT_UNKNOWN);
468 } else {
469 if (DozeMachine.DEBUG) {
470 Log.d(TAG, "ProxCheck: Event: value=" + event.values[0] + " max=" + mMaxRange);
471 }
Lucas Dupin1946d872019-09-09 14:06:55 -0700472 final boolean isNear;
473 if (mUsingBrightnessSensor) {
474 // The custom brightness sensor is gated by the proximity sensor and will
475 // return 0 whenever prox is covered.
476 isNear = event.values[0] == 0;
477 } else {
478 isNear = event.values[0] < mMaxRange;
479 }
Adrian Roosff2c4562016-11-03 12:13:36 -0700480 finishWithResult(isNear ? RESULT_NEAR : RESULT_FAR);
481 }
482 }
483
484 @Override
485 public void run() {
486 if (DozeMachine.DEBUG) Log.d(TAG, "ProxCheck: No event received before timeout");
487 finishWithResult(RESULT_UNKNOWN);
488 }
489
490 private void finishWithResult(int result) {
491 if (mFinished) return;
492 boolean wasRegistered = mRegistered;
493 if (mRegistered) {
494 mHandler.removeCallbacks(this);
495 mSensorManager.unregisterListener(this);
496 mDozeSensors.setDisableSensorsInterferingWithProximity(false);
497 mRegistered = false;
498 }
499 onProximityResult(result);
500 if (wasRegistered) {
Lucas Dupinee4c9b72019-02-18 17:04:58 -0800501 mWakeLock.release(TAG);
Adrian Roosff2c4562016-11-03 12:13:36 -0700502 }
503 mFinished = true;
504 }
505
506 @Override
507 public void onAccuracyChanged(Sensor sensor, int accuracy) {
508 // noop
509 }
510 }
511
512 private class TriggerReceiver extends BroadcastReceiver {
Adrian Roos67cca742017-04-13 16:52:51 -0700513 private boolean mRegistered;
514
Adrian Roosff2c4562016-11-03 12:13:36 -0700515 @Override
516 public void onReceive(Context context, Intent intent) {
517 if (PULSE_ACTION.equals(intent.getAction())) {
518 if (DozeMachine.DEBUG) Log.d(TAG, "Received pulse intent");
Selim Cinek65c96f22019-07-25 20:09:04 -0700519 requestPulse(DozeLog.PULSE_REASON_INTENT, false, /* performedProxCheck */
520 null /* onPulseSupressedListener */);
Adrian Roosff2c4562016-11-03 12:13:36 -0700521 }
522 if (UiModeManager.ACTION_ENTER_CAR_MODE.equals(intent.getAction())) {
Adrian Roosf2d545e2017-07-05 16:45:42 +0200523 mMachine.requestState(DozeMachine.State.FINISH);
Adrian Roosff2c4562016-11-03 12:13:36 -0700524 }
525 if (Intent.ACTION_USER_SWITCHED.equals(intent.getAction())) {
526 mDozeSensors.onUserSwitched();
527 }
528 }
529
530 public void register(Context context) {
Adrian Roos67cca742017-04-13 16:52:51 -0700531 if (mRegistered) {
532 return;
533 }
Adrian Roosff2c4562016-11-03 12:13:36 -0700534 IntentFilter filter = new IntentFilter(PULSE_ACTION);
535 filter.addAction(UiModeManager.ACTION_ENTER_CAR_MODE);
536 filter.addAction(Intent.ACTION_USER_SWITCHED);
537 context.registerReceiver(this, filter);
Adrian Roos67cca742017-04-13 16:52:51 -0700538 mRegistered = true;
Adrian Roosff2c4562016-11-03 12:13:36 -0700539 }
540
541 public void unregister(Context context) {
Adrian Roos67cca742017-04-13 16:52:51 -0700542 if (!mRegistered) {
543 return;
544 }
Adrian Roosff2c4562016-11-03 12:13:36 -0700545 context.unregisterReceiver(this);
Adrian Roos67cca742017-04-13 16:52:51 -0700546 mRegistered = false;
Adrian Roosff2c4562016-11-03 12:13:36 -0700547 }
548 }
549
lpeter8a5f4702019-01-18 16:53:07 +0800550 private class DockEventListener implements DockManager.DockEventListener {
551 @Override
552 public void onEvent(int event) {
553 if (DEBUG) Log.d(TAG, "dock event = " + event);
554 switch (event) {
555 case DockManager.STATE_DOCKED:
556 case DockManager.STATE_DOCKED_HIDE:
557 mDozeSensors.ignoreTouchScreenSensorsSettingInterferingWithDocking(true);
558 break;
559 case DockManager.STATE_NONE:
560 mDozeSensors.ignoreTouchScreenSensorsSettingInterferingWithDocking(false);
561 break;
562 default:
563 // no-op
564 }
565 }
566 }
567
Adrian Roosff2c4562016-11-03 12:13:36 -0700568 private DozeHost.Callback mHostCallback = new DozeHost.Callback() {
569 @Override
Selim Cinek65c96f22019-07-25 20:09:04 -0700570 public void onNotificationAlerted(Runnable onPulseSuppressedListener) {
571 onNotification(onPulseSuppressedListener);
Adrian Roosff2c4562016-11-03 12:13:36 -0700572 }
573
574 @Override
Adrian Roosff2c4562016-11-03 12:13:36 -0700575 public void onPowerSaveChanged(boolean active) {
Lucas Dupin6edeb182019-09-25 13:39:21 -0700576 if (mDozeHost.isPowerSaveActive()) {
577 mMachine.requestState(DozeMachine.State.DOZE);
Adrian Roosff2c4562016-11-03 12:13:36 -0700578 }
579 }
580 };
581}