AccessibilityRecord.java revision 8643aa0179e598e78d938c59035389054535a229
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.view.accessibility; 18 19import android.os.Parcelable; 20 21import java.util.ArrayList; 22import java.util.List; 23 24/** 25 * Represents a record in an accessibility event. This class encapsulates 26 * the information for a {@link android.view.View}. Note that not all properties 27 * are applicable to all view types. For detailed information please refer to 28 * {@link AccessibilityEvent}. 29 * 30 * @see AccessibilityEvent 31 */ 32public class AccessibilityRecord { 33 34 private static final int INVALID_POSITION = -1; 35 36 private static final int PROPERTY_CHECKED = 0x00000001; 37 private static final int PROPERTY_ENABLED = 0x00000002; 38 private static final int PROPERTY_PASSWORD = 0x00000004; 39 private static final int PROPERTY_FULL_SCREEN = 0x00000080; 40 41 // Housekeeping 42 private static final int MAX_POOL_SIZE = 10; 43 private static final Object sPoolLock = new Object(); 44 private static AccessibilityRecord sPool; 45 private static int sPoolSize; 46 private AccessibilityRecord mNext; 47 private boolean mIsInPool; 48 private boolean mSealed; 49 50 protected int mBooleanProperties; 51 protected int mCurrentItemIndex; 52 protected int mItemCount; 53 protected int mFromIndex; 54 protected int mAddedCount; 55 protected int mRemovedCount; 56 57 protected CharSequence mClassName; 58 protected CharSequence mContentDescription; 59 protected CharSequence mBeforeText; 60 protected Parcelable mParcelableData; 61 62 protected final List<CharSequence> mText = new ArrayList<CharSequence>(); 63 64 /* 65 * Hide constructor. 66 */ 67 protected AccessibilityRecord() { 68 69 } 70 71 /** 72 * Initialize this record from another one. 73 * 74 * @param record The to initialize from. 75 */ 76 void init(AccessibilityRecord record) { 77 mSealed = record.isSealed(); 78 mBooleanProperties = record.mBooleanProperties; 79 mCurrentItemIndex = record.mCurrentItemIndex; 80 mItemCount = record.mItemCount; 81 mFromIndex = record.mFromIndex; 82 mAddedCount = record.mAddedCount; 83 mRemovedCount = record.mRemovedCount; 84 mClassName = record.mClassName; 85 mContentDescription = record.mContentDescription; 86 mBeforeText = record.mBeforeText; 87 mParcelableData = record.mParcelableData; 88 mText.addAll(record.mText); 89 } 90 91 /** 92 * Gets if the source is checked. 93 * 94 * @return True if the view is checked, false otherwise. 95 */ 96 public boolean isChecked() { 97 return getBooleanProperty(PROPERTY_CHECKED); 98 } 99 100 /** 101 * Sets if the source is checked. 102 * 103 * @param isChecked True if the view is checked, false otherwise. 104 * 105 * @throws IllegalStateException If called from an AccessibilityService. 106 */ 107 public void setChecked(boolean isChecked) { 108 enforceNotSealed(); 109 setBooleanProperty(PROPERTY_CHECKED, isChecked); 110 } 111 112 /** 113 * Gets if the source is enabled. 114 * 115 * @return True if the view is enabled, false otherwise. 116 */ 117 public boolean isEnabled() { 118 return getBooleanProperty(PROPERTY_ENABLED); 119 } 120 121 /** 122 * Sets if the source is enabled. 123 * 124 * @param isEnabled True if the view is enabled, false otherwise. 125 * 126 * @throws IllegalStateException If called from an AccessibilityService. 127 */ 128 public void setEnabled(boolean isEnabled) { 129 enforceNotSealed(); 130 setBooleanProperty(PROPERTY_ENABLED, isEnabled); 131 } 132 133 /** 134 * Gets if the source is a password field. 135 * 136 * @return True if the view is a password field, false otherwise. 137 */ 138 public boolean isPassword() { 139 return getBooleanProperty(PROPERTY_PASSWORD); 140 } 141 142 /** 143 * Sets if the source is a password field. 144 * 145 * @param isPassword True if the view is a password field, false otherwise. 146 * 147 * @throws IllegalStateException If called from an AccessibilityService. 148 */ 149 public void setPassword(boolean isPassword) { 150 enforceNotSealed(); 151 setBooleanProperty(PROPERTY_PASSWORD, isPassword); 152 } 153 154 /** 155 * Gets if the source is taking the entire screen. 156 * 157 * @return True if the source is full screen, false otherwise. 158 */ 159 public boolean isFullScreen() { 160 return getBooleanProperty(PROPERTY_FULL_SCREEN); 161 } 162 163 /** 164 * Sets if the source is taking the entire screen. 165 * 166 * @param isFullScreen True if the source is full screen, false otherwise. 167 * 168 * @throws IllegalStateException If called from an AccessibilityService. 169 */ 170 public void setFullScreen(boolean isFullScreen) { 171 enforceNotSealed(); 172 setBooleanProperty(PROPERTY_FULL_SCREEN, isFullScreen); 173 } 174 175 /** 176 * Gets the number of items that can be visited. 177 * 178 * @return The number of items. 179 */ 180 public int getItemCount() { 181 return mItemCount; 182 } 183 184 /** 185 * Sets the number of items that can be visited. 186 * 187 * @param itemCount The number of items. 188 * 189 * @throws IllegalStateException If called from an AccessibilityService. 190 */ 191 public void setItemCount(int itemCount) { 192 enforceNotSealed(); 193 mItemCount = itemCount; 194 } 195 196 /** 197 * Gets the index of the source in the list of items the can be visited. 198 * 199 * @return The current item index. 200 */ 201 public int getCurrentItemIndex() { 202 return mCurrentItemIndex; 203 } 204 205 /** 206 * Sets the index of the source in the list of items that can be visited. 207 * 208 * @param currentItemIndex The current item index. 209 * 210 * @throws IllegalStateException If called from an AccessibilityService. 211 */ 212 public void setCurrentItemIndex(int currentItemIndex) { 213 enforceNotSealed(); 214 mCurrentItemIndex = currentItemIndex; 215 } 216 217 /** 218 * Gets the index of the first character of the changed sequence. 219 * 220 * @return The index of the first character. 221 */ 222 public int getFromIndex() { 223 return mFromIndex; 224 } 225 226 /** 227 * Sets the index of the first character of the changed sequence. 228 * 229 * @param fromIndex The index of the first character. 230 * 231 * @throws IllegalStateException If called from an AccessibilityService. 232 */ 233 public void setFromIndex(int fromIndex) { 234 enforceNotSealed(); 235 mFromIndex = fromIndex; 236 } 237 238 /** 239 * Gets the number of added characters. 240 * 241 * @return The number of added characters. 242 */ 243 public int getAddedCount() { 244 return mAddedCount; 245 } 246 247 /** 248 * Sets the number of added characters. 249 * 250 * @param addedCount The number of added characters. 251 * 252 * @throws IllegalStateException If called from an AccessibilityService. 253 */ 254 public void setAddedCount(int addedCount) { 255 enforceNotSealed(); 256 mAddedCount = addedCount; 257 } 258 259 /** 260 * Gets the number of removed characters. 261 * 262 * @return The number of removed characters. 263 */ 264 public int getRemovedCount() { 265 return mRemovedCount; 266 } 267 268 /** 269 * Sets the number of removed characters. 270 * 271 * @param removedCount The number of removed characters. 272 * 273 * @throws IllegalStateException If called from an AccessibilityService. 274 */ 275 public void setRemovedCount(int removedCount) { 276 enforceNotSealed(); 277 mRemovedCount = removedCount; 278 } 279 280 /** 281 * Gets the class name of the source. 282 * 283 * @return The class name. 284 */ 285 public CharSequence getClassName() { 286 return mClassName; 287 } 288 289 /** 290 * Sets the class name of the source. 291 * 292 * @param className The lass name. 293 * 294 * @throws IllegalStateException If called from an AccessibilityService. 295 */ 296 public void setClassName(CharSequence className) { 297 enforceNotSealed(); 298 mClassName = className; 299 } 300 301 /** 302 * Gets the text of the event. The index in the list represents the priority 303 * of the text. Specifically, the lower the index the higher the priority. 304 * 305 * @return The text. 306 */ 307 public List<CharSequence> getText() { 308 return mText; 309 } 310 311 /** 312 * Sets the text before a change. 313 * 314 * @return The text before the change. 315 */ 316 public CharSequence getBeforeText() { 317 return mBeforeText; 318 } 319 320 /** 321 * Sets the text before a change. 322 * 323 * @param beforeText The text before the change. 324 * 325 * @throws IllegalStateException If called from an AccessibilityService. 326 */ 327 public void setBeforeText(CharSequence beforeText) { 328 enforceNotSealed(); 329 mBeforeText = beforeText; 330 } 331 332 /** 333 * Gets the description of the source. 334 * 335 * @return The description. 336 */ 337 public CharSequence getContentDescription() { 338 return mContentDescription; 339 } 340 341 /** 342 * Sets the description of the source. 343 * 344 * @param contentDescription The description. 345 * 346 * @throws IllegalStateException If called from an AccessibilityService. 347 */ 348 public void setContentDescription(CharSequence contentDescription) { 349 enforceNotSealed(); 350 mContentDescription = contentDescription; 351 } 352 353 /** 354 * Gets the {@link Parcelable} data. 355 * 356 * @return The parcelable data. 357 */ 358 public Parcelable getParcelableData() { 359 return mParcelableData; 360 } 361 362 /** 363 * Sets the {@link Parcelable} data of the event. 364 * 365 * @param parcelableData The parcelable data. 366 * 367 * @throws IllegalStateException If called from an AccessibilityService. 368 */ 369 public void setParcelableData(Parcelable parcelableData) { 370 enforceNotSealed(); 371 mParcelableData = parcelableData; 372 } 373 374 /** 375 * Sets if this instance is sealed. 376 * 377 * @param sealed Whether is sealed. 378 * 379 * @hide 380 */ 381 public void setSealed(boolean sealed) { 382 mSealed = sealed; 383 } 384 385 /** 386 * Gets if this instance is sealed. 387 * 388 * @return Whether is sealed. 389 * 390 * @hide 391 */ 392 public boolean isSealed() { 393 return mSealed; 394 } 395 396 /** 397 * Enforces that this instance is sealed. 398 * 399 * @throws IllegalStateException If this instance is not sealed. 400 * 401 * @hide 402 */ 403 protected void enforceSealed() { 404 if (!isSealed()) { 405 throw new IllegalStateException("Cannot perform this " 406 + "action on a not sealed instance."); 407 } 408 } 409 410 /** 411 * Enforces that this instance is not sealed. 412 * 413 * @throws IllegalStateException If this instance is sealed. 414 * 415 * @hide 416 */ 417 protected void enforceNotSealed() { 418 if (isSealed()) { 419 throw new IllegalStateException("Cannot perform this " 420 + "action on an sealed instance."); 421 } 422 } 423 424 /** 425 * Gets the value of a boolean property. 426 * 427 * @param property The property. 428 * @return The value. 429 */ 430 private boolean getBooleanProperty(int property) { 431 return (mBooleanProperties & property) == property; 432 } 433 434 /** 435 * Sets a boolean property. 436 * 437 * @param property The property. 438 * @param value The value. 439 */ 440 private void setBooleanProperty(int property, boolean value) { 441 if (value) { 442 mBooleanProperties |= property; 443 } else { 444 mBooleanProperties &= ~property; 445 } 446 } 447 448 /** 449 * Returns a cached instance if such is available or a new one is 450 * instantiated. The instance is initialized with data from the 451 * given record. 452 * 453 * @return An instance. 454 */ 455 public static AccessibilityRecord obtain(AccessibilityRecord record) { 456 AccessibilityRecord clone = AccessibilityRecord.obtain(); 457 clone.init(record); 458 return clone; 459 } 460 461 /** 462 * Returns a cached instance if such is available or a new one is 463 * instantiated. 464 * 465 * @return An instance. 466 */ 467 public static AccessibilityRecord obtain() { 468 synchronized (sPoolLock) { 469 if (sPool != null) { 470 AccessibilityRecord record = sPool; 471 sPool = sPool.mNext; 472 sPoolSize--; 473 record.mNext = null; 474 record.mIsInPool = false; 475 return record; 476 } 477 return new AccessibilityRecord(); 478 } 479 } 480 481 /** 482 * Return an instance back to be reused. 483 * <p> 484 * <b>Note: You must not touch the object after calling this function.</b> 485 * 486 * @throws IllegalStateException If the record is already recycled. 487 */ 488 public void recycle() { 489 if (mIsInPool) { 490 throw new IllegalStateException("Record already recycled!"); 491 } 492 clear(); 493 synchronized (sPoolLock) { 494 if (sPoolSize <= MAX_POOL_SIZE) { 495 mNext = sPool; 496 sPool = this; 497 mIsInPool = true; 498 sPoolSize++; 499 } 500 } 501 } 502 503 /** 504 * Clears the state of this instance. 505 * 506 * @hide 507 */ 508 protected void clear() { 509 mSealed = false; 510 mBooleanProperties = 0; 511 mCurrentItemIndex = INVALID_POSITION; 512 mItemCount = 0; 513 mFromIndex = 0; 514 mAddedCount = 0; 515 mRemovedCount = 0; 516 mClassName = null; 517 mContentDescription = null; 518 mBeforeText = null; 519 mParcelableData = null; 520 mText.clear(); 521 } 522 523 @Override 524 public String toString() { 525 StringBuilder builder = new StringBuilder(); 526 builder.append(" [ ClassName: " + mClassName); 527 builder.append("; Text: " + mText); 528 builder.append("; ContentDescription: " + mContentDescription); 529 builder.append("; ItemCount: " + mItemCount); 530 builder.append("; CurrentItemIndex: " + mCurrentItemIndex); 531 builder.append("; IsEnabled: " + getBooleanProperty(PROPERTY_ENABLED)); 532 builder.append("; IsPassword: " + getBooleanProperty(PROPERTY_PASSWORD)); 533 builder.append("; IsChecked: " + getBooleanProperty(PROPERTY_CHECKED)); 534 builder.append("; IsFullScreen: " + getBooleanProperty(PROPERTY_FULL_SCREEN)); 535 builder.append("; BeforeText: " + mBeforeText); 536 builder.append("; FromIndex: " + mFromIndex); 537 builder.append("; AddedCount: " + mAddedCount); 538 builder.append("; RemovedCount: " + mRemovedCount); 539 builder.append("; ParcelableData: " + mParcelableData); 540 builder.append(" ]"); 541 return builder.toString(); 542 } 543} 544