1 /*
2  * Copyright (C) 2020 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.classifier;
18 
19 import static com.android.systemui.dock.DockManager.DockEventListener;
20 
21 import android.hardware.SensorManager;
22 import android.hardware.biometrics.BiometricSourceType;
23 import android.util.Log;
24 import android.view.MotionEvent;
25 
26 import androidx.annotation.VisibleForTesting;
27 
28 import com.android.keyguard.KeyguardUpdateMonitor;
29 import com.android.keyguard.KeyguardUpdateMonitorCallback;
30 import com.android.systemui.dagger.SysUISingleton;
31 import com.android.systemui.dagger.qualifiers.Main;
32 import com.android.systemui.dock.DockManager;
33 import com.android.systemui.plugins.FalsingManager;
34 import com.android.systemui.plugins.statusbar.StatusBarStateController;
35 import com.android.systemui.shade.ShadeExpansionStateManager;
36 import com.android.systemui.statusbar.StatusBarState;
37 import com.android.systemui.statusbar.policy.BatteryController;
38 import com.android.systemui.statusbar.policy.BatteryController.BatteryStateChangeCallback;
39 import com.android.systemui.statusbar.policy.KeyguardStateController;
40 import com.android.systemui.util.concurrency.DelayableExecutor;
41 import com.android.systemui.util.sensors.ProximitySensor;
42 import com.android.systemui.util.sensors.ThresholdSensor;
43 import com.android.systemui.util.sensors.ThresholdSensorEvent;
44 import com.android.systemui.util.time.SystemClock;
45 
46 import java.util.Collections;
47 
48 import javax.inject.Inject;
49 
50 @SysUISingleton
51 class FalsingCollectorImpl implements FalsingCollector {
52 
53     private static final String TAG = "FalsingCollector";
54     private static final String PROXIMITY_SENSOR_TAG = "FalsingCollector";
55     private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
56     private static final long GESTURE_PROCESSING_DELAY_MS = 100;
57 
58     private final FalsingDataProvider mFalsingDataProvider;
59     private final FalsingManager mFalsingManager;
60     private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
61     private final HistoryTracker mHistoryTracker;
62     private final ProximitySensor mProximitySensor;
63     private final StatusBarStateController mStatusBarStateController;
64     private final KeyguardStateController mKeyguardStateController;
65     private final BatteryController mBatteryController;
66     private final DockManager mDockManager;
67     private final DelayableExecutor mMainExecutor;
68     private final SystemClock mSystemClock;
69 
70     private int mState;
71     private boolean mShowingAod;
72     private boolean mScreenOn;
73     private boolean mSessionStarted;
74     private MotionEvent mPendingDownEvent;
75     private boolean mAvoidGesture;
76 
77     private final ThresholdSensor.Listener mSensorEventListener = this::onProximityEvent;
78 
79     private final StatusBarStateController.StateListener mStatusBarStateListener =
80             new StatusBarStateController.StateListener() {
81                 @Override
82                 public void onStateChanged(int newState) {
83                     logDebug("StatusBarState=" + StatusBarState.toString(newState));
84                     mState = newState;
85                     updateSessionActive();
86                 }
87             };
88 
89 
90     private final KeyguardUpdateMonitorCallback mKeyguardUpdateCallback =
91             new KeyguardUpdateMonitorCallback() {
92                 @Override
93                 public void onBiometricAuthenticated(int userId,
94                         BiometricSourceType biometricSourceType,
95                         boolean isStrongBiometric) {
96                     if (userId == KeyguardUpdateMonitor.getCurrentUser()
97                             && biometricSourceType == BiometricSourceType.FACE) {
98                         mFalsingDataProvider.setJustUnlockedWithFace(true);
99                     }
100                 }
101             };
102 
103 
104     private final BatteryStateChangeCallback mBatteryListener = new BatteryStateChangeCallback() {
105         @Override
106         public void onBatteryLevelChanged(int level, boolean pluggedIn, boolean charging) {
107         }
108 
109         @Override
110         public void onWirelessChargingChanged(boolean isWirelessCharging) {
111             if (isWirelessCharging || mDockManager.isDocked()) {
112                 mProximitySensor.pause();
113             } else {
114                 mProximitySensor.resume();
115             }
116         }
117     };
118 
119     private final DockEventListener mDockEventListener = new DockEventListener() {
120         @Override
121         public void onEvent(int event) {
122             if (event == DockManager.STATE_NONE && !mBatteryController.isWirelessCharging()) {
123                 mProximitySensor.resume();
124             } else {
125                 mProximitySensor.pause();
126             }
127         }
128     };
129 
130     @Inject
FalsingCollectorImpl( FalsingDataProvider falsingDataProvider, FalsingManager falsingManager, KeyguardUpdateMonitor keyguardUpdateMonitor, HistoryTracker historyTracker, ProximitySensor proximitySensor, StatusBarStateController statusBarStateController, KeyguardStateController keyguardStateController, ShadeExpansionStateManager shadeExpansionStateManager, BatteryController batteryController, DockManager dockManager, @Main DelayableExecutor mainExecutor, SystemClock systemClock)131     FalsingCollectorImpl(
132             FalsingDataProvider falsingDataProvider,
133             FalsingManager falsingManager,
134             KeyguardUpdateMonitor keyguardUpdateMonitor,
135             HistoryTracker historyTracker,
136             ProximitySensor proximitySensor,
137             StatusBarStateController statusBarStateController,
138             KeyguardStateController keyguardStateController,
139             ShadeExpansionStateManager shadeExpansionStateManager,
140             BatteryController batteryController,
141             DockManager dockManager,
142             @Main DelayableExecutor mainExecutor,
143             SystemClock systemClock) {
144         mFalsingDataProvider = falsingDataProvider;
145         mFalsingManager = falsingManager;
146         mKeyguardUpdateMonitor = keyguardUpdateMonitor;
147         mHistoryTracker = historyTracker;
148         mProximitySensor = proximitySensor;
149         mStatusBarStateController = statusBarStateController;
150         mKeyguardStateController = keyguardStateController;
151         mBatteryController = batteryController;
152         mDockManager = dockManager;
153         mMainExecutor = mainExecutor;
154         mSystemClock = systemClock;
155 
156         mProximitySensor.setTag(PROXIMITY_SENSOR_TAG);
157         mProximitySensor.setDelay(SensorManager.SENSOR_DELAY_GAME);
158 
159         mStatusBarStateController.addCallback(mStatusBarStateListener);
160         mState = mStatusBarStateController.getState();
161 
162         mKeyguardUpdateMonitor.registerCallback(mKeyguardUpdateCallback);
163 
164         shadeExpansionStateManager.addQsExpansionListener(this::onQsExpansionChanged);
165 
166         mBatteryController.addCallback(mBatteryListener);
167         mDockManager.addListener(mDockEventListener);
168     }
169 
170     @Override
onSuccessfulUnlock()171     public void onSuccessfulUnlock() {
172         mFalsingManager.onSuccessfulUnlock();
173         sessionEnd();
174     }
175 
176     @Override
setShowingAod(boolean showingAod)177     public void setShowingAod(boolean showingAod) {
178         mShowingAod = showingAod;
179         updateSessionActive();
180     }
181 
182     @Override
onNotificationStartDraggingDown()183     public void onNotificationStartDraggingDown() {
184     }
185 
186     @Override
onNotificationStopDraggingDown()187     public void onNotificationStopDraggingDown() {
188     }
189 
190     @Override
setNotificationExpanded()191     public void setNotificationExpanded() {
192     }
193 
194     @Override
onQsDown()195     public void onQsDown() {
196     }
197 
198     @VisibleForTesting
onQsExpansionChanged(Boolean expanded)199     void onQsExpansionChanged(Boolean expanded) {
200         if (expanded) {
201             unregisterSensors();
202         } else if (mSessionStarted) {
203             registerSensors();
204         }
205     }
206 
207     @Override
shouldEnforceBouncer()208     public boolean shouldEnforceBouncer() {
209         return false;
210     }
211 
212     @Override
onTrackingStarted(boolean secure)213     public void onTrackingStarted(boolean secure) {
214     }
215 
216     @Override
onTrackingStopped()217     public void onTrackingStopped() {
218     }
219 
220     @Override
onLeftAffordanceOn()221     public void onLeftAffordanceOn() {
222     }
223 
224     @Override
onCameraOn()225     public void onCameraOn() {
226     }
227 
228     @Override
onAffordanceSwipingStarted(boolean rightCorner)229     public void onAffordanceSwipingStarted(boolean rightCorner) {
230     }
231 
232     @Override
onAffordanceSwipingAborted()233     public void onAffordanceSwipingAborted() {
234     }
235 
236     @Override
onStartExpandingFromPulse()237     public void onStartExpandingFromPulse() {
238     }
239 
240     @Override
onExpansionFromPulseStopped()241     public void onExpansionFromPulseStopped() {
242     }
243 
244     @Override
onScreenOnFromTouch()245     public void onScreenOnFromTouch() {
246         onScreenTurningOn();
247     }
248 
249     @Override
isReportingEnabled()250     public boolean isReportingEnabled() {
251         return false;
252     }
253 
254     @Override
onUnlockHintStarted()255     public void onUnlockHintStarted() {
256     }
257 
258     @Override
onCameraHintStarted()259     public void onCameraHintStarted() {
260     }
261 
262     @Override
onLeftAffordanceHintStarted()263     public void onLeftAffordanceHintStarted() {
264     }
265 
266     @Override
onScreenTurningOn()267     public void onScreenTurningOn() {
268         mScreenOn = true;
269         updateSessionActive();
270     }
271 
272     @Override
onScreenOff()273     public void onScreenOff() {
274         mScreenOn = false;
275         updateSessionActive();
276     }
277 
278     @Override
onNotificationStopDismissing()279     public void onNotificationStopDismissing() {
280     }
281 
282     @Override
onNotificationDismissed()283     public void onNotificationDismissed() {
284     }
285 
286     @Override
onNotificationStartDismissing()287     public void onNotificationStartDismissing() {
288     }
289 
290     @Override
onNotificationDoubleTap(boolean accepted, float dx, float dy)291     public void onNotificationDoubleTap(boolean accepted, float dx, float dy) {
292     }
293 
294     @Override
onBouncerShown()295     public void onBouncerShown() {
296         unregisterSensors();
297     }
298 
299     @Override
onBouncerHidden()300     public void onBouncerHidden() {
301         if (mSessionStarted) {
302             registerSensors();
303         }
304     }
305 
306     @Override
onTouchEvent(MotionEvent ev)307     public void onTouchEvent(MotionEvent ev) {
308         if (!mKeyguardStateController.isShowing()) {
309             avoidGesture();
310             return;
311         }
312         if (ev.getActionMasked() == MotionEvent.ACTION_OUTSIDE) {
313             return;
314         }
315 
316         // We delay processing down events to see if another component wants to process them.
317         // If #avoidGesture is called after a MotionEvent.ACTION_DOWN, all following motion events
318         // will be ignored by the collector until another MotionEvent.ACTION_DOWN is passed in.
319         // avoidGesture must be called immediately following the MotionEvent.ACTION_DOWN, before
320         // any other events are processed, otherwise the whole gesture will be recorded.
321         if (ev.getActionMasked() == MotionEvent.ACTION_DOWN) {
322             // Make a copy of ev, since it will be recycled after we exit this method.
323             mPendingDownEvent = MotionEvent.obtain(ev);
324             mAvoidGesture = false;
325         } else if (!mAvoidGesture) {
326             if (mPendingDownEvent != null) {
327                 mFalsingDataProvider.onMotionEvent(mPendingDownEvent);
328                 mPendingDownEvent.recycle();
329                 mPendingDownEvent = null;
330             }
331             mFalsingDataProvider.onMotionEvent(ev);
332         }
333     }
334 
335     @Override
onMotionEventComplete()336     public void onMotionEventComplete() {
337         // We must delay processing the completion because of the way Android handles click events.
338         // It generally delays executing them immediately, instead choosing to give the UI a chance
339         // to respond to touch events before acknowledging the click. As such, we must also delay,
340         // giving click handlers a chance to analyze it.
341         // You might think we could do something clever to remove this delay - adding non-committed
342         // results that can later be changed - but this won't help. Calling the code
343         // below can eventually end up in a "Falsing Event" being fired. If we remove the delay
344         // here, we would still have to add the delay to the event, but we'd also have to make all
345         // the intervening code more complicated in the process. This is the simplest insertion
346         // point for the delay.
347         mMainExecutor.executeDelayed(
348                 mFalsingDataProvider::onMotionEventComplete, GESTURE_PROCESSING_DELAY_MS);
349     }
350 
351     @Override
avoidGesture()352     public void avoidGesture() {
353         mAvoidGesture = true;
354         if (mPendingDownEvent != null) {
355             mPendingDownEvent.recycle();
356             mPendingDownEvent = null;
357         }
358     }
359 
360     @Override
cleanup()361     public void cleanup() {
362         unregisterSensors();
363         mKeyguardUpdateMonitor.removeCallback(mKeyguardUpdateCallback);
364         mStatusBarStateController.removeCallback(mStatusBarStateListener);
365         mBatteryController.removeCallback(mBatteryListener);
366         mDockManager.removeListener(mDockEventListener);
367     }
368 
369     @Override
updateFalseConfidence(FalsingClassifier.Result result)370     public void updateFalseConfidence(FalsingClassifier.Result result) {
371         mHistoryTracker.addResults(Collections.singleton(result), mSystemClock.uptimeMillis());
372     }
373 
374     @Override
onA11yAction()375     public void onA11yAction() {
376         if (mPendingDownEvent != null) {
377             mPendingDownEvent.recycle();
378             mPendingDownEvent = null;
379         }
380         mFalsingDataProvider.onA11yAction();
381     }
382 
shouldSessionBeActive()383     private boolean shouldSessionBeActive() {
384         return mScreenOn && (mState == StatusBarState.KEYGUARD) && !mShowingAod;
385     }
386 
updateSessionActive()387     private void updateSessionActive() {
388         if (shouldSessionBeActive()) {
389             sessionStart();
390         } else {
391             sessionEnd();
392         }
393     }
394 
sessionStart()395     private void sessionStart() {
396         if (!mSessionStarted && shouldSessionBeActive()) {
397             logDebug("Starting Session");
398             mSessionStarted = true;
399             mFalsingDataProvider.setJustUnlockedWithFace(false);
400             registerSensors();
401             mFalsingDataProvider.onSessionStarted();
402         }
403     }
404 
sessionEnd()405     private void sessionEnd() {
406         if (mSessionStarted) {
407             logDebug("Ending Session");
408             mSessionStarted = false;
409             unregisterSensors();
410             mFalsingDataProvider.onSessionEnd();
411         }
412     }
413 
registerSensors()414     private void registerSensors() {
415         mProximitySensor.register(mSensorEventListener);
416     }
417 
unregisterSensors()418     private void unregisterSensors() {
419         mProximitySensor.unregister(mSensorEventListener);
420     }
421 
onProximityEvent(ThresholdSensorEvent proximityEvent)422     private void onProximityEvent(ThresholdSensorEvent proximityEvent) {
423         // TODO: some of these classifiers might allow us to abort early, meaning we don't have to
424         // make these calls.
425         mFalsingManager.onProximityEvent(new ProximityEventImpl(proximityEvent));
426     }
427 
428 
logDebug(String msg)429     static void logDebug(String msg) {
430         logDebug(msg, null);
431     }
432 
logDebug(String msg, Throwable throwable)433     static void logDebug(String msg, Throwable throwable) {
434         if (DEBUG) {
435             Log.d(TAG, msg, throwable);
436         }
437     }
438 
439     private static class ProximityEventImpl implements FalsingManager.ProximityEvent {
440         private ThresholdSensorEvent mThresholdSensorEvent;
441 
ProximityEventImpl(ThresholdSensorEvent thresholdSensorEvent)442         ProximityEventImpl(ThresholdSensorEvent thresholdSensorEvent) {
443             mThresholdSensorEvent = thresholdSensorEvent;
444         }
445         @Override
getCovered()446         public boolean getCovered() {
447             return mThresholdSensorEvent.getBelow();
448         }
449 
450         @Override
getTimestampNs()451         public long getTimestampNs() {
452             return mThresholdSensorEvent.getTimestampNs();
453         }
454     }
455 }
456