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