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 android.view.MotionEvent; 20 21 import com.android.systemui.plugins.FalsingManager; 22 23 import java.util.List; 24 25 /** 26 * Base class for rules that determine False touches. 27 */ 28 public abstract class FalsingClassifier { 29 private final FalsingDataProvider mDataProvider; 30 31 private final FalsingDataProvider.MotionEventListener mMotionEventListener = this::onTouchEvent; 32 FalsingClassifier(FalsingDataProvider dataProvider)33 FalsingClassifier(FalsingDataProvider dataProvider) { 34 mDataProvider = dataProvider; 35 mDataProvider.addMotionEventListener(mMotionEventListener); 36 } 37 getFalsingContext()38 protected String getFalsingContext() { 39 return getClass().getSimpleName(); 40 } 41 falsed(double confidence, String reason)42 protected Result falsed(double confidence, String reason) { 43 return Result.falsed(confidence, getFalsingContext(), reason); 44 } 45 getRecentMotionEvents()46 List<MotionEvent> getRecentMotionEvents() { 47 return mDataProvider.getRecentMotionEvents(); 48 } 49 getPriorMotionEvents()50 List<MotionEvent> getPriorMotionEvents() { 51 return mDataProvider.getPriorMotionEvents(); 52 } 53 getFirstMotionEvent()54 MotionEvent getFirstMotionEvent() { 55 return mDataProvider.getFirstRecentMotionEvent(); 56 } 57 getLastMotionEvent()58 MotionEvent getLastMotionEvent() { 59 return mDataProvider.getLastMotionEvent(); 60 } 61 isHorizontal()62 boolean isHorizontal() { 63 return mDataProvider.isHorizontal(); 64 } 65 isRight()66 boolean isRight() { 67 return mDataProvider.isRight(); 68 } 69 isVertical()70 boolean isVertical() { 71 return mDataProvider.isVertical(); 72 } 73 isUp()74 boolean isUp() { 75 return mDataProvider.isUp(); 76 } 77 getAngle()78 float getAngle() { 79 return mDataProvider.getAngle(); 80 } 81 getWidthPixels()82 int getWidthPixels() { 83 return mDataProvider.getWidthPixels(); 84 } 85 getHeightPixels()86 int getHeightPixels() { 87 return mDataProvider.getHeightPixels(); 88 } 89 getXdpi()90 float getXdpi() { 91 return mDataProvider.getXdpi(); 92 } 93 getYdpi()94 float getYdpi() { 95 return mDataProvider.getYdpi(); 96 } 97 cleanup()98 void cleanup() { 99 mDataProvider.removeMotionEventListener(mMotionEventListener); 100 } 101 102 /** 103 * Called whenever a MotionEvent occurs. 104 * 105 * Useful for classifiers that need to see every MotionEvent, but most can probably 106 * use {@link #getRecentMotionEvents()} instead, which will return a list of MotionEvents. 107 */ onTouchEvent(MotionEvent motionEvent)108 void onTouchEvent(MotionEvent motionEvent) {} 109 110 /** 111 * Called when a ProximityEvent occurs (change in near/far). 112 */ onProximityEvent(FalsingManager.ProximityEvent proximityEvent)113 void onProximityEvent(FalsingManager.ProximityEvent proximityEvent) {} 114 115 /** 116 * The phone screen has turned on and we need to begin falsing detection. 117 */ onSessionStarted()118 void onSessionStarted() {} 119 120 /** 121 * The phone screen has turned off and falsing data can be discarded. 122 */ onSessionEnded()123 void onSessionEnded() {} 124 125 /** 126 * Returns whether a gesture looks like a false touch, taking history into consideration. 127 * 128 * See {@link HistoryTracker#falseBelief()} and {@link HistoryTracker#falseConfidence()}. 129 */ classifyGesture( @lassifier.InteractionType int interactionType, double historyBelief, double historyConfidence)130 Result classifyGesture( 131 @Classifier.InteractionType int interactionType, 132 double historyBelief, double historyConfidence) { 133 return calculateFalsingResult(interactionType, historyBelief, historyConfidence); 134 } 135 136 /** 137 * Calculate a result based on available data. 138 * 139 * When passed a historyConfidence of 0, the history belief should be wholly ignored. 140 */ calculateFalsingResult( @lassifier.InteractionType int interactionType, double historyBelief, double historyConfidence)141 abstract Result calculateFalsingResult( 142 @Classifier.InteractionType int interactionType, 143 double historyBelief, double historyConfidence); 144 145 /** */ logDebug(String msg)146 public static void logDebug(String msg) { 147 BrightLineFalsingManager.logDebug(msg); 148 } 149 150 /** */ logVerbose(String msg)151 public static void logVerbose(String msg) { 152 BrightLineFalsingManager.logVerbose(msg); 153 } 154 155 /** */ logInfo(String msg)156 public static void logInfo(String msg) { 157 BrightLineFalsingManager.logInfo(msg); 158 } 159 160 /** */ logError(String msg)161 public static void logError(String msg) { 162 BrightLineFalsingManager.logError(msg); 163 } 164 165 /** 166 * A Falsing result that encapsulates the boolean result along with confidence and a reason. 167 */ 168 public static class Result { 169 private final boolean mFalsed; 170 private final double mConfidence; 171 private final String mContext; 172 private final String mReason; 173 174 /** 175 * See {@link #falsed(double, String, String)} abd {@link #passed(double)}. 176 */ Result(boolean falsed, double confidence, String context, String reason)177 private Result(boolean falsed, double confidence, String context, String reason) { 178 mFalsed = falsed; 179 mConfidence = confidence; 180 mContext = context; 181 mReason = reason; 182 } 183 isFalse()184 public boolean isFalse() { 185 return mFalsed; 186 } 187 getConfidence()188 public double getConfidence() { 189 return mConfidence; 190 } 191 getReason()192 public String getReason() { 193 return String.format("{context=%s reason=%s}", mContext, mReason); 194 } 195 196 /** 197 * Construct a "falsed" result indicating that a gesture should be treated as accidental. 198 */ falsed(double confidence, String context, String reason)199 public static Result falsed(double confidence, String context, String reason) { 200 return new Result(true, confidence, context, reason); 201 } 202 203 /** 204 * Construct a "passed" result indicating that a gesture should be allowed. 205 */ passed(double confidence)206 public static Result passed(double confidence) { 207 return new Result(false, confidence, null, null); 208 } 209 } 210 } 211