19f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski/*
29f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski * Copyright (C) 2015 The Android Open Source Project
39f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski *
49f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski * Licensed under the Apache License, Version 2.0 (the "License");
59f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski * you may not use this file except in compliance with the License.
69f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski * You may obtain a copy of the License at
79f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski *
89f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski *      http://www.apache.org/licenses/LICENSE-2.0
99f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski *
109f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski * Unless required by applicable law or agreed to in writing, software
119f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski * distributed under the License is distributed on an "AS IS" BASIS,
129f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
139f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski * See the License for the specific language governing permissions and
149f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski * limitations under the License
159f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski */
169f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski
179f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowskipackage com.android.systemui.classifier;
189f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski
199f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowskiimport java.util.ArrayList;
209f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski
219f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski/**
229f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski * Holds the evaluations for ended strokes and gestures. These values are decreased through time.
239f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski */
249f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowskipublic class HistoryEvaluator {
259f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski    private static final float INTERVAL = 50.0f;
269f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski    private static final float HISTORY_FACTOR = 0.9f;
279f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski    private static final float EPSILON = 1e-5f;
289f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski
299f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski    private final ArrayList<Data> mStrokes = new ArrayList<>();
309f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski    private final ArrayList<Data> mGestureWeights = new ArrayList<>();
319f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski    private long mLastUpdate;
329f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski
339f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski    public HistoryEvaluator() {
349f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski        mLastUpdate = System.currentTimeMillis();
359f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski    }
369f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski
379f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski    public void addStroke(float evaluation) {
389f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski        decayValue();
399f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski        mStrokes.add(new Data(evaluation));
409f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski    }
419f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski
429f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski    public void addGesture(float evaluation) {
439f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski        decayValue();
449f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski        mGestureWeights.add(new Data(evaluation));
459f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski    }
469f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski
479f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski    /**
489f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski     * Calculates the weighted average of strokes and adds to it the weighted average of gestures
499f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski     */
509f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski    public float getEvaluation() {
519f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski        return weightedAverage(mStrokes) + weightedAverage(mGestureWeights);
529f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski    }
539f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski
549f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski    private float weightedAverage(ArrayList<Data> list) {
559f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski        float sumValue = 0.0f;
569f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski        float sumWeight = 0.0f;
579f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski        int size = list.size();
589f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski        for (int i = 0; i < size; i++) {
599f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski            Data data = list.get(i);
609f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski            sumValue += data.evaluation * data.weight;
619f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski            sumWeight += data.weight;
629f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski        }
639f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski
649f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski        if (sumWeight == 0.0f) {
659f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski            return 0.0f;
669f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski        }
679f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski
689f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski        return sumValue / sumWeight;
699f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski    }
709f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski
719f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski    private void decayValue() {
729f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski        long currentTimeMillis = System.currentTimeMillis();
739f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski
749f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski        // All weights are multiplied by HISTORY_FACTOR after each INTERVAL milliseconds.
759f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski        float factor = (float) Math.pow(HISTORY_FACTOR,
769f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski                (float) (currentTimeMillis - mLastUpdate) / INTERVAL);
779f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski
789f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski        decayValue(mStrokes, factor);
799f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski        decayValue(mGestureWeights, factor);
809f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski        mLastUpdate = currentTimeMillis;
819f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski    }
829f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski
839f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski    private void decayValue(ArrayList<Data> list, float factor) {
849f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski        int size = list.size();
859f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski        for (int i = 0; i < size; i++) {
869f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski            list.get(i).weight *= factor;
879f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski        }
889f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski
899f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski        // Removing evaluations with such small weights that they do not matter anymore
909f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski        while (!list.isEmpty() && isZero(list.get(0).weight)) {
919f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski            list.remove(0);
929f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski        }
939f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski    }
949f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski
959f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski    private boolean isZero(float x) {
969f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski        return x <= EPSILON && x >= -EPSILON;
979f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski    }
989f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski
999f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski    /**
1009f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski     * For each stroke it holds its initial value and the current weight. Initially the
1019f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski     * weight is set to 1.0
1029f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski     */
10368d0c9b1e9f1df04b3a0e1ebb1e7ed4c18994cf3Blazej Magnowski    private static class Data {
1049f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski        public float evaluation;
1059f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski        public float weight;
1069f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski
1079f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski        public Data(float evaluation) {
1089f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski            this.evaluation = evaluation;
1099f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski            weight = 1.0f;
1109f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski        }
1119f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski    }
1129f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski}
113