blob: 347273ac0f68bb8deb830d2480399bd212520152 [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
42 private static final int[] SENSORS = new int[] {
43 Sensor.TYPE_ACCELEROMETER,
44 Sensor.TYPE_GYROSCOPE,
45 Sensor.TYPE_PROXIMITY,
46 Sensor.TYPE_LIGHT,
47 Sensor.TYPE_ROTATION_VECTOR,
48 };
49
50 private final Handler mHandler = new Handler();
51 private final Context mContext;
52
53 private final SensorManager mSensorManager;
54 private final DataCollector mDataCollector;
55 private final HumanInteractionClassifier mHumanInteractionClassifier;
56
57 private static FalsingManager sInstance = null;
58
59 private boolean mEnforceBouncer = false;
60 private boolean mBouncerOn = false;
61 private boolean mSessionActive = false;
62 private int mState = StatusBarState.SHADE;
63
64 protected final ContentObserver mSettingsObserver = new ContentObserver(mHandler) {
65 @Override
66 public void onChange(boolean selfChange) {
67 updateConfiguration();
68 }
69 };
70
71 private FalsingManager(Context context) {
72 mContext = context;
73 mSensorManager = (SensorManager) mContext.getSystemService(Context.SENSOR_SERVICE);
74 mDataCollector = DataCollector.getInstance(mContext);
75 mHumanInteractionClassifier = HumanInteractionClassifier.getInstance(mContext);
76
77 mContext.getContentResolver().registerContentObserver(
78 Settings.Secure.getUriFor(ENFORCE_BOUNCER), false,
79 mSettingsObserver,
80 UserHandle.USER_ALL);
81
82 updateConfiguration();
83 }
84
85 public static FalsingManager getInstance(Context context) {
86 if (sInstance == null) {
87 sInstance = new FalsingManager(context);
88 }
89 return sInstance;
90 }
91
92 private void updateConfiguration() {
93 mEnforceBouncer = 0 != Settings.Secure.getInt(mContext.getContentResolver(),
94 ENFORCE_BOUNCER, 0);
95 }
96
97 private boolean sessionEntrypoint() {
98 if (!mSessionActive && isEnabled() &&
99 (mState == StatusBarState.KEYGUARD || mState == StatusBarState.SHADE_LOCKED)) {
100 onSessionStart();
101 return true;
102 }
103 return false;
104 }
105
106 private void sessionExitpoint() {
107 if (mSessionActive) {
108 mSessionActive = false;
109 mSensorManager.unregisterListener(this);
110 }
111 }
112
113 private void onSessionStart() {
114 mBouncerOn = false;
115 mSessionActive = true;
116 for (int sensorType : SENSORS) {
117 Sensor s = mSensorManager.getDefaultSensor(sensorType);
118 if (s != null) {
119 mSensorManager.registerListener(this, s, SensorManager.SENSOR_DELAY_GAME);
120 }
121 }
122 }
123
124 private boolean isEnabled() {
125 return mHumanInteractionClassifier.isEnabled() || mDataCollector.isEnabled();
126 }
127
128 /**
129 * @param type the type of action for which this method is called
130 * @return true if the classifier determined that this is not a human interacting with the phone
131 */
132 public boolean isFalseTouch(int type) {
133 return mHumanInteractionClassifier.getFalseTouchEvaluation(type) > 0.5;
134 }
135
136 @Override
137 public synchronized void onSensorChanged(SensorEvent event) {
138 mDataCollector.onSensorChanged(event);
139 mHumanInteractionClassifier.onSensorChanged(event);
140 }
141
142 @Override
143 public void onAccuracyChanged(Sensor sensor, int accuracy) {
144 mDataCollector.onAccuracyChanged(sensor, accuracy);
145 }
146
147 public boolean shouldEnforceBouncer() {
148 return mEnforceBouncer;
149 }
150
151 public void setStatusBarState(int state) {
152 mState = state;
153 }
154
155 public void onScreenTurningOn() {
156 if (sessionEntrypoint()) {
157 mDataCollector.onScreenTurningOn();
158 }
159 }
160
161 public void onScreenOnFromTouch() {
162 if (sessionEntrypoint()) {
163 mDataCollector.onScreenOnFromTouch();
164 }
165 }
166
167 public void onScreenOff() {
168 mDataCollector.onScreenOff();
169 sessionExitpoint();
170 }
171
172 public void onSucccessfulUnlock() {
173 mDataCollector.onSucccessfulUnlock();
174 sessionExitpoint();
175 }
176
177 public void onBouncerShown() {
178 if (!mBouncerOn) {
179 mBouncerOn = true;
180 mDataCollector.onBouncerShown();
181 }
182 }
183
184 public void onBouncerHidden() {
185 if (mBouncerOn) {
186 mBouncerOn = false;
187 mDataCollector.onBouncerHidden();
188 }
189 }
190
191 public void onQsDown() {
192 mDataCollector.onQsDown();
193 }
194
195 public void setQsExpanded(boolean expanded) {
196 mDataCollector.setQsExpanded(expanded);
197 }
198
199 public void onTrackingStarted() {
200 mDataCollector.onTrackingStarted();
201 }
202
203 public void onTrackingStopped() {
204 mDataCollector.onTrackingStopped();
205 }
206
207 public void onNotificationActive() {
208 mDataCollector.onNotificationActive();
209 }
210
211 public void onNotificationDoubleTap() {
212 mDataCollector.onNotificationDoubleTap();
213 }
214
215 public void setNotificationExpanded() {
216 mDataCollector.setNotificationExpanded();
217 }
218
219 public void onNotificatonStartDraggingDown() {
220 mDataCollector.onNotificatonStartDraggingDown();
221 }
222
223 public void onNotificatonStopDraggingDown() {
224 mDataCollector.onNotificatonStopDraggingDown();
225 }
226
227 public void onNotificationDismissed() {
228 mDataCollector.onNotificationDismissed();
229 }
230
231 public void onNotificatonStartDismissing() {
232 mDataCollector.onNotificatonStartDismissing();
233 }
234
235 public void onNotificatonStopDismissing() {
236 mDataCollector.onNotificatonStopDismissing();
237 }
238
239 public void onCameraOn() {
240 mDataCollector.onCameraOn();
241 }
242
243 public void onLeftAffordanceOn() {
244 mDataCollector.onLeftAffordanceOn();
245 }
246
247 public void onAffordanceSwipingStarted(boolean rightCorner) {
248 mDataCollector.onAffordanceSwipingStarted(rightCorner);
249 }
250
251 public void onAffordanceSwipingAborted() {
252 mDataCollector.onAffordanceSwipingAborted();
253 }
254
255 public void onUnlockHintStarted() {
256 mDataCollector.onUnlockHintStarted();
257 }
258
259 public void onCameraHintStarted() {
260 mDataCollector.onCameraHintStarted();
261 }
262
263 public void onLeftAffordanceHintStarted() {
264 mDataCollector.onLeftAffordanceHintStarted();
265 }
266
267 public void onTouchEvent(MotionEvent event, int width, int height) {
268 if (mSessionActive && !mBouncerOn) {
269 mDataCollector.onTouchEvent(event, width, height);
270 mHumanInteractionClassifier.onTouchEvent(event);
271 }
272 }
273}