[Auto Pin Confirmation]: Add talkback capability for Auto-confirm correct PIN checkbox even if it is not in focus am: 01637b556e

Original change: https://googleplex-android-review.googlesource.com/c/platform/packages/apps/Settings/+/23601571

Change-Id: Ib3b5ae9d55f47da3f9a7e5734bd8f6a55ae267f8
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 6689645..2c3e7f3 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -864,6 +864,7 @@
 
         <activity
             android:name="Settings$LongBackgroundTasksActivity"
+            android:knownActivityEmbeddingCerts="@array/config_known_host_certs"
             android:exported="true"
             android:label="@string/long_background_tasks_label">
             <intent-filter android:priority="1">
@@ -1545,6 +1546,7 @@
 
         <activity
             android:name="Settings$ManageApplicationsActivity"
+            android:knownActivityEmbeddingCerts="@array/config_known_host_certs"
             android:exported="true"
             android:label="@string/applications_settings">
             <intent-filter android:priority="1">
@@ -1607,6 +1609,7 @@
 
         <activity
             android:name="Settings$HighPowerApplicationsActivity"
+            android:knownActivityEmbeddingCerts="@array/config_known_host_certs"
             android:exported="true"
             android:label="@string/high_power_apps">
             <intent-filter android:priority="1">
@@ -1665,6 +1668,7 @@
              This is for compatibility with old shortcuts. -->
         <activity-alias android:name=".RunningServices"
                 android:label="@string/runningservices_settings_title"
+                android:knownActivityEmbeddingCerts="@array/config_known_host_certs"
                 android:exported="true"
                 android:targetActivity="Settings$ManageApplicationsActivity">
             <meta-data android:name="com.android.settings.FRAGMENT_CLASS"
@@ -1677,6 +1681,7 @@
              This is for compatibility with old shortcuts. -->
         <activity-alias android:name=".applications.StorageUse"
                 android:label="@string/storageuse_settings_title"
+                android:knownActivityEmbeddingCerts="@array/config_known_host_certs"
                 android:exported="true"
                 android:targetActivity="Settings$ManageApplicationsActivity">
             <meta-data android:name="com.android.settings.FRAGMENT_CLASS"
@@ -1743,6 +1748,7 @@
         <!-- Provide direct entry into manage apps showing running services. -->
         <activity android:name="Settings$RunningServicesActivity"
                 android:exported="true"
+                android:knownActivityEmbeddingCerts="@array/config_known_host_certs"
                 android:label="@string/runningservices_settings_title">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
@@ -1761,6 +1767,7 @@
         <!-- Provide direct entry into manage apps showing storage usage of apps. -->
         <activity
             android:name="Settings$StorageUseActivity"
+            android:knownActivityEmbeddingCerts="@array/config_known_host_certs"
             android:exported="true"
             android:label="@string/storageuse_settings_title">
             <intent-filter android:priority="1">
@@ -2105,6 +2112,7 @@
 
         <activity
             android:name="Settings$UsageAccessSettingsActivity"
+            android:knownActivityEmbeddingCerts="@array/config_known_host_certs"
             android:exported="true"
             android:label="@string/usage_access_title">
             <intent-filter android:priority="1">
@@ -3483,6 +3491,7 @@
         <activity
             android:name="Settings$TurnScreenOnSettingsActivity"
             android:exported="true"
+            android:knownActivityEmbeddingCerts="@array/config_known_host_certs"
             android:label="@string/turn_screen_on_title">
             <intent-filter android:priority="1">
                 <action android:name="android.settings.TURN_SCREEN_ON_SETTINGS" />
@@ -3662,6 +3671,7 @@
         <activity android:name="Settings$NotificationAppListActivity"
                   android:label="@string/app_notifications_title"
                   android:icon="@drawable/ic_notifications"
+                  android:knownActivityEmbeddingCerts="@array/config_known_host_certs"
                   android:exported="true">
             <intent-filter android:priority="1">
                 <action android:name="android.settings.ALL_APPS_NOTIFICATION_SETTINGS" />
@@ -3676,6 +3686,7 @@
         <!-- Displays a list of apps available for cloning on the device -->
         <activity android:name=".Settings$ClonedAppsListActivity"
                   android:label="@string/cloned_apps_dashboard_title"
+                  android:knownActivityEmbeddingCerts="@array/config_known_host_certs"
                   android:exported="true">
             <intent-filter android:priority="1">
                 <action android:name="android.settings.MANAGE_CLONED_APPS_SETTINGS" />
@@ -3941,6 +3952,7 @@
 
         <activity
             android:name="Settings$OverlaySettingsActivity"
+            android:knownActivityEmbeddingCerts="@array/config_known_host_certs"
             android:exported="true"
             android:label="@string/draw_overlay">
             <intent-filter android:priority="1">
@@ -3978,6 +3990,7 @@
 
         <activity
             android:name="Settings$WriteSettingsActivity"
+            android:knownActivityEmbeddingCerts="@array/config_known_host_certs"
             android:exported="true"
             android:label="@string/write_settings_title">
             <intent-filter android:priority="1">
@@ -4011,6 +4024,7 @@
         <activity
             android:name="Settings$AlarmsAndRemindersActivity"
             android:exported="true"
+            android:knownActivityEmbeddingCerts="@array/config_known_host_certs"
             android:label="@string/alarms_and_reminders_label">
             <intent-filter android:priority="1">
                 <action android:name="android.settings.REQUEST_SCHEDULE_EXACT_ALARM" />
@@ -4041,6 +4055,7 @@
 
         <activity
             android:name="Settings$ManageExternalSourcesActivity"
+            android:knownActivityEmbeddingCerts="@array/config_known_host_certs"
             android:exported="true"
             android:label="@string/install_other_apps">
             <intent-filter android:priority="1">
@@ -4095,6 +4110,7 @@
 
         <activity
             android:name="Settings$ManageExternalStorageActivity"
+            android:knownActivityEmbeddingCerts="@array/config_known_host_certs"
             android:exported="true"
             android:label="@string/manage_external_storage_title">
             <intent-filter android:priority="1">
@@ -4126,6 +4142,7 @@
 
         <activity
             android:name="Settings$MediaManagementAppsActivity"
+            android:knownActivityEmbeddingCerts="@array/config_known_host_certs"
             android:exported="true"
             android:label="@string/media_management_apps_title">
             <intent-filter android:priority="1">
@@ -4881,6 +4898,7 @@
         <activity
             android:name=".spa.SpaActivity"
             android:configChanges="orientation|screenLayout|screenSize|smallestScreenSize"
+            android:knownActivityEmbeddingCerts="@array/config_known_host_certs"
             android:exported="false" />
         <activity android:name=".spa.SpaBridgeActivity" android:exported="false"/>
         <activity android:name=".spa.SpaAppBridgeActivity" android:exported="false"/>
diff --git a/res/layout/preference_external_action_icon.xml b/res/layout/preference_external_action_icon.xml
new file mode 100644
index 0000000..fcec430
--- /dev/null
+++ b/res/layout/preference_external_action_icon.xml
@@ -0,0 +1,22 @@
+<?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.
+-->
+
+<ImageView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:src="@drawable/ic_chevron_right_24dp"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:layout_marginHorizontal="8dp" />
\ No newline at end of file
diff --git a/res/values-bs/strings.xml b/res/values-bs/strings.xml
index 8719626..25663e7 100644
--- a/res/values-bs/strings.xml
+++ b/res/values-bs/strings.xml
@@ -2945,8 +2945,7 @@
     <string name="keywords_storage_settings" msgid="6018856193950281898">"memorija, keš memorija, podaci, izbrisati, obrisati, osloboditi, prostor"</string>
     <string name="keywords_bluetooth_settings" msgid="2588159530959868188">"povezan, uređaj, slušalice, slušalice s mikrofonom, zvučnik, bežično, uparivanje, slušalice za umetanje u uho, muzika, medij"</string>
     <string name="keywords_wallpaper" msgid="7332890404629446192">"pozadina, tema, mreža, prilagođavanje, personaliziranje"</string>
-    <!-- no translation found for keywords_styles (3367789885254807447) -->
-    <skip />
+    <string name="keywords_styles" msgid="3367789885254807447">"ikona, boja isticanja, početni zaslon, zaključan zaslon, prečac, veličina sata"</string>
     <string name="keywords_assist_input" msgid="3086289530227075593">"zadani, asistent"</string>
     <string name="keywords_default_payment_app" msgid="5162298193637362104">"plaćanje, zadano"</string>
     <string name="keywords_ambient_display" msgid="3149287105145443697">"dolazno obavještenje"</string>
@@ -3226,8 +3225,7 @@
     <string name="notification_channel_summary_min" msgid="8823399508450176842">"Suzite obavještenja u jedan red na padajućoj traci"</string>
     <string name="notification_channel_summary_low" msgid="5549662596677692000">"Bez zvuka ili vibracije"</string>
     <string name="notification_conversation_summary_low" msgid="6352818857388412326">"Bez zvuka ili vibracije i pojavljuje se pri dnu odjeljka razgovora"</string>
-    <!-- no translation found for notification_channel_summary_default (1168420867670390611) -->
-    <skip />
+    <string name="notification_channel_summary_default" msgid="1168420867670390611">"Možda će zvoniti ili vibrirati, ovisno o postavkama uređaja"</string>
     <string name="notification_channel_summary_high" msgid="3411637309360617621">"Kada je uređaj otključan, vidite obavještenja u vidu banera na vrhu ekrana"</string>
     <string name="notification_switch_label" msgid="8029371325967501557">"Sva obavještenja aplikacije \"<xliff:g id="APP_NAME">%1$s</xliff:g>\""</string>
     <string name="notification_app_switch_label" msgid="4422902423925084193">"Sva obavještenja aplikacije <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
diff --git a/res/values/config.xml b/res/values/config.xml
index 334d4e5..0c5c7a0 100755
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -364,7 +364,7 @@
     <bool name="config_show_wifi_hotspot_settings">true</bool>
 
     <!-- Whether Wi-Fi hotspot speed should be shown or not. -->
-    <bool name="config_show_wifi_hotspot_speed">false</bool>
+    <bool name="config_show_wifi_hotspot_speed">true</bool>
 
     <!-- Whether toggle_airplane is available or not. -->
     <bool name="config_show_toggle_airplane">true</bool>
diff --git a/src/com/android/settings/biometrics/face/FaceSettings.java b/src/com/android/settings/biometrics/face/FaceSettings.java
index 979faa2..54775f8 100644
--- a/src/com/android/settings/biometrics/face/FaceSettings.java
+++ b/src/com/android/settings/biometrics/face/FaceSettings.java
@@ -208,6 +208,10 @@
         mRemoveButton = findPreference(FaceSettingsRemoveButtonPreferenceController.KEY);
         mEnrollButton = findPreference(FaceSettingsEnrollButtonPreferenceController.KEY);
 
+        final boolean hasEnrolled = mFaceManager.hasEnrolledTemplates(mUserId);
+        mEnrollButton.setVisible(!hasEnrolled);
+        mRemoveButton.setVisible(hasEnrolled);
+
         // There is no better way to do this :/
         for (AbstractPreferenceController controller : mControllers) {
             if (controller instanceof FaceSettingsPreferenceController) {
@@ -233,8 +237,6 @@
     public void onStart() {
         super.onStart();
         final boolean hasEnrolled = mFaceManager.hasEnrolledTemplates(mUserId);
-        mEnrollButton.setVisible(!hasEnrolled);
-        mRemoveButton.setVisible(hasEnrolled);
 
         // When the user has face id registered but failed enrolling in device lock state,
         // lead users directly to the confirm deletion dialog in Face Unlock settings.
diff --git a/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrolling.java b/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrolling.java
index 7e76405..f653942 100644
--- a/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrolling.java
+++ b/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrolling.java
@@ -265,6 +265,12 @@
             updateUdfpsEnrollView(udfpsEnrollView, props.get(0));
             switch (rotation) {
                 case Surface.ROTATION_90:
+                    final View sudContent = layout.findViewById(R.id.sud_layout_content);
+                    if (sudContent != null) {
+                        sudContent.setPadding(sudContent.getPaddingLeft(), 0,
+                                sudContent.getPaddingRight(), sudContent.getPaddingBottom());
+                    }
+
                     final LinearLayout layoutContainer = layout.findViewById(
                             R.id.layout_container);
                     final LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(
diff --git a/src/com/android/settings/bluetooth/BluetoothDetailsProfilesController.java b/src/com/android/settings/bluetooth/BluetoothDetailsProfilesController.java
index 724947c..701967b 100644
--- a/src/com/android/settings/bluetooth/BluetoothDetailsProfilesController.java
+++ b/src/com/android/settings/bluetooth/BluetoothDetailsProfilesController.java
@@ -96,12 +96,6 @@
     protected void init(PreferenceScreen screen) {
         mProfilesContainer = (PreferenceCategory)screen.findPreference(getPreferenceKey());
         mProfilesContainer.setLayoutResource(R.layout.preference_bluetooth_profile_category);
-        mIsLeContactSharingEnabled = DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_SETTINGS_UI,
-                SettingsUIDeviceConfig.BT_LE_AUDIO_CONTACT_SHARING_ENABLED, true);
-        mIsLeAudioToggleEnabled = DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_SETTINGS_UI,
-                SettingsUIDeviceConfig.BT_LE_AUDIO_DEVICE_DETAIL_ENABLED, false)
-                || DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_BLUETOOTH,
-                CONFIG_LE_AUDIO_ENABLED_BY_DEFAULT, false);
         // Call refresh here even though it will get called later in onResume, to avoid the
         // list of switches appearing to "pop" into the page.
         refresh();
@@ -151,8 +145,8 @@
             profilePref.setEnabled(!mCachedDevice.isBusy());
         }
 
-        if (profile instanceof LeAudioProfile && !mIsLeAudioToggleEnabled) {
-            profilePref.setVisible(false);
+        if (profile instanceof LeAudioProfile) {
+            profilePref.setVisible(mIsLeAudioToggleEnabled);
         }
 
         if (profile instanceof MapProfile) {
@@ -437,6 +431,7 @@
 
     @Override
     public void onResume() {
+        updateLeAudioConfig();
         for (CachedBluetoothDevice item : mAllOfCachedDevices) {
             item.registerCallback(this);
         }
@@ -444,6 +439,20 @@
         refresh();
     }
 
+    private void updateLeAudioConfig() {
+        mIsLeContactSharingEnabled = DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_SETTINGS_UI,
+                SettingsUIDeviceConfig.BT_LE_AUDIO_CONTACT_SHARING_ENABLED, true);
+        boolean isLeDeviceDetailEnabled = DeviceConfig.getBoolean(
+                DeviceConfig.NAMESPACE_SETTINGS_UI,
+                SettingsUIDeviceConfig.BT_LE_AUDIO_DEVICE_DETAIL_ENABLED, true);
+        boolean isLeEnabledByDefault = DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_BLUETOOTH,
+                CONFIG_LE_AUDIO_ENABLED_BY_DEFAULT, false);
+        mIsLeAudioToggleEnabled = isLeDeviceDetailEnabled || isLeEnabledByDefault;
+        Log.d(TAG, "BT_LE_AUDIO_CONTACT_SHARING_ENABLED:" + mIsLeContactSharingEnabled
+                + ", BT_LE_AUDIO_DEVICE_DETAIL_ENABLED:" + isLeDeviceDetailEnabled
+                + ", CONFIG_LE_AUDIO_ENABLED_BY_DEFAULT:" + isLeEnabledByDefault);
+    }
+
     @Override
     public void onDeviceAttributesChanged() {
         for (CachedBluetoothDevice item : mAllOfCachedDevices) {
diff --git a/src/com/android/settings/bluetooth/ForgetDeviceDialogFragment.java b/src/com/android/settings/bluetooth/ForgetDeviceDialogFragment.java
index 1da8672..60d63c6 100644
--- a/src/com/android/settings/bluetooth/ForgetDeviceDialogFragment.java
+++ b/src/com/android/settings/bluetooth/ForgetDeviceDialogFragment.java
@@ -23,6 +23,7 @@
 import android.content.Context;
 import android.content.DialogInterface;
 import android.os.Bundle;
+import android.util.Log;
 
 import androidx.annotation.VisibleForTesting;
 import androidx.appcompat.app.AlertDialog;
@@ -63,6 +64,13 @@
 
     @Override
     public Dialog onCreateDialog(Bundle inState) {
+        Context context = getContext();
+        mDevice = getDevice(context);
+        if (mDevice == null) {
+            Log.e(TAG, "onCreateDialog: Device is null.");
+            return null;
+        }
+
         DialogInterface.OnClickListener onConfirm = (dialog, which) -> {
             mDevice.unpair();
             Activity activity = getActivity();
@@ -70,9 +78,6 @@
                 activity.finish();
             }
         };
-        Context context = getContext();
-        mDevice = getDevice(context);
-
         AlertDialog dialog = new AlertDialog.Builder(context)
                 .setPositiveButton(R.string.bluetooth_unpair_dialog_forget_confirm_button,
                         onConfirm)
diff --git a/src/com/android/settings/dashboard/DashboardFeatureProviderImpl.java b/src/com/android/settings/dashboard/DashboardFeatureProviderImpl.java
index 4dc8f1a..578493a 100644
--- a/src/com/android/settings/dashboard/DashboardFeatureProviderImpl.java
+++ b/src/com/android/settings/dashboard/DashboardFeatureProviderImpl.java
@@ -33,6 +33,7 @@
 import static com.android.settingslib.drawer.TileUtils.META_DATA_PREFERENCE_TITLE;
 import static com.android.settingslib.drawer.TileUtils.META_DATA_PREFERENCE_TITLE_URI;
 
+import android.app.PendingIntent;
 import android.app.settings.SettingsEnums;
 import android.content.ComponentName;
 import android.content.Context;
@@ -75,6 +76,8 @@
 import com.android.settingslib.utils.ThreadUtils;
 import com.android.settingslib.widget.AdaptiveIcon;
 
+import com.google.common.collect.Iterables;
+
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
@@ -152,7 +155,14 @@
         }
         bindIcon(pref, tile, forceRoundedIcon);
 
-        if (tile instanceof ActivityTile) {
+        if (tile.hasPendingIntent()) {
+            // Pending intent cannot be launched within the settings app panel, and will thus always
+            // be executed directly.
+            pref.setOnPreferenceClickListener(preference -> {
+                launchPendingIntentOrSelectProfile(activity, tile, fragment.getMetricsCategory());
+                return true;
+            });
+        } else if (tile instanceof ActivityTile) {
             final int sourceMetricsCategory = fragment.getMetricsCategory();
             final Bundle metadata = tile.getMetaData();
             String clsName = null;
@@ -441,6 +451,33 @@
         preference.setIcon(iconDrawable);
     }
 
+    private void launchPendingIntentOrSelectProfile(FragmentActivity activity, Tile tile,
+            int sourceMetricCategory) {
+        ProfileSelectDialog.updatePendingIntentsIfNeeded(mContext, tile);
+
+        if (tile.pendingIntentMap.isEmpty()) {
+            Log.w(TAG, "Cannot resolve pendingIntent, skipping. " + tile.getIntent());
+            return;
+        }
+
+        mMetricsFeatureProvider.logSettingsTileClick(tile.getKey(mContext), sourceMetricCategory);
+
+        // Launch the pending intent directly if there's only one available.
+        if (tile.pendingIntentMap.size() == 1) {
+            PendingIntent pendingIntent = Iterables.getOnlyElement(tile.pendingIntentMap.values());
+            try {
+                pendingIntent.send();
+            } catch (PendingIntent.CanceledException e) {
+                Log.w(TAG, "Failed executing pendingIntent. " + pendingIntent.getIntent(), e);
+            }
+            return;
+        }
+
+        ProfileSelectDialog.show(activity.getSupportFragmentManager(), tile,
+                sourceMetricCategory, /* onShowListener= */ null,
+                /* onDismissListener= */ null, /* onCancelListener= */ null);
+    }
+
     private void launchIntentOrSelectProfile(FragmentActivity activity, Tile tile, Intent intent,
             int sourceMetricCategory, TopLevelHighlightMixin highlightMixin,
             boolean isDuplicateClick) {
diff --git a/src/com/android/settings/dashboard/DashboardFragment.java b/src/com/android/settings/dashboard/DashboardFragment.java
index 6076a25..f8a5d76 100644
--- a/src/com/android/settings/dashboard/DashboardFragment.java
+++ b/src/com/android/settings/dashboard/DashboardFragment.java
@@ -31,6 +31,7 @@
 import androidx.annotation.VisibleForTesting;
 import androidx.lifecycle.LifecycleObserver;
 import androidx.preference.Preference;
+import androidx.preference.PreferenceCategory;
 import androidx.preference.PreferenceGroup;
 import androidx.preference.PreferenceManager;
 import androidx.preference.PreferenceScreen;
@@ -47,7 +48,6 @@
 import com.android.settingslib.core.AbstractPreferenceController;
 import com.android.settingslib.core.lifecycle.Lifecycle;
 import com.android.settingslib.drawer.DashboardCategory;
-import com.android.settingslib.drawer.ProviderTile;
 import com.android.settingslib.drawer.Tile;
 import com.android.settingslib.search.Indexable;
 
@@ -55,6 +55,7 @@
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
+import java.util.Comparator;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
@@ -504,6 +505,10 @@
         // Install dashboard tiles and collect pending observers.
         final boolean forceRoundedIcons = shouldForceRoundedIcon();
         final List<DynamicDataObserver> pendingObservers = new ArrayList<>();
+
+        // Move group tiles to the beginning of the list to ensure they are created before the
+        // other tiles.
+        tiles.sort(Comparator.comparingInt(tile -> tile.getType() == Tile.Type.GROUP ? 0 : 1));
         for (Tile tile : tiles) {
             final String key = mDashboardFeatureProvider.getDashboardKeyForTile(tile);
             if (TextUtils.isEmpty(key)) {
@@ -526,7 +531,14 @@
                 observers = mDashboardFeatureProvider.bindPreferenceToTileAndGetObservers(
                         getActivity(), this, forceRoundedIcons, pref, tile, key,
                         mPlaceholderPreferenceController.getOrder());
-                screen.addPreference(pref);
+                if (tile.hasGroupKey() && mDashboardTilePrefKeys.containsKey(tile.getGroupKey())) {
+                    final Preference group = screen.findPreference(tile.getGroupKey());
+                    if (group instanceof PreferenceCategory) {
+                        ((PreferenceCategory) group).addPreference(pref);
+                    }
+                } else {
+                    screen.addPreference(pref);
+                }
                 registerDynamicDataObservers(observers);
                 mDashboardTilePrefKeys.put(key, observers);
             }
@@ -569,11 +581,28 @@
     }
 
     protected Preference createPreference(Tile tile) {
-        return tile instanceof ProviderTile
-                ? new SwitchPreference(getPrefContext())
-                : tile.hasSwitch()
-                        ? new PrimarySwitchPreference(getPrefContext())
-                        : new Preference(getPrefContext());
+        switch (tile.getType()) {
+            case EXTERNAL_ACTION:
+                Preference externalActionPreference = new Preference(getPrefContext());
+                externalActionPreference
+                        .setWidgetLayoutResource(R.layout.preference_external_action_icon);
+                return externalActionPreference;
+            case SWITCH:
+                return new SwitchPreference(getPrefContext());
+            case SWITCH_WITH_ACTION:
+                return new PrimarySwitchPreference(getPrefContext());
+            case GROUP:
+                mMetricsFeatureProvider.action(
+                        mMetricsFeatureProvider.getAttribution(getActivity()),
+                        SettingsEnums.ACTION_SETTINGS_GROUP_TILE_ADDED_TO_SCREEN,
+                        getMetricsCategory(),
+                        tile.getKey(getContext()),
+                        /* value= */ 0);
+                return new PreferenceCategory((getPrefContext()));
+            case ACTION:
+            default:
+                return new Preference(getPrefContext());
+        }
     }
 
     @VisibleForTesting
diff --git a/src/com/android/settings/dashboard/profileselector/ProfileSelectDialog.java b/src/com/android/settings/dashboard/profileselector/ProfileSelectDialog.java
index ef6ad83..58a51cb 100644
--- a/src/com/android/settings/dashboard/profileselector/ProfileSelectDialog.java
+++ b/src/com/android/settings/dashboard/profileselector/ProfileSelectDialog.java
@@ -17,6 +17,7 @@
 package com.android.settings.dashboard.profileselector;
 
 import android.app.Dialog;
+import android.app.PendingIntent;
 import android.content.Context;
 import android.content.DialogInterface;
 import android.content.DialogInterface.OnCancelListener;
@@ -127,13 +128,25 @@
     @Override
     public void onClick(int position) {
         final UserHandle user = mSelectedTile.userHandle.get(position);
-        // Show menu on top level items.
-        final Intent intent = new Intent(mSelectedTile.getIntent());
-        FeatureFactory.getFactory(getContext()).getMetricsFeatureProvider()
-                .logStartedIntentWithProfile(intent, mSourceMetricCategory,
-                        position == 1 /* isWorkProfile */);
-        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
-        getActivity().startActivityAsUser(intent, user);
+        if (!mSelectedTile.hasPendingIntent()) {
+            final Intent intent = new Intent(mSelectedTile.getIntent());
+            FeatureFactory.getFactory(getContext()).getMetricsFeatureProvider()
+                    .logStartedIntentWithProfile(intent, mSourceMetricCategory,
+                            position == 1 /* isWorkProfile */);
+            intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
+            getActivity().startActivityAsUser(intent, user);
+        } else {
+            PendingIntent pendingIntent = mSelectedTile.pendingIntentMap.get(user);
+            FeatureFactory.getFactory(getContext()).getMetricsFeatureProvider()
+                    .logSettingsTileClickWithProfile(mSelectedTile.getKey(getContext()),
+                            mSourceMetricCategory,
+                            position == 1 /* isWorkProfile */);
+            try {
+                pendingIntent.send();
+            } catch (PendingIntent.CanceledException e) {
+                Log.w(TAG, "Failed executing pendingIntent. " + pendingIntent.getIntent(), e);
+            }
+        }
         dismiss();
     }
 
@@ -178,4 +191,36 @@
             }
         }
     }
+
+    /**
+     * Checks the userHandle and pendingIntentMap in the provided tile, and remove the invalid
+     * entries if any.
+     */
+    public static void updatePendingIntentsIfNeeded(Context context, Tile tile) {
+        if (tile.userHandle == null || tile.userHandle.size() <= 1
+                || tile.pendingIntentMap.size() <= 1) {
+            return;
+        }
+        for (UserHandle userHandle : List.copyOf(tile.userHandle)) {
+            if (!tile.pendingIntentMap.containsKey(userHandle)) {
+                if (DEBUG) {
+                    Log.d(TAG, "Delete the user without pending intent: "
+                            + userHandle.getIdentifier());
+                }
+                tile.userHandle.remove(userHandle);
+            }
+        }
+
+        final UserManager userManager = UserManager.get(context);
+        for (UserHandle userHandle : List.copyOf(tile.pendingIntentMap.keySet())) {
+            UserInfo userInfo = userManager.getUserInfo(userHandle.getIdentifier());
+            if (userInfo == null || userInfo.isCloneProfile()) {
+                if (DEBUG) {
+                    Log.d(TAG, "Delete the user: " + userHandle.getIdentifier());
+                }
+                tile.userHandle.remove(userHandle);
+                tile.pendingIntentMap.remove(userHandle);
+            }
+        }
+    }
 }
diff --git a/src/com/android/settings/development/BluetoothLeAudioDeviceDetailsPreferenceController.java b/src/com/android/settings/development/BluetoothLeAudioDeviceDetailsPreferenceController.java
index a54c594..298ced0 100644
--- a/src/com/android/settings/development/BluetoothLeAudioDeviceDetailsPreferenceController.java
+++ b/src/com/android/settings/development/BluetoothLeAudioDeviceDetailsPreferenceController.java
@@ -40,6 +40,7 @@
 
     private static final String PREFERENCE_KEY = "bluetooth_show_leaudio_device_details";
     private static final String CONFIG_LE_AUDIO_ENABLED_BY_DEFAULT = "le_audio_enabled_by_default";
+    private static final boolean LE_AUDIO_DEVICE_DETAIL_DEFAULT_VALUE = true;
     static int sLeAudioSupportedStateCache = BluetoothStatusCodes.ERROR_UNKNOWN;
 
     @VisibleForTesting
@@ -75,7 +76,7 @@
         DeviceConfig.setProperty(
                 DeviceConfig.NAMESPACE_SETTINGS_UI,
                 SettingsUIDeviceConfig.BT_LE_AUDIO_DEVICE_DETAIL_ENABLED,
-                isEnabled ? "true" : "false", false);
+                isEnabled ? "true" : "false", LE_AUDIO_DEVICE_DETAIL_DEFAULT_VALUE);
         return true;
     }
 
@@ -87,7 +88,8 @@
 
         final boolean leAudioDeviceDetailEnabled = DeviceConfig.getBoolean(
                 DeviceConfig.NAMESPACE_SETTINGS_UI,
-                SettingsUIDeviceConfig.BT_LE_AUDIO_DEVICE_DETAIL_ENABLED, false);
+                SettingsUIDeviceConfig.BT_LE_AUDIO_DEVICE_DETAIL_ENABLED,
+                LE_AUDIO_DEVICE_DETAIL_DEFAULT_VALUE);
         final boolean leAudioEnabledByDefault = DeviceConfig.getBoolean(
                 DeviceConfig.NAMESPACE_BLUETOOTH, CONFIG_LE_AUDIO_ENABLED_BY_DEFAULT, false);
 
@@ -102,6 +104,7 @@
         // Reset the toggle to null when the developer option is disabled
         DeviceConfig.setProperty(
                 DeviceConfig.NAMESPACE_SETTINGS_UI,
-                SettingsUIDeviceConfig.BT_LE_AUDIO_DEVICE_DETAIL_ENABLED, "null", false);
+                SettingsUIDeviceConfig.BT_LE_AUDIO_DEVICE_DETAIL_ENABLED, "null",
+                LE_AUDIO_DEVICE_DETAIL_DEFAULT_VALUE);
     }
 }
diff --git a/src/com/android/settings/fuelgauge/batteryusage/BatteryEntry.java b/src/com/android/settings/fuelgauge/batteryusage/BatteryEntry.java
index b3e190f..7f86b7c 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/BatteryEntry.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/BatteryEntry.java
@@ -172,7 +172,6 @@
                     mName = mDefaultPackageName;
                 }
             }
-            getQuickNameIconForUid(uid, packages, loadDataInBackground);
             mTimeInForegroundMs =
                     uidBatteryConsumer.getTimeInStateMs(UidBatteryConsumer.STATE_FOREGROUND);
             mTimeInBackgroundMs =
diff --git a/src/com/android/settings/wifi/repository/WifiHotspotRepository.java b/src/com/android/settings/wifi/repository/WifiHotspotRepository.java
index 6764214..af8eb47 100644
--- a/src/com/android/settings/wifi/repository/WifiHotspotRepository.java
+++ b/src/com/android/settings/wifi/repository/WifiHotspotRepository.java
@@ -623,9 +623,11 @@
 
     @VisibleForTesting
     class SoftApCallback implements WifiManager.SoftApCallback {
+        private static final String TAG = "SoftApCallback";
+
         @Override
         public void onStateChanged(int state, int failureReason) {
-            log("onStateChanged(), state:" + state + ", failureReason:" + failureReason);
+            Log.d(TAG, "onStateChanged(), state:" + state + ", failureReason:" + failureReason);
             mWifiApState = state;
             if (!mIsRestarting) {
                 return;
diff --git a/src/com/android/settings/wifi/tether/WifiHotspotSpeedSettings.java b/src/com/android/settings/wifi/tether/WifiHotspotSpeedSettings.java
index f5066bd..a5e12d8 100644
--- a/src/com/android/settings/wifi/tether/WifiHotspotSpeedSettings.java
+++ b/src/com/android/settings/wifi/tether/WifiHotspotSpeedSettings.java
@@ -108,15 +108,17 @@
             if (radioButton == null) {
                 continue;
             }
-            if (radioButton.isChecked() != speedInfo.mIsChecked) {
-                radioButton.setChecked(speedInfo.mIsChecked);
+            if (!speedInfo.mIsVisible) {
+                radioButton.setVisible(false);
+                continue;
             }
-            if (radioButton.isEnabled() != speedInfo.mIsEnabled) {
-                radioButton.setEnabled(speedInfo.mIsEnabled);
+            radioButton.setEnabled(speedInfo.mIsEnabled);
+            radioButton.setChecked(speedInfo.mIsChecked);
+            if (speedInfo.mSummary != null) {
+                radioButton.setSummary(speedInfo.mSummary);
             }
-            if (radioButton.isVisible() != speedInfo.mIsVisible) {
-                radioButton.setVisible(speedInfo.mIsVisible);
-            }
+            // setVisible at the end to avoid UI flickering
+            radioButton.setVisible(true);
         }
     }
 
diff --git a/src/com/android/settings/wifi/tether/WifiHotspotSpeedViewModel.java b/src/com/android/settings/wifi/tether/WifiHotspotSpeedViewModel.java
index f04669a..e7eb3a6 100644
--- a/src/com/android/settings/wifi/tether/WifiHotspotSpeedViewModel.java
+++ b/src/com/android/settings/wifi/tether/WifiHotspotSpeedViewModel.java
@@ -22,12 +22,15 @@
 import static com.android.settings.wifi.repository.WifiHotspotRepository.SPEED_6GHZ;
 
 import android.app.Application;
+import android.util.Log;
 
+import androidx.annotation.VisibleForTesting;
 import androidx.lifecycle.AndroidViewModel;
 import androidx.lifecycle.LiveData;
 import androidx.lifecycle.MutableLiveData;
 import androidx.lifecycle.Observer;
 
+import com.android.settings.R;
 import com.android.settings.overlay.FeatureFactory;
 import com.android.settings.wifi.repository.WifiHotspotRepository;
 
@@ -41,6 +44,12 @@
  */
 public class WifiHotspotSpeedViewModel extends AndroidViewModel {
     private static final String TAG = "WifiHotspotSpeedViewModel";
+    @VisibleForTesting
+    static final int RES_SPEED_5G_SUMMARY = R.string.wifi_hotspot_speed_5g_summary;
+    @VisibleForTesting
+    static final int RES_SPEED_6G_SUMMARY = R.string.wifi_hotspot_speed_6g_summary;
+    @VisibleForTesting
+    static final int RES_SUMMARY_UNAVAILABLE = R.string.wifi_hotspot_speed_summary_unavailable;
 
     protected final WifiHotspotRepository mWifiHotspotRepository;
     protected Map<Integer, SpeedInfo> mSpeedInfoMap = new HashMap<>();
@@ -75,14 +84,18 @@
     }
 
     protected void on6gAvailableChanged(Boolean available) {
-        log("on6gAvailableChanged(), available:" + available);
+        Log.d(TAG, "on6gAvailableChanged(), available:" + available);
         mSpeedInfo6g.mIsEnabled = available;
+        mSpeedInfo6g.mSummary = getApplication()
+                .getString(available ? RES_SPEED_6G_SUMMARY : RES_SUMMARY_UNAVAILABLE);
         updateSpeedInfoMapData();
     }
 
     protected void on5gAvailableChanged(Boolean available) {
-        log("on5gAvailableChanged(), available:" + available);
+        Log.d(TAG, "on5gAvailableChanged(), available:" + available);
         mSpeedInfo5g.mIsEnabled = available;
+        mSpeedInfo5g.mSummary = getApplication()
+                .getString(available ? RES_SPEED_5G_SUMMARY : RES_SUMMARY_UNAVAILABLE);
 
         boolean showDualBand = mWifiHotspotRepository.isDualBand() && available;
         log("on5gAvailableChanged(), showDualBand:" + showDualBand);
@@ -144,6 +157,7 @@
         Boolean mIsChecked;
         boolean mIsEnabled;
         boolean mIsVisible;
+        String mSummary;
 
         public SpeedInfo(boolean isChecked, boolean isEnabled, boolean isVisible) {
             this.mIsChecked = isChecked;
@@ -157,6 +171,7 @@
                     .append("isChecked:").append(mIsChecked)
                     .append(",isEnabled:").append(mIsEnabled)
                     .append(",isVisible:").append(mIsVisible)
+                    .append(",mSummary:").append(mSummary)
                     .append('}').toString();
         }
     }
diff --git a/tests/robotests/src/com/android/settings/dashboard/DashboardFeatureProviderImplTest.java b/tests/robotests/src/com/android/settings/dashboard/DashboardFeatureProviderImplTest.java
index 4ba6eae..f7a940f 100644
--- a/tests/robotests/src/com/android/settings/dashboard/DashboardFeatureProviderImplTest.java
+++ b/tests/robotests/src/com/android/settings/dashboard/DashboardFeatureProviderImplTest.java
@@ -43,6 +43,7 @@
 import static org.mockito.Mockito.verifyNoInteractions;
 import static org.mockito.Mockito.when;
 
+import android.app.PendingIntent;
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.ActivityInfo;
@@ -57,6 +58,7 @@
 import android.os.UserManager;
 import android.util.Pair;
 
+import androidx.fragment.app.Fragment;
 import androidx.fragment.app.FragmentActivity;
 import androidx.preference.Preference;
 import androidx.preference.SwitchPreference;
@@ -200,6 +202,27 @@
     }
 
     @Test
+    public void bindPreference_providerTileWithPendingIntent_shouldBindIntent() {
+        final Preference preference = new SwitchPreference(RuntimeEnvironment.application);
+        Bundle metaData = new Bundle();
+        metaData.putInt(META_DATA_PREFERENCE_TITLE, R.string.settings_label);
+        metaData.putInt(META_DATA_PREFERENCE_SUMMARY, R.string.about_settings_summary);
+        metaData.putInt(META_DATA_KEY_ORDER, 10);
+        metaData.putString(META_DATA_PREFERENCE_KEYHINT, KEY);
+        final Tile tile = new ProviderTile(mProviderInfo, CategoryKey.CATEGORY_HOMEPAGE, metaData);
+        PendingIntent pendingIntent =
+                PendingIntent.getActivity(RuntimeEnvironment.application, 0, new Intent("test"), 0);
+        tile.pendingIntentMap.put(UserHandle.CURRENT, pendingIntent);
+
+        mImpl.bindPreferenceToTileAndGetObservers(mActivity, mFragment, mForceRoundedIcon,
+                preference, tile, "123", Preference.DEFAULT_ORDER);
+
+        assertThat(preference.getFragment()).isNull();
+        assertThat(preference.getOnPreferenceClickListener()).isNotNull();
+        assertThat(preference.getOrder()).isEqualTo(tile.getOrder());
+    }
+
+    @Test
     public void bindPreference_noFragmentMetadata_shouldBindIntent() {
         final Preference preference = new Preference(RuntimeEnvironment.application);
         mActivityInfo.metaData.putInt(META_DATA_KEY_ORDER, 10);
@@ -631,6 +654,55 @@
     }
 
     @Test
+    public void clickPreference_providerTileWithPendingIntent_singleUser_executesPendingIntent() {
+        final Preference preference = new SwitchPreference(RuntimeEnvironment.application);
+        Bundle metaData = new Bundle();
+        metaData.putInt(META_DATA_PREFERENCE_TITLE, R.string.settings_label);
+        metaData.putInt(META_DATA_PREFERENCE_SUMMARY, R.string.about_settings_summary);
+        metaData.putInt(META_DATA_KEY_ORDER, 10);
+        metaData.putString(META_DATA_PREFERENCE_KEYHINT, KEY);
+        final Tile tile = new ProviderTile(mProviderInfo, CategoryKey.CATEGORY_HOMEPAGE, metaData);
+        PendingIntent pendingIntent =
+                PendingIntent.getActivity(RuntimeEnvironment.application, 0, new Intent("test"), 0);
+        tile.pendingIntentMap.put(UserHandle.CURRENT, pendingIntent);
+
+        mImpl.bindPreferenceToTileAndGetObservers(mActivity, mFragment, mForceRoundedIcon,
+                preference, tile, "123", Preference.DEFAULT_ORDER);
+        preference.performClick();
+
+        Intent nextStartedActivity =
+                Shadows.shadowOf(RuntimeEnvironment.application).peekNextStartedActivity();
+        assertThat(nextStartedActivity).isNotNull();
+        assertThat(nextStartedActivity.getAction()).isEqualTo("test");
+    }
+
+    @Test
+    public void clickPreference_providerTileWithPendingIntent_multiUser_showsProfileDialog() {
+        final Preference preference = new SwitchPreference(RuntimeEnvironment.application);
+        Bundle metaData = new Bundle();
+        metaData.putInt(META_DATA_PREFERENCE_TITLE, R.string.settings_label);
+        metaData.putInt(META_DATA_PREFERENCE_SUMMARY, R.string.about_settings_summary);
+        metaData.putInt(META_DATA_KEY_ORDER, 10);
+        metaData.putString(META_DATA_PREFERENCE_KEYHINT, KEY);
+        final Tile tile = new ProviderTile(mProviderInfo, CategoryKey.CATEGORY_HOMEPAGE, metaData);
+        PendingIntent pendingIntent =
+                PendingIntent.getActivity(RuntimeEnvironment.application, 0, new Intent("test"), 0);
+        tile.pendingIntentMap.put(UserHandle.CURRENT, pendingIntent);
+        tile.pendingIntentMap.put(new UserHandle(10), pendingIntent);
+
+        mImpl.bindPreferenceToTileAndGetObservers(mActivity, mFragment, mForceRoundedIcon,
+                preference, tile, "123", Preference.DEFAULT_ORDER);
+        preference.performClick();
+
+        Fragment dialogFragment =
+                mActivity.getSupportFragmentManager().findFragmentByTag("select_profile");
+        assertThat(dialogFragment).isNotNull();
+        Intent nextStartedActivity =
+                Shadows.shadowOf(RuntimeEnvironment.application).peekNextStartedActivity();
+        assertThat(nextStartedActivity).isNull();
+    }
+
+    @Test
     public void openTileIntent_profileSelectionDialog_shouldShow() {
         ShadowUserManager.getShadow().addUser(10, "Someone", 0);
 
diff --git a/tests/robotests/src/com/android/settings/dashboard/DashboardFragmentTest.java b/tests/robotests/src/com/android/settings/dashboard/DashboardFragmentTest.java
index 0739294..ecaf36f 100644
--- a/tests/robotests/src/com/android/settings/dashboard/DashboardFragmentTest.java
+++ b/tests/robotests/src/com/android/settings/dashboard/DashboardFragmentTest.java
@@ -16,7 +16,9 @@
 package com.android.settings.dashboard;
 
 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.DASHBOARD_CONTAINER;
+import static com.android.settingslib.drawer.TileUtils.META_DATA_PREFERENCE_GROUP_KEY;
 import static com.android.settingslib.drawer.TileUtils.META_DATA_PREFERENCE_KEYHINT;
+import static com.android.settingslib.drawer.TileUtils.META_DATA_PREFERENCE_PENDING_INTENT;
 import static com.android.settingslib.drawer.TileUtils.META_DATA_PREFERENCE_SWITCH_URI;
 
 import static com.google.common.truth.Truth.assertThat;
@@ -30,6 +32,7 @@
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
+import android.app.PendingIntent;
 import android.app.settings.SettingsEnums;
 import android.content.ContentResolver;
 import android.content.Context;
@@ -38,15 +41,18 @@
 import android.content.pm.ProviderInfo;
 import android.net.Uri;
 import android.os.Bundle;
+import android.os.UserHandle;
 import android.preference.PreferenceManager.OnActivityResultListener;
 
 import androidx.preference.Preference;
+import androidx.preference.PreferenceCategory;
 import androidx.preference.PreferenceFragmentCompat;
 import androidx.preference.PreferenceManager;
 import androidx.preference.PreferenceScreen;
 import androidx.preference.SwitchPreference;
 
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.settings.R;
 import com.android.settings.core.PreferenceControllerMixin;
 import com.android.settings.slices.BlockingSlicePrefController;
 import com.android.settings.testutils.FakeFeatureFactory;
@@ -57,6 +63,7 @@
 import com.android.settingslib.drawer.ActivityTile;
 import com.android.settingslib.drawer.DashboardCategory;
 import com.android.settingslib.drawer.ProviderTile;
+import com.android.settingslib.drawer.Tile;
 
 import org.junit.Before;
 import org.junit.Ignore;
@@ -178,6 +185,43 @@
     }
 
     @Test
+    public void displayTilesAsPreference_withGroup_shouldAddTilesIntoGroup() {
+        final ProviderInfo providerInfo = new ProviderInfo();
+        providerInfo.packageName = "pkg";
+        providerInfo.name = "provider";
+        providerInfo.authority = "authority";
+        final Bundle groupTileMetaData = new Bundle();
+        groupTileMetaData.putString(META_DATA_PREFERENCE_KEYHINT, "injected_tile_group_key");
+        ProviderTile groupTile = new ProviderTile(providerInfo, mDashboardCategory.key,
+                groupTileMetaData);
+        mDashboardCategory.addTile(groupTile);
+
+        final Bundle subTileMetaData = new Bundle();
+        subTileMetaData.putString(META_DATA_PREFERENCE_KEYHINT, "injected_tile_key3");
+        subTileMetaData.putString(META_DATA_PREFERENCE_GROUP_KEY, "injected_tile_group_key");
+        subTileMetaData.putParcelable(
+                META_DATA_PREFERENCE_PENDING_INTENT,
+                PendingIntent.getActivity(mContext, 0, new Intent(), 0));
+        ProviderTile subTile = new ProviderTile(providerInfo, mDashboardCategory.key,
+                subTileMetaData);
+        mDashboardCategory.addTile(subTile);
+
+        PreferenceCategory groupPreference = mock(PreferenceCategory.class);
+        when(mFakeFeatureFactory.dashboardFeatureProvider
+                .getTilesForCategory(nullable(String.class)))
+                .thenReturn(mDashboardCategory);
+        when(mFakeFeatureFactory.dashboardFeatureProvider
+                .getDashboardKeyForTile(any(Tile.class)))
+                .then(invocation -> ((Tile) invocation.getArgument(0)).getKey(mContext));
+        when(mTestFragment.mScreen.findPreference("injected_tile_group_key"))
+                .thenReturn(groupPreference);
+        mTestFragment.onCreatePreferences(new Bundle(), "rootKey");
+
+        verify(mTestFragment.mScreen, times(3)).addPreference(nullable(Preference.class));
+        verify(groupPreference).addPreference(nullable(Preference.class));
+    }
+
+    @Test
     public void displayTilesAsPreference_shouldNotAddTilesWithoutIntent() {
         mTestFragment.onCreatePreferences(new Bundle(), "rootKey");
 
@@ -352,6 +396,16 @@
     }
 
     @Test
+    public void createPreference_isActivityTile_returnPreference() {
+        final Preference pref = mTestFragment.createPreference(mActivityTile);
+
+        assertThat(pref).isInstanceOf(Preference.class);
+        assertThat(pref).isNotInstanceOf(PrimarySwitchPreference.class);
+        assertThat(pref).isNotInstanceOf(SwitchPreference.class);
+        assertThat(pref.getWidgetLayoutResource()).isEqualTo(0);
+    }
+
+    @Test
     public void createPreference_isActivityTileAndHasSwitch_returnPrimarySwitchPreference() {
         mActivityTile.getMetaData().putString(META_DATA_PREFERENCE_SWITCH_URI, "uri");
 
@@ -361,6 +415,64 @@
     }
 
     @Test
+    public void createPreference_isProviderTileWithPendingIntent_returnPreferenceWithIcon() {
+        final ProviderInfo providerInfo = new ProviderInfo();
+        providerInfo.packageName = "pkg";
+        providerInfo.name = "provider";
+        providerInfo.authority = "authority";
+        final Bundle metaData = new Bundle();
+        metaData.putString(META_DATA_PREFERENCE_KEYHINT, "injected_tile_key2");
+        ProviderTile providerTile = new ProviderTile(providerInfo, mDashboardCategory.key,
+                metaData);
+        providerTile.pendingIntentMap.put(
+                UserHandle.CURRENT, PendingIntent.getActivity(mContext, 0, new Intent(), 0));
+
+        final Preference pref = mTestFragment.createPreference(providerTile);
+
+        assertThat(pref).isInstanceOf(Preference.class);
+        assertThat(pref).isNotInstanceOf(PrimarySwitchPreference.class);
+        assertThat(pref).isNotInstanceOf(SwitchPreference.class);
+        assertThat(pref.getWidgetLayoutResource())
+                .isEqualTo(R.layout.preference_external_action_icon);
+    }
+
+    @Test
+    public void createPreference_isProviderTileWithPendingIntentAndSwitch_returnPrimarySwitch() {
+        mProviderTile.pendingIntentMap.put(
+                UserHandle.CURRENT, PendingIntent.getActivity(mContext, 0, new Intent(), 0));
+
+        final Preference pref = mTestFragment.createPreference(mProviderTile);
+
+        assertThat(pref).isInstanceOf(PrimarySwitchPreference.class);
+    }
+
+    @Test
+    public void createPreference_isGroupTile_returnPreferenceCategory_logTileAdded() {
+        final ProviderInfo providerInfo = new ProviderInfo();
+        providerInfo.packageName = "pkg";
+        providerInfo.name = "provider";
+        providerInfo.authority = "authority";
+        final Bundle metaData = new Bundle();
+        metaData.putString(META_DATA_PREFERENCE_KEYHINT, "injected_tile_key2");
+        ProviderTile providerTile =
+                new ProviderTile(providerInfo, mDashboardCategory.key, metaData);
+        MetricsFeatureProvider metricsFeatureProvider =
+                mFakeFeatureFactory.getMetricsFeatureProvider();
+        when(metricsFeatureProvider.getAttribution(any())).thenReturn(123);
+
+        final Preference pref = mTestFragment.createPreference(providerTile);
+
+        assertThat(pref).isInstanceOf(PreferenceCategory.class);
+        verify(metricsFeatureProvider)
+                .action(
+                        123,
+                        SettingsEnums.ACTION_SETTINGS_GROUP_TILE_ADDED_TO_SCREEN,
+                        mTestFragment.getMetricsCategory(),
+                        "injected_tile_key2",
+                        0);
+    }
+
+    @Test
     public void onActivityResult_test() {
         final int requestCode = 10;
         final int resultCode = 1;
diff --git a/tests/robotests/src/com/android/settings/dashboard/profileselector/ProfileSelectDialogTest.java b/tests/robotests/src/com/android/settings/dashboard/profileselector/ProfileSelectDialogTest.java
index 4e81cee..9a13961 100644
--- a/tests/robotests/src/com/android/settings/dashboard/profileselector/ProfileSelectDialogTest.java
+++ b/tests/robotests/src/com/android/settings/dashboard/profileselector/ProfileSelectDialogTest.java
@@ -24,7 +24,9 @@
 import static org.mockito.Mockito.when;
 
 import android.app.Dialog;
+import android.app.PendingIntent;
 import android.content.Context;
+import android.content.Intent;
 import android.content.pm.ActivityInfo;
 import android.content.pm.UserInfo;
 import android.os.UserHandle;
@@ -119,6 +121,28 @@
     }
 
     @Test
+    public void updatePendingIntentsIfNeeded_removesUsersWithNoPendingIntentsAndCloneProfile() {
+        final UserInfo userInfo = new UserInfo(CLONE_USER.getIdentifier(), "clone_user", null,
+                UserInfo.FLAG_PROFILE, UserManager.USER_TYPE_PROFILE_CLONE);
+        when(mUserManager.getUserInfo(CLONE_USER.getIdentifier())).thenReturn(userInfo);
+        final Tile tile = new ActivityTile(mActivityInfo, CategoryKey.CATEGORY_HOMEPAGE);
+        tile.userHandle.add(CLONE_USER);
+        tile.userHandle.add(NORMAL_USER);
+        tile.userHandle.add(new UserHandle(10));
+        PendingIntent pendingIntent = PendingIntent.getActivity(mContext, 0, new Intent(), 0);
+        tile.pendingIntentMap.put(CLONE_USER, pendingIntent);
+        tile.pendingIntentMap.put(NORMAL_USER, pendingIntent);
+
+        ProfileSelectDialog.updatePendingIntentsIfNeeded(mContext, tile);
+
+        assertThat(tile.userHandle).hasSize(1);
+        assertThat(tile.userHandle).containsExactly(NORMAL_USER);
+        assertThat(tile.pendingIntentMap).hasSize(1);
+        assertThat(tile.pendingIntentMap).containsKey(NORMAL_USER);
+        verify(mUserManager, times(1)).getUserInfo(CLONE_USER.getIdentifier());
+    }
+
+    @Test
     public void createDialog_showsCorrectTitle() {
         mContext.setTheme(R.style.Theme_AppCompat);
 
diff --git a/tests/robotests/src/com/android/settings/wifi/tether/WifiHotspotSpeedSettingsTest.java b/tests/robotests/src/com/android/settings/wifi/tether/WifiHotspotSpeedSettingsTest.java
index 969f992..31f4c09 100644
--- a/tests/robotests/src/com/android/settings/wifi/tether/WifiHotspotSpeedSettingsTest.java
+++ b/tests/robotests/src/com/android/settings/wifi/tether/WifiHotspotSpeedSettingsTest.java
@@ -25,8 +25,10 @@
 import static com.android.settings.wifi.tether.WifiHotspotSpeedSettings.KEY_SPEED_5GHZ;
 import static com.android.settings.wifi.tether.WifiHotspotSpeedSettings.KEY_SPEED_6GHZ;
 
+import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.Mockito.anyBoolean;
 import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
@@ -89,98 +91,156 @@
 
     @Test
     public void onSpeedInfoMapDataChanged_checkedSpeed2g_checkedToRadioButton2g() {
-        mSpeedInfo2g = new WifiHotspotSpeedViewModel.SpeedInfo(false, true, false);
+        mSpeedInfo2g = new WifiHotspotSpeedViewModel.SpeedInfo(true, true, true);
         updateSpeedInfoMap();
-        mockRadioButton(true, false, true);
+        mockRadioButton(false, false, false);
         mSettings.mSpeedPreferenceMap.put(SPEED_2GHZ, mRadioButton);
 
         mSettings.onSpeedInfoMapDataChanged(mSpeedInfoMap);
 
-        verifyRadioButton(false, true, false);
+        verifyRadioButton(true, true, true);
     }
 
     @Test
     public void onSpeedInfoMapDataChanged_uncheckedSpeed2g_uncheckedToRadioButton2g() {
-        mSpeedInfo2g = new WifiHotspotSpeedViewModel.SpeedInfo(true, false, true);
+        mSpeedInfo2g = new WifiHotspotSpeedViewModel.SpeedInfo(false, false, true);
         updateSpeedInfoMap();
-        mockRadioButton(false, true, false);
+        mockRadioButton(true, true, true);
         mSettings.mSpeedPreferenceMap.put(SPEED_2GHZ, mRadioButton);
 
         mSettings.onSpeedInfoMapDataChanged(mSpeedInfoMap);
 
-        verifyRadioButton(true, false, true);
+        verifyRadioButton(false, false, true);
     }
 
     @Test
     public void onSpeedInfoMapDataChanged_checkedSpeed5g_checkedToRadioButton5g() {
-        mSpeedInfo5g = new WifiHotspotSpeedViewModel.SpeedInfo(false, true, false);
+        mSpeedInfo5g = new WifiHotspotSpeedViewModel.SpeedInfo(true, true, true);
         updateSpeedInfoMap();
-        mockRadioButton(true, false, true);
+        mockRadioButton(false, false, false);
         mSettings.mSpeedPreferenceMap.put(SPEED_5GHZ, mRadioButton);
 
         mSettings.onSpeedInfoMapDataChanged(mSpeedInfoMap);
 
-        verifyRadioButton(false, true, false);
+        verifyRadioButton(true, true, true);
     }
 
     @Test
     public void onSpeedInfoMapDataChanged_uncheckedSpeed5g_uncheckedToRadioButton5g() {
-        mSpeedInfo5g = new WifiHotspotSpeedViewModel.SpeedInfo(true, false, true);
+        mSpeedInfo5g = new WifiHotspotSpeedViewModel.SpeedInfo(false, false, true);
         updateSpeedInfoMap();
-        mockRadioButton(false, true, false);
+        mockRadioButton(true, true, true);
         mSettings.mSpeedPreferenceMap.put(SPEED_5GHZ, mRadioButton);
 
         mSettings.onSpeedInfoMapDataChanged(mSpeedInfoMap);
 
-        verifyRadioButton(true, false, true);
+        verifyRadioButton(false, false, true);
     }
 
     @Test
     public void onSpeedInfoMapDataChanged_checkedSpeed2g5g_checkedToRadioButton2g5g() {
-        mSpeedInfo2g5g = new WifiHotspotSpeedViewModel.SpeedInfo(false, true, false);
+        mSpeedInfo2g5g = new WifiHotspotSpeedViewModel.SpeedInfo(true, true, true);
         updateSpeedInfoMap();
-        mockRadioButton(true, false, true);
+        mockRadioButton(false, false, false);
         mSettings.mSpeedPreferenceMap.put(SPEED_2GHZ_5GHZ, mRadioButton);
 
         mSettings.onSpeedInfoMapDataChanged(mSpeedInfoMap);
 
-        verifyRadioButton(false, true, false);
+        verifyRadioButton(true, true, true);
     }
 
     @Test
-    public void onSpeedInfoMapDataChanged_uncheckedSpeed25g_uncheckedToRadioButton25g() {
-        mSpeedInfo2g5g = new WifiHotspotSpeedViewModel.SpeedInfo(true, false, true);
+    public void onSpeedInfoMapDataChanged_uncheckedSpeed2g5g_uncheckedToRadioButton2g5g() {
+        mSpeedInfo2g5g = new WifiHotspotSpeedViewModel.SpeedInfo(false, false, true);
         updateSpeedInfoMap();
-        mockRadioButton(false, true, false);
+        mockRadioButton(true, true, true);
         mSettings.mSpeedPreferenceMap.put(SPEED_2GHZ_5GHZ, mRadioButton);
 
         mSettings.onSpeedInfoMapDataChanged(mSpeedInfoMap);
 
-        verifyRadioButton(true, false, true);
+        verifyRadioButton(false, false, true);
     }
 
     @Test
     public void onSpeedInfoMapDataChanged_checkedSpeed6g_checkedToRadioButton6g() {
-        mSpeedInfo6g = new WifiHotspotSpeedViewModel.SpeedInfo(false, true, false);
+        mSpeedInfo6g = new WifiHotspotSpeedViewModel.SpeedInfo(true, true, true);
         updateSpeedInfoMap();
+        mockRadioButton(false, false, false);
+        mSettings.mSpeedPreferenceMap.put(SPEED_6GHZ, mRadioButton);
+
+        mSettings.onSpeedInfoMapDataChanged(mSpeedInfoMap);
+
+        verifyRadioButton(true, true, true);
+    }
+
+    @Test
+    public void onSpeedInfoMapDataChanged_uncheckedSpeed6g_uncheckedToRadioButton6g() {
+        mSpeedInfo6g = new WifiHotspotSpeedViewModel.SpeedInfo(false, false, true);
+        updateSpeedInfoMap();
+        mockRadioButton(true, true, true);
+        mSettings.mSpeedPreferenceMap.put(SPEED_6GHZ, mRadioButton);
+
+        mSettings.onSpeedInfoMapDataChanged(mSpeedInfoMap);
+
+        verifyRadioButton(false, false, true);
+    }
+
+    @Test
+    public void onSpeedInfoMapDataChanged_setVisibleFalse_setVisibleOnly() {
+        mSpeedInfo6g = new WifiHotspotSpeedViewModel.SpeedInfo(true, true, false);
+        mSpeedInfo6g.mSummary = "summary";
+        mSpeedInfoMap.put(SPEED_6GHZ, mSpeedInfo6g);
+        mockRadioButton(true, true, true);
+        mSettings.mSpeedPreferenceMap.put(SPEED_6GHZ, mRadioButton);
+
+        mSettings.onSpeedInfoMapDataChanged(mSpeedInfoMap);
+
+        verify(mRadioButton).setVisible(false);
+        verify(mRadioButton, never()).setChecked(anyBoolean());
+        verify(mRadioButton, never()).setEnabled(anyBoolean());
+        verify(mRadioButton, never()).setSummary(anyString());
+    }
+
+    @Test
+    public void onSpeedInfoMapDataChanged_setVisibleTrue_setAllProperties() {
+        mSpeedInfo6g = new WifiHotspotSpeedViewModel.SpeedInfo(true, true, true);
+        mSpeedInfo6g.mSummary = "summary";
+        mSpeedInfoMap.put(SPEED_6GHZ, mSpeedInfo6g);
+        mockRadioButton(true, true, true);
+        mSettings.mSpeedPreferenceMap.put(SPEED_6GHZ, mRadioButton);
+
+        mSettings.onSpeedInfoMapDataChanged(mSpeedInfoMap);
+
+        verify(mRadioButton).setVisible(true);
+        verify(mRadioButton).setChecked(anyBoolean());
+        verify(mRadioButton).setEnabled(anyBoolean());
+        verify(mRadioButton).setSummary(anyString());
+    }
+
+    @Test
+    public void onSpeedInfoMapDataChanged_summaryIsNull_doNotSetSummary() {
+        mSpeedInfo6g = new WifiHotspotSpeedViewModel.SpeedInfo(true, true, true);
+        mSpeedInfo6g.mSummary = null;
+        mSpeedInfoMap.put(SPEED_6GHZ, mSpeedInfo6g);
+        mockRadioButton(true, true, true);
+        mSettings.mSpeedPreferenceMap.put(SPEED_6GHZ, mRadioButton);
+
+        mSettings.onSpeedInfoMapDataChanged(mSpeedInfoMap);
+
+        verify(mRadioButton, never()).setSummary(anyString());
+    }
+
+    @Test
+    public void onSpeedInfoMapDataChanged_summaryNotNull_setSummary() {
+        mSpeedInfo6g = new WifiHotspotSpeedViewModel.SpeedInfo(true, false, true);
+        mSpeedInfo6g.mSummary = "summary";
+        mSpeedInfoMap.put(SPEED_6GHZ, mSpeedInfo6g);
         mockRadioButton(true, false, true);
         mSettings.mSpeedPreferenceMap.put(SPEED_6GHZ, mRadioButton);
 
         mSettings.onSpeedInfoMapDataChanged(mSpeedInfoMap);
 
-        verifyRadioButton(false, true, false);
-    }
-
-    @Test
-    public void onSpeedInfoMapDataChanged_uncheckedSpeed6g_uncheckedToRadioButton6g() {
-        mSpeedInfo6g = new WifiHotspotSpeedViewModel.SpeedInfo(true, false, true);
-        updateSpeedInfoMap();
-        mockRadioButton(false, true, false);
-        mSettings.mSpeedPreferenceMap.put(SPEED_6GHZ, mRadioButton);
-
-        mSettings.onSpeedInfoMapDataChanged(mSpeedInfoMap);
-
-        verifyRadioButton(true, false, true);
+        verify(mRadioButton).setSummary(mSpeedInfo6g.mSummary);
     }
 
     @Test
diff --git a/tests/unit/src/com/android/settings/wifi/tether/WifiHotspotSpeedViewModelTest.java b/tests/unit/src/com/android/settings/wifi/tether/WifiHotspotSpeedViewModelTest.java
index 3a1a927..f52478e 100644
--- a/tests/unit/src/com/android/settings/wifi/tether/WifiHotspotSpeedViewModelTest.java
+++ b/tests/unit/src/com/android/settings/wifi/tether/WifiHotspotSpeedViewModelTest.java
@@ -20,6 +20,9 @@
 import static com.android.settings.wifi.repository.WifiHotspotRepository.SPEED_2GHZ_5GHZ;
 import static com.android.settings.wifi.repository.WifiHotspotRepository.SPEED_5GHZ;
 import static com.android.settings.wifi.repository.WifiHotspotRepository.SPEED_6GHZ;
+import static com.android.settings.wifi.tether.WifiHotspotSpeedViewModel.RES_SPEED_5G_SUMMARY;
+import static com.android.settings.wifi.tether.WifiHotspotSpeedViewModel.RES_SPEED_6G_SUMMARY;
+import static com.android.settings.wifi.tether.WifiHotspotSpeedViewModel.RES_SUMMARY_UNAVAILABLE;
 
 import static com.google.common.truth.Truth.assertThat;
 
@@ -128,7 +131,9 @@
         mViewModel.on6gAvailableChanged(true);
 
         verify(mSpeedInfoMapData).setValue(mViewModel.mSpeedInfoMap);
-        assertThat(mViewModel.mSpeedInfoMap.get(SPEED_6GHZ).mIsEnabled).isTrue();
+        WifiHotspotSpeedViewModel.SpeedInfo speedInfo = mViewModel.mSpeedInfoMap.get(SPEED_6GHZ);
+        assertThat(speedInfo.mIsEnabled).isTrue();
+        assertThat(speedInfo.mSummary).isEqualTo(mContext.getString(RES_SPEED_6G_SUMMARY));
     }
 
     @Test
@@ -139,7 +144,9 @@
         mViewModel.on6gAvailableChanged(false);
 
         verify(mSpeedInfoMapData).setValue(mViewModel.mSpeedInfoMap);
-        assertThat(mViewModel.mSpeedInfoMap.get(SPEED_6GHZ).mIsEnabled).isFalse();
+        WifiHotspotSpeedViewModel.SpeedInfo speedInfo = mViewModel.mSpeedInfoMap.get(SPEED_6GHZ);
+        assertThat(speedInfo.mIsEnabled).isFalse();
+        assertThat(speedInfo.mSummary).isEqualTo(mContext.getString(RES_SUMMARY_UNAVAILABLE));
     }
 
     @Test
@@ -150,7 +157,9 @@
         mViewModel.on5gAvailableChanged(true);
 
         verify(mSpeedInfoMapData).setValue(mViewModel.mSpeedInfoMap);
-        assertThat(mViewModel.mSpeedInfoMap.get(SPEED_5GHZ).mIsEnabled).isTrue();
+        WifiHotspotSpeedViewModel.SpeedInfo speedInfo = mViewModel.mSpeedInfoMap.get(SPEED_5GHZ);
+        assertThat(speedInfo.mIsEnabled).isTrue();
+        assertThat(speedInfo.mSummary).isEqualTo(mContext.getString(RES_SPEED_5G_SUMMARY));
     }
 
     @Test
@@ -161,7 +170,9 @@
         mViewModel.on5gAvailableChanged(false);
 
         verify(mSpeedInfoMapData).setValue(mViewModel.mSpeedInfoMap);
-        assertThat(mViewModel.mSpeedInfoMap.get(SPEED_5GHZ).mIsEnabled).isFalse();
+        WifiHotspotSpeedViewModel.SpeedInfo speedInfo = mViewModel.mSpeedInfoMap.get(SPEED_5GHZ);
+        assertThat(speedInfo.mIsEnabled).isFalse();
+        assertThat(speedInfo.mSummary).isEqualTo(mContext.getString(RES_SUMMARY_UNAVAILABLE));
     }
 
     @Test