Merge "Update screen lock complexity permission to password complexity"
diff --git a/res/layout/homepage_condition_footer.xml b/res/layout/homepage_condition_footer.xml
index 56687fe..cc84f52 100644
--- a/res/layout/homepage_condition_footer.xml
+++ b/res/layout/homepage_condition_footer.xml
@@ -29,6 +29,7 @@
         android:id="@+id/collapse_button"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:src="@drawable/ic_expand_less"/>
+        android:src="@drawable/ic_expand_less"
+        android:tint="?android:attr/colorAccent"/>
 
 </LinearLayout>
\ No newline at end of file
diff --git a/res/layout/homepage_condition_header.xml b/res/layout/homepage_condition_header.xml
index a2796ec..5c1b181 100644
--- a/res/layout/homepage_condition_header.xml
+++ b/res/layout/homepage_condition_header.xml
@@ -45,7 +45,8 @@
             android:paddingTop="@dimen/homepage_condition_header_indicator_padding_top"
             android:paddingStart="@dimen/homepage_condition_header_indicator_padding_start"
             android:paddingEnd="@dimen/homepage_condition_header_indicator_padding_end"
-            android:src="@*android:drawable/ic_expand_more"/>
+            android:src="@*android:drawable/ic_expand_more"
+            android:tint="?android:attr/colorAccent"/>
 
     </LinearLayout>
 
diff --git a/res/layout/wifi_button_preference_widget.xml b/res/layout/wifi_button_preference_widget.xml
index 1ecb98c..0999d20 100644
--- a/res/layout/wifi_button_preference_widget.xml
+++ b/res/layout/wifi_button_preference_widget.xml
@@ -23,5 +23,4 @@
            android:minHeight="@dimen/min_tap_target_size"
            android:layout_gravity="center"
            android:background="@null"
-           android:visibility="gone"
-           android:contentDescription="@string/wifi_add_network" />
+           android:visibility="gone"/>
diff --git a/res/layout/wifi_dialog.xml b/res/layout/wifi_dialog.xml
index 1ae3bf5..333296c 100644
--- a/res/layout/wifi_dialog.xml
+++ b/res/layout/wifi_dialog.xml
@@ -71,7 +71,7 @@
                         android:layout_centerVertical="true"
                         android:background="@null"
                         android:src="@drawable/ic_scan_24dp"
-                        android:contentDescription="@string/wifi_add_network" />
+                        android:contentDescription="@string/wifi_dpp_scan_qr_code"/>
                 </RelativeLayout>
 
                 <LinearLayout android:id="@+id/ssid_too_long_warning"
@@ -307,7 +307,7 @@
                         android:layout_centerVertical="true"
                         android:background="@null"
                         android:src="@drawable/ic_scan_24dp"
-                        android:contentDescription="@string/wifi_add_network" />
+                        android:contentDescription="@string/wifi_dpp_scan_qr_code"/>
                 </RelativeLayout>
             </LinearLayout>
 
diff --git a/res/layout/wifi_dpp_fragment_header.xml b/res/layout/wifi_dpp_fragment_header.xml
index e8e71d1..364f360 100644
--- a/res/layout/wifi_dpp_fragment_header.xml
+++ b/res/layout/wifi_dpp_fragment_header.xml
@@ -40,27 +40,35 @@
         android:src="@drawable/ic_devices_check_circle_green"
         android:scaleType="fitCenter"/>
 
-    <TextView
-        android:id="@android:id/title"
-        style="@style/TextAppearance.EntityHeaderTitle"
-        android:layout_width="match_parent"
+    <!-- Add title_summary_container to group content for Talkback -->
+    <LinearLayout
+        android:id="@+id/title_summary_container"
+        android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:gravity="center_horizontal"
-        android:textAlignment="center"
-        android:layout_marginTop="8dp"
-        android:paddingStart="32dp"
-        android:paddingEnd="32dp"/>
+        android:orientation="vertical"
+        android:focusable="true">
 
-    <TextView
-        android:id="@android:id/summary"
-        style="@style/TextAppearance.EntityHeaderSummary"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:singleLine="false"
-        android:gravity="center_horizontal"
-        android:textAlignment="center"
-        android:layout_marginTop="2dp"
-        android:paddingStart="32dp"
-        android:paddingEnd="32dp"/>
+        <TextView
+            android:id="@android:id/title"
+            style="@style/TextAppearance.EntityHeaderTitle"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:gravity="center_horizontal"
+            android:textAlignment="center"
+            android:layout_marginTop="8dp"
+            android:paddingStart="32dp"
+            android:paddingEnd="32dp"/>
 
+        <TextView
+            android:id="@android:id/summary"
+            style="@style/TextAppearance.EntityHeaderSummary"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:singleLine="false"
+            android:gravity="center_horizontal"
+            android:textAlignment="center"
+            android:layout_marginTop="2dp"
+            android:paddingStart="32dp"
+            android:paddingEnd="32dp"/>
+    </LinearLayout>
 </LinearLayout>
diff --git a/res/values/arrays.xml b/res/values/arrays.xml
index dc91f22..7e0ba10 100644
--- a/res/values/arrays.xml
+++ b/res/values/arrays.xml
@@ -1365,4 +1365,17 @@
         <item>"9"</item>
     </string-array>
 
+    <!-- WiFi calling mode array -->
+    <string-array name="wifi_calling_mode_summaries" translatable="false">
+         <item>@string/wifi_calling_mode_wifi_preferred_summary</item>
+         <item>@string/wifi_calling_mode_cellular_preferred_summary</item>
+         <item>@string/wifi_calling_mode_wifi_only_summary</item>
+    </string-array>
+
+    <!-- WiFi calling mode array without wifi only mode -->
+    <string-array name="wifi_calling_mode_summaries_without_wifi_only" translatable="false">
+         <item>@string/wifi_calling_mode_wifi_preferred_summary</item>
+         <item>@string/wifi_calling_mode_cellular_preferred_summary</item>
+    </string-array>
+
 </resources>
diff --git a/res/values/attrs.xml b/res/values/attrs.xml
index c7bf1c7..e099cf0 100644
--- a/res/values/attrs.xml
+++ b/res/values/attrs.xml
@@ -132,6 +132,11 @@
         <attr name="aspectRatio" format="float" />
     </declare-styleable>
 
+    <declare-styleable name="ListWithEntrySummaryPreference">
+        <!-- Summaries of entry -->
+        <attr name="entrySummaries" format="reference" />
+    </declare-styleable>
+
     <!-- For UsageView -->
     <declare-styleable name="UsageView">
         <attr name="android:colorAccent" />
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index aeeb403..a36d8ab 100755
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -279,6 +279,15 @@
 
     <dimen name="password_requirement_textsize">14sp</dimen>
 
+    <!-- Visible vertical space we want to show below password edittext field when ime is shown.
+         The unit is sp as it is related to the text size of password requirement item. -->
+    <dimen name="visible_vertical_space_below_password">20sp</dimen>
+
+    <!-- Select dialog -->
+    <dimen name="select_dialog_padding_start">20dp</dimen>
+    <dimen name="select_dialog_item_margin_start">12dp</dimen>
+    <dimen name="select_dialog_summary_padding_bottom">8dp</dimen>
+
     <!-- Padding between the donut and the storage summary. -->
     <dimen name="storage_summary_padding_end">16dp</dimen>
     <!-- Text size of the big number in the donut. -->
diff --git a/res/values/strings.xml b/res/values/strings.xml
index f3fe1f0..b912c9d 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -2157,6 +2157,10 @@
     <string name="wifi_dpp_sharing_wifi_with_this_device">Sharing Wi\u2011Fi with this device\u2026</string>
     <!-- Hint for Wi-Fi DPP handshake running [CHAR LIMIT=NONE]  -->
     <string name="wifi_dpp_connecting">Connecting\u2026</string>
+    <!-- Title for the fragment to show that the QR code is for sharing Wi-Fi hotspot network [CHAR LIMIT=50] -->
+    <string name="wifi_dpp_share_hotspot">Share hotspot</string>
+    <!-- Hint for the user to share Wi-Fi hotspot network [CHAR LIMIT=NONE] -->
+    <string name="wifi_dpp_scan_qr_code_to_share_hotspot">Scan this QR code with another device to join hotspot \u201c<xliff:g id="ssid" example="OfficeWifi">%1$s</xliff:g>\u201d</string>
      <!-- Label for the try again button [CHAR LIMIT=20]-->
     <string name="retry">Retry</string>
     <!-- Label for the check box to share a network with other users on the same device -->
@@ -2221,6 +2225,14 @@
 
     <!-- Button label to connect to a Wi-Fi network -->
     <string name="wifi_connect">Connect</string>
+    <!-- Turned on notification for Wi-Fi [CHAR LIMIT=40] -->
+    <string name="wifi_turned_on_message">Wi\u2011Fi turned on</string>
+    <!-- Connected to notification for Wi-Fi [CHAR LIMIT=NONE] -->
+    <string name="wifi_connected_to_message">@string/bluetooth_connected_summary</string>
+    <!-- Button label to connecting progress to a Wi-Fi network [CHAR LIMIT=20] -->
+    <string name="wifi_connecting">Connecting\u2026</string>
+    <!-- Button label to disconnect to a Wi-Fi network [CHAR LIMIT=NONE] -->
+    <string name="wifi_disconnect">@string/bluetooth_device_context_disconnect</string>
     <!-- Failured notification for connect -->
     <string name="wifi_failed_connect_message">Failed to connect to network</string>
     <!-- Button label to delete a Wi-Fi network -->
@@ -2476,7 +2488,7 @@
     <!-- Title of WFC preference item [CHAR LIMIT=30] -->
     <string name="wifi_calling_mode_title">Calling preference</string>
     <!-- Title of WFC preference selection dialog [CHAR LIMIT=30] -->
-    <string name="wifi_calling_mode_dialog_title">Wi-Fi calling mode</string>
+    <string name="wifi_calling_mode_dialog_title">Calling preference</string>
     <!-- Title of WFC roaming preference item [CHAR LIMIT=45] -->
     <string name="wifi_calling_roaming_mode_title">Roaming preference</string>
     <!-- Summary of WFC roaming preference item [CHAR LIMIT=NONE]-->
@@ -2484,9 +2496,9 @@
     <!-- WFC mode dialog [CHAR LIMIT=45] -->
     <string name="wifi_calling_roaming_mode_dialog_title">Roaming preference</string>
     <string-array name="wifi_calling_mode_choices">
-        <item>Wi-Fi preferred</item>
-        <item>Mobile preferred</item>
-        <item>Wi-Fi only</item>
+        <item>@*android:string/wfc_mode_wifi_preferred_summary</item>
+        <item>@*android:string/wfc_mode_cellular_preferred_summary</item>
+        <item>@*android:string/wfc_mode_wifi_only_summary</item>
     </string-array>
     <string-array name="wifi_calling_mode_choices_v2">
         <item>Wi-Fi</item>
@@ -2499,8 +2511,8 @@
         <item>"0"</item>
     </string-array>
     <string-array name="wifi_calling_mode_choices_without_wifi_only">
-        <item>Wi-Fi preferred</item>
-        <item>Mobile preferred</item>
+        <item>@*android:string/wfc_mode_wifi_preferred_summary</item>
+        <item>@*android:string/wfc_mode_cellular_preferred_summary</item>
     </string-array>
     <string-array name="wifi_calling_mode_choices_v2_without_wifi_only">
         <item>Wi-Fi</item>
@@ -2510,6 +2522,14 @@
         <item>"2"</item>
         <item>"1"</item>
     </string-array>
+
+    <!-- Summary of WFC preference item on the WFC preference selection dialog. [CHAR LIMIT=70]-->
+    <string name="wifi_calling_mode_wifi_preferred_summary">If Wi\u2011Fi is unavailable, use mobile network</string>
+    <!-- Summary of WFC preference item on the WFC preference selection dialog. [CHAR LIMIT=70]-->
+    <string name="wifi_calling_mode_cellular_preferred_summary">If mobile network is unavailable, use Wi\u2011Fi</string>
+    <!-- Summary of WFC preference item on the WFC preference selection dialog. [CHAR LIMIT=70]-->
+    <string name="wifi_calling_mode_wifi_only_summary">Call over Wi\u2011Fi. If Wi\u2011Fi is lost, call will end.</string>
+
     <!-- Wi-Fi Calling settings. Text displayed when Wi-Fi Calling is off -->
     <string name="wifi_calling_off_explanation">When Wi-Fi calling is on, your phone can route calls via Wi-Fi networks or your carrier\u2019s network, depending on your preference and which signal is stronger. Before turning on this feature, check with your carrier regarding fees and other details.<xliff:g id="additional_text" example="Learn More">%1$s</xliff:g></string>
     <!-- Wi-Fi Calling settings. Additional text displayed when Wi-Fi Calling is off. Default empty. [CHAR LIMIT=NONE] -->
@@ -10666,9 +10686,6 @@
     <!-- Title for the Volume dialog (settings panel) with all volume streams[CHAR LIMIT=50] -->
     <string name="volume_connectivity_panel_title">Volume</string>
 
-    <!-- Subtitle explaining that mobile data cannot be used while airplane mode is on [CHAR LIMIT=50] -->
-    <string name="mobile_data_ap_mode_disabled">Unavailable during airplane mode</string>
-
     <!-- UI debug setting: force desktop mode [CHAR LIMIT=50] -->
     <string name="force_desktop_mode">Force desktop mode</string>
     <!-- UI debug setting: force desktop mode summary [CHAR LIMIT=NONE] -->
diff --git a/res/xml/single_choice_list_item_2.xml b/res/xml/single_choice_list_item_2.xml
new file mode 100644
index 0000000..ca80f44
--- /dev/null
+++ b/res/xml/single_choice_list_item_2.xml
@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:paddingStart="@dimen/select_dialog_padding_start"
+    android:paddingEnd="?android:attr/dialogPreferredPadding"
+    android:orientation="horizontal"
+    android:descendantFocusability="blocksDescendants">
+
+    <RadioButton
+        android:id="@+id/radio"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center_vertical"
+        android:clickable="false" />
+
+    <LinearLayout
+        android:layout_width="0dp"
+        android:layout_height="wrap_content"
+        android:layout_weight="1"
+        android:orientation="vertical"
+        android:layout_marginStart="@dimen/select_dialog_item_margin_start"
+        android:layout_gravity="center_vertical">
+
+        <TextView
+            android:id="@+id/title"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:textAppearance="?android:attr/textAppearanceMedium"
+            android:textColor="?android:attr/textColorAlertDialogListItem"
+            android:ellipsize="marquee" />
+
+        <TextView
+            android:id="@+id/summary"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:paddingBottom="@dimen/select_dialog_summary_padding_bottom"
+            android:textAppearance="?android:attr/textAppearanceListItemSecondary"
+            android:textColor="?android:attr/textColorSecondary"
+            android:maxLines="10" />
+
+    </LinearLayout>
+</LinearLayout>
diff --git a/res/xml/sound_settings.xml b/res/xml/sound_settings.xml
index 81a0453..57bee1f 100644
--- a/res/xml/sound_settings.xml
+++ b/res/xml/sound_settings.xml
@@ -41,7 +41,7 @@
         settings:controller="com.android.settings.notification.MediaVolumePreferenceController"/>
 
     <!-- Media output switcher -->
-    <ListPreference
+    <Preference
         android:key="media_output"
         android:title="@string/media_output_title"
         android:dialogTitle="@string/media_output_title"
diff --git a/res/xml/wifi_calling_settings.xml b/res/xml/wifi_calling_settings.xml
index 0adb1e8..0276bdb 100644
--- a/res/xml/wifi_calling_settings.xml
+++ b/res/xml/wifi_calling_settings.xml
@@ -15,24 +15,27 @@
 -->
 
 <PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
+                  xmlns:settings="http://schemas.android.com/apk/res-auto"
                   android:key="wifi_calling_settings"
                   android:title="@string/wifi_calling_settings_title">
 
-    <ListPreference
+    <com.android.settings.wifi.calling.ListWithEntrySummaryPreference
             android:key="wifi_calling_mode"
             android:title="@string/wifi_calling_mode_title"
             android:summary="@string/wifi_calling_mode_title"
             android:entries="@array/wifi_calling_mode_choices"
             android:entryValues="@array/wifi_calling_mode_values"
-            android:dialogTitle="@string/wifi_calling_mode_dialog_title" />
+            android:dialogTitle="@string/wifi_calling_mode_dialog_title"
+            settings:entrySummaries="@array/wifi_calling_mode_summaries" />
 
-    <ListPreference
+    <com.android.settings.wifi.calling.ListWithEntrySummaryPreference
             android:key="wifi_calling_roaming_mode"
             android:title="@string/wifi_calling_roaming_mode_title"
             android:summary="@string/wifi_calling_roaming_mode_summary"
             android:entries="@array/wifi_calling_mode_choices_v2"
             android:entryValues="@array/wifi_calling_mode_values"
-            android:dialogTitle="@string/wifi_calling_roaming_mode_dialog_title" />
+            android:dialogTitle="@string/wifi_calling_roaming_mode_dialog_title"
+            settings:entrySummaries="@array/wifi_calling_mode_summaries" />
 
     <Preference
             android:key="emergency_address_key"
diff --git a/res/xml/wifi_tether_settings.xml b/res/xml/wifi_tether_settings.xml
index 6c5e3c4..81e60a2 100644
--- a/res/xml/wifi_tether_settings.xml
+++ b/res/xml/wifi_tether_settings.xml
@@ -23,7 +23,7 @@
     settings:searchable="false"
     settings:initialExpandedChildrenCount="3">
 
-    <com.android.settings.widget.ValidatedEditTextPreference
+    <com.android.settings.wifi.tether.WifiTetherSsidPreference
         android:key="wifi_tether_network_name"
         android:title="@string/wifi_hotspot_name_title"
         android:summary="@string/summary_placeholder"/>
diff --git a/src/com/android/settings/applications/defaultapps/DefaultEmergencyPicker.java b/src/com/android/settings/applications/defaultapps/DefaultEmergencyPicker.java
index f088967..32cc9a8 100644
--- a/src/com/android/settings/applications/defaultapps/DefaultEmergencyPicker.java
+++ b/src/com/android/settings/applications/defaultapps/DefaultEmergencyPicker.java
@@ -17,9 +17,7 @@
 package com.android.settings.applications.defaultapps;
 
 import android.app.role.RoleManager;
-import android.app.role.RoleManagerCallback;
 import android.app.settings.SettingsEnums;
-import android.content.ContentResolver;
 import android.content.Context;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageInfo;
@@ -27,7 +25,6 @@
 import android.content.pm.ResolveInfo;
 import android.os.AsyncTask;
 import android.os.Process;
-import android.provider.Settings;
 import android.text.TextUtils;
 import android.util.Log;
 
@@ -100,18 +97,13 @@
         final String previousValue = getDefaultKey();
 
         if (!TextUtils.isEmpty(key) && !TextUtils.equals(key, previousValue)) {
-            getContext().getSystemService(RoleManager.class)
-                      .addRoleHolderAsUser(
-                              RoleManager.ROLE_EMERGENCY, key, 0, Process.myUserHandle(),
-                              AsyncTask.THREAD_POOL_EXECUTOR, new RoleManagerCallback() {
-                                  @Override
-                                  public void onSuccess() {}
-
-                                  @Override
-                                  public void onFailure() {
-                                      Log.e(TAG, "Failed to set emergency default app.");
-                                  }
-                              });
+            getContext().getSystemService(RoleManager.class).addRoleHolderAsUser(
+                    RoleManager.ROLE_EMERGENCY, key, 0, Process.myUserHandle(),
+                    AsyncTask.THREAD_POOL_EXECUTOR, successful -> {
+                        if (!successful) {
+                            Log.e(TAG, "Failed to set emergency default app.");
+                        }
+                    });
             return true;
         }
         return false;
diff --git a/src/com/android/settings/homepage/contextualcards/EligibleCardChecker.java b/src/com/android/settings/homepage/contextualcards/EligibleCardChecker.java
index 5423ce3..fe68d02 100644
--- a/src/com/android/settings/homepage/contextualcards/EligibleCardChecker.java
+++ b/src/com/android/settings/homepage/contextualcards/EligibleCardChecker.java
@@ -51,6 +51,9 @@
 
     @VisibleForTesting
     boolean isCardEligibleToDisplay(ContextualCard card) {
+        if (card.getRankingScore() < 0) {
+            return false;
+        }
         if (card.isCustomCard()) {
             return true;
         }
diff --git a/src/com/android/settings/media/MediaDeviceUpdateWorker.java b/src/com/android/settings/media/MediaDeviceUpdateWorker.java
index 7416018..d1e55e4 100644
--- a/src/com/android/settings/media/MediaDeviceUpdateWorker.java
+++ b/src/com/android/settings/media/MediaDeviceUpdateWorker.java
@@ -70,7 +70,7 @@
 
     @Override
     public void close() {
-
+        mLocalMediaManager = null;
     }
 
     @Override
diff --git a/src/com/android/settings/media/MediaOutputSlice.java b/src/com/android/settings/media/MediaOutputSlice.java
index d52b441..232986c 100644
--- a/src/com/android/settings/media/MediaOutputSlice.java
+++ b/src/com/android/settings/media/MediaOutputSlice.java
@@ -20,13 +20,11 @@
 
 import android.annotation.ColorInt;
 import android.app.PendingIntent;
+import android.bluetooth.BluetoothAdapter;
 import android.content.Context;
 import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.graphics.drawable.Drawable;
 import android.net.Uri;
-import android.os.UserHandle;
-import android.util.IconDrawableFactory;
+import android.text.TextUtils;
 import android.util.Log;
 
 import androidx.annotation.VisibleForTesting;
@@ -58,37 +56,48 @@
 
     private MediaDeviceUpdateWorker mWorker;
     private String mPackageName;
-    private IconDrawableFactory mIconDrawableFactory;
 
     public MediaOutputSlice(Context context) {
         mContext = context;
         mPackageName = getUri().getQueryParameter(MEDIA_PACKAGE_NAME);
-        mIconDrawableFactory = IconDrawableFactory.newInstance(mContext);
     }
 
     @VisibleForTesting
-    void init(String packageName, MediaDeviceUpdateWorker worker, IconDrawableFactory factory) {
+    void init(String packageName, MediaDeviceUpdateWorker worker) {
         mPackageName = packageName;
         mWorker = worker;
-        mIconDrawableFactory = factory;
     }
 
     @Override
     public Slice getSlice() {
-        final PackageManager pm = mContext.getPackageManager();
+        final BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
+        if (!adapter.isEnabled()) {
+            Log.d(TAG, "getSlice() Bluetooth is off");
+            return null;
+        }
 
         final List<MediaDevice> devices = getMediaDevices();
-        final CharSequence title = Utils.getApplicationLabel(mContext, mPackageName);
-        final CharSequence summary =
-                mContext.getString(R.string.media_output_panel_summary_of_playing_device,
-                        getConnectedDeviceName());
-
-        final Drawable drawable =
-                Utils.getBadgedIcon(mIconDrawableFactory, pm, mPackageName, UserHandle.myUserId());
-        final IconCompat icon = Utils.createIconWithDrawable(drawable);
-
         @ColorInt final int color = Utils.getColorAccentDefaultColor(mContext);
-        final SliceAction primarySliceAction = SliceAction.createDeeplink(getPrimaryAction(), icon,
+
+        final MediaDevice connectedDevice = getWorker().getCurrentConnectedMediaDevice();
+        final ListBuilder listBuilder = buildActiveDeviceHeader(color, connectedDevice);
+
+        for (MediaDevice device : devices) {
+            if (!TextUtils.equals(connectedDevice.getId(), device.getId())) {
+                listBuilder.addRow(getMediaDeviceRow(device));
+            }
+        }
+
+        return listBuilder.build();
+    }
+
+    private ListBuilder buildActiveDeviceHeader(@ColorInt int color, MediaDevice device) {
+        final String title = device.getName();
+        final IconCompat icon = IconCompat.createWithResource(mContext, device.getIcon());
+
+        final PendingIntent broadcastAction =
+                getBroadcastIntent(mContext, device.getId(), device.hashCode());
+        final SliceAction primarySliceAction = SliceAction.createDeeplink(broadcastAction, icon,
                 ListBuilder.ICON_IMAGE, title);
 
         final ListBuilder listBuilder = new ListBuilder(mContext, MEDIA_OUTPUT_SLICE_URI,
@@ -97,14 +106,10 @@
                 .addRow(new ListBuilder.RowBuilder()
                         .setTitleItem(icon, ListBuilder.ICON_IMAGE)
                         .setTitle(title)
-                        .setSubtitle(summary)
+                        .setSubtitle(device.getSummary())
                         .setPrimaryAction(primarySliceAction));
 
-        for (MediaDevice device : devices) {
-            listBuilder.addRow(getMediaDeviceRow(device));
-        }
-
-        return listBuilder.build();
+        return listBuilder;
     }
 
     private MediaDeviceUpdateWorker getWorker() {
@@ -120,18 +125,6 @@
         return devices;
     }
 
-    private String getConnectedDeviceName() {
-        final MediaDevice device = getWorker().getCurrentConnectedMediaDevice();
-        return device != null ? device.getName() : "";
-    }
-
-    private PendingIntent getPrimaryAction() {
-        final PackageManager pm = mContext.getPackageManager();
-        final Intent launchIntent = pm.getLaunchIntentForPackage(mPackageName);
-        final Intent intent = launchIntent;
-        return PendingIntent.getActivity(mContext, 0  /* requestCode */, intent, 0  /* flags */);
-    }
-
     private ListBuilder.RowBuilder getMediaDeviceRow(MediaDevice device) {
         final String title = device.getName();
         final PendingIntent broadcastAction =
@@ -141,7 +134,8 @@
                 .setTitleItem(deviceIcon, ListBuilder.ICON_IMAGE)
                 .setPrimaryAction(SliceAction.create(broadcastAction, deviceIcon,
                         ListBuilder.ICON_IMAGE, title))
-                .setTitle(title);
+                .setTitle(title)
+                .setSubtitle(device.getSummary());
 
         return rowBuilder;
     }
diff --git a/src/com/android/settings/network/telephony/MobileDataSlice.java b/src/com/android/settings/network/telephony/MobileDataSlice.java
index 5a5d6a2..6efd8c3 100644
--- a/src/com/android/settings/network/telephony/MobileDataSlice.java
+++ b/src/com/android/settings/network/telephony/MobileDataSlice.java
@@ -74,27 +74,8 @@
         final IconCompat icon = IconCompat.createWithResource(mContext,
                 R.drawable.ic_network_cell);
         final String title = mContext.getText(R.string.mobile_data_settings_title).toString();
-        @ColorInt final int color = Utils.getColorAccentDefaultColor(mContext);
-
-        // Return a Slice without the mobile data toggle when airplane mode is on.
-        if (isAirplaneModeEnabled()) {
-            final CharSequence summary = mContext.getText(R.string.mobile_data_ap_mode_disabled);
-            // Intent does nothing, but we have to pass an intent to the Row.
-            final PendingIntent intent = PendingIntent.getActivity(mContext, 0 /* requestCode */,
-                    new Intent(), 0 /* flags */);
-            final SliceAction deadAction =
-                    SliceAction.create(intent, icon, ListBuilder.ICON_IMAGE, title);
-            final ListBuilder listBuilder = new ListBuilder(mContext, getUri(),
-                    ListBuilder.INFINITY)
-                    .setAccentColor(color)
-                    .addRow(new ListBuilder.RowBuilder()
-                            .setTitle(title)
-                            .setSubtitle(summary)
-                            .setPrimaryAction(deadAction));
-            return listBuilder.build();
-        }
-
         final CharSequence summary = getSummary();
+        @ColorInt final int color = Utils.getColorAccentDefaultColor(mContext);
         final PendingIntent toggleAction = getBroadcastIntent(mContext);
         final PendingIntent primaryAction = getPrimaryAction();
         final SliceAction primarySliceAction = SliceAction.createDeeplink(primaryAction, icon,
@@ -120,6 +101,11 @@
 
     @Override
     public void onNotifyChange(Intent intent) {
+        // Don't make a change if we are in Airplane Mode.
+        if (isAirplaneModeEnabled()) {
+            return;
+        }
+
         final boolean newState = intent.getBooleanExtra(EXTRA_TOGGLE_STATE,
                     isMobileDataEnabled());
 
diff --git a/src/com/android/settings/notification/SoundSettings.java b/src/com/android/settings/notification/SoundSettings.java
index b26b921..eec0fb8 100644
--- a/src/com/android/settings/notification/SoundSettings.java
+++ b/src/com/android/settings/notification/SoundSettings.java
@@ -38,7 +38,6 @@
 import com.android.settings.dashboard.DashboardFragment;
 import com.android.settings.search.BaseSearchIndexProvider;
 import com.android.settings.sound.HandsFreeProfileOutputPreferenceController;
-import com.android.settings.sound.MediaOutputPreferenceController;
 import com.android.settings.widget.PreferenceCategoryController;
 import com.android.settings.widget.UpdatableListPreferenceDialogFragment;
 import com.android.settingslib.core.AbstractPreferenceController;
@@ -77,7 +76,6 @@
 
     private RingtonePreference mRequestPreference;
     private UpdatableListPreferenceDialogFragment mDialogFragment;
-    private String mMediaOutputControllerKey;
     private String mHfpOutputControllerKey;
 
     @Override
@@ -132,8 +130,6 @@
         final int metricsCategory;
         if (mHfpOutputControllerKey.equals(preference.getKey())) {
             metricsCategory = SettingsEnums.DIALOG_SWITCH_HFP_DEVICES;
-        } else if (mMediaOutputControllerKey.equals(preference.getKey())) {
-            metricsCategory = SettingsEnums.DIALOG_SWITCH_A2DP_DEVICES;
         } else {
             metricsCategory = Instrumentable.METRICS_CATEGORY_UNKNOWN;
         }
@@ -186,9 +182,6 @@
         volumeControllers.add(use(CallVolumePreferenceController.class));
         volumeControllers.add(use(RemoteVolumePreferenceController.class));
 
-        use(MediaOutputPreferenceController.class).setCallback(listPreference ->
-                onPreferenceDataChanged(listPreference));
-        mMediaOutputControllerKey = use(MediaOutputPreferenceController.class).getPreferenceKey();
         use(HandsFreeProfileOutputPreferenceController.class).setCallback(listPreference ->
                 onPreferenceDataChanged(listPreference));
         mHfpOutputControllerKey =
diff --git a/src/com/android/settings/panel/SettingsPanelActivity.java b/src/com/android/settings/panel/SettingsPanelActivity.java
index 3819c80..8aee382 100644
--- a/src/com/android/settings/panel/SettingsPanelActivity.java
+++ b/src/com/android/settings/panel/SettingsPanelActivity.java
@@ -16,13 +16,11 @@
 
 package com.android.settings.panel;
 
-import static com.android.settingslib.media.MediaOutputSliceConstants.ACTION_MEDIA_OUTPUT;
 import static com.android.settingslib.media.MediaOutputSliceConstants.EXTRA_PACKAGE_NAME;
 
 import android.app.settings.SettingsEnums;
 import android.content.Intent;
 import android.os.Bundle;
-import android.text.TextUtils;
 import android.util.Log;
 import android.view.Gravity;
 import android.view.MotionEvent;
@@ -75,15 +73,8 @@
             return;
         }
 
-        final String mediaPackageName =
-                callingIntent.getStringExtra(EXTRA_PACKAGE_NAME);
-
-        if (TextUtils.equals(ACTION_MEDIA_OUTPUT, callingIntent.getAction())
-                && TextUtils.isEmpty(mediaPackageName)) {
-            Log.e(TAG, "Missing EXTRA_PACKAGE_NAME, closing Panel Activity");
-            finish();
-            return;
-        }
+        // We will use it once media output switch panel support remote device.
+        final String mediaPackageName = callingIntent.getStringExtra(EXTRA_PACKAGE_NAME);
 
         setContentView(R.layout.settings_panel);
 
diff --git a/src/com/android/settings/sound/AudioSwitchPreferenceController.java b/src/com/android/settings/sound/AudioSwitchPreferenceController.java
index f77dfca..0da0f21 100644
--- a/src/com/android/settings/sound/AudioSwitchPreferenceController.java
+++ b/src/com/android/settings/sound/AudioSwitchPreferenceController.java
@@ -32,7 +32,6 @@
 import android.media.MediaRouter.Callback;
 import android.os.Handler;
 import android.os.Looper;
-import android.text.TextUtils;
 import android.util.FeatureFlagUtils;
 import android.util.Log;
 
@@ -40,7 +39,6 @@
 import androidx.preference.Preference;
 import androidx.preference.PreferenceScreen;
 
-import com.android.settings.R;
 import com.android.settings.bluetooth.Utils;
 import com.android.settings.core.BasePreferenceController;
 import com.android.settings.core.FeatureFlags;
@@ -63,15 +61,11 @@
 /**
  * Abstract class for audio switcher controller to notify subclass
  * updating the current status of switcher entry. Subclasses must overwrite
- * {@link #setActiveBluetoothDevice(BluetoothDevice)} to set the
- * active device for corresponding profile.
  */
 public abstract class AudioSwitchPreferenceController extends BasePreferenceController
-        implements Preference.OnPreferenceChangeListener, BluetoothCallback,
-        LifecycleObserver, OnStart, OnStop {
+        implements BluetoothCallback, LifecycleObserver, OnStart, OnStop {
 
     private static final String TAG = "AudioSwitchPrefCtrl";
-    private static final int INVALID_INDEX = -1;
 
     protected final List<BluetoothDevice> mConnectedDevices;
     protected final AudioManager mAudioManager;
@@ -129,35 +123,6 @@
     }
 
     @Override
-    public boolean onPreferenceChange(Preference preference, Object newValue) {
-        final String address = (String) newValue;
-        if (!(preference instanceof ListPreference)) {
-            return false;
-        }
-
-        final ListPreference listPreference = (ListPreference) preference;
-        if (TextUtils.equals(address, mContext.getText(R.string.media_output_default_summary))) {
-            // Switch to default device which address is device name
-            mSelectedIndex = getDefaultDeviceIndex();
-            setActiveBluetoothDevice(null);
-            listPreference.setSummary(mContext.getText(R.string.media_output_default_summary));
-        } else {
-            // Switch to BT device which address is hardware address
-            final int connectedDeviceIndex = getConnectedDeviceIndex(address);
-            if (connectedDeviceIndex == INVALID_INDEX) {
-                return false;
-            }
-            final BluetoothDevice btDevice = mConnectedDevices.get(connectedDeviceIndex);
-            mSelectedIndex = connectedDeviceIndex;
-            setActiveBluetoothDevice(btDevice);
-            listPreference.setSummary(btDevice.getAliasName());
-        }
-        return true;
-    }
-
-    public abstract void setActiveBluetoothDevice(BluetoothDevice device);
-
-    @Override
     public void displayPreference(PreferenceScreen screen) {
         super.displayPreference(screen);
         mPreference = screen.findPreference(mPreferenceKey);
@@ -185,6 +150,12 @@
     }
 
     @Override
+    public void onBluetoothStateChanged(int bluetoothState) {
+        // To handle the case that Bluetooth on and no connected devices
+        updateState(mPreference);
+    }
+
+    @Override
     public void onActiveDeviceChanged(CachedBluetoothDevice activeDevice, int bluetoothProfile) {
         updateState(mPreference);
     }
@@ -236,21 +207,15 @@
     }
 
     /**
-     * get A2dp connected device
+     * get A2dp devices on all states
+     * (STATE_DISCONNECTED, STATE_CONNECTING, STATE_CONNECTED,  STATE_DISCONNECTING)
      */
-    protected List<BluetoothDevice> getConnectedA2dpDevices() {
-        final List<BluetoothDevice> connectedDevices = new ArrayList<>();
+    protected List<BluetoothDevice> getConnectableA2dpDevices() {
         final A2dpProfile a2dpProfile = mProfileManager.getA2dpProfile();
         if (a2dpProfile == null) {
-            return connectedDevices;
+            return new ArrayList<>();
         }
-        final List<BluetoothDevice> devices = a2dpProfile.getConnectedDevices();
-        for (BluetoothDevice device : devices) {
-            if (device.isConnected()) {
-                connectedDevices.add(device);
-            }
-        }
-        return connectedDevices;
+        return a2dpProfile.getConnectableDevices();
     }
 
     /**
@@ -277,6 +242,31 @@
     }
 
     /**
+     * get hearing aid profile devices on all states
+     * (STATE_DISCONNECTED, STATE_CONNECTING, STATE_CONNECTED,  STATE_DISCONNECTING)
+     * exclude other devices with same hiSyncId.
+     */
+    protected List<BluetoothDevice> getConnectableHearingAidDevices() {
+        final List<BluetoothDevice> connectedDevices = new ArrayList<>();
+        final HearingAidProfile hapProfile = mProfileManager.getHearingAidProfile();
+        if (hapProfile == null) {
+            return connectedDevices;
+        }
+        final List<Long> devicesHiSyncIds = new ArrayList<>();
+        final List<BluetoothDevice> devices = hapProfile.getConnectableDevices();
+        for (BluetoothDevice device : devices) {
+            final long hiSyncId = hapProfile.getHiSyncId(device);
+            // device with same hiSyncId should not be shown in the UI.
+            // So do not add it into connectedDevices.
+            if (!devicesHiSyncIds.contains(hiSyncId)) {
+                devicesHiSyncIds.add(hiSyncId);
+                connectedDevices.add(device);
+            }
+        }
+        return connectedDevices;
+    }
+
+    /**
      * Find active hearing aid device
      */
     protected BluetoothDevice findActiveHearingAidDevice() {
@@ -306,52 +296,6 @@
      */
     public abstract BluetoothDevice findActiveDevice();
 
-    int getDefaultDeviceIndex() {
-        // Default device is after all connected devices.
-        return mConnectedDevices.size();
-    }
-
-    void setupPreferenceEntries(CharSequence[] mediaOutputs, CharSequence[] mediaValues,
-            BluetoothDevice activeDevice) {
-        // default to current device
-        mSelectedIndex = getDefaultDeviceIndex();
-        // default device is after all connected devices.
-        mediaOutputs[mSelectedIndex] = mContext.getText(R.string.media_output_default_summary);
-        // use default device name as address
-        mediaValues[mSelectedIndex] = mContext.getText(R.string.media_output_default_summary);
-        for (int i = 0, size = mConnectedDevices.size(); i < size; i++) {
-            final BluetoothDevice btDevice = mConnectedDevices.get(i);
-            mediaOutputs[i] = btDevice.getAliasName();
-            mediaValues[i] = btDevice.getAddress();
-            if (btDevice.equals(activeDevice)) {
-                // select the active connected device.
-                mSelectedIndex = i;
-            }
-        }
-    }
-
-    void setPreference(CharSequence[] mediaOutputs, CharSequence[] mediaValues,
-            Preference preference) {
-        final ListPreference listPreference = (ListPreference) preference;
-        listPreference.setEntries(mediaOutputs);
-        listPreference.setEntryValues(mediaValues);
-        listPreference.setValueIndex(mSelectedIndex);
-        listPreference.setSummary(mediaOutputs[mSelectedIndex]);
-        mAudioSwitchPreferenceCallback.onPreferenceDataChanged(listPreference);
-    }
-
-    private int getConnectedDeviceIndex(String hardwareAddress) {
-        if (mConnectedDevices != null) {
-            for (int i = 0, size = mConnectedDevices.size(); i < size; i++) {
-                final BluetoothDevice btDevice = mConnectedDevices.get(i);
-                if (TextUtils.equals(btDevice.getAddress(), hardwareAddress)) {
-                    return i;
-                }
-            }
-        }
-        return INVALID_INDEX;
-    }
-
     private void register() {
         mLocalBluetoothManager.getEventManager().registerCallback(this);
         mAudioManager.registerAudioDeviceCallback(mAudioManagerAudioDeviceCallback, mHandler);
diff --git a/src/com/android/settings/sound/HandsFreeProfileOutputPreferenceController.java b/src/com/android/settings/sound/HandsFreeProfileOutputPreferenceController.java
index a02c0b2..9157477 100644
--- a/src/com/android/settings/sound/HandsFreeProfileOutputPreferenceController.java
+++ b/src/com/android/settings/sound/HandsFreeProfileOutputPreferenceController.java
@@ -20,7 +20,9 @@
 
 import android.bluetooth.BluetoothDevice;
 import android.content.Context;
+import android.text.TextUtils;
 
+import androidx.preference.ListPreference;
 import androidx.preference.Preference;
 
 import com.android.settings.R;
@@ -32,14 +34,56 @@
  * This class allows switching between HFP-connected & HAP-connected BT devices
  * while in on-call state.
  */
-public class HandsFreeProfileOutputPreferenceController extends
-        AudioSwitchPreferenceController {
+public class HandsFreeProfileOutputPreferenceController extends AudioSwitchPreferenceController
+        implements Preference.OnPreferenceChangeListener {
+
+    private static final int INVALID_INDEX = -1;
 
     public HandsFreeProfileOutputPreferenceController(Context context, String key) {
         super(context, key);
     }
 
     @Override
+    public boolean onPreferenceChange(Preference preference, Object newValue) {
+        final String address = (String) newValue;
+        if (!(preference instanceof ListPreference)) {
+            return false;
+        }
+
+        final CharSequence defaultSummary = mContext.getText(R.string.media_output_default_summary);
+        final ListPreference listPreference = (ListPreference) preference;
+        if (TextUtils.equals(address, defaultSummary)) {
+            // Switch to default device which address is device name
+            mSelectedIndex = getDefaultDeviceIndex();
+            setActiveBluetoothDevice(null);
+            listPreference.setSummary(defaultSummary);
+        } else {
+            // Switch to BT device which address is hardware address
+            final int connectedDeviceIndex = getConnectedDeviceIndex(address);
+            if (connectedDeviceIndex == INVALID_INDEX) {
+                return false;
+            }
+            final BluetoothDevice btDevice = mConnectedDevices.get(connectedDeviceIndex);
+            mSelectedIndex = connectedDeviceIndex;
+            setActiveBluetoothDevice(btDevice);
+            listPreference.setSummary(btDevice.getAliasName());
+        }
+        return true;
+    }
+
+    private int getConnectedDeviceIndex(String hardwareAddress) {
+        if (mConnectedDevices != null) {
+            for (int i = 0, size = mConnectedDevices.size(); i < size; i++) {
+                final BluetoothDevice btDevice = mConnectedDevices.get(i);
+                if (TextUtils.equals(btDevice.getAddress(), hardwareAddress)) {
+                    return i;
+                }
+            }
+        }
+        return INVALID_INDEX;
+    }
+
+    @Override
     public void updateState(Preference preference) {
         if (preference == null) {
             // In case UI is not ready.
@@ -83,7 +127,41 @@
         setPreference(mediaOutputs, mediaValues, preference);
     }
 
-    @Override
+    int getDefaultDeviceIndex() {
+        // Default device is after all connected devices.
+        return mConnectedDevices.size();
+    }
+
+    void setupPreferenceEntries(CharSequence[] mediaOutputs, CharSequence[] mediaValues,
+            BluetoothDevice activeDevice) {
+        // default to current device
+        mSelectedIndex = getDefaultDeviceIndex();
+        // default device is after all connected devices.
+        final CharSequence defaultSummary = mContext.getText(R.string.media_output_default_summary);
+        mediaOutputs[mSelectedIndex] = defaultSummary;
+        // use default device name as address
+        mediaValues[mSelectedIndex] = defaultSummary;
+        for (int i = 0, size = mConnectedDevices.size(); i < size; i++) {
+            final BluetoothDevice btDevice = mConnectedDevices.get(i);
+            mediaOutputs[i] = btDevice.getAliasName();
+            mediaValues[i] = btDevice.getAddress();
+            if (btDevice.equals(activeDevice)) {
+                // select the active connected device.
+                mSelectedIndex = i;
+            }
+        }
+    }
+
+    void setPreference(CharSequence[] mediaOutputs, CharSequence[] mediaValues,
+            Preference preference) {
+        final ListPreference listPreference = (ListPreference) preference;
+        listPreference.setEntries(mediaOutputs);
+        listPreference.setEntryValues(mediaValues);
+        listPreference.setValueIndex(mSelectedIndex);
+        listPreference.setSummary(mediaOutputs[mSelectedIndex]);
+        mAudioSwitchPreferenceCallback.onPreferenceDataChanged(listPreference);
+    }
+
     public void setActiveBluetoothDevice(BluetoothDevice device) {
         if (!Utils.isAudioModeOngoingCall(mContext)) {
             return;
diff --git a/src/com/android/settings/sound/MediaOutputPreferenceController.java b/src/com/android/settings/sound/MediaOutputPreferenceController.java
index ce476ad..47810f7 100644
--- a/src/com/android/settings/sound/MediaOutputPreferenceController.java
+++ b/src/com/android/settings/sound/MediaOutputPreferenceController.java
@@ -16,13 +16,14 @@
 
 package com.android.settings.sound;
 
-import static android.bluetooth.IBluetoothHearingAid.HI_SYNC_ID_INVALID;
 import static android.media.AudioManager.STREAM_MUSIC;
 import static android.media.AudioSystem.DEVICE_OUT_REMOTE_SUBMIX;
 
 import android.bluetooth.BluetoothDevice;
 import android.content.Context;
+import android.content.Intent;
 import android.media.AudioManager;
+import android.text.TextUtils;
 
 import androidx.preference.Preference;
 
@@ -30,12 +31,16 @@
 import com.android.settingslib.Utils;
 import com.android.settingslib.bluetooth.A2dpProfile;
 import com.android.settingslib.bluetooth.HearingAidProfile;
+import com.android.settingslib.media.MediaOutputSliceConstants;
+
+import java.util.List;
 
 /**
- * This class which allows switching between A2dp-connected & HAP-connected BT devices.
- * A few conditions will disable this switcher:
- * - No available BT device(s)
- * - Media stream captured by cast device
+ * This class allows launching MediaOutputSlice to switch output device.
+ * Preference would hide only when
+ * - Bluetooth = OFF
+ * - Bluetooth = ON and Connected Devices = 0 and Previously Connected = 0
+ * - Media stream captured by remote device
  * - During a call.
  */
 public class MediaOutputPreferenceController extends AudioSwitchPreferenceController {
@@ -66,40 +71,22 @@
             return;
         }
 
-        mConnectedDevices.clear();
-        // Otherwise, list all of the A2DP connected device and display the active device.
-        if (mAudioManager.getMode() == AudioManager.MODE_NORMAL) {
-            mConnectedDevices.addAll(getConnectedA2dpDevices());
-            mConnectedDevices.addAll(getConnectedHearingAidDevices());
+        boolean deviceConnectable = false;
+        BluetoothDevice activeDevice = null;
+        // Show preference if there is connected or previously connected device
+        // Find active device and set its name as the preference's summary
+        List<BluetoothDevice> connectableA2dpDevices = getConnectableA2dpDevices();
+        List<BluetoothDevice> connectableHADevices = getConnectableHearingAidDevices();
+        if (mAudioManager.getMode() == AudioManager.MODE_NORMAL
+                && ((connectableA2dpDevices != null && !connectableA2dpDevices.isEmpty())
+                || (connectableHADevices != null && !connectableHADevices.isEmpty()))) {
+            deviceConnectable = true;
+            activeDevice = findActiveDevice();
         }
-
-        final int numDevices = mConnectedDevices.size();
-        mPreference.setVisible((numDevices == 0) ? false : true);
-        CharSequence[] mediaOutputs = new CharSequence[numDevices + 1];
-        CharSequence[] mediaValues = new CharSequence[numDevices + 1];
-
-        // Setup devices entries, select active connected device
-        setupPreferenceEntries(mediaOutputs, mediaValues, findActiveDevice());
-
-        // Display connected devices, default device and show the active device
-        setPreference(mediaOutputs, mediaValues, preference);
-    }
-
-    @Override
-    public void setActiveBluetoothDevice(BluetoothDevice device) {
-        if (mAudioManager.getMode() != AudioManager.MODE_NORMAL) {
-            return;
-        }
-        final HearingAidProfile hapProfile = mProfileManager.getHearingAidProfile();
-        final A2dpProfile a2dpProfile = mProfileManager.getA2dpProfile();
-        if (hapProfile != null && a2dpProfile != null && device == null) {
-            hapProfile.setActiveDevice(null);
-            a2dpProfile.setActiveDevice(null);
-        } else if (hapProfile != null && hapProfile.getHiSyncId(device) != HI_SYNC_ID_INVALID) {
-            hapProfile.setActiveDevice(device);
-        } else if (a2dpProfile != null) {
-            a2dpProfile.setActiveDevice(device);
-        }
+        mPreference.setVisible(deviceConnectable);
+        mPreference.setSummary((activeDevice == null) ?
+                mContext.getText(R.string.media_output_default_summary) :
+                activeDevice.getAliasName());
     }
 
     @Override
@@ -112,4 +99,34 @@
         }
         return activeDevice;
     }
+
+    /**
+     * Find active hearing aid device
+     */
+    @Override
+    protected BluetoothDevice findActiveHearingAidDevice() {
+        final HearingAidProfile hearingAidProfile = mProfileManager.getHearingAidProfile();
+
+        if (hearingAidProfile != null) {
+            List<BluetoothDevice> activeDevices = hearingAidProfile.getActiveDevices();
+            for (BluetoothDevice btDevice : activeDevices) {
+                if (btDevice != null) {
+                    return btDevice;
+                }
+            }
+        }
+        return null;
+    }
+
+    @Override
+    public boolean handlePreferenceTreeClick(Preference preference) {
+        if (TextUtils.equals(preference.getKey(), getPreferenceKey())) {
+            final Intent intent = new Intent()
+                    .setAction(MediaOutputSliceConstants.ACTION_MEDIA_OUTPUT)
+                    .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+            mContext.startActivity(intent);
+            return true;
+        }
+        return false;
+    }
 }
diff --git a/src/com/android/settings/wifi/ButtonPreference.java b/src/com/android/settings/wifi/ButtonPreference.java
index 9a0abf6..5169d7a 100644
--- a/src/com/android/settings/wifi/ButtonPreference.java
+++ b/src/com/android/settings/wifi/ButtonPreference.java
@@ -49,6 +49,7 @@
     private ImageButton mImageButton;
     private Drawable mButtonIcon;
     private View.OnClickListener mClickListener;
+    private String mContentDescription;
 
     // Used for dummy pref.
     public ButtonPreference(Context context, AttributeSet attrs) {
@@ -57,6 +58,7 @@
         mImageButton = null;
         mButtonIcon = null;
         mClickListener = null;
+        mContentDescription = null;
     }
 
     public ButtonPreference(Context context) {
@@ -83,6 +85,7 @@
         if (mImageButton != null) {
             mImageButton.setImageDrawable(mButtonIcon);
             mImageButton.setOnClickListener(mClickListener);
+            mImageButton.setContentDescription(mContentDescription);
         }
         setButtonVisibility();
     }
@@ -96,9 +99,9 @@
     /**
      * Sets the drawable to be displayed in button.
      */
-    public ButtonPreference setButtonIcon(@DrawableRes int iconResId) {
+    public void setButtonIcon(@DrawableRes int iconResId) {
         if (iconResId == 0) {
-            return this;
+            return;
         }
 
         try {
@@ -107,17 +110,26 @@
         } catch (Resources.NotFoundException exception) {
             Log.e(TAG, "Resource does not exist: " + iconResId);
         }
-        return this;
     }
 
     /**
      * Register a callback to be invoked when button is clicked.
      */
-    public ButtonPreference setButtonOnClickListener(View.OnClickListener listener) {
+    public void setButtonOnClickListener(View.OnClickListener listener) {
         if (listener != mClickListener) {
             mClickListener = listener;
             notifyChanged();
         }
-        return this;
+    }
+
+    /**
+     * A content description briefly describes the button and is primarily used for accessibility
+     * support to determine how a button should be presented to the user.
+     */
+    public void setButtonContentDescription(String contentDescription) {
+        if (contentDescription != mContentDescription) {
+            mContentDescription = contentDescription;
+            notifyChanged();
+        }
     }
 }
diff --git a/src/com/android/settings/wifi/WifiConfigController.java b/src/com/android/settings/wifi/WifiConfigController.java
index 916d330..665e253 100644
--- a/src/com/android/settings/wifi/WifiConfigController.java
+++ b/src/com/android/settings/wifi/WifiConfigController.java
@@ -265,11 +265,7 @@
             configureSecuritySpinner();
             mConfigUi.setSubmitButton(res.getString(R.string.wifi_save));
         } else {
-            if (!mAccessPoint.isPasspointConfig()) {
-                mConfigUi.setTitle(mAccessPoint.getSsid());
-            } else {
-                mConfigUi.setTitle(mAccessPoint.getConfigName());
-            }
+            mConfigUi.setTitle(mAccessPoint.getTitle());
 
             ViewGroup group = (ViewGroup) mView.findViewById(R.id.info);
 
diff --git a/src/com/android/settings/wifi/WifiSettings.java b/src/com/android/settings/wifi/WifiSettings.java
index c00fe24..9e5bfc8 100644
--- a/src/com/android/settings/wifi/WifiSettings.java
+++ b/src/com/android/settings/wifi/WifiSettings.java
@@ -247,6 +247,7 @@
             getContext().startActivity(
                     WifiDppUtils.getEnrolleeQrCodeScannerIntent(/* ssid */ null));
         });
+        mAddPreference.setButtonContentDescription(getString(R.string.wifi_dpp_scan_qr_code));
         mStatusMessagePreference = (LinkablePreference) findPreference(PREF_KEY_STATUS_MESSAGE);
 
         mUserBadgeCache = new AccessPointPreference.UserBadgeCache(getPackageManager());
@@ -483,7 +484,7 @@
         if (preference instanceof LongPressAccessPointPreference) {
             mSelectedAccessPoint =
                     ((LongPressAccessPointPreference) preference).getAccessPoint();
-            menu.setHeaderTitle(mSelectedAccessPoint.getSsid());
+            menu.setHeaderTitle(mSelectedAccessPoint.getTitle());
             if (mSelectedAccessPoint.isConnectable()) {
                 menu.add(Menu.NONE, MENU_ID_CONNECT, 0, R.string.wifi_menu_connect);
             }
diff --git a/src/com/android/settings/wifi/calling/ListWithEntrySummaryPreference.java b/src/com/android/settings/wifi/calling/ListWithEntrySummaryPreference.java
new file mode 100644
index 0000000..a44fcbe
--- /dev/null
+++ b/src/com/android/settings/wifi/calling/ListWithEntrySummaryPreference.java
@@ -0,0 +1,203 @@
+/*
+ * Copyright (C) 2018 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.wifi.calling;
+
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.res.TypedArray;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ArrayAdapter;
+import android.widget.ListAdapter;
+import android.widget.RadioButton;
+import android.widget.TextView;
+import androidx.appcompat.app.AlertDialog.Builder;
+import com.android.settings.CustomListPreference;
+import com.android.settings.R;
+
+/**
+ * ListPreference contain the entry summary.
+ */
+public class ListWithEntrySummaryPreference extends CustomListPreference {
+    private static final String LOG_TAG = "ListWithEntrySummaryPreference";
+    private final Context mContext;
+    private CharSequence[] mSummaries;
+
+    /**
+     * ListWithEntrySummaryPreference constructor.
+     *
+     * @param context The context of view.
+     * @param attrs The attributes of the XML tag that is inflating the linear layout.
+     */
+    public ListWithEntrySummaryPreference(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        mContext = context;
+
+        TypedArray array = context.obtainStyledAttributes(attrs,
+                R.styleable.ListWithEntrySummaryPreference, 0, 0);
+        mSummaries = array.getTextArray(R.styleable.ListWithEntrySummaryPreference_entrySummaries);
+        array.recycle();
+    }
+
+    /**
+     * Sets the summaries of mode items to be shown in the mode select dialog.
+     *
+     * @param summariesResId The summaries of mode items.
+     */
+    public void setEntrySummaries(int summariesResId) {
+        mSummaries = getContext().getResources().getTextArray(summariesResId);
+    }
+
+    /**
+     * Sets the summaries of mode items to be shown in the mode select dialog.
+     *
+     * @param summaries The summaries of mode items.
+     */
+    public void setEntrySummaries(CharSequence[] summaries) {
+        mSummaries = summaries;
+    }
+
+    private CharSequence getEntrySummary(int index) {
+        if (mSummaries == null) {
+            Log.w(LOG_TAG, "getEntrySummary : mSummaries is null");
+            return "";
+        }
+        return mSummaries[index];
+    }
+
+    @Override
+    protected void onPrepareDialogBuilder(Builder builder,
+            DialogInterface.OnClickListener listener) {
+        ListAdapter la = (ListAdapter) new SelectorAdapter(mContext,
+                R.xml.single_choice_list_item_2, this);
+        builder.setSingleChoiceItems(la, findIndexOfValue(getValue()), listener);
+        super.onPrepareDialogBuilder(builder, listener);
+    }
+
+    private static class SelectorAdapter extends ArrayAdapter<CharSequence> {
+        private final Context mContext;
+        private ListWithEntrySummaryPreference mSelector;
+
+        /**
+         * SelectorAdapter constructor.
+         *
+         * @param context The current context.
+         * @param rowResourceId The resource id of the XML tag that is inflating the linear layout.
+         * @param listPreference The instance of ListWithEntrySummaryPreference.
+         */
+        public SelectorAdapter(Context context, int rowResourceId,
+                ListWithEntrySummaryPreference listPreference) {
+            super(context, rowResourceId, listPreference.getEntryValues());
+            mContext = context;
+            mSelector = listPreference;
+        }
+
+        @Override
+        public View getView(int position, View convertView, ViewGroup parent) {
+            LayoutInflater inflater = LayoutInflater.from(mContext);
+            View row = inflater.inflate(R.xml.single_choice_list_item_2, parent, false);
+
+            TextView title = (TextView) row.findViewById(R.id.title);
+            title.setText(mSelector.getEntries()[position]);
+
+            TextView summary = (TextView) row.findViewById(R.id.summary);
+            summary.setText(mSelector.getEntrySummary(position));
+
+            RadioButton rb = (RadioButton) row.findViewById(R.id.radio);
+            if (position == mSelector.findIndexOfValue(mSelector.getValue())) {
+                rb.setChecked(true);
+            }
+
+            return row;
+        }
+    }
+
+    @Override
+    protected Parcelable onSaveInstanceState() {
+        final Parcelable superState = super.onSaveInstanceState();
+
+        final SavedState myState = new SavedState(superState);
+        myState.mEntries = getEntries();
+        myState.mEntryValues = getEntryValues();
+        myState.mSummaries = mSummaries;
+        return myState;
+    }
+
+    @Override
+    protected void onRestoreInstanceState(Parcelable state) {
+        if (state == null || !state.getClass().equals(SavedState.class)) {
+            // Didn't save state for us in onSaveInstanceState
+            super.onRestoreInstanceState(state);
+            return;
+        }
+
+        SavedState myState = (SavedState) state;
+        super.onRestoreInstanceState(myState.getSuperState());
+        setEntries(myState.mEntries);
+        setEntryValues(myState.mEntryValues);
+        mSummaries = myState.mSummaries;
+    }
+
+    /**
+     *  We save entries, entryValues and summaries into bundle.
+     *  At onCreate of fragment, dialog will be restored if it was open. In this case,
+     *  we need to restore entries, entryValues and summaries. Without those information,
+     *  crash when entering multi window during wfc modes dialog shown.
+     */
+    private static class SavedState extends BaseSavedState {
+        private CharSequence[] mEntries;
+        private CharSequence[] mEntryValues;
+        private CharSequence[] mSummaries;
+
+        public SavedState(Parcel source) {
+            super(source);
+            mEntries = source.readCharSequenceArray();
+            mEntryValues = source.readCharSequenceArray();
+            mSummaries = source.readCharSequenceArray();
+        }
+
+        @Override
+        public void writeToParcel(Parcel dest, int flags) {
+            super.writeToParcel(dest, flags);
+            dest.writeCharSequenceArray(mEntries);
+            dest.writeCharSequenceArray(mEntryValues);
+            dest.writeCharSequenceArray(mSummaries);
+        }
+
+        public SavedState(Parcelable superState) {
+            super(superState);
+        }
+
+        public static final Parcelable.Creator<SavedState> CREATOR =
+                new Parcelable.Creator<SavedState>() {
+            @Override
+            public SavedState createFromParcel(Parcel in) {
+                return new SavedState(in);
+            }
+
+            @Override
+            public SavedState[] newArray(int size) {
+                return new SavedState[size];
+            }
+        };
+    }
+}
diff --git a/src/com/android/settings/wifi/calling/WifiCallingSettingsForSub.java b/src/com/android/settings/wifi/calling/WifiCallingSettingsForSub.java
index 6fe1795..4255f3c 100644
--- a/src/com/android/settings/wifi/calling/WifiCallingSettingsForSub.java
+++ b/src/com/android/settings/wifi/calling/WifiCallingSettingsForSub.java
@@ -82,8 +82,8 @@
     //UI objects
     private SwitchBar mSwitchBar;
     private Switch mSwitch;
-    private ListPreference mButtonWfcMode;
-    private ListPreference mButtonWfcRoamingMode;
+    private ListWithEntrySummaryPreference mButtonWfcMode;
+    private ListWithEntrySummaryPreference mButtonWfcRoamingMode;
     private Preference mUpdateAddress;
     private TextView mEmptyView;
 
@@ -265,10 +265,11 @@
         mTelephonyManager = ((TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE))
                 .createForSubscriptionId(mSubId);
 
-        mButtonWfcMode = (ListPreference) findPreference(BUTTON_WFC_MODE);
+        mButtonWfcMode = (ListWithEntrySummaryPreference) findPreference(BUTTON_WFC_MODE);
         mButtonWfcMode.setOnPreferenceChangeListener(this);
 
-        mButtonWfcRoamingMode = (ListPreference) findPreference(BUTTON_WFC_ROAMING_MODE);
+        mButtonWfcRoamingMode = (ListWithEntrySummaryPreference) findPreference(
+                BUTTON_WFC_ROAMING_MODE);
         mButtonWfcRoamingMode.setOnPreferenceChangeListener(this);
 
         mUpdateAddress = (Preference) findPreference(PREFERENCE_EMERGENCY_ADDRESS);
@@ -329,10 +330,14 @@
         if (!isWifiOnlySupported) {
             mButtonWfcMode.setEntries(R.array.wifi_calling_mode_choices_without_wifi_only);
             mButtonWfcMode.setEntryValues(R.array.wifi_calling_mode_values_without_wifi_only);
+            mButtonWfcMode.setEntrySummaries(R.array.wifi_calling_mode_summaries_without_wifi_only);
+
             mButtonWfcRoamingMode.setEntries(
                     R.array.wifi_calling_mode_choices_v2_without_wifi_only);
             mButtonWfcRoamingMode.setEntryValues(
                     R.array.wifi_calling_mode_values_without_wifi_only);
+            mButtonWfcRoamingMode.setEntrySummaries(
+                    R.array.wifi_calling_mode_summaries_without_wifi_only);
         }
 
 
diff --git a/src/com/android/settings/wifi/details/WifiDetailPreferenceController.java b/src/com/android/settings/wifi/details/WifiDetailPreferenceController.java
index 01673e3..c2daa94 100644
--- a/src/com/android/settings/wifi/details/WifiDetailPreferenceController.java
+++ b/src/com/android/settings/wifi/details/WifiDetailPreferenceController.java
@@ -21,16 +21,12 @@
 
 import android.app.Activity;
 import android.app.AlertDialog;
-import android.app.KeyguardManager;
 import android.app.settings.SettingsEnums;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.graphics.drawable.Drawable;
-import android.hardware.biometrics.BiometricPrompt;
-import android.os.CancellationSignal;
-import android.os.Looper;
 import android.net.ConnectivityManager;
 import android.net.ConnectivityManager.NetworkCallback;
 import android.net.LinkAddress;
@@ -327,7 +323,7 @@
                 mContext.getDrawable(R.drawable.ic_settings_widget_background));
         iconView.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
 
-        mEntityHeaderController.setLabel(mAccessPoint.getSsidStr());
+        mEntityHeaderController.setLabel(mAccessPoint.getTitle());
     }
 
     @Override
@@ -619,48 +615,16 @@
      * Share the wifi network with QR code.
      */
     private void shareNetwork() {
-        final KeyguardManager keyguardManager = (KeyguardManager) mContext.getSystemService(
-                Context.KEYGUARD_SERVICE);
-        if (keyguardManager.isKeyguardSecure()) {
-            // Show authentication screen to confirm credentials (pin, pattern or password) for
-            // the current user of the device.
-            final String title = mContext.getString(
-                    R.string.lockpassword_confirm_your_pattern_header);
-            final String description = String.format(
-                    mContext.getString(R.string.wifi_sharing_message),
-                    mAccessPoint.getSsidStr());
+        final String title = mContext.getString(
+                R.string.lockpassword_confirm_your_pattern_header);
+        final String description = String.format(
+                mContext.getString(R.string.wifi_sharing_message),
+                mAccessPoint.getSsidStr());
 
-            final BiometricPrompt.Builder builder = new BiometricPrompt.Builder(mContext)
-                    .setTitle(title)
-                    .setDescription(description);
-
-            if (keyguardManager.isDeviceSecure()) {
-                builder.setDeviceCredentialAllowed(true);
-            }
-
-            final BiometricPrompt bp = builder.build();
-            final Handler handler = new Handler(Looper.getMainLooper());
-            bp.authenticate(new CancellationSignal(),
-                    runnable -> handler.post(runnable),
-                    mAuthenticationCallback);
-        } else {
-            launchWifiDppConfiguratorActivity();
-        }
+        WifiDppUtils.showLockScreen(mContext, title, description,
+                () -> launchWifiDppConfiguratorActivity());
     }
 
-    private BiometricPrompt.AuthenticationCallback mAuthenticationCallback =
-            new BiometricPrompt.AuthenticationCallback() {
-        @Override
-        public void onAuthenticationSucceeded(BiometricPrompt.AuthenticationResult result) {
-            launchWifiDppConfiguratorActivity();
-        }
-
-        @Override
-        public void onAuthenticationError(int errorCode, CharSequence errString) {
-            //Do nothing
-        }
-    };
-
     /**
      * Sign in to the captive portal found on this wifi network associated with this preference.
      */
diff --git a/src/com/android/settings/wifi/dpp/WifiDppAddDeviceFragment.java b/src/com/android/settings/wifi/dpp/WifiDppAddDeviceFragment.java
index 9e731ba..3a9308e 100644
--- a/src/com/android/settings/wifi/dpp/WifiDppAddDeviceFragment.java
+++ b/src/com/android/settings/wifi/dpp/WifiDppAddDeviceFragment.java
@@ -29,6 +29,7 @@
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
+import android.view.accessibility.AccessibilityEvent;
 import android.widget.Button;
 import android.widget.ImageView;
 import android.widget.ProgressBar;
@@ -99,6 +100,7 @@
 
         if (!isConfigurationChange) {
             mLatestStatusCode = WifiDppUtils.EASY_CONNECT_EVENT_SUCCESS;
+            changeFocusAndAnnounceChange(mButtonRight, mTitle);
         }
     }
 
@@ -168,15 +170,17 @@
             mButtonLeft.setVisibility(View.INVISIBLE);
         }
 
-        if (!isConfigurationChange) {
-            mLatestStatusCode = code;
-        }
-
         if (isGoingInitiator()) {
             mSummary.setText(R.string.wifi_dpp_sharing_wifi_with_this_device);
         }
+
         mProgressBar.setVisibility(isGoingInitiator() ? View.VISIBLE : View.INVISIBLE);
         mButtonRight.setVisibility(isGoingInitiator() ? View.INVISIBLE : View.VISIBLE);
+
+        if (!isConfigurationChange) {
+            mLatestStatusCode = code;
+            changeFocusAndAnnounceChange(mButtonRight, mSummary);
+        }
     }
 
     private boolean hasRetryButton(int code) {
@@ -277,6 +281,7 @@
             mButtonRight.setVisibility(View.INVISIBLE);
             startWifiDppConfiguratorInitiator();
             updateSummary();
+            mTitleSummaryContainer.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED);
         });
 
         if (savedInstanceState != null) {
@@ -288,6 +293,8 @@
             } else {
                 showErrorUi(mLatestStatusCode, /* isConfigurationChange */ true);
             }
+        } else {
+            changeFocusAndAnnounceChange(mButtonRight, mTitleSummaryContainer);
         }
     }
 
@@ -354,4 +361,17 @@
             mSummary.setText(getString(R.string.wifi_dpp_add_device_to_wifi, getSsid()));
         }
     }
+
+    /**
+     * This fragment will change UI display and text messages for events. To improve Talkback user
+     * experienience, using this method to focus on a right component and announce a changed text
+     * after an UI changing event.
+     *
+     * @param focusView The UI component which will be focused
+     * @param announceView The UI component's text will be talked
+     */
+    private void changeFocusAndAnnounceChange(View focusView, View announceView) {
+        focusView.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED);
+        announceView.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
+    }
 }
diff --git a/src/com/android/settings/wifi/dpp/WifiDppChooseSavedWifiNetworkFragment.java b/src/com/android/settings/wifi/dpp/WifiDppChooseSavedWifiNetworkFragment.java
index 72e845f..ddba933 100644
--- a/src/com/android/settings/wifi/dpp/WifiDppChooseSavedWifiNetworkFragment.java
+++ b/src/com/android/settings/wifi/dpp/WifiDppChooseSavedWifiNetworkFragment.java
@@ -23,6 +23,7 @@
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
+import android.view.accessibility.AccessibilityEvent;
 import android.widget.Button;
 import android.widget.ListView;
 
@@ -105,5 +106,11 @@
 
         mButtonRight = view.findViewById(R.id.button_right);
         mButtonRight.setVisibility(View.GONE);
+
+        if (savedInstanceState == null) {
+            // For Talkback to describe this fragment
+            mTitleSummaryContainer.sendAccessibilityEvent(
+                    AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
+        }
     }
 }
diff --git a/src/com/android/settings/wifi/dpp/WifiDppConfiguratorActivity.java b/src/com/android/settings/wifi/dpp/WifiDppConfiguratorActivity.java
index 0a2c09b..7308741 100644
--- a/src/com/android/settings/wifi/dpp/WifiDppConfiguratorActivity.java
+++ b/src/com/android/settings/wifi/dpp/WifiDppConfiguratorActivity.java
@@ -75,6 +75,7 @@
     private static final String KEY_WIFI_PRESHARED_KEY = "key_wifi_preshared_key";
     private static final String KEY_WIFI_HIDDEN_SSID = "key_wifi_hidden_ssid";
     private static final String KEY_WIFI_NETWORK_ID = "key_wifi_network_id";
+    private static final String KEY_IS_HOTSPOT = "key_is_hotspot";
 
     private FragmentManager mFragmentManager;
 
@@ -104,14 +105,15 @@
 
             mWifiDppQrCode = WifiQrCode.getValidWifiDppQrCodeOrNull(qrCode);
 
-            String security = savedInstanceState.getString(KEY_WIFI_SECURITY);
-            String ssid = savedInstanceState.getString(KEY_WIFI_SSID);
-            String preSharedKey = savedInstanceState.getString(KEY_WIFI_PRESHARED_KEY);
-            boolean hiddenSsid = savedInstanceState.getBoolean(KEY_WIFI_HIDDEN_SSID);
-            int networkId = savedInstanceState.getInt(KEY_WIFI_NETWORK_ID);
+            final String security = savedInstanceState.getString(KEY_WIFI_SECURITY);
+            final String ssid = savedInstanceState.getString(KEY_WIFI_SSID);
+            final String preSharedKey = savedInstanceState.getString(KEY_WIFI_PRESHARED_KEY);
+            final boolean hiddenSsid = savedInstanceState.getBoolean(KEY_WIFI_HIDDEN_SSID);
+            final int networkId = savedInstanceState.getInt(KEY_WIFI_NETWORK_ID);
+            final boolean isHotspot = savedInstanceState.getBoolean(KEY_IS_HOTSPOT);
 
             mWifiNetworkConfig = WifiNetworkConfig.getValidConfigOrNull(security, ssid,
-                    preSharedKey, hiddenSsid, networkId);
+                    preSharedKey, hiddenSsid, networkId, isHotspot);
         } else {
             handleIntent(getIntent());
         }
@@ -361,6 +363,7 @@
             outState.putString(KEY_WIFI_PRESHARED_KEY, mWifiNetworkConfig.getPreSharedKey());
             outState.putBoolean(KEY_WIFI_HIDDEN_SSID, mWifiNetworkConfig.getHiddenSsid());
             outState.putInt(KEY_WIFI_NETWORK_ID, mWifiNetworkConfig.getNetworkId());
+            outState.putBoolean(KEY_IS_HOTSPOT, mWifiNetworkConfig.isHotspot());
         }
 
         super.onSaveInstanceState(outState);
@@ -393,7 +396,8 @@
                     wifiConfiguration.getPrintableSsid(),
                     wifiConfiguration.preSharedKey,
                     /* hiddenSsid */ false,
-                    wifiConfiguration.networkId);
+                    wifiConfiguration.networkId,
+                    /* isHotspot */ false);
             }
         }
 
diff --git a/src/com/android/settings/wifi/dpp/WifiDppQrCodeBaseFragment.java b/src/com/android/settings/wifi/dpp/WifiDppQrCodeBaseFragment.java
index fab495d..eafbe68 100644
--- a/src/com/android/settings/wifi/dpp/WifiDppQrCodeBaseFragment.java
+++ b/src/com/android/settings/wifi/dpp/WifiDppQrCodeBaseFragment.java
@@ -38,6 +38,7 @@
     private ImageView mDevicesCheckCircleGreenHeaderIcon;
     protected TextView mTitle;
     protected TextView mSummary;
+    protected View mTitleSummaryContainer;
 
     @Override
     public void onViewCreated(View view, Bundle savedInstanceState) {
@@ -48,6 +49,10 @@
                 view.findViewById(R.id.devices_check_circle_green_icon);
         mTitle = view.findViewById(android.R.id.title);
         mSummary = view.findViewById(android.R.id.summary);
+
+        // This is the LinearLayout which groups mTitle and mSummary for Talkback to announce the
+        // content in a way that reflects its natural groupings.
+        mTitleSummaryContainer =  view.findViewById(R.id.title_summary_container);
     }
 
     protected void setHeaderIconImageResource(int resId) {
diff --git a/src/com/android/settings/wifi/dpp/WifiDppQrCodeGeneratorFragment.java b/src/com/android/settings/wifi/dpp/WifiDppQrCodeGeneratorFragment.java
index daa41d9f..2cd5e23 100644
--- a/src/com/android/settings/wifi/dpp/WifiDppQrCodeGeneratorFragment.java
+++ b/src/com/android/settings/wifi/dpp/WifiDppQrCodeGeneratorFragment.java
@@ -60,6 +60,14 @@
     public void onActivityCreated(Bundle savedInstanceState) {
         super.onActivityCreated(savedInstanceState);
 
+        // setTitle for Talkback
+        final WifiNetworkConfig wifiNetworkConfig = getWifiNetworkConfigFromHostActivity();
+        if (wifiNetworkConfig.isHotspot()) {
+            getActivity().setTitle(R.string.wifi_dpp_share_hotspot);
+        } else {
+            getActivity().setTitle(R.string.wifi_dpp_share_wifi);
+        }
+
         setHasOptionsMenu(true);
         final ActionBar actionBar = getActivity().getActionBar();
         if (actionBar != null) {
@@ -86,7 +94,8 @@
     public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
         final WifiNetworkConfig wifiNetworkConfig = getWifiNetworkConfigFromHostActivity();
         MenuItem menuItem;
-        if (wifiNetworkConfig.isSupportWifiDpp(getActivity())) {
+        if (!wifiNetworkConfig.isHotspot() &&
+                wifiNetworkConfig.isSupportWifiDpp(getActivity())) {
             menuItem = menu.add(0, Menu.FIRST, 0, R.string.next_label);
             menuItem.setIcon(R.drawable.ic_scan_24dp);
             menuItem.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);
@@ -127,9 +136,15 @@
         setHeaderIconImageResource(R.drawable.ic_qrcode_24dp);
 
         final WifiNetworkConfig wifiNetworkConfig = getWifiNetworkConfigFromHostActivity();
-        mTitle.setText(R.string.wifi_dpp_share_wifi);
-        mSummary.setText(getString(R.string.wifi_dpp_scan_qr_code_with_another_device,
-                wifiNetworkConfig.getSsid()));
+        if (wifiNetworkConfig.isHotspot()) {
+            mTitle.setText(R.string.wifi_dpp_share_hotspot);
+            mSummary.setText(getString(R.string.wifi_dpp_scan_qr_code_to_share_hotspot,
+                    wifiNetworkConfig.getSsid()));
+        } else {
+            mTitle.setText(R.string.wifi_dpp_share_wifi);
+            mSummary.setText(getString(R.string.wifi_dpp_scan_qr_code_with_another_device,
+                    wifiNetworkConfig.getSsid()));
+        }
 
         mQrCode = wifiNetworkConfig.getQrCode();
         setQrCode();
diff --git a/src/com/android/settings/wifi/dpp/WifiDppQrCodeScannerFragment.java b/src/com/android/settings/wifi/dpp/WifiDppQrCodeScannerFragment.java
index a19069b..4535599 100644
--- a/src/com/android/settings/wifi/dpp/WifiDppQrCodeScannerFragment.java
+++ b/src/com/android/settings/wifi/dpp/WifiDppQrCodeScannerFragment.java
@@ -41,6 +41,7 @@
 import android.view.TextureView.SurfaceTextureListener;
 import android.view.View;
 import android.view.ViewGroup;
+import android.view.accessibility.AccessibilityEvent;
 import android.widget.ProgressBar;
 import android.widget.TextView;
 
@@ -174,6 +175,13 @@
     public void onActivityCreated(Bundle savedInstanceState) {
         super.onActivityCreated(savedInstanceState);
 
+        // setTitle for Talkback
+        if (mIsConfiguratorMode) {
+            getActivity().setTitle(R.string.wifi_dpp_add_device_to_network);
+        } else {
+            getActivity().setTitle(R.string.wifi_dpp_scan_qr_code);
+        }
+
         final ActionBar actionBar = getActivity().getActionBar();
         if (actionBar != null) {
             actionBar.setDisplayHomeAsUpEnabled(true);
@@ -380,6 +388,7 @@
     public void showErrorMessage(String message) {
         mErrorMessage.setVisibility(View.VISIBLE);
         mErrorMessage.setText(message);
+        mErrorMessage.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
 
         mHandler.removeMessages(MESSAGE_HIDE_ERROR_MESSAGE);
         mHandler.sendEmptyMessageDelayed(MESSAGE_HIDE_ERROR_MESSAGE,
@@ -410,6 +419,8 @@
                         mProgressBar.setVisibility(View.VISIBLE);
                         startWifiDppEnrolleeInitiator((WifiQrCode)msg.obj);
                         updateEnrolleeSummary();
+                        mSummary.sendAccessibilityEvent(
+                                AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
                     }
                     break;
 
diff --git a/src/com/android/settings/wifi/dpp/WifiDppUtils.java b/src/com/android/settings/wifi/dpp/WifiDppUtils.java
index 4d8cca5..fe7af27 100644
--- a/src/com/android/settings/wifi/dpp/WifiDppUtils.java
+++ b/src/com/android/settings/wifi/dpp/WifiDppUtils.java
@@ -16,11 +16,16 @@
 
 package com.android.settings.wifi.dpp;
 
+import android.app.KeyguardManager;
 import android.content.Context;
 import android.content.Intent;
+import android.hardware.biometrics.BiometricPrompt;
 import android.net.wifi.WifiConfiguration.KeyMgmt;
 import android.net.wifi.WifiConfiguration;
 import android.net.wifi.WifiManager;
+import android.os.CancellationSignal;
+import android.os.Handler;
+import android.os.Looper;
 import android.text.TextUtils;
 import android.util.FeatureFlagUtils;
 
@@ -70,6 +75,9 @@
     /** The data corresponding to {@code WifiConfiguration} networkId */
     public static final String EXTRA_WIFI_NETWORK_ID = "networkId";
 
+    /** The data to recognize if it's a Wi-Fi hotspot for configuration */
+    public static final String EXTRA_IS_HOTSPOT = "isHotspot";
+
     /** Used by {@link android.provider.Settings#ACTION_PROCESS_WIFI_EASY_CONNECT_URI} to
      * indicate test mode UI should be shown. Test UI does not make API calls. Value is a boolean.*/
     public static final String EXTRA_TEST = "test";
@@ -142,24 +150,12 @@
         return str.substring(begin, end+1);
     }
 
-    private static String getSecurityString(AccessPoint accessPoint) {
-        switch(accessPoint.getSecurity()) {
-            case AccessPoint.SECURITY_WEP:
-                return WifiQrCode.SECURITY_WEP;
-            case AccessPoint.SECURITY_PSK:
-                return WifiQrCode.SECURITY_WPA_PSK;
-            case AccessPoint.SECURITY_SAE:
-                return WifiQrCode.SECURITY_SAE;
-            default:
-                return WifiQrCode.SECURITY_NO_PASSWORD;
-        }
-    }
-
     static String getSecurityString(WifiConfiguration config) {
         if (config.allowedKeyManagement.get(KeyMgmt.SAE)) {
             return WifiQrCode.SECURITY_SAE;
         }
-        if (config.allowedKeyManagement.get(KeyMgmt.WPA_PSK)) {
+        if (config.allowedKeyManagement.get(KeyMgmt.WPA_PSK) ||
+                config.allowedKeyManagement.get(KeyMgmt.WPA2_PSK)) {
             return WifiQrCode.SECURITY_WPA_PSK;
         }
         return (config.wepKeys[0] == null) ?
@@ -171,6 +167,9 @@
      * security. It may return null if the security is not supported by QR code generator nor
      * scanner.
      *
+     * Do not use this method for Wi-Fi hotspot network, use
+     * {@code getHotspotConfiguratorIntentOrNull} instead.
+     *
      * @param context     The context to use for the content resolver
      * @param wifiManager An instance of {@link WifiManager}
      * @param accessPoint An instance of {@link AccessPoint}
@@ -187,15 +186,63 @@
             return null;
         }
 
-        final WifiConfiguration wifiConfig = accessPoint.getConfig();
-        final String ssid = removeFirstAndLastDoubleQuotes(wifiConfig.SSID);
-        final String security = getSecurityString(accessPoint);
-        String preSharedKey = wifiConfig.preSharedKey;
+        final WifiConfiguration wifiConfiguration = accessPoint.getConfig();
+        setConfiguratorIntentExtra(intent, wifiManager, wifiConfiguration);
+
+        if (wifiConfiguration.networkId == WifiConfiguration.INVALID_NETWORK_ID) {
+            throw new IllegalArgumentException("Invalid network ID");
+        } else {
+            intent.putExtra(EXTRA_WIFI_NETWORK_ID, wifiConfiguration.networkId);
+        }
+
+        return intent;
+    }
+
+    /**
+     * Returns an intent to launch QR code generator for the Wi-Fi hotspot. It may return null if
+     * the security is not supported by QR code generator.
+     *
+     * @param context The context to use for the content resolver
+     * @param wifiManager An instance of {@link WifiManager}
+     * @param wifiConfiguration {@link WifiConfiguration} of the Wi-Fi hotspot
+     * @return Intent for launching QR code generator
+     */
+    public static Intent getHotspotConfiguratorIntentOrNull(Context context,
+            WifiManager wifiManager, WifiConfiguration wifiConfiguration) {
+        final Intent intent = new Intent(context, WifiDppConfiguratorActivity.class);
+        if (isSupportHotspotConfiguratorQrCodeGenerator(wifiConfiguration)) {
+            intent.setAction(WifiDppConfiguratorActivity.ACTION_CONFIGURATOR_QR_CODE_GENERATOR);
+        } else {
+            return null;
+        }
+
+        setConfiguratorIntentExtra(intent, wifiManager, wifiConfiguration);
+
+        intent.putExtra(EXTRA_WIFI_NETWORK_ID, WifiConfiguration.INVALID_NETWORK_ID);
+        intent.putExtra(EXTRA_IS_HOTSPOT, true);
+
+        return intent;
+    }
+
+    /**
+     * Set all extra except {@code EXTRA_WIFI_NETWORK_ID} for the intent to
+     * launch configurator activity later.
+     *
+     * @param intent the target to set extra
+     * @param wifiManager an instance of {@code WifiManager}
+     * @param wifiConfiguration the Wi-Fi network for launching configurator activity
+     */
+    private static void setConfiguratorIntentExtra(Intent intent, WifiManager wifiManager,
+            WifiConfiguration wifiConfiguration) {
+        final String ssid = removeFirstAndLastDoubleQuotes(wifiConfiguration.SSID);
+        final String security = getSecurityString(wifiConfiguration);
+        String preSharedKey = wifiConfiguration.preSharedKey;
 
         if (preSharedKey != null) {
             // When the value of this key is read, the actual key is not returned, just a "*".
             // Call privileged system API to obtain actual key.
-            preSharedKey = removeFirstAndLastDoubleQuotes(getPresharedKey(wifiManager, wifiConfig));
+            preSharedKey = removeFirstAndLastDoubleQuotes(getPresharedKey(wifiManager,
+                    wifiConfiguration));
         }
 
         if (!TextUtils.isEmpty(ssid)) {
@@ -207,13 +254,6 @@
         if (!TextUtils.isEmpty(preSharedKey)) {
             intent.putExtra(EXTRA_WIFI_PRE_SHARED_KEY, preSharedKey);
         }
-        if (wifiConfig.networkId == WifiConfiguration.INVALID_NETWORK_ID) {
-            throw new IllegalArgumentException("Invalid network ID");
-        } else {
-            intent.putExtra(EXTRA_WIFI_NETWORK_ID, wifiConfig.networkId);
-        }
-
-        return intent;
     }
 
     /**
@@ -228,6 +268,54 @@
                 isSupportConfiguratorQrCodeGenerator(accessPoint);
     }
 
+    /**
+     * Shows authentication screen to confirm credentials (pin, pattern or password) for the current
+     * user of the device.
+     *
+     * @param context The {@code Context} used to get {@code KeyguardManager} service
+     * @param title The title on lock screen
+     * @param description The description on lock screen
+     * @param successRunnable The {@code Runnable} which will be executed if the user does not setup
+     *                        device security or if lock screen is unlocked
+     */
+    public static void showLockScreen(Context context, String title, String description,
+            Runnable successRunnable) {
+        final KeyguardManager keyguardManager = (KeyguardManager) context.getSystemService(
+                Context.KEYGUARD_SERVICE);
+
+        if (keyguardManager.isKeyguardSecure()) {
+            final BiometricPrompt.AuthenticationCallback authenticationCallback =
+                    new BiometricPrompt.AuthenticationCallback() {
+                        @Override
+                        public void onAuthenticationSucceeded(
+                                    BiometricPrompt.AuthenticationResult result) {
+                            successRunnable.run();
+                        }
+
+                        @Override
+                        public void onAuthenticationError(int errorCode, CharSequence errString) {
+                            //Do nothing
+                        }
+            };
+
+            final BiometricPrompt.Builder builder = new BiometricPrompt.Builder(context)
+                    .setTitle(title)
+                    .setDescription(description);
+
+            if (keyguardManager.isDeviceSecure()) {
+                builder.setDeviceCredentialAllowed(true);
+            }
+
+            final BiometricPrompt bp = builder.build();
+            final Handler handler = new Handler(Looper.getMainLooper());
+            bp.authenticate(new CancellationSignal(),
+                    runnable -> handler.post(runnable),
+                    authenticationCallback);
+        } else {
+            successRunnable.run();
+        }
+    }
+
     private static boolean isSupportConfiguratorQrCodeScanner(Context context,
             AccessPoint accessPoint) {
         if (!isWifiDppEnabled(context)) {
@@ -254,4 +342,13 @@
 
         return false;
     }
+
+    private static boolean isSupportHotspotConfiguratorQrCodeGenerator(
+            WifiConfiguration wifiConfiguration) {
+        // QR code generator produces QR code with ZXing's Wi-Fi network config format,
+        // it supports PSK and WEP and non security
+        // KeyMgmt.NONE is for WEP or non security
+        return wifiConfiguration.allowedKeyManagement.get(KeyMgmt.WPA2_PSK) ||
+                wifiConfiguration.allowedKeyManagement.get(KeyMgmt.NONE);
+    }
 }
diff --git a/src/com/android/settings/wifi/dpp/WifiNetworkConfig.java b/src/com/android/settings/wifi/dpp/WifiNetworkConfig.java
index a483073..fdc74d8 100644
--- a/src/com/android/settings/wifi/dpp/WifiNetworkConfig.java
+++ b/src/com/android/settings/wifi/dpp/WifiNetworkConfig.java
@@ -30,7 +30,6 @@
 import android.text.TextUtils;
 import android.util.Log;
 
-import androidx.annotation.Keep;
 import androidx.annotation.VisibleForTesting;
 
 /**
@@ -52,15 +51,17 @@
     private String mPreSharedKey;
     private boolean mHiddenSsid;
     private int mNetworkId;
+    private boolean mIsHotspot;
 
     @VisibleForTesting
     WifiNetworkConfig(String security, String ssid, String preSharedKey,
-            boolean hiddenSsid, int networkId) {
+            boolean hiddenSsid, int networkId, boolean isHotspot) {
         mSecurity = security;
         mSsid = ssid;
         mPreSharedKey = preSharedKey;
         mHiddenSsid = hiddenSsid;
         mNetworkId = networkId;
+        mIsHotspot = isHotspot;
     }
 
     public WifiNetworkConfig(WifiNetworkConfig config) {
@@ -69,6 +70,7 @@
         mPreSharedKey = config.mPreSharedKey;
         mHiddenSsid = config.mHiddenSsid;
         mNetworkId = config.mNetworkId;
+        mIsHotspot = config.mIsHotspot;
     }
 
     /**
@@ -86,23 +88,26 @@
      * android.settings.WIFI_DPP_CONFIGURATOR_QR_CODE_SCANNER
      */
     public static WifiNetworkConfig getValidConfigOrNull(Intent intent) {
-        String security = intent.getStringExtra(WifiDppUtils.EXTRA_WIFI_SECURITY);
-        String ssid = intent.getStringExtra(WifiDppUtils.EXTRA_WIFI_SSID);
-        String preSharedKey = intent.getStringExtra(WifiDppUtils.EXTRA_WIFI_PRE_SHARED_KEY);
-        boolean hiddenSsid = intent.getBooleanExtra(WifiDppUtils.EXTRA_WIFI_HIDDEN_SSID, false);
-        int networkId = intent.getIntExtra(WifiDppUtils.EXTRA_WIFI_NETWORK_ID,
+        final String security = intent.getStringExtra(WifiDppUtils.EXTRA_WIFI_SECURITY);
+        final String ssid = intent.getStringExtra(WifiDppUtils.EXTRA_WIFI_SSID);
+        final String preSharedKey = intent.getStringExtra(WifiDppUtils.EXTRA_WIFI_PRE_SHARED_KEY);
+        final boolean hiddenSsid = intent.getBooleanExtra(WifiDppUtils.EXTRA_WIFI_HIDDEN_SSID,
+                false);
+        final int networkId = intent.getIntExtra(WifiDppUtils.EXTRA_WIFI_NETWORK_ID,
                 WifiConfiguration.INVALID_NETWORK_ID);
+        final boolean isHotspot = intent.getBooleanExtra(WifiDppUtils.EXTRA_IS_HOTSPOT, false);
 
-        return getValidConfigOrNull(security, ssid, preSharedKey, hiddenSsid, networkId);
+        return getValidConfigOrNull(security, ssid, preSharedKey, hiddenSsid, networkId, isHotspot);
     }
 
     public static WifiNetworkConfig getValidConfigOrNull(String security, String ssid,
-            String preSharedKey, boolean hiddenSsid, int networkId) {
+            String preSharedKey, boolean hiddenSsid, int networkId, boolean isHotspot) {
         if (!isValidConfig(security, ssid, preSharedKey, hiddenSsid)) {
             return null;
         }
 
-        return new WifiNetworkConfig(security, ssid, preSharedKey, hiddenSsid, networkId);
+        return new WifiNetworkConfig(security, ssid, preSharedKey, hiddenSsid, networkId,
+                isHotspot);
     }
 
     public static boolean isValidConfig(WifiNetworkConfig config) {
@@ -174,31 +179,30 @@
         return barcode;
     }
 
-    @Keep
     public String getSecurity() {
         return mSecurity;
     }
 
-    @Keep
     public String getSsid() {
         return mSsid;
     }
 
-    @Keep
     public String getPreSharedKey() {
         return mPreSharedKey;
     }
 
-    @Keep
     public boolean getHiddenSsid() {
         return mHiddenSsid;
     }
 
-    @Keep
     public int getNetworkId() {
         return mNetworkId;
     }
 
+    public boolean isHotspot() {
+        return mIsHotspot;
+    }
+
     public void connect(Context context, WifiManager.ActionListener listener) {
         WifiConfiguration wifiConfiguration = getWifiConfigurationOrNull();
         if (wifiConfiguration == null) {
diff --git a/src/com/android/settings/wifi/dpp/WifiNetworkListFragment.java b/src/com/android/settings/wifi/dpp/WifiNetworkListFragment.java
index ce92f90..4688d76 100644
--- a/src/com/android/settings/wifi/dpp/WifiNetworkListFragment.java
+++ b/src/com/android/settings/wifi/dpp/WifiNetworkListFragment.java
@@ -218,7 +218,7 @@
             final WifiNetworkConfig networkConfig = WifiNetworkConfig.getValidConfigOrNull(
                     selectedAccessPoint.getSecurityString(/* concise */ true),
                     wifiConfig.getPrintableSsid(), wifiConfig.preSharedKey, /* hiddenSsid */ false,
-                    wifiConfig.networkId);
+                    wifiConfig.networkId, /* isHotspot */ false);
             if (mOnChooseNetworkListener != null) {
                 mOnChooseNetworkListener.onChooseNetwork(networkConfig);
             }
@@ -232,7 +232,8 @@
                                 /* ssid */ WifiNetworkConfig.FAKE_SSID,
                                 /* preSharedKey */ WifiNetworkConfig.FAKE_PASSWORD,
                                 /* hiddenSsid */ true,
-                                /* networkId */ WifiConfiguration.INVALID_NETWORK_ID));
+                                /* networkId */ WifiConfiguration.INVALID_NETWORK_ID,
+                                /* isHotspot*/ false));
             }
         } else {
             return super.onPreferenceTreeClick(preference);
diff --git a/src/com/android/settings/wifi/dpp/WifiQrCode.java b/src/com/android/settings/wifi/dpp/WifiQrCode.java
index 10971cf..8296a62 100644
--- a/src/com/android/settings/wifi/dpp/WifiQrCode.java
+++ b/src/com/android/settings/wifi/dpp/WifiQrCode.java
@@ -133,7 +133,7 @@
         password = removeBackSlash(password);
 
         mWifiNetworkConfig = WifiNetworkConfig.getValidConfigOrNull(security, ssid, password,
-                hiddenSsid, WifiConfiguration.INVALID_NETWORK_ID);
+                hiddenSsid, WifiConfiguration.INVALID_NETWORK_ID, /* isHotspot */ false);
 
         if (mWifiNetworkConfig == null) {
             throw new IllegalArgumentException("Invalid format");
diff --git a/src/com/android/settings/wifi/tether/WifiTetherSSIDPreferenceController.java b/src/com/android/settings/wifi/tether/WifiTetherSSIDPreferenceController.java
index eb6a123..10f3e56 100644
--- a/src/com/android/settings/wifi/tether/WifiTetherSSIDPreferenceController.java
+++ b/src/com/android/settings/wifi/tether/WifiTetherSSIDPreferenceController.java
@@ -17,13 +17,18 @@
 package com.android.settings.wifi.tether;
 
 import android.content.Context;
+import android.content.Intent;
 import android.net.wifi.WifiConfiguration;
+import android.util.Log;
+import android.view.View;
 
 import androidx.annotation.VisibleForTesting;
 import androidx.preference.EditTextPreference;
 import androidx.preference.Preference;
 
+import com.android.settings.R;
 import com.android.settings.widget.ValidatedEditTextPreference;
+import com.android.settings.wifi.dpp.WifiDppUtils;
 
 public class WifiTetherSSIDPreferenceController extends WifiTetherBasePreferenceController
         implements ValidatedEditTextPreference.Validator {
@@ -56,6 +61,23 @@
             mSSID = DEFAULT_SSID;
         }
         ((ValidatedEditTextPreference) mPreference).setValidator(this);
+
+        if (mWifiManager.isWifiApEnabled() && config != null) {
+            final Intent intent = WifiDppUtils.getHotspotConfiguratorIntentOrNull(mContext,
+                    mWifiManager, config);
+
+            if (intent == null) {
+                Log.e(TAG, "Invalid security to share hotspot");
+                ((WifiTetherSsidPreference) mPreference).setButtonVisible(false);
+            } else {
+                ((WifiTetherSsidPreference) mPreference).setButtonOnClickListener(
+                        view -> shareHotspotNetwork(intent));
+                ((WifiTetherSsidPreference) mPreference).setButtonVisible(true);
+            }
+        } else {
+            ((WifiTetherSsidPreference) mPreference).setButtonVisible(false);
+        }
+
         updateSsidDisplay((EditTextPreference) mPreference);
     }
 
@@ -80,4 +102,19 @@
         preference.setText(mSSID);
         preference.setSummary(mSSID);
     }
+
+    private void shareHotspotNetwork(Intent intent) {
+        final String title = mContext.getString(
+                R.string.lockpassword_confirm_your_pattern_header);
+        final String description = String.format(
+                mContext.getString(R.string.wifi_sharing_message), mSSID);
+
+        WifiDppUtils.showLockScreen(mContext, title, description,
+                () -> mContext.startActivity(intent));
+    }
+
+    @VisibleForTesting
+    boolean isQrCodeButtonAvailable() {
+        return ((WifiTetherSsidPreference) mPreference).isQrCodeButtonAvailable();
+    }
 }
diff --git a/src/com/android/settings/wifi/tether/WifiTetherSsidPreference.java b/src/com/android/settings/wifi/tether/WifiTetherSsidPreference.java
new file mode 100644
index 0000000..64014d9
--- /dev/null
+++ b/src/com/android/settings/wifi/tether/WifiTetherSsidPreference.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2019 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.wifi.tether;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.drawable.Drawable;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.View;
+import android.widget.ImageButton;
+
+import androidx.annotation.DrawableRes;
+import androidx.preference.PreferenceViewHolder;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.settings.R;
+import com.android.settings.widget.ValidatedEditTextPreference;
+
+/**
+ * Support a QR code share button for {@code EditTextPreference} that supports input validation.
+ */
+public class WifiTetherSsidPreference extends ValidatedEditTextPreference {
+    private static final String TAG = "WifiTetherSsidPreference";
+
+    private ImageButton mImageButton;
+    private Drawable mButtonIcon;
+    private View.OnClickListener mClickListener;
+    private boolean mVisible;
+
+    public WifiTetherSsidPreference(Context context, AttributeSet attrs,
+            int defStyleAttr, int defStyleRes) {
+        super(context, attrs, defStyleAttr, defStyleRes);
+
+        initialize();
+    }
+
+    public WifiTetherSsidPreference(Context context, AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+
+        initialize();
+    }
+
+    public WifiTetherSsidPreference(Context context, AttributeSet attrs) {
+        super(context, attrs);
+
+        initialize();
+    }
+
+    public WifiTetherSsidPreference(Context context) {
+        super(context);
+
+        initialize();
+    }
+
+    private void initialize() {
+        setWidgetLayoutResource(R.layout.wifi_button_preference_widget);
+    }
+
+    @Override
+    public void onBindViewHolder(PreferenceViewHolder holder) {
+        super.onBindViewHolder(holder);
+
+        if (mImageButton == null) {
+            mImageButton = (ImageButton) holder.findViewById(R.id.button_icon);
+
+            mImageButton.setContentDescription(
+                    getContext().getString(R.string.wifi_dpp_share_hotspot));
+            setButtonIcon(R.drawable.ic_qrcode_24dp);
+            mImageButton.setImageDrawable(mButtonIcon);
+        }
+
+        if (mVisible) {
+            mImageButton.setOnClickListener(mClickListener);
+            mImageButton.setVisibility(View.VISIBLE);
+        } else {
+            mImageButton.setVisibility(View.GONE);
+        }
+    }
+
+    public void setButtonOnClickListener(View.OnClickListener listener) {
+        mClickListener = listener;
+    }
+
+    public void setButtonVisible(boolean visible) {
+        mVisible = visible;
+    }
+
+    private void setButtonIcon(@DrawableRes int iconResId) {
+        try {
+            mButtonIcon = getContext().getDrawable(iconResId);
+        } catch (Resources.NotFoundException exception) {
+            Log.e(TAG, "Resource does not exist: " + iconResId);
+        }
+    }
+
+    @VisibleForTesting
+    boolean isQrCodeButtonAvailable() {
+        return mVisible && mClickListener != null;
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/applications/defaultapps/DefaultEmergencyPickerTest.java b/tests/robotests/src/com/android/settings/applications/defaultapps/DefaultEmergencyPickerTest.java
index 5d97f52..b7b046c 100644
--- a/tests/robotests/src/com/android/settings/applications/defaultapps/DefaultEmergencyPickerTest.java
+++ b/tests/robotests/src/com/android/settings/applications/defaultapps/DefaultEmergencyPickerTest.java
@@ -19,7 +19,6 @@
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.mockito.Matchers.any;
-import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.eq;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.verify;
@@ -27,15 +26,10 @@
 
 import android.app.Activity;
 import android.app.role.RoleManager;
-import android.app.role.RoleManagerCallback;
 import android.content.Context;
 import android.content.pm.PackageManager;
-import android.os.AsyncTask;
-import android.os.Process;
 import android.os.UserHandle;
 import android.os.UserManager;
-import android.provider.Settings;
-import android.util.Log;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -50,6 +44,7 @@
 
 import java.util.Arrays;
 import java.util.concurrent.Executor;
+import java.util.function.Consumer;
 
 @RunWith(RobolectricTestRunner.class)
 public class DefaultEmergencyPickerTest {
@@ -90,7 +85,7 @@
             eq(0),
             any(UserHandle.class),
             any(Executor.class),
-            any(RoleManagerCallback.class));
+            any(Consumer.class));
     }
 
     @Test
diff --git a/tests/robotests/src/com/android/settings/homepage/contextualcards/ContextualCardLoaderTest.java b/tests/robotests/src/com/android/settings/homepage/contextualcards/ContextualCardLoaderTest.java
index 8b04ef3..e66774e 100644
--- a/tests/robotests/src/com/android/settings/homepage/contextualcards/ContextualCardLoaderTest.java
+++ b/tests/robotests/src/com/android/settings/homepage/contextualcards/ContextualCardLoaderTest.java
@@ -22,7 +22,7 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
-import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyList;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.spy;
@@ -87,6 +87,19 @@
     }
 
     @Test
+    public void isCardEligibleToDisplay_invalidRankingScore_returnFalse() {
+        final ContextualCard card = new ContextualCard.Builder()
+                .setName("test_card")
+                .setCardType(ContextualCard.CardType.SLICE)
+                .setSliceUri(CustomSliceRegistry.FLASHLIGHT_SLICE_URI)
+                .setRankingScore(-1)
+                .build();
+
+        assertThat(mEligibleCardChecker.isCardEligibleToDisplay(card))
+                .isFalse();
+    }
+
+    @Test
     public void isCardEligibleToDisplay_nullSlice_returnFalse() {
         doReturn(null).when(mEligibleCardChecker).bindSlice(Uri.parse(TEST_SLICE_URI));
 
@@ -108,7 +121,7 @@
     public void getDisplayableCards_twoEligibleCards_shouldShowAll() {
         final List<ContextualCard> cards = getContextualCardList().stream().limit(2)
                 .collect(Collectors.toList());
-        doReturn(cards).when(mContextualCardLoader).filterEligibleCards(any(List.class));
+        doReturn(cards).when(mContextualCardLoader).filterEligibleCards(anyList());
 
         final List<ContextualCard> result = mContextualCardLoader.getDisplayableCards(cards);
 
@@ -118,7 +131,7 @@
     @Test
     public void getDisplayableCards_fiveEligibleCardsNoLarge_shouldShowDefaultCardCount() {
         final List<ContextualCard> fiveCards = getContextualCardListWithNoLargeCard();
-        doReturn(fiveCards).when(mContextualCardLoader).filterEligibleCards(any(List.class));
+        doReturn(fiveCards).when(mContextualCardLoader).filterEligibleCards(anyList());
 
         final List<ContextualCard> result = mContextualCardLoader.getDisplayableCards(
                 fiveCards);
@@ -136,7 +149,7 @@
                 .setSliceUri(Uri.parse(
                         "content://com.android.settings.test.slices/action/gesture_pick_up"))
                 .build());
-        doReturn(cards).when(mContextualCardLoader).filterEligibleCards(any(List.class));
+        doReturn(cards).when(mContextualCardLoader).filterEligibleCards(anyList());
 
         final List<ContextualCard> result = mContextualCardLoader.getDisplayableCards(cards);
 
@@ -147,7 +160,7 @@
     public void getDisplayableCards_threeEligibleCardsTwoLarge_shouldShowTwoCards() {
         final List<ContextualCard> threeCards = getContextualCardList().stream().limit(3)
                 .collect(Collectors.toList());
-        doReturn(threeCards).when(mContextualCardLoader).filterEligibleCards(any(List.class));
+        doReturn(threeCards).when(mContextualCardLoader).filterEligibleCards(anyList());
 
         final List<ContextualCard> result = mContextualCardLoader.getDisplayableCards(
                 threeCards);
@@ -167,25 +180,26 @@
     public void getDisplayableCards_refreshCardUri_shouldLogContextualCardDisplay() {
         mContextualCardLoader.mNotifyUri = CardContentProvider.REFRESH_CARD_URI;
 
-        mContextualCardLoader.getDisplayableCards(new ArrayList<ContextualCard>());
+        mContextualCardLoader.getDisplayableCards(new ArrayList<>());
 
         verify(mFakeFeatureFactory.mContextualCardFeatureProvider).logContextualCardDisplay(
-                any(List.class), any(List.class));
+                anyList(), anyList());
     }
 
     @Test
     public void getDisplayableCards_deleteCardUri_shouldNotLogContextualCardDisplay() {
         mContextualCardLoader.mNotifyUri = CardContentProvider.DELETE_CARD_URI;
 
-        mContextualCardLoader.getDisplayableCards(new ArrayList<ContextualCard>());
+        mContextualCardLoader.getDisplayableCards(new ArrayList<>());
 
         verify(mFakeFeatureFactory.mContextualCardFeatureProvider, never())
-                .logContextualCardDisplay(any(List.class), any(List.class));
+                .logContextualCardDisplay(anyList(), anyList());
     }
 
     private ContextualCard getContextualCard(String sliceUri) {
         return new ContextualCard.Builder()
                 .setName("test_card")
+                .setRankingScore(0.5)
                 .setCardType(ContextualCard.CardType.SLICE)
                 .setSliceUri(Uri.parse(sliceUri))
                 .build();
diff --git a/tests/robotests/src/com/android/settings/media/MediaOutputSliceTest.java b/tests/robotests/src/com/android/settings/media/MediaOutputSliceTest.java
index daaba90..da0d85b 100644
--- a/tests/robotests/src/com/android/settings/media/MediaOutputSliceTest.java
+++ b/tests/robotests/src/com/android/settings/media/MediaOutputSliceTest.java
@@ -21,21 +21,15 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
+import android.bluetooth.BluetoothAdapter;
 import android.content.Context;
 import android.content.Intent;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageManager;
-import android.graphics.drawable.Drawable;
-import android.os.UserHandle;
-import android.util.IconDrawableFactory;
 
 import androidx.slice.Slice;
 import androidx.slice.SliceMetadata;
@@ -43,6 +37,7 @@
 import androidx.slice.core.SliceAction;
 import androidx.slice.widget.SliceLiveData;
 
+import com.android.settings.testutils.shadow.ShadowBluetoothAdapter;
 import com.android.settingslib.media.LocalMediaManager;
 import com.android.settingslib.media.MediaDevice;
 
@@ -53,70 +48,64 @@
 import org.mockito.MockitoAnnotations;
 import org.robolectric.RobolectricTestRunner;
 import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
+import org.robolectric.shadow.api.Shadow;
 
 import java.util.ArrayList;
 import java.util.List;
 
 @RunWith(RobolectricTestRunner.class)
+@Config(shadows = {ShadowBluetoothAdapter.class})
 public class MediaOutputSliceTest {
 
     private static final String TEST_PACKAGE_NAME = "com.fake.android.music";
-    private static final String TEST_LABEL = "Test app";
     private static final String TEST_DEVICE_1_ID = "test_device_1_id";
+    private static final String TEST_DEVICE_1_NAME = "test_device_1_name";
+    private static final int TEST_DEVICE_1_ICON =
+            com.android.internal.R.drawable.ic_bt_headphones_a2dp;
 
     @Mock
-    private PackageManager mPackageManager;
-    @Mock
-    private ApplicationInfo mApplicationInfo;
-    @Mock
-    private ApplicationInfo mApplicationInfo2;
-    @Mock
     private LocalMediaManager mLocalMediaManager;
-    @Mock
-    private IconDrawableFactory mIconDrawableFactory;
-    @Mock
-    private Drawable mTestDrawable;
 
     private final List<MediaDevice> mDevices = new ArrayList<>();
 
     private Context mContext;
     private MediaOutputSlice mMediaOutputSlice;
     private MediaDeviceUpdateWorker mMediaDeviceUpdateWorker;
+    private ShadowBluetoothAdapter mShadowBluetoothAdapter;
 
     @Before
     public void setUp() throws Exception {
         MockitoAnnotations.initMocks(this);
         mContext = spy(RuntimeEnvironment.application);
 
-        when(mContext.getPackageManager()).thenReturn(mPackageManager);
-        when(mPackageManager.getApplicationInfo(eq(TEST_PACKAGE_NAME), anyInt()))
-                .thenReturn(mApplicationInfo);
-        when(mPackageManager.getApplicationInfoAsUser(eq(TEST_PACKAGE_NAME), anyInt(), anyInt()))
-                .thenReturn(mApplicationInfo2);
-        when(mApplicationInfo.loadLabel(mPackageManager)).thenReturn(TEST_LABEL);
-        when(mIconDrawableFactory.getBadgedIcon(mApplicationInfo2, UserHandle.myUserId()))
-                .thenReturn(mTestDrawable);
-        when(mTestDrawable.getIntrinsicWidth()).thenReturn(100);
-        when(mTestDrawable.getIntrinsicHeight()).thenReturn(100);
-
         // Set-up specs for SliceMetadata.
         SliceProvider.setSpecs(SliceLiveData.SUPPORTED_SPECS);
+        // Setup BluetoothAdapter
+        mShadowBluetoothAdapter = Shadow.extract(BluetoothAdapter.getDefaultAdapter());
+        mShadowBluetoothAdapter.setEnabled(true);
 
         mMediaOutputSlice = new MediaOutputSlice(mContext);
         mMediaDeviceUpdateWorker = new MediaDeviceUpdateWorker(mContext, MEDIA_OUTPUT_SLICE_URI);
         mMediaDeviceUpdateWorker.setPackageName(TEST_PACKAGE_NAME);
         mMediaDeviceUpdateWorker.onDeviceListUpdate(mDevices);
         mMediaDeviceUpdateWorker.mLocalMediaManager = mLocalMediaManager;
-        mMediaOutputSlice.init(TEST_PACKAGE_NAME, mMediaDeviceUpdateWorker, mIconDrawableFactory);
+        mMediaOutputSlice.init(TEST_PACKAGE_NAME, mMediaDeviceUpdateWorker);
     }
 
     @Test
-    public void getSlice_shouldHaveAppTitle() {
+    public void getSlice_shouldHaveActiveDeviceName() {
+        mDevices.clear();
+        final MediaDevice device = mock(MediaDevice.class);
+        when(device.getName()).thenReturn(TEST_DEVICE_1_NAME);
+        when(device.getIcon()).thenReturn(TEST_DEVICE_1_ICON);
+        when(mLocalMediaManager.getCurrentConnectedDevice()).thenReturn(device);
+
         final Slice mediaSlice = mMediaOutputSlice.getSlice();
         final SliceMetadata metadata = SliceMetadata.from(mContext, mediaSlice);
 
         final SliceAction primaryAction = metadata.getPrimaryAction();
-        assertThat(primaryAction.getTitle().toString()).isEqualTo(TEST_LABEL);
+        assertThat(primaryAction.getTitle().toString()).isEqualTo(TEST_DEVICE_1_NAME);
     }
 
     @Test
diff --git a/tests/robotests/src/com/android/settings/network/telephony/MobileDataSliceTest.java b/tests/robotests/src/com/android/settings/network/telephony/MobileDataSliceTest.java
index 31daa37..c497cf8 100644
--- a/tests/robotests/src/com/android/settings/network/telephony/MobileDataSliceTest.java
+++ b/tests/robotests/src/com/android/settings/network/telephony/MobileDataSliceTest.java
@@ -24,7 +24,6 @@
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 
-import android.app.PendingIntent;
 import android.content.Context;
 import android.content.Intent;
 import android.provider.Settings;
@@ -163,27 +162,4 @@
 
         assertThat(isMobileDataEnabled).isEqualTo(seed);
     }
-
-    @Test
-    public void airplaneModeEnabled_slicePrimaryActionIsEmpty() {
-        doReturn(true).when(mMobileDataSlice).isAirplaneModeEnabled();
-        doReturn(mSubscriptionInfo).when(mSubscriptionManager).getActiveSubscriptionInfo(SUB_ID);
-        final Slice mobileData = mMobileDataSlice.getSlice();
-
-        final SliceMetadata metadata = SliceMetadata.from(mContext, mobileData);
-        assertThat(metadata.getTitle())
-                .isEqualTo(mContext.getString(R.string.mobile_data_settings_title));
-
-        assertThat(metadata.getSubtitle())
-                .isEqualTo(mContext.getString(R.string.mobile_data_ap_mode_disabled));
-
-        final List<SliceAction> toggles = metadata.getToggles();
-        assertThat(toggles).hasSize(0);
-
-        final SliceAction primaryAction = metadata.getPrimaryAction();
-        final PendingIntent pendingIntent = primaryAction.getAction();
-        final Intent actionIntent = pendingIntent.getIntent();
-
-        assertThat(actionIntent.getAction()).isNull();
-    }
 }
diff --git a/tests/robotests/src/com/android/settings/panel/SettingsPanelActivityTest.java b/tests/robotests/src/com/android/settings/panel/SettingsPanelActivityTest.java
index a51b7b0..1d5c3c2 100644
--- a/tests/robotests/src/com/android/settings/panel/SettingsPanelActivityTest.java
+++ b/tests/robotests/src/com/android/settings/panel/SettingsPanelActivityTest.java
@@ -76,15 +76,16 @@
     }
 
     @Test
-    public void startMediaOutputSlice_withoutPackageName_bundleShouldNotHaveValue() {
+    public void startMediaOutputSlice_withoutPackageName_bundleShouldHaveValue() {
         final Intent intent = new Intent()
                 .setAction("com.android.settings.panel.action.MEDIA_OUTPUT");
 
         final SettingsPanelActivity activity =
                 Robolectric.buildActivity(SettingsPanelActivity.class, intent).create().get();
 
-        assertThat(activity.mBundle.containsKey(KEY_MEDIA_PACKAGE_NAME)).isFalse();
-        assertThat(activity.mBundle.containsKey(KEY_PANEL_TYPE_ARGUMENT)).isFalse();
+        assertThat(activity.mBundle.containsKey(KEY_MEDIA_PACKAGE_NAME)).isTrue();
+        assertThat(activity.mBundle.getString(KEY_PANEL_TYPE_ARGUMENT))
+                .isEqualTo("com.android.settings.panel.action.MEDIA_OUTPUT");
     }
 
     @Test
diff --git a/tests/robotests/src/com/android/settings/sound/AudioOutputSwitchPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/sound/AudioOutputSwitchPreferenceControllerTest.java
index 54a79f4..5b7c863 100644
--- a/tests/robotests/src/com/android/settings/sound/AudioOutputSwitchPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/sound/AudioOutputSwitchPreferenceControllerTest.java
@@ -238,63 +238,6 @@
         verify(mLocalBluetoothManager).setForegroundActivity(null);
     }
 
-    @Test
-    public void onPreferenceChange_toThisDevice_shouldSetDefaultSummary() {
-        mController.mConnectedDevices.clear();
-        mController.mConnectedDevices.add(mBluetoothDevice);
-
-        mController.onPreferenceChange(mPreference,
-                mContext.getText(R.string.media_output_default_summary));
-
-        assertThat(mPreference.getSummary()).isEqualTo(
-                mContext.getText(R.string.media_output_default_summary));
-    }
-
-    /**
-     * One Bluetooth devices are available, and select the device.
-     * Preference summary should be device name.
-     */
-    @Test
-    public void onPreferenceChange_toBtDevice_shouldSetBtDeviceName() {
-        mController.mConnectedDevices.clear();
-        mController.mConnectedDevices.add(mBluetoothDevice);
-
-        mController.onPreferenceChange(mPreference, TEST_DEVICE_ADDRESS_1);
-
-        assertThat(mPreference.getSummary()).isEqualTo(TEST_DEVICE_NAME_1);
-    }
-
-    /**
-     * More than one Bluetooth devices are available, and select second device.
-     * Preference summary should be second device name.
-     */
-    @Test
-    public void onPreferenceChange_toBtDevices_shouldSetSecondBtDeviceName() {
-        ShadowBluetoothDevice shadowBluetoothDevice;
-        BluetoothDevice secondBluetoothDevice;
-        secondBluetoothDevice = mBluetoothAdapter.getRemoteDevice(TEST_DEVICE_ADDRESS_2);
-        shadowBluetoothDevice = Shadows.shadowOf(secondBluetoothDevice);
-        shadowBluetoothDevice.setName(TEST_DEVICE_NAME_2);
-        mController.mConnectedDevices.clear();
-        mController.mConnectedDevices.add(mBluetoothDevice);
-        mController.mConnectedDevices.add(secondBluetoothDevice);
-
-        mController.onPreferenceChange(mPreference, TEST_DEVICE_ADDRESS_2);
-
-        assertThat(mPreference.getSummary()).isEqualTo(TEST_DEVICE_NAME_2);
-    }
-
-    /**
-     * mConnectedDevices is empty.
-     * onPreferenceChange should return false.
-     */
-    @Test
-    public void onPreferenceChange_connectedDeviceIsNull_shouldReturnFalse() {
-        mController.mConnectedDevices.clear();
-
-        assertThat(mController.onPreferenceChange(mPreference, TEST_DEVICE_ADDRESS_1)).isFalse();
-    }
-
     /**
      * Audio stream output to bluetooth sco headset which is the subset of all sco device.
      * isStreamFromOutputDevice should return true.
@@ -416,39 +359,6 @@
     }
 
     /**
-     * One A2dp device is connected.
-     * getConnectedA2dpDevices should add this device to list.
-     */
-    @Test
-    public void getConnectedA2dpDevices_oneConnectedA2dpDevice_shouldAddDeviceToList() {
-        mEmptyDevices.clear();
-        mProfileConnectedDevices.clear();
-        mProfileConnectedDevices.add(mBluetoothDevice);
-        when(mA2dpProfile.getConnectedDevices()).thenReturn(mProfileConnectedDevices);
-
-        mEmptyDevices.addAll(mController.getConnectedA2dpDevices());
-
-        assertThat(mEmptyDevices).containsExactly(mBluetoothDevice);
-    }
-
-    /**
-     * More than one A2dp devices are connected.
-     * getConnectedA2dpDevices should add all devices to list.
-     */
-    @Test
-    public void getConnectedA2dpDevices_moreThanOneConnectedA2dpDevice_shouldAddDeviceToList() {
-        mEmptyDevices.clear();
-        mProfileConnectedDevices.clear();
-        mProfileConnectedDevices.add(mBluetoothDevice);
-        mProfileConnectedDevices.add(mLeftBluetoothHapDevice);
-        when(mA2dpProfile.getConnectedDevices()).thenReturn(mProfileConnectedDevices);
-
-        mEmptyDevices.addAll(mController.getConnectedA2dpDevices());
-
-        assertThat(mEmptyDevices).containsExactly(mBluetoothDevice, mLeftBluetoothHapDevice);
-    }
-
-    /**
      * One hands free profile device is connected.
      * getConnectedA2dpDevices should add this device to list.
      */
@@ -488,10 +398,6 @@
         }
 
         @Override
-        public void setActiveBluetoothDevice(BluetoothDevice device) {
-        }
-
-        @Override
         public BluetoothDevice findActiveDevice() {
             return null;
         }
diff --git a/tests/robotests/src/com/android/settings/sound/HandsFreeProfileOutputPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/sound/HandsFreeProfileOutputPreferenceControllerTest.java
index 4010145..0eada60 100644
--- a/tests/robotests/src/com/android/settings/sound/HandsFreeProfileOutputPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/sound/HandsFreeProfileOutputPreferenceControllerTest.java
@@ -57,6 +57,7 @@
 import org.mockito.MockitoAnnotations;
 import org.robolectric.RobolectricTestRunner;
 import org.robolectric.RuntimeEnvironment;
+import org.robolectric.Shadows;
 import org.robolectric.annotation.Config;
 import org.robolectric.shadows.ShadowBluetoothDevice;
 
@@ -107,7 +108,7 @@
     private BluetoothDevice mLeftBluetoothHapDevice;
     private BluetoothDevice mRightBluetoothHapDevice;
     private LocalBluetoothManager mLocalBluetoothManager;
-    private AudioSwitchPreferenceController mController;
+    private HandsFreeProfileOutputPreferenceController mController;
     private List<BluetoothDevice> mProfileConnectedDevices;
     private List<BluetoothDevice> mHearingAidActiveDevices;
 
@@ -478,4 +479,61 @@
 
         assertThat(mController.findActiveDevice()).isNull();
     }
+
+    /**
+     * One Bluetooth devices are available, and select the device.
+     * Preference summary should be device name.
+     */
+    @Test
+    public void onPreferenceChange_toBtDevice_shouldSetBtDeviceName() {
+        mController.mConnectedDevices.clear();
+        mController.mConnectedDevices.add(mBluetoothDevice);
+
+        mController.onPreferenceChange(mPreference, TEST_DEVICE_ADDRESS_1);
+
+        assertThat(mPreference.getSummary()).isEqualTo(TEST_DEVICE_NAME_1);
+    }
+
+    /**
+     * More than one Bluetooth devices are available, and select second device.
+     * Preference summary should be second device name.
+     */
+    @Test
+    public void onPreferenceChange_toBtDevices_shouldSetSecondBtDeviceName() {
+        ShadowBluetoothDevice shadowBluetoothDevice;
+        BluetoothDevice secondBluetoothDevice;
+        secondBluetoothDevice = mBluetoothAdapter.getRemoteDevice(TEST_DEVICE_ADDRESS_2);
+        shadowBluetoothDevice = Shadows.shadowOf(secondBluetoothDevice);
+        shadowBluetoothDevice.setName(TEST_DEVICE_NAME_2);
+        mController.mConnectedDevices.clear();
+        mController.mConnectedDevices.add(mBluetoothDevice);
+        mController.mConnectedDevices.add(secondBluetoothDevice);
+
+        mController.onPreferenceChange(mPreference, TEST_DEVICE_ADDRESS_2);
+
+        assertThat(mPreference.getSummary()).isEqualTo(TEST_DEVICE_NAME_2);
+    }
+
+    /**
+     * mConnectedDevices is empty.
+     * onPreferenceChange should return false.
+     */
+    @Test
+    public void onPreferenceChange_connectedDeviceIsNull_shouldReturnFalse() {
+        mController.mConnectedDevices.clear();
+
+        assertThat(mController.onPreferenceChange(mPreference, TEST_DEVICE_ADDRESS_1)).isFalse();
+    }
+
+    @Test
+    public void onPreferenceChange_toThisDevice_shouldSetDefaultSummary() {
+        mController.mConnectedDevices.clear();
+        mController.mConnectedDevices.add(mBluetoothDevice);
+
+        mController.onPreferenceChange(mPreference,
+                mContext.getText(R.string.media_output_default_summary));
+
+        assertThat(mPreference.getSummary()).isEqualTo(
+                mContext.getText(R.string.media_output_default_summary));
+    }
 }
diff --git a/tests/robotests/src/com/android/settings/sound/MediaOutputPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/sound/MediaOutputPreferenceControllerTest.java
index 8c7faef..7fcd3d2 100644
--- a/tests/robotests/src/com/android/settings/sound/MediaOutputPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/sound/MediaOutputPreferenceControllerTest.java
@@ -17,16 +17,15 @@
 package com.android.settings.sound;
 
 import static android.media.AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP;
+import static android.media.AudioSystem.DEVICE_OUT_EARPIECE;
 import static android.media.AudioSystem.DEVICE_OUT_HEARING_AID;
 import static android.media.AudioSystem.DEVICE_OUT_REMOTE_SUBMIX;
 
 import static com.google.common.truth.Truth.assertThat;
 
-import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
@@ -34,9 +33,10 @@
 import android.bluetooth.BluetoothDevice;
 import android.bluetooth.BluetoothManager;
 import android.content.Context;
+import android.content.Intent;
 import android.media.AudioManager;
 
-import androidx.preference.ListPreference;
+import androidx.preference.Preference;
 import androidx.preference.PreferenceManager;
 import androidx.preference.PreferenceScreen;
 
@@ -49,11 +49,13 @@
 import com.android.settingslib.bluetooth.HearingAidProfile;
 import com.android.settingslib.bluetooth.LocalBluetoothManager;
 import com.android.settingslib.bluetooth.LocalBluetoothProfileManager;
+import com.android.settingslib.media.MediaOutputSliceConstants;
 
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 import org.robolectric.RobolectricTestRunner;
@@ -80,8 +82,6 @@
     private static final String TEST_DEVICE_ADDRESS_2 = "00:B2:B2:B2:B2:B2";
     private static final String TEST_DEVICE_ADDRESS_3 = "00:C3:C3:C3:C3:C3";
     private static final String TEST_DEVICE_ADDRESS_4 = "00:D4:D4:D4:D4:D4";
-    private final static long HISYNCID1 = 10;
-    private final static long HISYNCID2 = 11;
 
     @Mock
     private LocalBluetoothManager mLocalManager;
@@ -98,7 +98,7 @@
 
     private Context mContext;
     private PreferenceScreen mScreen;
-    private ListPreference mPreference;
+    private Preference mPreference;
     private AudioManager mAudioManager;
     private ShadowAudioManager mShadowAudioManager;
     private BluetoothManager mBluetoothManager;
@@ -108,8 +108,8 @@
     private BluetoothDevice mLeftBluetoothHapDevice;
     private BluetoothDevice mRightBluetoothHapDevice;
     private LocalBluetoothManager mLocalBluetoothManager;
-    private AudioSwitchPreferenceController mController;
-    private List<BluetoothDevice> mProfileConnectedDevices;
+    private MediaOutputPreferenceController mController;
+    private List<BluetoothDevice> mProfileConnectableDevices;
     private List<BluetoothDevice> mHearingAidActiveDevices;
 
     @Before
@@ -149,8 +149,8 @@
 
         mController = new MediaOutputPreferenceController(mContext, TEST_KEY);
         mScreen = spy(new PreferenceScreen(mContext, null));
-        mPreference = new ListPreference(mContext);
-        mProfileConnectedDevices = new ArrayList<>();
+        mPreference = new Preference(mContext);
+        mProfileConnectableDevices = new ArrayList<>();
         mHearingAidActiveDevices = new ArrayList<>(2);
 
         when(mScreen.getPreferenceManager()).thenReturn(mock(PreferenceManager.class));
@@ -166,61 +166,140 @@
         ShadowBluetoothUtils.reset();
     }
 
+
     /**
-     * In normal mode, bluetooth device with HisyncId.
-     * HearingAidProfile should set active device to this device.
+     * A2DP Bluetooth device(s) are not connected nor previously connected
+     * Preference should be invisible
      */
     @Test
-    public void setActiveBluetoothDevice_btDeviceWithHisyncId_shouldSetBtDeviceActive() {
+    public void updateState_withoutConnectableBtDevice_preferenceInvisible() {
+        mShadowAudioManager.setOutputDevice(DEVICE_OUT_EARPIECE);
         mAudioManager.setMode(AudioManager.MODE_NORMAL);
-        when(mHearingAidProfile.getHiSyncId(mLeftBluetoothHapDevice)).thenReturn(HISYNCID1);
+        mProfileConnectableDevices.clear();
+        when(mA2dpProfile.getConnectableDevices()).thenReturn(mProfileConnectableDevices);
+        mPreference.setVisible(true);
 
-        mController.setActiveBluetoothDevice(mLeftBluetoothHapDevice);
-
-        verify(mHearingAidProfile).setActiveDevice(mLeftBluetoothHapDevice);
-        verify(mA2dpProfile, never()).setActiveDevice(mLeftBluetoothHapDevice);
+        assertThat(mPreference.isVisible()).isTrue();
+        mController.updateState(mPreference);
+        assertThat(mPreference.isVisible()).isFalse();
     }
 
     /**
-     * In normal mode, bluetooth device without HisyncId.
-     * A2dpProfile should set active device to this device.
+     * A2DP Bluetooth device(s) are connectable, no matter active or inactive
+     * Preference should be visible
      */
     @Test
-    public void setActiveBluetoothDevice_btDeviceWithoutHisyncId_shouldSetBtDeviceActive() {
+    public void updateState_withConnectableBtDevice_preferenceVisible() {
+        mShadowAudioManager.setOutputDevice(DEVICE_OUT_BLUETOOTH_A2DP);
         mAudioManager.setMode(AudioManager.MODE_NORMAL);
+        mProfileConnectableDevices.clear();
+        mProfileConnectableDevices.add(mBluetoothDevice);
+        when(mA2dpProfile.getConnectableDevices()).thenReturn(mProfileConnectableDevices);
+        assertThat(mPreference.isVisible()).isFalse();
 
-        mController.setActiveBluetoothDevice(mBluetoothDevice);
+        // Without Active Bluetooth Device
+        mController.updateState(mPreference);
+        assertThat(mPreference.isVisible()).isTrue();
 
-        verify(mA2dpProfile).setActiveDevice(mBluetoothDevice);
-        verify(mHearingAidProfile, never()).setActiveDevice(mBluetoothDevice);
+        // With Active Bluetooth Device
+        when(mA2dpProfile.getActiveDevice()).thenReturn(mBluetoothDevice);
+        mController.updateState(mPreference);
+        assertThat(mPreference.isVisible()).isTrue();
     }
 
     /**
-     * In normal mode, set active device to "this device".
-     * A2dpProfile should set to null.
-     * HearingAidProfile should set to null.
+     * A2DP Bluetooth device(s) are connectable, but no device is set as activated
+     * Preference summary should be "This device"
      */
     @Test
-    public void setActiveBluetoothDevice_setNull_shouldSetNullToBothProfiles() {
+    public void updateState_withConnectableBtDevice_withoutActiveBtDevice_setDefaultSummary() {
+        mShadowAudioManager.setOutputDevice(DEVICE_OUT_EARPIECE);
         mAudioManager.setMode(AudioManager.MODE_NORMAL);
+        mProfileConnectableDevices.clear();
+        mProfileConnectableDevices.add(mBluetoothDevice);
+        mProfileConnectableDevices.add(mSecondBluetoothDevice);
+        when(mA2dpProfile.getConnectableDevices()).thenReturn(mProfileConnectableDevices);
+        when(mA2dpProfile.getActiveDevice()).thenReturn(null);
 
-        mController.setActiveBluetoothDevice(null);
-
-        verify(mA2dpProfile).setActiveDevice(null);
-        verify(mHearingAidProfile).setActiveDevice(null);
+        assertThat(mPreference.getSummary()).isNull();
+        mController.updateState(mPreference);
+        assertThat(mPreference.getSummary()).isEqualTo(
+                mContext.getText(R.string.media_output_default_summary));
     }
 
     /**
-     * During a call
-     * A2dpProfile should not set active device.
+     * A2DP Bluetooth device(s) are connected and active
+     * Preference summary should be device's name
      */
     @Test
-    public void setActiveBluetoothDevice_duringACall_shouldNotSetActiveDeviceToA2dpProfile() {
-        mAudioManager.setMode(AudioManager.MODE_IN_COMMUNICATION);
+    public void updateState_withActiveBtDevice_setActivatedDeviceName() {
+        mShadowAudioManager.setOutputDevice(DEVICE_OUT_BLUETOOTH_A2DP);
+        mAudioManager.setMode(AudioManager.MODE_NORMAL);
+        mProfileConnectableDevices.clear();
+        mProfileConnectableDevices.add(mBluetoothDevice);
+        mProfileConnectableDevices.add(mSecondBluetoothDevice);
+        when(mA2dpProfile.getConnectableDevices()).thenReturn(mProfileConnectableDevices);
+        when(mA2dpProfile.getActiveDevice()).thenReturn(mBluetoothDevice);
 
-        mController.setActiveBluetoothDevice(mBluetoothDevice);
+        assertThat(mPreference.getSummary()).isNull();
+        mController.updateState(mPreference);
+        assertThat(mPreference.getSummary()).isEqualTo(TEST_DEVICE_NAME_1);
+    }
 
-        verify(mA2dpProfile, times(0)).setActiveDevice(any(BluetoothDevice.class));
+
+    /**
+     * Hearing Aid device(s) are connectable, no matter active or inactive
+     * Preference should be visible
+     */
+    @Test
+    public void updateState_withConnectableHADevice_preferenceVisible() {
+        mShadowAudioManager.setOutputDevice(DEVICE_OUT_HEARING_AID);
+        mAudioManager.setMode(AudioManager.MODE_NORMAL);
+        mHearingAidActiveDevices.clear();
+        mHearingAidActiveDevices.add(mLeftBluetoothHapDevice);
+        when(mHearingAidProfile.getConnectableDevices()).thenReturn(mHearingAidActiveDevices);
+        assertThat(mPreference.isVisible()).isFalse();
+
+        // Without Active Hearing Aid Device
+        mController.updateState(mPreference);
+        assertThat(mPreference.isVisible()).isTrue();
+
+        // With Active Hearing Aid Device
+        when(mHearingAidProfile.getActiveDevices()).thenReturn(mHearingAidActiveDevices);
+        mController.updateState(mPreference);
+        assertThat(mPreference.isVisible()).isTrue();
+    }
+
+    /**
+     * Hearing Aid device(s) are connected and active
+     * Preference summary should be device's name
+     */
+    @Test
+    public void updateState_withActiveHADevice_setActivatedDeviceName() {
+        mShadowAudioManager.setOutputDevice(DEVICE_OUT_HEARING_AID);
+        mAudioManager.setMode(AudioManager.MODE_NORMAL);
+        mHearingAidActiveDevices.clear();
+        mHearingAidActiveDevices.add(mLeftBluetoothHapDevice);
+        when(mHearingAidProfile.getConnectableDevices()).thenReturn(mHearingAidActiveDevices);
+        when(mHearingAidProfile.getActiveDevices()).thenReturn(mHearingAidActiveDevices);
+
+        assertThat(mPreference.getSummary()).isNull();
+        mController.updateState(mPreference);
+        assertThat(mPreference.getSummary()).isEqualTo(TEST_HAP_DEVICE_NAME_1);
+
+    }
+
+    @Test
+    public void click_launch_outputSwitcherSlice() {
+        final ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
+        mController.handlePreferenceTreeClick(mPreference);
+        verify(mContext, never()).startActivity(intentCaptor.capture());
+
+        mPreference.setKey(TEST_KEY);
+        mController.handlePreferenceTreeClick(mPreference);
+        verify(mContext).startActivity(intentCaptor.capture());
+        assertThat(intentCaptor.getValue().getAction())
+                .isEqualTo(MediaOutputSliceConstants.ACTION_MEDIA_OUTPUT);
     }
 
     /**
@@ -254,24 +333,6 @@
     }
 
     /**
-     * No available A2dp BT devices:
-     * Preference should be invisible
-     * Preference summary should be "This device"
-     */
-    @Test
-    public void updateState_noAvailableA2dpBtDevices_shouldDisableAndSetDefaultSummary() {
-        mAudioManager.setMode(AudioManager.MODE_NORMAL);
-        List<BluetoothDevice> emptyDeviceList = new ArrayList<>();
-        when(mA2dpProfile.getConnectedDevices()).thenReturn(emptyDeviceList);
-
-        mController.updateState(mPreference);
-
-        assertThat(mPreference.isVisible()).isFalse();
-        String defaultString = mContext.getString(R.string.media_output_default_summary);
-        assertThat(mPreference.getSummary()).isEqualTo(defaultString);
-    }
-
-    /**
      * Media stream is captured by something else (cast device):
      * Preference should be invisible
      * Preference summary should be "unavailable"
@@ -287,235 +348,6 @@
         assertThat(mPreference.getSummary()).isEqualTo(defaultString);
     }
 
-    /**
-     * One A2DP Bluetooth device is available and active.
-     * Preference should be visible
-     * Preference summary should be the activated device name
-     */
-    @Test
-    public void updateState_oneA2dpBtDeviceAreAvailable_shouldSetActivatedDeviceName() {
-        mAudioManager.setMode(AudioManager.MODE_NORMAL);
-        mShadowAudioManager.setOutputDevice(DEVICE_OUT_BLUETOOTH_A2DP);
-        mProfileConnectedDevices.clear();
-        mProfileConnectedDevices.add(mBluetoothDevice);
-        when(mA2dpProfile.getConnectedDevices()).thenReturn(mProfileConnectedDevices);
-        when(mA2dpProfile.getActiveDevice()).thenReturn(mBluetoothDevice);
-
-        mController.updateState(mPreference);
-
-        assertThat(mPreference.isVisible()).isTrue();
-        assertThat(mPreference.getSummary()).isEqualTo(TEST_DEVICE_NAME_1);
-    }
-
-    /**
-     * More than one A2DP Bluetooth devices are available, and second device is active.
-     * Preference should be visible
-     * Preference summary should be the activated device name
-     */
-    @Test
-    public void updateState_moreThanOneA2DpBtDevicesAreAvailable_shouldSetActivatedDeviceName() {
-        mAudioManager.setMode(AudioManager.MODE_NORMAL);
-        mShadowAudioManager.setOutputDevice(DEVICE_OUT_BLUETOOTH_A2DP);
-        mProfileConnectedDevices.clear();
-        mProfileConnectedDevices.add(mBluetoothDevice);
-        mProfileConnectedDevices.add(mSecondBluetoothDevice);
-        when(mA2dpProfile.getConnectedDevices()).thenReturn(mProfileConnectedDevices);
-        when(mA2dpProfile.getActiveDevice()).thenReturn(mSecondBluetoothDevice);
-
-        mController.updateState(mPreference);
-
-        assertThat(mPreference.isVisible()).isTrue();
-        assertThat(mPreference.getSummary()).isEqualTo(TEST_DEVICE_NAME_2);
-    }
-
-    /**
-     * A2DP Bluetooth device(s) are available, but wired headset is plugged in and activated
-     * Preference should be visible
-     * Preference summary should be "This device"
-     */
-    @Test
-    public void updateState_a2dpDevicesAvailableWiredHeadsetIsActivated_shouldSetDefaultSummary() {
-        mAudioManager.setMode(AudioManager.MODE_NORMAL);
-        mProfileConnectedDevices.clear();
-        mProfileConnectedDevices.add(mBluetoothDevice);
-        when(mLocalBluetoothProfileManager.getHearingAidProfile()).thenReturn(null);
-        when(mA2dpProfile.getConnectedDevices()).thenReturn(mProfileConnectedDevices);
-        when(mA2dpProfile.getActiveDevice()).thenReturn(null);
-
-        mController.updateState(mPreference);
-
-        assertThat(mPreference.isVisible()).isTrue();
-        assertThat(mPreference.getSummary()).isEqualTo(
-                mContext.getString(R.string.media_output_default_summary));
-    }
-
-
-    /**
-     * A2DP Bluetooth device(s) are available, but current device speaker is activated
-     * Preference should be visible
-     * Preference summary should be "This device"
-     */
-    @Test
-    public void updateState_a2dpDevicesAvailableCurrentDeviceActivated_shouldSetDefaultSummary() {
-        mAudioManager.setMode(AudioManager.MODE_NORMAL);
-        mProfileConnectedDevices.clear();
-        mProfileConnectedDevices.add(mBluetoothDevice);
-        when(mA2dpProfile.getConnectedDevices()).thenReturn(mProfileConnectedDevices);
-        when(mA2dpProfile.getActiveDevice()).thenReturn(null);
-
-        mController.updateState(mPreference);
-
-        assertThat(mPreference.isVisible()).isTrue();
-        assertThat(mPreference.getSummary()).isEqualTo(
-                mContext.getString(R.string.media_output_default_summary));
-    }
-
-    /**
-     * One hearing aid profile Bluetooth device is available and active.
-     * Preference should be visible
-     * Preference summary should be the activated device name
-     */
-    @Test
-    public void updateState_oneHapBtDeviceAreAvailable_shouldSetActivatedDeviceName() {
-        mAudioManager.setMode(AudioManager.MODE_NORMAL);
-        mShadowAudioManager.setOutputDevice(DEVICE_OUT_HEARING_AID);
-        mProfileConnectedDevices.clear();
-        mProfileConnectedDevices.add(mLeftBluetoothHapDevice);
-        mHearingAidActiveDevices.clear();
-        mHearingAidActiveDevices.add(mLeftBluetoothHapDevice);
-        when(mHearingAidProfile.getConnectedDevices()).thenReturn(mProfileConnectedDevices);
-        when(mHearingAidProfile.getActiveDevices()).thenReturn(mHearingAidActiveDevices);
-        when(mHearingAidProfile.getHiSyncId(mLeftBluetoothHapDevice)).thenReturn(HISYNCID1);
-
-        mController.updateState(mPreference);
-
-        assertThat(mPreference.isVisible()).isTrue();
-        assertThat(mPreference.getSummary()).isEqualTo(mLeftBluetoothHapDevice.getName());
-    }
-
-    /**
-     * More than one hearing aid profile Bluetooth devices are available, and second
-     * device is active.
-     * Preference should be visible
-     * Preference summary should be the activated device name
-     */
-    @Test
-    public void updateState_moreThanOneHapBtDevicesAreAvailable_shouldSetActivatedDeviceName() {
-        mAudioManager.setMode(AudioManager.MODE_NORMAL);
-        mShadowAudioManager.setOutputDevice(DEVICE_OUT_HEARING_AID);
-        mProfileConnectedDevices.clear();
-        mProfileConnectedDevices.add(mLeftBluetoothHapDevice);
-        mProfileConnectedDevices.add(mRightBluetoothHapDevice);
-        mHearingAidActiveDevices.clear();
-        mHearingAidActiveDevices.add(mRightBluetoothHapDevice);
-        when(mHearingAidProfile.getConnectedDevices()).thenReturn(mProfileConnectedDevices);
-        when(mHearingAidProfile.getActiveDevices()).thenReturn(mHearingAidActiveDevices);
-        when(mHearingAidProfile.getHiSyncId(mLeftBluetoothHapDevice)).thenReturn(HISYNCID1);
-        when(mHearingAidProfile.getHiSyncId(mRightBluetoothHapDevice)).thenReturn(HISYNCID2);
-
-        mController.updateState(mPreference);
-
-        assertThat(mPreference.isVisible()).isTrue();
-        assertThat(mPreference.getSummary()).isEqualTo(mRightBluetoothHapDevice.getName());
-    }
-
-    /**
-     * Both hearing aid profile and A2dp Bluetooth devices are available, and two hearing aid
-     * profile devices with same HisyncId are active. Both of HAP device are active,
-     * "left" side HAP device is added first.
-     * Preference should be visible
-     * Preference summary should be the activated device name
-     * ConnectedDevice should not contain second HAP device with same HisyncId
-     */
-    @Test
-    public void updateState_hapBtDeviceWithSameId_shouldSetActivatedDeviceName() {
-        mAudioManager.setMode(AudioManager.MODE_NORMAL);
-        mShadowAudioManager.setOutputDevice(DEVICE_OUT_HEARING_AID);
-        mProfileConnectedDevices.clear();
-        mProfileConnectedDevices.add(mBluetoothDevice);
-        //with same HisyncId, first one will remain in UI.
-        mProfileConnectedDevices.add(mLeftBluetoothHapDevice);
-        mProfileConnectedDevices.add(mRightBluetoothHapDevice);
-        mHearingAidActiveDevices.clear();
-        mHearingAidActiveDevices.add(mLeftBluetoothHapDevice);
-        mHearingAidActiveDevices.add(mRightBluetoothHapDevice);
-        when(mHearingAidProfile.getConnectedDevices()).thenReturn(mProfileConnectedDevices);
-        when(mHearingAidProfile.getActiveDevices()).thenReturn(mHearingAidActiveDevices);
-        when(mHearingAidProfile.getHiSyncId(mLeftBluetoothHapDevice)).thenReturn(HISYNCID1);
-        when(mHearingAidProfile.getHiSyncId(mRightBluetoothHapDevice)).thenReturn(HISYNCID1);
-
-        mController.updateState(mPreference);
-
-        assertThat(mPreference.isVisible()).isTrue();
-        assertThat(mPreference.getSummary()).isEqualTo(mLeftBluetoothHapDevice.getName());
-        assertThat(mController.mConnectedDevices.contains(mLeftBluetoothHapDevice)).isTrue();
-        assertThat(mController.mConnectedDevices.contains(mRightBluetoothHapDevice)).isFalse();
-    }
-
-    /**
-     * Both hearing aid profile and A2dp Bluetooth devices are available, and two hearing aid
-     * profile devices with same HisyncId. Both of HAP device are active,
-     * "right" side HAP device is added first.
-     * Preference should be visible
-     * Preference summary should be the activated device name
-     * ConnectedDevice should not contain second HAP device with same HisyncId
-     */
-    @Test
-    public void updateState_hapBtDeviceWithSameIdButDifferentOrder_shouldSetActivatedDeviceName() {
-        mAudioManager.setMode(AudioManager.MODE_NORMAL);
-        mShadowAudioManager.setOutputDevice(DEVICE_OUT_HEARING_AID);
-        mProfileConnectedDevices.clear();
-        mProfileConnectedDevices.add(mBluetoothDevice);
-        //with same HisyncId, first one will remain in UI.
-        mProfileConnectedDevices.add(mRightBluetoothHapDevice);
-        mProfileConnectedDevices.add(mLeftBluetoothHapDevice);
-        mHearingAidActiveDevices.clear();
-        mHearingAidActiveDevices.add(mLeftBluetoothHapDevice);
-        mHearingAidActiveDevices.add(mRightBluetoothHapDevice);
-        when(mHearingAidProfile.getConnectedDevices()).thenReturn(mProfileConnectedDevices);
-        when(mHearingAidProfile.getActiveDevices()).thenReturn(mHearingAidActiveDevices);
-        when(mHearingAidProfile.getHiSyncId(mLeftBluetoothHapDevice)).thenReturn(HISYNCID1);
-        when(mHearingAidProfile.getHiSyncId(mRightBluetoothHapDevice)).thenReturn(HISYNCID1);
-
-        mController.updateState(mPreference);
-
-        assertThat(mPreference.isVisible()).isTrue();
-        assertThat(mPreference.getSummary()).isEqualTo(mRightBluetoothHapDevice.getName());
-        assertThat(mController.mConnectedDevices.contains(mRightBluetoothHapDevice)).isTrue();
-        assertThat(mController.mConnectedDevices.contains(mLeftBluetoothHapDevice)).isFalse();
-    }
-
-    /**
-     * Both hearing aid profile and A2dp Bluetooth devices are available, and two hearing aid
-     * profile devices with different HisyncId. One of HAP device is active.
-     * Preference should be visible
-     * Preference summary should be the activated device name
-     * ConnectedDevice should contain both HAP device with different HisyncId
-     */
-    @Test
-    public void updateState_hapBtDeviceWithDifferentId_shouldSetActivatedDeviceName() {
-        mAudioManager.setMode(AudioManager.MODE_NORMAL);
-        mShadowAudioManager.setOutputDevice(DEVICE_OUT_HEARING_AID);
-        mProfileConnectedDevices.clear();
-        mProfileConnectedDevices.add(mBluetoothDevice);
-        mProfileConnectedDevices.add(mLeftBluetoothHapDevice);
-        mProfileConnectedDevices.add(mRightBluetoothHapDevice);
-        mHearingAidActiveDevices.clear();
-        mHearingAidActiveDevices.add(null);
-        mHearingAidActiveDevices.add(mRightBluetoothHapDevice);
-        when(mHearingAidProfile.getConnectedDevices()).thenReturn(mProfileConnectedDevices);
-        when(mHearingAidProfile.getActiveDevices()).thenReturn(mHearingAidActiveDevices);
-        when(mHearingAidProfile.getHiSyncId(mLeftBluetoothHapDevice)).thenReturn(HISYNCID1);
-        when(mHearingAidProfile.getHiSyncId(mRightBluetoothHapDevice)).thenReturn(HISYNCID2);
-
-        mController.updateState(mPreference);
-
-        assertThat(mPreference.isVisible()).isTrue();
-        assertThat(mPreference.getSummary()).isEqualTo(mRightBluetoothHapDevice.getName());
-        assertThat(mController.mConnectedDevices).containsExactly(mBluetoothDevice,
-                mLeftBluetoothHapDevice, mRightBluetoothHapDevice);
-    }
-
     @Test
     public void findActiveDevice_onlyA2dpDeviceActive_returnA2dpDevice() {
         when(mLocalBluetoothProfileManager.getHearingAidProfile()).thenReturn(null);
diff --git a/tests/robotests/src/com/android/settings/wifi/calling/ListWithEntrySummaryPreferenceTest.java b/tests/robotests/src/com/android/settings/wifi/calling/ListWithEntrySummaryPreferenceTest.java
new file mode 100644
index 0000000..cc2622f
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/wifi/calling/ListWithEntrySummaryPreferenceTest.java
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2018 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.wifi.calling;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.content.Context;
+import android.os.Parcelable;
+import android.widget.ListAdapter;
+import android.widget.TextView;
+
+import androidx.appcompat.app.AlertDialog;
+
+import com.android.settings.R;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+
+import java.io.IOException;
+
+@RunWith(RobolectricTestRunner.class)
+public class ListWithEntrySummaryPreferenceTest {
+
+    private Context mContext;
+    private ListWithEntrySummaryPreference mPreference;
+
+    private CharSequence[] mDefaultEntries =
+            {"default_entry1", "default_entry2", "default_entry3"};
+    private CharSequence[] mDefaultEntryValues = {"0", "1", "2"};
+    private CharSequence[] mDefaultEntrySummaries =
+            {"default_summary1", "default_summary2", "default_summary3"};
+
+    private CharSequence[] mCustomEntries = {"custom_entry1", "custom_entry2"};
+    private CharSequence[] mCustomEntryValues = {"0", "1"};
+    private CharSequence[] mCustomEntrySummaries = {"custom_summary1", "custom_summary2"};
+
+    @Before
+    public void setUp() {
+        mContext = RuntimeEnvironment.application;
+        mPreference = new ListWithEntrySummaryPreference(mContext, null);
+        mPreference.setEntries(mDefaultEntries);
+        mPreference.setEntryValues(mDefaultEntryValues);
+        mPreference.setEntrySummaries(mDefaultEntrySummaries);
+    }
+
+    @Test
+    public void initialize_defaultEntries_shouldDisplayDefalutEntries() {
+        AlertDialog dialog = showDialog(mPreference);
+        ListAdapter adapter = dialog.getListView().getAdapter();
+
+        int len = mDefaultEntries.length;
+        assertThat(adapter.getCount()).isEqualTo(len);
+        for (int i = 0; i < len; i++) {
+            TextView title = adapter.getView(i, null, null).findViewById(R.id.title);
+            TextView summary = adapter.getView(i, null, null).findViewById(R.id.summary);
+            assertThat(title.getText()).isEqualTo(mDefaultEntries[i]);
+            assertThat(summary.getText()).isEqualTo(mDefaultEntrySummaries[i]);
+        }
+    }
+
+    @Test
+    public void setEntries_customEntries_shouldUpdateEntries() {
+        mPreference.setEntries(mCustomEntries);
+        mPreference.setEntryValues(mCustomEntryValues);
+        mPreference.setEntrySummaries(mCustomEntrySummaries);
+
+        AlertDialog dialog = showDialog(mPreference);
+        ListAdapter adapter = dialog.getListView().getAdapter();
+
+        int len = mCustomEntries.length;
+        assertThat(adapter.getCount()).isEqualTo(len);
+        for (int i = 0; i < len; i++) {
+            TextView title = adapter.getView(i, null, null).findViewById(R.id.title);
+            TextView summary = adapter.getView(i, null, null).findViewById(R.id.summary);
+            assertThat(title.getText()).isEqualTo(mCustomEntries[i]);
+            assertThat(summary.getText()).isEqualTo(mCustomEntrySummaries[i]);
+        }
+    }
+
+    @Test
+    public void onSaveAndRestoreInstanceState_resumePreference_shouldNotChangeEntries() {
+        setEntries_customEntries_shouldUpdateEntries();
+
+        final Parcelable parcelable = mPreference.onSaveInstanceState();
+        ListWithEntrySummaryPreference preference
+                = new ListWithEntrySummaryPreference(mContext, null);
+        preference.setEntries(mDefaultEntries);
+        preference.setEntryValues(mDefaultEntryValues);
+        preference.setEntrySummaries(mDefaultEntrySummaries);
+        preference.onRestoreInstanceState(parcelable);
+
+        AlertDialog dialog = showDialog(preference);
+        ListAdapter adapter = dialog.getListView().getAdapter();
+
+        int len = mCustomEntries.length;
+        assertThat(adapter.getCount()).isEqualTo(len);
+        for (int i = 0; i < len; i++) {
+            TextView title = adapter.getView(i, null, null).findViewById(R.id.title);
+            TextView summary = adapter.getView(i, null, null).findViewById(R.id.summary);
+            assertThat(title.getText()).isEqualTo(mCustomEntries[i]);
+            assertThat(summary.getText()).isEqualTo(mCustomEntrySummaries[i]);
+        }
+    }
+
+    private AlertDialog showDialog(ListWithEntrySummaryPreference preference) {
+        AlertDialog.Builder builder = new AlertDialog.Builder(mContext);
+        preference.onPrepareDialogBuilder(builder, null);
+        return builder.show();
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/wifi/details/WifiDetailPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/wifi/details/WifiDetailPreferenceControllerTest.java
index 640c426..e640dee 100644
--- a/tests/robotests/src/com/android/settings/wifi/details/WifiDetailPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/wifi/details/WifiDetailPreferenceControllerTest.java
@@ -384,9 +384,9 @@
     }
 
     @Test
-    public void entityHeader_shouldHaveLabelSetToSsid() {
-        String label = "ssid";
-        when(mockAccessPoint.getSsidStr()).thenReturn(label);
+    public void entityHeader_shouldHaveLabelSetToTitle() {
+        String label = "title";
+        when(mockAccessPoint.getTitle()).thenReturn(label);
 
         displayAndResume();
 
diff --git a/tests/robotests/src/com/android/settings/wifi/tether/WifiTetherSSIDPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/wifi/tether/WifiTetherSSIDPreferenceControllerTest.java
index cb58778..3d15197 100644
--- a/tests/robotests/src/com/android/settings/wifi/tether/WifiTetherSSIDPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/wifi/tether/WifiTetherSSIDPreferenceControllerTest.java
@@ -26,6 +26,7 @@
 import android.content.Context;
 import android.net.ConnectivityManager;
 import android.net.wifi.WifiConfiguration;
+import android.net.wifi.WifiConfiguration.KeyMgmt;
 import android.net.wifi.WifiManager;
 
 import androidx.preference.PreferenceScreen;
@@ -56,12 +57,12 @@
     private PreferenceScreen mScreen;
 
     private WifiTetherSSIDPreferenceController mController;
-    private ValidatedEditTextPreference mPreference;
+    private WifiTetherSsidPreference mPreference;
 
     @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
-        mPreference = new ValidatedEditTextPreference(RuntimeEnvironment.application);
+        mPreference = new WifiTetherSsidPreference(RuntimeEnvironment.application);
 
         when(mContext.getSystemService(Context.WIFI_SERVICE)).thenReturn(mWifiManager);
         when(mContext.getSystemService(Context.CONNECTIVITY_SERVICE))
@@ -121,4 +122,28 @@
         assertThat(mController.getSSID()).isEqualTo(config.SSID);
         assertThat(mPreference.getSummary()).isEqualTo(config.SSID);
     }
+
+    @Test
+    public void displayPreference_wifiApDisabled_shouldHideQrCodeIcon() {
+        when(mWifiManager.isWifiApEnabled()).thenReturn(false);
+        final WifiConfiguration config = new WifiConfiguration();
+        config.SSID = "test_1234";
+        config.allowedKeyManagement.set(KeyMgmt.WPA2_PSK);
+        when(mWifiManager.getWifiApConfiguration()).thenReturn(config);
+
+        mController.displayPreference(mScreen);
+        assertThat(mController.isQrCodeButtonAvailable()).isEqualTo(false);
+    }
+
+    @Test
+    public void displayPreference_wifiApEnabled_shouldShowQrCodeIcon() {
+        when(mWifiManager.isWifiApEnabled()).thenReturn(true);
+        final WifiConfiguration config = new WifiConfiguration();
+        config.SSID = "test_1234";
+        config.allowedKeyManagement.set(KeyMgmt.WPA2_PSK);
+        when(mWifiManager.getWifiApConfiguration()).thenReturn(config);
+
+        mController.displayPreference(mScreen);
+        assertThat(mController.isQrCodeButtonAvailable()).isEqualTo(true);
+    }
 }
diff --git a/tests/unit/src/com/android/settings/homepage/contextualcards/ContextualCardLoaderTest.java b/tests/unit/src/com/android/settings/homepage/contextualcards/ContextualCardLoaderTest.java
index 447e2b4..653e55e 100644
--- a/tests/unit/src/com/android/settings/homepage/contextualcards/ContextualCardLoaderTest.java
+++ b/tests/unit/src/com/android/settings/homepage/contextualcards/ContextualCardLoaderTest.java
@@ -86,6 +86,7 @@
     private ContextualCard getContextualCard(Uri sliceUri) {
         return new ContextualCard.Builder()
                 .setName("test_card")
+                .setRankingScore(0.5f)
                 .setCardType(ContextualCard.CardType.SLICE)
                 .setSliceUri(sliceUri)
                 .build();
diff --git a/tests/unit/src/com/android/settings/wifi/dpp/WifiDppConfiguratorActivityTest.java b/tests/unit/src/com/android/settings/wifi/dpp/WifiDppConfiguratorActivityTest.java
index 405ed4a..38211b3 100644
--- a/tests/unit/src/com/android/settings/wifi/dpp/WifiDppConfiguratorActivityTest.java
+++ b/tests/unit/src/com/android/settings/wifi/dpp/WifiDppConfiguratorActivityTest.java
@@ -147,7 +147,7 @@
     @Test
     public void rotateScreen_shouldGetCorrectWifiNetworkConfig() {
         final WifiNetworkConfig wifiNetworkConfig = new WifiNetworkConfig("WPA", "WifiSsid",
-                "password", /* hiddenSsid */ false, /* networkId */ 0);
+                "password", /* hiddenSsid */ false, /* networkId */ 0, /* isHotspot */ true);
         final Intent intent = new Intent(Settings.ACTION_PROCESS_WIFI_EASY_CONNECT_URI);
         intent.setData(Uri.parse(VALID_WIFI_DPP_QR_CODE));
 
@@ -173,5 +173,6 @@
         assertThat(restoredWifiNetworkConfig.getPreSharedKey()).isEqualTo("password");
         assertThat(restoredWifiNetworkConfig.getHiddenSsid()).isFalse();
         assertThat(restoredWifiNetworkConfig.getNetworkId()).isEqualTo(0);
+        assertThat(restoredWifiNetworkConfig.isHotspot()).isTrue();
     }
 }