Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 68d0c9b1 authored by Blazej Magnowski's avatar Blazej Magnowski
Browse files

added Classifiers and Evaluators

Change-Id: I9054c30cde665546de453e64572da619b1f6a799
parent 9f01c5bf
Loading
Loading
Loading
Loading
+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
+43 −22
Original line number Diff line number Diff line
@@ -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<>();
@@ -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) {
@@ -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;
@@ -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
+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;
    }
}
+6 −2
Original line number Diff line number Diff line
@@ -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) {
@@ -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());
+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