1 /* 2 * Copyright (C) 2012 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 androidx.core.view.accessibility; 18 19 import android.os.Build; 20 import android.os.Bundle; 21 import android.view.accessibility.AccessibilityNodeInfo; 22 import android.view.accessibility.AccessibilityNodeProvider; 23 24 import androidx.annotation.RequiresApi; 25 26 import org.jspecify.annotations.NonNull; 27 import org.jspecify.annotations.Nullable; 28 29 import java.util.ArrayList; 30 import java.util.List; 31 32 /** 33 * Helper for accessing {@link android.view.accessibility.AccessibilityNodeProvider}. 34 * <p> 35 * <aside class="note"> 36 * <b>Note:</b> Consider using a {@link androidx.customview.widget.ExploreByTouchHelper}, a utility 37 * extension of AccessibilityNodeProvider, to simplify many aspects of providing information to 38 * accessibility services and managing accessibility focus. </aside> 39 */ 40 public class AccessibilityNodeProviderCompat { 41 42 static class AccessibilityNodeProviderApi19 extends AccessibilityNodeProvider { 43 final AccessibilityNodeProviderCompat mCompat; 44 AccessibilityNodeProviderApi19(AccessibilityNodeProviderCompat compat)45 AccessibilityNodeProviderApi19(AccessibilityNodeProviderCompat compat) { 46 mCompat = compat; 47 } 48 49 @Override createAccessibilityNodeInfo(int virtualViewId)50 public AccessibilityNodeInfo createAccessibilityNodeInfo(int virtualViewId) { 51 final AccessibilityNodeInfoCompat compatInfo = 52 mCompat.createAccessibilityNodeInfo(virtualViewId); 53 if (compatInfo == null) { 54 return null; 55 } else { 56 return compatInfo.unwrap(); 57 } 58 } 59 60 @Override findAccessibilityNodeInfosByText( String text, int virtualViewId)61 public List<AccessibilityNodeInfo> findAccessibilityNodeInfosByText( 62 String text, int virtualViewId) { 63 final List<AccessibilityNodeInfoCompat> compatInfos = 64 mCompat.findAccessibilityNodeInfosByText(text, virtualViewId); 65 if (compatInfos == null) { 66 return null; 67 } else { 68 final List<AccessibilityNodeInfo> infoList = new ArrayList<>(); 69 final int infoCount = compatInfos.size(); 70 for (int i = 0; i < infoCount; i++) { 71 AccessibilityNodeInfoCompat infoCompat = compatInfos.get(i); 72 infoList.add(infoCompat.unwrap()); 73 } 74 return infoList; 75 } 76 } 77 78 @Override performAction(int virtualViewId, int action, Bundle arguments)79 public boolean performAction(int virtualViewId, int action, Bundle arguments) { 80 return mCompat.performAction(virtualViewId, action, arguments); 81 } 82 83 @Override findFocus(int focus)84 public AccessibilityNodeInfo findFocus(int focus) { 85 final AccessibilityNodeInfoCompat compatInfo = mCompat.findFocus(focus); 86 if (compatInfo == null) { 87 return null; 88 } else { 89 return compatInfo.unwrap(); 90 } 91 } 92 } 93 94 @RequiresApi(26) 95 static class AccessibilityNodeProviderApi26 extends AccessibilityNodeProviderApi19 { AccessibilityNodeProviderApi26(AccessibilityNodeProviderCompat compat)96 AccessibilityNodeProviderApi26(AccessibilityNodeProviderCompat compat) { 97 super(compat); 98 } 99 100 @Override addExtraDataToAccessibilityNodeInfo(int virtualViewId, AccessibilityNodeInfo info, String extraDataKey, Bundle arguments)101 public void addExtraDataToAccessibilityNodeInfo(int virtualViewId, 102 AccessibilityNodeInfo info, String extraDataKey, Bundle arguments) { 103 mCompat.addExtraDataToAccessibilityNodeInfo(virtualViewId, 104 AccessibilityNodeInfoCompat.wrap(info), extraDataKey, arguments); 105 } 106 } 107 108 /** 109 * The virtual id for the hosting View. 110 */ 111 public static final int HOST_VIEW_ID = -1; 112 113 private final @Nullable Object mProvider; 114 115 /** 116 * Creates a new instance. 117 */ AccessibilityNodeProviderCompat()118 public AccessibilityNodeProviderCompat() { 119 if (Build.VERSION.SDK_INT >= 26) { 120 mProvider = new AccessibilityNodeProviderApi26(this); 121 } else { 122 mProvider = new AccessibilityNodeProviderApi19(this); 123 } 124 } 125 126 /** 127 * Creates a new instance wrapping an 128 * {@link android.view.accessibility.AccessibilityNodeProvider}. 129 * 130 * @param provider The provider. 131 */ AccessibilityNodeProviderCompat(@ullable Object provider)132 public AccessibilityNodeProviderCompat(@Nullable Object provider) { 133 mProvider = provider; 134 } 135 136 /** 137 * @return The wrapped {@link android.view.accessibility.AccessibilityNodeProvider}. 138 */ getProvider()139 public @Nullable Object getProvider() { 140 return mProvider; 141 } 142 143 /** 144 * Returns an {@link AccessibilityNodeInfoCompat} representing a virtual view, 145 * i.e. a descendant of the host View, with the given <code>virtualViewId</code> 146 * or the host View itself if <code>virtualViewId</code> equals to {@link #HOST_VIEW_ID}. 147 * <p> 148 * A virtual descendant is an imaginary View that is reported as a part of the view 149 * hierarchy for accessibility purposes. This enables custom views that draw complex 150 * content to report them selves as a tree of virtual views, thus conveying their 151 * logical structure. 152 * </p> 153 * <p> 154 * The implementer is responsible for obtaining an accessibility node info from the 155 * pool of reusable instances and setting the desired properties of the node info 156 * before returning it. 157 * </p> 158 * 159 * @param virtualViewId A client defined virtual view id. 160 * @return A populated {@link AccessibilityNodeInfoCompat} for a virtual descendant 161 * or the host View. 162 * 163 * @see AccessibilityNodeInfoCompat 164 */ createAccessibilityNodeInfo(int virtualViewId)165 public @Nullable AccessibilityNodeInfoCompat createAccessibilityNodeInfo(int virtualViewId) { 166 return null; 167 } 168 169 /** 170 * Performs an accessibility action on a virtual view, i.e. a descendant of the 171 * host View, with the given <code>virtualViewId</code> or the host View itself 172 * if <code>virtualViewId</code> equals to {@link #HOST_VIEW_ID}. 173 * 174 * @param virtualViewId A client defined virtual view id. 175 * @param action The action to perform. 176 * @param arguments Optional arguments. 177 * @return True if the action was performed. 178 * 179 * @see #createAccessibilityNodeInfo(int) 180 * @see AccessibilityNodeInfoCompat 181 */ 182 @SuppressWarnings("unused") performAction(int virtualViewId, int action, @Nullable Bundle arguments)183 public boolean performAction(int virtualViewId, int action, @Nullable Bundle arguments) { 184 return false; 185 } 186 187 /** 188 * Finds {@link AccessibilityNodeInfoCompat}s by text. The match is case insensitive 189 * containment. The search is relative to the virtual view, i.e. a descendant of the 190 * host View, with the given <code>virtualViewId</code> or the host View itself 191 * <code>virtualViewId</code> equals to {@link #HOST_VIEW_ID}. 192 * 193 * @param virtualViewId A client defined virtual view id which defined 194 * the root of the tree in which to perform the search. 195 * @param text The searched text. 196 * @return A list of node info. 197 * 198 * @see #createAccessibilityNodeInfo(int) 199 * @see AccessibilityNodeInfoCompat 200 */ 201 @SuppressWarnings("unused") findAccessibilityNodeInfosByText( @onNull String text, int virtualViewId)202 public @Nullable List<AccessibilityNodeInfoCompat> findAccessibilityNodeInfosByText( 203 @NonNull String text, int virtualViewId) { 204 return null; 205 } 206 207 /** 208 * Find the virtual view, i.e. a descendant of the host View, that has the 209 * specified focus type. 210 * 211 * @param focus The focus to find. One of 212 * {@link AccessibilityNodeInfoCompat#FOCUS_INPUT} or 213 * {@link AccessibilityNodeInfoCompat#FOCUS_ACCESSIBILITY}. 214 * @return The node info of the focused view or null. 215 * @see AccessibilityNodeInfoCompat#FOCUS_INPUT 216 * @see AccessibilityNodeInfoCompat#FOCUS_ACCESSIBILITY 217 */ 218 @SuppressWarnings("unused") findFocus(int focus)219 public @Nullable AccessibilityNodeInfoCompat findFocus(int focus) { 220 return null; 221 } 222 223 /** 224 * Adds extra data to an {@link AccessibilityNodeInfoCompat} based on an explicit request for 225 * the additional data. 226 * <p> 227 * This method only needs to be implemented if a virtual view offers to provide additional 228 * data. 229 * </p> 230 * 231 * @param virtualViewId The virtual view id used to create the node 232 * @param info The info to which to add the extra data 233 * @param extraDataKey A key specifying the type of extra data to add to the info. The 234 * extra data should be added to the {@link Bundle} returned by 235 * the info's {@link AccessibilityNodeInfoCompat#getExtras} method. 236 * @param arguments A {@link Bundle} holding any arguments relevant for this request. 237 * 238 * @see AccessibilityNodeInfo#setAvailableExtraData(List) 239 */ 240 @SuppressWarnings("unused") addExtraDataToAccessibilityNodeInfo(int virtualViewId, @NonNull AccessibilityNodeInfoCompat info, @NonNull String extraDataKey, @Nullable Bundle arguments)241 public void addExtraDataToAccessibilityNodeInfo(int virtualViewId, 242 @NonNull AccessibilityNodeInfoCompat info, @NonNull String extraDataKey, 243 @Nullable Bundle arguments) { 244 } 245 } 246