1/* 2 * Copyright 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package android.view.accessibility; 18 19import static org.hamcrest.Matchers.emptyCollectionOf; 20import static org.hamcrest.Matchers.equalTo; 21import static org.hamcrest.Matchers.hasItem; 22import static org.junit.Assert.assertThat; 23import static org.junit.Assert.fail; 24 25import android.os.Parcel; 26import android.support.test.filters.LargeTest; 27import android.support.test.runner.AndroidJUnit4; 28import android.util.ArraySet; 29import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction; 30 31import com.android.internal.util.CollectionUtils; 32 33import org.junit.Test; 34import org.junit.runner.RunWith; 35 36import java.util.ArrayList; 37 38@LargeTest 39@RunWith(AndroidJUnit4.class) 40public class AccessibilityNodeInfoTest { 41 // The number of fields tested in the corresponding CTS AccessibilityNodeInfoTest: 42 // See fullyPopulateAccessibilityNodeInfo, assertEqualsAccessibilityNodeInfo, 43 // and assertAccessibilityNodeInfoCleared in that class. 44 private static final int NUM_MARSHALLED_PROPERTIES = 35; 45 46 /** 47 * The number of properties that are purposely not marshalled 48 * mOriginalText - Used when resolving clickable spans; intentionally not parceled 49 */ 50 private static final int NUM_NONMARSHALLED_PROPERTIES = 1; 51 52 @Test 53 public void testStandardActions_serializationFlagIsValid() { 54 AccessibilityAction brokenStandardAction = CollectionUtils.find( 55 new ArrayList<>(AccessibilityAction.sStandardActions), 56 action -> Long.bitCount(action.mSerializationFlag) != 1); 57 if (brokenStandardAction != null) { 58 String message = "Invalid serialization flag(0x" 59 + Long.toHexString(brokenStandardAction.mSerializationFlag) 60 + ") in " + brokenStandardAction; 61 if (brokenStandardAction.mSerializationFlag == 0L) { 62 message += "\nThis is likely due to an overflow"; 63 } 64 fail(message); 65 } 66 67 brokenStandardAction = CollectionUtils.find( 68 new ArrayList<>(AccessibilityAction.sStandardActions), 69 action -> Integer.bitCount(action.getId()) == 1 70 && action.getId() <= AccessibilityNodeInfo.LAST_LEGACY_STANDARD_ACTION 71 && action.getId() != action.mSerializationFlag); 72 if (brokenStandardAction != null) { 73 fail("Serialization flag(0x" 74 + Long.toHexString(brokenStandardAction.mSerializationFlag) 75 + ") is different from legacy action id(0x" 76 + Integer.toHexString(brokenStandardAction.getId()) 77 + ") in " + brokenStandardAction); 78 } 79 } 80 81 @Test 82 public void testStandardActions_idsAreUnique() { 83 ArraySet<AccessibilityAction> actions = AccessibilityAction.sStandardActions; 84 for (int i = 0; i < actions.size(); i++) { 85 for (int j = 0; j < i; j++) { 86 int id = actions.valueAt(i).getId(); 87 if (id == actions.valueAt(j).getId()) { 88 fail("Id 0x" + Integer.toHexString(id) 89 + " is duplicated for standard actions #" + i + " and #" + j); 90 } 91 } 92 } 93 } 94 95 @Test 96 public void testStandardActions_allComeThroughParceling() { 97 for (AccessibilityAction action : AccessibilityAction.sStandardActions) { 98 final AccessibilityNodeInfo nodeWithAction = AccessibilityNodeInfo.obtain(); 99 nodeWithAction.addAction(action); 100 assertThat(nodeWithAction.getActionList(), hasItem(action)); 101 final Parcel parcel = Parcel.obtain(); 102 nodeWithAction.writeToParcel(parcel, 0); 103 parcel.setDataPosition(0); 104 final AccessibilityNodeInfo unparceledNode = 105 AccessibilityNodeInfo.CREATOR.createFromParcel(parcel); 106 assertThat(unparceledNode.getActionList(), hasItem(action)); 107 } 108 } 109 110 @Test 111 public void testEmptyListOfActions_parcelsCorrectly() { 112 // Also set text, as if there's nothing else in the parcel it can unparcel even with 113 // a bug present. 114 final String text = "text"; 115 final AccessibilityNodeInfo nodeWithEmptyActionList = AccessibilityNodeInfo.obtain(); 116 nodeWithEmptyActionList.addAction(AccessibilityAction.ACTION_ACCESSIBILITY_FOCUS); 117 nodeWithEmptyActionList.removeAction(AccessibilityAction.ACTION_ACCESSIBILITY_FOCUS); 118 nodeWithEmptyActionList.setText(text); 119 final Parcel parcel = Parcel.obtain(); 120 nodeWithEmptyActionList.writeToParcel(parcel, 0); 121 parcel.setDataPosition(0); 122 final AccessibilityNodeInfo unparceledNode = 123 AccessibilityNodeInfo.CREATOR.createFromParcel(parcel); 124 assertThat(unparceledNode.getActionList(), emptyCollectionOf(AccessibilityAction.class)); 125 assertThat(unparceledNode.getText(), equalTo(text)); 126 } 127 128 @Test 129 public void dontForgetToUpdateCtsParcelingTestWhenYouAddNewFields() { 130 AccessibilityEventTest.assertNoNewNonStaticFieldsAdded(AccessibilityNodeInfo.class, 131 NUM_MARSHALLED_PROPERTIES + NUM_NONMARSHALLED_PROPERTIES); 132 } 133} 134