1/*
2 * Copyright (C) 2011 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
17package android.support.v4.view.accessibility;
18
19import android.os.Build;
20import android.view.accessibility.AccessibilityEvent;
21
22/**
23 * Helper for accessing features in {@link AccessibilityEvent}
24 * introduced after API level 4 in a backwards compatible fashion.
25 */
26public final class AccessibilityEventCompat {
27
28    static interface AccessibilityEventVersionImpl {
29        int getRecordCount(AccessibilityEvent event);
30        void appendRecord(AccessibilityEvent event, Object record);
31        Object getRecord(AccessibilityEvent event, int index);
32        void setContentChangeTypes(AccessibilityEvent event, int types);
33        int getContentChangeTypes(AccessibilityEvent event);
34        public void setMovementGranularity(AccessibilityEvent event, int granularity);
35        public int getMovementGranularity(AccessibilityEvent event);
36        public void setAction(AccessibilityEvent event, int action);
37        public int getAction(AccessibilityEvent event);
38    }
39
40    static class AccessibilityEventStubImpl implements AccessibilityEventVersionImpl {
41
42        @Override
43        public void appendRecord(AccessibilityEvent event, Object record) {
44
45        }
46
47        @Override
48        public Object getRecord(AccessibilityEvent event, int index) {
49            return null;
50        }
51
52        @Override
53        public void setContentChangeTypes(AccessibilityEvent event, int types) {
54
55        }
56
57        @Override
58        public int getRecordCount(AccessibilityEvent event) {
59            return 0;
60        }
61
62        @Override
63        public int getContentChangeTypes(AccessibilityEvent event) {
64            return 0;
65        }
66
67        @Override
68        public void setMovementGranularity(AccessibilityEvent event, int granularity) {
69        }
70
71        @Override
72        public int getMovementGranularity(AccessibilityEvent event) {
73            return 0;
74        }
75
76        @Override
77        public void setAction(AccessibilityEvent event, int action) {
78        }
79
80        @Override
81        public int getAction(AccessibilityEvent event) {
82            return 0;
83        }
84    }
85
86    static class AccessibilityEventIcsImpl extends AccessibilityEventStubImpl {
87
88        @Override
89        public void appendRecord(AccessibilityEvent event, Object record) {
90            AccessibilityEventCompatIcs.appendRecord(event, record);
91        }
92
93        @Override
94        public Object getRecord(AccessibilityEvent event, int index) {
95            return AccessibilityEventCompatIcs.getRecord(event, index);
96        }
97
98        @Override
99        public int getRecordCount(AccessibilityEvent event) {
100            return AccessibilityEventCompatIcs.getRecordCount(event);
101        }
102    }
103
104    static class AccessibilityEventJellyBeanImpl extends AccessibilityEventIcsImpl {
105        @Override
106        public void setMovementGranularity(AccessibilityEvent event, int granularity) {
107            AccessibilityEventCompatJellyBean.setMovementGranularity(event, granularity);
108        }
109
110        @Override
111        public int getMovementGranularity(AccessibilityEvent event) {
112            return AccessibilityEventCompatJellyBean.getMovementGranularity(event);
113        }
114
115        @Override
116        public void setAction(AccessibilityEvent event, int action) {
117            AccessibilityEventCompatJellyBean.setAction(event, action);
118        }
119
120        @Override
121        public int getAction(AccessibilityEvent event) {
122            return AccessibilityEventCompatJellyBean.getAction(event);
123        }
124    }
125
126    static class AccessibilityEventKitKatImpl extends AccessibilityEventJellyBeanImpl {
127
128        @Override
129        public void setContentChangeTypes(AccessibilityEvent event, int types) {
130            AccessibilityEventCompatKitKat.setContentChangeTypes(event, types);
131        }
132
133        @Override
134        public int getContentChangeTypes(AccessibilityEvent event) {
135            return AccessibilityEventCompatKitKat.getContentChangeTypes(event);
136        }
137    }
138
139    private final static AccessibilityEventVersionImpl IMPL;
140
141    static {
142        if (Build.VERSION.SDK_INT >= 19) { // KitKat
143            IMPL = new AccessibilityEventKitKatImpl();
144        } else if (Build.VERSION.SDK_INT >= 16) { // Jellybean
145            IMPL = new AccessibilityEventJellyBeanImpl();
146        } else if (Build.VERSION.SDK_INT >= 14) { // ICS
147            IMPL = new AccessibilityEventIcsImpl();
148        } else {
149            IMPL = new AccessibilityEventStubImpl();
150        }
151    }
152
153    /**
154     * Represents the event of a hover enter over a {@link android.view.View}.
155     */
156    public static final int TYPE_VIEW_HOVER_ENTER = 0x00000080;
157
158    /**
159     * Represents the event of a hover exit over a {@link android.view.View}.
160     */
161    public static final int TYPE_VIEW_HOVER_EXIT = 0x00000100;
162
163    /**
164     * Represents the event of starting a touch exploration gesture.
165     */
166    public static final int TYPE_TOUCH_EXPLORATION_GESTURE_START = 0x00000200;
167
168    /**
169     * Represents the event of ending a touch exploration gesture.
170     */
171    public static final int TYPE_TOUCH_EXPLORATION_GESTURE_END = 0x00000400;
172
173    /**
174     * Represents the event of changing the content of a window.
175     */
176    public static final int TYPE_WINDOW_CONTENT_CHANGED = 0x00000800;
177
178    /**
179     * Represents the event of scrolling a view.
180     */
181    public static final int TYPE_VIEW_SCROLLED = 0x00001000;
182
183    /**
184     * Represents the event of changing the selection in an {@link android.widget.EditText}.
185     */
186    public static final int TYPE_VIEW_TEXT_SELECTION_CHANGED = 0x00002000;
187
188    /**
189     * Represents the event of an application making an announcement.
190     */
191    public static final int TYPE_ANNOUNCEMENT = 0x00004000;
192
193    /**
194     * Represents the event of gaining accessibility focus.
195     */
196    public static final int TYPE_VIEW_ACCESSIBILITY_FOCUSED = 0x00008000;
197
198    /**
199     * Represents the event of clearing accessibility focus.
200     */
201    public static final int TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED = 0x00010000;
202
203    /**
204     * Represents the event of traversing the text of a view at a given movement granularity.
205     */
206    public static final int TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY = 0x00020000;
207
208    /**
209     * Represents the event of beginning gesture detection.
210     */
211    public static final int TYPE_GESTURE_DETECTION_START = 0x00040000;
212
213    /**
214     * Represents the event of ending gesture detection.
215     */
216    public static final int TYPE_GESTURE_DETECTION_END = 0x00080000;
217
218    /**
219     * Represents the event of the user starting to touch the screen.
220     */
221    public static final int TYPE_TOUCH_INTERACTION_START = 0x00100000;
222
223    /**
224     * Represents the event of the user ending to touch the screen.
225     */
226    public static final int TYPE_TOUCH_INTERACTION_END = 0x00200000;
227
228    /**
229     * Represents the event change in the windows shown on the screen.
230     */
231    public static final int TYPE_WINDOWS_CHANGED = 0x00400000;
232
233    /**
234     * Represents the event of a context click on a {@link android.view.View}.
235     */
236    public static final int TYPE_VIEW_CONTEXT_CLICKED = 0x00800000;
237
238    /**
239     * Represents the event of the assistant currently reading the users screen context.
240     */
241    public static final int TYPE_ASSIST_READING_CONTEXT = 0x01000000;
242
243    /**
244     * Change type for {@link #TYPE_WINDOW_CONTENT_CHANGED} event:
245     * The type of change is not defined.
246     */
247    public static final int CONTENT_CHANGE_TYPE_UNDEFINED = 0x00000000;
248
249    /**
250     * Change type for {@link #TYPE_WINDOW_CONTENT_CHANGED} event:
251     * A node in the subtree rooted at the source node was added or removed.
252     */
253    public static final int CONTENT_CHANGE_TYPE_SUBTREE = 0x00000001;
254
255    /**
256     * Change type for {@link #TYPE_WINDOW_CONTENT_CHANGED} event:
257     * The node's text changed.
258     */
259    public static final int CONTENT_CHANGE_TYPE_TEXT = 0x00000002;
260
261    /**
262     * Change type for {@link #TYPE_WINDOW_CONTENT_CHANGED} event:
263     * The node's content description changed.
264     */
265    public static final int CONTENT_CHANGE_TYPE_CONTENT_DESCRIPTION = 0x00000004;
266
267    /**
268     * Mask for {@link AccessibilityEvent} all types.
269     *
270     * @see AccessibilityEvent#TYPE_VIEW_CLICKED
271     * @see AccessibilityEvent#TYPE_VIEW_LONG_CLICKED
272     * @see AccessibilityEvent#TYPE_VIEW_SELECTED
273     * @see AccessibilityEvent#TYPE_VIEW_FOCUSED
274     * @see AccessibilityEvent#TYPE_VIEW_TEXT_CHANGED
275     * @see AccessibilityEvent#TYPE_WINDOW_STATE_CHANGED
276     * @see AccessibilityEvent#TYPE_NOTIFICATION_STATE_CHANGED
277     * @see #TYPE_VIEW_HOVER_ENTER
278     * @see #TYPE_VIEW_HOVER_EXIT
279     * @see #TYPE_TOUCH_EXPLORATION_GESTURE_START
280     * @see #TYPE_TOUCH_EXPLORATION_GESTURE_END
281     * @see #TYPE_WINDOW_CONTENT_CHANGED
282     * @see #TYPE_VIEW_SCROLLED
283     * @see #TYPE_VIEW_TEXT_SELECTION_CHANGED
284     * @see #TYPE_ANNOUNCEMENT
285     * @see #TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
286     * @see #TYPE_GESTURE_DETECTION_START
287     * @see #TYPE_GESTURE_DETECTION_END
288     * @see #TYPE_TOUCH_INTERACTION_START
289     * @see #TYPE_TOUCH_INTERACTION_END
290     */
291    public static final int TYPES_ALL_MASK = 0xFFFFFFFF;
292
293    /*
294     * Hide constructor from clients.
295     */
296    private AccessibilityEventCompat() {
297
298    }
299
300    /**
301     * Gets the number of records contained in the event.
302     *
303     * @return The number of records.
304     */
305    public static int getRecordCount(AccessibilityEvent event) {
306        return IMPL.getRecordCount(event);
307    }
308
309    /**
310     * Appends an {@link android.view.accessibility.AccessibilityRecord} to the end of
311     * event records.
312     *
313     * @param record The record to append.
314     *
315     * @throws IllegalStateException If called from an AccessibilityService.
316     */
317    public static void appendRecord(AccessibilityEvent event, AccessibilityRecordCompat record) {
318        IMPL.appendRecord(event, record.getImpl());
319    }
320
321    /**
322     * Gets the record at a given index.
323     *
324     * @param index The index.
325     * @return The record at the specified index.
326     */
327    public static AccessibilityRecordCompat getRecord(AccessibilityEvent event, int index) {
328        return new AccessibilityRecordCompat(IMPL.getRecord(event, index));
329    }
330
331    /**
332     * Creates an {@link AccessibilityRecordCompat} from an {@link AccessibilityEvent}
333     * that can be used to manipulate the event properties defined in
334     * {@link android.view.accessibility.AccessibilityRecord}.
335     * <p>
336     * <strong>Note:</strong> Do not call {@link AccessibilityRecordCompat#recycle()} on the
337     * returned {@link AccessibilityRecordCompat}. Call {@link AccessibilityEvent#recycle()}
338     * in case you want to recycle the event.
339     * </p>
340     *
341     * @param event The from which to create a record.
342     * @return An {@link AccessibilityRecordCompat}.
343     */
344    public static AccessibilityRecordCompat asRecord(AccessibilityEvent event) {
345        return new AccessibilityRecordCompat(event);
346    }
347
348    /**
349     * Sets the bit mask of node tree changes signaled by an
350     * {@link #TYPE_WINDOW_CONTENT_CHANGED} event.
351     *
352     * @param changeTypes The bit mask of change types.
353     * @throws IllegalStateException If called from an AccessibilityService.
354     * @see #getContentChangeTypes(AccessibilityEvent)
355     */
356    public static void setContentChangeTypes(AccessibilityEvent event, int changeTypes) {
357        IMPL.setContentChangeTypes(event, changeTypes);
358    }
359
360    /**
361     * Gets the bit mask of change types signaled by an
362     * {@link #TYPE_WINDOW_CONTENT_CHANGED} event. A single event may represent
363     * multiple change types.
364     *
365     * @return The bit mask of change types. One or more of:
366     *         <ul>
367     *         <li>{@link AccessibilityEvent#CONTENT_CHANGE_TYPE_CONTENT_DESCRIPTION}
368     *         <li>{@link AccessibilityEvent#CONTENT_CHANGE_TYPE_SUBTREE}
369     *         <li>{@link AccessibilityEvent#CONTENT_CHANGE_TYPE_TEXT}
370     *         <li>{@link AccessibilityEvent#CONTENT_CHANGE_TYPE_UNDEFINED}
371     *         </ul>
372     */
373    public static int getContentChangeTypes(AccessibilityEvent event) {
374        return IMPL.getContentChangeTypes(event);
375    }
376
377    /**
378     * Sets the movement granularity that was traversed.
379     *
380     * @param granularity The granularity.
381     *
382     * @throws IllegalStateException If called from an AccessibilityService.
383     */
384    public void setMovementGranularity(AccessibilityEvent event, int granularity) {
385        IMPL.setMovementGranularity(event, granularity);
386    }
387
388    /**
389     * Gets the movement granularity that was traversed.
390     *
391     * @return The granularity.
392     */
393    public int getMovementGranularity(AccessibilityEvent event) {
394        return IMPL.getMovementGranularity(event);
395    }
396
397    /**
398     * Sets the performed action that triggered this event.
399     * <p>
400     * Valid actions are defined in {@link AccessibilityNodeInfoCompat}:
401     * <ul>
402     * <li>{@link AccessibilityNodeInfoCompat#ACTION_ACCESSIBILITY_FOCUS}
403     * <li>{@link AccessibilityNodeInfoCompat#ACTION_CLEAR_ACCESSIBILITY_FOCUS}
404     * <li>{@link AccessibilityNodeInfoCompat#ACTION_CLEAR_FOCUS}
405     * <li>{@link AccessibilityNodeInfoCompat#ACTION_CLEAR_SELECTION}
406     * <li>{@link AccessibilityNodeInfoCompat#ACTION_CLICK}
407     * <li>etc.
408     * </ul>
409     *
410     * @param action The action.
411     * @throws IllegalStateException If called from an AccessibilityService.
412     * @see AccessibilityNodeInfoCompat#performAction(int)
413     */
414    public void setAction(AccessibilityEvent event, int action) {
415        IMPL.setAction(event, action);
416    }
417
418    /**
419     * Gets the performed action that triggered this event.
420     *
421     * @return The action.
422     */
423    public int getAction(AccessibilityEvent event) {
424        return IMPL.getAction(event);
425    }
426}
427