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