Merge "Update Modes List if modes change in the background" into main
diff --git a/res/layout-sw600dp/mode_interstitial_layout.xml b/res/layout-sw600dp/mode_interstitial_layout.xml
new file mode 100644
index 0000000..595f353
--- /dev/null
+++ b/res/layout-sw600dp/mode_interstitial_layout.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2024 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<FrameLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:paddingHorizontal="80dp" >
+
+    <include
+        layout="@layout/mode_interstitial_layout_base"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:layout_gravity="center_horizontal" />
+</FrameLayout>
\ 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 e17198b..3356977 100644
--- a/res/values/aliases.xml
+++ b/res/values/aliases.xml
@@ -23,5 +23,6 @@
      <item name="fingerprint_enroll_finish" type="layout">@layout/fingerprint_enroll_finish_base</item>
      <item name="sfps_enroll_finish" type="layout">@layout/sfps_enroll_finish_base</item>
      <item name="choose_lock_pattern" type="layout">@layout/choose_lock_pattern_common</item>
+     <item name="mode_interstitial_layout" type="layout">@layout/mode_interstitial_layout_base</item>
 </resources>
 
diff --git a/src/com/android/settings/accessibility/AccessibilitySettings.java b/src/com/android/settings/accessibility/AccessibilitySettings.java
index f3eab93..8de4936 100644
--- a/src/com/android/settings/accessibility/AccessibilitySettings.java
+++ b/src/com/android/settings/accessibility/AccessibilitySettings.java
@@ -23,7 +23,6 @@
 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.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.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 @@
         final List<AccessibilityShortcutInfo> installedShortcutList =
                 a11yManager.getInstalledAccessibilityShortcutListAsUser(getPrefContext(),
                         UserHandle.myUserId());
-        final List<AccessibilityServiceInfo> modifiableInstalledServiceList =
-                new ArrayList<>(a11yManager.getInstalledAccessibilityServiceList());
+        final List<AccessibilityServiceInfo> installedServiceList =
+                a11yManager.getInstalledAccessibilityServiceList();
         final List<RestrictedPreference> preferenceList = getInstalledAccessibilityPreferences(
-                getPrefContext(), installedShortcutList, modifiableInstalledServiceList);
+                getPrefContext(), installedShortcutList, installedServiceList);
 
         if (Flags.checkPrebundledIsPreinstalled()) {
             removeNonPreinstalledComponents(mPreBundledServiceComponentToCategoryMap,
-                    installedShortcutList, modifiableInstalledServiceList);
+                    installedShortcutList, installedServiceList);
         }
 
         final PreferenceCategory downloadedServicesCategory =
@@ -474,31 +470,18 @@
      * <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.
+     * @param installedShortcutList A list of installed {@link AccessibilityShortcutInfo}s.
+     * @param installedServiceList  A list of installed {@link AccessibilityServiceInfo}s.
      */
     private List<RestrictedPreference> getInstalledAccessibilityPreferences(Context context,
             List<AccessibilityShortcutInfo> installedShortcutList,
-            List<AccessibilityServiceInfo> modifiableInstalledServiceList) {
+            List<AccessibilityServiceInfo> installedServiceList) {
         final RestrictedPreferenceHelper preferenceHelper = new RestrictedPreferenceHelper(context);
 
         final List<AccessibilityActivityPreference> activityList =
                 preferenceHelper.createAccessibilityActivityPreferenceList(installedShortcutList);
-        final Set<Pair<String, CharSequence>> 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<RestrictedPreference> serviceList =
-                preferenceHelper.createAccessibilityServicePreferenceList(
-                        modifiableInstalledServiceList);
+                preferenceHelper.createAccessibilityServicePreferenceList(installedServiceList);
 
         final List<RestrictedPreference> preferenceList = new ArrayList<>();
         preferenceList.addAll(activityList);
@@ -523,16 +506,6 @@
         }
     }
 
-    private boolean containsPackageAndLabelInList(
-            Set<Pair<String, CharSequence>> 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/src/com/android/settings/network/ims/ImsQueryProvisioningStat.java b/src/com/android/settings/network/ims/ImsQueryProvisioningStat.java
index a43fda0..d06eacc 100644
--- a/src/com/android/settings/network/ims/ImsQueryProvisioningStat.java
+++ b/src/com/android/settings/network/ims/ImsQueryProvisioningStat.java
@@ -53,10 +53,10 @@
      */
     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;
diff --git a/src/com/android/settings/notification/modes/ZenSettingsObserver.java b/src/com/android/settings/notification/modes/ZenSettingsObserver.java
index a853646..0f22d7d 100644
--- a/src/com/android/settings/notification/modes/ZenSettingsObserver.java
+++ b/src/com/android/settings/notification/modes/ZenSettingsObserver.java
@@ -16,6 +16,7 @@
 
 package com.android.settings.notification.modes;
 
+import android.app.Flags;
 import android.content.Context;
 import android.database.ContentObserver;
 import android.net.Uri;
@@ -42,13 +43,17 @@
     }
 
     void register() {
-        mContext.getContentResolver().registerContentObserver(ZEN_MODE_URI, false, this);
-        mContext.getContentResolver().registerContentObserver(ZEN_MODE_CONFIG_ETAG_URI, false,
-                this);
+        if (Flags.modesApi() && Flags.modesUi()) {
+            mContext.getContentResolver().registerContentObserver(ZEN_MODE_URI, false, this);
+            mContext.getContentResolver().registerContentObserver(ZEN_MODE_CONFIG_ETAG_URI, false,
+                    this);
+        }
     }
 
     void unregister() {
-        mContext.getContentResolver().unregisterContentObserver(this);
+        if (Flags.modesApi() && Flags.modesUi()) {
+            mContext.getContentResolver().unregisterContentObserver(this);
+        }
     }
 
     void setOnChangeListener(@Nullable Runnable callback) {
diff --git a/src/com/android/settings/wifi/details2/WifiPrivacyPageProvider.kt b/src/com/android/settings/wifi/details2/WifiPrivacyPageProvider.kt
index e41863c..7744a73 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 @@
                 }
             })
             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 @@
             }
         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
+            }
         }
     })
 }
diff --git a/tests/robotests/src/com/android/settings/accessibility/AccessibilitySettingsTest.java b/tests/robotests/src/com/android/settings/accessibility/AccessibilitySettingsTest.java
index 86763fd..3982dc0 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 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.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.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 @@
 /** Test for {@link AccessibilitySettings}. */
 @RunWith(RobolectricTestRunner.class)
 @Config(shadows = {
+        ShadowAccessibilityManager.class,
         ShadowBluetoothAdapter.class,
         ShadowUserManager.class,
         ShadowColorDisplayManager.class,
@@ -93,8 +97,10 @@
 })
 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 @@
     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 @@
 
     @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 @@
         mFragment.onContentChanged();
 
         RestrictedPreference preference = mFragment.getPreferenceScreen().findPreference(
-                COMPONENT_NAME.flattenToString());
+                SERVICE_COMPONENT_NAME.flattenToString());
 
         assertThat(preference).isNotNull();
 
@@ -389,7 +396,7 @@
         mFragment.onResume();
 
         RestrictedPreference preference = mFragment.getPreferenceScreen().findPreference(
-                COMPONENT_NAME.flattenToString());
+                SERVICE_COMPONENT_NAME.flattenToString());
 
         assertThat(preference).isNotNull();
 
@@ -430,6 +437,36 @@
         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 @@
             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 @@
         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/notification/modes/ZenSettingsObserverTest.java b/tests/robotests/src/com/android/settings/notification/modes/ZenSettingsObserverTest.java
new file mode 100644
index 0000000..7fd47d9
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/notification/modes/ZenSettingsObserverTest.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.notification.modes;
+
+import static android.provider.Settings.Global.ZEN_MODE_CONFIG_ETAG;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.robolectric.Shadows.shadowOf;
+
+import android.app.Flags;
+import android.content.Context;
+import android.database.ContentObserver;
+import android.net.Uri;
+import android.platform.test.annotations.DisableFlags;
+import android.platform.test.annotations.EnableFlags;
+import android.platform.test.flag.junit.SetFlagsRule;
+import android.provider.Settings;
+
+import androidx.test.core.app.ApplicationProvider;
+
+import com.google.common.collect.ImmutableList;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.shadows.ShadowLooper;
+
+import java.util.concurrent.atomic.AtomicInteger;
+
+@RunWith(RobolectricTestRunner.class)
+public class ZenSettingsObserverTest {
+
+    @Rule
+    public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
+
+    private static final Uri SETTINGS_URI = Settings.Global.getUriFor(
+            ZEN_MODE_CONFIG_ETAG);
+
+    private Context mContext;
+    private ZenSettingsObserver mObserver;
+
+    @Before
+    public void setUp() {
+        mContext = ApplicationProvider.getApplicationContext();
+        mObserver = new ZenSettingsObserver(mContext);
+    }
+
+    @Test
+    @EnableFlags(Flags.FLAG_MODES_UI)
+    public void register_withFlagEnabled_registersAndCallsBack() {
+        AtomicInteger someValue = new AtomicInteger();
+        mObserver.setOnChangeListener(someValue::incrementAndGet);
+        assertThat(getSettingsContentObservers()).isEmpty();
+
+        mObserver.register();
+        assertThat(getSettingsContentObservers()).hasSize(1);
+
+        getSettingsContentObservers().forEach(o -> o.dispatchChange(false, SETTINGS_URI));
+        ShadowLooper.idleMainLooper();
+        assertThat(someValue.get()).isEqualTo(1);
+
+        mObserver.unregister();
+        assertThat(getSettingsContentObservers()).isEmpty();
+    }
+
+    @Test
+    @DisableFlags(Flags.FLAG_MODES_UI)
+    public void register_withFlagDisabled_doesNotRegister() {
+        mObserver.register();
+        assertThat(getSettingsContentObservers()).isEmpty();
+        mObserver.unregister();
+        assertThat(getSettingsContentObservers()).isEmpty();
+    }
+
+    private ImmutableList<ContentObserver> getSettingsContentObservers() {
+        return ImmutableList.copyOf(
+                shadowOf(mContext.getContentResolver())
+                        .getContentObservers(SETTINGS_URI));
+    }
+}
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 de7792c..fcd1e42 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 @@
 @Implements(AccessibilityManager.class)
 public class ShadowAccessibilityManager extends org.robolectric.shadows.ShadowAccessibilityManager {
     private Map<ComponentName, ComponentName> mA11yFeatureToTileMap = new ArrayMap<>();
+    private List<AccessibilityShortcutInfo> mInstalledAccessibilityShortcutList = List.of();
 
     /**
-     * Implements a hidden method {@link AccessibilityManager.getA11yFeatureToTileMap}
+     * Implements a hidden method {@link AccessibilityManager#getA11yFeatureToTileMap}
      */
     @Implementation
     public Map<ComponentName, ComponentName> getA11yFeatureToTileMap(@UserIdInt int userId) {
@@ -49,4 +53,22 @@
             @NonNull Map<ComponentName, ComponentName> a11yFeatureToTileMap) {
         mA11yFeatureToTileMap = a11yFeatureToTileMap;
     }
+
+    /**
+     * Implements the hidden method
+     * {@link AccessibilityManager#getInstalledAccessibilityShortcutListAsUser}.
+     */
+    @Implementation
+    public List<AccessibilityShortcutInfo> getInstalledAccessibilityShortcutListAsUser(
+            @NonNull Context context, @UserIdInt int userId) {
+        return mInstalledAccessibilityShortcutList;
+    }
+
+    /**
+     * Sets the value to be returned by {@link #getInstalledAccessibilityShortcutListAsUser}.
+     */
+    public void setInstalledAccessibilityShortcutListAsUser(
+            @NonNull List<AccessibilityShortcutInfo> installedAccessibilityShortcutList) {
+        mInstalledAccessibilityShortcutList = installedAccessibilityShortcutList;
+    }
 }