blob: 8fc555f14c8aa66138a46f6a2d3c278b90950fee [file] [log] [blame]
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -07001/*
2 * Copyright (C) 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License
15 */
16
17package com.android.systemui.classifier;
18
19import android.content.Context;
20import android.database.ContentObserver;
21import android.hardware.Sensor;
22import android.hardware.SensorEvent;
23import android.hardware.SensorEventListener;
24import android.hardware.SensorManager;
Adrian Roos7bb38a92016-07-21 11:44:01 -070025import android.net.Uri;
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -070026import android.os.Handler;
Adrian Roosc5584ce2016-02-24 14:17:19 -080027import android.os.PowerManager;
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -070028import android.os.UserHandle;
29import android.provider.Settings;
30import android.view.MotionEvent;
Adrian Roosca664b92016-04-18 14:40:27 -070031import android.view.accessibility.AccessibilityManager;
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -070032
33import com.android.systemui.analytics.DataCollector;
34import com.android.systemui.statusbar.StatusBarState;
35
Adrian Roos401caae2016-03-04 13:35:21 -080036import java.io.PrintWriter;
37
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -070038/**
39 * When the phone is locked, listens to touch, sensor and phone events and sends them to
40 * DataCollector and HumanInteractionClassifier.
41 *
42 * It does not collect touch events when the bouncer shows up.
43 */
44public class FalsingManager implements SensorEventListener {
45 private static final String ENFORCE_BOUNCER = "falsing_manager_enforce_bouncer";
46
Blazej Magnowski6dc59b42015-09-22 15:14:20 -070047 private static final int[] CLASSIFIER_SENSORS = new int[] {
48 Sensor.TYPE_PROXIMITY,
49 };
50
51 private static final int[] COLLECTOR_SENSORS = new int[] {
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -070052 Sensor.TYPE_ACCELEROMETER,
53 Sensor.TYPE_GYROSCOPE,
54 Sensor.TYPE_PROXIMITY,
55 Sensor.TYPE_LIGHT,
56 Sensor.TYPE_ROTATION_VECTOR,
57 };
58
59 private final Handler mHandler = new Handler();
60 private final Context mContext;
61
62 private final SensorManager mSensorManager;
63 private final DataCollector mDataCollector;
64 private final HumanInteractionClassifier mHumanInteractionClassifier;
Adrian Roosca664b92016-04-18 14:40:27 -070065 private final AccessibilityManager mAccessibilityManager;
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -070066
67 private static FalsingManager sInstance = null;
68
69 private boolean mEnforceBouncer = false;
70 private boolean mBouncerOn = false;
71 private boolean mSessionActive = false;
72 private int mState = StatusBarState.SHADE;
Adrian Roosc5584ce2016-02-24 14:17:19 -080073 private boolean mScreenOn;
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -070074
75 protected final ContentObserver mSettingsObserver = new ContentObserver(mHandler) {
76 @Override
77 public void onChange(boolean selfChange) {
78 updateConfiguration();
79 }
80 };
81
82 private FalsingManager(Context context) {
83 mContext = context;
Adrian Roosca664b92016-04-18 14:40:27 -070084 mSensorManager = mContext.getSystemService(SensorManager.class);
85 mAccessibilityManager = context.getSystemService(AccessibilityManager.class);
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -070086 mDataCollector = DataCollector.getInstance(mContext);
87 mHumanInteractionClassifier = HumanInteractionClassifier.getInstance(mContext);
Adrian Roosc5584ce2016-02-24 14:17:19 -080088 mScreenOn = context.getSystemService(PowerManager.class).isInteractive();
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -070089
90 mContext.getContentResolver().registerContentObserver(
91 Settings.Secure.getUriFor(ENFORCE_BOUNCER), false,
92 mSettingsObserver,
93 UserHandle.USER_ALL);
94
95 updateConfiguration();
96 }
97
98 public static FalsingManager getInstance(Context context) {
99 if (sInstance == null) {
100 sInstance = new FalsingManager(context);
101 }
102 return sInstance;
103 }
104
105 private void updateConfiguration() {
106 mEnforceBouncer = 0 != Settings.Secure.getInt(mContext.getContentResolver(),
107 ENFORCE_BOUNCER, 0);
108 }
109
Adrian Roosc5584ce2016-02-24 14:17:19 -0800110 private boolean shouldSessionBeActive() {
Adrian Roos401caae2016-03-04 13:35:21 -0800111 if (FalsingLog.ENABLED && FalsingLog.VERBOSE)
112 FalsingLog.v("shouldBeActive", new StringBuilder()
113 .append("enabled=").append(isEnabled() ? 1 : 0)
114 .append(" mScreenOn=").append(mScreenOn ? 1 : 0)
115 .append(" mState=").append(StatusBarState.toShortString(mState))
116 .toString()
117 );
118 return isEnabled() && mScreenOn && (mState == StatusBarState.KEYGUARD);
Adrian Roosc5584ce2016-02-24 14:17:19 -0800119 }
120
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -0700121 private boolean sessionEntrypoint() {
Adrian Roosc5584ce2016-02-24 14:17:19 -0800122 if (!mSessionActive && shouldSessionBeActive()) {
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -0700123 onSessionStart();
124 return true;
125 }
126 return false;
127 }
128
Adrian Roosc5584ce2016-02-24 14:17:19 -0800129 private void sessionExitpoint(boolean force) {
130 if (mSessionActive && (force || !shouldSessionBeActive())) {
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -0700131 mSessionActive = false;
132 mSensorManager.unregisterListener(this);
133 }
134 }
135
136 private void onSessionStart() {
Adrian Roos401caae2016-03-04 13:35:21 -0800137 if (FalsingLog.ENABLED) {
138 FalsingLog.i("onSessionStart", "classifierEnabled=" + isClassiferEnabled());
139 }
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -0700140 mBouncerOn = false;
141 mSessionActive = true;
Blazej Magnowski6dc59b42015-09-22 15:14:20 -0700142
143 if (mHumanInteractionClassifier.isEnabled()) {
144 registerSensors(CLASSIFIER_SENSORS);
145 }
Adrian Roos7bb38a92016-07-21 11:44:01 -0700146 if (mDataCollector.isEnabledFull()) {
Blazej Magnowski6dc59b42015-09-22 15:14:20 -0700147 registerSensors(COLLECTOR_SENSORS);
148 }
149 }
150
151 private void registerSensors(int [] sensors) {
152 for (int sensorType : sensors) {
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -0700153 Sensor s = mSensorManager.getDefaultSensor(sensorType);
154 if (s != null) {
155 mSensorManager.registerListener(this, s, SensorManager.SENSOR_DELAY_GAME);
156 }
157 }
158 }
159
Blazej Magnowski6dc59b42015-09-22 15:14:20 -0700160 public boolean isClassiferEnabled() {
161 return mHumanInteractionClassifier.isEnabled();
162 }
163
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -0700164 private boolean isEnabled() {
165 return mHumanInteractionClassifier.isEnabled() || mDataCollector.isEnabled();
166 }
167
168 /**
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -0700169 * @return true if the classifier determined that this is not a human interacting with the phone
170 */
Blazej Magnowski9f01c5b2015-09-17 15:14:29 -0700171 public boolean isFalseTouch() {
Adrian Roos401caae2016-03-04 13:35:21 -0800172 if (FalsingLog.ENABLED) {
Adrian Roos6a04cb12016-03-14 20:21:02 -0700173 // We're getting some false wtfs from touches that happen after the device went
174 // to sleep. Only report missing sessions that happen when the device is interactive.
175 if (!mSessionActive && mContext.getSystemService(PowerManager.class).isInteractive()) {
Adrian Roos401caae2016-03-04 13:35:21 -0800176 FalsingLog.wtf("isFalseTouch", new StringBuilder()
177 .append("Session is not active, yet there's a query for a false touch.")
178 .append(" enabled=").append(isEnabled() ? 1 : 0)
179 .append(" mScreenOn=").append(mScreenOn ? 1 : 0)
180 .append(" mState=").append(StatusBarState.toShortString(mState))
181 .toString());
182 }
183 }
Adrian Roosca664b92016-04-18 14:40:27 -0700184 if (mAccessibilityManager.isTouchExplorationEnabled()) {
185 // Touch exploration triggers false positives in the classifier and
186 // already sufficiently prevents false unlocks.
187 return false;
188 }
Blazej Magnowski9f01c5b2015-09-17 15:14:29 -0700189 return mHumanInteractionClassifier.isFalseTouch();
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -0700190 }
191
192 @Override
193 public synchronized void onSensorChanged(SensorEvent event) {
194 mDataCollector.onSensorChanged(event);
195 mHumanInteractionClassifier.onSensorChanged(event);
196 }
197
198 @Override
199 public void onAccuracyChanged(Sensor sensor, int accuracy) {
200 mDataCollector.onAccuracyChanged(sensor, accuracy);
201 }
202
203 public boolean shouldEnforceBouncer() {
204 return mEnforceBouncer;
205 }
206
207 public void setStatusBarState(int state) {
Adrian Roos401caae2016-03-04 13:35:21 -0800208 if (FalsingLog.ENABLED) {
209 FalsingLog.i("setStatusBarState", new StringBuilder()
210 .append("from=").append(StatusBarState.toShortString(mState))
211 .append(" to=").append(StatusBarState.toShortString(state))
212 .toString());
213 }
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -0700214 mState = state;
Adrian Roosc5584ce2016-02-24 14:17:19 -0800215 if (shouldSessionBeActive()) {
216 sessionEntrypoint();
217 } else {
218 sessionExitpoint(false /* force */);
219 }
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -0700220 }
221
222 public void onScreenTurningOn() {
Adrian Roos401caae2016-03-04 13:35:21 -0800223 if (FalsingLog.ENABLED) {
224 FalsingLog.i("onScreenTurningOn", new StringBuilder()
225 .append("from=").append(mScreenOn ? 1 : 0)
226 .toString());
227 }
Adrian Roosc5584ce2016-02-24 14:17:19 -0800228 mScreenOn = true;
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -0700229 if (sessionEntrypoint()) {
230 mDataCollector.onScreenTurningOn();
231 }
232 }
233
234 public void onScreenOnFromTouch() {
Adrian Roos401caae2016-03-04 13:35:21 -0800235 if (FalsingLog.ENABLED) {
236 FalsingLog.i("onScreenOnFromTouch", new StringBuilder()
237 .append("from=").append(mScreenOn ? 1 : 0)
238 .toString());
239 }
Adrian Roosc5584ce2016-02-24 14:17:19 -0800240 mScreenOn = true;
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -0700241 if (sessionEntrypoint()) {
242 mDataCollector.onScreenOnFromTouch();
243 }
244 }
245
246 public void onScreenOff() {
Adrian Roos401caae2016-03-04 13:35:21 -0800247 if (FalsingLog.ENABLED) {
248 FalsingLog.i("onScreenOff", new StringBuilder()
249 .append("from=").append(mScreenOn ? 1 : 0)
250 .toString());
251 }
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -0700252 mDataCollector.onScreenOff();
Adrian Roosc5584ce2016-02-24 14:17:19 -0800253 mScreenOn = false;
254 sessionExitpoint(false /* force */);
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -0700255 }
256
257 public void onSucccessfulUnlock() {
Adrian Roos401caae2016-03-04 13:35:21 -0800258 if (FalsingLog.ENABLED) {
259 FalsingLog.i("onSucccessfulUnlock", "");
260 }
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -0700261 mDataCollector.onSucccessfulUnlock();
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -0700262 }
263
264 public void onBouncerShown() {
Adrian Roos401caae2016-03-04 13:35:21 -0800265 if (FalsingLog.ENABLED) {
266 FalsingLog.i("onBouncerShown", new StringBuilder()
267 .append("from=").append(mBouncerOn ? 1 : 0)
268 .toString());
269 }
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -0700270 if (!mBouncerOn) {
271 mBouncerOn = true;
272 mDataCollector.onBouncerShown();
273 }
274 }
275
276 public void onBouncerHidden() {
Adrian Roos401caae2016-03-04 13:35:21 -0800277 if (FalsingLog.ENABLED) {
278 FalsingLog.i("onBouncerHidden", new StringBuilder()
279 .append("from=").append(mBouncerOn ? 1 : 0)
280 .toString());
281 }
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -0700282 if (mBouncerOn) {
283 mBouncerOn = false;
284 mDataCollector.onBouncerHidden();
285 }
286 }
287
288 public void onQsDown() {
Adrian Roos401caae2016-03-04 13:35:21 -0800289 if (FalsingLog.ENABLED) {
290 FalsingLog.i("onQsDown", "");
291 }
Blazej Magnowski9f01c5b2015-09-17 15:14:29 -0700292 mHumanInteractionClassifier.setType(Classifier.QUICK_SETTINGS);
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -0700293 mDataCollector.onQsDown();
294 }
295
296 public void setQsExpanded(boolean expanded) {
297 mDataCollector.setQsExpanded(expanded);
298 }
299
300 public void onTrackingStarted() {
Adrian Roos401caae2016-03-04 13:35:21 -0800301 if (FalsingLog.ENABLED) {
302 FalsingLog.i("onTrackingStarted", "");
303 }
Blazej Magnowski9f01c5b2015-09-17 15:14:29 -0700304 mHumanInteractionClassifier.setType(Classifier.UNLOCK);
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -0700305 mDataCollector.onTrackingStarted();
306 }
307
308 public void onTrackingStopped() {
309 mDataCollector.onTrackingStopped();
310 }
311
312 public void onNotificationActive() {
313 mDataCollector.onNotificationActive();
314 }
315
Adrian Roos9f0b0022016-11-09 15:56:50 -0800316 public void onNotificationDoubleTap(boolean accepted, float dx, float dy) {
317 if (FalsingLog.ENABLED) {
318 FalsingLog.i("onNotificationDoubleTap", "accepted=" + accepted
319 + " dx=" + dx + " dy=" + dy + " (px)");
320 }
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -0700321 mDataCollector.onNotificationDoubleTap();
322 }
323
324 public void setNotificationExpanded() {
325 mDataCollector.setNotificationExpanded();
326 }
327
328 public void onNotificatonStartDraggingDown() {
Adrian Roos401caae2016-03-04 13:35:21 -0800329 if (FalsingLog.ENABLED) {
330 FalsingLog.i("onNotificatonStartDraggingDown", "");
331 }
Blazej Magnowski9f01c5b2015-09-17 15:14:29 -0700332 mHumanInteractionClassifier.setType(Classifier.NOTIFICATION_DRAG_DOWN);
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -0700333 mDataCollector.onNotificatonStartDraggingDown();
334 }
335
336 public void onNotificatonStopDraggingDown() {
337 mDataCollector.onNotificatonStopDraggingDown();
338 }
339
340 public void onNotificationDismissed() {
341 mDataCollector.onNotificationDismissed();
342 }
343
344 public void onNotificatonStartDismissing() {
Adrian Roos401caae2016-03-04 13:35:21 -0800345 if (FalsingLog.ENABLED) {
346 FalsingLog.i("onNotificatonStartDismissing", "");
347 }
Blazej Magnowski9f01c5b2015-09-17 15:14:29 -0700348 mHumanInteractionClassifier.setType(Classifier.NOTIFICATION_DISMISS);
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -0700349 mDataCollector.onNotificatonStartDismissing();
350 }
351
352 public void onNotificatonStopDismissing() {
353 mDataCollector.onNotificatonStopDismissing();
354 }
355
356 public void onCameraOn() {
357 mDataCollector.onCameraOn();
358 }
359
360 public void onLeftAffordanceOn() {
361 mDataCollector.onLeftAffordanceOn();
362 }
363
364 public void onAffordanceSwipingStarted(boolean rightCorner) {
Adrian Roos401caae2016-03-04 13:35:21 -0800365 if (FalsingLog.ENABLED) {
366 FalsingLog.i("onAffordanceSwipingStarted", "");
367 }
Blazej Magnowski9f01c5b2015-09-17 15:14:29 -0700368 if (rightCorner) {
369 mHumanInteractionClassifier.setType(Classifier.RIGHT_AFFORDANCE);
370 } else {
371 mHumanInteractionClassifier.setType(Classifier.LEFT_AFFORDANCE);
372 }
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -0700373 mDataCollector.onAffordanceSwipingStarted(rightCorner);
374 }
375
376 public void onAffordanceSwipingAborted() {
377 mDataCollector.onAffordanceSwipingAborted();
378 }
379
380 public void onUnlockHintStarted() {
381 mDataCollector.onUnlockHintStarted();
382 }
383
384 public void onCameraHintStarted() {
385 mDataCollector.onCameraHintStarted();
386 }
387
388 public void onLeftAffordanceHintStarted() {
389 mDataCollector.onLeftAffordanceHintStarted();
390 }
391
392 public void onTouchEvent(MotionEvent event, int width, int height) {
393 if (mSessionActive && !mBouncerOn) {
394 mDataCollector.onTouchEvent(event, width, height);
395 mHumanInteractionClassifier.onTouchEvent(event);
396 }
397 }
Adrian Roos401caae2016-03-04 13:35:21 -0800398
399 public void dump(PrintWriter pw) {
400 pw.println("FALSING MANAGER");
401 pw.print("classifierEnabled="); pw.println(isClassiferEnabled() ? 1 : 0);
402 pw.print("mSessionActive="); pw.println(mSessionActive ? 1 : 0);
403 pw.print("mBouncerOn="); pw.println(mSessionActive ? 1 : 0);
404 pw.print("mState="); pw.println(StatusBarState.toShortString(mState));
405 pw.print("mScreenOn="); pw.println(mScreenOn ? 1 : 0);
406 pw.println();
407 }
Adrian Roos7bb38a92016-07-21 11:44:01 -0700408
409 public Uri reportRejectedTouch() {
410 if (mDataCollector.isEnabled()) {
411 return mDataCollector.reportRejectedTouch();
412 }
413 return null;
414 }
415
416 public boolean isReportingEnabled() {
417 return mDataCollector.isReportingEnabled();
418 }
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -0700419}