Loading packages/SystemUI/src/com/android/systemui/classifier/AccelerationClassifier.java 0 → 100644 +94 −0 Original line number Diff line number Diff line /* * 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.view.MotionEvent; import java.util.HashMap; /** * A classifier which looks at the speed and distance between successive points of a Stroke. * It looks at two consecutive speeds between two points and calculates the ratio between them. * The final result is the maximum of these values. It does the same for distances. If some speed * or distance is equal to zero then the ratio between this and the next part is not calculated. To * the duration of each part there is added one nanosecond so that it is always possible to * calculate the speed of a part. */ public class AccelerationClassifier extends StrokeClassifier { private final HashMap<Stroke, Data> mStrokeMap = new HashMap<>(); public AccelerationClassifier(ClassifierData classifierData) { mClassifierData = classifierData; } @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)); Point point = stroke.getPoints().get(stroke.getPoints().size() - 1); if (mStrokeMap.get(stroke) == null) { mStrokeMap.put(stroke, new Data(point)); } else { mStrokeMap.get(stroke).addPoint(point); } } } @Override public float getFalseTouchEvaluation(int type, Stroke stroke) { Data data = mStrokeMap.get(stroke); return SpeedRatioEvaluator.evaluate(data.maxSpeedRatio) + DistanceRatioEvaluator.evaluate(data.maxDistanceRatio); } private static class Data { public Point previousPoint; public float previousSpeed; public float previousDistance; public float maxSpeedRatio; public float maxDistanceRatio; public Data(Point point) { previousPoint = point; previousSpeed = previousDistance = 0.0f; maxDistanceRatio = maxSpeedRatio = 0.0f; } public void addPoint(Point point) { float distance = previousPoint.dist(point); float duration = (float) (point.timeOffsetNano - previousPoint.timeOffsetNano + 1); float speed = distance / duration; if (previousDistance != 0.0f) { maxDistanceRatio = Math.max(maxDistanceRatio, distance / previousDistance); } if (previousSpeed != 0.0f) { maxSpeedRatio = Math.max(maxSpeedRatio, speed / previousSpeed); } previousDistance = distance; previousSpeed = speed; previousPoint = point; } } } No newline at end of file packages/SystemUI/src/com/android/systemui/classifier/AnglesVarianceClassifier.java +43 −22 Original line number Diff line number Diff line Loading @@ -29,10 +29,15 @@ import java.util.List; * 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. To the differences there is artificially added value 0.0 and the * difference between the first angle and PI (angles are in radians). It helps with strokes which * have few points and punishes more strokes which are not smooth. * previously calculated angle. Then it calculates the variance of the differences from a stroke. * To the differences there is artificially added value 0.0 and the difference between the first * angle and PI (angles are in radians). It helps with strokes which have few points and punishes * more strokes which are not smooth. This classifier also tries to split the stroke into two parts * int the place in which the biggest angle is. It calculates the angle variance of the two parts * and sums them up. The reason the classifier is doing this, is because some human swipes at the * beginning go for a moment in one direction and then they rapidly change direction for the rest * of the stroke (like a tick). The final result is the minimum of angle variance of the whole * stroke and the sum of angle variances of the two parts split up. */ public class AnglesVarianceClassifier extends StrokeClassifier { private HashMap<Stroke, Data> mStrokeMap = new HashMap<>(); Loading Loading @@ -61,21 +66,28 @@ public class AnglesVarianceClassifier extends StrokeClassifier { @Override public float getFalseTouchEvaluation(int type, Stroke stroke) { return mStrokeMap.get(stroke).getAnglesVariance(); return AnglesVarianceEvaluator.evaluate(mStrokeMap.get(stroke).getAnglesVariance()); } private class Data { private static class Data { private List<Point> mLastThreePoints = new ArrayList<>(); private float mFirstAngleVariance; private float mPreviousAngle; private float mBiggestAngle; private float mSumSquares; private float mSecondSumSquares; private float mSum; private float mSecondSum; private float mCount; private float mSecondCount; public Data() { mFirstAngleVariance = 0.0f; mPreviousAngle = (float) Math.PI; mSumSquares = 0.0f; mSum = 0.0f; mCount = 1.0f; mBiggestAngle = 0.0f; mSumSquares = mSecondSumSquares = 0.0f; mSum = mSecondSum = 0.0f; mCount = mSecondCount = 1.0f; } public void addPoint(Point point) { Loading @@ -87,10 +99,26 @@ public class AnglesVarianceClassifier extends StrokeClassifier { if (mLastThreePoints.size() == 4) { mLastThreePoints.remove(0); float angle = getAngle(mLastThreePoints.get(0), mLastThreePoints.get(1), float angle = mLastThreePoints.get(1).getAngle(mLastThreePoints.get(0), mLastThreePoints.get(2)); float difference = angle - mPreviousAngle; // If this is the biggest angle of the stroke so then we save the value of // the angle variance so far and start to count the values for the angle // variance of the second part. if (mBiggestAngle < angle) { mBiggestAngle = angle; mFirstAngleVariance = getAnglesVariance(mSumSquares, mSum, mCount); mSecondSumSquares = 0.0f; mSecondSum = 0.0f; mSecondCount = 1.0f; } else { mSecondSum += difference; mSecondSumSquares += difference * difference; mSecondCount += 1.0; } mSum += difference; mSumSquares += difference * difference; mCount += 1.0; Loading @@ -99,21 +127,14 @@ public class AnglesVarianceClassifier extends StrokeClassifier { } } 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(float sumSquares, float sum, float count) { return sumSquares / count - (sum / count) * (sum / count); } public float getAnglesVariance() { return mSumSquares / mCount - (mSum / mCount) * (mSum / mCount); return Math.min(getAnglesVariance(mSumSquares, mSum, mCount), mFirstAngleVariance + getAnglesVariance(mSecondSumSquares, mSecondSum, mSecondCount)); } } } No newline at end of file packages/SystemUI/src/com/android/systemui/classifier/AnglesVarianceEvaluator.java 0 → 100644 +30 −0 Original line number Diff line number Diff line /* * 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 AnglesVarianceEvaluator { public static float evaluate(float value) { float evaluation = 0.0f; if (value > 0.05) evaluation++; if (value > 0.10) evaluation++; if (value > 0.20) evaluation++; if (value > 0.40) evaluation++; if (value > 0.80) evaluation++; if (value > 1.50) evaluation++; return evaluation; } } packages/SystemUI/src/com/android/systemui/classifier/ClassifierData.java +6 −2 Original line number Diff line number Diff line Loading @@ -28,8 +28,12 @@ import java.util.ArrayList; public class ClassifierData { private SparseArray<Stroke> mCurrentStrokes = new SparseArray<>(); private ArrayList<Stroke> mEndingStrokes = new ArrayList<>(); private float mXdpi; private float mYdpi; public ClassifierData() { public ClassifierData(float xdpi, float ydpi) { mXdpi = xdpi; mYdpi = ydpi; } public void update(MotionEvent event) { Loading @@ -42,7 +46,7 @@ public class ClassifierData { 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.put(id, new Stroke(event.getEventTimeNano(), mXdpi, mYdpi)); } mCurrentStrokes.get(id).addPoint(event.getX(i), event.getY(i), event.getEventTimeNano()); Loading packages/SystemUI/src/com/android/systemui/classifier/DistanceRatioEvaluator.java 0 → 100644 +29 −0 Original line number Diff line number Diff line /* * 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 DistanceRatioEvaluator { public static float evaluate(float value) { float evaluation = 0.0f; if (value <= 1.0) evaluation++; if (value <= 0.5) evaluation++; if (value > 4.0) evaluation++; if (value > 7.0) evaluation++; if (value > 14.0) evaluation++; return evaluation; } } Loading
packages/SystemUI/src/com/android/systemui/classifier/AccelerationClassifier.java 0 → 100644 +94 −0 Original line number Diff line number Diff line /* * 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.view.MotionEvent; import java.util.HashMap; /** * A classifier which looks at the speed and distance between successive points of a Stroke. * It looks at two consecutive speeds between two points and calculates the ratio between them. * The final result is the maximum of these values. It does the same for distances. If some speed * or distance is equal to zero then the ratio between this and the next part is not calculated. To * the duration of each part there is added one nanosecond so that it is always possible to * calculate the speed of a part. */ public class AccelerationClassifier extends StrokeClassifier { private final HashMap<Stroke, Data> mStrokeMap = new HashMap<>(); public AccelerationClassifier(ClassifierData classifierData) { mClassifierData = classifierData; } @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)); Point point = stroke.getPoints().get(stroke.getPoints().size() - 1); if (mStrokeMap.get(stroke) == null) { mStrokeMap.put(stroke, new Data(point)); } else { mStrokeMap.get(stroke).addPoint(point); } } } @Override public float getFalseTouchEvaluation(int type, Stroke stroke) { Data data = mStrokeMap.get(stroke); return SpeedRatioEvaluator.evaluate(data.maxSpeedRatio) + DistanceRatioEvaluator.evaluate(data.maxDistanceRatio); } private static class Data { public Point previousPoint; public float previousSpeed; public float previousDistance; public float maxSpeedRatio; public float maxDistanceRatio; public Data(Point point) { previousPoint = point; previousSpeed = previousDistance = 0.0f; maxDistanceRatio = maxSpeedRatio = 0.0f; } public void addPoint(Point point) { float distance = previousPoint.dist(point); float duration = (float) (point.timeOffsetNano - previousPoint.timeOffsetNano + 1); float speed = distance / duration; if (previousDistance != 0.0f) { maxDistanceRatio = Math.max(maxDistanceRatio, distance / previousDistance); } if (previousSpeed != 0.0f) { maxSpeedRatio = Math.max(maxSpeedRatio, speed / previousSpeed); } previousDistance = distance; previousSpeed = speed; previousPoint = point; } } } No newline at end of file
packages/SystemUI/src/com/android/systemui/classifier/AnglesVarianceClassifier.java +43 −22 Original line number Diff line number Diff line Loading @@ -29,10 +29,15 @@ import java.util.List; * 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. To the differences there is artificially added value 0.0 and the * difference between the first angle and PI (angles are in radians). It helps with strokes which * have few points and punishes more strokes which are not smooth. * previously calculated angle. Then it calculates the variance of the differences from a stroke. * To the differences there is artificially added value 0.0 and the difference between the first * angle and PI (angles are in radians). It helps with strokes which have few points and punishes * more strokes which are not smooth. This classifier also tries to split the stroke into two parts * int the place in which the biggest angle is. It calculates the angle variance of the two parts * and sums them up. The reason the classifier is doing this, is because some human swipes at the * beginning go for a moment in one direction and then they rapidly change direction for the rest * of the stroke (like a tick). The final result is the minimum of angle variance of the whole * stroke and the sum of angle variances of the two parts split up. */ public class AnglesVarianceClassifier extends StrokeClassifier { private HashMap<Stroke, Data> mStrokeMap = new HashMap<>(); Loading Loading @@ -61,21 +66,28 @@ public class AnglesVarianceClassifier extends StrokeClassifier { @Override public float getFalseTouchEvaluation(int type, Stroke stroke) { return mStrokeMap.get(stroke).getAnglesVariance(); return AnglesVarianceEvaluator.evaluate(mStrokeMap.get(stroke).getAnglesVariance()); } private class Data { private static class Data { private List<Point> mLastThreePoints = new ArrayList<>(); private float mFirstAngleVariance; private float mPreviousAngle; private float mBiggestAngle; private float mSumSquares; private float mSecondSumSquares; private float mSum; private float mSecondSum; private float mCount; private float mSecondCount; public Data() { mFirstAngleVariance = 0.0f; mPreviousAngle = (float) Math.PI; mSumSquares = 0.0f; mSum = 0.0f; mCount = 1.0f; mBiggestAngle = 0.0f; mSumSquares = mSecondSumSquares = 0.0f; mSum = mSecondSum = 0.0f; mCount = mSecondCount = 1.0f; } public void addPoint(Point point) { Loading @@ -87,10 +99,26 @@ public class AnglesVarianceClassifier extends StrokeClassifier { if (mLastThreePoints.size() == 4) { mLastThreePoints.remove(0); float angle = getAngle(mLastThreePoints.get(0), mLastThreePoints.get(1), float angle = mLastThreePoints.get(1).getAngle(mLastThreePoints.get(0), mLastThreePoints.get(2)); float difference = angle - mPreviousAngle; // If this is the biggest angle of the stroke so then we save the value of // the angle variance so far and start to count the values for the angle // variance of the second part. if (mBiggestAngle < angle) { mBiggestAngle = angle; mFirstAngleVariance = getAnglesVariance(mSumSquares, mSum, mCount); mSecondSumSquares = 0.0f; mSecondSum = 0.0f; mSecondCount = 1.0f; } else { mSecondSum += difference; mSecondSumSquares += difference * difference; mSecondCount += 1.0; } mSum += difference; mSumSquares += difference * difference; mCount += 1.0; Loading @@ -99,21 +127,14 @@ public class AnglesVarianceClassifier extends StrokeClassifier { } } 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(float sumSquares, float sum, float count) { return sumSquares / count - (sum / count) * (sum / count); } public float getAnglesVariance() { return mSumSquares / mCount - (mSum / mCount) * (mSum / mCount); return Math.min(getAnglesVariance(mSumSquares, mSum, mCount), mFirstAngleVariance + getAnglesVariance(mSecondSumSquares, mSecondSum, mSecondCount)); } } } No newline at end of file
packages/SystemUI/src/com/android/systemui/classifier/AnglesVarianceEvaluator.java 0 → 100644 +30 −0 Original line number Diff line number Diff line /* * 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 AnglesVarianceEvaluator { public static float evaluate(float value) { float evaluation = 0.0f; if (value > 0.05) evaluation++; if (value > 0.10) evaluation++; if (value > 0.20) evaluation++; if (value > 0.40) evaluation++; if (value > 0.80) evaluation++; if (value > 1.50) evaluation++; return evaluation; } }
packages/SystemUI/src/com/android/systemui/classifier/ClassifierData.java +6 −2 Original line number Diff line number Diff line Loading @@ -28,8 +28,12 @@ import java.util.ArrayList; public class ClassifierData { private SparseArray<Stroke> mCurrentStrokes = new SparseArray<>(); private ArrayList<Stroke> mEndingStrokes = new ArrayList<>(); private float mXdpi; private float mYdpi; public ClassifierData() { public ClassifierData(float xdpi, float ydpi) { mXdpi = xdpi; mYdpi = ydpi; } public void update(MotionEvent event) { Loading @@ -42,7 +46,7 @@ public class ClassifierData { 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.put(id, new Stroke(event.getEventTimeNano(), mXdpi, mYdpi)); } mCurrentStrokes.get(id).addPoint(event.getX(i), event.getY(i), event.getEventTimeNano()); Loading
packages/SystemUI/src/com/android/systemui/classifier/DistanceRatioEvaluator.java 0 → 100644 +29 −0 Original line number Diff line number Diff line /* * 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 DistanceRatioEvaluator { public static float evaluate(float value) { float evaluation = 0.0f; if (value <= 1.0) evaluation++; if (value <= 0.5) evaluation++; if (value > 4.0) evaluation++; if (value > 7.0) evaluation++; if (value > 14.0) evaluation++; return evaluation; } }