1*d57664e9SAndroid Build Coastguard Worker# Falsing in SystemUI 2*d57664e9SAndroid Build Coastguard Worker 3*d57664e9SAndroid Build Coastguard WorkerPhones are easily and often accidentally-activated in owners' pockets ("falsing" or "pocket 4*d57664e9SAndroid Build Coastguard Workerdialing"). Because a phone's screen can be turned on with a single tap, and because we have further 5*d57664e9SAndroid Build Coastguard Workeractions that be activated with basic tapping and swiping, it is critical that we 6*d57664e9SAndroid Build Coastguard Workeranalyze touch events on the screen for intentional vs accidental behavior. With analysis, 7*d57664e9SAndroid Build Coastguard Workerfeatures within SystemUI have an opportunity to ignore or even undo accidental interactions as they 8*d57664e9SAndroid Build Coastguard Workerare occurring. 9*d57664e9SAndroid Build Coastguard Worker 10*d57664e9SAndroid Build Coastguard Worker## Technical Details 11*d57664e9SAndroid Build Coastguard Worker 12*d57664e9SAndroid Build Coastguard WorkerThe `FalsingManager` tracks all touch interactions happening on a phone's lock screen. 13*d57664e9SAndroid Build Coastguard Worker 14*d57664e9SAndroid Build Coastguard WorkerIf you support any sort of touch gestures on the lock screen, you **must**, at a 15*d57664e9SAndroid Build Coastguard Workerminimum, inform the `FalsingManager` of what touches are on touch targets vs not (things that may be 16*d57664e9SAndroid Build Coastguard Worker intentional). If you do not tell the `FalsingManager`, it will assume touches on your feature are 17*d57664e9SAndroid Build Coastguard Workeralways accidental and penalize the session accordingly. 18*d57664e9SAndroid Build Coastguard Worker 19*d57664e9SAndroid Build Coastguard WorkerIndividual touch targets do not _have_ to be separated out; it's acceptable to 20*d57664e9SAndroid Build Coastguard Workerwrap your whole feature in one virtual block that reports touches to the 21*d57664e9SAndroid Build Coastguard Worker`FalsingManager`, however more granular tracking will result in better results 22*d57664e9SAndroid Build Coastguard Workeracross the whole lock screen. 23*d57664e9SAndroid Build Coastguard Worker 24*d57664e9SAndroid Build Coastguard WorkerYou can _act_ on the results of the `FalsingManager`. Instead of only telling 25*d57664e9SAndroid Build Coastguard Workerthe `FalsingManager` that touch events were on touch targets, you can further use the 26*d57664e9SAndroid Build Coastguard Workerreturned results to decide if you want to respond to an owner's touch, if you 27*d57664e9SAndroid Build Coastguard Workerwant to prompt them to confirm their action, or if you simply want to ignore the 28*d57664e9SAndroid Build Coastguard Workertouch. 29*d57664e9SAndroid Build Coastguard Worker 30*d57664e9SAndroid Build Coastguard WorkerThe flow through the system looks like such: 31*d57664e9SAndroid Build Coastguard Worker 32*d57664e9SAndroid Build Coastguard Worker1. Gesture on the screen. 33*d57664e9SAndroid Build Coastguard Worker2. The `FalsingManager` makes a note of all of the `MotionEvents`. 34*d57664e9SAndroid Build Coastguard Worker * If no feature/touch target receives the `MotionEvents`, skip to 4. 35*d57664e9SAndroid Build Coastguard Worker3. Your touch target receives the `MotionEvents`. 36*d57664e9SAndroid Build Coastguard Worker * Once your feature is ready to respond to the gesture in a substantive manner, it queries 37*d57664e9SAndroid Build Coastguard Worker the `FalsingManager`. 38*d57664e9SAndroid Build Coastguard Worker - Dragging animations, touch ripples, and other purely visual effects should not query. 39*d57664e9SAndroid Build Coastguard Worker - Query once you are ready to launch a new feature or dialogue, or are otherwise going to 40*d57664e9SAndroid Build Coastguard Worker change the state of the UI. 41*d57664e9SAndroid Build Coastguard Worker - Generally, wait until `MotionEvent.ACTION_UP` to query or `View.OnClickListener#onClick`. 42*d57664e9SAndroid Build Coastguard Worker - Only query once per gesture, at the end. 43*d57664e9SAndroid Build Coastguard Worker * If the `FalsingManager` says it looks good, respond to the touch. 44*d57664e9SAndroid Build Coastguard Worker4. The `FalsingManager` checks to see if anyone queried about the gesture. If not, mark it as 45*d57664e9SAndroid Build Coastguard Worker accidental. 46*d57664e9SAndroid Build Coastguard Worker 47*d57664e9SAndroid Build Coastguard WorkerThere is also an event fired by the `FalsingManager` that can be listened to by anyone, that 48*d57664e9SAndroid Build Coastguard Workerindicates that the the `FalsingManager` believes the phone is actively being pocket-dialed. When 49*d57664e9SAndroid Build Coastguard Workerfired, modal features, such as quick settings, keyguard bouncer, and others should retract 50*d57664e9SAndroid Build Coastguard Workerthemselves to prevent further pocket-dialing. 51*d57664e9SAndroid Build Coastguard Worker 52*d57664e9SAndroid Build Coastguard Worker## Falsing "Belief" and History 53*d57664e9SAndroid Build Coastguard Worker 54*d57664e9SAndroid Build Coastguard WorkerThe `FalsingManager` maintains a recent history of false analyses. Using 55*d57664e9SAndroid Build Coastguard WorkerBayesian statistics, it updates a "belief" in whether recent 56*d57664e9SAndroid Build Coastguard Workergestures are intentional or not. Any gesture that it is not explicitly queried about is treated as 57*d57664e9SAndroid Build Coastguard Workeraccidental, increasing the overall belief in 58*d57664e9SAndroid Build Coastguard Workerfalse-iness. Gestures that are explicitly queried and that pass the relevant heuristics 59*d57664e9SAndroid Build Coastguard Workerreduce belief that falsing is occurring. This information is tracked within the `HistoryTracker`. 60*d57664e9SAndroid Build Coastguard Worker 61*d57664e9SAndroid Build Coastguard WorkerChanges in belief may influence internal heurstics within the `FalsingManager`, 62*d57664e9SAndroid Build Coastguard Workermaking it easier or harder for an owner to interact with their device. (An owner 63*d57664e9SAndroid Build Coastguard Workerwill always be able to interact with their device, but we may require double 64*d57664e9SAndroid Build Coastguard Workertaps, or more deliberate swipes.) 65*d57664e9SAndroid Build Coastguard Worker 66*d57664e9SAndroid Build Coastguard Worker## Responding to Touch Events 67*d57664e9SAndroid Build Coastguard Worker 68*d57664e9SAndroid Build Coastguard WorkerThe methods below inform the `FalsingManager` that a tap is occurring within an expected touch 69*d57664e9SAndroid Build Coastguard Workertarget. Match the methods with the gesture you expect the device owner to use. 70*d57664e9SAndroid Build Coastguard Worker 71*d57664e9SAndroid Build Coastguard Worker### Single Tap 72*d57664e9SAndroid Build Coastguard Worker 73*d57664e9SAndroid Build Coastguard Worker`FalsingManager#isSimpleTape()`. This method 74*d57664e9SAndroid Build Coastguard Workerperforms a only very basic checking, checking that observed `MotionEvent`s are 75*d57664e9SAndroid Build Coastguard Workerall within some small x & y region ("touch slop"). Useful for only the most simple of scenarios, 76*d57664e9SAndroid Build Coastguard Workeryou probably want `FalsingManager#isFalseTap` method for most cases. 77*d57664e9SAndroid Build Coastguard Worker 78*d57664e9SAndroid Build Coastguard Worker`FalsingManager#isFalseTap(@Penalty int penalty)`. This 79*d57664e9SAndroid Build Coastguard Workermethod tells the `FalsingManager` that you want to thoroughly validate a single tap. It 80*d57664e9SAndroid Build Coastguard Workerreturns true if it thinks the tap should be rejected (i.e. the tap looks more 81*d57664e9SAndroid Build Coastguard Workerlike a swipe) and false otherwise. 82*d57664e9SAndroid Build Coastguard Worker 83*d57664e9SAndroid Build Coastguard WorkerIt runs through the following heuristics to validate a tap: 84*d57664e9SAndroid Build Coastguard Worker 85*d57664e9SAndroid Build Coastguard Worker1. If the device recognizes a face (i.e. face-auth) the tap is **accepted**. 86*d57664e9SAndroid Build Coastguard Worker2. If the tap is the _second_ tap in recent history and looks like a valid Double Tap 87*d57664e9SAndroid Build Coastguard Worker the tap is **accepted**. This works exactly like `FalsingManager#isFalseDoubleTap`. 88*d57664e9SAndroid Build Coastguard Worker3. If the `HistoryTracker` reports strong belief in recent falsing, the tap is 89*d57664e9SAndroid Build Coastguard Worker **rejected**. 90*d57664e9SAndroid Build Coastguard Worker4. Otherwise the tap is **accepted**. 91*d57664e9SAndroid Build Coastguard Worker 92*d57664e9SAndroid Build Coastguard WorkerAll the above rules are applied only after first confirming the gesture does 93*d57664e9SAndroid Build Coastguard Workerin fact look like a simple tap. 94*d57664e9SAndroid Build Coastguard Worker 95*d57664e9SAndroid Build Coastguard Worker`penalty` is a measure of how much the `HistoryTracker`'s belief should be 96*d57664e9SAndroid Build Coastguard Workerpenalized in the event that the tap is rejected. This value is only used if 97*d57664e9SAndroid Build Coastguard Workerthe gesture fails to validate as a simple tap. 98*d57664e9SAndroid Build Coastguard Worker 99*d57664e9SAndroid Build Coastguard WorkerThe `@FalsingManager.Penalty` values are fairly straightforward, but note that you 100*d57664e9SAndroid Build Coastguard Workershould generally be choosing `LOW_PENALTY`. It is inherently difficult to know if a 101*d57664e9SAndroid Build Coastguard Workertap is truly false or not, so a single mis-tap should apply only a small penalty. 102*d57664e9SAndroid Build Coastguard WorkerIf the owner is further along in a UX flow, and is still mis-tapping, it may make more 103*d57664e9SAndroid Build Coastguard Workersense to increase the penalty as mis-taps should be less likely to occur after 104*d57664e9SAndroid Build Coastguard Workerseveral successful gestures. 105*d57664e9SAndroid Build Coastguard Worker 106*d57664e9SAndroid Build Coastguard Worker### Double Tap 107*d57664e9SAndroid Build Coastguard Worker 108*d57664e9SAndroid Build Coastguard Worker`FalsingManager#isFalseDoubleTap()`. This method tells the `FalsingManager` that 109*d57664e9SAndroid Build Coastguard Workeryour UI wants to validate a double tap. There are no parameters to pass to this method. 110*d57664e9SAndroid Build Coastguard WorkerCall this when you explicitly receive and want to verify a double tap, _not_ a single tap. 111*d57664e9SAndroid Build Coastguard Worker 112*d57664e9SAndroid Build Coastguard WorkerNote that `FalsingManager#isFalseTap(boolean robustCheck, double falsePenalty)` 113*d57664e9SAndroid Build Coastguard Workerwill also check for double taps when `robustCheck` is set to true. If you are 114*d57664e9SAndroid Build Coastguard Workerwilling to use single taps, use that instead. 115*d57664e9SAndroid Build Coastguard Worker 116*d57664e9SAndroid Build Coastguard Worker### Swipes and Other Gestures 117*d57664e9SAndroid Build Coastguard Worker 118*d57664e9SAndroid Build Coastguard Worker`FalsingManager#isFalseTouch(@Classifier.InteractionType int interactionType)`. 119*d57664e9SAndroid Build Coastguard WorkerUse this for any non-tap interactions. This includes expanding notifications, 120*d57664e9SAndroid Build Coastguard Workerexpanding quick settings, pulling up the bouncer, and more. You must pass 121*d57664e9SAndroid Build Coastguard Workerthe type of interaction you are evaluating when calling it. A large set of 122*d57664e9SAndroid Build Coastguard Workerheuristics will be applied to analyze the gesture, and the exact rules vary depending upon 123*d57664e9SAndroid Build Coastguard Workerthe `InteractionType`. 124*d57664e9SAndroid Build Coastguard Worker 125*d57664e9SAndroid Build Coastguard Worker### Ignoring A Gesture 126*d57664e9SAndroid Build Coastguard Worker 127*d57664e9SAndroid Build Coastguard Worker`FalsingCollector#avoidGesture()`. Tell the `FalsingManager` to pretend like the 128*d57664e9SAndroid Build Coastguard Workerobserved gesture never happened. **This method must be called when the observed 129*d57664e9SAndroid Build Coastguard Worker`MotionEvent` is `MotionEvent.ACTION_DOWN`.** Attempting to call this method 130*d57664e9SAndroid Build Coastguard Workerlater in a gesture will not work. 131*d57664e9SAndroid Build Coastguard Worker 132*d57664e9SAndroid Build Coastguard WorkerNotice that this method is actually a method on `FalsingCollector`. It is 133*d57664e9SAndroid Build Coastguard Workerforcefully telling the `FalsingManager` to wholly pretend the gesture never 134*d57664e9SAndroid Build Coastguard Workerhappened. This is intended for security and PII sensitive gestures, such as 135*d57664e9SAndroid Build Coastguard Workerpassword inputs. Please don't use this as a shortcut for avoiding the 136*d57664e9SAndroid Build Coastguard WorkerFalsingManager. Falsing works better the more behavior it is told about. 137*d57664e9SAndroid Build Coastguard Worker 138*d57664e9SAndroid Build Coastguard Worker### Other Considerations 139*d57664e9SAndroid Build Coastguard Worker 140*d57664e9SAndroid Build Coastguard WorkerPlease try to call the `FalsingManager` only once per gesture. Wait until you 141*d57664e9SAndroid Build Coastguard Workerare ready to act on the owner's action, and then query the `FalsingManager`. The `FalsingManager` 142*d57664e9SAndroid Build Coastguard Workerwill update its belief in pocket dialing based only on the last call made, so multiple calls per 143*d57664e9SAndroid Build Coastguard Workergesture are not well defined. 144*d57664e9SAndroid Build Coastguard Worker 145*d57664e9SAndroid Build Coastguard WorkerThe `FalsingManager` does not update its belief in pocket-dialing until after a gesture completes. 146*d57664e9SAndroid Build Coastguard WorkerThat is to say, if the owner makes a bad tap on your feature, the "belief" in pocket dialing will 147*d57664e9SAndroid Build Coastguard Workernot incorporate this new data after processing on the final `ACTION_UP` or `ACTION_CANCEL` event 148*d57664e9SAndroid Build Coastguard Workeroccurs. 149*d57664e9SAndroid Build Coastguard Worker 150*d57664e9SAndroid Build Coastguard WorkerIf you expect a mix of taps, double taps, and swipes on your feature, segment them 151*d57664e9SAndroid Build Coastguard Workeraccordingly. Figure out which `FalsingManager` method you need to call first, rather than relying 152*d57664e9SAndroid Build Coastguard Workeron multiple calls to the `FalsingManager` to act as a sieve. 153*d57664e9SAndroid Build Coastguard Worker 154*d57664e9SAndroid Build Coastguard WorkerDon't: 155*d57664e9SAndroid Build Coastguard Worker``` 156*d57664e9SAndroid Build Coastguard Workerif (!mFalsingManager.isFalseTap(false, 0)) { 157*d57664e9SAndroid Build Coastguard Worker // its a tap 158*d57664e9SAndroid Build Coastguard Worker} else if (!mFalsingManager.isFalseTouch(GESTURE_A) { 159*d57664e9SAndroid Build Coastguard Worker // do thing a 160*d57664e9SAndroid Build Coastguard Worker} else if (!mFalsingManager.isFalseTouch(GESTURE_B) { 161*d57664e9SAndroid Build Coastguard Worker // do thing b 162*d57664e9SAndroid Build Coastguard Worker} else { 163*d57664e9SAndroid Build Coastguard Worker // must be a false. 164*d57664e9SAndroid Build Coastguard Worker} 165*d57664e9SAndroid Build Coastguard Worker``` 166*d57664e9SAndroid Build Coastguard Worker 167*d57664e9SAndroid Build Coastguard WorkerDo: 168*d57664e9SAndroid Build Coastguard Worker``` 169*d57664e9SAndroid Build Coastguard Workervoid onTap() { 170*d57664e9SAndroid Build Coastguard Worker if (!mFalsingManager.isFalseTap(false, 0)) { 171*d57664e9SAndroid Build Coastguard Worker // its a tap 172*d57664e9SAndroid Build Coastguard Worker} 173*d57664e9SAndroid Build Coastguard Worker 174*d57664e9SAndroid Build Coastguard Workervoid onGestureA() { 175*d57664e9SAndroid Build Coastguard Worker if (!mFalsingManager.isFalseTouch(GESTURE_A) { 176*d57664e9SAndroid Build Coastguard Worker // do thing a 177*d57664e9SAndroid Build Coastguard Worker } 178*d57664e9SAndroid Build Coastguard Worker} 179*d57664e9SAndroid Build Coastguard Worker 180*d57664e9SAndroid Build Coastguard Workervoid onGestureB() { 181*d57664e9SAndroid Build Coastguard Worker if (!mFalsingManager.isFalseTouch(GESTURE_B) { 182*d57664e9SAndroid Build Coastguard Worker // do thing b 183*d57664e9SAndroid Build Coastguard Worker } 184*d57664e9SAndroid Build Coastguard Worker} 185*d57664e9SAndroid Build Coastguard Worker``` 186*d57664e9SAndroid Build Coastguard Worker 187*d57664e9SAndroid Build Coastguard Worker 188*d57664e9SAndroid Build Coastguard Worker## Influencing Belief 189*d57664e9SAndroid Build Coastguard Worker 190*d57664e9SAndroid Build Coastguard Worker`FalsingCollector#updateFalseConfidence(FalsingClassifier.Result result)`. This 191*d57664e9SAndroid Build Coastguard Workermethod allows you to directly change the `FalsingManager`'s belief in the state 192*d57664e9SAndroid Build Coastguard Workerof pocket dialing. If the owner does something unusual with their phone that you 193*d57664e9SAndroid Build Coastguard Workerthink indicates pocket dialing, you can call: 194*d57664e9SAndroid Build Coastguard Worker 195*d57664e9SAndroid Build Coastguard Worker``` 196*d57664e9SAndroid Build Coastguard Worker mFalsingCollector.updateFalseConfidence( 197*d57664e9SAndroid Build Coastguard Worker FalsingClassifier.Result.falsed(0.6, "Owner is doing something fishy")); 198*d57664e9SAndroid Build Coastguard Worker``` 199*d57664e9SAndroid Build Coastguard Worker 200*d57664e9SAndroid Build Coastguard WorkerA belief value of `1` indicates a 100% confidence of false behavior. A belief 201*d57664e9SAndroid Build Coastguard Workervalue of `0` would make no change in the `FalsingManager` and should be avoided 202*d57664e9SAndroid Build Coastguard Workeras it simply creates noise in the logs. Generally, a middle value between the 203*d57664e9SAndroid Build Coastguard Workertwo extremes makes sense. 204*d57664e9SAndroid Build Coastguard Worker 205*d57664e9SAndroid Build Coastguard WorkerA good example of where this is used is in the "Pattern" password input. We 206*d57664e9SAndroid Build Coastguard Workeravoid recording those gestures in the `FalsingManager`, but we have the pattern input update 207*d57664e9SAndroid Build Coastguard Workerthe `FalsingManager` directly in some cases. If the owner simply taps on the pattern input, we 208*d57664e9SAndroid Build Coastguard Workerrecord it as a false, (patterns are always 4 "cells" long, so single "cell" inputs are penalized). 209*d57664e9SAndroid Build Coastguard Worker 210*d57664e9SAndroid Build Coastguard WorkerConversely, if you think the owner does something that deserves a nice reward: 211*d57664e9SAndroid Build Coastguard Worker 212*d57664e9SAndroid Build Coastguard Worker``` 213*d57664e9SAndroid Build Coastguard Worker mFalsingCollector.updateFalseConfidence( 214*d57664e9SAndroid Build Coastguard Worker FalsingClassifier.Result.passed(0.6)); 215*d57664e9SAndroid Build Coastguard Worker``` 216*d57664e9SAndroid Build Coastguard Worker 217*d57664e9SAndroid Build Coastguard WorkerAgain, useful on password inputs where the FalsingManager is avoiding recording 218*d57664e9SAndroid Build Coastguard Workerthe gesture. This is used on the "pin" password input, to recognize successful 219*d57664e9SAndroid Build Coastguard Workertaps on the input buttons. 220*d57664e9SAndroid Build Coastguard Worker 221*d57664e9SAndroid Build Coastguard Worker## Global Falsing Event 222*d57664e9SAndroid Build Coastguard Worker 223*d57664e9SAndroid Build Coastguard WorkerIf the `FalsingManager`'s belief in falsing crosses some internally defined 224*d57664e9SAndroid Build Coastguard Workerthreshold, it will fire an event that other parts of the system can listen for. 225*d57664e9SAndroid Build Coastguard WorkerThis even indicates that the owner is likely actively pocket-dialing, and any 226*d57664e9SAndroid Build Coastguard Workercurrently open activities on the phone should retract themselves. 227*d57664e9SAndroid Build Coastguard Worker 228*d57664e9SAndroid Build Coastguard WorkerTo subscribe to this event, call 229*d57664e9SAndroid Build Coastguard Worker`FalsingManager#addFalsingBeliefListener(FalsingBeliefListener listener)`. 230*d57664e9SAndroid Build Coastguard Worker`FalsingBeliefListener` is a simple one method interface that will be called 231*d57664e9SAndroid Build Coastguard Workerafter when activities should retract themselves. 232*d57664e9SAndroid Build Coastguard Worker 233*d57664e9SAndroid Build Coastguard Worker**Do Listen For This**. Your code will work without it, but it is a handy, 234*d57664e9SAndroid Build Coastguard Workeruniversal signal that will save the phone owner a lot of accidents. A simple 235*d57664e9SAndroid Build Coastguard Workerimplementation looks like: 236*d57664e9SAndroid Build Coastguard Worker 237*d57664e9SAndroid Build Coastguard Worker``` 238*d57664e9SAndroid Build Coastguard Worker mFalsingManager.addFalsingBeliefListener(MyFeatureClass::hide); 239*d57664e9SAndroid Build Coastguard Worker``` 240