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.incallui.answer.impl.classifier;
18 
19 import android.hardware.Sensor;
20 import android.hardware.SensorEvent;
21 import android.view.MotionEvent;
22 import java.util.concurrent.TimeUnit;
23 
24 /**
25  * A classifier which looks at the proximity sensor during the gesture. It calculates the percentage
26  * the proximity sensor showing the near state during the whole gesture
27  */
28 class ProximityClassifier extends GestureClassifier {
29   private long mGestureStartTimeNano;
30   private long mNearStartTimeNano;
31   private long mNearDuration;
32   private boolean mNear;
33   private float mAverageNear;
34 
ProximityClassifier(ClassifierData classifierData)35   public ProximityClassifier(ClassifierData classifierData) {}
36 
37   @Override
getTag()38   public String getTag() {
39     return "PROX";
40   }
41 
42   @Override
onSensorChanged(SensorEvent event)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 = TimeUnit.MILLISECONDS.toNanos(event.getEventTime());
55       mNearStartTimeNano = TimeUnit.MILLISECONDS.toNanos(event.getEventTime());
56       mNearDuration = 0;
57     }
58 
59     if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) {
60       update(mNear, TimeUnit.MILLISECONDS.toNanos(event.getEventTime()));
61       long duration = TimeUnit.MILLISECONDS.toNanos(event.getEventTime()) - 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    * @param near is the sensor showing the near state right now
73    * @param timestampNano time of this event in nanoseconds
74    */
75   private void update(boolean near, long timestampNano) {
76     // This if is necessary because MotionEvents and SensorEvents do not come in
77     // chronological order
78     if (timestampNano > mNearStartTimeNano) {
79       // if the state before was near then add the difference of the current time and
80       // mNearStartTimeNano to mNearDuration.
81       if (mNear) {
82         mNearDuration += timestampNano - mNearStartTimeNano;
83       }
84 
85       // if the new state is near, set mNearStartTimeNano equal to this moment.
86       if (near) {
87         mNearStartTimeNano = timestampNano;
88       }
89     }
90     mNear = near;
91   }
92 
93   @Override
getFalseTouchEvaluation()94   public float getFalseTouchEvaluation() {
95     return ProximityEvaluator.evaluate(mAverageNear);
96   }
97 }
98