From c4963a73f0d9266a246330527ef9422b336db91d Mon Sep 17 00:00:00 2001 From: Daniel Norman Date: Wed, 14 Aug 2024 21:15:42 +0000 Subject: [PATCH 1/8] RESTRICT AUTOMERGE Stops hiding a11y services with the same package+label as an activity. Bug: 353700779 Test: Install poc APKs from the bug, observe issue not reproducible Test: (automated tests on 'main' branch) Flag: NONE security fix Change-Id: Ia8d43229d277dd4442173166ae0402f05096da4b --- .../accessibility/AccessibilitySettings.java | 25 ------------------- 1 file changed, 25 deletions(-) diff --git a/src/com/android/settings/accessibility/AccessibilitySettings.java b/src/com/android/settings/accessibility/AccessibilitySettings.java index 78bea0f00a9..f77d5a0612a 100644 --- a/src/com/android/settings/accessibility/AccessibilitySettings.java +++ b/src/com/android/settings/accessibility/AccessibilitySettings.java @@ -27,7 +27,6 @@ import android.content.Context; import android.content.pm.ActivityInfo; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; -import android.content.pm.ServiceInfo; import android.graphics.Color; import android.graphics.drawable.Drawable; import android.net.Uri; @@ -407,17 +406,11 @@ public class AccessibilitySettings extends DashboardFragment { final List installedShortcutList = a11yManager.getInstalledAccessibilityShortcutListAsUser(context, UserHandle.myUserId()); - - // Remove duplicate item here, new a ArrayList to copy unmodifiable list result - // (getInstalledAccessibilityServiceList). final List installedServiceList = new ArrayList<>( a11yManager.getInstalledAccessibilityServiceList()); - installedServiceList.removeIf( - target -> containsTargetNameInList(installedShortcutList, target)); final List activityList = preferenceHelper.createAccessibilityActivityPreferenceList(installedShortcutList); - final List serviceList = preferenceHelper.createAccessibilityServicePreferenceList(installedServiceList); @@ -428,24 +421,6 @@ public class AccessibilitySettings extends DashboardFragment { return preferenceList; } - private boolean containsTargetNameInList(List shortcutInfos, - AccessibilityServiceInfo targetServiceInfo) { - final ServiceInfo serviceInfo = targetServiceInfo.getResolveInfo().serviceInfo; - final String servicePackageName = serviceInfo.packageName; - final CharSequence serviceLabel = serviceInfo.loadLabel(getPackageManager()); - - for (int i = 0, count = shortcutInfos.size(); i < count; ++i) { - final ActivityInfo activityInfo = shortcutInfos.get(i).getActivityInfo(); - final String activityPackageName = activityInfo.packageName; - final CharSequence activityLabel = activityInfo.loadLabel(getPackageManager()); - if (servicePackageName.equals(activityPackageName) - && serviceLabel.equals(activityLabel)) { - return true; - } - } - return false; - } - private void initializePreBundledServicesMapFromArray(String categoryKey, int key) { String[] services = getResources().getStringArray(key); PreferenceCategory category = mCategoryToPrefCategoryMap.get(categoryKey); From 1bcc4049583085522767c3da7866ee83d0f5e104 Mon Sep 17 00:00:00 2001 From: Daniel Norman Date: Wed, 14 Aug 2024 21:15:42 +0000 Subject: [PATCH 2/8] RESTRICT AUTOMERGE Stops hiding a11y services with the same package+label as an activity. Bug: 353700779 Test: Install poc APKs from the bug, observe issue not reproducible Test: (automated tests on 'main' branch) Flag: NONE security fix Change-Id: Ia8d43229d277dd4442173166ae0402f05096da4b --- .../accessibility/AccessibilitySettings.java | 25 ------------------- 1 file changed, 25 deletions(-) diff --git a/src/com/android/settings/accessibility/AccessibilitySettings.java b/src/com/android/settings/accessibility/AccessibilitySettings.java index 78bea0f00a9..f77d5a0612a 100644 --- a/src/com/android/settings/accessibility/AccessibilitySettings.java +++ b/src/com/android/settings/accessibility/AccessibilitySettings.java @@ -27,7 +27,6 @@ import android.content.Context; import android.content.pm.ActivityInfo; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; -import android.content.pm.ServiceInfo; import android.graphics.Color; import android.graphics.drawable.Drawable; import android.net.Uri; @@ -407,17 +406,11 @@ public class AccessibilitySettings extends DashboardFragment { final List installedShortcutList = a11yManager.getInstalledAccessibilityShortcutListAsUser(context, UserHandle.myUserId()); - - // Remove duplicate item here, new a ArrayList to copy unmodifiable list result - // (getInstalledAccessibilityServiceList). final List installedServiceList = new ArrayList<>( a11yManager.getInstalledAccessibilityServiceList()); - installedServiceList.removeIf( - target -> containsTargetNameInList(installedShortcutList, target)); final List activityList = preferenceHelper.createAccessibilityActivityPreferenceList(installedShortcutList); - final List serviceList = preferenceHelper.createAccessibilityServicePreferenceList(installedServiceList); @@ -428,24 +421,6 @@ public class AccessibilitySettings extends DashboardFragment { return preferenceList; } - private boolean containsTargetNameInList(List shortcutInfos, - AccessibilityServiceInfo targetServiceInfo) { - final ServiceInfo serviceInfo = targetServiceInfo.getResolveInfo().serviceInfo; - final String servicePackageName = serviceInfo.packageName; - final CharSequence serviceLabel = serviceInfo.loadLabel(getPackageManager()); - - for (int i = 0, count = shortcutInfos.size(); i < count; ++i) { - final ActivityInfo activityInfo = shortcutInfos.get(i).getActivityInfo(); - final String activityPackageName = activityInfo.packageName; - final CharSequence activityLabel = activityInfo.loadLabel(getPackageManager()); - if (servicePackageName.equals(activityPackageName) - && serviceLabel.equals(activityLabel)) { - return true; - } - } - return false; - } - private void initializePreBundledServicesMapFromArray(String categoryKey, int key) { String[] services = getResources().getStringArray(key); PreferenceCategory category = mCategoryToPrefCategoryMap.get(categoryKey); From 398ab199230563aabebbba61e1809306e478a0b9 Mon Sep 17 00:00:00 2001 From: Daniel Norman Date: Wed, 14 Aug 2024 21:15:42 +0000 Subject: [PATCH 3/8] RESTRICT AUTOMERGE Stops hiding a11y services with the same package+label as an activity. Bug: 353700779 Test: Install poc APKs from the bug, observe issue not reproducible Test: (automated tests on 'main' branch) Flag: NONE security fix Change-Id: Ia8d43229d277dd4442173166ae0402f05096da4b --- .../accessibility/AccessibilitySettings.java | 25 ------------------- 1 file changed, 25 deletions(-) diff --git a/src/com/android/settings/accessibility/AccessibilitySettings.java b/src/com/android/settings/accessibility/AccessibilitySettings.java index ef7c2ba02e1..093f644d0a7 100644 --- a/src/com/android/settings/accessibility/AccessibilitySettings.java +++ b/src/com/android/settings/accessibility/AccessibilitySettings.java @@ -22,7 +22,6 @@ import android.app.settings.SettingsEnums; import android.content.ComponentName; import android.content.Context; import android.content.pm.ActivityInfo; -import android.content.pm.ServiceInfo; import android.os.Bundle; import android.os.Handler; import android.os.UserHandle; @@ -389,17 +388,11 @@ public class AccessibilitySettings extends DashboardFragment { final List installedShortcutList = a11yManager.getInstalledAccessibilityShortcutListAsUser(context, UserHandle.myUserId()); - - // Remove duplicate item here, new a ArrayList to copy unmodifiable list result - // (getInstalledAccessibilityServiceList). final List installedServiceList = new ArrayList<>( a11yManager.getInstalledAccessibilityServiceList()); - installedServiceList.removeIf( - target -> containsTargetNameInList(installedShortcutList, target)); final List activityList = preferenceHelper.createAccessibilityActivityPreferenceList(installedShortcutList); - final List serviceList = preferenceHelper.createAccessibilityServicePreferenceList(installedServiceList); @@ -410,24 +403,6 @@ public class AccessibilitySettings extends DashboardFragment { return preferenceList; } - private boolean containsTargetNameInList(List shortcutInfos, - AccessibilityServiceInfo targetServiceInfo) { - final ServiceInfo serviceInfo = targetServiceInfo.getResolveInfo().serviceInfo; - final String servicePackageName = serviceInfo.packageName; - final CharSequence serviceLabel = serviceInfo.loadLabel(getPackageManager()); - - for (int i = 0, count = shortcutInfos.size(); i < count; ++i) { - final ActivityInfo activityInfo = shortcutInfos.get(i).getActivityInfo(); - final String activityPackageName = activityInfo.packageName; - final CharSequence activityLabel = activityInfo.loadLabel(getPackageManager()); - if (servicePackageName.equals(activityPackageName) - && serviceLabel.equals(activityLabel)) { - return true; - } - } - return false; - } - private void initializePreBundledServicesMapFromArray(String categoryKey, int key) { String[] services = getResources().getStringArray(key); PreferenceCategory category = mCategoryToPrefCategoryMap.get(categoryKey); From 25ecee0563a2c6f9f6a47dbf8e5b4d66043d4f67 Mon Sep 17 00:00:00 2001 From: Daniel Norman Date: Wed, 14 Aug 2024 21:15:42 +0000 Subject: [PATCH 4/8] RESTRICT AUTOMERGE Stops hiding a11y services with the same package+label as an activity. Bug: 353700779 Test: Install poc APKs from the bug, observe issue not reproducible Test: (automated tests on 'main' branch) Flag: NONE security fix Change-Id: Ia8d43229d277dd4442173166ae0402f05096da4b --- .../accessibility/AccessibilitySettings.java | 25 ------------------- 1 file changed, 25 deletions(-) diff --git a/src/com/android/settings/accessibility/AccessibilitySettings.java b/src/com/android/settings/accessibility/AccessibilitySettings.java index 426d7c921cc..ce14be42d1c 100644 --- a/src/com/android/settings/accessibility/AccessibilitySettings.java +++ b/src/com/android/settings/accessibility/AccessibilitySettings.java @@ -22,7 +22,6 @@ import android.app.settings.SettingsEnums; import android.content.ComponentName; import android.content.Context; import android.content.pm.ActivityInfo; -import android.content.pm.ServiceInfo; import android.os.Bundle; import android.os.Handler; import android.os.UserHandle; @@ -416,17 +415,11 @@ public class AccessibilitySettings extends DashboardFragment { final List installedShortcutList = a11yManager.getInstalledAccessibilityShortcutListAsUser(context, UserHandle.myUserId()); - - // Remove duplicate item here, new a ArrayList to copy unmodifiable list result - // (getInstalledAccessibilityServiceList). final List installedServiceList = new ArrayList<>( a11yManager.getInstalledAccessibilityServiceList()); - installedServiceList.removeIf( - target -> containsTargetNameInList(installedShortcutList, target)); final List activityList = preferenceHelper.createAccessibilityActivityPreferenceList(installedShortcutList); - final List serviceList = preferenceHelper.createAccessibilityServicePreferenceList(installedServiceList); @@ -437,24 +430,6 @@ public class AccessibilitySettings extends DashboardFragment { return preferenceList; } - private boolean containsTargetNameInList(List shortcutInfos, - AccessibilityServiceInfo targetServiceInfo) { - final ServiceInfo serviceInfo = targetServiceInfo.getResolveInfo().serviceInfo; - final String servicePackageName = serviceInfo.packageName; - final CharSequence serviceLabel = serviceInfo.loadLabel(getPackageManager()); - - for (int i = 0, count = shortcutInfos.size(); i < count; ++i) { - final ActivityInfo activityInfo = shortcutInfos.get(i).getActivityInfo(); - final String activityPackageName = activityInfo.packageName; - final CharSequence activityLabel = activityInfo.loadLabel(getPackageManager()); - if (servicePackageName.equals(activityPackageName) - && serviceLabel.equals(activityLabel)) { - return true; - } - } - return false; - } - private void initializePreBundledServicesMapFromArray(String categoryKey, int key) { String[] services = getResources().getStringArray(key); PreferenceCategory category = mCategoryToPrefCategoryMap.get(categoryKey); From c38fd822ba27224c179b80de2b89a1e9ab8bee59 Mon Sep 17 00:00:00 2001 From: Daniel Norman Date: Wed, 14 Aug 2024 21:02:27 +0000 Subject: [PATCH 5/8] Stops hiding a11y services with the same package+label as an activity. Bug: 353700779 Test: atest AccessibilitySettings, ensure new test passes Test: revert AccessibilitySettings.java change, ensure new test fails Test: Install poc APKs from the bug, observe issue not reproducible Flag: NONE security fix Change-Id: Ie680e80169aa734f2559fe50ef06e4d1eae46779 --- .../accessibility/AccessibilitySettings.java | 43 +++--------- .../AccessibilitySettingsTest.java | 66 ++++++++++++++++--- .../shadow/ShadowAccessibilityManager.java | 24 ++++++- 3 files changed, 89 insertions(+), 44 deletions(-) diff --git a/src/com/android/settings/accessibility/AccessibilitySettings.java b/src/com/android/settings/accessibility/AccessibilitySettings.java index f3eab935e91..8de49365060 100644 --- a/src/com/android/settings/accessibility/AccessibilitySettings.java +++ b/src/com/android/settings/accessibility/AccessibilitySettings.java @@ -23,7 +23,6 @@ import android.accessibilityservice.AccessibilityShortcutInfo; import android.app.settings.SettingsEnums; import android.content.ComponentName; import android.content.Context; -import android.content.pm.ServiceInfo; import android.hardware.input.InputManager; import android.os.Bundle; import android.os.Handler; @@ -31,7 +30,6 @@ import android.os.UserHandle; import android.provider.Settings; import android.text.TextUtils; import android.util.ArrayMap; -import android.util.Pair; import android.view.InputDevice; import android.view.accessibility.AccessibilityManager; @@ -59,8 +57,6 @@ import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.Map; -import java.util.Set; -import java.util.stream.Collectors; /** Activity with the accessibility settings. */ @SearchIndexable(forTarget = SearchIndexable.ALL & ~SearchIndexable.ARC) @@ -415,14 +411,14 @@ public class AccessibilitySettings extends DashboardFragment implements final List installedShortcutList = a11yManager.getInstalledAccessibilityShortcutListAsUser(getPrefContext(), UserHandle.myUserId()); - final List modifiableInstalledServiceList = - new ArrayList<>(a11yManager.getInstalledAccessibilityServiceList()); + final List installedServiceList = + a11yManager.getInstalledAccessibilityServiceList(); final List preferenceList = getInstalledAccessibilityPreferences( - getPrefContext(), installedShortcutList, modifiableInstalledServiceList); + getPrefContext(), installedShortcutList, installedServiceList); if (Flags.checkPrebundledIsPreinstalled()) { removeNonPreinstalledComponents(mPreBundledServiceComponentToCategoryMap, - installedShortcutList, modifiableInstalledServiceList); + installedShortcutList, installedServiceList); } final PreferenceCategory downloadedServicesCategory = @@ -474,31 +470,18 @@ public class AccessibilitySettings extends DashboardFragment implements *

{@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. + * @param installedShortcutList A list of installed {@link AccessibilityShortcutInfo}s. + * @param installedServiceList A list of installed {@link AccessibilityServiceInfo}s. */ private List getInstalledAccessibilityPreferences(Context context, List installedShortcutList, - List modifiableInstalledServiceList) { + List installedServiceList) { final RestrictedPreferenceHelper preferenceHelper = new RestrictedPreferenceHelper(context); final List activityList = preferenceHelper.createAccessibilityActivityPreferenceList(installedShortcutList); - final Set> packageLabelPairs = - activityList.stream() - .map(a11yActivityPref -> new Pair<>( - a11yActivityPref.getPackageName(), a11yActivityPref.getLabel()) - ).collect(Collectors.toSet()); - - // Remove duplicate A11yServices that are already shown as A11yActivities. - if (!packageLabelPairs.isEmpty()) { - modifiableInstalledServiceList.removeIf( - target -> containsPackageAndLabelInList(packageLabelPairs, target)); - } final List serviceList = - preferenceHelper.createAccessibilityServicePreferenceList( - modifiableInstalledServiceList); + preferenceHelper.createAccessibilityServicePreferenceList(installedServiceList); final List preferenceList = new ArrayList<>(); preferenceList.addAll(activityList); @@ -523,16 +506,6 @@ public class AccessibilitySettings extends DashboardFragment implements } } - private boolean containsPackageAndLabelInList( - Set> packageLabelPairs, - AccessibilityServiceInfo targetServiceInfo) { - final ServiceInfo serviceInfo = targetServiceInfo.getResolveInfo().serviceInfo; - final String servicePackageName = serviceInfo.packageName; - final CharSequence serviceLabel = serviceInfo.loadLabel(getPackageManager()); - - return packageLabelPairs.contains(new Pair<>(servicePackageName, serviceLabel)); - } - private void initializePreBundledServicesMapFromArray(String categoryKey, int key) { String[] services = getResources().getStringArray(key); PreferenceCategory category = mCategoryToPrefCategoryMap.get(categoryKey); diff --git a/tests/robotests/src/com/android/settings/accessibility/AccessibilitySettingsTest.java b/tests/robotests/src/com/android/settings/accessibility/AccessibilitySettingsTest.java index 86763fd983c..3982dc0c68c 100644 --- a/tests/robotests/src/com/android/settings/accessibility/AccessibilitySettingsTest.java +++ b/tests/robotests/src/com/android/settings/accessibility/AccessibilitySettingsTest.java @@ -26,10 +26,13 @@ import static org.robolectric.Shadows.shadowOf; 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.PackageManager; import android.content.pm.ResolveInfo; import android.content.pm.ServiceInfo; import android.database.ContentObserver; @@ -48,6 +51,7 @@ import com.android.internal.accessibility.util.AccessibilityUtils; import com.android.settings.R; import com.android.settings.SettingsActivity; import com.android.settings.testutils.XmlTestUtils; +import com.android.settings.testutils.shadow.ShadowAccessibilityManager; import com.android.settings.testutils.shadow.ShadowApplicationPackageManager; import com.android.settings.testutils.shadow.ShadowBluetoothAdapter; import com.android.settings.testutils.shadow.ShadowBluetoothUtils; @@ -73,7 +77,6 @@ import org.robolectric.RobolectricTestRunner; import org.robolectric.android.controller.ActivityController; import org.robolectric.annotation.Config; import org.robolectric.shadow.api.Shadow; -import org.robolectric.shadows.ShadowAccessibilityManager; import org.robolectric.shadows.ShadowContentResolver; import org.xmlpull.v1.XmlPullParserException; @@ -85,6 +88,7 @@ import java.util.List; /** Test for {@link AccessibilitySettings}. */ @RunWith(RobolectricTestRunner.class) @Config(shadows = { + ShadowAccessibilityManager.class, ShadowBluetoothAdapter.class, ShadowUserManager.class, ShadowColorDisplayManager.class, @@ -93,8 +97,10 @@ import java.util.List; }) public class AccessibilitySettingsTest { private static final String PACKAGE_NAME = "com.android.test"; - private static final String CLASS_NAME = PACKAGE_NAME + ".test_a11y_service"; - private static final ComponentName COMPONENT_NAME = new ComponentName(PACKAGE_NAME, CLASS_NAME); + private static final ComponentName SERVICE_COMPONENT_NAME = + new ComponentName(PACKAGE_NAME, PACKAGE_NAME + ".test_a11y_service"); + private static final ComponentName ACTIVITY_COMPONENT_NAME = + new ComponentName(PACKAGE_NAME, PACKAGE_NAME + ".test_a11y_activity"); private static final String EMPTY_STRING = ""; private static final String DEFAULT_SUMMARY = "default summary"; private static final String DEFAULT_DESCRIPTION = "default description"; @@ -108,7 +114,7 @@ public class AccessibilitySettingsTest { private final Context mContext = ApplicationProvider.getApplicationContext(); @Spy private final AccessibilityServiceInfo mServiceInfo = getMockAccessibilityServiceInfo( - new ComponentName(PACKAGE_NAME, CLASS_NAME)); + SERVICE_COMPONENT_NAME); private ShadowAccessibilityManager mShadowAccessibilityManager; @Mock private LocalBluetoothManager mLocalBluetoothManager; @@ -117,7 +123,8 @@ public class AccessibilitySettingsTest { @Before public void setup() { - mShadowAccessibilityManager = Shadow.extract(AccessibilityManager.getInstance(mContext)); + mShadowAccessibilityManager = Shadow.extract( + mContext.getSystemService(AccessibilityManager.class)); mShadowAccessibilityManager.setInstalledAccessibilityServiceList(new ArrayList<>()); mContext.setTheme(androidx.appcompat.R.style.Theme_AppCompat); ShadowBluetoothUtils.sLocalBluetoothManager = mLocalBluetoothManager; @@ -369,7 +376,7 @@ public class AccessibilitySettingsTest { mFragment.onContentChanged(); RestrictedPreference preference = mFragment.getPreferenceScreen().findPreference( - COMPONENT_NAME.flattenToString()); + SERVICE_COMPONENT_NAME.flattenToString()); assertThat(preference).isNotNull(); @@ -389,7 +396,7 @@ public class AccessibilitySettingsTest { mFragment.onResume(); RestrictedPreference preference = mFragment.getPreferenceScreen().findPreference( - COMPONENT_NAME.flattenToString()); + SERVICE_COMPONENT_NAME.flattenToString()); assertThat(preference).isNotNull(); @@ -430,6 +437,36 @@ public class AccessibilitySettingsTest { assertThat(pref).isNull(); } + @Test + public void testSameNamedServiceAndActivity_bothPreferencesExist() { + final PackageManager pm = mContext.getPackageManager(); + AccessibilityServiceInfo a11yServiceInfo = mServiceInfo; + AccessibilityShortcutInfo a11yShortcutInfo = getMockAccessibilityShortcutInfo(); + // Ensure the test service and activity have the same package name and label. + // Before this change, any service and activity with the same package name and + // label would cause the service to be hidden. + assertThat(a11yServiceInfo.getComponentName()) + .isNotEqualTo(a11yShortcutInfo.getComponentName()); + assertThat(a11yServiceInfo.getComponentName().getPackageName()) + .isEqualTo(a11yShortcutInfo.getComponentName().getPackageName()); + assertThat(a11yServiceInfo.getResolveInfo().serviceInfo.loadLabel(pm)) + .isEqualTo(a11yShortcutInfo.getActivityInfo().loadLabel(pm)); + // Prepare A11yManager with the test service and activity. + mShadowAccessibilityManager.setInstalledAccessibilityServiceList( + List.of(mServiceInfo)); + mShadowAccessibilityManager.setInstalledAccessibilityShortcutListAsUser( + List.of(getMockAccessibilityShortcutInfo())); + setupFragment(); + + // Both service and activity preferences should exist on the page. + RestrictedPreference servicePref = mFragment.getPreferenceScreen().findPreference( + a11yServiceInfo.getComponentName().flattenToString()); + RestrictedPreference activityPref = mFragment.getPreferenceScreen().findPreference( + a11yShortcutInfo.getComponentName().flattenToString()); + assertThat(servicePref).isNotNull(); + assertThat(activityPref).isNotNull(); + } + private String getPreferenceCategory(ComponentName componentName) { return mFragment.mServicePreferenceToPreferenceCategoryMap.get( mFragment.getPreferenceScreen().findPreference( @@ -444,11 +481,12 @@ public class AccessibilitySettingsTest { boolean isSystemApp) { final ApplicationInfo applicationInfo = Mockito.mock(ApplicationInfo.class); when(applicationInfo.isSystemApp()).thenReturn(isSystemApp); - final ServiceInfo serviceInfo = new ServiceInfo(); + final ServiceInfo serviceInfo = Mockito.spy(new ServiceInfo()); applicationInfo.packageName = componentName.getPackageName(); serviceInfo.packageName = componentName.getPackageName(); serviceInfo.name = componentName.getClassName(); serviceInfo.applicationInfo = applicationInfo; + when(serviceInfo.loadLabel(any())).thenReturn(DEFAULT_LABEL); final ResolveInfo resolveInfo = new ResolveInfo(); resolveInfo.serviceInfo = serviceInfo; @@ -464,6 +502,18 @@ public class AccessibilitySettingsTest { return null; } + private AccessibilityShortcutInfo getMockAccessibilityShortcutInfo() { + AccessibilityShortcutInfo mockInfo = Mockito.mock(AccessibilityShortcutInfo.class); + 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(ACTIVITY_COMPONENT_NAME); + return mockInfo; + } + private void setInvisibleToggleFragmentType(AccessibilityServiceInfo info) { info.getResolveInfo().serviceInfo.applicationInfo.targetSdkVersion = Build.VERSION_CODES.R; info.flags |= AccessibilityServiceInfo.FLAG_REQUEST_ACCESSIBILITY_BUTTON; diff --git a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowAccessibilityManager.java b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowAccessibilityManager.java index de7792c2ec0..fcd1e42c547 100644 --- a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowAccessibilityManager.java +++ b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowAccessibilityManager.java @@ -16,15 +16,18 @@ package com.android.settings.testutils.shadow; +import android.accessibilityservice.AccessibilityShortcutInfo; import android.annotation.NonNull; import android.annotation.UserIdInt; import android.content.ComponentName; +import android.content.Context; import android.util.ArrayMap; import android.view.accessibility.AccessibilityManager; import org.robolectric.annotation.Implementation; import org.robolectric.annotation.Implements; +import java.util.List; import java.util.Map; /** @@ -33,9 +36,10 @@ import java.util.Map; @Implements(AccessibilityManager.class) public class ShadowAccessibilityManager extends org.robolectric.shadows.ShadowAccessibilityManager { private Map mA11yFeatureToTileMap = new ArrayMap<>(); + private List mInstalledAccessibilityShortcutList = List.of(); /** - * Implements a hidden method {@link AccessibilityManager.getA11yFeatureToTileMap} + * Implements a hidden method {@link AccessibilityManager#getA11yFeatureToTileMap} */ @Implementation public Map getA11yFeatureToTileMap(@UserIdInt int userId) { @@ -49,4 +53,22 @@ public class ShadowAccessibilityManager extends org.robolectric.shadows.ShadowAc @NonNull Map a11yFeatureToTileMap) { mA11yFeatureToTileMap = a11yFeatureToTileMap; } + + /** + * Implements the hidden method + * {@link AccessibilityManager#getInstalledAccessibilityShortcutListAsUser}. + */ + @Implementation + public List getInstalledAccessibilityShortcutListAsUser( + @NonNull Context context, @UserIdInt int userId) { + return mInstalledAccessibilityShortcutList; + } + + /** + * Sets the value to be returned by {@link #getInstalledAccessibilityShortcutListAsUser}. + */ + public void setInstalledAccessibilityShortcutListAsUser( + @NonNull List installedAccessibilityShortcutList) { + mInstalledAccessibilityShortcutList = installedAccessibilityShortcutList; + } } From 739fa3f4c3c669aef98f14800b5419b53dedd5b2 Mon Sep 17 00:00:00 2001 From: Weng Su Date: Wed, 21 Aug 2024 15:32:14 +0800 Subject: [PATCH 6/8] Refine Wi-Fi privacy settings - When changing two configurations, the configuration must be refreshed before modifying the second configuration to prevent the first configuration from being rolled back by the old configuration. Fix: 360313149 Flag: EXEMPT bugfix Test: Manual testing atest -c WifiPrivacyPageProviderTest Change-Id: If0e2c2b6a708fa59929b23409aff1254c6566fef --- .../wifi/details2/WifiPrivacyPageProvider.kt | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/com/android/settings/wifi/details2/WifiPrivacyPageProvider.kt b/src/com/android/settings/wifi/details2/WifiPrivacyPageProvider.kt index e41863cd5b8..7744a73cc17 100644 --- a/src/com/android/settings/wifi/details2/WifiPrivacyPageProvider.kt +++ b/src/com/android/settings/wifi/details2/WifiPrivacyPageProvider.kt @@ -17,7 +17,6 @@ package com.android.settings.wifi.details2 import android.content.Context -import android.net.wifi.WifiConfiguration import android.net.wifi.WifiManager import android.os.Bundle import android.os.Handler @@ -114,19 +113,19 @@ fun WifiPrivacyPage(wifiEntry: WifiEntry) { } }) wifiEntry.wifiConfiguration?.let { - DeviceNameSwitchPreference(it) + DeviceNameSwitchPreference(wifiEntry) } } } } @Composable -fun DeviceNameSwitchPreference(wifiConfiguration: WifiConfiguration){ +fun DeviceNameSwitchPreference(wifiEntry: WifiEntry) { Spacer(modifier = Modifier.width(SettingsDimension.itemDividerHeight)) CategoryTitle(title = stringResource(R.string.wifi_privacy_device_name_settings)) Spacer(modifier = Modifier.width(SettingsDimension.itemDividerHeight)) var checked by remember { - mutableStateOf(wifiConfiguration.isSendDhcpHostnameEnabled) + mutableStateOf(wifiEntry.wifiConfiguration?.isSendDhcpHostnameEnabled) } val context = LocalContext.current val wifiManager = context.getSystemService(WifiManager::class.java)!! @@ -143,9 +142,11 @@ fun DeviceNameSwitchPreference(wifiConfiguration: WifiConfiguration){ } override val checked = { checked } override val onCheckedChange: (Boolean) -> Unit = { newChecked -> - wifiConfiguration.isSendDhcpHostnameEnabled = newChecked - wifiManager.save(wifiConfiguration, null /* listener */) - checked = newChecked + wifiEntry.wifiConfiguration?.let { + it.isSendDhcpHostnameEnabled = newChecked + wifiManager.save(it, null /* listener */) + checked = newChecked + } } }) } From 29042b18a783a9638183944018c94df2788857ea Mon Sep 17 00:00:00 2001 From: Yuri Lin Date: Wed, 21 Aug 2024 14:41:42 -0400 Subject: [PATCH 7/8] Add interstitial layout for larger screen devices For large enough screens, always use the portrait (all vertical in one column) layout for the intestitial, since the landscape split in two halves only makes sense for smaller screens. Renames the layout to mode_interstitial_layout_base and uses an alias so that we can reuse the same layout but with additional padding. Fixes: 361344824 Test: manual Flag: android.app.modes_ui Change-Id: I4e02e9a246ee799e3a79508f11290397a236574c --- .../mode_interstitial_layout.xml | 28 +++++++++++++++++++ ....xml => mode_interstitial_layout_base.xml} | 0 res/values/aliases.xml | 1 + 3 files changed, 29 insertions(+) create mode 100644 res/layout-sw600dp/mode_interstitial_layout.xml rename res/layout/{mode_interstitial_layout.xml => mode_interstitial_layout_base.xml} (100%) diff --git a/res/layout-sw600dp/mode_interstitial_layout.xml b/res/layout-sw600dp/mode_interstitial_layout.xml new file mode 100644 index 00000000000..595f353bb71 --- /dev/null +++ b/res/layout-sw600dp/mode_interstitial_layout.xml @@ -0,0 +1,28 @@ + + + + + + \ No newline at end of file diff --git a/res/layout/mode_interstitial_layout.xml b/res/layout/mode_interstitial_layout_base.xml similarity index 100% rename from res/layout/mode_interstitial_layout.xml rename to res/layout/mode_interstitial_layout_base.xml diff --git a/res/values/aliases.xml b/res/values/aliases.xml index e17198b71a2..3356977c699 100644 --- a/res/values/aliases.xml +++ b/res/values/aliases.xml @@ -23,5 +23,6 @@ @layout/fingerprint_enroll_finish_base @layout/sfps_enroll_finish_base @layout/choose_lock_pattern_common + @layout/mode_interstitial_layout_base From b781605c1e67ad98161b7edbb1c73e0f61649378 Mon Sep 17 00:00:00 2001 From: SongFerng Wang Date: Wed, 21 Aug 2024 10:28:20 +0000 Subject: [PATCH 8/8] Catch IllegalArgumentException when getting provisioning status getProvisioningStatusForCapability still need the IllegalArgumentException when the subId is -1. Bug: 346600036 Test: manual test. Disable sim and the settings did not crash. Flag: EXEMPT bugfix (cherry picked from https://googleplex-android-review.googlesource.com/q/commit:37e1d258f88c5129035501d6ced1dab6627da102) Merged-In: Ib5c41ab9214cf34a17ef02864dccffb5371cfe3a Change-Id: Ib5c41ab9214cf34a17ef02864dccffb5371cfe3a --- .../settings/network/ims/ImsQueryProvisioningStat.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/com/android/settings/network/ims/ImsQueryProvisioningStat.java b/src/com/android/settings/network/ims/ImsQueryProvisioningStat.java index a43fda04626..d06eacc8881 100644 --- a/src/com/android/settings/network/ims/ImsQueryProvisioningStat.java +++ b/src/com/android/settings/network/ims/ImsQueryProvisioningStat.java @@ -53,10 +53,10 @@ public class ImsQueryProvisioningStat implements ImsQuery { */ public boolean query() { try { - final ProvisioningManager privisionManager = + final ProvisioningManager provisioningManager = ProvisioningManager.createForSubscriptionId(mSubId); - return privisionManager.getProvisioningStatusForCapability(mCapability, mTech); - } catch (UnsupportedOperationException exception) { + return provisioningManager.getProvisioningStatusForCapability(mCapability, mTech); + } catch (IllegalArgumentException | UnsupportedOperationException exception) { Log.w(LOG_TAG, "fail to get Provisioning stat. subId=" + mSubId, exception); } return false;