xref: /aosp_15_r20/frameworks/base/packages/SystemUI/docs/falsing.md (revision d57664e9bc4670b3ecf6748a746a57c557b6bc9e)
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