Merge "Fixes crash from selecting uninstalled app info from recents."
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 1766ffb..c526d6f 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -1013,6 +1013,7 @@
                   android:parentActivityName="Settings">
             <intent-filter android:priority="1">
                 <action android:name="android.settings.DEVICE_INFO_SETTINGS" />
+                <action android:name="android.settings.DEVICE_NAME" />
                 <category android:name="android.intent.category.DEFAULT" />
             </intent-filter>
             <intent-filter>
@@ -2012,13 +2013,21 @@
             </intent-filter>
         </activity>
 
-        <activity android:name=".deviceinfo.UsbModeChooserActivity"
+        <activity android:name=".connecteddevice.usb.UsbModeChooserActivity"
                   android:excludeFromRecents="true"
                   android:exported="true"
                   android:permission="android.permission.MANAGE_USB"
                   android:theme="@*android:style/Theme.DeviceDefault.Settings.Dialog.NoActionBar">
         </activity>
 
+        <activity android:name=".Settings$UsbDetailsActivity"
+                  android:excludeFromRecents="true"
+                  android:permission="android.permission.MANAGE_USB"
+                  android:exported="true">
+            <meta-data android:name="com.android.settings.FRAGMENT_CLASS"
+                android:value="com.android.settings.connecteddevice.usb.UsbDetailsFragment"/>
+        </activity>
+
         <activity android:name=".RemoteBugreportActivity"
                   android:excludeFromRecents="true"
                   android:exported="true"
@@ -3189,16 +3198,11 @@
         <activity android:name="Settings$AdvancedConnectedDeviceActivity"
                   android:label="@string/connected_device_connections_title"
                   android:taskAffinity="com.android.settings"
-                  android:parentActivityName="Settings$ConnectedDeviceDashboardActivity"
-                  android:enabled="false">
+                  android:parentActivityName="Settings$ConnectedDeviceDashboardActivity">
             <intent-filter android:priority="1">
                 <action android:name="com.android.settings.ADVANCED_CONNECTED_DEVICE_SETTINGS" />
                 <category android:name="android.intent.category.DEFAULT" />
             </intent-filter>
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-                <category android:name="android.intent.category.DEFAULT" />
-            </intent-filter>
             <meta-data android:name="com.android.settings.FRAGMENT_CLASS"
                        android:value="com.android.settings.connecteddevice.AdvancedConnectedDeviceDashboardFragment" />
             <meta-data android:name="com.android.settings.PRIMARY_PROFILE_CONTROLLED"
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index d6f3cb5..12193c4 100755
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -119,8 +119,8 @@
     <!-- The following two margins need to match, with the caveat that
          the second should be negative. The second one ensures that the icons and text
          align despite the additional padding caused by the search bar's card background. -->
-    <dimen name="search_bar_margin">8dp</dimen>
-    <dimen name="search_bar_negative_margin">-8dp</dimen>
+    <dimen name="search_bar_margin">16dp</dimen>
+    <dimen name="search_bar_negative_margin">-16dp</dimen>
 
     <dimen name="search_bar_height">48dp</dimen>
     <dimen name="search_bar_corner_radius">2dp</dimen>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 3e211b4..9a6ff90 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -8005,15 +8005,15 @@
     <!-- Title of one of the choices in a dialog (with title defined in usb_use) that lets the user
          select what the USB connection for this device should be used for. This choice
          is for powering the other device only. -->
-    <string name="usb_use_power_only">Supply power</string>
+    <string name="usb_use_power_only">Charging connected device</string>
     <!-- Decription of one of the choices in a dialog (with title defined in usb_use) that lets the
          user select what the USB connection for this device should be used for. This choice
          is for powering the other device. -->
-    <string name="usb_use_power_only_desc">Charge the connected device. Works only with devices that support USB charging.</string>
+    <string name="usb_use_power_only_desc">Other settings unavailable when turned on</string>
     <!-- Title of one of the choices in a dialog (with title defined in usb_use) that lets the user
          select what the USB connection for this device should be used for. This choice
          is for transferring files via MTP. -->
-    <string name="usb_use_file_transfers">Transfer files</string>
+    <string name="usb_use_file_transfers">File Transfer</string>
     <!-- Description of one of the choices in a dialog (with title defined in usb_use) that lets the user
          select what the USB connection for this device should be used for. This choice
          is for transferring files via MTP. -->
@@ -8021,23 +8021,31 @@
     <!-- Title of one of the choices in a dialog (with title defined in usb_use) that lets the user
          select what the USB connection for this device should be used for. This choice
          is for transferring photos via PTP. -->
-    <string name="usb_use_photo_transfers">Transfer photos (PTP)</string>
+    <string name="usb_use_photo_transfers">PTP</string>
     <!-- Description of one of the choices in a dialog (with title defined in usb_use) that lets the user
          select what the USB connection for this device should be used for. This choice
          is for transferring photos via PTP. -->
     <string name="usb_use_photo_transfers_desc">Transfer photos or files if MTP is not supported (PTP)</string>
     <!-- Title of one of the choices in a dialog (with title defined in usb_use) that lets the user
          select what the USB connection for this device should be used for. This choice
+         is for USB tethering. -->
+    <string name="usb_use_tethering">USB tethering</string>
+    <!-- Title of one of the choices in a dialog (with title defined in usb_use) that lets the user
+         select what the USB connection for this device should be used for. This choice
          is for entering MIDI mode. -->
-    <string name="usb_use_MIDI">Use device as MIDI</string>
+    <string name="usb_use_MIDI">MIDI</string>
     <!-- Description of one of the choices in a dialog (with title defined in usb_use) that lets the user
          select what the USB connection for this device should be used for. This choice
          is for entering MIDI mode. -->
     <string name="usb_use_MIDI_desc">Use this device as MIDI</string>
     <!-- The title used in a dialog which lets the user select what the USB connection
-         for this device should be used for. Choices are usb_use_charging_only,
-         usb_use_file_transfer, use_use_photo_transfer, and usb_use_MIDI -->
-    <string name="usb_use">Use USB to</string>
+         for this device should be used for. These options are more commonly used.
+         Choices are usb_use_file_transfer.-->
+    <string name="usb_use">Use USB for</string>
+    <!-- The title used in a dialog which lets the user select what the USB connection
+         for this device should be used for. These options are less commonly used.
+         Choices are usb_use_tethering, usb_use_photo_transfers, usb_use_MIDI, and usb_use_power_only.-->
+    <string name="usb_use_also">Also use USB for</string>
 
     <!-- Settings item title for USB preference [CHAR LIMIT=35] -->
     <string name="usb_pref">USB</string>
@@ -8045,13 +8053,27 @@
     <!-- Settings item summary for USB preference when set to charging only [CHAR LIMIT=NONE] -->
     <string name="usb_summary_charging_only">Charging this device</string>
     <!-- Settings item summary for USB preference when set to powering the other device only [CHAR LIMIT=NONE] -->
-    <string name="usb_summary_power_only">Supplying power</string>
+    <string name="usb_summary_power_only">Charging connected device</string>
     <!-- Settings item summary for USB preference when set to transferring files via MTP [CHAR LIMIT=NONE] -->
-    <string name="usb_summary_file_transfers">Transferring files</string>
+    <string name="usb_summary_file_transfers">File transfer</string>
+    <!-- Settings item summary for USB preference when set to USB tethering [CHAR LIMIT=NONE] -->
+    <string name="usb_summary_tether">USB tethering</string>
     <!-- Settings item summary for USB preference when set to transferring photos via PTP [CHAR LIMIT=NONE] -->
-    <string name="usb_summary_photo_transfers">Transferring photos (PTP)</string>
+    <string name="usb_summary_photo_transfers">PTP</string>
     <!-- Settings item summary for USB preference when set to entering MIDI mode [CHAR LIMIT=NONE] -->
-    <string name="usb_summary_MIDI">Using device as MIDI</string>
+    <string name="usb_summary_MIDI">MIDI</string>
+    <!-- Settings item summary for USB preference when set to transferring files via MTP
+          and powering other device [CHAR LIMIT=NONE] -->
+    <string name="usb_summary_file_transfers_power">File transfer and supplying power</string>
+    <!-- Settings item summary for USB preference when set to USB tethering
+         and powering other device [CHAR LIMIT=NONE] -->
+    <string name="usb_summary_tether_power">USB tethering and supplying power</string>
+    <!-- Settings item summary for USB preference when set to transferring photos via PTP
+         and powering other device [CHAR LIMIT=NONE] -->
+    <string name="usb_summary_photo_transfers_power">PTP and supplying power</string>
+    <!-- Settings item summary for USB preference when set to entering MIDI mode
+         and powering other device [CHAR LIMIT=NONE] -->
+    <string name="usb_summary_MIDI_power">MIDI and supplying power</string>
 
     <!-- Settings item title for SMS Mirroring preference [CHAR LIMIT=35] -->
     <string name="sms_mirroring_pref">SMS Mirroring</string>
@@ -8345,8 +8367,10 @@
     <!-- Backup disabled summary [CHAR LIMIT=NONE] -->
     <string name="backup_disabled">Back up disabled</string>
 
-    <!-- Summary of device info page [CHAR LIMIT=NONE] -->
-    <string name="about_summary">Updated to Android <xliff:g id="version" example="6.0">%1$s</xliff:g></string>
+    <!-- Summary of Android version info [CHAR LIMIT=NONE] -->
+    <string name="android_version_summary">Updated to Android <xliff:g id="version" example="6.0">%1$s</xliff:g></string>
+    <!-- Summary of Android version info (when there is a pending upgrade available) [CHAR LIMIT=NONE] -->
+    <string name="android_version_pending_update_summary">Update available</string>
 
     <!-- Title for dialog displayed when user clicks on a setting locked by an admin [CHAR LIMIT=30] -->
     <string name="disabled_by_policy_title">Action not allowed</string>
diff --git a/res/xml/connected_devices_advanced.xml b/res/xml/connected_devices_advanced.xml
index 8ca6b81..0b75abf 100644
--- a/res/xml/connected_devices_advanced.xml
+++ b/res/xml/connected_devices_advanced.xml
@@ -57,16 +57,6 @@
         android:order="-2"/>
 
     <Preference
-        android:key="usb_mode"
-        android:title="@string/usb_pref"
-        android:icon="@drawable/ic_usb"
-        android:order="-1">
-        <intent android:action="android.intent.action.MAIN"
-                android:targetPackage="com.android.settings"
-                android:targetClass="com.android.settings.deviceinfo.UsbModeChooserActivity"/>
-    </Preference>
-
-    <Preference
         android:key="bt_received_files"
         android:icon="@drawable/ic_folder_vd_theme_24"
         android:title="@string/bluetooth_show_received_files" />
diff --git a/res/xml/connected_devices_old.xml b/res/xml/connected_devices_old.xml
index 3eb62ea..cc7b5b4 100644
--- a/res/xml/connected_devices_old.xml
+++ b/res/xml/connected_devices_old.xml
@@ -53,7 +53,7 @@
         android:order="-2">
         <intent android:action="android.intent.action.MAIN"
                 android:targetPackage="com.android.settings"
-                android:targetClass="com.android.settings.deviceinfo.UsbModeChooserActivity"/>
+                android:targetClass="com.android.settings.connecteddevice.usb.UsbModeChooserActivity"/>
     </Preference>
 
     <PreferenceCategory
diff --git a/res/xml/system_dashboard_fragment.xml b/res/xml/system_dashboard_fragment.xml
index 73aab4b..d8459dd 100644
--- a/res/xml/system_dashboard_fragment.xml
+++ b/res/xml/system_dashboard_fragment.xml
@@ -55,7 +55,7 @@
         android:summary="@string/summary_placeholder"
         android:icon="@drawable/ic_system_update"
         android:order="-30"
-        settings:controller="com.android.settings.deviceinfo.SystemUpdatePreferenceController">
+        settings:controller="com.android.settings.system.SystemUpdatePreferenceController">
         <intent android:action="android.settings.SYSTEM_UPDATE_SETTINGS" />
     </Preference>
 
@@ -63,7 +63,7 @@
         android:key="additional_system_update_settings"
         android:title="@string/additional_system_update_settings_list_item_title"
         android:order="-31"
-        settings:controller="com.android.settings.deviceinfo.AdditionalSystemUpdatePreferenceController">
+        settings:controller="com.android.settings.system.AdditionalSystemUpdatePreferenceController">
         <intent android:action="android.intent.action.MAIN"
                 android:targetPackage="@string/additional_system_update"
                 android:targetClass="@string/additional_system_update_menu" />
diff --git a/res/xml/usb_details_fragment.xml b/res/xml/usb_details_fragment.xml
new file mode 100644
index 0000000..30ca993
--- /dev/null
+++ b/res/xml/usb_details_fragment.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright (C) 2017 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/device_details_title">
+
+    <com.android.settings.applications.LayoutPreference
+        android:key="usb_device_header"
+        android:layout="@layout/settings_entity_header"
+        android:selectable="false"/>
+
+    <PreferenceCategory
+        android:key="usb_main_options"
+        android:title="@string/usb_use"/>
+
+    <PreferenceCategory
+        android:key="usb_secondary_options"
+        android:title="@string/usb_use_also"/>
+
+</PreferenceScreen>
diff --git a/src/com/android/settings/Settings.java b/src/com/android/settings/Settings.java
index 7bd85cd..741bfda 100644
--- a/src/com/android/settings/Settings.java
+++ b/src/com/android/settings/Settings.java
@@ -96,6 +96,7 @@
     public static class ZenAccessSettingsActivity extends SettingsActivity { /* empty */ }
     public static class ConditionProviderSettingsActivity extends SettingsActivity { /* empty */ }
     public static class UsbSettingsActivity extends SettingsActivity { /* empty */ }
+    public static class UsbDetailsActivity extends SettingsActivity { /* empty */ }
     public static class TrustedCredentialsSettingsActivity extends SettingsActivity { /* empty */ }
     public static class PaymentSettingsActivity extends SettingsActivity { /* empty */ }
     public static class PrintSettingsActivity extends SettingsActivity { /* empty */ }
diff --git a/src/com/android/settings/connecteddevice/AdvancedConnectedDeviceDashboardFragment.java b/src/com/android/settings/connecteddevice/AdvancedConnectedDeviceDashboardFragment.java
index 2a136bc..9ac6ebd 100644
--- a/src/com/android/settings/connecteddevice/AdvancedConnectedDeviceDashboardFragment.java
+++ b/src/com/android/settings/connecteddevice/AdvancedConnectedDeviceDashboardFragment.java
@@ -24,8 +24,9 @@
 import com.android.settings.bluetooth.BluetoothFilesPreferenceController;
 import com.android.settings.bluetooth.BluetoothMasterSwitchPreferenceController;
 import com.android.settings.bluetooth.BluetoothSwitchPreferenceController;
+import com.android.settings.connecteddevice.usb.UsbBackend;
+import com.android.settings.connecteddevice.usb.UsbModePreferenceController;
 import com.android.settings.dashboard.DashboardFragment;
-import com.android.settings.deviceinfo.UsbBackend;
 import com.android.settings.nfc.NfcPreferenceController;
 import com.android.settings.overlay.FeatureFactory;
 import com.android.settings.search.BaseSearchIndexProvider;
diff --git a/src/com/android/settings/connecteddevice/ConnectedDeviceDashboardFragmentOld.java b/src/com/android/settings/connecteddevice/ConnectedDeviceDashboardFragmentOld.java
index 7097b36..bde5e81 100644
--- a/src/com/android/settings/connecteddevice/ConnectedDeviceDashboardFragmentOld.java
+++ b/src/com/android/settings/connecteddevice/ConnectedDeviceDashboardFragmentOld.java
@@ -26,9 +26,10 @@
 import com.android.settings.SettingsActivity;
 import com.android.settings.bluetooth.BluetoothMasterSwitchPreferenceController;
 import com.android.settings.bluetooth.Utils;
+import com.android.settings.connecteddevice.usb.UsbBackend;
+import com.android.settings.connecteddevice.usb.UsbModePreferenceController;
 import com.android.settings.dashboard.DashboardFragment;
 import com.android.settings.dashboard.SummaryLoader;
-import com.android.settings.deviceinfo.UsbBackend;
 import com.android.settings.nfc.NfcPreferenceController;
 import com.android.settings.overlay.FeatureFactory;
 import com.android.settings.search.BaseSearchIndexProvider;
diff --git a/src/com/android/settings/connecteddevice/ConnectedDeviceGroupController.java b/src/com/android/settings/connecteddevice/ConnectedDeviceGroupController.java
index 3cccc15..3d5d0e5 100644
--- a/src/com/android/settings/connecteddevice/ConnectedDeviceGroupController.java
+++ b/src/com/android/settings/connecteddevice/ConnectedDeviceGroupController.java
@@ -20,6 +20,7 @@
 import android.support.v7.preference.PreferenceGroup;
 import android.support.v7.preference.PreferenceScreen;
 
+import com.android.settings.connecteddevice.usb.ConnectedUsbDeviceUpdater;
 import com.android.settings.core.PreferenceControllerMixin;
 import com.android.settings.bluetooth.BluetoothDeviceUpdater;
 import com.android.settings.bluetooth.ConnectedBluetoothDeviceUpdater;
@@ -48,7 +49,7 @@
     public ConnectedDeviceGroupController(DashboardFragment fragment, Lifecycle lifecycle) {
         super(fragment.getContext());
         init(lifecycle, new ConnectedBluetoothDeviceUpdater(fragment, this),
-                new ConnectedUsbDeviceUpdater(fragment.getContext(), this));
+                new ConnectedUsbDeviceUpdater(fragment, this));
     }
 
     @VisibleForTesting
diff --git a/src/com/android/settings/connecteddevice/UsbConnectionBroadcastReceiver.java b/src/com/android/settings/connecteddevice/UsbConnectionBroadcastReceiver.java
deleted file mode 100644
index 07a7691..0000000
--- a/src/com/android/settings/connecteddevice/UsbConnectionBroadcastReceiver.java
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * Copyright (C) 2017 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.connecteddevice;
-
-
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.hardware.usb.UsbManager;
-
-/**
- * Receiver to receive usb update and use {@link UsbConnectionListener} to invoke callback
- */
-public class UsbConnectionBroadcastReceiver extends BroadcastReceiver {
-    private Context mContext;
-    private UsbConnectionListener mUsbConnectionListener;
-    private boolean mListeningToUsbEvents;
-    private boolean mConnected;
-
-    public UsbConnectionBroadcastReceiver(Context context,
-            UsbConnectionListener usbConnectionListener) {
-        mContext = context;
-        mUsbConnectionListener = usbConnectionListener;
-    }
-
-    @Override
-    public void onReceive(Context context, Intent intent) {
-        mConnected = intent != null
-                && intent.getExtras().getBoolean(UsbManager.USB_CONNECTED);
-        if (mUsbConnectionListener != null) {
-            mUsbConnectionListener.onUsbConnectionChanged(mConnected);
-        }
-    }
-
-    public void register() {
-        if (!mListeningToUsbEvents) {
-            final IntentFilter intentFilter = new IntentFilter(UsbManager.ACTION_USB_STATE);
-            final Intent intent = mContext.registerReceiver(this, intentFilter);
-            mConnected = intent != null
-                    && intent.getExtras().getBoolean(UsbManager.USB_CONNECTED);
-            mListeningToUsbEvents = true;
-        }
-    }
-
-    public void unregister() {
-        if (mListeningToUsbEvents) {
-            mContext.unregisterReceiver(this);
-            mListeningToUsbEvents = false;
-        }
-    }
-
-    public boolean isConnected() {
-        return mConnected;
-    }
-
-    /**
-     * Interface definition for a callback to be invoked when usb connection is changed.
-     */
-    interface UsbConnectionListener {
-        void onUsbConnectionChanged(boolean connected);
-    }
-}
diff --git a/src/com/android/settings/connecteddevice/ConnectedUsbDeviceUpdater.java b/src/com/android/settings/connecteddevice/usb/ConnectedUsbDeviceUpdater.java
similarity index 65%
rename from src/com/android/settings/connecteddevice/ConnectedUsbDeviceUpdater.java
rename to src/com/android/settings/connecteddevice/usb/ConnectedUsbDeviceUpdater.java
index 0468b0f..dd29902 100644
--- a/src/com/android/settings/connecteddevice/ConnectedUsbDeviceUpdater.java
+++ b/src/com/android/settings/connecteddevice/usb/ConnectedUsbDeviceUpdater.java
@@ -13,22 +13,24 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package com.android.settings.connecteddevice;
+package com.android.settings.connecteddevice.usb;
 
 import android.content.Context;
-import android.content.Intent;
+import android.os.Bundle;
 import android.support.annotation.VisibleForTesting;
+import android.support.v14.preference.PreferenceFragment;
 
 import com.android.settings.R;
-import com.android.settings.deviceinfo.UsbBackend;
-import com.android.settings.deviceinfo.UsbModeChooserActivity;
+import com.android.settings.SettingsActivity;
+import com.android.settings.connecteddevice.DevicePreferenceCallback;
+import com.android.settings.dashboard.DashboardFragment;
 import com.android.settings.widget.GearPreference;
 
 /**
  * Controller to maintain connected usb device
  */
 public class ConnectedUsbDeviceUpdater {
-    private Context mContext;
+    private PreferenceFragment mFragment;
     private UsbBackend mUsbBackend;
     private DevicePreferenceCallback mDevicePreferenceCallback;
     @VisibleForTesting
@@ -36,8 +38,9 @@
     @VisibleForTesting
     UsbConnectionBroadcastReceiver mUsbReceiver;
 
-    private UsbConnectionBroadcastReceiver.UsbConnectionListener mUsbConnectionListener =
-            (connected) -> {
+    @VisibleForTesting
+    UsbConnectionBroadcastReceiver.UsbConnectionListener mUsbConnectionListener =
+            (connected, newMode) -> {
                 if (connected) {
                     mUsbPreference.setSummary(
                             UsbModePreferenceController.getSummary(mUsbBackend.getCurrentMode()));
@@ -47,18 +50,19 @@
                 }
             };
 
-    public ConnectedUsbDeviceUpdater(Context context,
+    public ConnectedUsbDeviceUpdater(DashboardFragment fragment,
             DevicePreferenceCallback devicePreferenceCallback) {
-        this(context, devicePreferenceCallback, new UsbBackend(context));
+        this(fragment, devicePreferenceCallback, new UsbBackend(fragment.getContext()));
     }
 
     @VisibleForTesting
-    ConnectedUsbDeviceUpdater(Context context, DevicePreferenceCallback devicePreferenceCallback,
-            UsbBackend usbBackend) {
-        mContext = context;
+    ConnectedUsbDeviceUpdater(DashboardFragment fragment,
+            DevicePreferenceCallback devicePreferenceCallback, UsbBackend usbBackend) {
+        mFragment = fragment;
         mDevicePreferenceCallback = devicePreferenceCallback;
         mUsbBackend = usbBackend;
-        mUsbReceiver = new UsbConnectionBroadcastReceiver(context, mUsbConnectionListener);
+        mUsbReceiver = new UsbConnectionBroadcastReceiver(fragment.getContext(),
+                mUsbConnectionListener, mUsbBackend);
     }
 
     public void registerCallback() {
@@ -76,8 +80,12 @@
         mUsbPreference.setIcon(R.drawable.ic_usb);
         mUsbPreference.setSelectable(false);
         mUsbPreference.setOnGearClickListener((GearPreference p) -> {
-            final Intent intent = new Intent(mContext, UsbModeChooserActivity.class);
-            mContext.startActivity(intent);
+            // New version - uses a separate screen.
+            final Bundle args = new Bundle();
+            final SettingsActivity activity = (SettingsActivity) mFragment.getContext();
+            activity.startPreferencePanel(mFragment,
+                    UsbDetailsFragment.class.getName(), args,
+                    R.string.device_details_title, null /* titleText */, null /* resultTo */, 0);
         });
 
         forceUpdate();
@@ -87,6 +95,5 @@
         // Register so we can get the connection state from sticky intent.
         //TODO(b/70336520): Use an API to get data instead of sticky intent
         mUsbReceiver.register();
-        mUsbConnectionListener.onUsbConnectionChanged(mUsbReceiver.isConnected());
     }
 }
diff --git a/src/com/android/settings/connecteddevice/usb/OWNERS b/src/com/android/settings/connecteddevice/usb/OWNERS
new file mode 100644
index 0000000..add985c
--- /dev/null
+++ b/src/com/android/settings/connecteddevice/usb/OWNERS
@@ -0,0 +1,3 @@
+# Default reviewers for this and subdirectories.
+zhangjerry@google.com
+badhri@google.com
diff --git a/src/com/android/settings/connecteddevice/usb/UsbBackend.java b/src/com/android/settings/connecteddevice/usb/UsbBackend.java
new file mode 100644
index 0000000..cdfb6b0
--- /dev/null
+++ b/src/com/android/settings/connecteddevice/usb/UsbBackend.java
@@ -0,0 +1,247 @@
+/*
+ * Copyright (C) 2015 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.connecteddevice.usb;
+
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.hardware.usb.UsbManager;
+import android.hardware.usb.UsbPort;
+import android.hardware.usb.UsbPortStatus;
+import android.net.ConnectivityManager;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.support.annotation.VisibleForTesting;
+
+public class UsbBackend {
+
+    public static final int MODE_POWER_MASK  = 0x01;
+    public static final int MODE_POWER_SINK   = 0x00;
+    public static final int MODE_POWER_SOURCE = 0x01;
+
+    public static final int MODE_DATA_MASK  = 0x0f << 1;
+    public static final int MODE_DATA_NONE   = 0;
+    public static final int MODE_DATA_MTP    = 0x01 << 1;
+    public static final int MODE_DATA_PTP    = 0x01 << 2;
+    public static final int MODE_DATA_MIDI   = 0x01 << 3;
+    public static final int MODE_DATA_TETHER   = 0x01 << 4;
+
+    private final boolean mFileTransferRestricted;
+    private final boolean mFileTransferRestrictedBySystem;
+    private final boolean mTetheringRestricted;
+    private final boolean mTetheringRestrictedBySystem;
+    private final boolean mMidiSupported;
+    private final boolean mTetheringSupported;
+
+    private UsbManager mUsbManager;
+    @VisibleForTesting
+    UsbManagerPassThrough mUsbManagerPassThrough;
+    private UsbPort mPort;
+    private UsbPortStatus mPortStatus;
+
+    private Context mContext;
+
+    public UsbBackend(Context context) {
+        this(context, new UserRestrictionUtil(context), null);
+    }
+
+    @VisibleForTesting
+    public UsbBackend(Context context, UserRestrictionUtil userRestrictionUtil,
+            UsbManagerPassThrough usbManagerPassThrough) {
+        mContext = context;
+        mUsbManager = context.getSystemService(UsbManager.class);
+
+        mUsbManagerPassThrough = usbManagerPassThrough;
+        if (mUsbManagerPassThrough == null) {
+            mUsbManagerPassThrough = new UsbManagerPassThrough(mUsbManager);
+        }
+
+        mFileTransferRestricted = userRestrictionUtil.isUsbFileTransferRestricted();
+        mFileTransferRestrictedBySystem = userRestrictionUtil.isUsbFileTransferRestrictedBySystem();
+        mTetheringRestricted = userRestrictionUtil.isUsbTetheringRestricted();
+        mTetheringRestrictedBySystem = userRestrictionUtil.isUsbTetheringRestrictedBySystem();
+
+        mMidiSupported = context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_MIDI);
+        ConnectivityManager cm =
+                (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
+        mTetheringSupported = cm.isTetheringSupported();
+
+        UsbPort[] ports = mUsbManager.getPorts();
+        if (ports == null) {
+            return;
+        }
+        // For now look for a connected port, in the future we should identify port in the
+        // notification and pick based on that.
+        final int N = ports.length;
+        for (int i = 0; i < N; i++) {
+            UsbPortStatus status = mUsbManager.getPortStatus(ports[i]);
+            if (status.isConnected()) {
+                mPort = ports[i];
+                mPortStatus = status;
+                break;
+            }
+        }
+    }
+
+    public int getCurrentMode() {
+        if (mPort != null) {
+            int power = mPortStatus.getCurrentPowerRole() == UsbPort.POWER_ROLE_SOURCE
+                    && mPortStatus.isConnected()
+                    ? MODE_POWER_SOURCE : MODE_POWER_SINK;
+            return power | getUsbDataMode();
+        }
+        return MODE_POWER_SINK | getUsbDataMode();
+    }
+
+    public int getUsbDataMode() {
+        long functions = mUsbManagerPassThrough.getCurrentFunctions();
+        if (functions == UsbManager.FUNCTION_MTP) {
+            return MODE_DATA_MTP;
+        } else if (functions == UsbManager.FUNCTION_PTP) {
+            return MODE_DATA_PTP;
+        } else if (functions == UsbManager.FUNCTION_MIDI) {
+            return MODE_DATA_MIDI;
+        } else if (functions == UsbManager.FUNCTION_RNDIS) {
+            return MODE_DATA_TETHER;
+        }
+        return MODE_DATA_NONE;
+    }
+
+    private void setUsbFunction(int mode) {
+        switch (mode) {
+            case MODE_DATA_MTP:
+                mUsbManager.setCurrentFunctions(UsbManager.FUNCTION_MTP);
+                break;
+            case MODE_DATA_PTP:
+                mUsbManager.setCurrentFunctions(UsbManager.FUNCTION_PTP);
+                break;
+            case MODE_DATA_MIDI:
+                mUsbManager.setCurrentFunctions(UsbManager.FUNCTION_MIDI);
+                break;
+            case MODE_DATA_TETHER:
+                mUsbManager.setCurrentFunctions(UsbManager.FUNCTION_RNDIS);
+                break;
+            default:
+                mUsbManager.setCurrentFunctions(UsbManager.FUNCTION_NONE);
+                break;
+        }
+    }
+
+    public void setMode(int mode) {
+        if (mPort != null) {
+            int powerRole = modeToPower(mode);
+            // If we aren't using any data modes and we support host mode, then go to host mode
+            // so maybe? the other device can provide data if it wants, otherwise go into device
+            // mode because we have no choice.
+            int dataRole = (mode & MODE_DATA_MASK) == MODE_DATA_NONE
+                    && mPortStatus.isRoleCombinationSupported(powerRole, UsbPort.DATA_ROLE_HOST)
+                    ? UsbPort.DATA_ROLE_HOST : UsbPort.DATA_ROLE_DEVICE;
+            mUsbManager.setPortRoles(mPort, powerRole, dataRole);
+        }
+        setUsbFunction(mode & MODE_DATA_MASK);
+    }
+
+    private int modeToPower(int mode) {
+        return (mode & MODE_POWER_MASK) == MODE_POWER_SOURCE
+                    ? UsbPort.POWER_ROLE_SOURCE : UsbPort.POWER_ROLE_SINK;
+    }
+
+    public boolean isModeDisallowed(int mode) {
+        if (mFileTransferRestricted && ((mode & MODE_DATA_MASK) == MODE_DATA_MTP
+                || (mode & MODE_DATA_MASK) == MODE_DATA_PTP)) {
+            return true;
+        } else if (mTetheringRestricted && ((mode & MODE_DATA_MASK) == MODE_DATA_TETHER)) {
+            return true;
+        }
+        return false;
+    }
+
+    public boolean isModeDisallowedBySystem(int mode) {
+        if (mFileTransferRestrictedBySystem && ((mode & MODE_DATA_MASK) == MODE_DATA_MTP
+                || (mode & MODE_DATA_MASK) == MODE_DATA_PTP)) {
+            return true;
+        } else if (mTetheringRestrictedBySystem && ((mode & MODE_DATA_MASK) == MODE_DATA_TETHER)) {
+            return true;
+        }
+        return false;
+    }
+
+    public boolean isModeSupported(int mode) {
+        if (!mMidiSupported && (mode & MODE_DATA_MASK) == MODE_DATA_MIDI) {
+            return false;
+        }
+        if (!mTetheringSupported && (mode & MODE_DATA_MASK) == MODE_DATA_TETHER) {
+                return false;
+        }
+        if (mPort != null) {
+            int power = modeToPower(mode);
+            if ((mode & MODE_DATA_MASK) != 0) {
+                // We have a port and data, need to be in device mode.
+                return mPortStatus.isRoleCombinationSupported(power,
+                        UsbPort.DATA_ROLE_DEVICE);
+            } else {
+                // No data needed, we can do this power mode in either device or host.
+                return mPortStatus.isRoleCombinationSupported(power, UsbPort.DATA_ROLE_DEVICE)
+                        || mPortStatus.isRoleCombinationSupported(power, UsbPort.DATA_ROLE_HOST);
+            }
+        }
+        // No port, support sink modes only.
+        return (mode & MODE_POWER_MASK) != MODE_POWER_SOURCE;
+    }
+
+    // Wrapper class to enable testing with UserManager APIs
+    public static class UserRestrictionUtil {
+        private UserManager mUserManager;
+
+        public UserRestrictionUtil(Context context) {
+            mUserManager = UserManager.get(context);
+        }
+
+        public boolean isUsbFileTransferRestricted() {
+            return mUserManager.hasUserRestriction(UserManager.DISALLOW_USB_FILE_TRANSFER);
+        }
+
+        public boolean isUsbTetheringRestricted() {
+            return mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_TETHERING);
+        }
+
+        public boolean isUsbFileTransferRestrictedBySystem() {
+            return mUserManager.hasBaseUserRestriction(
+                UserManager.DISALLOW_USB_FILE_TRANSFER, UserHandle.of(UserHandle.myUserId()));
+        }
+
+        public boolean isUsbTetheringRestrictedBySystem() {
+            return mUserManager.hasBaseUserRestriction(
+                UserManager.DISALLOW_CONFIG_TETHERING, UserHandle.of(UserHandle.myUserId()));
+        }
+    }
+
+    // Temporary pass-through to allow roboelectric to use getCurrentFunctions()
+    public static class UsbManagerPassThrough {
+        private UsbManager mUsbManager;
+
+        public UsbManagerPassThrough(UsbManager manager) {
+            mUsbManager = manager;
+        }
+
+        public long getCurrentFunctions() {
+            return mUsbManager.getCurrentFunctions();
+        }
+
+        public long usbFunctionsFromString(String str) {
+            return UsbManager.usbFunctionsFromString(str);
+        }
+    }
+}
diff --git a/src/com/android/settings/connecteddevice/usb/UsbConnectionBroadcastReceiver.java b/src/com/android/settings/connecteddevice/usb/UsbConnectionBroadcastReceiver.java
new file mode 100644
index 0000000..91d22dc
--- /dev/null
+++ b/src/com/android/settings/connecteddevice/usb/UsbConnectionBroadcastReceiver.java
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2017 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.connecteddevice.usb;
+
+
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.hardware.usb.UsbManager;
+import android.hardware.usb.UsbPort;
+import android.hardware.usb.UsbPortStatus;
+
+import com.android.settingslib.core.lifecycle.LifecycleObserver;
+import com.android.settingslib.core.lifecycle.events.OnResume;
+import com.android.settingslib.core.lifecycle.events.OnPause;
+
+/**
+ * Receiver to receive usb update and use {@link UsbConnectionListener} to invoke callback
+ */
+public class UsbConnectionBroadcastReceiver extends BroadcastReceiver implements LifecycleObserver,
+        OnResume, OnPause {
+    private Context mContext;
+    private UsbConnectionListener mUsbConnectionListener;
+    private boolean mListeningToUsbEvents;
+    private int mMode;
+    private boolean mConnected;
+    private UsbBackend mUsbBackend;
+
+    public UsbConnectionBroadcastReceiver(Context context,
+            UsbConnectionListener usbConnectionListener, UsbBackend backend) {
+        mContext = context;
+        mUsbConnectionListener = usbConnectionListener;
+        mUsbBackend = backend;
+    }
+
+    @Override
+    public void onReceive(Context context, Intent intent) {
+        if (UsbManager.ACTION_USB_STATE.equals(intent.getAction())) {
+            mConnected = intent.getExtras().getBoolean(UsbManager.USB_CONNECTED)
+                    || intent.getExtras().getBoolean(UsbManager.USB_HOST_CONNECTED);
+            if (mConnected) {
+                mMode &= UsbBackend.MODE_POWER_MASK;
+                if (intent.getExtras().getBoolean(UsbManager.USB_FUNCTION_MTP)
+                        && intent.getExtras().getBoolean(UsbManager.USB_DATA_UNLOCKED, false)) {
+                    mMode |= UsbBackend.MODE_DATA_MTP;
+                }
+                if (intent.getExtras().getBoolean(UsbManager.USB_FUNCTION_PTP)
+                        && intent.getExtras().getBoolean(UsbManager.USB_DATA_UNLOCKED, false)) {
+                    mMode |= UsbBackend.MODE_DATA_PTP;
+                }
+                if (intent.getExtras().getBoolean(UsbManager.USB_FUNCTION_MIDI)) {
+                    mMode |= UsbBackend.MODE_DATA_MIDI;
+                }
+                if (intent.getExtras().getBoolean(UsbManager.USB_FUNCTION_RNDIS)) {
+                    mMode |= UsbBackend.MODE_DATA_TETHER;
+                }
+            }
+        } else if (UsbManager.ACTION_USB_PORT_CHANGED.equals(intent.getAction())) {
+            mMode &= UsbBackend.MODE_DATA_MASK;
+            UsbPortStatus portStatus = intent.getExtras()
+                    .getParcelable(UsbManager.EXTRA_PORT_STATUS);
+            if (portStatus != null) {
+                mConnected = portStatus.isConnected();
+                if (mConnected) {
+                    mMode |= portStatus.getCurrentPowerRole() == UsbPort.POWER_ROLE_SOURCE
+                            ? UsbBackend.MODE_POWER_SOURCE : UsbBackend.MODE_POWER_SINK;
+                }
+            }
+        }
+        if (mUsbConnectionListener != null) {
+            mUsbConnectionListener.onUsbConnectionChanged(mConnected, mMode);
+        }
+    }
+
+    public void register() {
+        if (!mListeningToUsbEvents) {
+            mMode = mUsbBackend.getCurrentMode();
+            mConnected = false;
+            final IntentFilter intentFilter = new IntentFilter();
+            intentFilter.addAction(UsbManager.ACTION_USB_STATE);
+            intentFilter.addAction(UsbManager.ACTION_USB_PORT_CHANGED);
+            mContext.registerReceiver(this, intentFilter);
+            mListeningToUsbEvents = true;
+        }
+    }
+
+    public void unregister() {
+        if (mListeningToUsbEvents) {
+            mContext.unregisterReceiver(this);
+            mListeningToUsbEvents = false;
+        }
+    }
+
+    public boolean isConnected() {
+        return mConnected;
+    }
+
+    @Override
+    public void onResume() {
+        register();
+    }
+
+    @Override
+    public void onPause() {
+        unregister();
+    }
+
+    /**
+     * Interface definition for a callback to be invoked when usb connection is changed.
+     */
+    interface UsbConnectionListener {
+        void onUsbConnectionChanged(boolean connected, int newMode);
+    }
+}
diff --git a/src/com/android/settings/connecteddevice/usb/UsbDetailsController.java b/src/com/android/settings/connecteddevice/usb/UsbDetailsController.java
new file mode 100644
index 0000000..09c7554
--- /dev/null
+++ b/src/com/android/settings/connecteddevice/usb/UsbDetailsController.java
@@ -0,0 +1,54 @@
+/*
+ * 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.connecteddevice.usb;
+
+import android.content.Context;
+import android.support.annotation.UiThread;
+import android.support.v14.preference.PreferenceFragment;
+
+import com.android.settings.core.PreferenceControllerMixin;
+import com.android.settingslib.core.AbstractPreferenceController;
+
+/**
+ * This class provides common members and refresh functionality for usb controllers.
+ */
+public abstract class UsbDetailsController extends AbstractPreferenceController
+        implements PreferenceControllerMixin {
+
+    protected final Context mContext;
+    protected final PreferenceFragment mFragment;
+    protected final UsbBackend mUsbBackend;
+
+    public UsbDetailsController(Context context, PreferenceFragment fragment, UsbBackend backend) {
+        super(context);
+        mContext = context;
+        mFragment = fragment;
+        mUsbBackend = backend;
+    }
+
+    @Override
+    public boolean isAvailable() {
+        return true;
+    }
+
+    /**
+     * This method is called when the USB mode has changed and the controller needs to update.
+     * @param newMode the new mode, made up of OR'd values from UsbBackend
+     */
+    @UiThread
+    protected abstract void refresh(int newMode);
+}
diff --git a/src/com/android/settings/connecteddevice/usb/UsbDetailsFragment.java b/src/com/android/settings/connecteddevice/usb/UsbDetailsFragment.java
new file mode 100644
index 0000000..c861188
--- /dev/null
+++ b/src/com/android/settings/connecteddevice/usb/UsbDetailsFragment.java
@@ -0,0 +1,131 @@
+/*
+ * 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.connecteddevice.usb;
+
+import android.content.Context;
+import android.hardware.usb.UsbManager;
+import android.os.Bundle;
+import android.provider.SearchIndexableResource;
+import android.support.annotation.VisibleForTesting;
+
+import com.android.internal.logging.nano.MetricsProto;
+import com.android.settings.R;
+
+import com.android.settings.dashboard.DashboardFragment;
+import com.android.settings.search.BaseSearchIndexProvider;
+import com.android.settings.search.Indexable;
+import com.android.settingslib.core.AbstractPreferenceController;
+
+import com.google.android.collect.Lists;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Controls the USB device details and provides updates to individual controllers.
+ */
+public class UsbDetailsFragment extends DashboardFragment {
+    private static final String TAG = UsbDetailsFragment.class.getSimpleName();
+
+    private List<UsbDetailsController> mControllers;
+    private UsbBackend mUsbBackend;
+
+    @VisibleForTesting
+    UsbConnectionBroadcastReceiver mUsbReceiver;
+
+    private UsbConnectionBroadcastReceiver.UsbConnectionListener mUsbConnectionListener =
+            (connected, newMode) -> {
+                if (!connected) {
+                    this.finish();
+                } else {
+                    for (UsbDetailsController controller : mControllers) {
+                        controller.refresh(newMode);
+                    }
+                }
+            };
+
+    @Override
+    public int getMetricsCategory() {
+        return MetricsProto.MetricsEvent.USB_DEVICE_DETAILS;
+    }
+
+    @Override
+    protected String getLogTag() {
+        return TAG;
+    }
+
+    @Override
+    protected int getPreferenceScreenResId() {
+        return R.xml.usb_details_fragment;
+    }
+
+    @Override
+    public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
+        super.onCreatePreferences(savedInstanceState, rootKey);
+    }
+
+    @Override
+    protected List<AbstractPreferenceController> getPreferenceControllers(Context context) {
+        mUsbBackend = new UsbBackend(context);
+        mControllers = createControllerList(context, mUsbBackend, this);
+        mUsbReceiver = new UsbConnectionBroadcastReceiver(context, mUsbConnectionListener,
+                mUsbBackend);
+        this.getLifecycle().addObserver(mUsbReceiver);
+
+        List<AbstractPreferenceController> ret = new ArrayList<>();
+        ret.addAll(mControllers);
+        return ret;
+    }
+
+    private static List<UsbDetailsController> createControllerList(Context context,
+            UsbBackend usbBackend, DashboardFragment fragment) {
+        List<UsbDetailsController> ret = new ArrayList<>();
+        ret.add(new UsbDetailsHeaderController(context, fragment, usbBackend));
+        ret.add(new UsbDetailsProfilesController(context, fragment,
+                usbBackend, Lists.newArrayList(UsbManager.USB_FUNCTION_MTP), "usb_main_options"));
+        ret.add(new UsbDetailsProfilesController(context, fragment,
+                usbBackend, Lists.newArrayList(UsbDetailsProfilesController.KEY_POWER,
+                UsbManager.USB_FUNCTION_RNDIS, UsbManager.USB_FUNCTION_MIDI,
+                UsbManager.USB_FUNCTION_PTP), "usb_secondary_options"));
+        return ret;
+    }
+
+    /**
+     * For Search.
+     */
+    public static final Indexable.SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
+            new BaseSearchIndexProvider() {
+                @Override
+                public List<SearchIndexableResource> getXmlResourcesToIndex(
+                        Context context, boolean enabled) {
+                    return new ArrayList<>();
+                }
+
+                @Override
+                public List<String> getNonIndexableKeys(Context context) {
+                    return super.getNonIndexableKeys(context);
+                }
+
+                @Override
+                public List<AbstractPreferenceController> getPreferenceControllers(
+                        Context context) {
+                    List<AbstractPreferenceController> ret = new ArrayList<>();
+                    ret.addAll(createControllerList(context, new UsbBackend(context), null));
+                    return ret;
+                }
+            };
+}
diff --git a/src/com/android/settings/connecteddevice/usb/UsbDetailsHeaderController.java b/src/com/android/settings/connecteddevice/usb/UsbDetailsHeaderController.java
new file mode 100644
index 0000000..7ac0235
--- /dev/null
+++ b/src/com/android/settings/connecteddevice/usb/UsbDetailsHeaderController.java
@@ -0,0 +1,64 @@
+/*
+ * 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.connecteddevice.usb;
+
+import android.content.Context;
+import android.support.v14.preference.PreferenceFragment;
+import android.support.v7.preference.PreferenceScreen;
+
+import com.android.settings.R;
+import com.android.settings.applications.LayoutPreference;
+import com.android.settings.widget.EntityHeaderController;
+
+/**
+ * This class adds a header with device name and current function.
+ */
+public class UsbDetailsHeaderController extends UsbDetailsController {
+    private static final String KEY_DEVICE_HEADER = "usb_device_header";
+
+    private EntityHeaderController mHeaderController;
+
+    public UsbDetailsHeaderController(Context context, PreferenceFragment fragment,
+            UsbBackend backend) {
+        super(context, fragment, backend);
+    }
+
+    @Override
+    public void displayPreference(PreferenceScreen screen) {
+        super.displayPreference(screen);
+        final LayoutPreference headerPreference =
+                (LayoutPreference) screen.findPreference(KEY_DEVICE_HEADER);
+        mHeaderController = EntityHeaderController.newInstance(mFragment.getActivity(), mFragment,
+                headerPreference.findViewById(R.id.entity_header));
+        screen.addPreference(headerPreference);
+    }
+
+
+    @Override
+    protected void refresh(int newMode) {
+        mHeaderController.setLabel(mContext.getString(R.string.usb_pref));
+        mHeaderController.setIcon(mContext.getDrawable(R.drawable.ic_usb));
+        mHeaderController.setSummary(
+                mContext.getString(UsbModePreferenceController.getSummary(newMode)));
+        mHeaderController.done(mFragment.getActivity(), true /* rebindActions */);
+    }
+
+    @Override
+    public String getPreferenceKey() {
+        return KEY_DEVICE_HEADER;
+    }
+}
diff --git a/src/com/android/settings/connecteddevice/usb/UsbDetailsProfilesController.java b/src/com/android/settings/connecteddevice/usb/UsbDetailsProfilesController.java
new file mode 100644
index 0000000..1375b4c
--- /dev/null
+++ b/src/com/android/settings/connecteddevice/usb/UsbDetailsProfilesController.java
@@ -0,0 +1,147 @@
+/*
+ * 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.connecteddevice.usb;
+
+import com.android.settings.R;
+import android.content.Context;
+import android.hardware.usb.UsbManager;
+import android.support.v14.preference.PreferenceFragment;
+import android.support.v14.preference.SwitchPreference;
+import android.support.v7.preference.Preference;
+import android.support.v7.preference.PreferenceCategory;
+import android.support.v7.preference.PreferenceScreen;
+
+import java.util.List;
+
+/**
+ * This class adds switches for toggling individual USB options, such as "transfer files",
+ * "supply power", "usb tethering", etc.
+ */
+public class UsbDetailsProfilesController extends UsbDetailsController
+        implements Preference.OnPreferenceClickListener {
+
+    static final String KEY_POWER = "power";
+
+    private PreferenceCategory mProfilesContainer;
+    private List<String> mOptions;
+    private String mKey;
+
+    public UsbDetailsProfilesController(Context context, PreferenceFragment fragment,
+            UsbBackend backend, List<String> options, String key) {
+        super(context, fragment, backend);
+        mOptions = options;
+        mKey = key;
+    }
+
+    @Override
+    public void displayPreference(PreferenceScreen screen) {
+        super.displayPreference(screen);
+        mProfilesContainer = (PreferenceCategory) screen.findPreference(getPreferenceKey());
+    }
+
+    /**
+     * Gets a switch preference for the particular option, creating it if needed.
+     */
+    private SwitchPreference getProfilePreference(String key, int titleId) {
+        SwitchPreference pref = (SwitchPreference) mProfilesContainer.findPreference(key);
+        if (pref == null) {
+            pref = new SwitchPreference(mProfilesContainer.getContext());
+            pref.setKey(key);
+            pref.setTitle(titleId);
+            pref.setOnPreferenceClickListener(this);
+            mProfilesContainer.addPreference(pref);
+        }
+        return pref;
+    }
+
+    @Override
+    protected void refresh(int mode) {
+        SwitchPreference pref;
+        for (String option : mOptions) {
+            int newMode;
+            int summary = -1;
+            int title;
+            if (option.equals(UsbManager.USB_FUNCTION_MTP)) {
+                newMode = UsbBackend.MODE_DATA_MTP;
+                title = R.string.usb_use_file_transfers;
+            } else if (option.equals(KEY_POWER)) {
+                newMode = UsbBackend.MODE_POWER_SOURCE;
+                title = R.string.usb_use_power_only;
+                summary = R.string.usb_use_power_only_desc;
+            } else if (option.equals(UsbManager.USB_FUNCTION_PTP)) {
+                newMode = UsbBackend.MODE_DATA_PTP;
+                title = R.string.usb_use_photo_transfers;
+            } else if (option.equals(UsbManager.USB_FUNCTION_MIDI)) {
+                newMode = UsbBackend.MODE_DATA_MIDI;
+                title = R.string.usb_use_MIDI;
+            } else if (option.equals(UsbManager.USB_FUNCTION_RNDIS)) {
+                newMode = UsbBackend.MODE_DATA_TETHER;
+                title = R.string.usb_use_tethering;
+            } else {
+                continue;
+            }
+
+            pref = getProfilePreference(option, title);
+            // Only show supported and allowed options
+            if (mUsbBackend.isModeSupported(newMode)
+                    && !mUsbBackend.isModeDisallowedBySystem(newMode)
+                    && !mUsbBackend.isModeDisallowed(newMode)) {
+                if (summary != -1) {
+                    pref.setSummary(summary);
+                }
+                pref.setChecked((mode & newMode) != 0);
+            } else {
+                mProfilesContainer.removePreference(pref);
+            }
+        }
+    }
+
+    @Override
+    public boolean onPreferenceClick(Preference preference) {
+        SwitchPreference profilePref = (SwitchPreference) preference;
+        String key = profilePref.getKey();
+        int mode = mUsbBackend.getCurrentMode();
+        int thisMode = 0;
+        if (key.equals(KEY_POWER)) {
+            thisMode = UsbBackend.MODE_POWER_SOURCE;
+        } else if (key.equals(UsbManager.USB_FUNCTION_MTP)) {
+            thisMode = UsbBackend.MODE_DATA_MTP;
+        } else if (key.equals(UsbManager.USB_FUNCTION_PTP)) {
+            thisMode = UsbBackend.MODE_DATA_PTP;
+        } else if (key.equals(UsbManager.USB_FUNCTION_RNDIS)) {
+            thisMode = UsbBackend.MODE_DATA_TETHER;
+        } else if (key.equals(UsbManager.USB_FUNCTION_MIDI)) {
+            thisMode = UsbBackend.MODE_DATA_MIDI;
+        }
+        if (profilePref.isChecked()) {
+            if (!key.equals(KEY_POWER)) {
+                // Only one non power mode can currently be set at once.
+                mode &= UsbBackend.MODE_POWER_MASK;
+            }
+            mode |= thisMode;
+        } else {
+            mode &= ~thisMode;
+        }
+        mUsbBackend.setMode(mode);
+        return false;
+    }
+
+    @Override
+    public String getPreferenceKey() {
+        return mKey;
+    }
+}
diff --git a/src/com/android/settings/deviceinfo/UsbModeChooserActivity.java b/src/com/android/settings/connecteddevice/usb/UsbModeChooserActivity.java
similarity index 98%
rename from src/com/android/settings/deviceinfo/UsbModeChooserActivity.java
rename to src/com/android/settings/connecteddevice/usb/UsbModeChooserActivity.java
index 8ba3781..b3b0718 100644
--- a/src/com/android/settings/deviceinfo/UsbModeChooserActivity.java
+++ b/src/com/android/settings/connecteddevice/usb/UsbModeChooserActivity.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.settings.deviceinfo;
+package com.android.settings.connecteddevice.usb;
 
 import android.annotation.Nullable;
 import android.app.Activity;
diff --git a/src/com/android/settings/connecteddevice/UsbModePreferenceController.java b/src/com/android/settings/connecteddevice/usb/UsbModePreferenceController.java
similarity index 72%
rename from src/com/android/settings/connecteddevice/UsbModePreferenceController.java
rename to src/com/android/settings/connecteddevice/usb/UsbModePreferenceController.java
index 8693520..e342460 100644
--- a/src/com/android/settings/connecteddevice/UsbModePreferenceController.java
+++ b/src/com/android/settings/connecteddevice/usb/UsbModePreferenceController.java
@@ -13,15 +13,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package com.android.settings.connecteddevice;
+package com.android.settings.connecteddevice.usb;
 
 import android.content.Context;
 import android.support.v7.preference.Preference;
 import android.support.v7.preference.PreferenceScreen;
 
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.settings.R;
 import com.android.settings.core.PreferenceControllerMixin;
-import com.android.settings.deviceinfo.UsbBackend;
 import com.android.settingslib.core.AbstractPreferenceController;
 import com.android.settingslib.core.lifecycle.LifecycleObserver;
 import com.android.settingslib.core.lifecycle.events.OnPause;
@@ -33,27 +33,27 @@
     private static final String KEY_USB_MODE = "usb_mode";
 
     private UsbBackend mUsbBackend;
-    private UsbConnectionBroadcastReceiver mUsbReceiver;
+    @VisibleForTesting
+    UsbConnectionBroadcastReceiver mUsbReceiver;
     private Preference mUsbPreference;
 
     public UsbModePreferenceController(Context context, UsbBackend usbBackend) {
         super(context);
         mUsbBackend = usbBackend;
-        mUsbReceiver = new UsbConnectionBroadcastReceiver(mContext, (connected) -> {
-            updateSummary(mUsbPreference);
-        });
+        mUsbReceiver = new UsbConnectionBroadcastReceiver(mContext, (connected, newMode) -> {
+            updateSummary(mUsbPreference, connected, newMode);
+        }, mUsbBackend);
     }
 
     @Override
     public void displayPreference(PreferenceScreen screen) {
         super.displayPreference(screen);
         mUsbPreference = screen.findPreference(KEY_USB_MODE);
-        updateSummary(mUsbPreference);
     }
 
     @Override
     public void updateState(Preference preference) {
-        updateSummary(preference);
+        updateSummary(preference, mUsbReceiver.isConnected(), mUsbBackend.getCurrentMode());
     }
 
     @Override
@@ -88,17 +88,24 @@
                 return R.string.usb_summary_photo_transfers;
             case UsbBackend.MODE_POWER_SINK | UsbBackend.MODE_DATA_MIDI:
                 return R.string.usb_summary_MIDI;
+            case UsbBackend.MODE_POWER_SINK | UsbBackend.MODE_DATA_TETHER:
+                return R.string.usb_summary_tether;
+            case UsbBackend.MODE_POWER_SOURCE | UsbBackend.MODE_DATA_MTP:
+                return R.string.usb_summary_file_transfers_power;
+            case UsbBackend.MODE_POWER_SOURCE | UsbBackend.MODE_DATA_PTP:
+                return R.string.usb_summary_photo_transfers_power;
+            case UsbBackend.MODE_POWER_SOURCE | UsbBackend.MODE_DATA_MIDI:
+                return R.string.usb_summary_MIDI_power;
+            case UsbBackend.MODE_POWER_SOURCE | UsbBackend.MODE_DATA_TETHER:
+                return R.string.usb_summary_tether_power;
+            default:
+                return R.string.usb_summary_charging_only;
         }
-        return 0;
     }
 
-    private void updateSummary(Preference preference) {
-        updateSummary(preference, mUsbBackend.getCurrentMode());
-    }
-
-    private void updateSummary(Preference preference, int mode) {
+    private void updateSummary(Preference preference, boolean connected, int mode) {
         if (preference != null) {
-            if (mUsbReceiver.isConnected()) {
+            if (connected) {
                 preference.setEnabled(true);
                 preference.setSummary(getSummary(mode));
             } else {
@@ -107,5 +114,4 @@
             }
         }
     }
-
 }
diff --git a/src/com/android/settings/core/gateway/SettingsGateway.java b/src/com/android/settings/core/gateway/SettingsGateway.java
index af85ac9..f43c3c8 100644
--- a/src/com/android/settings/core/gateway/SettingsGateway.java
+++ b/src/com/android/settings/core/gateway/SettingsGateway.java
@@ -58,6 +58,7 @@
 import com.android.settings.connecteddevice.AdvancedConnectedDeviceDashboardFragment;
 import com.android.settings.connecteddevice.ConnectedDeviceDashboardFragment;
 import com.android.settings.connecteddevice.ConnectedDeviceDashboardFragmentOld;
+import com.android.settings.connecteddevice.usb.UsbDetailsFragment;
 import com.android.settings.datausage.DataPlanUsageSummary;
 import com.android.settings.datausage.DataUsageList;
 import com.android.settings.datausage.DataUsageSummary;
@@ -242,6 +243,7 @@
             NetworkDashboardFragment.class.getName(),
             ConnectedDeviceDashboardFragment.class.getName(),
             ConnectedDeviceDashboardFragmentOld.class.getName(),
+            UsbDetailsFragment.class.getName(),
             AppAndNotificationDashboardFragment.class.getName(),
             AccountDashboardFragment.class.getName(),
             EnterprisePrivacySettings.class.getName(),
diff --git a/src/com/android/settings/dashboard/suggestions/SuggestionAdapter.java b/src/com/android/settings/dashboard/suggestions/SuggestionAdapter.java
index 070e758..9bcf2a2 100644
--- a/src/com/android/settings/dashboard/suggestions/SuggestionAdapter.java
+++ b/src/com/android/settings/dashboard/suggestions/SuggestionAdapter.java
@@ -116,7 +116,7 @@
         mConfig.setCardLayout(holder, suggestionCount, position);
         final Icon icon = suggestion.getIcon();
         final Drawable drawable = mCache.getIcon(icon);
-        if (drawable != null && TextUtils.equals(icon.getResPackage(), mContext.getPackageName())) {
+        if ((suggestion.getFlags() & Suggestion.FLAG_ICON_TINTABLE) != 0) {
             drawable.setTint(Utils.getColorAccent(mContext));
         }
         holder.icon.setImageDrawable(drawable);
diff --git a/src/com/android/settings/development/SelectUsbConfigPreferenceController.java b/src/com/android/settings/development/SelectUsbConfigPreferenceController.java
index 77a9a75..63eb24c 100644
--- a/src/com/android/settings/development/SelectUsbConfigPreferenceController.java
+++ b/src/com/android/settings/development/SelectUsbConfigPreferenceController.java
@@ -27,11 +27,11 @@
 import android.support.v7.preference.ListPreference;
 import android.support.v7.preference.Preference;
 import android.support.v7.preference.PreferenceScreen;
-import android.text.TextUtils;
 
 import com.android.settings.R;
 import com.android.settings.Utils;
 import com.android.settings.core.PreferenceControllerMixin;
+import com.android.settings.connecteddevice.usb.UsbBackend;
 import com.android.settingslib.core.lifecycle.Lifecycle;
 import com.android.settingslib.core.lifecycle.LifecycleObserver;
 import com.android.settingslib.core.lifecycle.events.OnCreate;
@@ -48,6 +48,8 @@
     private final String[] mListValues;
     private final String[] mListSummaries;
     private final UsbManager mUsbManager;
+    @VisibleForTesting
+    UsbBackend.UsbManagerPassThrough mUsbManagerPassThrough;
     private BroadcastReceiver mUsbReceiver;
     private ListPreference mPreference;
 
@@ -57,6 +59,7 @@
         mListValues = context.getResources().getStringArray(R.array.usb_configuration_values);
         mListSummaries = context.getResources().getStringArray(R.array.usb_configuration_titles);
         mUsbManager = (UsbManager) context.getSystemService(Context.USB_SERVICE);
+        mUsbManagerPassThrough = new UsbBackend.UsbManagerPassThrough(mUsbManager);
         mUsbReceiver = new BroadcastReceiver() {
             @Override
             public void onReceive(Context context, Intent intent) {
@@ -95,7 +98,8 @@
             return false;
         }
 
-        writeUsbConfigurationOption(newValue.toString());
+        writeUsbConfigurationOption(mUsbManagerPassThrough
+                .usbFunctionsFromString(newValue.toString()));
         updateUsbConfigurationValues();
         return true;
     }
@@ -129,14 +133,15 @@
     }
 
     @VisibleForTesting
-    void setCurrentFunction(String newValue, boolean usbDataUnlocked) {
-        mUsbManager.setCurrentFunction(newValue, usbDataUnlocked);
+    void setCurrentFunctions(long functions) {
+        mUsbManager.setCurrentFunctions(functions);
     }
 
     private void updateUsbConfigurationValues() {
+        long functions = mUsbManagerPassThrough.getCurrentFunctions();
         int index = 0;
         for (int i = 0; i < mListValues.length; i++) {
-            if (mUsbManager.isFunctionEnabled(mListValues[i])) {
+            if (functions == mUsbManagerPassThrough.usbFunctionsFromString(mListValues[i])) {
                 index = i;
                 break;
             }
@@ -145,11 +150,7 @@
         mPreference.setSummary(mListSummaries[index]);
     }
 
-    private void writeUsbConfigurationOption(String newValue) {
-        if (TextUtils.equals(newValue, "none")) {
-            setCurrentFunction(newValue, false);
-        } else {
-            setCurrentFunction(newValue, true);
-        }
+    private void writeUsbConfigurationOption(long newValue) {
+        setCurrentFunctions(newValue);
     }
 }
diff --git a/src/com/android/settings/deviceinfo/PhoneNumberPreferenceController.java b/src/com/android/settings/deviceinfo/PhoneNumberPreferenceController.java
index 93f75bf..4eb2ddd 100644
--- a/src/com/android/settings/deviceinfo/PhoneNumberPreferenceController.java
+++ b/src/com/android/settings/deviceinfo/PhoneNumberPreferenceController.java
@@ -58,7 +58,7 @@
 
     @Override
     public boolean isAvailable() {
-        return true;
+        return mTelephonyManager.isVoiceCapable();
     }
 
     @Override
diff --git a/src/com/android/settings/deviceinfo/UsbBackend.java b/src/com/android/settings/deviceinfo/UsbBackend.java
deleted file mode 100644
index 5d2502b..0000000
--- a/src/com/android/settings/deviceinfo/UsbBackend.java
+++ /dev/null
@@ -1,202 +0,0 @@
-/*
- * Copyright (C) 2015 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.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.pm.PackageManager;
-import android.hardware.usb.UsbManager;
-import android.hardware.usb.UsbPort;
-import android.hardware.usb.UsbPortStatus;
-import android.os.UserHandle;
-import android.os.UserManager;
-import android.support.annotation.VisibleForTesting;
-
-public class UsbBackend {
-
-    public static final int MODE_POWER_MASK  = 0x01;
-    public static final int MODE_POWER_SINK   = 0x00;
-    public static final int MODE_POWER_SOURCE = 0x01;
-
-    public static final int MODE_DATA_MASK  = 0x03 << 1;
-    public static final int MODE_DATA_NONE   = 0x00 << 1;
-    public static final int MODE_DATA_MTP    = 0x01 << 1;
-    public static final int MODE_DATA_PTP    = 0x02 << 1;
-    public static final int MODE_DATA_MIDI   = 0x03 << 1;
-
-    private final boolean mRestricted;
-    private final boolean mRestrictedBySystem;
-    private final boolean mMidi;
-
-    private UsbManager mUsbManager;
-    private UsbPort mPort;
-    private UsbPortStatus mPortStatus;
-
-    private Context mContext;
-
-    public UsbBackend(Context context) {
-        this(context, new UserRestrictionUtil(context));
-    }
-
-    @VisibleForTesting
-    public UsbBackend(Context context, UserRestrictionUtil userRestrictionUtil) {
-        mContext = context;
-        mUsbManager = context.getSystemService(UsbManager.class);
-
-        mRestricted = userRestrictionUtil.isUsbFileTransferRestricted();
-        mRestrictedBySystem = userRestrictionUtil.isUsbFileTransferRestrictedBySystem();
-        mMidi = context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_MIDI);
-
-        UsbPort[] ports = mUsbManager.getPorts();
-        if (ports == null) {
-            return;
-        }
-        // For now look for a connected port, in the future we should identify port in the
-        // notification and pick based on that.
-        final int N = ports.length;
-        for (int i = 0; i < N; i++) {
-            UsbPortStatus status = mUsbManager.getPortStatus(ports[i]);
-            if (status.isConnected()) {
-                mPort = ports[i];
-                mPortStatus = status;
-                break;
-            }
-        }
-    }
-
-    public int getCurrentMode() {
-        if (mPort != null) {
-            int power = mPortStatus.getCurrentPowerRole() == UsbPort.POWER_ROLE_SOURCE
-                    ? MODE_POWER_SOURCE : MODE_POWER_SINK;
-            return power | getUsbDataMode();
-        }
-        return MODE_POWER_SINK | getUsbDataMode();
-    }
-
-    public int getUsbDataMode() {
-        if (!isUsbDataUnlocked()) {
-            return MODE_DATA_NONE;
-        } else if (mUsbManager.isFunctionEnabled(UsbManager.USB_FUNCTION_MTP)) {
-            return MODE_DATA_MTP;
-        } else if (mUsbManager.isFunctionEnabled(UsbManager.USB_FUNCTION_PTP)) {
-            return MODE_DATA_PTP;
-        } else if (mUsbManager.isFunctionEnabled(UsbManager.USB_FUNCTION_MIDI)) {
-            return MODE_DATA_MIDI;
-        }
-        return MODE_DATA_NONE; // ...
-    }
-
-    private boolean isUsbDataUnlocked() {
-        Intent intent = mContext.registerReceiver(null,
-            new IntentFilter(UsbManager.ACTION_USB_STATE));
-        return intent == null ?
-            false : intent.getBooleanExtra(UsbManager.USB_DATA_UNLOCKED, false);
-    }
-
-    private void setUsbFunction(int mode) {
-        switch (mode) {
-            case MODE_DATA_MTP:
-                mUsbManager.setCurrentFunction(UsbManager.USB_FUNCTION_MTP, true);
-                break;
-            case MODE_DATA_PTP:
-                mUsbManager.setCurrentFunction(UsbManager.USB_FUNCTION_PTP, true);
-                break;
-            case MODE_DATA_MIDI:
-                mUsbManager.setCurrentFunction(UsbManager.USB_FUNCTION_MIDI, true);
-                break;
-            default:
-                mUsbManager.setCurrentFunction(null, false);
-                break;
-        }
-    }
-
-    public void setMode(int mode) {
-        if (mPort != null) {
-            int powerRole = modeToPower(mode);
-            // If we aren't using any data modes and we support host mode, then go to host mode
-            // so maybe? the other device can provide data if it wants, otherwise go into device
-            // mode because we have no choice.
-            int dataRole = (mode & MODE_DATA_MASK) == MODE_DATA_NONE
-                    && mPortStatus.isRoleCombinationSupported(powerRole, UsbPort.DATA_ROLE_HOST)
-                    ? UsbPort.DATA_ROLE_HOST : UsbPort.DATA_ROLE_DEVICE;
-            mUsbManager.setPortRoles(mPort, powerRole, dataRole);
-        }
-        setUsbFunction(mode & MODE_DATA_MASK);
-    }
-
-    private int modeToPower(int mode) {
-        return (mode & MODE_POWER_MASK) == MODE_POWER_SOURCE
-                    ? UsbPort.POWER_ROLE_SOURCE : UsbPort.POWER_ROLE_SINK;
-    }
-
-    public boolean isModeDisallowed(int mode) {
-        if (mRestricted && (mode & MODE_DATA_MASK) != MODE_DATA_NONE
-                && (mode & MODE_DATA_MASK) != MODE_DATA_MIDI) {
-            // No USB data modes are supported.
-            return true;
-        }
-        return false;
-    }
-
-    public boolean isModeDisallowedBySystem(int mode) {
-        if (mRestrictedBySystem && (mode & MODE_DATA_MASK) != MODE_DATA_NONE
-                && (mode & MODE_DATA_MASK) != MODE_DATA_MIDI) {
-            // No USB data modes are supported.
-            return true;
-        }
-        return false;
-    }
-
-    public boolean isModeSupported(int mode) {
-        if (!mMidi && (mode & MODE_DATA_MASK) == MODE_DATA_MIDI) {
-            return false;
-        }
-
-        if (mPort != null) {
-            int power = modeToPower(mode);
-            if ((mode & MODE_DATA_MASK) != 0) {
-                // We have a port and data, need to be in device mode.
-                return mPortStatus.isRoleCombinationSupported(power,
-                        UsbPort.DATA_ROLE_DEVICE);
-            } else {
-                // No data needed, we can do this power mode in either device or host.
-                return mPortStatus.isRoleCombinationSupported(power, UsbPort.DATA_ROLE_DEVICE)
-                        || mPortStatus.isRoleCombinationSupported(power, UsbPort.DATA_ROLE_HOST);
-            }
-        }
-        // No port, support sink modes only.
-        return (mode & MODE_POWER_MASK) != MODE_POWER_SOURCE;
-    }
-
-    // Wrapper class to enable testing with UserManager APIs
-    public static class UserRestrictionUtil {
-        private UserManager mUserManager;
-
-        public UserRestrictionUtil(Context context) {
-            mUserManager = UserManager.get(context);
-        }
-
-        public boolean isUsbFileTransferRestricted() {
-            return mUserManager.hasUserRestriction(UserManager.DISALLOW_USB_FILE_TRANSFER);
-        }
-
-        public boolean isUsbFileTransferRestrictedBySystem() {
-            return mUserManager.hasBaseUserRestriction(
-                UserManager.DISALLOW_USB_FILE_TRANSFER, UserHandle.of(UserHandle.myUserId()));
-        }
-    }
-}
diff --git a/src/com/android/settings/search/SearchIndexableResourcesImpl.java b/src/com/android/settings/search/SearchIndexableResourcesImpl.java
index 38dc15d..1edc2de 100644
--- a/src/com/android/settings/search/SearchIndexableResourcesImpl.java
+++ b/src/com/android/settings/search/SearchIndexableResourcesImpl.java
@@ -21,6 +21,8 @@
 import com.android.settings.DateTimeSettings;
 import com.android.settings.DisplaySettings;
 import com.android.settings.LegalSettings;
+import com.android.settings.connecteddevice.ConnectedDeviceDashboardFragmentOld;
+import com.android.settings.deviceinfo.aboutphone.MyDeviceInfoFragment;
 import com.android.settings.accessibility.AccessibilitySettings;
 import com.android.settings.accessibility.AccessibilityShortcutPreferenceFragment;
 import com.android.settings.accessibility.MagnificationPreferenceFragment;
@@ -34,7 +36,7 @@
 import com.android.settings.bluetooth.BluetoothSettings;
 import com.android.settings.connecteddevice.AdvancedConnectedDeviceDashboardFragment;
 import com.android.settings.connecteddevice.ConnectedDeviceDashboardFragment;
-import com.android.settings.connecteddevice.ConnectedDeviceDashboardFragmentOld;
+import com.android.settings.connecteddevice.usb.UsbDetailsFragment;
 import com.android.settings.datausage.DataUsageSummary;
 import com.android.settings.deletionhelper.AutomaticStorageManagerSettings;
 import com.android.settings.development.DevelopmentSettingsDashboardFragment;
@@ -167,6 +169,7 @@
         addIndex(PowerUsageSummary.class);
         addIndex(BatterySaverSettings.class);
         addIndex(LockscreenDashboardFragment.class);
+        addIndex(UsbDetailsFragment.class);
         addIndex(WifiDisplaySettings.class);
         addIndex(ZenModeBehaviorSettings.class);
         addIndex(ZenModeAutomationSettings.class);
diff --git a/src/com/android/settings/deviceinfo/AdditionalSystemUpdatePreferenceController.java b/src/com/android/settings/system/AdditionalSystemUpdatePreferenceController.java
similarity index 88%
rename from src/com/android/settings/deviceinfo/AdditionalSystemUpdatePreferenceController.java
rename to src/com/android/settings/system/AdditionalSystemUpdatePreferenceController.java
index f91ed4e..1fbf835 100644
--- a/src/com/android/settings/deviceinfo/AdditionalSystemUpdatePreferenceController.java
+++ b/src/com/android/settings/system/AdditionalSystemUpdatePreferenceController.java
@@ -13,13 +13,11 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package com.android.settings.deviceinfo;
+package com.android.settings.system;
 
 import android.content.Context;
 
 import com.android.settings.core.BasePreferenceController;
-import com.android.settings.core.PreferenceControllerMixin;
-import com.android.settingslib.core.AbstractPreferenceController;
 
 public class AdditionalSystemUpdatePreferenceController extends BasePreferenceController {
 
diff --git a/src/com/android/settings/system/SystemDashboardFragment.java b/src/com/android/settings/system/SystemDashboardFragment.java
index 88cafb0..deabf54 100644
--- a/src/com/android/settings/system/SystemDashboardFragment.java
+++ b/src/com/android/settings/system/SystemDashboardFragment.java
@@ -26,8 +26,6 @@
 import com.android.settings.R;
 import com.android.settings.backup.BackupSettingsActivityPreferenceController;
 import com.android.settings.dashboard.DashboardFragment;
-import com.android.settings.deviceinfo.AdditionalSystemUpdatePreferenceController;
-import com.android.settings.deviceinfo.SystemUpdatePreferenceController;
 import com.android.settings.gestures.GesturesSettingPreferenceController;
 import com.android.settings.search.BaseSearchIndexProvider;
 import com.android.settings.search.Indexable;
diff --git a/src/com/android/settings/deviceinfo/SystemUpdatePreferenceController.java b/src/com/android/settings/system/SystemUpdatePreferenceController.java
similarity index 73%
rename from src/com/android/settings/deviceinfo/SystemUpdatePreferenceController.java
rename to src/com/android/settings/system/SystemUpdatePreferenceController.java
index 2806275..20f43ef 100644
--- a/src/com/android/settings/deviceinfo/SystemUpdatePreferenceController.java
+++ b/src/com/android/settings/system/SystemUpdatePreferenceController.java
@@ -13,14 +13,17 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package com.android.settings.deviceinfo;
+package com.android.settings.system;
 
 import static android.content.Context.CARRIER_CONFIG_SERVICE;
+import static android.content.Context.SYSTEM_UPDATE_SERVICE;
 
 import android.content.Context;
 import android.content.Intent;
 import android.os.Build;
+import android.os.Bundle;
 import android.os.PersistableBundle;
+import android.os.SystemUpdateManager;
 import android.os.UserManager;
 import android.support.v7.preference.Preference;
 import android.support.v7.preference.PreferenceScreen;
@@ -39,10 +42,12 @@
     private static final String KEY_SYSTEM_UPDATE_SETTINGS = "system_update_settings";
 
     private final UserManager mUm;
+    private final SystemUpdateManager mUpdateManager;
 
     public SystemUpdatePreferenceController(Context context) {
         super(context, KEY_SYSTEM_UPDATE_SETTINGS);
         mUm = UserManager.get(context);
+        mUpdateManager = (SystemUpdateManager) context.getSystemService(SYSTEM_UPDATE_SERVICE);
     }
 
     @Override
@@ -84,7 +89,27 @@
 
     @Override
     public String getSummary() {
-        return mContext.getString(R.string.about_summary, Build.VERSION.RELEASE);
+        final Bundle updateInfo = mUpdateManager.retrieveSystemUpdateInfo();
+        String summary = mContext.getString(R.string.android_version_summary,
+                Build.VERSION.RELEASE);
+        switch (updateInfo.getInt(SystemUpdateManager.KEY_STATUS)) {
+            case SystemUpdateManager.STATUS_WAITING_DOWNLOAD:
+            case SystemUpdateManager.STATUS_IN_PROGRESS:
+            case SystemUpdateManager.STATUS_WAITING_INSTALL:
+            case SystemUpdateManager.STATUS_WAITING_REBOOT:
+                summary = mContext.getString(R.string.android_version_pending_update_summary);
+                break;
+            case SystemUpdateManager.STATUS_UNKNOWN:
+                Log.d(TAG, "Update statue unknown");
+                // fall through to next branch
+            case SystemUpdateManager.STATUS_IDLE:
+                final String version = updateInfo.getString(SystemUpdateManager.KEY_TITLE);
+                if (!TextUtils.isEmpty(version)) {
+                    summary = mContext.getString(R.string.android_version_summary, version);
+                }
+                break;
+        }
+        return summary;
     }
 
     /**
diff --git a/src/com/android/settings/users/UserCapabilities.java b/src/com/android/settings/users/UserCapabilities.java
index 084a5db..f1bfae9 100644
--- a/src/com/android/settings/users/UserCapabilities.java
+++ b/src/com/android/settings/users/UserCapabilities.java
@@ -34,6 +34,7 @@
     boolean mCanAddGuest;
     boolean mDisallowAddUser;
     boolean mDisallowAddUserSetByAdmin;
+    boolean mDisallowSwitchUser;
     RestrictedLockUtils.EnforcedAdmin mEnforcedAdmin;
 
     private UserCapabilities() {}
@@ -79,6 +80,9 @@
         final boolean canAddUsersWhenLocked = mIsAdmin || Settings.Global.getInt(
                 context.getContentResolver(), Settings.Global.ADD_USERS_WHEN_LOCKED, 0) == 1;
         mCanAddGuest = !mIsGuest && !mDisallowAddUser && canAddUsersWhenLocked;
+
+        UserManager userManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
+        mDisallowSwitchUser = userManager.hasUserRestriction(UserManager.DISALLOW_USER_SWITCH);
     }
 
     public boolean isAdmin() {
@@ -109,6 +113,7 @@
                 ", mCanAddGuest=" + mCanAddGuest +
                 ", mDisallowAddUser=" + mDisallowAddUser +
                 ", mEnforcedAdmin=" + mEnforcedAdmin +
+                ", mDisallowSwitchUser=" + mDisallowSwitchUser +
                 '}';
     }
 }
diff --git a/src/com/android/settings/users/UserSettings.java b/src/com/android/settings/users/UserSettings.java
index fcb8aef..edeab23 100644
--- a/src/com/android/settings/users/UserSettings.java
+++ b/src/com/android/settings/users/UserSettings.java
@@ -757,8 +757,12 @@
                     synchronized (mUserLock) {
                         if (userType == USER_TYPE_USER) {
                             mHandler.sendEmptyMessage(MESSAGE_UPDATE_LIST);
-                            mHandler.sendMessage(mHandler.obtainMessage(
-                                    MESSAGE_SETUP_USER, user.id, user.serialNumber));
+                            // Skip setting up user which results in user switching when the
+                            // restriction is set.
+                            if (!mUserCaps.mDisallowSwitchUser) {
+                                mHandler.sendMessage(mHandler.obtainMessage(
+                                        MESSAGE_SETUP_USER, user.id, user.serialNumber));
+                            }
                         } else {
                             mHandler.sendMessage(mHandler.obtainMessage(
                                     MESSAGE_CONFIG_USER, user.id, user.serialNumber));
@@ -845,8 +849,12 @@
                 } else {
                     pref.setSummary(R.string.user_summary_not_set_up);
                 }
-                pref.setOnPreferenceClickListener(this);
-                pref.setSelectable(true);
+                // Disallow setting up user which results in user switching when the restriction is
+                // set.
+                if (!mUserCaps.mDisallowSwitchUser) {
+                    pref.setOnPreferenceClickListener(this);
+                    pref.setSelectable(true);
+                }
             } else if (user.isRestricted()) {
                 pref.setSummary(R.string.user_summary_restricted_profile);
             }
@@ -885,8 +893,13 @@
             pref.setTitle(R.string.user_guest);
             pref.setIcon(getEncircledDefaultIcon());
             userPreferences.add(pref);
-            pref.setDisabledByAdmin(
-                    mUserCaps.mDisallowAddUser ? mUserCaps.mEnforcedAdmin : null);
+            if (mUserCaps.mDisallowAddUser) {
+                pref.setDisabledByAdmin(mUserCaps.mEnforcedAdmin);
+            } else if (mUserCaps.mDisallowSwitchUser) {
+                pref.setDisabledByAdmin(RestrictedLockUtils.getDeviceOwner(context));
+            } else {
+                pref.setDisabledByAdmin(null);
+            }
             int finalGuestId = guestId;
             pref.setOnPreferenceClickListener(preference -> {
                 int id = finalGuestId;
diff --git a/tests/robotests/src/android/hardware/usb/UsbManagerExtras.java b/tests/robotests/src/android/hardware/usb/UsbManagerExtras.java
new file mode 100644
index 0000000..b9bccd2
--- /dev/null
+++ b/tests/robotests/src/android/hardware/usb/UsbManagerExtras.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2010 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 android.hardware.usb;
+
+import android.annotation.SystemService;
+import android.content.Context;
+import android.hardware.usb.gadget.V1_0.GadgetFunction;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.StringJoiner;
+
+/**
+ * Definitions that were added to UsbManager in P.
+ *
+ * Copied partially from frameworks/base/core/java/android/hardware/usb/UsbManager to
+ * fix issues with roboelectric during test.
+ */
+@SystemService(Context.USB_SERVICE)
+public class UsbManagerExtras {
+    public static final long NONE = 0;
+    public static final long MTP = GadgetFunction.MTP;
+    public static final long PTP = GadgetFunction.PTP;
+    public static final long RNDIS = GadgetFunction.RNDIS;
+    public static final long MIDI = GadgetFunction.MIDI;
+    public static final long ACCESSORY = GadgetFunction.ACCESSORY;
+    public static final long AUDIO_SOURCE = GadgetFunction.AUDIO_SOURCE;
+    public static final long ADB = GadgetFunction.ADB;
+
+    private static final long SETTABLE_FUNCTIONS = MTP | PTP | RNDIS | MIDI;
+
+    private static final Map<String, Long> STR_MAP = new HashMap<>();
+
+    static {
+        STR_MAP.put(UsbManager.USB_FUNCTION_MTP, MTP);
+        STR_MAP.put(UsbManager.USB_FUNCTION_PTP, PTP);
+        STR_MAP.put(UsbManager.USB_FUNCTION_RNDIS, RNDIS);
+        STR_MAP.put(UsbManager.USB_FUNCTION_MIDI, MIDI);
+        STR_MAP.put(UsbManager.USB_FUNCTION_ACCESSORY, ACCESSORY);
+        STR_MAP.put(UsbManager.USB_FUNCTION_AUDIO_SOURCE, AUDIO_SOURCE);
+        STR_MAP.put(UsbManager.USB_FUNCTION_ADB, ADB);
+    }
+
+    /**
+     * Returns whether the given functions are valid inputs to UsbManager.
+     * Currently the empty functions or any of MTP, PTP, RNDIS, MIDI are accepted.
+     */
+    public static boolean isSettableFunctions(long functions) {
+        return (~SETTABLE_FUNCTIONS & functions) == 0;
+    }
+
+    /**
+     * Returns the string representation of the given functions.
+     */
+    public static String usbFunctionsToString(long functions) {
+        StringJoiner joiner = new StringJoiner(",");
+        if ((functions | MTP) != 0) {
+            joiner.add(UsbManager.USB_FUNCTION_MTP);
+        }
+        if ((functions | PTP) != 0) {
+            joiner.add(UsbManager.USB_FUNCTION_PTP);
+        }
+        if ((functions | RNDIS) != 0) {
+            joiner.add(UsbManager.USB_FUNCTION_RNDIS);
+        }
+        if ((functions | MIDI) != 0) {
+            joiner.add(UsbManager.USB_FUNCTION_MIDI);
+        }
+        if ((functions | ACCESSORY) != 0) {
+            joiner.add(UsbManager.USB_FUNCTION_ACCESSORY);
+        }
+        if ((functions | AUDIO_SOURCE) != 0) {
+            joiner.add(UsbManager.USB_FUNCTION_AUDIO_SOURCE);
+        }
+        if ((functions | ADB) != 0) {
+            joiner.add(UsbManager.USB_FUNCTION_ADB);
+        }
+        return joiner.toString();
+    }
+
+    /**
+     * Parses a string of usb functions and returns a mask of the same functions.
+     */
+    public static long usbFunctionsFromString(String functions) {
+        if (functions == null) {
+            return 0;
+        }
+        long ret = 0;
+        for (String function : functions.split(",")) {
+            if (STR_MAP.containsKey(function)) {
+                ret |= STR_MAP.get(function);
+            }
+        }
+        return ret;
+    }
+}
diff --git a/tests/robotests/src/android/os/SystemUpdateManager.java b/tests/robotests/src/android/os/SystemUpdateManager.java
new file mode 100644
index 0000000..f81df36
--- /dev/null
+++ b/tests/robotests/src/android/os/SystemUpdateManager.java
@@ -0,0 +1,37 @@
+/*
+ * 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 android.os;
+
+/**
+ * Duplicate class for platform SystemUpdateManager to get around Robolectric sdk problem.
+ */
+public class SystemUpdateManager {
+
+    public static final String KEY_STATUS = "status";
+    public static final String KEY_TITLE = "title";
+
+    public static final int STATUS_UNKNOWN = 0;
+    public static final int STATUS_IDLE = 1;
+    public static final int STATUS_WAITING_DOWNLOAD = 2;
+    public static final int STATUS_IN_PROGRESS = 3;
+    public static final int STATUS_WAITING_INSTALL = 4;
+    public static final int STATUS_WAITING_REBOOT = 5;
+
+    public Bundle retrieveSystemUpdateInfo() {
+        return null;
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/connecteddevice/ConnectedDeviceGroupControllerTest.java b/tests/robotests/src/com/android/settings/connecteddevice/ConnectedDeviceGroupControllerTest.java
index 78be742..b478c4e 100644
--- a/tests/robotests/src/com/android/settings/connecteddevice/ConnectedDeviceGroupControllerTest.java
+++ b/tests/robotests/src/com/android/settings/connecteddevice/ConnectedDeviceGroupControllerTest.java
@@ -31,6 +31,7 @@
 
 import com.android.settings.TestConfig;
 import com.android.settings.bluetooth.ConnectedBluetoothDeviceUpdater;
+import com.android.settings.connecteddevice.usb.ConnectedUsbDeviceUpdater;
 import com.android.settings.dashboard.DashboardFragment;
 import com.android.settings.testutils.SettingsRobolectricTestRunner;
 import com.android.settingslib.core.lifecycle.Lifecycle;
diff --git a/tests/robotests/src/com/android/settings/connecteddevice/ConnectedUsbDeviceUpdaterTest.java b/tests/robotests/src/com/android/settings/connecteddevice/usb/ConnectedUsbDeviceUpdaterTest.java
similarity index 79%
rename from tests/robotests/src/com/android/settings/connecteddevice/ConnectedUsbDeviceUpdaterTest.java
rename to tests/robotests/src/com/android/settings/connecteddevice/usb/ConnectedUsbDeviceUpdaterTest.java
index 16cd3a7..011d620 100644
--- a/tests/robotests/src/com/android/settings/connecteddevice/ConnectedUsbDeviceUpdaterTest.java
+++ b/tests/robotests/src/com/android/settings/connecteddevice/usb/ConnectedUsbDeviceUpdaterTest.java
@@ -13,18 +13,20 @@
  * See the License for the specific language governing permissions and
  * limitations under the License
  */
-package com.android.settings.connecteddevice;
+package com.android.settings.connecteddevice.usb;
 
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
 
 import android.content.Context;
 
 import com.android.settings.R;
 import com.android.settings.TestConfig;
-import com.android.settings.deviceinfo.UsbBackend;
+import com.android.settings.connecteddevice.DevicePreferenceCallback;
+import com.android.settings.dashboard.DashboardFragment;
 import com.android.settings.testutils.SettingsRobolectricTestRunner;
 
 import org.junit.Before;
@@ -42,6 +44,8 @@
     private ConnectedUsbDeviceUpdater mDeviceUpdater;
 
     @Mock
+    private DashboardFragment mFragment;
+    @Mock
     private UsbConnectionBroadcastReceiver mUsbReceiver;
     @Mock
     private DevicePreferenceCallback mDevicePreferenceCallback;
@@ -53,7 +57,8 @@
         MockitoAnnotations.initMocks(this);
 
         mContext = RuntimeEnvironment.application;
-        mDeviceUpdater = new ConnectedUsbDeviceUpdater(mContext, mDevicePreferenceCallback,
+        when(mFragment.getContext()).thenReturn(mContext);
+        mDeviceUpdater = new ConnectedUsbDeviceUpdater(mFragment, mDevicePreferenceCallback,
                 mUsbBackend);
         mDeviceUpdater.mUsbReceiver = mUsbReceiver;
     }
@@ -70,18 +75,18 @@
 
     @Test
     public void testInitUsbPreference_usbConnected_preferenceAdded() {
-        doReturn(true).when(mUsbReceiver).isConnected();
-
         mDeviceUpdater.initUsbPreference(mContext);
+        mDeviceUpdater.mUsbConnectionListener.onUsbConnectionChanged(true /* connected */,
+                UsbBackend.MODE_DATA_NONE);
 
         verify(mDevicePreferenceCallback).onDeviceAdded(mDeviceUpdater.mUsbPreference);
     }
 
     @Test
     public void testInitUsbPreference_usbDisconnected_preferenceRemoved() {
-        doReturn(false).when(mUsbReceiver).isConnected();
-
         mDeviceUpdater.initUsbPreference(mContext);
+        mDeviceUpdater.mUsbConnectionListener.onUsbConnectionChanged(false /* connected */,
+                UsbBackend.MODE_DATA_NONE);
 
         verify(mDevicePreferenceCallback).onDeviceRemoved(mDeviceUpdater.mUsbPreference);
     }
diff --git a/tests/robotests/src/com/android/settings/deviceinfo/UsbBackendTest.java b/tests/robotests/src/com/android/settings/connecteddevice/usb/UsbBackendTest.java
similarity index 81%
rename from tests/robotests/src/com/android/settings/deviceinfo/UsbBackendTest.java
rename to tests/robotests/src/com/android/settings/connecteddevice/usb/UsbBackendTest.java
index ce384a5..40cfd73 100644
--- a/tests/robotests/src/com/android/settings/deviceinfo/UsbBackendTest.java
+++ b/tests/robotests/src/com/android/settings/connecteddevice/usb/UsbBackendTest.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.settings.deviceinfo;
+package com.android.settings.connecteddevice.usb;
 
 import static org.mockito.Answers.RETURNS_DEEP_STUBS;
 import static org.mockito.Matchers.argThat;
@@ -25,7 +25,9 @@
 import android.content.Context;
 import android.content.pm.PackageManager;
 import android.hardware.usb.UsbManager;
+import android.net.ConnectivityManager;
 
+import com.android.settings.connecteddevice.usb.UsbBackend;
 import com.android.settings.testutils.SettingsRobolectricTestRunner;
 import com.android.settings.TestConfig;
 
@@ -46,6 +48,8 @@
     private UsbManager mUsbManager;
     @Mock
     private UsbBackend.UserRestrictionUtil mUserRestrictionUtil;
+    @Mock
+    private ConnectivityManager mConnectivityManager;
 
     @Before
     public void setUp() {
@@ -53,22 +57,13 @@
         when(mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_MIDI))
             .thenReturn(true);
         when((Object)mContext.getSystemService(UsbManager.class)).thenReturn(mUsbManager);
+        when(mContext.getSystemService(Context.CONNECTIVITY_SERVICE))
+                .thenReturn((Object) mConnectivityManager);
     }
 
     @Test
     public void constructor_noUsbPort_shouldNotCrash() {
-        UsbBackend usbBackend = new UsbBackend(mContext, mUserRestrictionUtil);
+        UsbBackend usbBackend = new UsbBackend(mContext, mUserRestrictionUtil, null);
         // Should not crash
     }
-
-    @Test
-    public void getCurrentMode_shouldRegisterReceiverToGetUsbState() {
-        UsbBackend usbBackend = new UsbBackend(mContext, mUserRestrictionUtil);
-
-        usbBackend.getCurrentMode();
-
-        verify(mContext).registerReceiver(eq(null),
-            argThat(intentFilter -> intentFilter != null &&
-                UsbManager.ACTION_USB_STATE.equals(intentFilter.getAction(0))));
-    }
 }
diff --git a/tests/robotests/src/com/android/settings/connecteddevice/UsbConnectionBroadcastReceiverTest.java b/tests/robotests/src/com/android/settings/connecteddevice/usb/UsbConnectionBroadcastReceiverTest.java
similarity index 81%
rename from tests/robotests/src/com/android/settings/connecteddevice/UsbConnectionBroadcastReceiverTest.java
rename to tests/robotests/src/com/android/settings/connecteddevice/usb/UsbConnectionBroadcastReceiverTest.java
index 06bd5b7..50b47e0 100644
--- a/tests/robotests/src/com/android/settings/connecteddevice/UsbConnectionBroadcastReceiverTest.java
+++ b/tests/robotests/src/com/android/settings/connecteddevice/usb/UsbConnectionBroadcastReceiverTest.java
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License
  */
-package com.android.settings.connecteddevice;
+package com.android.settings.connecteddevice.usb;
 
 import static com.google.common.truth.Truth.assertThat;
 import static com.google.common.truth.Truth.assertWithMessage;
@@ -52,6 +52,8 @@
 
     @Mock
     private UsbConnectionBroadcastReceiver.UsbConnectionListener mListener;
+    @Mock
+    private UsbBackend mUsbBackend;
 
     @Before
     public void setUp() {
@@ -59,27 +61,42 @@
 
         mShadowApplication = ShadowApplication.getInstance();
         mContext = RuntimeEnvironment.application;
-        mReceiver = new UsbConnectionBroadcastReceiver(mContext, mListener);
+        mReceiver = new UsbConnectionBroadcastReceiver(mContext, mListener, mUsbBackend);
     }
 
     @Test
     public void testOnReceive_usbConnected_invokeCallback() {
         final Intent intent = new Intent();
+        intent.setAction(UsbManager.ACTION_USB_STATE);
         intent.putExtra(UsbManager.USB_CONNECTED, true);
 
         mReceiver.onReceive(mContext, intent);
 
-        verify(mListener).onUsbConnectionChanged(true);
+        verify(mListener).onUsbConnectionChanged(true /* connected */, UsbBackend.MODE_DATA_NONE);
     }
 
     @Test
     public void testOnReceive_usbDisconnected_invokeCallback() {
         final Intent intent = new Intent();
+        intent.setAction(UsbManager.ACTION_USB_STATE);
         intent.putExtra(UsbManager.USB_CONNECTED, false);
 
         mReceiver.onReceive(mContext, intent);
 
-        verify(mListener).onUsbConnectionChanged(false);
+        verify(mListener).onUsbConnectionChanged(false /* connected */, UsbBackend.MODE_DATA_NONE);
+    }
+
+    @Test
+    public void testOnReceive_usbConnectedMtpEnabled_invokeCallback() {
+        final Intent intent = new Intent();
+        intent.setAction(UsbManager.ACTION_USB_STATE);
+        intent.putExtra(UsbManager.USB_CONNECTED, true);
+        intent.putExtra(UsbManager.USB_FUNCTION_MTP, true);
+        intent.putExtra(UsbManager.USB_DATA_UNLOCKED, true);
+
+        mReceiver.onReceive(mContext, intent);
+
+        verify(mListener).onUsbConnectionChanged(true /* connected */, UsbBackend.MODE_DATA_MTP);
     }
 
     @Test
diff --git a/tests/robotests/src/com/android/settings/connecteddevice/usb/UsbDetailsHeaderControllerTest.java b/tests/robotests/src/com/android/settings/connecteddevice/usb/UsbDetailsHeaderControllerTest.java
new file mode 100644
index 0000000..e1f9078
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/connecteddevice/usb/UsbDetailsHeaderControllerTest.java
@@ -0,0 +1,122 @@
+/*
+ * 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.connecteddevice.usb;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.app.Activity;
+import android.arch.lifecycle.LifecycleOwner;
+import android.content.Context;
+import android.support.v7.preference.PreferenceManager;
+import android.support.v7.preference.PreferenceScreen;
+import android.support.v14.preference.PreferenceFragment;
+
+import com.android.settings.R;
+import com.android.settings.TestConfig;
+import com.android.settings.applications.LayoutPreference;
+import com.android.settings.testutils.FakeFeatureFactory;
+import com.android.settings.testutils.SettingsRobolectricTestRunner;
+import com.android.settings.testutils.shadow.SettingsShadowResources;
+import com.android.settings.testutils.shadow.ShadowEntityHeaderController;
+import com.android.settings.widget.EntityHeaderController;
+import com.android.settingslib.core.lifecycle.Lifecycle;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Answers;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
+
+@RunWith(SettingsRobolectricTestRunner.class)
+@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION,
+        shadows = {ShadowEntityHeaderController.class, SettingsShadowResources.class})
+public class UsbDetailsHeaderControllerTest {
+
+    private UsbDetailsHeaderController mDetailsHeaderController;
+    private Context mContext;
+    private Lifecycle mLifecycle;
+    private LifecycleOwner mLifecycleOwner;
+    private LayoutPreference mPreference;
+    private PreferenceManager mPreferenceManager;
+    private PreferenceScreen mScreen;
+
+    @Mock
+    private UsbBackend mUsbBackend;
+    @Mock
+    private PreferenceFragment mFragment;
+    @Mock
+    private Activity mActivity;
+    @Mock(answer = Answers.RETURNS_DEEP_STUBS)
+    private EntityHeaderController mHeaderController;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+
+        mContext = RuntimeEnvironment.application;
+        mLifecycleOwner = () -> mLifecycle;
+        mLifecycle = new Lifecycle(mLifecycleOwner);
+        mPreferenceManager = new PreferenceManager(mContext);
+        mScreen = mPreferenceManager.createPreferenceScreen(mContext);
+
+        when(mFragment.getActivity()).thenReturn(mActivity);
+        when(mActivity.getApplicationContext()).thenReturn(mContext);
+        when(mFragment.getContext()).thenReturn(mContext);
+        when(mFragment.getPreferenceManager()).thenReturn(mPreferenceManager);
+        when(mFragment.getPreferenceScreen()).thenReturn(mScreen);
+
+        ShadowEntityHeaderController.setUseMock(mHeaderController);
+        mDetailsHeaderController = new UsbDetailsHeaderController(mContext, mFragment, mUsbBackend);
+        mPreference = new LayoutPreference(mContext, R.layout.settings_entity_header);
+        mPreference.setKey(mDetailsHeaderController.getPreferenceKey());
+        mScreen.addPreference(mPreference);
+    }
+
+    @After
+    public void tearDown() {
+        ShadowEntityHeaderController.reset();
+    }
+
+    @Test
+    public void displayRefresh_charging_shouldSetHeader() {
+        mDetailsHeaderController.displayPreference(mScreen);
+        mDetailsHeaderController.refresh(UsbBackend.MODE_DATA_NONE);
+        verify(mHeaderController).setLabel(mContext.getString(R.string.usb_pref));
+        verify(mHeaderController).setIcon(mContext.getDrawable(R.drawable.ic_usb));
+        verify(mHeaderController).setSummary(
+                mContext.getString(R.string.usb_summary_charging_only));
+        verify(mHeaderController).done(mActivity, true);
+    }
+
+    @Test
+    public void displayRefresh_mtp_shouldSetHeader() {
+        mDetailsHeaderController.displayPreference(mScreen);
+        mDetailsHeaderController.refresh(UsbBackend.MODE_DATA_MTP);
+        verify(mHeaderController).setLabel(mContext.getString(R.string.usb_pref));
+        verify(mHeaderController).setIcon(mContext.getDrawable(R.drawable.ic_usb));
+        verify(mHeaderController).setSummary(
+                mContext.getString(R.string.usb_summary_file_transfers));
+        verify(mHeaderController).done(mActivity, true);
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/connecteddevice/usb/UsbDetailsProfilesControllerTest.java b/tests/robotests/src/com/android/settings/connecteddevice/usb/UsbDetailsProfilesControllerTest.java
new file mode 100644
index 0000000..557d836
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/connecteddevice/usb/UsbDetailsProfilesControllerTest.java
@@ -0,0 +1,238 @@
+/*
+ * 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.connecteddevice.usb;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.app.Activity;
+import android.content.Context;
+import android.hardware.usb.UsbManager;
+import android.support.v7.preference.PreferenceCategory;
+import android.support.v7.preference.PreferenceManager;
+import android.support.v7.preference.PreferenceScreen;
+import android.support.v14.preference.PreferenceFragment;
+import android.support.v14.preference.SwitchPreference;
+
+import com.android.settings.R;
+import com.android.settings.TestConfig;
+import com.android.settings.testutils.FakeFeatureFactory;
+import com.android.settings.testutils.SettingsRobolectricTestRunner;
+import com.android.settings.testutils.shadow.SettingsShadowResources;
+import com.android.settingslib.core.lifecycle.Lifecycle;
+
+import com.google.android.collect.Lists;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Answers;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@RunWith(SettingsRobolectricTestRunner.class)
+@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
+public class UsbDetailsProfilesControllerTest {
+
+    private UsbDetailsProfilesController mDetailsProfilesController;
+    private Context mContext;
+    private Lifecycle mLifecycle;
+    private PreferenceCategory mPreference;
+    private PreferenceManager mPreferenceManager;
+    private PreferenceScreen mScreen;
+    private List<String> mOptions;
+
+    @Mock
+    private UsbBackend mUsbBackend;
+    @Mock
+    private PreferenceFragment mFragment;
+    @Mock
+    private Activity mActivity;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+
+        mContext = RuntimeEnvironment.application;
+        mLifecycle = new Lifecycle(() -> mLifecycle);
+        mPreferenceManager = new PreferenceManager(mContext);
+        mScreen = mPreferenceManager.createPreferenceScreen(mContext);
+
+        when(mFragment.getActivity()).thenReturn(mActivity);
+        when(mActivity.getApplicationContext()).thenReturn(mContext);
+        when(mFragment.getContext()).thenReturn(mContext);
+        when(mFragment.getPreferenceManager()).thenReturn(mPreferenceManager);
+        when(mFragment.getPreferenceScreen()).thenReturn(mScreen);
+
+        mOptions = Lists.newArrayList(UsbManager.USB_FUNCTION_MTP, UsbManager.USB_FUNCTION_PTP,
+                UsbManager.USB_FUNCTION_MIDI, UsbDetailsProfilesController.KEY_POWER);
+        mDetailsProfilesController = new UsbDetailsProfilesController(mContext, mFragment,
+                mUsbBackend, mOptions, "usb_options");
+        mPreference = new PreferenceCategory(mContext);
+        mPreference.setKey(mDetailsProfilesController.getPreferenceKey());
+        mScreen.addPreference(mPreference);
+    }
+
+    @Test
+    public void testDisplayRefresh_allAllowed_shouldCreateSwitches() {
+        when(mUsbBackend.isModeSupported(anyInt())).thenReturn(true);
+        when(mUsbBackend.isModeDisallowed(anyInt())).thenReturn(false);
+        when(mUsbBackend.isModeDisallowedBySystem(anyInt())).thenReturn(false);
+
+        mDetailsProfilesController.displayPreference(mScreen);
+        mDetailsProfilesController.refresh(UsbBackend.MODE_DATA_NONE);
+        List<SwitchPreference> switches = getProfileSwitches();
+
+        for (int i = 0; i < switches.size(); i++) {
+            assertThat(switches.get(i).getKey().equals(mOptions.get(i)));
+        }
+    }
+
+    @Test
+    public void testDisplayRefresh_onlyMidiAllowed_shouldCreateOnlyMidiSwitch() {
+        when(mUsbBackend.isModeSupported(anyInt())).thenReturn(true);
+        when(mUsbBackend.isModeDisallowed(anyInt())).thenReturn(false);
+        when(mUsbBackend.isModeDisallowedBySystem(UsbBackend.MODE_DATA_MIDI)).thenReturn(false);
+        when(mUsbBackend.isModeDisallowedBySystem(UsbBackend.MODE_DATA_MTP)).thenReturn(true);
+        when(mUsbBackend.isModeDisallowedBySystem(UsbBackend.MODE_DATA_PTP)).thenReturn(true);
+        when(mUsbBackend.isModeDisallowedBySystem(UsbBackend.MODE_POWER_SOURCE)).thenReturn(true);
+
+        mDetailsProfilesController.displayPreference(mScreen);
+        mDetailsProfilesController.refresh(UsbBackend.MODE_DATA_NONE);
+        List<SwitchPreference> switches = getProfileSwitches();
+        assertThat(switches.size()).isEqualTo(1);
+        assertThat(switches.get(0).getKey()).isEqualTo(UsbManager.USB_FUNCTION_MIDI);
+    }
+
+    @Test
+    public void testDisplayRefresh_mtpEnabled_shouldCheckSwitches() {
+        when(mUsbBackend.isModeSupported(anyInt())).thenReturn(true);
+        when(mUsbBackend.isModeDisallowed(anyInt())).thenReturn(false);
+        when(mUsbBackend.isModeDisallowedBySystem(anyInt())).thenReturn(false);
+
+        mDetailsProfilesController.displayPreference(mScreen);
+        mDetailsProfilesController.refresh(UsbBackend.MODE_DATA_MTP);
+        List<SwitchPreference> switches = getProfileSwitches();
+
+        assertThat(switches.get(0).getKey().equals(UsbManager.USB_FUNCTION_MTP));
+        assertThat(switches.get(0).isChecked());
+    }
+
+    @Test
+    public void testDisplayRefresh_mtpSupplyPowerEnabled_shouldCheckSwitches() {
+        when(mUsbBackend.isModeSupported(anyInt())).thenReturn(true);
+        when(mUsbBackend.isModeDisallowed(anyInt())).thenReturn(false);
+        when(mUsbBackend.isModeDisallowedBySystem(anyInt())).thenReturn(false);
+
+        mDetailsProfilesController.displayPreference(mScreen);
+        mDetailsProfilesController.refresh(UsbBackend.MODE_DATA_MTP | UsbBackend.MODE_POWER_SOURCE);
+        List<SwitchPreference> switches = getProfileSwitches();
+
+        assertThat(switches.get(0).getKey()).isEqualTo(UsbManager.USB_FUNCTION_MTP);
+        assertThat(switches.get(0).isChecked());
+        assertThat(switches.get(3).getKey()).isEqualTo(UsbDetailsProfilesController.KEY_POWER);
+        assertThat(switches.get(3).isChecked());
+    }
+
+    @Test
+    public void testOnClickMtp_noneEnabled_shouldEnableMtp() {
+        when(mUsbBackend.isModeSupported(anyInt())).thenReturn(true);
+        when(mUsbBackend.isModeDisallowed(anyInt())).thenReturn(false);
+        when(mUsbBackend.isModeDisallowedBySystem(anyInt())).thenReturn(false);
+
+        mDetailsProfilesController.displayPreference(mScreen);
+        mDetailsProfilesController.refresh(UsbBackend.MODE_DATA_NONE);
+        List<SwitchPreference> switches = getProfileSwitches();
+        switches.get(0).performClick();
+
+        assertThat(switches.get(0).getKey()).isEqualTo(UsbManager.USB_FUNCTION_MTP);
+        verify(mUsbBackend).setMode(UsbBackend.MODE_DATA_MTP);
+        assertThat(switches.get(0).isChecked());
+    }
+
+    @Test
+    public void testOnClickMtp_supplyingPowerEnabled_shouldEnableBoth() {
+        when(mUsbBackend.isModeSupported(anyInt())).thenReturn(true);
+        when(mUsbBackend.isModeDisallowed(anyInt())).thenReturn(false);
+        when(mUsbBackend.isModeDisallowedBySystem(anyInt())).thenReturn(false);
+
+        mDetailsProfilesController.displayPreference(mScreen);
+        mDetailsProfilesController.refresh(UsbBackend.MODE_POWER_SOURCE);
+        when(mUsbBackend.getCurrentMode()).thenReturn(UsbBackend.MODE_POWER_SOURCE);
+        List<SwitchPreference> switches = getProfileSwitches();
+        switches.get(0).performClick();
+
+        assertThat(switches.get(0).getKey()).isEqualTo(UsbManager.USB_FUNCTION_MTP);
+        verify(mUsbBackend).setMode(UsbBackend.MODE_DATA_MTP | UsbBackend.MODE_POWER_SOURCE);
+        assertThat(switches.get(0).isChecked());
+        assertThat(switches.get(3).getKey()).isEqualTo(UsbDetailsProfilesController.KEY_POWER);
+        assertThat(switches.get(3).isChecked());
+    }
+
+    @Test
+    public void testOnClickMtp_ptpEnabled_shouldEnableMtpOnly() {
+        when(mUsbBackend.isModeSupported(anyInt())).thenReturn(true);
+        when(mUsbBackend.isModeDisallowed(anyInt())).thenReturn(false);
+        when(mUsbBackend.isModeDisallowedBySystem(anyInt())).thenReturn(false);
+
+        mDetailsProfilesController.displayPreference(mScreen);
+        mDetailsProfilesController.refresh(UsbBackend.MODE_DATA_PTP);
+        when(mUsbBackend.getCurrentMode()).thenReturn(UsbBackend.MODE_DATA_PTP);
+        List<SwitchPreference> switches = getProfileSwitches();
+        switches.get(0).performClick();
+
+        assertThat(switches.get(0).getKey()).isEqualTo(UsbManager.USB_FUNCTION_MTP);
+        verify(mUsbBackend).setMode(UsbBackend.MODE_DATA_MTP);
+        assertThat(switches.get(0).isChecked());
+        assertThat(switches.get(1).getKey()).isEqualTo(UsbManager.USB_FUNCTION_PTP);
+        assertThat(!switches.get(1).isChecked());
+    }
+
+    @Test
+    public void testOnClickMtp_mtpEnabled_shouldDisableMtp() {
+        when(mUsbBackend.isModeSupported(anyInt())).thenReturn(true);
+        when(mUsbBackend.isModeDisallowed(anyInt())).thenReturn(false);
+        when(mUsbBackend.isModeDisallowedBySystem(anyInt())).thenReturn(false);
+
+        mDetailsProfilesController.displayPreference(mScreen);
+        mDetailsProfilesController.refresh(UsbBackend.MODE_DATA_MTP);
+        when(mUsbBackend.getCurrentMode()).thenReturn(UsbBackend.MODE_DATA_MTP);
+        List<SwitchPreference> switches = getProfileSwitches();
+        switches.get(0).performClick();
+
+        assertThat(switches.get(0).getKey()).isEqualTo(UsbManager.USB_FUNCTION_MTP);
+        verify(mUsbBackend).setMode(UsbBackend.MODE_DATA_NONE);
+        assertThat(!switches.get(0).isChecked());
+    }
+
+    private List<SwitchPreference> getProfileSwitches() {
+        ArrayList<SwitchPreference> result = new ArrayList<>();
+        for (int i = 0; i < mPreference.getPreferenceCount(); i++) {
+            result.add((SwitchPreference) mPreference.getPreference(i));
+        }
+        return result;
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/deviceinfo/UsbModeChooserActivityTest.java b/tests/robotests/src/com/android/settings/connecteddevice/usb/UsbModeChooserActivityTest.java
similarity index 96%
rename from tests/robotests/src/com/android/settings/deviceinfo/UsbModeChooserActivityTest.java
rename to tests/robotests/src/com/android/settings/connecteddevice/usb/UsbModeChooserActivityTest.java
index 1817bfb..c02212b 100644
--- a/tests/robotests/src/com/android/settings/deviceinfo/UsbModeChooserActivityTest.java
+++ b/tests/robotests/src/com/android/settings/connecteddevice/usb/UsbModeChooserActivityTest.java
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package com.android.settings.deviceinfo;
+package com.android.settings.connecteddevice.usb;
 
 import static com.google.common.truth.Truth.assertThat;
 import static org.mockito.Matchers.anyInt;
@@ -22,6 +22,7 @@
 
 import android.widget.TextView;
 import com.android.settings.R;
+import com.android.settings.connecteddevice.usb.UsbModeChooserActivity;
 import com.android.settings.testutils.SettingsRobolectricTestRunner;
 import com.android.settings.TestConfig;
 import org.junit.Before;
diff --git a/tests/robotests/src/com/android/settings/connecteddevice/UsbModePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/connecteddevice/usb/UsbModePreferenceControllerTest.java
similarity index 67%
rename from tests/robotests/src/com/android/settings/connecteddevice/UsbModePreferenceControllerTest.java
rename to tests/robotests/src/com/android/settings/connecteddevice/usb/UsbModePreferenceControllerTest.java
index 7edde6e..d15a57f 100644
--- a/tests/robotests/src/com/android/settings/connecteddevice/UsbModePreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/connecteddevice/usb/UsbModePreferenceControllerTest.java
@@ -1,16 +1,12 @@
-package com.android.settings.connecteddevice;
+package com.android.settings.connecteddevice.usb;
 
 import android.content.Context;
-import android.content.Intent;
-import android.hardware.usb.UsbManager;
 import android.support.v7.preference.Preference;
 import android.support.v7.preference.PreferenceScreen;
 
 import com.android.settings.R;
 import com.android.settings.testutils.SettingsRobolectricTestRunner;
 import com.android.settings.TestConfig;
-import com.android.settings.deviceinfo.UsbBackend;
-import com.android.settings.deviceinfo.UsbModeChooserActivity;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -24,6 +20,7 @@
 import static org.mockito.Answers.RETURNS_DEEP_STUBS;
 import static org.mockito.Matchers.any;
 import static org.mockito.Mockito.when;
+import static org.mockito.Mockito.verify;
 
 @RunWith(SettingsRobolectricTestRunner.class)
 @Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
@@ -33,6 +30,8 @@
     private UsbBackend mUsbBackend;
     @Mock(answer = RETURNS_DEEP_STUBS)
     private PreferenceScreen mScreen;
+    @Mock
+    private UsbConnectionBroadcastReceiver mUsbConnectionBroadcastReceiver;
 
     private Context mContext;
     private UsbModePreferenceController mController;
@@ -42,61 +41,67 @@
         MockitoAnnotations.initMocks(this);
         mContext = ShadowApplication.getInstance().getApplicationContext();
         mController = new UsbModePreferenceController(mContext, mUsbBackend);
+        mController.mUsbReceiver = mUsbConnectionBroadcastReceiver;
     }
 
     @Test
     public void testGetSummary_chargeDevice() {
-        assertThat(mController.getSummary(UsbModeChooserActivity.DEFAULT_MODES[0]))
+        assertThat(mController.getSummary(0))
                 .isEqualTo(R.string.usb_summary_charging_only);
     }
 
     @Test
     public void testGetSummary_supplyPower() {
-        assertThat(mController.getSummary(UsbModeChooserActivity.DEFAULT_MODES[1]))
+        assertThat(mController.getSummary(UsbBackend.MODE_POWER_SOURCE))
                 .isEqualTo(R.string.usb_summary_power_only);
     }
 
     @Test
     public void testGetSummary_TransferFiles() {
-        assertThat(mController.getSummary(UsbModeChooserActivity.DEFAULT_MODES[2]))
+        assertThat(mController.getSummary(UsbBackend.MODE_DATA_MTP))
                 .isEqualTo(R.string.usb_summary_file_transfers);
     }
 
     @Test
     public void testGetSummary_TransferPhoto() {
-        assertThat(mController.getSummary(UsbModeChooserActivity.DEFAULT_MODES[3]))
+        assertThat(mController.getSummary(UsbBackend.MODE_DATA_PTP))
                 .isEqualTo(R.string.usb_summary_photo_transfers);
     }
 
     @Test
     public void testGetSummary_MIDI() {
-        assertThat(mController.getSummary(UsbModeChooserActivity.DEFAULT_MODES[4]))
+        assertThat(mController.getSummary(UsbBackend.MODE_DATA_MIDI))
                 .isEqualTo(R.string.usb_summary_MIDI);
     }
 
     @Test
+    public void testGetSummary_Tethering() {
+        assertThat(mController.getSummary(UsbBackend.MODE_DATA_TETHER))
+                .isEqualTo(R.string.usb_summary_tether);
+    }
+
+    @Test
     public void testPreferenceSummary_usbDisconnected() {
         final Preference preference = new Preference(mContext);
         preference.setKey("usb_mode");
         preference.setEnabled(true);
+        when(mUsbBackend.getCurrentMode()).thenReturn(UsbBackend.MODE_POWER_SINK);
+        when(mUsbConnectionBroadcastReceiver.isConnected()).thenReturn(false);
         mController.updateState(preference);
+
+        assertThat(preference.getKey()).isEqualTo("usb_mode");
         assertThat(preference.getSummary()).isEqualTo(
                 mContext.getString(R.string.disconnected));
     }
 
     @Test
-    public void testUsbBoradcastReceiver_usbConnected_shouldUpdateSummary() {
+    public void testUsbBroadcastReceiver_usbConnected_shouldUpdateSummary() {
         final Preference preference = new Preference(mContext);
         preference.setKey("usb_mode");
         preference.setEnabled(true);
-        when(mUsbBackend.getCurrentMode()).thenReturn(UsbModeChooserActivity.DEFAULT_MODES[0]);
-        when(mScreen.findPreference("usb_mode")).thenReturn(preference);
-
-        mController.displayPreference(mScreen);
-        mController.onResume();
-        final Intent intent = new Intent(UsbManager.ACTION_USB_STATE);
-        intent.putExtra(UsbManager.USB_CONNECTED, true);
-        mContext.sendStickyBroadcast(intent);
+        when(mUsbBackend.getCurrentMode()).thenReturn(UsbBackend.MODE_POWER_SINK);
+        when(mUsbConnectionBroadcastReceiver.isConnected()).thenReturn(true);
+        mController.updateState(preference);
 
         assertThat(preference.getSummary()).isEqualTo(
                 mContext.getString(R.string.usb_summary_charging_only));
diff --git a/tests/robotests/src/com/android/settings/dashboard/suggestions/SuggestionAdapterTest.java b/tests/robotests/src/com/android/settings/dashboard/suggestions/SuggestionAdapterTest.java
index ebf3dc7..825aee9 100644
--- a/tests/robotests/src/com/android/settings/dashboard/suggestions/SuggestionAdapterTest.java
+++ b/tests/robotests/src/com/android/settings/dashboard/suggestions/SuggestionAdapterTest.java
@@ -215,11 +215,9 @@
     }
 
     @Test
-    public void onBindViewHolder_differentPackage_shouldNotTintIcon()
-        throws PendingIntent.CanceledException {
+    public void onBindViewHolder_iconNotTintable_shouldNotTintIcon()
+            throws PendingIntent.CanceledException {
         final Icon icon = mock(Icon.class);
-        when(icon.getResPackage()).thenReturn("pkg1");
-        when(mActivity.getPackageName()).thenReturn("pkg2");
         final Suggestion suggestion = new Suggestion.Builder("pkg1")
             .setPendingIntent(mock(PendingIntent.class))
             .setIcon(icon)
@@ -243,15 +241,14 @@
     }
 
     @Test
-    public void onBindViewHolder_samePackage_shouldTintIcon()
-        throws PendingIntent.CanceledException {
+    public void onBindViewHolder_iconTintable_shouldTintIcon()
+            throws PendingIntent.CanceledException {
         final Icon icon = mock(Icon.class);
-        final String packageName = "pkg1";
-        when(icon.getResPackage()).thenReturn(packageName);
-        when(mActivity.getPackageName()).thenReturn(packageName);
-        final Suggestion suggestion = new Suggestion.Builder(packageName)
+        final int FLAG_ICON_TINTABLE = 1 << 1;
+        final Suggestion suggestion = new Suggestion.Builder("pkg1")
             .setPendingIntent(mock(PendingIntent.class))
             .setIcon(icon)
+            .setFlags(FLAG_ICON_TINTABLE)
             .build();
         final List<Suggestion> suggestions = new ArrayList<>();
         suggestions.add(suggestion);
diff --git a/tests/robotests/src/com/android/settings/development/SelectUsbConfigPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/development/SelectUsbConfigPreferenceControllerTest.java
index 8719bb4..67a6d6b 100644
--- a/tests/robotests/src/com/android/settings/development/SelectUsbConfigPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/development/SelectUsbConfigPreferenceControllerTest.java
@@ -25,6 +25,7 @@
 
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyLong;
 import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.Mockito.doNothing;
 import static org.mockito.Mockito.doReturn;
@@ -37,11 +38,13 @@
 import android.content.Context;
 import android.content.pm.PackageManager;
 import android.hardware.usb.UsbManager;
+import android.hardware.usb.UsbManagerExtras;
 import android.support.v7.preference.ListPreference;
 import android.support.v7.preference.PreferenceScreen;
 
 import com.android.settings.R;
 import com.android.settings.TestConfig;
+import com.android.settings.connecteddevice.usb.UsbBackend;
 import com.android.settings.testutils.SettingsRobolectricTestRunner;
 import com.android.settings.testutils.shadow.ShadowUtils;
 import com.android.settingslib.core.lifecycle.Lifecycle;
@@ -69,6 +72,8 @@
     private UsbManager mUsbManager;
     @Mock
     private PackageManager mPackageManager;
+    @Mock
+    private UsbBackend.UsbManagerPassThrough mUsbManagerPassThrough;
 
     private Context mContext;
     private LifecycleOwner mLifecycleOwner;
@@ -101,6 +106,13 @@
         mController = spy(new SelectUsbConfigPreferenceController(mContext, mLifecycle));
         when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(mPreference);
         mController.displayPreference(mScreen);
+        mController.mUsbManagerPassThrough = mUsbManagerPassThrough;
+
+        when(mUsbManagerPassThrough.usbFunctionsFromString("mtp")).thenReturn(UsbManagerExtras.MTP);
+        when(mUsbManagerPassThrough.usbFunctionsFromString("rndis"))
+                .thenReturn(UsbManagerExtras.RNDIS);
+        when(mUsbManagerPassThrough.usbFunctionsFromString("none"))
+                .thenReturn(UsbManagerExtras.NONE);
 
     }
 
@@ -111,11 +123,13 @@
 
     @Test
     public void onPreferenceChange_setCharging_shouldEnableCharging() {
-        when(mUsbManager.isFunctionEnabled(mValues[0])).thenReturn(true);
-        doNothing().when(mController).setCurrentFunction(anyString(), anyBoolean());
+        when(mUsbManagerPassThrough.getCurrentFunctions()).thenReturn(
+                UsbManagerExtras.usbFunctionsFromString(mValues[0]));
+        doNothing().when(mController).setCurrentFunctions(anyLong());
         mController.onPreferenceChange(mPreference, mValues[0]);
 
-        verify(mController).setCurrentFunction(mValues[0], false /* usb data unlock */);
+        verify(mController).setCurrentFunctions(
+                UsbManagerExtras.usbFunctionsFromString(mValues[0]));
     }
 
     @Test
@@ -144,28 +158,32 @@
 
     @Test
     public void onPreferenceChange_setMtp_shouldEnableMtp() {
-        when(mUsbManager.isFunctionEnabled(mValues[1])).thenReturn(true);
-        doNothing().when(mController).setCurrentFunction(anyString(), anyBoolean());
+        when(mUsbManagerPassThrough.getCurrentFunctions())
+                .thenReturn(UsbManagerExtras.usbFunctionsFromString(mValues[1]));
+        doNothing().when(mController).setCurrentFunctions(anyLong());
         mController.onPreferenceChange(mPreference, mValues[1]);
 
-        verify(mController).setCurrentFunction(mValues[1], true /* usb data unlock */);
+        verify(mController).setCurrentFunctions(
+                UsbManagerExtras.usbFunctionsFromString(mValues[1]));
     }
 
     @Test
     public void onPreferenceChange_monkeyUser_shouldReturnFalse() {
-        when(mUsbManager.isFunctionEnabled(mValues[1])).thenReturn(true);
+        when(mUsbManagerPassThrough.getCurrentFunctions())
+                .thenReturn(UsbManagerExtras.usbFunctionsFromString(mValues[1]));
         ShadowUtils.setIsUserAMonkey(true);
-        doNothing().when(mController).setCurrentFunction(anyString(), anyBoolean());
+        doNothing().when(mController).setCurrentFunctions(anyLong());
 
         final boolean isHandled = mController.onPreferenceChange(mPreference, mValues[1]);
 
         assertThat(isHandled).isFalse();
-        verify(mController, never()).setCurrentFunction(any(), anyBoolean());
+        verify(mController, never()).setCurrentFunctions(anyLong());
     }
 
     @Test
     public void updateState_chargingEnabled_shouldSetPreferenceToCharging() {
-        when(mUsbManager.isFunctionEnabled(mValues[0])).thenReturn(true);
+        when(mUsbManagerPassThrough.getCurrentFunctions())
+                .thenReturn(UsbManagerExtras.usbFunctionsFromString(mValues[0]));
 
         mController.updateState(mPreference);
 
@@ -175,7 +193,8 @@
 
     @Test
     public void updateState_RndisEnabled_shouldEnableRndis() {
-        when(mUsbManager.isFunctionEnabled(mValues[3])).thenReturn(true);
+        when(mUsbManagerPassThrough.getCurrentFunctions())
+                .thenReturn(UsbManagerExtras.usbFunctionsFromString(mValues[3]));
 
         mController.updateState(mPreference);
 
@@ -185,6 +204,7 @@
 
     @Test
     public void updateState_noValueSet_shouldEnableChargingAsDefault() {
+        when(mUsbManagerPassThrough.getCurrentFunctions()).thenReturn(UsbManagerExtras.NONE);
         mController.updateState(mPreference);
 
         verify(mPreference).setValue(mValues[0]);
diff --git a/tests/robotests/src/com/android/settings/deviceinfo/PhoneNumberPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/deviceinfo/PhoneNumberPreferenceControllerTest.java
index f30425b..0b83359 100644
--- a/tests/robotests/src/com/android/settings/deviceinfo/PhoneNumberPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/deviceinfo/PhoneNumberPreferenceControllerTest.java
@@ -16,6 +16,9 @@
 
 package com.android.settings.deviceinfo;
 
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertTrue;
+
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.spy;
@@ -74,6 +77,20 @@
     }
 
     @Test
+    public void isAvailable_shouldBeTrueIfCallCapable() {
+        when(mTelephonyManager.isVoiceCapable()).thenReturn(true);
+
+        assertTrue(mController.isAvailable());
+    }
+
+    @Test
+    public void isAvailable_shouldBeFalseIfNotCallCapable() {
+        when(mTelephonyManager.isVoiceCapable()).thenReturn(false);
+
+        assertFalse(mController.isAvailable());
+    }
+
+    @Test
     public void displayPreference_multiSim_shouldAddSecondPreference() {
         when(mTelephonyManager.getPhoneCount()).thenReturn(2);
 
diff --git a/tests/robotests/src/com/android/settings/deviceinfo/AdditionalSystemUpdatePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/system/AdditionalSystemUpdatePreferenceControllerTest.java
similarity index 94%
rename from tests/robotests/src/com/android/settings/deviceinfo/AdditionalSystemUpdatePreferenceControllerTest.java
rename to tests/robotests/src/com/android/settings/system/AdditionalSystemUpdatePreferenceControllerTest.java
index e5708ba..43f48c0 100644
--- a/tests/robotests/src/com/android/settings/deviceinfo/AdditionalSystemUpdatePreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/system/AdditionalSystemUpdatePreferenceControllerTest.java
@@ -13,20 +13,18 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package com.android.settings.deviceinfo;
+package com.android.settings.system;
 
 import static com.google.common.truth.Truth.assertThat;
 
 import android.content.Context;
 
-import com.android.settings.R;
 import com.android.settings.TestConfig;
 import com.android.settings.testutils.SettingsRobolectricTestRunner;
 
 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.annotation.Config;
diff --git a/tests/robotests/src/com/android/settings/deviceinfo/SystemUpdatePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/system/SystemUpdatePreferenceControllerTest.java
similarity index 64%
rename from tests/robotests/src/com/android/settings/deviceinfo/SystemUpdatePreferenceControllerTest.java
rename to tests/robotests/src/com/android/settings/system/SystemUpdatePreferenceControllerTest.java
index b5b84da..95a18a1 100644
--- a/tests/robotests/src/com/android/settings/deviceinfo/SystemUpdatePreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/system/SystemUpdatePreferenceControllerTest.java
@@ -13,17 +13,20 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package com.android.settings.deviceinfo;
+package com.android.settings.system;
 
+import static android.os.SystemUpdateManager.KEY_STATUS;
+import static android.os.SystemUpdateManager.KEY_TITLE;
+import static android.os.SystemUpdateManager.STATUS_IDLE;
+import static android.os.SystemUpdateManager.STATUS_UNKNOWN;
+import static android.os.SystemUpdateManager.STATUS_WAITING_DOWNLOAD;
 import static com.google.common.truth.Truth.assertThat;
-
-import static org.mockito.Answers.RETURNS_DEEP_STUBS;
-import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.when;
 
 import android.content.Context;
 import android.os.Build;
-import android.os.UserManager;
+import android.os.Bundle;
+import android.os.SystemUpdateManager;
 import android.support.v7.preference.Preference;
 import android.support.v7.preference.PreferenceScreen;
 
@@ -55,6 +58,8 @@
 
     @Mock
     private PreferenceScreen mScreen;
+    @Mock
+    private SystemUpdateManager mSystemUpdateManager;
 
     private Context mContext;
     private SystemUpdatePreferenceController mController;
@@ -64,7 +69,8 @@
     public void setUp() {
         MockitoAnnotations.initMocks(this);
         mContext = RuntimeEnvironment.application;
-
+        ShadowApplication.getInstance().setSystemService(Context.SYSTEM_UPDATE_SERVICE,
+                mSystemUpdateManager);
         mController = new SystemUpdatePreferenceController(mContext);
         mPreference = new Preference(RuntimeEnvironment.application);
         mPreference.setKey(mController.getPreferenceKey());
@@ -118,11 +124,41 @@
     }
 
     @Test
-    public void updateState_shouldSetToAndroidVersion() {
+    public void updateState_systemUpdateStatusUnknown_shouldSetToAndroidVersion() {
+        final Bundle bundle = new Bundle();
+        bundle.putInt(KEY_STATUS, STATUS_UNKNOWN);
+        when(mSystemUpdateManager.retrieveSystemUpdateInfo()).thenReturn(bundle);
+
         mController.updateState(mPreference);
 
-        assertThat(mPreference.getSummary())
-                .isEqualTo(RuntimeEnvironment.application.getString(R.string.about_summary,
-                        Build.VERSION.RELEASE));
+        assertThat(mPreference.getSummary()).isEqualTo(
+                mContext.getString(R.string.android_version_summary, Build.VERSION.RELEASE));
+    }
+
+    @Test
+    public void updateState_systemUpdateStatusIdle_shouldSetToAndroidVersion() {
+        final String testReleaseName = "ANDROID TEST VERSION";
+
+        final Bundle bundle = new Bundle();
+        bundle.putInt(KEY_STATUS, STATUS_IDLE);
+        bundle.putString(KEY_TITLE, testReleaseName);
+        when(mSystemUpdateManager.retrieveSystemUpdateInfo()).thenReturn(bundle);
+
+        mController.updateState(mPreference);
+
+        assertThat(mPreference.getSummary()).isEqualTo(
+                mContext.getString(R.string.android_version_summary, testReleaseName));
+    }
+
+    @Test
+    public void updateState_systemUpdateInProgress_shouldSetToUpdatePending() {
+        final Bundle bundle = new Bundle();
+        bundle.putInt(KEY_STATUS, STATUS_WAITING_DOWNLOAD);
+        when(mSystemUpdateManager.retrieveSystemUpdateInfo()).thenReturn(bundle);
+
+        mController.updateState(mPreference);
+
+        assertThat(mPreference.getSummary()).isEqualTo(
+                mContext.getString(R.string.android_version_pending_update_summary));
     }
 }
\ No newline at end of file
diff --git a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowConnectivityManager.java b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowConnectivityManager.java
index 742fbf8..fc19b44 100644
--- a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowConnectivityManager.java
+++ b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowConnectivityManager.java
@@ -26,6 +26,7 @@
 public class ShadowConnectivityManager extends org.robolectric.shadows.ShadowConnectivityManager {
 
     private final SparseBooleanArray mSupportedNetworkTypes = new SparseBooleanArray();
+    private boolean mTetheringSupported = false;
 
     public void setNetworkSupported(int networkType, boolean supported) {
         mSupportedNetworkTypes.put(networkType, supported);
@@ -35,4 +36,13 @@
     public boolean isNetworkSupported(int networkType) {
         return mSupportedNetworkTypes.get(networkType);
     }
+
+    public void setTetheringSupported(boolean supported) {
+        mTetheringSupported = supported;
+    }
+
+    @Implementation
+    public boolean isTetheringSupported() {
+        return mTetheringSupported;
+    }
 }
diff --git a/tests/robotests/src/com/android/settings/users/UserCapabilitiesTest.java b/tests/robotests/src/com/android/settings/users/UserCapabilitiesTest.java
new file mode 100644
index 0000000..4228ca0
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/users/UserCapabilitiesTest.java
@@ -0,0 +1,70 @@
+/*
+ * 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.users;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.os.UserManager;
+
+import com.android.settings.TestConfig;
+import com.android.settings.testutils.SettingsRobolectricTestRunner;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.annotation.Config;
+
+@RunWith(SettingsRobolectricTestRunner.class)
+@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
+public class UserCapabilitiesTest {
+
+    @Mock
+    private Context mContext;
+    @Mock
+    private UserManager mUserManager;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        when(mContext.getSystemService(Context.USER_SERVICE)).thenReturn(mUserManager);
+    }
+
+    @Test
+    public void disallowUserSwitchWhenRestrictionIsSet() {
+        when(mUserManager.hasUserRestriction(UserManager.DISALLOW_USER_SWITCH)).thenReturn(true);
+
+        UserCapabilities userCapabilities = UserCapabilities.create(mContext);
+        userCapabilities.updateAddUserCapabilities(mContext);
+
+        assertThat(userCapabilities.mDisallowSwitchUser).isTrue();
+    }
+
+    @Test
+    public void allowUserSwitchWhenRestrictionIsNotSet() {
+        when(mUserManager.hasUserRestriction(UserManager.DISALLOW_USER_SWITCH)).thenReturn(false);
+
+        UserCapabilities userCapabilities = UserCapabilities.create(mContext);
+        userCapabilities.updateAddUserCapabilities(mContext);
+
+        assertThat(userCapabilities.mDisallowSwitchUser).isFalse();
+    }
+}