Merge "Create a separate activity for Data warning/limit settings" into pi-car-dev
diff --git a/Android.mk b/Android.mk
index 39b7790..a9c6acf 100644
--- a/Android.mk
+++ b/Android.mk
@@ -22,6 +22,7 @@
 # (for example, projected). See b/30064991
 ifeq (,$(TARGET_BUILD_APPS))
   LOCAL_PACKAGE_NAME := CarSettings
+  LOCAL_OVERRIDES_PACKAGES := Settings
   LOCAL_PRIVATE_PLATFORM_APIS := true
 
   LOCAL_SRC_FILES := $(call all-java-files-under, src)
@@ -63,12 +64,6 @@
 
   LOCAL_DX_FLAGS := --multi-dex
 
-  ifdef DISABLE_AOSP_PHONE_SETTING
-    ifeq ($(DISABLE_AOSP_PHONE_SETTING),true)
-      # This will hide AOSP phone setting.
-      LOCAL_OVERRIDES_PACKAGES := Settings
-    endif
-  endif
   include $(BUILD_PACKAGE)
 endif
 
@@ -81,6 +76,7 @@
 # (for example, projected). See b/30064991
 ifeq (,$(TARGET_BUILD_APPS))
   LOCAL_PACKAGE_NAME := CarSettingsForTesting
+  LOCAL_OVERRIDES_PACKAGES := Settings
   LOCAL_PRIVATE_PLATFORM_APIS := true
 
   LOCAL_SRC_FILES := $(call all-java-files-under, src)
@@ -123,12 +119,6 @@
 
   LOCAL_DX_FLAGS := --multi-dex
 
-  ifdef DISABLE_AOSP_PHONE_SETTING
-    ifeq ($(DISABLE_AOSP_PHONE_SETTING),true)
-      # This will hide AOSP phone setting.
-      LOCAL_OVERRIDES_PACKAGES := Settings
-    endif
-  endif
   include $(BUILD_PACKAGE)
 endif
 ###################################################################################
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 1cbb4c4..10397eb 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -160,10 +160,25 @@
             </intent-filter>
 
             <intent-filter android:priority="100">
+                <action android:name="android.settings.action.MANAGE_WRITE_SETTINGS" />
+                <category android:name="android.intent.category.DEFAULT" />
+            </intent-filter>
+
+            <intent-filter android:priority="100">
                 <action android:name="android.settings.ACTION_NOTIFICATION_LISTENER_SETTINGS" />
                 <category android:name="android.intent.category.DEFAULT" />
             </intent-filter>
 
+            <intent-filter android:priority="100">
+                <action android:name="android.settings.USAGE_ACCESS_SETTINGS" />
+                <category android:name="android.intent.category.DEFAULT" />
+            </intent-filter>
+
+            <intent-filter android:priority="100">
+                <action android:name="android.settings.STORAGE_VOLUME_ACCESS_SETTINGS" />
+                <category android:name="android.intent.category.DEFAULT" />
+            </intent-filter>
+
             <intent-filter android:priority="1">
                 <action android:name="android.settings.DATE_SETTINGS" />
                 <action android:name="android.intent.action.QUICK_CLOCK" />
@@ -216,12 +231,11 @@
         </activity>
 
         <!-- Alias for launcher activity only, as this belongs to each profile. -->
-        <!-- TODO: once phone setting is removed from car system image, set priority to 1 -->
         <activity-alias android:name="Settings"
                         android:label="@string/settings_label"
                         android:launchMode="singleTask"
                         android:targetActivity=".common.CarSettingActivity">
-            <intent-filter android:priority="10">
+            <intent-filter android:priority="1">
                 <action android:name="android.intent.action.MAIN" />
                 <category android:name="android.intent.category.DEFAULT" />
                 <category android:name="android.intent.category.LAUNCHER" />
@@ -238,6 +252,16 @@
             <meta-data android:name="distractionOptimized" android:value="true"/>
         </activity>
 
+        <activity android:name=".bluetooth.BluetoothDevicePickerActivity"
+                  android:label="@string/bluetooth_device_picker"
+                  android:configChanges="orientation|keyboardHidden|screenSize"
+                  android:clearTaskOnLaunch="true">
+            <intent-filter>
+                <action android:name="android.bluetooth.devicepicker.action.LAUNCH" />
+                <category android:name="android.intent.category.DEFAULT" />
+            </intent-filter>
+        </activity>
+
         <activity android:name=".accounts.AddAccountActivity"
                   android:theme="@android:style/Theme.Translucent.NoTitleBar"
                   android:configChanges="orientation|keyboardHidden|screenSize"/>
diff --git a/res/drawable/ic_delete.xml b/res/drawable/ic_delete.xml
new file mode 100644
index 0000000..1f358ca
--- /dev/null
+++ b/res/drawable/ic_delete.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+    Copyright 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.
+-->
+
+<vector
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="@dimen/icon_size"
+    android:height="@dimen/icon_size"
+    android:viewportHeight="24.0"
+    android:viewportWidth="24.0">
+    <path
+        android:fillColor="?attr/iconColor"
+        android:pathData="M6,19c0,1.1 0.9,2 2,2h8c1.1,0 2,-0.9 2,-2V7H6v12zM19,4h-3.5l-1,-1h-5l-1,1H5v2h14V4z"/>
+</vector>
diff --git a/res/layout/delete_preference_widget.xml b/res/layout/delete_preference_widget.xml
new file mode 100644
index 0000000..7c2690e
--- /dev/null
+++ b/res/layout/delete_preference_widget.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+    Copyright 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.
+-->
+
+<ImageView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:layout_gravity="center"
+    android:src="@drawable/ic_delete"/>
diff --git a/res/values/config.xml b/res/values/config.xml
index 21b7908..939d08c 100644
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -26,6 +26,19 @@
     <bool name="config_show_regulatory_info">true</bool>
     <!-- Whether premium SMS should be shown or not. -->
     <bool name="config_show_premium_sms">true</bool>
+    <!-- Whether exit button in settings' root action bar should be shown or not -->
+    <bool name="config_show_settings_root_exit_icon">false</bool>
+    <!-- Whether all preferences should always ignore UX Restrictions -->
+    <bool name="config_always_ignore_ux_restrictions">false</bool>
+    <!-- Array of Preference Keys that ignore UX Restrictions -->
+    <string-array name="config_ignore_ux_restrictions">
+        <item>@string/pk_display_settings_entry</item>
+        <item>@string/pk_sound_settings_entry</item>
+        <item>@string/pk_storage_settings_entry</item>
+        <item>@string/pk_network_and_internet_entry</item>
+        <item>@string/pk_wifi_settings_entry</item>
+        <item>@string/pk_bluetooth_settings_entry</item>
+    </string-array>
 
     <!-- The component which listens for the enabling of developer options. -->
     <string name="config_dev_options_module" translatable="false">com.android.car.developeroptions/.Settings$DevelopmentSettingsDashboardActivity</string>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 21b0abd..9e7cba8 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -28,6 +28,8 @@
 
     <!-- Action Bar -->
     <dimen name="action_bar_height">@*android:dimen/car_app_bar_height</dimen>
+    <!-- Guideline begin margin for when not showing exit icon -->
+    <dimen name="action_bar_no_icon_start_margin">@*android:dimen/action_bar_button_margin</dimen>
 
     <!-- Suggestions -->
     <dimen name="suggestions_top_bottom_margin">@*android:dimen/car_padding_4</dimen>
diff --git a/res/values/preference_keys.xml b/res/values/preference_keys.xml
index fd6b2a5..cf33c99 100644
--- a/res/values/preference_keys.xml
+++ b/res/values/preference_keys.xml
@@ -108,6 +108,7 @@
     </string>
     <string name="pk_bluetooth_device_address" translatable="false">bluetooth_device_address
     </string>
+    <string name="pk_bluetooth_device_picker" translatable="false">bluetooth_device_picker</string>
 
     <!-- Applications and Notifications Settings -->
     <string name="pk_applications_settings_screen_entry" translatable="false">
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 3b36795..3b38e1e 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -315,6 +315,8 @@
     <string name="bluetooth_notif_title">Pairing request</string>
     <!-- Notification message when a Bluetooth device wants to pair with us -->
     <string name="bluetooth_notif_message">Tap to pair with <xliff:g id="device_name">%1$s</xliff:g>.</string>
+    <!-- Title for page which supports selecting a Bluetooth device from other applications. [CHAR_LIMIT=40]-->
+    <string name="bluetooth_device_picker">Choose Bluetooth device</string>
 
     <!-- Language settings screen heading. [CHAR LIMIT=30] -->
     <string name="language_settings">Languages</string>
diff --git a/res/xml/add_wifi_fragment.xml b/res/xml/add_wifi_fragment.xml
index c164f77..d0eafa3 100644
--- a/res/xml/add_wifi_fragment.xml
+++ b/res/xml/add_wifi_fragment.xml
@@ -30,7 +30,7 @@
         android:persistent="false"
         android:title="@string/wifi_security"
         settings:controller="com.android.car.settings.wifi.NetworkSecurityPreferenceController"/>
-    <com.android.car.settings.common.PasswordEditTextPreference
+    <com.android.car.settings.wifi.NetworkNameRestrictedPasswordEditTextPreference
         android:dialogTitle="@string/wifi_password"
         android:key="@string/pk_add_wifi_password"
         android:persistent="false"
diff --git a/res/xml/bluetooth_device_picker_fragment.xml b/res/xml/bluetooth_device_picker_fragment.xml
new file mode 100644
index 0000000..95dcacd
--- /dev/null
+++ b/res/xml/bluetooth_device_picker_fragment.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+    Copyright 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.
+-->
+
+<PreferenceScreen
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:settings="http://schemas.android.com/apk/res-auto"
+    android:title="@string/bluetooth_device_picker">
+    <com.android.car.settings.common.LogicalPreferenceGroup
+        android:key="@string/pk_bluetooth_device_picker"
+        settings:controller="com.android.car.settings.bluetooth.BluetoothDevicePickerPreferenceController"/>
+</PreferenceScreen>
diff --git a/res/xml/homepage_fragment.xml b/res/xml/homepage_fragment.xml
index 10e3e2d..75944e5 100644
--- a/res/xml/homepage_fragment.xml
+++ b/res/xml/homepage_fragment.xml
@@ -28,12 +28,14 @@
         android:fragment="com.android.car.settings.display.DisplaySettingsFragment"
         android:icon="@drawable/ic_settings_display"
         android:key="@string/pk_display_settings_entry"
-        android:title="@string/display_settings"/>
+        android:title="@string/display_settings"
+        settings:controller="com.android.car.settings.common.DefaultRestrictionsPreferenceController"/>
     <Preference
         android:fragment="com.android.car.settings.sound.SoundSettingsFragment"
         android:icon="@drawable/ic_settings_sound"
         android:key="@string/pk_sound_settings_entry"
-        android:title="@string/sound_settings"/>
+        android:title="@string/sound_settings"
+        settings:controller="com.android.car.settings.common.DefaultRestrictionsPreferenceController"/>
     <Preference
         android:fragment="com.android.car.settings.network.NetworkAndInternetFragment"
         android:icon="@drawable/ic_settings_wifi"
@@ -87,7 +89,8 @@
         android:fragment="com.android.car.settings.storage.StorageSettingsFragment"
         android:icon="@drawable/ic_storage"
         android:key="@string/pk_storage_settings_entry"
-        android:title="@string/storage_settings_title"/>
+        android:title="@string/storage_settings_title"
+        settings:controller="com.android.car.settings.common.DefaultRestrictionsPreferenceController"/>
     <Preference
         android:icon="@drawable/ic_lock"
         android:key="@string/pk_security_settings_entry"
diff --git a/src/com/android/car/settings/applications/ApplicationDetailsFragment.java b/src/com/android/car/settings/applications/ApplicationDetailsFragment.java
index 275968c..e997948 100644
--- a/src/com/android/car/settings/applications/ApplicationDetailsFragment.java
+++ b/src/com/android/car/settings/applications/ApplicationDetailsFragment.java
@@ -266,14 +266,6 @@
     }
 
     private boolean shouldDisableUninstallButton() {
-        // TODO: Remove this condition when phone settings is removed from automotive builds.
-        // This is a temporary measure to allow enabling the phone settings package.
-        // It is not an expected case long-term to have packages in the disabled state that
-        // normally cannot be disabled by a user.
-        if (mPackageName.equals("com.android.settings")) {
-            return false;
-        }
-
         if (shouldDisableUninstallForHomeApp()) {
             LOG.d("Uninstall disabled for home app");
             return true;
diff --git a/src/com/android/car/settings/bluetooth/BluetoothDevicePickerActivity.java b/src/com/android/car/settings/bluetooth/BluetoothDevicePickerActivity.java
new file mode 100644
index 0000000..db89075
--- /dev/null
+++ b/src/com/android/car/settings/bluetooth/BluetoothDevicePickerActivity.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright 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.car.settings.bluetooth;
+
+import androidx.annotation.Nullable;
+import androidx.fragment.app.Fragment;
+
+import com.android.car.settings.common.BaseCarSettingsActivity;
+
+/**
+ * Displays a list of Bluetooth devices at the request of another application. When a user selects a
+ * device from the list, its details are returned to the requester. See {@link
+ * android.bluetooth.BluetoothDevicePicker}.
+ */
+public class BluetoothDevicePickerActivity extends BaseCarSettingsActivity {
+
+    @Nullable
+    @Override
+    protected Fragment getInitialFragment() {
+        return new BluetoothDevicePickerFragment();
+    }
+}
diff --git a/src/com/android/car/settings/bluetooth/BluetoothDevicePickerFragment.java b/src/com/android/car/settings/bluetooth/BluetoothDevicePickerFragment.java
new file mode 100644
index 0000000..658690d
--- /dev/null
+++ b/src/com/android/car/settings/bluetooth/BluetoothDevicePickerFragment.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright 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.car.settings.bluetooth;
+
+import android.content.Context;
+import android.os.Bundle;
+import android.view.View;
+import android.widget.ProgressBar;
+
+import androidx.annotation.XmlRes;
+
+import com.android.car.settings.R;
+import com.android.car.settings.common.SettingsFragment;
+import com.android.settingslib.bluetooth.LocalBluetoothManager;
+
+/**
+ * Hosts {@link BluetoothDevicePickerPreferenceController} to display the list of Bluetooth
+ * devices. The progress bar is shown while this fragment is visible to indicate discovery or
+ * pairing progress.
+ */
+public class BluetoothDevicePickerFragment extends SettingsFragment {
+
+    private LocalBluetoothManager mManager;
+    private ProgressBar mProgressBar;
+
+    @Override
+    @XmlRes
+    protected int getPreferenceScreenResId() {
+        return R.xml.bluetooth_device_picker_fragment;
+    }
+
+    @Override
+    public void onAttach(Context context) {
+        super.onAttach(context);
+        mManager = BluetoothUtils.getLocalBtManager(context);
+        if (mManager == null) {
+            goBack();
+            return;
+        }
+
+        use(BluetoothDevicePickerPreferenceController.class,
+                R.string.pk_bluetooth_device_picker).setLaunchIntent(requireActivity().getIntent());
+    }
+
+    @Override
+    public void onActivityCreated(Bundle savedInstanceState) {
+        super.onActivityCreated(savedInstanceState);
+        mProgressBar = requireActivity().findViewById(R.id.progress_bar);
+    }
+
+    @Override
+    public void onStart() {
+        super.onStart();
+        mManager.setForegroundActivity(requireActivity());
+        mProgressBar.setVisibility(View.VISIBLE);
+    }
+
+    @Override
+    public void onStop() {
+        super.onStop();
+        mManager.setForegroundActivity(null);
+        mProgressBar.setVisibility(View.GONE);
+    }
+}
diff --git a/src/com/android/car/settings/bluetooth/BluetoothDevicePickerPreferenceController.java b/src/com/android/car/settings/bluetooth/BluetoothDevicePickerPreferenceController.java
new file mode 100644
index 0000000..0c68eb5
--- /dev/null
+++ b/src/com/android/car/settings/bluetooth/BluetoothDevicePickerPreferenceController.java
@@ -0,0 +1,144 @@
+/*
+ * Copyright 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.car.settings.bluetooth;
+
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothDevicePicker;
+import android.car.drivingstate.CarUxRestrictions;
+import android.content.Context;
+import android.content.Intent;
+
+import com.android.car.settings.R;
+import com.android.car.settings.common.FragmentController;
+import com.android.car.settings.common.Logger;
+import com.android.settingslib.bluetooth.BluetoothDeviceFilter;
+import com.android.settingslib.bluetooth.CachedBluetoothDevice;
+
+/**
+ * Displays a list of Bluetooth devices for the user to select. When a device is selected, a
+ * {@link BluetoothDevicePicker#ACTION_DEVICE_SELECTED} broadcast is sent containing {@link
+ * BluetoothDevice#EXTRA_DEVICE}.
+ *
+ * <p>This is useful to other application to obtain a device without needing to implement the UI.
+ * The activity hosting this controller should be launched with an intent as detailed in {@link
+ * BluetoothDevicePicker#ACTION_LAUNCH}. This controller will filter devices as specified by {@link
+ * BluetoothDevicePicker#EXTRA_FILTER_TYPE} and deliver the broadcast to the specified {@link
+ * BluetoothDevicePicker#EXTRA_LAUNCH_PACKAGE} {@link BluetoothDevicePicker#EXTRA_LAUNCH_CLASS}
+ * component.  If authentication is required ({@link BluetoothDevicePicker#EXTRA_NEED_AUTH}), this
+ * controller will initiate pairing with the device and send the selected broadcast once the device
+ * successfully pairs. If no device is selected and this controller is destroyed, a broadcast with
+ * a {@code null} {@link BluetoothDevice#EXTRA_DEVICE} is sent.
+ */
+public class BluetoothDevicePickerPreferenceController extends
+        BluetoothScanningDevicesGroupPreferenceController {
+
+    private static final Logger LOG = new Logger(BluetoothDevicePickerPreferenceController.class);
+
+    private BluetoothDeviceFilter.Filter mFilter;
+
+    private boolean mNeedAuth;
+    private String mLaunchPackage;
+    private String mLaunchClass;
+
+    private CachedBluetoothDevice mSelectedDevice;
+
+    public BluetoothDevicePickerPreferenceController(Context context, String preferenceKey,
+            FragmentController fragmentController, CarUxRestrictions uxRestrictions) {
+        super(context, preferenceKey, fragmentController, uxRestrictions);
+    }
+
+    /**
+     * Sets the intent with which {@link BluetoothDevicePickerActivity} was launched. The intent
+     * may contain {@link BluetoothDevicePicker} extras to customize the selection list and specify
+     * the destination of the selected device. See {@link BluetoothDevicePicker#ACTION_LAUNCH}.
+     */
+    public void setLaunchIntent(Intent intent) {
+        mNeedAuth = intent.getBooleanExtra(BluetoothDevicePicker.EXTRA_NEED_AUTH, false);
+        mFilter = BluetoothDeviceFilter.getFilter(
+                intent.getIntExtra(BluetoothDevicePicker.EXTRA_FILTER_TYPE,
+                        BluetoothDevicePicker.FILTER_TYPE_ALL));
+        mLaunchPackage = intent.getStringExtra(BluetoothDevicePicker.EXTRA_LAUNCH_PACKAGE);
+        mLaunchClass = intent.getStringExtra(BluetoothDevicePicker.EXTRA_LAUNCH_CLASS);
+    }
+
+    @Override
+    protected void checkInitialized() {
+        if (mFilter == null) {
+            throw new IllegalStateException("launch intent must be set");
+        }
+    }
+
+    @Override
+    protected BluetoothDeviceFilter.Filter getDeviceFilter() {
+        return mFilter;
+    }
+
+    @Override
+    protected void onDeviceClickedInternal(CachedBluetoothDevice cachedDevice) {
+        mSelectedDevice = cachedDevice;
+        BluetoothUtils.persistSelectedDeviceInPicker(getContext(), cachedDevice.getAddress());
+
+        if (cachedDevice.getBondState() == BluetoothDevice.BOND_BONDED || !mNeedAuth) {
+            sendDevicePickedIntent(cachedDevice.getDevice());
+            getFragmentController().goBack();
+            return;
+        }
+
+        if (cachedDevice.startPairing()) {
+            LOG.d("startPairing");
+        } else {
+            BluetoothUtils.showError(getContext(), cachedDevice.getName(),
+                    R.string.bluetooth_pairing_error_message);
+            refreshUi();
+        }
+    }
+
+    @Override
+    protected void onStartInternal() {
+        super.onStartInternal();
+        mSelectedDevice = null;
+    }
+
+    @Override
+    protected void onDestroyInternal() {
+        super.onDestroyInternal();
+        if (mSelectedDevice == null) {
+            // Notify that no device was selected.
+            sendDevicePickedIntent(null);
+        }
+    }
+
+    @Override
+    public void onDeviceBondStateChanged(CachedBluetoothDevice cachedDevice, int bondState) {
+        super.onDeviceBondStateChanged(cachedDevice, bondState);
+        if (bondState == BluetoothDevice.BOND_BONDED && cachedDevice.equals(mSelectedDevice)) {
+            sendDevicePickedIntent(mSelectedDevice.getDevice());
+            getFragmentController().goBack();
+        }
+    }
+
+    private void sendDevicePickedIntent(BluetoothDevice device) {
+        LOG.d("sendDevicePickedIntent device: " + device + " package: " + mLaunchPackage
+                + " class: " + mLaunchClass);
+        Intent intent = new Intent(BluetoothDevicePicker.ACTION_DEVICE_SELECTED);
+        intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
+        if (mLaunchPackage != null && mLaunchClass != null) {
+            intent.setClassName(mLaunchPackage, mLaunchClass);
+        }
+        getContext().sendBroadcast(intent);
+    }
+}
diff --git a/src/com/android/car/settings/bluetooth/BluetoothUtils.java b/src/com/android/car/settings/bluetooth/BluetoothUtils.java
index 6bda46b..731ee0b 100644
--- a/src/com/android/car/settings/bluetooth/BluetoothUtils.java
+++ b/src/com/android/car/settings/bluetooth/BluetoothUtils.java
@@ -161,6 +161,13 @@
         return false;
     }
 
+    static void persistSelectedDeviceInPicker(Context context, String deviceAddress) {
+        SharedPreferences.Editor editor = getSharedPreferences(context).edit();
+        editor.putString(KEY_LAST_SELECTED_DEVICE, deviceAddress);
+        editor.putLong(KEY_LAST_SELECTED_DEVICE_TIME, System.currentTimeMillis());
+        editor.apply();
+    }
+
     public static LocalBluetoothManager getLocalBtManager(Context context) {
         return LocalBluetoothManager.getInstance(context, mOnInitCallback);
     }
diff --git a/src/com/android/car/settings/common/FragmentResolver.java b/src/com/android/car/settings/common/FragmentResolver.java
index 8518825..4ae48da 100644
--- a/src/com/android/car/settings/common/FragmentResolver.java
+++ b/src/com/android/car/settings/common/FragmentResolver.java
@@ -32,7 +32,10 @@
 import com.android.car.settings.applications.DefaultApplicationsSettingsFragment;
 import com.android.car.settings.applications.assist.ManageAssistFragment;
 import com.android.car.settings.applications.defaultapps.DefaultAutofillPickerFragment;
+import com.android.car.settings.applications.specialaccess.DirectoryAccessFragment;
+import com.android.car.settings.applications.specialaccess.ModifySystemSettingsFragment;
 import com.android.car.settings.applications.specialaccess.NotificationAccessFragment;
+import com.android.car.settings.applications.specialaccess.UsageAccessFragment;
 import com.android.car.settings.bluetooth.BluetoothSettingsFragment;
 import com.android.car.settings.datausage.DataUsageFragment;
 import com.android.car.settings.datetime.DatetimeSettingsFragment;
@@ -137,9 +140,18 @@
             case Settings.ACTION_VOICE_INPUT_SETTINGS:
                 return new ManageAssistFragment();
 
+            case Settings.ACTION_MANAGE_WRITE_SETTINGS:
+                return new ModifySystemSettingsFragment();
+
             case Settings.ACTION_NOTIFICATION_LISTENER_SETTINGS:
                 return new NotificationAccessFragment();
 
+            case Settings.ACTION_USAGE_ACCESS_SETTINGS:
+                return new UsageAccessFragment();
+
+            case Settings.ACTION_STORAGE_VOLUME_ACCESS_SETTINGS:
+                return new DirectoryAccessFragment();
+
             case Intent.ACTION_QUICK_CLOCK:
             case Settings.ACTION_DATE_SETTINGS:
                 return new DatetimeSettingsFragment();
diff --git a/src/com/android/car/settings/common/PreferenceController.java b/src/com/android/car/settings/common/PreferenceController.java
index b8e0622..5dfe4ee 100644
--- a/src/com/android/car/settings/common/PreferenceController.java
+++ b/src/com/android/car/settings/common/PreferenceController.java
@@ -26,8 +26,13 @@
 import androidx.lifecycle.LifecycleOwner;
 import androidx.preference.Preference;
 
+import com.android.car.settings.R;
+
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Set;
 
 /**
  * Controller which encapsulates the business logic associated with a {@link Preference}. All car
@@ -114,6 +119,18 @@
      */
     public static final int DISABLED_FOR_USER = 3;
 
+    /**
+     * Indicates whether all Preferences are configured to ignore UX Restrictions Event.
+     */
+    private final boolean mAlwaysIgnoreUxRestrictions;
+
+    /**
+     * Set of the keys of Preferences that ignore UX Restrictions. When mAlwaysIgnoreUxRestrictions
+     * is configured to be false, then only the Preferences whose keys are contained in this Set
+     * ignore UX Restrictions.
+     */
+    private final Set<String> mPreferencesIgnoringUxRestrictions;
+
     private final Context mContext;
     private final String mPreferenceKey;
     private final FragmentController mFragmentController;
@@ -132,6 +149,10 @@
         mPreferenceKey = preferenceKey;
         mFragmentController = fragmentController;
         mUxRestrictions = uxRestrictions;
+        mPreferencesIgnoringUxRestrictions = new HashSet<String>(Arrays.asList(
+                mContext.getResources().getStringArray(R.array.config_ignore_ux_restrictions)));
+        mAlwaysIgnoreUxRestrictions =
+                mContext.getResources().getBoolean(R.bool.config_always_ignore_ux_restrictions);
     }
 
     /**
@@ -413,7 +434,9 @@
      * additional driving restrictions.
      */
     protected void onApplyUxRestrictions(CarUxRestrictions uxRestrictions) {
-        if (CarUxRestrictionsHelper.isNoSetup(uxRestrictions)) {
+        if (!isUxRestrictionsIgnored(mAlwaysIgnoreUxRestrictions,
+                mPreferencesIgnoringUxRestrictions)
+                && CarUxRestrictionsHelper.isNoSetup(uxRestrictions)) {
             mPreference.setEnabled(false);
         }
     }
@@ -442,4 +465,8 @@
     protected boolean handlePreferenceClicked(V preference) {
         return false;
     }
+
+    protected boolean isUxRestrictionsIgnored(boolean allIgnores, Set prefsThatIgnore) {
+        return allIgnores || prefsThatIgnore.contains(mPreferenceKey);
+    }
 }
diff --git a/src/com/android/car/settings/common/SettingsFragment.java b/src/com/android/car/settings/common/SettingsFragment.java
index 66b43d3..85d8085 100644
--- a/src/com/android/car/settings/common/SettingsFragment.java
+++ b/src/com/android/car/settings/common/SettingsFragment.java
@@ -36,6 +36,7 @@
 import androidx.annotation.StringRes;
 import androidx.annotation.VisibleForTesting;
 import androidx.annotation.XmlRes;
+import androidx.constraintlayout.widget.Guideline;
 import androidx.fragment.app.DialogFragment;
 import androidx.fragment.app.Fragment;
 import androidx.fragment.app.FragmentManager;
@@ -201,8 +202,13 @@
                     && fragmentManager.findFragmentByTag("0") != null
                     && fragmentManager.findFragmentByTag("0").getClass().getName().equals(
                     getString(R.string.config_settings_hierarchy_root_fragment))) {
-                imageView.setImageResource(R.drawable.ic_launcher_settings);
-                imageView.setTag(R.id.back_button, R.drawable.ic_launcher_settings);
+                if (getContext().getResources()
+                        .getBoolean(R.bool.config_show_settings_root_exit_icon)) {
+                    imageView.setImageResource(R.drawable.ic_launcher_settings);
+                    imageView.setTag(R.id.back_button, R.drawable.ic_launcher_settings);
+                } else {
+                    hideExitIcon();
+                }
             } else {
                 imageView.setTag(R.id.back_button, R.drawable.ic_arrow_back);
                 actionBarContainer.requireViewById(R.id.action_bar_icon_container)
@@ -360,4 +366,13 @@
             throw new IllegalArgumentException("Can only use lower 8 bits for requestCode");
         }
     }
+
+    private void hideExitIcon() {
+        requireActivity().findViewById(R.id.action_bar_icon_container)
+                .setVisibility(FrameLayout.GONE);
+
+        Guideline guideLine = (Guideline) requireActivity().findViewById(R.id.start_margin);
+        guideLine.setGuidelineBegin(getResources()
+                .getDimensionPixelOffset(R.dimen.action_bar_no_icon_start_margin));
+    }
 }
diff --git a/src/com/android/car/settings/quicksettings/QuickSettingFragment.java b/src/com/android/car/settings/quicksettings/QuickSettingFragment.java
index 5a091ef..2300263 100644
--- a/src/com/android/car/settings/quicksettings/QuickSettingFragment.java
+++ b/src/com/android/car/settings/quicksettings/QuickSettingFragment.java
@@ -29,10 +29,14 @@
 import android.view.View;
 import android.view.View.OnClickListener;
 import android.widget.Button;
+import android.widget.FrameLayout;
 import android.widget.TextView;
 
 import androidx.annotation.LayoutRes;
 import androidx.annotation.NonNull;
+import androidx.constraintlayout.widget.Guideline;
+import androidx.fragment.app.FragmentActivity;
+import androidx.fragment.app.FragmentManager;
 import androidx.recyclerview.widget.RecyclerView;
 
 import com.android.car.settings.R;
@@ -42,6 +46,9 @@
 import com.android.car.settings.users.UserIconProvider;
 import com.android.car.settings.users.UserSwitcherFragment;
 
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Set;
 import java.util.concurrent.TimeUnit;
 
 /**
@@ -50,6 +57,17 @@
 public class QuickSettingFragment extends BaseFragment {
     // Time to delay refreshing the build info, if the clock is not correct.
     private static final long BUILD_INFO_REFRESH_TIME_MS = TimeUnit.SECONDS.toMillis(5);
+    /**
+     * Indicates whether all Preferences are configured to ignore UX Restrictions Event.
+     */
+    private boolean mAllIgnoresUxRestrictions;
+
+    /**
+     * Set of the keys of Preferences that ignore UX Restrictions. When mAlwaysIgnoreUxRestrictions
+     * is configured to be false, then only the Preferences whose keys are contained in this Set
+     * ignore UX Restrictions.
+     */
+    private Set<String> mPreferencesIgnoringUxRestrictions;
 
     private CarUserManagerHelper mCarUserManagerHelper;
     private UserIconProvider mUserIconProvider;
@@ -79,6 +97,17 @@
         super.onActivityCreated(savedInstanceState);
         mHomeFragmentLauncher = new HomeFragmentLauncher();
         Activity activity = requireActivity();
+
+        FragmentManager fragmentManager = ((FragmentActivity) activity).getSupportFragmentManager();
+        if (fragmentManager.getBackStackEntryCount() == 1
+                && fragmentManager.findFragmentByTag("0") != null
+                && fragmentManager.findFragmentByTag("0").getClass().getName().equals(
+                getString(R.string.config_settings_hierarchy_root_fragment))
+                && !getContext().getResources()
+                .getBoolean(R.bool.config_show_settings_root_exit_icon)) {
+            hideExitIcon();
+        }
+
         activity.findViewById(R.id.action_bar_icon_container).setOnClickListener(
                 v -> activity.finish());
 
@@ -108,6 +137,11 @@
                 .addTile(new CelluarTile(activity, mGridAdapter))
                 .addSeekbarTile(new BrightnessTile(activity));
         mListView.setAdapter(mGridAdapter);
+
+        mPreferencesIgnoringUxRestrictions = new HashSet<String>(Arrays.asList(
+                getContext().getResources().getStringArray(R.array.config_ignore_ux_restrictions)));
+        mAllIgnoresUxRestrictions =
+                getContext().getResources().getBoolean(R.bool.config_always_ignore_ux_restrictions);
     }
 
     @Override
@@ -185,7 +219,10 @@
     @Override
     public void onUxRestrictionsChanged(CarUxRestrictions restrictionInfo) {
         // TODO: update tiles
-        applyRestriction(CarUxRestrictionsHelper.isNoSetup(restrictionInfo));
+        if (!hasPreferenceIgnoringUxRestrictions(mAllIgnoresUxRestrictions,
+                mPreferencesIgnoringUxRestrictions)) {
+            applyRestriction(CarUxRestrictionsHelper.isNoSetup(restrictionInfo));
+        }
     }
 
     private void applyRestriction(boolean restricted) {
@@ -209,4 +246,17 @@
             }
         }
     }
+
+    private boolean hasPreferenceIgnoringUxRestrictions(boolean allIgnores, Set prefsThatIgnore) {
+        return allIgnores || prefsThatIgnore.size() > 0;
+    }
+
+    private void hideExitIcon() {
+        requireActivity().findViewById(R.id.action_bar_icon_container)
+                .setVisibility(FrameLayout.GONE);
+
+        Guideline guideLine = (Guideline) requireActivity().findViewById(R.id.start_margin);
+        guideLine.setGuidelineBegin(getResources()
+                .getDimensionPixelOffset(R.dimen.action_bar_no_icon_start_margin));
+    }
 }
diff --git a/src/com/android/car/settings/wifi/AccessPointListPreferenceController.java b/src/com/android/car/settings/wifi/AccessPointListPreferenceController.java
index 10c7f84..f53c41b 100644
--- a/src/com/android/car/settings/wifi/AccessPointListPreferenceController.java
+++ b/src/com/android/car/settings/wifi/AccessPointListPreferenceController.java
@@ -20,7 +20,6 @@
 import android.car.drivingstate.CarUxRestrictionsManager;
 import android.content.Context;
 import android.net.wifi.WifiManager;
-import android.widget.Toast;
 
 import androidx.annotation.NonNull;
 import androidx.preference.Preference;
@@ -37,7 +36,7 @@
 import java.util.List;
 
 /**
- * Renders a list of {@link AccessPoint} as a list of preference.
+ * Renders a list of {@link AccessPoint} as a list of preferences.
  */
 public class AccessPointListPreferenceController extends
         WifiBasePreferenceController<PreferenceGroup> implements
@@ -45,21 +44,9 @@
         Preference.OnPreferenceChangeListener,
         CarUxRestrictionsManager.OnUxRestrictionsChangedListener {
     private static final Logger LOG = new Logger(AccessPointListPreferenceController.class);
-    private List<AccessPoint> mAccessPoints = new ArrayList<>();
-
     private final WifiManager.ActionListener mConnectionListener =
-            new WifiManager.ActionListener() {
-                @Override
-                public void onSuccess() {
-                }
-
-                @Override
-                public void onFailure(int reason) {
-                    Toast.makeText(getContext(),
-                            R.string.wifi_failed_connect_message,
-                            Toast.LENGTH_SHORT).show();
-                }
-            };
+            new WifiUtil.ActionFailedListener(getContext(), R.string.wifi_failed_connect_message);
+    private List<AccessPoint> mAccessPoints = new ArrayList<>();
 
     public AccessPointListPreferenceController(@NonNull Context context, String preferenceKey,
             FragmentController fragmentController, CarUxRestrictions uxRestrictions) {
@@ -115,7 +102,8 @@
             getCarWifiManager().connectToPublicWifi(accessPoint, mConnectionListener);
         } else if (accessPoint.isActive()) {
             getFragmentController().launchFragment(WifiDetailsFragment.getInstance(accessPoint));
-        } else if (accessPoint.isSaved()) {
+        } else if (accessPoint.isSaved() && !WifiUtil.isAccessPointDisabledByWrongPassword(
+                accessPoint)) {
             getCarWifiManager().connectToSavedWifi(accessPoint, mConnectionListener);
         }
         return true;
@@ -139,6 +127,15 @@
         accessPointPreference.setSummary(accessPoint.getSummary());
         accessPointPreference.setOnPreferenceClickListener(this);
         accessPointPreference.setOnPreferenceChangeListener(this);
+        accessPointPreference.showButton(false);
+
+        if (accessPoint.isSaved() && WifiUtil.isAccessPointDisabledByWrongPassword(accessPoint)) {
+            accessPointPreference.setWidgetLayoutResource(R.layout.delete_preference_widget);
+            accessPointPreference.setOnButtonClickListener(
+                    preference -> WifiUtil.forget(getContext(), accessPoint));
+            accessPointPreference.showButton(true);
+        }
+
         return accessPointPreference;
     }
 }
diff --git a/src/com/android/car/settings/wifi/AccessPointPreference.java b/src/com/android/car/settings/wifi/AccessPointPreference.java
index cddafee..f0e2a8d 100644
--- a/src/com/android/car/settings/wifi/AccessPointPreference.java
+++ b/src/com/android/car/settings/wifi/AccessPointPreference.java
@@ -19,16 +19,14 @@
 import android.content.Context;
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.StateListDrawable;
-import android.net.wifi.WifiConfiguration;
 
 import androidx.preference.PreferenceViewHolder;
 
 import com.android.car.settings.common.Logger;
-import com.android.car.settings.common.PasswordEditTextPreference;
 import com.android.settingslib.wifi.AccessPoint;
 
 /** Renders a {@link AccessPoint} as a preference. */
-public class AccessPointPreference extends PasswordEditTextPreference {
+public class AccessPointPreference extends ButtonPasswordEditTextPreference {
     private static final Logger LOG = new Logger(AccessPointPreference.class);
     private static final int[] STATE_SECURED = {
             com.android.settingslib.R.attr.state_encrypted
@@ -77,7 +75,7 @@
      */
     private boolean shouldShowPasswordDialog() {
         return mAccessPoint.getSecurity() != AccessPoint.SECURITY_NONE && (!mAccessPoint.isSaved()
-                || isAccessPointDisabledByWrongPassword(mAccessPoint));
+                || WifiUtil.isAccessPointDisabledByWrongPassword(mAccessPoint));
     }
 
     private Drawable getAccessPointIcon() {
@@ -93,18 +91,4 @@
         drawable.setLevel(mAccessPoint.getLevel());
         return drawable;
     }
-
-    private boolean isAccessPointDisabledByWrongPassword(AccessPoint accessPoint) {
-        WifiConfiguration config = accessPoint.getConfig();
-        if (config == null) {
-            return false;
-        }
-        WifiConfiguration.NetworkSelectionStatus networkStatus =
-                config.getNetworkSelectionStatus();
-        if (networkStatus == null || networkStatus.isNetworkEnabled()) {
-            return false;
-        }
-        return networkStatus.getNetworkSelectionDisableReason()
-                == WifiConfiguration.NetworkSelectionStatus.DISABLED_BY_WRONG_PASSWORD;
-    }
 }
diff --git a/src/com/android/car/settings/wifi/ButtonPasswordEditTextPreference.java b/src/com/android/car/settings/wifi/ButtonPasswordEditTextPreference.java
new file mode 100644
index 0000000..46834c1
--- /dev/null
+++ b/src/com/android/car/settings/wifi/ButtonPasswordEditTextPreference.java
@@ -0,0 +1,99 @@
+/*
+ * 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.car.settings.wifi;
+
+import android.content.Context;
+import android.view.View;
+
+import androidx.preference.PreferenceViewHolder;
+
+import com.android.car.settings.R;
+import com.android.car.settings.common.PasswordEditTextPreference;
+
+/**
+ * A {@link PasswordEditTextPreference} which has a second button which can perform another action
+ * defined by {@link OnButtonClickListener}.
+ */
+public class ButtonPasswordEditTextPreference extends PasswordEditTextPreference {
+
+    private OnButtonClickListener mOnButtonClickListener;
+
+    private boolean mIsButtonShown = true;
+
+    public ButtonPasswordEditTextPreference(Context context) {
+        super(context);
+        init();
+    }
+
+    private void init() {
+        setLayoutResource(R.layout.two_action_preference);
+    }
+
+    /**
+     * Sets whether the secondary button is visible in the preference.
+     *
+     * @param isShown {@code true} if the secondary button should be shown.
+     */
+    public void showButton(boolean isShown) {
+        mIsButtonShown = isShown;
+        notifyChanged();
+    }
+
+    /** Returns {@code true} if action is shown. */
+    public boolean isButtonShown() {
+        return mIsButtonShown;
+    }
+
+    @Override
+    public void onBindViewHolder(PreferenceViewHolder holder) {
+        super.onBindViewHolder(holder);
+        View actionConatiner = holder.findViewById(R.id.action_widget_container);
+        View widgetFrame = holder.findViewById(android.R.id.widget_frame);
+        if (mIsButtonShown) {
+            actionConatiner.setVisibility(View.VISIBLE);
+            widgetFrame.setOnClickListener(v -> performButtonClick());
+        } else {
+            actionConatiner.setVisibility(View.GONE);
+        }
+    }
+
+    /**
+     * Sets an {@link OnButtonClickListener} to be invoked when the button is clicked.
+     */
+    public void setOnButtonClickListener(OnButtonClickListener listener) {
+        mOnButtonClickListener = listener;
+    }
+
+    /** Virtually clicks the button contained inside this preference. */
+    public void performButtonClick() {
+        if (isButtonShown()) {
+            if (mOnButtonClickListener != null) {
+                mOnButtonClickListener.onButtonClick(this);
+            }
+        }
+    }
+
+    /** Callback to be invoked when the button is clicked. */
+    public interface OnButtonClickListener {
+        /**
+         * Called when a button has been clicked.
+         *
+         * @param preference the preference whose button was clicked.
+         */
+        void onButtonClick(ButtonPasswordEditTextPreference preference);
+    }
+}
diff --git a/src/com/android/car/settings/wifi/NetworkNameRestrictedPasswordEditTextPreference.java b/src/com/android/car/settings/wifi/NetworkNameRestrictedPasswordEditTextPreference.java
new file mode 100644
index 0000000..8f52152
--- /dev/null
+++ b/src/com/android/car/settings/wifi/NetworkNameRestrictedPasswordEditTextPreference.java
@@ -0,0 +1,67 @@
+/*
+ * 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.car.settings.wifi;
+
+import android.content.Context;
+import android.text.TextUtils;
+import android.util.AttributeSet;
+import android.widget.Toast;
+
+import com.android.car.settings.R;
+import com.android.car.settings.common.PasswordEditTextPreference;
+
+/**
+ * Custom {@link PasswordEditTextPreference} which doesn't open the password dialog unless the
+ * network name is provided.
+ */
+public class NetworkNameRestrictedPasswordEditTextPreference extends PasswordEditTextPreference {
+
+    private String mNetworkName;
+
+    public NetworkNameRestrictedPasswordEditTextPreference(Context context, AttributeSet attrs,
+            int defStyleAttr, int defStyleRes) {
+        super(context, attrs, defStyleAttr, defStyleRes);
+    }
+
+    public NetworkNameRestrictedPasswordEditTextPreference(Context context, AttributeSet attrs,
+            int defStyle) {
+        super(context, attrs, defStyle);
+    }
+
+    public NetworkNameRestrictedPasswordEditTextPreference(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    public NetworkNameRestrictedPasswordEditTextPreference(Context context) {
+        super(context);
+    }
+
+    /** Sets the network name. */
+    public void setNetworkName(String name) {
+        mNetworkName = name;
+    }
+
+    @Override
+    protected void onClick() {
+        if (TextUtils.isEmpty(mNetworkName)) {
+            Toast.makeText(getContext(), R.string.wifi_no_network_name, Toast.LENGTH_SHORT).show();
+            return;
+        }
+
+        super.onClick();
+    }
+}
diff --git a/src/com/android/car/settings/wifi/NetworkPasswordPreferenceController.java b/src/com/android/car/settings/wifi/NetworkPasswordPreferenceController.java
index 0b82f11..0616399 100644
--- a/src/com/android/car/settings/wifi/NetworkPasswordPreferenceController.java
+++ b/src/com/android/car/settings/wifi/NetworkPasswordPreferenceController.java
@@ -22,20 +22,18 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.text.TextUtils;
-import android.widget.Toast;
 
 import androidx.localbroadcastmanager.content.LocalBroadcastManager;
 
 import com.android.car.settings.R;
 import com.android.car.settings.common.FragmentController;
 import com.android.car.settings.common.Logger;
-import com.android.car.settings.common.PasswordEditTextPreference;
 import com.android.car.settings.common.PreferenceController;
 import com.android.settingslib.wifi.AccessPoint;
 
 /** Business logic relating to the security type and associated password. */
 public class NetworkPasswordPreferenceController extends
-        PreferenceController<PasswordEditTextPreference> {
+        PreferenceController<NetworkNameRestrictedPasswordEditTextPreference> {
 
     private static final Logger LOG = new Logger(NetworkPasswordPreferenceController.class);
 
@@ -43,6 +41,7 @@
         @Override
         public void onReceive(Context context, Intent intent) {
             mNetworkName = intent.getStringExtra(NetworkNamePreferenceController.KEY_NETWORK_NAME);
+            getPreference().setNetworkName(mNetworkName);
             refreshUi();
         }
     };
@@ -66,8 +65,8 @@
     }
 
     @Override
-    protected Class<PasswordEditTextPreference> getPreferenceType() {
-        return PasswordEditTextPreference.class;
+    protected Class<NetworkNameRestrictedPasswordEditTextPreference> getPreferenceType() {
+        return NetworkNameRestrictedPasswordEditTextPreference.class;
     }
 
     @Override
@@ -85,7 +84,7 @@
     }
 
     @Override
-    protected void updateState(PasswordEditTextPreference preference) {
+    protected void updateState(NetworkNameRestrictedPasswordEditTextPreference preference) {
         if (TextUtils.isEmpty(mNetworkName)) {
             getPreference().setDialogTitle(R.string.wifi_password);
         } else {
@@ -95,13 +94,8 @@
     }
 
     @Override
-    protected boolean handlePreferenceChanged(PasswordEditTextPreference preference,
-            Object newValue) {
-        if (TextUtils.isEmpty(mNetworkName)) {
-            Toast.makeText(getContext(), R.string.wifi_no_network_name, Toast.LENGTH_SHORT).show();
-            return true;
-        }
-
+    protected boolean handlePreferenceChanged(
+            NetworkNameRestrictedPasswordEditTextPreference preference, Object newValue) {
         String password = newValue.toString();
         int netId = WifiUtil.connectToAccessPoint(getContext(), mNetworkName, mSecurityType,
                 password, /* hidden= */ true);
diff --git a/src/com/android/car/settings/wifi/WifiUtil.java b/src/com/android/car/settings/wifi/WifiUtil.java
index 15f0134..6a33854 100644
--- a/src/com/android/car/settings/wifi/WifiUtil.java
+++ b/src/com/android/car/settings/wifi/WifiUtil.java
@@ -21,6 +21,7 @@
 import android.content.Context;
 import android.content.pm.PackageManager;
 import android.net.NetworkCapabilities;
+import android.net.NetworkInfo;
 import android.net.wifi.WifiConfiguration;
 import android.net.wifi.WifiManager;
 import android.provider.Settings;
@@ -30,6 +31,7 @@
 import androidx.annotation.StringRes;
 
 import com.android.car.settings.R;
+import com.android.car.settings.common.Logger;
 import com.android.settingslib.wifi.AccessPoint;
 
 import java.util.regex.Pattern;
@@ -39,6 +41,8 @@
  */
 public class WifiUtil {
 
+    private static final Logger LOG = new Logger(WifiUtil.class);
+
     /** Value that is returned when we fail to connect wifi. */
     public static final int INVALID_NET_ID = -1;
     private static final Pattern HEX_PATTERN = Pattern.compile("^[0-9A-F]+$");
@@ -201,7 +205,66 @@
         return netId;
     }
 
+    /** Forget the network specified by {@code accessPoint}. */
+    public static void forget(Context context, AccessPoint accessPoint) {
+        WifiManager wifiManager = context.getSystemService(WifiManager.class);
+        if (!accessPoint.isSaved()) {
+            if (accessPoint.getNetworkInfo() != null
+                    && accessPoint.getNetworkInfo().getState() != NetworkInfo.State.DISCONNECTED) {
+                // Network is active but has no network ID - must be ephemeral.
+                wifiManager.disableEphemeralNetwork(
+                        AccessPoint.convertToQuotedString(accessPoint.getSsidStr()));
+            } else {
+                // Should not happen, but a monkey seems to trigger it
+                LOG.e("Failed to forget invalid network " + accessPoint.getConfig());
+                return;
+            }
+        } else {
+            wifiManager.forget(accessPoint.getConfig().networkId,
+                    new ActionFailedListener(context, R.string.wifi_failed_forget_message));
+        }
+    }
+
+    /** Returns {@code true} if the access point was disabled due to the wrong password. */
+    public static boolean isAccessPointDisabledByWrongPassword(AccessPoint accessPoint) {
+        WifiConfiguration config = accessPoint.getConfig();
+        if (config == null) {
+            return false;
+        }
+        WifiConfiguration.NetworkSelectionStatus networkStatus =
+                config.getNetworkSelectionStatus();
+        if (networkStatus == null || networkStatus.isNetworkEnabled()) {
+            return false;
+        }
+        return networkStatus.getNetworkSelectionDisableReason()
+                == WifiConfiguration.NetworkSelectionStatus.DISABLED_BY_WRONG_PASSWORD;
+    }
+
     private static boolean isHexString(String password) {
         return HEX_PATTERN.matcher(password).matches();
     }
+
+    /**
+     * A shared implementation of {@link WifiManager.ActionListener} which shows a failure message
+     * in a toast.
+     */
+    public static class ActionFailedListener implements WifiManager.ActionListener {
+        private final Context mContext;
+        @StringRes
+        private final int mFailureMessage;
+
+        public ActionFailedListener(Context context, @StringRes int failureMessage) {
+            mContext = context;
+            mFailureMessage = failureMessage;
+        }
+
+        @Override
+        public void onSuccess() {
+        }
+
+        @Override
+        public void onFailure(int reason) {
+            Toast.makeText(mContext, mFailureMessage, Toast.LENGTH_SHORT).show();
+        }
+    }
 }
diff --git a/src/com/android/car/settings/wifi/details/WifiDetailsFragment.java b/src/com/android/car/settings/wifi/details/WifiDetailsFragment.java
index 0e49c38..9027df8 100644
--- a/src/com/android/car/settings/wifi/details/WifiDetailsFragment.java
+++ b/src/com/android/car/settings/wifi/details/WifiDetailsFragment.java
@@ -21,7 +21,6 @@
 import android.net.Network;
 import android.net.NetworkCapabilities;
 import android.net.NetworkInfo;
-import android.net.NetworkInfo.State;
 import android.net.wifi.WifiConfiguration;
 import android.net.wifi.WifiInfo;
 import android.net.wifi.WifiManager;
@@ -157,7 +156,7 @@
         mForgetButton = getActivity().findViewById(R.id.action_button1);
         mForgetButton.setText(R.string.forget);
         mForgetButton.setOnClickListener(v -> {
-            forget();
+            WifiUtil.forget(getContext(), mAccessPoint);
             goBack();
         });
     }
@@ -243,22 +242,4 @@
         LOG.d("wifiConfig is: " + wifiConfig);
         return wifiConfig != null && !WifiUtil.isNetworkLockedDown(getContext(), wifiConfig);
     }
-
-    private void forget() {
-        if (!mAccessPoint.isSaved()) {
-            if (mAccessPoint.getNetworkInfo() != null
-                    && mAccessPoint.getNetworkInfo().getState() != State.DISCONNECTED) {
-                // Network is active but has no network ID - must be ephemeral.
-                mWifiManager.disableEphemeralNetwork(
-                        AccessPoint.convertToQuotedString(mAccessPoint.getSsidStr()));
-            } else {
-                // Should not happen, but a monkey seems to trigger it
-                LOG.e("Failed to forget invalid network " + mAccessPoint.getConfig());
-                return;
-            }
-        } else {
-            mWifiManager.forget(mAccessPoint.getConfig().networkId,
-                    new ActionFailListener(R.string.wifi_failed_forget_message));
-        }
-    }
 }
diff --git a/tests/robotests/src/com/android/car/settings/bluetooth/BluetoothDevicePickerFragmentTest.java b/tests/robotests/src/com/android/car/settings/bluetooth/BluetoothDevicePickerFragmentTest.java
new file mode 100644
index 0000000..d6c877b
--- /dev/null
+++ b/tests/robotests/src/com/android/car/settings/bluetooth/BluetoothDevicePickerFragmentTest.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright 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.car.settings.bluetooth;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.app.Activity;
+import android.content.Context;
+import android.view.View;
+import android.widget.ProgressBar;
+
+import com.android.car.settings.CarSettingsRobolectricTestRunner;
+import com.android.car.settings.R;
+import com.android.car.settings.testutils.FragmentController;
+import com.android.car.settings.testutils.ShadowBluetoothAdapter;
+import com.android.car.settings.testutils.ShadowBluetoothPan;
+import com.android.settingslib.bluetooth.LocalBluetoothManager;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
+
+/** Unit test for {@link BluetoothDevicePickerFragment}. */
+@RunWith(CarSettingsRobolectricTestRunner.class)
+@Config(shadows = {ShadowBluetoothAdapter.class, ShadowBluetoothPan.class})
+public class BluetoothDevicePickerFragmentTest {
+
+    private LocalBluetoothManager mLocalBluetoothManager;
+    private FragmentController<BluetoothDevicePickerFragment> mFragmentController;
+    private BluetoothDevicePickerFragment mFragment;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        Context context = RuntimeEnvironment.application;
+        mLocalBluetoothManager = LocalBluetoothManager.getInstance(context, /* onInitCallback= */
+                null);
+
+        mFragment = new BluetoothDevicePickerFragment();
+        mFragmentController = FragmentController.of(mFragment);
+    }
+
+    @After
+    public void tearDown() {
+        ShadowBluetoothAdapter.reset();
+    }
+
+    @Test
+    public void onStart_setsBluetoothManagerForegroundActivity() {
+        mFragmentController.create().start();
+
+        assertThat(mLocalBluetoothManager.getForegroundActivity()).isEqualTo(
+                mFragment.requireActivity());
+    }
+
+    @Test
+    public void onStart_showsProgressBar() {
+        mFragmentController.create();
+        ProgressBar progressBar = findProgressBar(mFragment.requireActivity());
+        progressBar.setVisibility(View.GONE);
+
+        mFragmentController.start();
+
+        assertThat(progressBar.getVisibility()).isEqualTo(View.VISIBLE);
+    }
+
+    @Test
+    public void onStop_clearsBluetoothManagerForegroundActivity() {
+        mFragmentController.create().start().resume().pause().stop();
+
+        assertThat(mLocalBluetoothManager.getForegroundActivity()).isNull();
+    }
+
+    @Test
+    public void onStop_hidesProgressBar() {
+        mFragmentController.setup().onPause();
+        ProgressBar progressBar = findProgressBar(mFragment.requireActivity());
+        progressBar.setVisibility(View.VISIBLE);
+
+        mFragmentController.stop();
+
+        assertThat(progressBar.getVisibility()).isEqualTo(View.GONE);
+    }
+
+    private ProgressBar findProgressBar(Activity activity) {
+        return activity.findViewById(R.id.progress_bar);
+    }
+}
diff --git a/tests/robotests/src/com/android/car/settings/bluetooth/BluetoothDevicePickerPreferenceControllerTest.java b/tests/robotests/src/com/android/car/settings/bluetooth/BluetoothDevicePickerPreferenceControllerTest.java
new file mode 100644
index 0000000..1c4934a4
--- /dev/null
+++ b/tests/robotests/src/com/android/car/settings/bluetooth/BluetoothDevicePickerPreferenceControllerTest.java
@@ -0,0 +1,311 @@
+/*
+ * Copyright 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.car.settings.bluetooth;
+
+import static android.content.pm.PackageManager.FEATURE_BLUETOOTH;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import static org.testng.Assert.assertThrows;
+
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothDevicePicker;
+import android.bluetooth.BluetoothUuid;
+import android.car.userlib.CarUserManagerHelper;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.os.ParcelUuid;
+
+import androidx.lifecycle.Lifecycle;
+import androidx.preference.PreferenceGroup;
+
+import com.android.car.settings.CarSettingsRobolectricTestRunner;
+import com.android.car.settings.common.LogicalPreferenceGroup;
+import com.android.car.settings.common.PreferenceControllerTestHelper;
+import com.android.car.settings.testutils.ShadowBluetoothAdapter;
+import com.android.car.settings.testutils.ShadowBluetoothPan;
+import com.android.car.settings.testutils.ShadowCarUserManagerHelper;
+import com.android.settingslib.bluetooth.CachedBluetoothDevice;
+import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager;
+import com.android.settingslib.bluetooth.LocalBluetoothManager;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.Shadows;
+import org.robolectric.annotation.Config;
+import org.robolectric.shadow.api.Shadow;
+import org.robolectric.shadows.ShadowApplication;
+import org.robolectric.util.ReflectionHelpers;
+
+import java.util.Arrays;
+
+/** Unit test for {@link BluetoothDevicePickerPreferenceController}. */
+@RunWith(CarSettingsRobolectricTestRunner.class)
+@Config(shadows = {ShadowCarUserManagerHelper.class, ShadowBluetoothAdapter.class,
+        ShadowBluetoothPan.class})
+public class BluetoothDevicePickerPreferenceControllerTest {
+
+    @Mock
+    private CarUserManagerHelper mCarUserManagerHelper;
+    @Mock
+    private CachedBluetoothDevice mUnbondedCachedDevice;
+    @Mock
+    private BluetoothDevice mUnbondedDevice;
+    @Mock
+    private CachedBluetoothDevice mBondedCachedDevice;
+    @Mock
+    private BluetoothDevice mBondedDevice;
+    @Mock
+    private CachedBluetoothDeviceManager mCachedDeviceManager;
+    private CachedBluetoothDeviceManager mSaveRealCachedDeviceManager;
+    private LocalBluetoothManager mLocalBluetoothManager;
+    private PreferenceGroup mPreferenceGroup;
+    private PreferenceControllerTestHelper<BluetoothDevicePickerPreferenceController>
+            mControllerHelper;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        ShadowCarUserManagerHelper.setMockInstance(mCarUserManagerHelper);
+        Context context = RuntimeEnvironment.application;
+
+        mLocalBluetoothManager = LocalBluetoothManager.getInstance(context, /* onInitCallback= */
+                null);
+        mSaveRealCachedDeviceManager = mLocalBluetoothManager.getCachedDeviceManager();
+        ReflectionHelpers.setField(mLocalBluetoothManager, "mCachedDeviceManager",
+                mCachedDeviceManager);
+
+        when(mUnbondedDevice.getBondState()).thenReturn(BluetoothDevice.BOND_NONE);
+        when(mUnbondedCachedDevice.getBondState()).thenReturn(BluetoothDevice.BOND_NONE);
+        when(mUnbondedCachedDevice.getDevice()).thenReturn(mUnbondedDevice);
+        when(mBondedDevice.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
+        when(mBondedCachedDevice.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
+        when(mBondedCachedDevice.getDevice()).thenReturn(mBondedDevice);
+        when(mCachedDeviceManager.getCachedDevicesCopy()).thenReturn(
+                Arrays.asList(mUnbondedCachedDevice, mBondedCachedDevice));
+        // Make bonded device appear first in the list.
+        when(mBondedCachedDevice.compareTo(mUnbondedCachedDevice)).thenReturn(-1);
+        when(mUnbondedCachedDevice.compareTo(mBondedCachedDevice)).thenReturn(1);
+
+        // Make sure controller is available.
+        Shadows.shadowOf(context.getPackageManager()).setSystemFeature(
+                FEATURE_BLUETOOTH, /* supported= */ true);
+        BluetoothAdapter.getDefaultAdapter().enable();
+        getShadowBluetoothAdapter().setState(BluetoothAdapter.STATE_ON);
+
+        mPreferenceGroup = new LogicalPreferenceGroup(context);
+        mControllerHelper = new PreferenceControllerTestHelper<>(context,
+                BluetoothDevicePickerPreferenceController.class);
+    }
+
+    @After
+    public void tearDown() {
+        ShadowCarUserManagerHelper.reset();
+        ShadowBluetoothAdapter.reset();
+        ReflectionHelpers.setField(mLocalBluetoothManager, "mCachedDeviceManager",
+                mSaveRealCachedDeviceManager);
+    }
+
+    @Test
+    public void checkInitialized_noLaunchIntentSet_throwsIllegalStateException() {
+        assertThrows(IllegalStateException.class,
+                () -> mControllerHelper.setPreference(mPreferenceGroup));
+    }
+
+    @Test
+    public void onStart_appliesFilterType() {
+        // Setup device to pass the filter.
+        when(mBondedDevice.getUuids()).thenReturn(new ParcelUuid[]{BluetoothUuid.AudioSink});
+        Intent launchIntent = createLaunchIntent(/* needsAuth= */ false,
+                BluetoothDevicePicker.FILTER_TYPE_AUDIO, "test.package", "TestClass");
+        mControllerHelper.getController().setLaunchIntent(launchIntent);
+        mControllerHelper.setPreference(mPreferenceGroup);
+
+        mControllerHelper.sendLifecycleEvent(Lifecycle.Event.ON_START);
+
+        assertThat(mPreferenceGroup.getPreferenceCount()).isEqualTo(1);
+        assertThat(((BluetoothDevicePreference) mPreferenceGroup.getPreference(
+                0)).getCachedDevice()).isEqualTo(mBondedCachedDevice);
+    }
+
+    @Test
+    public void onDeviceClicked_bondedDevice_sendsPickedIntent() {
+        ComponentName component = new ComponentName("test.package", "TestClass");
+        Intent launchIntent = createLaunchIntent(/* needsAuth= */ true,
+                BluetoothDevicePicker.FILTER_TYPE_ALL, component.getPackageName(),
+                component.getClassName());
+        mControllerHelper.getController().setLaunchIntent(launchIntent);
+        mControllerHelper.setPreference(mPreferenceGroup);
+        mControllerHelper.markState(Lifecycle.State.STARTED);
+        BluetoothDevicePreference devicePreference =
+                (BluetoothDevicePreference) mPreferenceGroup.getPreference(0);
+
+        devicePreference.performClick();
+
+        assertThat(ShadowApplication.getInstance().getBroadcastIntents()).hasSize(1);
+        Intent pickedIntent = ShadowApplication.getInstance().getBroadcastIntents().get(0);
+        assertThat(pickedIntent.getAction()).isEqualTo(
+                BluetoothDevicePicker.ACTION_DEVICE_SELECTED);
+        assertThat(pickedIntent.getComponent()).isEqualTo(component);
+        assertThat((BluetoothDevice) pickedIntent.getParcelableExtra(
+                BluetoothDevice.EXTRA_DEVICE)).isEqualTo(mBondedDevice);
+    }
+
+    @Test
+    public void onDeviceClicked_bondedDevice_goesBack() {
+        Intent launchIntent = createLaunchIntent(/* needsAuth= */ true,
+                BluetoothDevicePicker.FILTER_TYPE_ALL, "test.package", "TestClass");
+        mControllerHelper.getController().setLaunchIntent(launchIntent);
+        mControllerHelper.setPreference(mPreferenceGroup);
+        mControllerHelper.markState(Lifecycle.State.STARTED);
+        BluetoothDevicePreference devicePreference =
+                (BluetoothDevicePreference) mPreferenceGroup.getPreference(0);
+
+        devicePreference.performClick();
+
+        verify(mControllerHelper.getMockFragmentController()).goBack();
+    }
+
+    @Test
+    public void onDeviceClicked_unbondedDevice_doesNotNeedAuth_sendsPickedIntent() {
+        Intent launchIntent = createLaunchIntent(/* needsAuth= */ false,
+                BluetoothDevicePicker.FILTER_TYPE_ALL, "test.package", "TestClass");
+        mControllerHelper.getController().setLaunchIntent(launchIntent);
+        mControllerHelper.setPreference(mPreferenceGroup);
+        mControllerHelper.markState(Lifecycle.State.STARTED);
+        BluetoothDevicePreference devicePreference =
+                (BluetoothDevicePreference) mPreferenceGroup.getPreference(1);
+
+        devicePreference.performClick();
+
+        Intent pickedIntent = ShadowApplication.getInstance().getBroadcastIntents().get(0);
+        assertThat(pickedIntent.getAction()).isEqualTo(
+                BluetoothDevicePicker.ACTION_DEVICE_SELECTED);
+    }
+
+    @Test
+    public void onDeviceClicked_unbondedDevice_needsAuth_startsPairing() {
+        Intent launchIntent = createLaunchIntent(/* needsAuth= */ true,
+                BluetoothDevicePicker.FILTER_TYPE_ALL, "test.package", "TestClass");
+        mControllerHelper.getController().setLaunchIntent(launchIntent);
+        mControllerHelper.setPreference(mPreferenceGroup);
+        mControllerHelper.markState(Lifecycle.State.STARTED);
+        BluetoothDevicePreference devicePreference =
+                (BluetoothDevicePreference) mPreferenceGroup.getPreference(1);
+
+        devicePreference.performClick();
+
+        verify(mUnbondedCachedDevice).startPairing();
+    }
+
+    @Test
+    public void onDeviceClicked_unbondedDevice_needsAuth_pairingStartFails_resumesScanning() {
+        Intent launchIntent = createLaunchIntent(/* needsAuth= */ true,
+                BluetoothDevicePicker.FILTER_TYPE_ALL, "test.package", "TestClass");
+        mControllerHelper.getController().setLaunchIntent(launchIntent);
+        mControllerHelper.setPreference(mPreferenceGroup);
+        mControllerHelper.markState(Lifecycle.State.STARTED);
+        BluetoothDevicePreference devicePreference =
+                (BluetoothDevicePreference) mPreferenceGroup.getPreference(1);
+        when(mUnbondedCachedDevice.startPairing()).thenReturn(false);
+        assertThat(BluetoothAdapter.getDefaultAdapter().isDiscovering()).isTrue();
+
+        devicePreference.performClick();
+
+        assertThat(BluetoothAdapter.getDefaultAdapter().isDiscovering()).isTrue();
+    }
+
+    @Test
+    public void onDeviceBondStateChanged_selectedDeviceBonded_sendsPickedIntent() {
+        Intent launchIntent = createLaunchIntent(/* needsAuth= */ true,
+                BluetoothDevicePicker.FILTER_TYPE_ALL, "test.package", "TestClass");
+        mControllerHelper.getController().setLaunchIntent(launchIntent);
+        mControllerHelper.setPreference(mPreferenceGroup);
+        mControllerHelper.markState(Lifecycle.State.STARTED);
+        BluetoothDevicePreference devicePreference =
+                (BluetoothDevicePreference) mPreferenceGroup.getPreference(1);
+
+        // Select device.
+        devicePreference.performClick();
+        // Device bonds.
+        mControllerHelper.getController().onDeviceBondStateChanged(
+                devicePreference.getCachedDevice(), BluetoothDevice.BOND_BONDED);
+
+        Intent pickedIntent = ShadowApplication.getInstance().getBroadcastIntents().get(0);
+        assertThat(pickedIntent.getAction()).isEqualTo(
+                BluetoothDevicePicker.ACTION_DEVICE_SELECTED);
+    }
+
+    @Test
+    public void onDeviceBondStateChanged_selectedDeviceBonded_goesBack() {
+        Intent launchIntent = createLaunchIntent(/* needsAuth= */ true,
+                BluetoothDevicePicker.FILTER_TYPE_ALL, "test.package", "TestClass");
+        mControllerHelper.getController().setLaunchIntent(launchIntent);
+        mControllerHelper.setPreference(mPreferenceGroup);
+        mControllerHelper.markState(Lifecycle.State.STARTED);
+        BluetoothDevicePreference devicePreference =
+                (BluetoothDevicePreference) mPreferenceGroup.getPreference(1);
+
+        // Select device.
+        devicePreference.performClick();
+        // Device bonds.
+        mControllerHelper.getController().onDeviceBondStateChanged(
+                devicePreference.getCachedDevice(), BluetoothDevice.BOND_BONDED);
+
+        verify(mControllerHelper.getMockFragmentController()).goBack();
+    }
+
+    @Test
+    public void onDestroy_noDeviceSelected_sendsNullPickedIntent() {
+        Intent launchIntent = createLaunchIntent(/* needsAuth= */ true,
+                BluetoothDevicePicker.FILTER_TYPE_ALL, "test.package", "TestClass");
+        mControllerHelper.getController().setLaunchIntent(launchIntent);
+        mControllerHelper.setPreference(mPreferenceGroup);
+        mControllerHelper.markState(Lifecycle.State.STARTED);
+
+        mControllerHelper.sendLifecycleEvent(Lifecycle.Event.ON_DESTROY);
+
+        Intent pickedIntent = ShadowApplication.getInstance().getBroadcastIntents().get(0);
+        assertThat(pickedIntent.getAction()).isEqualTo(
+                BluetoothDevicePicker.ACTION_DEVICE_SELECTED);
+        assertThat((BluetoothDevice) pickedIntent.getParcelableExtra(
+                BluetoothDevice.EXTRA_DEVICE)).isNull();
+    }
+
+    private Intent createLaunchIntent(boolean needAuth, int filterType, String packageName,
+            String className) {
+        Intent intent = new Intent(BluetoothDevicePicker.ACTION_LAUNCH);
+        intent.putExtra(BluetoothDevicePicker.EXTRA_NEED_AUTH, needAuth);
+        intent.putExtra(BluetoothDevicePicker.EXTRA_FILTER_TYPE, filterType);
+        intent.putExtra(BluetoothDevicePicker.EXTRA_LAUNCH_PACKAGE, packageName);
+        intent.putExtra(BluetoothDevicePicker.EXTRA_LAUNCH_CLASS, className);
+        return intent;
+    }
+
+    private ShadowBluetoothAdapter getShadowBluetoothAdapter() {
+        return (ShadowBluetoothAdapter) Shadow.extract(BluetoothAdapter.getDefaultAdapter());
+    }
+}
diff --git a/tests/robotests/src/com/android/car/settings/common/BaseCarSettingsActivityTest.java b/tests/robotests/src/com/android/car/settings/common/BaseCarSettingsActivityTest.java
index a763b80..8bae4a1 100644
--- a/tests/robotests/src/com/android/car/settings/common/BaseCarSettingsActivityTest.java
+++ b/tests/robotests/src/com/android/car/settings/common/BaseCarSettingsActivityTest.java
@@ -69,7 +69,7 @@
         mContext = RuntimeEnvironment.application;
         mActivityController = ActivityController.of(new TestBaseCarSettingsActivity());
         mActivity = mActivityController.get();
-        mActivityController.create();
+        mActivityController.setup();
     }
 
     @Test
diff --git a/tests/robotests/src/com/android/car/settings/common/FakePreferenceController.java b/tests/robotests/src/com/android/car/settings/common/FakePreferenceController.java
index c8893cd..0762f26 100644
--- a/tests/robotests/src/com/android/car/settings/common/FakePreferenceController.java
+++ b/tests/robotests/src/com/android/car/settings/common/FakePreferenceController.java
@@ -21,6 +21,9 @@
 
 import androidx.preference.Preference;
 
+import java.util.HashSet;
+import java.util.Set;
+
 /**
  * Concrete {@link PreferenceController} with methods for verifying behavior in tests.
  */
@@ -42,6 +45,8 @@
     private Object mHandlePreferenceChangedValueArg;
     private int mHandlePreferenceClickedCallCount;
     private Preference mHandlePreferenceClickedArg;
+    private boolean mAllIgnoresUxRestrictions = false;
+    private Set<String> mPreferencesIgnoringUxRestrictions = new HashSet<>();
 
     public FakePreferenceController(Context context, String preferenceKey,
             FragmentController fragmentController, CarUxRestrictions uxRestrictions) {
@@ -175,4 +180,16 @@
     Preference getHandlePreferenceClickedArg() {
         return mHandlePreferenceClickedArg;
     }
+
+    @Override
+    protected boolean isUxRestrictionsIgnored(boolean allIgnores, Set preferencesThatIgnore) {
+        return super.isUxRestrictionsIgnored(mAllIgnoresUxRestrictions,
+                mPreferencesIgnoringUxRestrictions);
+    }
+
+    protected void setUxRestrictionsIgnoredConfig(boolean allIgnore, Set preferencesThatIgnore) {
+        mAllIgnoresUxRestrictions = allIgnore;
+        mPreferencesIgnoringUxRestrictions = preferencesThatIgnore;
+    }
+
 }
diff --git a/tests/robotests/src/com/android/car/settings/common/PreferenceControllerTest.java b/tests/robotests/src/com/android/car/settings/common/PreferenceControllerTest.java
index 3c1cef3..b51db10 100644
--- a/tests/robotests/src/com/android/car/settings/common/PreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/car/settings/common/PreferenceControllerTest.java
@@ -47,6 +47,9 @@
 import org.mockito.MockitoAnnotations;
 import org.robolectric.RuntimeEnvironment;
 
+import java.util.HashSet;
+import java.util.Set;
+
 /**
  * Unit test for {@link PreferenceController}.
  */
@@ -65,11 +68,12 @@
             new CarUxRestrictions.Builder(/* reqOpt= */ true,
                     CarUxRestrictions.UX_RESTRICTIONS_BASELINE, /* timestamp= */ 0).build();
 
-    private Context mContext;
-    @Mock
-    private Preference mPreference;
     private PreferenceControllerTestHelper<FakePreferenceController> mControllerHelper;
     private FakePreferenceController mController;
+    private Context mContext;
+
+    @Mock
+    private Preference mPreference;
 
     @Before
     public void setUp() {
@@ -177,6 +181,58 @@
     }
 
     @Test
+    public void onUxRestrictionsChanged_restricted_allPreferencesIgnore_preferenceEnabled() {
+        // mPreference cannot be a Mock here because its real methods need to be invoked.
+        mPreference = new Preference(mContext);
+        mControllerHelper = new PreferenceControllerTestHelper<>(mContext,
+                FakePreferenceController.class, mPreference);
+        mController = mControllerHelper.getController();
+
+        Set preferencesIgnoringUxRestrictions = new HashSet();
+        mController.setUxRestrictionsIgnoredConfig(/* allIgnores= */ true,
+                preferencesIgnoringUxRestrictions);
+        mControllerHelper.markState(Lifecycle.State.CREATED);
+        mController.onUxRestrictionsChanged(NO_SETUP_UX_RESTRICTIONS);
+
+        assertThat(mPreference.isEnabled()).isTrue();
+    }
+
+    @Test
+    public void onUxRestrictionsChanged_restricted_thisPreferenceIgnores_preferenceEnabled() {
+        // mPreference cannot be a Mock here because its real methods need to be invoked.
+        mPreference = new Preference(mContext);
+        mControllerHelper = new PreferenceControllerTestHelper<>(mContext,
+                FakePreferenceController.class, mPreference);
+        mController = mControllerHelper.getController();
+
+        Set preferencesIgnoringUxRestrictions = new HashSet();
+        preferencesIgnoringUxRestrictions.add(PreferenceControllerTestHelper.getKey());
+        mController.setUxRestrictionsIgnoredConfig(/* allIgnores= */ false,
+                preferencesIgnoringUxRestrictions);
+        mControllerHelper.markState(Lifecycle.State.CREATED);
+        mController.onUxRestrictionsChanged(NO_SETUP_UX_RESTRICTIONS);
+
+        assertThat(mPreference.isEnabled()).isTrue();
+    }
+
+    @Test
+    public void onUxRestrictionsChanged_restricted_uxRestrictionsNotIgnored_preferenceDisabled() {
+        // mPreference cannot be a Mock here because its real methods need to be invoked.
+        mPreference = new Preference(mContext);
+        mControllerHelper = new PreferenceControllerTestHelper<>(mContext,
+                FakePreferenceController.class, mPreference);
+        mController = mControllerHelper.getController();
+
+        Set preferencesIgnoringUxRestrictions = new HashSet();
+        mController.setUxRestrictionsIgnoredConfig(/* allIgnores= */ false,
+                preferencesIgnoringUxRestrictions);
+        mControllerHelper.markState(Lifecycle.State.CREATED);
+        mController.onUxRestrictionsChanged(NO_SETUP_UX_RESTRICTIONS);
+
+        assertThat(mPreference.isEnabled()).isFalse();
+    }
+
+    @Test
     public void getAvailabilityStatus_defaultsToAvailable() {
         assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE);
     }
diff --git a/tests/robotests/src/com/android/car/settings/common/PreferenceControllerTestHelper.java b/tests/robotests/src/com/android/car/settings/common/PreferenceControllerTestHelper.java
index 96ee562..3ed36af 100644
--- a/tests/robotests/src/com/android/car/settings/common/PreferenceControllerTestHelper.java
+++ b/tests/robotests/src/com/android/car/settings/common/PreferenceControllerTestHelper.java
@@ -50,6 +50,7 @@
 public class PreferenceControllerTestHelper<T extends PreferenceController> {
 
     private static final String PREFERENCE_KEY = "preference_key";
+
     private static final CarUxRestrictions UX_RESTRICTIONS =
             new CarUxRestrictions.Builder(/* reqOpt= */ true,
                     CarUxRestrictions.UX_RESTRICTIONS_BASELINE, /* timestamp= */ 0).build();
@@ -150,6 +151,10 @@
         }
     }
 
+    public static String getKey() {
+        return PREFERENCE_KEY;
+    }
+
     /*
      * Ideally we would use androidx.lifecycle.LifecycleRegistry to drive the lifecycle changes.
      * However, doing so led to test flakiness with an unknown root cause. We dispatch state
diff --git a/tests/robotests/src/com/android/car/settings/testutils/ShadowWifiManager.java b/tests/robotests/src/com/android/car/settings/testutils/ShadowWifiManager.java
index 43c0710..77a8703 100644
--- a/tests/robotests/src/com/android/car/settings/testutils/ShadowWifiManager.java
+++ b/tests/robotests/src/com/android/car/settings/testutils/ShadowWifiManager.java
@@ -34,6 +34,7 @@
 
     private final Map<Integer, WifiConfiguration> mNetworkIdToConfiguredNetworks =
             new LinkedHashMap<>();
+    private int mLastForgottenNetwork = Integer.MIN_VALUE;
 
     @Implementation
     @Override
@@ -57,6 +58,15 @@
     }
 
     @Implementation
+    protected void forget(int netId, WifiManager.ActionListener listener) {
+        mLastForgottenNetwork = netId;
+    }
+
+    public int getLastForgottenNetwork() {
+        return mLastForgottenNetwork;
+    }
+
+    @Implementation
     protected void factoryReset() {
         sResetCalledCount++;
     }
diff --git a/tests/robotests/src/com/android/car/settings/wifi/AccessPointListPreferenceControllerTest.java b/tests/robotests/src/com/android/car/settings/wifi/AccessPointListPreferenceControllerTest.java
index f8cc53a..7ecf4ae 100644
--- a/tests/robotests/src/com/android/car/settings/wifi/AccessPointListPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/car/settings/wifi/AccessPointListPreferenceControllerTest.java
@@ -20,6 +20,7 @@
 
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
@@ -179,6 +180,33 @@
     }
 
     @Test
+    public void performButtonClick_savedAccessPoint_wrongPassword_forgetsNetwork() {
+        int netId = 1;
+
+        WifiConfiguration config = mock(WifiConfiguration.class);
+        WifiConfiguration.NetworkSelectionStatus status = mock(
+                WifiConfiguration.NetworkSelectionStatus.class);
+        config.networkId = netId;
+        when(mMockAccessPoint1.getSecurity()).thenReturn(AccessPoint.SECURITY_PSK);
+        when(mMockAccessPoint1.isSaved()).thenReturn(true);
+        when(mMockAccessPoint1.getConfig()).thenReturn(config);
+        when(config.getNetworkSelectionStatus()).thenReturn(status);
+        when(status.isNetworkEnabled()).thenReturn(false);
+        when(status.getNetworkSelectionDisableReason()).thenReturn(
+                WifiConfiguration.NetworkSelectionStatus.DISABLED_BY_WRONG_PASSWORD);
+
+        List<AccessPoint> accessPointList = Arrays.asList(mMockAccessPoint1);
+        when(mMockCarWifiManager.getAllAccessPoints()).thenReturn(accessPointList);
+        mController.refreshUi();
+
+        ButtonPasswordEditTextPreference preference =
+                (ButtonPasswordEditTextPreference) mPreferenceGroup.getPreference(0);
+        preference.performButtonClick();
+
+        assertThat(getShadowWifiManager().getLastForgottenNetwork()).isEqualTo(netId);
+    }
+
+    @Test
     public void callChangeListener_newSecureAccessPoint_wifiAdded() {
         String ssid = "test_ssid";
         String password = "test_password";
diff --git a/tests/robotests/src/com/android/car/settings/wifi/ButtonPasswordEditTextPreferenceTest.java b/tests/robotests/src/com/android/car/settings/wifi/ButtonPasswordEditTextPreferenceTest.java
new file mode 100644
index 0000000..4ed3a57
--- /dev/null
+++ b/tests/robotests/src/com/android/car/settings/wifi/ButtonPasswordEditTextPreferenceTest.java
@@ -0,0 +1,82 @@
+/*
+ * 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.car.settings.wifi;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+
+import android.view.View;
+
+import androidx.preference.PreferenceViewHolder;
+
+import com.android.car.settings.CarSettingsRobolectricTestRunner;
+import com.android.car.settings.R;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RuntimeEnvironment;
+
+@RunWith(CarSettingsRobolectricTestRunner.class)
+public class ButtonPasswordEditTextPreferenceTest {
+
+    private PreferenceViewHolder mViewHolder;
+    private ButtonPasswordEditTextPreference mButtonPreference;
+
+    @Before
+    public void setUp() {
+        View rootView = View.inflate(RuntimeEnvironment.application, R.layout.two_action_preference,
+                null);
+        mViewHolder = PreferenceViewHolder.createInstanceForTests(rootView);
+        mButtonPreference = new ButtonPasswordEditTextPreference(RuntimeEnvironment.application);
+    }
+
+    @Test
+    public void buttonClicked_callsListener() {
+        mButtonPreference.onBindViewHolder(mViewHolder);
+        ButtonPasswordEditTextPreference.OnButtonClickListener listener = mock(
+                ButtonPasswordEditTextPreference.OnButtonClickListener.class);
+        mButtonPreference.setOnButtonClickListener(listener);
+
+        mViewHolder.findViewById(android.R.id.widget_frame).performClick();
+
+        verify(listener).onButtonClick(mButtonPreference);
+    }
+
+    @Test
+    public void performButtonClick_listenerSetAndButtonVisible_listenerFired() {
+        ButtonPasswordEditTextPreference.OnButtonClickListener listener = mock(
+                ButtonPasswordEditTextPreference.OnButtonClickListener.class);
+        mButtonPreference.setOnButtonClickListener(listener);
+        mButtonPreference.showButton(true);
+
+        mButtonPreference.performButtonClick();
+        verify(listener).onButtonClick(mButtonPreference);
+    }
+
+    @Test
+    public void performButtonClick_listenerSetAndButtonInvisible_listenerNotFired() {
+        ButtonPasswordEditTextPreference.OnButtonClickListener listener = mock(
+                ButtonPasswordEditTextPreference.OnButtonClickListener.class);
+        mButtonPreference.setOnButtonClickListener(listener);
+        mButtonPreference.showButton(false);
+
+        mButtonPreference.performButtonClick();
+        verify(listener, never()).onButtonClick(mButtonPreference);
+    }
+}
diff --git a/tests/robotests/src/com/android/car/settings/wifi/NetworkNameRestrictedPasswordEditTextPreferenceTest.java b/tests/robotests/src/com/android/car/settings/wifi/NetworkNameRestrictedPasswordEditTextPreferenceTest.java
new file mode 100644
index 0000000..cbcef40
--- /dev/null
+++ b/tests/robotests/src/com/android/car/settings/wifi/NetworkNameRestrictedPasswordEditTextPreferenceTest.java
@@ -0,0 +1,79 @@
+/*
+ * 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.car.settings.wifi;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.content.Context;
+
+import com.android.car.settings.CarSettingsRobolectricTestRunner;
+import com.android.car.settings.R;
+import com.android.car.settings.common.SettingsFragment;
+import com.android.car.settings.testutils.FragmentController;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.shadows.ShadowDialog;
+import org.robolectric.shadows.ShadowToast;
+
+@RunWith(CarSettingsRobolectricTestRunner.class)
+public class NetworkNameRestrictedPasswordEditTextPreferenceTest {
+
+    private static final String KEY = "test_key";
+
+    private Context mContext;
+    private NetworkNameRestrictedPasswordEditTextPreference mPreference;
+
+    @Before
+    public void setUp() {
+        mContext = RuntimeEnvironment.application;
+        FragmentController<TestSettingsFragment> fragmentController = FragmentController.of(
+                new TestSettingsFragment());
+        TestSettingsFragment fragment = fragmentController.get();
+        fragmentController.setup();
+
+        mPreference = new NetworkNameRestrictedPasswordEditTextPreference(mContext);
+        mPreference.setKey(KEY);
+        fragment.getPreferenceScreen().addPreference(mPreference);
+    }
+
+    @Test
+    public void performClick_noName_toastShown() {
+        mPreference.performClick();
+
+        assertThat(ShadowToast.getTextOfLatestToast()).isEqualTo(
+                mContext.getString(R.string.wifi_no_network_name));
+    }
+
+    @Test
+    public void performClick_hasName_showsDialog() {
+        mPreference.setNetworkName("test_name");
+        mPreference.performClick();
+
+        assertThat(ShadowDialog.getLatestDialog()).isNotNull();
+    }
+
+    /** Concrete {@link SettingsFragment} for testing. */
+    public static class TestSettingsFragment extends SettingsFragment {
+        @Override
+        protected int getPreferenceScreenResId() {
+            return R.xml.settings_fragment;
+        }
+    }
+}
diff --git a/tests/robotests/src/com/android/car/settings/wifi/NetworkPasswordPreferenceControllerTest.java b/tests/robotests/src/com/android/car/settings/wifi/NetworkPasswordPreferenceControllerTest.java
index fc14fa9..28b555a 100644
--- a/tests/robotests/src/com/android/car/settings/wifi/NetworkPasswordPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/car/settings/wifi/NetworkPasswordPreferenceControllerTest.java
@@ -29,7 +29,6 @@
 
 import com.android.car.settings.CarSettingsRobolectricTestRunner;
 import com.android.car.settings.R;
-import com.android.car.settings.common.PasswordEditTextPreference;
 import com.android.car.settings.common.PreferenceControllerTestHelper;
 import com.android.car.settings.testutils.ShadowLocalBroadcastManager;
 import com.android.car.settings.testutils.ShadowWifiManager;
@@ -42,7 +41,6 @@
 import org.robolectric.RuntimeEnvironment;
 import org.robolectric.annotation.Config;
 import org.robolectric.shadow.api.Shadow;
-import org.robolectric.shadows.ShadowToast;
 
 import java.util.List;
 
@@ -52,7 +50,7 @@
 
     private Context mContext;
     private LocalBroadcastManager mLocalBroadcastManager;
-    private PasswordEditTextPreference mPasswordEditTextPreference;
+    private NetworkNameRestrictedPasswordEditTextPreference mPasswordEditTextPreference;
     private PreferenceControllerTestHelper<NetworkPasswordPreferenceController>
             mPreferenceControllerHelper;
     private NetworkPasswordPreferenceController mController;
@@ -61,7 +59,7 @@
     public void setUp() {
         mContext = RuntimeEnvironment.application;
         mLocalBroadcastManager = LocalBroadcastManager.getInstance(mContext);
-        mPasswordEditTextPreference = new PasswordEditTextPreference(mContext);
+        mPasswordEditTextPreference = new NetworkNameRestrictedPasswordEditTextPreference(mContext);
         mPreferenceControllerHelper = new PreferenceControllerTestHelper<>(mContext,
                 NetworkPasswordPreferenceController.class, mPasswordEditTextPreference);
         mController = mPreferenceControllerHelper.getController();
@@ -152,23 +150,6 @@
     }
 
     @Test
-    public void handlePreferenceChanged_hasSecurity_noNetworkNameSet_showToast() {
-        mPreferenceControllerHelper.sendLifecycleEvent(Lifecycle.Event.ON_START);
-        Intent intent = new Intent(NetworkSecurityPreferenceController.ACTION_SECURITY_CHANGE);
-        intent.putExtra(NetworkSecurityPreferenceController.KEY_SECURITY_TYPE,
-                AccessPoint.SECURITY_PSK);
-        mLocalBroadcastManager.sendBroadcastSync(intent);
-
-        intent = new Intent(NetworkNamePreferenceController.ACTION_NAME_CHANGE);
-        intent.putExtra(NetworkNamePreferenceController.KEY_NETWORK_NAME, "");
-        mLocalBroadcastManager.sendBroadcastSync(intent);
-
-        mPasswordEditTextPreference.callChangeListener("password");
-        assertThat(ShadowToast.getTextOfLatestToast()).isEqualTo(
-                mContext.getString(R.string.wifi_no_network_name));
-    }
-
-    @Test
     public void handlePreferenceChanged_hasSecurity_networkNameSet_wifiAdded() {
         mPreferenceControllerHelper.sendLifecycleEvent(Lifecycle.Event.ON_START);
         String networkName = "network_name";