diff options
| author | 2015-09-10 14:37:17 -0700 | |
|---|---|---|
| committer | 2015-09-15 18:28:49 -0700 | |
| commit | 0e2ffbd48bbedf47deb7f6aed96bd07e2fc96f53 (patch) | |
| tree | 27e55796ce2e94aceecb6d2af8fd267d0073f420 | |
| parent | b16e74693ef29b20e2d4327ff6ddec49eafd2873 (diff) | |
Add FalsingManager and Classifier to SystemUI
Adds the possibility to analyze and classify touch and sensor events as
human or false touches.
Change-Id: I5079c02406d532fea38ca2d302e8606effae0696
19 files changed, 857 insertions, 147 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/analytics/LockedPhoneAnalytics.java b/packages/SystemUI/src/com/android/systemui/analytics/DataCollector.java index e458862295e1..91f652056326 100644 --- a/packages/SystemUI/src/com/android/systemui/analytics/LockedPhoneAnalytics.java +++ b/packages/SystemUI/src/com/android/systemui/analytics/DataCollector.java @@ -21,7 +21,6 @@ import android.database.ContentObserver; import android.hardware.Sensor; import android.hardware.SensorEvent; import android.hardware.SensorEventListener; -import android.hardware.SensorManager; import android.os.AsyncTask; import android.os.Build; import android.os.Handler; @@ -30,8 +29,6 @@ import android.provider.Settings; import android.util.Log; import android.view.MotionEvent; -import com.android.systemui.statusbar.StatusBarState; - import java.io.File; import java.io.FileOutputStream; import java.io.IOException; @@ -47,94 +44,70 @@ import static com.android.systemui.statusbar.phone.TouchAnalyticsProto.Session.P * A session starts when the screen is turned on. * A session ends when the screen is turned off or user unlocks the phone. */ -public class LockedPhoneAnalytics implements SensorEventListener { - private static final String TAG = "LockedPhoneAnalytics"; - private static final String ANALYTICS_ENABLE = "locked_phone_analytics_enable"; - private static final String ENFORCE_BOUNCER = "locked_phone_analytics_enforce_bouncer"; - private static final String COLLECT_BAD_TOCUHES = "locked_phone_analytics_collect_bad_touches"; +public class DataCollector implements SensorEventListener { + private static final String TAG = "DataCollector"; + private static final String COLLECTOR_ENABLE = "data_collector_enable"; + private static final String COLLECT_BAD_TOUCHES = "data_collector_collect_bad_touches"; private static final long TIMEOUT_MILLIS = 11000; // 11 seconds. public static final boolean DEBUG = false; - private static final int[] SENSORS = new int[] { - Sensor.TYPE_ACCELEROMETER, - Sensor.TYPE_GYROSCOPE, - Sensor.TYPE_PROXIMITY, - Sensor.TYPE_LIGHT, - Sensor.TYPE_ROTATION_VECTOR, - }; - private final Handler mHandler = new Handler(); - protected final ContentObserver mSettingsObserver = new ContentObserver(mHandler) { - @Override - public void onChange(boolean selfChange) { - updateConfiguration(); - } - }; - - private final SensorManager mSensorManager; private final Context mContext; // Err on the side of caution, so logging is not started after a crash even tough the screen // is off. private SensorLoggerSession mCurrentSession = null; - private boolean mEnableAnalytics = false; - private boolean mEnforceBouncer = false; + private boolean mEnableCollector = false; private boolean mTimeoutActive = false; private boolean mCollectBadTouches = false; - private boolean mBouncerOn = false; private boolean mCornerSwiping = false; private boolean mTrackingStarted = false; - private int mState = StatusBarState.SHADE; + private static DataCollector sInstance = null; - private static LockedPhoneAnalytics sInstance = null; + protected final ContentObserver mSettingsObserver = new ContentObserver(mHandler) { + @Override + public void onChange(boolean selfChange) { + updateConfiguration(); + } + }; - private LockedPhoneAnalytics(Context context) { - mSensorManager = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE); + private DataCollector(Context context) { mContext = context; mContext.getContentResolver().registerContentObserver( - Settings.Secure.getUriFor(ANALYTICS_ENABLE), false, + Settings.Secure.getUriFor(COLLECTOR_ENABLE), false, mSettingsObserver, UserHandle.USER_ALL); mContext.getContentResolver().registerContentObserver( - Settings.Secure.getUriFor(ENFORCE_BOUNCER), false, - mSettingsObserver, - UserHandle.USER_ALL); - - mContext.getContentResolver().registerContentObserver( - Settings.Secure.getUriFor(COLLECT_BAD_TOCUHES), false, + Settings.Secure.getUriFor(COLLECT_BAD_TOUCHES), false, mSettingsObserver, UserHandle.USER_ALL); updateConfiguration(); } - public static LockedPhoneAnalytics getInstance(Context context) { + public static DataCollector getInstance(Context context) { if (sInstance == null) { - sInstance = new LockedPhoneAnalytics(context); + sInstance = new DataCollector(context); } return sInstance; } private void updateConfiguration() { - mEnableAnalytics = Build.IS_DEBUGGABLE && 0 != Settings.Secure.getInt( + mEnableCollector = Build.IS_DEBUGGABLE && 0 != Settings.Secure.getInt( mContext.getContentResolver(), - ANALYTICS_ENABLE, 0); - mEnforceBouncer = mEnableAnalytics && 0 != Settings.Secure.getInt( + COLLECTOR_ENABLE, 0); + mCollectBadTouches = mEnableCollector && 0 != Settings.Secure.getInt( mContext.getContentResolver(), - ENFORCE_BOUNCER, 0); - mCollectBadTouches = mEnableAnalytics && 0 != Settings.Secure.getInt( - mContext.getContentResolver(), - COLLECT_BAD_TOCUHES, 0); + COLLECT_BAD_TOUCHES, 0); } private boolean sessionEntrypoint() { - if ((mState == StatusBarState.KEYGUARD || mState == StatusBarState.SHADE_LOCKED) - && mEnableAnalytics && mCurrentSession == null) { + if (mEnableCollector && mCurrentSession == null) { onSessionStart(); return true; } @@ -142,22 +115,15 @@ public class LockedPhoneAnalytics implements SensorEventListener { } private void sessionExitpoint(int result) { - if (mEnableAnalytics && mCurrentSession != null) { + if (mEnableCollector && mCurrentSession != null) { onSessionEnd(result); } } private void onSessionStart() { - mBouncerOn = false; mCornerSwiping = false; mTrackingStarted = false; mCurrentSession = new SensorLoggerSession(System.currentTimeMillis(), System.nanoTime()); - for (int sensorType : SENSORS) { - Sensor s = mSensorManager.getDefaultSensor(sensorType); - if (s != null) { - mSensorManager.registerListener(this, s, SensorManager.SENSOR_DELAY_GAME); - } - } } private void onSessionEnd(int result) { @@ -196,10 +162,9 @@ public class LockedPhoneAnalytics implements SensorEventListener { }); } - @Override public synchronized void onSensorChanged(SensorEvent event) { - if (mEnableAnalytics && mCurrentSession != null) { + if (mEnableCollector && mCurrentSession != null) { mCurrentSession.addSensorEvent(event, System.nanoTime()); enforceTimeout(); } @@ -221,18 +186,14 @@ public class LockedPhoneAnalytics implements SensorEventListener { public void onAccuracyChanged(Sensor sensor, int accuracy) { } - public boolean shouldEnforceBouncer() { - return mEnforceBouncer; + public boolean isEnabled() { + return mEnableCollector; } - public void setStatusBarState(int state) { - mState = state; - } - - public void onScreenOn() { + public void onScreenTurningOn() { if (sessionEntrypoint()) { if (DEBUG) { - Log.d(TAG, "onScreenOn"); + Log.d(TAG, "onScreenTurningOn"); } addEvent(PhoneEvent.ON_SCREEN_ON); } @@ -264,23 +225,17 @@ public class LockedPhoneAnalytics implements SensorEventListener { } public void onBouncerShown() { - if (!mBouncerOn) { - if (DEBUG) { - Log.d(TAG, "onBouncerShown"); - } - mBouncerOn = true; - addEvent(PhoneEvent.ON_BOUNCER_SHOWN); + if (DEBUG) { + Log.d(TAG, "onBouncerShown"); } + addEvent(PhoneEvent.ON_BOUNCER_SHOWN); } public void onBouncerHidden() { - if (mBouncerOn) { - if (DEBUG) { - Log.d(TAG, "onBouncerHidden"); - } - mBouncerOn = false; - addEvent(PhoneEvent.ON_BOUNCER_HIDDEN); + if (DEBUG) { + Log.d(TAG, "onBouncerHidden"); } + addEvent(PhoneEvent.ON_BOUNCER_HIDDEN); } public void onQsDown() { @@ -433,20 +388,20 @@ public class LockedPhoneAnalytics implements SensorEventListener { addEvent(PhoneEvent.ON_LEFT_AFFORDANCE_HINT_STARTED); } - public void onTouchEvent(MotionEvent ev, int width, int height) { - if (!mBouncerOn && mCurrentSession != null) { + public void onTouchEvent(MotionEvent event, int width, int height) { + if (mCurrentSession != null) { if (DEBUG) { Log.v(TAG, "onTouchEvent(ev.action=" - + MotionEvent.actionToString(ev.getAction()) + ")"); + + MotionEvent.actionToString(event.getAction()) + ")"); } - mCurrentSession.addMotionEvent(ev); + mCurrentSession.addMotionEvent(event); mCurrentSession.setTouchArea(width, height); enforceTimeout(); } } private void addEvent(int eventType) { - if (mEnableAnalytics && mCurrentSession != null) { + if (mEnableCollector && mCurrentSession != null) { mCurrentSession.addPhoneEvent(eventType, System.nanoTime()); } } diff --git a/packages/SystemUI/src/com/android/systemui/analytics/SensorLoggerSession.java b/packages/SystemUI/src/com/android/systemui/analytics/SensorLoggerSession.java index 09383f6aa8d1..0e280028b6f0 100644 --- a/packages/SystemUI/src/com/android/systemui/analytics/SensorLoggerSession.java +++ b/packages/SystemUI/src/com/android/systemui/analytics/SensorLoggerSession.java @@ -57,7 +57,7 @@ public class SensorLoggerSession { mResult = result; mEndTimestampMillis = endTimestampMillis; - if (LockedPhoneAnalytics.DEBUG) { + if (DataCollector.DEBUG) { Log.d(TAG, "Ending session result=" + result + " it lasted for " + (float) (mEndTimestampMillis - mStartTimestampMillis) / 1000f + "s"); } diff --git a/packages/SystemUI/src/com/android/systemui/classifier/AnglesVarianceClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/AnglesVarianceClassifier.java new file mode 100644 index 000000000000..5cd914f06828 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/classifier/AnglesVarianceClassifier.java @@ -0,0 +1,156 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.android.systemui.classifier; + +import android.hardware.SensorEvent; +import android.view.MotionEvent; + +import java.lang.Math; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +/** + * A classifier which calculates the variance of differences between successive angles in a stroke. + * For each stroke it keeps its last three points. If some successive points are the same, it ignores + * the repetitions. If a new point is added, the classifier calculates the angle between the last + * three points. After that it calculates the difference between this angle and the previously + * calculated angle. The return value of the classifier is the variance of the differences + * from a stroke. If there are multiple strokes created at once, the classifier sums up the + * variances of all the strokes. Also the value is multiplied by HISTORY_FACTOR after each + * INTERVAL milliseconds. + */ +public class AnglesVarianceClassifier extends Classifier { + private final float INTERVAL = 10.0f; + private final float CLEAR_HISTORY = 500f; + private final float HISTORY_FACTOR = 0.9f; + + private HashMap<Stroke, Data> mStrokeMap = new HashMap<>(); + private float mValue; + private long mLastUpdate; + + public AnglesVarianceClassifier(ClassifierData classifierData) { + mClassifierData = classifierData; + mValue = 0.0f; + mLastUpdate = System.currentTimeMillis(); + } + + @Override + public void onTouchEvent(MotionEvent event) { + int action = event.getActionMasked(); + + if (action == MotionEvent.ACTION_DOWN) { + mStrokeMap.clear(); + } + + for (int i = 0; i < event.getPointerCount(); i++) { + Stroke stroke = mClassifierData.getStroke(event.getPointerId(i)); + + if (mStrokeMap.get(stroke) == null) { + mStrokeMap.put(stroke, new Data()); + } + mStrokeMap.get(stroke).addPoint(stroke.getPoints().get(stroke.getPoints().size() - 1)); + + if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL + || (action == MotionEvent.ACTION_POINTER_UP && i == event.getActionIndex())) { + decayValue(); + mValue += mStrokeMap.get(stroke).getAnglesVariance(); + } + } + } + + /** + * Decreases mValue through time + */ + private void decayValue() { + long currentTimeMillis = System.currentTimeMillis(); + if (currentTimeMillis - mLastUpdate > CLEAR_HISTORY) { + mValue = 0.0f; + } else { + mValue *= Math.pow(HISTORY_FACTOR, (float) (currentTimeMillis - mLastUpdate) / INTERVAL); + } + mLastUpdate = currentTimeMillis; + } + + @Override + public void onSensorChanged(SensorEvent event) { + } + + @Override + public float getFalseTouchEvaluation(int type) { + decayValue(); + float currentValue = 0.0f; + for (Data data: mStrokeMap.values()) { + currentValue += data.getAnglesVariance(); + } + return (float) (mValue + currentValue); + } + + private class Data { + private List<Point> mLastThreePoints = new ArrayList<>(); + private float mPreviousAngle; + private float mSumSquares; + private float mSum; + private float mCount; + + public Data() { + mPreviousAngle = (float) Math.PI; + mSumSquares = 0.0f; + mSum = 0.0f; + mCount = 1.0f; + } + + public void addPoint(Point point) { + // Checking if the added point is different than the previously added point + // Repetitions are being ignored so that proper angles are calculated. + if (mLastThreePoints.isEmpty() + || !mLastThreePoints.get(mLastThreePoints.size() - 1).equals(point)) { + mLastThreePoints.add(point); + if (mLastThreePoints.size() == 4) { + mLastThreePoints.remove(0); + + float angle = getAngle(mLastThreePoints.get(0), mLastThreePoints.get(1), + mLastThreePoints.get(2)); + + float difference = angle - mPreviousAngle; + mSum += difference; + mSumSquares += difference * difference; + mCount += 1.0; + mPreviousAngle = angle; + } + } + } + + private float getAngle(Point a, Point b, Point c) { + float dist1 = a.dist(b); + float dist2 = b.dist(c); + float crossProduct = b.crossProduct(a, c); + float dotProduct = b.dotProduct(a, c); + float cos = Math.min(1.0f, Math.max(-1.0f, dotProduct / dist1 / dist2)); + float angle = (float) Math.acos(cos); + if (crossProduct < 0.0) { + angle = 2.0f * (float) Math.PI - angle; + } + return angle; + } + + public float getAnglesVariance() { + return mSumSquares / mCount + (mSum / mCount) * (mSum / mCount); + } + } +}
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/classifier/Classifier.java b/packages/SystemUI/src/com/android/systemui/classifier/Classifier.java new file mode 100644 index 000000000000..b76be1478bb4 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/classifier/Classifier.java @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.android.systemui.classifier; + +import android.hardware.SensorEvent; +import android.view.MotionEvent; + +/** + * An interface for classifiers for touch and sensor events. + */ +public abstract class Classifier { + public static final int QUICK_SETTINGS = 0; + public static final int NOTIFICATION_DISMISS = 1; + public static final int NOTIFICATION_DRAG_DOWN = 2; + public static final int NOTIFICATION_DOUBLE_TAP = 3; + public static final int UNLOCK = 4; + public static final int LEFT_AFFORDANCE = 5; + public static final int RIGHT_AFFORDANCE = 6; + + /** + * Contains all the information about touch events from which the classifier can query + */ + protected ClassifierData mClassifierData; + + /** + * Informs the classifier that a new touch event has occurred + */ + public void onTouchEvent(MotionEvent event) { + } + + /** + * Informs the classifier that a sensor change occurred + */ + public void onSensorChanged(SensorEvent event) { + } + + /** + * @param type the type of action for which this method is called + * @return a nonnegative value which is used to determine whether this a false touch. The + * bigger the value the greater the chance that this a false touch. + */ + public abstract float getFalseTouchEvaluation(int type); +} diff --git a/packages/SystemUI/src/com/android/systemui/classifier/ClassifierData.java b/packages/SystemUI/src/com/android/systemui/classifier/ClassifierData.java new file mode 100644 index 000000000000..77b81d2b68fa --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/classifier/ClassifierData.java @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.android.systemui.classifier; + +import android.util.SparseArray; +import android.view.MotionEvent; + +/** + * Contains data which is used to classify interaction sequences on the lockscreen. It does, for + * example, provide information on the current touch state. + */ +public class ClassifierData { + private SparseArray<Stroke> mCurrentStrokes = new SparseArray<>(); + + public ClassifierData() { + } + + public void update(MotionEvent event) { + int action = event.getActionMasked(); + if (action == MotionEvent.ACTION_DOWN) { + mCurrentStrokes.clear(); + } + for (int i = 0; i < event.getPointerCount(); i++) { + int id = event.getPointerId(i); + if (mCurrentStrokes.get(id) == null) { + mCurrentStrokes.put(id, new Stroke(event.getEventTimeNano())); + } + mCurrentStrokes.get(id).addPoint(event.getX(i), event.getY(i), + event.getEventTimeNano()); + } + } + + public void cleanUp(MotionEvent event) { + int action = event.getActionMasked(); + for (int i = 0; i < event.getPointerCount(); i++) { + int id = event.getPointerId(i); + if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL + || (action == MotionEvent.ACTION_POINTER_UP && i == event.getActionIndex())) { + mCurrentStrokes.remove(id); + } + } + } + + /** + * @param id the id from MotionEvent + * @return the Stroke assigned to the id + */ + public Stroke getStroke(int id) { + return mCurrentStrokes.get(id); + } +} diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManager.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManager.java new file mode 100644 index 000000000000..347273ac0f68 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManager.java @@ -0,0 +1,273 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.android.systemui.classifier; + +import android.content.Context; +import android.database.ContentObserver; +import android.hardware.Sensor; +import android.hardware.SensorEvent; +import android.hardware.SensorEventListener; +import android.hardware.SensorManager; +import android.os.Handler; +import android.os.UserHandle; +import android.provider.Settings; +import android.view.MotionEvent; + +import com.android.systemui.analytics.DataCollector; +import com.android.systemui.statusbar.StatusBarState; + +/** + * When the phone is locked, listens to touch, sensor and phone events and sends them to + * DataCollector and HumanInteractionClassifier. + * + * It does not collect touch events when the bouncer shows up. + */ +public class FalsingManager implements SensorEventListener { + private static final String ENFORCE_BOUNCER = "falsing_manager_enforce_bouncer"; + + private static final int[] SENSORS = new int[] { + Sensor.TYPE_ACCELEROMETER, + Sensor.TYPE_GYROSCOPE, + Sensor.TYPE_PROXIMITY, + Sensor.TYPE_LIGHT, + Sensor.TYPE_ROTATION_VECTOR, + }; + + private final Handler mHandler = new Handler(); + private final Context mContext; + + private final SensorManager mSensorManager; + private final DataCollector mDataCollector; + private final HumanInteractionClassifier mHumanInteractionClassifier; + + private static FalsingManager sInstance = null; + + private boolean mEnforceBouncer = false; + private boolean mBouncerOn = false; + private boolean mSessionActive = false; + private int mState = StatusBarState.SHADE; + + protected final ContentObserver mSettingsObserver = new ContentObserver(mHandler) { + @Override + public void onChange(boolean selfChange) { + updateConfiguration(); + } + }; + + private FalsingManager(Context context) { + mContext = context; + mSensorManager = (SensorManager) mContext.getSystemService(Context.SENSOR_SERVICE); + mDataCollector = DataCollector.getInstance(mContext); + mHumanInteractionClassifier = HumanInteractionClassifier.getInstance(mContext); + + mContext.getContentResolver().registerContentObserver( + Settings.Secure.getUriFor(ENFORCE_BOUNCER), false, + mSettingsObserver, + UserHandle.USER_ALL); + + updateConfiguration(); + } + + public static FalsingManager getInstance(Context context) { + if (sInstance == null) { + sInstance = new FalsingManager(context); + } + return sInstance; + } + + private void updateConfiguration() { + mEnforceBouncer = 0 != Settings.Secure.getInt(mContext.getContentResolver(), + ENFORCE_BOUNCER, 0); + } + + private boolean sessionEntrypoint() { + if (!mSessionActive && isEnabled() && + (mState == StatusBarState.KEYGUARD || mState == StatusBarState.SHADE_LOCKED)) { + onSessionStart(); + return true; + } + return false; + } + + private void sessionExitpoint() { + if (mSessionActive) { + mSessionActive = false; + mSensorManager.unregisterListener(this); + } + } + + private void onSessionStart() { + mBouncerOn = false; + mSessionActive = true; + for (int sensorType : SENSORS) { + Sensor s = mSensorManager.getDefaultSensor(sensorType); + if (s != null) { + mSensorManager.registerListener(this, s, SensorManager.SENSOR_DELAY_GAME); + } + } + } + + private boolean isEnabled() { + return mHumanInteractionClassifier.isEnabled() || mDataCollector.isEnabled(); + } + + /** + * @param type the type of action for which this method is called + * @return true if the classifier determined that this is not a human interacting with the phone + */ + public boolean isFalseTouch(int type) { + return mHumanInteractionClassifier.getFalseTouchEvaluation(type) > 0.5; + } + + @Override + public synchronized void onSensorChanged(SensorEvent event) { + mDataCollector.onSensorChanged(event); + mHumanInteractionClassifier.onSensorChanged(event); + } + + @Override + public void onAccuracyChanged(Sensor sensor, int accuracy) { + mDataCollector.onAccuracyChanged(sensor, accuracy); + } + + public boolean shouldEnforceBouncer() { + return mEnforceBouncer; + } + + public void setStatusBarState(int state) { + mState = state; + } + + public void onScreenTurningOn() { + if (sessionEntrypoint()) { + mDataCollector.onScreenTurningOn(); + } + } + + public void onScreenOnFromTouch() { + if (sessionEntrypoint()) { + mDataCollector.onScreenOnFromTouch(); + } + } + + public void onScreenOff() { + mDataCollector.onScreenOff(); + sessionExitpoint(); + } + + public void onSucccessfulUnlock() { + mDataCollector.onSucccessfulUnlock(); + sessionExitpoint(); + } + + public void onBouncerShown() { + if (!mBouncerOn) { + mBouncerOn = true; + mDataCollector.onBouncerShown(); + } + } + + public void onBouncerHidden() { + if (mBouncerOn) { + mBouncerOn = false; + mDataCollector.onBouncerHidden(); + } + } + + public void onQsDown() { + mDataCollector.onQsDown(); + } + + public void setQsExpanded(boolean expanded) { + mDataCollector.setQsExpanded(expanded); + } + + public void onTrackingStarted() { + mDataCollector.onTrackingStarted(); + } + + public void onTrackingStopped() { + mDataCollector.onTrackingStopped(); + } + + public void onNotificationActive() { + mDataCollector.onNotificationActive(); + } + + public void onNotificationDoubleTap() { + mDataCollector.onNotificationDoubleTap(); + } + + public void setNotificationExpanded() { + mDataCollector.setNotificationExpanded(); + } + + public void onNotificatonStartDraggingDown() { + mDataCollector.onNotificatonStartDraggingDown(); + } + + public void onNotificatonStopDraggingDown() { + mDataCollector.onNotificatonStopDraggingDown(); + } + + public void onNotificationDismissed() { + mDataCollector.onNotificationDismissed(); + } + + public void onNotificatonStartDismissing() { + mDataCollector.onNotificatonStartDismissing(); + } + + public void onNotificatonStopDismissing() { + mDataCollector.onNotificatonStopDismissing(); + } + + public void onCameraOn() { + mDataCollector.onCameraOn(); + } + + public void onLeftAffordanceOn() { + mDataCollector.onLeftAffordanceOn(); + } + + public void onAffordanceSwipingStarted(boolean rightCorner) { + mDataCollector.onAffordanceSwipingStarted(rightCorner); + } + + public void onAffordanceSwipingAborted() { + mDataCollector.onAffordanceSwipingAborted(); + } + + public void onUnlockHintStarted() { + mDataCollector.onUnlockHintStarted(); + } + + public void onCameraHintStarted() { + mDataCollector.onCameraHintStarted(); + } + + public void onLeftAffordanceHintStarted() { + mDataCollector.onLeftAffordanceHintStarted(); + } + + public void onTouchEvent(MotionEvent event, int width, int height) { + if (mSessionActive && !mBouncerOn) { + mDataCollector.onTouchEvent(event, width, height); + mHumanInteractionClassifier.onTouchEvent(event); + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/classifier/HumanInteractionClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/HumanInteractionClassifier.java new file mode 100644 index 000000000000..a5f6df858d2c --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/classifier/HumanInteractionClassifier.java @@ -0,0 +1,98 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.android.systemui.classifier; + +import android.content.Context; +import android.database.ContentObserver; +import android.hardware.SensorEvent; +import android.os.Build; +import android.os.Handler; +import android.os.UserHandle; +import android.provider.Settings; +import android.view.MotionEvent; + +/** + * An classifier trying to determine whether it is a human interacting with the phone or not. + */ +public class HumanInteractionClassifier extends Classifier { + private static final String HIC_ENABLE = "HIC_enable"; + private static HumanInteractionClassifier sInstance = null; + + private final Handler mHandler = new Handler(); + private final Context mContext; + + private AnglesVarianceClassifier mAnglesVarianceClassifier; + private boolean mEnableClassifier = false; + + protected final ContentObserver mSettingsObserver = new ContentObserver(mHandler) { + @Override + public void onChange(boolean selfChange) { + updateConfiguration(); + } + }; + + private HumanInteractionClassifier(Context context) { + mContext = context; + mClassifierData = new ClassifierData(); + mAnglesVarianceClassifier = new AnglesVarianceClassifier(mClassifierData); + + mContext.getContentResolver().registerContentObserver( + Settings.Global.getUriFor(HIC_ENABLE), false, + mSettingsObserver, + UserHandle.USER_ALL); + + updateConfiguration(); + } + + public static HumanInteractionClassifier getInstance(Context context) { + if (sInstance == null) { + sInstance = new HumanInteractionClassifier(context); + } + return sInstance; + } + + private void updateConfiguration() { + mEnableClassifier = Build.IS_DEBUGGABLE && 0 != Settings.Global.getInt( + mContext.getContentResolver(), + HIC_ENABLE, 0); + } + + @Override + public void onTouchEvent(MotionEvent event) { + if (mEnableClassifier) { + mClassifierData.update(event); + mAnglesVarianceClassifier.onTouchEvent(event); + mClassifierData.cleanUp(event); + } + } + + @Override + public void onSensorChanged(SensorEvent event) { + } + + @Override + public float getFalseTouchEvaluation(int type) { + if (mEnableClassifier) { + return mAnglesVarianceClassifier.getFalseTouchEvaluation(type); + } + return 0.0f; + } + + public boolean isEnabled() { + return mEnableClassifier; + } +} diff --git a/packages/SystemUI/src/com/android/systemui/classifier/Point.java b/packages/SystemUI/src/com/android/systemui/classifier/Point.java new file mode 100644 index 000000000000..e7dbae19eb31 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/classifier/Point.java @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.android.systemui.classifier; + +public class Point { + public float x; + public float y; + public long timeOffsetNano; + + public Point(float x, float y) { + this.x = x; + this.y = y; + this.timeOffsetNano = 0; + } + + public Point(float x, float y, long timeOffsetNano) { + this.x = x; + this.y = y; + this.timeOffsetNano = timeOffsetNano; + } + + public boolean equals(Point p) { + return x == p.x && y == p.y; + } + + public float dist(Point a) { + return (float) Math.hypot(a.x - x, a.y - y); + } + + /** + * Calculates the cross product of vec(this, a) and vec(this, b) where vec(x,y) is the + * vector from point x to point y + */ + public float crossProduct(Point a, Point b) { + return (a.x - x) * (b.y - y) - (a.y - y) * (b.x - x); + } + + /** + * Calculates the dot product of vec(this, a) and vec(this, b) where vec(x,y) is the + * vector from point x to point y + */ + public float dotProduct(Point a, Point b) { + return (a.x - x) * (b.x - x) + (a.y - y) * (b.y - y); + } +} diff --git a/packages/SystemUI/src/com/android/systemui/classifier/Stroke.java b/packages/SystemUI/src/com/android/systemui/classifier/Stroke.java new file mode 100644 index 000000000000..f386cbe458e6 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/classifier/Stroke.java @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.android.systemui.classifier; + +import java.util.ArrayList; + +/** + * Contains data about movement traces (pointers) + */ +public class Stroke { + private ArrayList<Point> mPoints = new ArrayList<>(); + private long mStartTimeNano; + private long mEndTimeNano; + + public Stroke(long eventTimeNano) { + mStartTimeNano = mEndTimeNano = eventTimeNano; + } + + public void addPoint(float x, float y, long eventTimeNano) { + mEndTimeNano = eventTimeNano; + mPoints.add(new Point(x, y, eventTimeNano - mStartTimeNano)); + } + + public ArrayList<Point> getPoints() { + return mPoints; + } +} diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java index 3514c5de0d09..84e5d09b3cb9 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java @@ -68,8 +68,8 @@ import com.android.keyguard.KeyguardUpdateMonitor; import com.android.keyguard.KeyguardUpdateMonitorCallback; import com.android.keyguard.ViewMediatorCallback; import com.android.systemui.SystemUI; +import com.android.systemui.classifier.FalsingManager; import com.android.systemui.statusbar.phone.FingerprintUnlockController; -import com.android.systemui.analytics.LockedPhoneAnalytics; import com.android.systemui.statusbar.phone.PhoneStatusBar; import com.android.systemui.statusbar.phone.ScrimController; import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager; @@ -1244,7 +1244,7 @@ public class KeyguardViewMediator extends SystemUI { case START_KEYGUARD_EXIT_ANIM: StartKeyguardExitAnimParams params = (StartKeyguardExitAnimParams) msg.obj; handleStartKeyguardExitAnimation(params.startTime, params.fadeoutDuration); - LockedPhoneAnalytics.getInstance(mContext).onSucccessfulUnlock(); + FalsingManager.getInstance(mContext).onSucccessfulUnlock(); break; case KEYGUARD_DONE_PENDING_TIMEOUT: Log.w(TAG, "Timeout while waiting for activity drawn!"); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java index c1dfec3f954b..2e3e00c1a4cf 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java @@ -34,7 +34,7 @@ import android.view.animation.LinearInterpolator; import android.view.animation.PathInterpolator; import com.android.systemui.R; -import com.android.systemui.analytics.LockedPhoneAnalytics; +import com.android.systemui.classifier.FalsingManager; /** * Base class for both {@link ExpandableNotificationRow} and {@link NotificationOverflowContainer} @@ -129,7 +129,7 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView private final int mNormalColor; private final int mLowPriorityColor; private boolean mIsBelowSpeedBump; - private LockedPhoneAnalytics mLockedPhoneAnalytics; + private FalsingManager mFalsingManager; public ActivatableNotificationView(Context context, AttributeSet attrs) { super(context, attrs); @@ -153,7 +153,7 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView R.color.notification_ripple_color_low_priority); mNormalRippleColor = context.getColor( R.color.notification_ripple_untinted_color); - mLockedPhoneAnalytics = LockedPhoneAnalytics.getInstance(context); + mFalsingManager = FalsingManager.getInstance(context); } @Override @@ -222,7 +222,7 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView makeActive(); postDelayed(mTapTimeoutRunnable, DOUBLETAP_TIMEOUT_MS); } else { - mLockedPhoneAnalytics.onNotificationDoubleTap(); + mFalsingManager.onNotificationDoubleTap(); boolean performed = performClick(); if (performed) { removeCallbacks(mTapTimeoutRunnable); @@ -242,7 +242,7 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView } private void makeActive() { - mLockedPhoneAnalytics.onNotificationActive(); + mFalsingManager.onNotificationActive(); startActivateAnimation(false /* reverse */); mActivated = true; if (mOnActivatedListener != null) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java index e2304c100517..d9127952a329 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java @@ -29,7 +29,7 @@ import android.view.animation.Interpolator; import com.android.systemui.ExpandHelper; import com.android.systemui.Gefingerpoken; import com.android.systemui.R; -import com.android.systemui.analytics.LockedPhoneAnalytics; +import com.android.systemui.classifier.FalsingManager; /** * A utility class to enable the downward swipe on the lockscreen to go to the full shade and expand @@ -55,7 +55,7 @@ public class DragDownHelper implements Gefingerpoken { private ExpandableView mStartingChild; private Interpolator mInterpolator; private float mLastHeight; - private LockedPhoneAnalytics mLockedPhoneAnalytics; + private FalsingManager mFalsingManager; public DragDownHelper(Context context, View host, ExpandHelper.Callback callback, DragDownCallback dragDownCallback) { @@ -67,7 +67,7 @@ public class DragDownHelper implements Gefingerpoken { mCallback = callback; mDragDownCallback = dragDownCallback; mHost = host; - mLockedPhoneAnalytics = LockedPhoneAnalytics.getInstance(context); + mFalsingManager = FalsingManager.getInstance(context); } @Override @@ -87,7 +87,7 @@ public class DragDownHelper implements Gefingerpoken { case MotionEvent.ACTION_MOVE: final float h = y - mInitialTouchY; if (h > mTouchSlop && h > Math.abs(x - mInitialTouchX)) { - mLockedPhoneAnalytics.onNotificatonStartDraggingDown(); + mFalsingManager.onNotificatonStartDraggingDown(); mDraggingDown = true; captureStartingChild(mInitialTouchX, mInitialTouchY); mInitialTouchY = y; @@ -205,7 +205,7 @@ public class DragDownHelper implements Gefingerpoken { } private void stopDragging() { - mLockedPhoneAnalytics.onNotificatonStopDraggingDown(); + mFalsingManager.onNotificatonStopDraggingDown(); if (mStartingChild != null) { cancelExpansion(mStartingChild); } else { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java index 564a60aaeb39..210be9fe3505 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java @@ -24,7 +24,6 @@ import android.graphics.drawable.AnimatedVectorDrawable; import android.graphics.drawable.AnimationDrawable; import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; -import android.graphics.drawable.RippleDrawable; import android.service.notification.StatusBarNotification; import android.util.AttributeSet; import android.view.MotionEvent; @@ -35,7 +34,7 @@ import android.view.animation.LinearInterpolator; import android.widget.ImageView; import com.android.systemui.R; -import com.android.systemui.analytics.LockedPhoneAnalytics; +import com.android.systemui.classifier.FalsingManager; import com.android.systemui.statusbar.phone.NotificationGroupManager; import com.android.systemui.statusbar.phone.PhoneStatusBar; import com.android.systemui.statusbar.stack.NotificationChildrenContainer; @@ -111,7 +110,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView { !mChildrenExpanded); } }; - private LockedPhoneAnalytics mLockedPhoneAnalytics; + private FalsingManager mFalsingManager; private boolean mJustClicked; @@ -327,7 +326,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView { public ExpandableNotificationRow(Context context, AttributeSet attrs) { super(context, attrs); - mLockedPhoneAnalytics = LockedPhoneAnalytics.getInstance(context); + mFalsingManager = FalsingManager.getInstance(context); } /** @@ -515,7 +514,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView { * @param userExpanded whether the user wants this notification to be expanded */ public void setUserExpanded(boolean userExpanded) { - mLockedPhoneAnalytics.setNotificationExpanded(); + mFalsingManager.setNotificationExpanded(); if (userExpanded && !mExpandable) return; final boolean wasExpanded = isExpanded(); mHasUserChangedExpansion = true; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java index cbd23bb90ac0..99436a19333d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java @@ -31,7 +31,7 @@ import com.android.keyguard.KeyguardUpdateMonitorCallback; import com.android.keyguard.R; import com.android.keyguard.ViewMediatorCallback; import com.android.systemui.DejankUtils; -import com.android.systemui.analytics.LockedPhoneAnalytics; +import com.android.systemui.classifier.FalsingManager; import static com.android.keyguard.KeyguardHostView.OnDismissAction; import static com.android.keyguard.KeyguardSecurityModel.SecurityMode; @@ -50,7 +50,7 @@ public class KeyguardBouncer { private ViewGroup mRoot; private boolean mShowingSoon; private int mBouncerPromptReason; - private LockedPhoneAnalytics mLockedPhoneAnalytics; + private FalsingManager mFalsingManager; private KeyguardUpdateMonitorCallback mUpdateMonitorCallback = new KeyguardUpdateMonitorCallback() { @Override @@ -68,11 +68,11 @@ public class KeyguardBouncer { mContainer = container; mWindowManager = windowManager; KeyguardUpdateMonitor.getInstance(mContext).registerCallback(mUpdateMonitorCallback); - mLockedPhoneAnalytics = LockedPhoneAnalytics.getInstance(mContext); + mFalsingManager = FalsingManager.getInstance(mContext); } public void show(boolean resetSecuritySelection) { - mLockedPhoneAnalytics.onBouncerShown(); + mFalsingManager.onBouncerShown(); ensureView(); if (resetSecuritySelection) { // showPrimarySecurityScreen() updates the current security method. This is needed in @@ -132,7 +132,7 @@ public class KeyguardBouncer { } public void hide(boolean destroyView) { - mLockedPhoneAnalytics.onBouncerHidden(); + mFalsingManager.onBouncerHidden(); cancelShowRunnable(); if (mKeyguardView != null) { mKeyguardView.cancelDismissAction(); @@ -162,7 +162,7 @@ public class KeyguardBouncer { public void reset() { cancelShowRunnable(); inflateView(); - mLockedPhoneAnalytics.onBouncerHidden(); + mFalsingManager.onBouncerHidden(); } public void onScreenTurnedOff() { @@ -250,7 +250,7 @@ public class KeyguardBouncer { // We need to show it in case it is secure. If not, it will get dismissed in any case. mRoot.setVisibility(View.VISIBLE); - mLockedPhoneAnalytics.onBouncerShown(); + mFalsingManager.onBouncerShown(); mKeyguardView.requestFocus(); mKeyguardView.onResume(); return true; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java index f47ec20e4246..980527b82666 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java @@ -22,7 +22,6 @@ import android.animation.ObjectAnimator; import android.animation.PropertyValuesHolder; import android.animation.ValueAnimator; import android.app.ActivityManager; -import android.app.ActivityManager.RunningTaskInfo; import android.content.Context; import android.content.pm.ResolveInfo; import android.content.res.Configuration; @@ -50,6 +49,7 @@ import com.android.systemui.DejankUtils; import com.android.systemui.EventLogConstants; import com.android.systemui.EventLogTags; import com.android.systemui.R; +import com.android.systemui.classifier.FalsingManager; import com.android.systemui.qs.QSContainer; import com.android.systemui.qs.QSPanel; import com.android.systemui.statusbar.ExpandableNotificationRow; @@ -59,7 +59,6 @@ import com.android.systemui.statusbar.GestureRecorder; import com.android.systemui.statusbar.KeyguardAffordanceView; import com.android.systemui.statusbar.NotificationData; import com.android.systemui.statusbar.StatusBarState; -import com.android.systemui.analytics.LockedPhoneAnalytics; import com.android.systemui.statusbar.policy.HeadsUpManager; import com.android.systemui.statusbar.policy.KeyguardUserSwitcher; import com.android.systemui.statusbar.stack.NotificationStackScrollLayout; @@ -204,7 +203,7 @@ public class NotificationPanelView extends PanelView implements private boolean mClosingWithAlphaFadeOut; private boolean mHeadsUpAnimatingAway; private boolean mLaunchingAffordance; - private LockedPhoneAnalytics mLockedPhoneAnalytics; + private FalsingManager mFalsingManager; private Runnable mHeadsUpExistenceChangedRunnable = new Runnable() { @Override @@ -221,7 +220,7 @@ public class NotificationPanelView extends PanelView implements public NotificationPanelView(Context context, AttributeSet attrs) { super(context, attrs); setWillNotDraw(!DEBUG); - mLockedPhoneAnalytics = LockedPhoneAnalytics.getInstance(context); + mFalsingManager = FalsingManager.getInstance(context); } public void setStatusBar(PhoneStatusBar bar) { @@ -813,7 +812,7 @@ public class NotificationPanelView extends PanelView implements private void handleQsDown(MotionEvent event) { if (event.getActionMasked() == MotionEvent.ACTION_DOWN && shouldQuickSettingsIntercept(event.getX(), event.getY(), -1)) { - mLockedPhoneAnalytics.onQsDown(); + mFalsingManager.onQsDown(); mQsTracking = true; onQsExpansionStarted(); mInitialHeightOnTouch = mQsExpansionHeight; @@ -981,7 +980,7 @@ public class NotificationPanelView extends PanelView implements mQsExpanded = expanded; updateQsState(); requestPanelHeightUpdate(); - mLockedPhoneAnalytics.setQsExpanded(expanded); + mFalsingManager.setQsExpanded(expanded); mNotificationStackScroller.setInterceptDelegateEnabled(expanded); mStatusBar.setQsExpanded(expanded); mQsPanel.setExpanded(expanded); @@ -1308,7 +1307,7 @@ public class NotificationPanelView extends PanelView implements R.string.accessibility_desc_quick_settings)); mLastAnnouncementWasQuickSettings = true; } - if (mQsFullyExpanded && mLockedPhoneAnalytics.shouldEnforceBouncer()) { + if (mQsFullyExpanded && mFalsingManager.shouldEnforceBouncer()) { mStatusBar.executeRunnableDismissingKeyguard(null, null /* cancelAction */, false /* dismissShade */, true /* afterKeyguardGone */); } @@ -1839,7 +1838,7 @@ public class NotificationPanelView extends PanelView implements @Override protected void onTrackingStarted() { - mLockedPhoneAnalytics.onTrackingStarted(); + mFalsingManager.onTrackingStarted(); super.onTrackingStarted(); if (mQsFullyExpanded) { mQsExpandImmediate = true; @@ -1853,7 +1852,7 @@ public class NotificationPanelView extends PanelView implements @Override protected void onTrackingStopped(boolean expand) { - mLockedPhoneAnalytics.onTrackingStopped(); + mFalsingManager.onTrackingStopped(); super.onTrackingStopped(expand); if (expand) { mNotificationStackScroller.setOverScrolledPixels( @@ -1953,8 +1952,8 @@ public class NotificationPanelView extends PanelView implements EventLogTags.writeSysuiLockscreenGesture( EventLogConstants.SYSUI_LOCKSCREEN_GESTURE_SWIPE_DIALER, lengthDp, velocityDp); - mLockedPhoneAnalytics.onLeftAffordanceOn(); - if (mLockedPhoneAnalytics.shouldEnforceBouncer()) { + mFalsingManager.onLeftAffordanceOn(); + if (mFalsingManager.shouldEnforceBouncer()) { mStatusBar.executeRunnableDismissingKeyguard(new Runnable() { @Override public void run() { @@ -1969,8 +1968,8 @@ public class NotificationPanelView extends PanelView implements EventLogTags.writeSysuiLockscreenGesture( EventLogConstants.SYSUI_LOCKSCREEN_GESTURE_SWIPE_CAMERA, lengthDp, velocityDp); - mLockedPhoneAnalytics.onCameraOn(); - if (mLockedPhoneAnalytics.shouldEnforceBouncer()) { + mFalsingManager.onCameraOn(); + if (mFalsingManager.shouldEnforceBouncer()) { mStatusBar.executeRunnableDismissingKeyguard(new Runnable() { @Override public void run() { @@ -2024,7 +2023,7 @@ public class NotificationPanelView extends PanelView implements @Override public void onSwipingStarted(boolean rightIcon) { - mLockedPhoneAnalytics.onAffordanceSwipingStarted(rightIcon); + mFalsingManager.onAffordanceSwipingStarted(rightIcon); boolean camera = getLayoutDirection() == LAYOUT_DIRECTION_RTL ? !rightIcon : rightIcon; if (camera) { @@ -2037,7 +2036,7 @@ public class NotificationPanelView extends PanelView implements @Override public void onSwipingAborted() { - mLockedPhoneAnalytics.onAffordanceSwipingAborted(); + mFalsingManager.onAffordanceSwipingAborted(); mKeyguardBottomArea.unbindCameraPrewarmService(false /* launched */); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java index 9cd6ea3ffd0d..13d0e1e0fbc3 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java @@ -35,6 +35,9 @@ import android.widget.FrameLayout; import com.android.systemui.EventLogConstants; import com.android.systemui.EventLogTags; import com.android.systemui.R; +import com.android.systemui.classifier.Classifier; +import com.android.systemui.classifier.FalsingManager; +import com.android.systemui.classifier.HumanInteractionClassifier; import com.android.systemui.doze.DozeLog; import com.android.systemui.statusbar.FlingAnimationUtils; import com.android.systemui.statusbar.StatusBarState; @@ -85,6 +88,7 @@ public abstract class PanelView extends FrameLayout { private ObjectAnimator mPeekAnimator; private VelocityTrackerInterface mVelocityTracker; private FlingAnimationUtils mFlingAnimationUtils; + private FalsingManager mFalsingManager; /** * Whether an instant expand request is currently pending and we are just waiting for layout. @@ -190,6 +194,7 @@ public abstract class PanelView extends FrameLayout { mLinearOutSlowInInterpolator = AnimationUtils.loadInterpolator(context, android.R.interpolator.linear_out_slow_in); mBounceInterpolator = new BounceInterpolator(); + mFalsingManager = FalsingManager.getInstance(context); } protected void loadDimens() { @@ -605,6 +610,9 @@ public abstract class PanelView extends FrameLayout { if (!mStatusBar.isFalsingThresholdNeeded()) { return false; } + if (mFalsingManager.isFalseTouch(Classifier.UNLOCK)) { + return true; + } if (!mTouchAboveFalsingThreshold) { return true; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java index 33ebfff70f5c..ca16567a9479 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java @@ -108,6 +108,7 @@ import com.android.systemui.EventLogConstants; import com.android.systemui.EventLogTags; import com.android.systemui.Prefs; import com.android.systemui.R; +import com.android.systemui.classifier.FalsingManager; import com.android.systemui.assist.AssistManager; import com.android.systemui.doze.DozeHost; import com.android.systemui.doze.DozeLog; @@ -131,7 +132,6 @@ import com.android.systemui.statusbar.ScrimView; import com.android.systemui.statusbar.SignalClusterView; import com.android.systemui.statusbar.SpeedBumpView; import com.android.systemui.statusbar.StatusBarState; -import com.android.systemui.analytics.LockedPhoneAnalytics; import com.android.systemui.statusbar.phone.UnlockMethodCache.OnUnlockMethodChangedListener; import com.android.systemui.statusbar.policy.AccessibilityController; import com.android.systemui.statusbar.policy.BatteryController; @@ -598,7 +598,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, private HashSet<Entry> mHeadsUpEntriesToRemoveOnSwitch = new HashSet<>(); private RankingMap mLatestRankingMap; private boolean mNoAnimationOnNextBarModeChange; - private LockedPhoneAnalytics mLockedPhoneAnalytics; + private FalsingManager mFalsingManager; @Override public void start() { @@ -646,7 +646,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, notifyUserAboutHiddenNotifications(); mScreenPinningRequest = new ScreenPinningRequest(mContext); - mLockedPhoneAnalytics = LockedPhoneAnalytics.getInstance(mContext); + mFalsingManager = FalsingManager.getInstance(mContext); } // ================================================================================ @@ -3805,7 +3805,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, } mState = state; mGroupManager.setStatusBarState(state); - mLockedPhoneAnalytics.setStatusBarState(state); + mFalsingManager.setStatusBarState(state); mStatusBarWindowManager.setStatusBarState(state); updateDozing(); } @@ -3827,7 +3827,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, } public void onUnlockHintStarted() { - mLockedPhoneAnalytics.onUnlockHintStarted(); + mFalsingManager.onUnlockHintStarted(); mKeyguardIndicationController.showTransientIndication(R.string.keyguard_unlock); } @@ -3837,17 +3837,17 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, } public void onCameraHintStarted() { - mLockedPhoneAnalytics.onCameraHintStarted(); + mFalsingManager.onCameraHintStarted(); mKeyguardIndicationController.showTransientIndication(R.string.camera_hint); } public void onVoiceAssistHintStarted() { - mLockedPhoneAnalytics.onLeftAffordanceHintStarted(); + mFalsingManager.onLeftAffordanceHintStarted(); mKeyguardIndicationController.showTransientIndication(R.string.voice_hint); } public void onPhoneHintStarted() { - mLockedPhoneAnalytics.onLeftAffordanceHintStarted(); + mFalsingManager.onLeftAffordanceHintStarted(); mKeyguardIndicationController.showTransientIndication(R.string.phone_hint); } @@ -3922,7 +3922,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, row.setUserExpanded(true); } boolean fullShadeNeedsBouncer = !userAllowsPrivateNotificationsInPublic(mCurrentUserId) - || !mShowLockscreenNotifications || mLockedPhoneAnalytics.shouldEnforceBouncer(); + || !mShowLockscreenNotifications || mFalsingManager.shouldEnforceBouncer(); if (isLockscreenPublicMode() && fullShadeNeedsBouncer) { mLeaveOpenOnKeyguardHide = true; showBouncer(); @@ -3970,7 +3970,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, mDeviceInteractive = false; mWakeUpComingFromTouch = false; mWakeUpTouchLocation = null; - mLockedPhoneAnalytics.onScreenOff(); + mFalsingManager.onScreenOff(); mStackScroller.setAnimationsEnabled(false); updateVisibleToUser(); } @@ -3980,11 +3980,11 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, mStackScroller.setAnimationsEnabled(true); mNotificationPanel.setTouchDisabled(false); updateVisibleToUser(); - mLockedPhoneAnalytics.onScreenOn(); } public void onScreenTurningOn() { mScreenTurningOn = true; + mFalsingManager.onScreenTurningOn(); mNotificationPanel.onScreenTurningOn(); if (mLaunchCameraOnScreenTurningOn) { mNotificationPanel.launchCamera(false); @@ -4119,7 +4119,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, mWakeUpTouchLocation = new PointF(event.getX(), event.getY()); mNotificationPanel.setTouchDisabled(false); mStatusBarKeyguardViewManager.notifyDeviceWakeUpRequested(); - mLockedPhoneAnalytics.onScreenOnFromTouch(); + mFalsingManager.onScreenOnFromTouch(); } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java index bbf981f3de4c..cfd33589588c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java @@ -36,10 +36,10 @@ import android.view.WindowManagerGlobal; import android.widget.FrameLayout; import com.android.systemui.R; +import com.android.systemui.classifier.FalsingManager; import com.android.systemui.statusbar.BaseStatusBar; import com.android.systemui.statusbar.DragDownHelper; import com.android.systemui.statusbar.StatusBarState; -import com.android.systemui.analytics.LockedPhoneAnalytics; import com.android.systemui.statusbar.stack.NotificationStackScrollLayout; @@ -56,14 +56,14 @@ public class StatusBarWindowView extends FrameLayout { private PhoneStatusBar mService; private final Paint mTransparentSrcPaint = new Paint(); - private LockedPhoneAnalytics mLockedPhoneAnalytics; + private FalsingManager mFalsingManager; public StatusBarWindowView(Context context, AttributeSet attrs) { super(context, attrs); setMotionEventSplittingEnabled(false); mTransparentSrcPaint.setColor(0); mTransparentSrcPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC)); - mLockedPhoneAnalytics = LockedPhoneAnalytics.getInstance(context); + mFalsingManager = FalsingManager.getInstance(context); } @Override @@ -200,7 +200,7 @@ public class StatusBarWindowView extends FrameLayout { @Override public boolean dispatchTouchEvent(MotionEvent ev) { - mLockedPhoneAnalytics.onTouchEvent(ev, getWidth(), getHeight()); + mFalsingManager.onTouchEvent(ev, getWidth(), getHeight()); if (mBrightnessMirror != null && mBrightnessMirror.getVisibility() == VISIBLE) { // Disallow new pointers while the brightness mirror is visible. This is so that you // can't touch anything other than the brightness slider while the mirror is showing diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java index 51c22081f46c..5e5f8108dfb8 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java @@ -37,6 +37,7 @@ import android.widget.OverScroller; import com.android.systemui.ExpandHelper; import com.android.systemui.R; import com.android.systemui.SwipeHelper; +import com.android.systemui.classifier.FalsingManager; import com.android.systemui.statusbar.ActivatableNotificationView; import com.android.systemui.statusbar.DismissView; import com.android.systemui.statusbar.EmptyShadeView; @@ -47,7 +48,6 @@ import com.android.systemui.statusbar.NotificationOverflowContainer; import com.android.systemui.statusbar.SpeedBumpView; import com.android.systemui.statusbar.StackScrollerDecorView; import com.android.systemui.statusbar.StatusBarState; -import com.android.systemui.analytics.LockedPhoneAnalytics; import com.android.systemui.statusbar.phone.NotificationGroupManager; import com.android.systemui.statusbar.phone.PhoneStatusBar; import com.android.systemui.statusbar.phone.ScrimController; @@ -232,7 +232,7 @@ public class NotificationStackScrollLayout extends ViewGroup private boolean mForceNoOverlappingRendering; private NotificationOverflowContainer mOverflowContainer; private final ArrayList<Pair<ExpandableNotificationRow, Boolean>> mTmpList = new ArrayList<>(); - private LockedPhoneAnalytics mLockedPhoneAnalytics; + private FalsingManager mFalsingManager; public NotificationStackScrollLayout(Context context) { this(context, null); @@ -266,7 +266,7 @@ public class NotificationStackScrollLayout extends ViewGroup mDebugPaint.setStrokeWidth(2); mDebugPaint.setStyle(Paint.Style.STROKE); } - mLockedPhoneAnalytics = LockedPhoneAnalytics.getInstance(context); + mFalsingManager = FalsingManager.getInstance(context); } @Override @@ -599,8 +599,8 @@ public class NotificationStackScrollLayout extends ViewGroup } if (DEBUG) Log.v(TAG, "onChildDismissed: " + v); - mLockedPhoneAnalytics.onNotificationDismissed(); - if (mLockedPhoneAnalytics.shouldEnforceBouncer()) { + mFalsingManager.onNotificationDismissed(); + if (mFalsingManager.shouldEnforceBouncer()) { mPhoneStatusBar.executeRunnableDismissingKeyguard(null, null /* cancelAction */, false /* dismissShade */, true /* afterKeyguardGone */); } @@ -631,7 +631,7 @@ public class NotificationStackScrollLayout extends ViewGroup } public void onBeginDrag(View v) { - mLockedPhoneAnalytics.onNotificatonStartDismissing(); + mFalsingManager.onNotificatonStartDismissing(); setSwipingInProgress(true); mAmbientState.onBeginDrag(v); if (mAnimationsEnabled && (mIsExpanded || !isPinnedHeadsUp(v))) { @@ -658,7 +658,7 @@ public class NotificationStackScrollLayout extends ViewGroup } public void onDragCancelled(View v) { - mLockedPhoneAnalytics.onNotificatonStopDismissing(); + mFalsingManager.onNotificatonStopDismissing(); setSwipingInProgress(false); } |