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 19bbb6919945180f76d5776858b1a49f910c8341d8Adrian Roosimport android.os.SystemClock; 20bbb6919945180f76d5776858b1a49f910c8341d8Adrian Roos 219f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowskiimport java.util.ArrayList; 229f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski 239f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski/** 249f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski * Holds the evaluations for ended strokes and gestures. These values are decreased through time. 259f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski */ 269f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowskipublic class HistoryEvaluator { 279f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski private static final float INTERVAL = 50.0f; 289f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski private static final float HISTORY_FACTOR = 0.9f; 299f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski private static final float EPSILON = 1e-5f; 309f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski 319f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski private final ArrayList<Data> mStrokes = new ArrayList<>(); 329f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski private final ArrayList<Data> mGestureWeights = new ArrayList<>(); 339f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski private long mLastUpdate; 349f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski 359f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski public HistoryEvaluator() { 36bbb6919945180f76d5776858b1a49f910c8341d8Adrian Roos mLastUpdate = SystemClock.elapsedRealtime(); 379f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski } 389f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski 399f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski public void addStroke(float evaluation) { 409f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski decayValue(); 419f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski mStrokes.add(new Data(evaluation)); 429f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski } 439f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski 449f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski public void addGesture(float evaluation) { 459f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski decayValue(); 469f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski mGestureWeights.add(new Data(evaluation)); 479f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski } 489f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski 499f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski /** 509f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski * Calculates the weighted average of strokes and adds to it the weighted average of gestures 519f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski */ 529f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski public float getEvaluation() { 539f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski return weightedAverage(mStrokes) + weightedAverage(mGestureWeights); 549f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski } 559f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski 569f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski private float weightedAverage(ArrayList<Data> list) { 579f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski float sumValue = 0.0f; 589f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski float sumWeight = 0.0f; 599f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski int size = list.size(); 609f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski for (int i = 0; i < size; i++) { 619f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski Data data = list.get(i); 629f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski sumValue += data.evaluation * data.weight; 639f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski sumWeight += data.weight; 649f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski } 659f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski 669f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski if (sumWeight == 0.0f) { 679f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski return 0.0f; 689f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski } 699f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski 709f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski return sumValue / sumWeight; 719f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski } 729f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski 739f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski private void decayValue() { 74bbb6919945180f76d5776858b1a49f910c8341d8Adrian Roos long time = SystemClock.elapsedRealtime(); 75bbb6919945180f76d5776858b1a49f910c8341d8Adrian Roos 76bbb6919945180f76d5776858b1a49f910c8341d8Adrian Roos if (time <= mLastUpdate) { 77bbb6919945180f76d5776858b1a49f910c8341d8Adrian Roos return; 78bbb6919945180f76d5776858b1a49f910c8341d8Adrian Roos } 799f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski 809f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski // All weights are multiplied by HISTORY_FACTOR after each INTERVAL milliseconds. 81bbb6919945180f76d5776858b1a49f910c8341d8Adrian Roos float factor = (float) Math.pow(HISTORY_FACTOR, (time - mLastUpdate) / INTERVAL); 829f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski 839f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski decayValue(mStrokes, factor); 849f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski decayValue(mGestureWeights, factor); 85bbb6919945180f76d5776858b1a49f910c8341d8Adrian Roos mLastUpdate = time; 869f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski } 879f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski 889f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski private void decayValue(ArrayList<Data> list, float factor) { 899f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski int size = list.size(); 909f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski for (int i = 0; i < size; i++) { 919f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski list.get(i).weight *= factor; 929f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski } 939f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski 949f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski // Removing evaluations with such small weights that they do not matter anymore 959f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski while (!list.isEmpty() && isZero(list.get(0).weight)) { 969f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski list.remove(0); 979f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski } 989f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski } 999f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski 1009f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski private boolean isZero(float x) { 1019f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski return x <= EPSILON && x >= -EPSILON; 1029f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski } 1039f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski 1049f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski /** 1059f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski * For each stroke it holds its initial value and the current weight. Initially the 1069f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski * weight is set to 1.0 1079f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski */ 10868d0c9b1e9f1df04b3a0e1ebb1e7ed4c18994cf3Blazej Magnowski private static class Data { 1099f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski public float evaluation; 1109f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski public float weight; 1119f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski 1129f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski public Data(float evaluation) { 1139f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski this.evaluation = evaluation; 1149f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski weight = 1.0f; 1159f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski } 1169f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski } 1179f01c5bfa5c1c63e350808c154adfc2953949b15Blazej Magnowski} 118