blob: 62254a64dfcca636716a768c999a89587b9e0c19 [file] [log] [blame]
Dave Mankoff07fb7b72019-06-10 16:36:19 -04001/*
2 * Copyright (C) 2019 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
17package com.android.systemui.classifier.brightline;
18
Dave Mankoff1dee0342019-07-11 17:44:54 -040019import static com.android.systemui.classifier.FalsingManagerImpl.FALSING_REMAIN_LOCKED;
20import static com.android.systemui.classifier.FalsingManagerImpl.FALSING_SUCCESS;
21
Lucas Dupin13b8cec2020-02-28 16:31:57 -080022import android.app.ActivityManager;
Dave Mankoffd61f01b2019-08-09 17:58:56 -040023import android.hardware.biometrics.BiometricSourceType;
Dave Mankoff07fb7b72019-06-10 16:36:19 -040024import android.net.Uri;
Dave Mankoffd13251a2020-02-11 10:36:57 -050025import android.os.Build;
Dave Mankoff07fb7b72019-06-10 16:36:19 -040026import android.util.Log;
27import android.view.MotionEvent;
28
Dave Mankoff1dee0342019-07-11 17:44:54 -040029import com.android.internal.logging.MetricsLogger;
Dave Mankoff9febfeb2019-12-18 12:18:00 -050030import com.android.internal.util.IndentingPrintWriter;
Dave Mankoffd61f01b2019-08-09 17:58:56 -040031import com.android.keyguard.KeyguardUpdateMonitor;
32import com.android.keyguard.KeyguardUpdateMonitorCallback;
Dave Mankoff07fb7b72019-06-10 16:36:19 -040033import com.android.systemui.classifier.Classifier;
Dave Mankoff9febfeb2019-12-18 12:18:00 -050034import com.android.systemui.dock.DockManager;
Dave Mankoff07fb7b72019-06-10 16:36:19 -040035import com.android.systemui.plugins.FalsingManager;
Dave Mankoff6e636792020-02-19 10:22:21 -050036import com.android.systemui.plugins.statusbar.StatusBarStateController;
37import com.android.systemui.statusbar.StatusBarState;
Dave Mankoff186bd742019-08-15 10:26:38 -040038import com.android.systemui.util.DeviceConfigProxy;
Dave Mankoff63a12822019-09-16 14:38:06 -040039import com.android.systemui.util.sensors.ProximitySensor;
Dave Mankoff07fb7b72019-06-10 16:36:19 -040040
41import java.io.PrintWriter;
Dave Mankoff9febfeb2019-12-18 12:18:00 -050042import java.util.ArrayDeque;
Dave Mankoff07fb7b72019-06-10 16:36:19 -040043import java.util.ArrayList;
44import java.util.List;
Dave Mankoff7f20a1a2019-09-19 15:41:16 -040045import java.util.Locale;
Dave Mankoff9febfeb2019-12-18 12:18:00 -050046import java.util.Queue;
Dave Mankoffd13251a2020-02-11 10:36:57 -050047import java.util.StringJoiner;
48import java.util.stream.Collectors;
Dave Mankoff07fb7b72019-06-10 16:36:19 -040049
50/**
51 * FalsingManager designed to make clear why a touch was rejected.
52 */
53public class BrightLineFalsingManager implements FalsingManager {
54
Dave Mankoff7f20a1a2019-09-19 15:41:16 -040055 private static final String TAG = "FalsingManager";
Dave Mankoffd13251a2020-02-11 10:36:57 -050056 static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
57
58 private static final int RECENT_INFO_LOG_SIZE = 40;
59 private static final int RECENT_SWIPE_LOG_SIZE = 20;
Dave Mankoff07fb7b72019-06-10 16:36:19 -040060
Dave Mankoff07fb7b72019-06-10 16:36:19 -040061 private final FalsingDataProvider mDataProvider;
Dave Mankoffd61f01b2019-08-09 17:58:56 -040062 private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
Dave Mankoff84fa2702019-09-12 13:39:42 -040063 private final ProximitySensor mProximitySensor;
Dave Mankoff9febfeb2019-12-18 12:18:00 -050064 private final DockManager mDockManager;
Dave Mankoff6e636792020-02-19 10:22:21 -050065 private final StatusBarStateController mStatusBarStateController;
Dave Mankoff07fb7b72019-06-10 16:36:19 -040066 private boolean mSessionStarted;
Dave Mankoff1dee0342019-07-11 17:44:54 -040067 private MetricsLogger mMetricsLogger;
68 private int mIsFalseTouchCalls;
Dave Mankoff622eeaf2019-07-26 13:50:08 -040069 private boolean mShowingAod;
70 private boolean mScreenOn;
Dave Mankoffd61f01b2019-08-09 17:58:56 -040071 private boolean mJustUnlockedWithFace;
Dave Mankoff9febfeb2019-12-18 12:18:00 -050072 private static final Queue<String> RECENT_INFO_LOG =
73 new ArrayDeque<>(RECENT_INFO_LOG_SIZE + 1);
Dave Mankoffd13251a2020-02-11 10:36:57 -050074 private static final Queue<DebugSwipeRecord> RECENT_SWIPES =
75 new ArrayDeque<>(RECENT_SWIPE_LOG_SIZE + 1);
Dave Mankoff07fb7b72019-06-10 16:36:19 -040076
Dave Mankoff07fb7b72019-06-10 16:36:19 -040077 private final List<FalsingClassifier> mClassifiers;
78
Dave Mankoff84fa2702019-09-12 13:39:42 -040079 private ProximitySensor.ProximitySensorListener mSensorEventListener = this::onProximityEvent;
Dave Mankoff07fb7b72019-06-10 16:36:19 -040080
Dave Mankoffd61f01b2019-08-09 17:58:56 -040081 private final KeyguardUpdateMonitorCallback mKeyguardUpdateCallback =
82 new KeyguardUpdateMonitorCallback() {
83 @Override
84 public void onBiometricAuthenticated(int userId,
Haining Chenc06c4812020-01-13 20:38:53 -080085 BiometricSourceType biometricSourceType,
86 boolean isStrongBiometric) {
Dave Mankoffd61f01b2019-08-09 17:58:56 -040087 if (userId == KeyguardUpdateMonitor.getCurrentUser()
88 && biometricSourceType == BiometricSourceType.FACE) {
89 mJustUnlockedWithFace = true;
90 }
91 }
92 };
Dave Mankoffd13251a2020-02-11 10:36:57 -050093 private boolean mPreviousResult = false;
Dave Mankoffd61f01b2019-08-09 17:58:56 -040094
Dave Mankoff6e636792020-02-19 10:22:21 -050095 private StatusBarStateController.StateListener mStatusBarStateListener =
96 new StatusBarStateController.StateListener() {
97 @Override
98 public void onStateChanged(int newState) {
99 logDebug("StatusBarState=" + StatusBarState.toShortString(newState));
100 mState = newState;
101 updateSessionActive();
102 }
103 };
104 private int mState;
105
Dave Mankoff9febfeb2019-12-18 12:18:00 -0500106 public BrightLineFalsingManager(FalsingDataProvider falsingDataProvider,
107 KeyguardUpdateMonitor keyguardUpdateMonitor, ProximitySensor proximitySensor,
108 DeviceConfigProxy deviceConfigProxy,
Dave Mankoff6e636792020-02-19 10:22:21 -0500109 DockManager dockManager, StatusBarStateController statusBarStateController) {
Dave Mankoffd61f01b2019-08-09 17:58:56 -0400110 mKeyguardUpdateMonitor = keyguardUpdateMonitor;
Dave Mankoff07fb7b72019-06-10 16:36:19 -0400111 mDataProvider = falsingDataProvider;
Dave Mankoff84fa2702019-09-12 13:39:42 -0400112 mProximitySensor = proximitySensor;
Dave Mankoff9febfeb2019-12-18 12:18:00 -0500113 mDockManager = dockManager;
Dave Mankoff6e636792020-02-19 10:22:21 -0500114 mStatusBarStateController = statusBarStateController;
Dave Mankoffd61f01b2019-08-09 17:58:56 -0400115 mKeyguardUpdateMonitor.registerCallback(mKeyguardUpdateCallback);
Dave Mankoff6e636792020-02-19 10:22:21 -0500116 mStatusBarStateController.addCallback(mStatusBarStateListener);
117 mState = mStatusBarStateController.getState();
Dave Mankoffd61f01b2019-08-09 17:58:56 -0400118
Dave Mankoff1dee0342019-07-11 17:44:54 -0400119 mMetricsLogger = new MetricsLogger();
Dave Mankoff07fb7b72019-06-10 16:36:19 -0400120 mClassifiers = new ArrayList<>();
Dave Mankoff186bd742019-08-15 10:26:38 -0400121 DistanceClassifier distanceClassifier =
122 new DistanceClassifier(mDataProvider, deviceConfigProxy);
123 ProximityClassifier proximityClassifier =
124 new ProximityClassifier(distanceClassifier, mDataProvider, deviceConfigProxy);
Dave Mankoff7abe1352019-06-11 11:32:52 -0400125 mClassifiers.add(new PointerCountClassifier(mDataProvider));
Dave Mankofffd42bdbb2019-06-11 14:51:45 -0400126 mClassifiers.add(new TypeClassifier(mDataProvider));
Dave Mankoff186bd742019-08-15 10:26:38 -0400127 mClassifiers.add(new DiagonalClassifier(mDataProvider, deviceConfigProxy));
Dave Mankoff8bfbe332019-06-12 17:58:30 -0400128 mClassifiers.add(distanceClassifier);
129 mClassifiers.add(proximityClassifier);
Dave Mankoff186bd742019-08-15 10:26:38 -0400130 mClassifiers.add(new ZigZagClassifier(mDataProvider, deviceConfigProxy));
Dave Mankoff07fb7b72019-06-10 16:36:19 -0400131 }
132
133 private void registerSensors() {
Dave Mankoff84fa2702019-09-12 13:39:42 -0400134 mProximitySensor.register(mSensorEventListener);
Dave Mankoff07fb7b72019-06-10 16:36:19 -0400135 }
136
Dave Mankoff07fb7b72019-06-10 16:36:19 -0400137 private void unregisterSensors() {
Dave Mankoff84fa2702019-09-12 13:39:42 -0400138 mProximitySensor.unregister(mSensorEventListener);
Dave Mankoff07fb7b72019-06-10 16:36:19 -0400139 }
140
141 private void sessionStart() {
Dave Mankoff6e636792020-02-19 10:22:21 -0500142 if (!mSessionStarted && shouldSessionBeActive()) {
Dave Mankoff0ae8f2e2019-07-24 18:06:44 -0400143 logDebug("Starting Session");
144 mSessionStarted = true;
Dave Mankoffd61f01b2019-08-09 17:58:56 -0400145 mJustUnlockedWithFace = false;
Dave Mankoff0ae8f2e2019-07-24 18:06:44 -0400146 registerSensors();
147 mClassifiers.forEach(FalsingClassifier::onSessionStarted);
148 }
Dave Mankoff07fb7b72019-06-10 16:36:19 -0400149 }
150
151 private void sessionEnd() {
152 if (mSessionStarted) {
153 logDebug("Ending Session");
154 mSessionStarted = false;
155 unregisterSensors();
156 mDataProvider.onSessionEnd();
157 mClassifiers.forEach(FalsingClassifier::onSessionEnded);
Dave Mankoff1dee0342019-07-11 17:44:54 -0400158 if (mIsFalseTouchCalls != 0) {
159 mMetricsLogger.histogram(FALSING_REMAIN_LOCKED, mIsFalseTouchCalls);
160 mIsFalseTouchCalls = 0;
161 }
Dave Mankoff07fb7b72019-06-10 16:36:19 -0400162 }
163 }
164
Dave Mankoff6e636792020-02-19 10:22:21 -0500165
166 private void updateSessionActive() {
167 if (shouldSessionBeActive()) {
168 sessionStart();
169 } else {
170 sessionEnd();
171 }
172 }
173
174 private boolean shouldSessionBeActive() {
175 return mScreenOn && (mState == StatusBarState.KEYGUARD) && !mShowingAod;
176 }
177
Dave Mankoff07fb7b72019-06-10 16:36:19 -0400178 private void updateInteractionType(@Classifier.InteractionType int type) {
179 logDebug("InteractionType: " + type);
Dave Mankoff1b2144d2020-02-11 14:45:46 -0500180 mDataProvider.setInteractionType(type);
Dave Mankoff07fb7b72019-06-10 16:36:19 -0400181 }
182
183 @Override
Dave Mankoff9febfeb2019-12-18 12:18:00 -0500184 public boolean isClassifierEnabled() {
Dave Mankoff07fb7b72019-06-10 16:36:19 -0400185 return true;
186 }
187
188 @Override
189 public boolean isFalseTouch() {
Dave Mankoffd13251a2020-02-11 10:36:57 -0500190 if (!mDataProvider.isDirty()) {
191 return mPreviousResult;
192 }
193
Lucas Dupin13b8cec2020-02-28 16:31:57 -0800194 mPreviousResult = !ActivityManager.isRunningInUserTestHarness() && !mJustUnlockedWithFace
195 && !mDockManager.isDocked() && mClassifiers.stream().anyMatch(falsingClassifier -> {
Dave Mankoff9febfeb2019-12-18 12:18:00 -0500196 boolean result = falsingClassifier.isFalseTouch();
197 if (result) {
198 logInfo(String.format(
199 (Locale) null,
200 "{classifier=%s, interactionType=%d}",
201 falsingClassifier.getClass().getName(),
202 mDataProvider.getInteractionType()));
203 String reason = falsingClassifier.getReason();
204 if (reason != null) {
205 logInfo(reason);
206 }
207 } else {
208 logDebug(falsingClassifier.getClass().getName() + ": false");
209 }
210 return result;
211 });
Dave Mankoff07fb7b72019-06-10 16:36:19 -0400212
Dave Mankoffd13251a2020-02-11 10:36:57 -0500213 logDebug("Is false touch? " + mPreviousResult);
Dave Mankoff07fb7b72019-06-10 16:36:19 -0400214
Dave Mankoffd13251a2020-02-11 10:36:57 -0500215 if (Build.IS_ENG || Build.IS_USERDEBUG) {
216 // Copy motion events, as the passed in list gets emptied out elsewhere in the code.
217 RECENT_SWIPES.add(new DebugSwipeRecord(
218 mPreviousResult,
219 mDataProvider.getInteractionType(),
220 mDataProvider.getRecentMotionEvents().stream().map(
221 motionEvent -> new XYDt(
222 (int) motionEvent.getX(),
223 (int) motionEvent.getY(),
224 (int) (motionEvent.getEventTime() - motionEvent.getDownTime())))
225 .collect(Collectors.toList())));
226 while (RECENT_SWIPES.size() > RECENT_INFO_LOG_SIZE) {
227 DebugSwipeRecord record = RECENT_SWIPES.remove();
228 }
229
230 }
231
232 return mPreviousResult;
Dave Mankoff07fb7b72019-06-10 16:36:19 -0400233 }
234
235 @Override
236 public void onTouchEvent(MotionEvent motionEvent, int width, int height) {
237 // TODO: some of these classifiers might allow us to abort early, meaning we don't have to
238 // make these calls.
239 mDataProvider.onMotionEvent(motionEvent);
240 mClassifiers.forEach((classifier) -> classifier.onTouchEvent(motionEvent));
241 }
242
Dave Mankoff84fa2702019-09-12 13:39:42 -0400243 private void onProximityEvent(ProximitySensor.ProximityEvent proximityEvent) {
Dave Mankoff07fb7b72019-06-10 16:36:19 -0400244 // TODO: some of these classifiers might allow us to abort early, meaning we don't have to
245 // make these calls.
Dave Mankoff84fa2702019-09-12 13:39:42 -0400246 mClassifiers.forEach((classifier) -> classifier.onProximityEvent(proximityEvent));
Dave Mankoff07fb7b72019-06-10 16:36:19 -0400247 }
248
249 @Override
Dave Mankoff1b2144d2020-02-11 14:45:46 -0500250 public void onSuccessfulUnlock() {
Dave Mankoff1dee0342019-07-11 17:44:54 -0400251 if (mIsFalseTouchCalls != 0) {
252 mMetricsLogger.histogram(FALSING_SUCCESS, mIsFalseTouchCalls);
253 mIsFalseTouchCalls = 0;
254 }
Dave Mankoff622eeaf2019-07-26 13:50:08 -0400255 sessionEnd();
Dave Mankoff07fb7b72019-06-10 16:36:19 -0400256 }
257
258 @Override
259 public void onNotificationActive() {
260 }
261
262 @Override
263 public void setShowingAod(boolean showingAod) {
Dave Mankoff622eeaf2019-07-26 13:50:08 -0400264 mShowingAod = showingAod;
Dave Mankoff6e636792020-02-19 10:22:21 -0500265 updateSessionActive();
Dave Mankoff07fb7b72019-06-10 16:36:19 -0400266 }
267
268 @Override
269 public void onNotificatonStartDraggingDown() {
270 updateInteractionType(Classifier.NOTIFICATION_DRAG_DOWN);
Dave Mankoff07fb7b72019-06-10 16:36:19 -0400271 }
272
273 @Override
274 public boolean isUnlockingDisabled() {
275 return false;
276 }
277
278
279 @Override
280 public void onNotificatonStopDraggingDown() {
281 }
282
283 @Override
284 public void setNotificationExpanded() {
285 }
286
287 @Override
288 public void onQsDown() {
289 updateInteractionType(Classifier.QUICK_SETTINGS);
290 }
291
292 @Override
Dave Mankoff1b2144d2020-02-11 14:45:46 -0500293 public void setQsExpanded(boolean expanded) {
294 if (expanded) {
295 unregisterSensors();
296 } else if (mSessionStarted) {
297 registerSensors();
298 }
Dave Mankoff07fb7b72019-06-10 16:36:19 -0400299 }
300
301 @Override
302 public boolean shouldEnforceBouncer() {
303 return false;
304 }
305
306 @Override
307 public void onTrackingStarted(boolean secure) {
308 updateInteractionType(secure ? Classifier.BOUNCER_UNLOCK : Classifier.UNLOCK);
309 }
310
311 @Override
312 public void onTrackingStopped() {
313 }
314
315 @Override
316 public void onLeftAffordanceOn() {
317 }
318
319 @Override
320 public void onCameraOn() {
321 }
322
323 @Override
324 public void onAffordanceSwipingStarted(boolean rightCorner) {
325 updateInteractionType(
326 rightCorner ? Classifier.RIGHT_AFFORDANCE : Classifier.LEFT_AFFORDANCE);
327 }
328
329 @Override
330 public void onAffordanceSwipingAborted() {
331 }
332
333 @Override
334 public void onStartExpandingFromPulse() {
335 updateInteractionType(Classifier.PULSE_EXPAND);
336 }
337
338 @Override
339 public void onExpansionFromPulseStopped() {
340 }
341
342 @Override
343 public Uri reportRejectedTouch() {
344 return null;
345 }
346
347 @Override
348 public void onScreenOnFromTouch() {
Dave Mankoff622eeaf2019-07-26 13:50:08 -0400349 onScreenTurningOn();
Dave Mankoff07fb7b72019-06-10 16:36:19 -0400350 }
351
352 @Override
353 public boolean isReportingEnabled() {
354 return false;
355 }
356
357 @Override
358 public void onUnlockHintStarted() {
359 }
360
361 @Override
362 public void onCameraHintStarted() {
363 }
364
365 @Override
366 public void onLeftAffordanceHintStarted() {
367 }
368
369 @Override
370 public void onScreenTurningOn() {
Dave Mankoff622eeaf2019-07-26 13:50:08 -0400371 mScreenOn = true;
Dave Mankoff6e636792020-02-19 10:22:21 -0500372 updateSessionActive();
Dave Mankoff07fb7b72019-06-10 16:36:19 -0400373 }
374
375 @Override
376 public void onScreenOff() {
Dave Mankoff622eeaf2019-07-26 13:50:08 -0400377 mScreenOn = false;
Dave Mankoff6e636792020-02-19 10:22:21 -0500378 updateSessionActive();
Dave Mankoff07fb7b72019-06-10 16:36:19 -0400379 }
380
381
382 @Override
Selim Cinekafae4e72020-06-16 18:21:41 -0700383 public void onNotificationStopDismissing() {
Dave Mankoff07fb7b72019-06-10 16:36:19 -0400384 }
385
386 @Override
387 public void onNotificationDismissed() {
388 }
389
390 @Override
Selim Cinekafae4e72020-06-16 18:21:41 -0700391 public void onNotificationStartDismissing() {
Dave Mankoff07fb7b72019-06-10 16:36:19 -0400392 updateInteractionType(Classifier.NOTIFICATION_DISMISS);
393 }
394
395 @Override
396 public void onNotificationDoubleTap(boolean b, float v, float v1) {
397 }
398
399 @Override
400 public void onBouncerShown() {
Dave Mankoff1b2144d2020-02-11 14:45:46 -0500401 unregisterSensors();
Dave Mankoff07fb7b72019-06-10 16:36:19 -0400402 }
403
404 @Override
405 public void onBouncerHidden() {
Dave Mankoff1b2144d2020-02-11 14:45:46 -0500406 if (mSessionStarted) {
407 registerSensors();
408 }
Dave Mankoff07fb7b72019-06-10 16:36:19 -0400409 }
410
411 @Override
Dave Mankoff9febfeb2019-12-18 12:18:00 -0500412 public void dump(PrintWriter pw) {
413 IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ");
414 ipw.println("BRIGHTLINE FALSING MANAGER");
Dave Mankoffd13251a2020-02-11 10:36:57 -0500415 ipw.print("classifierEnabled=");
416 ipw.println(isClassifierEnabled() ? 1 : 0);
417 ipw.print("mJustUnlockedWithFace=");
418 ipw.println(mJustUnlockedWithFace ? 1 : 0);
419 ipw.print("isDocked=");
420 ipw.println(mDockManager.isDocked() ? 1 : 0);
421 ipw.print("width=");
422 ipw.println(mDataProvider.getWidthPixels());
423 ipw.print("height=");
424 ipw.println(mDataProvider.getHeightPixels());
425 ipw.println();
426 if (RECENT_SWIPES.size() != 0) {
427 ipw.println("Recent swipes:");
428 ipw.increaseIndent();
429 for (DebugSwipeRecord record : RECENT_SWIPES) {
430 ipw.println(record.getString());
431 ipw.println();
432 }
433 ipw.decreaseIndent();
434 } else {
435 ipw.println("No recent swipes");
436 }
Dave Mankoff9febfeb2019-12-18 12:18:00 -0500437 ipw.println();
438 ipw.println("Recent falsing info:");
439 ipw.increaseIndent();
440 for (String msg : RECENT_INFO_LOG) {
441 ipw.println(msg);
442 }
Dave Mankoffd13251a2020-02-11 10:36:57 -0500443 ipw.println();
Dave Mankoff07fb7b72019-06-10 16:36:19 -0400444 }
445
Dave Mankoff4c5a13e2019-07-16 15:07:01 -0400446 @Override
447 public void cleanup() {
448 unregisterSensors();
Dave Mankoffd61f01b2019-08-09 17:58:56 -0400449 mKeyguardUpdateMonitor.removeCallback(mKeyguardUpdateCallback);
Dave Mankoff6e636792020-02-19 10:22:21 -0500450 mStatusBarStateController.removeCallback(mStatusBarStateListener);
Dave Mankoff4c5a13e2019-07-16 15:07:01 -0400451 }
452
Dave Mankoff07fb7b72019-06-10 16:36:19 -0400453 static void logDebug(String msg) {
454 logDebug(msg, null);
455 }
456
457 static void logDebug(String msg, Throwable throwable) {
458 if (DEBUG) {
459 Log.d(TAG, msg, throwable);
460 }
461 }
462
463 static void logInfo(String msg) {
464 Log.i(TAG, msg);
Dave Mankoff9febfeb2019-12-18 12:18:00 -0500465 RECENT_INFO_LOG.add(msg);
466 while (RECENT_INFO_LOG.size() > RECENT_INFO_LOG_SIZE) {
467 RECENT_INFO_LOG.remove();
468 }
Dave Mankoff07fb7b72019-06-10 16:36:19 -0400469 }
470
471 static void logError(String msg) {
472 Log.e(TAG, msg);
473 }
Dave Mankoffd13251a2020-02-11 10:36:57 -0500474
475 private static class DebugSwipeRecord {
476 private static final byte VERSION = 1; // opaque version number indicating format of data.
477 private final boolean mIsFalse;
478 private final int mInteractionType;
479 private final List<XYDt> mRecentMotionEvents;
480
481 DebugSwipeRecord(boolean isFalse, int interactionType,
482 List<XYDt> recentMotionEvents) {
483 mIsFalse = isFalse;
484 mInteractionType = interactionType;
485 mRecentMotionEvents = recentMotionEvents;
486 }
487
488 String getString() {
489 StringJoiner sj = new StringJoiner(",");
490 sj.add(Integer.toString(VERSION))
491 .add(mIsFalse ? "1" : "0")
492 .add(Integer.toString(mInteractionType));
493 for (XYDt event : mRecentMotionEvents) {
494 sj.add(event.toString());
495 }
496 return sj.toString();
497 }
498 }
499
500 private static class XYDt {
501 private final int mX;
502 private final int mY;
503 private final int mDT;
504
505 XYDt(int x, int y, int dT) {
506 mX = x;
507 mY = y;
508 mDT = dT;
509 }
510
511 @Override
512 public String toString() {
513 return mX + "," + mY + "," + mDT;
514 }
515 }
Dave Mankoff07fb7b72019-06-10 16:36:19 -0400516}