AccessibilityNodeInfoCompat.java revision 000bc861de12bc3a26f69135ac224e1eb8106f4f
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.support.v4.view.accessibility;
18
19import android.graphics.Rect;
20import android.os.Build;
21import android.view.View;
22
23import java.util.ArrayList;
24import java.util.Collections;
25import java.util.List;
26
27/**
28 * Helper for accessing {@link android.view.accessibility.AccessibilityNodeInfo}
29 * introduced after API level 4 in a backwards compatible fashion.
30 */
31public class AccessibilityNodeInfoCompat {
32
33    static interface AccessibilityNodeInfoImpl {
34        public Object obtain();
35        public Object obtain(View source);
36        public Object obtain(Object info);
37        public void setSource(Object info, View source);
38        public void setSource(Object info, View root, int virtualDescendantId);
39        public int getWindowId(Object info);
40        public int getChildCount(Object info);
41        public AccessibilityNodeInfoCompat getChild(Object info, int index);
42        public void addChild(Object info, View child);
43        public void addChild(Object info, View child, int virtualDescendantId);
44        public int getActions(Object info);
45        public void addAction(Object info, int action);
46        public boolean performAction(Object info, int action);
47        public List<Object> findAccessibilityNodeInfosByText(Object info, String text);
48        public AccessibilityNodeInfoCompat getParent(Object info);
49        public void setParent(Object info, View parent);
50        public void getBoundsInParent(Object info, Rect outBounds);
51        public void setBoundsInParent(Object info, Rect bounds);
52        public void getBoundsInScreen(Object info, Rect outBounds);
53        public void setBoundsInScreen(Object info, Rect bounds);
54        public boolean isCheckable(Object info);
55        public void setCheckable(Object info, boolean checkable);
56        public boolean isChecked(Object info);
57        public void setChecked(Object info, boolean checked);
58        public boolean isFocusable(Object info);
59        public void setFocusable(Object info, boolean focusable);
60        public boolean isFocused(Object info);
61        public void setFocused(Object info, boolean focused);
62        public boolean isSelected(Object info);
63        public void setSelected(Object info, boolean selected);
64        public boolean isClickable(Object info);
65        public void setClickable(Object info, boolean clickable);
66        public boolean isLongClickable(Object info);
67        public void setLongClickable(Object info, boolean longClickable);
68        public boolean isEnabled(Object info);
69        public void setEnabled(Object info, boolean enabled);
70        public boolean isPassword(Object info);
71        public void setPassword(Object info, boolean password);
72        public boolean isScrollable(Object info);
73        public void setScrollable(Object info, boolean scrollable);
74        public CharSequence getPackageName(Object info);
75        public void setPackageName(Object info, CharSequence packageName);
76        public CharSequence getClassName(Object info);
77        public void setClassName(Object info, CharSequence className);
78        public CharSequence getText(Object info);
79        public void setText(Object info, CharSequence text);
80        public CharSequence getContentDescription(Object info);
81        public void setContentDescription(Object info, CharSequence contentDescription);
82        public void recycle(Object info);
83    }
84
85    static class AccessibilityNodeInfoStubImpl implements AccessibilityNodeInfoImpl {
86        public Object obtain() {
87            return null;
88        }
89
90        public Object obtain(View source) {
91            return null;
92        }
93
94        public Object obtain(Object info) {
95            return null;
96        }
97
98        public void addAction(Object info, int action) {
99
100        }
101
102        public void addChild(Object info, View child) {
103
104        }
105
106        public void addChild(Object info, View child, int virtualDescendantId) {
107
108        }
109
110        public List<Object> findAccessibilityNodeInfosByText(Object info, String text) {
111            return Collections.emptyList();
112        }
113
114        public int getActions(Object info) {
115            return 0;
116        }
117
118        public void getBoundsInParent(Object info, Rect outBounds) {
119
120        }
121
122        public void getBoundsInScreen(Object info, Rect outBounds) {
123
124        }
125
126        public AccessibilityNodeInfoCompat getChild(Object info, int index) {
127            return null;
128        }
129
130        public int getChildCount(Object info) {
131            return 0;
132        }
133
134        public CharSequence getClassName(Object info) {
135            return null;
136        }
137
138        public CharSequence getContentDescription(Object info) {
139            return null;
140        }
141
142        public CharSequence getPackageName(Object info) {
143            return null;
144        }
145
146        public AccessibilityNodeInfoCompat getParent(Object info) {
147            return null;
148        }
149
150        public CharSequence getText(Object info) {
151            return null;
152        }
153
154        public int getWindowId(Object info) {
155            return 0;
156        }
157
158        public boolean isCheckable(Object info) {
159            return false;
160        }
161
162        public boolean isChecked(Object info) {
163            return false;
164        }
165
166        public boolean isClickable(Object info) {
167            return false;
168        }
169
170        public boolean isEnabled(Object info) {
171            return false;
172        }
173
174        public boolean isFocusable(Object info) {
175            return false;
176        }
177
178        public boolean isFocused(Object info) {
179            return false;
180        }
181
182        public boolean isLongClickable(Object info) {
183            return false;
184        }
185
186        public boolean isPassword(Object info) {
187            return false;
188        }
189
190        public boolean isScrollable(Object info) {
191            return false;
192        }
193
194        public boolean isSelected(Object info) {
195            return false;
196        }
197
198        public boolean performAction(Object info, int action) {
199            return false;
200        }
201
202        public void setBoundsInParent(Object info, Rect bounds) {
203
204        }
205
206        public void setBoundsInScreen(Object info, Rect bounds) {
207
208        }
209
210        public void setCheckable(Object info, boolean checkable) {
211
212        }
213
214        public void setChecked(Object info, boolean checked) {
215
216        }
217
218        public void setClassName(Object info, CharSequence className) {
219
220        }
221
222        public void setClickable(Object info, boolean clickable) {
223
224        }
225
226        public void setContentDescription(Object info, CharSequence contentDescription) {
227
228        }
229
230        public void setEnabled(Object info, boolean enabled) {
231
232        }
233
234        public void setFocusable(Object info, boolean focusable) {
235
236        }
237
238        public void setFocused(Object info, boolean focused) {
239
240        }
241
242        public void setLongClickable(Object info, boolean longClickable) {
243
244        }
245
246        public void setPackageName(Object info, CharSequence packageName) {
247
248        }
249
250        public void setParent(Object info, View parent) {
251
252        }
253
254        public void setPassword(Object info, boolean password) {
255
256        }
257
258        public void setScrollable(Object info, boolean scrollable) {
259
260        }
261
262        public void setSelected(Object info, boolean selected) {
263
264        }
265
266        public void setSource(Object info, View source) {
267
268        }
269
270        public void setSource(Object info, View root, int virtualDescendantId) {
271
272        }
273
274        public void setText(Object info, CharSequence text) {
275
276        }
277
278        public void recycle(Object info) {
279
280        }
281    }
282
283    static class AccessibilityNodeInfoIcsImpl extends AccessibilityNodeInfoStubImpl {
284        @Override
285        public Object obtain() {
286            return AccessibilityNodeInfoCompatIcs.obtain();
287        }
288
289        @Override
290        public Object obtain(View source) {
291            return AccessibilityNodeInfoCompatIcs.obtain(source);
292        }
293
294        @Override
295        public Object obtain(Object info) {
296            return AccessibilityNodeInfoCompatIcs.obtain(info);
297        }
298
299        @Override
300        public void addAction(Object info, int action) {
301            AccessibilityNodeInfoCompatIcs.addAction(info, action);
302        }
303
304        @Override
305        public void addChild(Object info, View child) {
306            AccessibilityNodeInfoCompatIcs.addChild(info, child);
307        }
308
309        @Override
310        public List<Object> findAccessibilityNodeInfosByText(Object info, String text) {
311            return AccessibilityNodeInfoCompatIcs.findAccessibilityNodeInfosByText(info, text);
312        }
313
314        @Override
315        public int getActions(Object info) {
316            return AccessibilityNodeInfoCompatIcs.getActions(info);
317        }
318
319        @Override
320        public void getBoundsInParent(Object info, Rect outBounds) {
321            AccessibilityNodeInfoCompatIcs.getBoundsInParent(info, outBounds);
322        }
323
324        @Override
325        public void getBoundsInScreen(Object info, Rect outBounds) {
326            AccessibilityNodeInfoCompatIcs.getBoundsInScreen(info, outBounds);
327        }
328
329        @Override
330        public AccessibilityNodeInfoCompat getChild(Object info, int index) {
331            return AccessibilityNodeInfoCompat.wrapNonNullInstance(
332                    AccessibilityNodeInfoCompatIcs.getChild(info, index));
333        }
334
335        @Override
336        public int getChildCount(Object info) {
337            return AccessibilityNodeInfoCompatIcs.getChildCount(info);
338        }
339
340        @Override
341        public CharSequence getClassName(Object info) {
342            return AccessibilityNodeInfoCompatIcs.getClassName(info);
343        }
344
345        @Override
346        public CharSequence getContentDescription(Object info) {
347            return AccessibilityNodeInfoCompatIcs.getContentDescription(info);
348        }
349
350        @Override
351        public CharSequence getPackageName(Object info) {
352            return AccessibilityNodeInfoCompatIcs.getPackageName(info);
353        }
354
355        @Override
356        public AccessibilityNodeInfoCompat getParent(Object info) {
357            return AccessibilityNodeInfoCompat.wrapNonNullInstance(
358                    AccessibilityNodeInfoCompatIcs.getParent(info));
359        }
360
361        @Override
362        public CharSequence getText(Object info) {
363            return AccessibilityNodeInfoCompatIcs.getText(info);
364        }
365
366        @Override
367        public int getWindowId(Object info) {
368            return AccessibilityNodeInfoCompatIcs.getWindowId(info);
369        }
370
371        @Override
372        public boolean isCheckable(Object info) {
373            return AccessibilityNodeInfoCompatIcs.isCheckable(info);
374        }
375
376        @Override
377        public boolean isChecked(Object info) {
378            return AccessibilityNodeInfoCompatIcs.isChecked(info);
379        }
380
381        @Override
382        public boolean isClickable(Object info) {
383            return AccessibilityNodeInfoCompatIcs.isClickable(info);
384        }
385
386        @Override
387        public boolean isEnabled(Object info) {
388            return AccessibilityNodeInfoCompatIcs.isEnabled(info);
389        }
390
391        @Override
392        public boolean isFocusable(Object info) {
393            return AccessibilityNodeInfoCompatIcs.isFocusable(info);
394        }
395
396        @Override
397        public boolean isFocused(Object info) {
398            return AccessibilityNodeInfoCompatIcs.isFocused(info);
399        }
400
401        @Override
402        public boolean isLongClickable(Object info) {
403            return AccessibilityNodeInfoCompatIcs.isLongClickable(info);
404        }
405
406        @Override
407        public boolean isPassword(Object info) {
408            return AccessibilityNodeInfoCompatIcs.isPassword(info);
409        }
410
411        @Override
412        public boolean isScrollable(Object info) {
413            return AccessibilityNodeInfoCompatIcs.isScrollable(info);
414        }
415
416        @Override
417        public boolean isSelected(Object info) {
418            return AccessibilityNodeInfoCompatIcs.isSelected(info);
419        }
420
421        @Override
422        public boolean performAction(Object info, int action) {
423            return AccessibilityNodeInfoCompatIcs.performAction(info, action);
424        }
425
426        @Override
427        public void setBoundsInParent(Object info, Rect bounds) {
428            AccessibilityNodeInfoCompatIcs.setBoundsInParent(info, bounds);
429        }
430
431        @Override
432        public void setBoundsInScreen(Object info, Rect bounds) {
433            AccessibilityNodeInfoCompatIcs.setBoundsInScreen(info, bounds);
434        }
435
436        @Override
437        public void setCheckable(Object info, boolean checkable) {
438            AccessibilityNodeInfoCompatIcs.setCheckable(info, checkable);
439        }
440
441        @Override
442        public void setChecked(Object info, boolean checked) {
443            AccessibilityNodeInfoCompatIcs.setChecked(info, checked);
444        }
445
446        @Override
447        public void setClassName(Object info, CharSequence className) {
448            AccessibilityNodeInfoCompatIcs.setClassName(info, className);
449        }
450
451        @Override
452        public void setClickable(Object info, boolean clickable) {
453            AccessibilityNodeInfoCompatIcs.setClickable(info, clickable);
454        }
455
456        @Override
457        public void setContentDescription(Object info, CharSequence contentDescription) {
458            AccessibilityNodeInfoCompatIcs.setContentDescription(info, contentDescription);
459        }
460
461        @Override
462        public void setEnabled(Object info, boolean enabled) {
463            AccessibilityNodeInfoCompatIcs.setEnabled(info, enabled);
464        }
465
466        @Override
467        public void setFocusable(Object info, boolean focusable) {
468            AccessibilityNodeInfoCompatIcs.setFocusable(info, focusable);
469        }
470
471        @Override
472        public void setFocused(Object info, boolean focused) {
473            AccessibilityNodeInfoCompatIcs.setFocused(info, focused);
474        }
475
476        @Override
477        public void setLongClickable(Object info, boolean longClickable) {
478            AccessibilityNodeInfoCompatIcs.setLongClickable(info, longClickable);
479        }
480
481        @Override
482        public void setPackageName(Object info, CharSequence packageName) {
483            AccessibilityNodeInfoCompatIcs.setPackageName(info, packageName);
484        }
485
486        @Override
487        public void setParent(Object info, View parent) {
488            AccessibilityNodeInfoCompatIcs.setParent(info, parent);
489        }
490
491        @Override
492        public void setPassword(Object info, boolean password) {
493            AccessibilityNodeInfoCompatIcs.setPassword(info, password);
494        }
495
496        @Override
497        public void setScrollable(Object info, boolean scrollable) {
498            AccessibilityNodeInfoCompatIcs.setScrollable(info, scrollable);
499        }
500
501        @Override
502        public void setSelected(Object info, boolean selected) {
503            AccessibilityNodeInfoCompatIcs.setSelected(info, selected);
504        }
505
506        @Override
507        public void setSource(Object info, View source) {
508            AccessibilityNodeInfoCompatIcs.setSource(info, source);
509        }
510
511        @Override
512        public void setText(Object info, CharSequence text) {
513            AccessibilityNodeInfoCompatIcs.setText(info, text);
514        }
515
516        @Override
517        public void recycle(Object info) {
518            AccessibilityNodeInfoCompatIcs.recycle(info);
519        }
520    }
521
522    static class AccessibilityNodeInfoJellybeanImpl extends AccessibilityNodeInfoIcsImpl {
523        @Override
524        public void addChild(Object info, View child, int virtualDescendantId) {
525            AccessibilityNodeInfoCompatJellyBean.addChild(info, child, virtualDescendantId);
526        }
527
528        @Override
529        public void setSource(Object info, View root, int virtualDescendantId) {
530            AccessibilityNodeInfoCompatJellyBean.setSource(info, root, virtualDescendantId);
531        }
532    }
533
534    static {
535        // TODO: Update the conditional to use SDK_INT when we have an SDK version set.
536        //       (tracked by bug:5947249)
537        if (Build.VERSION.CODENAME.equals("JellyBean")) { // JellyBean
538            IMPL = new AccessibilityNodeInfoJellybeanImpl();
539        } else if (Build.VERSION.SDK_INT >= 14) { // ICS
540            IMPL = new AccessibilityNodeInfoIcsImpl();
541        } else {
542            IMPL = new AccessibilityNodeInfoStubImpl();
543        }
544    }
545
546    private static final AccessibilityNodeInfoImpl IMPL;
547
548    private final Object mInfo;
549
550    // Actions.
551
552    /**
553     * Action that focuses the node.
554     */
555    public static final int ACTION_FOCUS = 0x00000001;
556
557    /**
558     * Action that unfocuses the node.
559     */
560    public static final int ACTION_CLEAR_FOCUS = 0x00000002;
561
562    /**
563     * Action that selects the node.
564     */
565    public static final int ACTION_SELECT = 0x00000004;
566
567    /**
568     * Action that unselects the node.
569     */
570    public static final int ACTION_CLEAR_SELECTION = 0x00000008;
571
572    /**
573     * Creates a wrapper for info implementation.
574     *
575     * @param object The info to wrap.
576     * @return A wrapper for if the object is not null, null otherwise.
577     */
578    static AccessibilityNodeInfoCompat wrapNonNullInstance(Object object) {
579        if (object != null) {
580            return new AccessibilityNodeInfoCompat(object);
581        }
582        return null;
583    }
584
585    /**
586     * Creates a new instance wrapping an
587     * {@link android.view.accessibility.AccessibilityNodeInfo}.
588     *
589     * @param info The info.
590     */
591    public AccessibilityNodeInfoCompat(Object info) {
592        mInfo = info;
593    }
594
595    /**
596     * @return The wrapped {@link android.view.accessibility.AccessibilityNodeInfo}.
597     */
598    public Object getInfo() {
599        return mInfo;
600    }
601
602    /**
603     * Returns a cached instance if such is available otherwise a new one and
604     * sets the source.
605     *
606     * @return An instance.
607     * @see #setSource(View)
608     */
609    public static AccessibilityNodeInfoCompat obtain(View source) {
610        return new AccessibilityNodeInfoCompat(IMPL.obtain(source));
611    }
612
613    /**
614     * Returns a cached instance if such is available otherwise a new one.
615     *
616     * @return An instance.
617     */
618    public static AccessibilityNodeInfoCompat obtain() {
619        return new AccessibilityNodeInfoCompat(IMPL.obtain());
620    }
621
622    /**
623     * Returns a cached instance if such is available or a new one is create.
624     * The returned instance is initialized from the given <code>info</code>.
625     *
626     * @param info The other info.
627     * @return An instance.
628     */
629    public static AccessibilityNodeInfoCompat obtain(AccessibilityNodeInfoCompat info) {
630        return new AccessibilityNodeInfoCompat(IMPL.obtain(info.mInfo));
631    }
632
633    /**
634     * Sets the source.
635     *
636     * @param source The info source.
637     */
638    public void setSource(View source) {
639        IMPL.setSource(mInfo, source);
640    }
641
642    /**
643     * Sets the source to be a virtual descendant of the given <code>root</code>.
644     * If <code>virtualDescendantId</code> is {@link View#NO_ID} the root
645     * is set as the source.
646     * <p>
647     * A virtual descendant is an imaginary View that is reported as a part of the view
648     * hierarchy for accessibility purposes. This enables custom views that draw complex
649     * content to report themselves as a tree of virtual views, thus conveying their
650     * logical structure.
651     * </p>
652     * <p>
653     *   <strong>Note:</strong> Cannot be called from an
654     *   {@link android.accessibilityservice.AccessibilityService}.
655     *   This class is made immutable before being delivered to an AccessibilityService.
656     * </p>
657     *
658     * @param root The root of the virtual subtree.
659     * @param virtualDescendantId The id of the virtual descendant.
660     */
661    public void setSource(View root, int virtualDescendantId) {
662        IMPL.setSource(mInfo, root, virtualDescendantId);
663    }
664
665    /**
666     * Gets the id of the window from which the info comes from.
667     *
668     * @return The window id.
669     */
670    public int getWindowId() {
671        return IMPL.getWindowId(mInfo);
672    }
673
674    /**
675     * Gets the number of children.
676     *
677     * @return The child count.
678     */
679    public int getChildCount() {
680        return IMPL.getChildCount(mInfo);
681    }
682
683    /**
684     * Get the child at given index.
685     * <p>
686     * <strong>Note:</strong> It is a client responsibility to recycle the
687     * received info by calling {@link AccessibilityNodeInfoCompat#recycle()} to
688     * avoid creating of multiple instances.
689     * </p>
690     *
691     * @param index The child index.
692     * @return The child node.
693     * @throws IllegalStateException If called outside of an
694     *             AccessibilityService.
695     */
696    public AccessibilityNodeInfoCompat getChild(int index) {
697        return IMPL.getChild(mInfo, index);
698    }
699
700    /**
701     * Adds a child.
702     * <p>
703     * <strong>Note:</strong> Cannot be called from an
704     * {@link android.accessibilityservice.AccessibilityService}. This class is
705     * made immutable before being delivered to an AccessibilityService.
706     * </p>
707     *
708     * @param child The child.
709     * @throws IllegalStateException If called from an AccessibilityService.
710     */
711    public void addChild(View child) {
712        IMPL.addChild(mInfo, child);
713    }
714
715    /**
716     * Adds a virtual child which is a descendant of the given <code>root</code>.
717     * If <code>virtualDescendantId</code> is {@link View#NO_ID} the root
718     * is added as a child.
719     * <p>
720     * A virtual descendant is an imaginary View that is reported as a part of the view
721     * hierarchy for accessibility purposes. This enables custom views that draw complex
722     * content to report them selves as a tree of virtual views, thus conveying their
723     * logical structure.
724     * </p>
725     *
726     * @param root The root of the virtual subtree.
727     * @param virtualDescendantId The id of the virtual child.
728     */
729    public void addChild(View root, int virtualDescendantId) {
730        IMPL.addChild(mInfo, root, virtualDescendantId);
731    }
732
733    /**
734     * Gets the actions that can be performed on the node.
735     *
736     * @return The bit mask of with actions.
737     * @see android.view.accessibility.AccessibilityNodeInfo#ACTION_FOCUS
738     * @see android.view.accessibility.AccessibilityNodeInfo#ACTION_CLEAR_FOCUS
739     * @see android.view.accessibility.AccessibilityNodeInfo#ACTION_SELECT
740     * @see android.view.accessibility.AccessibilityNodeInfo#ACTION_CLEAR_SELECTION
741     */
742    public int getActions() {
743        return IMPL.getActions(mInfo);
744    }
745
746    /**
747     * Adds an action that can be performed on the node.
748     * <p>
749     * <strong>Note:</strong> Cannot be called from an
750     * {@link android.accessibilityservice.AccessibilityService}. This class is
751     * made immutable before being delivered to an AccessibilityService.
752     * </p>
753     *
754     * @param action The action.
755     * @throws IllegalStateException If called from an AccessibilityService.
756     */
757    public void addAction(int action) {
758        IMPL.addAction(mInfo, action);
759    }
760
761    /**
762     * Performs an action on the node.
763     * <p>
764     * <strong>Note:</strong> An action can be performed only if the request is
765     * made from an {@link android.accessibilityservice.AccessibilityService}.
766     * </p>
767     *
768     * @param action The action to perform.
769     * @return True if the action was performed.
770     * @throws IllegalStateException If called outside of an
771     *             AccessibilityService.
772     */
773    public boolean performAction(int action) {
774        return IMPL.performAction(mInfo, action);
775    }
776
777    /**
778     * Finds {@link android.view.accessibility.AccessibilityNodeInfo}s by text. The match
779     * is case insensitive containment. The search is relative to this info i.e. this
780     * info is the root of the traversed tree.
781     * <p>
782     * <strong>Note:</strong> It is a client responsibility to recycle the
783     * received info by calling {@link android.view.accessibility.AccessibilityNodeInfo#recycle()}
784     * to avoid creating of multiple instances.
785     * </p>
786     *
787     * @param text The searched text.
788     * @return A list of node info.
789     */
790    public List<AccessibilityNodeInfoCompat> findAccessibilityNodeInfosByText(String text) {
791        List<AccessibilityNodeInfoCompat> result = new ArrayList<AccessibilityNodeInfoCompat>();
792        List<Object> infos = IMPL.findAccessibilityNodeInfosByText(mInfo, text);
793        final int infoCount = infos.size();
794        for (int i = 0; i < infoCount; i++) {
795            Object info = infos.get(i);
796            result.add(new AccessibilityNodeInfoCompat(info));
797        }
798        return result;
799    }
800
801    /**
802     * Gets the parent.
803     * <p>
804     * <strong>Note:</strong> It is a client responsibility to recycle the
805     * received info by calling {@link android.view.accessibility.AccessibilityNodeInfo#recycle()}
806     * to avoid creating of multiple instances.
807     * </p>
808     *
809     * @return The parent.
810     */
811    public AccessibilityNodeInfoCompat getParent() {
812        return IMPL.getParent(mInfo);
813    }
814
815    /**
816     * Sets the parent.
817     * <p>
818     * <strong>Note:</strong> Cannot be called from an
819     * {@link android.accessibilityservice.AccessibilityService}. This class is
820     * made immutable before being delivered to an AccessibilityService.
821     * </p>
822     *
823     * @param parent The parent.
824     * @throws IllegalStateException If called from an AccessibilityService.
825     */
826    public void setParent(View parent) {
827        IMPL.setParent(mInfo, parent);
828    }
829
830    /**
831     * Gets the node bounds in parent coordinates.
832     *
833     * @param outBounds The output node bounds.
834     */
835    public void getBoundsInParent(Rect outBounds) {
836        IMPL.getBoundsInParent(mInfo, outBounds);
837    }
838
839    /**
840     * Sets the node bounds in parent coordinates.
841     * <p>
842     * <strong>Note:</strong> Cannot be called from an
843     * {@link android.accessibilityservice.AccessibilityService}. This class is
844     * made immutable before being delivered to an AccessibilityService.
845     * </p>
846     *
847     * @param bounds The node bounds.
848     *@throws IllegalStateException If called from an AccessibilityService.
849     */
850    public void setBoundsInParent(Rect bounds) {
851        IMPL.setBoundsInParent(mInfo, bounds);
852    }
853
854    /**
855     * Gets the node bounds in screen coordinates.
856     *
857     * @param outBounds The output node bounds.
858     */
859    public void getBoundsInScreen(Rect outBounds) {
860        IMPL.getBoundsInScreen(mInfo, outBounds);
861    }
862
863    /**
864     * Sets the node bounds in screen coordinates.
865     * <p>
866     * <strong>Note:</strong> Cannot be called from an
867     * {@link android.accessibilityservice.AccessibilityService}. This class is
868     * made immutable before being delivered to an AccessibilityService.
869     * </p>
870     *
871     * @param bounds The node bounds.
872     * @throws IllegalStateException If called from an AccessibilityService.
873     */
874    public void setBoundsInScreen(Rect bounds) {
875        IMPL.setBoundsInScreen(mInfo, bounds);
876    }
877
878    /**
879     * Gets whether this node is checkable.
880     *
881     * @return True if the node is checkable.
882     */
883    public boolean isCheckable() {
884        return IMPL.isCheckable(mInfo);
885    }
886
887    /**
888     * Sets whether this node is checkable.
889     * <p>
890     * <strong>Note:</strong> Cannot be called from an
891     * {@link android.accessibilityservice.AccessibilityService}. This class is
892     * made immutable before being delivered to an AccessibilityService.
893     * </p>
894     *
895     * @param checkable True if the node is checkable.
896     * @throws IllegalStateException If called from an AccessibilityService.
897     */
898    public void setCheckable(boolean checkable) {
899        IMPL.setCheckable(mInfo, checkable);
900    }
901
902    /**
903     * Gets whether this node is checked.
904     *
905     * @return True if the node is checked.
906     */
907    public boolean isChecked() {
908        return IMPL.isChecked(mInfo);
909    }
910
911    /**
912     * Sets whether this node is checked.
913     * <p>
914     * <strong>Note:</strong> Cannot be called from an
915     * {@link android.accessibilityservice.AccessibilityService}. This class is
916     * made immutable before being delivered to an AccessibilityService.
917     * </p>
918     *
919     * @param checked True if the node is checked.
920     * @throws IllegalStateException If called from an AccessibilityService.
921     */
922    public void setChecked(boolean checked) {
923        IMPL.setChecked(mInfo, checked);
924    }
925
926    /**
927     * Gets whether this node is focusable.
928     *
929     * @return True if the node is focusable.
930     */
931    public boolean isFocusable() {
932        return IMPL.isFocusable(mInfo);
933    }
934
935    /**
936     * Sets whether this node is focusable.
937     * <p>
938     * <strong>Note:</strong> Cannot be called from an
939     * {@link android.accessibilityservice.AccessibilityService}. This class is
940     * made immutable before being delivered to an AccessibilityService.
941     * </p>
942     *
943     * @param focusable True if the node is focusable.
944     * @throws IllegalStateException If called from an AccessibilityService.
945     */
946    public void setFocusable(boolean focusable) {
947        IMPL.setFocusable(mInfo, focusable);
948    }
949
950    /**
951     * Gets whether this node is focused.
952     *
953     * @return True if the node is focused.
954     */
955    public boolean isFocused() {
956        return IMPL.isFocused(mInfo);
957    }
958
959    /**
960     * Sets whether this node is focused.
961     * <p>
962     * <strong>Note:</strong> Cannot be called from an
963     * {@link android.accessibilityservice.AccessibilityService}. This class is
964     * made immutable before being delivered to an AccessibilityService.
965     * </p>
966     *
967     * @param focused True if the node is focused.
968     * @throws IllegalStateException If called from an AccessibilityService.
969     */
970    public void setFocused(boolean focused) {
971        IMPL.setFocused(mInfo, focused);
972    }
973
974    /**
975     * Gets whether this node is selected.
976     *
977     * @return True if the node is selected.
978     */
979    public boolean isSelected() {
980        return IMPL.isSelected(mInfo);
981    }
982
983    /**
984     * Sets whether this node is selected.
985     * <p>
986     * <strong>Note:</strong> Cannot be called from an
987     * {@link android.accessibilityservice.AccessibilityService}. This class is
988     * made immutable before being delivered to an AccessibilityService.
989     * </p>
990     *
991     * @param selected True if the node is selected.
992     * @throws IllegalStateException If called from an AccessibilityService.
993     */
994    public void setSelected(boolean selected) {
995        IMPL.setSelected(mInfo, selected);
996    }
997
998    /**
999     * Gets whether this node is clickable.
1000     *
1001     * @return True if the node is clickable.
1002     */
1003    public boolean isClickable() {
1004        return IMPL.isClickable(mInfo);
1005    }
1006
1007    /**
1008     * Sets whether this node is clickable.
1009     * <p>
1010     * <strong>Note:</strong> Cannot be called from an
1011     * {@link android.accessibilityservice.AccessibilityService}. This class is
1012     * made immutable before being delivered to an AccessibilityService.
1013     * </p>
1014     *
1015     * @param clickable True if the node is clickable.
1016     * @throws IllegalStateException If called from an AccessibilityService.
1017     */
1018    public void setClickable(boolean clickable) {
1019        IMPL.setClickable(mInfo, clickable);
1020    }
1021
1022    /**
1023     * Gets whether this node is long clickable.
1024     *
1025     * @return True if the node is long clickable.
1026     */
1027    public boolean isLongClickable() {
1028        return IMPL.isLongClickable(mInfo);
1029    }
1030
1031    /**
1032     * Sets whether this node is long clickable.
1033     * <p>
1034     * <strong>Note:</strong> Cannot be called from an
1035     * {@link android.accessibilityservice.AccessibilityService}. This class is
1036     * made immutable before being delivered to an AccessibilityService.
1037     * </p>
1038     *
1039     * @param longClickable True if the node is long clickable.
1040     * @throws IllegalStateException If called from an AccessibilityService.
1041     */
1042    public void setLongClickable(boolean longClickable) {
1043        IMPL.setLongClickable(mInfo, longClickable);
1044    }
1045
1046    /**
1047     * Gets whether this node is enabled.
1048     *
1049     * @return True if the node is enabled.
1050     */
1051    public boolean isEnabled() {
1052        return IMPL.isEnabled(mInfo);
1053    }
1054
1055    /**
1056     * Sets whether this node is enabled.
1057     * <p>
1058     * <strong>Note:</strong> Cannot be called from an
1059     * {@link android.accessibilityservice.AccessibilityService}. This class is
1060     * made immutable before being delivered to an AccessibilityService.
1061     * </p>
1062     *
1063     * @param enabled True if the node is enabled.
1064     * @throws IllegalStateException If called from an AccessibilityService.
1065     */
1066    public void setEnabled(boolean enabled) {
1067        IMPL.setEnabled(mInfo, enabled);
1068    }
1069
1070    /**
1071     * Gets whether this node is a password.
1072     *
1073     * @return True if the node is a password.
1074     */
1075    public boolean isPassword() {
1076        return IMPL.isPassword(mInfo);
1077    }
1078
1079    /**
1080     * Sets whether this node is a password.
1081     * <p>
1082     * <strong>Note:</strong> Cannot be called from an
1083     * {@link android.accessibilityservice.AccessibilityService}. This class is
1084     * made immutable before being delivered to an AccessibilityService.
1085     * </p>
1086     *
1087     * @param password True if the node is a password.
1088     * @throws IllegalStateException If called from an AccessibilityService.
1089     */
1090    public void setPassword(boolean password) {
1091        IMPL.setPassword(mInfo, password);
1092    }
1093
1094    /**
1095     * Gets if the node is scrollable.
1096     *
1097     * @return True if the node is scrollable, false otherwise.
1098     */
1099    public boolean isScrollable() {
1100        return IMPL.isScrollable(mInfo);
1101    }
1102
1103    /**
1104     * Sets if the node is scrollable.
1105     * <p>
1106     * <strong>Note:</strong> Cannot be called from an
1107     * {@link android.accessibilityservice.AccessibilityService}. This class is
1108     * made immutable before being delivered to an AccessibilityService.
1109     * </p>
1110     *
1111     * @param scrollable True if the node is scrollable, false otherwise.
1112     * @throws IllegalStateException If called from an AccessibilityService.
1113     */
1114    public void setScrollable(boolean scrollable) {
1115        IMPL.setScrollable(mInfo, scrollable);
1116    }
1117
1118    /**
1119     * Gets the package this node comes from.
1120     *
1121     * @return The package name.
1122     */
1123    public CharSequence getPackageName() {
1124        return IMPL.getPackageName(mInfo);
1125    }
1126
1127    /**
1128     * Sets the package this node comes from.
1129     * <p>
1130     * <strong>Note:</strong> Cannot be called from an
1131     * {@link android.accessibilityservice.AccessibilityService}. This class is
1132     * made immutable before being delivered to an AccessibilityService.
1133     * </p>
1134     *
1135     * @param packageName The package name.
1136     * @throws IllegalStateException If called from an AccessibilityService.
1137     */
1138    public void setPackageName(CharSequence packageName) {
1139        IMPL.setPackageName(mInfo, packageName);
1140    }
1141
1142    /**
1143     * Gets the class this node comes from.
1144     *
1145     * @return The class name.
1146     */
1147    public CharSequence getClassName() {
1148        return IMPL.getClassName(mInfo);
1149    }
1150
1151    /**
1152     * Sets the class this node comes from.
1153     * <p>
1154     * <strong>Note:</strong> Cannot be called from an
1155     * {@link android.accessibilityservice.AccessibilityService}. This class is
1156     * made immutable before being delivered to an AccessibilityService.
1157     * </p>
1158     *
1159     * @param className The class name.
1160     * @throws IllegalStateException If called from an AccessibilityService.
1161     */
1162    public void setClassName(CharSequence className) {
1163        IMPL.setClassName(mInfo, className);
1164    }
1165
1166    /**
1167     * Gets the text of this node.
1168     *
1169     * @return The text.
1170     */
1171    public CharSequence getText() {
1172        return IMPL.getText(mInfo);
1173    }
1174
1175    /**
1176     * Sets the text of this node.
1177     * <p>
1178     * <strong>Note:</strong> Cannot be called from an
1179     * {@link android.accessibilityservice.AccessibilityService}. This class is
1180     * made immutable before being delivered to an AccessibilityService.
1181     * </p>
1182     *
1183     * @param text The text.
1184     * @throws IllegalStateException If called from an AccessibilityService.
1185     */
1186    public void setText(CharSequence text) {
1187        IMPL.setText(mInfo, text);
1188    }
1189
1190    /**
1191     * Gets the content description of this node.
1192     *
1193     * @return The content description.
1194     */
1195    public CharSequence getContentDescription() {
1196        return IMPL.getContentDescription(mInfo);
1197    }
1198
1199    /**
1200     * Sets the content description of this node.
1201     * <p>
1202     * <strong>Note:</strong> Cannot be called from an
1203     * {@link android.accessibilityservice.AccessibilityService}. This class is
1204     * made immutable before being delivered to an AccessibilityService.
1205     * </p>
1206     *
1207     * @param contentDescription The content description.
1208     * @throws IllegalStateException If called from an AccessibilityService.
1209     */
1210    public void setContentDescription(CharSequence contentDescription) {
1211        IMPL.setContentDescription(mInfo, contentDescription);
1212    }
1213
1214    /**
1215     * Return an instance back to be reused.
1216     * <p>
1217     * <strong>Note:</strong> You must not touch the object after calling this function.
1218     *
1219     * @throws IllegalStateException If the info is already recycled.
1220     */
1221    public void recycle() {
1222        IMPL.recycle(mInfo);
1223    }
1224
1225    @Override
1226    public int hashCode() {
1227        return (mInfo == null) ? 0 : mInfo.hashCode();
1228    }
1229
1230    @Override
1231    public boolean equals(Object obj) {
1232        if (this == obj) {
1233            return true;
1234        }
1235        if (obj == null) {
1236            return false;
1237        }
1238        if (getClass() != obj.getClass()) {
1239            return false;
1240        }
1241        AccessibilityNodeInfoCompat other = (AccessibilityNodeInfoCompat) obj;
1242        if (mInfo == null) {
1243            if (other.mInfo != null) {
1244                return false;
1245            }
1246        } else if (!mInfo.equals(other.mInfo)) {
1247            return false;
1248        }
1249        return true;
1250    }
1251}
1252