Merge "Add NPE check for method assignDefaultPhoto in Utils.java"
diff --git a/res/layout/preference_iconless_slider.xml b/res/layout/preference_iconless_slider.xml
deleted file mode 100644
index 8e2b8f3..0000000
--- a/res/layout/preference_iconless_slider.xml
+++ /dev/null
@@ -1,55 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- 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.
--->
-
-<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="match_parent"
-    android:layout_height="wrap_content"
-    android:minHeight="?android:attr/listPreferredItemHeight"
-    android:gravity="center_vertical"
-    android:paddingStart="?android:attr/listPreferredItemPaddingStart"
-    android:paddingEnd="?android:attr/listPreferredItemPaddingEnd">
-
-    <LinearLayout
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:orientation="vertical"
-        android:layout_marginTop="8dip"
-        android:layout_marginBottom="8dip">
-
-        <TextView android:id="@android:id/title"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:singleLine="true"
-            android:textAppearance="@android:style/TextAppearance.Material.Subhead"
-            android:textColor="?android:attr/textColorPrimary"
-            android:ellipsize="marquee"
-            android:fadingEdge="horizontal" />
-
-        <LinearLayout
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:layout_marginTop="6dip">
-
-            <SeekBar android:id="@*android:id/seekbar"
-                android:layout_gravity="center_vertical"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content" />
-
-        </LinearLayout>
-
-    </LinearLayout>
-
-</FrameLayout>
diff --git a/res/layout/preference_tts_engine.xml b/res/layout/preference_tts_engine.xml
index 277fc23..8f4036b 100644
--- a/res/layout/preference_tts_engine.xml
+++ b/res/layout/preference_tts_engine.xml
@@ -18,22 +18,19 @@
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="?android:attr/listPreferredItemHeight"
-    android:paddingStart="?android:attr/listPreferredItemPaddingStart"
+    android:paddingStart="@dimen/preference_no_icon_padding_start"
     android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
     android:layout_gravity="center_vertical">
 
     <RadioButton
         android:id="@+id/tts_engine_radiobutton"
-        android:layout_width="wrap_content"
-        android:layout_height="match_parent"
-        android:clickable="true"
-        android:textAppearance="?android:attr/textAppearanceMedium" />
-
-    <View
         android:layout_width="0dp"
         android:layout_height="match_parent"
+        android:clickable="true"
         android:layout_weight="1"
-        android:background="@android:drawable/divider_horizontal_dark" />
+        android:maxLines="2"
+        android:textAppearance="?android:attr/textAppearanceListItem"
+        android:ellipsize="marquee"/>
 
     <ImageView
         android:id="@+id/tts_engine_settings"
@@ -46,5 +43,5 @@
         android:layout_centerVertical="true"
         android:clickable="true"
         android:focusable="true"
-        android:background="?android:attr/selectableItemBackground" />
+        android:background="?android:attr/selectableItemBackground"/>
 </LinearLayout>
diff --git a/res/layout/preference_widget_seekbar_settings.xml b/res/layout/preference_widget_seekbar_settings.xml
new file mode 100644
index 0000000..77c27a4
--- /dev/null
+++ b/res/layout/preference_widget_seekbar_settings.xml
@@ -0,0 +1,95 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 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.
+-->
+
+<!-- Layout used by SeekBarPreference for the seekbar widget style. -->
+<!-- Same as frameworks/base/core/res/res/layout/preference_widget_seekbar_material.xml with
+     reserved icon space -->
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:minHeight="?android:attr/listPreferredItemHeight"
+    android:gravity="center_vertical"
+    android:paddingStart="?android:attr/listPreferredItemPaddingStart"
+    android:paddingEnd="?android:attr/listPreferredItemPaddingEnd">
+
+    <LinearLayout
+        android:id="@+id/icon_container"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:minWidth="60dp"
+        android:gravity="start|center_vertical"
+        android:orientation="horizontal"
+        android:paddingEnd="12dp"
+        android:paddingTop="4dp"
+        android:paddingBottom="4dp">
+        <com.android.internal.widget.PreferenceImageView
+            android:id="@android:id/icon"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:maxWidth="48dp"
+            android:maxHeight="48dp"/>
+    </LinearLayout>
+
+    <RelativeLayout
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginEnd="8dip"
+        android:layout_marginTop="6dip"
+        android:layout_marginBottom="6dip"
+        android:layout_weight="1">
+
+        <TextView
+            android:id="@android:id/title"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:singleLine="true"
+            android:textAppearance="@android:style/TextAppearance.Material.Subhead"
+            android:textColor="?android:attr/textColorPrimary"
+            android:ellipsize="marquee"
+            android:fadingEdge="horizontal"/>
+
+        <TextView
+            android:id="@android:id/summary"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_below="@android:id/title"
+            android:layout_alignStart="@android:id/title"
+            android:textAppearance="?android:attr/textAppearanceListItemSecondary"
+            android:textColor="?android:attr/textColorSecondary"
+            android:maxLines="4"/>
+
+        <!-- Preference should place its actual preference widget here. -->
+        <LinearLayout
+            android:id="@android:id/widget_frame"
+            android:layout_width="wrap_content"
+            android:layout_height="match_parent"
+            android:layout_below="@android:id/summary"
+            android:layout_alignStart="@android:id/title"
+            android:gravity="center"
+            android:orientation="vertical"/>
+
+        <SeekBar
+            android:id="@*android:id/seekbar"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_below="@android:id/summary"
+            android:layout_toEndOf="@android:id/widget_frame"
+            android:layout_alignParentEnd="true"/>
+
+    </RelativeLayout>
+
+</LinearLayout>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index dd89e71..955b8cc 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -5369,9 +5369,9 @@
     <string name="vpn_not_supported_by_this_app">Not supported by this app</string>
     <!-- Preference title for forcing all network connections to go through VPN. -->
     <string name="vpn_require_connection">Only allow connections through VPN</string>
-    <!-- Preference summary for network connections being forced to go through VPN. -->
+    <!-- Preference summary when the preference to force all network connections to go through a VPN is enabled, blocking all other network traffic. In this case apps must use the VPN for all connections. -->
     <string name="vpn_lockdown_active">Lockdown active</string>
-    <!-- Preference summary for network connections not being forced to go through VPN. -->
+    <!-- Preference summary when the preference to force all network connections to go through a VPN is disabled. In this case use of the VPN is optional for apps. -->
     <string name="vpn_lockdown_inactive">Lockdown inactive</string>
 
     <!-- Summary describing the always-on VPN feature. [CHAR LIMIT=NONE] -->
diff --git a/res/values/styles_preference.xml b/res/values/styles_preference.xml
index 1eedd4d..a78d87b 100644
--- a/res/values/styles_preference.xml
+++ b/res/values/styles_preference.xml
@@ -49,6 +49,10 @@
         <item name="android:layout">@layout/preference_category_material_settings</item>
     </style>
 
+    <style name="SettingsSeekBarPreference">
+        <item name="android:layout">@layout/preference_widget_seekbar_settings</item>
+    </style>
+
     <style name="SettingsSwitchPreference" parent="SettingsPreference">
         <item name="widgetLayout">@*android:layout/preference_widget_switch</item>
         <item name="switchTextOn">@*android:string/capital_on</item>
diff --git a/res/values/themes.xml b/res/values/themes.xml
index 02bf523..6438e70 100644
--- a/res/values/themes.xml
+++ b/res/values/themes.xml
@@ -90,6 +90,7 @@
         <item name="preferenceCategoryStyle">@style/SettingsPreferenceCategory</item>
         <item name="preferenceFragmentStyle">@style/PreferenceFragmentStyle</item>
         <item name="preferenceStyle">@style/SettingsPreference</item>
+        <item name="seekBarPreferenceStyle">@style/SettingsSeekBarPreference</item>
         <item name="switchPreferenceStyle">@style/SettingsSwitchPreference</item>
     </style>
 
diff --git a/res/xml/accessibility_autoclick_settings.xml b/res/xml/accessibility_autoclick_settings.xml
index 39b9736..f774335 100644
--- a/res/xml/accessibility_autoclick_settings.xml
+++ b/res/xml/accessibility_autoclick_settings.xml
@@ -15,12 +15,11 @@
 -->
 
 <PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
-    android:title="@string/accessibility_autoclick_preference_title" >
+                  android:title="@string/accessibility_autoclick_preference_title">
 
 
     <com.android.settings.SeekBarPreference
         android:key="autoclick_delay"
-        android:title="@string/accessibility_autoclick_delay_preference_title"
-        android:layout="@layout/preference_iconless_slider" />
+        android:title="@string/accessibility_autoclick_delay_preference_title"/>
 
 </PreferenceScreen>
diff --git a/res/xml/tts_settings.xml b/res/xml/tts_settings.xml
index a74431d..31d2b17 100644
--- a/res/xml/tts_settings.xml
+++ b/res/xml/tts_settings.xml
@@ -31,16 +31,14 @@
             android:title="@string/tts_default_rate_title"
             android:summary="@string/tts_default_rate_summary"
             android:defaultValue="50"
-            android:max="600"
-            android:layout="@layout/preference_iconless_slider" />
+            android:max="600"/>
 
         <com.android.settings.SeekBarPreference
             android:key="tts_default_pitch"
             android:title="@string/tts_default_pitch_title"
             android:summary="@string/tts_default_pitch_summary"
             android:defaultValue="100"
-            android:max="400"
-            android:layout="@layout/preference_iconless_slider" />
+            android:max="400"/>
 
         <Preference android:key="reset_speech_rate"
             android:persistent="false"
diff --git a/src/com/android/settings/DeviceInfoSettings.java b/src/com/android/settings/DeviceInfoSettings.java
index ec34947..0da44cd 100644
--- a/src/com/android/settings/DeviceInfoSettings.java
+++ b/src/com/android/settings/DeviceInfoSettings.java
@@ -28,6 +28,7 @@
 import android.os.UserManager;
 import android.provider.SearchIndexableResource;
 import android.provider.Settings;
+import android.support.annotation.VisibleForTesting;
 import android.support.v7.preference.Preference;
 import android.support.v7.preference.PreferenceGroup;
 import android.text.TextUtils;
@@ -38,6 +39,7 @@
 import com.android.settings.deviceinfo.AdditionalSystemUpdatePreferenceController;
 import com.android.settings.deviceinfo.BuildNumberPreferenceController;
 import com.android.settings.deviceinfo.SystemUpdatePreferenceController;
+import com.android.settings.overlay.FeatureFactory;
 import com.android.settings.search.BaseSearchIndexProvider;
 import com.android.settings.search.Indexable;
 import com.android.settingslib.DeviceInfoUtils;
@@ -55,6 +57,7 @@
 
     private static final String KEY_MANUAL = "manual";
     private static final String KEY_REGULATORY_INFO = "regulatory_info";
+    private static final String KEY_SYSTEM_UPDATE_SETTINGS = "system_update_settings";
     private static final String PROPERTY_URL_SAFETYLEGAL = "ro.url.safetylegal";
     private static final String PROPERTY_SELINUX_STATUS = "ro.build.selinux";
     private static final String KEY_KERNEL_VERSION = "kernel_version";
@@ -102,7 +105,6 @@
         super.onCreate(icicle);
         final Activity activity = getActivity();
         mUm = UserManager.get(activity);
-        mSystemUpdatePreferenceController = new SystemUpdatePreferenceController(activity, mUm);
         mAdditionalSystemUpdatePreferenceController =
                 new AdditionalSystemUpdatePreferenceController(activity);
         mBuildNumberPreferenceController =
@@ -160,7 +162,7 @@
          * Settings is a generic app and should not contain any device-specific
          * info.
          */
-        mSystemUpdatePreferenceController.displayPreference(getPreferenceScreen());
+        displaySystemUpdates(activity);
         mAdditionalSystemUpdatePreferenceController.displayPreference(getPreferenceScreen());
 
         // Remove manual entry if none present.
@@ -220,10 +222,23 @@
         } else if (preference.getKey().equals(KEY_DEVICE_FEEDBACK)) {
             sendFeedback();
         }
-        mSystemUpdatePreferenceController.handlePreferenceTreeClick(preference);
+        if (mSystemUpdatePreferenceController != null) {
+            mSystemUpdatePreferenceController.handlePreferenceTreeClick(preference);
+        }
         return super.onPreferenceTreeClick(preference);
     }
 
+    @VisibleForTesting
+    void displaySystemUpdates(Context context) {
+        if (!FeatureFactory.getFactory(context).getDashboardFeatureProvider(context).isEnabled()) {
+            mSystemUpdatePreferenceController
+                    = new SystemUpdatePreferenceController(context, UserManager.get(context));
+            mSystemUpdatePreferenceController.displayPreference(getPreferenceScreen());
+        } else {
+            getPreferenceScreen().removePreference(findPreference(KEY_SYSTEM_UPDATE_SETTINGS));
+        }
+    }
+
     private void removePreferenceIfPropertyMissing(PreferenceGroup preferenceGroup,
             String preference, String property ) {
         if (SystemProperties.get(property).equals("")) {
diff --git a/src/com/android/settings/SeekBarPreference.java b/src/com/android/settings/SeekBarPreference.java
index ef28ed7..26b69db 100644
--- a/src/com/android/settings/SeekBarPreference.java
+++ b/src/com/android/settings/SeekBarPreference.java
@@ -20,6 +20,7 @@
 import android.content.res.TypedArray;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.support.v4.content.res.TypedArrayUtils;
 import android.support.v7.preference.Preference;
 import android.support.v7.preference.PreferenceViewHolder;
 import android.util.AttributeSet;
@@ -64,7 +65,9 @@
     }
 
     public SeekBarPreference(Context context, AttributeSet attrs) {
-        this(context, attrs, com.android.internal.R.attr.seekBarPreferenceStyle);
+        this(context, attrs, TypedArrayUtils.getAttr(context,
+                        android.support.v7.preference.R.attr.seekBarPreferenceStyle,
+                        com.android.internal.R.attr.seekBarPreferenceStyle));
     }
 
     public SeekBarPreference(Context context) {
diff --git a/src/com/android/settings/SettingsDumpService.java b/src/com/android/settings/SettingsDumpService.java
index 472a2eb..67a8f50 100644
--- a/src/com/android/settings/SettingsDumpService.java
+++ b/src/com/android/settings/SettingsDumpService.java
@@ -16,14 +16,18 @@
 
 import android.app.Service;
 import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
 import android.net.ConnectivityManager;
 import android.net.NetworkTemplate;
+import android.net.Uri;
 import android.os.IBinder;
 import android.os.storage.StorageManager;
 import android.os.storage.VolumeInfo;
 import android.telephony.SubscriptionInfo;
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.settings.applications.ProcStatsData;
 import com.android.settingslib.net.DataUsageController;
 import org.json.JSONArray;
@@ -35,6 +39,13 @@
 import java.io.PrintWriter;
 
 public class SettingsDumpService extends Service {
+    @VisibleForTesting static final String KEY_SERVICE = "service";
+    @VisibleForTesting static final String KEY_STORAGE = "storage";
+    @VisibleForTesting static final String KEY_DATAUSAGE = "datausage";
+    @VisibleForTesting static final String KEY_MEMORY = "memory";
+    @VisibleForTesting static final String KEY_DEFAULT_BROWSER_APP = "default_browser_app";
+    @VisibleForTesting static final Intent BROWSER_INTENT =
+            new Intent("android.intent.action.VIEW", Uri.parse("http://"));
 
     @Override
     public IBinder onBind(Intent intent) {
@@ -46,10 +57,11 @@
         JSONObject dump = new JSONObject();
 
         try {
-            dump.put("service", "Settings State");
-            dump.put("storage", dumpStorage());
-            dump.put("datausage", dumpDataUsage());
-            dump.put("memory", dumpMemory());
+            dump.put(KEY_SERVICE, "Settings State");
+            dump.put(KEY_STORAGE, dumpStorage());
+            dump.put(KEY_DATAUSAGE, dumpDataUsage());
+            dump.put(KEY_MEMORY, dumpMemory());
+            dump.put(KEY_DEFAULT_BROWSER_APP, dumpDefaultBrowser());
         } catch (Exception e) {
             e.printStackTrace();
         }
@@ -127,4 +139,16 @@
         }
         return obj;
     }
+
+    @VisibleForTesting
+    String dumpDefaultBrowser() {
+        final ResolveInfo resolveInfo = getPackageManager().resolveActivity(
+                BROWSER_INTENT, PackageManager.MATCH_DEFAULT_ONLY);
+
+        if (resolveInfo == null || resolveInfo.activityInfo.packageName.equals("android")) {
+            return null;
+        } else {
+            return resolveInfo.activityInfo.packageName;
+        }
+    }
 }
diff --git a/src/com/android/settings/bluetooth/BluetoothSettings.java b/src/com/android/settings/bluetooth/BluetoothSettings.java
index 5c18d66..2a1341e 100644
--- a/src/com/android/settings/bluetooth/BluetoothSettings.java
+++ b/src/com/android/settings/bluetooth/BluetoothSettings.java
@@ -27,7 +27,7 @@
 import android.content.res.Resources;
 import android.os.Bundle;
 import android.provider.Settings;
-import android.support.v7.preference.Preference;
+import android.support.annotation.VisibleForTesting;
 import android.support.v7.preference.PreferenceCategory;
 import android.support.v7.preference.PreferenceGroup;
 import android.support.v7.preference.PreferenceScreen;
@@ -58,6 +58,7 @@
 import com.android.settingslib.bluetooth.LocalBluetoothManager;
 
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.List;
 import java.util.Locale;
 import java.util.Set;
@@ -105,7 +106,7 @@
         public void onReceive(Context context, Intent intent) {
             final String action = intent.getAction();
             final int state =
-                intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR);
+                    intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR);
 
             if (action.equals(BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED)) {
                 updateDeviceName(context);
@@ -122,8 +123,8 @@
                 final Locale locale = res.getConfiguration().getLocales().get(0);
                 final BidiFormatter bidiFormatter = BidiFormatter.getInstance(locale);
                 mMyDevicePreference.setTitle(res.getString(
-                            R.string.bluetooth_is_visible_message,
-                            bidiFormatter.unicodeWrap(mLocalAdapter.getName())));
+                        R.string.bluetooth_is_visible_message,
+                        bidiFormatter.unicodeWrap(mLocalAdapter.getName())));
             }
         }
     };
@@ -230,7 +231,7 @@
         boolean bluetoothIsEnabled = mLocalAdapter.getBluetoothState() == BluetoothAdapter.STATE_ON;
         boolean isDiscovering = mLocalAdapter.isDiscovering();
         int textId = isDiscovering ? R.string.bluetooth_searching_for_devices :
-            R.string.bluetooth_search_for_devices;
+                R.string.bluetooth_search_for_devices;
         menu.add(Menu.NONE, MENU_ID_SCAN, 0, textId)
                 .setEnabled(bluetoothIsEnabled && !isDiscovering)
                 .setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
@@ -356,8 +357,8 @@
                 final Locale locale = res.getConfiguration().getLocales().get(0);
                 final BidiFormatter bidiFormatter = BidiFormatter.getInstance(locale);
                 mMyDevicePreference.setTitle(res.getString(
-                            R.string.bluetooth_is_visible_message,
-                            bidiFormatter.unicodeWrap(mLocalAdapter.getName())));
+                        R.string.bluetooth_is_visible_message,
+                        bidiFormatter.unicodeWrap(mLocalAdapter.getName())));
 
                 getActivity().invalidateOptionsMenu();
 
@@ -438,8 +439,9 @@
         super.onBluetoothStateChanged(bluetoothState);
         // If BT is turned off/on staying in the same BT Settings screen
         // discoverability to be set again
-        if (BluetoothAdapter.STATE_ON == bluetoothState)
+        if (BluetoothAdapter.STATE_ON == bluetoothState) {
             mInitiateDiscoverable = true;
+        }
         updateContent(bluetoothState);
     }
 
@@ -481,6 +483,7 @@
 
     /**
      * Add a listener, which enables the advanced settings icon.
+     *
      * @param preference the newly added preference
      */
     @Override
@@ -497,7 +500,8 @@
         return R.string.help_url_bluetooth;
     }
 
-    private static class SummaryProvider
+    @VisibleForTesting
+    static class SummaryProvider
             implements SummaryLoader.SummaryProvider, BluetoothCallback {
 
         private final LocalBluetoothManager mBluetoothManager;
@@ -505,10 +509,11 @@
         private final SummaryLoader mSummaryLoader;
 
         private boolean mEnabled;
-        private boolean mConnected;
+        private int mConnectionState;
 
-        public SummaryProvider(Context context, SummaryLoader summaryLoader) {
-            mBluetoothManager = Utils.getLocalBtManager(context);
+        public SummaryProvider(Context context, SummaryLoader summaryLoader,
+                LocalBluetoothManager bluetoothManager) {
+            mBluetoothManager = bluetoothManager;
             mContext = context;
             mSummaryLoader = summaryLoader;
         }
@@ -519,8 +524,7 @@
             if (defaultAdapter == null) return;
             if (listening) {
                 mEnabled = defaultAdapter.isEnabled();
-                mConnected =
-                        defaultAdapter.getConnectionState() == BluetoothAdapter.STATE_CONNECTED;
+                mConnectionState = defaultAdapter.getConnectionState();
                 mSummaryLoader.setSummary(this, getSummary());
                 mBluetoothManager.getEventManager().registerCallback(this);
             } else {
@@ -529,20 +533,26 @@
         }
 
         private CharSequence getSummary() {
-            return mContext.getString(!mEnabled ? R.string.bluetooth_disabled
-                    : mConnected ? R.string.bluetooth_connected
-                    : R.string.bluetooth_disconnected);
+            if (!mEnabled) {
+                return mContext.getString(R.string.bluetooth_disabled);
+            } else if (mConnectionState == BluetoothAdapter.STATE_CONNECTED) {
+                return mContext.getString(R.string.bluetooth_connected);
+            } else {
+                return mContext.getString(R.string.bluetooth_disconnected);
+            }
         }
 
         @Override
         public void onBluetoothStateChanged(int bluetoothState) {
-            mEnabled = bluetoothState == BluetoothAdapter.STATE_ON;
+            mEnabled = bluetoothState == BluetoothAdapter.STATE_ON
+                    || bluetoothState == BluetoothAdapter.STATE_TURNING_ON;
             mSummaryLoader.setSummary(this, getSummary());
         }
 
         @Override
         public void onConnectionStateChanged(CachedBluetoothDevice cachedDevice, int state) {
-            mConnected = state == BluetoothAdapter.STATE_CONNECTED;
+            mConnectionState = state;
+            updateConnected();
             mSummaryLoader.setSummary(this, getSummary());
         }
 
@@ -565,49 +575,84 @@
         public void onDeviceBondStateChanged(CachedBluetoothDevice cachedDevice, int bondState) {
 
         }
+
+        private void updateConnected() {
+            // Make sure our connection state is up to date.
+            int state = mBluetoothManager.getBluetoothAdapter().getConnectionState();
+            if (state != mConnectionState) {
+                mConnectionState = state;
+                return;
+            }
+            final Collection<CachedBluetoothDevice> devices = getDevices();
+            if (devices == null) {
+                mConnectionState = BluetoothAdapter.STATE_DISCONNECTED;
+                return;
+            }
+            if (mConnectionState == BluetoothAdapter.STATE_CONNECTED) {
+                CachedBluetoothDevice connectedDevice = null;
+                for (CachedBluetoothDevice device : devices) {
+                    if (device.isConnected()) {
+                        connectedDevice = device;
+                    }
+                }
+                if (connectedDevice == null) {
+                    // If somehow we think we are connected, but have no connected devices, we
+                    // aren't connected.
+                    mConnectionState = BluetoothAdapter.STATE_DISCONNECTED;
+                }
+            }
+        }
+
+        private Collection<CachedBluetoothDevice> getDevices() {
+            return mBluetoothManager != null
+                    ? mBluetoothManager.getCachedDeviceManager().getCachedDevicesCopy()
+                    : null;
+        }
     }
 
     public static final SummaryLoader.SummaryProviderFactory SUMMARY_PROVIDER_FACTORY
             = new SummaryLoader.SummaryProviderFactory() {
         @Override
         public SummaryLoader.SummaryProvider createSummaryProvider(Activity activity,
-                                                                   SummaryLoader summaryLoader) {
-            return new SummaryProvider(activity, summaryLoader);
+                SummaryLoader summaryLoader) {
+
+            return new SummaryProvider(activity, summaryLoader, Utils.getLocalBtManager(activity));
         }
     };
 
     public static final SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
-        new BaseSearchIndexProvider() {
-            @Override
-            public List<SearchIndexableRaw> getRawDataToIndex(Context context, boolean enabled) {
+            new BaseSearchIndexProvider() {
+                @Override
+                public List<SearchIndexableRaw> getRawDataToIndex(Context context,
+                        boolean enabled) {
 
-                final List<SearchIndexableRaw> result = new ArrayList<SearchIndexableRaw>();
+                    final List<SearchIndexableRaw> result = new ArrayList<SearchIndexableRaw>();
 
-                final Resources res = context.getResources();
+                    final Resources res = context.getResources();
 
-                // Add fragment title
-                SearchIndexableRaw data = new SearchIndexableRaw(context);
-                data.title = res.getString(R.string.bluetooth_settings);
-                data.screenTitle = res.getString(R.string.bluetooth_settings);
-                result.add(data);
+                    // Add fragment title
+                    SearchIndexableRaw data = new SearchIndexableRaw(context);
+                    data.title = res.getString(R.string.bluetooth_settings);
+                    data.screenTitle = res.getString(R.string.bluetooth_settings);
+                    result.add(data);
 
-                // Add cached paired BT devices
-                LocalBluetoothManager lbtm = Utils.getLocalBtManager(context);
-                // LocalBluetoothManager.getInstance can return null if the device does not
-                // support bluetooth (e.g. the emulator).
-                if (lbtm != null) {
-                    Set<BluetoothDevice> bondedDevices =
-                            lbtm.getBluetoothAdapter().getBondedDevices();
+                    // Add cached paired BT devices
+                    LocalBluetoothManager lbtm = Utils.getLocalBtManager(context);
+                    // LocalBluetoothManager.getInstance can return null if the device does not
+                    // support bluetooth (e.g. the emulator).
+                    if (lbtm != null) {
+                        Set<BluetoothDevice> bondedDevices =
+                                lbtm.getBluetoothAdapter().getBondedDevices();
 
-                    for (BluetoothDevice device : bondedDevices) {
-                        data = new SearchIndexableRaw(context);
-                        data.title = device.getName();
-                        data.screenTitle = res.getString(R.string.bluetooth_settings);
-                        data.enabled = enabled;
-                        result.add(data);
+                        for (BluetoothDevice device : bondedDevices) {
+                            data = new SearchIndexableRaw(context);
+                            data.title = device.getName();
+                            data.screenTitle = res.getString(R.string.bluetooth_settings);
+                            data.enabled = enabled;
+                            result.add(data);
+                        }
                     }
+                    return result;
                 }
-                return result;
-            }
-        };
+            };
 }
diff --git a/src/com/android/settings/dashboard/DashboardFragment.java b/src/com/android/settings/dashboard/DashboardFragment.java
index ab1ec13..9afe4b2 100644
--- a/src/com/android/settings/dashboard/DashboardFragment.java
+++ b/src/com/android/settings/dashboard/DashboardFragment.java
@@ -330,5 +330,6 @@
             mDashboardTilePrefKeys.remove(key);
             mProgressiveDisclosureMixin.removePreference(screen, key);
         }
+        mSummaryLoader.setListening(true);
     }
 }
diff --git a/src/com/android/settings/fuelgauge/PowerUsageSummary.java b/src/com/android/settings/fuelgauge/PowerUsageSummary.java
index 14e6693..c4b97d4 100644
--- a/src/com/android/settings/fuelgauge/PowerUsageSummary.java
+++ b/src/com/android/settings/fuelgauge/PowerUsageSummary.java
@@ -30,6 +30,7 @@
 import android.support.v7.preference.Preference;
 import android.support.v7.preference.PreferenceGroup;
 import android.text.TextUtils;
+import android.util.Log;
 import android.util.SparseArray;
 import android.util.TypedValue;
 import android.view.Menu;
@@ -359,10 +360,8 @@
                         userHandle);
                 final CharSequence contentDescription = mUm.getBadgedLabelForUser(entry.getLabel(),
                         userHandle);
-                final String key = sipper.drainType == DrainType.APP ? sipper.getPackages() != null
-                        ? TextUtils.concat(sipper.getPackages()).toString()
-                        : String.valueOf(sipper.getUid())
-                        : sipper.drainType.toString();
+
+                final String key = extractKeyFromSipper(sipper);
                 PowerGaugePreference pref = (PowerGaugePreference) getCachedPreference(key);
                 if (pref == null) {
                     pref = new PowerGaugePreference(getPrefContext(), badgedIcon,
@@ -376,9 +375,6 @@
                 pref.setTitle(entry.getLabel());
                 pref.setOrder(i + 1);
                 pref.setPercent(percentOfMax, percentOfTotal);
-                if (sipper.uidObj != null) {
-                    pref.setKey(Integer.toString(sipper.uidObj.getUid()));
-                }
                 if ((sipper.drainType != DrainType.APP || sipper.uidObj.getUid() == 0)
                          && sipper.drainType != DrainType.USER) {
                     pref.setTint(colorControl);
@@ -399,6 +395,20 @@
         BatteryEntry.startRequestQueue();
     }
 
+    @VisibleForTesting
+    String extractKeyFromSipper(BatterySipper sipper) {
+        if (sipper.uidObj != null) {
+            return Integer.toString(sipper.getUid());
+        } else if (sipper.drainType != DrainType.APP) {
+            return sipper.drainType.toString();
+        } else if (sipper.getPackages() != null) {
+            return TextUtils.concat(sipper.getPackages()).toString();
+        } else {
+            Log.w(TAG, "Inappropriate BatterySipper without uid and package names: " + sipper);
+            return "-1";
+        }
+    }
+
     private static List<BatterySipper> getFakeStats() {
         ArrayList<BatterySipper> stats = new ArrayList<>();
         float use = 5;
diff --git a/src/com/android/settings/search/Index.java b/src/com/android/settings/search/Index.java
index bff841b..cd6e562 100644
--- a/src/com/android/settings/search/Index.java
+++ b/src/com/android/settings/search/Index.java
@@ -217,20 +217,20 @@
      */
     public static Index getInstance(Context context) {
         if (sInstance == null) {
-            sInstance = new Index(context.getApplicationContext(), BASE_AUTHORITY);
+            synchronized (Index.class) {
+                if (sInstance == null) {
+                    sInstance = new Index(context.getApplicationContext(), BASE_AUTHORITY);
+                }
+            }
         }
         return sInstance;
     }
 
-    public Index(Context context, String baseAuthority) {
+    private Index(Context context, String baseAuthority) {
         mContext = context;
         mBaseAuthority = baseAuthority;
     }
 
-    public void setContext(Context context) {
-        mContext = context;
-    }
-
     public boolean isAvailable() {
         return mIsAvailable.get();
     }
diff --git a/src/com/android/settings/users/UserSettings.java b/src/com/android/settings/users/UserSettings.java
index 567ae95..a794953 100644
--- a/src/com/android/settings/users/UserSettings.java
+++ b/src/com/android/settings/users/UserSettings.java
@@ -54,6 +54,7 @@
 import android.view.View.OnClickListener;
 import android.widget.SimpleAdapter;
 
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.internal.widget.LockPatternUtils;
 import com.android.settings.ChooseLockGeneric;
@@ -66,6 +67,7 @@
 import com.android.settings.accounts.AddUserWhenLockedPreferenceController;
 import com.android.settings.accounts.EmergencyInfoPreferenceController;
 import com.android.settings.dashboard.SummaryLoader;
+import com.android.settings.overlay.FeatureFactory;
 import com.android.settings.search.BaseSearchIndexProvider;
 import com.android.settings.search.Indexable;
 import com.android.settings.search.SearchIndexableRaw;
@@ -137,6 +139,7 @@
     private UserPreference mMePreference;
     private DimmableIconPreference mAddUser;
     private PreferenceGroup mLockScreenSettings;
+    private RestrictedSwitchPreference mAddUserWhenLocked;
     private Preference mEmergencyInfoPreference;
     private int mRemovingUserId = -1;
     private int mAddedUserId = 0;
@@ -235,10 +238,14 @@
                 mAddUser.setTitle(R.string.user_add_user_menu);
             }
         }
-        mLockScreenSettings = (PreferenceGroup) findPreference("lock_screen_settings");
-        mEmergencyInfoPreference = findPreference(KEY_EMERGENCY_INFO);
-        mEnergencyInfoController = new EmergencyInfoPreferenceController(context);
-        mAddUserWhenLockedController = new AddUserWhenLockedPreferenceController(context);
+        if (showEmergencyInfoAndAddUsersWhenLock(context)) {
+            mLockScreenSettings = (PreferenceGroup) findPreference("lock_screen_settings");
+            mAddUserWhenLocked =
+                    (RestrictedSwitchPreference) findPreference("add_users_when_locked");
+            mEmergencyInfoPreference = findPreference(KEY_EMERGENCY_INFO);
+            mEnergencyInfoController = new EmergencyInfoPreferenceController(context);
+            mAddUserWhenLockedController = new AddUserWhenLockedPreferenceController(context);
+        }
         setHasOptionsMenu(true);
         IntentFilter filter = new IntentFilter(Intent.ACTION_USER_REMOVED);
         filter.addAction(Intent.ACTION_USER_INFO_CHANGED);
@@ -653,6 +660,11 @@
         }
     }
 
+    @VisibleForTesting
+    boolean showEmergencyInfoAndAddUsersWhenLock(Context context) {
+        return !FeatureFactory.getFactory(context).getDashboardFeatureProvider(context).isEnabled();
+    }
+
     private static boolean emergencyInfoActivityPresent(Context context) {
         Intent intent = new Intent(ACTION_EDIT_EMERGENCY_INFO).setPackage("com.android.emergency");
         List<ResolveInfo> infos = context.getPackageManager().queryIntentActivities(intent, 0);
@@ -893,15 +905,19 @@
             }
         }
 
-        if (mAddUserWhenLockedController.isAvailable()) {
-            mLockScreenSettings.setOrder(Preference.DEFAULT_ORDER);
-            preferenceScreen.addPreference(mLockScreenSettings);
-        }
+        if (showEmergencyInfoAndAddUsersWhenLock(context)) {
+            if (mAddUserWhenLockedController.isAvailable()) {
+                mLockScreenSettings.setOrder(Preference.DEFAULT_ORDER);
+                preferenceScreen.addPreference(mLockScreenSettings);
+                mAddUserWhenLockedController.updateState(mAddUserWhenLocked);
+                mAddUserWhenLocked.setOnPreferenceChangeListener(mAddUserWhenLockedController);
+            }
 
-        if (emergencyInfoActivityPresent(getContext())) {
-            mEmergencyInfoPreference.setOnPreferenceClickListener(this);
-            mEmergencyInfoPreference.setOrder(Preference.DEFAULT_ORDER);
-            preferenceScreen.addPreference(mEmergencyInfoPreference);
+            if (emergencyInfoActivityPresent(getContext())) {
+                mEmergencyInfoPreference.setOnPreferenceClickListener(this);
+                mEmergencyInfoPreference.setOrder(Preference.DEFAULT_ORDER);
+                preferenceScreen.addPreference(mEmergencyInfoPreference);
+            }
         }
     }
 
@@ -983,7 +999,7 @@
             } else {
                 onAddUserClicked(USER_TYPE_USER);
             }
-        } else {
+        } else if (mEnergencyInfoController != null) {
             mEnergencyInfoController.handlePreferenceTreeClick(pref);
         }
         return false;
diff --git a/tests/robotests/src/com/android/settings/DeviceInfoSettingsTest.java b/tests/robotests/src/com/android/settings/DeviceInfoSettingsTest.java
index c66c2b4..c3365b8 100644
--- a/tests/robotests/src/com/android/settings/DeviceInfoSettingsTest.java
+++ b/tests/robotests/src/com/android/settings/DeviceInfoSettingsTest.java
@@ -16,17 +16,56 @@
 
 package com.android.settings;
 
+import android.content.Context;
+import android.os.UserManager;
+import android.support.v7.preference.Preference;
+import android.support.v7.preference.PreferenceScreen;
 import android.test.AndroidTestCase;
 import android.test.suitebuilder.annotation.SmallTest;
+
 import com.android.settingslib.DeviceInfoUtils;
+import com.android.settings.testutils.FakeFeatureFactory;
+
+import org.junit.Before;
 import org.junit.runner.RunWith;
 import org.junit.Test;
+import org.mockito.Answers;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
 import org.robolectric.annotation.Config;
 
+import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
 @RunWith(SettingsRobolectricTestRunner.class)
 @Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
 public class DeviceInfoSettingsTest extends AndroidTestCase {
 
+    @Mock(answer = Answers.RETURNS_DEEP_STUBS)
+    private Context mContext;
+    @Mock
+    private PreferenceScreen mScreen;
+    @Mock
+    private UserManager mUserManager;
+
+    private FakeFeatureFactory mFeatureFactory;
+    private DeviceInfoSettings mSettings;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        FakeFeatureFactory.setupForTest(mContext);
+        mFeatureFactory = (FakeFeatureFactory) FakeFeatureFactory.getFactory(mContext);
+        when(mContext.getSystemService(Context.USER_SERVICE)).thenReturn(mUserManager);
+        mSettings = spy(new DeviceInfoSettings());
+        doReturn(mScreen).when(mSettings).getPreferenceScreen();
+    }
+
     @Test
     public void testGetFormattedKernelVersion() throws Exception {
         if ("Unavailable".equals(DeviceInfoUtils.getFormattedKernelVersion())) {
@@ -65,4 +104,20 @@
                         "version 3.8.275480 (based on LLVM 3.8.275480)) " +
                         "#5 SMP PREEMPT Fri Oct 28 14:38:13 PDT 2016"));
     }
+
+    @Test
+    public void testShowSystemUpdatesWhenIADisabled() throws Exception {
+        when(mFeatureFactory.dashboardFeatureProvider.isEnabled()).thenReturn(true);
+        mSettings.displaySystemUpdates(mContext);
+
+        verify(mScreen).removePreference(any(Preference.class));
+    }
+
+    @Test
+    public void testHideSystemUpdatesWhenIAEnabled() throws Exception {
+        when(mFeatureFactory.dashboardFeatureProvider.isEnabled()).thenReturn(false);
+        mSettings.displaySystemUpdates(mContext);
+
+        verify(mScreen, never()).removePreference(any(Preference.class));
+    }
 }
diff --git a/tests/robotests/src/com/android/settings/SettingsDumpServiceTest.java b/tests/robotests/src/com/android/settings/SettingsDumpServiceTest.java
new file mode 100644
index 0000000..043b0fe
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/SettingsDumpServiceTest.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2016 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;
+
+import android.content.pm.ActivityInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.support.annotation.NonNull;
+import org.json.JSONException;
+import org.json.JSONObject;
+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;
+
+import java.io.OutputStream;
+import java.io.PrintWriter;
+
+import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Mockito.when;
+
+@RunWith(SettingsRobolectricTestRunner.class)
+@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
+public class SettingsDumpServiceTest {
+    private static final String PACKAGE_BROWSER = "com.android.test.browser";
+    private static final String PACKAGE_NULL = "android";
+    @Mock
+    private PackageManager mPackageManager;
+    @Mock
+    private ResolveInfo mResolveInfo;
+    private TestService mTestService;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+
+        when(mPackageManager.resolveActivity(TestService.BROWSER_INTENT,
+                PackageManager.MATCH_DEFAULT_ONLY)).thenReturn(mResolveInfo);
+        mTestService = new TestService();
+        mTestService.setPackageManager(mPackageManager);
+    }
+
+    @Test
+    public void testDumpDefaultBrowser_DefaultBrowser_ReturnBrowserName() {
+        mResolveInfo.activityInfo = new ActivityInfo();
+        mResolveInfo.activityInfo.packageName = PACKAGE_BROWSER;
+
+        assertThat(mTestService.dumpDefaultBrowser()).isEqualTo(PACKAGE_BROWSER);
+    }
+
+    @Test
+    public void testDumpDefaultBrowser_NoDefault_ReturnNull() {
+        mResolveInfo.activityInfo = new ActivityInfo();
+        mResolveInfo.activityInfo.packageName = PACKAGE_NULL;
+
+        assertThat(mTestService.dumpDefaultBrowser()).isEqualTo(null);
+    }
+
+    @Test
+    public void testDump_ReturnJsonObject() throws JSONException {
+        mResolveInfo.activityInfo = new ActivityInfo();
+        mResolveInfo.activityInfo.packageName = PACKAGE_BROWSER;
+        TestPrintWriter printWriter = new TestPrintWriter(System.out);
+
+        mTestService.dump(null, printWriter, null);
+        JSONObject object = (JSONObject)printWriter.getPrintObject();
+
+        assertThat(object.get(TestService.KEY_SERVICE)).isNotNull();
+    }
+
+    /**
+     * Test service used to pass in the mock {@link PackageManager}
+     */
+    private class TestService extends SettingsDumpService {
+        private PackageManager mPm;
+
+        public void setPackageManager(PackageManager pm) {
+            mPm = pm;
+        }
+
+        @Override
+        public PackageManager getPackageManager() {
+            return mPm;
+        }
+    }
+
+    /**
+     * Test printWriter to store the object to be printed
+     */
+    private class TestPrintWriter extends PrintWriter {
+        private Object mPrintObject;
+
+        public TestPrintWriter(@NonNull OutputStream out) {
+            super(out);
+        }
+
+        @Override
+        public void println(Object object) {
+            mPrintObject = object;
+        }
+
+        public Object getPrintObject() {
+            return mPrintObject;
+        }
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/bluetooth/BluetoothSettingsSummaryProviderTest.java b/tests/robotests/src/com/android/settings/bluetooth/BluetoothSettingsSummaryProviderTest.java
new file mode 100644
index 0000000..7ac7cb1
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/bluetooth/BluetoothSettingsSummaryProviderTest.java
@@ -0,0 +1,168 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.bluetooth;
+
+import android.bluetooth.BluetoothAdapter;
+import android.content.Context;
+
+import com.android.settings.R;
+import com.android.settings.SettingsRobolectricTestRunner;
+import com.android.settings.TestConfig;
+import com.android.settings.dashboard.SummaryLoader;
+import com.android.settingslib.bluetooth.CachedBluetoothDevice;
+import com.android.settingslib.bluetooth.LocalBluetoothManager;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Answers;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
+import org.robolectric.shadows.ShadowBluetoothAdapter;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+@RunWith(SettingsRobolectricTestRunner.class)
+@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
+public class BluetoothSettingsSummaryProviderTest {
+
+    private Context mContext;
+    @Mock(answer = Answers.RETURNS_DEEP_STUBS)
+    private LocalBluetoothManager mBluetoothManager;
+    @Mock
+    private SummaryLoader mSummaryLoader;
+
+    private BluetoothSettings.SummaryProvider mSummaryProvider;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        mContext = RuntimeEnvironment.application.getApplicationContext();
+        mSummaryProvider = new BluetoothSettings.SummaryProvider(mContext, mSummaryLoader,
+                mBluetoothManager);
+    }
+
+    @Test
+    public void setListening_shouldUpdateSummary() {
+        mSummaryProvider.setListening(true);
+
+        verify(mBluetoothManager.getEventManager()).registerCallback(mSummaryProvider);
+        verify(mSummaryLoader).setSummary(eq(mSummaryProvider), anyString());
+    }
+
+    @Test
+    public void setNotListening_shouldUnregister() {
+        mSummaryProvider.setListening(false);
+
+        verify(mBluetoothManager.getEventManager()).unregisterCallback(mSummaryProvider);
+    }
+
+    @Test
+    public void updateSummary_btDisabled_shouldShowDisabledMessage() {
+        ShadowBluetoothAdapter.getDefaultAdapter().disable();
+        mSummaryProvider.setListening(true);
+
+        verify(mSummaryLoader).setSummary(mSummaryProvider,
+                mContext.getString(R.string.bluetooth_disabled));
+    }
+
+    @Test
+    public void updateSummary_btEnabled_noDevice_shouldShowDisconnectedMessage() {
+        ShadowBluetoothAdapter.getDefaultAdapter().enable();
+        mSummaryProvider.setListening(true);
+
+        verify(mSummaryLoader).setSummary(mSummaryProvider,
+                mContext.getString(R.string.bluetooth_disconnected));
+    }
+
+    @Test
+    public void updateState_btEnabled_noDevice_shouldShowDisconnectedMessage() {
+        ShadowBluetoothAdapter.getDefaultAdapter().enable();
+        mSummaryProvider.onBluetoothStateChanged(BluetoothAdapter.STATE_TURNING_ON);
+
+        verify(mSummaryLoader).setSummary(mSummaryProvider,
+                mContext.getString(R.string.bluetooth_disconnected));
+    }
+
+    @Test
+    public void updateState_btDisabled_shouldShowDisabledMessage() {
+        ShadowBluetoothAdapter.getDefaultAdapter().enable();
+        mSummaryProvider.onBluetoothStateChanged(BluetoothAdapter.STATE_TURNING_OFF);
+
+        verify(mSummaryLoader).setSummary(mSummaryProvider,
+                mContext.getString(R.string.bluetooth_disabled));
+    }
+
+    @Test
+    public void updateConnectionState_disconnected_shouldShowDisconnectedMessage() {
+        ShadowBluetoothAdapter.getDefaultAdapter().enable();
+        when(mBluetoothManager.getBluetoothAdapter().getConnectionState())
+                .thenReturn(BluetoothAdapter.STATE_DISCONNECTED);
+
+        mSummaryProvider.setListening(true);
+        mSummaryProvider.onConnectionStateChanged(null /* device */,
+                BluetoothAdapter.STATE_DISCONNECTED);
+
+        verify(mSummaryLoader, times(2)).setSummary(mSummaryProvider,
+                mContext.getString(R.string.bluetooth_disconnected));
+    }
+
+
+    @Test
+    public void updateConnectionState_connected_shouldShowConnectedMessage() {
+        ShadowBluetoothAdapter.getDefaultAdapter().enable();
+        when(mBluetoothManager.getBluetoothAdapter().getConnectionState())
+                .thenReturn(BluetoothAdapter.STATE_CONNECTED);
+        final List<CachedBluetoothDevice> devices = new ArrayList<>();
+        devices.add(mock(CachedBluetoothDevice.class));
+        when(devices.get(0).isConnected()).thenReturn(true);
+        when(mBluetoothManager.getCachedDeviceManager().getCachedDevicesCopy())
+                .thenReturn(devices);
+
+        mSummaryProvider.setListening(true);
+        mSummaryProvider.onConnectionStateChanged(null /* device */,
+                BluetoothAdapter.STATE_CONNECTED);
+
+        verify(mSummaryLoader).setSummary(mSummaryProvider,
+                mContext.getString(R.string.bluetooth_connected));
+    }
+
+    @Test
+    public void updateConnectionState_inconsistentState_shouldShowDisconnectedMessage() {
+        ShadowBluetoothAdapter.getDefaultAdapter().enable();
+        when(mBluetoothManager.getBluetoothAdapter().getConnectionState())
+                .thenReturn(BluetoothAdapter.STATE_CONNECTED);
+
+        mSummaryProvider.setListening(true);
+        mSummaryProvider.onConnectionStateChanged(null /* device */,
+                BluetoothAdapter.STATE_CONNECTED);
+
+        verify(mSummaryLoader, times(2)).setSummary(mSummaryProvider,
+                mContext.getString(R.string.bluetooth_disconnected));
+    }
+
+}
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageSummaryTest.java b/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageSummaryTest.java
index ff84741..1cf83f1 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageSummaryTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageSummaryTest.java
@@ -1,10 +1,28 @@
+/*
+ * Copyright (C) 2016 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.fuelgauge;
 
 import android.content.Context;
 import android.content.Intent;
+import android.text.TextUtils;
 import android.view.Menu;
 import android.view.MenuInflater;
 import android.view.MenuItem;
+import com.android.internal.os.BatterySipper;
+import com.android.internal.os.BatteryStatsImpl;
 import com.android.settings.R;
 import com.android.settings.TestConfig;
 import com.android.settings.testutils.FakeFeatureFactory;
@@ -32,6 +50,8 @@
 @RunWith(RobolectricTestRunner.class)
 @Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
 public class PowerUsageSummaryTest {
+    private static final String[] PACKAGE_NAMES = {"com.app1", "com.app2"};
+    private static final int UID = 123;
 
     private static final Intent ADDITIONAL_BATTERY_INFO_INTENT =
             new Intent("com.example.app.ADDITIONAL_BATTERY_INFO");
@@ -46,13 +66,17 @@
     private MenuItem mAdditionalBatteryInfoMenu;
     @Mock
     private MenuInflater mMenuInflater;
+    @Mock
+    private BatterySipper mBatterySipper;
 
     private TestFragment mFragment;
     private FakeFeatureFactory mFeatureFactory;
+    private PowerUsageSummary mPowerUsageSummary;
 
     @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
+
         FakeFeatureFactory.setupForTest(mContext);
         mFeatureFactory = (FakeFeatureFactory) FakeFeatureFactory.getFactory(mContext);
 
@@ -67,6 +91,11 @@
                 .thenReturn(MENU_ADDITIONAL_BATTERY_INFO);
         when(mFeatureFactory.powerUsageFeatureProvider.getAdditionalBatteryInfoIntent())
                 .thenReturn(ADDITIONAL_BATTERY_INFO_INTENT);
+
+        mPowerUsageSummary = new PowerUsageSummary();
+
+        when(mBatterySipper.getPackages()).thenReturn(PACKAGE_NAMES);
+        when(mBatterySipper.getUid()).thenReturn(UID);
     }
 
     @Test
@@ -96,6 +125,33 @@
                 Menu.NONE, R.string.additional_battery_info);
     }
 
+    @Test
+    public void testExtractKeyFromSipper_TypeAPPUidObjectNull_ReturnPackageNames() {
+        mBatterySipper.uidObj = null;
+        mBatterySipper.drainType = BatterySipper.DrainType.APP;
+
+        final String key = mPowerUsageSummary.extractKeyFromSipper(mBatterySipper);
+        assertThat(key).isEqualTo(TextUtils.concat(mBatterySipper.getPackages()).toString());
+    }
+
+    @Test
+    public void testExtractKeyFromSipper_TypeOther_ReturnDrainType() {
+        mBatterySipper.uidObj = null;
+        mBatterySipper.drainType = BatterySipper.DrainType.BLUETOOTH;
+
+        final String key = mPowerUsageSummary.extractKeyFromSipper(mBatterySipper);
+        assertThat(key).isEqualTo(mBatterySipper.drainType.toString());
+    }
+
+    @Test
+    public void testExtractKeyFromSipper_TypeAPPUidObjectNotNull_ReturnUid() {
+        mBatterySipper.uidObj = new BatteryStatsImpl.Uid(new BatteryStatsImpl(), UID);
+        mBatterySipper.drainType = BatterySipper.DrainType.APP;
+
+        final String key = mPowerUsageSummary.extractKeyFromSipper(mBatterySipper);
+        assertThat(key).isEqualTo(Integer.toString(mBatterySipper.getUid()));
+    }
+
     public static class TestFragment extends PowerUsageSummary {
 
         private Context mContext;
diff --git a/tests/robotests/src/com/android/settings/users/UserSettingsTest.java b/tests/robotests/src/com/android/settings/users/UserSettingsTest.java
new file mode 100644
index 0000000..005ac19
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/users/UserSettingsTest.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2016 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 android.content.Context;
+
+import com.android.settings.SettingsRobolectricTestRunner;
+import com.android.settings.TestConfig;
+import com.android.settings.testutils.FakeFeatureFactory;
+
+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.annotation.Config;
+
+import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Mockito.when;
+
+@RunWith(SettingsRobolectricTestRunner.class)
+@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
+public class UserSettingsTest {
+
+    @Mock(answer = Answers.RETURNS_DEEP_STUBS)
+    private Context mContext;
+
+    private FakeFeatureFactory mFeatureFactory;
+    private UserSettings mSetting;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        FakeFeatureFactory.setupForTest(mContext);
+        mFeatureFactory = (FakeFeatureFactory) FakeFeatureFactory.getFactory(mContext);
+        mSetting = new UserSettings();
+    }
+
+    @Test
+    public void testShowEmergencyInfoAndAddUsers_IAEnabled_shouldReturnFalse() {
+        when(mFeatureFactory.dashboardFeatureProvider.isEnabled()).thenReturn(true);
+        assertThat(mSetting.showEmergencyInfoAndAddUsersWhenLock(mContext)).isFalse();
+    }
+
+    @Test
+    public void testShowEmergencyInfoAndAddUsers_IADisabled_shouldReturnTrue() {
+        when(mFeatureFactory.dashboardFeatureProvider.isEnabled()).thenReturn(false);
+        assertThat(mSetting.showEmergencyInfoAndAddUsersWhenLock(mContext)).isTrue();
+    }
+
+}