Merge "Settings: add a new developer menu entry to show hdr/sdr ratio overlay." into main
diff --git a/aconfig/Android.bp b/aconfig/Android.bp
index 5c6c8c3..f485869 100644
--- a/aconfig/Android.bp
+++ b/aconfig/Android.bp
@@ -11,6 +11,7 @@
         "settings_development_flag_declarations.aconfig",
         "settings_globalintl_flag_declarations.aconfig",
         "settings_experience_flag_declarations.aconfig",
+	"settings_notification_flag_declarations.aconfig",
         "settings_onboarding_experience_flag_declarations.aconfig",
         "settings_telephony_flag_declarations.aconfig",
         "settings_biometrics_integration_declarations.aconfig",
diff --git a/aconfig/settings_notification_flag_declarations.aconfig b/aconfig/settings_notification_flag_declarations.aconfig
new file mode 100644
index 0000000..f2bf1c8
--- /dev/null
+++ b/aconfig/settings_notification_flag_declarations.aconfig
@@ -0,0 +1,9 @@
+package: "com.android.settings.flags"
+
+flag {
+  name: "dedupe_dnd_settings_channels"
+  namespace: "systemui"
+  description: "Controls adding group names to channel names in the DND>Apps settings page"
+  bug: "294333850"
+}
+
diff --git a/protos/fuelgauge_log.proto b/protos/fuelgauge_log.proto
index e75ca48..36126a5 100644
--- a/protos/fuelgauge_log.proto
+++ b/protos/fuelgauge_log.proto
@@ -43,6 +43,7 @@
     RECHECK_JOB = 3;
     FETCH_USAGE_DATA = 4;
     INSERT_USAGE_DATA = 5;
+    TIME_UPDATED = 6;
   }
 
   optional int64 timestamp = 1;
diff --git a/res/drawable/ic_error_red.xml b/res/drawable/ic_error_red.xml
new file mode 100644
index 0000000..d17c85b
--- /dev/null
+++ b/res/drawable/ic_error_red.xml
@@ -0,0 +1,26 @@
+<!--
+  ~ 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.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="24dp"
+        android:height="24dp"
+        android:viewportWidth="960"
+        android:viewportHeight="960"
+        android:tint="?android:attr/colorError">
+    <path
+        android:fillColor="@android:color/white"
+        android:pathData="M480,680Q497,680 508.5,668.5Q520,657 520,640Q520,623 508.5,611.5Q497,600 480,600Q463,600 451.5,611.5Q440,623 440,640Q440,657 451.5,668.5Q463,680 480,680ZM440,520L520,520L520,280L440,280L440,520ZM480,880Q397,880 324,848.5Q251,817 197,763Q143,709 111.5,636Q80,563 80,480Q80,397 111.5,324Q143,251 197,197Q251,143 324,111.5Q397,80 480,80Q563,80 636,111.5Q709,143 763,197Q817,251 848.5,324Q880,397 880,480Q880,563 848.5,636Q817,709 763,763Q709,817 636,848.5Q563,880 480,880ZM480,800Q614,800 707,707Q800,614 800,480Q800,346 707,253Q614,160 480,160Q346,160 253,253Q160,346 160,480Q160,614 253,707Q346,800 480,800ZM480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Z"/>
+</vector>
diff --git a/res/layout/privatespace_account_login_error.xml b/res/layout/privatespace_account_login_error.xml
new file mode 100644
index 0000000..a38dd50
--- /dev/null
+++ b/res/layout/privatespace_account_login_error.xml
@@ -0,0 +1,28 @@
+<?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.
+  -->
+
+<com.google.android.setupdesign.GlifLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    android:id="@+id/ps_error_page_layout"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:filterTouchesWhenObscured="true"
+    app:sucHeaderText="@string/privatespace_retry_signin_title"
+    app:sudDescriptionText="@string/privatespace_retry_summary"
+    android:icon="@drawable/ic_error_red">
+</com.google.android.setupdesign.GlifLayout>
diff --git a/res/navigation/privatespace_main_context_nav.xml b/res/navigation/privatespace_main_context_nav.xml
index 5b2552a..ffc63ec 100644
--- a/res/navigation/privatespace_main_context_nav.xml
+++ b/res/navigation/privatespace_main_context_nav.xml
@@ -33,8 +33,8 @@
             android:id="@+id/action_advance_profile_error"
             app:destination="@id/ps_profile_error_fragment"/>
         <action
-            android:id="@+id/action_advance_to_success"
-            app:destination="@id/ps_profile_success_fragment"/>
+            android:id="@+id/action_advance_login_error"
+            app:destination="@id/ps_account_error_fragment"/>
     </fragment>
     <fragment android:id="@+id/ps_profile_error_fragment"
               android:name="com.android.settings.privatespace.PrivateProfileCreationError"
@@ -46,4 +46,18 @@
     <fragment android:id="@+id/ps_profile_success_fragment"
               android:name="com.android.settings.privatespace.SetupSuccessFragment"
               android:label="fragment_ps_success"/>
-</navigation>
\ No newline at end of file
+    <fragment android:id="@+id/ps_account_error_fragment"
+              android:name="com.android.settings.privatespace.PrivateSpaceAccountLoginError"
+              android:label="fragment_account_error">
+        <action
+            android:id="@+id/action_advance_login_error"
+            app:destination="@id/ps_account_error_fragment"/>
+    </fragment>
+    <fragment android:id="@+id/ps_profile_lock_fragment"
+              android:name="com.android.settings.privatespace.PrivateSpaceSetLockFragment"
+              android:label="fragment_ps_lock"/>
+    <action android:id="@+id/action_success_fragment"
+            app:destination="@id/ps_profile_success_fragment"/>
+    <action android:id="@+id/action_set_lock_fragment"
+            app:destination="@id/ps_profile_lock_fragment"/>
+</navigation>
diff --git a/res/navigation/privatespace_private_context_nav.xml b/res/navigation/privatespace_private_context_nav.xml
deleted file mode 100644
index 3df8fa5..0000000
--- a/res/navigation/privatespace_private_context_nav.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<!--
-  ~ 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.
-  -->
-
-<navigation xmlns:android="http://schemas.android.com/apk/res/android"
-            xmlns:app="http://schemas.android.com/apk/res-auto"
-            android:id="@+id/private_space_navigation"
-            app:startDestination="@id/ps_profile_lock_fragment">
-    <fragment android:id="@+id/ps_profile_lock_fragment"
-              android:name="com.android.settings.privatespace.PrivateSpaceSetLockFragment"
-              android:label="fragment_ps_lock"/>
-</navigation>
diff --git a/res/values/config.xml b/res/values/config.xml
index 99052ca..f50e918 100755
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -753,6 +753,9 @@
     <!-- Whether to display Cloned Apps page in Settings (Settings > Apps > Cloned Apps).-->
     <bool name="config_cloned_apps_page_enabled">false</bool>
 
+    <!-- Whether to initiate Account login during Private Space setup.-->
+    <bool name="config_privatespace_account_login_enabled">false</bool>
+
     <!-- Certificates of apps which are allowed to use activity embedding with Settings.-->
     <string-array name="config_known_host_certs" translatable="false">
         <item></item>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index a503710..7ed9ade 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -1298,6 +1298,10 @@
     <string name="privatespace_done_label">Done</string>
     <!-- Toast to show on private space setup completion informing user to scroll down All apps to access private space. [CHAR LIMIT=60] -->
     <string name="scrolldown_to_access">Scroll down to access Private Space</string>
+    <!-- Title for Private Space account login error screen. [CHAR LIMIT=60] -->
+    <string name="privatespace_retry_signin_title">Sign in to set up Private Space</string>
+    <!-- Summary for the Private Space account login error screen. [CHAR LIMIT=NONE] -->
+    <string name="privatespace_retry_summary">You need to sign in to a Account to set up Private Space</string>
 
     <!-- Text shown when "Add fingerprint" button is disabled -->
     <string name="fingerprint_add_max">You can add up to <xliff:g id="count" example="5">%d</xliff:g> fingerprints</string>
@@ -9525,6 +9529,13 @@
     <!-- Label for showing apps that can manage external storage[CHAR LIMIT=45] -->
     <string name="filter_manage_external_storage">Can access all files</string>
 
+    <!-- Voice Activation apps settings title [CHAR LIMIT=40] -->
+    <string name="voice_activation_apps_title">Voice activation apps</string>
+    <!-- Label for a setting which controls whether an app can be voice activated [CHAR LIMIT=NONE] -->
+    <string name="permit_voice_activation_apps">Allow voice activation</string>
+    <!-- Description for a setting which controls whether an app can be voice activated [CHAR LIMIT=NONE] -->
+    <string name ="allow_voice_activation_apps_description">Voice activation turns-on approved apps, hands-free, using voice command. Built-in adaptive sensing ensures data stays private only to you.\n\n<a href="">More about protected adaptive sensing</a></string>
+
     <!-- Manage full screen intent permission title [CHAR LIMIT=40] -->
     <string name="full_screen_intent_title">Full screen notifications</string>
 
diff --git a/res/xml/special_access.xml b/res/xml/special_access.xml
index b3f3f7d..3f3d75d 100644
--- a/res/xml/special_access.xml
+++ b/res/xml/special_access.xml
@@ -100,6 +100,11 @@
         settings:controller="com.android.settings.spa.app.specialaccess.UseFullScreenIntentPreferenceController" />
 
     <Preference
+        android:key="voice_activation_apps"
+        android:title="@string/voice_activation_apps_title"
+        settings:controller="com.android.settings.spa.app.specialaccess.VoiceActivationAppsPreferenceController" />
+
+    <Preference
         android:key="picture_in_picture"
         android:title="@string/picture_in_picture_title"
         android:order="-1100"
diff --git a/src/com/android/settings/SettingsActivityUtil.kt b/src/com/android/settings/SettingsActivityUtil.kt
index 65d26de..c23bc18 100644
--- a/src/com/android/settings/SettingsActivityUtil.kt
+++ b/src/com/android/settings/SettingsActivityUtil.kt
@@ -37,6 +37,7 @@
 import com.android.settings.spa.app.specialaccess.ModifySystemSettingsAppListProvider
 import com.android.settings.spa.app.specialaccess.NfcTagAppsSettingsProvider
 import com.android.settings.spa.app.specialaccess.PictureInPictureListProvider
+import com.android.settings.spa.app.specialaccess.VoiceActivationAppsListProvider
 import com.android.settings.spa.app.specialaccess.WifiControlAppListProvider
 import com.android.settings.wifi.ChangeWifiStateDetails
 
@@ -65,6 +66,8 @@
             WifiControlAppListProvider.getAppInfoRoutePrefix(),
         NfcTagAppsSettingsProvider::class.qualifiedName to
             NfcTagAppsSettingsProvider.getAppInfoRoutePrefix(),
+        VoiceActivationAppsListProvider::class.qualifiedName to
+            VoiceActivationAppsListProvider.getAppInfoRoutePrefix(),
     )
 
     @JvmStatic
diff --git a/src/com/android/settings/applications/appcompat/UserAspectRatioDetails.java b/src/com/android/settings/applications/appcompat/UserAspectRatioDetails.java
index 076d37c..02d5c27 100644
--- a/src/com/android/settings/applications/appcompat/UserAspectRatioDetails.java
+++ b/src/com/android/settings/applications/appcompat/UserAspectRatioDetails.java
@@ -28,6 +28,7 @@
 
 import android.app.ActivityManager;
 import android.app.IActivityManager;
+import android.app.settings.SettingsEnums;
 import android.content.Intent;
 import android.content.pm.PackageManager;
 import android.os.Build;
@@ -44,8 +45,10 @@
 import com.android.settings.R;
 import com.android.settings.Utils;
 import com.android.settings.applications.AppInfoBase;
+import com.android.settings.overlay.FeatureFactory;
 import com.android.settings.widget.EntityHeaderController;
 import com.android.settingslib.applications.AppUtils;
+import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
 import com.android.settingslib.widget.ActionButtonsPreference;
 
 import java.util.ArrayList;
@@ -104,6 +107,7 @@
             Log.e(TAG, "Unable to set user min aspect ratio");
             return;
         }
+        logActionMetrics(selectedKey, mSelectedKey);
         // Only update to selected aspect ratio if nothing goes wrong
         mSelectedKey = selectedKey;
         updateAllPreferences(mSelectedKey);
@@ -118,8 +122,7 @@
 
     @Override
     public int getMetricsCategory() {
-        // TODO(b/292566895): add metrics for logging
-        return 0;
+        return SettingsEnums.USER_ASPECT_RATIO_APP_INFO_SETTINGS;
     }
 
     @Override
@@ -244,6 +247,68 @@
         }
     }
 
+    private void logActionMetrics(@NonNull String selectedKey, @NonNull String unselectedKey) {
+        final MetricsFeatureProvider metricsFeatureProvider =
+                FeatureFactory.getFeatureFactory().getMetricsFeatureProvider();
+        final int attribution = metricsFeatureProvider.getAttribution(getActivity());
+        metricsFeatureProvider.action(
+                attribution,
+                getUnselectedAspectRatioAction(unselectedKey),
+                getMetricsCategory(),
+                mPackageName,
+                mUserId
+        );
+        metricsFeatureProvider.action(
+                attribution,
+                getSelectedAspectRatioAction(selectedKey),
+                getMetricsCategory(),
+                mPackageName,
+                mUserId
+        );
+    }
+
+    private static int getSelectedAspectRatioAction(@NonNull String selectedKey) {
+        switch (selectedKey) {
+            case KEY_PREF_DEFAULT:
+                return SettingsEnums.ACTION_USER_ASPECT_RATIO_APP_DEFAULT_SELECTED;
+            case KEY_PREF_FULLSCREEN:
+                return SettingsEnums.ACTION_USER_ASPECT_RATIO_FULL_SCREEN_SELECTED;
+            case KEY_PREF_HALF_SCREEN:
+                return SettingsEnums.ACTION_USER_ASPECT_RATIO_HALF_SCREEN_SELECTED;
+            case KEY_PREF_4_3:
+                return SettingsEnums.ACTION_USER_ASPECT_RATIO_4_3_SELECTED;
+            case KEY_PREF_16_9:
+                return SettingsEnums.ACTION_USER_ASPECT_RATIO_16_9_SELECTED;
+            case KEY_PREF_3_2:
+                return SettingsEnums.ACTION_USER_ASPECT_RATIO_3_2_SELECTED;
+            case KEY_PREF_DISPLAY_SIZE:
+                return SettingsEnums.ACTION_USER_ASPECT_RATIO_DISPLAY_SIZE_SELECTED;
+            default:
+                return SettingsEnums.ACTION_UNKNOWN;
+        }
+    }
+
+    private static int getUnselectedAspectRatioAction(@NonNull String unselectedKey) {
+        switch (unselectedKey) {
+            case KEY_PREF_DEFAULT:
+                return SettingsEnums.ACTION_USER_ASPECT_RATIO_APP_DEFAULT_UNSELECTED;
+            case KEY_PREF_FULLSCREEN:
+                return SettingsEnums.ACTION_USER_ASPECT_RATIO_FULL_SCREEN_UNSELECTED;
+            case KEY_PREF_HALF_SCREEN:
+                return SettingsEnums.ACTION_USER_ASPECT_RATIO_HALF_SCREEN_UNSELECTED;
+            case KEY_PREF_4_3:
+                return SettingsEnums.ACTION_USER_ASPECT_RATIO_4_3_UNSELECTED;
+            case KEY_PREF_16_9:
+                return SettingsEnums.ACTION_USER_ASPECT_RATIO_16_9_UNSELECTED;
+            case KEY_PREF_3_2:
+                return SettingsEnums.ACTION_USER_ASPECT_RATIO_3_2_UNSELECTED;
+            case KEY_PREF_DISPLAY_SIZE:
+                return SettingsEnums.ACTION_USER_ASPECT_RATIO_DISPLAY_SIZE_UNSELECTED;
+            default:
+                return SettingsEnums.ACTION_UNKNOWN;
+        }
+    }
+
     @VisibleForTesting
     UserAspectRatioManager getAspectRatioManager() {
         return mUserAspectRatioManager;
diff --git a/src/com/android/settings/applications/manageapplications/ApplicationViewHolder.java b/src/com/android/settings/applications/manageapplications/ApplicationViewHolder.java
index c94edc6..1d96688 100644
--- a/src/com/android/settings/applications/manageapplications/ApplicationViewHolder.java
+++ b/src/com/android/settings/applications/manageapplications/ApplicationViewHolder.java
@@ -46,14 +46,14 @@
 import com.android.settingslib.applications.ApplicationsState;
 import com.android.settingslib.applications.ApplicationsState.AppEntry;
 import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
-import com.android.settingslib.spaprivileged.template.app.AppListItemKt;
+import com.android.settingslib.spaprivileged.template.app.AppListItemModelKt;
 import com.android.settingslib.spaprivileged.template.app.AppListPageKt;
 import com.android.settingslib.widget.LottieColorUtils;
 
 import com.airbnb.lottie.LottieAnimationView;
 
 /**
- * @deprecated Will be removed, use {@link AppListItemKt} {@link AppListPageKt} instead.
+ * @deprecated Will be removed, use {@link AppListItemModelKt} {@link AppListPageKt} instead.
  */
 @Deprecated(forRemoval = true)
 public class ApplicationViewHolder extends RecyclerView.ViewHolder {
diff --git a/src/com/android/settings/applications/manageapplications/ManageApplicationsUtil.kt b/src/com/android/settings/applications/manageapplications/ManageApplicationsUtil.kt
index 216ce47..82e987e 100644
--- a/src/com/android/settings/applications/manageapplications/ManageApplicationsUtil.kt
+++ b/src/com/android/settings/applications/manageapplications/ManageApplicationsUtil.kt
@@ -64,9 +64,11 @@
 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.LongBackgroundTasksAppListProvider
 import com.android.settings.spa.app.specialaccess.MediaManagementAppsAppListProvider
 import com.android.settings.spa.app.specialaccess.ModifySystemSettingsAppListProvider
 import com.android.settings.spa.app.specialaccess.NfcTagAppsSettingsProvider
+import com.android.settings.spa.app.specialaccess.TurnScreenOnAppsAppListProvider
 import com.android.settings.spa.app.specialaccess.WifiControlAppListProvider
 import com.android.settings.spa.app.storage.StorageAppListPageProvider
 import com.android.settings.spa.notification.AppListNotificationsPageProvider
@@ -120,6 +122,8 @@
             LIST_TYPE_MAIN -> AllAppListPageProvider.name
             LIST_TYPE_NFC_TAG_APPS -> NfcTagAppsSettingsProvider.getAppListRoute()
             LIST_TYPE_USER_ASPECT_RATIO_APPS -> UserAspectRatioAppsPageProvider.name
+            LIST_TYPE_LONG_BACKGROUND_TASKS -> LongBackgroundTasksAppListProvider.getAppListRoute()
+            LIST_TYPE_TURN_SCREEN_ON -> TurnScreenOnAppsAppListProvider.getAppListRoute()
             // TODO(b/292165031) enable once sorting is supported
             //LIST_TYPE_STORAGE -> StorageAppListPageProvider.Apps.name
             //LIST_TYPE_GAMES -> StorageAppListPageProvider.Games.name
diff --git a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDialogFragment.java b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDialogFragment.java
index 5b99907..1fd0b87 100644
--- a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDialogFragment.java
+++ b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDialogFragment.java
@@ -38,6 +38,26 @@
 public class AudioSharingDialogFragment extends InstrumentedDialogFragment {
     private static final String TAG = "AudioSharingDialog";
 
+    private static final String BUNDLE_KEY_DEVICE_NAMES = "bundle_key_device_names";
+
+    // The host creates an instance of this dialog fragment must implement this interface to receive
+    // event callbacks.
+    public interface DialogEventListener {
+        /**
+         * Called when users click the device item for sharing in the dialog.
+         *
+         * @param position The position of the item clicked.
+         */
+        void onItemClick(int position);
+
+        /**
+         * Called when users click the cancel button in the dialog.
+         */
+        void onCancelClick();
+    }
+
+    private static DialogEventListener sListener;
+
     private View mRootView;
 
     @Override
@@ -50,40 +70,59 @@
      *
      * @param host The Fragment this dialog will be hosted.
      */
-    public static void show(Fragment host) {
+    public static void show(
+            Fragment host, ArrayList<String> deviceNames, DialogEventListener listener) {
         if (!Flags.enableLeAudioSharing()) return;
         final FragmentManager manager = host.getChildFragmentManager();
+        sListener = listener;
         if (manager.findFragmentByTag(TAG) == null) {
-            final AudioSharingDialogFragment dialog = new AudioSharingDialogFragment();
+            final Bundle bundle = new Bundle();
+            bundle.putStringArrayList(BUNDLE_KEY_DEVICE_NAMES, deviceNames);
+            AudioSharingDialogFragment dialog = new AudioSharingDialogFragment();
+            dialog.setArguments(bundle);
             dialog.show(manager, TAG);
         }
     }
 
     @Override
     public Dialog onCreateDialog(Bundle savedInstanceState) {
+        Bundle arguments = requireArguments();
+        ArrayList<String> deviceNames = arguments.getStringArrayList(BUNDLE_KEY_DEVICE_NAMES);
         final AlertDialog.Builder builder =
-                new AlertDialog.Builder(getActivity()).setTitle("Share audio");
+                new AlertDialog.Builder(getActivity()).setTitle("Share audio").setCancelable(false);
         mRootView =
                 LayoutInflater.from(builder.getContext())
                         .inflate(R.layout.dialog_audio_sharing, /* parent= */ null);
-        // TODO: use real subtitle according to device count.
         TextView subTitle1 = mRootView.findViewById(R.id.share_audio_subtitle1);
         TextView subTitle2 = mRootView.findViewById(R.id.share_audio_subtitle2);
-        subTitle1.setText("2 devices connected");
-        subTitle2.setText("placeholder");
+        if (deviceNames.isEmpty()) {
+            subTitle1.setVisibility(View.INVISIBLE);
+            subTitle2.setText("To start sharing audio, connect headphones that support LE audio");
+            builder.setNegativeButton(
+                    "Close",
+                    (dialog, which) -> {
+                        sListener.onCancelClick();
+                    });
+        } else if (deviceNames.size() == 1) {
+            // TODO: add real impl
+            subTitle1.setText("1 devices connected");
+            subTitle2.setText("placeholder");
+        } else {
+            // TODO: add real impl
+            subTitle1.setText("2 devices connected");
+            subTitle2.setText("placeholder");
+        }
         RecyclerView recyclerView = mRootView.findViewById(R.id.btn_list);
-        // TODO: use real audio sharing device list.
-        ArrayList<String> devices = new ArrayList<>();
-        devices.add("Buds 1");
-        devices.add("Buds 2");
         recyclerView.setAdapter(
                 new AudioSharingDeviceAdapter(
-                        devices,
+                        deviceNames,
                         (int position) -> {
-                            // TODO: add on click callback.
+                            sListener.onItemClick(position);
                         }));
         recyclerView.setLayoutManager(
                 new LinearLayoutManager(getActivity(), LinearLayoutManager.VERTICAL, false));
-        return builder.setView(mRootView).create();
+        AlertDialog dialog = builder.setView(mRootView).create();
+        dialog.setCanceledOnTouchOutside(false);
+        return dialog;
     }
 }
diff --git a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingSwitchBarController.java b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingSwitchBarController.java
index a375a3c..bd8027c 100644
--- a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingSwitchBarController.java
+++ b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingSwitchBarController.java
@@ -16,6 +16,8 @@
 
 package com.android.settings.connecteddevice.audiosharing;
 
+import android.bluetooth.BluetoothLeBroadcast;
+import android.bluetooth.BluetoothLeBroadcastMetadata;
 import android.content.Context;
 import android.util.Log;
 import android.widget.Switch;
@@ -24,36 +26,116 @@
 import androidx.lifecycle.DefaultLifecycleObserver;
 import androidx.lifecycle.LifecycleOwner;
 
+import com.android.settings.bluetooth.Utils;
 import com.android.settings.core.BasePreferenceController;
 import com.android.settings.dashboard.DashboardFragment;
 import com.android.settings.flags.Flags;
 import com.android.settings.widget.SettingsMainSwitchBar;
+import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcast;
+import com.android.settingslib.bluetooth.LocalBluetoothManager;
+import com.android.settingslib.utils.ThreadUtils;
 import com.android.settingslib.widget.OnMainSwitchChangeListener;
 
+import java.util.ArrayList;
+import java.util.concurrent.Executor;
+import java.util.concurrent.Executors;
+
 public class AudioSharingSwitchBarController extends BasePreferenceController
         implements DefaultLifecycleObserver, OnMainSwitchChangeListener {
     private static final String TAG = "AudioSharingSwitchBarCtl";
     private static final String PREF_KEY = "audio_sharing_main_switch";
-
-    private final Context mContext;
     private final SettingsMainSwitchBar mSwitchBar;
+    private final LocalBluetoothManager mBtManager;
+    private final LocalBluetoothLeBroadcast mBroadcast;
+    private final Executor mExecutor;
     private DashboardFragment mFragment;
 
+    private final BluetoothLeBroadcast.Callback mBroadcastCallback =
+            new BluetoothLeBroadcast.Callback() {
+                @Override
+                public void onBroadcastStarted(int reason, int broadcastId) {
+                    Log.d(
+                            TAG,
+                            "onBroadcastStarted(), reason = "
+                                    + reason
+                                    + ", broadcastId = "
+                                    + broadcastId);
+                    updateSwitch();
+                }
+
+                @Override
+                public void onBroadcastStartFailed(int reason) {
+                    Log.d(TAG, "onBroadcastStartFailed(), reason = " + reason);
+                    // TODO: handle broadcast start fail
+                    updateSwitch();
+                }
+
+                @Override
+                public void onBroadcastMetadataChanged(
+                        int broadcastId, @NonNull BluetoothLeBroadcastMetadata metadata) {
+                    Log.d(
+                            TAG,
+                            "onBroadcastMetadataChanged(), broadcastId = "
+                                    + broadcastId
+                                    + ", metadata = "
+                                    + metadata);
+                    // TODO: handle add sink if there are connected lea devices.
+                }
+
+                @Override
+                public void onBroadcastStopped(int reason, int broadcastId) {
+                    Log.d(
+                            TAG,
+                            "onBroadcastStopped(), reason = "
+                                    + reason
+                                    + ", broadcastId = "
+                                    + broadcastId);
+                    updateSwitch();
+                }
+
+                @Override
+                public void onBroadcastStopFailed(int reason) {
+                    Log.d(TAG, "onBroadcastStopFailed(), reason = " + reason);
+                    // TODO: handle broadcast stop fail
+                    updateSwitch();
+                }
+
+                @Override
+                public void onBroadcastUpdated(int reason, int broadcastId) {}
+
+                @Override
+                public void onBroadcastUpdateFailed(int reason, int broadcastId) {}
+
+                @Override
+                public void onPlaybackStarted(int reason, int broadcastId) {}
+
+                @Override
+                public void onPlaybackStopped(int reason, int broadcastId) {}
+            };
+
     AudioSharingSwitchBarController(Context context, SettingsMainSwitchBar switchBar) {
         super(context, PREF_KEY);
-        mContext = context;
         mSwitchBar = switchBar;
-        mSwitchBar.setChecked(false);
+        mBtManager = Utils.getLocalBtManager(context);
+        mBroadcast = mBtManager.getProfileManager().getLeAudioBroadcastProfile();
+        mExecutor = Executors.newSingleThreadExecutor();
+        mSwitchBar.setChecked(isBroadcasting());
     }
 
     @Override
     public void onStart(@NonNull LifecycleOwner owner) {
         mSwitchBar.addOnSwitchChangeListener(this);
+        if (mBroadcast != null) {
+            mBroadcast.registerServiceCallBack(mExecutor, mBroadcastCallback);
+        }
     }
 
     @Override
     public void onStop(@NonNull LifecycleOwner owner) {
         mSwitchBar.removeOnSwitchChangeListener(this);
+        if (mBroadcast != null) {
+            mBroadcast.unregisterServiceCallBack(mBroadcastCallback);
+        }
     }
 
     @Override
@@ -63,7 +145,7 @@
         if (isChecked) {
             startAudioSharing();
         } else {
-            // TODO: stop sharing
+            stopAudioSharing();
         }
     }
 
@@ -82,10 +164,53 @@
     }
 
     private void startAudioSharing() {
-        if (mFragment != null) {
-            AudioSharingDialogFragment.show(mFragment);
-        } else {
-            Log.w(TAG, "Dialog fail to show due to null fragment.");
+        mSwitchBar.setEnabled(false);
+        if (mBroadcast == null || isBroadcasting()) {
+            Log.d(TAG, "Already in broadcasting or broadcast not support, ignore!");
+            mSwitchBar.setEnabled(true);
+            return;
         }
+        if (mFragment == null) {
+            Log.w(TAG, "Dialog fail to show due to null fragment.");
+            mSwitchBar.setEnabled(true);
+            return;
+        }
+        ArrayList<String> deviceNames = new ArrayList<>();
+        AudioSharingDialogFragment.show(
+                mFragment,
+                deviceNames,
+                new AudioSharingDialogFragment.DialogEventListener() {
+                    @Override
+                    public void onItemClick(int position) {
+                        // TODO: handle broadcast based on the dialog device item clicked
+                    }
+
+                    @Override
+                    public void onCancelClick() {
+                        mBroadcast.startBroadcast("test", /* language= */ null);
+                    }
+                });
+    }
+
+    private void stopAudioSharing() {
+        mSwitchBar.setEnabled(false);
+        if (mBroadcast == null || !isBroadcasting()) {
+            Log.d(TAG, "Already not broadcasting or broadcast not support, ignore!");
+            mSwitchBar.setEnabled(true);
+            return;
+        }
+        mBroadcast.stopBroadcast(mBroadcast.getLatestBroadcastId());
+    }
+
+    private void updateSwitch() {
+        ThreadUtils.postOnMainThread(
+                () -> {
+                    mSwitchBar.setChecked(isBroadcasting());
+                    mSwitchBar.setEnabled(true);
+                });
+    }
+
+    private boolean isBroadcasting() {
+        return mBroadcast != null && mBroadcast.isEnabled(null);
     }
 }
diff --git a/src/com/android/settings/fuelgauge/batteryusage/BootBroadcastReceiver.java b/src/com/android/settings/fuelgauge/batteryusage/BootBroadcastReceiver.java
index ebf1543..dc8dfb6 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/BootBroadcastReceiver.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/BootBroadcastReceiver.java
@@ -70,8 +70,7 @@
                 break;
             case Intent.ACTION_TIME_CHANGED:
                 Log.d(TAG, "refresh job and clear all data from action=" + action);
-                DatabaseUtils.clearAll(context);
-                PeriodicJobManager.getInstance(context).refreshJob(/*fromBoot=*/ false);
+                DatabaseUtils.clearDataAfterTimeChangedIfNeeded(context);
                 break;
             default:
                 Log.w(TAG, "receive unsupported action=" + action);
diff --git a/src/com/android/settings/fuelgauge/batteryusage/DataProcessManager.java b/src/com/android/settings/fuelgauge/batteryusage/DataProcessManager.java
index 1a226fd..c298afa 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/DataProcessManager.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/DataProcessManager.java
@@ -72,8 +72,6 @@
     private static final String TAG = "DataProcessManager";
     private static final List<BatteryEventType> POWER_CONNECTION_EVENTS =
             List.of(BatteryEventType.POWER_CONNECTED, BatteryEventType.POWER_DISCONNECTED);
-    private static final List<BatteryEventType> BATTERY_LEVEL_RECORD_EVENTS =
-            List.of(BatteryEventType.FULL_CHARGED, BatteryEventType.EVEN_HOUR);
 
     // For testing only.
     @VisibleForTesting
@@ -575,7 +573,7 @@
         final List<BatteryEvent> batteryLevelRecordEvents =
                 DatabaseUtils.getBatteryEvents(
                         context, Calendar.getInstance(), lastFullChargeTime,
-                        BATTERY_LEVEL_RECORD_EVENTS);
+                        DatabaseUtils.BATTERY_LEVEL_RECORD_EVENTS);
         final long startTimestamp = batteryLevelRecordEvents.isEmpty()
                 ? lastFullChargeTime : batteryLevelRecordEvents.get(0).getTimestamp();
         final BatteryLevelData batteryLevelData = getPeriodBatteryLevelData(context, handler,
diff --git a/src/com/android/settings/fuelgauge/batteryusage/DatabaseUtils.java b/src/com/android/settings/fuelgauge/batteryusage/DatabaseUtils.java
index e78d25c..d099843 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/DatabaseUtils.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/DatabaseUtils.java
@@ -53,6 +53,7 @@
 import java.util.ArrayList;
 import java.util.Calendar;
 import java.util.List;
+import java.util.Locale;
 import java.util.Map;
 import java.util.Set;
 import java.util.function.Function;
@@ -133,6 +134,9 @@
                     .authority(AUTHORITY)
                     .appendPath(BATTERY_USAGE_SLOT_TABLE)
                     .build();
+    /** A list of level record event types to access battery usage data. */
+    public static final List<BatteryEventType> BATTERY_LEVEL_RECORD_EVENTS =
+            List.of(BatteryEventType.FULL_CHARGED, BatteryEventType.EVEN_HOUR);
 
     // For testing only.
     @VisibleForTesting
@@ -408,6 +412,35 @@
         });
     }
 
+    /** Clears all data and jobs if current timestamp is out of the range of last recorded job. */
+    public static void clearDataAfterTimeChangedIfNeeded(Context context) {
+        AsyncTask.execute(() -> {
+            try {
+                final List<BatteryEvent> batteryLevelRecordEvents =
+                        DatabaseUtils.getBatteryEvents(context, Calendar.getInstance(),
+                                getLastFullChargeTime(context), BATTERY_LEVEL_RECORD_EVENTS);
+                final long lastRecordTimestamp = batteryLevelRecordEvents.isEmpty()
+                        ? INVALID_TIMESTAMP : batteryLevelRecordEvents.get(0).getTimestamp();
+                final long nextRecordTimestamp =
+                        TimestampUtils.getNextEvenHourTimestamp(lastRecordTimestamp);
+                final long currentTime = System.currentTimeMillis();
+                final boolean isOutOfTimeRange = lastRecordTimestamp == INVALID_TIMESTAMP
+                        || currentTime < lastRecordTimestamp || currentTime > nextRecordTimestamp;
+                final String logInfo = String.format(Locale.ENGLISH,
+                        "clear database = %b, current time = %d, last record time = %d",
+                        isOutOfTimeRange, currentTime, lastRecordTimestamp);
+                Log.d(TAG, logInfo);
+                BatteryUsageLogUtils.writeLog(context, Action.TIME_UPDATED, logInfo);
+                if (isOutOfTimeRange) {
+                    DatabaseUtils.clearAll(context);
+                    PeriodicJobManager.getInstance(context).refreshJob(/* fromBoot= */ false);
+                }
+            } catch (RuntimeException e) {
+                Log.e(TAG, "refreshDataAndJobIfNeededAfterTimeChanged() failed", e);
+            }
+        });
+    }
+
     /** Returns the timestamp for 00:00 6 days before the calendar date. */
     public static long getTimestampSixDaysAgo(Calendar calendar) {
         Calendar startCalendar =
diff --git a/src/com/android/settings/localepicker/AppLocalePickerActivity.java b/src/com/android/settings/localepicker/AppLocalePickerActivity.java
index 194a08f..6706c6d 100644
--- a/src/com/android/settings/localepicker/AppLocalePickerActivity.java
+++ b/src/com/android/settings/localepicker/AppLocalePickerActivity.java
@@ -23,6 +23,7 @@
 import android.app.NotificationChannel;
 import android.app.NotificationManager;
 import android.app.PendingIntent;
+import android.app.settings.SettingsEnums;
 import android.content.Intent;
 import android.content.pm.PackageManager;
 import android.net.Uri;
@@ -45,12 +46,18 @@
 import com.android.settings.applications.AppLocaleUtil;
 import com.android.settings.applications.appinfo.AppLocaleDetails;
 import com.android.settings.core.SettingsBaseActivity;
+import com.android.settings.overlay.FeatureFactory;
+import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
 
 public class AppLocalePickerActivity extends SettingsBaseActivity
         implements LocalePickerWithRegion.LocaleSelectedListener, MenuItem.OnActionExpandListener {
     private static final String TAG = AppLocalePickerActivity.class.getSimpleName();
     private static final String CHANNEL_ID_SUGGESTION = "suggestion";
     private static final String CHANNEL_ID_SUGGESTION_TO_USER = "Locale suggestion";
+    private static final int SIM_LOCALE = 1 << 0;
+    private static final int SYSTEM_LOCALE = 1 << 1;
+    private static final int APP_LOCALE = 1 << 2;
+    private static final int IME_LOCALE = 1 << 3;
     static final String EXTRA_APP_LOCALE = "app_locale";
     static final String EXTRA_NOTIFICATION_ID = "notification_id";
 
@@ -59,6 +66,7 @@
     private AppLocaleDetails mAppLocaleDetails;
     private View mAppLocaleDetailContainer;
     private NotificationController mNotificationController;
+    private MetricsFeatureProvider mMetricsFeatureProvider;
 
     @Override
     public void onCreate(Bundle savedInstanceState) {
@@ -84,6 +92,7 @@
 
         setTitle(R.string.app_locale_picker_title);
         getActionBar().setDisplayHomeAsUpEnabled(true);
+        mMetricsFeatureProvider = FeatureFactory.getFeatureFactory().getMetricsFeatureProvider();
         mNotificationController = NotificationController.getInstance(this);
 
         mLocalePickerWithRegion = LocalePickerWithRegion.createLanguagePicker(
@@ -113,6 +122,7 @@
         if (localeInfo == null || localeInfo.getLocale() == null || localeInfo.isSystemLocale()) {
             setAppDefaultLocale("");
         } else {
+            logLocaleSource(localeInfo);
             setAppDefaultLocale(localeInfo.getLocale().toLanguageTag());
             broadcastAppLocaleChange(localeInfo);
         }
@@ -268,4 +278,32 @@
 
         return false;
     }
+
+    private void logLocaleSource(LocaleStore.LocaleInfo localeInfo) {
+        if (!localeInfo.isSuggested() || localeInfo.isAppCurrentLocale()) {
+            return;
+        }
+        int localeSource = 0;
+        if (hasSuggestionType(localeInfo,
+                LocaleStore.LocaleInfo.SUGGESTION_TYPE_SYSTEM_AVAILABLE_LANGUAGE)) {
+            localeSource |= SYSTEM_LOCALE;
+        }
+        if (hasSuggestionType(localeInfo,
+                LocaleStore.LocaleInfo.SUGGESTION_TYPE_OTHER_APP_LANGUAGE)) {
+            localeSource |= APP_LOCALE;
+        }
+        if (hasSuggestionType(localeInfo, LocaleStore.LocaleInfo.SUGGESTION_TYPE_IME_LANGUAGE)) {
+            localeSource |= IME_LOCALE;
+        }
+        if (hasSuggestionType(localeInfo, LocaleStore.LocaleInfo.SUGGESTION_TYPE_SIM)) {
+            localeSource |= SIM_LOCALE;
+        }
+        mMetricsFeatureProvider.action(this,
+                SettingsEnums.ACTION_CHANGE_APP_LANGUAGE_FROM_SUGGESTED, localeSource);
+    }
+
+    private static boolean hasSuggestionType(LocaleStore.LocaleInfo localeInfo,
+            int suggestionType) {
+        return localeInfo.isSuggestionOfType(suggestionType);
+    }
 }
diff --git a/src/com/android/settings/notification/app/AppChannelsBypassingDndPreferenceController.java b/src/com/android/settings/notification/app/AppChannelsBypassingDndPreferenceController.java
index 2830024..200a47b 100644
--- a/src/com/android/settings/notification/app/AppChannelsBypassingDndPreferenceController.java
+++ b/src/com/android/settings/notification/app/AppChannelsBypassingDndPreferenceController.java
@@ -39,13 +39,18 @@
 import com.android.settings.applications.AppInfoBase;
 import com.android.settings.core.PreferenceControllerMixin;
 import com.android.settings.core.SubSettingLauncher;
+import com.android.settings.flags.Flags;
 import com.android.settings.notification.NotificationBackend;
 import com.android.settingslib.PrimarySwitchPreference;
 import com.android.settingslib.RestrictedSwitchPreference;
 
 import java.util.ArrayList;
 import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
 import java.util.List;
+import java.util.Map;
+import java.util.Set;
 
 /**
  * Populates the PreferenceCategory with notification channels associated with the given app.
@@ -61,6 +66,9 @@
     private RestrictedSwitchPreference mAllNotificationsToggle;
     private PreferenceCategory mPreferenceCategory;
     private List<NotificationChannel> mChannels = new ArrayList<>();
+    private Set<String> mDuplicateChannelNames = new HashSet<>();
+    private Map<NotificationChannel, String> mChannelGroupNames =
+            new HashMap<NotificationChannel, String>();
 
     public AppChannelsBypassingDndPreferenceController(
             Context context,
@@ -135,10 +143,20 @@
                 List<NotificationChannel> newChannelList = new ArrayList<>();
                 List<NotificationChannelGroup> mChannelGroupList = mBackend.getGroups(mAppRow.pkg,
                         mAppRow.uid).getList();
+                Set<String> allChannelNames = new HashSet<>();
                 for (NotificationChannelGroup channelGroup : mChannelGroupList) {
                     for (NotificationChannel channel : channelGroup.getChannels()) {
                         if (!isConversation(channel)) {
                             newChannelList.add(channel);
+                            if (Flags.dedupeDndSettingsChannels()) {
+                                mChannelGroupNames.put(channel, channelGroup.getName().toString());
+                                // Check if channel name is unique on this page; if not, save it.
+                                if (allChannelNames.contains(channel.getName())) {
+                                    mDuplicateChannelNames.add(channel.getName().toString());
+                                } else {
+                                    allChannelNames.add(channel.getName().toString());
+                                }
+                            }
                         }
                     }
                 }
@@ -172,6 +190,17 @@
                             && isChannelConfigurable(channel)
                             && showNotification(channel));
             channelPreference.setTitle(BidiFormatter.getInstance().unicodeWrap(channel.getName()));
+            if (Flags.dedupeDndSettingsChannels()) {
+                // If the channel shares its name with another channel, set group name as summary
+                // to disambiguate in the list.
+                if (mDuplicateChannelNames.contains(channel.getName().toString())
+                        && mChannelGroupNames.containsKey(channel)
+                        && mChannelGroupNames.get(channel) != null
+                        && !mChannelGroupNames.get(channel).isEmpty()) {
+                    channelPreference.setSummary(BidiFormatter.getInstance().unicodeWrap(
+                            mChannelGroupNames.get(channel)));
+                }
+            }
             channelPreference.setChecked(showNotificationInDnd(channel));
             channelPreference.setOnPreferenceChangeListener(
                     new Preference.OnPreferenceChangeListener() {
diff --git a/src/com/android/settings/overlay/FeatureFactory.kt b/src/com/android/settings/overlay/FeatureFactory.kt
index ac689d9..bc0cf1f 100644
--- a/src/com/android/settings/overlay/FeatureFactory.kt
+++ b/src/com/android/settings/overlay/FeatureFactory.kt
@@ -39,6 +39,7 @@
 import com.android.settings.onboarding.OnboardingFeatureProvider
 import com.android.settings.overlay.FeatureFactory.Companion.setFactory
 import com.android.settings.panel.PanelFeatureProvider
+import com.android.settings.privatespace.PrivateSpaceLoginFeatureProvider
 import com.android.settings.search.SearchFeatureProvider
 import com.android.settings.security.SecurityFeatureProvider
 import com.android.settings.security.SecuritySettingsFeatureProvider
@@ -170,6 +171,11 @@
      */
     abstract val fastPairFeatureProvider: FastPairFeatureProvider
 
+    /**
+     * Gets implementation for Private Space account login feature.
+     */
+    abstract val privateSpaceLoginFeatureProvider: PrivateSpaceLoginFeatureProvider
+
     companion object {
         private var _factory: FeatureFactory? = null
 
diff --git a/src/com/android/settings/overlay/FeatureFactoryImpl.kt b/src/com/android/settings/overlay/FeatureFactoryImpl.kt
index 7f991b7..28dbb23 100644
--- a/src/com/android/settings/overlay/FeatureFactoryImpl.kt
+++ b/src/com/android/settings/overlay/FeatureFactoryImpl.kt
@@ -59,6 +59,8 @@
 import com.android.settings.security.SecurityFeatureProviderImpl
 import com.android.settings.security.SecuritySettingsFeatureProvider
 import com.android.settings.security.SecuritySettingsFeatureProviderImpl
+import com.android.settings.privatespace.PrivateSpaceLoginFeatureProvider
+import com.android.settings.privatespace.PrivateSpaceLoginFeatureProviderImpl
 import com.android.settings.slices.SlicesFeatureProviderImpl
 import com.android.settings.users.UserFeatureProviderImpl
 import com.android.settings.vpn2.AdvancedVpnFeatureProviderImpl
@@ -184,4 +186,8 @@
     override val fastPairFeatureProvider: FastPairFeatureProvider by lazy {
         FastPairFeatureProviderImpl()
     }
+
+    override val privateSpaceLoginFeatureProvider: PrivateSpaceLoginFeatureProvider by lazy {
+        PrivateSpaceLoginFeatureProviderImpl()
+    }
 }
diff --git a/src/com/android/settings/privatespace/AutoAdvanceSetupFragment.java b/src/com/android/settings/privatespace/AutoAdvanceSetupFragment.java
index 5456c01..3b59166 100644
--- a/src/com/android/settings/privatespace/AutoAdvanceSetupFragment.java
+++ b/src/com/android/settings/privatespace/AutoAdvanceSetupFragment.java
@@ -16,7 +16,8 @@
 
 package com.android.settings.privatespace;
 
-import static com.android.settings.privatespace.PrivateSpaceSetupActivity.SET_LOCK_ACTION;
+import static com.android.settings.privatespace.PrivateSpaceSetupActivity.ACCOUNT_LOGIN_ACTION;
+import static com.android.settings.privatespace.PrivateSpaceSetupActivity.EXTRA_ACTION_TYPE;
 
 import android.annotation.SuppressLint;
 import android.content.Intent;
@@ -134,7 +135,8 @@
     private void startActivityInPrivateUser(UserHandle userHandle) {
         /* Start new activity in private profile which is needed to set private profile lock */
         Intent intent = new Intent(getContext(), PrivateProfileContextHelperActivity.class);
-        getActivity().startActivityForResultAsUser(intent, SET_LOCK_ACTION, userHandle);
+        intent.putExtra(EXTRA_ACTION_TYPE, ACCOUNT_LOGIN_ACTION);
+        getActivity().startActivityForResultAsUser(intent, ACCOUNT_LOGIN_ACTION, userHandle);
     }
 
     private void showPrivateSpaceErrorScreen() {
diff --git a/src/com/android/settings/privatespace/PrivateProfileContextHelperActivity.java b/src/com/android/settings/privatespace/PrivateProfileContextHelperActivity.java
index c0d762a..0539f60 100644
--- a/src/com/android/settings/privatespace/PrivateProfileContextHelperActivity.java
+++ b/src/com/android/settings/privatespace/PrivateProfileContextHelperActivity.java
@@ -16,27 +16,84 @@
 
 package com.android.settings.privatespace;
 
+import static android.app.admin.DevicePolicyManager.ACTION_SET_NEW_PASSWORD;
+import static android.app.admin.DevicePolicyManager.EXTRA_PASSWORD_COMPLEXITY;
+import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_LOW;
+
+import static com.android.settings.privatespace.PrivateSpaceSetupActivity.ACCOUNT_LOGIN_ACTION;
+import static com.android.settings.privatespace.PrivateSpaceSetupActivity.EXTRA_ACTION_TYPE;
+import static com.android.settings.privatespace.PrivateSpaceSetupActivity.SET_LOCK_ACTION;
+
+import android.app.KeyguardManager;
+import android.content.Intent;
 import android.os.Bundle;
 
+import androidx.activity.result.ActivityResult;
+import androidx.activity.result.ActivityResultLauncher;
+import androidx.activity.result.contract.ActivityResultContracts;
+import androidx.annotation.Nullable;
 import androidx.fragment.app.FragmentActivity;
-import androidx.navigation.fragment.NavHostFragment;
 
-import com.android.settings.R;
 import com.android.settings.SetupWizardUtils;
+import com.android.settings.overlay.FeatureFactory;
 
 import com.google.android.setupdesign.util.ThemeHelper;
 
-/** Activity that is started as private profile user that helps to set private profile lock. */
+/** Activity that is started as private profile user that helps to set private profile lock or
+ * add an account on the private profile. */
 public class PrivateProfileContextHelperActivity extends FragmentActivity {
     private static final String TAG = "PrivateProfileHelper";
+    private final ActivityResultLauncher<Intent> mAddAccountToPrivateProfile =
+            registerForActivityResult(new ActivityResultContracts.StartActivityForResult(),
+                    this::onAccountAdded);
+    private final ActivityResultLauncher<Intent> mVerifyDeviceLock =
+            registerForActivityResult(new ActivityResultContracts.StartActivityForResult(),
+                    this::onSetDeviceNewLock);
+
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         setTheme(SetupWizardUtils.getTheme(this, getIntent()));
         ThemeHelper.trySetDynamicColor(this);
         super.onCreate(savedInstanceState);
-        setContentView(R.layout.privatespace_setup_root);
-        NavHostFragment navHostFragment = (NavHostFragment) getSupportFragmentManager()
-                .findFragmentById(R.id.ps_nav_host_fragment);
-        navHostFragment.getNavController().setGraph(R.navigation.privatespace_private_context_nav);
+        if (savedInstanceState == null) {
+            int action = getIntent().getIntExtra(EXTRA_ACTION_TYPE, -1);
+            if (action == ACCOUNT_LOGIN_ACTION) {
+                PrivateSpaceLoginFeatureProvider privateSpaceLoginFeatureProvider =
+                        FeatureFactory.getFeatureFactory().getPrivateSpaceLoginFeatureProvider();
+                if (!privateSpaceLoginFeatureProvider.initiateAccountLogin(this,
+                        mAddAccountToPrivateProfile)) {
+                    setResult(RESULT_OK);
+                    finish();
+                }
+            } else if (action == SET_LOCK_ACTION) {
+                createPrivateSpaceLock();
+            }
+        }
+    }
+
+    private void createPrivateSpaceLock() {
+        final Intent intent = new Intent(ACTION_SET_NEW_PASSWORD);
+        intent.putExtra(EXTRA_PASSWORD_COMPLEXITY, PASSWORD_COMPLEXITY_LOW);
+        mVerifyDeviceLock.launch(intent);
+    }
+
+    private void onAccountAdded(@Nullable ActivityResult result) {
+        if (result != null && result.getResultCode() == RESULT_OK) {
+            setResult(RESULT_OK);
+        } else {
+            setResult(RESULT_CANCELED);
+        }
+        finish();
+    }
+
+    private void onSetDeviceNewLock(@Nullable ActivityResult result) {
+        // TODO(b/307281644) : Verify this for biometrics and check result code after new
+        //  Authentication changes are merged.
+        if (result != null && getSystemService(KeyguardManager.class).isDeviceSecure()) {
+            setResult(RESULT_OK);
+        } else {
+            setResult(RESULT_CANCELED);
+        }
+        finish();
     }
 }
diff --git a/src/com/android/settings/privatespace/PrivateSpaceAccountLoginError.java b/src/com/android/settings/privatespace/PrivateSpaceAccountLoginError.java
new file mode 100644
index 0000000..2d263d7
--- /dev/null
+++ b/src/com/android/settings/privatespace/PrivateSpaceAccountLoginError.java
@@ -0,0 +1,85 @@
+/*
+ * 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.privatespace;
+
+import static com.android.settings.privatespace.PrivateSpaceSetupActivity.ACCOUNT_LOGIN_ACTION;
+import static com.android.settings.privatespace.PrivateSpaceSetupActivity.EXTRA_ACTION_TYPE;
+
+import android.annotation.SuppressLint;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.UserHandle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import androidx.activity.OnBackPressedCallback;
+import androidx.annotation.Nullable;
+import androidx.fragment.app.Fragment;
+
+import com.android.settings.R;
+
+import com.google.android.setupcompat.template.FooterBarMixin;
+import com.google.android.setupcompat.template.FooterButton;
+import com.google.android.setupdesign.GlifLayout;
+
+/** Fragment to display error screen if the profile is not signed in with a Google account. */
+public class PrivateSpaceAccountLoginError extends Fragment {
+    @Override
+    public View onCreateView(
+            LayoutInflater inflater,
+            @Nullable ViewGroup container,
+            @Nullable Bundle savedInstanceState) {
+        GlifLayout rootView =
+                (GlifLayout) inflater
+                        .inflate(R.layout.privatespace_account_login_error, container, false);
+        final FooterBarMixin mixin = rootView.getMixin(FooterBarMixin.class);
+        mixin.setPrimaryButton(
+                new FooterButton.Builder(getContext())
+                        .setText(R.string.privatespace_tryagain_label)
+                        .setListener(nextScreen())
+                        .setButtonType(FooterButton.ButtonType.NEXT)
+                        .setTheme(com.google.android.setupdesign.R.style.SudGlifButton_Primary)
+                        .build());
+        OnBackPressedCallback callback =
+                new OnBackPressedCallback(true /* enabled by default */) {
+                    @Override
+                    public void handleOnBackPressed() {
+                        // Handle the back button event
+                    }
+                };
+        requireActivity().getOnBackPressedDispatcher().addCallback(this, callback);
+
+        return rootView;
+    }
+
+    @SuppressLint("MissingPermission")
+    private View.OnClickListener nextScreen() {
+        return v -> {
+            PrivateSpaceMaintainer privateSpaceMaintainer = PrivateSpaceMaintainer
+                    .getInstance(getActivity());
+            UserHandle userHandle;
+            if (privateSpaceMaintainer.doesPrivateSpaceExist() && (userHandle =
+                    privateSpaceMaintainer.getPrivateProfileHandle()) != null) {
+                Intent intent = new Intent(getContext(), PrivateProfileContextHelperActivity.class);
+                intent.putExtra(EXTRA_ACTION_TYPE, ACCOUNT_LOGIN_ACTION);
+                getActivity().startActivityForResultAsUser(intent, ACCOUNT_LOGIN_ACTION,
+                        userHandle);
+            }
+        };
+    }
+}
diff --git a/src/com/android/settings/privatespace/PrivateSpaceLoginFeatureProvider.java b/src/com/android/settings/privatespace/PrivateSpaceLoginFeatureProvider.java
new file mode 100644
index 0000000..76ea9ac
--- /dev/null
+++ b/src/com/android/settings/privatespace/PrivateSpaceLoginFeatureProvider.java
@@ -0,0 +1,30 @@
+/*
+ * 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.privatespace;
+
+import android.content.Context;
+import android.content.Intent;
+
+import androidx.activity.result.ActivityResultLauncher;
+import androidx.annotation.NonNull;
+
+/** Feature provider for account login during Private Space setup. */
+public interface PrivateSpaceLoginFeatureProvider {
+    /** Returns true if login to an account is enabled during Private Space setup. */
+    boolean initiateAccountLogin(@NonNull Context context,
+            @NonNull ActivityResultLauncher<Intent> resultLauncher);
+}
diff --git a/src/com/android/settings/privatespace/PrivateSpaceLoginFeatureProviderImpl.java b/src/com/android/settings/privatespace/PrivateSpaceLoginFeatureProviderImpl.java
new file mode 100644
index 0000000..7fca2a4
--- /dev/null
+++ b/src/com/android/settings/privatespace/PrivateSpaceLoginFeatureProviderImpl.java
@@ -0,0 +1,32 @@
+/*
+ * 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.privatespace;
+
+import android.content.Context;
+import android.content.Intent;
+
+import androidx.activity.result.ActivityResultLauncher;
+import androidx.annotation.NonNull;
+
+/** Stub class for Private space to not initiate account login during setup */
+public class PrivateSpaceLoginFeatureProviderImpl implements PrivateSpaceLoginFeatureProvider {
+    @Override
+    public boolean initiateAccountLogin(@NonNull Context context,
+            @NonNull ActivityResultLauncher<Intent> resultLauncher) {
+        return false;
+    }
+}
diff --git a/src/com/android/settings/privatespace/PrivateSpaceSetLockFragment.java b/src/com/android/settings/privatespace/PrivateSpaceSetLockFragment.java
index 3d17638..93dc43b 100644
--- a/src/com/android/settings/privatespace/PrivateSpaceSetLockFragment.java
+++ b/src/com/android/settings/privatespace/PrivateSpaceSetLockFragment.java
@@ -16,25 +16,21 @@
 
 package com.android.settings.privatespace;
 
-import static android.app.Activity.RESULT_OK;
-import static android.app.admin.DevicePolicyManager.ACTION_SET_NEW_PASSWORD;
-import static android.app.admin.DevicePolicyManager.EXTRA_PASSWORD_COMPLEXITY;
-import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_LOW;
+import static com.android.settings.privatespace.PrivateSpaceSetupActivity.EXTRA_ACTION_TYPE;
+import static com.android.settings.privatespace.PrivateSpaceSetupActivity.SET_LOCK_ACTION;
 
-import android.app.Activity;
-import android.app.KeyguardManager;
+import android.annotation.SuppressLint;
 import android.content.Intent;
 import android.os.Bundle;
+import android.os.UserHandle;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
 
 import androidx.activity.OnBackPressedCallback;
-import androidx.activity.result.ActivityResult;
-import androidx.activity.result.ActivityResultLauncher;
-import androidx.activity.result.contract.ActivityResultContracts;
 import androidx.annotation.Nullable;
 import androidx.fragment.app.Fragment;
+import androidx.navigation.fragment.NavHostFragment;
 
 import com.android.settings.R;
 
@@ -45,9 +41,6 @@
 /** Fragment that provides an option to user to choose between the existing screen lock or set a
  * separate private profile lock. */
 public class PrivateSpaceSetLockFragment extends Fragment {
-    private final ActivityResultLauncher<Intent> mVerifyDeviceLock =
-            registerForActivityResult(new ActivityResultContracts.StartActivityForResult(),
-                    this::onSetDeviceNewLock);
 
     @Override
     public View onCreateView(
@@ -90,11 +83,8 @@
     private View.OnClickListener onClickUse() {
         return v -> {
             // Simply Use default screen lock. No need to handle
-            Activity activity = getActivity();
-            if (activity != null) {
-                activity.setResult(RESULT_OK);
-                activity.finish();
-            }
+            NavHostFragment.findNavController(PrivateSpaceSetLockFragment.this)
+                    .navigate(R.id.action_success_fragment);
         };
     }
 
@@ -104,22 +94,17 @@
         };
     }
 
+    @SuppressLint("MissingPermission")
     private void createPrivateSpaceLock() {
-        final Intent intent = new Intent(ACTION_SET_NEW_PASSWORD);
-        intent.putExtra(EXTRA_PASSWORD_COMPLEXITY, PASSWORD_COMPLEXITY_LOW);
-        mVerifyDeviceLock.launch(intent);
-    }
-
-    private void onSetDeviceNewLock(@Nullable ActivityResult result) {
-        // TODO(b/307281644) : Verify this for biometrics and check result code after new
-        //  Authentication changes are merged.
-        if (result != null) {
-            Activity profileContextHelperActivity = getActivity();
-            if (profileContextHelperActivity != null && profileContextHelperActivity
-                    .getSystemService(KeyguardManager.class).isDeviceSecure()) {
-                profileContextHelperActivity.setResult(RESULT_OK);
-                profileContextHelperActivity.finish();
-            }
+        PrivateSpaceMaintainer privateSpaceMaintainer = PrivateSpaceMaintainer
+                .getInstance(getActivity());
+        UserHandle userHandle;
+        if (privateSpaceMaintainer.doesPrivateSpaceExist() && (userHandle =
+                privateSpaceMaintainer.getPrivateProfileHandle()) != null) {
+            Intent intent = new Intent(getContext(), PrivateProfileContextHelperActivity.class);
+            intent.putExtra(EXTRA_ACTION_TYPE, SET_LOCK_ACTION);
+            getActivity().startActivityForResultAsUser(intent, SET_LOCK_ACTION,
+                    userHandle);
         }
     }
 }
diff --git a/src/com/android/settings/privatespace/PrivateSpaceSetupActivity.java b/src/com/android/settings/privatespace/PrivateSpaceSetupActivity.java
index 3a58e9e..a5628c8 100644
--- a/src/com/android/settings/privatespace/PrivateSpaceSetupActivity.java
+++ b/src/com/android/settings/privatespace/PrivateSpaceSetupActivity.java
@@ -31,6 +31,8 @@
 /** Activity class that helps in setting up of private space */
 public class PrivateSpaceSetupActivity extends FragmentActivity {
     public static final int SET_LOCK_ACTION = 1;
+    public static final int ACCOUNT_LOGIN_ACTION = 2;
+    public static final String EXTRA_ACTION_TYPE = "action_type";
     private NavHostFragment mNavHostFragment;
     @Override
     protected void onCreate(Bundle savedInstanceState) {
@@ -46,7 +48,13 @@
     @Override
     protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
         if (requestCode == SET_LOCK_ACTION && resultCode == RESULT_OK) {
-            mNavHostFragment.getNavController().navigate(R.id.action_advance_to_success);
+            mNavHostFragment.getNavController().navigate(R.id.action_success_fragment);
+        } else if (requestCode == ACCOUNT_LOGIN_ACTION) {
+            if (resultCode == RESULT_OK) {
+                mNavHostFragment.getNavController().navigate(R.id.action_set_lock_fragment);
+            } else {
+                mNavHostFragment.getNavController().navigate(R.id.action_advance_login_error);
+            }
         }
         super.onActivityResult(requestCode, resultCode, data);
     }
diff --git a/src/com/android/settings/privatespace/SetupSuccessFragment.java b/src/com/android/settings/privatespace/SetupSuccessFragment.java
index a8ca3f1..b761da7 100644
--- a/src/com/android/settings/privatespace/SetupSuccessFragment.java
+++ b/src/com/android/settings/privatespace/SetupSuccessFragment.java
@@ -70,7 +70,7 @@
     private View.OnClickListener onClickNext() {
         return v -> {
             accessPrivateSpaceToast();
-            // TODO: Replace with the intent to launch PS/PS Launch Settings
+            // TODO(b/306228087): Replace with the intent to launch All Apps once it is working.
             Intent startMain = new Intent(Intent.ACTION_MAIN);
             startMain.addCategory(Intent.CATEGORY_HOME);
             startActivity(startMain);
diff --git a/src/com/android/settings/spa/SettingsSpaEnvironment.kt b/src/com/android/settings/spa/SettingsSpaEnvironment.kt
index 40cc9a2..6b96460 100644
--- a/src/com/android/settings/spa/SettingsSpaEnvironment.kt
+++ b/src/com/android/settings/spa/SettingsSpaEnvironment.kt
@@ -30,12 +30,15 @@
 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.LongBackgroundTasksAppListProvider
 import com.android.settings.spa.app.specialaccess.MediaManagementAppsAppListProvider
 import com.android.settings.spa.app.specialaccess.ModifySystemSettingsAppListProvider
 import com.android.settings.spa.app.specialaccess.NfcTagAppsSettingsProvider
 import com.android.settings.spa.app.specialaccess.PictureInPictureListProvider
 import com.android.settings.spa.app.specialaccess.SpecialAppAccessPageProvider
+import com.android.settings.spa.app.specialaccess.TurnScreenOnAppsAppListProvider
 import com.android.settings.spa.app.specialaccess.UseFullScreenIntentAppListProvider
+import com.android.settings.spa.app.specialaccess.VoiceActivationAppsListProvider
 import com.android.settings.spa.app.specialaccess.WifiControlAppListProvider
 import com.android.settings.spa.app.storage.StorageAppListPageProvider
 import com.android.settings.spa.core.instrumentation.SpaLogProvider
@@ -66,8 +69,11 @@
             PictureInPictureListProvider,
             InstallUnknownAppsListProvider,
             AlarmsAndRemindersAppListProvider,
+            VoiceActivationAppsListProvider,
             WifiControlAppListProvider,
             NfcTagAppsSettingsProvider,
+            LongBackgroundTasksAppListProvider,
+            TurnScreenOnAppsAppListProvider,
         )
     }
 
diff --git a/src/com/android/settings/spa/about/AboutPhone.kt b/src/com/android/settings/spa/about/AboutPhone.kt
index 7343da0..5f9aa97 100644
--- a/src/com/android/settings/spa/about/AboutPhone.kt
+++ b/src/com/android/settings/spa/about/AboutPhone.kt
@@ -29,7 +29,6 @@
 import com.android.settingslib.spa.framework.common.SpaEnvironmentFactory
 import com.android.settingslib.spa.framework.common.createSettingsPage
 import com.android.settingslib.spa.framework.compose.navigator
-import com.android.settingslib.spa.framework.compose.toState
 import com.android.settingslib.spa.widget.preference.Preference
 import com.android.settingslib.spa.widget.preference.PreferenceModel
 import com.android.settingslib.spa.widget.scaffold.RegularScaffold
@@ -56,7 +55,7 @@
                 val deviceNamePresenter = remember { DeviceNamePresenter(context) }
                 Preference(object : PreferenceModel {
                     override val title = stringResource(R.string.about_settings)
-                    override val summary = deviceNamePresenter.deviceName.toState()
+                    override val summary = { deviceNamePresenter.deviceName }
                     override val onClick = navigator(name)
                     override val icon = @Composable {
                         SettingsIcon(imageVector = Icons.Outlined.PermDeviceInformation)
diff --git a/src/com/android/settings/spa/about/DeviceName.kt b/src/com/android/settings/spa/about/DeviceName.kt
index c481e32..86a9512 100644
--- a/src/com/android/settings/spa/about/DeviceName.kt
+++ b/src/com/android/settings/spa/about/DeviceName.kt
@@ -24,7 +24,6 @@
 import androidx.compose.ui.res.stringResource
 import com.android.settings.R
 import com.android.settings.deviceinfo.DeviceNamePreferenceController
-import com.android.settingslib.spa.framework.compose.toState
 import com.android.settingslib.spa.widget.dialog.AlertDialogButton
 import com.android.settingslib.spa.widget.dialog.rememberAlertDialogPresenter
 import com.android.settingslib.spa.widget.preference.Preference
@@ -48,7 +47,7 @@
         Preference(object : PreferenceModel {
             override val title =
                 stringResource(R.string.my_device_info_device_name_preference_title)
-            override val summary = deviceNamePresenter.deviceName.toState()
+            override val summary = { deviceNamePresenter.deviceName }
             override val onClick = dialogPresenter::open
         })
 
diff --git a/src/com/android/settings/spa/app/AllAppList.kt b/src/com/android/settings/spa/app/AllAppList.kt
index 383a0e8..5b13211 100644
--- a/src/com/android/settings/spa/app/AllAppList.kt
+++ b/src/com/android/settings/spa/app/AllAppList.kt
@@ -21,8 +21,6 @@
 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
 import com.android.settings.spa.app.appinfo.AppInfoSettingsProvider
@@ -116,7 +114,7 @@
         option: Int,
         recordListFlow: Flow<List<AppRecordWithSize>>,
     ): Flow<List<AppRecordWithSize>> = recordListFlow.filterItem(
-        when (SpinnerItem.values().getOrNull(option)) {
+        when (SpinnerItem.entries.getOrNull(option)) {
             SpinnerItem.Enabled -> ({ it.app.enabled && !it.app.isInstantApp })
             SpinnerItem.Disabled -> isDisabled
             SpinnerItem.Instant -> isInstant
@@ -130,22 +128,20 @@
     private val isInstant: (AppRecordWithSize) -> Boolean = { it.app.isInstantApp }
 
     @Composable
-    override fun getSummary(option: Int, record: AppRecordWithSize): State<String> {
+    override fun getSummary(option: Int, record: AppRecordWithSize): () -> String {
         val storageSummary = record.app.getStorageSummary()
-        return remember {
-            derivedStateOf {
-                storageSummary.value +
-                    when {
-                        !record.app.installed && !record.app.isArchived -> {
-                            System.lineSeparator() + context.getString(R.string.not_installed)
-                        }
-                        isDisabled(record) -> {
-                            System.lineSeparator() +
-                                context.getString(com.android.settingslib.R.string.disabled)
-                        }
-                        else -> ""
-                    }
+        return {
+            val summaryList = mutableListOf(storageSummary.value)
+            when {
+                !record.app.installed && !record.app.isArchived -> {
+                    summaryList += context.getString(R.string.not_installed)
+                }
+
+                isDisabled(record) -> {
+                    summaryList += context.getString(com.android.settingslib.R.string.disabled)
+                }
             }
+            summaryList.joinToString(separator = System.lineSeparator())
         }
     }
 
diff --git a/src/com/android/settings/spa/app/AppsMain.kt b/src/com/android/settings/spa/app/AppsMain.kt
index 2dea9c5..83b3080 100644
--- a/src/com/android/settings/spa/app/AppsMain.kt
+++ b/src/com/android/settings/spa/app/AppsMain.kt
@@ -30,7 +30,6 @@
 import com.android.settingslib.spa.framework.common.SpaEnvironmentFactory
 import com.android.settingslib.spa.framework.common.createSettingsPage
 import com.android.settingslib.spa.framework.compose.navigator
-import com.android.settingslib.spa.framework.compose.toState
 import com.android.settingslib.spa.widget.preference.Preference
 import com.android.settingslib.spa.widget.preference.PreferenceModel
 import com.android.settingslib.spa.widget.scaffold.RegularScaffold
@@ -54,10 +53,10 @@
     fun buildInjectEntry() =
         SettingsEntryBuilder.createInject(owner = owner)
             .setUiLayoutFn {
+                val summary = stringResource(R.string.app_and_notification_dashboard_summary)
                 Preference(object : PreferenceModel {
                     override val title = stringResource(R.string.apps_dashboard_title)
-                    override val summary =
-                        stringResource(R.string.app_and_notification_dashboard_summary).toState()
+                    override val summary = { summary }
                     override val onClick = navigator(name)
                     override val icon = @Composable {
                         SettingsIcon(imageVector = Icons.Outlined.Apps)
diff --git a/src/com/android/settings/spa/app/appcompat/UserAspectRatioAppPreference.kt b/src/com/android/settings/spa/app/appcompat/UserAspectRatioAppPreference.kt
index 61098e8..96884be 100644
--- a/src/com/android/settings/spa/app/appcompat/UserAspectRatioAppPreference.kt
+++ b/src/com/android/settings/spa/app/appcompat/UserAspectRatioAppPreference.kt
@@ -19,6 +19,7 @@
 import android.content.Context
 import android.content.pm.ApplicationInfo
 import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
 import androidx.compose.runtime.remember
 import androidx.compose.ui.platform.LocalContext
 import androidx.compose.ui.res.stringResource
@@ -40,11 +41,12 @@
     val presenter = remember { UserAspectRatioAppPresenter(context, app) }
     if (!presenter.isAvailableFlow.collectAsStateWithLifecycle(initialValue = false).value) return
 
+    val summary by presenter.summaryFlow.collectAsStateWithLifecycle(
+        initialValue = stringResource(R.string.summary_placeholder),
+    )
     Preference(object : PreferenceModel {
         override val title = stringResource(R.string.aspect_ratio_experimental_title)
-        override val summary = presenter.summaryFlow.collectAsStateWithLifecycle(
-            initialValue = stringResource(R.string.summary_placeholder),
-        )
+        override val summary = { summary }
         override val onClick = presenter::startActivity
     })
 }
@@ -75,4 +77,4 @@
         context,
         AppInfoSettingsProvider.METRICS_CATEGORY,
     )
-}
\ No newline at end of file
+}
diff --git a/src/com/android/settings/spa/app/appcompat/UserAspectRatioAppsPageProvider.kt b/src/com/android/settings/spa/app/appcompat/UserAspectRatioAppsPageProvider.kt
index deea745..5af29ef 100644
--- a/src/com/android/settings/spa/app/appcompat/UserAspectRatioAppsPageProvider.kt
+++ b/src/com/android/settings/spa/app/appcompat/UserAspectRatioAppsPageProvider.kt
@@ -28,7 +28,7 @@
 import androidx.compose.foundation.layout.Box
 import androidx.compose.foundation.layout.padding
 import androidx.compose.runtime.Composable
-import androidx.compose.runtime.State
+import androidx.compose.runtime.getValue
 import androidx.compose.runtime.remember
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.res.stringResource
@@ -41,15 +41,14 @@
 import com.android.settingslib.spa.framework.common.createSettingsPage
 import com.android.settingslib.spa.framework.compose.navigator
 import com.android.settingslib.spa.framework.compose.rememberContext
-import com.android.settingslib.spa.framework.compose.toState
 import com.android.settingslib.spa.framework.theme.SettingsDimension
 import com.android.settingslib.spa.framework.util.asyncMap
 import com.android.settingslib.spa.framework.util.filterItem
-import com.android.settingslib.spa.widget.preference.Preference
-import com.android.settingslib.spa.widget.preference.PreferenceModel
 import com.android.settingslib.spa.widget.illustration.Illustration
 import com.android.settingslib.spa.widget.illustration.IllustrationModel
 import com.android.settingslib.spa.widget.illustration.ResourceType
+import com.android.settingslib.spa.widget.preference.Preference
+import com.android.settingslib.spa.widget.preference.PreferenceModel
 import com.android.settingslib.spa.widget.ui.SettingsBody
 import com.android.settingslib.spa.widget.ui.SpinnerOption
 import com.android.settingslib.spaprivileged.model.app.AppListModel
@@ -80,12 +79,14 @@
 
     @Composable
     @VisibleForTesting
-    fun EntryItem() =
+    fun EntryItem() {
+        val summary = getSummary()
         Preference(object : PreferenceModel {
             override val title = stringResource(R.string.aspect_ratio_experimental_title)
-            override val summary = getSummary().toState()
+            override val summary = { summary }
             override val onClick = navigator(name)
         })
+    }
 
     @VisibleForTesting
     fun buildInjectEntry() = SettingsEntryBuilder
@@ -177,7 +178,7 @@
         option: Int,
         recordListFlow: Flow<List<UserAspectRatioAppListItemModel>>
     ): Flow<List<UserAspectRatioAppListItemModel>> = recordListFlow.filterItem(
-        when (SpinnerItem.values().getOrNull(option)) {
+        when (SpinnerItem.entries.getOrNull(option)) {
             SpinnerItem.Suggested -> ({ it.canDisplay && it.suggested })
             SpinnerItem.Overridden -> ({ it.userOverride != USER_MIN_ASPECT_RATIO_UNSET })
             else -> ({ it.canDisplay })
@@ -185,13 +186,15 @@
     )
 
     @Composable
-    override fun getSummary(option: Int, record: UserAspectRatioAppListItemModel) : State<String> =
-        remember(record.userOverride) {
+    override fun getSummary(option: Int, record: UserAspectRatioAppListItemModel): () -> String {
+        val summary by remember(record.userOverride) {
             flow {
                 emit(userAspectRatioManager.getUserMinAspectRatioEntry(record.userOverride,
                     record.app.packageName))
             }.flowOn(Dispatchers.IO)
         }.collectAsStateWithLifecycle(initialValue = stringResource(R.string.summary_placeholder))
+        return { summary }
+    }
 
     private fun getPackageAndActivityInfo(app: ApplicationInfo): PackageInfo? = try {
         packageManager.getPackageInfoAsUser(app.packageName, GET_ACTIVITIES_FLAGS, app.userId)
diff --git a/src/com/android/settings/spa/app/appinfo/AppAllServicesPreference.kt b/src/com/android/settings/spa/app/appinfo/AppAllServicesPreference.kt
index 34272d4..31e068c 100644
--- a/src/com/android/settings/spa/app/appinfo/AppAllServicesPreference.kt
+++ b/src/com/android/settings/spa/app/appinfo/AppAllServicesPreference.kt
@@ -24,6 +24,7 @@
 import android.os.Bundle
 import android.util.Log
 import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
 import androidx.compose.runtime.remember
 import androidx.compose.runtime.rememberCoroutineScope
 import androidx.compose.ui.platform.LocalContext
@@ -52,11 +53,12 @@
     val presenter = remember { AppAllServicesPresenter(context, app, coroutineScope) }
     if (!presenter.isAvailableFlow.collectAsStateWithLifecycle(initialValue = false).value) return
 
+    val summary by presenter.summaryFlow.collectAsStateWithLifecycle(
+        initialValue = stringResource(R.string.summary_placeholder),
+    )
     Preference(object : PreferenceModel {
         override val title = stringResource(R.string.app_info_all_services_label)
-        override val summary = presenter.summaryFlow.collectAsStateWithLifecycle(
-            initialValue = stringResource(R.string.summary_placeholder),
-        )
+        override val summary = { summary }
         override val onClick = presenter::startActivity
     })
 }
diff --git a/src/com/android/settings/spa/app/appinfo/AppBatteryPreference.kt b/src/com/android/settings/spa/app/appinfo/AppBatteryPreference.kt
index 7dd78a9..c707b44b 100644
--- a/src/com/android/settings/spa/app/appinfo/AppBatteryPreference.kt
+++ b/src/com/android/settings/spa/app/appinfo/AppBatteryPreference.kt
@@ -21,7 +21,6 @@
 import android.util.Log
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.LaunchedEffect
-import androidx.compose.runtime.derivedStateOf
 import androidx.compose.runtime.getValue
 import androidx.compose.runtime.mutableStateOf
 import androidx.compose.runtime.remember
@@ -91,16 +90,17 @@
         }
     }
 
-    val enabled = derivedStateOf { batteryDiffEntryState is LoadingState.Done }
+    val enabled = { batteryDiffEntryState is LoadingState.Done }
 
-    val summary = derivedStateOf<String> {
-        if (!app.installed) return@derivedStateOf ""
-        batteryDiffEntryState.let { batteryDiffEntryState ->
-            when (batteryDiffEntryState) {
-                is LoadingState.Loading -> context.getString(R.string.summary_placeholder)
-                is LoadingState.Done -> batteryDiffEntryState.result.getSummary()
+    val summary = {
+        if (app.installed) {
+            batteryDiffEntryState.let { batteryDiffEntryState ->
+                when (batteryDiffEntryState) {
+                    is LoadingState.Loading -> context.getString(R.string.summary_placeholder)
+                    is LoadingState.Done -> batteryDiffEntryState.result.getSummary()
+                }
             }
-        }
+        } else ""
     }
 
     private fun BatteryDiffEntry?.getSummary(): String =
@@ -155,7 +155,7 @@
 }
 
 private sealed class LoadingState<out T> {
-    object Loading : LoadingState<Nothing>()
+    data object Loading : LoadingState<Nothing>()
 
     data class Done<T>(val result: T) : LoadingState<T>()
 
diff --git a/src/com/android/settings/spa/app/appinfo/AppDataUsagePreference.kt b/src/com/android/settings/spa/app/appinfo/AppDataUsagePreference.kt
index ceb3986..057f911 100644
--- a/src/com/android/settings/spa/app/appinfo/AppDataUsagePreference.kt
+++ b/src/com/android/settings/spa/app/appinfo/AppDataUsagePreference.kt
@@ -20,6 +20,7 @@
 import android.content.pm.ApplicationInfo
 import android.net.NetworkTemplate
 import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
 import androidx.compose.runtime.remember
 import androidx.compose.runtime.rememberCoroutineScope
 import androidx.compose.ui.platform.LocalContext
@@ -34,7 +35,6 @@
 import com.android.settings.datausage.lib.INetworkTemplates
 import com.android.settings.datausage.lib.NetworkTemplates
 import com.android.settings.datausage.lib.NetworkTemplates.getTitleResId
-import com.android.settingslib.spa.framework.compose.toState
 import com.android.settingslib.spa.widget.preference.Preference
 import com.android.settingslib.spa.widget.preference.PreferenceModel
 import com.android.settingslib.spaprivileged.model.app.hasFlag
@@ -64,16 +64,17 @@
     }
     if (!presenter.isAvailableFlow.collectAsStateWithLifecycle(initialValue = false).value) return
 
+    val summary by presenter.summaryFlow.collectAsStateWithLifecycle(
+        initialValue = stringResource(R.string.computing_size),
+    )
     Preference(object : PreferenceModel {
         override val title = stringResource(
             presenter.titleResIdFlow.collectAsStateWithLifecycle(
                 initialValue = R.string.summary_placeholder,
             ).value
         )
-        override val summary = presenter.summaryFlow.collectAsStateWithLifecycle(
-            initialValue = stringResource(R.string.computing_size),
-        )
-        override val enabled = presenter.isEnabled().toState()
+        override val summary = { summary }
+        override val enabled = { presenter.isEnabled() }
         override val onClick = presenter::startActivity
     })
 }
diff --git a/src/com/android/settings/spa/app/appinfo/AppInfoSettings.kt b/src/com/android/settings/spa/app/appinfo/AppInfoSettings.kt
index ed912c3..3b7f579 100644
--- a/src/com/android/settings/spa/app/appinfo/AppInfoSettings.kt
+++ b/src/com/android/settings/spa/app/appinfo/AppInfoSettings.kt
@@ -32,6 +32,7 @@
 import androidx.lifecycle.compose.collectAsStateWithLifecycle
 import androidx.navigation.NavType
 import androidx.navigation.navArgument
+import com.android.settings.flags.Flags
 import com.android.settings.R
 import com.android.settings.applications.AppInfoBase
 import com.android.settings.applications.appinfo.AppInfoDashboardFragment
@@ -42,6 +43,7 @@
 import com.android.settings.spa.app.specialaccess.InstallUnknownAppsListProvider
 import com.android.settings.spa.app.specialaccess.ModifySystemSettingsAppListProvider
 import com.android.settings.spa.app.specialaccess.PictureInPictureListProvider
+import com.android.settings.spa.app.specialaccess.VoiceActivationAppsListProvider
 import com.android.settingslib.spa.framework.common.SettingsPageProvider
 import com.android.settingslib.spa.framework.compose.LifecycleEffect
 import com.android.settingslib.spa.framework.compose.navigator
@@ -160,6 +162,9 @@
             InstallUnknownAppsListProvider.InfoPageEntryItem(app)
             InteractAcrossProfilesDetailsPreference(app)
             AlarmsAndRemindersAppListProvider.InfoPageEntryItem(app)
+            if (Flags.enableVoiceActivationAppsInSettings()) {
+                VoiceActivationAppsListProvider.InfoPageEntryItem(app)
+            }
         }
 
         Category(title = stringResource(R.string.app_install_details_group_title)) {
diff --git a/src/com/android/settings/spa/app/appinfo/AppInstallerInfoPreference.kt b/src/com/android/settings/spa/app/appinfo/AppInstallerInfoPreference.kt
index 5a348f7..62e714a 100644
--- a/src/com/android/settings/spa/app/appinfo/AppInstallerInfoPreference.kt
+++ b/src/com/android/settings/spa/app/appinfo/AppInstallerInfoPreference.kt
@@ -19,15 +19,16 @@
 import android.content.Context
 import android.content.pm.ApplicationInfo
 import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
 import androidx.compose.runtime.remember
 import androidx.compose.runtime.rememberCoroutineScope
 import androidx.compose.ui.platform.LocalContext
 import androidx.compose.ui.res.stringResource
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
 import com.android.settings.R
 import com.android.settings.Utils
 import com.android.settings.applications.AppStoreUtil
 import com.android.settingslib.applications.AppUtils
-import androidx.lifecycle.compose.collectAsStateWithLifecycle
 import com.android.settingslib.spa.widget.preference.Preference
 import com.android.settingslib.spa.widget.preference.PreferenceModel
 import com.android.settingslib.spaprivileged.framework.common.asUser
@@ -49,13 +50,14 @@
     val presenter = remember { AppInstallerInfoPresenter(context, app, coroutineScope) }
     if (!presenter.isAvailableFlow.collectAsStateWithLifecycle(initialValue = false).value) return
 
+    val summary by presenter.summaryFlow.collectAsStateWithLifecycle(
+        initialValue = stringResource(R.string.summary_placeholder),
+    )
+    val enabled by presenter.enabledFlow.collectAsStateWithLifecycle(initialValue = false)
     Preference(object : PreferenceModel {
         override val title = stringResource(R.string.app_install_details_title)
-        override val summary = presenter.summaryFlow.collectAsStateWithLifecycle(
-            initialValue = stringResource(R.string.summary_placeholder),
-        )
-        override val enabled =
-            presenter.enabledFlow.collectAsStateWithLifecycle(initialValue = false)
+        override val summary = { summary }
+        override val enabled = { enabled }
         override val onClick = presenter::startActivity
     })
 }
diff --git a/src/com/android/settings/spa/app/appinfo/AppLocalePreference.kt b/src/com/android/settings/spa/app/appinfo/AppLocalePreference.kt
index 2d6fbb6..3b2aace 100644
--- a/src/com/android/settings/spa/app/appinfo/AppLocalePreference.kt
+++ b/src/com/android/settings/spa/app/appinfo/AppLocalePreference.kt
@@ -23,15 +23,16 @@
 import android.content.pm.PackageManager.ResolveInfoFlags
 import android.net.Uri
 import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
 import androidx.compose.runtime.remember
 import androidx.compose.ui.platform.LocalContext
 import androidx.compose.ui.res.stringResource
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
 import com.android.settings.R
 import com.android.settings.applications.AppInfoBase
 import com.android.settings.applications.AppLocaleUtil
 import com.android.settings.applications.appinfo.AppLocaleDetails
 import com.android.settings.localepicker.AppLocalePickerActivity
-import androidx.lifecycle.compose.collectAsStateWithLifecycle
 import com.android.settingslib.spa.widget.preference.Preference
 import com.android.settingslib.spa.widget.preference.PreferenceModel
 import com.android.settingslib.spaprivileged.model.app.userHandle
@@ -46,11 +47,12 @@
     val presenter = remember { AppLocalePresenter(context, app) }
     if (!presenter.isAvailableFlow.collectAsStateWithLifecycle(initialValue = false).value) return
 
+    val summary by presenter.summaryFlow.collectAsStateWithLifecycle(
+        initialValue = stringResource(R.string.summary_placeholder),
+    )
     Preference(object : PreferenceModel {
         override val title = stringResource(R.string.app_locale_preference_title)
-        override val summary = presenter.summaryFlow.collectAsStateWithLifecycle(
-            initialValue = stringResource(R.string.summary_placeholder),
-        )
+        override val summary = { summary }
         override val onClick = presenter::startActivity
     })
 }
diff --git a/src/com/android/settings/spa/app/appinfo/AppNotificationPreference.kt b/src/com/android/settings/spa/app/appinfo/AppNotificationPreference.kt
index 45033e7..28527c1 100644
--- a/src/com/android/settings/spa/app/appinfo/AppNotificationPreference.kt
+++ b/src/com/android/settings/spa/app/appinfo/AppNotificationPreference.kt
@@ -19,6 +19,7 @@
 import android.content.Context
 import android.content.pm.ApplicationInfo
 import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
 import androidx.compose.runtime.remember
 import androidx.compose.ui.platform.LocalContext
 import androidx.compose.ui.res.stringResource
@@ -29,7 +30,6 @@
 import com.android.settings.spa.notification.AppNotificationRepository
 import com.android.settings.spa.notification.IAppNotificationRepository
 import com.android.settingslib.spa.framework.compose.rememberContext
-import com.android.settingslib.spa.framework.compose.stateOf
 import com.android.settingslib.spa.widget.preference.Preference
 import com.android.settingslib.spa.widget.preference.PreferenceModel
 import com.android.settingslib.spaprivileged.model.app.installed
@@ -43,17 +43,17 @@
     repository: IAppNotificationRepository = rememberContext(::AppNotificationRepository),
 ) {
     val context = LocalContext.current
-    val summaryFlow = remember(app) {
+    val summary by remember(app) {
         flow {
             emit(repository.getNotificationSummary(app))
-        }.flowOn(Dispatchers.IO)
-    }
+        }.flowOn(Dispatchers.Default)
+    }.collectAsStateWithLifecycle(
+        initialValue = stringResource(R.string.summary_placeholder)
+    )
     Preference(object : PreferenceModel {
         override val title = stringResource(R.string.notifications_label)
-        override val summary = summaryFlow.collectAsStateWithLifecycle(
-            initialValue = stringResource(R.string.summary_placeholder)
-        )
-        override val enabled = stateOf(app.installed)
+        override val summary = { summary }
+        override val enabled = { app.installed }
         override val onClick = { navigateToAppNotificationSettings(context, app) }
     })
 }
@@ -65,4 +65,4 @@
         context,
         AppInfoSettingsProvider.METRICS_CATEGORY,
     )
-}
\ No newline at end of file
+}
diff --git a/src/com/android/settings/spa/app/appinfo/AppOpenByDefaultPreference.kt b/src/com/android/settings/spa/app/appinfo/AppOpenByDefaultPreference.kt
index 757ddc2..aae9569 100644
--- a/src/com/android/settings/spa/app/appinfo/AppOpenByDefaultPreference.kt
+++ b/src/com/android/settings/spa/app/appinfo/AppOpenByDefaultPreference.kt
@@ -19,6 +19,7 @@
 import android.content.Context
 import android.content.pm.ApplicationInfo
 import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
 import androidx.compose.runtime.remember
 import androidx.compose.ui.platform.LocalContext
 import androidx.compose.ui.res.stringResource
@@ -28,7 +29,6 @@
 import com.android.settings.applications.intentpicker.AppLaunchSettings
 import com.android.settings.applications.intentpicker.IntentPickerUtils
 import com.android.settingslib.applications.AppUtils
-import com.android.settingslib.spa.framework.compose.stateOf
 import com.android.settingslib.spa.widget.preference.Preference
 import com.android.settingslib.spa.widget.preference.PreferenceModel
 import com.android.settingslib.spaprivileged.framework.common.asUser
@@ -46,12 +46,13 @@
     val presenter = remember(app) { AppOpenByDefaultPresenter(context, app) }
     if (remember(presenter) { !presenter.isAvailable() }) return
 
+    val summary by presenter.summaryFlow.collectAsStateWithLifecycle(
+        initialValue = stringResource(R.string.summary_placeholder),
+    )
     Preference(object : PreferenceModel {
         override val title = stringResource(R.string.launch_by_default)
-        override val summary = presenter.summaryFlow.collectAsStateWithLifecycle(
-            initialValue = stringResource(R.string.summary_placeholder),
-        )
-        override val enabled = stateOf(presenter.isEnabled())
+        override val summary = { summary }
+        override val enabled = { presenter.isEnabled() }
         override val onClick = presenter::startActivity
     })
 }
diff --git a/src/com/android/settings/spa/app/appinfo/AppPermissionPreference.kt b/src/com/android/settings/spa/app/appinfo/AppPermissionPreference.kt
index ad666dc..ec1780f 100644
--- a/src/com/android/settings/spa/app/appinfo/AppPermissionPreference.kt
+++ b/src/com/android/settings/spa/app/appinfo/AppPermissionPreference.kt
@@ -22,7 +22,6 @@
 import android.content.pm.ApplicationInfo
 import android.util.Log
 import androidx.compose.runtime.Composable
-import androidx.compose.runtime.derivedStateOf
 import androidx.compose.runtime.livedata.observeAsState
 import androidx.compose.runtime.remember
 import androidx.compose.ui.platform.LocalContext
@@ -52,8 +51,8 @@
         model = remember {
             object : PreferenceModel {
                 override val title = context.getString(R.string.permissions_label)
-                override val summary = derivedStateOf { summaryState.value.summary }
-                override val enabled = derivedStateOf { summaryState.value.enabled }
+                override val summary = { summaryState.value.summary }
+                override val enabled = { summaryState.value.enabled }
                 override val onClick = { startManagePermissionsActivity(context, app) }
             }
         },
diff --git a/src/com/android/settings/spa/app/appinfo/AppStoragePreference.kt b/src/com/android/settings/spa/app/appinfo/AppStoragePreference.kt
index e8b1018..2b96454 100644
--- a/src/com/android/settings/spa/app/appinfo/AppStoragePreference.kt
+++ b/src/com/android/settings/spa/app/appinfo/AppStoragePreference.kt
@@ -19,9 +19,6 @@
 import android.content.Context
 import android.content.pm.ApplicationInfo
 import androidx.compose.runtime.Composable
-import androidx.compose.runtime.State
-import androidx.compose.runtime.derivedStateOf
-import androidx.compose.runtime.remember
 import androidx.compose.ui.platform.LocalContext
 import androidx.compose.ui.res.stringResource
 import com.android.settings.R
@@ -47,12 +44,13 @@
 }
 
 @Composable
-private fun getSummary(context: Context, app: ApplicationInfo): State<String> {
+private fun getSummary(context: Context, app: ApplicationInfo): () -> String {
     val sizeState = app.getStorageSize()
-    return remember {
-        derivedStateOf {
-            val size = sizeState.value
-            if (size.isBlank()) return@derivedStateOf context.getString(R.string.computing_size)
+    return {
+        val size = sizeState.value
+        if (size.isBlank()) {
+            context.getString(R.string.computing_size)
+        } else {
             val storageType = context.getString(
                 when (app.hasFlag(ApplicationInfo.FLAG_EXTERNAL_STORAGE)) {
                     true -> R.string.storage_type_external
diff --git a/src/com/android/settings/spa/app/appinfo/AppTimeSpentPreference.kt b/src/com/android/settings/spa/app/appinfo/AppTimeSpentPreference.kt
index 21b3d73..7ba61dc 100644
--- a/src/com/android/settings/spa/app/appinfo/AppTimeSpentPreference.kt
+++ b/src/com/android/settings/spa/app/appinfo/AppTimeSpentPreference.kt
@@ -22,6 +22,7 @@
 import android.content.pm.PackageManager.ResolveInfoFlags
 import android.provider.Settings
 import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
 import androidx.compose.runtime.livedata.observeAsState
 import androidx.compose.runtime.remember
 import androidx.compose.ui.platform.LocalContext
@@ -29,7 +30,6 @@
 import androidx.lifecycle.liveData
 import com.android.settings.R
 import com.android.settings.overlay.FeatureFactory.Companion.featureFactory
-import com.android.settingslib.spa.framework.compose.stateOf
 import com.android.settingslib.spa.widget.preference.Preference
 import com.android.settingslib.spa.widget.preference.PreferenceModel
 import com.android.settingslib.spaprivileged.model.app.hasFlag
@@ -43,12 +43,13 @@
     val presenter = remember { AppTimeSpentPresenter(context, app) }
     if (!presenter.isAvailable()) return
 
+    val summary by presenter.summaryLiveData.observeAsState(
+        initial = stringResource(R.string.summary_placeholder),
+    )
     Preference(object : PreferenceModel {
         override val title = stringResource(R.string.time_spent_in_app_pref_title)
-        override val summary = presenter.summaryLiveData.observeAsState(
-            initial = stringResource(R.string.summary_placeholder),
-        )
-        override val enabled = stateOf(presenter.isEnabled())
+        override val summary = { summary }
+        override val enabled = { presenter.isEnabled() }
         override val onClick = presenter::startActivity
     })
 }
diff --git a/src/com/android/settings/spa/app/appinfo/DefaultAppShortcutPreference.kt b/src/com/android/settings/spa/app/appinfo/DefaultAppShortcutPreference.kt
index 74c0aa4..51f6845 100644
--- a/src/com/android/settings/spa/app/appinfo/DefaultAppShortcutPreference.kt
+++ b/src/com/android/settings/spa/app/appinfo/DefaultAppShortcutPreference.kt
@@ -22,6 +22,7 @@
 import android.content.pm.ApplicationInfo
 import androidx.annotation.StringRes
 import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
 import androidx.compose.runtime.livedata.observeAsState
 import androidx.compose.runtime.remember
 import androidx.compose.ui.platform.LocalContext
@@ -57,11 +58,12 @@
     if (remember(presenter) { !presenter.isAvailable() }) return
     if (presenter.isVisible().observeAsState().value != true) return
 
+    val summary by presenter.summaryFlow.collectAsStateWithLifecycle(
+        initialValue = stringResource(R.string.summary_placeholder),
+    )
     Preference(object : PreferenceModel {
         override val title = stringResource(shortcut.titleResId)
-        override val summary = presenter.summaryFlow.collectAsStateWithLifecycle(
-            initialValue = stringResource(R.string.summary_placeholder),
-        )
+        override val summary = { summary }
         override val onClick = presenter::startActivity
     })
 }
diff --git a/src/com/android/settings/spa/app/appinfo/HibernationSwitchPreference.kt b/src/com/android/settings/spa/app/appinfo/HibernationSwitchPreference.kt
index f62a3be..77d68b5 100644
--- a/src/com/android/settings/spa/app/appinfo/HibernationSwitchPreference.kt
+++ b/src/com/android/settings/spa/app/appinfo/HibernationSwitchPreference.kt
@@ -31,12 +31,11 @@
 import androidx.compose.runtime.derivedStateOf
 import androidx.compose.runtime.remember
 import androidx.compose.ui.platform.LocalContext
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
 import com.android.settings.R
 import com.android.settings.Utils.PROPERTY_APP_HIBERNATION_ENABLED
 import com.android.settings.Utils.PROPERTY_HIBERNATION_TARGETS_PRE_S_APPS
 import com.android.settingslib.spa.framework.compose.OverridableFlow
-import androidx.lifecycle.compose.collectAsStateWithLifecycle
-import com.android.settingslib.spa.framework.compose.stateOf
 import com.android.settingslib.spa.widget.preference.SwitchPreference
 import com.android.settingslib.spa.widget.preference.SwitchPreferenceModel
 import com.android.settingslib.spaprivileged.framework.common.appHibernationManager
@@ -44,12 +43,12 @@
 import com.android.settingslib.spaprivileged.framework.common.asUser
 import com.android.settingslib.spaprivileged.framework.common.permissionControllerManager
 import com.android.settingslib.spaprivileged.model.app.userHandle
+import kotlin.coroutines.resume
+import kotlin.coroutines.suspendCoroutine
 import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.asExecutor
 import kotlinx.coroutines.flow.flow
 import kotlinx.coroutines.withContext
-import kotlin.coroutines.resume
-import kotlin.coroutines.suspendCoroutine
 
 @Composable
 fun HibernationSwitchPreference(app: ApplicationInfo) {
@@ -62,7 +61,7 @@
     SwitchPreference(remember {
         object : SwitchPreferenceModel {
             override val title = context.getString(R.string.unused_apps_switch)
-            override val summary = stateOf(context.getString(R.string.unused_apps_switch_summary))
+            override val summary = { context.getString(R.string.unused_apps_switch_summary) }
             override val changeable = isEligibleState
 
             override val checked = derivedStateOf {
diff --git a/src/com/android/settings/spa/app/appinfo/InstantAppDomainsPreference.kt b/src/com/android/settings/spa/app/appinfo/InstantAppDomainsPreference.kt
index 7b9480d..9c3ec97 100644
--- a/src/com/android/settings/spa/app/appinfo/InstantAppDomainsPreference.kt
+++ b/src/com/android/settings/spa/app/appinfo/InstantAppDomainsPreference.kt
@@ -32,9 +32,9 @@
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.platform.LocalContext
 import androidx.compose.ui.res.stringResource
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
 import com.android.settings.R
 import com.android.settings.Utils
-import androidx.lifecycle.compose.collectAsStateWithLifecycle
 import com.android.settingslib.spa.framework.theme.SettingsDimension
 import com.android.settingslib.spa.widget.preference.Preference
 import com.android.settingslib.spa.widget.preference.PreferenceModel
@@ -53,11 +53,12 @@
     val presenter = remember { InstantAppDomainsPresenter(context, app) }
     var openDialog by rememberSaveable { mutableStateOf(false) }
 
+    val summary by presenter.summaryFlow.collectAsStateWithLifecycle(
+        initialValue = stringResource(R.string.summary_placeholder),
+    )
     Preference(object : PreferenceModel {
         override val title = stringResource(R.string.app_launch_supported_domain_urls_title)
-        override val summary = presenter.summaryFlow.collectAsStateWithLifecycle(
-            initialValue = stringResource(R.string.summary_placeholder),
-        )
+        override val summary = { summary }
         override val onClick = { openDialog = true }
     })
 
diff --git a/src/com/android/settings/spa/app/appinfo/InteractAcrossProfilesDetailsPreference.kt b/src/com/android/settings/spa/app/appinfo/InteractAcrossProfilesDetailsPreference.kt
index 12f6907..905e057 100644
--- a/src/com/android/settings/spa/app/appinfo/InteractAcrossProfilesDetailsPreference.kt
+++ b/src/com/android/settings/spa/app/appinfo/InteractAcrossProfilesDetailsPreference.kt
@@ -19,13 +19,14 @@
 import android.content.Context
 import android.content.pm.ApplicationInfo
 import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
 import androidx.compose.runtime.remember
 import androidx.compose.ui.platform.LocalContext
 import androidx.compose.ui.res.stringResource
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
 import com.android.settings.R
 import com.android.settings.applications.appinfo.AppInfoDashboardFragment
 import com.android.settings.applications.specialaccess.interactacrossprofiles.InteractAcrossProfilesDetails
-import androidx.lifecycle.compose.collectAsStateWithLifecycle
 import com.android.settingslib.spa.widget.preference.Preference
 import com.android.settingslib.spa.widget.preference.PreferenceModel
 import com.android.settingslib.spaprivileged.framework.common.crossProfileApps
@@ -39,11 +40,12 @@
     val presenter = remember { InteractAcrossProfilesDetailsPresenter(context, app) }
     if (!presenter.isAvailableFlow.collectAsStateWithLifecycle(initialValue = false).value) return
 
+    val summary by presenter.summaryFlow.collectAsStateWithLifecycle(
+        initialValue = stringResource(R.string.summary_placeholder),
+    )
     Preference(object : PreferenceModel {
         override val title = stringResource(R.string.interact_across_profiles_title)
-        override val summary = presenter.summaryFlow.collectAsStateWithLifecycle(
-            initialValue = stringResource(R.string.summary_placeholder),
-        )
+        override val summary = { summary }
         override val onClick = presenter::startActivity
     })
 }
diff --git a/src/com/android/settings/spa/app/backgroundinstall/BackgroundInstalledAppsPageProvider.kt b/src/com/android/settings/spa/app/backgroundinstall/BackgroundInstalledAppsPageProvider.kt
index 6e0643b..89f473b 100644
--- a/src/com/android/settings/spa/app/backgroundinstall/BackgroundInstalledAppsPageProvider.kt
+++ b/src/com/android/settings/spa/app/backgroundinstall/BackgroundInstalledAppsPageProvider.kt
@@ -32,6 +32,7 @@
 import androidx.compose.material.icons.outlined.Delete
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.State
+import androidx.compose.runtime.getValue
 import androidx.compose.runtime.produceState
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.platform.LocalContext
@@ -88,9 +89,10 @@
     @Composable
     fun EntryItem() {
         if(featureIsDisabled) return
+        val summary by generatePreferenceSummary()
         Preference(object : PreferenceModel {
             override val title = stringResource(R.string.background_install_title)
-            override val summary = generatePreferenceSummary()
+            override val summary = { summary }
             override val onClick = navigator(name)
         })
     }
diff --git a/src/com/android/settings/spa/app/specialaccess/LongBackgroundTasksApps.kt b/src/com/android/settings/spa/app/specialaccess/LongBackgroundTasksApps.kt
new file mode 100644
index 0000000..3ba9b08
--- /dev/null
+++ b/src/com/android/settings/spa/app/specialaccess/LongBackgroundTasksApps.kt
@@ -0,0 +1,54 @@
+/*
+ * 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.specialaccess
+
+import android.Manifest
+import android.app.AppOpsManager
+import android.app.settings.SettingsEnums
+import android.content.Context
+import com.android.settings.R
+import com.android.settings.overlay.FeatureFactory.Companion.featureFactory
+import com.android.settingslib.spaprivileged.template.app.AppOpPermissionListModel
+import com.android.settingslib.spaprivileged.template.app.AppOpPermissionRecord
+import com.android.settingslib.spaprivileged.template.app.TogglePermissionAppListProvider
+
+object LongBackgroundTasksAppListProvider : TogglePermissionAppListProvider {
+    override val permissionType = "LongBackgroundTasksApps"
+    override fun createModel(context: Context) = LongBackgroundTasksAppsListModel(context)
+}
+
+class LongBackgroundTasksAppsListModel(context: Context) : AppOpPermissionListModel(context) {
+    override val pageTitleResId = R.string.long_background_tasks_title
+    override val switchTitleResId = R.string.long_background_tasks_switch_title
+    override val footerResId = R.string.long_background_tasks_footer_title
+    override val appOp = AppOpsManager.OP_RUN_USER_INITIATED_JOBS
+    override val permission = Manifest.permission.RUN_USER_INITIATED_JOBS
+    override val setModeByUid = true
+
+    override fun setAllowed(record: AppOpPermissionRecord, newAllowed: Boolean) {
+        super.setAllowed(record, newAllowed)
+        logPermissionChange(newAllowed)
+    }
+
+    private fun logPermissionChange(newAllowed: Boolean) {
+        featureFactory.metricsFeatureProvider.action(
+            context,
+            SettingsEnums.ACTION_LONG_BACKGROUND_TASKS_TOGGLE,
+            if (newAllowed) 1 else 0
+        )
+    }
+}
\ No newline at end of file
diff --git a/src/com/android/settings/spa/app/specialaccess/SpecialAppAccess.kt b/src/com/android/settings/spa/app/specialaccess/SpecialAppAccess.kt
index b40e32b..fb05a38 100644
--- a/src/com/android/settings/spa/app/specialaccess/SpecialAppAccess.kt
+++ b/src/com/android/settings/spa/app/specialaccess/SpecialAppAccess.kt
@@ -66,7 +66,10 @@
                 PictureInPictureListProvider,
                 InstallUnknownAppsListProvider,
                 AlarmsAndRemindersAppListProvider,
+                VoiceActivationAppsListProvider,
                 WifiControlAppListProvider,
+                LongBackgroundTasksAppListProvider,
+                TurnScreenOnAppsAppListProvider,
             )
             .map { it.buildAppListInjectEntry().setLink(fromPage = owner).build() }
     }
diff --git a/src/com/android/settings/spa/app/specialaccess/TurnScreenOnApps.kt b/src/com/android/settings/spa/app/specialaccess/TurnScreenOnApps.kt
new file mode 100644
index 0000000..262acb7
--- /dev/null
+++ b/src/com/android/settings/spa/app/specialaccess/TurnScreenOnApps.kt
@@ -0,0 +1,54 @@
+/*
+ * 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.specialaccess
+
+import android.Manifest
+import android.app.AppOpsManager
+import android.app.settings.SettingsEnums
+import android.content.Context
+import com.android.settings.R
+import com.android.settings.overlay.FeatureFactory.Companion.featureFactory
+import com.android.settingslib.spaprivileged.template.app.AppOpPermissionListModel
+import com.android.settingslib.spaprivileged.template.app.AppOpPermissionRecord
+import com.android.settingslib.spaprivileged.template.app.TogglePermissionAppListProvider
+
+object TurnScreenOnAppsAppListProvider : TogglePermissionAppListProvider {
+    override val permissionType = "TurnScreenOnApps"
+    override fun createModel(context: Context) = TurnScreenOnAppsListModel(context)
+}
+
+class TurnScreenOnAppsListModel(context: Context) : AppOpPermissionListModel(context) {
+    override val pageTitleResId = com.android.settingslib.R.string.turn_screen_on_title
+    override val switchTitleResId = com.android.settingslib.R.string.allow_turn_screen_on
+    override val footerResId = com.android.settingslib.R.string.allow_turn_screen_on_description
+    override val appOp = AppOpsManager.OP_TURN_SCREEN_ON
+    override val permission = Manifest.permission.TURN_SCREEN_ON
+    override val setModeByUid = true
+
+    override fun setAllowed(record: AppOpPermissionRecord, newAllowed: Boolean) {
+        super.setAllowed(record, newAllowed)
+        logPermissionChange(newAllowed)
+    }
+
+    private fun logPermissionChange(newAllowed: Boolean) {
+        featureFactory.metricsFeatureProvider.action(
+            context,
+            SettingsEnums.SETTINGS_MANAGE_TURN_SCREEN_ON,
+            if (newAllowed) 1 else 0
+        )
+    }
+}
\ No newline at end of file
diff --git a/src/com/android/settings/spa/app/specialaccess/VoiceActivationApps.kt b/src/com/android/settings/spa/app/specialaccess/VoiceActivationApps.kt
new file mode 100644
index 0000000..de5f3b7
--- /dev/null
+++ b/src/com/android/settings/spa/app/specialaccess/VoiceActivationApps.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.specialaccess
+
+import android.Manifest
+import android.app.AppOpsManager
+import android.app.settings.SettingsEnums
+import android.content.Context
+import android.content.res.Resources
+import com.android.settings.R
+import com.android.settings.overlay.FeatureFactory
+import com.android.settingslib.spaprivileged.template.app.AppOpPermissionListModel
+import com.android.settingslib.spaprivileged.template.app.AppOpPermissionRecord
+import com.android.settingslib.spaprivileged.template.app.TogglePermissionAppListProvider
+
+
+object VoiceActivationAppsListProvider : TogglePermissionAppListProvider {
+    override val permissionType = "VoiceActivationApps"
+    override fun createModel(context: Context) = VoiceActivationAppsListModel(context)
+}
+
+class VoiceActivationAppsListModel(context: Context) : AppOpPermissionListModel(context) {
+    override val pageTitleResId = R.string.voice_activation_apps_title
+    override val switchTitleResId = R.string.permit_voice_activation_apps
+    override val footerResId = R.string.allow_voice_activation_apps_description
+    override val appOp = AppOpsManager.OP_RECEIVE_SANDBOX_TRIGGER_AUDIO
+    override val permission = Manifest.permission.RECEIVE_SANDBOX_TRIGGER_AUDIO
+    override val setModeByUid = true
+
+    override fun setAllowed(record: AppOpPermissionRecord, newAllowed: Boolean) {
+        super.setAllowed(record, newAllowed)
+        logPermissionChange(newAllowed)
+    }
+
+    private fun logPermissionChange(newAllowed: Boolean) {
+        val category = when {
+            newAllowed -> SettingsEnums.APP_SPECIAL_PERMISSION_RECEIVE_SANDBOX_TRIGGER_AUDIO_ALLOW
+            else -> SettingsEnums.APP_SPECIAL_PERMISSION_RECEIVE_SANDBOX_TRIGGER_AUDIO_DENY
+        }
+        /**
+         * Leave the package string empty as we should not log the package names for the collected
+         * metrics.
+         */
+        FeatureFactory.featureFactory.metricsFeatureProvider.action(context, category, "")
+    }
+}
\ No newline at end of file
diff --git a/src/com/android/settings/spa/app/specialaccess/VoiceActivationAppsPreferenceController.kt b/src/com/android/settings/spa/app/specialaccess/VoiceActivationAppsPreferenceController.kt
new file mode 100644
index 0000000..27d4b4b
--- /dev/null
+++ b/src/com/android/settings/spa/app/specialaccess/VoiceActivationAppsPreferenceController.kt
@@ -0,0 +1,38 @@
+/*
+ * 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.specialaccess
+
+import android.content.Context
+import androidx.preference.Preference
+import com.android.settings.core.BasePreferenceController
+import com.android.settings.flags.Flags
+import com.android.settings.spa.SpaActivity.Companion.startSpaActivity
+
+class VoiceActivationAppsPreferenceController(context: Context, preferenceKey: String) :
+        BasePreferenceController(context, preferenceKey) {
+    override fun getAvailabilityStatus() =
+        if (Flags.enableVoiceActivationAppsInSettings()) AVAILABLE
+        else CONDITIONALLY_UNAVAILABLE
+
+    override fun handlePreferenceTreeClick(preference: Preference): Boolean {
+        if (preference.key == mPreferenceKey) {
+            mContext.startSpaActivity(VoiceActivationAppsListProvider.getAppListRoute())
+            return true
+        }
+        return false
+    }
+}
\ No newline at end of file
diff --git a/src/com/android/settings/spa/app/storage/StorageAppList.kt b/src/com/android/settings/spa/app/storage/StorageAppList.kt
index 8fc3eb5..c33de33 100644
--- a/src/com/android/settings/spa/app/storage/StorageAppList.kt
+++ b/src/com/android/settings/spa/app/storage/StorageAppList.kt
@@ -22,7 +22,7 @@
 import androidx.annotation.StringRes
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.State
-import androidx.compose.runtime.derivedStateOf
+import androidx.compose.runtime.getValue
 import androidx.compose.runtime.remember
 import androidx.compose.ui.platform.LocalContext
 import androidx.compose.ui.res.stringResource
@@ -121,13 +121,9 @@
     ): Flow<List<AppRecordWithSize>> = recordListFlow.filterItem { type.filter(it) }
 
     @Composable
-    override fun getSummary(option: Int, record: AppRecordWithSize): State<String> {
-        val storageSummary = record.app.getStorageSummary()
-        return remember {
-            derivedStateOf {
-                storageSummary.value
-            }
-        }
+    override fun getSummary(option: Int, record: AppRecordWithSize): () -> String {
+        val storageSummary by record.app.getStorageSummary()
+        return { storageSummary }
     }
 
     @Composable
diff --git a/src/com/android/settings/spa/development/UsageStatsListModel.kt b/src/com/android/settings/spa/development/UsageStatsListModel.kt
index 61c24ac..d27796d 100644
--- a/src/com/android/settings/spa/development/UsageStatsListModel.kt
+++ b/src/com/android/settings/spa/development/UsageStatsListModel.kt
@@ -22,10 +22,8 @@
 import android.content.pm.ApplicationInfo
 import android.text.format.DateUtils
 import androidx.compose.runtime.Composable
-import androidx.compose.runtime.State
 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
@@ -55,7 +53,7 @@
         }
 
     override fun getSpinnerOptions(recordList: List<UsageStatsAppRecord>): List<SpinnerOption> =
-        SpinnerItem.values().map {
+        SpinnerItem.entries.map {
             SpinnerOption(
                 id = it.ordinal,
                 text = context.getString(it.stringResId),
@@ -77,7 +75,7 @@
     }.then(super.getComparator(option))
 
     @Composable
-    override fun getSummary(option: Int, record: UsageStatsAppRecord): State<String>? {
+    override fun getSummary(option: Int, record: UsageStatsAppRecord): (() -> String)? {
         val usageStats = record.usageStats ?: return null
         val lastTimeUsed = DateUtils.formatSameDayTime(
             usageStats.lastTimeUsed, now, DateFormat.MEDIUM, DateFormat.MEDIUM
@@ -85,7 +83,7 @@
         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"
-        return stateOf("$lastTimeUsedLine\n$usageTimeLine")
+        return { "$lastTimeUsedLine\n$usageTimeLine" }
     }
 
     private fun getUsageStats(): Map<String, UsageStats> {
@@ -101,7 +99,7 @@
         AppName(R.string.usage_stats_sort_by_app_name);
 
         companion object {
-            fun Int.toSpinnerItem(): SpinnerItem = values()[this]
+            fun Int.toSpinnerItem(): SpinnerItem = entries[this]
         }
     }
 }
diff --git a/src/com/android/settings/spa/development/compat/PlatformCompatAppListModel.kt b/src/com/android/settings/spa/development/compat/PlatformCompatAppListModel.kt
index c6752b9..8f53698 100644
--- a/src/com/android/settings/spa/development/compat/PlatformCompatAppListModel.kt
+++ b/src/com/android/settings/spa/development/compat/PlatformCompatAppListModel.kt
@@ -24,7 +24,6 @@
 import androidx.core.os.bundleOf
 import com.android.settings.core.SubSettingLauncher
 import com.android.settings.development.compat.PlatformCompatDashboard
-import com.android.settingslib.spa.framework.compose.stateOf
 import com.android.settingslib.spa.framework.util.filterItem
 import com.android.settingslib.spa.framework.util.mapItem
 import com.android.settingslib.spaprivileged.model.app.AppListModel
@@ -53,8 +52,9 @@
     }
 
     @Composable
-    override fun getSummary(option: Int, record: PlatformCompatAppRecord) =
-        stateOf(record.app.packageName)
+    override fun getSummary(option: Int, record: PlatformCompatAppRecord): () -> String = {
+        record.app.packageName
+    }
 
     @Composable
     override fun AppListItemModel<PlatformCompatAppRecord>.AppItem() {
diff --git a/src/com/android/settings/spa/network/NetworkAndInternet.kt b/src/com/android/settings/spa/network/NetworkAndInternet.kt
index 777133e..f985237 100644
--- a/src/com/android/settings/spa/network/NetworkAndInternet.kt
+++ b/src/com/android/settings/spa/network/NetworkAndInternet.kt
@@ -34,7 +34,6 @@
 import com.android.settingslib.spa.framework.common.SpaEnvironmentFactory
 import com.android.settingslib.spa.framework.common.createSettingsPage
 import com.android.settingslib.spa.framework.compose.navigator
-import com.android.settingslib.spa.framework.compose.toState
 import com.android.settingslib.spa.widget.preference.Preference
 import com.android.settingslib.spa.widget.preference.PreferenceModel
 import com.android.settingslib.spa.widget.scaffold.RegularScaffold
@@ -60,9 +59,10 @@
     fun buildInjectEntry(): SettingsEntryBuilder {
         return SettingsEntryBuilder.createInject(owner = owner)
             .setUiLayoutFn {
+                val summary = stringResource(getSummaryResId())
                 Preference(object : PreferenceModel {
                     override val title = stringResource(R.string.network_dashboard_title)
-                    override val summary = stringResource(getSummaryResId()).toState()
+                    override val summary = { summary }
                     override val onClick = navigator(name)
                     override val icon = @Composable {
                         SettingsIcon(imageVector = Icons.Outlined.Wifi)
diff --git a/src/com/android/settings/spa/notification/AppListNotifications.kt b/src/com/android/settings/spa/notification/AppListNotifications.kt
index c1e5d64..00e4394 100644
--- a/src/com/android/settings/spa/notification/AppListNotifications.kt
+++ b/src/com/android/settings/spa/notification/AppListNotifications.kt
@@ -23,7 +23,6 @@
 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.compose.toState
 import com.android.settingslib.spa.widget.preference.Preference
 import com.android.settingslib.spa.widget.preference.PreferenceModel
 import com.android.settingslib.spaprivileged.template.app.AppListPage
@@ -41,9 +40,10 @@
 
     @Composable
     fun EntryItem() {
+        val summary = stringResource(R.string.app_notification_field_summary)
         Preference(object : PreferenceModel {
             override val title = stringResource(R.string.app_notifications_title)
-            override val summary = stringResource(R.string.app_notification_field_summary).toState()
+            override val summary = { summary }
             override val onClick = navigator(name)
         })
     }
diff --git a/src/com/android/settings/spa/notification/AppNotificationsListModel.kt b/src/com/android/settings/spa/notification/AppNotificationsListModel.kt
index 0b9b676..692ffcb 100644
--- a/src/com/android/settings/spa/notification/AppNotificationsListModel.kt
+++ b/src/com/android/settings/spa/notification/AppNotificationsListModel.kt
@@ -27,7 +27,6 @@
 import com.android.settings.applications.AppInfoBase
 import com.android.settings.notification.app.AppNotificationSettings
 import com.android.settings.spa.notification.SpinnerItem.Companion.toSpinnerItem
-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
@@ -91,16 +90,17 @@
     }.then(super.getComparator(option))
 
     @Composable
-    override fun getSummary(option: Int, record: AppNotificationsRecord) = record.sentState?.let {
-        when (option.toSpinnerItem()) {
-            SpinnerItem.MostRecent -> stateOf(formatLastSent(it.lastSent))
-            SpinnerItem.MostFrequent -> stateOf(repository.calculateFrequencySummary(it.sentCount))
-            else -> null
+    override fun getSummary(option: Int, record: AppNotificationsRecord): (() -> String)? =
+        record.sentState?.let {
+            when (option.toSpinnerItem()) {
+                SpinnerItem.MostRecent -> ({ formatLastSent(it.lastSent) })
+                SpinnerItem.MostFrequent -> ({ repository.calculateFrequencySummary(it.sentCount) })
+                else -> null
+            }
         }
-    }
 
     override fun getSpinnerOptions(recordList: List<AppNotificationsRecord>): List<SpinnerOption> =
-        SpinnerItem.values().map {
+        SpinnerItem.entries.map {
             SpinnerOption(
                 id = it.ordinal,
                 text = context.getString(it.stringResId),
@@ -145,6 +145,6 @@
     TurnedOff(R.string.filter_notif_blocked_apps);
 
     companion object {
-        fun Int.toSpinnerItem(): SpinnerItem = values()[this]
+        fun Int.toSpinnerItem(): SpinnerItem = entries[this]
     }
 }
diff --git a/src/com/android/settings/spa/notification/NotificationMain.kt b/src/com/android/settings/spa/notification/NotificationMain.kt
index 305f201..b3c7a55 100644
--- a/src/com/android/settings/spa/notification/NotificationMain.kt
+++ b/src/com/android/settings/spa/notification/NotificationMain.kt
@@ -25,13 +25,12 @@
 import com.android.settingslib.spa.framework.common.SettingsEntryBuilder
 import com.android.settingslib.spa.framework.common.SettingsPageProvider
 import com.android.settingslib.spa.framework.common.SpaEnvironmentFactory
+import com.android.settingslib.spa.framework.common.createSettingsPage
 import com.android.settingslib.spa.framework.compose.navigator
-import com.android.settingslib.spa.framework.compose.toState
 import com.android.settingslib.spa.widget.preference.Preference
 import com.android.settingslib.spa.widget.preference.PreferenceModel
 import com.android.settingslib.spa.widget.scaffold.RegularScaffold
 import com.android.settingslib.spa.widget.ui.SettingsIcon
-import com.android.settingslib.spa.framework.common.createSettingsPage
 
 object NotificationMainPageProvider : SettingsPageProvider {
     override val name = "NotificationMain"
@@ -53,9 +52,10 @@
     fun buildInjectEntry(): SettingsEntryBuilder {
         return SettingsEntryBuilder.createInject(owner = owner)
             .setUiLayoutFn {
+                val summary = stringResource(R.string.notification_dashboard_summary)
                 Preference(object : PreferenceModel {
                     override val title = stringResource(R.string.configure_notification_settings)
-                    override val summary = stringResource(R.string.notification_dashboard_summary).toState()
+                    override val summary = { summary }
                     override val onClick = navigator(name)
                     override val icon = @Composable {
                         SettingsIcon(imageVector = Icons.Outlined.Notifications)
diff --git a/src/com/android/settings/spa/system/AppLanguages.kt b/src/com/android/settings/spa/system/AppLanguages.kt
index b878aa7..d836a32 100644
--- a/src/com/android/settings/spa/system/AppLanguages.kt
+++ b/src/com/android/settings/spa/system/AppLanguages.kt
@@ -26,7 +26,6 @@
 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.compose.toState
 import com.android.settingslib.spa.framework.theme.SettingsDimension
 import com.android.settingslib.spa.widget.preference.Preference
 import com.android.settingslib.spa.widget.preference.PreferenceModel
@@ -52,9 +51,10 @@
 
     @Composable
     fun EntryItem() {
+        val summary = stringResource(R.string.app_locale_picker_summary)
         Preference(object : PreferenceModel {
             override val title = stringResource(R.string.app_locales_picker_menu_title)
-            override val summary = stringResource(R.string.app_locale_picker_summary).toState()
+            override val summary = { summary }
             override val onClick = navigator(name)
         })
     }
diff --git a/src/com/android/settings/spa/system/AppLanguagesListModel.kt b/src/com/android/settings/spa/system/AppLanguagesListModel.kt
index 3413ff0..3573e25 100644
--- a/src/com/android/settings/spa/system/AppLanguagesListModel.kt
+++ b/src/com/android/settings/spa/system/AppLanguagesListModel.kt
@@ -23,7 +23,7 @@
 import android.net.Uri
 import android.os.UserHandle
 import androidx.compose.runtime.Composable
-import androidx.compose.runtime.State
+import androidx.compose.runtime.getValue
 import androidx.compose.runtime.remember
 import androidx.compose.ui.res.stringResource
 import androidx.lifecycle.compose.collectAsStateWithLifecycle
@@ -79,12 +79,14 @@
     ) = recordListFlow.filterItem { it.isAppLocaleSupported }
 
     @Composable
-    override fun getSummary(option: Int, record: AppLanguagesRecord): State<String> =
-        remember(record.app) {
+    override fun getSummary(option: Int, record: AppLanguagesRecord): () -> String {
+        val summary by remember(record.app) {
             flow {
                 emit(getSummary(record.app))
             }.flowOn(Dispatchers.IO)
         }.collectAsStateWithLifecycle(initialValue = stringResource(R.string.summary_placeholder))
+        return { summary }
+    }
 
     private fun getSummary(app: ApplicationInfo): String =
         AppLocaleDetails.getSummary(context, app).toString()
diff --git a/src/com/android/settings/spa/system/LanguageAndInputPageProvider.kt b/src/com/android/settings/spa/system/LanguageAndInputPageProvider.kt
index b5cd299..5c1038d 100644
--- a/src/com/android/settings/spa/system/LanguageAndInputPageProvider.kt
+++ b/src/com/android/settings/spa/system/LanguageAndInputPageProvider.kt
@@ -24,7 +24,6 @@
 import com.android.settings.R
 import com.android.settingslib.spa.framework.common.SettingsPageProvider
 import com.android.settingslib.spa.framework.compose.navigator
-import com.android.settingslib.spa.framework.compose.toState
 import com.android.settingslib.spa.widget.preference.Preference
 import com.android.settingslib.spa.widget.preference.PreferenceModel
 import com.android.settingslib.spa.widget.scaffold.RegularScaffold
@@ -42,9 +41,10 @@
 
     @Composable
     fun EntryItem() {
+        val summary = stringResource(R.string.language_settings)
         Preference(object : PreferenceModel {
             override val title = stringResource(R.string.language_settings)
-            override val summary = stringResource(R.string.language_settings).toState()
+            override val summary = { summary }
             override val onClick = navigator(name)
             override val icon = @Composable {
                 SettingsIcon(imageVector = Icons.Outlined.Language)
diff --git a/src/com/android/settings/spa/system/SystemMain.kt b/src/com/android/settings/spa/system/SystemMain.kt
index 04ae512..c9aa8cc 100644
--- a/src/com/android/settings/spa/system/SystemMain.kt
+++ b/src/com/android/settings/spa/system/SystemMain.kt
@@ -27,7 +27,6 @@
 import com.android.settingslib.spa.framework.common.SpaEnvironmentFactory
 import com.android.settingslib.spa.framework.common.createSettingsPage
 import com.android.settingslib.spa.framework.compose.navigator
-import com.android.settingslib.spa.framework.compose.toState
 import com.android.settingslib.spa.widget.preference.Preference
 import com.android.settingslib.spa.widget.preference.PreferenceModel
 import com.android.settingslib.spa.widget.scaffold.RegularScaffold
@@ -53,9 +52,10 @@
     fun buildInjectEntry(): SettingsEntryBuilder {
         return SettingsEntryBuilder.createInject(owner = owner)
             .setUiLayoutFn {
+                val summary = stringResource(R.string.system_dashboard_summary)
                 Preference(object : PreferenceModel {
                     override val title = stringResource(R.string.header_category_system)
-                    override val summary = stringResource(R.string.system_dashboard_summary).toState()
+                    override val summary = { summary }
                     override val onClick = navigator(name)
                     override val icon = @Composable {
                         SettingsIcon(imageVector = Icons.Outlined.Info)
diff --git a/tests/robotests/src/com/android/settings/applications/appcompat/UserAspectRatioDetailsTest.java b/tests/robotests/src/com/android/settings/applications/appcompat/UserAspectRatioDetailsTest.java
index d98b0e7..b615163 100644
--- a/tests/robotests/src/com/android/settings/applications/appcompat/UserAspectRatioDetailsTest.java
+++ b/tests/robotests/src/com/android/settings/applications/appcompat/UserAspectRatioDetailsTest.java
@@ -21,21 +21,27 @@
 
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.inOrder;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
 import android.app.IActivityManager;
+import android.app.settings.SettingsEnums;
 import android.content.Context;
 import android.os.RemoteException;
 
 import androidx.test.core.app.ApplicationProvider;
 
+import com.android.settings.testutils.FakeFeatureFactory;
 import com.android.settings.testutils.shadow.ShadowActivityManager;
+import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
 
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.InOrder;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 import org.robolectric.RobolectricTestRunner;
@@ -56,6 +62,7 @@
     private RadioWithImagePreference mRadioButtonPref;
     private Context mContext;
     private UserAspectRatioDetails mFragment;
+    private MetricsFeatureProvider mMetricsFeatureProvider;
 
     @Before
     public void setUp() {
@@ -67,6 +74,8 @@
         when(mFragment.getAspectRatioManager()).thenReturn(mUserAspectRatioManager);
         ShadowActivityManager.setService(mAm);
         mRadioButtonPref = new RadioWithImagePreference(mContext);
+        final FakeFeatureFactory featureFactory = FakeFeatureFactory.setupForTest();
+        mMetricsFeatureProvider = featureFactory.metricsFeatureProvider;
     }
 
     @Test
@@ -93,4 +102,31 @@
         verify(mUserAspectRatioManager).setUserMinAspectRatio(
                 any(), anyInt(), anyInt());
     }
+
+    @Test
+    public void onRadioButtonClicked_prefChange_logMetrics() throws NullPointerException {
+        // Default was already selected
+        mRadioButtonPref.setKey(KEY_PREF_DEFAULT);
+        mFragment.onRadioButtonClicked(mRadioButtonPref);
+        // Preference changed
+        mRadioButtonPref.setKey(KEY_PREF_3_2);
+        mFragment.onRadioButtonClicked(mRadioButtonPref);
+        InOrder inOrder = inOrder(mMetricsFeatureProvider);
+        // Check the old aspect ratio value is logged as having been unselected
+        inOrder.verify(mMetricsFeatureProvider)
+                .action(
+                        eq(SettingsEnums.PAGE_UNKNOWN),
+                        eq(SettingsEnums.ACTION_USER_ASPECT_RATIO_APP_DEFAULT_UNSELECTED),
+                        eq(SettingsEnums.USER_ASPECT_RATIO_APP_INFO_SETTINGS),
+                        any(),
+                        anyInt());
+        // Check the new aspect ratio value is logged as having been selected
+        inOrder.verify(mMetricsFeatureProvider)
+                .action(
+                        eq(SettingsEnums.PAGE_UNKNOWN),
+                        eq(SettingsEnums.ACTION_USER_ASPECT_RATIO_3_2_SELECTED),
+                        eq(SettingsEnums.USER_ASPECT_RATIO_APP_INFO_SETTINGS),
+                        any(),
+                        anyInt());
+    }
 }
diff --git a/tests/robotests/src/com/android/settings/localepicker/AppLocalePickerActivityTest.java b/tests/robotests/src/com/android/settings/localepicker/AppLocalePickerActivityTest.java
index 72b01f8..817df4c 100644
--- a/tests/robotests/src/com/android/settings/localepicker/AppLocalePickerActivityTest.java
+++ b/tests/robotests/src/com/android/settings/localepicker/AppLocalePickerActivityTest.java
@@ -18,6 +18,8 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.times;
@@ -27,6 +29,7 @@
 import android.app.Activity;
 import android.app.ApplicationPackageManager;
 import android.app.LocaleConfig;
+import android.app.settings.SettingsEnums;
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.ApplicationInfo;
@@ -51,6 +54,7 @@
 import com.android.settings.applications.AppInfoBase;
 import com.android.settings.applications.AppLocaleUtil;
 import com.android.settings.flags.Flags;
+import com.android.settings.testutils.FakeFeatureFactory;
 
 import org.junit.After;
 import org.junit.Before;
@@ -91,6 +95,7 @@
     private static final String EN_US = "en-US";
     private static int sUid;
 
+    private FakeFeatureFactory mFeatureFactory;
     private LocaleNotificationDataManager mDataManager;
     private AppLocalePickerActivity mActivity;
 
@@ -117,6 +122,7 @@
         when(mLocaleConfig.getSupportedLocales()).thenReturn(LocaleList.forLanguageTags("en-US"));
         ReflectionHelpers.setStaticField(AppLocaleUtil.class, "sLocaleConfig", mLocaleConfig);
         sUid = Process.myUid();
+        mFeatureFactory = FakeFeatureFactory.setupForTest();
     }
 
     @After
@@ -229,6 +235,37 @@
     }
 
     @Test
+    public void onLocaleSelected_logLocaleSource() {
+        ActivityController<TestAppLocalePickerActivity> controller =
+                initActivityController(true);
+        LocaleList.setDefault(LocaleList.forLanguageTags("ja-JP,en-CA,en-US"));
+        Locale locale = new Locale("en", "US");
+        when(mLocaleInfo.getLocale()).thenReturn(locale);
+        when(mLocaleInfo.isSystemLocale()).thenReturn(false);
+        when(mLocaleInfo.isSuggested()).thenReturn(true);
+        when(mLocaleInfo.isSuggestionOfType(LocaleStore.LocaleInfo.SUGGESTION_TYPE_SIM)).thenReturn(
+                true);
+        when(mLocaleInfo.isSuggestionOfType(
+                LocaleStore.LocaleInfo.SUGGESTION_TYPE_SYSTEM_AVAILABLE_LANGUAGE)).thenReturn(
+                true);
+        when(mLocaleInfo.isSuggestionOfType(
+                LocaleStore.LocaleInfo.SUGGESTION_TYPE_OTHER_APP_LANGUAGE)).thenReturn(
+                true);
+        when(mLocaleInfo.isSuggestionOfType(
+                LocaleStore.LocaleInfo.SUGGESTION_TYPE_IME_LANGUAGE)).thenReturn(
+                true);
+
+        controller.create();
+        AppLocalePickerActivity mActivity = controller.get();
+        mActivity.onLocaleSelected(mLocaleInfo);
+
+        int localeSource = 15; // SIM_LOCALE | SYSTEM_LOCALE |IME_LOCALE|APP_LOCALE
+        verify(mFeatureFactory.metricsFeatureProvider).action(
+                any(), eq(SettingsEnums.ACTION_CHANGE_APP_LANGUAGE_FROM_SUGGESTED),
+                eq(localeSource));
+    }
+
+    @Test
     @RequiresFlagsEnabled(Flags.FLAG_LOCALE_NOTIFICATION_ENABLED)
     public void onLocaleSelected_evaluateNotification_simpleLocaleUpdate_localeCreatedWithUid()
             throws Exception {
diff --git a/tests/robotests/src/com/android/settings/notification/app/AppChannelsBypassingDndPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/app/AppChannelsBypassingDndPreferenceControllerTest.java
index 13528b4..053b352 100644
--- a/tests/robotests/src/com/android/settings/notification/app/AppChannelsBypassingDndPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/notification/app/AppChannelsBypassingDndPreferenceControllerTest.java
@@ -26,16 +26,19 @@
 import android.app.NotificationManager;
 import android.content.Context;
 import android.content.pm.ParceledListSlice;
+import android.platform.test.flag.junit.SetFlagsRule;
 
 import androidx.preference.PreferenceCategory;
 import androidx.preference.PreferenceManager;
 import androidx.preference.PreferenceScreen;
 import androidx.test.core.app.ApplicationProvider;
 
+import com.android.settings.flags.Flags;
 import com.android.settings.notification.NotificationBackend;
 import com.android.settingslib.PrimarySwitchPreference;
 
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
@@ -51,6 +54,9 @@
 @LooperMode(LooperMode.Mode.LEGACY)
 public class AppChannelsBypassingDndPreferenceControllerTest {
 
+    @Rule
+    public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
+
     @Mock
     private NotificationBackend mBackend;
 
@@ -150,4 +156,44 @@
         }
         return new ParceledListSlice<>(Collections.singletonList(group));
     }
+
+    @Test
+    public void displayPreference_duplicateChannelName_AddsGroupNameAsSummary() {
+        mSetFlagsRule.enableFlags(Flags.FLAG_DEDUPE_DND_SETTINGS_CHANNELS);
+        NotificationChannelGroup group1 = new NotificationChannelGroup("group1_id", "Group1");
+        NotificationChannelGroup group2 = new NotificationChannelGroup("group2_id", "Group2");
+
+        group1.addChannel(new NotificationChannel("mail_group1_id", "Mail",
+                NotificationManager.IMPORTANCE_DEFAULT));
+        group1.addChannel(new NotificationChannel("other_group1_id", "Other",
+                NotificationManager.IMPORTANCE_DEFAULT));
+
+        group2.addChannel(new NotificationChannel("music_group2_id", "Music",
+                NotificationManager.IMPORTANCE_DEFAULT));
+        // This channel has the same name as a channel in group1.
+        group2.addChannel(new NotificationChannel("mail_group2_id", "Mail",
+                NotificationManager.IMPORTANCE_DEFAULT));
+
+        ParceledListSlice<NotificationChannelGroup> groups = new ParceledListSlice<>(
+                new ArrayList<NotificationChannelGroup>() {
+                    {
+                        add(group1);
+                        add(group2);
+                    }
+                }
+        );
+
+        when(mBackend.getGroups(eq(mAppRow.pkg), eq(mAppRow.uid))).thenReturn(groups);
+        mController.displayPreference(mPreferenceScreen);
+        ShadowApplication.runBackgroundTasks();
+        // Check that we've added the group name as a summary to channels that have identical names.
+        // Channels are also alphabetized.
+        assertThat(mCategory.getPreference(1).getTitle().toString()).isEqualTo("Mail");
+        assertThat(mCategory.getPreference(1).getSummary().toString()).isEqualTo("Group1");
+        assertThat(mCategory.getPreference(2).getTitle().toString()).isEqualTo("Mail");
+        assertThat(mCategory.getPreference(2).getSummary().toString()).isEqualTo("Group2");
+        assertThat(mCategory.getPreference(3).getTitle().toString()).isEqualTo("Music");
+        assertThat(mCategory.getPreference(4).getTitle().toString()).isEqualTo("Other");
+
+    }
 }
diff --git a/tests/robotests/testutils/com/android/settings/testutils/FakeFeatureFactory.java b/tests/robotests/testutils/com/android/settings/testutils/FakeFeatureFactory.java
index 9156cae..5a5008c 100644
--- a/tests/robotests/testutils/com/android/settings/testutils/FakeFeatureFactory.java
+++ b/tests/robotests/testutils/com/android/settings/testutils/FakeFeatureFactory.java
@@ -46,6 +46,7 @@
 import com.android.settings.overlay.SupportFeatureProvider;
 import com.android.settings.overlay.SurveyFeatureProvider;
 import com.android.settings.panel.PanelFeatureProvider;
+import com.android.settings.privatespace.PrivateSpaceLoginFeatureProvider;
 import com.android.settings.search.SearchFeatureProvider;
 import com.android.settings.security.SecurityFeatureProvider;
 import com.android.settings.security.SecuritySettingsFeatureProvider;
@@ -99,6 +100,7 @@
     public StylusFeatureProvider mStylusFeatureProvider;
     public OnboardingFeatureProvider mOnboardingFeatureProvider;
     public FastPairFeatureProvider mFastPairFeatureProvider;
+    public PrivateSpaceLoginFeatureProvider mPrivateSpaceLoginFeatureProvider;
 
     /**
      * Call this in {@code @Before} method of the test class to use fake factory.
@@ -146,6 +148,7 @@
         mStylusFeatureProvider = mock(StylusFeatureProvider.class);
         mOnboardingFeatureProvider = mock(OnboardingFeatureProvider.class);
         mFastPairFeatureProvider = mock(FastPairFeatureProvider.class);
+        mPrivateSpaceLoginFeatureProvider =  mock(PrivateSpaceLoginFeatureProvider.class);
     }
 
     @Override
@@ -323,5 +326,10 @@
     public FastPairFeatureProvider getFastPairFeatureProvider() {
         return mFastPairFeatureProvider;
     }
+
+    @Override
+    public PrivateSpaceLoginFeatureProvider getPrivateSpaceLoginFeatureProvider() {
+        return mPrivateSpaceLoginFeatureProvider;
+    }
 }
 
diff --git a/tests/spa_unit/Android.bp b/tests/spa_unit/Android.bp
index 28a2667..c3e99f7 100644
--- a/tests/spa_unit/Android.bp
+++ b/tests/spa_unit/Android.bp
@@ -34,6 +34,7 @@
         "androidx.compose.runtime_runtime",
         "androidx.test.ext.junit",
         "androidx.test.runner",
+        "flag-junit",
         "mockito-target-extended-minus-junit4",
     ],
     jni_libs: [
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 53ed4f0..1a05479 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
@@ -21,7 +21,6 @@
 import android.content.pm.PackageManager
 import android.graphics.drawable.Drawable
 import androidx.compose.runtime.SideEffect
-import androidx.compose.runtime.State
 import androidx.compose.ui.test.assertIsDisplayed
 import androidx.compose.ui.test.junit4.createComposeRule
 import androidx.compose.ui.test.onNodeWithText
@@ -146,12 +145,12 @@
     fun allAppListModel_getSummary() {
         val listModel = AllAppListModel(context) { stateOf(SUMMARY) }
 
-        lateinit var summaryState: State<String>
+        lateinit var summary: () -> String
         composeTestRule.setContent {
-            summaryState = listModel.getSummary(option = 0, record = AppRecordWithSize(app = APP))
+            summary = listModel.getSummary(option = 0, record = AppRecordWithSize(app = APP))
         }
 
-        assertThat(summaryState.value).isEqualTo(SUMMARY)
+        assertThat(summary()).isEqualTo(SUMMARY)
     }
 
     @Test
@@ -163,13 +162,13 @@
             enabled = false
         }
 
-        lateinit var summaryState: State<String>
+        lateinit var summary: () -> String
         composeTestRule.setContent {
-            summaryState =
+            summary =
                 listModel.getSummary(option = 0, record = AppRecordWithSize(app = disabledApp))
         }
 
-        assertThat(summaryState.value).isEqualTo("$SUMMARY${System.lineSeparator()}Disabled")
+        assertThat(summary()).isEqualTo("$SUMMARY${System.lineSeparator()}Disabled")
     }
 
     @Test
@@ -179,13 +178,13 @@
             packageName = PACKAGE_NAME
         }
 
-        lateinit var summaryState: State<String>
+        lateinit var summary: () -> String
         composeTestRule.setContent {
-            summaryState =
+            summary =
                 listModel.getSummary(option = 0, record = AppRecordWithSize(app = notInstalledApp))
         }
 
-        assertThat(summaryState.value)
+        assertThat(summary())
             .isEqualTo("$SUMMARY${System.lineSeparator()}Not installed for this user")
     }
 
@@ -207,7 +206,7 @@
                     AppListItemModel(
                         record = AppRecordWithSize(app = app),
                         label = LABEL,
-                        summary = stateOf(SUMMARY),
+                        summary = { SUMMARY },
                     ).AppItem()
                 }
             }
@@ -224,13 +223,13 @@
             isArchived = true
         }
 
-        lateinit var summaryState: State<String>
+        lateinit var summary: () -> String
         composeTestRule.setContent {
-            summaryState =
+            summary =
                 listModel.getSummary(option = 0, record = AppRecordWithSize(app = archivedApp))
         }
 
-        assertThat(summaryState.value).isEqualTo(SUMMARY)
+        assertThat(summary()).isEqualTo(SUMMARY)
     }
 
     private fun getAppListInput(): AppListInput<AppRecordWithSize> {
@@ -252,7 +251,7 @@
                     AppListItemModel(
                         record = AppRecordWithSize(app = APP),
                         label = LABEL,
-                        summary = stateOf(SUMMARY),
+                        summary = { SUMMARY },
                     ).AppItem()
                 }
             }
diff --git a/tests/spa_unit/src/com/android/settings/spa/app/appcompat/UserAspectRatioAppsPageProviderTest.kt b/tests/spa_unit/src/com/android/settings/spa/app/appcompat/UserAspectRatioAppsPageProviderTest.kt
index 4f372e2..dfacca8 100644
--- a/tests/spa_unit/src/com/android/settings/spa/app/appcompat/UserAspectRatioAppsPageProviderTest.kt
+++ b/tests/spa_unit/src/com/android/settings/spa/app/appcompat/UserAspectRatioAppsPageProviderTest.kt
@@ -21,7 +21,6 @@
 import android.content.pm.PackageManager.USER_MIN_ASPECT_RATIO_SPLIT_SCREEN
 import android.content.pm.PackageManager.USER_MIN_ASPECT_RATIO_UNSET
 import android.os.Build
-import androidx.compose.runtime.State
 import androidx.compose.ui.test.assertIsDisplayed
 import androidx.compose.ui.test.junit4.createComposeRule
 import androidx.compose.ui.test.onNodeWithText
@@ -29,7 +28,6 @@
 import androidx.test.core.app.ApplicationProvider
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import com.android.settings.R
-import com.android.settingslib.spa.framework.compose.stateOf
 import com.android.settingslib.spa.testutils.FakeNavControllerWrapper
 import com.android.settingslib.spa.testutils.firstWithTimeoutOrNull
 import com.android.settingslib.spaprivileged.template.app.AppListItemModel
@@ -132,7 +130,7 @@
                     AppListItemModel(
                         record = APP_RECORD_SUGGESTED,
                         label = LABEL,
-                        summary = stateOf(SUMMARY)
+                        summary = { SUMMARY }
                     ).AppItem()
                 }
             }
@@ -141,23 +139,23 @@
 
     @Test
     fun aspectRatioAppListModel_getSummaryDefault() {
-        val summaryState = setSummaryState(USER_MIN_ASPECT_RATIO_UNSET)
-        assertThat(summaryState.value)
-            .isEqualTo(context.getString(R.string.user_aspect_ratio_app_default))
+        val summary = getSummary(USER_MIN_ASPECT_RATIO_UNSET)
+
+        assertThat(summary).isEqualTo(context.getString(R.string.user_aspect_ratio_app_default))
     }
 
     @Test
     fun aspectRatioAppListModel_getSummaryWhenSplitScreen() {
-        val summaryState = setSummaryState(USER_MIN_ASPECT_RATIO_SPLIT_SCREEN)
-        assertThat(summaryState.value)
-            .isEqualTo(context.getString(R.string.user_aspect_ratio_half_screen))
+        val summary = getSummary(USER_MIN_ASPECT_RATIO_SPLIT_SCREEN)
+
+        assertThat(summary).isEqualTo(context.getString(R.string.user_aspect_ratio_half_screen))
     }
 
-    private fun setSummaryState(userOverride: Int): State<String> {
+    private fun getSummary(userOverride: Int): String {
         val listModel = UserAspectRatioAppListModel(context)
-        lateinit var summaryState: State<String>
+        lateinit var summary: () -> String
         composeTestRule.setContent {
-            summaryState = listModel.getSummary(option = 0,
+            summary = listModel.getSummary(option = 0,
                 record = UserAspectRatioAppListItemModel(
                     app = APP,
                     userOverride = userOverride,
@@ -165,7 +163,7 @@
                     canDisplay = true,
                 ))
         }
-        return summaryState
+        return summary()
     }
 
 
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 ccd385f..5c65da1 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
@@ -29,7 +29,6 @@
 import androidx.test.core.app.ApplicationProvider
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import com.android.settings.R
-import com.android.settingslib.spa.framework.compose.stateOf
 import com.android.settingslib.spa.testutils.FakeNavControllerWrapper
 import com.android.settingslib.spaprivileged.template.app.AppListItemModel
 import com.google.common.truth.Truth.assertThat
@@ -244,7 +243,7 @@
                                 app = APP,
                                 dateOfInstall = TEST_FIRST_INSTALL_TIME),
                             label = TEST_LABEL,
-                            summary = stateOf(TEST_SUMMARY),
+                            summary = { TEST_SUMMARY },
                         ).AppItem()
                     }
                 }
diff --git a/tests/spa_unit/src/com/android/settings/spa/app/specialaccess/LongBackgroundTasksAppsTest.kt b/tests/spa_unit/src/com/android/settings/spa/app/specialaccess/LongBackgroundTasksAppsTest.kt
new file mode 100644
index 0000000..579c6c9
--- /dev/null
+++ b/tests/spa_unit/src/com/android/settings/spa/app/specialaccess/LongBackgroundTasksAppsTest.kt
@@ -0,0 +1,44 @@
+/*
+ * 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.specialaccess
+
+import android.Manifest
+import android.app.AppOpsManager
+import android.content.Context
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.google.common.truth.Truth.assertThat
+import com.android.settings.R
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+class LongBackgroundTasksAppsTest {
+    private val context: Context = ApplicationProvider.getApplicationContext()
+
+    private val listModel = LongBackgroundTasksAppsListModel(context)
+
+    @Test
+    fun modelResourceIdAndProperties() {
+        assertThat(listModel.pageTitleResId).isEqualTo(R.string.long_background_tasks_title)
+        assertThat(listModel.switchTitleResId).isEqualTo(R.string.long_background_tasks_switch_title)
+        assertThat(listModel.footerResId).isEqualTo(R.string.long_background_tasks_footer_title)
+        assertThat(listModel.appOp).isEqualTo(AppOpsManager.OP_RUN_USER_INITIATED_JOBS)
+        assertThat(listModel.permission).isEqualTo(Manifest.permission.RUN_USER_INITIATED_JOBS)
+        assertThat(listModel.setModeByUid).isTrue()
+    }
+}
\ No newline at end of file
diff --git a/tests/spa_unit/src/com/android/settings/spa/app/specialaccess/TurnScreenOnAppsTest.kt b/tests/spa_unit/src/com/android/settings/spa/app/specialaccess/TurnScreenOnAppsTest.kt
new file mode 100644
index 0000000..54ae6c6
--- /dev/null
+++ b/tests/spa_unit/src/com/android/settings/spa/app/specialaccess/TurnScreenOnAppsTest.kt
@@ -0,0 +1,62 @@
+/*
+ * 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.specialaccess
+
+import android.Manifest
+import android.app.AppOpsManager
+import android.content.Context
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+class TurnScreenOnAppsTest {
+    private val context: Context = ApplicationProvider.getApplicationContext()
+
+    private val listModel = TurnScreenOnAppsListModel(context)
+
+    @Test
+    fun pageTitleResId() {
+        assertThat(listModel.pageTitleResId).isEqualTo(com.android.settingslib.R.string.turn_screen_on_title)
+    }
+
+    @Test
+    fun switchTitleResId() {
+        assertThat(listModel.switchTitleResId).isEqualTo(com.android.settingslib.R.string.allow_turn_screen_on)
+    }
+
+    @Test
+    fun footerResId() {
+        assertThat(listModel.footerResId).isEqualTo(com.android.settingslib.R.string.allow_turn_screen_on_description)
+    }
+
+    @Test
+    fun appOp() {
+        assertThat(listModel.appOp).isEqualTo(AppOpsManager.OP_TURN_SCREEN_ON)
+    }
+
+    @Test
+    fun permission() {
+        assertThat(listModel.permission).isEqualTo(Manifest.permission.TURN_SCREEN_ON)
+    }
+
+    @Test
+    fun setModeByUid() {
+        assertThat(listModel.setModeByUid).isTrue()
+    }
+}
\ No newline at end of file
diff --git a/tests/spa_unit/src/com/android/settings/spa/app/specialaccess/VoiceActivationAppsPreferenceControllerTest.kt b/tests/spa_unit/src/com/android/settings/spa/app/specialaccess/VoiceActivationAppsPreferenceControllerTest.kt
new file mode 100644
index 0000000..2127497
--- /dev/null
+++ b/tests/spa_unit/src/com/android/settings/spa/app/specialaccess/VoiceActivationAppsPreferenceControllerTest.kt
@@ -0,0 +1,65 @@
+package com.android.settings.spa.app.specialaccess
+
+import android.content.Context
+import android.platform.test.annotations.RequiresFlagsDisabled
+import android.platform.test.annotations.RequiresFlagsEnabled
+import android.platform.test.flag.junit.CheckFlagsRule
+import android.platform.test.flag.junit.DeviceFlagsValueProvider
+import androidx.preference.Preference
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.ext.junit.runners.AndroidJUnit4
+
+import com.android.settings.flags.Flags
+import com.google.common.truth.Truth.assertThat
+
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.kotlin.any
+import org.mockito.kotlin.doNothing
+import org.mockito.kotlin.spy
+import org.mockito.kotlin.whenever
+
+@RunWith(AndroidJUnit4::class)
+class VoiceActivationAppsPreferenceControllerTest {
+
+    @get:Rule
+    val checkFlagsRule: CheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule()
+
+    private val context: Context = spy(ApplicationProvider.getApplicationContext()) {
+        doNothing().whenever(mock).startActivity(any())
+    }
+
+    private val matchedPreference = Preference(context).apply { key = preferenceKey }
+
+    private val misMatchedPreference = Preference(context).apply { key = testPreferenceKey }
+
+    private val controller = VoiceActivationAppsPreferenceController(context, preferenceKey)
+
+    @Test
+    @RequiresFlagsEnabled(Flags.FLAG_ENABLE_VOICE_ACTIVATION_APPS_IN_SETTINGS)
+    fun getAvailabilityStatus_enableVoiceActivationApps_returnAvailable() {
+        assertThat(controller.isAvailable).isTrue()
+    }
+
+    @Test
+    @RequiresFlagsDisabled(Flags.FLAG_ENABLE_VOICE_ACTIVATION_APPS_IN_SETTINGS)
+    fun getAvailableStatus_disableVoiceActivationApps_returnConditionallyUnavailable() {
+        assertThat(controller.isAvailable).isFalse()
+    }
+
+    @Test
+    fun handlePreferenceTreeClick_keyMatched_returnTrue() {
+        assertThat(controller.handlePreferenceTreeClick(matchedPreference)).isTrue()
+    }
+
+    @Test
+    fun handlePreferenceTreeClick_keyMisMatched_returnFalse() {
+        assertThat(controller.handlePreferenceTreeClick(misMatchedPreference)).isFalse()
+    }
+
+    companion object {
+        private const val preferenceKey: String = "voice_activation_apps"
+        private const val testPreferenceKey: String = "test_key"
+    }
+}
\ No newline at end of file
diff --git a/tests/spa_unit/src/com/android/settings/spa/app/specialaccess/VoiceActivationAppsTest.kt b/tests/spa_unit/src/com/android/settings/spa/app/specialaccess/VoiceActivationAppsTest.kt
new file mode 100644
index 0000000..7d636b3
--- /dev/null
+++ b/tests/spa_unit/src/com/android/settings/spa/app/specialaccess/VoiceActivationAppsTest.kt
@@ -0,0 +1,50 @@
+package com.android.settings.spa.app.specialaccess
+
+import android.Manifest
+import android.app.AppOpsManager
+import android.content.Context
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.settings.R
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+class VoiceActivationAppsTest {
+    private val context: Context = ApplicationProvider.getApplicationContext()
+
+    private val listModel = VoiceActivationAppsListModel(context)
+
+    @Test
+    fun pageTitleResId() {
+        assertThat(listModel.pageTitleResId).isEqualTo(R.string.voice_activation_apps_title)
+    }
+
+    @Test
+    fun switchTitleResId() {
+        assertThat(listModel.switchTitleResId).isEqualTo(R.string.permit_voice_activation_apps)
+    }
+
+    @Test
+    fun footerResId() {
+        assertThat(listModel.footerResId)
+            .isEqualTo(R.string.allow_voice_activation_apps_description)
+    }
+
+    @Test
+    fun appOp() {
+        assertThat(listModel.appOp).isEqualTo(AppOpsManager.OP_RECEIVE_SANDBOX_TRIGGER_AUDIO)
+    }
+
+    @Test
+    fun permission() {
+        assertThat(listModel.permission).isEqualTo(
+            Manifest.permission.RECEIVE_SANDBOX_TRIGGER_AUDIO)
+    }
+
+    @Test
+    fun setModeByUid() {
+        assertThat(listModel.setModeByUid).isTrue()
+    }
+}
\ No newline at end of file
diff --git a/tests/spa_unit/src/com/android/settings/spa/development/compat/PlatformCompatAppListModelTest.kt b/tests/spa_unit/src/com/android/settings/spa/development/compat/PlatformCompatAppListModelTest.kt
index 0cfdc7d..6aee4ce 100644
--- a/tests/spa_unit/src/com/android/settings/spa/development/compat/PlatformCompatAppListModelTest.kt
+++ b/tests/spa_unit/src/com/android/settings/spa/development/compat/PlatformCompatAppListModelTest.kt
@@ -20,7 +20,6 @@
 import android.content.pm.ApplicationInfo
 import android.content.pm.PackageManager
 import android.content.pm.PackageManager.PackageInfoFlags
-import androidx.compose.runtime.State
 import androidx.compose.ui.test.junit4.createComposeRule
 import androidx.test.core.app.ApplicationProvider
 import androidx.test.ext.junit.runners.AndroidJUnit4
@@ -79,20 +78,20 @@
 
     @Test
     fun getSummary() = runTest {
-        val summaryState = getSummaryState(APP)
+        val summary = getSummary(APP)
 
-        assertThat(summaryState.value).isEqualTo(PACKAGE_NAME)
+        assertThat(summary).isEqualTo(PACKAGE_NAME)
     }
 
-    private fun getSummaryState(app: ApplicationInfo): State<String> {
-        lateinit var summary: State<String>
+    private fun getSummary(app: ApplicationInfo): String {
+        lateinit var summary: () -> String
         composeTestRule.setContent {
             summary = listModel.getSummary(
                 option = 0,
                 record = PlatformCompatAppRecord(app),
             )
         }
-        return summary
+        return summary()
     }
 
     private companion object {
diff --git a/tests/spa_unit/src/com/android/settings/testutils/FakeFeatureFactory.kt b/tests/spa_unit/src/com/android/settings/testutils/FakeFeatureFactory.kt
index 54299eb..9b098a7 100644
--- a/tests/spa_unit/src/com/android/settings/testutils/FakeFeatureFactory.kt
+++ b/tests/spa_unit/src/com/android/settings/testutils/FakeFeatureFactory.kt
@@ -41,6 +41,7 @@
 import com.android.settings.overlay.FeatureFactory
 import com.android.settings.overlay.SurveyFeatureProvider
 import com.android.settings.panel.PanelFeatureProvider
+import com.android.settings.privatespace.PrivateSpaceLoginFeatureProvider
 import com.android.settings.search.SearchFeatureProvider
 import com.android.settings.security.SecurityFeatureProvider
 import com.android.settings.security.SecuritySettingsFeatureProvider
@@ -143,4 +144,6 @@
         get() = TODO("Not yet implemented")
     override val fastPairFeatureProvider: FastPairFeatureProvider
         get() = TODO("Not yet implemented")
+    override val privateSpaceLoginFeatureProvider: PrivateSpaceLoginFeatureProvider
+        get() = TODO("Not yet implemented")
 }
diff --git a/tests/unit/src/com/android/settings/testutils/FakeFeatureFactory.java b/tests/unit/src/com/android/settings/testutils/FakeFeatureFactory.java
index b5062a0..bf2c84a 100644
--- a/tests/unit/src/com/android/settings/testutils/FakeFeatureFactory.java
+++ b/tests/unit/src/com/android/settings/testutils/FakeFeatureFactory.java
@@ -46,6 +46,7 @@
 import com.android.settings.overlay.SupportFeatureProvider;
 import com.android.settings.overlay.SurveyFeatureProvider;
 import com.android.settings.panel.PanelFeatureProvider;
+import com.android.settings.privatespace.PrivateSpaceLoginFeatureProvider;
 import com.android.settings.search.SearchFeatureProvider;
 import com.android.settings.security.SecurityFeatureProvider;
 import com.android.settings.security.SecuritySettingsFeatureProvider;
@@ -98,6 +99,7 @@
     public StylusFeatureProvider mStylusFeatureProvider;
     public OnboardingFeatureProvider mOnboardingFeatureProvider;
     public FastPairFeatureProvider mFastPairFeatureProvider;
+    public PrivateSpaceLoginFeatureProvider mPrivateSpaceLoginFeatureProvider;
 
     /**
      * Call this in {@code @Before} method of the test class to use fake factory.
@@ -145,6 +147,7 @@
         mStylusFeatureProvider = mock(StylusFeatureProvider.class);
         mOnboardingFeatureProvider = mock(OnboardingFeatureProvider.class);
         mFastPairFeatureProvider = mock(FastPairFeatureProvider.class);
+        mPrivateSpaceLoginFeatureProvider = mock(PrivateSpaceLoginFeatureProvider.class);
     }
 
     @Override
@@ -322,4 +325,9 @@
     public FastPairFeatureProvider getFastPairFeatureProvider() {
         return mFastPairFeatureProvider;
     }
+
+    @Override
+    public PrivateSpaceLoginFeatureProvider getPrivateSpaceLoginFeatureProvider() {
+        return mPrivateSpaceLoginFeatureProvider;
+    }
 }