1 /* 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 package android.accessibilityservice.cts; 17 18 import static com.google.common.truth.Truth.assertThat; 19 import static com.google.common.truth.Truth.assertWithMessage; 20 21 import android.accessibility.cts.common.InstrumentedAccessibilityService; 22 import android.accessibilityservice.AccessibilityGestureEvent; 23 import android.view.accessibility.AccessibilityEvent; 24 25 import java.util.ArrayList; 26 import java.util.List; 27 28 /** Accessibility service stub, which will collect recognized gestures. */ 29 public class GestureDetectionStubAccessibilityService extends InstrumentedAccessibilityService { 30 private static final long GESTURE_RECOGNIZE_TIMEOUT_MS = 3000; 31 protected static final long EVENT_RECOGNIZE_TIMEOUT_MS = 5000; 32 // Member variables 33 protected final Object mLock = new Object(); 34 private ArrayList<Integer> mCollectedGestures = new ArrayList(); 35 private ArrayList<AccessibilityGestureEvent> mCollectedGestureEvents = new ArrayList(); 36 protected ArrayList<Integer> mCollectedEvents = new ArrayList(); 37 38 @Override onGesture(int gestureId)39 protected boolean onGesture(int gestureId) { 40 synchronized (mCollectedGestures) { 41 mCollectedGestures.add(gestureId); 42 } 43 return true; 44 } 45 46 @Override onGesture(AccessibilityGestureEvent gestureEvent)47 public boolean onGesture(AccessibilityGestureEvent gestureEvent) { 48 super.onGesture(gestureEvent); 49 synchronized (mCollectedGestureEvents) { 50 mCollectedGestureEvents.add(gestureEvent); 51 mCollectedGestureEvents.notifyAll(); // Stop waiting for gesture. 52 } 53 return true; 54 } 55 clearGestures()56 public void clearGestures() { 57 synchronized (mCollectedGestures) { 58 mCollectedGestures.clear(); 59 } 60 synchronized (mCollectedGestureEvents) { 61 mCollectedGestureEvents.clear(); 62 } 63 } 64 getGesturesSize()65 public int getGesturesSize() { 66 synchronized (mCollectedGestures) { 67 return mCollectedGestures.size(); 68 } 69 } 70 getGesture(int index)71 public int getGesture(int index) { 72 synchronized (mCollectedGestures) { 73 return mCollectedGestures.get(index); 74 } 75 } 76 77 /** Waits for {@link #onGesture(AccessibilityGestureEvent)} to collect next gesture. */ waitUntilGestureInfo()78 public void waitUntilGestureInfo() { 79 synchronized (mCollectedGestureEvents) { 80 // Assume the size of mCollectedGestures is changed before mCollectedGestureEvents. 81 if (mCollectedGestureEvents.size() > 0) { 82 return; 83 } 84 try { 85 mCollectedGestureEvents.wait(GESTURE_RECOGNIZE_TIMEOUT_MS); 86 } catch (InterruptedException e) { 87 throw new RuntimeException(e); 88 } 89 } 90 } 91 getGestureInfoSize()92 public int getGestureInfoSize() { 93 synchronized (mCollectedGestureEvents) { 94 return mCollectedGestureEvents.size(); 95 } 96 } 97 getGestureInfo(int index)98 public AccessibilityGestureEvent getGestureInfo(int index) { 99 synchronized (mCollectedGestureEvents) { 100 return mCollectedGestureEvents.get(index); 101 } 102 } 103 104 @Override onAccessibilityEvent(AccessibilityEvent event)105 public void onAccessibilityEvent(AccessibilityEvent event) { 106 synchronized (mLock) { 107 switch (event.getEventType()) { 108 case AccessibilityEvent.TYPE_TOUCH_INTERACTION_END: 109 mCollectedEvents.add(event.getEventType()); 110 mLock.notifyAll(); 111 break; 112 case AccessibilityEvent.TYPE_TOUCH_INTERACTION_START: 113 case AccessibilityEvent.TYPE_TOUCH_EXPLORATION_GESTURE_START: 114 case AccessibilityEvent.TYPE_TOUCH_EXPLORATION_GESTURE_END: 115 mCollectedEvents.add(event.getEventType()); 116 } 117 } 118 super.onAccessibilityEvent(event); 119 } 120 clearEvents()121 public void clearEvents() { 122 synchronized (mLock) { 123 mCollectedEvents.clear(); 124 } 125 } 126 getEventsSize()127 public int getEventsSize() { 128 synchronized (mLock) { 129 return mCollectedEvents.size(); 130 } 131 } 132 getEvent(int index)133 public int getEvent(int index) { 134 synchronized (mLock) { 135 return mCollectedEvents.get(index); 136 } 137 } 138 139 /** Wait for onAccessibilityEvent() to collect next gesture. */ waitUntilEvent(int count)140 public void waitUntilEvent(int count) { 141 synchronized (mLock) { 142 if (mCollectedEvents.size() >= count) { 143 return; 144 } 145 try { 146 mLock.wait(EVENT_RECOGNIZE_TIMEOUT_MS); 147 } catch (InterruptedException e) { 148 throw new RuntimeException(e); 149 } 150 } 151 } 152 153 /** Ensure that the specified accessibility gesture event has been received. */ assertGestureReceived(int gestureId, int displayId)154 public void assertGestureReceived(int gestureId, int displayId) { 155 // Wait for gesture recognizer, and check recognized gesture. 156 waitUntilGestureInfo(); 157 AccessibilityGestureEvent expected = new AccessibilityGestureEvent(gestureId, displayId); 158 assertWithMessage("Expected " + expected.toString()) 159 .that(getGestureInfoSize()) 160 .isEqualTo(1); 161 AccessibilityGestureEvent received = getGestureInfo(0); 162 assertThat(expected.toString()).isEqualTo(received.toString()); 163 clearGestures(); 164 } 165 166 /** Insure that the specified accessibility events have been received. */ assertPropagated(int... events)167 public void assertPropagated(int... events) { 168 waitUntilEvent(events.length); 169 // Set up readable error reporting. 170 List<String> received = new ArrayList<>(); 171 List<String> expected = new ArrayList<>(); 172 for (int event : events) { 173 expected.add(AccessibilityEvent.eventTypeToString(event)); 174 } 175 for (int i = 0; i < getEventsSize(); ++i) { 176 received.add(AccessibilityEvent.eventTypeToString(getEvent(i))); 177 } 178 assertThat(expected).isEqualTo(received); 179 } 180 } 181