blob: 310f04abc36c70112ebd0ddf76eccc4a1c0b44b4 [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;
lpeter8a5f4702019-01-18 16:53:07 +080044import com.android.systemui.dock.DockManager;
Adrian Roosff2c4562016-11-03 12:13:36 -070045import com.android.systemui.statusbar.phone.DozeParameters;
46import com.android.systemui.util.Assert;
Adrian Roosc1b50322017-02-27 21:07:58 +010047import com.android.systemui.util.wakelock.WakeLock;
Adrian Roosff2c4562016-11-03 12:13:36 -070048
49import java.io.PrintWriter;
Adrian Roosd32b3662017-06-27 14:48:50 +020050import java.util.function.IntConsumer;
Adrian Roosff2c4562016-11-03 12:13:36 -070051
52/**
53 * Handles triggers for ambient state changes.
54 */
55public class DozeTriggers implements DozeMachine.Part {
56
57 private static final String TAG = "DozeTriggers";
Adrian Roos67cca742017-04-13 16:52:51 -070058 private static final boolean DEBUG = DozeService.DEBUG;
Adrian Roosff2c4562016-11-03 12:13:36 -070059
60 /** adb shell am broadcast -a com.android.systemui.doze.pulse com.android.systemui */
61 private static final String PULSE_ACTION = "com.android.systemui.doze.pulse";
62
Lucas Dupin1ae6cf92018-12-14 18:06:38 -080063 /**
64 * Last value sent by the wake-display sensor.
65 * Assuming that the screen should start on.
66 */
67 private static boolean sWakeDisplaySensorState = true;
68
Adrian Roosff2c4562016-11-03 12:13:36 -070069 private final Context mContext;
70 private final DozeMachine mMachine;
71 private final DozeSensors mDozeSensors;
72 private final DozeHost mDozeHost;
73 private final AmbientDisplayConfiguration mConfig;
74 private final DozeParameters mDozeParameters;
75 private final SensorManager mSensorManager;
76 private final Handler mHandler;
Adrian Roosc1b50322017-02-27 21:07:58 +010077 private final WakeLock mWakeLock;
Adrian Roosf9d13f62016-11-08 15:42:20 -080078 private final boolean mAllowPulseTriggers;
Adrian Roosff2c4562016-11-03 12:13:36 -070079 private final UiModeManager mUiModeManager;
80 private final TriggerReceiver mBroadcastReceiver = new TriggerReceiver();
lpeter8a5f4702019-01-18 16:53:07 +080081 private final DockEventListener mDockEventListener = new DockEventListener();
82 private final DockManager mDockManager;
Adrian Roosff2c4562016-11-03 12:13:36 -070083
84 private long mNotificationPulseTime;
85 private boolean mPulsePending;
86
Steven Wude353052019-03-12 13:49:23 -040087 private final MetricsLogger mMetricsLogger = Dependency.get(MetricsLogger.class);
Adrian Roosff2c4562016-11-03 12:13:36 -070088
89 public DozeTriggers(Context context, DozeMachine machine, DozeHost dozeHost,
Adrian Roos6023ccb2017-06-28 16:22:02 +020090 AlarmManager alarmManager, AmbientDisplayConfiguration config,
Adrian Roosff2c4562016-11-03 12:13:36 -070091 DozeParameters dozeParameters, SensorManager sensorManager, Handler handler,
lpeter8a5f4702019-01-18 16:53:07 +080092 WakeLock wakeLock, boolean allowPulseTriggers, DockManager dockManager) {
Adrian Roosff2c4562016-11-03 12:13:36 -070093 mContext = context;
94 mMachine = machine;
95 mDozeHost = dozeHost;
96 mConfig = config;
97 mDozeParameters = dozeParameters;
98 mSensorManager = sensorManager;
99 mHandler = handler;
100 mWakeLock = wakeLock;
Adrian Roosf9d13f62016-11-08 15:42:20 -0800101 mAllowPulseTriggers = allowPulseTriggers;
Adrian Roos6023ccb2017-06-28 16:22:02 +0200102 mDozeSensors = new DozeSensors(context, alarmManager, mSensorManager, dozeParameters,
Lucas Dupinb2d9f482018-11-16 18:55:13 -0800103 config, wakeLock, this::onSensor, this::onProximityFar,
Adrian Roos2f5a3852018-04-23 17:48:08 +0200104 dozeParameters.getPolicy());
Adrian Roosff2c4562016-11-03 12:13:36 -0700105 mUiModeManager = mContext.getSystemService(UiModeManager.class);
lpeter8a5f4702019-01-18 16:53:07 +0800106 mDockManager = dockManager;
Adrian Roosff2c4562016-11-03 12:13:36 -0700107 }
108
Selim Cinek65c96f22019-07-25 20:09:04 -0700109 private void onNotification(Runnable onPulseSuppressedListener) {
Dave Mankoff15bbec62019-06-27 15:17:42 -0400110 if (DozeMachine.DEBUG) {
111 Log.d(TAG, "requestNotificationPulse");
112 }
113 if (!sWakeDisplaySensorState) {
114 Log.d(TAG, "Wake display false. Pulse denied.");
Selim Cinek65c96f22019-07-25 20:09:04 -0700115 runIfNotNull(onPulseSuppressedListener);
Lucas Dupinc0b81112019-07-25 18:56:12 -0700116 DozeLog.tracePulseDropped(mContext, "wakeDisplaySensor");
Dave Mankoff15bbec62019-06-27 15:17:42 -0400117 return;
118 }
Adrian Roosff2c4562016-11-03 12:13:36 -0700119 mNotificationPulseTime = SystemClock.elapsedRealtime();
Dave Mankoff15bbec62019-06-27 15:17:42 -0400120 if (!mConfig.pulseOnNotificationEnabled(UserHandle.USER_CURRENT)) {
Selim Cinek65c96f22019-07-25 20:09:04 -0700121 runIfNotNull(onPulseSuppressedListener);
Lucas Dupinc0b81112019-07-25 18:56:12 -0700122 DozeLog.tracePulseDropped(mContext, "pulseOnNotificationsDisabled");
Dave Mankoff15bbec62019-06-27 15:17:42 -0400123 return;
124 }
Selim Cinek65c96f22019-07-25 20:09:04 -0700125 requestPulse(DozeLog.PULSE_REASON_NOTIFICATION, false /* performedProxCheck */,
126 onPulseSuppressedListener);
Adrian Roos181c3202016-11-07 13:24:31 -0800127 DozeLog.traceNotificationPulse(mContext);
Adrian Roosff2c4562016-11-03 12:13:36 -0700128 }
129
Selim Cinek65c96f22019-07-25 20:09:04 -0700130 private static void runIfNotNull(Runnable runnable) {
131 if (runnable != null) {
132 runnable.run();
133 }
134 }
135
Adrian Roosd32b3662017-06-27 14:48:50 +0200136 private void proximityCheckThenCall(IntConsumer callback,
137 boolean alreadyPerformedProxCheck,
Lucas Dupin323f9ff2018-08-27 16:55:56 -0700138 int reason) {
Adrian Roos70da03a2017-07-24 16:42:57 +0200139 Boolean cachedProxFar = mDozeSensors.isProximityCurrentlyFar();
Adrian Roosd32b3662017-06-27 14:48:50 +0200140 if (alreadyPerformedProxCheck) {
141 callback.accept(ProximityCheck.RESULT_NOT_CHECKED);
Adrian Roos70da03a2017-07-24 16:42:57 +0200142 } else if (cachedProxFar != null) {
143 callback.accept(cachedProxFar ? ProximityCheck.RESULT_FAR : ProximityCheck.RESULT_NEAR);
Adrian Roosd32b3662017-06-27 14:48:50 +0200144 } else {
145 final long start = SystemClock.uptimeMillis();
146 new ProximityCheck() {
147 @Override
148 public void onProximityResult(int result) {
149 final long end = SystemClock.uptimeMillis();
150 DozeLog.traceProximityResult(mContext, result == RESULT_NEAR,
Lucas Dupin323f9ff2018-08-27 16:55:56 -0700151 end - start, reason);
Adrian Roosd32b3662017-06-27 14:48:50 +0200152 callback.accept(result);
153 }
154 }.check();
155 }
156 }
157
lpeter8a5f4702019-01-18 16:53:07 +0800158 @VisibleForTesting
159 void onSensor(int pulseReason, boolean sensorPerformedProxCheck,
Lucas Dupinb2d9f482018-11-16 18:55:13 -0800160 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) {
Selim Cinek65c96f22019-07-25 20:09:04 -0700172 requestPulse(pulseReason, sensorPerformedProxCheck, null /* onPulseSupressedListener */);
Lucas Dupin8a13aa72019-02-22 12:45:21 -0800173 } else if (isWakeLockScreen) {
174 if (wakeEvent) {
Selim Cinek65c96f22019-07-25 20:09:04 -0700175 requestPulse(pulseReason, sensorPerformedProxCheck,
176 null /* onPulseSupressedListener */);
Lucas Dupin8a13aa72019-02-22 12:45:21 -0800177 }
Lucas Dupin4359b552018-08-09 15:07:54 -0700178 } else {
Adrian Roosd32b3662017-06-27 14:48:50 +0200179 proximityCheckThenCall((result) -> {
180 if (result == ProximityCheck.RESULT_NEAR) {
181 // In pocket, drop event.
182 return;
183 }
Lucas Dupind43bf702019-01-15 13:40:42 -0800184 if (isDoubleTap || isTap) {
185 if (screenX != -1 && screenY != -1) {
186 mDozeHost.onSlpiTap(screenX, screenY);
187 }
Lucas Dupined5b7a92019-03-20 11:00:27 -0700188 gentleWakeUp(pulseReason);
Lucas Dupinb2d9f482018-11-16 18:55:13 -0800189 } else if (isPickup) {
Lucas Dupined5b7a92019-03-20 11:00:27 -0700190 gentleWakeUp(pulseReason);
Adrian Roosd32b3662017-06-27 14:48:50 +0200191 } else {
Lucas Dupin5f00fa52019-03-27 22:46:53 -0700192 mDozeHost.extendPulse(pulseReason);
Adrian Roosd32b3662017-06-27 14:48:50 +0200193 }
lpeterac798f22019-02-12 15:15:22 +0800194 }, sensorPerformedProxCheck
195 || (mDockManager != null && mDockManager.isDocked()), 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 }
281 }, false /* alreadyPerformedProxCheck */, DozeLog.REASON_SENSOR_WAKE_UP);
282 } 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
348 || mDozeHost.isPowerSaveActive()
Adrian Roos710a0b12017-07-07 19:02:34 +0200349 || mDozeHost.isBlockingDoze()
Adrian Roosf2d545e2017-07-05 16:45:42 +0200350 || !mDozeHost.isProvisioned()) {
351 mMachine.requestState(DozeMachine.State.FINISH);
Adrian Roosff2c4562016-11-03 12:13:36 -0700352 }
353 }
354
Selim Cinek65c96f22019-07-25 20:09:04 -0700355 private void requestPulse(final int reason, boolean performedProxCheck,
356 Runnable onPulseSuppressedListener) {
Adrian Roosff2c4562016-11-03 12:13:36 -0700357 Assert.isMainThread();
Lucas Dupin5f00fa52019-03-27 22:46:53 -0700358 mDozeHost.extendPulse(reason);
359
360 // When already pulsing we're allowed to show the wallpaper directly without
361 // requesting a new pulse.
362 if (mMachine.getState() == DozeMachine.State.DOZE_PULSING
363 && reason == DozeLog.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN) {
364 mMachine.requestState(DozeMachine.State.DOZE_PULSING_BRIGHT);
365 return;
366 }
367
Adrian Roosf9d13f62016-11-08 15:42:20 -0800368 if (mPulsePending || !mAllowPulseTriggers || !canPulse()) {
Adrian Roosd35d4ca2017-04-19 14:31:03 -0700369 if (mAllowPulseTriggers) {
370 DozeLog.tracePulseDropped(mContext, mPulsePending, mMachine.getState(),
371 mDozeHost.isPulsingBlocked());
372 }
Selim Cinek65c96f22019-07-25 20:09:04 -0700373 runIfNotNull(onPulseSuppressedListener);
Adrian Roosff2c4562016-11-03 12:13:36 -0700374 return;
375 }
376
377 mPulsePending = true;
Adrian Roosd32b3662017-06-27 14:48:50 +0200378 proximityCheckThenCall((result) -> {
379 if (result == ProximityCheck.RESULT_NEAR) {
380 // in pocket, abort pulse
Lucas Dupinc0b81112019-07-25 18:56:12 -0700381 DozeLog.tracePulseDropped(mContext, "inPocket");
Adrian Roosd32b3662017-06-27 14:48:50 +0200382 mPulsePending = false;
Selim Cinek65c96f22019-07-25 20:09:04 -0700383 runIfNotNull(onPulseSuppressedListener);
Adrian Roosd32b3662017-06-27 14:48:50 +0200384 } else {
385 // not in pocket, continue pulsing
Adrian Roosff2c4562016-11-03 12:13:36 -0700386 continuePulseRequest(reason);
387 }
Adrian Roosd32b3662017-06-27 14:48:50 +0200388 }, !mDozeParameters.getProxCheckBeforePulse() || performedProxCheck, reason);
Steven Wude353052019-03-12 13:49:23 -0400389
390 // Logs request pulse reason on AOD screen.
391 mMetricsLogger.write(new LogMaker(MetricsEvent.DOZING)
392 .setType(MetricsEvent.TYPE_UPDATE).setSubtype(reason));
Adrian Roosff2c4562016-11-03 12:13:36 -0700393 }
394
395 private boolean canPulse() {
396 return mMachine.getState() == DozeMachine.State.DOZE
397 || mMachine.getState() == DozeMachine.State.DOZE_AOD;
398 }
399
400 private void continuePulseRequest(int reason) {
401 mPulsePending = false;
402 if (mDozeHost.isPulsingBlocked() || !canPulse()) {
Adrian Roosd35d4ca2017-04-19 14:31:03 -0700403 DozeLog.tracePulseDropped(mContext, mPulsePending, mMachine.getState(),
404 mDozeHost.isPulsingBlocked());
Adrian Roosff2c4562016-11-03 12:13:36 -0700405 return;
406 }
Adrian Roosd7b9d102017-04-28 15:42:58 -0700407 mMachine.requestPulse(reason);
Adrian Roosff2c4562016-11-03 12:13:36 -0700408 }
409
410 @Override
411 public void dump(PrintWriter pw) {
412 pw.print(" notificationPulseTime=");
413 pw.println(Formatter.formatShortElapsedTime(mContext, mNotificationPulseTime));
414
415 pw.print(" pulsePending="); pw.println(mPulsePending);
416 pw.println("DozeSensors:");
417 mDozeSensors.dump(pw);
418 }
419
420 private abstract class ProximityCheck implements SensorEventListener, Runnable {
421 private static final int TIMEOUT_DELAY_MS = 500;
422
423 protected static final int RESULT_UNKNOWN = 0;
424 protected static final int RESULT_NEAR = 1;
425 protected static final int RESULT_FAR = 2;
Adrian Roosd32b3662017-06-27 14:48:50 +0200426 protected static final int RESULT_NOT_CHECKED = 3;
Adrian Roosff2c4562016-11-03 12:13:36 -0700427
428 private boolean mRegistered;
429 private boolean mFinished;
430 private float mMaxRange;
431
432 protected abstract void onProximityResult(int result);
433
434 public void check() {
435 Preconditions.checkState(!mFinished && !mRegistered);
436 final Sensor sensor = mSensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY);
437 if (sensor == null) {
438 if (DozeMachine.DEBUG) Log.d(TAG, "ProxCheck: No sensor found");
439 finishWithResult(RESULT_UNKNOWN);
440 return;
441 }
442 mDozeSensors.setDisableSensorsInterferingWithProximity(true);
443
444 mMaxRange = sensor.getMaximumRange();
445 mSensorManager.registerListener(this, sensor, SensorManager.SENSOR_DELAY_NORMAL, 0,
446 mHandler);
447 mHandler.postDelayed(this, TIMEOUT_DELAY_MS);
Lucas Dupinee4c9b72019-02-18 17:04:58 -0800448 mWakeLock.acquire(TAG);
Adrian Roosff2c4562016-11-03 12:13:36 -0700449 mRegistered = true;
450 }
451
452 @Override
453 public void onSensorChanged(SensorEvent event) {
454 if (event.values.length == 0) {
455 if (DozeMachine.DEBUG) Log.d(TAG, "ProxCheck: Event has no values!");
456 finishWithResult(RESULT_UNKNOWN);
457 } else {
458 if (DozeMachine.DEBUG) {
459 Log.d(TAG, "ProxCheck: Event: value=" + event.values[0] + " max=" + mMaxRange);
460 }
461 final boolean isNear = event.values[0] < mMaxRange;
462 finishWithResult(isNear ? RESULT_NEAR : RESULT_FAR);
463 }
464 }
465
466 @Override
467 public void run() {
468 if (DozeMachine.DEBUG) Log.d(TAG, "ProxCheck: No event received before timeout");
469 finishWithResult(RESULT_UNKNOWN);
470 }
471
472 private void finishWithResult(int result) {
473 if (mFinished) return;
474 boolean wasRegistered = mRegistered;
475 if (mRegistered) {
476 mHandler.removeCallbacks(this);
477 mSensorManager.unregisterListener(this);
478 mDozeSensors.setDisableSensorsInterferingWithProximity(false);
479 mRegistered = false;
480 }
481 onProximityResult(result);
482 if (wasRegistered) {
Lucas Dupinee4c9b72019-02-18 17:04:58 -0800483 mWakeLock.release(TAG);
Adrian Roosff2c4562016-11-03 12:13:36 -0700484 }
485 mFinished = true;
486 }
487
488 @Override
489 public void onAccuracyChanged(Sensor sensor, int accuracy) {
490 // noop
491 }
492 }
493
494 private class TriggerReceiver extends BroadcastReceiver {
Adrian Roos67cca742017-04-13 16:52:51 -0700495 private boolean mRegistered;
496
Adrian Roosff2c4562016-11-03 12:13:36 -0700497 @Override
498 public void onReceive(Context context, Intent intent) {
499 if (PULSE_ACTION.equals(intent.getAction())) {
500 if (DozeMachine.DEBUG) Log.d(TAG, "Received pulse intent");
Selim Cinek65c96f22019-07-25 20:09:04 -0700501 requestPulse(DozeLog.PULSE_REASON_INTENT, false, /* performedProxCheck */
502 null /* onPulseSupressedListener */);
Adrian Roosff2c4562016-11-03 12:13:36 -0700503 }
504 if (UiModeManager.ACTION_ENTER_CAR_MODE.equals(intent.getAction())) {
Adrian Roosf2d545e2017-07-05 16:45:42 +0200505 mMachine.requestState(DozeMachine.State.FINISH);
Adrian Roosff2c4562016-11-03 12:13:36 -0700506 }
507 if (Intent.ACTION_USER_SWITCHED.equals(intent.getAction())) {
508 mDozeSensors.onUserSwitched();
509 }
510 }
511
512 public void register(Context context) {
Adrian Roos67cca742017-04-13 16:52:51 -0700513 if (mRegistered) {
514 return;
515 }
Adrian Roosff2c4562016-11-03 12:13:36 -0700516 IntentFilter filter = new IntentFilter(PULSE_ACTION);
517 filter.addAction(UiModeManager.ACTION_ENTER_CAR_MODE);
518 filter.addAction(Intent.ACTION_USER_SWITCHED);
519 context.registerReceiver(this, filter);
Adrian Roos67cca742017-04-13 16:52:51 -0700520 mRegistered = true;
Adrian Roosff2c4562016-11-03 12:13:36 -0700521 }
522
523 public void unregister(Context context) {
Adrian Roos67cca742017-04-13 16:52:51 -0700524 if (!mRegistered) {
525 return;
526 }
Adrian Roosff2c4562016-11-03 12:13:36 -0700527 context.unregisterReceiver(this);
Adrian Roos67cca742017-04-13 16:52:51 -0700528 mRegistered = false;
Adrian Roosff2c4562016-11-03 12:13:36 -0700529 }
530 }
531
lpeter8a5f4702019-01-18 16:53:07 +0800532 private class DockEventListener implements DockManager.DockEventListener {
533 @Override
534 public void onEvent(int event) {
535 if (DEBUG) Log.d(TAG, "dock event = " + event);
536 switch (event) {
537 case DockManager.STATE_DOCKED:
538 case DockManager.STATE_DOCKED_HIDE:
539 mDozeSensors.ignoreTouchScreenSensorsSettingInterferingWithDocking(true);
540 break;
541 case DockManager.STATE_NONE:
542 mDozeSensors.ignoreTouchScreenSensorsSettingInterferingWithDocking(false);
543 break;
544 default:
545 // no-op
546 }
547 }
548 }
549
Adrian Roosff2c4562016-11-03 12:13:36 -0700550 private DozeHost.Callback mHostCallback = new DozeHost.Callback() {
551 @Override
Selim Cinek65c96f22019-07-25 20:09:04 -0700552 public void onNotificationAlerted(Runnable onPulseSuppressedListener) {
553 onNotification(onPulseSuppressedListener);
Adrian Roosff2c4562016-11-03 12:13:36 -0700554 }
555
556 @Override
Adrian Roosff2c4562016-11-03 12:13:36 -0700557 public void onPowerSaveChanged(boolean active) {
558 if (active) {
Adrian Roosf2d545e2017-07-05 16:45:42 +0200559 mMachine.requestState(DozeMachine.State.FINISH);
Adrian Roosff2c4562016-11-03 12:13:36 -0700560 }
561 }
562 };
563}