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