• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2020 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 static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.BRIGHTLINE_FALSING_PROXIMITY_PERCENT_COVERED_THRESHOLD;
20 import static com.android.systemui.classifier.Classifier.BRIGHTNESS_SLIDER;
21 import static com.android.systemui.classifier.Classifier.MEDIA_SEEKBAR;
22 import static com.android.systemui.classifier.Classifier.QS_COLLAPSE;
23 import static com.android.systemui.classifier.Classifier.QS_SWIPE_SIDE;
24 import static com.android.systemui.classifier.Classifier.QUICK_SETTINGS;
25 
26 import android.provider.DeviceConfig;
27 import android.view.MotionEvent;
28 
29 import com.android.systemui.plugins.FalsingManager;
30 import com.android.systemui.util.DeviceConfigProxy;
31 
32 import java.util.Locale;
33 
34 import javax.inject.Inject;
35 
36 
37 /**
38  * False touch if proximity sensor is covered for more than a certain percentage of the gesture.
39  *
40  * This classifier is essentially a no-op for QUICK_SETTINGS, as we assume the sensor may be
41  * covered when swiping from the top.
42  */
43 class ProximityClassifier extends FalsingClassifier {
44 
45     private static final float PERCENT_COVERED_THRESHOLD = 0.1f;
46     private final DistanceClassifier mDistanceClassifier;
47     private final float mPercentCoveredThreshold;
48 
49     private boolean mNear;
50     private long mGestureStartTimeNs;
51     private long mPrevNearTimeNs;
52     private long mNearDurationNs;
53     private float mPercentNear;
54 
55     @Inject
ProximityClassifier(DistanceClassifier distanceClassifier, FalsingDataProvider dataProvider, DeviceConfigProxy deviceConfigProxy)56     ProximityClassifier(DistanceClassifier distanceClassifier,
57             FalsingDataProvider dataProvider, DeviceConfigProxy deviceConfigProxy) {
58         super(dataProvider);
59         mDistanceClassifier = distanceClassifier;
60 
61         mPercentCoveredThreshold = deviceConfigProxy.getFloat(
62                 DeviceConfig.NAMESPACE_SYSTEMUI,
63                 BRIGHTLINE_FALSING_PROXIMITY_PERCENT_COVERED_THRESHOLD,
64                 PERCENT_COVERED_THRESHOLD);
65     }
66 
67     @Override
onSessionStarted()68     void onSessionStarted() {
69         mPrevNearTimeNs = 0;
70         mPercentNear = 0;
71     }
72 
73     @Override
onSessionEnded()74     void onSessionEnded() {
75         mPrevNearTimeNs = 0;
76         mPercentNear = 0;
77     }
78 
79     @Override
onTouchEvent(MotionEvent motionEvent)80     public void onTouchEvent(MotionEvent motionEvent) {
81         int action = motionEvent.getActionMasked();
82 
83         if (action == MotionEvent.ACTION_DOWN) {
84             mGestureStartTimeNs = motionEvent.getEventTimeNanos();
85             if (mPrevNearTimeNs > 0) {
86                 // We only care about if the proximity sensor is triggered while a move event is
87                 // happening.
88                 mPrevNearTimeNs = motionEvent.getEventTimeNanos();
89             }
90             logDebug("Gesture start time: " + mGestureStartTimeNs);
91             mNearDurationNs = 0;
92         }
93 
94         if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) {
95             update(mNear, motionEvent.getEventTimeNanos());
96             long duration = motionEvent.getEventTimeNanos() - mGestureStartTimeNs;
97 
98             logDebug("Gesture duration, Proximity duration: " + duration + ", " + mNearDurationNs);
99 
100             if (duration == 0) {
101                 mPercentNear = mNear ? 1.0f : 0.0f;
102             } else {
103                 mPercentNear = (float) mNearDurationNs / (float) duration;
104             }
105         }
106 
107     }
108 
109     @Override
onProximityEvent( FalsingManager.ProximityEvent proximityEvent)110     public void onProximityEvent(
111             FalsingManager.ProximityEvent proximityEvent) {
112         boolean covered = proximityEvent.getCovered();
113         long timestampNs = proximityEvent.getTimestampNs();
114         logDebug("Sensor is: " + covered + " at time " + timestampNs);
115         update(covered, timestampNs);
116     }
117 
118     @Override
calculateFalsingResult( @lassifier.InteractionType int interactionType, double historyBelief, double historyConfidence)119     Result calculateFalsingResult(
120             @Classifier.InteractionType int interactionType,
121             double historyBelief, double historyConfidence) {
122         if (interactionType == QUICK_SETTINGS || interactionType == BRIGHTNESS_SLIDER
123                 || interactionType == QS_COLLAPSE || interactionType == QS_SWIPE_SIDE
124                 || interactionType == MEDIA_SEEKBAR) {
125             return Result.passed(0);
126         }
127 
128         if (mPercentNear > mPercentCoveredThreshold) {
129             Result longSwipeResult = mDistanceClassifier.isLongSwipe();
130             return longSwipeResult.isFalse()
131                     ? falsed(
132                             0.5, getReason(longSwipeResult, mPercentNear, mPercentCoveredThreshold))
133                     : Result.passed(0.5);
134         }
135 
136         return Result.passed(0.5);
137     }
138 
getReason(Result longSwipeResult, float percentNear, float percentCoveredThreshold)139     private static String getReason(Result longSwipeResult, float percentNear,
140             float percentCoveredThreshold) {
141         return String.format(
142                 (Locale) null,
143                 "{percentInProximity=%f, threshold=%f, distanceClassifier=%s}",
144                 percentNear,
145                 percentCoveredThreshold,
146                 longSwipeResult.getReason());
147     }
148 
149     /**
150      * @param near        is the sensor showing the near state right now
151      * @param timeStampNs time of this event in nanoseconds
152      */
update(boolean near, long timeStampNs)153     private void update(boolean near, long timeStampNs) {
154         if (mPrevNearTimeNs != 0 && timeStampNs > mPrevNearTimeNs && mNear) {
155             mNearDurationNs += timeStampNs - mPrevNearTimeNs;
156             logDebug("Updating duration: " + mNearDurationNs);
157         }
158 
159         if (near) {
160             logDebug("Set prevNearTimeNs: " + timeStampNs);
161             mPrevNearTimeNs = timeStampNs;
162         }
163 
164         mNear = near;
165     }
166 }
167