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

Commit 9f01c5bf authored by Blazej Magnowski's avatar Blazej Magnowski
Browse files

Add HistoryEvaluator

Adds the possibility to store the evaluations for previous strokes and gestures.
Also and enables to take the history into account when classifying current
interatcions.

Change-Id: Ia8fa54a00daa80b4e5aebf11b11b568ed23165d4
parent 31cb4bb4
Loading
Loading
Loading
Loading
+11 −48
Original line number Diff line number Diff line
@@ -16,7 +16,6 @@

package com.android.systemui.classifier;

import android.hardware.SensorEvent;
import android.view.MotionEvent;

import java.lang.Math;
@@ -27,27 +26,19 @@ 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.
 * 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.
 */
public class AnglesVarianceClassifier extends Classifier {
    private final float INTERVAL = 10.0f;
    private final float CLEAR_HISTORY = 500f;
    private final float HISTORY_FACTOR = 0.9f;

public class AnglesVarianceClassifier extends StrokeClassifier {
    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
@@ -65,40 +56,12 @@ public class AnglesVarianceClassifier extends Classifier {
                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);
    public float getFalseTouchEvaluation(int type, Stroke stroke) {
        return mStrokeMap.get(stroke).getAnglesVariance();
    }

    private class Data {
@@ -150,7 +113,7 @@ public class AnglesVarianceClassifier extends Classifier {
        }

        public float getAnglesVariance() {
            return mSumSquares / mCount + (mSum / mCount) * (mSum / mCount);
            return mSumSquares / mCount - (mSum / mCount) * (mSum / mCount);
        }
    }
}
 No newline at end of file
+2 −8
Original line number Diff line number Diff line
@@ -20,7 +20,7 @@ import android.hardware.SensorEvent;
import android.view.MotionEvent;

/**
 * An interface for classifiers for touch and sensor events.
 * An abstract class for classifiers for touch and sensor events.
 */
public abstract class Classifier {
    public static final int QUICK_SETTINGS = 0;
@@ -30,6 +30,7 @@ public abstract class Classifier {
    public static final int UNLOCK = 4;
    public static final int LEFT_AFFORDANCE = 5;
    public static final int RIGHT_AFFORDANCE = 6;
    public static final int GENERIC = 7;

    /**
     * Contains all the information about touch events from which the classifier can query
@@ -47,11 +48,4 @@ public abstract class Classifier {
     */
    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);
}
+18 −0
Original line number Diff line number Diff line
@@ -19,21 +19,26 @@ package com.android.systemui.classifier;
import android.util.SparseArray;
import android.view.MotionEvent;

import java.util.ArrayList;

/**
 * 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<>();
    private ArrayList<Stroke> mEndingStrokes = new ArrayList<>();

    public ClassifierData() {
    }

    public void update(MotionEvent event) {
        mEndingStrokes.clear();
        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) {
@@ -41,10 +46,16 @@ public class ClassifierData {
            }
            mCurrentStrokes.get(id).addPoint(event.getX(i), event.getY(i),
                    event.getEventTimeNano());

            if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL
                    || (action == MotionEvent.ACTION_POINTER_UP && i == event.getActionIndex())) {
                mEndingStrokes.add(getStroke(id));
            }
        }
    }

    public void cleanUp(MotionEvent event) {
        mEndingStrokes.clear();
        int action = event.getActionMasked();
        for (int i = 0; i < event.getPointerCount(); i++) {
            int id = event.getPointerId(i);
@@ -55,6 +66,13 @@ public class ClassifierData {
        }
    }

    /**
     * @return the list of Strokes which are ending in the recently added MotionEvent
     */
    public ArrayList<Stroke> getEndingStrokes() {
        return mEndingStrokes;
    }

    /**
     * @param id the id from MotionEvent
     * @return the Stroke assigned to the id
+11 −3
Original line number Diff line number Diff line
@@ -126,11 +126,10 @@ public class FalsingManager implements SensorEventListener {
    }

    /**
     * @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;
    public boolean isFalseTouch() {
        return mHumanInteractionClassifier.isFalseTouch();
    }

    @Override
@@ -189,6 +188,7 @@ public class FalsingManager implements SensorEventListener {
    }

    public void onQsDown() {
        mHumanInteractionClassifier.setType(Classifier.QUICK_SETTINGS);
        mDataCollector.onQsDown();
    }

@@ -197,6 +197,7 @@ public class FalsingManager implements SensorEventListener {
    }

    public void onTrackingStarted() {
        mHumanInteractionClassifier.setType(Classifier.UNLOCK);
        mDataCollector.onTrackingStarted();
    }

@@ -217,6 +218,7 @@ public class FalsingManager implements SensorEventListener {
    }

    public void onNotificatonStartDraggingDown() {
        mHumanInteractionClassifier.setType(Classifier.NOTIFICATION_DRAG_DOWN);
        mDataCollector.onNotificatonStartDraggingDown();
    }

@@ -229,6 +231,7 @@ public class FalsingManager implements SensorEventListener {
    }

    public void onNotificatonStartDismissing() {
        mHumanInteractionClassifier.setType(Classifier.NOTIFICATION_DISMISS);
        mDataCollector.onNotificatonStartDismissing();
    }

@@ -245,6 +248,11 @@ public class FalsingManager implements SensorEventListener {
    }

    public void onAffordanceSwipingStarted(boolean rightCorner) {
        if (rightCorner) {
            mHumanInteractionClassifier.setType(Classifier.RIGHT_AFFORDANCE);
        } else {
            mHumanInteractionClassifier.setType(Classifier.LEFT_AFFORDANCE);
        }
        mDataCollector.onAffordanceSwipingStarted(rightCorner);
    }

+32 −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;

/**
 * An abstract class for classifiers which classify the whole gesture (all the strokes which
 * occurred from DOWN event to UP/CANCEL event)
 */
public abstract class GestureClassifier extends Classifier {

    /**
     * @param type the type of action for which this method is called
     * @return a non-negative value which is used to determine whether the most recent gesture is a
     *         false interaction. The bigger the value the greater the chance that this a false
     *         interaction.
     */
    public abstract float getFalseTouchEvaluation(int type);
}
Loading