AccessibilityWindowInfoCompat.java revision ac5fe7c617c66850fff75a9fce9979c6e5674b0f
1/* 2 * Copyright (C) 2015 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 androidx.core.view.accessibility; 18 19import static android.os.Build.VERSION.SDK_INT; 20 21import android.graphics.Rect; 22import android.view.accessibility.AccessibilityWindowInfo; 23 24/** 25 * Helper for accessing {@link android.view.accessibility.AccessibilityWindowInfo}. 26 */ 27public class AccessibilityWindowInfoCompat { 28 private Object mInfo; 29 30 private static final int UNDEFINED = -1; 31 32 /** 33 * Window type: This is an application window. Such a window shows UI for 34 * interacting with an application. 35 */ 36 public static final int TYPE_APPLICATION = 1; 37 38 /** 39 * Window type: This is an input method window. Such a window shows UI for 40 * inputting text such as keyboard, suggestions, etc. 41 */ 42 public static final int TYPE_INPUT_METHOD = 2; 43 44 /** 45 * Window type: This is an system window. Such a window shows UI for 46 * interacting with the system. 47 */ 48 public static final int TYPE_SYSTEM = 3; 49 50 /** 51 * Window type: Windows that are overlaid <em>only</em> by an {@link 52 * android.accessibilityservice.AccessibilityService} for interception of 53 * user interactions without changing the windows an accessibility service 54 * can introspect. In particular, an accessibility service can introspect 55 * only windows that a sighted user can interact with which they can touch 56 * these windows or can type into these windows. For example, if there 57 * is a full screen accessibility overlay that is touchable, the windows 58 * below it will be introspectable by an accessibility service regardless 59 * they are covered by a touchable window. 60 */ 61 public static final int TYPE_ACCESSIBILITY_OVERLAY = 4; 62 63 /** 64 * Window type: A system window used to divide the screen in split-screen mode. 65 * This type of window is present only in split-screen mode. 66 */ 67 public static final int TYPE_SPLIT_SCREEN_DIVIDER = 5; 68 69 /** 70 * Creates a wrapper for info implementation. 71 * 72 * @param object The info to wrap. 73 * @return A wrapper for if the object is not null, null otherwise. 74 */ 75 static AccessibilityWindowInfoCompat wrapNonNullInstance(Object object) { 76 if (object != null) { 77 return new AccessibilityWindowInfoCompat(object); 78 } 79 return null; 80 } 81 82 private AccessibilityWindowInfoCompat(Object info) { 83 mInfo = info; 84 } 85 86 /** 87 * Gets the type of the window. 88 * 89 * @return The type. 90 * 91 * @see #TYPE_APPLICATION 92 * @see #TYPE_INPUT_METHOD 93 * @see #TYPE_SYSTEM 94 * @see #TYPE_ACCESSIBILITY_OVERLAY 95 */ 96 public int getType() { 97 if (SDK_INT >= 21) { 98 return ((AccessibilityWindowInfo) mInfo).getType(); 99 } else { 100 return UNDEFINED; 101 } 102 } 103 104 /** 105 * Gets the layer which determines the Z-order of the window. Windows 106 * with greater layer appear on top of windows with lesser layer. 107 * 108 * @return The window layer. 109 */ 110 public int getLayer() { 111 if (SDK_INT >= 21) { 112 return ((AccessibilityWindowInfo) mInfo).getLayer(); 113 } else { 114 return UNDEFINED; 115 } 116 } 117 118 /** 119 * Gets the root node in the window's hierarchy. 120 * 121 * @return The root node. 122 */ 123 public AccessibilityNodeInfoCompat getRoot() { 124 if (SDK_INT >= 21) { 125 return AccessibilityNodeInfoCompat.wrapNonNullInstance( 126 ((AccessibilityWindowInfo) mInfo).getRoot()); 127 } else { 128 return null; 129 } 130 } 131 132 /** 133 * Gets the parent window if such. 134 * 135 * @return The parent window. 136 */ 137 public AccessibilityWindowInfoCompat getParent() { 138 if (SDK_INT >= 21) { 139 return wrapNonNullInstance(((AccessibilityWindowInfo) mInfo).getParent()); 140 } else { 141 return null; 142 } 143 } 144 145 /** 146 * Gets the unique window id. 147 * 148 * @return windowId The window id. 149 */ 150 public int getId() { 151 if (SDK_INT >= 21) { 152 return ((AccessibilityWindowInfo) mInfo).getId(); 153 } else { 154 return UNDEFINED; 155 } 156 } 157 158 /** 159 * Gets the bounds of this window in the screen. 160 * 161 * @param outBounds The out window bounds. 162 */ 163 public void getBoundsInScreen(Rect outBounds) { 164 if (SDK_INT >= 21) { 165 ((AccessibilityWindowInfo) mInfo).getBoundsInScreen(outBounds); 166 } 167 } 168 169 /** 170 * Gets if this window is active. An active window is the one 171 * the user is currently touching or the window has input focus 172 * and the user is not touching any window. 173 * 174 * @return Whether this is the active window. 175 */ 176 public boolean isActive() { 177 if (SDK_INT >= 21) { 178 return ((AccessibilityWindowInfo) mInfo).isActive(); 179 } else { 180 return true; 181 } 182 } 183 184 /** 185 * Gets if this window has input focus. 186 * 187 * @return Whether has input focus. 188 */ 189 public boolean isFocused() { 190 if (SDK_INT >= 21) { 191 return ((AccessibilityWindowInfo) mInfo).isFocused(); 192 } else { 193 return true; 194 } 195 } 196 197 /** 198 * Gets if this window has accessibility focus. 199 * 200 * @return Whether has accessibility focus. 201 */ 202 public boolean isAccessibilityFocused() { 203 if (SDK_INT >= 21) { 204 return ((AccessibilityWindowInfo) mInfo).isAccessibilityFocused(); 205 } else { 206 return true; 207 } 208 } 209 210 /** 211 * Gets the number of child windows. 212 * 213 * @return The child count. 214 */ 215 public int getChildCount() { 216 if (SDK_INT >= 21) { 217 return ((AccessibilityWindowInfo) mInfo).getChildCount(); 218 } else { 219 return 0; 220 } 221 } 222 223 /** 224 * Gets the child window at a given index. 225 * 226 * @param index The index. 227 * @return The child. 228 */ 229 public AccessibilityWindowInfoCompat getChild(int index) { 230 if (SDK_INT >= 21) { 231 return wrapNonNullInstance(((AccessibilityWindowInfo) mInfo).getChild(index)); 232 } else { 233 return null; 234 } 235 } 236 237 /** 238 * Gets the title of the window. 239 * 240 * @return The title of the window, or the application label for the window if no title was 241 * explicitly set, or {@code null} if neither is available. 242 */ 243 public CharSequence getTitle() { 244 if (SDK_INT >= 24) { 245 return ((AccessibilityWindowInfo) mInfo).getTitle(); 246 } else { 247 return null; 248 } 249 } 250 251 /** 252 * Gets the node that anchors this window to another. 253 * 254 * @return The anchor node, or {@code null} if none exists. 255 */ 256 public AccessibilityNodeInfoCompat getAnchor() { 257 if (SDK_INT >= 24) { 258 return AccessibilityNodeInfoCompat.wrapNonNullInstance( 259 ((AccessibilityWindowInfo) mInfo).getAnchor()); 260 } else { 261 return null; 262 } 263 } 264 265 /** 266 * Returns a cached instance if such is available or a new one is 267 * created. 268 * 269 * @return An instance. 270 */ 271 public static AccessibilityWindowInfoCompat obtain() { 272 if (SDK_INT >= 21) { 273 return wrapNonNullInstance(AccessibilityWindowInfo.obtain()); 274 } else { 275 return null; 276 } 277 } 278 279 /** 280 * Returns a cached instance if such is available or a new one is 281 * created. The returned instance is initialized from the given 282 * <code>info</code>. 283 * 284 * @param info The other info. 285 * @return An instance. 286 */ 287 public static AccessibilityWindowInfoCompat obtain(AccessibilityWindowInfoCompat info) { 288 if (SDK_INT >= 21) { 289 return info == null 290 ? null 291 : wrapNonNullInstance( 292 AccessibilityWindowInfo.obtain((AccessibilityWindowInfo) info.mInfo)); 293 } else { 294 return null; 295 } 296 } 297 298 /** 299 * Return an instance back to be reused. 300 * <p> 301 * <strong>Note:</strong> You must not touch the object after calling this function. 302 * </p> 303 * 304 * @throws IllegalStateException If the info is already recycled. 305 */ 306 public void recycle() { 307 if (SDK_INT >= 21) { 308 ((AccessibilityWindowInfo) mInfo).recycle(); 309 } 310 } 311 312 @Override 313 public int hashCode() { 314 return (mInfo == null) ? 0 : mInfo.hashCode(); 315 } 316 317 @Override 318 public boolean equals(Object obj) { 319 if (this == obj) { 320 return true; 321 } 322 if (obj == null) { 323 return false; 324 } 325 if (getClass() != obj.getClass()) { 326 return false; 327 } 328 AccessibilityWindowInfoCompat other = (AccessibilityWindowInfoCompat) obj; 329 if (mInfo == null) { 330 if (other.mInfo != null) { 331 return false; 332 } 333 } else if (!mInfo.equals(other.mInfo)) { 334 return false; 335 } 336 return true; 337 } 338 339 @Override 340 public String toString() { 341 StringBuilder builder = new StringBuilder(); 342 Rect bounds = new Rect(); 343 getBoundsInScreen(bounds); 344 builder.append("AccessibilityWindowInfo["); 345 builder.append("id=").append(getId()); 346 builder.append(", type=").append(typeToString(getType())); 347 builder.append(", layer=").append(getLayer()); 348 builder.append(", bounds=").append(bounds); 349 builder.append(", focused=").append(isFocused()); 350 builder.append(", active=").append(isActive()); 351 builder.append(", hasParent=").append(getParent() != null); 352 builder.append(", hasChildren=").append(getChildCount() > 0); 353 builder.append(']'); 354 return builder.toString(); 355 } 356 357 private static String typeToString(int type) { 358 switch (type) { 359 case TYPE_APPLICATION: { 360 return "TYPE_APPLICATION"; 361 } 362 case TYPE_INPUT_METHOD: { 363 return "TYPE_INPUT_METHOD"; 364 } 365 case TYPE_SYSTEM: { 366 return "TYPE_SYSTEM"; 367 } 368 case TYPE_ACCESSIBILITY_OVERLAY: { 369 return "TYPE_ACCESSIBILITY_OVERLAY"; 370 } 371 default: 372 return "<UNKNOWN>"; 373 } 374 } 375} 376