blob: 026a62528c8d86ac1c4b0f160ada7e0c32da292c [file] [log] [blame]
Adrian Roosea8d6ae2016-10-26 10:40:12 -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
Adrian Roosff2c4562016-11-03 12:13:36 -070014 * limitations under the License.
Adrian Roosea8d6ae2016-10-26 10:40:12 -070015 */
16
17package com.android.systemui.doze;
18
Lucas Dupinb2d9f482018-11-16 18:55:13 -080019import static com.android.systemui.plugins.SensorManagerPlugin.Sensor.TYPE_WAKE_DISPLAY;
Lucas Dupinde64ee02018-12-21 14:45:12 -080020import static com.android.systemui.plugins.SensorManagerPlugin.Sensor.TYPE_WAKE_LOCK_SCREEN;
Lucas Dupin3d951752018-10-10 12:00:40 -070021
Adrian Roosea8d6ae2016-10-26 10:40:12 -070022import android.annotation.AnyThread;
23import android.app.ActivityManager;
Adrian Roos6023ccb2017-06-28 16:22:02 +020024import android.app.AlarmManager;
Adrian Roosea8d6ae2016-10-26 10:40:12 -070025import android.content.ContentResolver;
26import android.content.Context;
27import android.database.ContentObserver;
28import android.hardware.Sensor;
Adrian Roos67cca742017-04-13 16:52:51 -070029import android.hardware.SensorEventListener;
Adrian Roosea8d6ae2016-10-26 10:40:12 -070030import android.hardware.SensorManager;
31import android.hardware.TriggerEvent;
32import android.hardware.TriggerEventListener;
Issei Suzukica19e6e2019-02-26 12:39:11 +010033import android.hardware.display.AmbientDisplayConfiguration;
Adrian Roosea8d6ae2016-10-26 10:40:12 -070034import android.net.Uri;
35import android.os.Handler;
Adrian Roos6023ccb2017-06-28 16:22:02 +020036import android.os.SystemClock;
Adrian Roosea8d6ae2016-10-26 10:40:12 -070037import android.os.UserHandle;
Adrian Roosea8d6ae2016-10-26 10:40:12 -070038import android.provider.Settings;
39import android.text.TextUtils;
40import android.util.Log;
41
Lucas Dupin8a13aa72019-02-22 12:45:21 -080042import androidx.annotation.VisibleForTesting;
43
Adrian Roosff2c4562016-11-03 12:13:36 -070044import com.android.internal.logging.MetricsLogger;
Tamas Berghammer383db5eb2016-06-22 15:21:38 +010045import com.android.internal.logging.nano.MetricsProto;
Lucas Dupinf61c1042019-07-19 12:16:25 -070046import com.android.systemui.R;
Lucas Dupin3d951752018-10-10 12:00:40 -070047import com.android.systemui.plugins.SensorManagerPlugin;
Adrian Roosff2c4562016-11-03 12:13:36 -070048import com.android.systemui.statusbar.phone.DozeParameters;
Adrian Roos6023ccb2017-06-28 16:22:02 +020049import com.android.systemui.util.AlarmTimeout;
Lucas Dupin3d951752018-10-10 12:00:40 -070050import com.android.systemui.util.AsyncSensorManager;
Adrian Roosc1b50322017-02-27 21:07:58 +010051import com.android.systemui.util.wakelock.WakeLock;
Adrian Roosff2c4562016-11-03 12:13:36 -070052
53import java.io.PrintWriter;
Adrian Roosea8d6ae2016-10-26 10:40:12 -070054import java.util.List;
Adrian Roos67cca742017-04-13 16:52:51 -070055import java.util.function.Consumer;
Adrian Roosea8d6ae2016-10-26 10:40:12 -070056
57public class DozeSensors {
58
59 private static final boolean DEBUG = DozeService.DEBUG;
60
61 private static final String TAG = "DozeSensors";
62
63 private final Context mContext;
Adrian Roos6023ccb2017-06-28 16:22:02 +020064 private final AlarmManager mAlarmManager;
Adrian Roosea8d6ae2016-10-26 10:40:12 -070065 private final SensorManager mSensorManager;
Adrian Roosea8d6ae2016-10-26 10:40:12 -070066 private final ContentResolver mResolver;
67 private final TriggerSensor mPickupSensor;
68 private final DozeParameters mDozeParameters;
69 private final AmbientDisplayConfiguration mConfig;
Adrian Roosc1b50322017-02-27 21:07:58 +010070 private final WakeLock mWakeLock;
Adrian Roos67cca742017-04-13 16:52:51 -070071 private final Consumer<Boolean> mProxCallback;
Adrian Roosea8d6ae2016-10-26 10:40:12 -070072 private final Callback mCallback;
Lucas Dupin8a13aa72019-02-22 12:45:21 -080073 @VisibleForTesting
lpeteraca97632019-06-11 11:13:54 +080074 protected TriggerSensor[] mSensors;
Adrian Roosea8d6ae2016-10-26 10:40:12 -070075
76 private final Handler mHandler = new Handler();
Adrian Roos67cca742017-04-13 16:52:51 -070077 private final ProxSensor mProxSensor;
Lucas Dupin8a13aa72019-02-22 12:45:21 -080078 private long mDebounceFrom;
lpeteraca97632019-06-11 11:13:54 +080079 private boolean mSettingRegistered;
Lucas Dupinfac2e8e2019-06-27 16:10:19 -070080 private boolean mListening;
81 private boolean mPaused;
Adrian Roosea8d6ae2016-10-26 10:40:12 -070082
Adrian Roos6023ccb2017-06-28 16:22:02 +020083 public DozeSensors(Context context, AlarmManager alarmManager, SensorManager sensorManager,
Lucas Dupin323f9ff2018-08-27 16:55:56 -070084 DozeParameters dozeParameters, AmbientDisplayConfiguration config, WakeLock wakeLock,
Lucas Dupinb2d9f482018-11-16 18:55:13 -080085 Callback callback, Consumer<Boolean> proxCallback, AlwaysOnDisplayPolicy policy) {
Adrian Roosea8d6ae2016-10-26 10:40:12 -070086 mContext = context;
Adrian Roos6023ccb2017-06-28 16:22:02 +020087 mAlarmManager = alarmManager;
Adrian Roosea8d6ae2016-10-26 10:40:12 -070088 mSensorManager = sensorManager;
89 mDozeParameters = dozeParameters;
90 mConfig = config;
91 mWakeLock = wakeLock;
Adrian Roos67cca742017-04-13 16:52:51 -070092 mProxCallback = proxCallback;
Adrian Roosea8d6ae2016-10-26 10:40:12 -070093 mResolver = mContext.getContentResolver();
94
Lucas Dupin70bda672018-12-27 15:43:40 -080095 boolean alwaysOn = mConfig.alwaysOnEnabled(UserHandle.USER_CURRENT);
Adrian Roosea8d6ae2016-10-26 10:40:12 -070096 mSensors = new TriggerSensor[] {
97 new TriggerSensor(
98 mSensorManager.getDefaultSensor(Sensor.TYPE_SIGNIFICANT_MOTION),
99 null /* setting */,
100 dozeParameters.getPulseOnSigMotion(),
Adrian Roos98d31982017-08-02 20:50:16 +0200101 DozeLog.PULSE_REASON_SENSOR_SIGMOTION, false /* touchCoords */,
102 false /* touchscreen */),
Adrian Roosea8d6ae2016-10-26 10:40:12 -0700103 mPickupSensor = new TriggerSensor(
104 mSensorManager.getDefaultSensor(Sensor.TYPE_PICK_UP_GESTURE),
Lucas Dupin4359b552018-08-09 15:07:54 -0700105 Settings.Secure.DOZE_PICK_UP_GESTURE,
Lucas Dupinfac2e8e2019-06-27 16:10:19 -0700106 true /* settingDef */,
Lucas Dupin4359b552018-08-09 15:07:54 -0700107 config.dozePickupSensorAvailable(),
Lucas Dupin3d053532019-01-29 12:35:22 -0800108 DozeLog.REASON_SENSOR_PICKUP, false /* touchCoords */,
Lucas Dupinfac2e8e2019-06-27 16:10:19 -0700109 false /* touchscreen */,
Lucas Dupinf40bd8f2019-08-07 15:55:00 -0700110 false /* ignoresSetting */),
Adrian Roosea8d6ae2016-10-26 10:40:12 -0700111 new TriggerSensor(
112 findSensorWithType(config.doubleTapSensorType()),
Lucas Dupin4359b552018-08-09 15:07:54 -0700113 Settings.Secure.DOZE_DOUBLE_TAP_GESTURE,
Adrian Roosea8d6ae2016-10-26 10:40:12 -0700114 true /* configured */,
Lucas Dupin3d053532019-01-29 12:35:22 -0800115 DozeLog.REASON_SENSOR_DOUBLE_TAP,
Adrian Roos98d31982017-08-02 20:50:16 +0200116 dozeParameters.doubleTapReportsTouchCoordinates(),
117 true /* touchscreen */),
Adrian Roosd0963a02017-05-15 14:33:37 -0700118 new TriggerSensor(
Lucas Dupind43bf702019-01-15 13:40:42 -0800119 findSensorWithType(config.tapSensorType()),
120 Settings.Secure.DOZE_TAP_SCREEN_GESTURE,
121 true /* configured */,
Lucas Dupin3d053532019-01-29 12:35:22 -0800122 DozeLog.REASON_SENSOR_TAP,
Lucas Dupind43bf702019-01-15 13:40:42 -0800123 false /* reports touch coordinates */,
124 true /* touchscreen */),
125 new TriggerSensor(
Adrian Roosd0963a02017-05-15 14:33:37 -0700126 findSensorWithType(config.longPressSensorType()),
127 Settings.Secure.DOZE_PULSE_ON_LONG_PRESS,
128 false /* settingDef */,
129 true /* configured */,
130 DozeLog.PULSE_REASON_SENSOR_LONG_PRESS,
Adrian Roos98d31982017-08-02 20:50:16 +0200131 true /* reports touch coordinates */,
132 true /* touchscreen */),
Lucas Dupin1ae6cf92018-12-14 18:06:38 -0800133 new PluginSensor(
Lucas Dupinb2d9f482018-11-16 18:55:13 -0800134 new SensorManagerPlugin.Sensor(TYPE_WAKE_DISPLAY),
Lucas Dupin7c7b8c22019-06-12 15:23:17 -0700135 Settings.Secure.DOZE_WAKE_DISPLAY_GESTURE,
Lucas Dupin70bda672018-12-27 15:43:40 -0800136 mConfig.wakeScreenGestureAvailable() && alwaysOn,
Lucas Dupinb2d9f482018-11-16 18:55:13 -0800137 DozeLog.REASON_SENSOR_WAKE_UP,
138 false /* reports touch coordinates */,
139 false /* touchscreen */),
Lucas Dupinde64ee02018-12-21 14:45:12 -0800140 new PluginSensor(
141 new SensorManagerPlugin.Sensor(TYPE_WAKE_LOCK_SCREEN),
Lucas Dupin7c7b8c22019-06-12 15:23:17 -0700142 Settings.Secure.DOZE_WAKE_LOCK_SCREEN_GESTURE,
143 mConfig.wakeScreenGestureAvailable(),
Lucas Dupinde64ee02018-12-21 14:45:12 -0800144 DozeLog.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN,
145 false /* reports touch coordinates */,
Lucas Dupin8a13aa72019-02-22 12:45:21 -0800146 false /* touchscreen */, mConfig.getWakeLockScreenDebounce()),
Adrian Roosea8d6ae2016-10-26 10:40:12 -0700147 };
Adrian Roos67cca742017-04-13 16:52:51 -0700148
jackqdyulei8443dd02017-08-24 16:14:34 -0700149 mProxSensor = new ProxSensor(policy);
Adrian Roosea8d6ae2016-10-26 10:40:12 -0700150 mCallback = callback;
151 }
152
Lucas Dupin8a13aa72019-02-22 12:45:21 -0800153 /**
154 * Temporarily disable some sensors to avoid turning on the device while the user is
155 * turning it off.
156 */
157 public void requestTemporaryDisable() {
158 mDebounceFrom = SystemClock.uptimeMillis();
159 }
160
Adrian Roosea8d6ae2016-10-26 10:40:12 -0700161 private Sensor findSensorWithType(String type) {
Adrian Roos2981eb02017-05-26 18:40:09 -0700162 return findSensorWithType(mSensorManager, type);
163 }
164
165 static Sensor findSensorWithType(SensorManager sensorManager, String type) {
Adrian Roosea8d6ae2016-10-26 10:40:12 -0700166 if (TextUtils.isEmpty(type)) {
167 return null;
168 }
Adrian Roos2981eb02017-05-26 18:40:09 -0700169 List<Sensor> sensorList = sensorManager.getSensorList(Sensor.TYPE_ALL);
Adrian Roosea8d6ae2016-10-26 10:40:12 -0700170 for (Sensor s : sensorList) {
171 if (type.equals(s.getStringType())) {
172 return s;
173 }
174 }
175 return null;
176 }
177
Lucas Dupinfac2e8e2019-06-27 16:10:19 -0700178 /**
179 * If sensors should be registered and sending signals.
180 */
Adrian Roosd6ec13132016-10-27 11:50:47 -0700181 public void setListening(boolean listen) {
Lucas Dupinfac2e8e2019-06-27 16:10:19 -0700182 if (mListening == listen) {
183 return;
Adrian Roosea8d6ae2016-10-26 10:40:12 -0700184 }
Lucas Dupinfac2e8e2019-06-27 16:10:19 -0700185 mListening = listen;
186 updateListening();
187 }
188
189 /**
190 * Unregister sensors, when listening, unless they are prox gated.
191 * @see #setListening(boolean)
192 */
193 public void setPaused(boolean paused) {
194 if (mPaused == paused) {
195 return;
196 }
197 mPaused = paused;
198 updateListening();
199 }
200
Lucas Dupin3174c662019-07-15 15:49:54 -0700201 /**
202 * Registers/unregisters sensors based on internal state.
203 */
204 public void updateListening() {
Lucas Dupinfac2e8e2019-06-27 16:10:19 -0700205 boolean anyListening = false;
206 for (TriggerSensor s : mSensors) {
Lucas Dupinf40bd8f2019-08-07 15:55:00 -0700207 s.setListening(mListening);
208 if (mListening) {
Lucas Dupinfac2e8e2019-06-27 16:10:19 -0700209 anyListening = true;
210 }
211 }
212
213 if (!anyListening) {
214 mResolver.unregisterContentObserver(mSettingsObserver);
215 } else if (!mSettingRegistered) {
216 for (TriggerSensor s : mSensors) {
217 s.registerSettingsObserver(mSettingsObserver);
218 }
219 }
220 mSettingRegistered = anyListening;
Adrian Roosea8d6ae2016-10-26 10:40:12 -0700221 }
222
Adrian Roos98d31982017-08-02 20:50:16 +0200223 /** Set the listening state of only the sensors that require the touchscreen. */
224 public void setTouchscreenSensorsListening(boolean listening) {
225 for (TriggerSensor sensor : mSensors) {
226 if (sensor.mRequiresTouchscreen) {
227 sensor.setListening(listening);
228 }
229 }
230 }
231
Adrian Roosea8d6ae2016-10-26 10:40:12 -0700232 public void onUserSwitched() {
233 for (TriggerSensor s : mSensors) {
Lucas Dupin3174c662019-07-15 15:49:54 -0700234 s.updateListening();
Adrian Roosea8d6ae2016-10-26 10:40:12 -0700235 }
236 }
237
Adrian Roos67cca742017-04-13 16:52:51 -0700238 public void setProxListening(boolean listen) {
Adrian Roos6023ccb2017-06-28 16:22:02 +0200239 mProxSensor.setRequested(listen);
Adrian Roos67cca742017-04-13 16:52:51 -0700240 }
241
Adrian Roosea8d6ae2016-10-26 10:40:12 -0700242 private final ContentObserver mSettingsObserver = new ContentObserver(mHandler) {
243 @Override
244 public void onChange(boolean selfChange, Uri uri, int userId) {
245 if (userId != ActivityManager.getCurrentUser()) {
246 return;
247 }
248 for (TriggerSensor s : mSensors) {
Lucas Dupin3174c662019-07-15 15:49:54 -0700249 s.updateListening();
Adrian Roosea8d6ae2016-10-26 10:40:12 -0700250 }
251 }
252 };
253
254 public void setDisableSensorsInterferingWithProximity(boolean disable) {
255 mPickupSensor.setDisabled(disable);
256 }
257
lpeter8a5f4702019-01-18 16:53:07 +0800258 /** Ignore the setting value of only the sensors that require the touchscreen. */
259 public void ignoreTouchScreenSensorsSettingInterferingWithDocking(boolean ignore) {
260 for (TriggerSensor sensor : mSensors) {
261 if (sensor.mRequiresTouchscreen) {
262 sensor.ignoreSetting(ignore);
263 }
264 }
265 }
266
Adrian Roosff2c4562016-11-03 12:13:36 -0700267 /** Dump current state */
268 public void dump(PrintWriter pw) {
269 for (TriggerSensor s : mSensors) {
Lucas Dupindc13fe42019-04-10 16:07:50 -0700270 pw.print(" Sensor: "); pw.println(s.toString());
Adrian Roosff2c4562016-11-03 12:13:36 -0700271 }
Lucas Dupindc13fe42019-04-10 16:07:50 -0700272 pw.print(" ProxSensor: "); pw.println(mProxSensor.toString());
Adrian Roosff2c4562016-11-03 12:13:36 -0700273 }
274
Adrian Roos70da03a2017-07-24 16:42:57 +0200275 /**
276 * @return true if prox is currently far, false if near or null if unknown.
277 */
278 public Boolean isProximityCurrentlyFar() {
279 return mProxSensor.mCurrentlyFar;
280 }
281
Adrian Roos67cca742017-04-13 16:52:51 -0700282 private class ProxSensor implements SensorEventListener {
283
Adrian Roos6023ccb2017-06-28 16:22:02 +0200284 boolean mRequested;
Adrian Roos67cca742017-04-13 16:52:51 -0700285 boolean mRegistered;
286 Boolean mCurrentlyFar;
Adrian Roos6023ccb2017-06-28 16:22:02 +0200287 long mLastNear;
288 final AlarmTimeout mCooldownTimer;
jackqdyulei8443dd02017-08-24 16:14:34 -0700289 final AlwaysOnDisplayPolicy mPolicy;
Lucas Dupinf61c1042019-07-19 12:16:25 -0700290 final Sensor mSensor;
Lucas Dupincf06eb32019-08-12 14:14:08 -0700291 final boolean mUsingBrightnessSensor;
Adrian Roos6023ccb2017-06-28 16:22:02 +0200292
jackqdyulei8443dd02017-08-24 16:14:34 -0700293 public ProxSensor(AlwaysOnDisplayPolicy policy) {
294 mPolicy = policy;
Adrian Roos6023ccb2017-06-28 16:22:02 +0200295 mCooldownTimer = new AlarmTimeout(mAlarmManager, this::updateRegistered,
296 "prox_cooldown", mHandler);
Lucas Dupinf61c1042019-07-19 12:16:25 -0700297
298 // The default prox sensor can be noisy, so let's use a prox gated brightness sensor
299 // if available.
300 Sensor sensor = DozeSensors.findSensorWithType(mSensorManager,
301 mContext.getString(R.string.doze_brightness_sensor_type));
Lucas Dupincf06eb32019-08-12 14:14:08 -0700302 mUsingBrightnessSensor = sensor != null;
Lucas Dupinf61c1042019-07-19 12:16:25 -0700303 if (sensor == null) {
304 sensor = mSensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY);
305 }
306 mSensor = sensor;
Adrian Roos6023ccb2017-06-28 16:22:02 +0200307 }
308
309 void setRequested(boolean requested) {
310 if (mRequested == requested) {
Adrian Roos67cca742017-04-13 16:52:51 -0700311 // Send an update even if we don't re-register.
312 mHandler.post(() -> {
313 if (mCurrentlyFar != null) {
314 mProxCallback.accept(mCurrentlyFar);
315 }
316 });
317 return;
318 }
Adrian Roos6023ccb2017-06-28 16:22:02 +0200319 mRequested = requested;
320 updateRegistered();
321 }
322
323 private void updateRegistered() {
324 setRegistered(mRequested && !mCooldownTimer.isScheduled());
325 }
326
327 private void setRegistered(boolean register) {
328 if (mRegistered == register) {
329 return;
330 }
Adrian Roos67cca742017-04-13 16:52:51 -0700331 if (register) {
Lucas Dupincf06eb32019-08-12 14:14:08 -0700332 mRegistered = mSensorManager.registerListener(this, mSensor,
Adrian Roos67cca742017-04-13 16:52:51 -0700333 SensorManager.SENSOR_DELAY_NORMAL, mHandler);
334 } else {
335 mSensorManager.unregisterListener(this);
336 mRegistered = false;
337 mCurrentlyFar = null;
338 }
339 }
340
341 @Override
Lucas Dupin1ae6cf92018-12-14 18:06:38 -0800342 public void onSensorChanged(android.hardware.SensorEvent event) {
Lucas Dupin58543842018-02-15 14:00:54 -0800343 if (DEBUG) Log.d(TAG, "onSensorChanged " + event);
344
Lucas Dupincf06eb32019-08-12 14:14:08 -0700345 if (mUsingBrightnessSensor) {
346 // The custom brightness sensor is gated by the proximity sensor and will return 0
347 // whenever prox is covered.
348 mCurrentlyFar = event.values[0] > 0;
349 } else {
350 mCurrentlyFar = event.values[0] >= event.sensor.getMaximumRange();
351 }
Adrian Roos67cca742017-04-13 16:52:51 -0700352 mProxCallback.accept(mCurrentlyFar);
Adrian Roos6023ccb2017-06-28 16:22:02 +0200353
354 long now = SystemClock.elapsedRealtime();
Adrian Roos8f72b3c2017-07-07 12:20:21 +0200355 if (mCurrentlyFar == null) {
356 // Sensor has been unregistered by the proxCallback. Do nothing.
357 } else if (!mCurrentlyFar) {
Adrian Roos6023ccb2017-06-28 16:22:02 +0200358 mLastNear = now;
jackqdyulei8443dd02017-08-24 16:14:34 -0700359 } else if (mCurrentlyFar && now - mLastNear < mPolicy.proxCooldownTriggerMs) {
Adrian Roos6023ccb2017-06-28 16:22:02 +0200360 // If the last near was very recent, we might be using more power for prox
361 // wakeups than we're saving from turning of the screen. Instead, turn it off
362 // for a while.
jackqdyulei8443dd02017-08-24 16:14:34 -0700363 mCooldownTimer.schedule(mPolicy.proxCooldownPeriodMs,
364 AlarmTimeout.MODE_IGNORE_IF_SCHEDULED);
Adrian Roos6023ccb2017-06-28 16:22:02 +0200365 updateRegistered();
366 }
Adrian Roos67cca742017-04-13 16:52:51 -0700367 }
368
369 @Override
370 public void onAccuracyChanged(Sensor sensor, int accuracy) {
371 }
Adrian Roos2ca9cd72017-07-03 15:14:37 +0200372
373 @Override
374 public String toString() {
Lucas Dupinf61c1042019-07-19 12:16:25 -0700375 return String.format("{registered=%s, requested=%s, coolingDown=%s, currentlyFar=%s,"
376 + " sensor=%s}", mRegistered, mRequested, mCooldownTimer.isScheduled(),
377 mCurrentlyFar, mSensor);
Adrian Roos2ca9cd72017-07-03 15:14:37 +0200378 }
Adrian Roos67cca742017-04-13 16:52:51 -0700379 }
380
Lucas Dupin8a13aa72019-02-22 12:45:21 -0800381 @VisibleForTesting
382 class TriggerSensor extends TriggerEventListener {
Adrian Roosea8d6ae2016-10-26 10:40:12 -0700383 final Sensor mSensor;
384 final boolean mConfigured;
385 final int mPulseReason;
Lucas Dupinfac2e8e2019-06-27 16:10:19 -0700386 private final String mSetting;
387 private final boolean mReportsTouchCoordinates;
388 private final boolean mSettingDefault;
389 private final boolean mRequiresTouchscreen;
Adrian Roosea8d6ae2016-10-26 10:40:12 -0700390
Lucas Dupin323f9ff2018-08-27 16:55:56 -0700391 protected boolean mRequested;
392 protected boolean mRegistered;
393 protected boolean mDisabled;
lpeter8a5f4702019-01-18 16:53:07 +0800394 protected boolean mIgnoresSetting;
Adrian Roosea8d6ae2016-10-26 10:40:12 -0700395
Adrian Roos25c7a582017-06-02 12:50:38 -0700396 public TriggerSensor(Sensor sensor, String setting, boolean configured, int pulseReason,
Adrian Roos98d31982017-08-02 20:50:16 +0200397 boolean reportsTouchCoordinates, boolean requiresTouchscreen) {
Adrian Roosd0963a02017-05-15 14:33:37 -0700398 this(sensor, setting, true /* settingDef */, configured, pulseReason,
Adrian Roos98d31982017-08-02 20:50:16 +0200399 reportsTouchCoordinates, requiresTouchscreen);
Adrian Roosd0963a02017-05-15 14:33:37 -0700400 }
401
402 public TriggerSensor(Sensor sensor, String setting, boolean settingDef,
Adrian Roos98d31982017-08-02 20:50:16 +0200403 boolean configured, int pulseReason, boolean reportsTouchCoordinates,
404 boolean requiresTouchscreen) {
lpeter8a5f4702019-01-18 16:53:07 +0800405 this(sensor, setting, settingDef, configured, pulseReason, reportsTouchCoordinates,
Lucas Dupinf40bd8f2019-08-07 15:55:00 -0700406 requiresTouchscreen, false /* ignoresSetting */);
lpeter8a5f4702019-01-18 16:53:07 +0800407 }
408
409 private TriggerSensor(Sensor sensor, String setting, boolean settingDef,
410 boolean configured, int pulseReason, boolean reportsTouchCoordinates,
Lucas Dupinf40bd8f2019-08-07 15:55:00 -0700411 boolean requiresTouchscreen, boolean ignoresSetting) {
Adrian Roosea8d6ae2016-10-26 10:40:12 -0700412 mSensor = sensor;
413 mSetting = setting;
Adrian Roosd0963a02017-05-15 14:33:37 -0700414 mSettingDefault = settingDef;
Adrian Roosea8d6ae2016-10-26 10:40:12 -0700415 mConfigured = configured;
416 mPulseReason = pulseReason;
Adrian Roos25c7a582017-06-02 12:50:38 -0700417 mReportsTouchCoordinates = reportsTouchCoordinates;
Adrian Roos98d31982017-08-02 20:50:16 +0200418 mRequiresTouchscreen = requiresTouchscreen;
lpeter8a5f4702019-01-18 16:53:07 +0800419 mIgnoresSetting = ignoresSetting;
Adrian Roosea8d6ae2016-10-26 10:40:12 -0700420 }
421
422 public void setListening(boolean listen) {
423 if (mRequested == listen) return;
424 mRequested = listen;
Lucas Dupin3174c662019-07-15 15:49:54 -0700425 updateListening();
Adrian Roosea8d6ae2016-10-26 10:40:12 -0700426 }
427
428 public void setDisabled(boolean disabled) {
429 if (mDisabled == disabled) return;
430 mDisabled = disabled;
Lucas Dupin3174c662019-07-15 15:49:54 -0700431 updateListening();
Adrian Roosea8d6ae2016-10-26 10:40:12 -0700432 }
433
lpeter8a5f4702019-01-18 16:53:07 +0800434 public void ignoreSetting(boolean ignored) {
435 if (mIgnoresSetting == ignored) return;
436 mIgnoresSetting = ignored;
Lucas Dupin3174c662019-07-15 15:49:54 -0700437 updateListening();
lpeter8a5f4702019-01-18 16:53:07 +0800438 }
439
Lucas Dupin3174c662019-07-15 15:49:54 -0700440 public void updateListening() {
Adrian Roosea8d6ae2016-10-26 10:40:12 -0700441 if (!mConfigured || mSensor == null) return;
lpeter8a5f4702019-01-18 16:53:07 +0800442 if (mRequested && !mDisabled && (enabledBySetting() || mIgnoresSetting)
443 && !mRegistered) {
Adrian Roosea8d6ae2016-10-26 10:40:12 -0700444 mRegistered = mSensorManager.requestTriggerSensor(this, mSensor);
445 if (DEBUG) Log.d(TAG, "requestTriggerSensor " + mRegistered);
446 } else if (mRegistered) {
447 final boolean rt = mSensorManager.cancelTriggerSensor(this, mSensor);
448 if (DEBUG) Log.d(TAG, "cancelTriggerSensor " + rt);
449 mRegistered = false;
450 }
451 }
452
Lucas Dupin323f9ff2018-08-27 16:55:56 -0700453 protected boolean enabledBySetting() {
Jerry Chang5d3eb4472018-12-21 11:49:06 +0800454 if (!mConfig.enabled(UserHandle.USER_CURRENT)) {
455 return false;
456 } else if (TextUtils.isEmpty(mSetting)) {
Adrian Roosea8d6ae2016-10-26 10:40:12 -0700457 return true;
458 }
Adrian Roosd0963a02017-05-15 14:33:37 -0700459 return Settings.Secure.getIntForUser(mResolver, mSetting, mSettingDefault ? 1 : 0,
Adrian Roosea8d6ae2016-10-26 10:40:12 -0700460 UserHandle.USER_CURRENT) != 0;
461 }
462
463 @Override
464 public String toString() {
465 return new StringBuilder("{mRegistered=").append(mRegistered)
466 .append(", mRequested=").append(mRequested)
467 .append(", mDisabled=").append(mDisabled)
468 .append(", mConfigured=").append(mConfigured)
lpeter8a5f4702019-01-18 16:53:07 +0800469 .append(", mIgnoresSetting=").append(mIgnoresSetting)
Adrian Roosea8d6ae2016-10-26 10:40:12 -0700470 .append(", mSensor=").append(mSensor).append("}").toString();
471 }
472
473 @Override
474 @AnyThread
475 public void onTrigger(TriggerEvent event) {
Adrian Roos2ca9cd72017-07-03 15:14:37 +0200476 DozeLog.traceSensor(mContext, mPulseReason);
Adrian Roos79bacbb2016-10-26 11:00:12 -0700477 mHandler.post(mWakeLock.wrap(() -> {
Adrian Roosd6ec13132016-10-27 11:50:47 -0700478 if (DEBUG) Log.d(TAG, "onTrigger: " + triggerEventToString(event));
Lucas Dupin3d951752018-10-10 12:00:40 -0700479 if (mSensor != null && mSensor.getType() == Sensor.TYPE_PICK_UP_GESTURE) {
Adrian Roosea8d6ae2016-10-26 10:40:12 -0700480 int subType = (int) event.values[0];
481 MetricsLogger.action(
Adrian Roos79bacbb2016-10-26 11:00:12 -0700482 mContext, MetricsProto.MetricsEvent.ACTION_AMBIENT_GESTURE,
483 subType);
Adrian Roosea8d6ae2016-10-26 10:40:12 -0700484 }
485
486 mRegistered = false;
Adrian Roos25c7a582017-06-02 12:50:38 -0700487 float screenX = -1;
488 float screenY = -1;
489 if (mReportsTouchCoordinates && event.values.length >= 2) {
490 screenX = event.values[0];
491 screenY = event.values[1];
492 }
Lucas Dupinf40bd8f2019-08-07 15:55:00 -0700493 mCallback.onSensorPulse(mPulseReason, screenX, screenY, event.values);
Lucas Dupin65104382018-12-04 11:53:42 -0800494 if (!mRegistered) {
Lucas Dupin3174c662019-07-15 15:49:54 -0700495 updateListening(); // reregister, this sensor only fires once
Lucas Dupin65104382018-12-04 11:53:42 -0800496 }
Adrian Roos79bacbb2016-10-26 11:00:12 -0700497 }));
Adrian Roosea8d6ae2016-10-26 10:40:12 -0700498 }
499
500 public void registerSettingsObserver(ContentObserver settingsObserver) {
501 if (mConfigured && !TextUtils.isEmpty(mSetting)) {
502 mResolver.registerContentObserver(
503 Settings.Secure.getUriFor(mSetting), false /* descendants */,
504 mSettingsObserver, UserHandle.USER_ALL);
505 }
506 }
507
Lucas Dupin323f9ff2018-08-27 16:55:56 -0700508 protected String triggerEventToString(TriggerEvent event) {
Adrian Roosea8d6ae2016-10-26 10:40:12 -0700509 if (event == null) return null;
Lucas Dupin1ae6cf92018-12-14 18:06:38 -0800510 final StringBuilder sb = new StringBuilder("SensorEvent[")
Adrian Roosea8d6ae2016-10-26 10:40:12 -0700511 .append(event.timestamp).append(',')
512 .append(event.sensor.getName());
513 if (event.values != null) {
514 for (int i = 0; i < event.values.length; i++) {
515 sb.append(',').append(event.values[i]);
516 }
517 }
518 return sb.append(']').toString();
519 }
520 }
521
Lucas Dupin3d951752018-10-10 12:00:40 -0700522 /**
Kevin Chynf7c39032018-10-11 00:44:39 -0700523 * A Sensor that is injected via plugin.
Lucas Dupin3d951752018-10-10 12:00:40 -0700524 */
Lucas Dupin8a13aa72019-02-22 12:45:21 -0800525 @VisibleForTesting
526 class PluginSensor extends TriggerSensor implements SensorManagerPlugin.SensorEventListener {
Lucas Dupin3d951752018-10-10 12:00:40 -0700527
Lucas Dupin8a13aa72019-02-22 12:45:21 -0800528 final SensorManagerPlugin.Sensor mPluginSensor;
529 private long mDebounce;
Lucas Dupin3d951752018-10-10 12:00:40 -0700530
Lucas Dupin1ae6cf92018-12-14 18:06:38 -0800531 PluginSensor(SensorManagerPlugin.Sensor sensor, String setting, boolean configured,
Lucas Dupin3d951752018-10-10 12:00:40 -0700532 int pulseReason, boolean reportsTouchCoordinates, boolean requiresTouchscreen) {
Lucas Dupin8a13aa72019-02-22 12:45:21 -0800533 this(sensor, setting, configured, pulseReason, reportsTouchCoordinates,
534 requiresTouchscreen, 0L /* debounce */);
535 }
536
537 PluginSensor(SensorManagerPlugin.Sensor sensor, String setting, boolean configured,
538 int pulseReason, boolean reportsTouchCoordinates, boolean requiresTouchscreen,
539 long debounce) {
Lucas Dupin3d951752018-10-10 12:00:40 -0700540 super(null, setting, configured, pulseReason, reportsTouchCoordinates,
541 requiresTouchscreen);
542 mPluginSensor = sensor;
Lucas Dupin8a13aa72019-02-22 12:45:21 -0800543 mDebounce = debounce;
Lucas Dupin3d951752018-10-10 12:00:40 -0700544 }
545
546 @Override
Lucas Dupin3174c662019-07-15 15:49:54 -0700547 public void updateListening() {
Lucas Dupin3d951752018-10-10 12:00:40 -0700548 if (!mConfigured) return;
549 AsyncSensorManager asyncSensorManager = (AsyncSensorManager) mSensorManager;
lpeter8a5f4702019-01-18 16:53:07 +0800550 if (mRequested && !mDisabled && (enabledBySetting() || mIgnoresSetting)
551 && !mRegistered) {
Lucas Dupin8a13aa72019-02-22 12:45:21 -0800552 asyncSensorManager.registerPluginListener(mPluginSensor, this);
Lucas Dupin3d951752018-10-10 12:00:40 -0700553 mRegistered = true;
Lucas Dupin1ae6cf92018-12-14 18:06:38 -0800554 if (DEBUG) Log.d(TAG, "registerPluginListener");
Lucas Dupin3d951752018-10-10 12:00:40 -0700555 } else if (mRegistered) {
Lucas Dupin8a13aa72019-02-22 12:45:21 -0800556 asyncSensorManager.unregisterPluginListener(mPluginSensor, this);
Lucas Dupin3d951752018-10-10 12:00:40 -0700557 mRegistered = false;
Lucas Dupin1ae6cf92018-12-14 18:06:38 -0800558 if (DEBUG) Log.d(TAG, "unregisterPluginListener");
Lucas Dupin3d951752018-10-10 12:00:40 -0700559 }
560 }
561
562 @Override
563 public String toString() {
564 return new StringBuilder("{mRegistered=").append(mRegistered)
565 .append(", mRequested=").append(mRequested)
566 .append(", mDisabled=").append(mDisabled)
567 .append(", mConfigured=").append(mConfigured)
lpeter8a5f4702019-01-18 16:53:07 +0800568 .append(", mIgnoresSetting=").append(mIgnoresSetting)
Lucas Dupin3d951752018-10-10 12:00:40 -0700569 .append(", mSensor=").append(mPluginSensor).append("}").toString();
570 }
571
Lucas Dupin1ae6cf92018-12-14 18:06:38 -0800572 private String triggerEventToString(SensorManagerPlugin.SensorEvent event) {
Lucas Dupinb2d9f482018-11-16 18:55:13 -0800573 if (event == null) return null;
574 final StringBuilder sb = new StringBuilder("PluginTriggerEvent[")
575 .append(event.getSensor()).append(',')
576 .append(event.getVendorType());
577 if (event.getValues() != null) {
578 for (int i = 0; i < event.getValues().length; i++) {
579 sb.append(',').append(event.getValues()[i]);
580 }
581 }
582 return sb.append(']').toString();
Lucas Dupin323f9ff2018-08-27 16:55:56 -0700583 }
Lucas Dupin8a13aa72019-02-22 12:45:21 -0800584
585 @Override
586 public void onSensorChanged(SensorManagerPlugin.SensorEvent event) {
587 DozeLog.traceSensor(mContext, mPulseReason);
588 mHandler.post(mWakeLock.wrap(() -> {
589 final long now = SystemClock.uptimeMillis();
590 if (now < mDebounceFrom + mDebounce) {
Lucas Dupinbca7ec72019-05-30 10:24:54 -0700591 Log.d(TAG, "onSensorEvent dropped: " + triggerEventToString(event));
Lucas Dupin8a13aa72019-02-22 12:45:21 -0800592 return;
593 }
594 if (DEBUG) Log.d(TAG, "onSensorEvent: " + triggerEventToString(event));
Lucas Dupinf40bd8f2019-08-07 15:55:00 -0700595 mCallback.onSensorPulse(mPulseReason, -1, -1, event.getValues());
Lucas Dupin8a13aa72019-02-22 12:45:21 -0800596 }));
597 }
Lucas Dupin323f9ff2018-08-27 16:55:56 -0700598 }
599
Adrian Roosea8d6ae2016-10-26 10:40:12 -0700600 public interface Callback {
Adrian Roosd6ec13132016-10-27 11:50:47 -0700601
602 /**
603 * Called when a sensor requests a pulse
Lucas Dupin3d053532019-01-29 12:35:22 -0800604 * @param pulseReason Requesting sensor, e.g. {@link DozeLog#REASON_SENSOR_PICKUP}
Adrian Roos25c7a582017-06-02 12:50:38 -0700605 * @param screenX the location on the screen where the sensor fired or -1
Lucas Dupinf40bd8f2019-08-07 15:55:00 -0700606 * if the sensor doesn't support reporting screen locations.
Adrian Roos25c7a582017-06-02 12:50:38 -0700607 * @param screenY the location on the screen where the sensor fired or -1
Lucas Dupinb2d9f482018-11-16 18:55:13 -0800608 * @param rawValues raw values array from the event.
Adrian Roosd6ec13132016-10-27 11:50:47 -0700609 */
Lucas Dupinf40bd8f2019-08-07 15:55:00 -0700610 void onSensorPulse(int pulseReason, float screenX, float screenY, float[] rawValues);
Adrian Roosea8d6ae2016-10-26 10:40:12 -0700611 }
612}