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