blob: 976b586d089be58b58b40131ce3ac1b62556668b [file] [log] [blame]
Dave Mankoff89ad2462019-06-14 14:59:05 -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
19import static org.hamcrest.CoreMatchers.is;
20import static org.junit.Assert.assertThat;
21import static org.mockito.Mockito.when;
22
23import android.testing.AndroidTestingRunner;
24import android.testing.TestableLooper;
25import android.view.MotionEvent;
26
27import androidx.test.filters.SmallTest;
28
29import com.android.systemui.SysuiTestCase;
30
31import org.junit.After;
32import org.junit.Before;
33import org.junit.Test;
34import org.junit.runner.RunWith;
35import org.mockito.Mock;
36import org.mockito.MockitoAnnotations;
37import org.mockito.stubbing.Answer;
38
39import java.util.ArrayList;
40import java.util.List;
41import java.util.Random;
42
43@SmallTest
44@RunWith(AndroidTestingRunner.class)
45@TestableLooper.RunWithLooper
46public class ZigZagClassifierTest extends SysuiTestCase {
47
48 private static final long NS_PER_MS = 1000000;
49
50 @Mock
51 private FalsingDataProvider mDataProvider;
52 private FalsingClassifier mClassifier;
53 private List<MotionEvent> mMotionEvents = new ArrayList<>();
54 private float mOffsetX = 0;
55 private float mOffsetY = 0;
56 private float mDx;
57 private float mDy;
58
59 @Before
60 public void setup() {
61 MockitoAnnotations.initMocks(this);
62 when(mDataProvider.getXdpi()).thenReturn(100f);
63 when(mDataProvider.getYdpi()).thenReturn(100f);
64 when(mDataProvider.getRecentMotionEvents()).thenReturn(mMotionEvents);
65 mClassifier = new ZigZagClassifier(mDataProvider);
66
67
68 // Calculate the response to these calls on the fly, otherwise Mockito gets bogged down
69 // everytime we call appendMotionEvent.
70 when(mDataProvider.getFirstRecentMotionEvent()).thenAnswer(
71 (Answer<MotionEvent>) invocation -> mMotionEvents.get(0));
72 when(mDataProvider.getLastMotionEvent()).thenAnswer(
73 (Answer<MotionEvent>) invocation -> mMotionEvents.get(mMotionEvents.size() - 1));
74 when(mDataProvider.isHorizontal()).thenAnswer(
75 (Answer<Boolean>) invocation -> Math.abs(mDy) < Math.abs(mDx));
76 when(mDataProvider.isVertical()).thenAnswer(
77 (Answer<Boolean>) invocation -> Math.abs(mDy) > Math.abs(mDx));
78 when(mDataProvider.isRight()).thenAnswer((Answer<Boolean>) invocation -> mDx > 0);
79 when(mDataProvider.isUp()).thenAnswer((Answer<Boolean>) invocation -> mDy < 0);
80 }
81
82 @After
83 public void tearDown() {
84 for (MotionEvent motionEvent : mMotionEvents) {
85 motionEvent.recycle();
86 }
87 mMotionEvents.clear();
88 }
89
90 @Test
91 public void testPass_fewTouchesVertical() {
92 assertThat(mClassifier.isFalseTouch(), is(false));
93 appendMotionEvent(0, 0);
94 assertThat(mClassifier.isFalseTouch(), is(false));
95 appendMotionEvent(0, 100);
96 assertThat(mClassifier.isFalseTouch(), is(false));
97 }
98
99 @Test
100 public void testPass_vertical() {
101 appendMotionEvent(0, 0);
102 appendMotionEvent(0, 100);
103 appendMotionEvent(0, 200);
104 assertThat(mClassifier.isFalseTouch(), is(false));
105 }
106
107 @Test
108 public void testPass_fewTouchesHorizontal() {
109 assertThat(mClassifier.isFalseTouch(), is(false));
110 appendMotionEvent(0, 0);
111 assertThat(mClassifier.isFalseTouch(), is(false));
112 appendMotionEvent(100, 0);
113 assertThat(mClassifier.isFalseTouch(), is(false));
114 }
115
116 @Test
117 public void testPass_horizontal() {
118 appendMotionEvent(0, 0);
119 appendMotionEvent(100, 0);
120 appendMotionEvent(200, 0);
121 assertThat(mClassifier.isFalseTouch(), is(false));
122 }
123
124
125 @Test
126 public void testFail_minimumTouchesVertical() {
127 appendMotionEvent(0, 0);
128 appendMotionEvent(0, 100);
129 appendMotionEvent(0, 1);
130 assertThat(mClassifier.isFalseTouch(), is(true));
131 }
132
133 @Test
134 public void testFail_minimumTouchesHorizontal() {
135 appendMotionEvent(0, 0);
136 appendMotionEvent(100, 0);
137 appendMotionEvent(1, 0);
138 assertThat(mClassifier.isFalseTouch(), is(true));
139 }
140
141 @Test
142 public void testPass_fortyFiveDegreesStraight() {
143 appendMotionEvent(0, 0);
144 appendMotionEvent(10, 10);
145 appendMotionEvent(20, 20);
146 assertThat(mClassifier.isFalseTouch(), is(false));
147 }
148
149 @Test
150 public void testPass_horizontalZigZagVerticalStraight() {
151 // This test looks just like testFail_horizontalZigZagVerticalStraight but with
152 // a longer y range, making it look straighter.
153 appendMotionEvent(0, 0);
154 appendMotionEvent(5, 100);
155 appendMotionEvent(-5, 200);
156 assertThat(mClassifier.isFalseTouch(), is(false));
157 }
158
159 @Test
160 public void testPass_horizontalStraightVerticalZigZag() {
161 // This test looks just like testFail_horizontalStraightVerticalZigZag but with
162 // a longer x range, making it look straighter.
163 appendMotionEvent(0, 0);
164 appendMotionEvent(100, 5);
165 appendMotionEvent(200, -5);
166 assertThat(mClassifier.isFalseTouch(), is(false));
167 }
168
169 @Test
170 public void testFail_horizontalZigZagVerticalStraight() {
171 // This test looks just like testPass_horizontalZigZagVerticalStraight but with
172 // a shorter y range, making it look more crooked.
173 appendMotionEvent(0, 0);
174 appendMotionEvent(5, 10);
175 appendMotionEvent(-5, 20);
176 assertThat(mClassifier.isFalseTouch(), is(true));
177 }
178
179 @Test
180 public void testFail_horizontalStraightVerticalZigZag() {
181 // This test looks just like testPass_horizontalStraightVerticalZigZag but with
182 // a shorter x range, making it look more crooked.
183 appendMotionEvent(0, 0);
184 appendMotionEvent(10, 5);
185 appendMotionEvent(20, -5);
186 assertThat(mClassifier.isFalseTouch(), is(true));
187 }
188
189 @Test
190 public void test_between0And45() {
191 appendMotionEvent(0, 0);
192 appendMotionEvent(100, 5);
193 appendMotionEvent(200, 10);
194 assertThat(mClassifier.isFalseTouch(), is(false));
195
196 mMotionEvents.clear();
197 appendMotionEvent(0, 0);
198 appendMotionEvent(100, 0);
199 appendMotionEvent(200, 10);
200 assertThat(mClassifier.isFalseTouch(), is(false));
201
202 mMotionEvents.clear();
203 appendMotionEvent(0, 0);
204 appendMotionEvent(100, -10);
205 appendMotionEvent(200, 10);
206 assertThat(mClassifier.isFalseTouch(), is(false));
207
208 mMotionEvents.clear();
209 appendMotionEvent(0, 0);
210 appendMotionEvent(100, -10);
211 appendMotionEvent(200, 50);
212 assertThat(mClassifier.isFalseTouch(), is(true));
213 }
214
215 @Test
216 public void test_between45And90() {
217 appendMotionEvent(0, 0);
218 appendMotionEvent(10, 50);
219 appendMotionEvent(8, 100);
220 assertThat(mClassifier.isFalseTouch(), is(false));
221
222 mMotionEvents.clear();
223 appendMotionEvent(0, 0);
224 appendMotionEvent(1, 800);
225 appendMotionEvent(2, 900);
226 assertThat(mClassifier.isFalseTouch(), is(false));
227
228 mMotionEvents.clear();
229 appendMotionEvent(0, 0);
230 appendMotionEvent(-10, 600);
231 appendMotionEvent(30, 700);
232 assertThat(mClassifier.isFalseTouch(), is(false));
233
234 mMotionEvents.clear();
235 appendMotionEvent(0, 0);
236 appendMotionEvent(40, 100);
237 appendMotionEvent(0, 101);
238 assertThat(mClassifier.isFalseTouch(), is(true));
239 }
240
241 @Test
242 public void test_between90And135() {
243 appendMotionEvent(0, 0);
244 appendMotionEvent(-10, 50);
245 appendMotionEvent(-24, 100);
246 assertThat(mClassifier.isFalseTouch(), is(false));
247
248 mMotionEvents.clear();
249 appendMotionEvent(0, 0);
250 appendMotionEvent(-20, 800);
251 appendMotionEvent(-20, 900);
252 assertThat(mClassifier.isFalseTouch(), is(false));
253
254 mMotionEvents.clear();
255 appendMotionEvent(0, 0);
256 appendMotionEvent(30, 600);
257 appendMotionEvent(-10, 700);
258 assertThat(mClassifier.isFalseTouch(), is(false));
259
260 mMotionEvents.clear();
261 appendMotionEvent(0, 0);
262 appendMotionEvent(-80, 100);
263 appendMotionEvent(-10, 101);
264 assertThat(mClassifier.isFalseTouch(), is(true));
265 }
266
267 @Test
268 public void test_between135And180() {
269 appendMotionEvent(0, 0);
270 appendMotionEvent(-120, 10);
271 appendMotionEvent(-200, 20);
272 assertThat(mClassifier.isFalseTouch(), is(false));
273
274 mMotionEvents.clear();
275 appendMotionEvent(0, 0);
276 appendMotionEvent(-20, 8);
277 appendMotionEvent(-40, 2);
278 assertThat(mClassifier.isFalseTouch(), is(false));
279
280 mMotionEvents.clear();
281 appendMotionEvent(0, 0);
282 appendMotionEvent(-500, -2);
283 appendMotionEvent(-600, 70);
284 assertThat(mClassifier.isFalseTouch(), is(false));
285
286 mMotionEvents.clear();
287 appendMotionEvent(0, 0);
288 appendMotionEvent(-80, 100);
289 appendMotionEvent(-100, 1);
290 assertThat(mClassifier.isFalseTouch(), is(true));
291 }
292
293 @Test
294 public void test_between180And225() {
295 appendMotionEvent(0, 0);
296 appendMotionEvent(-120, -10);
297 appendMotionEvent(-200, -20);
298 assertThat(mClassifier.isFalseTouch(), is(false));
299
300 mMotionEvents.clear();
301 appendMotionEvent(0, 0);
302 appendMotionEvent(-20, -8);
303 appendMotionEvent(-40, -2);
304 assertThat(mClassifier.isFalseTouch(), is(false));
305
306 mMotionEvents.clear();
307 appendMotionEvent(0, 0);
308 appendMotionEvent(-500, 2);
309 appendMotionEvent(-600, -70);
310 assertThat(mClassifier.isFalseTouch(), is(false));
311
312 mMotionEvents.clear();
313 appendMotionEvent(0, 0);
314 appendMotionEvent(-80, -100);
315 appendMotionEvent(-100, -1);
316 assertThat(mClassifier.isFalseTouch(), is(true));
317 }
318
319 @Test
320 public void test_between225And270() {
321 appendMotionEvent(0, 0);
322 appendMotionEvent(-12, -20);
323 appendMotionEvent(-20, -40);
324 assertThat(mClassifier.isFalseTouch(), is(false));
325
326 mMotionEvents.clear();
327 appendMotionEvent(0, 0);
328 appendMotionEvent(-20, -130);
329 appendMotionEvent(-40, -260);
330 assertThat(mClassifier.isFalseTouch(), is(false));
331
332 mMotionEvents.clear();
333 appendMotionEvent(0, 0);
334 appendMotionEvent(1, -100);
335 appendMotionEvent(-6, -200);
336 assertThat(mClassifier.isFalseTouch(), is(false));
337
338 mMotionEvents.clear();
339 appendMotionEvent(0, 0);
340 appendMotionEvent(-80, -100);
341 appendMotionEvent(-10, -110);
342 assertThat(mClassifier.isFalseTouch(), is(true));
343 }
344
345 @Test
346 public void test_between270And315() {
347 appendMotionEvent(0, 0);
348 appendMotionEvent(12, -20);
349 appendMotionEvent(20, -40);
350 assertThat(mClassifier.isFalseTouch(), is(false));
351
352 mMotionEvents.clear();
353 appendMotionEvent(0, 0);
354 appendMotionEvent(20, -130);
355 appendMotionEvent(40, -260);
356 assertThat(mClassifier.isFalseTouch(), is(false));
357
358 mMotionEvents.clear();
359 appendMotionEvent(0, 0);
360 appendMotionEvent(-1, -100);
361 appendMotionEvent(6, -200);
362 assertThat(mClassifier.isFalseTouch(), is(false));
363
364 mMotionEvents.clear();
365 appendMotionEvent(0, 0);
366 appendMotionEvent(80, -100);
367 appendMotionEvent(10, -110);
368 assertThat(mClassifier.isFalseTouch(), is(true));
369 }
370
371 @Test
372 public void test_between315And360() {
373 appendMotionEvent(0, 0);
374 appendMotionEvent(120, -20);
375 appendMotionEvent(200, -40);
376 assertThat(mClassifier.isFalseTouch(), is(false));
377
378 mMotionEvents.clear();
379 appendMotionEvent(0, 0);
380 appendMotionEvent(200, -13);
381 appendMotionEvent(400, -30);
382 assertThat(mClassifier.isFalseTouch(), is(false));
383
384 mMotionEvents.clear();
385 appendMotionEvent(0, 0);
386 appendMotionEvent(100, 10);
387 appendMotionEvent(600, -20);
388 assertThat(mClassifier.isFalseTouch(), is(false));
389
390 mMotionEvents.clear();
391 appendMotionEvent(0, 0);
392 appendMotionEvent(80, -100);
393 appendMotionEvent(100, -1);
394 assertThat(mClassifier.isFalseTouch(), is(true));
395 }
396
397 @Test
398 public void test_randomOrigins() {
399 // The purpose of this test is to try all the other tests from different starting points.
400 // We use a pre-determined seed to make this test repeatable.
401 Random rand = new Random(23);
402 for (int i = 0; i < 100; i++) {
403 mOffsetX = rand.nextInt(2000) - 1000;
404 mOffsetY = rand.nextInt(2000) - 1000;
405 try {
406 mMotionEvents.clear();
407 testPass_fewTouchesVertical();
408 mMotionEvents.clear();
409 testPass_vertical();
410 mMotionEvents.clear();
411 testFail_horizontalStraightVerticalZigZag();
412 mMotionEvents.clear();
413 testFail_horizontalZigZagVerticalStraight();
414 mMotionEvents.clear();
415 testFail_minimumTouchesHorizontal();
416 mMotionEvents.clear();
417 testFail_minimumTouchesVertical();
418 mMotionEvents.clear();
419 testPass_fewTouchesHorizontal();
420 mMotionEvents.clear();
421 testPass_fortyFiveDegreesStraight();
422 mMotionEvents.clear();
423 testPass_horizontal();
424 mMotionEvents.clear();
425 testPass_horizontalStraightVerticalZigZag();
426 mMotionEvents.clear();
427 testPass_horizontalZigZagVerticalStraight();
428 mMotionEvents.clear();
429 test_between0And45();
430 mMotionEvents.clear();
431 test_between45And90();
432 mMotionEvents.clear();
433 test_between90And135();
434 mMotionEvents.clear();
435 test_between135And180();
436 mMotionEvents.clear();
437 test_between180And225();
438 mMotionEvents.clear();
439 test_between225And270();
440 mMotionEvents.clear();
441 test_between270And315();
442 mMotionEvents.clear();
443 test_between315And360();
444 } catch (AssertionError e) {
445 throw new AssertionError("Random origin failure in iteration " + i, e);
446 }
447 }
448 }
449
450
451 private void appendMotionEvent(float x, float y) {
452 x += mOffsetX;
453 y += mOffsetY;
454
455 long eventTime = mMotionEvents.size() + 1;
456 MotionEvent motionEvent = MotionEvent.obtain(1, eventTime, MotionEvent.ACTION_DOWN, x, y,
457 0);
458 mMotionEvents.add(motionEvent);
459
460 mDx = mDataProvider.getFirstRecentMotionEvent().getX()
461 - mDataProvider.getLastMotionEvent().getX();
462 mDy = mDataProvider.getFirstRecentMotionEvent().getY()
463 - mDataProvider.getLastMotionEvent().getY();
464
465 mClassifier.onTouchEvent(motionEvent);
466 }
467}