168d0c9b1e9f1df04b3a0e1ebb1e7ed4c18994cf3Blazej Magnowski/*
268d0c9b1e9f1df04b3a0e1ebb1e7ed4c18994cf3Blazej Magnowski * Copyright (C) 2015 The Android Open Source Project
368d0c9b1e9f1df04b3a0e1ebb1e7ed4c18994cf3Blazej Magnowski *
468d0c9b1e9f1df04b3a0e1ebb1e7ed4c18994cf3Blazej Magnowski * Licensed under the Apache License, Version 2.0 (the "License");
568d0c9b1e9f1df04b3a0e1ebb1e7ed4c18994cf3Blazej Magnowski * you may not use this file except in compliance with the License.
668d0c9b1e9f1df04b3a0e1ebb1e7ed4c18994cf3Blazej Magnowski * You may obtain a copy of the License at
768d0c9b1e9f1df04b3a0e1ebb1e7ed4c18994cf3Blazej Magnowski *
868d0c9b1e9f1df04b3a0e1ebb1e7ed4c18994cf3Blazej Magnowski *      http://www.apache.org/licenses/LICENSE-2.0
968d0c9b1e9f1df04b3a0e1ebb1e7ed4c18994cf3Blazej Magnowski *
1068d0c9b1e9f1df04b3a0e1ebb1e7ed4c18994cf3Blazej Magnowski * Unless required by applicable law or agreed to in writing, software
1168d0c9b1e9f1df04b3a0e1ebb1e7ed4c18994cf3Blazej Magnowski * distributed under the License is distributed on an "AS IS" BASIS,
1268d0c9b1e9f1df04b3a0e1ebb1e7ed4c18994cf3Blazej Magnowski * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1368d0c9b1e9f1df04b3a0e1ebb1e7ed4c18994cf3Blazej Magnowski * See the License for the specific language governing permissions and
1468d0c9b1e9f1df04b3a0e1ebb1e7ed4c18994cf3Blazej Magnowski * limitations under the License
1568d0c9b1e9f1df04b3a0e1ebb1e7ed4c18994cf3Blazej Magnowski */
1668d0c9b1e9f1df04b3a0e1ebb1e7ed4c18994cf3Blazej Magnowski
1768d0c9b1e9f1df04b3a0e1ebb1e7ed4c18994cf3Blazej Magnowskipackage com.android.systemui.classifier;
1868d0c9b1e9f1df04b3a0e1ebb1e7ed4c18994cf3Blazej Magnowski
1968d0c9b1e9f1df04b3a0e1ebb1e7ed4c18994cf3Blazej Magnowskiimport android.view.MotionEvent;
2068d0c9b1e9f1df04b3a0e1ebb1e7ed4c18994cf3Blazej Magnowski
2168d0c9b1e9f1df04b3a0e1ebb1e7ed4c18994cf3Blazej Magnowskiimport java.util.HashMap;
2268d0c9b1e9f1df04b3a0e1ebb1e7ed4c18994cf3Blazej Magnowski
2368d0c9b1e9f1df04b3a0e1ebb1e7ed4c18994cf3Blazej Magnowski/**
2468d0c9b1e9f1df04b3a0e1ebb1e7ed4c18994cf3Blazej Magnowski * A classifier which looks at the speed and distance between successive points of a Stroke.
2568d0c9b1e9f1df04b3a0e1ebb1e7ed4c18994cf3Blazej Magnowski * It looks at two consecutive speeds between two points and calculates the ratio between them.
2668d0c9b1e9f1df04b3a0e1ebb1e7ed4c18994cf3Blazej Magnowski * The final result is the maximum of these values. It does the same for distances. If some speed
2768d0c9b1e9f1df04b3a0e1ebb1e7ed4c18994cf3Blazej Magnowski * or distance is equal to zero then the ratio between this and the next part is not calculated. To
2868d0c9b1e9f1df04b3a0e1ebb1e7ed4c18994cf3Blazej Magnowski * the duration of each part there is added one nanosecond so that it is always possible to
2968d0c9b1e9f1df04b3a0e1ebb1e7ed4c18994cf3Blazej Magnowski * calculate the speed of a part.
3068d0c9b1e9f1df04b3a0e1ebb1e7ed4c18994cf3Blazej Magnowski */
3168d0c9b1e9f1df04b3a0e1ebb1e7ed4c18994cf3Blazej Magnowskipublic class AccelerationClassifier extends StrokeClassifier {
3268d0c9b1e9f1df04b3a0e1ebb1e7ed4c18994cf3Blazej Magnowski    private final HashMap<Stroke, Data> mStrokeMap = new HashMap<>();
3368d0c9b1e9f1df04b3a0e1ebb1e7ed4c18994cf3Blazej Magnowski
3468d0c9b1e9f1df04b3a0e1ebb1e7ed4c18994cf3Blazej Magnowski    public AccelerationClassifier(ClassifierData classifierData) {
3568d0c9b1e9f1df04b3a0e1ebb1e7ed4c18994cf3Blazej Magnowski        mClassifierData = classifierData;
3668d0c9b1e9f1df04b3a0e1ebb1e7ed4c18994cf3Blazej Magnowski    }
3768d0c9b1e9f1df04b3a0e1ebb1e7ed4c18994cf3Blazej Magnowski
3868d0c9b1e9f1df04b3a0e1ebb1e7ed4c18994cf3Blazej Magnowski    @Override
39401caaedd871894620accc1d14592c08095b5523Adrian Roos    public String getTag() {
40401caaedd871894620accc1d14592c08095b5523Adrian Roos        return "ACC";
41401caaedd871894620accc1d14592c08095b5523Adrian Roos    }
42401caaedd871894620accc1d14592c08095b5523Adrian Roos
43401caaedd871894620accc1d14592c08095b5523Adrian Roos    @Override
4468d0c9b1e9f1df04b3a0e1ebb1e7ed4c18994cf3Blazej Magnowski    public void onTouchEvent(MotionEvent event) {
4568d0c9b1e9f1df04b3a0e1ebb1e7ed4c18994cf3Blazej Magnowski        int action = event.getActionMasked();
4668d0c9b1e9f1df04b3a0e1ebb1e7ed4c18994cf3Blazej Magnowski
4768d0c9b1e9f1df04b3a0e1ebb1e7ed4c18994cf3Blazej Magnowski        if (action == MotionEvent.ACTION_DOWN) {
4868d0c9b1e9f1df04b3a0e1ebb1e7ed4c18994cf3Blazej Magnowski            mStrokeMap.clear();
4968d0c9b1e9f1df04b3a0e1ebb1e7ed4c18994cf3Blazej Magnowski        }
5068d0c9b1e9f1df04b3a0e1ebb1e7ed4c18994cf3Blazej Magnowski
5168d0c9b1e9f1df04b3a0e1ebb1e7ed4c18994cf3Blazej Magnowski        for (int i = 0; i < event.getPointerCount(); i++) {
5268d0c9b1e9f1df04b3a0e1ebb1e7ed4c18994cf3Blazej Magnowski            Stroke stroke = mClassifierData.getStroke(event.getPointerId(i));
5368d0c9b1e9f1df04b3a0e1ebb1e7ed4c18994cf3Blazej Magnowski            Point point = stroke.getPoints().get(stroke.getPoints().size() - 1);
5468d0c9b1e9f1df04b3a0e1ebb1e7ed4c18994cf3Blazej Magnowski            if (mStrokeMap.get(stroke) == null) {
5568d0c9b1e9f1df04b3a0e1ebb1e7ed4c18994cf3Blazej Magnowski                mStrokeMap.put(stroke, new Data(point));
5668d0c9b1e9f1df04b3a0e1ebb1e7ed4c18994cf3Blazej Magnowski            } else {
5768d0c9b1e9f1df04b3a0e1ebb1e7ed4c18994cf3Blazej Magnowski                mStrokeMap.get(stroke).addPoint(point);
5868d0c9b1e9f1df04b3a0e1ebb1e7ed4c18994cf3Blazej Magnowski            }
5968d0c9b1e9f1df04b3a0e1ebb1e7ed4c18994cf3Blazej Magnowski        }
6068d0c9b1e9f1df04b3a0e1ebb1e7ed4c18994cf3Blazej Magnowski    }
6168d0c9b1e9f1df04b3a0e1ebb1e7ed4c18994cf3Blazej Magnowski
6268d0c9b1e9f1df04b3a0e1ebb1e7ed4c18994cf3Blazej Magnowski    @Override
6368d0c9b1e9f1df04b3a0e1ebb1e7ed4c18994cf3Blazej Magnowski    public float getFalseTouchEvaluation(int type, Stroke stroke) {
6468d0c9b1e9f1df04b3a0e1ebb1e7ed4c18994cf3Blazej Magnowski        Data data = mStrokeMap.get(stroke);
6568d0c9b1e9f1df04b3a0e1ebb1e7ed4c18994cf3Blazej Magnowski        return SpeedRatioEvaluator.evaluate(data.maxSpeedRatio)
6668d0c9b1e9f1df04b3a0e1ebb1e7ed4c18994cf3Blazej Magnowski                + DistanceRatioEvaluator.evaluate(data.maxDistanceRatio);
6768d0c9b1e9f1df04b3a0e1ebb1e7ed4c18994cf3Blazej Magnowski    }
6868d0c9b1e9f1df04b3a0e1ebb1e7ed4c18994cf3Blazej Magnowski
6968d0c9b1e9f1df04b3a0e1ebb1e7ed4c18994cf3Blazej Magnowski    private static class Data {
7068d0c9b1e9f1df04b3a0e1ebb1e7ed4c18994cf3Blazej Magnowski        public Point previousPoint;
7168d0c9b1e9f1df04b3a0e1ebb1e7ed4c18994cf3Blazej Magnowski        public float previousSpeed;
7268d0c9b1e9f1df04b3a0e1ebb1e7ed4c18994cf3Blazej Magnowski        public float previousDistance;
7368d0c9b1e9f1df04b3a0e1ebb1e7ed4c18994cf3Blazej Magnowski        public float maxSpeedRatio;
7468d0c9b1e9f1df04b3a0e1ebb1e7ed4c18994cf3Blazej Magnowski        public float maxDistanceRatio;
7568d0c9b1e9f1df04b3a0e1ebb1e7ed4c18994cf3Blazej Magnowski
7668d0c9b1e9f1df04b3a0e1ebb1e7ed4c18994cf3Blazej Magnowski        public Data(Point point) {
7768d0c9b1e9f1df04b3a0e1ebb1e7ed4c18994cf3Blazej Magnowski            previousPoint = point;
7868d0c9b1e9f1df04b3a0e1ebb1e7ed4c18994cf3Blazej Magnowski            previousSpeed = previousDistance = 0.0f;
7968d0c9b1e9f1df04b3a0e1ebb1e7ed4c18994cf3Blazej Magnowski            maxDistanceRatio = maxSpeedRatio = 0.0f;
8068d0c9b1e9f1df04b3a0e1ebb1e7ed4c18994cf3Blazej Magnowski        }
8168d0c9b1e9f1df04b3a0e1ebb1e7ed4c18994cf3Blazej Magnowski
8268d0c9b1e9f1df04b3a0e1ebb1e7ed4c18994cf3Blazej Magnowski        public void addPoint(Point point) {
8368d0c9b1e9f1df04b3a0e1ebb1e7ed4c18994cf3Blazej Magnowski            float distance = previousPoint.dist(point);
8468d0c9b1e9f1df04b3a0e1ebb1e7ed4c18994cf3Blazej Magnowski            float duration = (float) (point.timeOffsetNano - previousPoint.timeOffsetNano + 1);
8568d0c9b1e9f1df04b3a0e1ebb1e7ed4c18994cf3Blazej Magnowski            float speed = distance / duration;
8668d0c9b1e9f1df04b3a0e1ebb1e7ed4c18994cf3Blazej Magnowski            if (previousDistance != 0.0f) {
8768d0c9b1e9f1df04b3a0e1ebb1e7ed4c18994cf3Blazej Magnowski                maxDistanceRatio = Math.max(maxDistanceRatio, distance / previousDistance);
8868d0c9b1e9f1df04b3a0e1ebb1e7ed4c18994cf3Blazej Magnowski            }
8968d0c9b1e9f1df04b3a0e1ebb1e7ed4c18994cf3Blazej Magnowski
9068d0c9b1e9f1df04b3a0e1ebb1e7ed4c18994cf3Blazej Magnowski            if (previousSpeed != 0.0f) {
9168d0c9b1e9f1df04b3a0e1ebb1e7ed4c18994cf3Blazej Magnowski                maxSpeedRatio = Math.max(maxSpeedRatio, speed / previousSpeed);
9268d0c9b1e9f1df04b3a0e1ebb1e7ed4c18994cf3Blazej Magnowski            }
9368d0c9b1e9f1df04b3a0e1ebb1e7ed4c18994cf3Blazej Magnowski
9468d0c9b1e9f1df04b3a0e1ebb1e7ed4c18994cf3Blazej Magnowski            previousDistance = distance;
9568d0c9b1e9f1df04b3a0e1ebb1e7ed4c18994cf3Blazej Magnowski            previousSpeed = speed;
9668d0c9b1e9f1df04b3a0e1ebb1e7ed4c18994cf3Blazej Magnowski            previousPoint = point;
9768d0c9b1e9f1df04b3a0e1ebb1e7ed4c18994cf3Blazej Magnowski        }
9868d0c9b1e9f1df04b3a0e1ebb1e7ed4c18994cf3Blazej Magnowski    }
9968d0c9b1e9f1df04b3a0e1ebb1e7ed4c18994cf3Blazej Magnowski}