Merge "Update for DisposableBroadcastReceiverAsUser"
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 8c05051..74cf865 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -341,6 +341,25 @@
         </receiver>
 
         <activity
+            android:name="Settings$MemtagPageActivity"
+            android:label="@string/memtag_title"
+            android:icon="@drawable/ic_homepage_security"
+            android:exported="true"
+            android:configChanges="orientation|keyboardHidden|screenSize">
+            <intent-filter android:priority="1">
+                <action android:name="android.settings.MEMTAG_SETTINGS"/>
+                <category android:name="android.intent.category.BROWSABLE" />
+                <category android:name="android.intent.category.DEFAULT"/>
+            </intent-filter>
+            <meta-data android:name="com.android.settings.FRAGMENT_CLASS"
+                       android:value="com.android.settings.security.MemtagPage"/>
+            <meta-data android:name="com.android.settings.HIGHLIGHT_MENU_KEY"
+                       android:value="@string/menu_key_security"/>
+            <meta-data android:name="com.android.settings.PRIMARY_PROFILE_CONTROLLED"
+                       android:value="true"/>
+        </activity>
+
+        <activity
             android:name="Settings$WifiSettingsActivity"
             android:label="@string/wifi_settings"
             android:icon="@drawable/ic_homepage_network"
diff --git a/src/com/android/settings/Settings.java b/src/com/android/settings/Settings.java
index 342ab70..b95c9b0 100644
--- a/src/com/android/settings/Settings.java
+++ b/src/com/android/settings/Settings.java
@@ -46,6 +46,8 @@
     /*
     * Settings subclasses for launching independently.
     */
+
+    public static class MemtagPageActivity extends SettingsActivity { /* empty */}
     public static class AssistGestureSettingsActivity extends SettingsActivity { /* empty */}
     public static class BluetoothSettingsActivity extends SettingsActivity { /* empty */ }
     public static class CreateShortcutActivity extends SettingsActivity { /* empty */ }
diff --git a/src/com/android/settings/applications/AppLocaleUtil.java b/src/com/android/settings/applications/AppLocaleUtil.java
index 79406f0..70d284d 100644
--- a/src/com/android/settings/applications/AppLocaleUtil.java
+++ b/src/com/android/settings/applications/AppLocaleUtil.java
@@ -17,48 +17,55 @@
 package com.android.settings.applications;
 
 import android.annotation.NonNull;
-import android.app.ActivityManager;
 import android.app.LocaleConfig;
 import android.content.Context;
 import android.content.Intent;
-import android.content.pm.PackageInfo;
+import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
 import android.os.LocaleList;
+import android.text.TextUtils;
 import android.util.FeatureFlagUtils;
 import android.util.Log;
 
+import androidx.annotation.VisibleForTesting;
+
 import com.android.settings.R;
 
 import java.util.List;
 
-/** This class provides methods that help dealing with per app locale. */
+/**
+ * This class provides methods that help dealing with per app locale.
+ */
 public class AppLocaleUtil {
     private static final String TAG = AppLocaleUtil.class.getSimpleName();
 
     public static final Intent LAUNCHER_ENTRY_INTENT =
             new Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_LAUNCHER);
 
+    @VisibleForTesting
+    static LocaleConfig sLocaleConfig;
+
     /**
      * Decides the UI display of per app locale.
      */
     public static boolean canDisplayLocaleUi(
             @NonNull Context context,
-            @NonNull String packageName,
+            @NonNull ApplicationInfo app,
             @NonNull List<ResolveInfo> infos) {
-        boolean isDisallowedPackage = isDisallowedPackage(context, packageName);
-        boolean hasLauncherEntry = hasLauncherEntry(packageName, infos);
-        boolean isSignedWithPlatformKey = isSignedWithPlatformKey(context, packageName);
+        boolean isDisallowedPackage = isDisallowedPackage(context, app.packageName);
+        boolean hasLauncherEntry = hasLauncherEntry(app.packageName, infos);
+        boolean isSignedWithPlatformKey = app.isSignedWithPlatformKey();
         boolean canDisplay = !isDisallowedPackage
                 && !isSignedWithPlatformKey
                 && hasLauncherEntry
-                && isAppLocaleSupported(context, packageName);
+                && isAppLocaleSupported(context, app.packageName);
 
-        Log.i(TAG, "Can display preference - [" + packageName + "] :"
+        Log.i(TAG, "Can display preference - [" + app.packageName + "] :"
                 + " isDisallowedPackage : " + isDisallowedPackage
                 + " / isSignedWithPlatformKey : " + isSignedWithPlatformKey
                 + " / hasLauncherEntry : " + hasLauncherEntry
-                + " / canDisplay : " + canDisplay);
+                + " / canDisplay : " + canDisplay + " / 1.1");
         return canDisplay;
     }
 
@@ -66,30 +73,13 @@
         final String[] disallowedPackages = context.getResources().getStringArray(
                 R.array.config_disallowed_app_localeChange_packages);
         for (String disallowedPackage : disallowedPackages) {
-            if (packageName.equals(disallowedPackage)) {
+            if (TextUtils.equals(packageName, disallowedPackage)) {
                 return true;
             }
         }
         return false;
     }
 
-    private static boolean isSignedWithPlatformKey(Context context, String packageName) {
-        PackageInfo packageInfo = null;
-        PackageManager packageManager = context.getPackageManager();
-        ActivityManager activityManager = context.getSystemService(ActivityManager.class);
-        try {
-            packageInfo = packageManager.getPackageInfoAsUser(
-                    packageName, /* flags= */ 0,
-                    activityManager.getCurrentUser());
-        } catch (PackageManager.NameNotFoundException ex) {
-            Log.e(TAG, "package not found: " + packageName);
-        }
-        if (packageInfo == null) {
-            return false;
-        }
-        return packageInfo.applicationInfo.isSignedWithPlatformKey();
-    }
-
     private static boolean hasLauncherEntry(String packageName, List<ResolveInfo> infos) {
         return infos.stream()
                 .anyMatch(info -> info.activityInfo.packageName.equals(packageName));
@@ -99,7 +89,13 @@
      * Check the function of per app language is supported by current application.
      */
     public static boolean isAppLocaleSupported(Context context, String packageName) {
-        LocaleList localeList = getPackageLocales(context, packageName);
+        LocaleList localeList;
+        if (sLocaleConfig != null) {
+            localeList = getPackageLocales(sLocaleConfig);
+        } else {
+            localeList = getPackageLocales(context, packageName);
+        }
+
         if (localeList != null) {
             return localeList.size() > 0;
         }
@@ -118,9 +114,8 @@
     public static String[] getAssetLocales(Context context, String packageName) {
         try {
             PackageManager packageManager = context.getPackageManager();
-            String[] locales = packageManager.getResourcesForApplication(
-                    packageManager.getPackageInfo(packageName, PackageManager.MATCH_ALL)
-                            .applicationInfo).getAssets().getNonSystemLocales();
+            String[] locales = packageManager.getResourcesForApplication(packageName)
+                    .getAssets().getNonSystemLocales();
             if (locales == null) {
                 Log.i(TAG, "[" + packageName + "] locales are null.");
             }
@@ -137,6 +132,14 @@
         return new String[0];
     }
 
+    @VisibleForTesting
+    static LocaleList getPackageLocales(LocaleConfig localeConfig) {
+        if (localeConfig.getStatus() == LocaleConfig.STATUS_SUCCESS) {
+            return localeConfig.getSupportedLocales();
+        }
+        return null;
+    }
+
     /**
      * Get locales from LocaleConfig.
      */
@@ -144,9 +147,7 @@
         try {
             LocaleConfig localeConfig =
                     new LocaleConfig(context.createPackageContext(packageName, 0));
-            if (localeConfig.getStatus() == LocaleConfig.STATUS_SUCCESS) {
-                return localeConfig.getSupportedLocales();
-            }
+            return getPackageLocales(localeConfig);
         } catch (PackageManager.NameNotFoundException e) {
             Log.w(TAG, "Can not found the package name : " + packageName + " / " + e);
         }
diff --git a/src/com/android/settings/applications/AppStateLocaleBridge.java b/src/com/android/settings/applications/AppStateLocaleBridge.java
index 8262ce7..2fea004 100644
--- a/src/com/android/settings/applications/AppStateLocaleBridge.java
+++ b/src/com/android/settings/applications/AppStateLocaleBridge.java
@@ -55,8 +55,7 @@
         AppInfoByProfiles appInfoByProfiles = getAppInfo(UserHandle.getUserId(uid));
 
         app.extraInfo = AppLocaleUtil.canDisplayLocaleUi(appInfoByProfiles.mContextAsUser,
-                app.info.packageName,
-                appInfoByProfiles.mListInfos) ? Boolean.TRUE : Boolean.FALSE;
+                app.info, appInfoByProfiles.mListInfos) ? Boolean.TRUE : Boolean.FALSE;
     }
 
     @Override
@@ -67,8 +66,7 @@
             AppInfoByProfiles appInfoByProfiles = getAppInfo(UserHandle.getUserId(app.info.uid));
 
             app.extraInfo = AppLocaleUtil.canDisplayLocaleUi(appInfoByProfiles.mContextAsUser,
-                    app.info.packageName,
-                    appInfoByProfiles.mListInfos) ? Boolean.TRUE : Boolean.FALSE;
+                    app.info, appInfoByProfiles.mListInfos) ? Boolean.TRUE : Boolean.FALSE;
         }
     }
 
diff --git a/src/com/android/settings/applications/appinfo/AppAllServicesPreferenceController.java b/src/com/android/settings/applications/appinfo/AppAllServicesPreferenceController.java
index 9444e72..b33d187 100644
--- a/src/com/android/settings/applications/appinfo/AppAllServicesPreferenceController.java
+++ b/src/com/android/settings/applications/appinfo/AppAllServicesPreferenceController.java
@@ -47,19 +47,10 @@
 
     private String mPackageName;
 
-    private boolean mCanPackageHandleAllServicesIntent;
-    private boolean mIsLocationProvider;
-
-
     public AppAllServicesPreferenceController(Context context,
             String preferenceKey) {
         super(context, preferenceKey);
         mPackageManager = context.getPackageManager();
-
-        // Set to false till we can confirm that the package can handle the intent.
-        mCanPackageHandleAllServicesIntent = false;
-        // Set to false till we can confirm that the package is a location provider.
-        mIsLocationProvider = false;
     }
 
     @Override
@@ -71,9 +62,8 @@
         }
     }
 
-    @VisibleForTesting
     @Nullable
-    CharSequence getStorageSummary() {
+    private CharSequence getStorageSummary() {
         ResolveInfo resolveInfo = getResolveInfo(PackageManager.GET_META_DATA);
         if (resolveInfo == null) {
             Log.d(TAG, "mResolveInfo is null.");
@@ -96,18 +86,20 @@
 
     @Override
     public int getAvailabilityStatus() {
-        if (mCanPackageHandleAllServicesIntent && mIsLocationProvider) {
+        if (canPackageHandleIntent() && isLocationProvider()) {
             return AVAILABLE;
         }
         return CONDITIONALLY_UNAVAILABLE;
     }
 
-    private boolean isLocationProvider() {
+    @VisibleForTesting
+    boolean isLocationProvider() {
         return Objects.requireNonNull(
                 mContext.getSystemService(LocationManager.class)).isProviderPackage(mPackageName);
     }
 
-    private boolean canPackageHandleIntent() {
+    @VisibleForTesting
+    boolean canPackageHandleIntent() {
         return getResolveInfo(0) != null;
     }
 
@@ -127,14 +119,6 @@
      */
     public void setPackageName(String packageName) {
         mPackageName = packageName;
-
-        //Once we have package name. Update conditions for availability.
-        updateAvailabilityConditions();
-    }
-
-    private void updateAvailabilityConditions() {
-        mCanPackageHandleAllServicesIntent = canPackageHandleIntent();
-        mIsLocationProvider = isLocationProvider();
     }
 
     private void startAllServicesActivity() {
diff --git a/src/com/android/settings/applications/appinfo/AppLocalePreferenceController.java b/src/com/android/settings/applications/appinfo/AppLocalePreferenceController.java
index 30fe1c4..d58607f 100644
--- a/src/com/android/settings/applications/appinfo/AppLocalePreferenceController.java
+++ b/src/com/android/settings/applications/appinfo/AppLocalePreferenceController.java
@@ -84,6 +84,6 @@
     @VisibleForTesting
     boolean canDisplayLocaleUi() {
         return AppLocaleUtil
-                .canDisplayLocaleUi(mContext, mParent.getAppEntry().info.packageName, mListInfos);
+                .canDisplayLocaleUi(mContext, mParent.getAppEntry().info, mListInfos);
     }
 }
diff --git a/src/com/android/settings/applications/manageapplications/ManageApplications.java b/src/com/android/settings/applications/manageapplications/ManageApplications.java
index fe7f996..a41230a 100644
--- a/src/com/android/settings/applications/manageapplications/ManageApplications.java
+++ b/src/com/android/settings/applications/manageapplications/ManageApplications.java
@@ -19,6 +19,7 @@
 import static androidx.recyclerview.widget.RecyclerView.SCROLL_STATE_DRAGGING;
 import static androidx.recyclerview.widget.RecyclerView.SCROLL_STATE_IDLE;
 
+import static com.android.internal.jank.InteractionJankMonitor.CUJ_SETTINGS_PAGE_SCROLL;
 import static com.android.settings.ChangeIds.CHANGE_RESTRICT_SAW_INTENT;
 import static com.android.settings.applications.manageapplications.AppFilterRegistry.FILTER_APPS_ALL;
 import static com.android.settings.applications.manageapplications.AppFilterRegistry.FILTER_APPS_BATTERY_OPTIMIZED;
@@ -86,6 +87,7 @@
 import androidx.recyclerview.widget.RecyclerView;
 
 import com.android.internal.compat.IPlatformCompat;
+import com.android.internal.jank.InteractionJankMonitor;
 import com.android.settings.R;
 import com.android.settings.Settings.AlarmsAndRemindersActivity;
 import com.android.settings.Settings.AppBatteryUsageActivity;
@@ -1242,8 +1244,10 @@
         @Override
         public void onAttachedToRecyclerView(@NonNull RecyclerView recyclerView) {
             super.onAttachedToRecyclerView(recyclerView);
+            final String className =
+                    mManageApplications.getClass().getName() + "_" + mManageApplications.mListType;
             mRecyclerView = recyclerView;
-            mOnScrollListener = new OnScrollListener(this);
+            mOnScrollListener = new OnScrollListener(this, className);
             mRecyclerView.addOnScrollListener(mOnScrollListener);
         }
 
@@ -1803,11 +1807,15 @@
             private boolean mDelayNotifyDataChange;
             private ApplicationsAdapter mAdapter;
             private InputMethodManager mInputMethodManager;
+            private InteractionJankMonitor mMonitor;
+            private String mClassName;
 
-            public OnScrollListener(ApplicationsAdapter adapter) {
+            public OnScrollListener(ApplicationsAdapter adapter, String className) {
                 mAdapter = adapter;
                 mInputMethodManager = mAdapter.mContext.getSystemService(
                         InputMethodManager.class);
+                mMonitor = InteractionJankMonitor.getInstance();
+                mClassName = className;
             }
 
             @Override
@@ -1822,6 +1830,15 @@
                         mInputMethodManager.hideSoftInputFromWindow(recyclerView.getWindowToken(),
                                 0);
                     }
+                    // Start jank monitoring during page scrolling.
+                    final InteractionJankMonitor.Configuration.Builder builder =
+                            InteractionJankMonitor.Configuration.Builder.withView(
+                                            CUJ_SETTINGS_PAGE_SCROLL, recyclerView)
+                                    .setTag(mClassName);
+                    mMonitor.begin(builder);
+                } else if (mScrollState == SCROLL_STATE_IDLE) {
+                    // Stop jank monitoring on page scrolling.
+                    mMonitor.end(CUJ_SETTINGS_PAGE_SCROLL);
                 }
             }
 
diff --git a/src/com/android/settings/core/gateway/SettingsGateway.java b/src/com/android/settings/core/gateway/SettingsGateway.java
index 5e3fa5e..b55b024 100644
--- a/src/com/android/settings/core/gateway/SettingsGateway.java
+++ b/src/com/android/settings/core/gateway/SettingsGateway.java
@@ -160,6 +160,7 @@
 import com.android.settings.privacy.PrivacyControlsFragment;
 import com.android.settings.privacy.PrivacyDashboardFragment;
 import com.android.settings.security.LockscreenDashboardFragment;
+import com.android.settings.security.MemtagPage;
 import com.android.settings.security.SecurityAdvancedSettings;
 import com.android.settings.security.SecuritySettings;
 import com.android.settings.shortcut.CreateShortcut;
@@ -328,6 +329,7 @@
             EnterprisePrivacySettings.class.getName(),
             WebViewAppPicker.class.getName(),
             LockscreenDashboardFragment.class.getName(),
+            MemtagPage.class.getName(),
             BluetoothDeviceDetailsFragment.class.getName(),
             BluetoothBroadcastDialog.class.getName(),
             BluetoothFindBroadcastsFragment.class.getName(),
@@ -400,5 +402,6 @@
             Settings.MyDeviceInfoActivity.class.getName(),
             Settings.ModuleLicensesActivity.class.getName(),
             UserBackupSettingsActivity.class.getName(),
+            Settings.MemtagPageActivity.class.getName(),
     };
 }
diff --git a/src/com/android/settings/spa/app/appinfo/AppLocalePreference.kt b/src/com/android/settings/spa/app/appinfo/AppLocalePreference.kt
index 68308d7..b9607b0 100644
--- a/src/com/android/settings/spa/app/appinfo/AppLocalePreference.kt
+++ b/src/com/android/settings/spa/app/appinfo/AppLocalePreference.kt
@@ -69,7 +69,7 @@
             ResolveInfoFlags.of(PackageManager.GET_META_DATA.toLong()),
             app.userId,
         )
-        AppLocaleUtil.canDisplayLocaleUi(context, app.packageName, resolveInfos)
+        AppLocaleUtil.canDisplayLocaleUi(context, app, resolveInfos)
     }
 
     val summaryFlow = flow { emit(getSummary()) }
diff --git a/src/com/android/settings/spa/system/AppLanguagesListModel.kt b/src/com/android/settings/spa/system/AppLanguagesListModel.kt
index 15a0b85..50b23d3 100644
--- a/src/com/android/settings/spa/system/AppLanguagesListModel.kt
+++ b/src/com/android/settings/spa/system/AppLanguagesListModel.kt
@@ -58,7 +58,7 @@
             appList.map { app ->
                 AppLanguagesRecord(app,
                     AppLocaleUtil.canDisplayLocaleUi(context,
-                    app.packageName, resolveInfos))
+                    app, resolveInfos))
             }
         }
 
diff --git a/src/com/android/settings/users/UserSettings.java b/src/com/android/settings/users/UserSettings.java
index 5f9f2fe..4b4813f 100644
--- a/src/com/android/settings/users/UserSettings.java
+++ b/src/com/android/settings/users/UserSettings.java
@@ -1489,7 +1489,7 @@
 
     private void updateAddUserCommon(Context context, RestrictedPreference addUser,
             boolean canAddRestrictedProfile) {
-        if ((mUserCaps.mCanAddUser || !mUserCaps.mDisallowAddUserSetByAdmin)
+        if ((mUserCaps.mCanAddUser && !mUserCaps.mDisallowAddUserSetByAdmin)
                 && WizardManagerHelper.isDeviceProvisioned(context)
                 && mUserCaps.mUserSwitcherEnabled) {
             addUser.setVisible(true);
diff --git a/tests/robotests/src/com/android/settings/applications/appinfo/AppAllServicesPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/applications/appinfo/AppAllServicesPreferenceControllerTest.java
new file mode 100644
index 0000000..c089c9e
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/applications/appinfo/AppAllServicesPreferenceControllerTest.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2022 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.applications.appinfo;
+
+import static com.android.settings.core.BasePreferenceController.CONDITIONALLY_UNAVAILABLE;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+
+import androidx.preference.Preference;
+import androidx.test.core.app.ApplicationProvider;
+
+import com.android.settings.core.BasePreferenceController;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
+
+@RunWith(RobolectricTestRunner.class)
+public class AppAllServicesPreferenceControllerTest {
+
+    @Mock
+    private AppInfoDashboardFragment mFragment;
+    @Mock
+    private Preference mPreference;
+
+    private final Context mContext = ApplicationProvider.getApplicationContext();
+    private AppAllServicesPreferenceController mController;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        mController = spy(new AppAllServicesPreferenceController(mContext, "test_key"));
+        mController.setParentFragment(mFragment);
+        mController.setPackageName("Package1");
+        final String key = mController.getPreferenceKey();
+        when(mPreference.getKey()).thenReturn(key);
+    }
+
+    @Test
+    public void getAvailabilityStatus_shouldReturnAvailable() {
+        doReturn(true).when(mController).canPackageHandleIntent();
+        doReturn(true).when(mController).isLocationProvider();
+
+        assertThat(mController.getAvailabilityStatus()).isEqualTo(
+                BasePreferenceController.AVAILABLE);
+    }
+
+    @Test
+    public void getAvailabilityStatus_canNotHandleIntent_shouldReturnConditionallyUnavailable() {
+        doReturn(false).when(mController).canPackageHandleIntent();
+        doReturn(true).when(mController).isLocationProvider();
+
+        assertThat(mController.getAvailabilityStatus()).isEqualTo(CONDITIONALLY_UNAVAILABLE);
+    }
+
+    @Test
+    public void getAvailabilityStatus_isNotLocationProvider_shouldReturnConditionallyUnavailable() {
+        doReturn(true).when(mController).canPackageHandleIntent();
+        doReturn(false).when(mController).isLocationProvider();
+
+        assertThat(mController.getAvailabilityStatus()).isEqualTo(CONDITIONALLY_UNAVAILABLE);
+    }
+
+    @Test
+    public void getAvailabilityStatus_shouldReturnConditionallyUnavailable() {
+        doReturn(false).when(mController).canPackageHandleIntent();
+        doReturn(false).when(mController).isLocationProvider();
+
+        assertThat(mController.getAvailabilityStatus()).isEqualTo(CONDITIONALLY_UNAVAILABLE);
+    }
+
+    @Test
+    public void canPackageHandleIntent_nullPackageInfo_shouldNotCrash() {
+        mController.setPackageName(null);
+        mController.canPackageHandleIntent();
+        // no crash
+    }
+
+}
diff --git a/tests/robotests/src/com/android/settings/applications/manageapplications/ManageApplicationsTest.java b/tests/robotests/src/com/android/settings/applications/manageapplications/ManageApplicationsTest.java
index da17f11..910fbed 100644
--- a/tests/robotests/src/com/android/settings/applications/manageapplications/ManageApplicationsTest.java
+++ b/tests/robotests/src/com/android/settings/applications/manageapplications/ManageApplicationsTest.java
@@ -60,6 +60,7 @@
 import com.android.settingslib.applications.ApplicationsState;
 import com.android.settingslib.applications.ApplicationsState.AppEntry;
 import com.android.settingslib.applications.ApplicationsState.AppFilter;
+import com.android.settingslib.testutils.shadow.ShadowInteractionJankMonitor;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -75,7 +76,8 @@
 import java.util.ArrayList;
 
 @RunWith(RobolectricTestRunner.class)
-@Config(shadows = {ShadowUserManager.class, ShadowAppUtils.class})
+@Config(shadows = {ShadowUserManager.class, ShadowAppUtils.class,
+        ShadowInteractionJankMonitor.class})
 public class ManageApplicationsTest {
 
     @Mock
diff --git a/tests/robotests/src/com/android/settings/users/UserSettingsTest.java b/tests/robotests/src/com/android/settings/users/UserSettingsTest.java
index 54f579c..8002582 100644
--- a/tests/robotests/src/com/android/settings/users/UserSettingsTest.java
+++ b/tests/robotests/src/com/android/settings/users/UserSettingsTest.java
@@ -417,12 +417,12 @@
     }
 
     @Test
-    public void updateUserList_cannotAddUserButCanSwitchUser_shouldShowDisabledAddUser() {
+    public void updateUserList_cannotAddUserButCanSwitchUser_shouldNotShowAddUser() {
         mUserCapabilities.mCanAddUser = false;
 
         mFragment.updateUserList();
 
-        verify(mAddUserPreference).setEnabled(false);
+        verify(mAddUserPreference).setVisible(false);
     }
 
     @Test
diff --git a/tests/spa_unit/src/com/android/settings/spa/app/appinfo/AppLocalePreferenceTest.kt b/tests/spa_unit/src/com/android/settings/spa/app/appinfo/AppLocalePreferenceTest.kt
index 688ced1..60c4f79 100644
--- a/tests/spa_unit/src/com/android/settings/spa/app/appinfo/AppLocalePreferenceTest.kt
+++ b/tests/spa_unit/src/com/android/settings/spa/app/appinfo/AppLocalePreferenceTest.kt
@@ -77,7 +77,8 @@
             .strictness(Strictness.LENIENT)
             .startMocking()
         whenever(context.packageManager).thenReturn(packageManager)
-        whenever(AppLocaleUtil.canDisplayLocaleUi(any(), eq(PACKAGE_NAME), any())).thenReturn(true)
+        whenever(AppLocaleUtil.canDisplayLocaleUi(any(), ArgumentMatchers.eq(APP), any()))
+                .thenReturn(true)
         whenever(AppLocaleDetails.getSummary(any(), ArgumentMatchers.eq(APP))).thenReturn(SUMMARY)
     }
 
@@ -88,7 +89,8 @@
 
     @Test
     fun whenCanNotDisplayLocalUi_notDisplayed() {
-        whenever(AppLocaleUtil.canDisplayLocaleUi(any(), eq(PACKAGE_NAME), any())).thenReturn(false)
+        whenever(AppLocaleUtil.canDisplayLocaleUi(any(), ArgumentMatchers.eq(APP), any()))
+                .thenReturn(false)
 
         setContent()
 
diff --git a/tests/unit/src/com/android/settings/applications/AppLocaleUtilTest.java b/tests/unit/src/com/android/settings/applications/AppLocaleUtilTest.java
index 8350bc7..8a7f504 100644
--- a/tests/unit/src/com/android/settings/applications/AppLocaleUtilTest.java
+++ b/tests/unit/src/com/android/settings/applications/AppLocaleUtilTest.java
@@ -17,27 +17,29 @@
 package com.android.settings.applications;
 
 import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.when;
 
 import android.app.ActivityManager;
+import android.app.LocaleConfig;
 import android.content.Context;
 import android.content.pm.ActivityInfo;
 import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
 import android.content.res.Resources;
+import android.os.LocaleList;
+import android.util.FeatureFlagUtils;
 
 import androidx.test.core.app.ApplicationProvider;
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 
+import org.junit.After;
 import org.junit.Before;
-import org.junit.Ignore;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
@@ -53,14 +55,15 @@
     @Mock
     private ActivityManager mActivityManager;
     @Mock
-    private ApplicationInfo mApplicationInfo;
-    @Mock
     private Resources mResources;
+    @Mock
+    private LocaleConfig mLocaleConfig;
 
     private Context mContext;
     private String mDisallowedPackage = "com.disallowed.package";
     private String mAllowedPackage = "com.allowed.package";
     private List<ResolveInfo> mListResolveInfo;
+    private ApplicationInfo mAppInfo;
 
     @Before
     public void setUp() {
@@ -68,47 +71,72 @@
         mContext = spy(ApplicationProvider.getApplicationContext());
         when(mContext.getPackageManager()).thenReturn(mPackageManager);
         when(mContext.getSystemService(ActivityManager.class)).thenReturn(mActivityManager);
+
+        FeatureFlagUtils.setEnabled(mContext, FeatureFlagUtils.SETTINGS_APP_LOCALE_OPT_IN_ENABLED,
+                true);
         setDisallowedPackageName(mDisallowedPackage);
+        mAppInfo = new ApplicationInfo();
+        mLocaleConfig = mock(LocaleConfig.class);
+    }
+
+    @After
+    public void tearDown() {
+        AppLocaleUtil.sLocaleConfig = null;
     }
 
     @Test
-    @Ignore("b/231904717")
-    public void canDisplayLocaleUi_showUI() throws PackageManager.NameNotFoundException {
-        setApplicationInfo(/*no platform key*/ false);
+    public void canDisplayLocaleUi_showUI() {
+        when(mLocaleConfig.getStatus()).thenReturn(LocaleConfig.STATUS_SUCCESS);
+        when(mLocaleConfig.getSupportedLocales()).thenReturn(LocaleList.forLanguageTags("en-US"));
+        AppLocaleUtil.sLocaleConfig = mLocaleConfig;
         setActivityInfo(mAllowedPackage);
+        mAppInfo.packageName = mAllowedPackage;
 
-        assertTrue(AppLocaleUtil.canDisplayLocaleUi(mContext, mAllowedPackage, mListResolveInfo));
+        assertTrue(AppLocaleUtil.canDisplayLocaleUi(mContext, mAppInfo, mListResolveInfo));
     }
 
     @Test
-    @Ignore("b/231904717")
-    public void canDisplayLocaleUi_notShowUI_hasPlatformKey()
-            throws PackageManager.NameNotFoundException {
-        setApplicationInfo(/*has platform key*/ true);
+    public void canDisplayLocaleUi_notShowUI_hasPlatformKey() {
         setActivityInfo(mAllowedPackage);
+        mAppInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_SIGNED_WITH_PLATFORM_KEY;
+        mAppInfo.packageName = mAllowedPackage;
 
-        assertFalse(AppLocaleUtil.canDisplayLocaleUi(mContext, mAllowedPackage, mListResolveInfo));
+        assertFalse(AppLocaleUtil.canDisplayLocaleUi(mContext, mAppInfo, mListResolveInfo));
     }
 
     @Test
-    @Ignore("b/231904717")
-    public void canDisplayLocaleUi_notShowUI_noLauncherEntry()
-            throws PackageManager.NameNotFoundException {
-        setApplicationInfo(/*no platform key*/false);
+    public void canDisplayLocaleUi_notShowUI_noLauncherEntry() {
         setActivityInfo("");
 
-        assertFalse(AppLocaleUtil.canDisplayLocaleUi(mContext, mAllowedPackage, mListResolveInfo));
+        assertFalse(AppLocaleUtil.canDisplayLocaleUi(mContext, mAppInfo, mListResolveInfo));
     }
 
     @Test
-    @Ignore("b/231904717")
-    public void canDisplayLocaleUi_notShowUI_matchDisallowedPackageList()
-            throws PackageManager.NameNotFoundException {
-        setApplicationInfo(/*no platform key*/false);
+    public void canDisplayLocaleUi_notShowUI_matchDisallowedPackageList() {
         setActivityInfo("");
+        mAppInfo.packageName = mDisallowedPackage;
 
         assertFalse(AppLocaleUtil
-                .canDisplayLocaleUi(mContext, mDisallowedPackage, mListResolveInfo));
+                .canDisplayLocaleUi(mContext, mAppInfo, mListResolveInfo));
+    }
+
+    @Test
+    public void getPackageLocales_getLocales_success() {
+        when(mLocaleConfig.getStatus()).thenReturn(LocaleConfig.STATUS_SUCCESS);
+        when(mLocaleConfig.getSupportedLocales()).thenReturn(LocaleList.forLanguageTags("en-US"));
+
+        LocaleList result = AppLocaleUtil.getPackageLocales(mLocaleConfig);
+
+        assertFalse(result.isEmpty());
+    }
+
+    @Test
+    public void getPackageLocales_getLocales_failed() {
+        when(mLocaleConfig.getStatus()).thenReturn(LocaleConfig.STATUS_PARSING_FAILED);
+
+        LocaleList result = AppLocaleUtil.getPackageLocales(mLocaleConfig);
+
+        assertNull(result);
     }
 
     private void setDisallowedPackageName(String packageName) {
@@ -116,20 +144,6 @@
         when(mResources.getStringArray(anyInt())).thenReturn(new String[]{packageName});
     }
 
-    private void setApplicationInfo(boolean signedWithPlatformKey)
-            throws PackageManager.NameNotFoundException {
-        ApplicationInfo applicationInfo = new ApplicationInfo();
-        if (signedWithPlatformKey) {
-            applicationInfo.privateFlags = applicationInfo.privateFlags
-                    | ApplicationInfo.PRIVATE_FLAG_SIGNED_WITH_PLATFORM_KEY;
-        }
-
-        PackageInfo packageInfo = new PackageInfo();
-        packageInfo.applicationInfo = applicationInfo;
-        when(mPackageManager.getPackageInfoAsUser(anyString(), anyInt(), anyInt())).thenReturn(
-                packageInfo);
-    }
-
     private void setActivityInfo(String packageName) {
         ResolveInfo resolveInfo = mock(ResolveInfo.class);
         ActivityInfo activityInfo = mock(ActivityInfo.class);