Merge "Remove EXTRA_USER_HANDLE from startSpaActivityForApp"
diff --git a/res-product/values/strings.xml b/res-product/values/strings.xml
index 17fd4d5..c824a6a 100644
--- a/res-product/values/strings.xml
+++ b/res-product/values/strings.xml
@@ -329,6 +329,24 @@
     <string name="fingerprint_last_delete_message" product="tablet">You won\'t be able to use your fingerprint to unlock your tablet or verify it\'s you in apps.</string>
     <!-- Message shown in a dialog which asks the user to confirm when the last fingerprint gets deleted by them. [CHAR LIMIT=NONE]-->
     <string name="fingerprint_last_delete_message" product="device">You won\'t be able to use your fingerprint to unlock your device or verify it\'s you in apps.</string>
+    <!-- Message shown in screen lock picker while setting up the new screen lock with fingerprint option. [CHAR LIMIT=NONE]-->
+    <string name="fingerprint_unlock_title" product="default">You can unlock your phone using your fingerprint. For security, this option requires a backup screen lock.</string>
+    <!-- Message shown in screen lock picker while setting up the new screen lock with fingerprint option. [CHAR LIMIT=NONE]-->
+    <string name="fingerprint_unlock_title" product="tablet">You can unlock your tablet using your fingerprint. For security, this option requires a backup screen lock.</string>
+    <!-- Message shown in screen lock picker while setting up the new screen lock with fingerprint option. [CHAR LIMIT=NONE]-->
+    <string name="fingerprint_unlock_title" product="device">You can unlock your device using your fingerprint. For security, this option requires a backup screen lock.</string>
+    <!-- Message shown in screen lock picker while setting up the new screen lock with face unlock option. [CHAR LIMIT=NONE] -->
+    <string name="face_unlock_title" product="default">You can unlock your phone using your face. For security, this option requires a backup screen lock.</string>
+    <!-- Message shown in screen lock picker while setting up the new screen lock with face unlock option. [CHAR LIMIT=NONE] -->
+    <string name="face_unlock_title" product="tablet">You can unlock your tablet using your face. For security, this option requires a backup screen lock.</string>
+    <!-- Message shown in screen lock picker while setting up the new screen lock with face unlock option. [CHAR LIMIT=NONE] -->
+    <string name="face_unlock_title" product="device">You can unlock your device using your face. For security, this option requires a backup screen lock.</string>
+    <!-- Message shown in screen lock picker while setting up the new screen lock with biometrics option. [CHAR LIMIT=NONE] -->
+    <string name="biometrics_unlock_title" product="default">You can unlock your phone using your face or fingerprint. For security, this option requires a backup screen lock.</string>
+    <!-- Message shown in screen lock picker while setting up the new screen lock with biometrics option. [CHAR LIMIT=NONE] -->
+    <string name="biometrics_unlock_title" product="tablet">You can unlock your tablet using your face or fingerprint. For security, this option requires a backup screen lock.</string>
+    <!-- Message shown in screen lock picker while setting up the new screen lock with biometrics option. [CHAR LIMIT=NONE] -->
+    <string name="biometrics_unlock_title" product="device">You can unlock your device using your face or fingerprint. For security, this option requires a backup screen lock.</string>
     <!-- Title of the preferences item to control encryption -->
     <string name="encrypt_title" product="tablet">Encrypt tablet</string>
     <!-- Title of the preferences item to control encryption -->
diff --git a/res/layout/preference_spinner.xml b/res/layout/preference_spinner.xml
new file mode 100644
index 0000000..4129303
--- /dev/null
+++ b/res/layout/preference_spinner.xml
@@ -0,0 +1,24 @@
+<!--
+  ~ Copyright (C) 2023 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.
+  -->
+
+<Spinner
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/spinner"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:layout_marginStart="24dp"
+    android:layout_marginTop="8dp"
+    android:theme="@style/Widget.PopupWindow.Settings" />
diff --git a/res/layout/preference_tab.xml b/res/layout/preference_tab.xml
deleted file mode 100644
index f9a7881..0000000
--- a/res/layout/preference_tab.xml
+++ /dev/null
@@ -1,37 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ~ 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.
-  -->
-
-<LinearLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:theme="@style/Theme.TabTheme"
-    android:id="@+id/tab_container"
-    android:clipToPadding="true"
-    android:clipChildren="true"
-    android:layout_width="match_parent"
-    android:layout_height="wrap_content"
-    android:orientation="vertical">
-
-    <com.google.android.material.tabs.TabLayout
-        android:id="@+id/tabs"
-        style="@style/SettingsLibTabsStyle" />
-
-    <androidx.viewpager2.widget.ViewPager2
-        android:id="@+id/view_pager"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent" />
-
-</LinearLayout>
diff --git a/res/layout/preference_widget_tick.xml b/res/layout/preference_widget_tick.xml
new file mode 100644
index 0000000..d67a93a
--- /dev/null
+++ b/res/layout/preference_widget_tick.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright (C) 2023 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.
+
+  -->
+
+<!-- Settings button -->
+<ImageView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/tick_button"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:layout_gravity="center"
+    android:scaleType="center"
+    android:src="@drawable/ic_check_24dp" />
\ No newline at end of file
diff --git a/res/values/arrays.xml b/res/values/arrays.xml
index 4d9a001..e41b8c1 100644
--- a/res/values/arrays.xml
+++ b/res/values/arrays.xml
@@ -1360,4 +1360,39 @@
          [CHAR LIMIT=NONE] -->
     <string-array name="allowlist_hide_summary_in_battery_usage" translatable="false">
     </string-array>
+
+    <!-- A list for all temperature units. [CHAR LIMIT=NONE] -->
+    <string-array name="temperature_units">
+        <item>default</item>
+        <item>celsius</item>
+        <item>fahrenheit</item>
+        <item>kelvin</item>
+    </string-array>
+
+    <!-- A list for all days of a week. [CHAR LIMIT=NONE] -->
+    <string-array name="first_day_of_week">
+        <item>default</item>
+        <item>sun</item>
+        <item>mon</item>
+        <item>tue</item>
+        <item>wed</item>
+        <item>thu</item>
+        <item>fri</item>
+        <item>sat</item>
+    </string-array>
+
+    <!-- A list for all supported calendar types. [CHAR LIMIT=NONE] -->
+    <string-array name="calendar_type">
+        <item>default</item>
+        <item>chinese</item>
+        <item>dangi</item>
+        <item>hebrew</item>
+        <item>indian</item>
+        <item>islamic</item>
+        <item>islamic-rgsa</item>
+        <item>islamic-tbla</item>
+        <item>islamic-umalqura</item>
+        <item>persian</item>
+    </string-array>
+
 </resources>
diff --git a/res/values/config.xml b/res/values/config.xml
index bbacc5c..40ca07f 100755
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -603,9 +603,6 @@
     <!-- Whether to show communal settings at the top level. -->
     <bool name="config_show_communal_settings">false</bool>
 
-    <!-- Whether to put the apps with system UID into system component bucket or not -->
-    <bool name="config_battery_combine_system_components">false</bool>
-
     <!-- The extra value for battery tip -->
     <integer name="config_battery_extra_tip_value">12</integer>
 
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 927f84d..1988d9d 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -371,6 +371,26 @@
     <string name="numbers_preferences_title">Numbers</string>
     <!-- The summary of default string for each regional preference. [CHAR LIMIT=50] -->
     <string name="default_string_of_regional_preference">[No preference]</string>
+    <!-- The title of Celsius for preference of temperature unit. [CHAR LIMIT=50] -->
+    <string name="celsius_temperature_unit">Celsius</string>
+    <!-- The title of Fahrenheit for preference of temperature unit. [CHAR LIMIT=50] -->
+    <string name="fahrenheit_temperature_unit">Fahrenheit</string>
+    <!-- The title of Kevin for preference of temperature unit. [CHAR LIMIT=50] -->
+    <string name="kevin_temperature_unit">Kevin</string>
+    <!-- The title of sunday for preference of first day of week. [CHAR LIMIT=50] -->
+    <string name="sunday_first_day_of_week">Sunday</string>
+    <!-- The title of monday for preference of first day of week. [CHAR LIMIT=50] -->
+    <string name="monday_first_day_of_week">Monday</string>
+    <!-- The title of tuesday for preference of first day of week. [CHAR LIMIT=50] -->
+    <string name="tuesday_first_day_of_week">Tuesday</string>
+    <!-- The title of wednesday for preference of first day of week. [CHAR LIMIT=50] -->
+    <string name="wednesday_first_day_of_week">Wednesday</string>
+    <!-- The title of thursday for preference of first day of week. [CHAR LIMIT=50] -->
+    <string name="thursday_first_day_of_week">Thursday</string>
+    <!-- The title of friday for preference of first day of week. [CHAR LIMIT=50] -->
+    <string name="friday_first_day_of_week">Friday</string>
+    <!-- The title of saturday for preference of first day of week. [CHAR LIMIT=50] -->
+    <string name="saturday_first_day_of_week">Saturday</string>
 
     <!-- The title of the confirmation dialog shown when the user selects one / several languages and tries to remove them [CHAR LIMIT=60] -->
     <string name="dlg_remove_locales_title">{count, plural,
@@ -1034,8 +1054,6 @@
     <string name="fingerprint_unlock_set_unlock_password">Fingerprint + Password</string>
     <!-- Title for preference that guides the user to skip fingerprint setup [CHAR LIMIT=60]-->
     <string name="fingerprint_unlock_skip_fingerprint">Continue without fingerprint</string>
-    <!-- Message shown in screen lock picker while setting up the new screen lock with fingerprint option. [CHAR LIMIT=NONE]-->
-    <string name="fingerprint_unlock_title">You can unlock your phone using your fingerprint. For security, this option requires a backup screen lock.</string>
 
     <!-- Title for preference that guides the user through creating a backup unlock pattern for Face Unlock [CHAR LIMIT=45]-->
     <string name="face_unlock_set_unlock_pattern">Face Unlock + Pattern</string>
@@ -1045,8 +1063,6 @@
     <string name="face_unlock_set_unlock_password">Face Unlock + Password</string>
     <!-- Title for preference that guides the user to skip Face Unlock setup [CHAR LIMIT=60]-->
     <string name="face_unlock_skip_face">Continue without Face Unlock</string>
-    <!-- Message shown in screen lock picker while setting up the new screen lock with face unlock option. [CHAR LIMIT=NONE] -->
-    <string name="face_unlock_title">You can unlock your phone using your face. For security, this option requires a backup screen lock.</string>
 
     <!-- Title for preference that guides the user through creating a backup unlock pattern for biometrics unlock [CHAR LIMIT=45]-->
     <string name="biometrics_unlock_set_unlock_pattern">Pattern \u2022 Face \u2022 Fingerprint</string>
@@ -1056,8 +1072,6 @@
     <string name="biometrics_unlock_set_unlock_password">Password \u2022 Face \u2022 Fingerprint</string>
     <!-- Title for preference that guides the user to skip face unlock setup [CHAR LIMIT=60]-->
     <string name="biometrics_unlock_skip_biometrics">Continue without face or fingerprint</string>
-    <!-- Message shown in screen lock picker while setting up the new screen lock with biometrics option. [CHAR LIMIT=NONE] -->
-    <string name="biometrics_unlock_title">You can unlock your phone using your face or fingerprint. For security, this option requires a backup screen lock.</string>
 
     <!-- Summary for "Configure lockscreen" when lock screen is off [CHAR LIMIT=45] -->
     <string name="unlock_set_unlock_mode_off">None</string>
@@ -2436,7 +2450,7 @@
     <!-- About phone, title of EID -->
     <string name="status_eid">EID</string>
     <!-- About phone, title of EID for multi-sim devices -->
-    <string name="eid_multi_sim">EID (sim slot %1$d)</string>
+    <string name="eid_multi_sim">EID (sim slot <xliff:g id="eid_slot_id">%1$d</xliff:g>)</string>
     <!-- About phone screen, title for IMEI for multi-sim devices -->
     <string name="imei_multi_sim">IMEI (sim slot %1$d)</string>
     <!-- About phone screen, summary of the MAC address [CHAR LIMIT=80] -->
@@ -5065,6 +5079,10 @@
     <string name="battery_not_usage_24hr">No usage for past 24 hr</string>
     <!-- Description for no usage time but have battery usage [CHAR LIMIT=120] -->
     <string name="battery_usage_without_time"></string>
+   <!-- Description for system apps aggregated battery usage data [CHAR LIMIT=120] -->
+    <string name="battery_usage_system_apps">System apps</string>
+    <!-- Description for others battery usage data [CHAR LIMIT=120] -->
+    <string name="battery_usage_others">Others</string>
 
     <!-- Description for battery time left, i.e. 50min Estimated time left. [CHAR LIMIT=80]-->
     <string name="estimated_time_left">Estimated time left</string>
@@ -5175,13 +5193,13 @@
     <!-- [CHAR_LIMIT=NONE] Accessibility content description for hourly battery chart view. -->
     <string name="hourly_battery_usage_chart">Hourly battery usage chart</string>
     <!-- [CHAR_LIMIT=NONE] Battery usage breakdown title since last full charge -->
-    <string name="battery_usage_breakdown_title_since_last_full_charge">Usage proportional breakdown since last full charge</string>
+    <string name="battery_usage_breakdown_title_since_last_full_charge">Battery usage since last full charge</string>
     <!-- [CHAR_LIMIT=NONE] Battery usage breakdown title for a selected slot -->
-    <string name="battery_usage_breakdown_title_for_slot">Usage proportional breakdown for <xliff:g id="slot">%s</xliff:g></string>
-    <!-- [CHAR_LIMIT=NONE] The tab title in the battery usage breakdown. -->
-    <string name="battery_usage_app_tab">App</string>
-    <!-- [CHAR_LIMIT=NONE] The tab title in the battery usage breakdown. -->
-    <string name="battery_usage_system_tab">System</string>
+    <string name="battery_usage_breakdown_title_for_slot">Battery usage for <xliff:g id="slot">%s</xliff:g></string>
+    <!-- [CHAR_LIMIT=NONE] The spinner item text in the battery usage breakdown. -->
+    <string name="battery_usage_spinner_breakdown_by_apps">Breakdown by apps</string>
+    <!-- [CHAR_LIMIT=NONE] The spinner item text in the battery usage breakdown. -->
+    <string name="battery_usage_spinner_breakdown_by_system">Breakdown by system</string>
     <!-- Process Stats strings -->
     <skip />
 
diff --git a/res/xml/power_usage_advanced.xml b/res/xml/power_usage_advanced.xml
index 4371995..af6152a 100644
--- a/res/xml/power_usage_advanced.xml
+++ b/res/xml/power_usage_advanced.xml
@@ -32,8 +32,8 @@
             "com.android.settings.fuelgauge.batteryusage.BatteryUsageBreakdownController"
         settings:isPreferenceVisible="false">
 
-        <com.android.settings.fuelgauge.batteryusage.TabPreference
-            android:key="battery_usage_tab"
+        <com.android.settings.fuelgauge.batteryusage.SpinnerPreference
+            android:key="battery_usage_spinner"
             settings:isPreferenceVisible="false" />
 
         <PreferenceCategory
diff --git a/res/xml/regional_preference_content_page.xml b/res/xml/regional_preference_content_page.xml
new file mode 100644
index 0000000..ed60eba
--- /dev/null
+++ b/res/xml/regional_preference_content_page.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2023 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.
+-->
+<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
+
+</PreferenceScreen>
\ No newline at end of file
diff --git a/src/com/android/settings/SettingsActivity.java b/src/com/android/settings/SettingsActivity.java
index c37b609..143c92d 100644
--- a/src/com/android/settings/SettingsActivity.java
+++ b/src/com/android/settings/SettingsActivity.java
@@ -572,6 +572,11 @@
     @VisibleForTesting
     void launchSettingFragment(String initialFragmentName, Intent intent) {
         if (initialFragmentName != null) {
+            if (SettingsActivityUtil.launchSpaActivity(this, initialFragmentName, intent)) {
+                finish();
+                return;
+            }
+
             setTitleFromIntent(intent);
 
             Bundle initialArguments = intent.getBundleExtra(EXTRA_SHOW_FRAGMENT_ARGUMENTS);
diff --git a/src/com/android/settings/SettingsActivityUtil.kt b/src/com/android/settings/SettingsActivityUtil.kt
new file mode 100644
index 0000000..cac341f
--- /dev/null
+++ b/src/com/android/settings/SettingsActivityUtil.kt
@@ -0,0 +1,82 @@
+/*
+ * 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
+
+import android.content.Context
+import android.content.Intent
+import android.util.FeatureFlagUtils
+import com.android.settings.applications.appinfo.AlarmsAndRemindersDetails
+import com.android.settings.applications.appinfo.DrawOverlayDetails
+import com.android.settings.applications.appinfo.ExternalSourcesDetails
+import com.android.settings.applications.appinfo.ManageExternalStorageDetails
+import com.android.settings.applications.appinfo.MediaManagementAppsDetails
+import com.android.settings.applications.appinfo.WriteSettingsDetails
+import com.android.settings.applications.specialaccess.pictureinpicture.PictureInPictureDetails
+import com.android.settings.applications.specialaccess.pictureinpicture.PictureInPictureSettings
+import com.android.settings.spa.SpaActivity.Companion.startSpaActivity
+import com.android.settings.spa.SpaActivity.Companion.startSpaActivityForApp
+import com.android.settings.spa.app.specialaccess.AlarmsAndRemindersAppListProvider
+import com.android.settings.spa.app.specialaccess.AllFilesAccessAppListProvider
+import com.android.settings.spa.app.specialaccess.DisplayOverOtherAppsAppListProvider
+import com.android.settings.spa.app.specialaccess.InstallUnknownAppsListProvider
+import com.android.settings.spa.app.specialaccess.MediaManagementAppsAppListProvider
+import com.android.settings.spa.app.specialaccess.ModifySystemSettingsAppListProvider
+import com.android.settings.spa.app.specialaccess.PictureInPictureListProvider
+import com.android.settings.spa.app.specialaccess.WifiControlAppListProvider
+import com.android.settings.wifi.ChangeWifiStateDetails
+
+object SettingsActivityUtil {
+    private val FRAGMENT_TO_SPA_DESTINATION_MAP = mapOf(
+        PictureInPictureSettings::class.qualifiedName to
+            PictureInPictureListProvider.getAppListRoute(),
+    )
+
+    private val FRAGMENT_TO_SPA_APP_DESTINATION_PREFIX_MAP = mapOf(
+        PictureInPictureDetails::class.qualifiedName to
+            PictureInPictureListProvider.getAppInfoRoutePrefix(),
+        DrawOverlayDetails::class.qualifiedName to
+            DisplayOverOtherAppsAppListProvider.getAppInfoRoutePrefix(),
+        WriteSettingsDetails::class.qualifiedName to
+            ModifySystemSettingsAppListProvider.getAppInfoRoutePrefix(),
+        AlarmsAndRemindersDetails::class.qualifiedName to
+            AlarmsAndRemindersAppListProvider.getAppInfoRoutePrefix(),
+        ExternalSourcesDetails::class.qualifiedName to
+            InstallUnknownAppsListProvider.getAppInfoRoutePrefix(),
+        ManageExternalStorageDetails::class.qualifiedName to
+            AllFilesAccessAppListProvider.getAppInfoRoutePrefix(),
+        MediaManagementAppsDetails::class.qualifiedName to
+            MediaManagementAppsAppListProvider.getAppInfoRoutePrefix(),
+        ChangeWifiStateDetails::class.qualifiedName to
+            WifiControlAppListProvider.getAppInfoRoutePrefix(),
+    )
+
+    @JvmStatic
+    fun Context.launchSpaActivity(fragmentName: String, intent: Intent): Boolean {
+        if (!FeatureFlagUtils.isEnabled(this, FeatureFlagUtils.SETTINGS_ENABLE_SPA)) {
+            return false
+        }
+        FRAGMENT_TO_SPA_DESTINATION_MAP[fragmentName]?.let { destination ->
+            startSpaActivity(destination)
+            return true
+        }
+        FRAGMENT_TO_SPA_APP_DESTINATION_PREFIX_MAP[fragmentName]?.let { appDestinationPrefix ->
+            startSpaActivityForApp(appDestinationPrefix, intent)
+            return true
+        }
+        return false
+    }
+}
diff --git a/src/com/android/settings/applications/appinfo/AppInfoDashboardFragment.java b/src/com/android/settings/applications/appinfo/AppInfoDashboardFragment.java
index 4a00260..06b25d6 100644
--- a/src/com/android/settings/applications/appinfo/AppInfoDashboardFragment.java
+++ b/src/com/android/settings/applications/appinfo/AppInfoDashboardFragment.java
@@ -415,7 +415,13 @@
             return;
         }
         super.onPrepareOptionsMenu(menu);
-        menu.findItem(UNINSTALL_ALL_USERS_MENU).setVisible(shouldShowUninstallForAll(mAppEntry));
+        final MenuItem uninstallAllUsersItem = menu.findItem(UNINSTALL_ALL_USERS_MENU);
+        uninstallAllUsersItem.setVisible(
+                shouldShowUninstallForAll(mAppEntry) && !mAppsControlDisallowedBySystem);
+        if (uninstallAllUsersItem.isVisible()) {
+            RestrictedLockUtilsInternal.setMenuItemAsDisabledByAdmin(getActivity(),
+                    uninstallAllUsersItem, mAppsControlDisallowedAdmin);
+        }
         menu.findItem(ACCESS_RESTRICTED_SETTINGS).setVisible(shouldShowAccessRestrictedSettings());
         mUpdatedSysApp = (mAppEntry.info.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0;
         final MenuItem uninstallUpdatesItem = menu.findItem(UNINSTALL_UPDATES);
diff --git a/src/com/android/settings/applications/manageapplications/ManageApplicationsUtil.kt b/src/com/android/settings/applications/manageapplications/ManageApplicationsUtil.kt
index c869fc5..8c4c41d 100644
--- a/src/com/android/settings/applications/manageapplications/ManageApplicationsUtil.kt
+++ b/src/com/android/settings/applications/manageapplications/ManageApplicationsUtil.kt
@@ -59,6 +59,7 @@
 import com.android.settings.spa.app.specialaccess.InstallUnknownAppsListProvider
 import com.android.settings.spa.app.specialaccess.MediaManagementAppsAppListProvider
 import com.android.settings.spa.app.specialaccess.ModifySystemSettingsAppListProvider
+import com.android.settings.spa.app.specialaccess.WifiControlAppListProvider
 import com.android.settings.spa.notification.AppListNotificationsPageProvider
 import com.android.settings.spa.system.AppLanguagesPageProvider
 
@@ -101,6 +102,7 @@
             LIST_MANAGE_EXTERNAL_STORAGE -> AllFilesAccessAppListProvider.getAppListRoute()
             LIST_TYPE_MEDIA_MANAGEMENT_APPS -> MediaManagementAppsAppListProvider.getAppListRoute()
             LIST_TYPE_ALARMS_AND_REMINDERS -> AlarmsAndRemindersAppListProvider.getAppListRoute()
+            LIST_TYPE_WIFI_ACCESS -> WifiControlAppListProvider.getAppListRoute()
             LIST_TYPE_NOTIFICATION -> AppListNotificationsPageProvider.name
             LIST_TYPE_APPS_LOCALE -> AppLanguagesPageProvider.name
             LIST_TYPE_MAIN -> AllAppListPageProvider.name
diff --git a/src/com/android/settings/applications/specialaccess/pictureinpicture/PictureInPictureSettings.java b/src/com/android/settings/applications/specialaccess/pictureinpicture/PictureInPictureSettings.java
index 034230e..d794de6 100644
--- a/src/com/android/settings/applications/specialaccess/pictureinpicture/PictureInPictureSettings.java
+++ b/src/com/android/settings/applications/specialaccess/pictureinpicture/PictureInPictureSettings.java
@@ -28,7 +28,6 @@
 import android.os.Bundle;
 import android.os.UserHandle;
 import android.os.UserManager;
-import android.util.FeatureFlagUtils;
 import android.util.IconDrawableFactory;
 import android.util.Pair;
 import android.view.View;
@@ -41,8 +40,6 @@
 import com.android.settings.R;
 import com.android.settings.applications.AppInfoBase;
 import com.android.settings.search.BaseSearchIndexProvider;
-import com.android.settings.spa.SpaActivity;
-import com.android.settings.spa.app.specialaccess.PictureInPictureListProvider;
 import com.android.settings.widget.EmptyTextSettings;
 import com.android.settingslib.search.SearchIndexable;
 import com.android.settingslib.widget.AppPreference;
@@ -130,16 +127,6 @@
     }
 
     @Override
-    public void onAttach(Context context) {
-        super.onAttach(context);
-        if (FeatureFlagUtils.isEnabled(context, FeatureFlagUtils.SETTINGS_ENABLE_SPA)) {
-            SpaActivity.startSpaActivity(
-                    context, PictureInPictureListProvider.INSTANCE.getAppListRoute());
-            finish();
-        }
-    }
-
-    @Override
     public void onCreate(Bundle icicle) {
         super.onCreate(icicle);
 
diff --git a/src/com/android/settings/bluetooth/BluetoothLengthDeviceNameFilter.java b/src/com/android/settings/bluetooth/BluetoothLengthDeviceNameFilter.java
index cdf5310..e7d97f7 100644
--- a/src/com/android/settings/bluetooth/BluetoothLengthDeviceNameFilter.java
+++ b/src/com/android/settings/bluetooth/BluetoothLengthDeviceNameFilter.java
@@ -17,7 +17,7 @@
 package com.android.settings.bluetooth;
 
 /**
- * Filter to max the length of a Bluetotoh device name to 248 bytes, as defined by the spec.
+ * Filter to max the length of a Bluetooth device name to 248 bytes, as defined by the spec.
  */
 public class BluetoothLengthDeviceNameFilter extends Utf8ByteLengthFilter {
     private static final int BLUETOOTH_NAME_MAX_LENGTH_BYTES = 248;
diff --git a/src/com/android/settings/bluetooth/BluetoothPairingController.java b/src/com/android/settings/bluetooth/BluetoothPairingController.java
index a9e89e9..535e040 100644
--- a/src/com/android/settings/bluetooth/BluetoothPairingController.java
+++ b/src/com/android/settings/bluetooth/BluetoothPairingController.java
@@ -31,6 +31,7 @@
 import com.android.settings.R;
 import com.android.settings.bluetooth.BluetoothPairingDialogFragment.BluetoothPairingDialogListener;
 import com.android.settings.core.SettingsUIDeviceConfig;
+import com.android.settingslib.bluetooth.BluetoothUtils;
 import com.android.settingslib.bluetooth.CachedBluetoothDevice;
 import com.android.settingslib.bluetooth.LocalBluetoothManager;
 import com.android.settingslib.bluetooth.LocalBluetoothProfile;
@@ -238,8 +239,8 @@
             case BluetoothDevice.ACCESS_REJECTED:
                 return false;
             default:
-                if (mDevice.getBluetoothClass().getDeviceClass()
-                        == BluetoothClass.Device.AUDIO_VIDEO_HANDSFREE) {
+                if (BluetoothUtils.isDeviceClassMatched(
+                        mDevice, BluetoothClass.Device.AUDIO_VIDEO_HANDSFREE)) {
                     return BluetoothDevice.EXTRA_PAIRING_INITIATOR_FOREGROUND == mInitiator;
                 }
                 return false;
@@ -250,11 +251,12 @@
      * Update Phone book permission
      *
      */
-     public void  setContactSharingState() {
+     public void setContactSharingState() {
          final int permission = mDevice.getPhonebookAccessPermission();
          if (permission == BluetoothDevice.ACCESS_ALLOWED
-                 || (permission == BluetoothDevice.ACCESS_UNKNOWN && mDevice.getBluetoothClass().
-                        getDeviceClass() == BluetoothClass.Device.AUDIO_VIDEO_HANDSFREE)) {
+                 || (permission == BluetoothDevice.ACCESS_UNKNOWN
+                 && BluetoothUtils.isDeviceClassMatched(mDevice,
+                 BluetoothClass.Device.AUDIO_VIDEO_HANDSFREE))) {
              onCheckedChanged(null, true);
          } else {
              onCheckedChanged(null, false);
diff --git a/src/com/android/settings/fuelgauge/PowerUsageFeatureProvider.java b/src/com/android/settings/fuelgauge/PowerUsageFeatureProvider.java
index 676af2c..db9a8bd 100644
--- a/src/com/android/settings/fuelgauge/PowerUsageFeatureProvider.java
+++ b/src/com/android/settings/fuelgauge/PowerUsageFeatureProvider.java
@@ -22,6 +22,7 @@
 
 import com.android.settingslib.fuelgauge.Estimate;
 
+import java.util.List;
 import java.util.Set;
 
 /**
@@ -35,6 +36,11 @@
     boolean isBatteryUsageEnabled(Context context);
 
     /**
+     * Returns an allowlist of app names combined into the system-apps item
+     */
+    List<String> getSystemAppsAllowlist(Context context);
+
+    /**
      * Check whether location setting is enabled
      */
     boolean isLocationSettingEnabled(String[] packages);
@@ -127,6 +133,11 @@
     Intent getResumeChargeIntent(boolean isDockDefender);
 
     /**
+     * Returns {@link Set} for the system component ids which are combined into others.
+     */
+    Set<Integer> getOthersSystemComponentSet(Context context);
+
+    /**
      * Returns {@link Set} for hiding system component ids in the usage screen.
      */
     Set<Integer> getHideSystemComponentSet(Context context);
diff --git a/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImpl.java b/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImpl.java
index 6e4ff95..06cb8be 100644
--- a/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImpl.java
+++ b/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImpl.java
@@ -26,6 +26,7 @@
 import com.android.internal.util.ArrayUtils;
 import com.android.settingslib.fuelgauge.Estimate;
 
+import java.util.List;
 import java.util.Set;
 
 /** Implementation of {@code PowerUsageFeatureProvider} */
@@ -71,6 +72,11 @@
     }
 
     @Override
+    public List<String> getSystemAppsAllowlist(Context context) {
+        return null;
+    }
+
+    @Override
     public boolean isLocationSettingEnabled(String[] packages) {
         return false;
     }
@@ -147,6 +153,11 @@
     }
 
     @Override
+    public Set<Integer> getOthersSystemComponentSet(Context context) {
+        return new ArraySet<>();
+    }
+
+    @Override
     public Set<Integer> getHideSystemComponentSet(Context context) {
         return new ArraySet<>();
     }
diff --git a/src/com/android/settings/fuelgauge/batteryusage/BatteryDiffEntry.java b/src/com/android/settings/fuelgauge/batteryusage/BatteryDiffEntry.java
index 2c23bb3..9e0c6d7 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/BatteryDiffEntry.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/BatteryDiffEntry.java
@@ -15,12 +15,12 @@
  */
 package com.android.settings.fuelgauge.batteryusage;
 
+import android.content.ContentValues;
 import android.content.Context;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.graphics.drawable.Drawable;
-import android.os.Process;
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.util.Log;
@@ -62,10 +62,10 @@
     // A BatteryHistEntry corresponding to this diff usage data.
     public final BatteryHistEntry mBatteryHistEntry;
 
+    protected Context mContext;
+
     private double mTotalConsumePower;
     private double mPercentOfTotal;
-
-    private Context mContext;
     private UserManager mUserManager;
     private String mDefaultPackageName = null;
 
@@ -111,6 +111,11 @@
                 ? 0 : (mConsumePower / mTotalConsumePower) * 100.0;
     }
 
+    /** Gets the total consumed power in a specific time slot. */
+    public double getTotalConsumePower() {
+        return mTotalConsumePower;
+    }
+
     /** Gets the percentage of total consumed power. */
     public double getPercentOfTotal() {
         return mPercentOfTotal;
@@ -176,23 +181,17 @@
 
     /** Whether the current BatteryDiffEntry is system component or not. */
     public boolean isSystemEntry() {
+        if (mBatteryHistEntry.mIsHidden) {
+            return false;
+        }
         switch (mBatteryHistEntry.mConsumerType) {
             case ConvertUtils.CONSUMER_TYPE_USER_BATTERY:
             case ConvertUtils.CONSUMER_TYPE_SYSTEM_BATTERY:
                 return true;
             case ConvertUtils.CONSUMER_TYPE_UID_BATTERY:
-                final int uid = (int) mBatteryHistEntry.mUid;
-                if (mBatteryHistEntry.mIsHidden
-                        || uid == BatteryUtils.UID_REMOVED_APPS
-                        || uid == BatteryUtils.UID_TETHERING) {
-                    return true;
-                }
-                final boolean combineSystemComponents =
-                        mContext.getResources().getBoolean(
-                                R.bool.config_battery_combine_system_components);
-                return combineSystemComponents && isSystemUid(uid);
+            default:
+                return false;
         }
-        return false;
     }
 
     void loadLabelAndIcon() {
@@ -396,8 +395,85 @@
                 mUserManager.getBadgedIconForUser(icon, new UserHandle(userId));
     }
 
-    private static boolean isSystemUid(int uid) {
-        final int appUid = UserHandle.getAppId(uid);
-        return appUid >= Process.SYSTEM_UID && appUid < Process.FIRST_APPLICATION_UID;
+    /** Specific battery diff entry for system apps. */
+    static class SystemAppsBatteryDiffEntry extends BatteryDiffEntry {
+        SystemAppsBatteryDiffEntry(Context context) {
+            super(context,
+                    /*foregroundUsageTimeInMs=*/ 0,
+                    /*backgroundUsageTimeInMs=*/ 0,
+                    /*screenOnTimeInMs=*/ 0,
+                    /*consumePower=*/ 0,
+                    /*foregroundUsageConsumePower=*/ 0,
+                    /*foregroundServiceUsageConsumePower=*/ 0,
+                    /*backgroundUsageConsumePower=*/ 0,
+                    /*cachedUsageConsumePower=*/ 0,
+                    new BatteryHistEntry(new ContentValues()));
+        }
+
+        @Override
+        public String getKey() {
+            return "A|SystemApps";
+        }
+
+        @Override
+        public String getAppLabel() {
+            return mContext.getString(R.string.battery_usage_system_apps);
+        }
+
+        @Override
+        public Drawable getAppIcon() {
+            return mContext.getDrawable(R.drawable.ic_power_system);
+        }
+
+        @Override
+        public boolean validForRestriction() {
+            return false;
+        }
+
+        @Override
+        public boolean isSystemEntry() {
+            return false;
+        }
+    }
+
+    /** Specific battery diff entry for others. */
+    static class OthersBatteryDiffEntry extends BatteryDiffEntry {
+        OthersBatteryDiffEntry(Context context) {
+            super(context,
+                    /*foregroundUsageTimeInMs=*/ 0,
+                    /*backgroundUsageTimeInMs=*/ 0,
+                    /*screenOnTimeInMs=*/ 0,
+                    /*consumePower=*/ 0,
+                    /*foregroundUsageConsumePower=*/ 0,
+                    /*foregroundServiceUsageConsumePower=*/ 0,
+                    /*backgroundUsageConsumePower=*/ 0,
+                    /*cachedUsageConsumePower=*/ 0,
+                    new BatteryHistEntry(new ContentValues()));
+        }
+
+        @Override
+        public String getKey() {
+            return "S|Others";
+        }
+
+        @Override
+        public String getAppLabel() {
+            return mContext.getString(R.string.battery_usage_others);
+        }
+
+        @Override
+        public Drawable getAppIcon() {
+            return mContext.getDrawable(R.drawable.ic_settings_ethernet);
+        }
+
+        @Override
+        public boolean validForRestriction() {
+            return false;
+        }
+
+        @Override
+        public boolean isSystemEntry() {
+            return true;
+        }
     }
 }
diff --git a/src/com/android/settings/fuelgauge/batteryusage/BatteryEntry.java b/src/com/android/settings/fuelgauge/batteryusage/BatteryEntry.java
index ba1ebab..acf62c2 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/BatteryEntry.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/BatteryEntry.java
@@ -200,11 +200,11 @@
 
     /** Battery entry for a power component of AggregateBatteryConsumer */
     public BatteryEntry(Context context, int powerComponentId, double devicePowerMah,
-            long usageDurationMs) {
+            long usageDurationMs, boolean isHidden) {
         mContext = context;
         mBatteryConsumer = null;
         mUid = Process.INVALID_UID;
-        mIsHidden = false;
+        mIsHidden = isHidden;
         mPowerComponentId = powerComponentId;
         mConsumedPower = devicePowerMah;
         mUsageDurationMs = usageDurationMs;
diff --git a/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBreakdownController.java b/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBreakdownController.java
index 1452b54..10cfd39 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBreakdownController.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBreakdownController.java
@@ -24,12 +24,13 @@
 import android.text.TextUtils;
 import android.text.format.DateUtils;
 import android.util.Log;
+import android.view.View;
+import android.widget.AdapterView;
 
 import androidx.preference.Preference;
 import androidx.preference.PreferenceCategory;
 import androidx.preference.PreferenceGroup;
 import androidx.preference.PreferenceScreen;
-import androidx.viewpager2.widget.ViewPager2;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.settings.R;
@@ -55,7 +56,7 @@
     private static final String TAG = "BatteryUsageBreakdownController";
     private static final String ROOT_PREFERENCE_KEY = "battery_usage_breakdown";
     private static final String FOOTER_PREFERENCE_KEY = "battery_usage_footer";
-    private static final String TAB_PREFERENCE_KEY = "battery_usage_tab";
+    private static final String SPINNER_PREFERENCE_KEY = "battery_usage_spinner";
     private static final String APP_LIST_PREFERENCE_KEY = "app_list";
     private static final String PACKAGE_NAME_NONE = "none";
     private static final int ENABLED_ICON_ALPHA = 255;
@@ -69,7 +70,7 @@
     @VisibleForTesting
     final Map<String, Preference> mPreferenceCache = new HashMap<>();
 
-    private int mTabPosition;
+    private int mSpinnerPosition;
     private String mSlotTimestamp;
 
     @VisibleForTesting
@@ -77,7 +78,7 @@
     @VisibleForTesting
     PreferenceCategory mRootPreference;
     @VisibleForTesting
-    TabPreference mTabPreference;
+    SpinnerPreference mSpinnerPreference;
     @VisibleForTesting
     PreferenceGroup mAppListPreferenceGroup;
     @VisibleForTesting
@@ -145,26 +146,33 @@
         super.displayPreference(screen);
         mPrefContext = screen.getContext();
         mRootPreference = screen.findPreference(ROOT_PREFERENCE_KEY);
-        mTabPreference = screen.findPreference(TAB_PREFERENCE_KEY);
+        mSpinnerPreference = screen.findPreference(SPINNER_PREFERENCE_KEY);
         mAppListPreferenceGroup = screen.findPreference(APP_LIST_PREFERENCE_KEY);
         mFooterPreference = screen.findPreference(FOOTER_PREFERENCE_KEY);
 
         mAppListPreferenceGroup.setOrderingAsAdded(false);
-        mTabPreference.initializeTabs(mFragment, new String[]{
-                mPrefContext.getString(R.string.battery_usage_app_tab),
-                mPrefContext.getString(R.string.battery_usage_system_tab)
-        });
-        mTabPreference.setOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() {
-            @Override
-            public void onPageSelected(int position) {
-                super.onPageSelected(position);
-                mTabPosition = position;
-                mHandler.post(() -> {
-                    removeAndCacheAllPreferences();
-                    addAllPreferences();
+        mSpinnerPreference.initializeSpinner(
+                new String[]{
+                        mPrefContext.getString(R.string.battery_usage_spinner_breakdown_by_apps),
+                        mPrefContext.getString(R.string.battery_usage_spinner_breakdown_by_system)
+                },
+                new AdapterView.OnItemSelectedListener() {
+                    @Override
+                    public void onItemSelected(
+                            AdapterView<?> parent, View view, int position, long id) {
+                        if (mSpinnerPosition != position) {
+                            mSpinnerPosition = position;
+                            mHandler.post(() -> {
+                                removeAndCacheAllPreferences();
+                                addAllPreferences();
+                            });
+                        }
+                    }
+
+                    @Override
+                    public void onNothingSelected(AdapterView<?> parent) {
+                    }
                 });
-            }
-        });
     }
 
     /**
@@ -182,7 +190,7 @@
         mSlotTimestamp = slotTimestamp;
 
         showCategoryTitle(slotTimestamp);
-        showTabAndAppList();
+        showSpinnerAndAppList();
         showFooterPreference(isAllUsageDataEmpty);
     }
 
@@ -204,12 +212,12 @@
         mFooterPreference.setVisible(true);
     }
 
-    private void showTabAndAppList() {
+    private void showSpinnerAndAppList() {
         removeAndCacheAllPreferences();
         if (mBatteryDiffData == null) {
             return;
         }
-        mTabPreference.setVisible(true);
+        mSpinnerPreference.setVisible(true);
         mAppListPreferenceGroup.setVisible(true);
         mHandler.post(() -> {
             addAllPreferences();
@@ -222,7 +230,7 @@
             return;
         }
         final long start = System.currentTimeMillis();
-        final List<BatteryDiffEntry> entries = mTabPosition == 0
+        final List<BatteryDiffEntry> entries = mSpinnerPosition == 0
                 ? mBatteryDiffData.getAppDiffEntryList()
                 : mBatteryDiffData.getSystemDiffEntryList();
         int prefIndex = mAppListPreferenceGroup.getPreferenceCount();
@@ -234,7 +242,7 @@
                 Log.w(TAG, "cannot find app resource for:" + entry.getPackageName());
                 continue;
             }
-            final String prefKey = entry.mBatteryHistEntry.getKey();
+            final String prefKey = entry.getKey();
             PowerGaugePreference pref = mAppListPreferenceGroup.findPreference(prefKey);
             if (pref != null) {
                 isAdded = true;
diff --git a/src/com/android/settings/fuelgauge/batteryusage/DataProcessor.java b/src/com/android/settings/fuelgauge/batteryusage/DataProcessor.java
index ff52774..649adbe 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/DataProcessor.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/DataProcessor.java
@@ -19,6 +19,7 @@
 import static com.android.settings.fuelgauge.batteryusage.ConvertUtils.getEffectivePackageName;
 import static com.android.settings.fuelgauge.batteryusage.ConvertUtils.utcToLocalTime;
 
+import android.app.Application;
 import android.app.usage.IUsageStatsManager;
 import android.app.usage.UsageEvents;
 import android.app.usage.UsageEvents.Event;
@@ -52,6 +53,7 @@
 import com.android.settings.Utils;
 import com.android.settings.fuelgauge.BatteryUtils;
 import com.android.settings.overlay.FeatureFactory;
+import com.android.settingslib.applications.ApplicationsState;
 import com.android.settingslib.fuelgauge.BatteryStatus;
 
 import java.time.Duration;
@@ -75,6 +77,8 @@
 public final class DataProcessor {
     private static final boolean DEBUG = false;
     private static final String TAG = "DataProcessor";
+    private static final int POWER_COMPONENT_SYSTEM_SERVICES = 7;
+    private static final int POWER_COMPONENT_WAKELOCK = 12;
     private static final int MIN_AVERAGE_POWER_THRESHOLD_MILLI_AMP = 10;
     private static final int MIN_DAILY_DATA_SIZE = 2;
     private static final int MIN_TIMESTAMP_DATA_SIZE = 2;
@@ -1448,6 +1452,9 @@
 
         // Calculates all packages diff usage data in a specific time slot.
         for (String key : allBatteryHistEntryKeys) {
+            if (key == null) {
+                continue;
+            }
             final BatteryHistEntry currentEntry =
                     currentBatteryHistMap.getOrDefault(key, EMPTY_BATTERY_HIST_ENTRY);
             final BatteryHistEntry nextEntry =
@@ -1711,6 +1718,8 @@
                         hideBackgroundUsageTimeSet);
                 batteryDiffData.setTotalConsumePower();
                 batteryDiffData.sortEntries();
+                combineIntoSystemApps(context, batteryDiffData);
+                combineSystemItemsIntoOthers(context, batteryDiffData);
             });
         });
     }
@@ -1736,6 +1745,91 @@
         }
     }
 
+    private static void combineSystemItemsIntoOthers(
+            final Context context, final BatteryDiffData batteryDiffData) {
+        final Set<Integer> othersSystemComponentSet =
+                FeatureFactory.getFactory(context)
+                        .getPowerUsageFeatureProvider(context)
+                        .getOthersSystemComponentSet(context);
+
+        BatteryDiffEntry.OthersBatteryDiffEntry othersDiffEntry = null;
+        final Iterator<BatteryDiffEntry> systemListIterator =
+                batteryDiffData.getSystemDiffEntryList().iterator();
+        while (systemListIterator.hasNext()) {
+            final BatteryDiffEntry batteryDiffEntry = systemListIterator.next();
+            if (othersSystemComponentSet.contains(batteryDiffEntry.mBatteryHistEntry.mDrainType)) {
+                if (othersDiffEntry == null) {
+                    othersDiffEntry = new BatteryDiffEntry.OthersBatteryDiffEntry(context);
+                }
+                othersDiffEntry.mConsumePower += batteryDiffEntry.mConsumePower;
+                othersDiffEntry.setTotalConsumePower(
+                        batteryDiffEntry.getTotalConsumePower());
+                systemListIterator.remove();
+            }
+        }
+        if (othersDiffEntry != null) {
+            batteryDiffData.getSystemDiffEntryList().add(othersDiffEntry);
+        }
+    }
+
+    private static void combineIntoSystemApps(
+            final Context context, final BatteryDiffData batteryDiffData) {
+        final List<String> systemAppsAllowlist =
+                FeatureFactory.getFactory(context)
+                        .getPowerUsageFeatureProvider(context)
+                        .getSystemAppsAllowlist(context);
+        final Application application = (Application) context.getApplicationContext();
+        final ApplicationsState applicationsState =
+                application == null ? null : ApplicationsState.getInstance(application);
+
+        BatteryDiffEntry.SystemAppsBatteryDiffEntry systemAppsDiffEntry = null;
+        final Iterator<BatteryDiffEntry> appListIterator =
+                batteryDiffData.getAppDiffEntryList().iterator();
+        while (appListIterator.hasNext()) {
+            final BatteryDiffEntry batteryDiffEntry = appListIterator.next();
+            if (needsCombineInSystemApp(batteryDiffEntry, systemAppsAllowlist, applicationsState)) {
+                if (systemAppsDiffEntry == null) {
+                    systemAppsDiffEntry = new BatteryDiffEntry.SystemAppsBatteryDiffEntry(context);
+                }
+                systemAppsDiffEntry.mConsumePower += batteryDiffEntry.mConsumePower;
+                systemAppsDiffEntry.setTotalConsumePower(
+                        batteryDiffEntry.getTotalConsumePower());
+                appListIterator.remove();
+            }
+        }
+        if (systemAppsDiffEntry != null) {
+            batteryDiffData.getAppDiffEntryList().add(systemAppsDiffEntry);
+        }
+    }
+
+    @VisibleForTesting
+    static boolean needsCombineInSystemApp(final BatteryDiffEntry batteryDiffEntry,
+            final List<String> systemAppsAllowlist, final ApplicationsState applicationsState) {
+        if (batteryDiffEntry.mBatteryHistEntry.mIsHidden) {
+            return true;
+        }
+
+        final String packageName = batteryDiffEntry.getPackageName();
+        if (packageName == null || packageName.isEmpty()) {
+            return false;
+        }
+
+        if (systemAppsAllowlist != null && systemAppsAllowlist.contains(packageName)) {
+            return true;
+        }
+
+        if (applicationsState == null) {
+            return false;
+        }
+        final ApplicationsState.AppEntry appEntry =
+                applicationsState.getEntry(packageName, /* userId= */ 0);
+        if (appEntry == null || appEntry.info == null) {
+            return false;
+        }
+        return !ApplicationsState.FILTER_DOWNLOADED_AND_LAUNCHER_AND_INSTANT.filterApp(
+                appEntry);
+    }
+
     private static boolean shouldShowBatteryAttributionList(final Context context) {
         final PowerProfile powerProfile = new PowerProfile(context);
         // Cheap hack to try to figure out if the power_profile.xml was populated.
@@ -1801,7 +1895,9 @@
                 componentId++) {
             results.add(new BatteryEntry(context, componentId,
                     deviceConsumer.getConsumedPower(componentId),
-                    deviceConsumer.getUsageDurationMillis(componentId)));
+                    deviceConsumer.getUsageDurationMillis(componentId),
+                    componentId == POWER_COMPONENT_SYSTEM_SERVICES
+                            || componentId == POWER_COMPONENT_WAKELOCK));
         }
 
         for (int componentId = BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID;
diff --git a/src/com/android/settings/fuelgauge/batteryusage/SpinnerPreference.java b/src/com/android/settings/fuelgauge/batteryusage/SpinnerPreference.java
new file mode 100644
index 0000000..47e051c
--- /dev/null
+++ b/src/com/android/settings/fuelgauge/batteryusage/SpinnerPreference.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2023 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.fuelgauge.batteryusage;
+
+import android.content.Context;
+import android.os.Parcelable;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.widget.AdapterView;
+import android.widget.Spinner;
+
+import androidx.preference.Preference;
+import androidx.preference.PreferenceViewHolder;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.settings.R;
+import com.android.settingslib.widget.SettingsSpinnerAdapter;
+
+/** A preference which contains a spinner. */
+public class SpinnerPreference extends Preference {
+    private static final String TAG = "SpinnerPreference";
+
+    private AdapterView.OnItemSelectedListener mOnItemSelectedListener;
+
+    @VisibleForTesting
+    Spinner mSpinner;
+    @VisibleForTesting
+    String[] mItems;
+    @VisibleForTesting
+    int mSavedSpinnerPosition;
+
+    public SpinnerPreference(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        setLayoutResource(R.layout.preference_spinner);
+    }
+
+    void initializeSpinner(
+            String[] items, AdapterView.OnItemSelectedListener onItemSelectedListener) {
+        mItems = items;
+        mOnItemSelectedListener = onItemSelectedListener;
+    }
+
+    @Override
+    public void onBindViewHolder(PreferenceViewHolder view) {
+        mSpinner = (Spinner) view.findViewById(R.id.spinner);
+        mSpinner.setAdapter(new SpinnerAdapter(getContext(), mItems));
+        mSpinner.setSelection(mSavedSpinnerPosition);
+        if (mOnItemSelectedListener != null) {
+            mSpinner.setOnItemSelectedListener(mOnItemSelectedListener);
+        }
+    }
+
+    @Override
+    protected Parcelable onSaveInstanceState() {
+        Log.d(TAG, "onSaveInstanceState() spinnerPosition=" + mSpinner.getSelectedItemPosition());
+        return new SavedState(super.onSaveInstanceState(), mSpinner.getSelectedItemPosition());
+    }
+
+    @Override
+    protected void onRestoreInstanceState(Parcelable state) {
+        if (state == null || !state.getClass().equals(SavedState.class)) {
+            super.onRestoreInstanceState(state);
+            return;
+        }
+        SavedState savedState = (SavedState) state;
+        super.onRestoreInstanceState(savedState.getSuperState());
+        mSavedSpinnerPosition = savedState.getSpinnerPosition();
+        if (mOnItemSelectedListener != null) {
+            mOnItemSelectedListener.onItemSelected(/* parent= */null, /* view= */null,
+                    savedState.getSpinnerPosition(), /* id= */ 0);
+        }
+        Log.d(TAG, "onRestoreInstanceState() spinnerPosition=" + savedState.getSpinnerPosition());
+    }
+
+    @VisibleForTesting
+    static class SavedState extends BaseSavedState {
+        private int mSpinnerPosition;
+
+        SavedState(Parcelable superState, int spinnerPosition) {
+            super(superState);
+            mSpinnerPosition = spinnerPosition;
+        }
+
+        int getSpinnerPosition() {
+            return mSpinnerPosition;
+        }
+    }
+
+    private static class SpinnerAdapter extends SettingsSpinnerAdapter<CharSequence> {
+        private final String[] mItems;
+
+        SpinnerAdapter(Context context, String[] items) {
+            super(context);
+            mItems = items;
+        }
+
+        @Override
+        public int getCount() {
+            return mItems.length;
+        }
+
+        @Override
+        public CharSequence getItem(int position) {
+            return mItems[position];
+        }
+    }
+}
diff --git a/src/com/android/settings/fuelgauge/batteryusage/TabPreference.java b/src/com/android/settings/fuelgauge/batteryusage/TabPreference.java
deleted file mode 100644
index 0c5a699..0000000
--- a/src/com/android/settings/fuelgauge/batteryusage/TabPreference.java
+++ /dev/null
@@ -1,152 +0,0 @@
-/*
- * 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.fuelgauge.batteryusage;
-
-import android.content.Context;
-import android.os.Parcelable;
-import android.util.AttributeSet;
-import android.util.Log;
-
-import androidx.annotation.NonNull;
-import androidx.fragment.app.Fragment;
-import androidx.preference.Preference;
-import androidx.preference.PreferenceViewHolder;
-import androidx.viewpager2.adapter.FragmentStateAdapter;
-import androidx.viewpager2.widget.ViewPager2;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.settings.R;
-
-import com.google.android.material.tabs.TabLayout;
-import com.google.android.material.tabs.TabLayoutMediator;
-
-/** A preference which contains a tab selection. */
-public class TabPreference extends Preference {
-    private static final String TAG = "TabPreference";
-
-    private Fragment mRootFragment;
-    private ViewPager2 mViewPager;
-    private ViewPager2.OnPageChangeCallback mOnPageChangeCallback;
-
-    @VisibleForTesting
-    String[] mTabTitles;
-    @VisibleForTesting
-    int mSavedTabPosition;
-    @VisibleForTesting
-    TabLayout mTabLayout;
-
-    public TabPreference(Context context, AttributeSet attrs) {
-        super(context, attrs);
-        setLayoutResource(R.layout.preference_tab);
-    }
-
-    void initializeTabs(Fragment rootFragment, String[] tabTitles) {
-        mRootFragment = rootFragment;
-        mTabTitles = tabTitles;
-    }
-
-    void setOnPageChangeCallback(ViewPager2.OnPageChangeCallback callback) {
-        mOnPageChangeCallback = callback;
-    }
-
-    @Override
-    public void onBindViewHolder(PreferenceViewHolder view) {
-        super.onBindViewHolder(view);
-        if (mViewPager != null && mTabLayout != null) {
-            return;
-        }
-
-        mViewPager = (ViewPager2) view.findViewById(R.id.view_pager);
-        mViewPager.setAdapter(new FragmentAdapter(mRootFragment, mTabTitles.length));
-        mViewPager.setUserInputEnabled(false);
-        if (mOnPageChangeCallback != null) {
-            mViewPager.registerOnPageChangeCallback(mOnPageChangeCallback);
-        }
-
-        mTabLayout = (TabLayout) view.findViewById(R.id.tabs);
-        new TabLayoutMediator(
-                mTabLayout, mViewPager, /* autoRefresh= */ true, /* smoothScroll= */ false,
-                (tab, position) -> tab.setText(mTabTitles[position])).attach();
-        mTabLayout.getTabAt(mSavedTabPosition).select();
-    }
-
-    @Override
-    public void onDetached() {
-        super.onDetached();
-        if (mViewPager != null && mOnPageChangeCallback != null) {
-            mViewPager.unregisterOnPageChangeCallback(mOnPageChangeCallback);
-        }
-    }
-
-    @Override
-    protected Parcelable onSaveInstanceState() {
-        Log.d(TAG, "onSaveInstanceState() tabPosition=" + mTabLayout.getSelectedTabPosition());
-        return new SavedState(super.onSaveInstanceState(), mTabLayout.getSelectedTabPosition());
-    }
-
-    @Override
-    protected void onRestoreInstanceState(Parcelable state) {
-        if (state == null || !state.getClass().equals(SavedState.class)) {
-            super.onRestoreInstanceState(state);
-            return;
-        }
-        SavedState savedState = (SavedState) state;
-        super.onRestoreInstanceState(savedState.getSuperState());
-        mSavedTabPosition = savedState.getTabPosition();
-        Log.d(TAG, "onRestoreInstanceState() tabPosition=" + savedState.getTabPosition());
-    }
-
-    @VisibleForTesting
-    static class SavedState extends BaseSavedState {
-        private int mTabPosition;
-
-        SavedState(Parcelable superState, int tabPosition) {
-            super(superState);
-            mTabPosition = tabPosition;
-        }
-
-        int getTabPosition() {
-            return mTabPosition;
-        }
-    }
-
-    private static class FragmentAdapter extends FragmentStateAdapter {
-        private final int mItemCount;
-        private final Fragment[] mItemFragments;
-
-        FragmentAdapter(@NonNull Fragment rootFragment, int itemCount) {
-            super(rootFragment);
-            mItemCount = itemCount;
-            mItemFragments = new Fragment[mItemCount];
-            for (int i = 0; i < mItemCount; i++) {
-                // Empty tab pages.
-                mItemFragments[i] = new Fragment();
-            }
-        }
-
-        @NonNull
-        @Override
-        public Fragment createFragment(int position) {
-            return mItemFragments[position];
-        }
-
-        @Override
-        public int getItemCount() {
-            return mItemCount;
-        }
-    }
-}
diff --git a/src/com/android/settings/regionalpreferences/CalendarTypeController.java b/src/com/android/settings/regionalpreferences/CalendarTypeController.java
index ea59191..1a81e7f 100644
--- a/src/com/android/settings/regionalpreferences/CalendarTypeController.java
+++ b/src/com/android/settings/regionalpreferences/CalendarTypeController.java
@@ -16,11 +16,17 @@
 
 package com.android.settings.regionalpreferences;
 
+import android.app.settings.SettingsEnums;
 import android.content.Context;
+import android.os.Bundle;
 import android.provider.Settings;
+import android.text.TextUtils;
+import android.util.Log;
 
-import com.android.settings.R;
+import androidx.preference.Preference;
+
 import com.android.settings.core.BasePreferenceController;
+import com.android.settings.core.SubSettingLauncher;
 
 import java.util.Locale;
 
@@ -28,6 +34,7 @@
  * A controller for the entry of Calendar types' page
  */
 public class CalendarTypeController extends BasePreferenceController {
+    private static final String TAG = CalendarTypeController.class.getSimpleName();
     public CalendarTypeController(Context context, String preferenceKey) {
         super(context, preferenceKey);
     }
@@ -60,7 +67,26 @@
         if (result.isEmpty()) {
             result = LocalePreferences.getCalendarType(false);
         }
-        return result.isEmpty()
-                ? mContext.getString(R.string.default_string_of_regional_preference) : result;
+
+        String inputStr = result.isEmpty() ? RegionalPreferencesFragment.TYPE_DEFAULT : result;
+        return RegionalPreferencesDataUtils.calendarConverter(mContext, inputStr);
+    }
+
+    @Override
+    public boolean handlePreferenceTreeClick(Preference preference) {
+        if (!TextUtils.equals(preference.getKey(), mPreferenceKey)) {
+            Log.e(TAG, "not the key " + preference.getKey() + " / " + mPreferenceKey);
+            return false;
+        }
+
+        final Bundle extra = new Bundle();
+        extra.putString(RegionalPreferencesFragment.TYPE_OF_REGIONAL_PREFERENCE,
+                RegionalPreferencesFragment.TYPE_CALENDAR);
+        new SubSettingLauncher(preference.getContext())
+                .setDestination(RegionalPreferencesFragment.class.getName())
+                .setSourceMetricsCategory(SettingsEnums.REGIONAL_PREFERENCE)
+                .setArguments(extra)
+                .launch();
+        return true;
     }
 }
diff --git a/src/com/android/settings/regionalpreferences/FirstDayOfWeekController.java b/src/com/android/settings/regionalpreferences/FirstDayOfWeekController.java
index 3fb8a1e..22823d7 100644
--- a/src/com/android/settings/regionalpreferences/FirstDayOfWeekController.java
+++ b/src/com/android/settings/regionalpreferences/FirstDayOfWeekController.java
@@ -16,16 +16,25 @@
 
 package com.android.settings.regionalpreferences;
 
+import android.app.settings.SettingsEnums;
 import android.content.Context;
+import android.os.Bundle;
 import android.provider.Settings;
+import android.text.TextUtils;
+import android.util.Log;
+
+import androidx.preference.Preference;
 
 import com.android.settings.R;
 import com.android.settings.core.BasePreferenceController;
+import com.android.settings.core.SubSettingLauncher;
 
 import java.util.Locale;
 
 /** A controller for the entry of First Day of Week's page */
 public class FirstDayOfWeekController extends BasePreferenceController {
+    private static final String TAG = FirstDayOfWeekController.class.getSimpleName();
+
     public FirstDayOfWeekController(Context context, String preferenceKey) {
         super(context, preferenceKey);
     }
@@ -59,6 +68,25 @@
             result = LocalePreferences.getFirstDayOfWeek(false);
         }
         return result.isEmpty()
-                ? mContext.getString(R.string.default_string_of_regional_preference) : result;
+                ? mContext.getString(R.string.default_string_of_regional_preference)
+                : RegionalPreferencesDataUtils.dayConverter(mContext, result);
+    }
+
+    @Override
+    public boolean handlePreferenceTreeClick(Preference preference) {
+        if (!TextUtils.equals(preference.getKey(), mPreferenceKey)) {
+            Log.e(TAG, "not the key " + preference.getKey() + " / " + mPreferenceKey);
+            return false;
+        }
+
+        final Bundle extra = new Bundle();
+        extra.putString(RegionalPreferencesFragment.TYPE_OF_REGIONAL_PREFERENCE,
+                RegionalPreferencesFragment.TYPE_FIRST_DAY_OF_WEEK);
+        new SubSettingLauncher(preference.getContext())
+                .setDestination(RegionalPreferencesFragment.class.getName())
+                .setSourceMetricsCategory(SettingsEnums.REGIONAL_PREFERENCE)
+                .setArguments(extra)
+                .launch();
+        return true;
     }
 }
diff --git a/src/com/android/settings/regionalpreferences/NumberingSystemController.java b/src/com/android/settings/regionalpreferences/NumberingSystemController.java
index e951fc2..80a2250 100644
--- a/src/com/android/settings/regionalpreferences/NumberingSystemController.java
+++ b/src/com/android/settings/regionalpreferences/NumberingSystemController.java
@@ -16,18 +16,26 @@
 
 package com.android.settings.regionalpreferences;
 
+import android.app.settings.SettingsEnums;
 import android.content.Context;
 import android.icu.text.NumberingSystem;
+import android.os.Bundle;
 import android.provider.Settings;
 import android.text.TextUtils;
+import android.util.Log;
+
+import androidx.preference.Preference;
 
 import com.android.settings.R;
 import com.android.settings.core.BasePreferenceController;
+import com.android.settings.core.SubSettingLauncher;
 
 import java.util.Locale;
 
 /** A controller for the entry of Numbering System's page */
 public class NumberingSystemController extends BasePreferenceController {
+    private static final String TAG = NumberingSystemController.class.getSimpleName();
+
     private static final String UNICODE_EXTENSION_NUMBERING_SYSTEM = "nu";
 
     public NumberingSystemController(Context context, String preferenceKey) {
@@ -47,7 +55,8 @@
      */
     @Override
     public int getAvailabilityStatus() {
-        return AVAILABLE;
+        // Hide this , and waiting for next implementation.
+        return CONDITIONALLY_UNAVAILABLE;
     }
 
     @Override
@@ -73,4 +82,22 @@
                 .build();
         return NumberingSystem.getInstance(locale).getName();
     }
+
+    @Override
+    public boolean handlePreferenceTreeClick(Preference preference) {
+        if (!TextUtils.equals(preference.getKey(), mPreferenceKey)) {
+            Log.e(TAG, "not the key " + preference.getKey() + " / " + mPreferenceKey);
+            return false;
+        }
+
+        final Bundle extra = new Bundle();
+        extra.putString(RegionalPreferencesFragment.TYPE_OF_REGIONAL_PREFERENCE,
+                RegionalPreferencesFragment.TYPE_NUMBERING_SYSTEM);
+        new SubSettingLauncher(preference.getContext())
+                .setDestination(RegionalPreferencesFragment.class.getName())
+                .setSourceMetricsCategory(SettingsEnums.REGIONAL_PREFERENCE)
+                .setArguments(extra)
+                .launch();
+        return true;
+    }
 }
diff --git a/src/com/android/settings/regionalpreferences/RegionalPreferencesDataUtils.java b/src/com/android/settings/regionalpreferences/RegionalPreferencesDataUtils.java
new file mode 100644
index 0000000..25dc8e1
--- /dev/null
+++ b/src/com/android/settings/regionalpreferences/RegionalPreferencesDataUtils.java
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2023 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.regionalpreferences;
+
+import android.content.Context;
+import android.icu.util.ULocale;
+import android.os.LocaleList;
+import android.provider.Settings;
+import android.text.TextUtils;
+
+import com.android.internal.app.LocalePicker;
+import com.android.settings.R;
+
+import java.util.Locale;
+
+/** Provides utils for regional preferences. */
+public class RegionalPreferencesDataUtils {
+    private static final String TAG = RegionalPreferencesDataUtils.class.getSimpleName();
+
+    private static final String U_EXTENSION_FAHRENHEIT = "fahrenhe";
+    private static final String KEYWORD_OF_CALENDAR = "calendar";
+
+    static String getDefaultUnicodeExtensionData(Context contxt, String type) {
+        // 1. Check cache data in Settings provider.
+        String record = Settings.System.getString(
+                contxt.getContentResolver(), Settings.System.LOCALE_PREFERENCES);
+        String result = "";
+
+        if (!TextUtils.isEmpty(record)) {
+            result = Locale.forLanguageTag(record).getUnicodeLocaleType(type);
+        }
+        // 2. Check cache data in default Locale(ICU lib).
+        if (TextUtils.isEmpty(result)) {
+            result = Locale.getDefault(Locale.Category.FORMAT).getUnicodeLocaleType(type);
+        }
+        if (result == null) {
+            return RegionalPreferencesFragment.TYPE_DEFAULT;
+        }
+
+        // In BCP47 expression, the tag of fahrenheit is "fahrenhe" i.e. und-u-mu-fahrenhe,
+        // so if it may need to convert from the langngiage tag, "fahrenhe", to "fahrenheit".
+        if (result.equals(U_EXTENSION_FAHRENHEIT)) {
+            return LocalePreferences.TemperatureUnit.FAHRENHEIT;
+        }
+
+        return result;
+    }
+
+    static void savePreference(Context context, String type, String value) {
+        if (type.equals(RegionalPreferencesFragment.TYPE_TEMPERATURE)
+                && value != null && value.equals(LocalePreferences.TemperatureUnit.FAHRENHEIT)) {
+            // In BCP47 expression, the temperature unit is expressed to "fahrenhe"
+            // i.e. zh-TW-u-mu-fahrenhe. Hence, if we want to save fahrenheit unit to u extension,
+            // It need to change from "fahrenheit" to "fahrenhe".
+            value = U_EXTENSION_FAHRENHEIT;
+        }
+        saveToSettingsProvider(context, type, value);
+        saveToSystem(type, value);
+    }
+
+    private static void saveToSettingsProvider(Context context, String type, String value) {
+        String record = Settings.System.getString(
+                context.getContentResolver(), Settings.System.LOCALE_PREFERENCES);
+
+        record = record == null ? "" : record;
+
+        Settings.System.putString(
+                context.getContentResolver(),
+                Settings.System.LOCALE_PREFERENCES,
+                addUnicodeKeywordToLocale(record, type, value).toLanguageTag());
+    }
+
+    private static void saveToSystem(String type, String value) {
+        LocaleList localeList = LocaleList.getDefault();
+        Locale[] resultLocales = new Locale[localeList.size()];
+        for (int i = 0; i < localeList.size(); i++) {
+            resultLocales[i] = addUnicodeKeywordToLocale(localeList.get(i), type, value);
+        }
+        LocalePicker.updateLocales(new LocaleList(resultLocales));
+    }
+
+    private static Locale addUnicodeKeywordToLocale(Locale locale, String type, String value) {
+        return new Locale.Builder()
+                .setLocale(locale)
+                .setUnicodeLocaleKeyword(type, value)
+                .build();
+    }
+
+    private static Locale addUnicodeKeywordToLocale(String languageTag, String type, String value) {
+        return addUnicodeKeywordToLocale(Locale.forLanguageTag(languageTag), type, value);
+    }
+
+    static String calendarConverter(Context context, String calendarType) {
+        if (calendarType.equals(RegionalPreferencesFragment.TYPE_DEFAULT)) {
+            return context.getString(R.string.default_string_of_regional_preference);
+        }
+
+        Locale locale = new Locale.Builder()
+                .setUnicodeLocaleKeyword(RegionalPreferencesFragment.TYPE_CALENDAR, calendarType)
+                .build();
+        return ULocale.getDisplayKeywordValue(locale.toLanguageTag(), KEYWORD_OF_CALENDAR,
+                ULocale.forLocale(Locale.getDefault(Locale.Category.FORMAT)));
+    }
+
+    static String temperatureUnitsConverter(Context context, String unit) {
+        switch (unit) {
+            case LocalePreferences.TemperatureUnit.CELSIUS:
+                return context.getString(R.string.celsius_temperature_unit);
+            case LocalePreferences.TemperatureUnit.FAHRENHEIT:
+                return context.getString(R.string.fahrenheit_temperature_unit);
+            case LocalePreferences.TemperatureUnit.KELVIN:
+                return context.getString(R.string.kevin_temperature_unit);
+            default:
+                return context.getString(R.string.default_string_of_regional_preference);
+        }
+    }
+
+    static String dayConverter(Context context, String day) {
+        switch (day) {
+            case LocalePreferences.FirstDayOfWeek.MONDAY:
+                return context.getString(R.string.monday_first_day_of_week);
+            case LocalePreferences.FirstDayOfWeek.TUESDAY:
+                return context.getString(R.string.tuesday_first_day_of_week);
+            case LocalePreferences.FirstDayOfWeek.WEDNESDAY:
+                return context.getString(R.string.wednesday_first_day_of_week);
+            case LocalePreferences.FirstDayOfWeek.THURSDAY:
+                return context.getString(R.string.thursday_first_day_of_week);
+            case LocalePreferences.FirstDayOfWeek.FRIDAY:
+                return context.getString(R.string.friday_first_day_of_week);
+            case LocalePreferences.FirstDayOfWeek.SATURDAY:
+                return context.getString(R.string.saturday_first_day_of_week);
+            case LocalePreferences.FirstDayOfWeek.SUNDAY:
+                return context.getString(R.string.sunday_first_day_of_week);
+            default:
+                return context.getString(R.string.default_string_of_regional_preference);
+        }
+    }
+}
diff --git a/src/com/android/settings/regionalpreferences/RegionalPreferencesFragment.java b/src/com/android/settings/regionalpreferences/RegionalPreferencesFragment.java
new file mode 100644
index 0000000..aa06a43
--- /dev/null
+++ b/src/com/android/settings/regionalpreferences/RegionalPreferencesFragment.java
@@ -0,0 +1,150 @@
+/*
+ * Copyright (C) 2023 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.regionalpreferences;
+
+import android.app.settings.SettingsEnums;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import androidx.annotation.VisibleForTesting;
+import androidx.preference.Preference;
+import androidx.preference.PreferenceScreen;
+
+import com.android.settings.R;
+import com.android.settings.SettingsPreferenceFragment;
+
+/** A fragment to include each kind of regional preferences. */
+public class RegionalPreferencesFragment extends SettingsPreferenceFragment {
+    private static final String TAG = RegionalPreferencesFragment.class.getSimpleName();
+
+    static final String TYPE_DEFAULT = "default";
+    static final String TYPE_TEMPERATURE = "mu";
+    static final String TYPE_CALENDAR = "ca";
+    static final String TYPE_FIRST_DAY_OF_WEEK = "fw";
+    static final String TYPE_NUMBERING_SYSTEM = "nu";
+    static final String TYPE_OF_REGIONAL_PREFERENCE = "type_of_regional_preference";
+
+    private PreferenceScreen mPreferenceScreen;
+    private String mTitle = "";
+    @VisibleForTesting
+    String mType = "";
+
+    private String[] initializeUIdata(String type) {
+        switch(type) {
+            case TYPE_TEMPERATURE:
+                mTitle = getPrefContext().getString(R.string.temperature_preferences_title);
+                return getPrefContext().getResources().getStringArray(R.array.temperature_units);
+            case TYPE_CALENDAR:
+                mTitle = getPrefContext().getString(R.string.calendar_preferences_title);
+                return getPrefContext().getResources().getStringArray(R.array.calendar_type);
+            case TYPE_FIRST_DAY_OF_WEEK:
+                mTitle = getPrefContext().getString(R.string.first_day_of_week_preferences_title);
+                return getPrefContext().getResources().getStringArray(R.array.first_day_of_week);
+            case TYPE_NUMBERING_SYSTEM:
+                mTitle = getPrefContext().getString(R.string.numbers_preferences_title);
+                return new String[0];
+            default:
+                mTitle = getPrefContext().getString(R.string.regional_preferences_title);
+                return new String[0];
+        }
+    }
+
+    @Override
+    public boolean onPreferenceTreeClick(Preference preference) {
+        for (int i = 0; i < mPreferenceScreen.getPreferenceCount(); i++) {
+            TickButtonPreference pref = (TickButtonPreference) mPreferenceScreen.getPreference(i);
+            Log.i(TAG, "[onPreferenceClick] key is " + pref.getKey());
+            if (pref.getKey().equals(preference.getKey())) {
+                pref.setTickEnable(true);
+                RegionalPreferencesDataUtils.savePreference(
+                        getPrefContext(),
+                        mType,
+                        preference.getKey().equals(TYPE_DEFAULT) ? null : preference.getKey());
+                continue;
+            }
+            pref.setTickEnable(false);
+        }
+        return true;
+    }
+
+    @Override
+    public void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+        Bundle bundle = getArguments();
+        String type = bundle.getString(TYPE_OF_REGIONAL_PREFERENCE, "");
+        if (type.isEmpty()) {
+            Log.w(TAG, "There is no type name.");
+            finish();
+        }
+        mType = type;
+        addPreferencesFromResource(R.xml.regional_preference_content_page);
+        mPreferenceScreen = getPreferenceScreen();
+    }
+
+    @Override
+    public View onCreateView(LayoutInflater inflater, ViewGroup container,
+            Bundle savedInstanceState) {
+        View view = super.onCreateView(inflater, container, savedInstanceState);
+        String[] uiData = initializeUIdata(mType);
+
+        for (String item : uiData) {
+            TickButtonPreference pref = new TickButtonPreference(getPrefContext());
+            if (mType.equals(TYPE_FIRST_DAY_OF_WEEK)) {
+                pref.setTitle(RegionalPreferencesDataUtils.dayConverter(
+                        getPrefContext(), item));
+            } else if (mType.equals(TYPE_TEMPERATURE)) {
+                pref.setTitle(RegionalPreferencesDataUtils.temperatureUnitsConverter(
+                        getPrefContext(), item));
+            } else if (mType.equals(TYPE_CALENDAR)) {
+                pref.setTitle(RegionalPreferencesDataUtils.calendarConverter(
+                        getPrefContext(), item));
+            } else {
+                Log.d(TAG, "Finish this page due to no suitable type.");
+                finish();
+            }
+
+            String value = RegionalPreferencesDataUtils.getDefaultUnicodeExtensionData(
+                    getPrefContext(), mType);
+            pref.setKey(item);
+            pref.setTickEnable(!value.isEmpty() && item.equals(value));
+            mPreferenceScreen.addPreference(pref);
+        }
+        return view;
+    }
+
+    @Override
+    public void onStart() {
+        super.onStart();
+        getActivity().setTitle(mTitle);
+    }
+
+    @Override
+    public int getMetricsCategory() {
+        switch(mType) {
+            case TYPE_CALENDAR:
+                return SettingsEnums.CALENDAR_PREFERENCE;
+            case TYPE_FIRST_DAY_OF_WEEK:
+                return SettingsEnums.FIRST_DAY_OF_WEEK_PREFERENCE;
+            default:
+                return SettingsEnums.TEMPERATURE_PREFERENCE;
+        }
+    }
+
+}
diff --git a/src/com/android/settings/regionalpreferences/TemperatureUnitController.java b/src/com/android/settings/regionalpreferences/TemperatureUnitController.java
index b13b6c4..950d137 100644
--- a/src/com/android/settings/regionalpreferences/TemperatureUnitController.java
+++ b/src/com/android/settings/regionalpreferences/TemperatureUnitController.java
@@ -16,16 +16,24 @@
 
 package com.android.settings.regionalpreferences;
 
+import android.app.settings.SettingsEnums;
 import android.content.Context;
+import android.os.Bundle;
 import android.provider.Settings;
+import android.text.TextUtils;
+import android.util.Log;
+
+import androidx.preference.Preference;
 
 import com.android.settings.R;
 import com.android.settings.core.BasePreferenceController;
+import com.android.settings.core.SubSettingLauncher;
 
 import java.util.Locale;
 
 /** A controller for the entry of Temperature units' page */
 public class TemperatureUnitController extends BasePreferenceController {
+    private static final String TAG = TemperatureUnitController.class.getSimpleName();
     public TemperatureUnitController(Context context, String preferenceKey) {
         super(context, preferenceKey);
     }
@@ -58,7 +66,26 @@
         if (result.isEmpty()) {
             result = LocalePreferences.getTemperatureUnit(false);
         }
+
         return result.isEmpty()
-                ? mContext.getString(R.string.default_string_of_regional_preference) : result;
+                ? mContext.getString(R.string.default_string_of_regional_preference)
+                : RegionalPreferencesDataUtils.temperatureUnitsConverter(mContext, result);
+    }
+
+    @Override
+    public boolean handlePreferenceTreeClick(Preference preference) {
+        if (!TextUtils.equals(preference.getKey(), mPreferenceKey)) {
+            Log.e(TAG, "not the key " + preference.getKey() + " / " + mPreferenceKey);
+            return false;
+        }
+        final Bundle extra = new Bundle();
+        extra.putString(RegionalPreferencesFragment.TYPE_OF_REGIONAL_PREFERENCE,
+                RegionalPreferencesFragment.TYPE_TEMPERATURE);
+        new SubSettingLauncher(preference.getContext())
+                .setDestination(RegionalPreferencesFragment.class.getName())
+                .setSourceMetricsCategory(SettingsEnums.REGIONAL_PREFERENCE)
+                .setArguments(extra)
+                .launch();
+        return true;
     }
 }
diff --git a/src/com/android/settings/regionalpreferences/TickButtonPreference.java b/src/com/android/settings/regionalpreferences/TickButtonPreference.java
new file mode 100644
index 0000000..c01521f
--- /dev/null
+++ b/src/com/android/settings/regionalpreferences/TickButtonPreference.java
@@ -0,0 +1,69 @@
+/*
+ * 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.regionalpreferences;
+
+import android.content.Context;
+import android.view.View;
+
+import androidx.preference.PreferenceViewHolder;
+
+import com.android.settings.R;
+import com.android.settingslib.widget.TwoTargetPreference;
+
+/** A preference with tick button */
+public class TickButtonPreference extends TwoTargetPreference {
+    private static final String TAG = TickButtonPreference.class.getSimpleName();
+    private boolean mIsTickEnabled;
+    private View mWidgetFrame;
+    private View mDivider;
+
+    public TickButtonPreference(Context context) {
+        super(context, null);
+    }
+
+    /** Set this preference to be selected. */
+    public void setTickEnable(boolean isEnable) {
+        mIsTickEnabled = isEnable;
+        if (mWidgetFrame != null) {
+            mWidgetFrame.setVisibility(isEnable ? View.VISIBLE : View.INVISIBLE);
+        }
+    }
+
+    /** Check if this preference is selected. */
+    public boolean isTickEnabled() {
+        return mIsTickEnabled;
+    }
+
+    @Override
+    public void onBindViewHolder(PreferenceViewHolder holder) {
+        super.onBindViewHolder(holder);
+        mDivider = holder.findViewById(R.id.two_target_divider);
+        mWidgetFrame = holder.findViewById(android.R.id.widget_frame);
+        if (mDivider != null) {
+            mDivider.setVisibility(View.GONE);
+        }
+        if (mWidgetFrame != null) {
+            mWidgetFrame.setVisibility(mIsTickEnabled ? View.VISIBLE : View.INVISIBLE);
+        }
+    }
+
+    @Override
+    protected int getSecondTargetResId() {
+        super.getSecondTargetResId();
+        return R.layout.preference_widget_tick;
+    }
+}
diff --git a/src/com/android/settings/spa/SettingsSpaEnvironment.kt b/src/com/android/settings/spa/SettingsSpaEnvironment.kt
index 9eab400..6b22b9e 100644
--- a/src/com/android/settings/spa/SettingsSpaEnvironment.kt
+++ b/src/com/android/settings/spa/SettingsSpaEnvironment.kt
@@ -29,6 +29,7 @@
 import com.android.settings.spa.app.specialaccess.ModifySystemSettingsAppListProvider
 import com.android.settings.spa.app.specialaccess.PictureInPictureListProvider
 import com.android.settings.spa.app.specialaccess.SpecialAppAccessPageProvider
+import com.android.settings.spa.app.specialaccess.WifiControlAppListProvider
 import com.android.settings.spa.development.UsageStatsPageProvider
 import com.android.settings.spa.home.HomePageProvider
 import com.android.settings.spa.notification.AppListNotificationsPageProvider
@@ -43,17 +44,20 @@
 
 open class SettingsSpaEnvironment(context: Context) : SpaEnvironment(context) {
     override val pageProviderRepository = lazy {
-        val togglePermissionAppListTemplate = TogglePermissionAppListTemplate(
-            allProviders = listOf(
-                AllFilesAccessAppListProvider,
-                DisplayOverOtherAppsAppListProvider,
-                MediaManagementAppsAppListProvider,
-                ModifySystemSettingsAppListProvider,
-                PictureInPictureListProvider,
-                InstallUnknownAppsListProvider,
-                AlarmsAndRemindersAppListProvider,
-            ),
-        )
+        val togglePermissionAppListTemplate =
+            TogglePermissionAppListTemplate(
+                allProviders =
+                    listOf(
+                        AllFilesAccessAppListProvider,
+                        DisplayOverOtherAppsAppListProvider,
+                        MediaManagementAppsAppListProvider,
+                        ModifySystemSettingsAppListProvider,
+                        PictureInPictureListProvider,
+                        InstallUnknownAppsListProvider,
+                        AlarmsAndRemindersAppListProvider,
+                        WifiControlAppListProvider,
+                    ),
+            )
         SettingsPageProviderRepository(
             allPageProviders = listOf(
                 HomePageProvider,
diff --git a/src/com/android/settings/spa/app/AllAppList.kt b/src/com/android/settings/spa/app/AllAppList.kt
index 05f77ed..08b06a6 100644
--- a/src/com/android/settings/spa/app/AllAppList.kt
+++ b/src/com/android/settings/spa/app/AllAppList.kt
@@ -16,10 +16,12 @@
 
 package com.android.settings.spa.app
 
+import android.content.Context
 import android.content.pm.ApplicationInfo
 import android.os.Bundle
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.State
+import androidx.compose.runtime.derivedStateOf
 import androidx.compose.runtime.remember
 import androidx.compose.ui.res.stringResource
 import com.android.settings.R
@@ -28,9 +30,12 @@
 import com.android.settingslib.spa.framework.common.SettingsPage
 import com.android.settingslib.spa.framework.common.SettingsPageProvider
 import com.android.settingslib.spa.framework.compose.navigator
+import com.android.settingslib.spa.framework.compose.rememberContext
+import com.android.settingslib.spa.framework.util.filterItem
 import com.android.settingslib.spa.framework.util.mapItem
 import com.android.settingslib.spa.widget.preference.Preference
 import com.android.settingslib.spa.widget.preference.PreferenceModel
+import com.android.settingslib.spa.widget.ui.SpinnerOption
 import com.android.settingslib.spaprivileged.model.app.AppListModel
 import com.android.settingslib.spaprivileged.model.app.AppRecord
 import com.android.settingslib.spaprivileged.template.app.AppList
@@ -67,7 +72,7 @@
     val resetAppDialogPresenter = rememberResetAppDialogPresenter()
     AppListPage(
         title = stringResource(R.string.all_apps),
-        listModel = remember { AllAppListModel() },
+        listModel = rememberContext(::AllAppListModel),
         showInstantApps = true,
         moreOptions = { ResetAppPreferences(resetAppDialogPresenter::open) },
         appList = appList,
@@ -79,17 +84,71 @@
 ) : AppRecord
 
 class AllAppListModel(
-    private val getSummary: @Composable ApplicationInfo.() -> State<String> = { getStorageSize() },
+    private val context: Context,
+    private val getStorageSummary: @Composable ApplicationInfo.() -> State<String> = {
+        getStorageSize()
+    },
 ) : AppListModel<AppRecordWithSize> {
 
+    override fun getSpinnerOptions(recordList: List<AppRecordWithSize>): List<SpinnerOption> {
+        val hasDisabled = recordList.any(isDisabled)
+        val hasInstant = recordList.any(isInstant)
+        if (!hasDisabled && !hasInstant) return emptyList()
+        val options = mutableListOf(SpinnerItem.All, SpinnerItem.Enabled)
+        if (hasDisabled) options += SpinnerItem.Disabled
+        if (hasInstant) options += SpinnerItem.Instant
+        return options.map {
+            SpinnerOption(
+                id = it.ordinal,
+                text = context.getString(it.stringResId),
+            )
+        }
+    }
+
     override fun transform(userIdFlow: Flow<Int>, appListFlow: Flow<List<ApplicationInfo>>) =
         appListFlow.mapItem(::AppRecordWithSize)
 
+    override fun filter(
+        userIdFlow: Flow<Int>,
+        option: Int,
+        recordListFlow: Flow<List<AppRecordWithSize>>,
+    ): Flow<List<AppRecordWithSize>> = recordListFlow.filterItem(
+        when (SpinnerItem.values().getOrNull(option)) {
+            SpinnerItem.Enabled -> ({ it.app.enabled && !it.app.isInstantApp })
+            SpinnerItem.Disabled -> isDisabled
+            SpinnerItem.Instant -> isInstant
+            else -> ({ true })
+        }
+    )
+
+    private val isDisabled: (AppRecordWithSize) -> Boolean =
+        { !it.app.enabled && !it.app.isInstantApp }
+
+    private val isInstant: (AppRecordWithSize) -> Boolean = { it.app.isInstantApp }
+
     @Composable
-    override fun getSummary(option: Int, record: AppRecordWithSize) = record.app.getSummary()
+    override fun getSummary(option: Int, record: AppRecordWithSize): State<String> {
+        val storageSummary = record.app.getStorageSummary()
+        return remember {
+            derivedStateOf {
+                storageSummary.value +
+                    when (isDisabled(record)) {
+                        true -> System.lineSeparator() + context.getString(R.string.disabled)
+                        else -> ""
+                    }
+            }
+        }
+    }
 
     @Composable
     override fun AppListItemModel<AppRecordWithSize>.AppItem() {
         AppListItem(onClick = AppInfoSettingsProvider.navigator(app = record.app))
     }
 }
+
+private enum class SpinnerItem(val stringResId: Int) {
+    All(R.string.filter_all_apps),
+    Enabled(R.string.filter_enabled_apps),
+    Disabled(R.string.filter_apps_disabled),
+    Instant(R.string.filter_instant_apps);
+}
diff --git a/src/com/android/settings/spa/app/AppUtil.kt b/src/com/android/settings/spa/app/AppUtil.kt
new file mode 100644
index 0000000..64da613
--- /dev/null
+++ b/src/com/android/settings/spa/app/AppUtil.kt
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2023 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.spa.app
+
+import android.content.Context
+import android.content.Intent
+import android.net.Uri
+import android.os.UserHandle
+
+/**
+ * Based on PackageManagerService design, and it looks like the suggested replacement in the
+ * deprecate notes suggest that we use PackageInstaller.uninstall which does not guarantee a pop up
+ * would open and depends on the calling application. Seems like further investigation is needed
+ * before we can move over to the new API.
+ */
+@Suppress("DEPRECATION")
+fun Context.startUninstallActivity(
+    packageName: String,
+    userHandle: UserHandle,
+    forAllUsers: Boolean = false,
+) {
+    val packageUri = Uri.parse("package:$packageName")
+
+    val intent = Intent(Intent.ACTION_UNINSTALL_PACKAGE, packageUri).apply {
+        putExtra(Intent.EXTRA_UNINSTALL_ALL_USERS, forAllUsers)
+    }
+    startActivityAsUser(intent, userHandle)
+}
\ No newline at end of file
diff --git a/src/com/android/settings/spa/app/appinfo/PackageInfoPresenter.kt b/src/com/android/settings/spa/app/appinfo/PackageInfoPresenter.kt
index cb74388..51426a1 100644
--- a/src/com/android/settings/spa/app/appinfo/PackageInfoPresenter.kt
+++ b/src/com/android/settings/spa/app/appinfo/PackageInfoPresenter.kt
@@ -22,11 +22,11 @@
 import android.content.IntentFilter
 import android.content.pm.PackageInfo
 import android.content.pm.PackageManager
-import android.net.Uri
 import android.os.UserHandle
 import android.util.Log
 import androidx.compose.runtime.Composable
 import com.android.settings.overlay.FeatureFactory
+import com.android.settings.spa.app.startUninstallActivity
 import com.android.settingslib.spa.framework.compose.LocalNavController
 import com.android.settingslib.spaprivileged.framework.common.activityManager
 import com.android.settingslib.spaprivileged.framework.common.asUser
@@ -116,11 +116,7 @@
     /** Starts the uninstallation activity. */
     fun startUninstallActivity(forAllUsers: Boolean = false) {
         logAction(SettingsEnums.ACTION_SETTINGS_UNINSTALL_APP)
-        val packageUri = Uri.parse("package:${packageName}")
-        val intent = Intent(Intent.ACTION_UNINSTALL_PACKAGE, packageUri).apply {
-            putExtra(Intent.EXTRA_UNINSTALL_ALL_USERS, forAllUsers)
-        }
-        context.startActivityAsUser(intent, userHandle)
+        context.startUninstallActivity(packageName, userHandle, forAllUsers)
     }
 
     /** Clears this instant app. */
diff --git a/src/com/android/settings/spa/app/backgroundinstall/BackgroundInstalledAppsPageProvider.kt b/src/com/android/settings/spa/app/backgroundinstall/BackgroundInstalledAppsPageProvider.kt
index 9cf9516..a6b10dd 100644
--- a/src/com/android/settings/spa/app/backgroundinstall/BackgroundInstalledAppsPageProvider.kt
+++ b/src/com/android/settings/spa/app/backgroundinstall/BackgroundInstalledAppsPageProvider.kt
@@ -17,13 +17,11 @@
 package com.android.settings.spa.app.backgroundinstall
 
 import android.content.Context
-import android.content.Intent
 import android.content.pm.ApplicationInfo
 import android.content.pm.IBackgroundInstallControlService
 import android.content.pm.PackageInfo
 import android.content.pm.PackageManager
 import android.content.pm.ParceledListSlice
-import android.net.Uri
 import android.os.Bundle
 import android.os.ServiceManager
 import android.provider.DeviceConfig
@@ -40,6 +38,7 @@
 import androidx.compose.ui.res.stringResource
 import com.android.settings.R
 import com.android.settings.spa.app.appinfo.AppInfoSettingsProvider
+import com.android.settings.spa.app.startUninstallActivity
 import com.android.settingslib.spa.framework.common.SettingsEntryBuilder
 import com.android.settingslib.spa.framework.common.SettingsPage
 import com.android.settingslib.spa.framework.common.SettingsPageProvider
@@ -54,6 +53,7 @@
 import com.android.settingslib.spaprivileged.model.app.AppEntry
 import com.android.settingslib.spaprivileged.model.app.AppListModel
 import com.android.settingslib.spaprivileged.model.app.AppRecord
+import com.android.settingslib.spaprivileged.model.app.userHandle
 import com.android.settingslib.spaprivileged.template.app.AppList
 import com.android.settingslib.spaprivileged.template.app.AppListButtonItem
 import com.android.settingslib.spaprivileged.template.app.AppListInput
@@ -150,23 +150,6 @@
             }
     )
 }
-/*
-Based on PackageManagerService design, and it looks like the suggested replacement in the deprecate
-notes suggest that we use PackageInstaller.uninstall which does not guarantee a pop up would open
-and depends on the calling application. Seems like further investigation is needed before we can
-move over to the new API.
- */
-@Suppress
-@VisibleForTesting
-fun startUninstallActivity(context: Context,
-                                   packageName: String,
-                                   forAllUsers: Boolean = false) {
-    val packageUri = Uri.parse("package:${packageName}")
-    val intent = Intent(Intent.ACTION_UNINSTALL_PACKAGE, packageUri).apply {
-        putExtra(Intent.EXTRA_UNINSTALL_ALL_USERS, forAllUsers)
-    }
-    context.startActivityAsUser(intent, context.user)
-}
 
 data class BackgroundInstalledAppListWithGroupingAppRecord(
     override val app: ApplicationInfo,
@@ -190,9 +173,10 @@
     @Composable
     override fun AppListItemModel<BackgroundInstalledAppListWithGroupingAppRecord>.AppItem() {
         val context = LocalContext.current
+        val app = record.app
         AppListButtonItem(
-            onClick = AppInfoSettingsProvider.navigator(app = record.app),
-            onButtonClick = { startUninstallActivity(context, record.app.packageName) },
+            onClick = AppInfoSettingsProvider.navigator(app = app),
+            onButtonClick = { context.startUninstallActivity(app.packageName, app.userHandle) },
             buttonIcon = Icons.Outlined.Delete,
             buttonIconDescription = stringResource(
                 R.string.background_install_uninstall_button_description))
@@ -209,11 +193,6 @@
             }
         }
 
-    @Composable
-    override fun getSummary(option: Int, record: BackgroundInstalledAppListWithGroupingAppRecord)
-        = null
-
-    @Suppress
     override fun filter(
             userIdFlow: Flow<Int>,
             option: Int,
@@ -224,6 +203,7 @@
             return flowOf()
         }
         return userIdFlow.combine(recordListFlow) { userId, recordList ->
+            @Suppress("UNCHECKED_CAST")
             val appList = (backgroundInstallService.getBackgroundInstalledPackages(
                 PackageManager.MATCH_ALL.toLong(), userId) as ParceledListSlice<PackageInfo>).list
             val appNameList = appList.map { it.packageName }
diff --git a/src/com/android/settings/spa/app/specialaccess/InstallUnknownApps.kt b/src/com/android/settings/spa/app/specialaccess/InstallUnknownApps.kt
index 556ea57..2d2dddf 100644
--- a/src/com/android/settings/spa/app/specialaccess/InstallUnknownApps.kt
+++ b/src/com/android/settings/spa/app/specialaccess/InstallUnknownApps.kt
@@ -19,6 +19,7 @@
 import android.Manifest
 import android.app.AppGlobals
 import android.app.AppOpsManager.MODE_DEFAULT
+import android.app.AppOpsManager.MODE_ERRORED
 import android.app.AppOpsManager.OP_REQUEST_INSTALL_PACKAGES
 import android.content.Context
 import android.content.pm.ApplicationInfo
@@ -50,27 +51,32 @@
     override val pageTitleResId = R.string.install_other_apps
     override val switchTitleResId = R.string.external_source_switch_title
     override val footerResId = R.string.install_all_warning
-    override val switchRestrictionKeys = listOf(
-        UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES,
-        UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES_GLOBALLY,
-    )
+    override val switchRestrictionKeys =
+        listOf(
+            UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES,
+            UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES_GLOBALLY,
+        )
 
-    override fun transformItem(app: ApplicationInfo) = InstallUnknownAppsRecord(
-        app = app,
-        appOpsController = AppOpsController(
-            context = context,
+    override fun transformItem(app: ApplicationInfo) =
+        InstallUnknownAppsRecord(
             app = app,
-            op = OP_REQUEST_INSTALL_PACKAGES,
-        ),
-    )
+            appOpsController =
+                AppOpsController(
+                    context = context,
+                    app = app,
+                    op = OP_REQUEST_INSTALL_PACKAGES,
+                    modeForNotAllowed = MODE_ERRORED
+                ),
+        )
 
     override fun filter(
-        userIdFlow: Flow<Int>, recordListFlow: Flow<List<InstallUnknownAppsRecord>>,
-    ) = userIdFlow.map(::getPotentialPackageNames)
-        .combine(recordListFlow) { potentialPackageNames, recordList ->
-            recordList.filter { record ->
-                isChangeable(record, potentialPackageNames)
-            }
+        userIdFlow: Flow<Int>,
+        recordListFlow: Flow<List<InstallUnknownAppsRecord>>,
+    ) =
+        userIdFlow.map(::getPotentialPackageNames).combine(recordListFlow) {
+            potentialPackageNames,
+            recordList ->
+            recordList.filter { record -> isChangeable(record, potentialPackageNames) }
         }
 
     @Composable
@@ -88,12 +94,13 @@
         private fun isChangeable(
             record: InstallUnknownAppsRecord,
             potentialPackageNames: Set<String>,
-        ) = record.appOpsController.getMode() != MODE_DEFAULT ||
+        ) =
+            record.appOpsController.getMode() != MODE_DEFAULT ||
                 record.app.packageName in potentialPackageNames
 
         private fun getPotentialPackageNames(userId: Int): Set<String> =
-            AppGlobals.getPackageManager().getAppOpPermissionPackages(
-                Manifest.permission.REQUEST_INSTALL_PACKAGES, userId
-            ).toSet()
+            AppGlobals.getPackageManager()
+                .getAppOpPermissionPackages(Manifest.permission.REQUEST_INSTALL_PACKAGES, userId)
+                .toSet()
     }
 }
diff --git a/src/com/android/settings/spa/app/specialaccess/PictureInPicture.kt b/src/com/android/settings/spa/app/specialaccess/PictureInPicture.kt
index 0c56e56..994ee92 100644
--- a/src/com/android/settings/spa/app/specialaccess/PictureInPicture.kt
+++ b/src/com/android/settings/spa/app/specialaccess/PictureInPicture.kt
@@ -16,6 +16,7 @@
 
 package com.android.settings.spa.app.specialaccess
 
+import android.app.AppOpsManager.MODE_ERRORED
 import android.app.AppOpsManager.OP_PICTURE_IN_PICTURE
 import android.content.Context
 import android.content.pm.ActivityInfo
@@ -46,8 +47,8 @@
     val appOpsController: AppOpsController,
 ) : AppRecord
 
-class PictureInPictureListModel(private val context: Context)
-    : TogglePermissionAppListModel<PictureInPictureRecord> {
+class PictureInPictureListModel(private val context: Context) :
+    TogglePermissionAppListModel<PictureInPictureRecord> {
     override val pageTitleResId = R.string.picture_in_picture_title
     override val switchTitleResId = R.string.picture_in_picture_app_detail_switch
     override val footerResId = R.string.picture_in_picture_app_detail_summary
@@ -55,15 +56,16 @@
     private val packageManager = context.packageManager
 
     override fun transform(userIdFlow: Flow<Int>, appListFlow: Flow<List<ApplicationInfo>>) =
-        userIdFlow.map(::getPictureInPicturePackages)
-            .combine(appListFlow) { pictureInPicturePackages, appList ->
-                appList.map { app ->
-                    createPictureInPictureRecord(
-                        app = app,
-                        isSupport = app.packageName in pictureInPicturePackages,
-                    )
-                }
+        userIdFlow.map(::getPictureInPicturePackages).combine(appListFlow) {
+            pictureInPicturePackages,
+            appList ->
+            appList.map { app ->
+                createPictureInPictureRecord(
+                    app = app,
+                    isSupport = app.packageName in pictureInPicturePackages,
+                )
             }
+        }
 
     override fun transformItem(app: ApplicationInfo): PictureInPictureRecord {
         val packageInfo =
@@ -78,17 +80,17 @@
         PictureInPictureRecord(
             app = app,
             isSupport = isSupport,
-            appOpsController = AppOpsController(
-                context = context,
-                app = app,
-                op = OP_PICTURE_IN_PICTURE,
-            ),
+            appOpsController =
+                AppOpsController(
+                    context = context,
+                    app = app,
+                    op = OP_PICTURE_IN_PICTURE,
+                    modeForNotAllowed = MODE_ERRORED,
+                ),
         )
 
     override fun filter(userIdFlow: Flow<Int>, recordListFlow: Flow<List<PictureInPictureRecord>>) =
-        recordListFlow.map { recordList ->
-            recordList.filter { it.isSupport }
-        }
+        recordListFlow.map { recordList -> recordList.filter { it.isSupport } }
 
     @Composable
     override fun isAllowed(record: PictureInPictureRecord) =
@@ -101,7 +103,8 @@
     }
 
     private fun getPictureInPicturePackages(userId: Int): Set<String> =
-        packageManager.getInstalledPackagesAsUser(GET_ACTIVITIES_FLAGS, userId)
+        packageManager
+            .getInstalledPackagesAsUser(GET_ACTIVITIES_FLAGS, userId)
             .filter { it.supportsPictureInPicture() }
             .map { it.packageName }
             .toSet()
diff --git a/src/com/android/settings/spa/app/specialaccess/SpecialAppAccess.kt b/src/com/android/settings/spa/app/specialaccess/SpecialAppAccess.kt
index f955adf..5b9205a 100644
--- a/src/com/android/settings/spa/app/specialaccess/SpecialAppAccess.kt
+++ b/src/com/android/settings/spa/app/specialaccess/SpecialAppAccess.kt
@@ -43,10 +43,12 @@
 
     @Composable
     fun EntryItem() {
-        Preference(object : PreferenceModel {
-            override val title = stringResource(R.string.special_access)
-            override val onClick = navigator(name)
-        })
+        Preference(
+            object : PreferenceModel {
+                override val title = stringResource(R.string.special_access)
+                override val onClick = navigator(name)
+            }
+        )
     }
 
     fun buildInjectEntry() = SettingsEntryBuilder.createInject(owner = SettingsPage.create(name))
@@ -54,13 +56,15 @@
     override fun buildEntry(arguments: Bundle?): List<SettingsEntry> {
         val owner = SettingsPage.create(name, parameter = parameter, arguments = arguments)
         return listOf(
-            AllFilesAccessAppListProvider,
-            DisplayOverOtherAppsAppListProvider,
-            MediaManagementAppsAppListProvider,
-            ModifySystemSettingsAppListProvider,
-            PictureInPictureListProvider,
-            InstallUnknownAppsListProvider,
-            AlarmsAndRemindersAppListProvider,
-        ).map { it.buildAppListInjectEntry().setLink(fromPage = owner).build() }
+                AllFilesAccessAppListProvider,
+                DisplayOverOtherAppsAppListProvider,
+                MediaManagementAppsAppListProvider,
+                ModifySystemSettingsAppListProvider,
+                PictureInPictureListProvider,
+                InstallUnknownAppsListProvider,
+                AlarmsAndRemindersAppListProvider,
+                WifiControlAppListProvider,
+            )
+            .map { it.buildAppListInjectEntry().setLink(fromPage = owner).build() }
     }
 }
diff --git a/src/com/android/settings/spa/app/specialaccess/WifiControlApps.kt b/src/com/android/settings/spa/app/specialaccess/WifiControlApps.kt
new file mode 100644
index 0000000..69f7b1e
--- /dev/null
+++ b/src/com/android/settings/spa/app/specialaccess/WifiControlApps.kt
@@ -0,0 +1,49 @@
+/*
+ * 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.spa.app.specialaccess
+
+import android.Manifest
+import android.app.AppOpsManager
+import android.app.AppOpsManager.MODE_IGNORED
+import android.content.Context
+import com.android.settings.R
+import com.android.settingslib.spaprivileged.model.app.IPackageManagers
+import com.android.settingslib.spaprivileged.model.app.PackageManagers
+import com.android.settingslib.spaprivileged.template.app.AppOpPermissionListModel
+import com.android.settingslib.spaprivileged.template.app.TogglePermissionAppListProvider
+
+object WifiControlAppListProvider : TogglePermissionAppListProvider {
+    override val permissionType = "WifiControl"
+    override fun createModel(context: Context) = WifiControlAppListModel(context)
+}
+
+class WifiControlAppListModel(
+    private val context: Context,
+    private val packageManagers: IPackageManagers = PackageManagers
+) : AppOpPermissionListModel(context, packageManagers) {
+    override val pageTitleResId = R.string.change_wifi_state_title
+    override val switchTitleResId = R.string.change_wifi_state_app_detail_switch
+    override val footerResId = R.string.change_wifi_state_app_detail_summary
+
+    override val appOp = AppOpsManager.OP_CHANGE_WIFI_STATE
+    override val permission = Manifest.permission.CHANGE_WIFI_STATE
+
+    /** NETWORK_SETTINGS permission trumps CHANGE_WIFI_CONFIG. */
+    override val broaderPermission = Manifest.permission.NETWORK_SETTINGS
+    override val permissionHasAppopFlag = false
+    override val modeForNotAllowed = MODE_IGNORED
+}
diff --git a/src/com/android/settings/spa/development/UsageStatsListModel.kt b/src/com/android/settings/spa/development/UsageStatsListModel.kt
index caa30cc..61c24ac 100644
--- a/src/com/android/settings/spa/development/UsageStatsListModel.kt
+++ b/src/com/android/settings/spa/development/UsageStatsListModel.kt
@@ -26,6 +26,7 @@
 import com.android.settings.R
 import com.android.settings.spa.development.UsageStatsListModel.SpinnerItem.Companion.toSpinnerItem
 import com.android.settingslib.spa.framework.compose.stateOf
+import com.android.settingslib.spa.widget.ui.SpinnerOption
 import com.android.settingslib.spaprivileged.model.app.AppEntry
 import com.android.settingslib.spaprivileged.model.app.AppListModel
 import com.android.settingslib.spaprivileged.model.app.AppRecord
@@ -53,9 +54,13 @@
             appList.map { app -> UsageStatsAppRecord(app, usageStatsMap[app.packageName]) }
         }
 
-    override fun getSpinnerOptions() = SpinnerItem.values().map {
-        context.getString(it.stringResId)
-    }
+    override fun getSpinnerOptions(recordList: List<UsageStatsAppRecord>): List<SpinnerOption> =
+        SpinnerItem.values().map {
+            SpinnerOption(
+                id = it.ordinal,
+                text = context.getString(it.stringResId),
+            )
+        }
 
     override fun filter(
         userIdFlow: Flow<Int>,
@@ -75,7 +80,8 @@
     override fun getSummary(option: Int, record: UsageStatsAppRecord): State<String>? {
         val usageStats = record.usageStats ?: return null
         val lastTimeUsed = DateUtils.formatSameDayTime(
-            usageStats.lastTimeUsed, now, DateFormat.MEDIUM, DateFormat.MEDIUM)
+            usageStats.lastTimeUsed, now, DateFormat.MEDIUM, DateFormat.MEDIUM
+        )
         val lastTimeUsedLine = "${context.getString(R.string.last_time_used_label)}: $lastTimeUsed"
         val usageTime = DateUtils.formatElapsedTime(usageStats.totalTimeInForeground / 1000)
         val usageTimeLine = "${context.getString(R.string.usage_time_label)}: $usageTime"
diff --git a/src/com/android/settings/spa/notification/AppNotificationsListModel.kt b/src/com/android/settings/spa/notification/AppNotificationsListModel.kt
index 29c8a2b..028b2f4 100644
--- a/src/com/android/settings/spa/notification/AppNotificationsListModel.kt
+++ b/src/com/android/settings/spa/notification/AppNotificationsListModel.kt
@@ -30,6 +30,7 @@
 import com.android.settingslib.spa.framework.compose.stateOf
 import com.android.settingslib.spa.framework.util.asyncFilter
 import com.android.settingslib.spa.framework.util.asyncForEach
+import com.android.settingslib.spa.widget.ui.SpinnerOption
 import com.android.settingslib.spaprivileged.model.app.AppEntry
 import com.android.settingslib.spaprivileged.model.app.AppListModel
 import com.android.settingslib.spaprivileged.model.app.AppRecord
@@ -78,8 +79,9 @@
         }
     }
 
-    override suspend fun onFirstLoaded(recordList: List<AppNotificationsRecord>) {
+    override suspend fun onFirstLoaded(recordList: List<AppNotificationsRecord>): Boolean {
         recordList.asyncForEach { it.controller.getEnabled() }
+        return true
     }
 
     override fun getComparator(option: Int) = when (option.toSpinnerItem()) {
@@ -97,9 +99,13 @@
         }
     }
 
-    override fun getSpinnerOptions() = SpinnerItem.values().map {
-        context.getString(it.stringResId)
-    }
+    override fun getSpinnerOptions(recordList: List<AppNotificationsRecord>): List<SpinnerOption> =
+        SpinnerItem.values().map {
+            SpinnerOption(
+                id = it.ordinal,
+                text = context.getString(it.stringResId),
+            )
+        }
 
     private fun formatLastSent(lastSent: Long) =
         StringUtil.formatRelativeTime(
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryChartPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryChartPreferenceControllerTest.java
index a31fffa..054b44f 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryChartPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryChartPreferenceControllerTest.java
@@ -95,6 +95,7 @@
                 .when(mContext)
                 .getSystemService(UserManager.class);
         doReturn(true).when(mUserManager).isUserUnlocked(anyInt());
+        doReturn(new int[]{0}).when(mUserManager).getProfileIdsWithDisabled(anyInt());
         final Resources resources = spy(mContext.getResources());
         resources.getConfiguration().setLocales(new LocaleList(new Locale("en_US")));
         doReturn(resources).when(mContext).getResources();
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryDiffEntryTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryDiffEntryTest.java
index 900913b..4883563 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryDiffEntryTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryDiffEntryTest.java
@@ -371,15 +371,6 @@
     }
 
     @Test
-    public void testIsSystemEntry_uidBatteryWithHiddenState_returnTrue() {
-        final BatteryDiffEntry entry =
-                createBatteryDiffEntry(
-                        ConvertUtils.CONSUMER_TYPE_UID_BATTERY,
-                        /*uid=*/ 123, /*isHidden=*/ true);
-        assertThat(entry.isSystemEntry()).isTrue();
-    }
-
-    @Test
     public void testIsSystemEntry_uidBatteryWithSystemProcess_returnFalse() {
         final BatteryDiffEntry entry =
                 createBatteryDiffEntry(
@@ -389,24 +380,6 @@
     }
 
     @Test
-    public void testIsSystemEntry_uidBatteryWithTetheringProcess_returnTrue() {
-        final BatteryDiffEntry entry =
-                createBatteryDiffEntry(
-                        ConvertUtils.CONSUMER_TYPE_UID_BATTERY,
-                        /*uid=*/ BatteryUtils.UID_TETHERING, /*isHidden=*/ false);
-        assertThat(entry.isSystemEntry()).isTrue();
-    }
-
-    @Test
-    public void testIsSystemEntry_uidBatteryWithRemovedAppsProcess_returnTrue() {
-        final BatteryDiffEntry entry =
-                createBatteryDiffEntry(
-                        ConvertUtils.CONSUMER_TYPE_UID_BATTERY,
-                        /*uid=*/ BatteryUtils.UID_REMOVED_APPS, /*isHidden=*/ false);
-        assertThat(entry.isSystemEntry()).isTrue();
-    }
-
-    @Test
     public void testUpdateRestrictionFlagState_updateFlagAsExpected() throws Exception {
         final String expectedAppLabel = "fake app label";
         final String fakePackageName = "com.fake.google.com";
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryEntryTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryEntryTest.java
index 7e5aaea..07a8dfe 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryEntryTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryEntryTest.java
@@ -108,7 +108,8 @@
                 mMockContext,
                 powerComponentId,
                 /* devicePowerMah= */ 200,
-                /* usageDurationMs= */ 1000);
+                /* usageDurationMs= */ 1000,
+                /* isHidden= */ false);
     }
 
     private BatteryEntry createCustomAggregateBatteryEntry(int powerComponentId) {
@@ -169,7 +170,8 @@
         final BatteryEntry entry = new BatteryEntry(RuntimeEnvironment.application,
                 BatteryConsumer.POWER_COMPONENT_AMBIENT_DISPLAY,
                 /* devicePowerMah= */ 200,
-                /* usageDurationMs= */ 1000);
+                /* usageDurationMs= */ 1000,
+                /* isHidden= */ false);
 
         assertThat(entry.mIconId).isEqualTo(R.drawable.ic_settings_aod);
         assertThat(entry.mName).isEqualTo("Ambient display");
@@ -202,7 +204,8 @@
         final BatteryEntry entry = new BatteryEntry(RuntimeEnvironment.application,
                 BatteryConsumer.POWER_COMPONENT_BLUETOOTH,
                 /* devicePowerMah= */ 10,
-                /* usageDurationMs= */ 100);
+                /* usageDurationMs= */ 100,
+                /* isHidden= */ false);
 
         assertThat(entry.getTimeInForegroundMs()).isEqualTo(100L);
     }
@@ -223,7 +226,8 @@
         final BatteryEntry entry = new BatteryEntry(RuntimeEnvironment.application,
                 BatteryConsumer.POWER_COMPONENT_BLUETOOTH,
                 /* devicePowerMah= */ 100,
-                /* usageDurationMs= */ 1000);
+                /* usageDurationMs= */ 1000,
+                /* isHidden= */ false);
 
         assertThat(entry.getTimeInBackgroundMs()).isEqualTo(0);
     }
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/DataProcessorTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/DataProcessorTest.java
index fb91ea2..a1caa2c 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/DataProcessorTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/DataProcessorTest.java
@@ -21,6 +21,7 @@
 import static org.mockito.ArgumentMatchers.anyLong;
 import static org.mockito.Mockito.any;
 import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.anyString;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.eq;
 import static org.mockito.Mockito.spy;
@@ -32,6 +33,7 @@
 import android.content.ContentValues;
 import android.content.Context;
 import android.content.Intent;
+import android.content.pm.ApplicationInfo;
 import android.content.pm.UserInfo;
 import android.os.BatteryConsumer;
 import android.os.BatteryManager;
@@ -43,6 +45,7 @@
 
 import com.android.settings.fuelgauge.PowerUsageFeatureProvider;
 import com.android.settings.testutils.FakeFeatureFactory;
+import com.android.settingslib.applications.ApplicationsState;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -75,13 +78,15 @@
     @Mock private BatteryUsageStats mBatteryUsageStats;
     @Mock private UserManager mUserManager;
     @Mock private IUsageStatsManager mUsageStatsManager;
+    @Mock private ApplicationsState mApplicationsState;
+    @Mock private ApplicationsState.AppEntry mAppEntry;
+    @Mock private ApplicationInfo mApplicationInfo;
     @Mock private BatteryEntry mMockBatteryEntry1;
     @Mock private BatteryEntry mMockBatteryEntry2;
     @Mock private BatteryEntry mMockBatteryEntry3;
     @Mock private BatteryEntry mMockBatteryEntry4;
     @Mock private UsageEvents mUsageEvents1;
 
-
     @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
@@ -95,7 +100,9 @@
         doReturn(mIntent).when(mContext).registerReceiver(any(), any());
         doReturn(100).when(mIntent).getIntExtra(eq(BatteryManager.EXTRA_SCALE), anyInt());
         doReturn(66).when(mIntent).getIntExtra(eq(BatteryManager.EXTRA_LEVEL), anyInt());
+        doReturn(mContext).when(mContext).getApplicationContext();
         doReturn(mUserManager).when(mContext).getSystemService(UserManager.class);
+        doReturn(new int[]{0}).when(mUserManager).getProfileIdsWithDisabled(anyInt());
     }
 
     @Test
@@ -768,7 +775,8 @@
                 /*foregroundUsageConsumePower=*/ 0, /*foregroundServiceUsageConsumePower=*/ 0,
                 /*backgroundUsageConsumePower=*/ 0, /*cachedUsageConsumePower=*/ 0,
                 /*uid=*/ 0L, currentUserId, ConvertUtils.CONSUMER_TYPE_UID_BATTERY,
-                /*foregroundUsageTimeInMs=*/ 0L,  /*backgroundUsageTimeInMs=*/ 0L);
+                /*foregroundUsageTimeInMs=*/ 0L,  /*backgroundUsageTimeInMs=*/ 0L,
+                /*isHidden=*/ false);
         // Adds the index = 0 data.
         Map<String, BatteryHistEntry> entryMap = new HashMap<>();
         BatteryHistEntry entry = createBatteryHistEntry(
@@ -777,7 +785,7 @@
                 /*backgroundUsageConsumePower=*/ 3, /*cachedUsageConsumePower=*/ 0,
                 /*uid=*/ 1L, currentUserId,
                 ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 10L,
-                /*backgroundUsageTimeInMs=*/ 20L);
+                /*backgroundUsageTimeInMs=*/ 20L, /*isHidden=*/ false);
         entryMap.put(entry.getKey(), entry);
         entryMap.put(fakeEntry.getKey(), fakeEntry);
         batteryHistoryMap.put(batteryHistoryKeys[0], entryMap);
@@ -793,7 +801,7 @@
                 /*backgroundUsageConsumePower=*/ 5, /*cachedUsageConsumePower=*/ 5,
                 /*uid=*/ 2L, currentUserId,
                 ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 15L,
-                /*backgroundUsageTimeInMs=*/ 25L);
+                /*backgroundUsageTimeInMs=*/ 25L, /*isHidden=*/ false);
         entryMap.put(entry.getKey(), entry);
         entryMap.put(fakeEntry.getKey(), fakeEntry);
         batteryHistoryMap.put(batteryHistoryKeys[2], entryMap);
@@ -805,7 +813,7 @@
                 /*backgroundUsageConsumePower=*/ 8, /*cachedUsageConsumePower=*/ 8,
                 /*uid=*/ 2L, currentUserId,
                 ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 25L,
-                /*backgroundUsageTimeInMs=*/ 35L);
+                /*backgroundUsageTimeInMs=*/ 35L, /*isHidden=*/ false);
         entryMap.put(entry.getKey(), entry);
         entry = createBatteryHistEntry(
                 "package3", "label3", /*consumePower=*/ 10.0,
@@ -813,7 +821,7 @@
                 /*backgroundUsageConsumePower=*/ 2, /*cachedUsageConsumePower=*/ 2,
                 /*uid=*/ 3L, currentUserId,
                 ConvertUtils.CONSUMER_TYPE_SYSTEM_BATTERY, /*foregroundUsageTimeInMs=*/ 40L,
-                /*backgroundUsageTimeInMs=*/ 50L);
+                /*backgroundUsageTimeInMs=*/ 50L, /*isHidden=*/ false);
         entryMap.put(entry.getKey(), entry);
         entry = createBatteryHistEntry(
                 "package4", "label3", /*consumePower=*/ 15.0,
@@ -821,7 +829,7 @@
                 /*backgroundUsageConsumePower=*/ 3, /*cachedUsageConsumePower=*/ 3,
                 /*uid=*/ 4L, currentUserId,
                 ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 5L,
-                /*backgroundUsageTimeInMs=*/ 5L);
+                /*backgroundUsageTimeInMs=*/ 5L, /*isHidden=*/ false);
         entryMap.put(entry.getKey(), entry);
         entryMap.put(fakeEntry.getKey(), fakeEntry);
         batteryHistoryMap.put(batteryHistoryKeys[3], entryMap);
@@ -833,7 +841,7 @@
                 /*backgroundUsageConsumePower=*/ 9, /*cachedUsageConsumePower=*/ 8,
                 /*uid=*/ 2L, currentUserId,
                 ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 30L,
-                /*backgroundUsageTimeInMs=*/ 40L);
+                /*backgroundUsageTimeInMs=*/ 40L, /*isHidden=*/ false);
         entryMap.put(entry.getKey(), entry);
         entry = createBatteryHistEntry(
                 "package3", "label3", /*consumePower=*/ 20.0,
@@ -841,7 +849,7 @@
                 /*backgroundUsageConsumePower=*/ 5, /*cachedUsageConsumePower=*/ 5,
                 /*uid=*/ 3L, currentUserId,
                 ConvertUtils.CONSUMER_TYPE_SYSTEM_BATTERY, /*foregroundUsageTimeInMs=*/ 50L,
-                /*backgroundUsageTimeInMs=*/ 60L);
+                /*backgroundUsageTimeInMs=*/ 60L, /*isHidden=*/ false);
         entryMap.put(entry.getKey(), entry);
         entry = createBatteryHistEntry(
                 "package4", "label4", /*consumePower=*/ 40.0,
@@ -849,7 +857,7 @@
                 /*backgroundUsageConsumePower=*/ 8, /*cachedUsageConsumePower=*/ 8,
                 /*uid=*/ 4L, currentUserId,
                 ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 5L,
-                /*backgroundUsageTimeInMs=*/ 5L);
+                /*backgroundUsageTimeInMs=*/ 5L, /*isHidden=*/ false);
         entryMap.put(entry.getKey(), entry);
         entryMap.put(fakeEntry.getKey(), fakeEntry);
         batteryHistoryMap.put(batteryHistoryKeys[4], entryMap);
@@ -966,7 +974,7 @@
                 /*backgroundUsageConsumePower=*/ 0, /*cachedUsageConsumePower=*/ 0,
                 /*uid=*/ 1L, currentUserId,
                 ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 10L,
-                /*backgroundUsageTimeInMs=*/ 20L);
+                /*backgroundUsageTimeInMs=*/ 20L, /*isHidden=*/ false);
         entryMap.put(entry.getKey(), entry);
         entry = createBatteryHistEntry(
                 "package1", "label1", /*consumePower=*/ 10.0,
@@ -974,7 +982,7 @@
                 /*backgroundUsageConsumePower=*/ 1, /*cachedUsageConsumePower=*/ 1,
                 /*uid=*/ 2L, currentUserId + 1,
                 ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 10L,
-                /*backgroundUsageTimeInMs=*/ 20L);
+                /*backgroundUsageTimeInMs=*/ 20L, /*isHidden=*/ false);
         entryMap.put(entry.getKey(), entry);
         entry = createBatteryHistEntry(
                 "package2", "label2", /*consumePower=*/ 5.0,
@@ -982,7 +990,7 @@
                 /*backgroundUsageConsumePower=*/ 0, /*cachedUsageConsumePower=*/ 0,
                 /*uid=*/ 3L, currentUserId + 2,
                 ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 20L,
-                /*backgroundUsageTimeInMs=*/ 30L);
+                /*backgroundUsageTimeInMs=*/ 30L, /*isHidden=*/ false);
         entryMap.put(entry.getKey(), entry);
         batteryHistoryMap.put(batteryHistoryKeys[0], entryMap);
         // Adds the index = 1 data.
@@ -993,7 +1001,7 @@
                 /*backgroundUsageConsumePower=*/ 2, /*cachedUsageConsumePower=*/ 2,
                 /*uid=*/ 1L, currentUserId,
                 ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 20L,
-                /*backgroundUsageTimeInMs=*/ 30L);
+                /*backgroundUsageTimeInMs=*/ 30L, /*isHidden=*/ false);
         entryMap.put(entry.getKey(), entry);
         entry = createBatteryHistEntry(
                 "package1", "label1", /*consumePower=*/ 30.0,
@@ -1001,7 +1009,7 @@
                 /*backgroundUsageConsumePower=*/ 2, /*cachedUsageConsumePower=*/ 2,
                 /*uid=*/ 2L, currentUserId + 1,
                 ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 10L,
-                /*backgroundUsageTimeInMs=*/ 20L);
+                /*backgroundUsageTimeInMs=*/ 20L, /*isHidden=*/ false);
         entryMap.put(entry.getKey(), entry);
         entry = createBatteryHistEntry(
                 "package2", "label2", /*consumePower=*/ 15.0,
@@ -1009,7 +1017,7 @@
                 /*backgroundUsageConsumePower=*/ 0, /*cachedUsageConsumePower=*/ 0,
                 /*uid=*/ 3L, currentUserId + 2,
                 ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 30L,
-                /*backgroundUsageTimeInMs=*/ 30L);
+                /*backgroundUsageTimeInMs=*/ 30L, /*isHidden=*/ false);
         entryMap.put(entry.getKey(), entry);
         batteryHistoryMap.put(batteryHistoryKeys[1], entryMap);
         // Adds the index = 2 data.
@@ -1020,7 +1028,7 @@
                 /*backgroundUsageConsumePower=*/ 5, /*cachedUsageConsumePower=*/ 5,
                 /*uid=*/ 1L, currentUserId,
                 ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 20L,
-                /*backgroundUsageTimeInMs=*/ 30L);
+                /*backgroundUsageTimeInMs=*/ 30L, /*isHidden=*/ false);
         entryMap.put(entry.getKey(), entry);
         entry = createBatteryHistEntry(
                 "package1", "label1", /*consumePower=*/ 50.0,
@@ -1028,7 +1036,7 @@
                 /*backgroundUsageConsumePower=*/ 10, /*cachedUsageConsumePower=*/ 10,
                 /*uid=*/ 2L, currentUserId + 1,
                 ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 20L,
-                /*backgroundUsageTimeInMs=*/ 20L);
+                /*backgroundUsageTimeInMs=*/ 20L, /*isHidden=*/ false);
         entryMap.put(entry.getKey(), entry);
         entry = createBatteryHistEntry(
                 "package2", "label2", /*consumePower=*/ 25.0,
@@ -1036,7 +1044,7 @@
                 /*backgroundUsageConsumePower=*/ 5, /*cachedUsageConsumePower=*/ 0,
                 /*uid=*/ 3L, currentUserId + 2,
                 ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 30L,
-                /*backgroundUsageTimeInMs=*/ 30L);
+                /*backgroundUsageTimeInMs=*/ 30L, /*isHidden=*/ false);
         entryMap.put(entry.getKey(), entry);
         batteryHistoryMap.put(batteryHistoryKeys[2], entryMap);
         final List<BatteryLevelData.PeriodBatteryLevelData> hourlyBatteryLevelsPerDay =
@@ -1084,7 +1092,7 @@
                 /*backgroundUsageConsumePower=*/ 0, /*cachedUsageConsumePower=*/ 0,
                 /*uid=*/ 1L, currentUserId,
                 ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 0L,
-                /*backgroundUsageTimeInMs=*/ 0L);
+                /*backgroundUsageTimeInMs=*/ 0L, /*isHidden=*/ false);
         entryMap.put(entry.getKey(), entry);
         batteryHistoryMap.put(batteryHistoryKeys[0], entryMap);
         // Adds the index = 1 data.
@@ -1095,7 +1103,7 @@
                 /*backgroundUsageConsumePower=*/ 0, /*cachedUsageConsumePower=*/ 0,
                 /*uid=*/ 1L, currentUserId,
                 ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 0L,
-                /*backgroundUsageTimeInMs=*/ 0L);
+                /*backgroundUsageTimeInMs=*/ 0L, /*isHidden=*/ false);
         entryMap.put(entry.getKey(), entry);
         batteryHistoryMap.put(batteryHistoryKeys[1], entryMap);
         // Adds the index = 2 data.
@@ -1106,7 +1114,7 @@
                 /*backgroundUsageConsumePower=*/ 100, /*cachedUsageConsumePower=*/ 100,
                 /*uid=*/ 1L, currentUserId,
                 ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 3600000L,
-                /*backgroundUsageTimeInMs=*/ 7200000L);
+                /*backgroundUsageTimeInMs=*/ 7200000L, /*isHidden=*/ false);
         entryMap.put(entry.getKey(), entry);
         batteryHistoryMap.put(batteryHistoryKeys[2], entryMap);
         final List<BatteryLevelData.PeriodBatteryLevelData> hourlyBatteryLevelsPerDay =
@@ -1174,7 +1182,7 @@
                 /*backgroundUsageConsumePower=*/ 0, /*cachedUsageConsumePower=*/ 0,
                 /*uid=*/ 1L, currentUserId,
                 ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 0L,
-                /*backgroundUsageTimeInMs=*/ 0L);
+                /*backgroundUsageTimeInMs=*/ 0L, /*isHidden=*/ false);
         entryMap.put(entry.getKey(), entry);
         entry = createBatteryHistEntry(
                 "package2", "label2", /*consumePower=*/ 0,
@@ -1182,7 +1190,7 @@
                 /*backgroundUsageConsumePower=*/ 0, /*cachedUsageConsumePower=*/ 0,
                 /*uid=*/ 2L, currentUserId,
                 ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 0L,
-                /*backgroundUsageTimeInMs=*/ 0L);
+                /*backgroundUsageTimeInMs=*/ 0L, /*isHidden=*/ false);
         entryMap.put(entry.getKey(), entry);
         batteryHistoryMap.put(batteryHistoryKeys[0], entryMap);
         // Adds the index = 1 data.
@@ -1193,7 +1201,7 @@
                 /*backgroundUsageConsumePower=*/ 0, /*cachedUsageConsumePower=*/ 0,
                 /*uid=*/ 1L, currentUserId,
                 ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 0L,
-                /*backgroundUsageTimeInMs=*/ 0L);
+                /*backgroundUsageTimeInMs=*/ 0L, /*isHidden=*/ false);
         entryMap.put(entry.getKey(), entry);
         entry = createBatteryHistEntry(
                 "package2", "label2", /*consumePower=*/ 0,
@@ -1201,7 +1209,7 @@
                 /*backgroundUsageConsumePower=*/ 0, /*cachedUsageConsumePower=*/ 0,
                 /*uid=*/ 2L, currentUserId,
                 ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 0L,
-                /*backgroundUsageTimeInMs=*/ 0L);
+                /*backgroundUsageTimeInMs=*/ 0L, /*isHidden=*/ false);
         entryMap.put(entry.getKey(), entry);
         batteryHistoryMap.put(batteryHistoryKeys[1], entryMap);
         // Adds the index = 2 data.
@@ -1212,7 +1220,7 @@
                 /*backgroundUsageConsumePower=*/ 0, /*cachedUsageConsumePower=*/ 0,
                 /*uid=*/ 1L, currentUserId,
                 ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 10L,
-                /*backgroundUsageTimeInMs=*/ 20L);
+                /*backgroundUsageTimeInMs=*/ 20L, /*isHidden=*/ false);
         entryMap.put(entry.getKey(), entry);
         entry = createBatteryHistEntry(
                 "package2", "label2", /*consumePower=*/ 10.0,
@@ -1220,7 +1228,7 @@
                 /*backgroundUsageConsumePower=*/ 5, /*cachedUsageConsumePower=*/ 5,
                 /*uid=*/ 2L, currentUserId,
                 ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 10L,
-                /*backgroundUsageTimeInMs=*/ 20L);
+                /*backgroundUsageTimeInMs=*/ 20L, /*isHidden=*/ false);
         entryMap.put(entry.getKey(), entry);
         batteryHistoryMap.put(batteryHistoryKeys[2], entryMap);
         final List<BatteryLevelData.PeriodBatteryLevelData> hourlyBatteryLevelsPerDay =
@@ -1267,7 +1275,7 @@
                 /*backgroundUsageConsumePower=*/ 0, /*cachedUsageConsumePower=*/ 0,
                 /*uid=*/ 1L, currentUserId,
                 ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 0L,
-                /*backgroundUsageTimeInMs=*/ 0L);
+                /*backgroundUsageTimeInMs=*/ 0L, /*isHidden=*/ false);
         entryMap.put(entry.getKey(), entry);
         entry = createBatteryHistEntry(
                 "package2", "label2", /*consumePower=*/ 0,
@@ -1275,7 +1283,7 @@
                 /*backgroundUsageConsumePower=*/ 0, /*cachedUsageConsumePower=*/ 0,
                 /*uid=*/ 2L, currentUserId,
                 ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 0L,
-                /*backgroundUsageTimeInMs=*/ 0L);
+                /*backgroundUsageTimeInMs=*/ 0L, /*isHidden=*/ false);
         entryMap.put(entry.getKey(), entry);
         batteryHistoryMap.put(batteryHistoryKeys[0], entryMap);
         // Adds the index = 1 data.
@@ -1286,7 +1294,7 @@
                 /*backgroundUsageConsumePower=*/ 0, /*cachedUsageConsumePower=*/ 0,
                 /*uid=*/ 1L, currentUserId,
                 ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 0L,
-                /*backgroundUsageTimeInMs=*/ 0L);
+                /*backgroundUsageTimeInMs=*/ 0L, /*isHidden=*/ false);
         entryMap.put(entry.getKey(), entry);
         entry = createBatteryHistEntry(
                 "package2", "label2", /*consumePower=*/ 0,
@@ -1294,7 +1302,7 @@
                 /*backgroundUsageConsumePower=*/ 0, /*cachedUsageConsumePower=*/ 0,
                 /*uid=*/ 2L, currentUserId,
                 ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 0L,
-                /*backgroundUsageTimeInMs=*/ 0L);
+                /*backgroundUsageTimeInMs=*/ 0L, /*isHidden=*/ false);
         entryMap.put(entry.getKey(), entry);
         batteryHistoryMap.put(batteryHistoryKeys[1], entryMap);
         // Adds the index = 2 data.
@@ -1305,7 +1313,7 @@
                 /*backgroundUsageConsumePower=*/ 0, /*cachedUsageConsumePower=*/ 0,
                 /*uid=*/ 1L, currentUserId,
                 ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 10L,
-                /*backgroundUsageTimeInMs=*/ 20L);
+                /*backgroundUsageTimeInMs=*/ 20L, /*isHidden=*/ false);
         entryMap.put(entry.getKey(), entry);
         entry = createBatteryHistEntry(
                 "package2", "label2", /*consumePower=*/ 10.0,
@@ -1313,7 +1321,7 @@
                 /*backgroundUsageConsumePower=*/ 5, /*cachedUsageConsumePower=*/ 5,
                 /*uid=*/ 2L, currentUserId,
                 ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 10L,
-                /*backgroundUsageTimeInMs=*/ 20L);
+                /*backgroundUsageTimeInMs=*/ 20L, /*isHidden=*/ false);
         entryMap.put(entry.getKey(), entry);
         batteryHistoryMap.put(batteryHistoryKeys[2], entryMap);
         final List<BatteryLevelData.PeriodBatteryLevelData> hourlyBatteryLevelsPerDay =
@@ -1603,6 +1611,93 @@
         assertThat(DataProcessor.getScreenOnTime(appUsageMap, userId, packageName)).isEqualTo(0);
     }
 
+    @Test
+    public void needsCombineInSystemApp_isHidden_returnTrue() {
+        final int currentUserId = mContext.getUserId();
+        final BatteryHistEntry hiddenHistEntry = createBatteryHistEntry(
+                ConvertUtils.FAKE_PACKAGE_NAME, "fake_label", /*consumePower=*/ 0,
+                /*foregroundUsageConsumePower=*/ 0, /*foregroundServiceUsageConsumePower=*/ 0,
+                /*backgroundUsageConsumePower=*/ 0, /*cachedUsageConsumePower=*/ 0,
+                /*uid=*/ 0L, currentUserId, ConvertUtils.CONSUMER_TYPE_UID_BATTERY,
+                /*foregroundUsageTimeInMs=*/ 0L,  /*backgroundUsageTimeInMs=*/ 0L, true);
+        final BatteryDiffEntry hiddenDiffEntry = new BatteryDiffEntry(
+                mContext,
+                /*foregroundUsageTimeInMs=*/ 0,
+                /*backgroundUsageTimeInMs=*/ 0,
+                /*screenOnTimeInMs=*/ 0,
+                /*consumePower=*/ 0,
+                /*foregroundUsageConsumePower=*/ 0,
+                /*foregroundServiceUsageConsumePower=*/ 0,
+                /*backgroundUsageConsumePower=*/ 0,
+                /*cachedUsageConsumePower=*/ 0,
+                hiddenHistEntry);
+
+        boolean needsCombineInSystemApp = DataProcessor.needsCombineInSystemApp(
+                hiddenDiffEntry, List.of(), mApplicationsState);
+
+        assertThat(needsCombineInSystemApp).isTrue();
+    }
+
+    @Test
+    public void needsCombineInSystemApp_isSystemApp_returnTrue() {
+        final int currentUserId = mContext.getUserId();
+        final BatteryHistEntry batteryHistEntry = createBatteryHistEntry(
+                ConvertUtils.FAKE_PACKAGE_NAME, "fake_label", /*consumePower=*/ 0,
+                /*foregroundUsageConsumePower=*/ 0, /*foregroundServiceUsageConsumePower=*/ 0,
+                /*backgroundUsageConsumePower=*/ 0, /*cachedUsageConsumePower=*/ 0,
+                /*uid=*/ 0L, currentUserId, ConvertUtils.CONSUMER_TYPE_UID_BATTERY,
+                /*foregroundUsageTimeInMs=*/ 0L,  /*backgroundUsageTimeInMs=*/ 0L, false);
+        final BatteryDiffEntry batteryDiffEntry = new BatteryDiffEntry(
+                mContext,
+                /*foregroundUsageTimeInMs=*/ 0,
+                /*backgroundUsageTimeInMs=*/ 0,
+                /*screenOnTimeInMs=*/ 0,
+                /*consumePower=*/ 0,
+                /*foregroundUsageConsumePower=*/ 0,
+                /*foregroundServiceUsageConsumePower=*/ 0,
+                /*backgroundUsageConsumePower=*/ 0,
+                /*cachedUsageConsumePower=*/ 0,
+                batteryHistEntry);
+        doReturn(mAppEntry).when(mApplicationsState).getEntry(anyString(), anyInt());
+        mAppEntry.info = mApplicationInfo;
+        mApplicationInfo.flags = ApplicationInfo.FLAG_SYSTEM;
+
+        boolean needsCombineInSystemApp = DataProcessor.needsCombineInSystemApp(
+                batteryDiffEntry, List.of(), mApplicationsState);
+
+        assertThat(needsCombineInSystemApp).isTrue();
+    }
+
+    @Test
+    public void needsCombineInSystemApp_notSystemApp_returnFalse() {
+        final int currentUserId = mContext.getUserId();
+        final BatteryHistEntry batteryHistEntry = createBatteryHistEntry(
+                ConvertUtils.FAKE_PACKAGE_NAME, "fake_label", /*consumePower=*/ 0,
+                /*foregroundUsageConsumePower=*/ 0, /*foregroundServiceUsageConsumePower=*/ 0,
+                /*backgroundUsageConsumePower=*/ 0, /*cachedUsageConsumePower=*/ 0,
+                /*uid=*/ 0L, currentUserId, ConvertUtils.CONSUMER_TYPE_UID_BATTERY,
+                /*foregroundUsageTimeInMs=*/ 0L,  /*backgroundUsageTimeInMs=*/ 0L, false);
+        final BatteryDiffEntry batteryDiffEntry = new BatteryDiffEntry(
+                mContext,
+                /*foregroundUsageTimeInMs=*/ 0,
+                /*backgroundUsageTimeInMs=*/ 0,
+                /*screenOnTimeInMs=*/ 0,
+                /*consumePower=*/ 0,
+                /*foregroundUsageConsumePower=*/ 0,
+                /*foregroundServiceUsageConsumePower=*/ 0,
+                /*backgroundUsageConsumePower=*/ 0,
+                /*cachedUsageConsumePower=*/ 0,
+                batteryHistEntry);
+        doReturn(mAppEntry).when(mApplicationsState).getEntry(anyString(), anyInt());
+        mAppEntry.info = mApplicationInfo;
+        mApplicationInfo.flags = 0;
+
+        boolean needsCombineInSystemApp = DataProcessor.needsCombineInSystemApp(
+                batteryDiffEntry, List.of(), mApplicationsState);
+
+        assertThat(needsCombineInSystemApp).isFalse();
+    }
+
     private static Map<Long, Map<String, BatteryHistEntry>> createHistoryMap(
             final long[] timestamps, final int[] levels) {
         final Map<Long, Map<String, BatteryHistEntry>> batteryHistoryMap = new HashMap<>();
@@ -1639,7 +1734,8 @@
             final double foregroundServiceUsageConsumePower,
             final double backgroundUsageConsumePower, final double cachedUsageConsumePower,
             final long uid, final long userId, final int consumerType,
-            final long foregroundUsageTimeInMs, final long backgroundUsageTimeInMs) {
+            final long foregroundUsageTimeInMs, final long backgroundUsageTimeInMs,
+            final boolean isHidden) {
         // Only insert required fields.
         final BatteryInformation batteryInformation =
                 BatteryInformation
@@ -1652,6 +1748,7 @@
                         .setCachedUsageConsumePower(cachedUsageConsumePower)
                         .setForegroundUsageTimeInMs(foregroundUsageTimeInMs)
                         .setBackgroundUsageTimeInMs(backgroundUsageTimeInMs)
+                        .setIsHidden(isHidden)
                         .build();
         final ContentValues values = new ContentValues();
         values.put(BatteryHistEntry.KEY_PACKAGE_NAME, packageName);
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/SpinnerPreferenceTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/SpinnerPreferenceTest.java
new file mode 100644
index 0000000..4c2192c
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/SpinnerPreferenceTest.java
@@ -0,0 +1,83 @@
+/*
+ * 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.fuelgauge.batteryusage;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.spy;
+
+import android.content.Context;
+import android.widget.Spinner;
+
+import androidx.preference.Preference;
+
+import com.android.settings.R;
+
+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;
+import org.robolectric.RuntimeEnvironment;
+
+@RunWith(RobolectricTestRunner.class)
+public final class SpinnerPreferenceTest {
+
+    private Context mContext;
+    private SpinnerPreference mSpinnerPreference;
+
+    @Mock
+    private Spinner mMockSpinner;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        mContext = spy(RuntimeEnvironment.application);
+        mSpinnerPreference = new SpinnerPreference(mContext, /*attrs=*/ null);
+    }
+
+    @Test
+    public void constructor_returnExpectedResult() {
+        assertThat(mSpinnerPreference.getLayoutResource()).isEqualTo(R.layout.preference_spinner);
+    }
+
+    @Test
+    public void initializeSpinner_returnExpectedResult() {
+        final String[] items = new String[]{"item1", "item2"};
+        mSpinnerPreference.initializeSpinner(items, null);
+        assertThat(mSpinnerPreference.mItems).isEqualTo(items);
+    }
+
+    @Test
+    public void onSaveInstanceState_returnExpectedResult() {
+        doReturn(1).when(mMockSpinner).getSelectedItemPosition();
+        mSpinnerPreference.mSpinner = mMockSpinner;
+        SpinnerPreference.SavedState savedState =
+                (SpinnerPreference.SavedState) mSpinnerPreference.onSaveInstanceState();
+        assertThat(savedState.getSpinnerPosition()).isEqualTo(1);
+    }
+
+    @Test
+    public void onRestoreInstanceState_returnExpectedResult() {
+        SpinnerPreference.SavedState savedState =
+                new SpinnerPreference.SavedState(Preference.BaseSavedState.EMPTY_STATE, 2);
+        mSpinnerPreference.onRestoreInstanceState(savedState);
+        assertThat(mSpinnerPreference.mSavedSpinnerPosition).isEqualTo(2);
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/TabPreferenceTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/TabPreferenceTest.java
deleted file mode 100644
index c106b48..0000000
--- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/TabPreferenceTest.java
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * 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.fuelgauge.batteryusage;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.spy;
-
-import android.content.Context;
-
-import androidx.fragment.app.Fragment;
-import androidx.preference.Preference;
-
-import com.android.settings.R;
-
-import com.google.android.material.tabs.TabLayout;
-
-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;
-import org.robolectric.RuntimeEnvironment;
-
-@RunWith(RobolectricTestRunner.class)
-public final class TabPreferenceTest {
-
-    private Context mContext;
-    private TabPreference mTabPreference;
-
-    @Mock
-    private Fragment mMockFragment;
-    @Mock
-    private TabLayout mMockTabLayout;
-
-    private final String[] mTabTitles = new String[]{"tab1", "tab2"};
-
-    @Before
-    public void setUp() {
-        MockitoAnnotations.initMocks(this);
-        mContext = spy(RuntimeEnvironment.application);
-        mTabPreference = new TabPreference(mContext, /*attrs=*/ null);
-    }
-
-    @Test
-    public void constructor_returnExpectedResult() {
-        assertThat(mTabPreference.getLayoutResource()).isEqualTo(R.layout.preference_tab);
-    }
-
-    @Test
-    public void initializeTabs_returnExpectedResult() {
-        mTabPreference.initializeTabs(mMockFragment, mTabTitles);
-        assertThat(mTabPreference.mTabTitles).isEqualTo(mTabTitles);
-    }
-
-    @Test
-    public void onSaveInstanceState_returnExpectedResult() {
-        doReturn(1).when(mMockTabLayout).getSelectedTabPosition();
-        mTabPreference.mTabLayout = mMockTabLayout;
-        TabPreference.SavedState savedState =
-                (TabPreference.SavedState) mTabPreference.onSaveInstanceState();
-        assertThat(savedState.getTabPosition()).isEqualTo(1);
-    }
-
-    @Test
-    public void onRestoreInstanceState_returnExpectedResult() {
-        TabPreference.SavedState savedState =
-                new TabPreference.SavedState(Preference.BaseSavedState.EMPTY_STATE, 2);
-        mTabPreference.onRestoreInstanceState(savedState);
-        assertThat(mTabPreference.mSavedTabPosition).isEqualTo(2);
-    }
-}
diff --git a/tests/spa_unit/src/com/android/settings/spa/app/AllAppListTest.kt b/tests/spa_unit/src/com/android/settings/spa/app/AllAppListTest.kt
index b767912..b5dfddc 100644
--- a/tests/spa_unit/src/com/android/settings/spa/app/AllAppListTest.kt
+++ b/tests/spa_unit/src/com/android/settings/spa/app/AllAppListTest.kt
@@ -121,7 +121,7 @@
     @OptIn(ExperimentalCoroutinesApi::class)
     @Test
     fun allAppListModel_transform() = runTest {
-        val listModel = AllAppListModel { stateOf(SUMMARY) }
+        val listModel = AllAppListModel(context) { stateOf(SUMMARY) }
 
         val recordListFlow = listModel.transform(flowOf(USER_ID), flowOf(listOf(APP)))
 
@@ -132,7 +132,7 @@
 
     @Test
     fun allAppListModel_getSummary() {
-        val listModel = AllAppListModel { stateOf(SUMMARY) }
+        val listModel = AllAppListModel(context) { stateOf(SUMMARY) }
 
         lateinit var summaryState: State<String>
         composeTestRule.setContent {
@@ -142,6 +142,23 @@
         assertThat(summaryState.value).isEqualTo(SUMMARY)
     }
 
+    @Test
+    fun allAppListModel_getSummaryWhenDisabled() {
+        val listModel = AllAppListModel(context) { stateOf(SUMMARY) }
+        val disabledApp = ApplicationInfo().apply {
+            packageName = PACKAGE_NAME
+            enabled = false
+        }
+
+        lateinit var summaryState: State<String>
+        composeTestRule.setContent {
+            summaryState =
+                listModel.getSummary(option = 0, record = AppRecordWithSize(app = disabledApp))
+        }
+
+        assertThat(summaryState.value).isEqualTo("$SUMMARY${System.lineSeparator()}Disabled")
+    }
+
     private fun getAppListInput(): AppListInput<AppRecordWithSize> {
         lateinit var input: AppListInput<AppRecordWithSize>
         composeTestRule.setContent {
@@ -157,7 +174,7 @@
     private fun setItemContent() {
         composeTestRule.setContent {
             fakeNavControllerWrapper.Wrapper {
-                with(AllAppListModel()) {
+                with(AllAppListModel(context)) {
                     AppListItemModel(
                         record = AppRecordWithSize(app = APP),
                         label = LABEL,
diff --git a/tests/spa_unit/src/com/android/settings/spa/app/AppUtilTest.kt b/tests/spa_unit/src/com/android/settings/spa/app/AppUtilTest.kt
new file mode 100644
index 0000000..15f87ed
--- /dev/null
+++ b/tests/spa_unit/src/com/android/settings/spa/app/AppUtilTest.kt
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2023 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.spa.app
+
+import android.content.Context
+import android.content.Intent
+import android.net.Uri
+import android.os.UserHandle
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.google.common.truth.Truth.assertThat
+import org.junit.Rule
+
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.ArgumentCaptor
+import org.mockito.Mock
+import org.mockito.Mockito.eq
+import org.mockito.Mockito.verify
+import org.mockito.junit.MockitoJUnit
+import org.mockito.junit.MockitoRule
+
+@RunWith(AndroidJUnit4::class)
+class AppUtilTest {
+    @get:Rule
+    val mockito: MockitoRule = MockitoJUnit.rule()
+
+    @Mock
+    private lateinit var context: Context
+
+    @Test
+    fun startUninstallActivity() {
+        context.startUninstallActivity(packageName = PACKAGE_NAME, userHandle = USER_HANDLE)
+
+        val intentCaptor = ArgumentCaptor.forClass(Intent::class.java)
+        verify(context).startActivityAsUser(intentCaptor.capture(), eq(USER_HANDLE))
+        val intent = intentCaptor.value
+        assertThat(intent.action).isEqualTo(Intent.ACTION_UNINSTALL_PACKAGE)
+        assertThat(intent.data).isEqualTo(Uri.parse("package:$PACKAGE_NAME"))
+        assertThat(intent.extras?.getBoolean(Intent.EXTRA_UNINSTALL_ALL_USERS)).isFalse()
+    }
+
+    private companion object {
+        const val PACKAGE_NAME = "package.name"
+        val USER_HANDLE: UserHandle = UserHandle.of(0)
+    }
+}
\ No newline at end of file
diff --git a/tests/spa_unit/src/com/android/settings/spa/app/WifiControlAppListModelTest.kt b/tests/spa_unit/src/com/android/settings/spa/app/WifiControlAppListModelTest.kt
new file mode 100644
index 0000000..c5c48f5
--- /dev/null
+++ b/tests/spa_unit/src/com/android/settings/spa/app/WifiControlAppListModelTest.kt
@@ -0,0 +1,283 @@
+/*
+ * 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.spa.app.specialaccess
+
+import android.Manifest
+import android.app.AppOpsManager
+import android.app.AppOpsManager.MODE_ALLOWED
+import android.app.AppOpsManager.MODE_DEFAULT
+import android.content.Context
+import android.content.pm.ApplicationInfo
+import androidx.compose.runtime.State
+import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.lifecycle.MutableLiveData
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.settingslib.spa.testutils.firstWithTimeoutOrNull
+import com.android.settingslib.spaprivileged.model.app.IAppOpsController
+import com.android.settingslib.spaprivileged.model.app.IPackageManagers
+import com.android.settingslib.spaprivileged.template.app.AppOpPermissionRecord
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.flowOf
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.Mockito.`when` as whenever
+import org.mockito.junit.MockitoJUnit
+import org.mockito.junit.MockitoRule
+
+@ExperimentalCoroutinesApi
+@RunWith(AndroidJUnit4::class)
+class WifiControlAppListModelTest {
+
+    @get:Rule val mockito: MockitoRule = MockitoJUnit.rule()
+
+    @get:Rule val composeTestRule = createComposeRule()
+
+    private val context: Context = ApplicationProvider.getApplicationContext()
+
+    @Mock private lateinit var packageManagers: IPackageManagers
+
+    private lateinit var listModel: WifiControlAppListModel
+
+    @Before
+    fun setUp() {
+        listModel = WifiControlAppListModel(context, packageManagers)
+    }
+
+    @Test
+    fun transformItem_recordHasCorrectApp() {
+        val record = listModel.transformItem(APP)
+
+        assertThat(record.app).isSameInstanceAs(APP)
+    }
+
+    @Test
+    fun transformItem_hasRequestPermission() = runTest {
+        with(packageManagers) {
+            whenever(APP.hasRequestPermission(PM_CHANGE_WIFI_STATE)).thenReturn(true)
+        }
+
+        val record = listModel.transformItem(APP)
+
+        assertThat(record.hasRequestPermission).isTrue()
+    }
+
+    @Test
+    fun transformItem_notRequestPermission() = runTest {
+        with(packageManagers) {
+            whenever(APP.hasRequestPermission(PM_CHANGE_WIFI_STATE)).thenReturn(false)
+        }
+
+        val record = listModel.transformItem(APP)
+
+        assertThat(record.hasRequestPermission).isFalse()
+    }
+
+    @Test
+    fun transformItem_hasRequestNetworkSettingsPermission() = runTest {
+        with(packageManagers) {
+            whenever(APP.hasRequestPermission(PM_NETWORK_SETTINGS)).thenReturn(true)
+        }
+
+        val record = listModel.transformItem(APP)
+
+        assertThat(record.hasRequestBroaderPermission).isTrue()
+    }
+
+    @Test
+    fun transformItem_notRequestNetworkSettingsPermission() = runTest {
+        with(packageManagers) {
+            whenever(APP.hasRequestPermission(PM_NETWORK_SETTINGS)).thenReturn(false)
+        }
+
+        val record = listModel.transformItem(APP)
+
+        assertThat(record.hasRequestBroaderPermission).isFalse()
+    }
+
+    @Test
+    fun filter() = runTest {
+        val appNotRequestPermissionRecord =
+            AppOpPermissionRecord(
+                app = APP_NOT_REQUEST_PERMISSION,
+                hasRequestPermission = false,
+                hasRequestBroaderPermission = false,
+                appOpsController = FakeAppOpsController(fakeMode = AppOpsManager.MODE_DEFAULT),
+            )
+        val appRequestedNetworkSettingsRecord =
+            AppOpPermissionRecord(
+                app = APP_REQUESTED_NETWORK_SETTINGS,
+                hasRequestPermission = true,
+                hasRequestBroaderPermission = false,
+                appOpsController = FakeAppOpsController(fakeMode = AppOpsManager.MODE_DEFAULT)
+            )
+
+        val recordListFlow =
+            listModel.filter(
+                flowOf(USER_ID),
+                flowOf(listOf(appNotRequestPermissionRecord, appRequestedNetworkSettingsRecord))
+            )
+
+        val recordList = checkNotNull(recordListFlow.firstWithTimeoutOrNull())
+        assertThat(recordList).containsExactly(appRequestedNetworkSettingsRecord)
+    }
+
+    @Test
+    fun isAllowed_networkSettingsShouldTrump() {
+        val record =
+            AppOpPermissionRecord(
+                app = APP,
+                hasRequestPermission = false,
+                hasRequestBroaderPermission = true,
+                appOpsController = FakeAppOpsController(fakeMode = AppOpsManager.MODE_DEFAULT),
+            )
+
+        val isAllowed = getIsAllowed(record)
+
+        assertThat(isAllowed).isTrue()
+    }
+
+    @Test
+    fun isAllowed_grantedChangeWifiState() {
+        val record =
+            AppOpPermissionRecord(
+                app = APP,
+                hasRequestPermission = true,
+                hasRequestBroaderPermission = false,
+                appOpsController = FakeAppOpsController(fakeMode = AppOpsManager.MODE_ALLOWED),
+            )
+
+        val isAllowed = getIsAllowed(record)
+
+        assertThat(isAllowed).isTrue()
+    }
+
+    @Test
+    fun isAllowed_notAllowed() {
+        val record =
+            AppOpPermissionRecord(
+                app = APP,
+                hasRequestPermission = true,
+                hasRequestBroaderPermission = false,
+                appOpsController = FakeAppOpsController(fakeMode = AppOpsManager.MODE_IGNORED),
+            )
+
+        val isAllowed = getIsAllowed(record)
+
+        assertThat(isAllowed).isFalse()
+    }
+
+    @Test
+    fun isChangeable_noRequestedPermission() {
+        val record =
+            AppOpPermissionRecord(
+                app = APP,
+                hasRequestPermission = false,
+                hasRequestBroaderPermission = false,
+                appOpsController = FakeAppOpsController(fakeMode = AppOpsManager.MODE_DEFAULT),
+            )
+
+        val isChangeable = listModel.isChangeable(record)
+
+        assertThat(isChangeable).isFalse()
+    }
+
+    @Test
+    fun isChangeable_notChangableWhenRequestedNetworkSettingPermissions() {
+        val record =
+            AppOpPermissionRecord(
+                app = APP,
+                hasRequestPermission = false,
+                hasRequestBroaderPermission = true,
+                appOpsController = FakeAppOpsController(fakeMode = AppOpsManager.MODE_DEFAULT),
+            )
+
+        val isChangeable = listModel.isChangeable(record)
+
+        assertThat(isChangeable).isFalse()
+    }
+
+    @Test
+    fun isChangeable_changableWhenRequestedChangeWifiStatePermission() {
+        val record =
+            AppOpPermissionRecord(
+                app = APP,
+                hasRequestPermission = true,
+                hasRequestBroaderPermission = false,
+                appOpsController = FakeAppOpsController(fakeMode = AppOpsManager.MODE_DEFAULT),
+            )
+
+        val isChangeable = listModel.isChangeable(record)
+
+        assertThat(isChangeable).isTrue()
+    }
+
+    @Test
+    fun setAllowed_shouldCallController() {
+        val appOpsController = FakeAppOpsController(fakeMode = AppOpsManager.MODE_DEFAULT)
+        val record =
+            AppOpPermissionRecord(
+                app = APP,
+                hasRequestPermission = true,
+                hasRequestBroaderPermission = false,
+                appOpsController = appOpsController,
+            )
+
+        listModel.setAllowed(record = record, newAllowed = true)
+
+        assertThat(appOpsController.setAllowedCalledWith).isTrue()
+    }
+
+    private fun getIsAllowed(record: AppOpPermissionRecord): Boolean? {
+        lateinit var isAllowedState: State<Boolean?>
+        composeTestRule.setContent { isAllowedState = listModel.isAllowed(record) }
+        return isAllowedState.value
+    }
+
+    private companion object {
+        const val USER_ID = 0
+        const val PACKAGE_NAME = "package.name"
+        const val PM_CHANGE_WIFI_STATE = Manifest.permission.CHANGE_WIFI_STATE
+        const val PM_NETWORK_SETTINGS = Manifest.permission.NETWORK_SETTINGS
+
+        val APP = ApplicationInfo().apply { packageName = PACKAGE_NAME }
+
+        val APP_NOT_REQUEST_PERMISSION =
+            ApplicationInfo().apply { packageName = "app1.package.name" }
+        val APP_REQUESTED_NETWORK_SETTINGS =
+            ApplicationInfo().apply { packageName = "app2.package.name" }
+        val APP_REQUESTED_CHANGE_WIFI_STATE =
+            ApplicationInfo().apply { packageName = "app3.package.name" }
+    }
+}
+
+private class FakeAppOpsController(private val fakeMode: Int) : IAppOpsController {
+    var setAllowedCalledWith: Boolean? = null
+
+    override val mode = MutableLiveData(fakeMode)
+
+    override fun setAllowed(allowed: Boolean) {
+        setAllowedCalledWith = allowed
+    }
+
+    override fun getMode() = fakeMode
+}
diff --git a/tests/spa_unit/src/com/android/settings/spa/app/backgroundinstall/BackgroundInstalledAppsPageProviderTest.kt b/tests/spa_unit/src/com/android/settings/spa/app/backgroundinstall/BackgroundInstalledAppsPageProviderTest.kt
index 8e1757f..b3e29af 100644
--- a/tests/spa_unit/src/com/android/settings/spa/app/backgroundinstall/BackgroundInstalledAppsPageProviderTest.kt
+++ b/tests/spa_unit/src/com/android/settings/spa/app/backgroundinstall/BackgroundInstalledAppsPageProviderTest.kt
@@ -17,14 +17,11 @@
 package com.android.settings.spa.app.backgroundinstall
 
 import android.content.Context
-import android.content.Intent
 import android.content.pm.ApplicationInfo
 import android.content.pm.IBackgroundInstallControlService
 import android.content.pm.PackageInfo
 import android.content.pm.PackageManager
 import android.content.pm.ParceledListSlice
-import android.net.Uri
-import android.os.UserHandle
 import androidx.compose.ui.test.assertIsDisplayed
 import androidx.compose.ui.test.junit4.createComposeRule
 import androidx.compose.ui.test.onNodeWithText
@@ -74,9 +71,6 @@
     private var packageInfoFlagsCaptor =
         ArgumentCaptor.forClass(PackageManager.PackageInfoFlags::class.java)
 
-    private var intentCaptor =
-        ArgumentCaptor.forClass(Intent::class.java)
-
     private val fakeNavControllerWrapper = FakeNavControllerWrapper()
 
     @Before
@@ -177,26 +171,6 @@
             .isEqualTo("AppInfoSettings/package.name/0")
     }
 
-    @Suppress
-    @OptIn(ExperimentalCoroutinesApi::class)
-    @Test
-    fun startUninstallActivity_success() = runTest {
-        val expectedPackageUri = Uri.parse("package:package.name")
-        val mockUserHandle = UserHandle(0)
-        Mockito.`when`(mockContext.user).thenReturn(mockUserHandle)
-        Mockito.`when`(mockContext.startActivityAsUser(
-            intentCaptor.capture(),
-            eq(mockUserHandle)
-        )).then {  }
-
-        startUninstallActivity(mockContext, TEST_PACKAGE_NAME)
-
-        Truth.assertThat(intentCaptor.value.action).isEqualTo(Intent.ACTION_UNINSTALL_PACKAGE)
-        Truth.assertThat(intentCaptor.value.data).isEqualTo(expectedPackageUri)
-        Truth.assertThat(intentCaptor.value.extras?.getBoolean(Intent.EXTRA_UNINSTALL_ALL_USERS))
-            .isEqualTo(false)
-    }
-
     @OptIn(ExperimentalCoroutinesApi::class)
     @Test
     fun backgroundInstalledAppsWithGroupingListModel_getGroupTitleOne() = runTest {
diff --git a/tests/unit/src/com/android/settings/regionalpreferences/CalendarTypeControllerTest.java b/tests/unit/src/com/android/settings/regionalpreferences/CalendarTypeControllerTest.java
index 7e1ec94..4ac2532 100644
--- a/tests/unit/src/com/android/settings/regionalpreferences/CalendarTypeControllerTest.java
+++ b/tests/unit/src/com/android/settings/regionalpreferences/CalendarTypeControllerTest.java
@@ -19,6 +19,7 @@
 import static org.junit.Assert.assertEquals;
 
 import android.content.Context;
+import android.icu.util.ULocale;
 import android.provider.Settings;
 
 import androidx.test.core.app.ApplicationProvider;
@@ -48,49 +49,57 @@
 
     @After
     public void tearDown() throws Exception {
-        RegionalPreferenceUtils.setSettingsProviderContent(
+        RegionalPreferenceTestUtils.setSettingsProviderContent(
                 mApplicationContext, mCacheProviderContent);
         Locale.setDefault(mCacheLocale);
     }
 
     @Test
-    public void getSummary_hasProviderValue_resultIsChinese() {
-        RegionalPreferenceUtils.setSettingsProviderContent(
+    public void getSummary_hasProviderValue_resultIsChineseCalendar() {
+        RegionalPreferenceTestUtils.setSettingsProviderContent(
                 mApplicationContext, "und-u-ca-chinese");
 
-        CharSequence type = mController.getSummary();
+        String summary = mController.getSummary().toString();
 
-        assertEquals(LocalePreferences.CalendarType.CHINESE, type.toString());
+        assertEquals(getDisplayKeywordValue(LocalePreferences.CalendarType.CHINESE), summary);
     }
 
     @Test
-    public void getSummary_hasProviderValue_resultIsDangi() {
-        RegionalPreferenceUtils.setSettingsProviderContent(
+    public void getSummary_hasProviderValue_resultIsDangiCalendar() {
+        RegionalPreferenceTestUtils.setSettingsProviderContent(
                 mApplicationContext, "und-u-ca-dangi");
 
-        CharSequence type = mController.getSummary();
+        String summary = mController.getSummary().toString();
 
-        assertEquals(LocalePreferences.CalendarType.DANGI, type.toString());
+        assertEquals(getDisplayKeywordValue(LocalePreferences.CalendarType.DANGI), summary);
     }
 
     @Test
-    public void getSummary_noProviderValueButHasDefaultLocaleWithSubtag_resultIsSat() {
-        RegionalPreferenceUtils.setSettingsProviderContent(mApplicationContext, "");
+    public void getSummary_noProviderValueButHasDefaultLocaleWithSubtag_resultIsChineseCalendar() {
+        RegionalPreferenceTestUtils.setSettingsProviderContent(mApplicationContext, "");
         Locale.setDefault(Locale.forLanguageTag("en-US-u-ca-chinese"));
 
-        CharSequence type = mController.getSummary();
+        String summary = mController.getSummary().toString();
 
-        assertEquals(LocalePreferences.CalendarType.CHINESE, type.toString());
+        assertEquals(getDisplayKeywordValue(LocalePreferences.CalendarType.CHINESE), summary);
     }
 
     @Test
     public void getSummary_noProviderValueAndDefaultLocaleWithoutSubtag_resultIsEmpty() {
-        RegionalPreferenceUtils.setSettingsProviderContent(mApplicationContext, "");
+        RegionalPreferenceTestUtils.setSettingsProviderContent(mApplicationContext, "");
         Locale.setDefault(Locale.forLanguageTag("en-US"));
 
-        CharSequence type = mController.getSummary();
+        String summary = mController.getSummary().toString();
 
         assertEquals(ResourcesUtils.getResourcesString(
-                mApplicationContext, "default_string_of_regional_preference"), type.toString());
+                mApplicationContext, "default_string_of_regional_preference"), summary);
+    }
+
+    private static String getDisplayKeywordValue(String value) {
+        String languageTag = new Locale.Builder()
+                .setUnicodeLocaleKeyword(
+                        RegionalPreferencesFragment.TYPE_CALENDAR, value).build().toLanguageTag();
+        return ULocale.getDisplayKeywordValue(languageTag, "calendar",
+                ULocale.forLocale(Locale.getDefault(Locale.Category.FORMAT)));
     }
 }
diff --git a/tests/unit/src/com/android/settings/regionalpreferences/FirstDayOfWeekControllerTest.java b/tests/unit/src/com/android/settings/regionalpreferences/FirstDayOfWeekControllerTest.java
index b658242..062aef8 100644
--- a/tests/unit/src/com/android/settings/regionalpreferences/FirstDayOfWeekControllerTest.java
+++ b/tests/unit/src/com/android/settings/regionalpreferences/FirstDayOfWeekControllerTest.java
@@ -48,47 +48,50 @@
 
     @After
     public void tearDown() throws Exception {
-        RegionalPreferenceUtils.setSettingsProviderContent(
+        RegionalPreferenceTestUtils.setSettingsProviderContent(
                 mApplicationContext, mCacheProviderContent);
         Locale.setDefault(mCacheLocale);
     }
 
     @Test
     public void getSummary_hasProviderValue_resultIsWed() {
-        RegionalPreferenceUtils.setSettingsProviderContent(mApplicationContext, "und-u-fw-wed");
+        RegionalPreferenceTestUtils.setSettingsProviderContent(mApplicationContext, "und-u-fw-wed");
 
-        CharSequence day = mController.getSummary();
+        String summary = mController.getSummary().toString();
 
-        assertEquals(LocalePreferences.FirstDayOfWeek.WEDNESDAY, day.toString());
+        assertEquals(ResourcesUtils.getResourcesString(
+                mApplicationContext, "wednesday_first_day_of_week"), summary);
     }
 
     @Test
     public void getSummary_hasProviderValue_resultIsSat() {
-        RegionalPreferenceUtils.setSettingsProviderContent(mApplicationContext, "und-u-fw-sat");
+        RegionalPreferenceTestUtils.setSettingsProviderContent(mApplicationContext, "und-u-fw-sat");
 
-        CharSequence day = mController.getSummary();
+        String summary = mController.getSummary().toString();
 
-        assertEquals(LocalePreferences.FirstDayOfWeek.SATURDAY, day.toString());
+        assertEquals(ResourcesUtils.getResourcesString(
+                mApplicationContext, "saturday_first_day_of_week"), summary);
     }
 
     @Test
     public void getSummary_noProviderValueButHasDefaultLocaleWithSubtag_resultIsSat() {
-        RegionalPreferenceUtils.setSettingsProviderContent(mApplicationContext, "");
+        RegionalPreferenceTestUtils.setSettingsProviderContent(mApplicationContext, "");
         Locale.setDefault(Locale.forLanguageTag("en-US-u-fw-sat"));
 
-        CharSequence day = mController.getSummary();
+        String summary = mController.getSummary().toString();
 
-        assertEquals(LocalePreferences.FirstDayOfWeek.SATURDAY, day.toString());
+        assertEquals(ResourcesUtils.getResourcesString(
+                mApplicationContext, "saturday_first_day_of_week"), summary);
     }
 
     @Test
-    public void getSummary_noProviderValueAndDefaultLocaleWithoutSubtag_resultIsEmpty() {
-        RegionalPreferenceUtils.setSettingsProviderContent(mApplicationContext, "");
+    public void getSummary_noProviderValueAndDefaultLocaleWithoutSubtag_resultIsdefault() {
+        RegionalPreferenceTestUtils.setSettingsProviderContent(mApplicationContext, "");
         Locale.setDefault(Locale.forLanguageTag("en-US"));
 
-        CharSequence day = mController.getSummary();
+        String summary = mController.getSummary().toString();
 
         assertEquals(ResourcesUtils.getResourcesString(
-                mApplicationContext, "default_string_of_regional_preference"), day.toString());
+                mApplicationContext, "default_string_of_regional_preference"), summary);
     }
 }
diff --git a/tests/unit/src/com/android/settings/regionalpreferences/RegionalPreferenceUtils.java b/tests/unit/src/com/android/settings/regionalpreferences/RegionalPreferenceTestUtils.java
similarity index 95%
rename from tests/unit/src/com/android/settings/regionalpreferences/RegionalPreferenceUtils.java
rename to tests/unit/src/com/android/settings/regionalpreferences/RegionalPreferenceTestUtils.java
index 709413c..d973236 100644
--- a/tests/unit/src/com/android/settings/regionalpreferences/RegionalPreferenceUtils.java
+++ b/tests/unit/src/com/android/settings/regionalpreferences/RegionalPreferenceTestUtils.java
@@ -20,7 +20,7 @@
 import android.provider.Settings;
 
 /** Utils for each regional preference unit test. */
-public final class RegionalPreferenceUtils {
+public final class RegionalPreferenceTestUtils {
     /** Set language tag to Settings Provider */
     public static void setSettingsProviderContent(Context context, String languageTag) {
         Settings.System.putString(context.getContentResolver(),
diff --git a/tests/unit/src/com/android/settings/regionalpreferences/RegionalPreferencesDataUtilsTest.java b/tests/unit/src/com/android/settings/regionalpreferences/RegionalPreferencesDataUtilsTest.java
new file mode 100644
index 0000000..0de3b7e
--- /dev/null
+++ b/tests/unit/src/com/android/settings/regionalpreferences/RegionalPreferencesDataUtilsTest.java
@@ -0,0 +1,161 @@
+/*
+ * Copyright (C) 2023 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.regionalpreferences;
+
+import static org.junit.Assert.assertEquals;
+
+import android.content.Context;
+import android.os.LocaleList;
+import android.provider.Settings;
+
+import androidx.test.core.app.ApplicationProvider;
+
+import com.android.internal.app.LocalePicker;
+import com.android.settings.testutils.ResourcesUtils;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.Locale;
+
+public class RegionalPreferencesDataUtilsTest {
+    private Context mApplicationContext;
+    private String mCacheProviderContent = "";
+    private Locale mCacheLocale;
+    private LocaleList mCacheLocaleList;
+
+    @Before
+    public void setUp() throws Exception {
+        mApplicationContext = ApplicationProvider.getApplicationContext();
+        mCacheProviderContent = Settings.System.getString(
+                mApplicationContext.getContentResolver(), Settings.System.LOCALE_PREFERENCES);
+        mCacheLocale = Locale.getDefault(Locale.Category.FORMAT);
+        mCacheLocaleList = LocaleList.getDefault();
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        RegionalPreferenceTestUtils.setSettingsProviderContent(
+                mApplicationContext, mCacheProviderContent);
+        Locale.setDefault(mCacheLocale);
+        LocalePicker.updateLocales(mCacheLocaleList);
+    }
+
+    @Test
+    public void getDefaultUnicodeExtensionData_hasProviderValue_resultIsCelsius() {
+        RegionalPreferenceTestUtils.setSettingsProviderContent(
+                mApplicationContext, "und-u-mu-celsius");
+
+        String unit = RegionalPreferencesDataUtils.getDefaultUnicodeExtensionData(
+                mApplicationContext, RegionalPreferencesFragment.TYPE_TEMPERATURE);
+
+        assertEquals(LocalePreferences.TemperatureUnit.CELSIUS, unit);
+    }
+
+    @Test
+    public void getDefaultUnicodeExtensionData_hasDefaultLocaleSubtag_resultIsCelsius() {
+        RegionalPreferenceTestUtils.setSettingsProviderContent(
+                mApplicationContext, "und");
+        Locale.setDefault(Locale.forLanguageTag("en-US-u-mu-celsius"));
+
+        String unit = RegionalPreferencesDataUtils.getDefaultUnicodeExtensionData(
+                mApplicationContext, RegionalPreferencesFragment.TYPE_TEMPERATURE);
+
+        assertEquals(LocalePreferences.TemperatureUnit.CELSIUS, unit);
+    }
+
+    @Test
+    public void getDefaultUnicodeExtensionData_noSubtag_resultIsDefault() {
+        RegionalPreferenceTestUtils.setSettingsProviderContent(
+                mApplicationContext, "und");
+        Locale.setDefault(Locale.forLanguageTag("en-US"));
+
+        String unit = RegionalPreferencesDataUtils.getDefaultUnicodeExtensionData(
+                mApplicationContext, RegionalPreferencesFragment.TYPE_TEMPERATURE);
+
+        assertEquals(RegionalPreferencesFragment.TYPE_DEFAULT, unit);
+    }
+
+    @Test
+    public void savePreference_saveCalendarIsDangi_success() {
+        RegionalPreferencesDataUtils.savePreference(
+                mApplicationContext,
+                RegionalPreferencesFragment.TYPE_CALENDAR,
+                LocalePreferences.CalendarType.DANGI
+        );
+        String providerContent = Settings.System.getString(
+                mApplicationContext.getContentResolver(), Settings.System.LOCALE_PREFERENCES);
+        Locale locale = Locale.forLanguageTag(providerContent);
+
+
+        String result1 = locale.getUnicodeLocaleType(RegionalPreferencesFragment.TYPE_CALENDAR);
+
+        assertEquals(LocalePreferences.CalendarType.DANGI, result1);
+
+        String result2 = Locale.getDefault(Locale.Category.FORMAT)
+                .getUnicodeLocaleType(RegionalPreferencesFragment.TYPE_CALENDAR);
+
+        assertEquals(LocalePreferences.CalendarType.DANGI, result2);
+
+    }
+
+    @Test
+    public void temperatureUnitsConverter_inputFahrenheit_resultIsFahrenheitString() {
+        String result = RegionalPreferencesDataUtils.temperatureUnitsConverter(mApplicationContext,
+                LocalePreferences.TemperatureUnit.FAHRENHEIT);
+
+        assertEquals(ResourcesUtils.getResourcesString(
+                mApplicationContext, "fahrenheit_temperature_unit"), result);
+    }
+
+    @Test
+    public void temperatureUnitsConverter_inputDefault_resultIsDefaultString() {
+        String result = RegionalPreferencesDataUtils.temperatureUnitsConverter(mApplicationContext,
+                RegionalPreferencesFragment.TYPE_DEFAULT);
+
+        assertEquals(ResourcesUtils.getResourcesString(
+                mApplicationContext, "default_string_of_regional_preference"), result);
+    }
+
+    @Test
+    public void dayConverter_inputWed_resultIsWedString() {
+        String result = RegionalPreferencesDataUtils.dayConverter(mApplicationContext,
+                LocalePreferences.FirstDayOfWeek.WEDNESDAY);
+
+        assertEquals(ResourcesUtils.getResourcesString(
+                mApplicationContext, "wednesday_first_day_of_week"), result);
+    }
+
+    @Test
+    public void dayConverter_inputDefault_resultIsDefaultString() {
+        String result = RegionalPreferencesDataUtils.dayConverter(mApplicationContext,
+                RegionalPreferencesFragment.TYPE_DEFAULT);
+
+        assertEquals(ResourcesUtils.getResourcesString(
+                mApplicationContext, "default_string_of_regional_preference"), result);
+    }
+
+    @Test
+    public void calendarConverter_inputDefault_resultIsDefaultString() {
+        String result = RegionalPreferencesDataUtils.dayConverter(mApplicationContext,
+                RegionalPreferencesFragment.TYPE_DEFAULT);
+
+        assertEquals(ResourcesUtils.getResourcesString(
+                mApplicationContext, "default_string_of_regional_preference"), result);
+    }
+}
diff --git a/tests/unit/src/com/android/settings/regionalpreferences/RegionalPreferencesFragmentTest.java b/tests/unit/src/com/android/settings/regionalpreferences/RegionalPreferencesFragmentTest.java
new file mode 100644
index 0000000..f059bf3
--- /dev/null
+++ b/tests/unit/src/com/android/settings/regionalpreferences/RegionalPreferencesFragmentTest.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2023 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.regionalpreferences;
+
+import static org.junit.Assert.assertEquals;
+
+import android.app.settings.SettingsEnums;
+import android.os.Looper;
+
+import androidx.test.annotation.UiThreadTest;
+
+import org.junit.Before;
+import org.junit.Test;
+
+public class RegionalPreferencesFragmentTest {
+    private RegionalPreferencesFragment mFragment;
+
+    @Before
+    @UiThreadTest
+    public void setUp() throws Exception {
+        if (Looper.myLooper() == null) {
+            Looper.prepare();
+        }
+        mFragment = new RegionalPreferencesFragment();
+    }
+
+    @Test
+    @UiThreadTest
+    public void getMetricsCategory_typeIsCa_resultIsCalendarPreference() {
+        mFragment.mType = RegionalPreferencesFragment.TYPE_CALENDAR;
+
+        int result = mFragment.getMetricsCategory();
+
+        assertEquals(SettingsEnums.CALENDAR_PREFERENCE, result);
+    }
+
+    @Test
+    @UiThreadTest
+    public void getMetricsCategory_typeIsFw_resultIsFirstDayOfWeekPreference() {
+        mFragment.mType = RegionalPreferencesFragment.TYPE_FIRST_DAY_OF_WEEK;
+
+        int result = mFragment.getMetricsCategory();
+
+        assertEquals(SettingsEnums.FIRST_DAY_OF_WEEK_PREFERENCE, result);
+    }
+
+    @Test
+    @UiThreadTest
+    public void getMetricsCategory_typeIsMu_resultIsTemperaturePreference() {
+        mFragment.mType = RegionalPreferencesFragment.TYPE_TEMPERATURE;
+
+        int result = mFragment.getMetricsCategory();
+
+        assertEquals(SettingsEnums.TEMPERATURE_PREFERENCE, result);
+    }
+}
diff --git a/tests/unit/src/com/android/settings/regionalpreferences/TemperatureUnitControllerTest.java b/tests/unit/src/com/android/settings/regionalpreferences/TemperatureUnitControllerTest.java
index 4f473ad..aa652ca 100644
--- a/tests/unit/src/com/android/settings/regionalpreferences/TemperatureUnitControllerTest.java
+++ b/tests/unit/src/com/android/settings/regionalpreferences/TemperatureUnitControllerTest.java
@@ -48,49 +48,52 @@
 
     @After
     public void tearDown() throws Exception {
-        RegionalPreferenceUtils.setSettingsProviderContent(
+        RegionalPreferenceTestUtils.setSettingsProviderContent(
                 mApplicationContext, mCacheProviderContent);
         Locale.setDefault(mCacheLocale);
     }
 
     @Test
     public void getSummary_hasProviderValue_resultIsCelsius() {
-        RegionalPreferenceUtils.setSettingsProviderContent(
+        RegionalPreferenceTestUtils.setSettingsProviderContent(
                 mApplicationContext, "und-u-mu-celsius");
 
-        CharSequence unit = mController.getSummary();
+        String summary = mController.getSummary().toString();
 
-        assertEquals(LocalePreferences.TemperatureUnit.CELSIUS, unit.toString());
+        assertEquals(ResourcesUtils.getResourcesString(
+                mApplicationContext, "celsius_temperature_unit"), summary);
     }
 
     @Test
     public void getSummary_hasProviderValue_resultIsFahrenheit() {
-        RegionalPreferenceUtils.setSettingsProviderContent(
+        RegionalPreferenceTestUtils.setSettingsProviderContent(
                 mApplicationContext, "und-u-mu-fahrenhe");
 
-        CharSequence unit = mController.getSummary();
+        String summary = mController.getSummary().toString();
 
-        assertEquals(LocalePreferences.TemperatureUnit.FAHRENHEIT, unit.toString());
+        assertEquals(ResourcesUtils.getResourcesString(
+                mApplicationContext, "fahrenheit_temperature_unit"), summary);
     }
 
     @Test
     public void getSummary_noProviderValueButHasDefaultLocaleWithSubtag_resultIsFahrenheit() {
-        RegionalPreferenceUtils.setSettingsProviderContent(mApplicationContext, "");
+        RegionalPreferenceTestUtils.setSettingsProviderContent(mApplicationContext, "");
         Locale.setDefault(Locale.forLanguageTag("en-US-u-mu-fahrenhe"));
 
-        CharSequence unit = mController.getSummary();
+        String summary = mController.getSummary().toString();
 
-        assertEquals(LocalePreferences.TemperatureUnit.FAHRENHEIT, unit.toString());
+        assertEquals(ResourcesUtils.getResourcesString(
+                mApplicationContext, "fahrenheit_temperature_unit"), summary);
     }
 
     @Test
-    public void getSummary_noProviderValueAndDefaultLocaleWithoutSubtag_resultIsEmpty() {
-        RegionalPreferenceUtils.setSettingsProviderContent(mApplicationContext, "");
+    public void getSummary_noProviderValueAndDefaultLocaleWithoutSubtag_resultIsDefault() {
+        RegionalPreferenceTestUtils.setSettingsProviderContent(mApplicationContext, "");
         Locale.setDefault(Locale.forLanguageTag("en-US"));
 
-        CharSequence unit = mController.getSummary();
+        String summary = mController.getSummary().toString();
 
         assertEquals(ResourcesUtils.getResourcesString(
-                mApplicationContext, "default_string_of_regional_preference"), unit.toString());
+                mApplicationContext, "default_string_of_regional_preference"), summary);
     }
 }