• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2017 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.server.accessibility;
18 
19 import static org.mockito.Mockito.mock;
20 import static org.mockito.Mockito.reset;
21 import static org.mockito.Mockito.when;
22 import static org.mockito.Mockito.verify;
23 
24 import android.accessibilityservice.AccessibilityService;
25 import android.content.Context;
26 import android.content.res.Resources;
27 import android.graphics.Point;
28 import android.graphics.PointF;
29 import android.os.Looper;
30 import android.util.DisplayMetrics;
31 import android.view.GestureDetector;
32 import android.view.MotionEvent;
33 import java.util.ArrayList;
34 import org.junit.Before;
35 import org.junit.BeforeClass;
36 import org.junit.Test;
37 
38 
39 /**
40  * Tests for AccessibilityGestureDetector
41  */
42 public class AccessibilityGestureDetectorTest {
43 
44     // Constants for testRecognizeGesturePath()
45     private static final PointF PATH_START = new PointF(300f, 300f);
46     private static final int PATH_STEP_PIXELS = 200;
47     private static final long PATH_STEP_MILLISEC = 100;
48 
49     /**
50      * AccessibilitGestureDetector that can mock double-tap detector.
51      */
52     private class AccessibilityGestureDetectorTestable extends AccessibilityGestureDetector {
AccessibilityGestureDetectorTestable(Context context, Listener listener)53         public AccessibilityGestureDetectorTestable(Context context, Listener listener) {
54             super(context, listener);
55         }
56 
setDoubleTapDetector(GestureDetector gestureDetector)57         protected void setDoubleTapDetector(GestureDetector gestureDetector) {
58             mGestureDetector = gestureDetector;
59             mGestureDetector.setOnDoubleTapListener(this);
60         }
61     }
62 
63 
64     // Data used by all tests
65     private AccessibilityGestureDetectorTestable mDetector;
66     private AccessibilityGestureDetector.Listener mResultListener;
67 
68 
69     @BeforeClass
oneTimeInitialization()70     public static void oneTimeInitialization() {
71         if (Looper.myLooper() == null) {
72             Looper.prepare();
73         }
74     }
75 
76     @Before
setUp()77     public void setUp() {
78         // Construct a mock Context.
79         DisplayMetrics displayMetricsMock = mock(DisplayMetrics.class);
80         displayMetricsMock.xdpi = 500;
81         displayMetricsMock.ydpi = 500;
82         Resources mockResources = mock(Resources.class);
83         when(mockResources.getDisplayMetrics()).thenReturn(displayMetricsMock);
84         Context contextMock = mock(Context.class);
85         when(contextMock.getMainLooper()).thenReturn(Looper.myLooper());
86         when(contextMock.getResources()).thenReturn(mockResources);
87 
88         // Construct a testable AccessibilityGestureDetector.
89         mResultListener = mock(AccessibilityGestureDetector.Listener.class);
90         mDetector = new AccessibilityGestureDetectorTestable(contextMock, mResultListener);
91         GestureDetector doubleTapDetectorMock = mock(GestureDetector.class);
92         mDetector.setDoubleTapDetector(doubleTapDetectorMock);
93     }
94 
95 
96     @Test
testRecognizeGesturePath()97     public void testRecognizeGesturePath() {
98         final int d = 1000;  // Length of each segment in the test gesture, in pixels.
99 
100         testPath(p(-d, +0), AccessibilityService.GESTURE_SWIPE_LEFT);
101         testPath(p(+d, +0), AccessibilityService.GESTURE_SWIPE_RIGHT);
102         testPath(p(+0, -d), AccessibilityService.GESTURE_SWIPE_UP);
103         testPath(p(+0, +d), AccessibilityService.GESTURE_SWIPE_DOWN);
104 
105         testPath(p(-d, +0), p((-d - d), +0), AccessibilityService.GESTURE_SWIPE_LEFT);
106         testPath(p(-d, +0), p(+0, +0), AccessibilityService.GESTURE_SWIPE_LEFT_AND_RIGHT);
107         testPath(p(-d, +0), p(-d, -d), AccessibilityService.GESTURE_SWIPE_LEFT_AND_UP);
108         testPath(p(-d, +0), p(-d, +d), AccessibilityService.GESTURE_SWIPE_LEFT_AND_DOWN);
109 
110         testPath(p(+d, +0), p(+0, +0), AccessibilityService.GESTURE_SWIPE_RIGHT_AND_LEFT);
111         testPath(p(+d, +0), p((+d + d), +0), AccessibilityService.GESTURE_SWIPE_RIGHT);
112         testPath(p(+d, +0), p(+d, -d), AccessibilityService.GESTURE_SWIPE_RIGHT_AND_UP);
113         testPath(p(+d, +0), p(+d, +d), AccessibilityService.GESTURE_SWIPE_RIGHT_AND_DOWN);
114 
115         testPath(p(+0, -d), p(-d, -d), AccessibilityService.GESTURE_SWIPE_UP_AND_LEFT);
116         testPath(p(+0, -d), p(+d, -d), AccessibilityService.GESTURE_SWIPE_UP_AND_RIGHT);
117         testPath(p(+0, -d), p(+0, (-d - d)), AccessibilityService.GESTURE_SWIPE_UP);
118         testPath(p(+0, -d), p(+0, +0), AccessibilityService.GESTURE_SWIPE_UP_AND_DOWN);
119 
120         testPath(p(+0, +d), p(-d, +d), AccessibilityService.GESTURE_SWIPE_DOWN_AND_LEFT);
121         testPath(p(+0, +d), p(+d, +d), AccessibilityService.GESTURE_SWIPE_DOWN_AND_RIGHT);
122         testPath(p(+0, +d), p(+0, +0), AccessibilityService.GESTURE_SWIPE_DOWN_AND_UP);
123         testPath(p(+0, +d), p(+0, (+d + d)), AccessibilityService.GESTURE_SWIPE_DOWN);
124     }
125 
126     /** Convenient short alias to make a Point. */
p(int x, int y)127     private static Point p(int x, int y) {
128         return new Point(x, y);
129     }
130 
131     /** Test recognizing path from PATH_START to PATH_START+delta. */
testPath(Point delta, int gestureId)132     private void testPath(Point delta, int gestureId) {
133         ArrayList<PointF> path = new ArrayList<>();
134         path.add(PATH_START);
135 
136         PointF segmentEnd = new PointF(PATH_START.x + delta.x, PATH_START.y + delta.y);
137         fillPath(PATH_START, segmentEnd, path);
138 
139         testPath(path, gestureId);
140     }
141 
142     /** Test recognizing path from PATH_START to PATH_START+delta1 to PATH_START+delta2. */
testPath(Point delta1, Point delta2, int gestureId)143     private void testPath(Point delta1, Point delta2, int gestureId) {
144         ArrayList<PointF> path = new ArrayList<>();
145         path.add(PATH_START);
146 
147         PointF startPlusDelta1 = new PointF(PATH_START.x + delta1.x, PATH_START.y + delta1.y);
148         fillPath(PATH_START, startPlusDelta1, path);
149 
150         PointF startPlusDelta2 = new PointF(PATH_START.x + delta2.x, PATH_START.y + delta2.y);
151         fillPath(startPlusDelta1, startPlusDelta2, path);
152 
153         testPath(path, gestureId);
154     }
155 
156     /** Fill in movement points from start to end, appending points to path. */
fillPath(PointF start, PointF end, ArrayList<PointF> path)157     private void fillPath(PointF start, PointF end, ArrayList<PointF> path) {
158         // Calculate number of path steps needed.
159         float deltaX = end.x - start.x;
160         float deltaY = end.y - start.y;
161         float distance = (float) Math.hypot(deltaX, deltaY);
162         float numSteps = distance / (float) PATH_STEP_PIXELS;
163         float stepX = (float) deltaX / numSteps;
164         float stepY = (float) deltaY / numSteps;
165 
166         // For each path step from start (non-inclusive) to end ... add a motion point.
167         for (int step = 1; step < numSteps; ++step) {
168             path.add(new PointF(
169                 (start.x + (stepX * (float) step)),
170                 (start.y + (stepY * (float) step))));
171         }
172     }
173 
174     /** Test recognizing a path made of motion event points. */
testPath(ArrayList<PointF> path, int gestureId)175     private void testPath(ArrayList<PointF> path, int gestureId) {
176         // Clear last recognition result.
177         reset(mResultListener);
178 
179         int policyFlags = 0;
180         long eventDownTimeMs = 0;
181         long eventTimeMs = eventDownTimeMs;
182 
183         // For each path point...
184         for (int pointIndex = 0; pointIndex < path.size(); ++pointIndex) {
185 
186             // Create motion event.
187             PointF point = path.get(pointIndex);
188             int action = MotionEvent.ACTION_MOVE;
189             if (pointIndex == 0) {
190                 action = MotionEvent.ACTION_DOWN;
191             } else if (pointIndex == path.size() - 1) {
192                 action = MotionEvent.ACTION_UP;
193             }
194             MotionEvent event = MotionEvent.obtain(eventDownTimeMs, eventTimeMs, action,
195                     point.x, point.y, 0);
196 
197             // Send event.
198             mDetector.onMotionEvent(event, policyFlags);
199             eventTimeMs += PATH_STEP_MILLISEC;
200         }
201 
202         // Check that correct gesture was recognized.
203         verify(mResultListener).onGestureCompleted(gestureId);
204     }
205 }
206