HumanInteractionClassifier.java revision 6dc59b48c040cf6871d7ff6d8e5242b1a5ddd032
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
17package com.android.systemui.classifier;
18
19import android.content.Context;
20import android.database.ContentObserver;
21import android.hardware.SensorEvent;
22import android.os.Build;
23import android.os.Handler;
24import android.os.UserHandle;
25import android.provider.Settings;
26import android.view.MotionEvent;
27
28import java.util.ArrayList;
29
30/**
31 * An classifier trying to determine whether it is a human interacting with the phone or not.
32 */
33public class HumanInteractionClassifier extends Classifier {
34    private static final String HIC_ENABLE = "HIC_enable";
35    private static HumanInteractionClassifier sInstance = null;
36
37    private final Handler mHandler = new Handler();
38    private final Context mContext;
39
40    private ArrayList<StrokeClassifier> mStrokeClassifiers = new ArrayList<>();
41    private ArrayList<GestureClassifier> mGestureClassifiers = new ArrayList<>();
42    private final int mStrokeClassifiersSize;
43    private final int mGestureClassifiersSize;
44
45    private HistoryEvaluator mHistoryEvaluator;
46    private boolean mEnableClassifier = false;
47    private int mCurrentType = Classifier.GENERIC;
48
49    protected final ContentObserver mSettingsObserver = new ContentObserver(mHandler) {
50        @Override
51        public void onChange(boolean selfChange) {
52            updateConfiguration();
53        }
54    };
55
56    private HumanInteractionClassifier(Context context) {
57        mContext = context;
58        mClassifierData = new ClassifierData(mContext.getResources().getDisplayMetrics().xdpi,
59                mContext.getResources().getDisplayMetrics().ydpi);
60        mHistoryEvaluator = new HistoryEvaluator();
61
62        mStrokeClassifiers.add(new AnglesVarianceClassifier(mClassifierData));
63        mStrokeClassifiers.add(new SpeedClassifier(mClassifierData));
64        mStrokeClassifiers.add(new DurationCountClassifier(mClassifierData));
65        mStrokeClassifiers.add(new EndPointRatioClassifier(mClassifierData));
66        mStrokeClassifiers.add(new EndPointLengthClassifier(mClassifierData));
67        mStrokeClassifiers.add(new AccelerationClassifier(mClassifierData));
68        mStrokeClassifiers.add(new SpeedVarianceClassifier(mClassifierData));
69        mStrokeClassifiers.add(new LengthCountClassifier(mClassifierData));
70
71        mGestureClassifiers.add(new PointerCountClassifier(mClassifierData));
72        mGestureClassifiers.add(new ProximityClassifier(mClassifierData));
73
74        mStrokeClassifiersSize = mStrokeClassifiers.size();
75        mGestureClassifiersSize = mGestureClassifiers.size();
76
77        mContext.getContentResolver().registerContentObserver(
78                Settings.Global.getUriFor(HIC_ENABLE), false,
79                mSettingsObserver,
80                UserHandle.USER_ALL);
81
82        updateConfiguration();
83    }
84
85    public static HumanInteractionClassifier getInstance(Context context) {
86        if (sInstance == null) {
87            sInstance = new HumanInteractionClassifier(context);
88        }
89        return sInstance;
90    }
91
92    private void updateConfiguration() {
93        mEnableClassifier = Build.IS_DEBUGGABLE && 0 != Settings.Global.getInt(
94                mContext.getContentResolver(),
95                HIC_ENABLE, 0);
96    }
97
98    public void setType(int type) {
99        mCurrentType = type;
100    }
101
102    @Override
103    public void onTouchEvent(MotionEvent event) {
104        if (mEnableClassifier) {
105            mClassifierData.update(event);
106
107            for (int i = 0; i < mStrokeClassifiersSize; i++) {
108                mStrokeClassifiers.get(i).onTouchEvent(event);
109            }
110
111            for (int i = 0; i < mGestureClassifiersSize; i++) {
112                mGestureClassifiers.get(i).onTouchEvent(event);
113            }
114
115            int size = mClassifierData.getEndingStrokes().size();
116            for (int i = 0; i < size; i++) {
117                Stroke stroke = mClassifierData.getEndingStrokes().get(i);
118                float evaluation = 0.0f;
119                for (int j = 0; j < mStrokeClassifiersSize; j++) {
120                    evaluation += mStrokeClassifiers.get(j).getFalseTouchEvaluation(
121                            mCurrentType, stroke);
122                }
123                mHistoryEvaluator.addStroke(evaluation);
124            }
125
126            int action = event.getActionMasked();
127            if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) {
128                float evaluation = 0.0f;
129                for (int i = 0; i < mGestureClassifiersSize; i++) {
130                    evaluation += mGestureClassifiers.get(i).getFalseTouchEvaluation(mCurrentType);
131                }
132                mHistoryEvaluator.addGesture(evaluation);
133                setType(Classifier.GENERIC);
134            }
135
136            mClassifierData.cleanUp(event);
137        }
138    }
139
140    @Override
141    public void onSensorChanged(SensorEvent event) {
142        for (int i = 0; i < mStrokeClassifiers.size(); i++) {
143            mStrokeClassifiers.get(i).onSensorChanged(event);
144        }
145
146        for (int i = 0; i < mGestureClassifiers.size(); i++) {
147            mGestureClassifiers.get(i).onSensorChanged(event);
148        }
149    }
150
151    public boolean isFalseTouch() {
152        if (mEnableClassifier) {
153            return mHistoryEvaluator.getEvaluation() >= 5.0f;
154        }
155        return false;
156    }
157
158    public boolean isEnabled() {
159        return mEnableClassifier;
160    }
161}
162