• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
17 package android.view.accessibility;
18 
19 import android.accessibilityservice.AccessibilityService;
20 import android.annotation.Nullable;
21 import android.os.Bundle;
22 import android.view.View;
23 
24 import java.util.List;
25 
26 /**
27  * This class is the contract a client should implement to enable support of a
28  * virtual view hierarchy rooted at a given view for accessibility purposes. A virtual
29  * view hierarchy is a tree of imaginary Views that is reported as a part of the view
30  * hierarchy when an {@link AccessibilityService} explores the window content.
31  * Since the virtual View tree does not exist this class is responsible for
32  * managing the {@link AccessibilityNodeInfo}s describing that tree to accessibility
33  * services.
34  * </p>
35  * <p>
36  * The main use case of these APIs is to enable a custom view that draws complex content,
37  * for example a monthly calendar grid, to be presented as a tree of logical nodes,
38  * for example month days each containing events, thus conveying its logical structure.
39  * <p>
40  * <p>
41  * A typical use case is to override {@link View#getAccessibilityNodeProvider()} of the
42  * View that is a root of a virtual View hierarchy to return an instance of this class.
43  * In such a case this instance is responsible for managing {@link AccessibilityNodeInfo}s
44  * describing the virtual sub-tree rooted at the View including the one representing the
45  * View itself. Similarly the returned instance is responsible for performing accessibility
46  * actions on any virtual view or the root view itself. For example:
47  * </p>
48  * <aside class="note">
49  * <b>Note:</b> Consider using a {@link androidx.customview.widget.ExploreByTouchHelper}, a utility
50  * extension of AccessibilityNodeProvider, to simplify many aspects of providing information to
51  * accessibility services and managing accessibility focus. </aside>
52  * <div>
53  * <div class="ds-selector-tabs"><section><h3 id="kotlin">Kotlin</h3>
54  * <pre class="prettyprint lang-kotlin">
55  * // "view" is the View instance on which this class performs accessibility functions.
56  * class MyCalendarViewAccessibilityDelegate(
57  *       private var view: MyCalendarView) : AccessibilityDelegate() {
58  *     override fun getAccessibilityNodeProvider(host: View): AccessibilityNodeProvider {
59  *         return object : AccessibilityNodeProvider() {
60  *             override fun createAccessibilityNodeInfo(virtualViewId: Int):
61  *                     AccessibilityNodeInfo? {
62  *                 when (virtualViewId) {
63  *                     <var>host-view-id</var> -&gt; {
64  *                         val node = AccessibilityNodeInfo.obtain(view)
65  *                         node.addChild(view, <var>child-view-id</var>)
66  *                         // Set other attributes like screenReaderFocusable
67  *                         // and contentDescription.
68  *                         return node
69  *                     }
70  *                     <var>child-view-id</var> -&gt; {
71  *                         val node = AccessibilityNodeInfo
72  *                                 .obtain(view, virtualViewId)
73  *                         node.setParent(view)
74  *                         node.addAction(ACTION_SCROLL_UP)
75  *                         node.addAction(ACTION_SCROLL_DOWN)
76  *                         // Set other attributes like focusable and visibleToUser.
77  *                         node.setBoundsInScreen(
78  *                                 Rect(<var>coords-of-edges-relative-to-screen</var>))
79  *                         return node
80  *                     }
81  *                     else -&gt; return null
82  *                 }
83  *             }
84  *
85  *             override fun performAction(
86  *                 virtualViewId: Int,
87  *                 action: Int,
88  *                 arguments: Bundle
89  *             ): Boolean {
90  *                 if (virtualViewId == <var>host-view-id</var>) {
91  *                     return view.performAccessibilityAction(action, arguments)
92  *                 }
93  *                 when (action) {
94  *                     ACTION_SCROLL_UP.id -&gt; {
95  *                         // Implement logic in a separate method.
96  *                         navigateToPreviousMonth()
97  *
98  *                         return true
99  *                     }
100  *                     ACTION_SCROLL_DOWN.id -&gt;
101  *                         // Implement logic in a separate method.
102  *                         navigateToNextMonth()
103  *
104  *                         return true
105  *                     else -&gt; return false
106  *                 }
107  *             }
108  *         }
109  *     }
110  * }
111  * </pre>
112  * </section><section><h3 id="java">Java</h3>
113  * <pre class="prettyprint lang-java">
114  * final class MyCalendarViewAccessibilityDelegate extends AccessibilityDelegate {
115  *     // The View instance on which this class performs accessibility functions.
116  *     private final MyCalendarView view;
117  *
118  *     MyCalendarViewAccessibilityDelegate(MyCalendarView view) {
119  *         this.view = view;
120  *     }
121  *
122  *     &#64;Override
123  *     public AccessibilityNodeProvider getAccessibilityNodeProvider(View host) {
124  *         return new AccessibilityNodeProvider() {
125  *             &#64;Override
126  *             &#64;Nullable
127  *             public AccessibilityNodeInfo createAccessibilityNodeInfo(int virtualViewId) {
128  *                 if (virtualViewId == <var>host-view-id</var>) {
129  *                     AccessibilityNodeInfo node = AccessibilityNodeInfo.obtain(view);
130  *                     node.addChild(view, <var>child-view-id</var>);
131  *                     // Set other attributes like screenReaderFocusable and contentDescription.
132  *                     return node;
133  *                 } else if (virtualViewId == <var>child-view-id</var>) {
134  *                     AccessibilityNodeInfo node =
135  *                         AccessibilityNodeInfo.obtain(view, virtualViewId);
136  *                     node.setParent(view);
137  *                     node.addAction(ACTION_SCROLL_UP);
138  *                     node.addAction(ACTION_SCROLL_DOWN);
139  *                     // Set other attributes like focusable and visibleToUser.
140  *                     node.setBoundsInScreen(
141  *                         new Rect(<var>coordinates-of-edges-relative-to-screen</var>));
142  *                     return node;
143  *                 } else {
144  *                     return null;
145  *                 }
146  *             }
147  *
148  *             &#64;Override
149  *             public boolean performAction(int virtualViewId, int action, Bundle arguments) {
150  *                 if (virtualViewId == <var>host-view-id</var>) {
151  *                     return view.performAccessibilityAction(action, arguments);
152  *                 }
153  *
154  *                 if (action == ACTION_SCROLL_UP.getId()) {
155  *                     // Implement logic in a separate method.
156  *                     navigateToPreviousMonth();
157  *
158  *                     return true;
159  *                 } else if (action == ACTION_SCROLL_DOWN.getId()) {
160  *                     // Implement logic in a separate method.
161  *                     navigateToNextMonth();
162  *
163  *                     return true;
164  *                 } else {
165  *                     return false;
166  *                 }
167  *             }
168  *         };
169  *     }
170  * }
171  * </pre></section></div></div>
172  */
173 public abstract class AccessibilityNodeProvider {
174 
175     /**
176      * The virtual id for the hosting View.
177      */
178     public static final int HOST_VIEW_ID = -1;
179 
180     /**
181      * Returns an {@link AccessibilityNodeInfo} representing a virtual view,
182      * such as a descendant of the host View, with the given <code>virtualViewId</code>
183      * or the host View itself if <code>virtualViewId</code> equals to {@link #HOST_VIEW_ID}.
184      * <p>
185      * A virtual descendant is an imaginary View that is reported as a part of the view
186      * hierarchy for accessibility purposes. This enables custom views that draw complex
187      * content to report them selves as a tree of virtual views, thus conveying their
188      * logical structure.
189      * </p>
190      * <p>
191      * The implementer is responsible for obtaining an accessibility node info from the
192      * pool of reusable instances and setting the desired properties of the node info
193      * before returning it.
194      * </p>
195      *
196      * @param virtualViewId A client defined virtual view id.
197      * @return A populated {@link AccessibilityNodeInfo} for a virtual descendant or the
198      *     host View.
199      *
200      * @see View#createAccessibilityNodeInfo()
201      * @see AccessibilityNodeInfo
202      */
createAccessibilityNodeInfo(int virtualViewId)203     public @Nullable AccessibilityNodeInfo createAccessibilityNodeInfo(int virtualViewId) {
204         return null;
205     }
206 
207     /**
208      * Adds extra data to an {@link AccessibilityNodeInfo} based on an explicit request for the
209      * additional data.
210      * <p>
211      * This method only needs to be implemented if a virtual view offers to provide additional
212      * data.
213      * </p>
214      *
215      * @param virtualViewId The virtual view id used to create the node
216      * @param info The info to which to add the extra data
217      * @param extraDataKey A key specifying the type of extra data to add to the info. The
218      *                     extra data should be added to the {@link Bundle} returned by
219      *                     the info's {@link AccessibilityNodeInfo#getExtras} method.
220      * @param arguments A {@link Bundle} holding any arguments relevant for this request.
221      *
222      * @see AccessibilityNodeInfo#setAvailableExtraData(List)
223      */
addExtraDataToAccessibilityNodeInfo( int virtualViewId, AccessibilityNodeInfo info, String extraDataKey, Bundle arguments)224     public void addExtraDataToAccessibilityNodeInfo(
225             int virtualViewId, AccessibilityNodeInfo info, String extraDataKey, Bundle arguments) {
226     }
227 
228     /**
229      * Performs an accessibility action on a virtual view, such as a descendant of the
230      * host View, with the given <code>virtualViewId</code> or the host View itself
231      * if <code>virtualViewId</code> equals to {@link #HOST_VIEW_ID}.
232      *
233      * @param virtualViewId A client defined virtual view id.
234      * @param action The action to perform.
235      * @param arguments Optional action arguments.
236      * @return True if the action was performed.
237      *
238      * @see View#performAccessibilityAction(int, Bundle)
239      * @see #createAccessibilityNodeInfo(int)
240      * @see AccessibilityNodeInfo
241      */
performAction(int virtualViewId, int action, @Nullable Bundle arguments)242     public boolean performAction(int virtualViewId, int action, @Nullable Bundle arguments) {
243         return false;
244     }
245 
246     /**
247      * Finds {@link AccessibilityNodeInfo}s by text. The match is case insensitive
248      * containment. The search is relative to the virtual view, i.e. a descendant of the
249      * host View, with the given <code>virtualViewId</code> or the host View itself
250      * <code>virtualViewId</code> equals to {@link #HOST_VIEW_ID}.
251      *
252      * @param virtualViewId A client defined virtual view id which defined
253      *     the root of the tree in which to perform the search.
254      * @param text The searched text.
255      * @return A list of node info.
256      *
257      * @see #createAccessibilityNodeInfo(int)
258      * @see AccessibilityNodeInfo
259      */
findAccessibilityNodeInfosByText(String text, int virtualViewId)260     public @Nullable List<AccessibilityNodeInfo> findAccessibilityNodeInfosByText(String text,
261             int virtualViewId) {
262         return null;
263     }
264 
265     /**
266      * Find the virtual view, such as a descendant of the host View, that has the
267      * specified focus type.
268      *
269      * @param focus The focus to find. One of
270      *            {@link AccessibilityNodeInfo#FOCUS_INPUT} or
271      *            {@link AccessibilityNodeInfo#FOCUS_ACCESSIBILITY}.
272      * @return The node info of the focused view or null.
273      * @see AccessibilityNodeInfo#FOCUS_INPUT
274      * @see AccessibilityNodeInfo#FOCUS_ACCESSIBILITY
275      */
findFocus(int focus)276     public @Nullable AccessibilityNodeInfo findFocus(int focus) {
277         return null;
278     }
279 }
280