Home | History | Annotate | Download | only in cts
      1 /*
      2  * Copyright (C) 2012 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 
     17 package android.view.accessibility.cts;
     18 
     19 import android.graphics.Rect;
     20 import android.graphics.Region;
     21 import android.os.Bundle;
     22 import android.os.Parcel;
     23 import android.platform.test.annotations.Presubmit;
     24 import android.test.AndroidTestCase;
     25 import android.test.suitebuilder.annotation.SmallTest;
     26 import android.text.InputType;
     27 import android.text.TextUtils;
     28 import android.util.ArrayMap;
     29 import android.view.View;
     30 import android.view.accessibility.AccessibilityEvent;
     31 import android.view.accessibility.AccessibilityNodeInfo;
     32 import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
     33 import android.view.accessibility.AccessibilityNodeInfo.CollectionInfo;
     34 import android.view.accessibility.AccessibilityNodeInfo.CollectionItemInfo;
     35 import android.view.accessibility.AccessibilityNodeInfo.RangeInfo;
     36 import android.view.accessibility.AccessibilityNodeInfo.TouchDelegateInfo;
     37 
     38 import java.util.ArrayList;
     39 import java.util.Arrays;
     40 import java.util.List;
     41 
     42 /**
     43  * Class for testing {@link AccessibilityNodeInfo}.
     44  */
     45 @Presubmit
     46 public class AccessibilityNodeInfoTest extends AndroidTestCase {
     47 
     48     @SmallTest
     49     public void testMarshaling() throws Exception {
     50         // fully populate the node info to marshal
     51         AccessibilityNodeInfo sentInfo = AccessibilityNodeInfo.obtain(new View(getContext()));
     52         fullyPopulateAccessibilityNodeInfo(sentInfo);
     53 
     54         // marshal and unmarshal the node info
     55         Parcel parcel = Parcel.obtain();
     56         sentInfo.writeToParcelNoRecycle(parcel, 0);
     57         parcel.setDataPosition(0);
     58         AccessibilityNodeInfo receivedInfo = AccessibilityNodeInfo.CREATOR.createFromParcel(parcel);
     59 
     60         // make sure all fields properly marshaled
     61         assertEqualsAccessibilityNodeInfo(sentInfo, receivedInfo);
     62 
     63         parcel.recycle();
     64     }
     65 
     66     /**
     67      * Tests if {@link AccessibilityNodeInfo}s are properly reused.
     68      */
     69     @SmallTest
     70     public void testReuse() {
     71         AccessibilityEvent firstInfo = AccessibilityEvent.obtain();
     72         firstInfo.recycle();
     73         AccessibilityEvent secondInfo = AccessibilityEvent.obtain();
     74         assertSame("AccessibilityNodeInfo not properly reused", firstInfo, secondInfo);
     75     }
     76 
     77     /**
     78      * Tests if {@link AccessibilityNodeInfo} are properly recycled.
     79      */
     80     @SmallTest
     81     public void testRecycle() {
     82         // obtain and populate an node info
     83         AccessibilityNodeInfo populatedInfo = AccessibilityNodeInfo.obtain();
     84         fullyPopulateAccessibilityNodeInfo(populatedInfo);
     85 
     86         // recycle and obtain the same recycled instance
     87         populatedInfo.recycle();
     88         AccessibilityNodeInfo recycledInfo = AccessibilityNodeInfo.obtain();
     89 
     90         // check expectations
     91         assertAccessibilityNodeInfoCleared(recycledInfo);
     92     }
     93 
     94     /**
     95      * Tests whether the event describes its contents consistently.
     96      */
     97     @SmallTest
     98     public void testDescribeContents() {
     99         AccessibilityNodeInfo info = AccessibilityNodeInfo.obtain();
    100         assertSame("Accessibility node infos always return 0 for this method.", 0,
    101                 info.describeContents());
    102         fullyPopulateAccessibilityNodeInfo(info);
    103         assertSame("Accessibility node infos always return 0 for this method.", 0,
    104                 info.describeContents());
    105     }
    106 
    107     /**
    108      * Tests whether accessibility actions are properly added.
    109      */
    110     @SmallTest
    111     public void testAddActions() {
    112         List<AccessibilityAction> customActions = new ArrayList<AccessibilityAction>();
    113         customActions.add(new AccessibilityAction(AccessibilityNodeInfo.ACTION_FOCUS, "Foo"));
    114         customActions.add(new AccessibilityAction(R.id.foo_custom_action, "Foo"));
    115 
    116         AccessibilityNodeInfo info = AccessibilityNodeInfo.obtain();
    117         info.addAction(AccessibilityNodeInfo.ACTION_FOCUS);
    118         info.addAction(AccessibilityNodeInfo.ACTION_CLEAR_FOCUS);
    119         for (AccessibilityAction customAction : customActions) {
    120             info.addAction(customAction);
    121         }
    122 
    123         assertSame(info.getActions(), (AccessibilityNodeInfo.ACTION_FOCUS
    124                 | AccessibilityNodeInfo.ACTION_CLEAR_FOCUS));
    125 
    126         List<AccessibilityAction> allActions = new ArrayList<AccessibilityAction>();
    127         allActions.add(AccessibilityAction.ACTION_CLEAR_FOCUS);
    128         allActions.addAll(customActions);
    129         assertEquals(info.getActionList(), allActions);
    130     }
    131 
    132     /**
    133      * Tests whether we catch addition of an action with invalid id.
    134      */
    135     @SmallTest
    136     public void testCreateInvalidActionId() {
    137         try {
    138             new AccessibilityAction(3, null);
    139         } catch (IllegalArgumentException iae) {
    140             /* expected */
    141         }
    142     }
    143 
    144     /**
    145      * Tests whether accessibility actions are properly removed.
    146      */
    147     @SmallTest
    148     public void testRemoveActions() {
    149         AccessibilityNodeInfo info = AccessibilityNodeInfo.obtain();
    150 
    151         info.addAction(AccessibilityNodeInfo.ACTION_FOCUS);
    152         assertSame(info.getActions(), AccessibilityNodeInfo.ACTION_FOCUS);
    153 
    154         info.removeAction(AccessibilityNodeInfo.ACTION_FOCUS);
    155         assertSame(info.getActions(), 0);
    156         assertTrue(info.getActionList().isEmpty());
    157 
    158         AccessibilityAction customFocus = new AccessibilityAction(
    159                 AccessibilityNodeInfo.ACTION_FOCUS, "Foo");
    160         info.addAction(AccessibilityNodeInfo.ACTION_FOCUS);
    161         info.addAction(customFocus);
    162         assertSame(info.getActionList().size(), 1);
    163         assertEquals(info.getActionList().get(0), customFocus);
    164         assertSame(info.getActions(), AccessibilityNodeInfo.ACTION_FOCUS);
    165 
    166         info.removeAction(customFocus);
    167         assertSame(info.getActions(), 0);
    168         assertTrue(info.getActionList().isEmpty());
    169     }
    170 
    171     /**
    172      * While CharSequence is immutable, some classes implementing it are mutable. Make sure they
    173      * can't change the object by changing the objects backing CharSequence
    174      */
    175     @SmallTest
    176     public void testChangeTextAfterSetting_shouldNotAffectInfo() {
    177         final String originalText = "Cassowaries";
    178         final String newText = "Hornbill";
    179         AccessibilityNodeInfo info = AccessibilityNodeInfo.obtain();
    180         StringBuffer updatingString = new StringBuffer(originalText);
    181         info.setText(updatingString);
    182         info.setError(updatingString);
    183         info.setContentDescription(updatingString);
    184 
    185         updatingString.delete(0, updatingString.length());
    186         updatingString.append(newText);
    187 
    188         assertTrue(TextUtils.equals(originalText, info.getText()));
    189         assertTrue(TextUtils.equals(originalText, info.getError()));
    190         assertTrue(TextUtils.equals(originalText, info.getContentDescription()));
    191     }
    192 
    193     @SmallTest
    194     public void testIsHeadingTakesOldApiIntoAccount() {
    195         final AccessibilityNodeInfo info = AccessibilityNodeInfo.obtain();
    196         assertFalse(info.isHeading());
    197         final CollectionItemInfo headingItemInfo = CollectionItemInfo.obtain(0, 1, 0, 1, true);
    198         info.setCollectionItemInfo(headingItemInfo);
    199         assertTrue(info.isHeading());
    200         final CollectionItemInfo nonHeadingItemInfo = CollectionItemInfo.obtain(0, 1, 0, 1, false);
    201         info.setCollectionItemInfo(nonHeadingItemInfo);
    202         assertFalse(info.isHeading());
    203     }
    204 
    205     /**
    206      * Fully populates the {@link AccessibilityNodeInfo} to marshal.
    207      *
    208      * @param info The node info to populate.
    209      */
    210     private void fullyPopulateAccessibilityNodeInfo(AccessibilityNodeInfo info) {
    211         // Populate 10 fields
    212         info.setBoundsInParent(new Rect(1,1,1,1));
    213         info.setBoundsInScreen(new Rect(2,2,2,2));
    214         info.setClassName("foo.bar.baz.Class");
    215         info.setContentDescription("content description");
    216         info.setTooltipText("tooltip");
    217         info.setPackageName("foo.bar.baz");
    218         info.setText("text");
    219         info.setHintText("hint");
    220         // 2 children = 1 field
    221         info.addChild(new View(getContext()));
    222         info.addChild(new View(getContext()), 1);
    223         // 2 built-in actions and 2 custom actions, but all are in 1 field
    224         info.addAction(AccessibilityNodeInfo.ACTION_FOCUS);
    225         info.addAction(AccessibilityNodeInfo.ACTION_CLEAR_FOCUS);
    226         info.addAction(new AccessibilityAction(AccessibilityNodeInfo.ACTION_FOCUS, "Foo"));
    227         info.addAction(new AccessibilityAction(R.id.foo_custom_action, "Foo"));
    228 
    229         // Populate 10 fields
    230         info.setMovementGranularities(AccessibilityNodeInfo.MOVEMENT_GRANULARITY_LINE);
    231         info.setViewIdResourceName("foo.bar:id/baz");
    232         info.setDrawingOrder(5);
    233         info.setAvailableExtraData(
    234                 Arrays.asList(AccessibilityNodeInfo.EXTRA_DATA_TEXT_CHARACTER_LOCATION_KEY));
    235         info.setPaneTitle("Pane title");
    236         info.setError("Error text");
    237         info.setMaxTextLength(42);
    238         // Text selection is 2 fields
    239         info.setTextSelection(3, 7);
    240         info.setLiveRegion(View.ACCESSIBILITY_LIVE_REGION_POLITE);
    241 
    242         // Populate 10 fields
    243         Bundle extras = info.getExtras();
    244         extras.putBoolean("areCassowariesAwesome", true);
    245         info.setInputType(InputType.TYPE_CLASS_TEXT);
    246         info.setRangeInfo(RangeInfo.obtain(RangeInfo.RANGE_TYPE_FLOAT, 0.05f, 1.0f, 0.01f));
    247         info.setCollectionInfo(
    248                 CollectionInfo.obtain(2, 2, true, CollectionInfo.SELECTION_MODE_MULTIPLE));
    249         info.setCollectionItemInfo(CollectionItemInfo.obtain(1, 2, 3, 4, true, true));
    250         info.setParent(new View(getContext()));
    251         info.setSource(new View(getContext())); // Populates 2 fields: source and window id
    252         info.setTraversalBefore(new View(getContext()));
    253         info.setTraversalAfter(new View(getContext()));
    254 
    255         // Populate 3 fields
    256         info.setLabeledBy(new View(getContext()));
    257         info.setLabelFor(new View(getContext()));
    258         populateTouchDelegateTargetMap(info);
    259 
    260         // And Boolean properties are another field. Total is 34
    261 
    262         // 10 Boolean properties
    263         info.setCheckable(true);
    264         info.setChecked(true);
    265         info.setFocusable(true);
    266         info.setFocused(true);
    267         info.setSelected(true);
    268         info.setClickable(true);
    269         info.setLongClickable(true);
    270         info.setEnabled(true);
    271         info.setPassword(true);
    272         info.setScrollable(true);
    273 
    274         // 10 Boolean properties
    275         info.setAccessibilityFocused(true);
    276         info.setVisibleToUser(true);
    277         info.setEditable(true);
    278         info.setCanOpenPopup(true);
    279         info.setDismissable(true);
    280         info.setMultiLine(true);
    281         info.setContentInvalid(true);
    282         info.setContextClickable(true);
    283         info.setImportantForAccessibility(true);
    284         info.setScreenReaderFocusable(true);
    285 
    286         // 3 Boolean properties, for a total of 23
    287         info.setShowingHintText(true);
    288         info.setHeading(true);
    289         info.setTextEntryKey(true);
    290     }
    291 
    292     /**
    293      * Populates touch delegate target map.
    294      */
    295     private void populateTouchDelegateTargetMap(AccessibilityNodeInfo info) {
    296         final ArrayMap<Region, View> targetMap = new ArrayMap<>(3);
    297         final Rect rect1 = new Rect(1, 1, 10, 10);
    298         final Rect rect2 = new Rect(2, 2, 20, 20);
    299         final Rect rect3 = new Rect(3, 3, 30, 30);
    300         targetMap.put(new Region(rect1), new View(getContext()));
    301         targetMap.put(new Region(rect2), new View(getContext()));
    302         targetMap.put(new Region(rect3), new View(getContext()));
    303 
    304         final TouchDelegateInfo touchDelegateInfo = new TouchDelegateInfo(targetMap);
    305         info.setTouchDelegateInfo(touchDelegateInfo);
    306     }
    307 
    308     private static void assertEqualsTouchDelegateInfo(String message,
    309             AccessibilityNodeInfo.TouchDelegateInfo expected,
    310             AccessibilityNodeInfo.TouchDelegateInfo actual) {
    311         if (expected == actual) return;
    312         assertEquals(message, expected.getRegionCount(), actual.getRegionCount());
    313         for (int i = 0; i < expected.getRegionCount(); i++) {
    314             final Region expectedRegion = expected.getRegionAt(i);
    315             final Long expectedId = expected.getAccessibilityIdForRegion(expectedRegion);
    316             boolean matched = false;
    317             for (int j = 0; j < actual.getRegionCount(); j++) {
    318                 final Region actualRegion = actual.getRegionAt(j);
    319                 final Long actualId = actual.getAccessibilityIdForRegion(actualRegion);
    320                 if (expectedRegion.equals(actualRegion) && expectedId.equals(actualId)) {
    321                     matched = true;
    322                     break;
    323                 }
    324             }
    325             assertTrue(message, matched);
    326         }
    327     }
    328 
    329     /**
    330      * Compares all properties of the <code>expectedInfo</code> and the
    331      * <code>receivedInfo</code> to verify that the received node info is
    332      * the one that is expected.
    333      */
    334     public static void assertEqualsAccessibilityNodeInfo(AccessibilityNodeInfo expectedInfo,
    335             AccessibilityNodeInfo receivedInfo) {
    336         // Check 10 fields
    337         Rect expectedBounds = new Rect();
    338         Rect receivedBounds = new Rect();
    339         expectedInfo.getBoundsInParent(expectedBounds);
    340         receivedInfo.getBoundsInParent(receivedBounds);
    341         assertEquals("boundsInParent has incorrect value", expectedBounds, receivedBounds);
    342         expectedInfo.getBoundsInScreen(expectedBounds);
    343         receivedInfo.getBoundsInScreen(receivedBounds);
    344         assertEquals("boundsInScreen has incorrect value", expectedBounds, receivedBounds);
    345         assertEquals("className has incorrect value", expectedInfo.getClassName(),
    346                 receivedInfo.getClassName());
    347         assertEquals("contentDescription has incorrect value", expectedInfo.getContentDescription(),
    348                 receivedInfo.getContentDescription());
    349         assertEquals("tooltip text has incorrect value", expectedInfo.getTooltipText(),
    350                 receivedInfo.getTooltipText());
    351         assertEquals("packageName has incorrect value", expectedInfo.getPackageName(),
    352                 receivedInfo.getPackageName());
    353         assertEquals("text has incorrect value", expectedInfo.getText(), receivedInfo.getText());
    354         assertEquals("Hint text has incorrect value",
    355                 expectedInfo.getHintText(), receivedInfo.getHintText());
    356         assertSame("childCount has incorrect value", expectedInfo.getChildCount(),
    357                 receivedInfo.getChildCount());
    358         // Actions is just 1 field, but we check it 2 ways
    359         assertSame("actions has incorrect value", expectedInfo.getActions(),
    360                 receivedInfo.getActions());
    361         assertEquals("actionsSet has incorrect value", expectedInfo.getActionList(),
    362                 receivedInfo.getActionList());
    363 
    364         // Check 10 fields
    365         assertSame("movementGranularities has incorrect value",
    366                 expectedInfo.getMovementGranularities(),
    367                 receivedInfo.getMovementGranularities());
    368         assertEquals("viewId has incorrect value", expectedInfo.getViewIdResourceName(),
    369                 receivedInfo.getViewIdResourceName());
    370         assertEquals("drawing order has incorrect value", expectedInfo.getDrawingOrder(),
    371                 receivedInfo.getDrawingOrder());
    372         assertEquals("Extra data flags have incorrect value", expectedInfo.getAvailableExtraData(),
    373                 receivedInfo.getAvailableExtraData());
    374         assertEquals("Pane title has incorrect value", expectedInfo.getPaneTitle(),
    375                 receivedInfo.getPaneTitle());
    376         assertEquals("Error text has incorrect value", expectedInfo.getError(),
    377                 receivedInfo.getError());
    378         assertEquals("Max text length has incorrect value", expectedInfo.getMaxTextLength(),
    379                 receivedInfo.getMaxTextLength());
    380         assertEquals("Text selection start has incorrect value",
    381                 expectedInfo.getTextSelectionStart(), receivedInfo.getTextSelectionStart());
    382         assertEquals("Text selection end has incorrect value",
    383                 expectedInfo.getTextSelectionEnd(), receivedInfo.getTextSelectionEnd());
    384         assertEquals("Live region has incorrect value", expectedInfo.getLiveRegion(),
    385                 receivedInfo.getLiveRegion());
    386 
    387         // Check 2 fields
    388         // Extras is a Bundle, and Bundle doesn't declare equals. Comparing the keyset gets us
    389         // what we need, though
    390         assertEquals("Extras have incorrect value", expectedInfo.getExtras().keySet(),
    391                 receivedInfo.getExtras().keySet());
    392         assertEquals("InputType has incorrect value", expectedInfo.getInputType(),
    393                 receivedInfo.getInputType());
    394 
    395         // Check 3 fields with sub-objects
    396         RangeInfo expectedRange = expectedInfo.getRangeInfo();
    397         RangeInfo receivedRange = receivedInfo.getRangeInfo();
    398         assertEquals("Range info has incorrect value", (expectedRange != null),
    399                 (receivedRange != null));
    400         if (expectedRange != null) {
    401             assertEquals("RangeInfo#getCurrent has incorrect value", expectedRange.getCurrent(),
    402                     receivedRange.getCurrent());
    403             assertEquals("RangeInfo#getMin has incorrect value", expectedRange.getMin(),
    404                     receivedRange.getMin());
    405             assertEquals("RangeInfo#getMax has incorrect value", expectedRange.getMax(),
    406                     receivedRange.getMax());
    407             assertEquals("RangeInfo#getType has incorrect value", expectedRange.getType(),
    408                     receivedRange.getType());
    409         }
    410 
    411         CollectionInfo expectedCollectionInfo = expectedInfo.getCollectionInfo();
    412         CollectionInfo receivedCollectionInfo = receivedInfo.getCollectionInfo();
    413         assertEquals("Collection info has incorrect value", (expectedCollectionInfo != null),
    414                 (receivedCollectionInfo != null));
    415         if (expectedCollectionInfo != null) {
    416             assertEquals("CollectionInfo#getColumnCount has incorrect value",
    417                     expectedCollectionInfo.getColumnCount(),
    418                     receivedCollectionInfo.getColumnCount());
    419             assertEquals("CollectionInfo#getRowCount has incorrect value",
    420                     expectedCollectionInfo.getRowCount(), receivedCollectionInfo.getRowCount());
    421             assertEquals("CollectionInfo#getSelectionMode has incorrect value",
    422                     expectedCollectionInfo.getSelectionMode(),
    423                     receivedCollectionInfo.getSelectionMode());
    424         }
    425 
    426         CollectionItemInfo expectedItemInfo = expectedInfo.getCollectionItemInfo();
    427         CollectionItemInfo receivedItemInfo = receivedInfo.getCollectionItemInfo();
    428         assertEquals("Collection item info has incorrect value", (expectedItemInfo != null),
    429                 (receivedItemInfo != null));
    430         if (expectedItemInfo != null) {
    431             assertEquals("CollectionItemInfo#getColumnIndex has incorrect value",
    432                     expectedItemInfo.getColumnIndex(),
    433                     receivedItemInfo.getColumnIndex());
    434             assertEquals("CollectionItemInfo#getColumnSpan has incorrect value",
    435                     expectedItemInfo.getColumnSpan(),
    436                     receivedItemInfo.getColumnSpan());
    437             assertEquals("CollectionItemInfo#getRowIndex has incorrect value",
    438                     expectedItemInfo.getRowIndex(),
    439                     receivedItemInfo.getRowIndex());
    440             assertEquals("CollectionItemInfo#getRowSpan has incorrect value",
    441                     expectedItemInfo.getRowSpan(),
    442                     receivedItemInfo.getRowSpan());
    443         }
    444 
    445         assertEqualsTouchDelegateInfo("TouchDelegate target map has incorrect value",
    446                 expectedInfo.getTouchDelegateInfo(),
    447                 receivedInfo.getTouchDelegateInfo());
    448 
    449         // And the boolean properties are another field, for a total of 26
    450         // Missing parent: Tested end-to-end in AccessibilityWindowTraversalTest#testObjectContract
    451         //                 (getting a child is also checked there)
    452         //         traversalbefore: AccessibilityEndToEndTest
    453         //                          #testTraversalBeforeReportedToAccessibility
    454         //         traversalafter: AccessibilityEndToEndTest
    455         //                         #testTraversalAfterReportedToAccessibility
    456         //         labelfor: AccessibilityEndToEndTest#testLabelForReportedToAccessibility
    457         //         labeledby: AccessibilityEndToEndTest#testLabelForReportedToAccessibility
    458         //         windowid: Not directly observable
    459         //         sourceid: Not directly observable
    460         // Which brings us to a total of 33
    461 
    462         // 10 Boolean properties
    463         assertSame("checkable has incorrect value", expectedInfo.isCheckable(),
    464                 receivedInfo.isCheckable());
    465         assertSame("checked has incorrect value", expectedInfo.isChecked(),
    466                 receivedInfo.isChecked());
    467         assertSame("focusable has incorrect value", expectedInfo.isFocusable(),
    468                 receivedInfo.isFocusable());
    469         assertSame("focused has incorrect value", expectedInfo.isFocused(),
    470                 receivedInfo.isFocused());
    471         assertSame("selected has incorrect value", expectedInfo.isSelected(),
    472                 receivedInfo.isSelected());
    473         assertSame("clickable has incorrect value", expectedInfo.isClickable(),
    474                 receivedInfo.isClickable());
    475         assertSame("longClickable has incorrect value", expectedInfo.isLongClickable(),
    476                 receivedInfo.isLongClickable());
    477         assertSame("enabled has incorrect value", expectedInfo.isEnabled(),
    478                 receivedInfo.isEnabled());
    479         assertSame("password has incorrect value", expectedInfo.isPassword(),
    480                 receivedInfo.isPassword());
    481         assertSame("scrollable has incorrect value", expectedInfo.isScrollable(),
    482                 receivedInfo.isScrollable());
    483 
    484         // 10 Boolean properties
    485         assertSame("AccessibilityFocused has incorrect value",
    486                 expectedInfo.isAccessibilityFocused(),
    487                 receivedInfo.isAccessibilityFocused());
    488         assertSame("VisibleToUser has incorrect value", expectedInfo.isVisibleToUser(),
    489                 receivedInfo.isVisibleToUser());
    490         assertSame("Editable has incorrect value", expectedInfo.isEditable(),
    491                 receivedInfo.isEditable());
    492         assertSame("canOpenPopup has incorrect value", expectedInfo.canOpenPopup(),
    493                 receivedInfo.canOpenPopup());
    494         assertSame("Dismissable has incorrect value", expectedInfo.isDismissable(),
    495                 receivedInfo.isDismissable());
    496         assertSame("Multiline has incorrect value", expectedInfo.isMultiLine(),
    497                 receivedInfo.isMultiLine());
    498         assertSame("ContentInvalid has incorrect value", expectedInfo.isContentInvalid(),
    499                 receivedInfo.isContentInvalid());
    500         assertSame("contextClickable has incorrect value", expectedInfo.isContextClickable(),
    501                 receivedInfo.isContextClickable());
    502         assertSame("importantForAccessibility has incorrect value",
    503                 expectedInfo.isImportantForAccessibility(),
    504                 receivedInfo.isImportantForAccessibility());
    505         assertSame("isScreenReaderFocusable has incorrect value",
    506                 expectedInfo.isScreenReaderFocusable(), receivedInfo.isScreenReaderFocusable());
    507 
    508         // 3 Boolean properties, for a total of 23
    509         assertSame("isShowingHint has incorrect value",
    510                 expectedInfo.isShowingHintText(), receivedInfo.isShowingHintText());
    511         assertSame("isHeading has incorrect value",
    512                 expectedInfo.isHeading(), receivedInfo.isHeading());
    513         assertSame("isTextEntryKey has incorrect value",
    514                 expectedInfo.isTextEntryKey(), receivedInfo.isTextEntryKey());
    515     }
    516 
    517     /**
    518      * Asserts that an {@link AccessibilityNodeInfo} is cleared.
    519      *
    520      * @param info The node info to check.
    521      */
    522     public static void assertAccessibilityNodeInfoCleared(AccessibilityNodeInfo info) {
    523         // Check 10 fields
    524         Rect bounds = new Rect();
    525         info.getBoundsInParent(bounds);
    526         assertTrue("boundsInParent not properly recycled", bounds.isEmpty());
    527         info.getBoundsInScreen(bounds);
    528         assertTrue("boundsInScreen not properly recycled", bounds.isEmpty());
    529         assertNull("className not properly recycled", info.getClassName());
    530         assertNull("contentDescription not properly recycled", info.getContentDescription());
    531         assertNull("tooltiptext not properly recycled", info.getTooltipText());
    532         assertNull("packageName not properly recycled", info.getPackageName());
    533         assertNull("text not properly recycled", info.getText());
    534         assertNull("Hint text not properly recycled", info.getHintText());
    535         assertEquals("Children list not properly recycled", 0, info.getChildCount());
    536         // Actions are in one field
    537         assertSame("actions not properly recycled", 0, info.getActions());
    538         assertTrue("action list not properly recycled", info.getActionList().isEmpty());
    539 
    540         // Check 10 fields
    541         assertSame("movementGranularities not properly recycled", 0,
    542                 info.getMovementGranularities());
    543         assertNull("viewId not properly recycled", info.getViewIdResourceName());
    544         assertEquals(0, info.getDrawingOrder());
    545         assertTrue(info.getAvailableExtraData().isEmpty());
    546         assertNull("Pane title not properly recycled", info.getPaneTitle());
    547         assertNull("Error text not properly recycled", info.getError());
    548         assertEquals("Max text length not properly recycled", -1, info.getMaxTextLength());
    549         assertEquals("Text selection start not properly recycled",
    550                 -1, info.getTextSelectionStart());
    551         assertEquals("Text selection end not properly recycled", -1, info.getTextSelectionEnd());
    552         assertEquals("Live region not properly recycled", 0, info.getLiveRegion());
    553 
    554         // Check 6 fields
    555         assertEquals("Extras not properly recycled", 0, info.getExtras().keySet().size());
    556         assertEquals("Input type not properly recycled", 0, info.getInputType());
    557         assertNull("Range info not properly recycled", info.getRangeInfo());
    558         assertNull("Collection info not properly recycled", info.getCollectionInfo());
    559         assertNull("Collection item info not properly recycled", info.getCollectionItemInfo());
    560         assertNull("TouchDelegate target map not recycled", info.getTouchDelegateInfo());
    561 
    562         // And Boolean properties brings up to 26 fields
    563         // Missing:
    564         //  parent (can't be performed on sealed instance, even if null)
    565         //  traversalbefore (can't be performed on sealed instance, even if null)
    566         //  traversalafter (can't be performed on sealed instance, even if null)
    567         //  labelfor (can't be performed on sealed instance, even if null)
    568         //  labeledby (can't be performed on sealed instance, even if null)
    569         //  sourceId (not directly observable)
    570         //  windowId (not directly observable)
    571         // a total of 33
    572 
    573         // 10 Boolean properties
    574         assertFalse("checkable not properly recycled", info.isCheckable());
    575         assertFalse("checked not properly recycled", info.isChecked());
    576         assertFalse("focusable not properly recycled", info.isFocusable());
    577         assertFalse("focused not properly recycled", info.isFocused());
    578         assertFalse("selected not properly recycled", info.isSelected());
    579         assertFalse("clickable not properly recycled", info.isClickable());
    580         assertFalse("longClickable not properly recycled", info.isLongClickable());
    581         assertFalse("enabled not properly recycled", info.isEnabled());
    582         assertFalse("password not properly recycled", info.isPassword());
    583         assertFalse("scrollable not properly recycled", info.isScrollable());
    584 
    585         // 10 Boolean properties
    586         assertFalse("accessibility focused not properly recycled", info.isAccessibilityFocused());
    587         assertFalse("VisibleToUser not properly recycled", info.isVisibleToUser());
    588         assertFalse("Editable not properly recycled", info.isEditable());
    589         assertFalse("canOpenPopup not properly recycled", info.canOpenPopup());
    590         assertFalse("Dismissable not properly recycled", info.isDismissable());
    591         assertFalse("Multiline not properly recycled", info.isMultiLine());
    592         assertFalse("ContentInvalid not properly recycled", info.isContentInvalid());
    593         assertFalse("contextClickable not properly recycled", info.isContextClickable());
    594         assertFalse("importantForAccessibility not properly recycled",
    595                 info.isImportantForAccessibility());
    596         assertFalse("ScreenReaderFocusable not properly recycled", info.isScreenReaderFocusable());
    597 
    598         // 3 Boolean properties
    599         assertFalse("isShowingHint not properly reset", info.isShowingHintText());
    600         assertFalse("isHeading not properly reset", info.isHeading());
    601         assertFalse("isTextEntryKey not properly reset", info.isTextEntryKey());
    602     }
    603 }
    604