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 
filterForEventTypeWithAction(int eventType, int action)55     public static AccessibilityEventFilter filterForEventTypeWithAction(int eventType, int action) {
56         TypeSafeMatcher<AccessibilityEvent> matchAction =
57                 new PropertyMatcher<>(
58                         action, "Action", (event, expect) -> event.getAction() == action);
59         return (both(new AccessibilityEventTypeMatcher(eventType)).and(matchAction))::matches;
60     }
61 
filterWindowsChangeTypesAndWindowTitle( @onNull UiAutomation uiAutomation, int changeTypes, @NonNull String title)62     public static AccessibilityEventFilter filterWindowsChangeTypesAndWindowTitle(
63             @NonNull UiAutomation uiAutomation, int changeTypes, @NonNull String title) {
64         return allOf(new AccessibilityEventTypeMatcher(AccessibilityEvent.TYPE_WINDOWS_CHANGED),
65                 new WindowChangesMatcher(changeTypes),
66                 new WindowTitleMatcher(uiAutomation, title))::matches;
67     }
68 
filterWindowsChangTypesAndWindowId(int windowId, int changeTypes)69     public static AccessibilityEventFilter filterWindowsChangTypesAndWindowId(int windowId,
70             int changeTypes) {
71         return allOf(new AccessibilityEventTypeMatcher(AccessibilityEvent.TYPE_WINDOWS_CHANGED),
72                 new WindowChangesMatcher(changeTypes),
73                 new WindowIdMatcher(windowId))::matches;
74     }
75 
76     public static class AccessibilityEventTypeMatcher extends TypeSafeMatcher<AccessibilityEvent> {
77         private int mType;
78 
AccessibilityEventTypeMatcher(int type)79         public AccessibilityEventTypeMatcher(int type) {
80             super();
81             mType = type;
82         }
83 
84         @Override
matchesSafely(AccessibilityEvent event)85         protected boolean matchesSafely(AccessibilityEvent event) {
86             return event.getEventType() == mType;
87         }
88 
89         @Override
describeTo(Description description)90         public void describeTo(Description description) {
91             description.appendText("Matching to type " + mType);
92         }
93     }
94 
95     public static class WindowChangesMatcher extends TypeSafeMatcher<AccessibilityEvent> {
96         private int mWindowChanges;
97 
WindowChangesMatcher(int windowChanges)98         public WindowChangesMatcher(int windowChanges) {
99             super();
100             mWindowChanges = windowChanges;
101         }
102 
103         @Override
matchesSafely(AccessibilityEvent event)104         protected boolean matchesSafely(AccessibilityEvent event) {
105             return (event.getWindowChanges() & mWindowChanges) == mWindowChanges;
106         }
107 
108         @Override
describeTo(Description description)109         public void describeTo(Description description) {
110             description.appendText("With window change type " + mWindowChanges);
111         }
112     }
113 
114     public static class ContentChangesMatcher extends TypeSafeMatcher<AccessibilityEvent> {
115         private int mContentChanges;
116 
ContentChangesMatcher(int contentChanges)117         public ContentChangesMatcher(int contentChanges) {
118             super();
119             mContentChanges = contentChanges;
120         }
121 
122         @Override
matchesSafely(AccessibilityEvent event)123         protected boolean matchesSafely(AccessibilityEvent event) {
124             return (event.getContentChangeTypes() & mContentChanges) == mContentChanges;
125         }
126 
127         @Override
describeTo(Description description)128         public void describeTo(Description description) {
129             description.appendText("With content change type " + mContentChanges);
130         }
131     }
132 
133     public static class PropertyMatcher<T> extends TypeSafeMatcher<AccessibilityEvent> {
134         private T mProperty;
135         private String mDescription;
136         private BiPredicate<AccessibilityEvent, T> mComparator;
137 
PropertyMatcher(T property, String description, BiPredicate<AccessibilityEvent, T> comparator)138         public PropertyMatcher(T property, String description,
139                 BiPredicate<AccessibilityEvent, T> comparator) {
140             super();
141             mProperty = property;
142             mDescription = description;
143             mComparator = comparator;
144         }
145 
146         @Override
matchesSafely(AccessibilityEvent event)147         protected boolean matchesSafely(AccessibilityEvent event) {
148             return mComparator.test(event, mProperty);
149         }
150 
151         @Override
describeTo(Description description)152         public void describeTo(Description description) {
153             description.appendText("Matching to " + mDescription + " " + mProperty.toString());
154         }
155     }
156 
157     public static class WindowTitleMatcher extends TypeSafeMatcher<AccessibilityEvent> {
158         private final UiAutomation mUiAutomation;
159         private final String mTitle;
160 
WindowTitleMatcher(@onNull UiAutomation uiAutomation, @NonNull String title)161         public WindowTitleMatcher(@NonNull UiAutomation uiAutomation, @NonNull String title) {
162             super();
163             mUiAutomation = uiAutomation;
164             mTitle = title;
165         }
166 
167         @Override
matchesSafely(AccessibilityEvent event)168         protected boolean matchesSafely(AccessibilityEvent event) {
169             final List<AccessibilityWindowInfo> windows = mUiAutomation.getWindows();
170             final int eventWindowId = event.getWindowId();
171             for (AccessibilityWindowInfo info : windows) {
172                 if (eventWindowId == info.getId() && mTitle.equals(info.getTitle())) {
173                     return true;
174                 }
175             }
176             return false;
177         }
178 
179         @Override
describeTo(Description description)180         public void describeTo(Description description) {
181             description.appendText("With window title " + mTitle);
182         }
183     }
184 
185     public static class WindowIdMatcher extends TypeSafeMatcher<AccessibilityEvent> {
186         private int mWindowId;
187 
WindowIdMatcher(int windowId)188         public WindowIdMatcher(int windowId) {
189             super();
190             mWindowId = windowId;
191         }
192 
193         @Override
matchesSafely(AccessibilityEvent event)194         protected boolean matchesSafely(AccessibilityEvent event) {
195             return event.getWindowId() == mWindowId;
196         }
197 
198         @Override
describeTo(Description description)199         public void describeTo(Description description) {
200             description.appendText("With window Id " + mWindowId);
201         }
202     }
203 }
204