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.hardware.Sensor;
20import android.hardware.SensorEvent;
21import android.view.MotionEvent;
22
23/**
24 * A classifier which looks at the proximity sensor during the gesture. It calculates the percentage
25 * the proximity sensor showing the near state during the whole gesture
26 */
27public class ProximityClassifier extends GestureClassifier {
28    private long mGestureStartTimeNano;
29    private long mNearStartTimeNano;
30    private long mNearDuration;
31    private boolean mNear;
32    private float mAverageNear;
33
34    public ProximityClassifier(ClassifierData classifierData) {
35    }
36
37    @Override
38    public String getTag() {
39        return "PROX";
40    }
41
42    @Override
43    public void onSensorChanged(SensorEvent event) {
44        if (event.sensor.getType() == Sensor.TYPE_PROXIMITY) {
45            update(event.values[0] < event.sensor.getMaximumRange(), event.timestamp);
46        }
47    }
48
49    @Override
50    public void onTouchEvent(MotionEvent event) {
51        int action = event.getActionMasked();
52
53        if (action == MotionEvent.ACTION_DOWN) {
54            mGestureStartTimeNano = event.getEventTimeNano();
55            mNearStartTimeNano = event.getEventTimeNano();
56            mNearDuration = 0;
57        }
58
59        if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) {
60            update(mNear, event.getEventTimeNano());
61            long duration = event.getEventTimeNano() - mGestureStartTimeNano;
62
63            if (duration == 0) {
64                mAverageNear = mNear ? 1.0f : 0.0f;
65            } else {
66                mAverageNear = (float) mNearDuration / (float) duration;
67            }
68        }
69    }
70
71
72    /**
73     * @param near is the sensor showing the near state right now
74     * @param timestampNano time of this event in nanoseconds
75     */
76    private void update(boolean near, long timestampNano) {
77        // This if is necessary because MotionEvents and SensorEvents do not come in
78        // chronological order
79        if (timestampNano > mNearStartTimeNano) {
80            // if the state before was near then add the difference of the current time and
81            // mNearStartTimeNano to mNearDuration.
82            if (mNear) {
83                mNearDuration += timestampNano - mNearStartTimeNano;
84            }
85
86            // if the new state is near, set mNearStartTimeNano equal to this moment.
87            if (near) {
88                mNearStartTimeNano = timestampNano;
89            }
90        }
91        mNear = near;
92    }
93
94    @Override
95    public float getFalseTouchEvaluation(int type) {
96        return ProximityEvaluator.evaluate(mAverageNear, type);
97    }
98}
99