1 /* 2 * Copyright (C) 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 17 package com.android.settings.accessibility; 18 19 import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType.SOFTWARE; 20 21 import static com.google.common.truth.Truth.assertThat; 22 23 import static org.mockito.ArgumentMatchers.any; 24 import static org.mockito.Mockito.doReturn; 25 import static org.mockito.Mockito.when; 26 import static org.robolectric.Shadows.shadowOf; 27 28 import static java.util.Collections.singletonList; 29 30 import android.accessibilityservice.AccessibilityServiceInfo; 31 import android.accessibilityservice.AccessibilityShortcutInfo; 32 import android.content.ComponentName; 33 import android.content.Context; 34 import android.content.Intent; 35 import android.content.pm.ActivityInfo; 36 import android.content.pm.ApplicationInfo; 37 import android.content.pm.PackageManager; 38 import android.content.pm.ResolveInfo; 39 import android.content.pm.ServiceInfo; 40 import android.database.ContentObserver; 41 import android.os.Build; 42 import android.platform.test.annotations.DisableFlags; 43 import android.platform.test.annotations.EnableFlags; 44 import android.platform.test.flag.junit.SetFlagsRule; 45 import android.provider.Settings; 46 import android.view.accessibility.AccessibilityManager; 47 48 import androidx.fragment.app.Fragment; 49 import androidx.test.core.app.ApplicationProvider; 50 51 import com.android.internal.accessibility.util.AccessibilityUtils; 52 import com.android.settings.R; 53 import com.android.settings.SettingsActivity; 54 import com.android.settings.testutils.FakeFeatureFactory; 55 import com.android.settings.testutils.XmlTestUtils; 56 import com.android.settings.testutils.shadow.ShadowAccessibilityManager; 57 import com.android.settings.testutils.shadow.ShadowApplicationPackageManager; 58 import com.android.settings.testutils.shadow.ShadowBluetoothAdapter; 59 import com.android.settings.testutils.shadow.ShadowBluetoothUtils; 60 import com.android.settings.testutils.shadow.ShadowRestrictedLockUtilsInternal; 61 import com.android.settings.testutils.shadow.ShadowUserManager; 62 import com.android.settingslib.RestrictedPreference; 63 import com.android.settingslib.bluetooth.LocalBluetoothManager; 64 import com.android.settingslib.search.SearchIndexableRaw; 65 import com.android.settingslib.testutils.shadow.ShadowColorDisplayManager; 66 67 import com.google.common.truth.BooleanSubject; 68 69 import org.junit.Before; 70 import org.junit.Rule; 71 import org.junit.Test; 72 import org.junit.runner.RunWith; 73 import org.mockito.Mock; 74 import org.mockito.Mockito; 75 import org.mockito.Spy; 76 import org.mockito.junit.MockitoJUnit; 77 import org.mockito.junit.MockitoRule; 78 import org.robolectric.RobolectricTestRunner; 79 import org.robolectric.android.controller.ActivityController; 80 import org.robolectric.annotation.Config; 81 import org.robolectric.shadow.api.Shadow; 82 import org.robolectric.shadows.ShadowContentResolver; 83 import org.robolectric.shadows.ShadowLooper; 84 import org.xmlpull.v1.XmlPullParserException; 85 86 import java.io.IOException; 87 import java.util.ArrayList; 88 import java.util.Collection; 89 import java.util.List; 90 91 /** Test for {@link AccessibilitySettings}. */ 92 @RunWith(RobolectricTestRunner.class) 93 @Config(shadows = { 94 ShadowAccessibilityManager.class, 95 ShadowBluetoothAdapter.class, 96 ShadowUserManager.class, 97 ShadowColorDisplayManager.class, 98 ShadowApplicationPackageManager.class, 99 ShadowRestrictedLockUtilsInternal.class, 100 }) 101 public class AccessibilitySettingsTest { 102 private static final String PACKAGE_NAME = "com.android.test"; 103 private static final ComponentName SERVICE_COMPONENT_NAME = 104 new ComponentName(PACKAGE_NAME, PACKAGE_NAME + ".test_a11y_service"); 105 private static final ComponentName ACTIVITY_COMPONENT_NAME = 106 new ComponentName(PACKAGE_NAME, PACKAGE_NAME + ".test_a11y_activity"); 107 private static final String EMPTY_STRING = ""; 108 private static final String DEFAULT_SUMMARY = "default summary"; 109 private static final String DEFAULT_DESCRIPTION = "default description"; 110 private static final String DEFAULT_LABEL = "default label"; 111 private static final Boolean SERVICE_ENABLED = true; 112 private static final Boolean SERVICE_DISABLED = false; 113 114 @Rule 115 public final MockitoRule mocks = MockitoJUnit.rule(); 116 @Rule 117 public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); 118 private final Context mContext = ApplicationProvider.getApplicationContext(); 119 @Spy 120 private final AccessibilityServiceInfo mServiceInfo = getMockAccessibilityServiceInfo( 121 SERVICE_COMPONENT_NAME); 122 private ShadowAccessibilityManager mShadowAccessibilityManager; 123 @Mock 124 private LocalBluetoothManager mLocalBluetoothManager; 125 126 private ActivityController<SettingsActivity> mActivityController; 127 128 private AccessibilitySettings mFragment; 129 130 @Before setup()131 public void setup() { 132 mShadowAccessibilityManager = Shadow.extract( 133 mContext.getSystemService(AccessibilityManager.class)); 134 mShadowAccessibilityManager.setInstalledAccessibilityServiceList(new ArrayList<>()); 135 mContext.setTheme(androidx.appcompat.R.style.Theme_AppCompat); 136 ShadowBluetoothUtils.sLocalBluetoothManager = mLocalBluetoothManager; 137 138 Intent intent = new Intent(); 139 intent.putExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT, 140 AccessibilitySettings.class.getName()); 141 142 mActivityController = ActivityController.of(new SettingsActivity(), intent); 143 } 144 145 @Test getNonIndexableKeys_existInXmlLayout()146 public void getNonIndexableKeys_existInXmlLayout() { 147 final List<String> niks = AccessibilitySettings.SEARCH_INDEX_DATA_PROVIDER 148 .getNonIndexableKeys(mContext); 149 final List<String> keys = 150 XmlTestUtils.getKeysFromPreferenceXml(mContext, R.xml.accessibility_settings); 151 152 assertThat(keys).containsAtLeastElementsIn(niks); 153 } 154 155 @Test getRawDataToIndex_isNull()156 public void getRawDataToIndex_isNull() { 157 final List<SearchIndexableRaw> indexableRawList = 158 AccessibilitySettings.SEARCH_INDEX_DATA_PROVIDER 159 .getRawDataToIndex(mContext, true); 160 161 assertThat(indexableRawList).isNull(); 162 } 163 164 @DisableFlags(Flags.FLAG_FIX_A11Y_SETTINGS_SEARCH) 165 @Test getDynamicRawDataToIndex_hasInstalledA11yFeatures_flagOff_returnEmpty()166 public void getDynamicRawDataToIndex_hasInstalledA11yFeatures_flagOff_returnEmpty() { 167 mShadowAccessibilityManager.setInstalledAccessibilityServiceList( 168 List.of(mServiceInfo)); 169 mShadowAccessibilityManager.setInstalledAccessibilityShortcutListAsUser( 170 List.of(getMockAccessibilityShortcutInfo())); 171 172 assertThat(AccessibilitySettings.SEARCH_INDEX_DATA_PROVIDER.getDynamicRawDataToIndex( 173 mContext, /* enabled= */ true)) 174 .isEmpty(); 175 } 176 177 @EnableFlags(Flags.FLAG_FIX_A11Y_SETTINGS_SEARCH) 178 @Test getDynamicRawDataToIndex_hasInstalledA11yFeatures_flagOn_returnRawDataForInstalledA11yFeatures()179 public void getDynamicRawDataToIndex_hasInstalledA11yFeatures_flagOn_returnRawDataForInstalledA11yFeatures() { 180 mShadowAccessibilityManager.setInstalledAccessibilityServiceList( 181 List.of(mServiceInfo)); 182 mShadowAccessibilityManager.setInstalledAccessibilityShortcutListAsUser( 183 List.of(getMockAccessibilityShortcutInfo())); 184 final AccessibilitySearchFeatureProvider featureProvider = 185 FakeFeatureFactory.setupForTest().getAccessibilitySearchFeatureProvider(); 186 final String synonyms = "fake keyword1, fake keyword2"; 187 when(featureProvider.getSynonymsForComponent(mContext, ACTIVITY_COMPONENT_NAME)) 188 .thenReturn(""); 189 when(featureProvider.getSynonymsForComponent(mContext, SERVICE_COMPONENT_NAME)) 190 .thenReturn(synonyms); 191 192 final List<SearchIndexableRaw> indexableRawDataList = 193 AccessibilitySettings.SEARCH_INDEX_DATA_PROVIDER.getDynamicRawDataToIndex( 194 mContext, /* enabled= */ true); 195 ShadowLooper.runUiThreadTasksIncludingDelayedTasks(); 196 197 assertThat(indexableRawDataList).hasSize(2); 198 SearchIndexableRaw a11yActivityIndexableData = indexableRawDataList.get(0); 199 assertThat(a11yActivityIndexableData.key).isEqualTo( 200 ACTIVITY_COMPONENT_NAME.flattenToString()); 201 assertThat(a11yActivityIndexableData.title).isEqualTo(DEFAULT_LABEL); 202 assertThat(a11yActivityIndexableData.keywords).isEmpty(); 203 204 SearchIndexableRaw a11yServiceIndexableData = indexableRawDataList.get(1); 205 assertThat(a11yServiceIndexableData.key).isEqualTo( 206 SERVICE_COMPONENT_NAME.flattenToString()); 207 assertThat(a11yServiceIndexableData.title).isEqualTo(DEFAULT_LABEL); 208 assertThat(a11yServiceIndexableData.keywords).isEqualTo(synonyms); 209 } 210 211 @Test getServiceSummary_serviceCrash_showsStopped()212 public void getServiceSummary_serviceCrash_showsStopped() { 213 mServiceInfo.crashed = true; 214 215 final CharSequence summary = AccessibilitySettings.getServiceSummary(mContext, 216 mServiceInfo, SERVICE_ENABLED); 217 218 assertThat(summary).isEqualTo( 219 mContext.getString(R.string.accessibility_summary_state_stopped)); 220 } 221 222 @Test getServiceSummary_invisibleToggle_shortcutEnabled_showsOnSummary()223 public void getServiceSummary_invisibleToggle_shortcutEnabled_showsOnSummary() { 224 setInvisibleToggleFragmentType(mServiceInfo); 225 doReturn(DEFAULT_SUMMARY).when(mServiceInfo).loadSummary(any()); 226 setShortcutEnabled(mServiceInfo.getComponentName(), true); 227 228 final CharSequence summary = AccessibilitySettings.getServiceSummary(mContext, 229 mServiceInfo, SERVICE_ENABLED); 230 231 assertThat(summary).isEqualTo( 232 mContext.getString( 233 com.android.settingslib.R.string.preference_summary_default_combination, 234 mContext.getString(R.string.accessibility_summary_shortcut_enabled), 235 DEFAULT_SUMMARY)); 236 } 237 238 @Test getServiceSummary_invisibleToggle_shortcutDisabled_showsOffSummary()239 public void getServiceSummary_invisibleToggle_shortcutDisabled_showsOffSummary() { 240 setInvisibleToggleFragmentType(mServiceInfo); 241 setShortcutEnabled(mServiceInfo.getComponentName(), false); 242 doReturn(DEFAULT_SUMMARY).when(mServiceInfo).loadSummary(any()); 243 244 final CharSequence summary = AccessibilitySettings.getServiceSummary(mContext, 245 mServiceInfo, SERVICE_ENABLED); 246 247 assertThat(summary).isEqualTo( 248 mContext.getString( 249 com.android.settingslib.R.string.preference_summary_default_combination, 250 mContext.getString(R.string.generic_accessibility_feature_shortcut_off), 251 DEFAULT_SUMMARY)); 252 } 253 254 @Test getServiceSummary_enableServiceShortcutOn_showsServiceEnabledShortcutOn()255 public void getServiceSummary_enableServiceShortcutOn_showsServiceEnabledShortcutOn() { 256 doReturn(EMPTY_STRING).when(mServiceInfo).loadSummary(any()); 257 setShortcutEnabled(mServiceInfo.getComponentName(), true); 258 259 String summary = AccessibilitySettings.getServiceSummary(mContext, 260 mServiceInfo, SERVICE_ENABLED).toString(); 261 262 assertThat(summary).isEqualTo( 263 mContext.getString(R.string.generic_accessibility_service_on)); 264 } 265 266 @Test getServiceSummary_enableServiceShortcutOff_showsServiceEnabledShortcutOff()267 public void getServiceSummary_enableServiceShortcutOff_showsServiceEnabledShortcutOff() { 268 doReturn(EMPTY_STRING).when(mServiceInfo).loadSummary(any()); 269 setShortcutEnabled(mServiceInfo.getComponentName(), false); 270 271 String summary = AccessibilitySettings.getServiceSummary( 272 mContext, mServiceInfo, SERVICE_ENABLED).toString(); 273 274 assertThat(summary).isEqualTo( 275 mContext.getString(R.string.generic_accessibility_service_on)); 276 } 277 278 @Test getServiceSummary_disableServiceShortcutOff_showsDisabledShortcutOff()279 public void getServiceSummary_disableServiceShortcutOff_showsDisabledShortcutOff() { 280 doReturn(EMPTY_STRING).when(mServiceInfo).loadSummary(any()); 281 setShortcutEnabled(mServiceInfo.getComponentName(), false); 282 283 String summary = AccessibilitySettings.getServiceSummary(mContext, 284 mServiceInfo, SERVICE_DISABLED).toString(); 285 286 assertThat(summary).isEqualTo( 287 mContext.getString(R.string.generic_accessibility_service_off)); 288 } 289 290 @Test getServiceSummary_disableServiceShortcutOn_showsDisabledShortcutOn()291 public void getServiceSummary_disableServiceShortcutOn_showsDisabledShortcutOn() { 292 doReturn(EMPTY_STRING).when(mServiceInfo).loadSummary(any()); 293 setShortcutEnabled(mServiceInfo.getComponentName(), true); 294 295 String summary = AccessibilitySettings.getServiceSummary(mContext, 296 mServiceInfo, SERVICE_DISABLED).toString(); 297 298 assertThat(summary).isEqualTo( 299 mContext.getString(R.string.generic_accessibility_service_off)); 300 } 301 302 @Test getServiceSummary_enableServiceShortcutOffAndHasSummary_showsEnabledSummary()303 public void getServiceSummary_enableServiceShortcutOffAndHasSummary_showsEnabledSummary() { 304 setShortcutEnabled(mServiceInfo.getComponentName(), false); 305 doReturn(DEFAULT_SUMMARY).when(mServiceInfo).loadSummary(any()); 306 307 String summary = AccessibilitySettings.getServiceSummary(mContext, 308 mServiceInfo, SERVICE_ENABLED).toString(); 309 310 assertThat(summary).isEqualTo( 311 mContext.getString( 312 com.android.settingslib.R.string.preference_summary_default_combination, 313 mContext.getString(R.string.generic_accessibility_service_on), 314 DEFAULT_SUMMARY)); 315 } 316 317 @Test getServiceSummary_enableServiceShortcutOnAndHasSummary_showsEnabledSummary()318 public void getServiceSummary_enableServiceShortcutOnAndHasSummary_showsEnabledSummary() { 319 doReturn(DEFAULT_SUMMARY).when(mServiceInfo).loadSummary(any()); 320 setShortcutEnabled(mServiceInfo.getComponentName(), true); 321 322 String summary = AccessibilitySettings.getServiceSummary(mContext, 323 mServiceInfo, SERVICE_ENABLED).toString(); 324 325 assertThat(summary).isEqualTo( 326 mContext.getString( 327 com.android.settingslib.R.string.preference_summary_default_combination, 328 mContext.getString(R.string.generic_accessibility_service_on), 329 DEFAULT_SUMMARY)); 330 } 331 332 @Test getServiceSummary_disableServiceShortcutOnAndHasSummary_showsDisabledSummary()333 public void getServiceSummary_disableServiceShortcutOnAndHasSummary_showsDisabledSummary() { 334 doReturn(DEFAULT_SUMMARY).when(mServiceInfo).loadSummary(any()); 335 setShortcutEnabled(mServiceInfo.getComponentName(), true); 336 337 String summary = AccessibilitySettings.getServiceSummary(mContext, 338 mServiceInfo, SERVICE_DISABLED).toString(); 339 340 assertThat(summary).isEqualTo( 341 mContext.getString( 342 com.android.settingslib.R.string.preference_summary_default_combination, 343 mContext.getString(R.string.generic_accessibility_service_off), 344 DEFAULT_SUMMARY)); 345 } 346 347 @Test getServiceSummary_disableServiceShortcutOffAndHasSummary_showsDisabledSummary()348 public void getServiceSummary_disableServiceShortcutOffAndHasSummary_showsDisabledSummary() { 349 setShortcutEnabled(mServiceInfo.getComponentName(), false); 350 doReturn(DEFAULT_SUMMARY).when(mServiceInfo).loadSummary(any()); 351 352 String summary = AccessibilitySettings.getServiceSummary(mContext, 353 mServiceInfo, SERVICE_DISABLED).toString(); 354 355 assertThat(summary).isEqualTo( 356 mContext.getString( 357 com.android.settingslib.R.string.preference_summary_default_combination, 358 mContext.getString(R.string.generic_accessibility_service_off), 359 DEFAULT_SUMMARY)); 360 } 361 362 @Test getServiceDescription_serviceCrash_showsStopped()363 public void getServiceDescription_serviceCrash_showsStopped() { 364 mServiceInfo.crashed = true; 365 366 String description = AccessibilitySettings.getServiceDescription(mContext, 367 mServiceInfo, SERVICE_ENABLED).toString(); 368 369 assertThat(description).isEqualTo( 370 mContext.getString(R.string.accessibility_description_state_stopped)); 371 } 372 373 @Test getServiceDescription_haveDescription_showsDescription()374 public void getServiceDescription_haveDescription_showsDescription() { 375 doReturn(DEFAULT_DESCRIPTION).when(mServiceInfo).loadDescription(any()); 376 377 String description = AccessibilitySettings.getServiceDescription(mContext, 378 mServiceInfo, SERVICE_ENABLED).toString(); 379 380 assertThat(description).isEqualTo(DEFAULT_DESCRIPTION); 381 } 382 383 @Test onCreate_haveRegisterToSpecificUrisAndActions()384 public void onCreate_haveRegisterToSpecificUrisAndActions() { 385 setupFragment(); 386 387 assertUriObserversContainsClazz(Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS, 388 AccessibilitySettingsContentObserver.class).isTrue(); 389 assertUriObserversContainsClazz(Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE, 390 AccessibilitySettingsContentObserver.class).isTrue(); 391 assertUriObserversContainsClazz(Settings.Secure.ACCESSIBILITY_QS_TARGETS, 392 AccessibilitySettingsContentObserver.class).isTrue(); 393 } 394 395 @Test onDestroy_unregisterObserverAndReceiver()396 public void onDestroy_unregisterObserverAndReceiver() { 397 setupFragment(); 398 399 mActivityController.pause().stop().destroy(); 400 401 assertUriObserversContainsClazz(Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS, 402 AccessibilitySettingsContentObserver.class).isFalse(); 403 assertUriObserversContainsClazz(Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE, 404 AccessibilitySettingsContentObserver.class).isFalse(); 405 assertUriObserversContainsClazz(Settings.Secure.ACCESSIBILITY_QS_TARGETS, 406 AccessibilitySettingsContentObserver.class).isFalse(); 407 } 408 409 @Test onContentChanged_updatePreferenceInForeground_preferenceUpdated()410 public void onContentChanged_updatePreferenceInForeground_preferenceUpdated() { 411 setupFragment(); 412 mShadowAccessibilityManager.setInstalledAccessibilityServiceList( 413 singletonList(mServiceInfo)); 414 415 mFragment.onContentChanged(); 416 417 RestrictedPreference preference = mFragment.getPreferenceScreen().findPreference( 418 SERVICE_COMPONENT_NAME.flattenToString()); 419 420 assertThat(preference).isNotNull(); 421 422 } 423 424 @Test onContentChanged_updatePreferenceInBackground_preferenceUpdated()425 public void onContentChanged_updatePreferenceInBackground_preferenceUpdated() { 426 setupFragment(); 427 mFragment.onPause(); 428 mFragment.onStop(); 429 430 mShadowAccessibilityManager.setInstalledAccessibilityServiceList( 431 singletonList(mServiceInfo)); 432 433 mFragment.onContentChanged(); 434 mFragment.onStart(); 435 mFragment.onResume(); 436 437 RestrictedPreference preference = mFragment.getPreferenceScreen().findPreference( 438 SERVICE_COMPONENT_NAME.flattenToString()); 439 440 assertThat(preference).isNotNull(); 441 442 } 443 444 @Test testAccessibilityMenuInSystem_IncludedInInteractionControl()445 public void testAccessibilityMenuInSystem_IncludedInInteractionControl() { 446 mShadowAccessibilityManager.setInstalledAccessibilityServiceList( 447 List.of(getMockAccessibilityServiceInfo( 448 AccessibilityUtils.ACCESSIBILITY_MENU_IN_SYSTEM, 449 /*isSystemApp=*/true))); 450 setupFragment(); 451 452 assertThat(getPreferenceCategory(AccessibilityUtils.ACCESSIBILITY_MENU_IN_SYSTEM)) 453 .isEqualTo(AccessibilitySettings.CATEGORY_INTERACTION_CONTROL); 454 } 455 456 @Test testNonPreinstalledApp_IncludedInDownloadedCategory()457 public void testNonPreinstalledApp_IncludedInDownloadedCategory() { 458 mShadowAccessibilityManager.setInstalledAccessibilityServiceList( 459 List.of(getMockAccessibilityServiceInfo( 460 AccessibilityUtils.ACCESSIBILITY_MENU_IN_SYSTEM, 461 /*isSystemApp=*/false))); 462 setupFragment(); 463 464 assertThat(getPreferenceCategory(AccessibilityUtils.ACCESSIBILITY_MENU_IN_SYSTEM)) 465 .isEqualTo(AccessibilitySettings.CATEGORY_DOWNLOADED_SERVICES); 466 } 467 468 @Test testAccessibilityMenuInSystem_NoPrefWhenNotInstalled()469 public void testAccessibilityMenuInSystem_NoPrefWhenNotInstalled() { 470 mShadowAccessibilityManager.setInstalledAccessibilityServiceList(List.of()); 471 setupFragment(); 472 473 final RestrictedPreference pref = mFragment.getPreferenceScreen().findPreference( 474 AccessibilityUtils.ACCESSIBILITY_MENU_IN_SYSTEM.flattenToString()); 475 assertThat(pref).isNull(); 476 } 477 478 @Test testSameNamedServiceAndActivity_bothPreferencesExist()479 public void testSameNamedServiceAndActivity_bothPreferencesExist() { 480 final PackageManager pm = mContext.getPackageManager(); 481 AccessibilityServiceInfo a11yServiceInfo = mServiceInfo; 482 AccessibilityShortcutInfo a11yShortcutInfo = getMockAccessibilityShortcutInfo(); 483 // Ensure the test service and activity have the same package name and label. 484 // Before this change, any service and activity with the same package name and 485 // label would cause the service to be hidden. 486 assertThat(a11yServiceInfo.getComponentName()) 487 .isNotEqualTo(a11yShortcutInfo.getComponentName()); 488 assertThat(a11yServiceInfo.getComponentName().getPackageName()) 489 .isEqualTo(a11yShortcutInfo.getComponentName().getPackageName()); 490 assertThat(a11yServiceInfo.getResolveInfo().serviceInfo.loadLabel(pm)) 491 .isEqualTo(a11yShortcutInfo.getActivityInfo().loadLabel(pm)); 492 // Prepare A11yManager with the test service and activity. 493 mShadowAccessibilityManager.setInstalledAccessibilityServiceList( 494 List.of(mServiceInfo)); 495 mShadowAccessibilityManager.setInstalledAccessibilityShortcutListAsUser( 496 List.of(getMockAccessibilityShortcutInfo())); 497 setupFragment(); 498 499 // Both service and activity preferences should exist on the page. 500 RestrictedPreference servicePref = mFragment.getPreferenceScreen().findPreference( 501 a11yServiceInfo.getComponentName().flattenToString()); 502 RestrictedPreference activityPref = mFragment.getPreferenceScreen().findPreference( 503 a11yShortcutInfo.getComponentName().flattenToString()); 504 assertThat(servicePref).isNotNull(); 505 assertThat(activityPref).isNotNull(); 506 } 507 getPreferenceCategory(ComponentName componentName)508 private String getPreferenceCategory(ComponentName componentName) { 509 return mFragment.getPreferenceScreen().findPreference( 510 componentName.flattenToString()).getParent().getKey(); 511 } 512 getMockAccessibilityServiceInfo(ComponentName componentName)513 private AccessibilityServiceInfo getMockAccessibilityServiceInfo(ComponentName componentName) { 514 return getMockAccessibilityServiceInfo(componentName, true); 515 } 516 getMockAccessibilityServiceInfo(ComponentName componentName, boolean isSystemApp)517 private AccessibilityServiceInfo getMockAccessibilityServiceInfo(ComponentName componentName, 518 boolean isSystemApp) { 519 final ApplicationInfo applicationInfo = Mockito.mock(ApplicationInfo.class); 520 when(applicationInfo.isSystemApp()).thenReturn(isSystemApp); 521 final ServiceInfo serviceInfo = Mockito.spy(new ServiceInfo()); 522 applicationInfo.packageName = componentName.getPackageName(); 523 serviceInfo.packageName = componentName.getPackageName(); 524 serviceInfo.name = componentName.getClassName(); 525 serviceInfo.applicationInfo = applicationInfo; 526 when(serviceInfo.loadLabel(any())).thenReturn(DEFAULT_LABEL); 527 528 final ResolveInfo resolveInfo = new ResolveInfo(); 529 resolveInfo.serviceInfo = serviceInfo; 530 try { 531 final AccessibilityServiceInfo info = new AccessibilityServiceInfo(resolveInfo, 532 mContext); 533 info.setComponentName(componentName); 534 return info; 535 } catch (XmlPullParserException | IOException e) { 536 // Do nothing 537 } 538 539 return null; 540 } 541 getMockAccessibilityShortcutInfo()542 private AccessibilityShortcutInfo getMockAccessibilityShortcutInfo() { 543 AccessibilityShortcutInfo mockInfo = Mockito.mock(AccessibilityShortcutInfo.class); 544 final ActivityInfo activityInfo = Mockito.mock(ActivityInfo.class); 545 activityInfo.applicationInfo = new ApplicationInfo(); 546 when(mockInfo.getActivityInfo()).thenReturn(activityInfo); 547 when(activityInfo.loadLabel(any())).thenReturn(DEFAULT_LABEL); 548 when(mockInfo.loadSummary(any())).thenReturn(DEFAULT_SUMMARY); 549 when(mockInfo.loadDescription(any())).thenReturn(DEFAULT_DESCRIPTION); 550 when(mockInfo.getComponentName()).thenReturn(ACTIVITY_COMPONENT_NAME); 551 return mockInfo; 552 } 553 setInvisibleToggleFragmentType(AccessibilityServiceInfo info)554 private void setInvisibleToggleFragmentType(AccessibilityServiceInfo info) { 555 info.getResolveInfo().serviceInfo.applicationInfo.targetSdkVersion = Build.VERSION_CODES.R; 556 info.flags |= AccessibilityServiceInfo.FLAG_REQUEST_ACCESSIBILITY_BUTTON; 557 } 558 setupFragment()559 private void setupFragment() { 560 mActivityController.create().start().resume(); 561 Fragment fragment = mActivityController.get().getSupportFragmentManager().findFragmentById( 562 R.id.main_content); 563 564 assertThat(fragment).isNotNull(); 565 assertThat(fragment).isInstanceOf(AccessibilitySettings.class); 566 567 mFragment = (AccessibilitySettings) fragment; 568 } 569 setShortcutEnabled(ComponentName componentName, boolean enabled)570 private void setShortcutEnabled(ComponentName componentName, boolean enabled) { 571 mShadowAccessibilityManager.setAccessibilityShortcutTargets( 572 SOFTWARE, (enabled) ? List.of(componentName.flattenToString()) : List.of()); 573 } 574 assertUriObserversContainsClazz( String settingUri, Class<?> clazz)575 private BooleanSubject assertUriObserversContainsClazz( 576 String settingUri, Class<?> clazz) { 577 ShadowContentResolver shadowContentResolver = shadowOf(mContext.getContentResolver()); 578 Collection<ContentObserver> observers = 579 shadowContentResolver.getContentObservers( 580 Settings.Secure.getUriFor(settingUri)); 581 582 return assertThat(observers.stream().anyMatch(clazz::isInstance)); 583 } 584 } 585