blob: fa505c97ba489bdd704816c2b43903009da6354c [file] [log] [blame]
Svetoslav Ganov736c2752011-04-22 18:30:36 -07001/*
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
Phil Weaver651fe9f2017-05-24 16:43:46 -070019import android.annotation.Nullable;
Svetoslav Ganov736c2752011-04-22 18:30:36 -070020import android.os.Parcelable;
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -070021import android.view.View;
Svetoslav Ganov736c2752011-04-22 18:30:36 -070022
23import java.util.ArrayList;
24import java.util.List;
25
26/**
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -070027 * Represents a record in an {@link AccessibilityEvent} and contains information
28 * about state change of its source {@link android.view.View}. When a view fires
29 * an accessibility event it requests from its parent to dispatch the
30 * constructed event. The parent may optionally append a record for itself
31 * for providing more context to
32 * {@link android.accessibilityservice.AccessibilityService}s. Hence,
33 * accessibility services can facilitate additional accessibility records
34 * to enhance feedback.
35 * </p>
36 * <p>
37 * Once the accessibility event containing a record is dispatched the record is
38 * made immutable and calling a state mutation method generates an error.
39 * </p>
40 * <p>
41 * <strong>Note:</strong> Not all properties are applicable to all accessibility
42 * event types. For detailed information please refer to {@link AccessibilityEvent}.
43 * </p>
Svetoslav Ganov736c2752011-04-22 18:30:36 -070044 *
Joe Fernandeze1302ed2012-02-06 14:30:15 -080045 * <div class="special reference">
46 * <h3>Developer Guides</h3>
47 * <p>For more information about creating and processing AccessibilityRecords, read the
48 * <a href="{@docRoot}guide/topics/ui/accessibility/index.html">Accessibility</a>
49 * developer guide.</p>
50 * </div>
51 *
Svetoslav Ganov736c2752011-04-22 18:30:36 -070052 * @see AccessibilityEvent
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -070053 * @see AccessibilityManager
54 * @see android.accessibilityservice.AccessibilityService
55 * @see AccessibilityNodeInfo
Svetoslav Ganov736c2752011-04-22 18:30:36 -070056 */
57public class AccessibilityRecord {
58
Svetoslav Ganov47b779b2011-07-17 11:07:53 -070059 private static final int UNDEFINED = -1;
Svetoslav Ganov736c2752011-04-22 18:30:36 -070060
61 private static final int PROPERTY_CHECKED = 0x00000001;
62 private static final int PROPERTY_ENABLED = 0x00000002;
63 private static final int PROPERTY_PASSWORD = 0x00000004;
64 private static final int PROPERTY_FULL_SCREEN = 0x00000080;
Svetoslav Ganova0156172011-06-26 17:55:44 -070065 private static final int PROPERTY_SCROLLABLE = 0x00000100;
Svetoslav Ganov42138042012-03-20 11:51:39 -070066 private static final int PROPERTY_IMPORTANT_FOR_ACCESSIBILITY = 0x00000200;
Svetoslav Ganov736c2752011-04-22 18:30:36 -070067
Svetoslav Ganov57c7fd52012-02-23 18:31:39 -080068 private static final int GET_SOURCE_PREFETCH_FLAGS =
69 AccessibilityNodeInfo.FLAG_PREFETCH_PREDECESSORS
70 | AccessibilityNodeInfo.FLAG_PREFETCH_SIBLINGS
71 | AccessibilityNodeInfo.FLAG_PREFETCH_DESCENDANTS;
72
Svetoslav Ganov8643aa02011-04-20 12:12:33 -070073 // Housekeeping
Svetoslav Ganov736c2752011-04-22 18:30:36 -070074 private static final int MAX_POOL_SIZE = 10;
Svetoslav Ganov887e1a12011-04-29 15:09:28 -070075 private static final Object sPoolLock = new Object();
Svetoslav Ganov736c2752011-04-22 18:30:36 -070076 private static AccessibilityRecord sPool;
77 private static int sPoolSize;
Svetoslav Ganov736c2752011-04-22 18:30:36 -070078 private AccessibilityRecord mNext;
79 private boolean mIsInPool;
80
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -070081 boolean mSealed;
Svetoslav8e3feb12014-02-24 13:46:47 -080082 int mBooleanProperties = 0;
Svetoslav Ganov47b779b2011-07-17 11:07:53 -070083 int mCurrentItemIndex = UNDEFINED;
84 int mItemCount = UNDEFINED;
85 int mFromIndex = UNDEFINED;
86 int mToIndex = UNDEFINED;
87 int mScrollX = UNDEFINED;
88 int mScrollY = UNDEFINED;
Eugene Suslacb45ddf2017-05-31 10:57:16 -070089
90 int mScrollDeltaX = UNDEFINED;
91 int mScrollDeltaY = UNDEFINED;
Svetoslav Ganovd9ee72f2011-10-05 22:26:05 -070092 int mMaxScrollX = UNDEFINED;
93 int mMaxScrollY = UNDEFINED;
Svetoslav Ganova0156172011-06-26 17:55:44 -070094
Svetoslav Ganov47b779b2011-07-17 11:07:53 -070095 int mAddedCount= UNDEFINED;
96 int mRemovedCount = UNDEFINED;
Phil Weaver651fe9f2017-05-24 16:43:46 -070097 long mSourceNodeId = AccessibilityNodeInfo.UNDEFINED_NODE_ID;
Phil Weaverf00cd142017-03-03 13:44:00 -080098 int mSourceWindowId = AccessibilityWindowInfo.UNDEFINED_WINDOW_ID;
Svetoslav Ganov736c2752011-04-22 18:30:36 -070099
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -0700100 CharSequence mClassName;
101 CharSequence mContentDescription;
102 CharSequence mBeforeText;
103 Parcelable mParcelableData;
Svetoslav Ganov736c2752011-04-22 18:30:36 -0700104
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -0700105 final List<CharSequence> mText = new ArrayList<CharSequence>();
Svetoslav Ganovd116d7c2011-11-21 18:41:59 -0800106
107 int mConnectionId = UNDEFINED;
Svetoslav Ganov736c2752011-04-22 18:30:36 -0700108
109 /*
110 * Hide constructor.
111 */
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -0700112 AccessibilityRecord() {
Svetoslav Ganov736c2752011-04-22 18:30:36 -0700113 }
114
115 /**
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -0700116 * Sets the event source.
117 *
118 * @param source The source.
119 *
120 * @throws IllegalStateException If called from an AccessibilityService.
121 */
122 public void setSource(View source) {
Phil Weaverb37bfe92017-05-30 16:23:10 -0700123 setSource(source, AccessibilityNodeProvider.HOST_VIEW_ID);
Svetoslav Ganov02107852011-10-03 17:06:56 -0700124 }
125
126 /**
127 * Sets the source to be a virtual descendant of the given <code>root</code>.
128 * If <code>virtualDescendantId</code> equals to {@link View#NO_ID} the root
129 * is set as the source.
130 * <p>
131 * A virtual descendant is an imaginary View that is reported as a part of the view
132 * hierarchy for accessibility purposes. This enables custom views that draw complex
133 * content to report them selves as a tree of virtual views, thus conveying their
134 * logical structure.
135 * </p>
136 *
137 * @param root The root of the virtual subtree.
138 * @param virtualDescendantId The id of the virtual descendant.
139 */
Phil Weaver651fe9f2017-05-24 16:43:46 -0700140 public void setSource(@Nullable View root, int virtualDescendantId) {
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -0700141 enforceNotSealed();
Maxim Bogatov2f55a3f2015-06-09 15:00:44 -0700142 boolean important = true;
Phil Weaver651fe9f2017-05-24 16:43:46 -0700143 int rootViewId = AccessibilityNodeInfo.UNDEFINED_ITEM_ID;
Phil Weaverf00cd142017-03-03 13:44:00 -0800144 mSourceWindowId = AccessibilityWindowInfo.UNDEFINED_WINDOW_ID;
Maxim Bogatov2f55a3f2015-06-09 15:00:44 -0700145 if (root != null) {
Phil Weaver651fe9f2017-05-24 16:43:46 -0700146 important = root.isImportantForAccessibility();
147 rootViewId = root.getAccessibilityViewId();
Maxim Bogatov2f55a3f2015-06-09 15:00:44 -0700148 mSourceWindowId = root.getAccessibilityWindowId();
Svetoslav Ganov52a62372012-05-02 14:19:37 -0700149 }
Svetoslav Ganov42138042012-03-20 11:51:39 -0700150 setBooleanProperty(PROPERTY_IMPORTANT_FOR_ACCESSIBILITY, important);
Phil Weaver651fe9f2017-05-24 16:43:46 -0700151 mSourceNodeId = AccessibilityNodeInfo.makeNodeId(rootViewId, virtualDescendantId);
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -0700152 }
153
154 /**
Phil Weaver651fe9f2017-05-24 16:43:46 -0700155 * Set the source node ID directly
Phil Weaverf00cd142017-03-03 13:44:00 -0800156 *
Phil Weaver651fe9f2017-05-24 16:43:46 -0700157 * @param sourceNodeId The source node Id
Phil Weaverf00cd142017-03-03 13:44:00 -0800158 * @hide
159 */
Phil Weaver651fe9f2017-05-24 16:43:46 -0700160 public void setSourceNodeId(long sourceNodeId) {
161 mSourceNodeId = sourceNodeId;
Phil Weaverf00cd142017-03-03 13:44:00 -0800162 }
163
164 /**
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -0700165 * Gets the {@link AccessibilityNodeInfo} of the event source.
166 * <p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -0700167 * <strong>Note:</strong> It is a client responsibility to recycle the received info
168 * by calling {@link AccessibilityNodeInfo#recycle() AccessibilityNodeInfo#recycle()}
169 * to avoid creating of multiple instances.
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -0700170 * </p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -0700171 * @return The info of the source.
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -0700172 */
173 public AccessibilityNodeInfo getSource() {
174 enforceSealed();
Phil Weaver651fe9f2017-05-24 16:43:46 -0700175 if ((mConnectionId == UNDEFINED)
176 || (mSourceWindowId == AccessibilityWindowInfo.UNDEFINED_WINDOW_ID)
177 || (AccessibilityNodeInfo.getAccessibilityViewId(mSourceNodeId)
178 == AccessibilityNodeInfo.UNDEFINED_ITEM_ID)) {
179 return null;
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -0700180 }
Phil Weaver651fe9f2017-05-24 16:43:46 -0700181 AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
182 return client.findAccessibilityNodeInfoByAccessibilityId(mConnectionId, mSourceWindowId,
183 mSourceNodeId, false, GET_SOURCE_PREFETCH_FLAGS, null);
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -0700184 }
185
186 /**
Svetoslav Ganovfc9c4cd2012-11-02 11:49:22 -0700187 * Sets the window id.
188 *
189 * @param windowId The window id.
190 *
191 * @hide
192 */
193 public void setWindowId(int windowId) {
194 mSourceWindowId = windowId;
195 }
196
197 /**
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -0700198 * Gets the id of the window from which the event comes from.
199 *
200 * @return The window id.
201 */
202 public int getWindowId() {
203 return mSourceWindowId;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700204 }
205
206 /**
Svetoslav Ganov736c2752011-04-22 18:30:36 -0700207 * Gets if the source is checked.
208 *
209 * @return True if the view is checked, false otherwise.
210 */
211 public boolean isChecked() {
212 return getBooleanProperty(PROPERTY_CHECKED);
213 }
214
215 /**
216 * Sets if the source is checked.
217 *
218 * @param isChecked True if the view is checked, false otherwise.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700219 *
220 * @throws IllegalStateException If called from an AccessibilityService.
Svetoslav Ganov736c2752011-04-22 18:30:36 -0700221 */
222 public void setChecked(boolean isChecked) {
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700223 enforceNotSealed();
Svetoslav Ganov736c2752011-04-22 18:30:36 -0700224 setBooleanProperty(PROPERTY_CHECKED, isChecked);
225 }
226
227 /**
228 * Gets if the source is enabled.
229 *
230 * @return True if the view is enabled, false otherwise.
231 */
232 public boolean isEnabled() {
233 return getBooleanProperty(PROPERTY_ENABLED);
234 }
235
236 /**
237 * Sets if the source is enabled.
238 *
239 * @param isEnabled True if the view is enabled, false otherwise.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700240 *
241 * @throws IllegalStateException If called from an AccessibilityService.
Svetoslav Ganov736c2752011-04-22 18:30:36 -0700242 */
243 public void setEnabled(boolean isEnabled) {
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700244 enforceNotSealed();
Svetoslav Ganov736c2752011-04-22 18:30:36 -0700245 setBooleanProperty(PROPERTY_ENABLED, isEnabled);
246 }
247
248 /**
249 * Gets if the source is a password field.
250 *
251 * @return True if the view is a password field, false otherwise.
252 */
253 public boolean isPassword() {
254 return getBooleanProperty(PROPERTY_PASSWORD);
255 }
256
257 /**
258 * Sets if the source is a password field.
259 *
260 * @param isPassword True if the view is a password field, false otherwise.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700261 *
262 * @throws IllegalStateException If called from an AccessibilityService.
Svetoslav Ganov736c2752011-04-22 18:30:36 -0700263 */
264 public void setPassword(boolean isPassword) {
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700265 enforceNotSealed();
Svetoslav Ganov736c2752011-04-22 18:30:36 -0700266 setBooleanProperty(PROPERTY_PASSWORD, isPassword);
267 }
268
269 /**
Svetoslav Ganov736c2752011-04-22 18:30:36 -0700270 * Gets if the source is taking the entire screen.
271 *
272 * @return True if the source is full screen, false otherwise.
273 */
274 public boolean isFullScreen() {
275 return getBooleanProperty(PROPERTY_FULL_SCREEN);
276 }
277
278 /**
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700279 * Sets if the source is taking the entire screen.
280 *
281 * @param isFullScreen True if the source is full screen, false otherwise.
282 *
283 * @throws IllegalStateException If called from an AccessibilityService.
284 */
285 public void setFullScreen(boolean isFullScreen) {
286 enforceNotSealed();
287 setBooleanProperty(PROPERTY_FULL_SCREEN, isFullScreen);
288 }
289
290 /**
Svetoslav Ganova0156172011-06-26 17:55:44 -0700291 * Gets if the source is scrollable.
292 *
293 * @return True if the source is scrollable, false otherwise.
294 */
295 public boolean isScrollable() {
296 return getBooleanProperty(PROPERTY_SCROLLABLE);
297 }
298
299 /**
300 * Sets if the source is scrollable.
301 *
302 * @param scrollable True if the source is scrollable, false otherwise.
303 *
304 * @throws IllegalStateException If called from an AccessibilityService.
305 */
306 public void setScrollable(boolean scrollable) {
307 enforceNotSealed();
308 setBooleanProperty(PROPERTY_SCROLLABLE, scrollable);
309 }
310
311 /**
Svetoslav Ganov42138042012-03-20 11:51:39 -0700312 * Gets if the source is important for accessibility.
313 *
314 * <strong>Note:</strong> Used only internally to determine whether
315 * to deliver the event to a given accessibility service since some
316 * services may want to regard all views for accessibility while others
317 * may want to regard only the important views for accessibility.
318 *
319 * @return True if the source is important for accessibility,
320 * false otherwise.
321 *
322 * @hide
323 */
324 public boolean isImportantForAccessibility() {
325 return getBooleanProperty(PROPERTY_IMPORTANT_FOR_ACCESSIBILITY);
326 }
327
328 /**
Phil Weaver0a8caa12017-08-09 11:28:41 -0700329 * Sets if the source is important for accessibility.
330 *
331 * @param importantForAccessibility True if the source is important for accessibility,
332 * false otherwise.
333 *
334 * @throws IllegalStateException If called from an AccessibilityService.
335 * @hide
336 */
337 public void setImportantForAccessibility(boolean importantForAccessibility) {
338 enforceNotSealed();
339 setBooleanProperty(PROPERTY_IMPORTANT_FOR_ACCESSIBILITY, importantForAccessibility);
340 }
341
342 /**
Svetoslav Ganov736c2752011-04-22 18:30:36 -0700343 * Gets the number of items that can be visited.
344 *
345 * @return The number of items.
346 */
347 public int getItemCount() {
348 return mItemCount;
349 }
350
351 /**
352 * Sets the number of items that can be visited.
353 *
354 * @param itemCount The number of items.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700355 *
356 * @throws IllegalStateException If called from an AccessibilityService.
Svetoslav Ganov736c2752011-04-22 18:30:36 -0700357 */
358 public void setItemCount(int itemCount) {
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700359 enforceNotSealed();
Svetoslav Ganov736c2752011-04-22 18:30:36 -0700360 mItemCount = itemCount;
361 }
362
363 /**
364 * Gets the index of the source in the list of items the can be visited.
365 *
366 * @return The current item index.
367 */
368 public int getCurrentItemIndex() {
369 return mCurrentItemIndex;
370 }
371
372 /**
373 * Sets the index of the source in the list of items that can be visited.
374 *
375 * @param currentItemIndex The current item index.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700376 *
377 * @throws IllegalStateException If called from an AccessibilityService.
Svetoslav Ganov736c2752011-04-22 18:30:36 -0700378 */
379 public void setCurrentItemIndex(int currentItemIndex) {
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700380 enforceNotSealed();
Svetoslav Ganov736c2752011-04-22 18:30:36 -0700381 mCurrentItemIndex = currentItemIndex;
382 }
383
384 /**
Svetoslav Ganova0156172011-06-26 17:55:44 -0700385 * Gets the index of the first character of the changed sequence,
386 * or the beginning of a text selection or the index of the first
387 * visible item when scrolling.
Svetoslav Ganov736c2752011-04-22 18:30:36 -0700388 *
Svetoslav Ganova0156172011-06-26 17:55:44 -0700389 * @return The index of the first character or selection
390 * start or the first visible item.
Svetoslav Ganov736c2752011-04-22 18:30:36 -0700391 */
392 public int getFromIndex() {
393 return mFromIndex;
394 }
395
396 /**
Svetoslav Ganova0156172011-06-26 17:55:44 -0700397 * Sets the index of the first character of the changed sequence
398 * or the beginning of a text selection or the index of the first
399 * visible item when scrolling.
Svetoslav Ganov736c2752011-04-22 18:30:36 -0700400 *
Svetoslav Ganova0156172011-06-26 17:55:44 -0700401 * @param fromIndex The index of the first character or selection
402 * start or the first visible item.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700403 *
404 * @throws IllegalStateException If called from an AccessibilityService.
Svetoslav Ganov736c2752011-04-22 18:30:36 -0700405 */
406 public void setFromIndex(int fromIndex) {
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700407 enforceNotSealed();
Svetoslav Ganov736c2752011-04-22 18:30:36 -0700408 mFromIndex = fromIndex;
409 }
410
411 /**
Svetoslav Ganova0156172011-06-26 17:55:44 -0700412 * Gets the index of text selection end or the index of the last
413 * visible item when scrolling.
414 *
415 * @return The index of selection end or last item index.
416 */
417 public int getToIndex() {
418 return mToIndex;
419 }
420
421 /**
422 * Sets the index of text selection end or the index of the last
423 * visible item when scrolling.
424 *
425 * @param toIndex The index of selection end or last item index.
426 */
427 public void setToIndex(int toIndex) {
428 enforceNotSealed();
429 mToIndex = toIndex;
430 }
431
432 /**
Svetoslav Ganovd9ee72f2011-10-05 22:26:05 -0700433 * Gets the scroll offset of the source left edge in pixels.
Svetoslav Ganova0156172011-06-26 17:55:44 -0700434 *
Svetoslav Ganovd9ee72f2011-10-05 22:26:05 -0700435 * @return The scroll.
Svetoslav Ganova0156172011-06-26 17:55:44 -0700436 */
437 public int getScrollX() {
438 return mScrollX;
439 }
440
441 /**
Svetoslav Ganovd9ee72f2011-10-05 22:26:05 -0700442 * Sets the scroll offset of the source left edge in pixels.
Svetoslav Ganova0156172011-06-26 17:55:44 -0700443 *
Svetoslav Ganovd9ee72f2011-10-05 22:26:05 -0700444 * @param scrollX The scroll.
Svetoslav Ganova0156172011-06-26 17:55:44 -0700445 */
446 public void setScrollX(int scrollX) {
447 enforceNotSealed();
448 mScrollX = scrollX;
449 }
450
451 /**
Svetoslav Ganovd9ee72f2011-10-05 22:26:05 -0700452 * Gets the scroll offset of the source top edge in pixels.
Svetoslav Ganova0156172011-06-26 17:55:44 -0700453 *
Svetoslav Ganovd9ee72f2011-10-05 22:26:05 -0700454 * @return The scroll.
Svetoslav Ganova0156172011-06-26 17:55:44 -0700455 */
456 public int getScrollY() {
457 return mScrollY;
458 }
459
460 /**
Svetoslav Ganovd9ee72f2011-10-05 22:26:05 -0700461 * Sets the scroll offset of the source top edge in pixels.
Svetoslav Ganova0156172011-06-26 17:55:44 -0700462 *
Svetoslav Ganovd9ee72f2011-10-05 22:26:05 -0700463 * @param scrollY The scroll.
Svetoslav Ganova0156172011-06-26 17:55:44 -0700464 */
465 public void setScrollY(int scrollY) {
466 enforceNotSealed();
467 mScrollY = scrollY;
468 }
469
470 /**
Eugene Suslacb45ddf2017-05-31 10:57:16 -0700471 * Gets the difference in pixels between the horizontal position before the scroll and the
472 * current horizontal position
473 *
474 * @return the scroll delta x
475 */
476 public int getScrollDeltaX() {
477 return mScrollDeltaX;
478 }
479
480 /**
481 * Sets the difference in pixels between the horizontal position before the scroll and the
482 * current horizontal position
483 *
484 * @param scrollDeltaX the scroll delta x
485 */
486 public void setScrollDeltaX(int scrollDeltaX) {
487 enforceNotSealed();
488 mScrollDeltaX = scrollDeltaX;
489 }
490
491 /**
492 * Gets the difference in pixels between the vertical position before the scroll and the
493 * current vertical position
494 *
495 * @return the scroll delta y
496 */
497 public int getScrollDeltaY() {
498 return mScrollDeltaY;
499 }
500
501 /**
502 * Sets the difference in pixels between the vertical position before the scroll and the
503 * current vertical position
504 *
505 * @param scrollDeltaY the scroll delta y
506 */
507 public void setScrollDeltaY(int scrollDeltaY) {
508 enforceNotSealed();
509 mScrollDeltaY = scrollDeltaY;
510 }
511
512 /**
Svetoslav Ganovd9ee72f2011-10-05 22:26:05 -0700513 * Gets the max scroll offset of the source left edge in pixels.
514 *
515 * @return The max scroll.
Svetoslav Ganovd9ee72f2011-10-05 22:26:05 -0700516 */
517 public int getMaxScrollX() {
518 return mMaxScrollX;
519 }
Svetoslav Ganov02107852011-10-03 17:06:56 -0700520
Svetoslav Ganovd9ee72f2011-10-05 22:26:05 -0700521 /**
522 * Sets the max scroll offset of the source left edge in pixels.
523 *
524 * @param maxScrollX The max scroll.
Svetoslav Ganovd9ee72f2011-10-05 22:26:05 -0700525 */
526 public void setMaxScrollX(int maxScrollX) {
527 enforceNotSealed();
528 mMaxScrollX = maxScrollX;
529 }
530
531 /**
532 * Gets the max scroll offset of the source top edge in pixels.
533 *
534 * @return The max scroll.
Svetoslav Ganovd9ee72f2011-10-05 22:26:05 -0700535 */
536 public int getMaxScrollY() {
537 return mMaxScrollY;
538 }
539
540 /**
541 * Sets the max scroll offset of the source top edge in pixels.
542 *
543 * @param maxScrollY The max scroll.
Svetoslav Ganovd9ee72f2011-10-05 22:26:05 -0700544 */
545 public void setMaxScrollY(int maxScrollY) {
546 enforceNotSealed();
547 mMaxScrollY = maxScrollY;
548 }
549
550 /**
Svetoslav Ganov736c2752011-04-22 18:30:36 -0700551 * Gets the number of added characters.
552 *
553 * @return The number of added characters.
554 */
555 public int getAddedCount() {
556 return mAddedCount;
557 }
558
559 /**
560 * Sets the number of added characters.
561 *
562 * @param addedCount The number of added characters.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700563 *
564 * @throws IllegalStateException If called from an AccessibilityService.
Svetoslav Ganov736c2752011-04-22 18:30:36 -0700565 */
566 public void setAddedCount(int addedCount) {
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700567 enforceNotSealed();
Svetoslav Ganov736c2752011-04-22 18:30:36 -0700568 mAddedCount = addedCount;
569 }
570
571 /**
572 * Gets the number of removed characters.
573 *
574 * @return The number of removed characters.
575 */
576 public int getRemovedCount() {
577 return mRemovedCount;
578 }
579
580 /**
581 * Sets the number of removed characters.
582 *
583 * @param removedCount The number of removed characters.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700584 *
585 * @throws IllegalStateException If called from an AccessibilityService.
Svetoslav Ganov736c2752011-04-22 18:30:36 -0700586 */
587 public void setRemovedCount(int removedCount) {
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700588 enforceNotSealed();
Svetoslav Ganov736c2752011-04-22 18:30:36 -0700589 mRemovedCount = removedCount;
590 }
591
592 /**
593 * Gets the class name of the source.
594 *
595 * @return The class name.
596 */
597 public CharSequence getClassName() {
598 return mClassName;
599 }
600
601 /**
602 * Sets the class name of the source.
603 *
604 * @param className The lass name.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700605 *
606 * @throws IllegalStateException If called from an AccessibilityService.
Svetoslav Ganov736c2752011-04-22 18:30:36 -0700607 */
608 public void setClassName(CharSequence className) {
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700609 enforceNotSealed();
Svetoslav Ganov736c2752011-04-22 18:30:36 -0700610 mClassName = className;
611 }
612
613 /**
614 * Gets the text of the event. The index in the list represents the priority
615 * of the text. Specifically, the lower the index the higher the priority.
616 *
617 * @return The text.
618 */
619 public List<CharSequence> getText() {
620 return mText;
621 }
622
623 /**
624 * Sets the text before a change.
625 *
626 * @return The text before the change.
627 */
628 public CharSequence getBeforeText() {
629 return mBeforeText;
630 }
631
632 /**
633 * Sets the text before a change.
634 *
635 * @param beforeText The text before the change.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700636 *
637 * @throws IllegalStateException If called from an AccessibilityService.
Svetoslav Ganov736c2752011-04-22 18:30:36 -0700638 */
639 public void setBeforeText(CharSequence beforeText) {
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700640 enforceNotSealed();
Phil Weaveref955ad2016-08-25 12:58:15 -0700641 mBeforeText = (beforeText == null) ? null
642 : beforeText.subSequence(0, beforeText.length());
Svetoslav Ganov736c2752011-04-22 18:30:36 -0700643 }
644
645 /**
646 * Gets the description of the source.
647 *
648 * @return The description.
649 */
650 public CharSequence getContentDescription() {
651 return mContentDescription;
652 }
653
654 /**
655 * Sets the description of the source.
656 *
657 * @param contentDescription The description.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700658 *
659 * @throws IllegalStateException If called from an AccessibilityService.
Svetoslav Ganov736c2752011-04-22 18:30:36 -0700660 */
661 public void setContentDescription(CharSequence contentDescription) {
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700662 enforceNotSealed();
Phil Weaveref955ad2016-08-25 12:58:15 -0700663 mContentDescription = (contentDescription == null) ? null
664 : contentDescription.subSequence(0, contentDescription.length());
Svetoslav Ganov736c2752011-04-22 18:30:36 -0700665 }
666
667 /**
668 * Gets the {@link Parcelable} data.
669 *
670 * @return The parcelable data.
671 */
672 public Parcelable getParcelableData() {
673 return mParcelableData;
674 }
675
676 /**
677 * Sets the {@link Parcelable} data of the event.
678 *
679 * @param parcelableData The parcelable data.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700680 *
681 * @throws IllegalStateException If called from an AccessibilityService.
Svetoslav Ganov736c2752011-04-22 18:30:36 -0700682 */
683 public void setParcelableData(Parcelable parcelableData) {
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700684 enforceNotSealed();
Svetoslav Ganov736c2752011-04-22 18:30:36 -0700685 mParcelableData = parcelableData;
686 }
687
688 /**
Svetoslav Ganov79311c42012-01-17 20:24:26 -0800689 * Gets the id of the source node.
690 *
691 * @return The id.
692 *
693 * @hide
694 */
695 public long getSourceNodeId() {
Phil Weaver651fe9f2017-05-24 16:43:46 -0700696 return mSourceNodeId;
Svetoslav Ganov79311c42012-01-17 20:24:26 -0800697 }
698
699 /**
Svetoslav Ganovd116d7c2011-11-21 18:41:59 -0800700 * Sets the unique id of the IAccessibilityServiceConnection over which
701 * this instance can send requests to the system.
702 *
703 * @param connectionId The connection id.
704 *
705 * @hide
706 */
707 public void setConnectionId(int connectionId) {
708 enforceNotSealed();
709 mConnectionId = connectionId;
710 }
711
712 /**
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700713 * Sets if this instance is sealed.
714 *
715 * @param sealed Whether is sealed.
716 *
717 * @hide
718 */
719 public void setSealed(boolean sealed) {
720 mSealed = sealed;
721 }
722
723 /**
724 * Gets if this instance is sealed.
725 *
726 * @return Whether is sealed.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700727 */
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -0700728 boolean isSealed() {
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700729 return mSealed;
730 }
731
732 /**
733 * Enforces that this instance is sealed.
734 *
735 * @throws IllegalStateException If this instance is not sealed.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700736 */
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -0700737 void enforceSealed() {
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700738 if (!isSealed()) {
739 throw new IllegalStateException("Cannot perform this "
740 + "action on a not sealed instance.");
741 }
742 }
743
744 /**
745 * Enforces that this instance is not sealed.
746 *
747 * @throws IllegalStateException If this instance is sealed.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700748 */
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -0700749 void enforceNotSealed() {
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700750 if (isSealed()) {
751 throw new IllegalStateException("Cannot perform this "
Ken Wakasaf76a50c2012-03-09 19:56:35 +0900752 + "action on a sealed instance.");
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700753 }
754 }
755
756 /**
Svetoslav Ganov736c2752011-04-22 18:30:36 -0700757 * Gets the value of a boolean property.
758 *
759 * @param property The property.
760 * @return The value.
761 */
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700762 private boolean getBooleanProperty(int property) {
Svetoslav Ganov736c2752011-04-22 18:30:36 -0700763 return (mBooleanProperties & property) == property;
764 }
765
766 /**
767 * Sets a boolean property.
768 *
769 * @param property The property.
770 * @param value The value.
771 */
772 private void setBooleanProperty(int property, boolean value) {
773 if (value) {
774 mBooleanProperties |= property;
775 } else {
776 mBooleanProperties &= ~property;
777 }
778 }
779
780 /**
781 * Returns a cached instance if such is available or a new one is
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700782 * instantiated. The instance is initialized with data from the
783 * given record.
784 *
785 * @return An instance.
786 */
787 public static AccessibilityRecord obtain(AccessibilityRecord record) {
788 AccessibilityRecord clone = AccessibilityRecord.obtain();
789 clone.init(record);
790 return clone;
791 }
792
793 /**
794 * Returns a cached instance if such is available or a new one is
Svetoslav Ganov736c2752011-04-22 18:30:36 -0700795 * instantiated.
796 *
797 * @return An instance.
798 */
Svetoslav Ganovd36a6992011-05-18 20:50:03 -0700799 public static AccessibilityRecord obtain() {
Svetoslav Ganov887e1a12011-04-29 15:09:28 -0700800 synchronized (sPoolLock) {
Svetoslav Ganov736c2752011-04-22 18:30:36 -0700801 if (sPool != null) {
802 AccessibilityRecord record = sPool;
803 sPool = sPool.mNext;
804 sPoolSize--;
805 record.mNext = null;
806 record.mIsInPool = false;
807 return record;
808 }
809 return new AccessibilityRecord();
810 }
811 }
812
813 /**
814 * Return an instance back to be reused.
815 * <p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -0700816 * <strong>Note:</strong> You must not touch the object after calling this function.
Svetoslav Ganov887e1a12011-04-29 15:09:28 -0700817 *
818 * @throws IllegalStateException If the record is already recycled.
Svetoslav Ganov736c2752011-04-22 18:30:36 -0700819 */
820 public void recycle() {
821 if (mIsInPool) {
Svetoslav Ganov887e1a12011-04-29 15:09:28 -0700822 throw new IllegalStateException("Record already recycled!");
Svetoslav Ganov736c2752011-04-22 18:30:36 -0700823 }
824 clear();
Svetoslav Ganov887e1a12011-04-29 15:09:28 -0700825 synchronized (sPoolLock) {
Svetoslav Ganov736c2752011-04-22 18:30:36 -0700826 if (sPoolSize <= MAX_POOL_SIZE) {
827 mNext = sPool;
828 sPool = this;
829 mIsInPool = true;
830 sPoolSize++;
831 }
832 }
833 }
834
835 /**
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -0700836 * Initialize this record from another one.
837 *
838 * @param record The to initialize from.
839 */
840 void init(AccessibilityRecord record) {
841 mSealed = record.mSealed;
842 mBooleanProperties = record.mBooleanProperties;
843 mCurrentItemIndex = record.mCurrentItemIndex;
844 mItemCount = record.mItemCount;
845 mFromIndex = record.mFromIndex;
846 mToIndex = record.mToIndex;
847 mScrollX = record.mScrollX;
848 mScrollY = record.mScrollY;
Svetoslav Ganovd9ee72f2011-10-05 22:26:05 -0700849 mMaxScrollX = record.mMaxScrollX;
850 mMaxScrollY = record.mMaxScrollY;
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -0700851 mAddedCount = record.mAddedCount;
852 mRemovedCount = record.mRemovedCount;
853 mClassName = record.mClassName;
854 mContentDescription = record.mContentDescription;
855 mBeforeText = record.mBeforeText;
856 mParcelableData = record.mParcelableData;
857 mText.addAll(record.mText);
858 mSourceWindowId = record.mSourceWindowId;
Phil Weaver651fe9f2017-05-24 16:43:46 -0700859 mSourceNodeId = record.mSourceNodeId;
Svetoslav Ganovd116d7c2011-11-21 18:41:59 -0800860 mConnectionId = record.mConnectionId;
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -0700861 }
862
863 /**
Svetoslav Ganov736c2752011-04-22 18:30:36 -0700864 * Clears the state of this instance.
865 */
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -0700866 void clear() {
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700867 mSealed = false;
Svetoslav8e3feb12014-02-24 13:46:47 -0800868 mBooleanProperties = 0;
Svetoslav Ganov47b779b2011-07-17 11:07:53 -0700869 mCurrentItemIndex = UNDEFINED;
870 mItemCount = UNDEFINED;
871 mFromIndex = UNDEFINED;
872 mToIndex = UNDEFINED;
873 mScrollX = UNDEFINED;
874 mScrollY = UNDEFINED;
Svetoslav Ganovd9ee72f2011-10-05 22:26:05 -0700875 mMaxScrollX = UNDEFINED;
876 mMaxScrollY = UNDEFINED;
Svetoslav Ganov47b779b2011-07-17 11:07:53 -0700877 mAddedCount = UNDEFINED;
878 mRemovedCount = UNDEFINED;
Svetoslav Ganov736c2752011-04-22 18:30:36 -0700879 mClassName = null;
880 mContentDescription = null;
881 mBeforeText = null;
882 mParcelableData = null;
883 mText.clear();
Phil Weaver651fe9f2017-05-24 16:43:46 -0700884 mSourceNodeId = AccessibilityNodeInfo.UNDEFINED_ITEM_ID;
885 mSourceWindowId = AccessibilityWindowInfo.UNDEFINED_WINDOW_ID;
Svetoslav Ganovd116d7c2011-11-21 18:41:59 -0800886 mConnectionId = UNDEFINED;
Svetoslav Ganov736c2752011-04-22 18:30:36 -0700887 }
888
889 @Override
890 public String toString() {
891 StringBuilder builder = new StringBuilder();
892 builder.append(" [ ClassName: " + mClassName);
893 builder.append("; Text: " + mText);
894 builder.append("; ContentDescription: " + mContentDescription);
895 builder.append("; ItemCount: " + mItemCount);
896 builder.append("; CurrentItemIndex: " + mCurrentItemIndex);
897 builder.append("; IsEnabled: " + getBooleanProperty(PROPERTY_ENABLED));
898 builder.append("; IsPassword: " + getBooleanProperty(PROPERTY_PASSWORD));
899 builder.append("; IsChecked: " + getBooleanProperty(PROPERTY_CHECKED));
900 builder.append("; IsFullScreen: " + getBooleanProperty(PROPERTY_FULL_SCREEN));
Svetoslav Ganova0156172011-06-26 17:55:44 -0700901 builder.append("; Scrollable: " + getBooleanProperty(PROPERTY_SCROLLABLE));
Svetoslav Ganov736c2752011-04-22 18:30:36 -0700902 builder.append("; BeforeText: " + mBeforeText);
903 builder.append("; FromIndex: " + mFromIndex);
Svetoslav Ganova0156172011-06-26 17:55:44 -0700904 builder.append("; ToIndex: " + mToIndex);
905 builder.append("; ScrollX: " + mScrollX);
906 builder.append("; ScrollY: " + mScrollY);
Svetoslav Ganovd9ee72f2011-10-05 22:26:05 -0700907 builder.append("; MaxScrollX: " + mMaxScrollX);
908 builder.append("; MaxScrollY: " + mMaxScrollY);
Svetoslav Ganov736c2752011-04-22 18:30:36 -0700909 builder.append("; AddedCount: " + mAddedCount);
910 builder.append("; RemovedCount: " + mRemovedCount);
911 builder.append("; ParcelableData: " + mParcelableData);
912 builder.append(" ]");
913 return builder.toString();
914 }
915}