• 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"); you may not use this file except
5  * in compliance with the License. You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software distributed under the
10  * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
11  * express or implied. See the License for the specific language governing permissions and
12  * limitations under the License.
13  */
14 
15 package android.accessibilityservice.cts.utils;
16 
17 import static org.hamcrest.CoreMatchers.allOf;
18 import static org.hamcrest.CoreMatchers.both;
19 
20 import android.app.UiAutomation;
21 import android.app.UiAutomation.AccessibilityEventFilter;
22 import android.view.accessibility.AccessibilityEvent;
23 import android.view.accessibility.AccessibilityWindowInfo;
24 
25 import androidx.annotation.NonNull;
26 
27 import org.hamcrest.Description;
28 import org.hamcrest.TypeSafeMatcher;
29 
30 import java.util.Arrays;
31 import java.util.LinkedList;
32 import java.util.List;
33 import java.util.function.BiPredicate;
34 
35 /**
36  * Utility class for creating AccessibilityEventFilters
37  */
38 public class AccessibilityEventFilterUtils {
filterForEventType(int eventType)39     public static AccessibilityEventFilter filterForEventType(int eventType) {
40         return (new AccessibilityEventTypeMatcher(eventType))::matches;
41     }
42 
filterWindowContentChangedWithChangeTypes(int changes)43     public static AccessibilityEventFilter filterWindowContentChangedWithChangeTypes(int changes) {
44         return (both(new AccessibilityEventTypeMatcher(
45                 AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED)).and(
46                         new ContentChangesMatcher(changes)))::matches;
47     }
48 
filterWindowsChangedWithChangeTypes(int changes)49     public static AccessibilityEventFilter filterWindowsChangedWithChangeTypes(int changes) {
50         return (both(new AccessibilityEventTypeMatcher(AccessibilityEvent.TYPE_WINDOWS_CHANGED))
51                         .and(new WindowChangesMatcher(changes)))::matches;
52     }
53 
filterForEventTypeWithResource(int eventType, String ResourceName)54     public static AccessibilityEventFilter filterForEventTypeWithResource(int eventType,
55             String ResourceName) {
56         TypeSafeMatcher<AccessibilityEvent> matchResourceName = new PropertyMatcher<>(
57                 ResourceName, "Resource name",
58                 (event, expect) -> event.getSource() != null
59                         && event.getSource().getViewIdResourceName().equals(expect));
60         return (both(new AccessibilityEventTypeMatcher(eventType)).and(matchResourceName))::matches;
61     }
62 
filterForEventTypeWithAction(int eventType, int action)63     public static AccessibilityEventFilter filterForEventTypeWithAction(int eventType, int action) {
64         TypeSafeMatcher<AccessibilityEvent> matchAction =
65                 new PropertyMatcher<>(
66                         action, "Action", (event, expect) -> event.getAction() == action);
67         return (both(new AccessibilityEventTypeMatcher(eventType)).and(matchAction))::matches;
68     }
69 
filterWindowsChangeTypesAndWindowTitle( @onNull UiAutomation uiAutomation, int changeTypes, @NonNull String title)70     public static AccessibilityEventFilter filterWindowsChangeTypesAndWindowTitle(
71             @NonNull UiAutomation uiAutomation, int changeTypes, @NonNull String title) {
72         return allOf(new AccessibilityEventTypeMatcher(AccessibilityEvent.TYPE_WINDOWS_CHANGED),
73                 new WindowChangesMatcher(changeTypes),
74                 new WindowTitleMatcher(uiAutomation, title))::matches;
75     }
76 
filterWindowsChangTypesAndWindowId(int windowId, int changeTypes)77     public static AccessibilityEventFilter filterWindowsChangTypesAndWindowId(int windowId,
78             int changeTypes) {
79         return allOf(new AccessibilityEventTypeMatcher(AccessibilityEvent.TYPE_WINDOWS_CHANGED),
80                 new WindowChangesMatcher(changeTypes),
81                 new WindowIdMatcher(windowId))::matches;
82     }
83 
84     /**
85      * Creates an {@link AccessibilityEventFilter} that returns {@code true} once all the given
86      * filters return {@code true} for any event.
87      * Each given filters are invoked on every AccessibilityEvent until it returns {@code true}.
88      * After all filters return {@code true} once, the created filter returns {@code true} forever.
89      */
filterWaitForAll(AccessibilityEventFilter... filters)90     public static AccessibilityEventFilter filterWaitForAll(AccessibilityEventFilter... filters) {
91         return new AccessibilityEventFilter() {
92             private final List<AccessibilityEventFilter> mUnresolved =
93                     new LinkedList<>(Arrays.asList(filters));
94 
95             @Override
96             public boolean accept(AccessibilityEvent event) {
97                 mUnresolved.removeIf(filter -> filter.accept(event));
98                 return mUnresolved.isEmpty();
99             }
100         };
101     }
102 
103     /**
104      * Returns a matcher for a display id from getDisplayId().
105      * @param displayId the display id to match.
106      * @return a matcher for comparing display ids.
107      */
matcherForDisplayId(int displayId)108     public static TypeSafeMatcher<AccessibilityEvent> matcherForDisplayId(int displayId) {
109         final TypeSafeMatcher<AccessibilityEvent> matchAction =
110                 new PropertyMatcher<>(
111                         displayId, "Display id",
112                         (event, expect) -> event.getDisplayId() == displayId);
113         return matchAction;
114     }
115 
116     /**
117      * Returns a matcher for a class name from getClassName().
118      * @param className the class name to match.
119      * @return a matcher for comparing class names.
120      */
matcherForClassName(CharSequence className)121     public static TypeSafeMatcher<AccessibilityEvent> matcherForClassName(CharSequence className) {
122         final TypeSafeMatcher<AccessibilityEvent> matchAction =
123                 new PropertyMatcher<>(
124                         className, "Class name",
125                         (event, expect) -> event.getClassName().equals(className));
126         return matchAction;
127     }
128 
129     /**
130      * Returns a matcher for the first text instance from getText().
131      * @param text the text to match.
132      * @return a matcher for comparing first text instances.
133      */
matcherForFirstText(CharSequence text)134     public static TypeSafeMatcher<AccessibilityEvent> matcherForFirstText(CharSequence text) {
135         final TypeSafeMatcher<AccessibilityEvent> matchAction =
136                 new PropertyMatcher<>(
137                         text, "Text",
138                         (event, expect) -> {
139                             if (event.getText() != null && event.getText().size() > 0) {
140                                 return event.getText().get(0).equals(text);
141                             }
142                             return false;
143                         });
144         return matchAction;
145     }
146 
147     public static class AccessibilityEventTypeMatcher extends TypeSafeMatcher<AccessibilityEvent> {
148         private int mType;
149 
AccessibilityEventTypeMatcher(int type)150         public AccessibilityEventTypeMatcher(int type) {
151             super();
152             mType = type;
153         }
154 
155         @Override
matchesSafely(AccessibilityEvent event)156         protected boolean matchesSafely(AccessibilityEvent event) {
157             return event.getEventType() == mType;
158         }
159 
160         @Override
describeTo(Description description)161         public void describeTo(Description description) {
162             description.appendText("Matching to type " + mType);
163         }
164     }
165 
166     public static class WindowChangesMatcher extends TypeSafeMatcher<AccessibilityEvent> {
167         private int mWindowChanges;
168 
WindowChangesMatcher(int windowChanges)169         public WindowChangesMatcher(int windowChanges) {
170             super();
171             mWindowChanges = windowChanges;
172         }
173 
174         @Override
matchesSafely(AccessibilityEvent event)175         protected boolean matchesSafely(AccessibilityEvent event) {
176             return (event.getWindowChanges() & mWindowChanges) == mWindowChanges;
177         }
178 
179         @Override
describeTo(Description description)180         public void describeTo(Description description) {
181             description.appendText("With window change type " + mWindowChanges);
182         }
183     }
184 
185     public static class ContentChangesMatcher extends TypeSafeMatcher<AccessibilityEvent> {
186         private int mContentChanges;
187 
ContentChangesMatcher(int contentChanges)188         public ContentChangesMatcher(int contentChanges) {
189             super();
190             mContentChanges = contentChanges;
191         }
192 
193         @Override
matchesSafely(AccessibilityEvent event)194         protected boolean matchesSafely(AccessibilityEvent event) {
195             return (event.getContentChangeTypes() & mContentChanges) == mContentChanges;
196         }
197 
198         @Override
describeTo(Description description)199         public void describeTo(Description description) {
200             description.appendText("With content change type " + mContentChanges);
201         }
202     }
203 
204     public static class PropertyMatcher<T> extends TypeSafeMatcher<AccessibilityEvent> {
205         private T mProperty;
206         private String mDescription;
207         private BiPredicate<AccessibilityEvent, T> mComparator;
208 
PropertyMatcher(T property, String description, BiPredicate<AccessibilityEvent, T> comparator)209         public PropertyMatcher(T property, String description,
210                 BiPredicate<AccessibilityEvent, T> comparator) {
211             super();
212             mProperty = property;
213             mDescription = description;
214             mComparator = comparator;
215         }
216 
217         @Override
matchesSafely(AccessibilityEvent event)218         protected boolean matchesSafely(AccessibilityEvent event) {
219             return mComparator.test(event, mProperty);
220         }
221 
222         @Override
describeTo(Description description)223         public void describeTo(Description description) {
224             description.appendText("Matching to " + mDescription + " " + mProperty.toString());
225         }
226     }
227 
228     public static class WindowTitleMatcher extends TypeSafeMatcher<AccessibilityEvent> {
229         private final UiAutomation mUiAutomation;
230         private final String mTitle;
231 
WindowTitleMatcher(@onNull UiAutomation uiAutomation, @NonNull String title)232         public WindowTitleMatcher(@NonNull UiAutomation uiAutomation, @NonNull String title) {
233             super();
234             mUiAutomation = uiAutomation;
235             mTitle = title;
236         }
237 
238         @Override
matchesSafely(AccessibilityEvent event)239         protected boolean matchesSafely(AccessibilityEvent event) {
240             final List<AccessibilityWindowInfo> windows = mUiAutomation.getWindows();
241             final int eventWindowId = event.getWindowId();
242             for (AccessibilityWindowInfo info : windows) {
243                 if (eventWindowId == info.getId() && mTitle.equals(info.getTitle())) {
244                     return true;
245                 }
246             }
247             return false;
248         }
249 
250         @Override
describeTo(Description description)251         public void describeTo(Description description) {
252             description.appendText("With window title " + mTitle);
253         }
254     }
255 
256     public static class WindowIdMatcher extends TypeSafeMatcher<AccessibilityEvent> {
257         private int mWindowId;
258 
WindowIdMatcher(int windowId)259         public WindowIdMatcher(int windowId) {
260             super();
261             mWindowId = windowId;
262         }
263 
264         @Override
matchesSafely(AccessibilityEvent event)265         protected boolean matchesSafely(AccessibilityEvent event) {
266             return event.getWindowId() == mWindowId;
267         }
268 
269         @Override
describeTo(Description description)270         public void describeTo(Description description) {
271             description.appendText("With window Id " + mWindowId);
272         }
273     }
274 }
275