Merge "Make homepage icons more colorful!"
diff --git a/res/layout/suggestion_container.xml b/res/layout/suggestion_container.xml
index e01a590..9110c58 100644
--- a/res/layout/suggestion_container.xml
+++ b/res/layout/suggestion_container.xml
@@ -20,7 +20,7 @@
     style="@style/SuggestionConditionStyle"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
-    android:paddingTop="20dp"
+    android:paddingTop="12dp"
     android:orientation="vertical">
 
     <LinearLayout
@@ -55,7 +55,7 @@
         android:id="@+id/suggestion_list"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
-        android:paddingTop="20dp"
+        android:paddingTop="18dp"
         android:paddingBottom="16dp"
         android:scrollbars="none"/>
 
diff --git a/res/layout/suggestion_tile_v2.xml b/res/layout/suggestion_tile_v2.xml
index 2164465..e04febb 100644
--- a/res/layout/suggestion_tile_v2.xml
+++ b/res/layout/suggestion_tile_v2.xml
@@ -20,6 +20,7 @@
     android:id="@+id/suggestion_card"
     android:layout_width="328dp"
     android:layout_height="wrap_content"
+    app:cardPreventCornerOverlap="false"
     app:cardUseCompatPadding="true"
     app:cardElevation="2dp"
     app:cardCornerRadius="@dimen/suggestion_card_corner_radius">
@@ -45,8 +46,9 @@
 
             <ImageView
                 android:id="@+id/close_button"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
+                android:layout_width="18dp"
+                android:layout_height="18dp"
+                android:alpha="0.54"
                 android:layout_alignParentEnd="true"
                 android:layout_marginTop="8dp"
                 android:layout_marginEnd="8dp"
@@ -62,7 +64,7 @@
             android:layout_marginStart="12dp"
             android:layout_marginEnd="12dp"
             android:singleLine="true"
-            android:textAppearance="@style/TextAppearance.TileTitle"
+            android:textAppearance="@style/TextAppearance.SuggestionTitleV2"
             android:ellipsize="marquee"
             android:fadingEdge="horizontal" />
 
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 1fc8e41..043196d 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -3228,7 +3228,7 @@
     <!-- SD card & phone storage settings screen, title for the checkbox to let user decide whether erase eSIM data together [CHAR LIMIT=NONE] -->
     <string name="reset_esim_title">Also reset eSIMs</string>
     <!-- SD card & phone storage settings screen, message for the checkbox to let user decide whether erase eSIM data together [CHAR LIMIT=NONE] -->
-    <string name="reset_esim_desc">Erase all eSIMs on the phone. You\u2019ll have to contract your carrier to redownload your eSIMs. This will not cancel your mobile service plan.</string>
+    <string name="reset_esim_desc">Erase all eSIMs on the phone. You\u2019ll have to contact your carrier to redownload your eSIMs. This will not cancel your mobile service plan.</string>
     <!-- SD card & phone storage settings screen, button on screen after user selects Reset network settings -->
     <string name="reset_network_button_text">Reset settings</string>
     <!-- SD card & phone storage settings screen, message on screen after user selects Reset settings button -->
diff --git a/res/values/styles.xml b/res/values/styles.xml
index 7764e74..b672247 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -318,7 +318,7 @@
 
     <style name="TextAppearance.SuggestionHeader"
            parent="@android:style/TextAppearance.Material.Subhead">
-        <item name="android:fontFamily">sans-serif-medium</item>
+        <item name="android:fontFamily">@config/config_headlineFontFamilyMedium</item>
         <item name="android:textSize">14sp</item>
         <item name="android:textColor">?android:attr/colorAccent</item>
     </style>
@@ -337,6 +337,11 @@
         <item name="android:fontFamily">sans-serif-medium</item>
     </style>
 
+    <style name="TextAppearance.SuggestionTitleV2"
+           parent="@android:style/TextAppearance.Material.Subhead">
+        <item name="android:fontFamily">@config/config_headlineFontFamily</item>
+    </style>
+
     <style name="TextAppearance.SuggestionSummary" parent="TextAppearance.Small">
         <item name="android:textColor">?android:attr/textColorSecondary</item>
     </style>
@@ -469,6 +474,7 @@
 
     <style name="TextAppearance.SearchBar" parent="@android:style/TextAppearance.Material.Widget.Toolbar.Subtitle">
         <item name="android:textSize">@dimen/search_bar_text_size</item>
+        <item name="android:fontFamily">@config/config_headlineFontFamily</item>
     </style>
 
     <style name="device_info_dialog_label">
diff --git a/res/xml/connected_devices_advanced.xml b/res/xml/connected_devices_advanced.xml
index 078d7dd..8ca6b81 100644
--- a/res/xml/connected_devices_advanced.xml
+++ b/res/xml/connected_devices_advanced.xml
@@ -16,6 +16,7 @@
 
 <PreferenceScreen
     xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:settings="http://schemas.android.com/apk/res-auto"
     android:key="connected_devices_screen"
     android:title="@string/connected_device_connections_title">
 
@@ -24,6 +25,7 @@
       android:title="@string/bluetooth_settings_title"
       android:icon="@drawable/ic_settings_bluetooth"
       android:summary="@string/bluetooth_pref_summary"
+      settings:controller="com.android.settings.bluetooth.BluetoothSwitchPreferenceController"
       android:order="-7"/>
 
     <SwitchPreference
diff --git a/res/xml/my_device_info.xml b/res/xml/my_device_info.xml
index 673b2a5..4988b16 100644
--- a/res/xml/my_device_info.xml
+++ b/res/xml/my_device_info.xml
@@ -30,7 +30,7 @@
 
     <!-- Account name -->
     <Preference
-        android:key="account"
+        android:key="branded_account"
         android:order="1"
         android:title="@string/my_device_info_account_preference_title"
         android:summary="@string/summary_placeholder"/>
@@ -43,7 +43,7 @@
         android:summary="@string/summary_placeholder"/>
 
     <!-- Device name -->
-    <Preference
+    <com.android.settings.widget.ValidatedEditTextPreference
         android:key="device_name"
         android:order="3"
         android:title="@string/my_device_info_device_name_preference_title"
diff --git a/src/com/android/settings/bluetooth/BluetoothLengthDeviceNameFilter.java b/src/com/android/settings/bluetooth/BluetoothLengthDeviceNameFilter.java
new file mode 100644
index 0000000..cdf5310
--- /dev/null
+++ b/src/com/android/settings/bluetooth/BluetoothLengthDeviceNameFilter.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.bluetooth;
+
+/**
+ * Filter to max the length of a Bluetotoh device name to 248 bytes, as defined by the spec.
+ */
+public class BluetoothLengthDeviceNameFilter extends Utf8ByteLengthFilter {
+    private static final int BLUETOOTH_NAME_MAX_LENGTH_BYTES = 248;
+
+    public BluetoothLengthDeviceNameFilter() {
+        super(BLUETOOTH_NAME_MAX_LENGTH_BYTES);
+    }
+}
diff --git a/src/com/android/settings/bluetooth/BluetoothNameDialogFragment.java b/src/com/android/settings/bluetooth/BluetoothNameDialogFragment.java
index 576e656..134bb97 100644
--- a/src/com/android/settings/bluetooth/BluetoothNameDialogFragment.java
+++ b/src/com/android/settings/bluetooth/BluetoothNameDialogFragment.java
@@ -43,8 +43,6 @@
  */
 abstract class BluetoothNameDialogFragment extends InstrumentedDialogFragment
         implements TextWatcher {
-    private static final int BLUETOOTH_NAME_MAX_LENGTH_BYTES = 248;
-
     private AlertDialog mAlertDialog;
     private Button mOkButton;
 
@@ -109,7 +107,7 @@
         View view = layoutInflater.inflate(R.layout.dialog_edittext, null);
         mDeviceNameView = (EditText) view.findViewById(R.id.edittext);
         mDeviceNameView.setFilters(new InputFilter[] {
-                new Utf8ByteLengthFilter(BLUETOOTH_NAME_MAX_LENGTH_BYTES)
+                new BluetoothLengthDeviceNameFilter()
         });
         mDeviceNameView.setText(deviceName);    // set initial value before adding listener
         if (!TextUtils.isEmpty(deviceName)) {
diff --git a/src/com/android/settings/bluetooth/Utf8ByteLengthFilter.java b/src/com/android/settings/bluetooth/Utf8ByteLengthFilter.java
index bae6e56..ab49818 100644
--- a/src/com/android/settings/bluetooth/Utf8ByteLengthFilter.java
+++ b/src/com/android/settings/bluetooth/Utf8ByteLengthFilter.java
@@ -37,7 +37,7 @@
  * pairs are encoded as 4 bytes, with the caveat that the maximum
  * length will be constrained more conservatively than necessary.
  */
-class Utf8ByteLengthFilter implements InputFilter {
+public class Utf8ByteLengthFilter implements InputFilter {
     private final int mMaxBytes;
 
     Utf8ByteLengthFilter(int maxBytes) {
diff --git a/src/com/android/settings/deviceinfo/BrandedAccountPreferenceController.java b/src/com/android/settings/deviceinfo/BrandedAccountPreferenceController.java
index 5565e3d..c968d25 100644
--- a/src/com/android/settings/deviceinfo/BrandedAccountPreferenceController.java
+++ b/src/com/android/settings/deviceinfo/BrandedAccountPreferenceController.java
@@ -31,7 +31,7 @@
 import com.android.settings.overlay.FeatureFactory;
 
 public class BrandedAccountPreferenceController extends BasePreferenceController {
-    private static final String KEY_PREFERENCE_TITLE = "account";
+    private static final String KEY_PREFERENCE_TITLE = "branded_account";
     private final Account[] mAccounts;
 
     public BrandedAccountPreferenceController(Context context) {
diff --git a/src/com/android/settings/deviceinfo/DeviceNamePreferenceController.java b/src/com/android/settings/deviceinfo/DeviceNamePreferenceController.java
new file mode 100644
index 0000000..0f1dea1
--- /dev/null
+++ b/src/com/android/settings/deviceinfo/DeviceNamePreferenceController.java
@@ -0,0 +1,151 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.deviceinfo;
+
+import android.annotation.Nullable;
+import android.content.Context;
+import android.net.wifi.WifiConfiguration;
+import android.net.wifi.WifiManager;
+import android.os.Build;
+import android.provider.Settings;
+import android.support.v7.preference.Preference;
+import android.support.v7.preference.PreferenceScreen;
+import android.text.SpannedString;
+
+import com.android.settings.bluetooth.BluetoothLengthDeviceNameFilter;
+import com.android.settings.core.BasePreferenceController;
+import com.android.settings.widget.ValidatedEditTextPreference;
+import com.android.settings.wifi.tether.WifiDeviceNameTextValidator;
+import com.android.settingslib.bluetooth.LocalBluetoothAdapter;
+import com.android.settingslib.bluetooth.LocalBluetoothManager;
+
+public class DeviceNamePreferenceController extends BasePreferenceController
+        implements ValidatedEditTextPreference.Validator, Preference.OnPreferenceChangeListener {
+    private static final String PREF_KEY = "device_name";
+    private String mDeviceName;
+    protected WifiManager mWifiManager;
+    private final WifiDeviceNameTextValidator mWifiDeviceNameTextValidator;
+    private ValidatedEditTextPreference mPreference;
+    @Nullable
+    private LocalBluetoothManager mBluetoothManager;
+
+    public DeviceNamePreferenceController(Context context) {
+        super(context, PREF_KEY);
+        mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
+        mWifiDeviceNameTextValidator = new WifiDeviceNameTextValidator();
+        initializeDeviceName();
+    }
+
+    @Override
+    public void displayPreference(PreferenceScreen screen) {
+        super.displayPreference(screen);
+        mPreference = (ValidatedEditTextPreference) screen.findPreference(PREF_KEY);
+        mPreference.setSummary(getSummary());
+        mPreference.setValidator(this);
+    }
+
+    private void initializeDeviceName() {
+        mDeviceName = Settings.Global.getString(mContext.getContentResolver(),
+                Settings.Global.DEVICE_NAME);
+        if (mDeviceName == null) {
+            mDeviceName = Build.MODEL;
+        }
+    }
+
+    @Override
+    public String getSummary() {
+        return mDeviceName;
+    }
+
+    @Override
+    public int getAvailabilityStatus() {
+        return AVAILABLE;
+    }
+
+    @Override
+    public String getPreferenceKey() {
+        return PREF_KEY;
+    }
+
+    @Override
+    public boolean onPreferenceChange(Preference preference, Object newValue) {
+        mDeviceName = (String) newValue;
+        setDeviceName(mDeviceName);
+        preference.setSummary(getSummary());
+        return true;
+    }
+
+    @Override
+    public boolean isTextValid(String deviceName) {
+        // BluetoothNameDialogFragment describes BT name filter as a 248 bytes long cap.
+        // Given the restrictions presented by the SSID name filter (32 char), I don't believe it is
+        // possible to construct an SSID that is not a valid Bluetooth name.
+        return mWifiDeviceNameTextValidator.isTextValid(deviceName);
+    }
+
+    public void setLocalBluetoothManager(LocalBluetoothManager localBluetoothManager) {
+        mBluetoothManager = localBluetoothManager;
+    }
+
+    /**
+     * This method presumes that security/validity checks have already been passed.
+     */
+    private void setDeviceName(String deviceName) {
+        setSettingsGlobalDeviceName(deviceName);
+        setBluetoothDeviceName(deviceName);
+        setTetherSsidName(deviceName);
+    }
+
+    private void setSettingsGlobalDeviceName(String deviceName) {
+        Settings.Global.putString(mContext.getContentResolver(), Settings.Global.DEVICE_NAME,
+                deviceName);
+    }
+
+    private void setBluetoothDeviceName(String deviceName) {
+        // Bluetooth manager doesn't exist for certain devices.
+        if (mBluetoothManager == null) {
+            return;
+        }
+
+        final LocalBluetoothAdapter localBluetoothAdapter = mBluetoothManager.getBluetoothAdapter();
+        if (localBluetoothAdapter != null) {
+            localBluetoothAdapter.setName(getFilteredBluetoothString(deviceName));
+        }
+    }
+
+    /**
+     * Using a UTF8ByteLengthFilter, we can filter a string to be compliant with the Bluetooth spec.
+     * For more information, see {@link com.android.settings.bluetooth.BluetoothNameDialogFragment}.
+     */
+    private static final String getFilteredBluetoothString(final String deviceName) {
+        CharSequence filteredSequence = new BluetoothLengthDeviceNameFilter().filter(deviceName, 0, deviceName.length(),
+                new SpannedString(""),
+                0, 0);
+        // null -> use the original
+        if (filteredSequence == null) {
+            return deviceName;
+        }
+        return filteredSequence.toString();
+    }
+
+    private void setTetherSsidName(String deviceName) {
+        final WifiConfiguration config = mWifiManager.getWifiApConfiguration();
+        config.SSID = deviceName;
+        // TODO: If tether is running, turn off the AP and restart it after setting config.
+        mWifiManager.setWifiApConfiguration(config);
+    }
+}
\ No newline at end of file
diff --git a/src/com/android/settings/deviceinfo/aboutphone/MyDeviceInfoFragment.java b/src/com/android/settings/deviceinfo/aboutphone/MyDeviceInfoFragment.java
index a301807..04e7fde 100644
--- a/src/com/android/settings/deviceinfo/aboutphone/MyDeviceInfoFragment.java
+++ b/src/com/android/settings/deviceinfo/aboutphone/MyDeviceInfoFragment.java
@@ -16,6 +16,8 @@
 
 package com.android.settings.deviceinfo.aboutphone;
 
+import static com.android.settings.bluetooth.Utils.getLocalBtManager;
+
 import android.app.Activity;
 import android.app.Fragment;
 import android.content.Context;
@@ -54,6 +56,7 @@
 import com.android.settings.widget.EntityHeaderController;
 import com.android.settingslib.core.AbstractPreferenceController;
 import com.android.settingslib.core.lifecycle.Lifecycle;
+import com.android.settings.deviceinfo.DeviceNamePreferenceController;
 
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -102,6 +105,10 @@
         final List<AbstractPreferenceController> controllers = new ArrayList<>();
         controllers.add(new PhoneNumberPreferenceController(context));
         controllers.add(new BrandedAccountPreferenceController(context));
+        DeviceNamePreferenceController deviceNamePreferenceController =
+                new DeviceNamePreferenceController(context);
+        deviceNamePreferenceController.setLocalBluetoothManager(getLocalBtManager(context));
+        controllers.add(deviceNamePreferenceController);
         controllers.add(new SimStatusPreferenceController(context, fragment));
         controllers.add(new DeviceModelPreferenceController(context, fragment));
         controllers.add(new ImeiInfoPreferenceController(context, fragment));
@@ -117,7 +124,6 @@
         controllers.add(new FccEquipmentIdPreferenceController(context));
         controllers.add(
                 new BuildNumberPreferenceController(context, activity, fragment, lifecycle));
-        // TODO: Add preference controller for getting the device name.
         return controllers;
     }
 
diff --git a/src/com/android/settings/slices/SettingsSliceProvider.java b/src/com/android/settings/slices/SettingsSliceProvider.java
index e068b2f..433bdf3 100644
--- a/src/com/android/settings/slices/SettingsSliceProvider.java
+++ b/src/com/android/settings/slices/SettingsSliceProvider.java
@@ -30,7 +30,6 @@
 import com.android.settings.R;
 import com.android.settingslib.utils.ThreadUtils;
 
-import java.util.HashMap;
 import java.util.Map;
 import java.util.WeakHashMap;
 
diff --git a/src/com/android/settings/slices/SliceBuilderUtils.java b/src/com/android/settings/slices/SliceBuilderUtils.java
index e9152ba..11ff1c1 100644
--- a/src/com/android/settings/slices/SliceBuilderUtils.java
+++ b/src/com/android/settings/slices/SliceBuilderUtils.java
@@ -23,6 +23,7 @@
 import android.content.Intent;
 import android.graphics.drawable.Icon;
 import android.text.TextUtils;
+import android.util.Log;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.settings.R;
@@ -85,17 +86,46 @@
      */
     public static BasePreferenceController getPreferenceController(Context context,
             SliceData sliceData) {
-        // TODO check for context-only controller first.
+        try {
+            return getController(context, sliceData, true /* isContextOnly */);
+        } catch (IllegalStateException e) {
+            // Do nothing
+            Log.d(TAG, "Could not find Context-only controller for preference controller: "
+                    + sliceData.getKey());
+        }
+
+        return getController(context, sliceData, false /* isContextOnly */);
+    }
+
+    /**
+     * Attempts to build a {@link BasePreferenceController} from {@param SliceData}.
+     *
+     * @param sliceData     Backing data for the Slice.
+     * @param contextOnlyCtor {@code true} when the constructor for the
+     *                      {@link BasePreferenceController}
+     *                      only takes a {@link Context}. Else the constructor will be ({@link
+     *                      Context}, {@code String}.
+     */
+    private static BasePreferenceController getController(Context context, SliceData sliceData,
+            boolean contextOnlyCtor) {
         try {
             Class<?> clazz = Class.forName(sliceData.getPreferenceController());
-            Constructor<?> preferenceConstructor = clazz.getConstructor(Context.class,
-                    String.class);
-            return (BasePreferenceController) preferenceConstructor.newInstance(
-                    new Object[]{context, sliceData.getKey()});
+            Constructor<?> preferenceConstructor;
+            Object[] params;
+
+            if (contextOnlyCtor) {
+                preferenceConstructor = clazz.getConstructor(Context.class);
+                params = new Object[]{context};
+            } else {
+                preferenceConstructor = clazz.getConstructor(Context.class, String.class);
+                params = new Object[]{context, sliceData.getKey()};
+            }
+
+            return (BasePreferenceController) preferenceConstructor.newInstance(params);
         } catch (ClassNotFoundException | NoSuchMethodException | InstantiationException |
                 IllegalArgumentException | InvocationTargetException | IllegalAccessException e) {
             throw new IllegalStateException(
-                    "Invalid preference controller: " + sliceData.getPreferenceController());
+                    "Invalid preference controller: " + sliceData.getPreferenceController(), e);
         }
     }
 
diff --git a/src/com/android/settings/wfd/WifiDisplaySettings.java b/src/com/android/settings/wfd/WifiDisplaySettings.java
index 7a9fc39..8f42389 100755
--- a/src/com/android/settings/wfd/WifiDisplaySettings.java
+++ b/src/com/android/settings/wfd/WifiDisplaySettings.java
@@ -22,6 +22,7 @@
 import android.content.DialogInterface;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.content.pm.PackageManager;
 import android.database.ContentObserver;
 import android.hardware.display.DisplayManager;
 import android.hardware.display.WifiDisplay;
@@ -218,13 +219,9 @@
     }
 
     public static boolean isAvailable(Context context) {
-        try {
-            return context.getSystemService(Context.DISPLAY_SERVICE) != null
-                    && context.getSystemService(Context.WIFI_P2P_SERVICE) != null;
-        } catch (Exception e) {
-            // Service is not registered, so this is definitely not available.
-            return false;
-        }
+        return context.getSystemService(Context.DISPLAY_SERVICE) != null
+                && context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WIFI_DIRECT)
+                && context.getSystemService(Context.WIFI_P2P_SERVICE) != null;
     }
 
     private void scheduleUpdate(int changes) {
diff --git a/src/com/android/settings/widget/SettingsAppWidgetProvider.java b/src/com/android/settings/widget/SettingsAppWidgetProvider.java
index 5ccfc1b..adc386a 100644
--- a/src/com/android/settings/widget/SettingsAppWidgetProvider.java
+++ b/src/com/android/settings/widget/SettingsAppWidgetProvider.java
@@ -26,6 +26,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.database.ContentObserver;
+import android.hardware.display.DisplayManager;
 import android.location.LocationManager;
 import android.net.ConnectivityManager;
 import android.net.Uri;
@@ -736,7 +737,7 @@
                     R.drawable.appwidget_settings_ind_on_r_holo);
         } else {
             final int brightness = getBrightness(context);
-            final PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
+            final PowerManager pm = context.getSystemService(PowerManager.class);
             // Set the icon
             final int full = (int)(pm.getMaximumScreenBrightnessSetting()
                     * FULL_BRIGHTNESS_THRESHOLD);
@@ -872,53 +873,48 @@
      */
     private void toggleBrightness(Context context) {
         try {
-            IPowerManager power = IPowerManager.Stub.asInterface(
-                    ServiceManager.getService("power"));
-            if (power != null) {
-                PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
+            DisplayManager dm = context.getSystemService(DisplayManager.class);
+            PowerManager pm = context.getSystemService(PowerManager.class);
 
-                ContentResolver cr = context.getContentResolver();
-                int brightness = Settings.System.getInt(cr,
-                        Settings.System.SCREEN_BRIGHTNESS);
-                int brightnessMode = Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL;
-                //Only get brightness setting if available
-                if (context.getResources().getBoolean(
-                        com.android.internal.R.bool.config_automatic_brightness_available)) {
-                    brightnessMode = Settings.System.getInt(cr,
-                            Settings.System.SCREEN_BRIGHTNESS_MODE);
-                }
-
-                // Rotate AUTO -> MINIMUM -> DEFAULT -> MAXIMUM
-                // Technically, not a toggle...
-                if (brightnessMode == Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC) {
-                    brightness = pm.getMinimumScreenBrightnessSetting();
-                    brightnessMode = Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL;
-                } else if (brightness < pm.getDefaultScreenBrightnessSetting()) {
-                    brightness = pm.getDefaultScreenBrightnessSetting();
-                } else if (brightness < pm.getMaximumScreenBrightnessSetting()) {
-                    brightness = pm.getMaximumScreenBrightnessSetting();
-                } else {
-                    brightnessMode = Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC;
-                    brightness = pm.getMinimumScreenBrightnessSetting();
-                }
-
-                if (context.getResources().getBoolean(
-                        com.android.internal.R.bool.config_automatic_brightness_available)) {
-                    // Set screen brightness mode (automatic or manual)
-                    Settings.System.putInt(context.getContentResolver(),
-                            Settings.System.SCREEN_BRIGHTNESS_MODE,
-                            brightnessMode);
-                } else {
-                    // Make sure we set the brightness if automatic mode isn't available
-                    brightnessMode = Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL;
-                }
-                if (brightnessMode == Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL) {
-                    power.setTemporaryScreenBrightnessSettingOverride(brightness);
-                    Settings.System.putInt(cr, Settings.System.SCREEN_BRIGHTNESS, brightness);
-                }
+            ContentResolver cr = context.getContentResolver();
+            int brightness = Settings.System.getInt(cr,
+                    Settings.System.SCREEN_BRIGHTNESS);
+            int brightnessMode = Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL;
+            //Only get brightness setting if available
+            if (context.getResources().getBoolean(
+                    com.android.internal.R.bool.config_automatic_brightness_available)) {
+                brightnessMode = Settings.System.getInt(cr,
+                        Settings.System.SCREEN_BRIGHTNESS_MODE);
             }
-        } catch (RemoteException e) {
-            Log.d(TAG, "toggleBrightness: " + e);
+
+            // Rotate AUTO -> MINIMUM -> DEFAULT -> MAXIMUM
+            // Technically, not a toggle...
+            if (brightnessMode == Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC) {
+                brightness = pm.getMinimumScreenBrightnessSetting();
+                brightnessMode = Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL;
+            } else if (brightness < pm.getDefaultScreenBrightnessSetting()) {
+                brightness = pm.getDefaultScreenBrightnessSetting();
+            } else if (brightness < pm.getMaximumScreenBrightnessSetting()) {
+                brightness = pm.getMaximumScreenBrightnessSetting();
+            } else {
+                brightnessMode = Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC;
+                brightness = pm.getMinimumScreenBrightnessSetting();
+            }
+
+            if (context.getResources().getBoolean(
+                    com.android.internal.R.bool.config_automatic_brightness_available)) {
+                // Set screen brightness mode (automatic or manual)
+                Settings.System.putInt(context.getContentResolver(),
+                        Settings.System.SCREEN_BRIGHTNESS_MODE,
+                        brightnessMode);
+            } else {
+                // Make sure we set the brightness if automatic mode isn't available
+                brightnessMode = Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL;
+            }
+            if (brightnessMode == Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL) {
+                dm.setTemporaryBrightness(brightness);
+                Settings.System.putInt(cr, Settings.System.SCREEN_BRIGHTNESS, brightness);
+            }
         } catch (Settings.SettingNotFoundException e) {
             Log.d(TAG, "toggleBrightness: " + e);
         }
diff --git a/src/com/android/settings/wifi/tether/WifiDeviceNameTextValidator.java b/src/com/android/settings/wifi/tether/WifiDeviceNameTextValidator.java
new file mode 100644
index 0000000..e766e32
--- /dev/null
+++ b/src/com/android/settings/wifi/tether/WifiDeviceNameTextValidator.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.wifi.tether;
+
+import com.android.settings.widget.ValidatedEditTextPreference;
+import com.android.settings.wifi.WifiUtils;
+
+/**
+ * Validates a text field for a valid Wi-Fi SSID name.
+ */
+public class WifiDeviceNameTextValidator implements ValidatedEditTextPreference.Validator {
+    @Override
+    public boolean isTextValid(String value) {
+        return !WifiUtils.isSSIDTooLong(value) && !WifiUtils.isSSIDTooShort(value);
+    }
+}
diff --git a/src/com/android/settings/wifi/tether/WifiTetherSSIDPreferenceController.java b/src/com/android/settings/wifi/tether/WifiTetherSSIDPreferenceController.java
index b563e53..d7cb441 100644
--- a/src/com/android/settings/wifi/tether/WifiTetherSSIDPreferenceController.java
+++ b/src/com/android/settings/wifi/tether/WifiTetherSSIDPreferenceController.java
@@ -35,10 +35,12 @@
     static final String DEFAULT_SSID = "AndroidAP";
 
     private String mSSID;
+    private WifiDeviceNameTextValidator mWifiDeviceNameTextValidator;
 
     public WifiTetherSSIDPreferenceController(Context context,
             OnTetherConfigUpdateListener listener) {
         super(context, listener);
+        mWifiDeviceNameTextValidator = new WifiDeviceNameTextValidator();
     }
 
     @Override
@@ -70,7 +72,7 @@
 
     @Override
     public boolean isTextValid(String value) {
-        return !WifiUtils.isSSIDTooLong(value) && !WifiUtils.isSSIDTooShort(value);
+        return mWifiDeviceNameTextValidator.isTextValid(value);
     }
 
     public String getSSID() {
diff --git a/tests/robotests/src/com/android/settings/core/XmlControllerAttributeTest.java b/tests/robotests/src/com/android/settings/core/XmlControllerAttributeTest.java
index 8ded9d6..e6ca59b 100644
--- a/tests/robotests/src/com/android/settings/core/XmlControllerAttributeTest.java
+++ b/tests/robotests/src/com/android/settings/core/XmlControllerAttributeTest.java
@@ -80,11 +80,6 @@
     private static final String BAD_CLASSNAME_ERROR =
             "The following controllers set in the XML did not have valid class names:\n";
 
-    private static final String BAD_CONSTRUCTOR_ERROR =
-            "The constructor provided by the following classes were insufficient to instantiate "
-                    + "the object. It could be due to being an interface, abstract, or an "
-                    + "IllegalAccessException. Please fix the following classes:\n";
-
     Context mContext;
     SearchFeatureProvider mSearchProvider;
     private FakeFeatureFactory mFakeFeatureFactory;
@@ -112,7 +107,6 @@
         Set<String> invalidConstructors = new HashSet<>();
         Set<String> invalidClassHierarchy = new HashSet<>();
         Set<String> badClassNameControllers = new HashSet<>();
-        Set<String> badConstructorControllers = new HashSet<>();
 
         for (int resId : xmlSet) {
             xmlControllers.addAll(getXmlControllers(resId));
@@ -133,13 +127,7 @@
                 continue;
             }
 
-            Object controller = getObjectFromConstructor(constructor);
-            if (controller == null) {
-                badConstructorControllers.add(controllerClassName);
-                continue;
-            }
-
-            if (!(controller instanceof BasePreferenceController)) {
+            if (!isBasePreferenceController(clazz)) {
                 invalidClassHierarchy.add(controllerClassName);
             }
         }
@@ -150,13 +138,10 @@
                 invalidClassHierarchy);
         final String badClassNameError = buildErrorMessage(BAD_CLASSNAME_ERROR,
                 badClassNameControllers);
-        final String badConstructorError = buildErrorMessage(BAD_CONSTRUCTOR_ERROR,
-                badConstructorControllers);
 
         assertWithMessage(invalidConstructorError).that(invalidConstructors).isEmpty();
         assertWithMessage(invalidClassHierarchyError).that(invalidClassHierarchy).isEmpty();
         assertWithMessage(badClassNameError).that(badClassNameControllers).isEmpty();
-        assertWithMessage(badConstructorError).that(badConstructorControllers).isEmpty();
     }
 
     private Set<Integer> getIndexableXml() {
@@ -260,25 +245,16 @@
         return constructor;
     }
 
-    private Object getObjectFromConstructor(Constructor<?> constructor) {
-        Object controller = null;
-
-        try {
-            controller = constructor.newInstance(mContext);
-        } catch (InstantiationException | IllegalAccessException | InvocationTargetException |
-                IllegalArgumentException e) {
+    /**
+     * Make sure that {@link BasePreferenceController} is in the class hierarchy.
+     */
+    private boolean isBasePreferenceController(Class<?> clazz) {
+        while (clazz != null) {
+            clazz = clazz.getSuperclass();
+            if (BasePreferenceController.class.equals(clazz)) {
+                return true;
+            }
         }
-
-        if (controller != null) {
-            return controller;
-        }
-
-        try {
-            controller = constructor.newInstance(mContext, "key");
-        } catch (InstantiationException | IllegalAccessException | InvocationTargetException |
-                IllegalArgumentException e) {
-        }
-
-        return controller;
+        return false;
     }
-}
+}
\ No newline at end of file
diff --git a/tests/robotests/src/com/android/settings/deviceinfo/DeviceNamePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/deviceinfo/DeviceNamePreferenceControllerTest.java
new file mode 100644
index 0000000..4ff79ca
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/deviceinfo/DeviceNamePreferenceControllerTest.java
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.deviceinfo;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.net.wifi.WifiConfiguration;
+import android.net.wifi.WifiManager;
+import android.os.Build;
+import android.provider.Settings;
+import android.support.v7.preference.PreferenceScreen;
+
+import com.android.settings.TestConfig;
+import com.android.settings.testutils.SettingsRobolectricTestRunner;
+import com.android.settings.widget.ValidatedEditTextPreference;
+import com.android.settingslib.bluetooth.LocalBluetoothAdapter;
+import com.android.settingslib.bluetooth.LocalBluetoothManager;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Answers;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
+import org.robolectric.shadows.ShadowApplication;
+
+@RunWith(SettingsRobolectricTestRunner.class)
+@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
+public class DeviceNamePreferenceControllerTest {
+    private static final String TESTING_STRING = "Testing";
+
+    @Mock
+    private LocalBluetoothAdapter mBluetoothAdapter;
+    @Mock(answer = Answers.RETURNS_DEEP_STUBS)
+    private LocalBluetoothManager mBluetoothManager;
+    @Mock
+    private WifiManager mWifiManager;
+    @Mock
+    private PreferenceScreen mScreen;
+    private ValidatedEditTextPreference mPreference;
+    private DeviceNamePreferenceController mController;
+    private Context mContext;
+
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        ShadowApplication shadowApplication = ShadowApplication.getInstance();
+        shadowApplication.setSystemService(Context.WIFI_SERVICE, mWifiManager);
+        mContext = shadowApplication.getApplicationContext();
+        mPreference = new ValidatedEditTextPreference(mContext);
+        when(mBluetoothManager.getBluetoothAdapter()).thenReturn(mBluetoothAdapter);
+        when(mScreen.findPreference(anyString())).thenReturn(mPreference);
+        final WifiConfiguration configuration = new WifiConfiguration();
+        configuration.SSID = "test-ap";
+        when(mWifiManager.getWifiApConfiguration()).thenReturn(configuration);
+
+        mController = new DeviceNamePreferenceController(mContext);
+        mController.setLocalBluetoothManager(mBluetoothManager);
+    }
+
+    @Test
+    public void constructor_defaultDeviceNameIsModelName() {
+        assertThat(mController.getSummary()).isEqualTo(Build.MODEL);
+    }
+
+    @Test
+    public void constructor_deviceNameLoadedIfSet() {
+        Settings.Global.putString(mContext.getContentResolver(), Settings.Global.DEVICE_NAME,
+                "Test");
+        mController = new DeviceNamePreferenceController(mContext);
+        mController.setLocalBluetoothManager(mBluetoothManager);
+        assertThat(mController.getSummary()).isEqualTo("Test");
+    }
+
+    @Test
+    public void isTextValid_nameUnder33CharactersIsValid() {
+        assertThat(mController.isTextValid("12345678901234567890123456789012")).isTrue();
+    }
+
+    @Test
+    public void isTextValid_nameTooLongIsInvalid() {
+        assertThat(mController.isTextValid("123456789012345678901234567890123")).isFalse();
+    }
+
+    @Test
+    public void setDeviceName_preferenceUpdatedWhenDeviceNameUpdated() {
+        mController.onPreferenceChange(mPreference, TESTING_STRING);
+
+        assertThat(mPreference.getSummary()).isEqualTo(TESTING_STRING);
+    }
+
+    @Test
+    public void setDeviceName_bluetoothNameUpdatedWhenDeviceNameUpdated() {
+        mController.onPreferenceChange(mPreference, TESTING_STRING);
+
+        verify(mBluetoothAdapter).setName(eq(TESTING_STRING));
+    }
+
+    @Test
+    public void setDeviceName_wifiTetherNameUpdatedWhenDeviceNameUpdated() {
+        mController.onPreferenceChange(mPreference, TESTING_STRING);
+
+        ArgumentCaptor<WifiConfiguration> captor = ArgumentCaptor.forClass(WifiConfiguration.class);
+        verify(mWifiManager).setWifiApConfiguration(captor.capture());
+        assertThat(captor.getValue().SSID).isEqualTo(TESTING_STRING);
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/slices/FakeContextOnlyPreferenceController.java b/tests/robotests/src/com/android/settings/slices/FakeContextOnlyPreferenceController.java
new file mode 100644
index 0000000..214607b
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/slices/FakeContextOnlyPreferenceController.java
@@ -0,0 +1,19 @@
+package com.android.settings.slices;
+
+import android.content.Context;
+
+import com.android.settings.core.BasePreferenceController;
+
+public class FakeContextOnlyPreferenceController extends BasePreferenceController {
+
+    public static final String KEY = "fakeController2";
+
+    public FakeContextOnlyPreferenceController(Context context) {
+        super(context, KEY);
+    }
+
+    @Override
+    public int getAvailabilityStatus() {
+        return AVAILABLE;
+    }
+}
\ No newline at end of file
diff --git a/tests/robotests/src/com/android/settings/slices/SliceBuilderUtilsTest.java b/tests/robotests/src/com/android/settings/slices/SliceBuilderUtilsTest.java
index 10e4b76..0923571 100644
--- a/tests/robotests/src/com/android/settings/slices/SliceBuilderUtilsTest.java
+++ b/tests/robotests/src/com/android/settings/slices/SliceBuilderUtilsTest.java
@@ -50,8 +50,8 @@
     private final String FRAGMENT_NAME = "fragment name";
     private final int ICON = 1234; // I declare a thumb war
     private final Uri URI = Uri.parse("content://com.android.settings.slices/test");
-    private final String PREF_CONTROLLER = FakeToggleController.class.getName();
-    ;
+    private final Class PREF_CONTROLLER = FakeToggleController.class;
+    private final Class PREF_CONTROLLER2 = FakeContextOnlyPreferenceController.class;
 
     private Context mContext;
 
@@ -76,6 +76,14 @@
     }
 
     @Test
+    public void testGetPreferenceController_contextOnly_buildsMatchingController() {
+        BasePreferenceController controller = SliceBuilderUtils.getPreferenceController(mContext,
+                getDummyData(PREF_CONTROLLER2));
+
+        assertThat(controller).isInstanceOf(FakeContextOnlyPreferenceController.class);
+    }
+
+    @Test
     public void testDynamicSummary_returnsSliceSummary() {
         SliceData data = getDummyData();
         FakePreferenceController controller = new FakePreferenceController(mContext, KEY);
@@ -87,7 +95,7 @@
 
     @Test
     public void testDynamicSummary_returnsFragmentSummary() {
-        SliceData data = getDummyData(null);
+        SliceData data = getDummyData((String) null);
         FakePreferenceController controller = spy(new FakePreferenceController(mContext, KEY));
         String controllerSummary = "new_Summary";
         doReturn(controllerSummary).when(controller).getSummary();
@@ -99,7 +107,7 @@
 
     @Test
     public void testDynamicSummary_returnsSliceScreenTitle() {
-        SliceData data = getDummyData(null);
+        SliceData data = getDummyData((String) null);
         FakePreferenceController controller = new FakePreferenceController(mContext, KEY);
 
         String summary = SliceBuilderUtils.getSubtitleText(mContext, controller, data);
@@ -129,10 +137,18 @@
     }
 
     private SliceData getDummyData() {
-        return getDummyData(SUMMARY);
+        return getDummyData(PREF_CONTROLLER, SUMMARY);
     }
 
     private SliceData getDummyData(String summary) {
+        return getDummyData(PREF_CONTROLLER, summary);
+    }
+
+    private SliceData getDummyData(Class prefController) {
+        return getDummyData(prefController, SUMMARY);
+    }
+
+    private SliceData getDummyData(Class prefController, String summary) {
         return new SliceData.Builder()
                 .setKey(KEY)
                 .setTitle(TITLE)
@@ -141,7 +157,7 @@
                 .setIcon(ICON)
                 .setFragmentName(FRAGMENT_NAME)
                 .setUri(URI)
-                .setPreferenceControllerClassName(PREF_CONTROLLER)
+                .setPreferenceControllerClassName(prefController.getName())
                 .build();
     }
 }
diff --git a/tests/robotests/src/com/android/settings/wfd/WifiDisplaySettingsTest.java b/tests/robotests/src/com/android/settings/wfd/WifiDisplaySettingsTest.java
index 1cf85fb..fc634d2 100644
--- a/tests/robotests/src/com/android/settings/wfd/WifiDisplaySettingsTest.java
+++ b/tests/robotests/src/com/android/settings/wfd/WifiDisplaySettingsTest.java
@@ -24,6 +24,7 @@
 
 import android.app.Activity;
 import android.content.Context;
+import android.content.pm.PackageManager;
 import android.hardware.display.DisplayManager;
 import android.media.MediaRouter;
 import android.net.wifi.p2p.WifiP2pManager;
@@ -50,6 +51,8 @@
     private SummaryLoader mSummaryLoader;
     @Mock
     private MediaRouter mMediaRouter;
+    @Mock
+    private PackageManager mPackageManager;
 
     private SummaryLoader.SummaryProvider mSummaryProvider;
 
@@ -58,6 +61,8 @@
         MockitoAnnotations.initMocks(this);
         when(mActivity.getSystemService(Context.MEDIA_ROUTER_SERVICE))
                 .thenReturn(mMediaRouter);
+        when(mActivity.getPackageManager()).thenReturn(mPackageManager);
+        when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_WIFI_DIRECT)).thenReturn(true);
 
         mSummaryProvider = WifiDisplaySettings.SUMMARY_PROVIDER_FACTORY.createSummaryProvider(
                 mActivity, mSummaryLoader);
@@ -86,15 +91,15 @@
     }
 
     @Test
-    public void isAvailable_noService_shouldReturnFalse() {
+    public void isAvailable_nullService_shouldReturnFalse() {
         assertThat(WifiDisplaySettings.isAvailable(mActivity))
                 .isFalse();
     }
 
     @Test
-    public void isAvailable_throwException_shouldReturnFalse() {
-        when(mActivity.getSystemService(Context.WIFI_P2P_SERVICE))
-                .thenThrow(new IllegalStateException());
+    public void isAvailable_noWifiDirectFeature_shouldReturnFalse() {
+        when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_WIFI_DIRECT))
+                .thenReturn(false);
 
         assertThat(WifiDisplaySettings.isAvailable(mActivity))
                 .isFalse();