• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2016 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.systemui.doze;
18 
19 import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FINGERPRINT;
20 import static android.hardware.biometrics.Flags.screenOffUnlockUdfps;
21 
22 import static com.android.systemui.doze.DozeLog.REASON_SENSOR_QUICK_PICKUP;
23 import static com.android.systemui.doze.DozeLog.REASON_SENSOR_UDFPS_LONG_PRESS;
24 import static com.android.systemui.plugins.SensorManagerPlugin.Sensor.TYPE_WAKE_DISPLAY;
25 import static com.android.systemui.plugins.SensorManagerPlugin.Sensor.TYPE_WAKE_LOCK_SCREEN;
26 
27 import android.annotation.AnyThread;
28 import android.content.res.Resources;
29 import android.database.ContentObserver;
30 import android.hardware.Sensor;
31 import android.hardware.SensorManager;
32 import android.hardware.TriggerEvent;
33 import android.hardware.TriggerEventListener;
34 import android.hardware.biometrics.BiometricAuthenticator;
35 import android.hardware.display.AmbientDisplayConfiguration;
36 import android.net.Uri;
37 import android.os.Handler;
38 import android.os.SystemClock;
39 import android.os.UserHandle;
40 import android.provider.Settings;
41 import android.text.TextUtils;
42 import android.util.IndentingPrintWriter;
43 import android.view.Display;
44 
45 import androidx.annotation.NonNull;
46 import androidx.annotation.VisibleForTesting;
47 
48 import com.android.internal.R;
49 import com.android.internal.logging.UiEvent;
50 import com.android.internal.logging.UiEventLogger;
51 import com.android.internal.logging.UiEventLoggerImpl;
52 import com.android.systemui.Flags;
53 import com.android.systemui.biometrics.AuthController;
54 import com.android.systemui.plugins.SensorManagerPlugin;
55 import com.android.systemui.statusbar.phone.DozeParameters;
56 import com.android.systemui.statusbar.policy.DevicePostureController;
57 import com.android.systemui.user.domain.interactor.SelectedUserInteractor;
58 import com.android.systemui.util.sensors.AsyncSensorManager;
59 import com.android.systemui.util.sensors.ProximitySensor;
60 import com.android.systemui.util.settings.SecureSettings;
61 import com.android.systemui.util.wakelock.WakeLock;
62 
63 import java.io.PrintWriter;
64 import java.util.Arrays;
65 import java.util.Collection;
66 import java.util.HashMap;
67 import java.util.List;
68 import java.util.Map;
69 import java.util.Objects;
70 import java.util.function.Consumer;
71 
72 /**
73  * Tracks and registers/unregisters sensors while the device is dozing based on the config
74  * provided by {@link AmbientDisplayConfiguration} and parameters provided by {@link DozeParameters}
75  *
76  * Sensors registration depends on:
77  *    - sensor existence/availability
78  *    - user configuration (some can be toggled on/off via settings)
79  *    - use of the proximity sensor (sometimes prox cannot be registered in certain display states)
80  *    - touch state
81  *    - device posture
82  *
83  * Sensors will trigger the provided Callback's {@link Callback#onSensorPulse} method.
84  * These sensors include:
85  *    - pickup gesture
86  *    - single and double tap gestures
87  *    - udfps long-press gesture
88  *    - reach and presence gestures
89  *    - quick pickup gesture (low-threshold pickup gesture)
90  *
91  * This class also registers a ProximitySensor that reports near/far events and will
92  * trigger callbacks on the provided {@link mProxCallback}.
93  */
94 public class DozeSensors {
95     private static final String TAG = "DozeSensors";
96     private static final UiEventLogger UI_EVENT_LOGGER = new UiEventLoggerImpl();
97     private static final String KEY_DOZE_PULSE_ON_AUTH = "doze_pulse_on_auth";
98 
99     private final AsyncSensorManager mSensorManager;
100     private final AmbientDisplayConfiguration mConfig;
101     private final WakeLock mWakeLock;
102     private final DozeLog mDozeLog;
103     private final SecureSettings mSecureSettings;
104     private final DevicePostureController mDevicePostureController;
105     private final AuthController mAuthController;
106     private final SelectedUserInteractor mSelectedUserInteractor;
107     private final boolean mScreenOffUdfpsEnabled;
108 
109     // Sensors
110     @VisibleForTesting
111     protected TriggerSensor[] mTriggerSensors;
112     private final ProximitySensor mProximitySensor;
113 
114     // Sensor callbacks
115     private final Callback mSensorCallback; // receives callbacks on registered sensor events
116     private final Consumer<Boolean> mProxCallback; // receives callbacks on near/far updates
117 
118     private final Handler mHandler = new Handler();
119     private long mDebounceFrom;
120     private boolean mSettingRegistered;
121     private boolean mListening;
122     private boolean mListeningTouchScreenSensors;
123     private boolean mListeningProxSensors;
124     private boolean mListeningAodOnlySensors;
125     private boolean mUdfpsEnrolled;
126 
127     @DevicePostureController.DevicePostureInt
128     private int mDevicePosture;
129 
130     // whether to only register sensors that use prox when the display state is dozing or off
131     private boolean mSelectivelyRegisterProxSensors;
132 
133     @VisibleForTesting
134     public enum DozeSensorsUiEvent implements UiEventLogger.UiEventEnum {
135         @UiEvent(doc = "User performs pickup gesture that activates the ambient display")
136         ACTION_AMBIENT_GESTURE_PICKUP(459);
137 
138         private final int mId;
139 
DozeSensorsUiEvent(int id)140         DozeSensorsUiEvent(int id) {
141             mId = id;
142         }
143 
144         @Override
getId()145         public int getId() {
146             return mId;
147         }
148     }
149 
DozeSensors( Resources resources, AsyncSensorManager sensorManager, DozeParameters dozeParameters, AmbientDisplayConfiguration config, WakeLock wakeLock, Callback sensorCallback, Consumer<Boolean> proxCallback, DozeLog dozeLog, ProximitySensor proximitySensor, SecureSettings secureSettings, AuthController authController, DevicePostureController devicePostureController, SelectedUserInteractor selectedUserInteractor )150     DozeSensors(
151             Resources resources,
152             AsyncSensorManager sensorManager,
153             DozeParameters dozeParameters,
154             AmbientDisplayConfiguration config,
155             WakeLock wakeLock,
156             Callback sensorCallback,
157             Consumer<Boolean> proxCallback,
158             DozeLog dozeLog,
159             ProximitySensor proximitySensor,
160             SecureSettings secureSettings,
161             AuthController authController,
162             DevicePostureController devicePostureController,
163             SelectedUserInteractor selectedUserInteractor
164     ) {
165         mSensorManager = sensorManager;
166         mConfig = config;
167         mWakeLock = wakeLock;
168         mProxCallback = proxCallback;
169         mSecureSettings = secureSettings;
170         mSensorCallback = sensorCallback;
171         mDozeLog = dozeLog;
172         mProximitySensor = proximitySensor;
173         mProximitySensor.setTag(TAG);
174         mSelectivelyRegisterProxSensors = dozeParameters.getSelectivelyRegisterSensorsUsingProx();
175         mListeningProxSensors = !mSelectivelyRegisterProxSensors;
176         mSelectedUserInteractor = selectedUserInteractor;
177         mScreenOffUdfpsEnabled =
178                 config.screenOffUdfpsEnabled(mSelectedUserInteractor.getSelectedUserId());
179         mDevicePostureController = devicePostureController;
180         mDevicePosture = mDevicePostureController.getDevicePosture();
181         mAuthController = authController;
182 
183         mUdfpsEnrolled =
184                 mAuthController.isUdfpsEnrolled(mSelectedUserInteractor.getSelectedUserId());
185         mAuthController.addCallback(mAuthControllerCallback);
186         mTriggerSensors = new TriggerSensor[] {
187                 new TriggerSensor(
188                         mSensorManager.getDefaultSensor(Sensor.TYPE_SIGNIFICANT_MOTION),
189                         null /* setting */,
190                         dozeParameters.getPulseOnSigMotion(),
191                         DozeLog.PULSE_REASON_SENSOR_SIGMOTION,
192                         false /* touchCoords */,
193                         false /* touchscreen */
194                 ),
195                 new TriggerSensor(
196                         mSensorManager.getDefaultSensor(Sensor.TYPE_PICK_UP_GESTURE),
197                         Settings.Secure.DOZE_PICK_UP_GESTURE,
198                         resources.getBoolean(
199                                 R.bool.config_dozePickupGestureEnabled) /* settingDef */,
200                         config.dozePickupSensorAvailable(),
201                         DozeLog.REASON_SENSOR_PICKUP, false /* touchCoords */,
202                         false /* touchscreen */,
203                         false /* ignoresSetting */,
204                         false /* requires prox */,
205                         true /* immediatelyReRegister */,
206                         false /* requiresAod */
207                 ),
208                 new TriggerSensor(
209                         findSensor(config.doubleTapSensorType()),
210                         Settings.Secure.DOZE_DOUBLE_TAP_GESTURE,
211                         true /* configured */,
212                         DozeLog.REASON_SENSOR_DOUBLE_TAP,
213                         dozeParameters.doubleTapReportsTouchCoordinates(),
214                         true /* touchscreen */
215                 ),
216                 new TriggerSensor(
217                         findSensors(config.tapSensorTypeMapping()),
218                         Settings.Secure.DOZE_TAP_SCREEN_GESTURE,
219                         true /* settingDef */,
220                         true /* configured */,
221                         DozeLog.REASON_SENSOR_TAP,
222                         true /* reports touch coordinates */,
223                         true /* touchscreen */,
224                         false /* ignoresSetting */,
225                         dozeParameters.singleTapUsesProx(mDevicePosture) /* requiresProx */,
226                         true /* immediatelyReRegister */,
227                         mDevicePosture,
228                         false
229                 ),
230                 new TriggerSensor(
231                         findSensor(config.longPressSensorType()),
232                         Settings.Secure.DOZE_PULSE_ON_LONG_PRESS,
233                         false /* settingDef */,
234                         true /* configured */,
235                         DozeLog.PULSE_REASON_SENSOR_LONG_PRESS,
236                         true /* reports touch coordinates */,
237                         true /* touchscreen */,
238                         false /* ignoresSetting */,
239                         dozeParameters.longPressUsesProx() /* requiresProx */,
240                         true /* immediatelyReRegister */,
241                         false /* requiresAod */
242                 ),
243                 new TriggerSensor(
244                         findSensor(config.udfpsLongPressSensorType()),
245                         KEY_DOZE_PULSE_ON_AUTH,
246                         true /* settingDef */,
247                         udfpsLongPressConfigured(),
248                         DozeLog.REASON_SENSOR_UDFPS_LONG_PRESS,
249                         true /* reports touch coordinates */,
250                         true /* touchscreen */,
251                         false /* ignoresSetting */,
252                         dozeParameters.longPressUsesProx(),
253                         screenOffUnlockUdfps() /* immediatelyReRegister */,
254                         !screenOffUnlockUdfps() /* requiresAod */
255                 ),
256                 new PluginSensor(
257                         new SensorManagerPlugin.Sensor(TYPE_WAKE_DISPLAY),
258                         Settings.Secure.DOZE_WAKE_DISPLAY_GESTURE,
259                         mConfig.wakeScreenGestureAvailable()
260                           && mConfig.alwaysOnEnabled(
261                                   mSelectedUserInteractor.getSelectedUserId()),
262                         DozeLog.REASON_SENSOR_WAKE_UP_PRESENCE,
263                         false /* reports touch coordinates */,
264                         false /* touchscreen */
265                 ),
266                 new PluginSensor(
267                         new SensorManagerPlugin.Sensor(TYPE_WAKE_LOCK_SCREEN),
268                         Settings.Secure.DOZE_WAKE_LOCK_SCREEN_GESTURE,
269                         mConfig.wakeScreenGestureAvailable(),
270                         DozeLog.PULSE_REASON_SENSOR_WAKE_REACH,
271                         false /* reports touch coordinates */,
272                         false /* touchscreen */,
273                         mConfig.getWakeLockScreenDebounce()
274                 ),
275                 new TriggerSensor(
276                         findSensor(config.quickPickupSensorType()),
277                         Settings.Secure.DOZE_QUICK_PICKUP_GESTURE,
278                         true /* setting default */,
279                         quickPickUpConfigured(),
280                         DozeLog.REASON_SENSOR_QUICK_PICKUP,
281                         false /* requiresTouchCoordinates */,
282                         false /* requiresTouchscreen */,
283                         false /* ignoresSetting */,
284                         false /* requiresProx */,
285                         true /* immediatelyReRegister */,
286                         false /* requiresAod */
287                 ),
288         };
289         setProxListening(false);  // Don't immediately start listening when we register.
290         mProximitySensor.register(
291                 proximityEvent -> {
292                     if (proximityEvent != null) {
293                         mProxCallback.accept(!proximityEvent.getBelow());
294                     }
295                 });
296 
297         mDevicePostureController.addCallback(mDevicePostureCallback);
298     }
299 
udfpsLongPressConfigured()300     private boolean udfpsLongPressConfigured() {
301         return mUdfpsEnrolled
302                 && (mConfig.alwaysOnEnabled(mSelectedUserInteractor.getSelectedUserId())
303                 || mScreenOffUdfpsEnabled);
304     }
305 
quickPickUpConfigured()306     private boolean quickPickUpConfigured() {
307         return mUdfpsEnrolled
308                 && mConfig.quickPickupSensorEnabled(mSelectedUserInteractor.getSelectedUserId());
309     }
310 
311     /**
312      *  Unregister all sensors and callbacks.
313      */
destroy()314     public void destroy() {
315         // Unregisters everything, which is enough to allow gc.
316         for (TriggerSensor triggerSensor : mTriggerSensors) {
317             triggerSensor.setListening(false);
318         }
319         mProximitySensor.destroy();
320 
321         mDevicePostureController.removeCallback(mDevicePostureCallback);
322         mAuthController.removeCallback(mAuthControllerCallback);
323     }
324 
325     /**
326      * Temporarily disable some sensors to avoid turning on the device while the user is
327      * turning it off.
328      */
requestTemporaryDisable()329     public void requestTemporaryDisable() {
330         mDebounceFrom = SystemClock.uptimeMillis();
331     }
332 
findSensor(String type)333     private Sensor findSensor(String type) {
334         return findSensor(mSensorManager, type, null);
335     }
336 
337     @NonNull
findSensors(@onNull String[] types)338     private Sensor[] findSensors(@NonNull String[] types) {
339         Sensor[] sensorMap = new Sensor[DevicePostureController.SUPPORTED_POSTURES_SIZE];
340 
341         // Map of sensorType => Sensor, so we reuse the same sensor if it's the same between
342         // postures
343         Map<String, Sensor> typeToSensorMap = new HashMap<>();
344         for (int i = 0; i < types.length; i++) {
345             String sensorType = types[i];
346             if (!typeToSensorMap.containsKey(sensorType)) {
347                 typeToSensorMap.put(sensorType, findSensor(sensorType));
348             }
349             sensorMap[i] = typeToSensorMap.get(sensorType);
350         }
351 
352         return sensorMap;
353     }
354 
355     /**
356      * Utility method to find a {@link Sensor} for the supplied string type and string name.
357      *
358      * Return the first sensor in the list that matches the specified inputs. Ignores type or name
359      * if the input is null or empty.
360      *
361      * @param type sensorType
362      * @parm name sensorName, to differentiate between sensors with the same type
363      */
findSensor(SensorManager sensorManager, String type, String name)364     public static Sensor findSensor(SensorManager sensorManager, String type, String name) {
365         final boolean isNameSpecified = !TextUtils.isEmpty(name);
366         final boolean isTypeSpecified = !TextUtils.isEmpty(type);
367         if (isNameSpecified || isTypeSpecified) {
368             final List<Sensor> sensors = sensorManager.getSensorList(Sensor.TYPE_ALL);
369             for (Sensor sensor : sensors) {
370                 if ((!isNameSpecified || name.equals(sensor.getName()))
371                         && (!isTypeSpecified || type.equals(sensor.getStringType()))) {
372                     return sensor;
373                 }
374             }
375         }
376         return null;
377     }
378 
379     /**
380      * If sensors should be registered and sending signals.
381      */
setListening(boolean listen, boolean includeTouchScreenSensors, boolean includeAodOnlySensors)382     public void setListening(boolean listen, boolean includeTouchScreenSensors,
383             boolean includeAodOnlySensors) {
384         if (mListening == listen && mListeningTouchScreenSensors == includeTouchScreenSensors
385                 && mListeningAodOnlySensors == includeAodOnlySensors) {
386             return;
387         }
388         mListening = listen;
389         mListeningTouchScreenSensors = includeTouchScreenSensors;
390         mListeningAodOnlySensors = includeAodOnlySensors;
391         updateListening();
392     }
393 
394     /**
395      * If sensors should be registered and sending signals.
396      */
setListeningWithPowerState(boolean listen, boolean includeTouchScreenSensors, boolean includeAodRequiringSensors, boolean lowPowerStateOrOff)397     public void setListeningWithPowerState(boolean listen, boolean includeTouchScreenSensors,
398             boolean includeAodRequiringSensors, boolean lowPowerStateOrOff) {
399         final boolean shouldRegisterProxSensors =
400                 !mSelectivelyRegisterProxSensors || lowPowerStateOrOff;
401         if (mListening == listen
402                 && mListeningTouchScreenSensors == includeTouchScreenSensors
403                 && mListeningProxSensors == shouldRegisterProxSensors
404                 && mListeningAodOnlySensors == includeAodRequiringSensors
405         ) {
406             return;
407         }
408         mListening = listen;
409         mListeningTouchScreenSensors = includeTouchScreenSensors;
410         mListeningProxSensors = shouldRegisterProxSensors;
411         mListeningAodOnlySensors = includeAodRequiringSensors;
412         updateListening();
413     }
414 
415     /**
416      * Registers/unregisters sensors based on internal state.
417      */
updateListening()418     private void updateListening() {
419         boolean anyListening = false;
420         for (TriggerSensor s : mTriggerSensors) {
421             boolean listen = mListening
422                     && (!s.mRequiresTouchscreen || mListeningTouchScreenSensors)
423                     && (!s.mRequiresProx || mListeningProxSensors)
424                     && (!s.mRequiresAod || mListeningAodOnlySensors);
425 
426             //AOD might be turned off in visual because of BetterySaver or isAlwaysOnSuppressed(),
427             //but AOD isn't really turned off, in these cases, udfpsLongPressSensor should be
428             //unregistered.
429             if (!mListeningAodOnlySensors && KEY_DOZE_PULSE_ON_AUTH.equals(s.mSetting)) {
430                 if (mConfig.alwaysOnEnabled(mSelectedUserInteractor.getSelectedUserId())
431                         && !mConfig.screenOffUdfpsEnabled(
432                         mSelectedUserInteractor.getSelectedUserId())) {
433                     listen = false;
434                 }
435             }
436 
437             s.setListening(listen);
438             if (listen) {
439                 anyListening = true;
440             }
441         }
442 
443         if (!anyListening) {
444             if (Flags.registerContentObserversAsync()) {
445                 mSecureSettings.unregisterContentObserverAsync(mSettingsObserver);
446             } else {
447                 mSecureSettings.unregisterContentObserverSync(mSettingsObserver);
448             }
449         } else if (!mSettingRegistered) {
450             for (TriggerSensor s : mTriggerSensors) {
451                 s.registerSettingsObserver(mSettingsObserver);
452             }
453         }
454         mSettingRegistered = anyListening;
455     }
456 
457     /** Set the listening state of only the sensors that require the touchscreen. */
setTouchscreenSensorsListening(boolean listening)458     public void setTouchscreenSensorsListening(boolean listening) {
459         for (TriggerSensor sensor : mTriggerSensors) {
460             if (sensor.mRequiresTouchscreen) {
461                 sensor.setListening(listening);
462             }
463         }
464     }
465 
onUserSwitched()466     public void onUserSwitched() {
467         for (TriggerSensor s : mTriggerSensors) {
468             s.updateListening();
469         }
470     }
471 
onScreenState(int state)472     void onScreenState(int state) {
473         mProximitySensor.setSecondarySafe(
474                 state == Display.STATE_DOZE
475                 || state == Display.STATE_DOZE_SUSPEND
476                 || state == Display.STATE_OFF);
477     }
478 
setProxListening(boolean listen)479     public void setProxListening(boolean listen) {
480         if (mProximitySensor.isRegistered() && listen) {
481             mProximitySensor.alertListeners();
482         } else {
483             if (listen) {
484                 mProximitySensor.resume();
485             } else {
486                 mProximitySensor.pause();
487             }
488         }
489     }
490 
491     private final ContentObserver mSettingsObserver = new ContentObserver(mHandler) {
492         @Override
493         public void onChange(boolean selfChange, Collection<Uri> uris, int flags, int userId) {
494             if (userId != mSelectedUserInteractor.getSelectedUserId()) {
495                 return;
496             }
497             for (TriggerSensor s : mTriggerSensors) {
498                 s.updateListening();
499             }
500         }
501     };
502 
503     /** Ignore the setting value of only the sensors that require the touchscreen. */
ignoreTouchScreenSensorsSettingInterferingWithDocking(boolean ignore)504     public void ignoreTouchScreenSensorsSettingInterferingWithDocking(boolean ignore) {
505         for (TriggerSensor sensor : mTriggerSensors) {
506             if (sensor.mRequiresTouchscreen) {
507                 sensor.ignoreSetting(ignore);
508             }
509         }
510     }
511 
512     /** Dump current state */
dump(PrintWriter pw)513     public void dump(PrintWriter pw) {
514         pw.println("mListening=" + mListening);
515         pw.println("mDevicePosture="
516                 + DevicePostureController.devicePostureToString(mDevicePosture));
517         pw.println("mListeningTouchScreenSensors=" + mListeningTouchScreenSensors);
518         pw.println("mSelectivelyRegisterProxSensors=" + mSelectivelyRegisterProxSensors);
519         pw.println("mListeningProxSensors=" + mListeningProxSensors);
520         pw.println("mScreenOffUdfpsEnabled=" + mScreenOffUdfpsEnabled);
521         pw.println("mUdfpsEnrolled=" + mUdfpsEnrolled);
522         IndentingPrintWriter idpw = new IndentingPrintWriter(pw);
523         idpw.increaseIndent();
524         for (TriggerSensor s : mTriggerSensors) {
525             idpw.println("Sensor: " + s.toString());
526         }
527         idpw.println("ProxSensor: " + mProximitySensor.toString());
528     }
529 
530     /**
531      * @return true if prox is currently near, false if far or null if unknown.
532      */
isProximityCurrentlyNear()533     public Boolean isProximityCurrentlyNear() {
534         return mProximitySensor.isNear();
535     }
536 
537     @VisibleForTesting
538     class TriggerSensor extends TriggerEventListener {
539         @NonNull final Sensor[] mSensors; // index = posture, value = sensor
540         boolean mConfigured;
541         final int mPulseReason;
542         private final String mSetting;
543         private final boolean mReportsTouchCoordinates;
544         private final boolean mSettingDefault;
545         private final boolean mRequiresTouchscreen;
546         private final boolean mRequiresProx;
547 
548         // Whether the sensor should only register if the device is in AOD
549         private final boolean mRequiresAod;
550 
551         // Whether to immediately re-register this sensor after the sensor is triggered.
552         // If false, the sensor registration will be updated on the next AOD state transition.
553         private final boolean mImmediatelyReRegister;
554 
555         protected boolean mRequested;
556         protected boolean mRegistered;
557         protected boolean mDisabled;
558         protected boolean mIgnoresSetting;
559         private @DevicePostureController.DevicePostureInt int mPosture;
560 
TriggerSensor( Sensor sensor, String setting, boolean configured, int pulseReason, boolean reportsTouchCoordinates, boolean requiresTouchscreen )561         TriggerSensor(
562                 Sensor sensor,
563                 String setting,
564                 boolean configured,
565                 int pulseReason,
566                 boolean reportsTouchCoordinates,
567                 boolean requiresTouchscreen
568         ) {
569             this(
570                     sensor,
571                     setting,
572                     true /* settingDef */,
573                     configured,
574                     pulseReason,
575                     reportsTouchCoordinates,
576                     requiresTouchscreen,
577                     false /* ignoresSetting */,
578                     false /* requiresProx */,
579                     true /* immediatelyReRegister */,
580                     false
581             );
582         }
583 
TriggerSensor( Sensor sensor, String setting, boolean settingDef, boolean configured, int pulseReason, boolean reportsTouchCoordinates, boolean requiresTouchscreen, boolean ignoresSetting, boolean requiresProx, boolean immediatelyReRegister, boolean requiresAod )584         TriggerSensor(
585                 Sensor sensor,
586                 String setting,
587                 boolean settingDef,
588                 boolean configured,
589                 int pulseReason,
590                 boolean reportsTouchCoordinates,
591                 boolean requiresTouchscreen,
592                 boolean ignoresSetting,
593                 boolean requiresProx,
594                 boolean immediatelyReRegister,
595                 boolean requiresAod
596         ) {
597             this(
598                     new Sensor[]{ sensor },
599                     setting,
600                     settingDef,
601                     configured,
602                     pulseReason,
603                     reportsTouchCoordinates,
604                     requiresTouchscreen,
605                     ignoresSetting,
606                     requiresProx,
607                     immediatelyReRegister,
608                     DevicePostureController.DEVICE_POSTURE_UNKNOWN,
609                     requiresAod
610             );
611         }
612 
TriggerSensor( @onNull Sensor[] sensors, String setting, boolean settingDef, boolean configured, int pulseReason, boolean reportsTouchCoordinates, boolean requiresTouchscreen, boolean ignoresSetting, boolean requiresProx, boolean immediatelyReRegister, @DevicePostureController.DevicePostureInt int posture, boolean requiresAod )613         TriggerSensor(
614                 @NonNull Sensor[] sensors,
615                 String setting,
616                 boolean settingDef,
617                 boolean configured,
618                 int pulseReason,
619                 boolean reportsTouchCoordinates,
620                 boolean requiresTouchscreen,
621                 boolean ignoresSetting,
622                 boolean requiresProx,
623                 boolean immediatelyReRegister,
624                 @DevicePostureController.DevicePostureInt int posture,
625                 boolean requiresAod
626         ) {
627             mSensors = sensors;
628             mSetting = setting;
629             mSettingDefault = settingDef;
630             mConfigured = configured;
631             mPulseReason = pulseReason;
632             mReportsTouchCoordinates = reportsTouchCoordinates;
633             mRequiresTouchscreen = requiresTouchscreen;
634             mIgnoresSetting = ignoresSetting;
635             mRequiresProx = requiresProx;
636             mRequiresAod = requiresAod;
637             mPosture = posture;
638             mImmediatelyReRegister = immediatelyReRegister;
639         }
640 
641         /**
642          * @return true if the sensor changed based for the new posture
643          */
setPosture(@evicePostureController.DevicePostureInt int posture)644         public boolean setPosture(@DevicePostureController.DevicePostureInt int posture) {
645             if (mPosture == posture
646                     || mSensors.length < 2
647                     || posture >= mSensors.length) {
648                 return false;
649             }
650 
651             Sensor oldSensor = mSensors[mPosture];
652             Sensor newSensor = mSensors[posture];
653             if (Objects.equals(oldSensor, newSensor)) {
654                 mPosture = posture;
655                 // uses the same sensor for the new posture
656                 return false;
657             }
658 
659             // cancel the previous sensor:
660             if (mRegistered) {
661                 final boolean rt = mSensorManager.cancelTriggerSensor(this, oldSensor);
662                 mDozeLog.traceSensorUnregisterAttempt(oldSensor.toString(), rt, "posture changed");
663                 mRegistered = false;
664             }
665 
666             // update the new sensor:
667             mPosture = posture;
668             updateListening();
669             mDozeLog.tracePostureChanged(mPosture, "DozeSensors swap "
670                     + "{" + oldSensor + "} => {" + newSensor + "}, mRegistered=" + mRegistered);
671             return true;
672         }
673 
setListening(boolean listen)674         public void setListening(boolean listen) {
675             if (mRequested == listen) return;
676             mRequested = listen;
677             updateListening();
678         }
679 
setDisabled(boolean disabled)680         public void setDisabled(boolean disabled) {
681             if (mDisabled == disabled) return;
682             mDisabled = disabled;
683             updateListening();
684         }
685 
ignoreSetting(boolean ignored)686         public void ignoreSetting(boolean ignored) {
687             if (mIgnoresSetting == ignored) return;
688             mIgnoresSetting = ignored;
689             updateListening();
690         }
691 
692         /**
693          * Update configured state.
694          */
setConfigured(boolean configured)695         public void setConfigured(boolean configured) {
696             if (mConfigured == configured) return;
697             mConfigured = configured;
698             updateListening();
699         }
700 
updateListening()701         public void updateListening() {
702             final Sensor sensor = mSensors[mPosture];
703 
704             if (!mConfigured || sensor == null) return;
705             if (mRequested && !mDisabled && (enabledBySetting() || mIgnoresSetting)) {
706                 if (!mRegistered) {
707                     mRegistered = mSensorManager.requestTriggerSensor(this, sensor);
708                     mDozeLog.traceSensorRegisterAttempt(sensor.toString(), mRegistered);
709                 } else {
710                     mDozeLog.traceSkipRegisterSensor(sensor.toString());
711                 }
712             } else if (mRegistered) {
713                 final boolean rt = mSensorManager.cancelTriggerSensor(this, sensor);
714                 mDozeLog.traceSensorUnregisterAttempt(sensor.toString(), rt);
715                 mRegistered = false;
716             }
717         }
718 
enabledBySetting()719         protected boolean enabledBySetting() {
720             if (!mConfig.enabled(mSelectedUserInteractor.getSelectedUserId())) {
721                 return false;
722             } else if (TextUtils.isEmpty(mSetting)) {
723                 return true;
724             }
725             return mSecureSettings.getIntForUser(mSetting, mSettingDefault ? 1 : 0,
726                     mSelectedUserInteractor.getSelectedUserId()) != 0;
727         }
728 
729         @Override
toString()730         public String toString() {
731             StringBuilder sb = new StringBuilder();
732             sb.append("{")
733                     .append("mRegistered=").append(mRegistered)
734                     .append(", mRequested=").append(mRequested)
735                     .append(", mDisabled=").append(mDisabled)
736                     .append(", mConfigured=").append(mConfigured)
737                     .append(", mIgnoresSetting=").append(mIgnoresSetting)
738                     .append(", mSensors=").append(Arrays.toString(mSensors));
739             if (mSensors.length > 2) {
740                 sb.append(", mPosture=")
741                         .append(DevicePostureController.devicePostureToString(mDevicePosture));
742             }
743             return sb.append("}").toString();
744         }
745 
746         @Override
747         @AnyThread
onTrigger(TriggerEvent event)748         public void onTrigger(TriggerEvent event) {
749             final Sensor sensor = mSensors[mPosture];
750             mDozeLog.traceSensor(mPulseReason);
751             mHandler.post(mWakeLock.wrap(() -> {
752                 if (sensor != null && sensor.getType() == Sensor.TYPE_PICK_UP_GESTURE) {
753                     UI_EVENT_LOGGER.log(DozeSensorsUiEvent.ACTION_AMBIENT_GESTURE_PICKUP);
754                 }
755 
756                 mRegistered = false;
757                 float screenX = -1;
758                 float screenY = -1;
759                 if (mReportsTouchCoordinates && event.values.length >= 2) {
760                     screenX = event.values[0];
761                     screenY = event.values[1];
762                 }
763                 mSensorCallback.onSensorPulse(mPulseReason, screenX, screenY, event.values);
764                 if (!mRegistered && mImmediatelyReRegister) {
765                     updateListening();
766                 }
767             }));
768         }
769 
registerSettingsObserver(ContentObserver settingsObserver)770         public void registerSettingsObserver(ContentObserver settingsObserver) {
771             if (mConfigured && !TextUtils.isEmpty(mSetting)) {
772                 if (Flags.registerContentObserversAsync()) {
773                     mSecureSettings.registerContentObserverForUserAsync(
774                             mSetting, mSettingsObserver, UserHandle.USER_ALL);
775                 } else {
776                     mSecureSettings.registerContentObserverForUserSync(
777                             mSetting, mSettingsObserver, UserHandle.USER_ALL);
778                 }
779             }
780         }
781 
triggerEventToString(TriggerEvent event)782         protected String triggerEventToString(TriggerEvent event) {
783             if (event == null) return null;
784             final StringBuilder sb = new StringBuilder("SensorEvent[")
785                     .append(event.timestamp).append(',')
786                     .append(event.sensor.getName());
787             if (event.values != null) {
788                 for (int i = 0; i < event.values.length; i++) {
789                     sb.append(',').append(event.values[i]);
790                 }
791             }
792             return sb.append(']').toString();
793         }
794     }
795 
796     /**
797      * A Sensor that is injected via plugin.
798      */
799     @VisibleForTesting
800     class PluginSensor extends TriggerSensor implements SensorManagerPlugin.SensorEventListener {
801 
802         final SensorManagerPlugin.Sensor mPluginSensor;
803         private long mDebounce;
804 
PluginSensor(SensorManagerPlugin.Sensor sensor, String setting, boolean configured, int pulseReason, boolean reportsTouchCoordinates, boolean requiresTouchscreen)805         PluginSensor(SensorManagerPlugin.Sensor sensor, String setting, boolean configured,
806                 int pulseReason, boolean reportsTouchCoordinates, boolean requiresTouchscreen) {
807             this(sensor, setting, configured, pulseReason, reportsTouchCoordinates,
808                     requiresTouchscreen, 0L /* debounce */);
809         }
810 
PluginSensor(SensorManagerPlugin.Sensor sensor, String setting, boolean configured, int pulseReason, boolean reportsTouchCoordinates, boolean requiresTouchscreen, long debounce)811         PluginSensor(SensorManagerPlugin.Sensor sensor, String setting, boolean configured,
812                 int pulseReason, boolean reportsTouchCoordinates, boolean requiresTouchscreen,
813                 long debounce) {
814             super(null, setting, configured, pulseReason, reportsTouchCoordinates,
815                     requiresTouchscreen);
816             mPluginSensor = sensor;
817             mDebounce = debounce;
818         }
819 
820         @Override
updateListening()821         public void updateListening() {
822             if (!mConfigured) return;
823             AsyncSensorManager asyncSensorManager = (AsyncSensorManager) mSensorManager;
824             if (mRequested && !mDisabled && (enabledBySetting() || mIgnoresSetting)
825                     && !mRegistered) {
826                 asyncSensorManager.registerPluginListener(mPluginSensor, this);
827                 mRegistered = true;
828                 mDozeLog.tracePluginSensorUpdate(true /* registered */);
829             } else if (mRegistered) {
830                 asyncSensorManager.unregisterPluginListener(mPluginSensor, this);
831                 mRegistered = false;
832                 mDozeLog.tracePluginSensorUpdate(false /* registered */);
833             }
834         }
835 
836         @Override
toString()837         public String toString() {
838             return new StringBuilder("{mRegistered=").append(mRegistered)
839                     .append(", mRequested=").append(mRequested)
840                     .append(", mDisabled=").append(mDisabled)
841                     .append(", mConfigured=").append(mConfigured)
842                     .append(", mIgnoresSetting=").append(mIgnoresSetting)
843                     .append(", mSensor=").append(mPluginSensor).append("}").toString();
844         }
845 
triggerEventToString(SensorManagerPlugin.SensorEvent event)846         private String triggerEventToString(SensorManagerPlugin.SensorEvent event) {
847             if (event == null) return null;
848             final StringBuilder sb = new StringBuilder("PluginTriggerEvent[")
849                     .append(event.getSensor()).append(',')
850                     .append(event.getVendorType());
851             if (event.getValues() != null) {
852                 for (int i = 0; i < event.getValues().length; i++) {
853                     sb.append(',').append(event.getValues()[i]);
854                 }
855             }
856             return sb.append(']').toString();
857         }
858 
859         @Override
onSensorChanged(SensorManagerPlugin.SensorEvent event)860         public void onSensorChanged(SensorManagerPlugin.SensorEvent event) {
861             mDozeLog.traceSensor(mPulseReason);
862             mHandler.post(mWakeLock.wrap(() -> {
863                 final long now = SystemClock.uptimeMillis();
864                 if (now < mDebounceFrom + mDebounce) {
865                     mDozeLog.traceSensorEventDropped(mPulseReason, "debounce");
866                     return;
867                 }
868                 mSensorCallback.onSensorPulse(mPulseReason, -1, -1, event.getValues());
869             }));
870         }
871     }
872 
873     private final DevicePostureController.Callback mDevicePostureCallback = posture -> {
874         if (mDevicePosture == posture) {
875             return;
876         }
877         mDevicePosture = posture;
878 
879         for (TriggerSensor triggerSensor : mTriggerSensors) {
880             triggerSensor.setPosture(mDevicePosture);
881         }
882     };
883 
884     private final AuthController.Callback mAuthControllerCallback = new AuthController.Callback() {
885         @Override
886         public void onAllAuthenticatorsRegistered(@BiometricAuthenticator.Modality int modality) {
887             if (modality == TYPE_FINGERPRINT) {
888                 updateUdfpsEnrolled();
889             }
890         }
891 
892         @Override
893         public void onEnrollmentsChanged(@BiometricAuthenticator.Modality int modality) {
894             if (modality == TYPE_FINGERPRINT) {
895                 updateUdfpsEnrolled();
896             }
897         }
898 
899         private void updateUdfpsEnrolled() {
900             mUdfpsEnrolled = mAuthController.isUdfpsEnrolled(
901                     mSelectedUserInteractor.getSelectedUserId());
902             for (TriggerSensor sensor : mTriggerSensors) {
903                 if (REASON_SENSOR_QUICK_PICKUP == sensor.mPulseReason) {
904                     sensor.setConfigured(quickPickUpConfigured());
905                 } else if (REASON_SENSOR_UDFPS_LONG_PRESS == sensor.mPulseReason) {
906                     sensor.setConfigured(udfpsLongPressConfigured());
907                 }
908             }
909         }
910     };
911 
912     public interface Callback {
913 
914         /**
915          * Called when a sensor requests a pulse
916          * @param pulseReason Requesting sensor, e.g. {@link DozeLog#REASON_SENSOR_PICKUP}
917          * @param screenX the location on the screen where the sensor fired or -1
918          *                if the sensor doesn't support reporting screen locations.
919          * @param screenY the location on the screen where the sensor fired or -1
920          * @param rawValues raw values array from the event.
921          */
onSensorPulse(int pulseReason, float screenX, float screenY, float[] rawValues)922         void onSensorPulse(int pulseReason, float screenX, float screenY, float[] rawValues);
923     }
924 }
925