1 /* 2 * Copyright (C) 2019 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 com.android.settings.accessibility; 18 19 import static com.google.common.truth.Truth.assertThat; 20 21 import android.accessibilityservice.AccessibilityServiceInfo; 22 import android.content.ComponentName; 23 import android.content.Context; 24 import android.content.pm.ApplicationInfo; 25 import android.content.pm.ResolveInfo; 26 import android.content.pm.ServiceInfo; 27 import android.os.Build; 28 import android.provider.Settings; 29 30 import com.android.settings.R; 31 import com.android.settings.accessibility.AccessibilityUtil.UserShortcutType; 32 33 import org.junit.Before; 34 import org.junit.Test; 35 import org.junit.runner.RunWith; 36 import org.robolectric.RobolectricTestRunner; 37 import org.robolectric.RuntimeEnvironment; 38 import org.xmlpull.v1.XmlPullParserException; 39 40 import java.io.IOException; 41 42 @RunWith(RobolectricTestRunner.class) 43 public final class AccessibilityUtilTest { 44 private static final int ON = 1; 45 private static final int OFF = 0; 46 private static final String SECURE_TEST_KEY = "secure_test_key"; 47 private static final String DUMMY_PACKAGE_NAME = "com.mock.example"; 48 private static final String DUMMY_CLASS_NAME = DUMMY_PACKAGE_NAME + ".mock_a11y_service"; 49 private static final String DUMMY_CLASS_NAME2 = DUMMY_PACKAGE_NAME + ".mock_a11y_service2"; 50 private static final ComponentName DUMMY_COMPONENT_NAME = new ComponentName(DUMMY_PACKAGE_NAME, 51 DUMMY_CLASS_NAME); 52 private static final ComponentName DUMMY_COMPONENT_NAME2 = new ComponentName(DUMMY_PACKAGE_NAME, 53 DUMMY_CLASS_NAME2); 54 private static final String SOFTWARE_SHORTCUT_KEY = 55 Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS; 56 private static final String HARDWARE_SHORTCUT_KEY = 57 Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE; 58 59 private Context mContext; 60 61 @Before setUp()62 public void setUp() { 63 mContext = RuntimeEnvironment.application; 64 } 65 66 @Test capitalize_shouldReturnCapitalizedString()67 public void capitalize_shouldReturnCapitalizedString() { 68 assertThat(AccessibilityUtil.capitalize(null)).isNull(); 69 assertThat(AccessibilityUtil.capitalize("")).isEmpty(); 70 assertThat(AccessibilityUtil.capitalize("Hans")).isEqualTo("Hans"); 71 assertThat(AccessibilityUtil.capitalize("hans")).isEqualTo("Hans"); 72 assertThat(AccessibilityUtil.capitalize(",hans")).isEqualTo(",hans"); 73 assertThat(AccessibilityUtil.capitalize("Hans, Hans")).isEqualTo("Hans, hans"); 74 } 75 76 @Test getSummary_hasValueAndEqualsToOne_shouldReturnOnString()77 public void getSummary_hasValueAndEqualsToOne_shouldReturnOnString() { 78 Settings.Secure.putInt(mContext.getContentResolver(), SECURE_TEST_KEY, ON); 79 80 final CharSequence result = AccessibilityUtil.getSummary(mContext, SECURE_TEST_KEY); 81 82 assertThat(result) 83 .isEqualTo(mContext.getText(R.string.accessibility_feature_state_on)); 84 } 85 86 @Test getSummary_hasValueAndEqualsToZero_shouldReturnOffString()87 public void getSummary_hasValueAndEqualsToZero_shouldReturnOffString() { 88 Settings.Secure.putInt(mContext.getContentResolver(), SECURE_TEST_KEY, OFF); 89 90 final CharSequence result = AccessibilityUtil.getSummary(mContext, SECURE_TEST_KEY); 91 92 assertThat(result) 93 .isEqualTo(mContext.getText(R.string.accessibility_feature_state_off)); 94 } 95 96 @Test getSummary_noValue_shouldReturnOffString()97 public void getSummary_noValue_shouldReturnOffString() { 98 final CharSequence result = AccessibilityUtil.getSummary(mContext, SECURE_TEST_KEY); 99 100 assertThat(result) 101 .isEqualTo(mContext.getText(R.string.accessibility_feature_state_off)); 102 } 103 104 @Test getAccessibilityServiceFragmentType_targetSdkQ_volumeShortcutType()105 public void getAccessibilityServiceFragmentType_targetSdkQ_volumeShortcutType() { 106 final AccessibilityServiceInfo info = getMockAccessibilityServiceInfo(); 107 108 info.getResolveInfo().serviceInfo.applicationInfo.targetSdkVersion = Build.VERSION_CODES.Q; 109 info.flags |= AccessibilityServiceInfo.FLAG_REQUEST_ACCESSIBILITY_BUTTON; 110 111 assertThat(AccessibilityUtil.getAccessibilityServiceFragmentType(info)).isEqualTo( 112 AccessibilityUtil.AccessibilityServiceFragmentType.VOLUME_SHORTCUT_TOGGLE); 113 } 114 115 @Test getAccessibilityServiceFragmentType_targetSdkR_HaveA11yButton_invisibleType()116 public void getAccessibilityServiceFragmentType_targetSdkR_HaveA11yButton_invisibleType() { 117 final AccessibilityServiceInfo info = getMockAccessibilityServiceInfo(); 118 119 info.getResolveInfo().serviceInfo.applicationInfo.targetSdkVersion = Build.VERSION_CODES.R; 120 info.flags |= AccessibilityServiceInfo.FLAG_REQUEST_ACCESSIBILITY_BUTTON; 121 122 assertThat(AccessibilityUtil.getAccessibilityServiceFragmentType(info)).isEqualTo( 123 AccessibilityUtil.AccessibilityServiceFragmentType.INVISIBLE_TOGGLE); 124 } 125 126 @Test getAccessibilityServiceFragmentType_targetSdkR_NoA11yButton_toggleType()127 public void getAccessibilityServiceFragmentType_targetSdkR_NoA11yButton_toggleType() { 128 final AccessibilityServiceInfo info = getMockAccessibilityServiceInfo(); 129 130 info.getResolveInfo().serviceInfo.applicationInfo.targetSdkVersion = Build.VERSION_CODES.R; 131 info.flags |= ~AccessibilityServiceInfo.FLAG_REQUEST_ACCESSIBILITY_BUTTON; 132 133 assertThat(AccessibilityUtil.getAccessibilityServiceFragmentType(info)).isEqualTo( 134 AccessibilityUtil.AccessibilityServiceFragmentType.TOGGLE); 135 } 136 137 @Test hasValueInSettings_putValue_hasValue()138 public void hasValueInSettings_putValue_hasValue() { 139 putStringIntoSettings(SOFTWARE_SHORTCUT_KEY, DUMMY_COMPONENT_NAME.flattenToString()); 140 141 assertThat(AccessibilityUtil.hasValueInSettings(mContext, UserShortcutType.SOFTWARE, 142 DUMMY_COMPONENT_NAME)).isTrue(); 143 } 144 145 @Test getUserShortcutTypeFromSettings_putOneValue_hasValue()146 public void getUserShortcutTypeFromSettings_putOneValue_hasValue() { 147 putStringIntoSettings(SOFTWARE_SHORTCUT_KEY, DUMMY_COMPONENT_NAME.flattenToString()); 148 149 final int shortcutType = AccessibilityUtil.getUserShortcutTypesFromSettings(mContext, 150 DUMMY_COMPONENT_NAME); 151 assertThat( 152 (shortcutType & UserShortcutType.SOFTWARE) == UserShortcutType.SOFTWARE).isTrue(); 153 } 154 155 @Test getUserShortcutTypeFromSettings_putTwoValues_hasValue()156 public void getUserShortcutTypeFromSettings_putTwoValues_hasValue() { 157 putStringIntoSettings(SOFTWARE_SHORTCUT_KEY, DUMMY_COMPONENT_NAME.flattenToString()); 158 putStringIntoSettings(HARDWARE_SHORTCUT_KEY, DUMMY_COMPONENT_NAME.flattenToString()); 159 160 final int shortcutType = AccessibilityUtil.getUserShortcutTypesFromSettings(mContext, 161 DUMMY_COMPONENT_NAME); 162 assertThat( 163 (shortcutType & UserShortcutType.SOFTWARE) == UserShortcutType.SOFTWARE).isTrue(); 164 assertThat( 165 (shortcutType & UserShortcutType.HARDWARE) == UserShortcutType.HARDWARE).isTrue(); 166 } 167 168 @Test optInAllValuesToSettings_optInValue_haveMatchString()169 public void optInAllValuesToSettings_optInValue_haveMatchString() { 170 int shortcutTypes = UserShortcutType.SOFTWARE | UserShortcutType.HARDWARE; 171 172 AccessibilityUtil.optInAllValuesToSettings(mContext, shortcutTypes, DUMMY_COMPONENT_NAME); 173 174 assertThat(getStringFromSettings(SOFTWARE_SHORTCUT_KEY)).isEqualTo( 175 DUMMY_COMPONENT_NAME.flattenToString()); 176 assertThat(getStringFromSettings(HARDWARE_SHORTCUT_KEY)).isEqualTo( 177 DUMMY_COMPONENT_NAME.flattenToString()); 178 179 } 180 181 @Test optInValueToSettings_optInValue_haveMatchString()182 public void optInValueToSettings_optInValue_haveMatchString() { 183 putStringIntoSettings(SOFTWARE_SHORTCUT_KEY, DUMMY_COMPONENT_NAME.flattenToString()); 184 AccessibilityUtil.optInValueToSettings(mContext, UserShortcutType.SOFTWARE, 185 DUMMY_COMPONENT_NAME2); 186 187 assertThat(getStringFromSettings(SOFTWARE_SHORTCUT_KEY)).isEqualTo( 188 DUMMY_COMPONENT_NAME.flattenToString() + ":" 189 + DUMMY_COMPONENT_NAME2.flattenToString()); 190 } 191 192 @Test optInValueToSettings_optInTwoValues_haveMatchString()193 public void optInValueToSettings_optInTwoValues_haveMatchString() { 194 putStringIntoSettings(SOFTWARE_SHORTCUT_KEY, DUMMY_COMPONENT_NAME.flattenToString()); 195 AccessibilityUtil.optInValueToSettings(mContext, UserShortcutType.SOFTWARE, 196 DUMMY_COMPONENT_NAME2); 197 AccessibilityUtil.optInValueToSettings(mContext, UserShortcutType.SOFTWARE, 198 DUMMY_COMPONENT_NAME2); 199 200 assertThat(getStringFromSettings(SOFTWARE_SHORTCUT_KEY)).isEqualTo( 201 DUMMY_COMPONENT_NAME.flattenToString() + ":" 202 + DUMMY_COMPONENT_NAME2.flattenToString()); 203 } 204 205 @Test optOutAllValuesToSettings_optOutValue_emptyString()206 public void optOutAllValuesToSettings_optOutValue_emptyString() { 207 putStringIntoSettings(SOFTWARE_SHORTCUT_KEY, DUMMY_COMPONENT_NAME.flattenToString()); 208 putStringIntoSettings(HARDWARE_SHORTCUT_KEY, DUMMY_COMPONENT_NAME.flattenToString()); 209 int shortcutTypes = 210 UserShortcutType.SOFTWARE | UserShortcutType.HARDWARE | UserShortcutType.TRIPLETAP; 211 212 AccessibilityUtil.optOutAllValuesFromSettings(mContext, shortcutTypes, 213 DUMMY_COMPONENT_NAME); 214 215 assertThat(getStringFromSettings(SOFTWARE_SHORTCUT_KEY)).isEmpty(); 216 assertThat(getStringFromSettings(HARDWARE_SHORTCUT_KEY)).isEmpty(); 217 } 218 219 @Test optOutValueFromSettings_optOutValue_emptyString()220 public void optOutValueFromSettings_optOutValue_emptyString() { 221 putStringIntoSettings(SOFTWARE_SHORTCUT_KEY, DUMMY_COMPONENT_NAME.flattenToString()); 222 AccessibilityUtil.optOutValueFromSettings(mContext, UserShortcutType.SOFTWARE, 223 DUMMY_COMPONENT_NAME); 224 225 assertThat(getStringFromSettings(SOFTWARE_SHORTCUT_KEY)).isEmpty(); 226 } 227 228 @Test optOutValueFromSettings_optOutValue_haveMatchString()229 public void optOutValueFromSettings_optOutValue_haveMatchString() { 230 putStringIntoSettings(SOFTWARE_SHORTCUT_KEY, DUMMY_COMPONENT_NAME.flattenToString() + ":" 231 + DUMMY_COMPONENT_NAME2.flattenToString()); 232 AccessibilityUtil.optOutValueFromSettings(mContext, UserShortcutType.SOFTWARE, 233 DUMMY_COMPONENT_NAME2); 234 235 assertThat(getStringFromSettings(SOFTWARE_SHORTCUT_KEY)).isEqualTo( 236 DUMMY_COMPONENT_NAME.flattenToString()); 237 } 238 getMockAccessibilityServiceInfo()239 private AccessibilityServiceInfo getMockAccessibilityServiceInfo() { 240 final ApplicationInfo applicationInfo = new ApplicationInfo(); 241 final ServiceInfo serviceInfo = new ServiceInfo(); 242 applicationInfo.packageName = DUMMY_PACKAGE_NAME; 243 serviceInfo.packageName = DUMMY_PACKAGE_NAME; 244 serviceInfo.name = DUMMY_CLASS_NAME; 245 serviceInfo.applicationInfo = applicationInfo; 246 247 final ResolveInfo resolveInfo = new ResolveInfo(); 248 resolveInfo.serviceInfo = serviceInfo; 249 250 try { 251 final AccessibilityServiceInfo info = new AccessibilityServiceInfo(resolveInfo, 252 mContext); 253 info.setComponentName(DUMMY_COMPONENT_NAME); 254 return info; 255 } catch (XmlPullParserException | IOException e) { 256 // Do nothing 257 } 258 259 return null; 260 } 261 putStringIntoSettings(String key, String componentName)262 private void putStringIntoSettings(String key, String componentName) { 263 Settings.Secure.putString(mContext.getContentResolver(), key, componentName); 264 } 265 getStringFromSettings(String key)266 private String getStringFromSettings(String key) { 267 return Settings.Secure.getString(mContext.getContentResolver(), key); 268 } 269 } 270