blob: 735a7c4bad4a1f40a02a5c01e0703544f7f579a1 [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;
25import android.os.Handler;
26import android.os.UserHandle;
27import android.provider.Settings;
28import android.view.MotionEvent;
29
30import com.android.systemui.analytics.DataCollector;
31import com.android.systemui.statusbar.StatusBarState;
32
33/**
34 * When the phone is locked, listens to touch, sensor and phone events and sends them to
35 * DataCollector and HumanInteractionClassifier.
36 *
37 * It does not collect touch events when the bouncer shows up.
38 */
39public class FalsingManager implements SensorEventListener {
40 private static final String ENFORCE_BOUNCER = "falsing_manager_enforce_bouncer";
41
Blazej Magnowski6dc59b42015-09-22 15:14:20 -070042 private static final int[] CLASSIFIER_SENSORS = new int[] {
43 Sensor.TYPE_PROXIMITY,
44 };
45
46 private static final int[] COLLECTOR_SENSORS = new int[] {
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -070047 Sensor.TYPE_ACCELEROMETER,
48 Sensor.TYPE_GYROSCOPE,
49 Sensor.TYPE_PROXIMITY,
50 Sensor.TYPE_LIGHT,
51 Sensor.TYPE_ROTATION_VECTOR,
52 };
53
54 private final Handler mHandler = new Handler();
55 private final Context mContext;
56
57 private final SensorManager mSensorManager;
58 private final DataCollector mDataCollector;
59 private final HumanInteractionClassifier mHumanInteractionClassifier;
60
61 private static FalsingManager sInstance = null;
62
63 private boolean mEnforceBouncer = false;
64 private boolean mBouncerOn = false;
65 private boolean mSessionActive = false;
66 private int mState = StatusBarState.SHADE;
67
68 protected final ContentObserver mSettingsObserver = new ContentObserver(mHandler) {
69 @Override
70 public void onChange(boolean selfChange) {
71 updateConfiguration();
72 }
73 };
74
75 private FalsingManager(Context context) {
76 mContext = context;
77 mSensorManager = (SensorManager) mContext.getSystemService(Context.SENSOR_SERVICE);
78 mDataCollector = DataCollector.getInstance(mContext);
79 mHumanInteractionClassifier = HumanInteractionClassifier.getInstance(mContext);
80
81 mContext.getContentResolver().registerContentObserver(
82 Settings.Secure.getUriFor(ENFORCE_BOUNCER), false,
83 mSettingsObserver,
84 UserHandle.USER_ALL);
85
86 updateConfiguration();
87 }
88
89 public static FalsingManager getInstance(Context context) {
90 if (sInstance == null) {
91 sInstance = new FalsingManager(context);
92 }
93 return sInstance;
94 }
95
96 private void updateConfiguration() {
97 mEnforceBouncer = 0 != Settings.Secure.getInt(mContext.getContentResolver(),
98 ENFORCE_BOUNCER, 0);
99 }
100
101 private boolean sessionEntrypoint() {
102 if (!mSessionActive && isEnabled() &&
103 (mState == StatusBarState.KEYGUARD || mState == StatusBarState.SHADE_LOCKED)) {
104 onSessionStart();
105 return true;
106 }
107 return false;
108 }
109
110 private void sessionExitpoint() {
111 if (mSessionActive) {
112 mSessionActive = false;
113 mSensorManager.unregisterListener(this);
114 }
115 }
116
117 private void onSessionStart() {
118 mBouncerOn = false;
119 mSessionActive = true;
Blazej Magnowski6dc59b42015-09-22 15:14:20 -0700120
121 if (mHumanInteractionClassifier.isEnabled()) {
122 registerSensors(CLASSIFIER_SENSORS);
123 }
124 if (mDataCollector.isEnabled()) {
125 registerSensors(COLLECTOR_SENSORS);
126 }
127 }
128
129 private void registerSensors(int [] sensors) {
130 for (int sensorType : sensors) {
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -0700131 Sensor s = mSensorManager.getDefaultSensor(sensorType);
132 if (s != null) {
133 mSensorManager.registerListener(this, s, SensorManager.SENSOR_DELAY_GAME);
134 }
135 }
136 }
137
Blazej Magnowski6dc59b42015-09-22 15:14:20 -0700138 public boolean isClassiferEnabled() {
139 return mHumanInteractionClassifier.isEnabled();
140 }
141
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -0700142 private boolean isEnabled() {
143 return mHumanInteractionClassifier.isEnabled() || mDataCollector.isEnabled();
144 }
145
146 /**
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -0700147 * @return true if the classifier determined that this is not a human interacting with the phone
148 */
Blazej Magnowski9f01c5b2015-09-17 15:14:29 -0700149 public boolean isFalseTouch() {
150 return mHumanInteractionClassifier.isFalseTouch();
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -0700151 }
152
153 @Override
154 public synchronized void onSensorChanged(SensorEvent event) {
155 mDataCollector.onSensorChanged(event);
156 mHumanInteractionClassifier.onSensorChanged(event);
157 }
158
159 @Override
160 public void onAccuracyChanged(Sensor sensor, int accuracy) {
161 mDataCollector.onAccuracyChanged(sensor, accuracy);
162 }
163
164 public boolean shouldEnforceBouncer() {
165 return mEnforceBouncer;
166 }
167
168 public void setStatusBarState(int state) {
169 mState = state;
170 }
171
172 public void onScreenTurningOn() {
173 if (sessionEntrypoint()) {
174 mDataCollector.onScreenTurningOn();
175 }
176 }
177
178 public void onScreenOnFromTouch() {
179 if (sessionEntrypoint()) {
180 mDataCollector.onScreenOnFromTouch();
181 }
182 }
183
184 public void onScreenOff() {
185 mDataCollector.onScreenOff();
186 sessionExitpoint();
187 }
188
189 public void onSucccessfulUnlock() {
190 mDataCollector.onSucccessfulUnlock();
191 sessionExitpoint();
192 }
193
194 public void onBouncerShown() {
195 if (!mBouncerOn) {
196 mBouncerOn = true;
197 mDataCollector.onBouncerShown();
198 }
199 }
200
201 public void onBouncerHidden() {
202 if (mBouncerOn) {
203 mBouncerOn = false;
204 mDataCollector.onBouncerHidden();
205 }
206 }
207
208 public void onQsDown() {
Blazej Magnowski9f01c5b2015-09-17 15:14:29 -0700209 mHumanInteractionClassifier.setType(Classifier.QUICK_SETTINGS);
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -0700210 mDataCollector.onQsDown();
211 }
212
213 public void setQsExpanded(boolean expanded) {
214 mDataCollector.setQsExpanded(expanded);
215 }
216
217 public void onTrackingStarted() {
Blazej Magnowski9f01c5b2015-09-17 15:14:29 -0700218 mHumanInteractionClassifier.setType(Classifier.UNLOCK);
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -0700219 mDataCollector.onTrackingStarted();
220 }
221
222 public void onTrackingStopped() {
223 mDataCollector.onTrackingStopped();
224 }
225
226 public void onNotificationActive() {
227 mDataCollector.onNotificationActive();
228 }
229
230 public void onNotificationDoubleTap() {
231 mDataCollector.onNotificationDoubleTap();
232 }
233
234 public void setNotificationExpanded() {
235 mDataCollector.setNotificationExpanded();
236 }
237
238 public void onNotificatonStartDraggingDown() {
Blazej Magnowski9f01c5b2015-09-17 15:14:29 -0700239 mHumanInteractionClassifier.setType(Classifier.NOTIFICATION_DRAG_DOWN);
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -0700240 mDataCollector.onNotificatonStartDraggingDown();
241 }
242
243 public void onNotificatonStopDraggingDown() {
244 mDataCollector.onNotificatonStopDraggingDown();
245 }
246
247 public void onNotificationDismissed() {
248 mDataCollector.onNotificationDismissed();
249 }
250
251 public void onNotificatonStartDismissing() {
Blazej Magnowski9f01c5b2015-09-17 15:14:29 -0700252 mHumanInteractionClassifier.setType(Classifier.NOTIFICATION_DISMISS);
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -0700253 mDataCollector.onNotificatonStartDismissing();
254 }
255
256 public void onNotificatonStopDismissing() {
257 mDataCollector.onNotificatonStopDismissing();
258 }
259
260 public void onCameraOn() {
261 mDataCollector.onCameraOn();
262 }
263
264 public void onLeftAffordanceOn() {
265 mDataCollector.onLeftAffordanceOn();
266 }
267
268 public void onAffordanceSwipingStarted(boolean rightCorner) {
Blazej Magnowski9f01c5b2015-09-17 15:14:29 -0700269 if (rightCorner) {
270 mHumanInteractionClassifier.setType(Classifier.RIGHT_AFFORDANCE);
271 } else {
272 mHumanInteractionClassifier.setType(Classifier.LEFT_AFFORDANCE);
273 }
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -0700274 mDataCollector.onAffordanceSwipingStarted(rightCorner);
275 }
276
277 public void onAffordanceSwipingAborted() {
278 mDataCollector.onAffordanceSwipingAborted();
279 }
280
281 public void onUnlockHintStarted() {
282 mDataCollector.onUnlockHintStarted();
283 }
284
285 public void onCameraHintStarted() {
286 mDataCollector.onCameraHintStarted();
287 }
288
289 public void onLeftAffordanceHintStarted() {
290 mDataCollector.onLeftAffordanceHintStarted();
291 }
292
293 public void onTouchEvent(MotionEvent event, int width, int height) {
294 if (mSessionActive && !mBouncerOn) {
295 mDataCollector.onTouchEvent(event, width, height);
296 mHumanInteractionClassifier.onTouchEvent(event);
297 }
298 }
299}