1 /* 2 * Copyright (C) 2015 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License 15 */ 16 17 package com.android.systemui.classifier; 18 19 import android.util.SparseArray; 20 import android.view.MotionEvent; 21 22 import java.util.ArrayList; 23 24 /** 25 * Contains data which is used to classify interaction sequences on the lockscreen. It does, for 26 * example, provide information on the current touch state. 27 */ 28 public class ClassifierData { 29 private static final long MINIMUM_DT_NANOS = 16666666; // 60Hz 30 private static final long MINIMUM_DT_SMEAR_NANOS = 2500000; // 2.5ms 31 32 private SparseArray<Stroke> mCurrentStrokes = new SparseArray<>(); 33 private ArrayList<Stroke> mEndingStrokes = new ArrayList<>(); 34 private final float mDpi; 35 ClassifierData(float dpi)36 public ClassifierData(float dpi) { 37 mDpi = dpi; 38 } 39 40 /** Returns true if the event should be considered, false otherwise. */ update(MotionEvent event)41 public boolean update(MotionEvent event) { 42 // We limit to 60hz sampling. Drop anything happening faster than that. 43 // Legacy code was created with an assumed sampling rate. As devices increase their 44 // sampling rate, this creates potentialy false positives. 45 if (event.getActionMasked() == MotionEvent.ACTION_MOVE 46 && mCurrentStrokes.size() != 0 47 && event.getEventTimeNano() - mCurrentStrokes.valueAt(0).getLastEventTimeNano() 48 < MINIMUM_DT_NANOS - MINIMUM_DT_SMEAR_NANOS) { 49 return false; 50 } 51 52 mEndingStrokes.clear(); 53 int action = event.getActionMasked(); 54 if (action == MotionEvent.ACTION_DOWN) { 55 mCurrentStrokes.clear(); 56 } 57 58 for (int i = 0; i < event.getPointerCount(); i++) { 59 int id = event.getPointerId(i); 60 if (mCurrentStrokes.get(id) == null) { 61 mCurrentStrokes.put(id, new Stroke(event.getEventTimeNano(), mDpi)); 62 } 63 mCurrentStrokes.get(id).addPoint(event.getX(i), event.getY(i), 64 event.getEventTimeNano()); 65 66 if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL 67 || (action == MotionEvent.ACTION_POINTER_UP && i == event.getActionIndex())) { 68 mEndingStrokes.add(getStroke(id)); 69 } 70 } 71 72 return true; 73 } 74 cleanUp(MotionEvent event)75 public void cleanUp(MotionEvent event) { 76 mEndingStrokes.clear(); 77 int action = event.getActionMasked(); 78 for (int i = 0; i < event.getPointerCount(); i++) { 79 int id = event.getPointerId(i); 80 if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL 81 || (action == MotionEvent.ACTION_POINTER_UP && i == event.getActionIndex())) { 82 mCurrentStrokes.remove(id); 83 } 84 } 85 } 86 87 /** 88 * @return the list of Strokes which are ending in the recently added MotionEvent 89 */ getEndingStrokes()90 public ArrayList<Stroke> getEndingStrokes() { 91 return mEndingStrokes; 92 } 93 94 /** 95 * @param id the id from MotionEvent 96 * @return the Stroke assigned to the id 97 */ getStroke(int id)98 public Stroke getStroke(int id) { 99 return mCurrentStrokes.get(id); 100 } 101 } 102