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.List;
31 import java.util.function.BiPredicate;
32 
33 /**
34  * Utility class for creating AccessibilityEventFilters
35  */
36 public class AccessibilityEventFilterUtils {
filterForEventType(int eventType)37     public static AccessibilityEventFilter filterForEventType(int eventType) {
38         return (new AccessibilityEventTypeMatcher(eventType))::matches;
39     }
40 
filterWindowsChangedWithChangeTypes(int changes)41     public static AccessibilityEventFilter filterWindowsChangedWithChangeTypes(int changes) {
42         return (both(new AccessibilityEventTypeMatcher(AccessibilityEvent.TYPE_WINDOWS_CHANGED))
43                         .and(new WindowChangesMatcher(changes)))::matches;
44     }
45 
filterForEventTypeWithResource(int eventType, String ResourceName)46     public static AccessibilityEventFilter filterForEventTypeWithResource(int eventType,
47             String ResourceName) {
48         TypeSafeMatcher<AccessibilityEvent> matchResourceName = new PropertyMatcher<>(
49                 ResourceName, "Resource name",
50                 (event, expect) -> event.getSource() != null
51                         && event.getSource().getViewIdResourceName().equals(expect));
52         return (both(new AccessibilityEventTypeMatcher(eventType)).and(matchResourceName))::matches;
53     }
54 
filterWindowsChangeTypesAndWindowTitle( @onNull UiAutomation uiAutomation, int changeTypes, @NonNull String title)55     public static AccessibilityEventFilter filterWindowsChangeTypesAndWindowTitle(
56             @NonNull UiAutomation uiAutomation, int changeTypes, @NonNull String title) {
57         return allOf(new AccessibilityEventTypeMatcher(AccessibilityEvent.TYPE_WINDOWS_CHANGED),
58                 new WindowChangesMatcher(changeTypes),
59                 new WindowTitleMatcher(uiAutomation, title))::matches;
60     }
61 
62     public static class AccessibilityEventTypeMatcher extends TypeSafeMatcher<AccessibilityEvent> {
63         private int mType;
64 
AccessibilityEventTypeMatcher(int type)65         public AccessibilityEventTypeMatcher(int type) {
66             super();
67             mType = type;
68         }
69 
70         @Override
matchesSafely(AccessibilityEvent event)71         protected boolean matchesSafely(AccessibilityEvent event) {
72             return event.getEventType() == mType;
73         }
74 
75         @Override
describeTo(Description description)76         public void describeTo(Description description) {
77             description.appendText("Matching to type " + mType);
78         }
79     }
80 
81     public static class WindowChangesMatcher extends TypeSafeMatcher<AccessibilityEvent> {
82         private int mWindowChanges;
83 
WindowChangesMatcher(int windowChanges)84         public WindowChangesMatcher(int windowChanges) {
85             super();
86             mWindowChanges = windowChanges;
87         }
88 
89         @Override
matchesSafely(AccessibilityEvent event)90         protected boolean matchesSafely(AccessibilityEvent event) {
91             return (event.getWindowChanges() & mWindowChanges) == mWindowChanges;
92         }
93 
94         @Override
describeTo(Description description)95         public void describeTo(Description description) {
96             description.appendText("With window change type " + mWindowChanges);
97         }
98     }
99 
100     public static class ContentChangesMatcher extends TypeSafeMatcher<AccessibilityEvent> {
101         private int mContentChanges;
102 
ContentChangesMatcher(int contentChanges)103         public ContentChangesMatcher(int contentChanges) {
104             super();
105             mContentChanges = contentChanges;
106         }
107 
108         @Override
matchesSafely(AccessibilityEvent event)109         protected boolean matchesSafely(AccessibilityEvent event) {
110             return (event.getContentChangeTypes() & mContentChanges) == mContentChanges;
111         }
112 
113         @Override
describeTo(Description description)114         public void describeTo(Description description) {
115             description.appendText("With content change type " + mContentChanges);
116         }
117     }
118 
119     public static class PropertyMatcher<T> extends TypeSafeMatcher<AccessibilityEvent> {
120         private T mProperty;
121         private String mDescription;
122         private BiPredicate<AccessibilityEvent, T> mComparator;
123 
PropertyMatcher(T property, String description, BiPredicate<AccessibilityEvent, T> comparator)124         public PropertyMatcher(T property, String description,
125                 BiPredicate<AccessibilityEvent, T> comparator) {
126             super();
127             mProperty = property;
128             mDescription = description;
129             mComparator = comparator;
130         }
131 
132         @Override
matchesSafely(AccessibilityEvent event)133         protected boolean matchesSafely(AccessibilityEvent event) {
134             return mComparator.test(event, mProperty);
135         }
136 
137         @Override
describeTo(Description description)138         public void describeTo(Description description) {
139             description.appendText("Matching to " + mDescription + " " + mProperty.toString());
140         }
141     }
142 
143     public static class WindowTitleMatcher extends TypeSafeMatcher<AccessibilityEvent> {
144         private final UiAutomation mUiAutomation;
145         private final String mTitle;
146 
WindowTitleMatcher(@onNull UiAutomation uiAutomation, @NonNull String title)147         public WindowTitleMatcher(@NonNull UiAutomation uiAutomation, @NonNull String title) {
148             super();
149             mUiAutomation = uiAutomation;
150             mTitle = title;
151         }
152 
153         @Override
matchesSafely(AccessibilityEvent event)154         protected boolean matchesSafely(AccessibilityEvent event) {
155             final List<AccessibilityWindowInfo> windows = mUiAutomation.getWindows();
156             final int eventWindowId = event.getWindowId();
157             for (AccessibilityWindowInfo info : windows) {
158                 if (eventWindowId == info.getId() && mTitle.equals(info.getTitle())) {
159                     return true;
160                 }
161             }
162             return false;
163         }
164 
165         @Override
describeTo(Description description)166         public void describeTo(Description description) {
167             description.appendText("With window title " + mTitle);
168         }
169     }
170 }
171