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