Merge "Checks that prebundled categories contain only preinstalled contents." into main
diff --git a/aconfig/accessibility/accessibility_flags.aconfig b/aconfig/accessibility/accessibility_flags.aconfig
index 3ed618b..3092b8f 100644
--- a/aconfig/accessibility/accessibility_flags.aconfig
+++ b/aconfig/accessibility/accessibility_flags.aconfig
@@ -21,6 +21,16 @@
}
flag {
+ name: "check_prebundled_is_preinstalled"
+ namespace: "accessibility"
+ description: "Checks that all 'prebundled' components, used for grouping, are also preinstalled"
+ bug: "353888087"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
+
+flag {
name: "edit_shortcuts_in_full_screen"
namespace: "accessibility"
description: "Show the edit shorcuts screen in full screen, since the shortcut options are increasing."
diff --git a/src/com/android/settings/accessibility/AccessibilitySettings.java b/src/com/android/settings/accessibility/AccessibilitySettings.java
index 23f8ec7..d01806a 100644
--- a/src/com/android/settings/accessibility/AccessibilitySettings.java
+++ b/src/com/android/settings/accessibility/AccessibilitySettings.java
@@ -75,7 +75,8 @@
private static final String CATEGORY_AUDIO = "audio_category";
private static final String CATEGORY_SPEECH = "speech_category";
private static final String CATEGORY_DISPLAY = "display_category";
- private static final String CATEGORY_DOWNLOADED_SERVICES = "user_installed_services_category";
+ @VisibleForTesting
+ static final String CATEGORY_DOWNLOADED_SERVICES = "user_installed_services_category";
private static final String CATEGORY_KEYBOARD_OPTIONS = "physical_keyboard_options_category";
@VisibleForTesting
static final String CATEGORY_INTERACTION_CONTROL = "interaction_control_category";
@@ -380,6 +381,7 @@
}
protected void updateServicePreferences() {
+ final AccessibilityManager a11yManager = AccessibilityManager.getInstance(getPrefContext());
// Since services category is auto generated we have to do a pass
// to generate it since services can come and go and then based on
// the global accessibility state to decided whether it is enabled.
@@ -410,8 +412,18 @@
AccessibilityUtils.ACCESSIBILITY_MENU_IN_SYSTEM,
mCategoryToPrefCategoryMap.get(CATEGORY_INTERACTION_CONTROL));
- final List<RestrictedPreference> preferenceList = getInstalledAccessibilityList(
- getPrefContext());
+ final List<AccessibilityShortcutInfo> installedShortcutList =
+ a11yManager.getInstalledAccessibilityShortcutListAsUser(getPrefContext(),
+ UserHandle.myUserId());
+ final List<AccessibilityServiceInfo> modifiableInstalledServiceList =
+ new ArrayList<>(a11yManager.getInstalledAccessibilityServiceList());
+ final List<RestrictedPreference> preferenceList = getInstalledAccessibilityPreferences(
+ getPrefContext(), installedShortcutList, modifiableInstalledServiceList);
+
+ if (Flags.checkPrebundledIsPreinstalled()) {
+ removeNonPreinstalledComponents(mPreBundledServiceComponentToCategoryMap,
+ installedShortcutList, modifiableInstalledServiceList);
+ }
final PreferenceCategory downloadedServicesCategory =
mCategoryToPrefCategoryMap.get(CATEGORY_DOWNLOADED_SERVICES);
@@ -456,13 +468,21 @@
updatePreferenceCategoryVisibility(CATEGORY_KEYBOARD_OPTIONS);
}
- private List<RestrictedPreference> getInstalledAccessibilityList(Context context) {
- final AccessibilityManager a11yManager = AccessibilityManager.getInstance(context);
+ /**
+ * Gets a list of {@link RestrictedPreference}s for the provided a11y shortcuts and services.
+ *
+ * <p>{@code modifiableInstalledServiceList} may be modified to remove any entries with
+ * matching package name and label as an entry in {@code installedShortcutList}.
+ *
+ * @param installedShortcutList A list of installed {@link AccessibilityShortcutInfo}s.
+ * @param modifiableInstalledServiceList A modifiable list of installed
+ * {@link AccessibilityServiceInfo}s.
+ */
+ private List<RestrictedPreference> getInstalledAccessibilityPreferences(Context context,
+ List<AccessibilityShortcutInfo> installedShortcutList,
+ List<AccessibilityServiceInfo> modifiableInstalledServiceList) {
final RestrictedPreferenceHelper preferenceHelper = new RestrictedPreferenceHelper(context);
- final List<AccessibilityShortcutInfo> installedShortcutList =
- a11yManager.getInstalledAccessibilityShortcutListAsUser(context,
- UserHandle.myUserId());
final List<AccessibilityActivityPreference> activityList =
preferenceHelper.createAccessibilityActivityPreferenceList(installedShortcutList);
final Set<Pair<String, CharSequence>> packageLabelPairs =
@@ -471,16 +491,14 @@
a11yActivityPref.getPackageName(), a11yActivityPref.getLabel())
).collect(Collectors.toSet());
- // Remove duplicate item here, new a ArrayList to copy unmodifiable list result
- // (getInstalledAccessibilityServiceList).
- final List<AccessibilityServiceInfo> installedServiceList = new ArrayList<>(
- a11yManager.getInstalledAccessibilityServiceList());
+ // Remove duplicate A11yServices that are already shown as A11yActivities.
if (!packageLabelPairs.isEmpty()) {
- installedServiceList.removeIf(
+ modifiableInstalledServiceList.removeIf(
target -> containsPackageAndLabelInList(packageLabelPairs, target));
}
final List<RestrictedPreference> serviceList =
- preferenceHelper.createAccessibilityServicePreferenceList(installedServiceList);
+ preferenceHelper.createAccessibilityServicePreferenceList(
+ modifiableInstalledServiceList);
final List<RestrictedPreference> preferenceList = new ArrayList<>();
preferenceList.addAll(activityList);
@@ -489,6 +507,22 @@
return preferenceList;
}
+ private static void removeNonPreinstalledComponents(
+ Map<ComponentName, PreferenceCategory> componentToCategory,
+ List<AccessibilityShortcutInfo> shortcutInfos,
+ List<AccessibilityServiceInfo> serviceInfos) {
+ for (AccessibilityShortcutInfo info : shortcutInfos) {
+ if (!info.getActivityInfo().applicationInfo.isSystemApp()) {
+ componentToCategory.remove(info.getComponentName());
+ }
+ }
+ for (AccessibilityServiceInfo info : serviceInfos) {
+ if (!info.getResolveInfo().serviceInfo.applicationInfo.isSystemApp()) {
+ componentToCategory.remove(info.getComponentName());
+ }
+ }
+ }
+
private boolean containsPackageAndLabelInList(
Set<Pair<String, CharSequence>> packageLabelPairs,
AccessibilityServiceInfo targetServiceInfo) {
diff --git a/tests/robotests/src/com/android/settings/accessibility/AccessibilitySettingsTest.java b/tests/robotests/src/com/android/settings/accessibility/AccessibilitySettingsTest.java
index 1463cd0..cb2429c 100644
--- a/tests/robotests/src/com/android/settings/accessibility/AccessibilitySettingsTest.java
+++ b/tests/robotests/src/com/android/settings/accessibility/AccessibilitySettingsTest.java
@@ -26,11 +26,9 @@
import static java.util.Collections.singletonList;
import android.accessibilityservice.AccessibilityServiceInfo;
-import android.accessibilityservice.AccessibilityShortcutInfo;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
-import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
@@ -110,9 +108,7 @@
private final Context mContext = ApplicationProvider.getApplicationContext();
@Spy
private final AccessibilityServiceInfo mServiceInfo = getMockAccessibilityServiceInfo(
- PACKAGE_NAME, CLASS_NAME);
- @Mock
- private AccessibilityShortcutInfo mShortcutInfo;
+ new ComponentName(PACKAGE_NAME, CLASS_NAME));
private ShadowAccessibilityManager mShadowAccessibilityManager;
@Mock
private LocalBluetoothManager mLocalBluetoothManager;
@@ -125,7 +121,6 @@
mShadowAccessibilityManager.setInstalledAccessibilityServiceList(new ArrayList<>());
mContext.setTheme(androidx.appcompat.R.style.Theme_AppCompat);
ShadowBluetoothUtils.sLocalBluetoothManager = mLocalBluetoothManager;
- setMockAccessibilityShortcutInfo(mShortcutInfo);
Intent intent = new Intent();
intent.putExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT,
@@ -398,14 +393,25 @@
public void testAccessibilityMenuInSystem_IncludedInInteractionControl() {
mShadowAccessibilityManager.setInstalledAccessibilityServiceList(
List.of(getMockAccessibilityServiceInfo(
- AccessibilityUtils.ACCESSIBILITY_MENU_IN_SYSTEM)));
+ AccessibilityUtils.ACCESSIBILITY_MENU_IN_SYSTEM,
+ /*isSystemApp=*/true)));
setupFragment();
- final RestrictedPreference pref = mFragment.getPreferenceScreen().findPreference(
- AccessibilityUtils.ACCESSIBILITY_MENU_IN_SYSTEM.flattenToString());
- final String prefCategory = mFragment.mServicePreferenceToPreferenceCategoryMap.get(
- pref).getKey();
- assertThat(prefCategory).isEqualTo(AccessibilitySettings.CATEGORY_INTERACTION_CONTROL);
+ assertThat(getPreferenceCategory(AccessibilityUtils.ACCESSIBILITY_MENU_IN_SYSTEM))
+ .isEqualTo(AccessibilitySettings.CATEGORY_INTERACTION_CONTROL);
+ }
+
+ @Test
+ @EnableFlags(com.android.settings.accessibility.Flags.FLAG_CHECK_PREBUNDLED_IS_PREINSTALLED)
+ public void testNonPreinstalledApp_IncludedInDownloadedCategory() {
+ mShadowAccessibilityManager.setInstalledAccessibilityServiceList(
+ List.of(getMockAccessibilityServiceInfo(
+ AccessibilityUtils.ACCESSIBILITY_MENU_IN_SYSTEM,
+ /*isSystemApp=*/false)));
+ setupFragment();
+
+ assertThat(getPreferenceCategory(AccessibilityUtils.ACCESSIBILITY_MENU_IN_SYSTEM))
+ .isEqualTo(AccessibilitySettings.CATEGORY_DOWNLOADED_SERVICES);
}
@Test
@@ -418,13 +424,20 @@
assertThat(pref).isNull();
}
- private AccessibilityServiceInfo getMockAccessibilityServiceInfo(String packageName,
- String className) {
- return getMockAccessibilityServiceInfo(new ComponentName(packageName, className));
+ private String getPreferenceCategory(ComponentName componentName) {
+ return mFragment.mServicePreferenceToPreferenceCategoryMap.get(
+ mFragment.getPreferenceScreen().findPreference(
+ componentName.flattenToString())).getKey();
}
private AccessibilityServiceInfo getMockAccessibilityServiceInfo(ComponentName componentName) {
- final ApplicationInfo applicationInfo = new ApplicationInfo();
+ return getMockAccessibilityServiceInfo(componentName, true);
+ }
+
+ private AccessibilityServiceInfo getMockAccessibilityServiceInfo(ComponentName componentName,
+ boolean isSystemApp) {
+ final ApplicationInfo applicationInfo = Mockito.mock(ApplicationInfo.class);
+ when(applicationInfo.isSystemApp()).thenReturn(isSystemApp);
final ServiceInfo serviceInfo = new ServiceInfo();
applicationInfo.packageName = componentName.getPackageName();
serviceInfo.packageName = componentName.getPackageName();
@@ -445,16 +458,6 @@
return null;
}
- private void setMockAccessibilityShortcutInfo(AccessibilityShortcutInfo mockInfo) {
- final ActivityInfo activityInfo = Mockito.mock(ActivityInfo.class);
- activityInfo.applicationInfo = new ApplicationInfo();
- when(mockInfo.getActivityInfo()).thenReturn(activityInfo);
- when(activityInfo.loadLabel(any())).thenReturn(DEFAULT_LABEL);
- when(mockInfo.loadSummary(any())).thenReturn(DEFAULT_SUMMARY);
- when(mockInfo.loadDescription(any())).thenReturn(DEFAULT_DESCRIPTION);
- when(mockInfo.getComponentName()).thenReturn(COMPONENT_NAME);
- }
-
private void setInvisibleToggleFragmentType(AccessibilityServiceInfo info) {
info.getResolveInfo().serviceInfo.applicationInfo.targetSdkVersion = Build.VERSION_CODES.R;
info.flags |= AccessibilityServiceInfo.FLAG_REQUEST_ACCESSIBILITY_BUTTON;