diff --git a/packages/SystemUI/src/com/android/systemui/classifier/AnglesVarianceClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/AnglesClassifier.java similarity index 62% rename from packages/SystemUI/src/com/android/systemui/classifier/AnglesVarianceClassifier.java rename to packages/SystemUI/src/com/android/systemui/classifier/AnglesClassifier.java index c74339b9082b0..a6ebc0bf0a9fb 100644 --- a/packages/SystemUI/src/com/android/systemui/classifier/AnglesVarianceClassifier.java +++ b/packages/SystemUI/src/com/android/systemui/classifier/AnglesClassifier.java @@ -32,17 +32,26 @@ import java.util.List; * 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. + * more strokes which are not smooth. + * + * This classifier also tries to split the stroke into two parts in 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. The classifier tries the tick option only if the first part is + * shorter than the second part. + * + * Additionally, the classifier classifies the angles as left angles (those angles which value is + * in [0.0, PI - ANGLE_DEVIATION) interval), straight angles + * ([PI - ANGLE_DEVIATION, PI + ANGLE_DEVIATION] interval) and right angles + * ((PI + ANGLE_DEVIATION, 2 * PI) interval) and then calculates the percentage of angles which are + * in the same direction (straight angles can be left angels or right angles) */ -public class AnglesVarianceClassifier extends StrokeClassifier { +public class AnglesClassifier extends StrokeClassifier { private HashMap mStrokeMap = new HashMap<>(); - public AnglesVarianceClassifier(ClassifierData classifierData) { + public AnglesClassifier(ClassifierData classifierData) { mClassifierData = classifierData; } @@ -66,10 +75,14 @@ public class AnglesVarianceClassifier extends StrokeClassifier { @Override public float getFalseTouchEvaluation(int type, Stroke stroke) { - return AnglesVarianceEvaluator.evaluate(mStrokeMap.get(stroke).getAnglesVariance()); + Data data = mStrokeMap.get(stroke); + return AnglesVarianceEvaluator.evaluate(data.getAnglesVariance()) + + AnglesPercentageEvaluator.evaluate(data.getAnglesPercentage()); } private static class Data { + private final float ANGLE_DEVIATION = (float) Math.PI / 20.0f; + private List mLastThreePoints = new ArrayList<>(); private float mFirstAngleVariance; private float mPreviousAngle; @@ -80,6 +93,12 @@ public class AnglesVarianceClassifier extends StrokeClassifier { private float mSecondSum; private float mCount; private float mSecondCount; + private float mFirstLength; + private float mLength; + private float mAnglesCount; + private float mLeftAngles; + private float mRightAngles; + private float mStraightAngles; public Data() { mFirstAngleVariance = 0.0f; @@ -88,6 +107,8 @@ public class AnglesVarianceClassifier extends StrokeClassifier { mSumSquares = mSecondSumSquares = 0.0f; mSum = mSecondSum = 0.0f; mCount = mSecondCount = 1.0f; + mLength = mFirstLength = 0.0f; + mAnglesCount = mLeftAngles = mRightAngles = mStraightAngles = 0.0f; } public void addPoint(Point point) { @@ -95,6 +116,9 @@ public class AnglesVarianceClassifier extends StrokeClassifier { // Repetitions are being ignored so that proper angles are calculated. if (mLastThreePoints.isEmpty() || !mLastThreePoints.get(mLastThreePoints.size() - 1).equals(point)) { + if (!mLastThreePoints.isEmpty()) { + mLength += mLastThreePoints.get(mLastThreePoints.size() - 1).dist(point); + } mLastThreePoints.add(point); if (mLastThreePoints.size() == 4) { mLastThreePoints.remove(0); @@ -102,6 +126,15 @@ public class AnglesVarianceClassifier extends StrokeClassifier { float angle = mLastThreePoints.get(1).getAngle(mLastThreePoints.get(0), mLastThreePoints.get(2)); + mAnglesCount++; + if (angle < Math.PI - ANGLE_DEVIATION) { + mLeftAngles++; + } else if (angle <= Math.PI + ANGLE_DEVIATION) { + mStraightAngles++; + } else { + mRightAngles++; + } + float difference = angle - mPreviousAngle; // If this is the biggest angle of the stroke so then we save the value of @@ -109,6 +142,7 @@ public class AnglesVarianceClassifier extends StrokeClassifier { // variance of the second part. if (mBiggestAngle < angle) { mBiggestAngle = angle; + mFirstLength = mLength; mFirstAngleVariance = getAnglesVariance(mSumSquares, mSum, mCount); mSecondSumSquares = 0.0f; mSecondSum = 0.0f; @@ -132,9 +166,19 @@ public class AnglesVarianceClassifier extends StrokeClassifier { } public float getAnglesVariance() { - return Math.min(getAnglesVariance(mSumSquares, mSum, mCount), - mFirstAngleVariance + getAnglesVariance(mSecondSumSquares, mSecondSum, - mSecondCount)); + float anglesVariance = getAnglesVariance(mSumSquares, mSum, mCount); + if (mFirstLength < mLength / 2f) { + anglesVariance = Math.min(anglesVariance, mFirstAngleVariance + + getAnglesVariance(mSecondSumSquares, mSecondSum, mSecondCount)); + } + return anglesVariance; + } + + public float getAnglesPercentage() { + if (mAnglesCount == 0.0f) { + return 1.0f; + } + return (Math.max(mLeftAngles, mRightAngles) + mStraightAngles) / mAnglesCount; } } } \ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/classifier/AnglesPercentageEvaluator.java b/packages/SystemUI/src/com/android/systemui/classifier/AnglesPercentageEvaluator.java new file mode 100644 index 0000000000000..a0ceb2958c330 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/classifier/AnglesPercentageEvaluator.java @@ -0,0 +1,27 @@ +/* + * 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 AnglesPercentageEvaluator { + public static float evaluate(float value) { + float evaluation = 0.0f; + if (value < 1.00) evaluation++; + if (value < 0.95) evaluation++; + if (value < 0.90) evaluation++; + return evaluation; + } +} diff --git a/packages/SystemUI/src/com/android/systemui/classifier/HumanInteractionClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/HumanInteractionClassifier.java index 0e45ac19469a6..7c8721c64a868 100644 --- a/packages/SystemUI/src/com/android/systemui/classifier/HumanInteractionClassifier.java +++ b/packages/SystemUI/src/com/android/systemui/classifier/HumanInteractionClassifier.java @@ -69,13 +69,13 @@ public class HumanInteractionClassifier extends Classifier { mClassifierData = new ClassifierData(mDpi); mHistoryEvaluator = new HistoryEvaluator(); - mStrokeClassifiers.add(new AnglesVarianceClassifier(mClassifierData)); + mStrokeClassifiers.add(new AnglesClassifier(mClassifierData)); mStrokeClassifiers.add(new SpeedClassifier(mClassifierData)); mStrokeClassifiers.add(new DurationCountClassifier(mClassifierData)); mStrokeClassifiers.add(new EndPointRatioClassifier(mClassifierData)); mStrokeClassifiers.add(new EndPointLengthClassifier(mClassifierData)); mStrokeClassifiers.add(new AccelerationClassifier(mClassifierData)); - mStrokeClassifiers.add(new SpeedVarianceClassifier(mClassifierData)); + mStrokeClassifiers.add(new SpeedAnglesClassifier(mClassifierData)); mStrokeClassifiers.add(new LengthCountClassifier(mClassifierData)); mGestureClassifiers.add(new PointerCountClassifier(mClassifierData)); diff --git a/packages/SystemUI/src/com/android/systemui/classifier/LengthCountClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/LengthCountClassifier.java index 1ea467bfb857d..cedf4676beec2 100644 --- a/packages/SystemUI/src/com/android/systemui/classifier/LengthCountClassifier.java +++ b/packages/SystemUI/src/com/android/systemui/classifier/LengthCountClassifier.java @@ -17,8 +17,11 @@ package com.android.systemui.classifier; /** - * A classifier which looks at the ratio between the duration of the stroke and its number of - * points. + * A classifier which looks at the ratio between the length of the stroke and its number of + * points. The number of points is subtracted by 2 because the UP event comes in with some delay + * and it should not influence the ratio and also strokes which are long and have a small number + * of points are punished more (these kind of strokes are usually bad ones and they tend to score + * well in other classifiers). */ public class LengthCountClassifier extends StrokeClassifier { public LengthCountClassifier(ClassifierData classifierData) { @@ -26,6 +29,7 @@ public class LengthCountClassifier extends StrokeClassifier { @Override public float getFalseTouchEvaluation(int type, Stroke stroke) { - return LengthCountEvaluator.evaluate(stroke.getTotalLength() / stroke.getCount()); + return LengthCountEvaluator.evaluate(stroke.getTotalLength() + / Math.max(1.0f, stroke.getCount() - 2)); } } \ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/classifier/LengthCountEvaluator.java b/packages/SystemUI/src/com/android/systemui/classifier/LengthCountEvaluator.java index 68f163d1916b4..dac7a6f720a77 100644 --- a/packages/SystemUI/src/com/android/systemui/classifier/LengthCountEvaluator.java +++ b/packages/SystemUI/src/com/android/systemui/classifier/LengthCountEvaluator.java @@ -23,10 +23,11 @@ package com.android.systemui.classifier; public class LengthCountEvaluator { public static float evaluate(float value) { float evaluation = 0.0f; - if (value < 0.07) evaluation++; + if (value < 0.09) evaluation++; if (value < 0.05) evaluation++; if (value < 0.02) evaluation++; if (value > 0.6) evaluation++; + if (value > 0.9) evaluation++; if (value > 1.2) evaluation++; return evaluation; } diff --git a/packages/SystemUI/src/com/android/systemui/classifier/SpeedVarianceClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/SpeedAnglesClassifier.java similarity index 75% rename from packages/SystemUI/src/com/android/systemui/classifier/SpeedVarianceClassifier.java rename to packages/SystemUI/src/com/android/systemui/classifier/SpeedAnglesClassifier.java index 9a30fe1a425c9..d544a3d68671f 100644 --- a/packages/SystemUI/src/com/android/systemui/classifier/SpeedVarianceClassifier.java +++ b/packages/SystemUI/src/com/android/systemui/classifier/SpeedAnglesClassifier.java @@ -28,14 +28,17 @@ import java.util.List; * A classifier which for each point from a stroke, it creates a point on plane with coordinates * (timeOffsetNano, distanceCoveredUpToThisPoint) (scaled by DURATION_SCALE and LENGTH_SCALE) * and then it calculates the angle variance of these points like the class - * {@link AnglesVarianceClassifier} (without splitting it into two parts). The classifier ignores + * {@link AnglesClassifier} (without splitting it into two parts). The classifier ignores * the last point of a stroke because the UP event comes in with some delay and this ruins the - * smoothness of this curve + * smoothness of this curve. Additionally, the classifier classifies calculates the percentage of + * angles which value is in [PI - ANGLE_DEVIATION, 2* PI) interval. The reason why the classifier + * does that is because the speed of a good stroke is most often increases, so most of these angels + * should be in this interval. */ -public class SpeedVarianceClassifier extends StrokeClassifier { +public class SpeedAnglesClassifier extends StrokeClassifier { private HashMap mStrokeMap = new HashMap<>(); - public SpeedVarianceClassifier(ClassifierData classifierData) { + public SpeedAnglesClassifier(ClassifierData classifierData) { mClassifierData = classifierData; } @@ -64,12 +67,15 @@ public class SpeedVarianceClassifier extends StrokeClassifier { @Override public float getFalseTouchEvaluation(int type, Stroke stroke) { - return SpeedVarianceEvaluator.evaluate(mStrokeMap.get(stroke).getAnglesVariance()); + Data data = mStrokeMap.get(stroke); + return SpeedVarianceEvaluator.evaluate(data.getAnglesVariance()) + + SpeedAnglesPercentageEvaluator.evaluate(data.getAnglesPercentage()); } private static class Data { private final float DURATION_SCALE = 1e8f; private final float LENGTH_SCALE = 1.0f; + private final float ANGLE_DEVIATION = (float) Math.PI / 10.0f; private List mLastThreePoints = new ArrayList<>(); private Point mPreviousPoint; @@ -78,6 +84,8 @@ public class SpeedVarianceClassifier extends StrokeClassifier { private float mSum; private float mCount; private float mDist; + private float mAnglesCount; + private float mAcceleratingAngles; public Data() { mPreviousPoint = null; @@ -86,6 +94,7 @@ public class SpeedVarianceClassifier extends StrokeClassifier { mSum = 0.0f; mCount = 1.0f; mDist = 0.0f; + mAnglesCount = mAcceleratingAngles = 0.0f; } public void addPoint(Point point) { @@ -108,6 +117,11 @@ public class SpeedVarianceClassifier extends StrokeClassifier { float angle = mLastThreePoints.get(1).getAngle(mLastThreePoints.get(0), mLastThreePoints.get(2)); + mAnglesCount++; + if (angle >= (float) Math.PI - ANGLE_DEVIATION) { + mAcceleratingAngles++; + } + float difference = angle - mPreviousAngle; mSum += difference; mSumSquares += difference * difference; @@ -120,5 +134,12 @@ public class SpeedVarianceClassifier extends StrokeClassifier { public float getAnglesVariance() { return mSumSquares / mCount - (mSum / mCount) * (mSum / mCount); } + + public float getAnglesPercentage() { + if (mAnglesCount == 0.0f) { + return 1.0f; + } + return (mAcceleratingAngles) / mAnglesCount; + } } } \ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/classifier/SpeedAnglesPercentageEvaluator.java b/packages/SystemUI/src/com/android/systemui/classifier/SpeedAnglesPercentageEvaluator.java new file mode 100644 index 0000000000000..2a45fa36dbc6a --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/classifier/SpeedAnglesPercentageEvaluator.java @@ -0,0 +1,27 @@ +/* + * 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 SpeedAnglesPercentageEvaluator { + public static float evaluate(float value) { + float evaluation = 0.0f; + if (value < 1.00) evaluation++; + if (value < 0.95) evaluation++; + if (value < 0.90) evaluation++; + return evaluation; + } +}