Merge "Rename wifi/NetworkRequestTimeoutDialogFragment to wifi/NetworkRequestErrorDialogFragment for extending usage."
diff --git a/res/drawable/ic_qrcode_24dp.xml b/res/drawable/ic_qrcode_24dp.xml
new file mode 100644
index 0000000..ff7806f
--- /dev/null
+++ b/res/drawable/ic_qrcode_24dp.xml
@@ -0,0 +1,39 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:fillColor="#FF000000"
+      android:pathData="M7,4v3H4V4H7M9,2H2v7h7V2L9,2z"/>
+  <path
+      android:fillColor="#FF000000"
+      android:pathData="M15,11l-8,0l0,2l8,0l0,-2z"/>
+  <path
+      android:fillColor="#FF000000"
+      android:pathData="M13,2l-2,0l0,11l2,0l0,-11z"/>
+  <path
+      android:fillColor="#FF000000"
+      android:pathData="M22,15l-11,0l0,2l11,0l0,-2z"/>
+  <path
+      android:fillColor="#FF000000"
+      android:pathData="M13,17l-2,0l0,5l2,0l0,-5z"/>
+  <path
+      android:fillColor="#FF000000"
+      android:pathData="M17,13l-2,0l0,9l2,0l0,-9z"/>
+  <path
+      android:fillColor="#FF000000"
+      android:pathData="M22,19l-3,0l0,3l3,0l0,-3z"/>
+  <path
+      android:fillColor="#FF000000"
+      android:pathData="M5,11l-3,0l0,2l3,0l0,-2z"/>
+  <path
+      android:fillColor="#FF000000"
+      android:pathData="M22,11l-5,0l0,2l5,0l0,-2z"/>
+  <path
+      android:fillColor="#FF000000"
+      android:pathData="M20,4v3h-3V4H20M22,2h-7v7h7V2L22,2z"/>
+  <path
+      android:fillColor="#FF000000"
+      android:pathData="M7,17v3H4v-3H7M9,15H2v7h7V15L9,15z"/>
+</vector>
diff --git a/res/drawable/ic_scan_24dp.xml b/res/drawable/ic_scan_24dp.xml
new file mode 100644
index 0000000..bcef8e3
--- /dev/null
+++ b/res/drawable/ic_scan_24dp.xml
@@ -0,0 +1,33 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:fillColor="#FF000000"
+      android:pathData="M9,2l-7,0l0,2l7,0l0,-2z"/>
+  <path
+      android:fillColor="#FF000000"
+      android:pathData="M22,2l-7,0l0,2l7,0l0,-2z"/>
+  <path
+      android:fillColor="#FF000000"
+      android:pathData="M22,11l-20,0l0,2l20,0l0,-2z"/>
+  <path
+      android:fillColor="#FF000000"
+      android:pathData="M22,2l-2,0l0,7l2,0l0,-7z"/>
+  <path
+      android:fillColor="#FF000000"
+      android:pathData="M4,2l-2,0l0,7l2,0l0,-7z"/>
+  <path
+      android:fillColor="#FF000000"
+      android:pathData="M9,20l-7,0l0,2l7,0l0,-2z"/>
+  <path
+      android:fillColor="#FF000000"
+      android:pathData="M22,20l-7,0l0,2l7,0l0,-2z"/>
+  <path
+      android:fillColor="#FF000000"
+      android:pathData="M22,15l-2,0l0,7l2,0l0,-7z"/>
+  <path
+      android:fillColor="#FF000000"
+      android:pathData="M4,15l-2,0l0,7l2,0l0,-7z"/>
+</vector>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index fcaf72a..bdc0081 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -653,6 +653,8 @@
     <string name="done">Done</string>
     <!-- Button label for generic apply action [CHAR LIMIT=20] -->
     <string name="apply">Apply</string>
+    <!-- Button label for generic share action [CHAR LIMIT=20] -->
+    <string name="share">Share</string>
 
     <!-- Title of the Settings activity shown within the application itself. -->
     <string name="settings_label">Settings</string>
@@ -2878,6 +2880,14 @@
     <string name="status_prl_version">PRL version</string>
     <!-- About phone screen, title for MEID for multi-sim devices -->
     <string name="meid_multi_sim">MEID (sim slot %1$d)</string>
+    <!-- The status text when both Wi-Fi scanning and Bluetooth scanning are on. [CHAR LIMIT=120] -->
+    <string name="scanning_status_text_wifi_on_ble_on">Both Wi\u2011Fi and Bluetooth are allowed to determine location</string>
+    <!-- The status text when Wi-Fi scanning is on and Bluetooth scanning are off. [CHAR LIMIT=120] -->
+    <string name="scanning_status_text_wifi_on_ble_off">Only Wi\u2011Fi is allowed to determine location</string>
+    <!-- The status text when Wi-Fi scanning is off and Bluetooth scanning are on. [CHAR LIMIT=120] -->
+    <string name="scanning_status_text_wifi_off_ble_on">Only Bluetooth is allowed to determine location</string>
+    <!-- The status text when both Wi-Fi scanning and Bluetooth scanning are off. [CHAR LIMIT=120] -->
+    <string name="scanning_status_text_wifi_off_ble_off">Neither Wi\u2011Fi nor Bluetooth is allowed to determine location</string>
     <!-- About phone, status item title.  The phone MEID number of the current LTE/CDMA device. [CHAR LIMIT=30] -->
     <string name="status_meid_number">MEID</string>
     <!-- About phone, status item title.  The ICCID of the current LTE device. [CHAR LIMIT=30] -->
@@ -3612,8 +3622,8 @@
     <string name="location_high_battery_use">High battery use</string>
     <!-- [CHAR LIMIT=30] Location settings screen, recent location requests low battery use-->
     <string name="location_low_battery_use">Low battery use</string>
-    <!-- [CHAR LIMIT=30] Wireless background scanning settings screen, screen title -->
-    <string name="location_scanning_screen_title">Scanning</string>
+    <!-- [CHAR LIMIT=60] Wireless background scanning settings screen, screen title -->
+    <string name="location_scanning_screen_title">Wi\u2011Fi and Bluetooth scanning</string>
     <!-- [CHAR LIMIT=130] Preference title for Wi-Fi always scanning -->
     <string name="location_scanning_wifi_always_scanning_title">Wi\u2011Fi scanning</string>
     <!-- Preference description text for Wi-Fi always scanning -->
@@ -3757,6 +3767,8 @@
     <string name="lockpassword_choose_your_pattern_header_for_face">To use face authentication, set pattern</string>
     <!-- Header on first screen of choose password/PIN as backup for face authentication flow. If this string cannot be translated in under 40 characters, please translate "Set face authentication backup" [CHAR LIMIT=40] -->
     <string name="lockpassword_choose_your_pin_header_for_face">To use face authentication, set PIN</string>
+    <!-- Message on Wi-Fi Sharing screen [CHAR LIMIT=NONE] -->
+    <string name="wifi_sharing_message">Your Wi\u2011Fi name and password for \"<xliff:g id="SSID" example="GoogleGuest">%1$s</xliff:g>\" will be shared.</string>
 
     <!-- Message to be used to explain the user that he needs to enter his pattern to continue a
          particular operation. [CHAR LIMIT=70]-->
@@ -8976,7 +8988,7 @@
     <string name="condition_cellular_title">Mobile data is off</string>
 
     <!-- Summary of condition that cellular data is off [CHAR LIMIT=NONE] -->
-    <string name="condition_cellular_summary">Internet is available only via Wi-Fi</string>
+    <string name="condition_cellular_summary">Internet only available via Wi\u2011Fi</string>
 
     <!-- Title of condition that background data is off [CHAR LIMIT=30] -->
     <string name="condition_bg_data_title">Data Saver</string>
@@ -8988,7 +9000,7 @@
     <string name="condition_work_title">Work profile is off</string>
 
     <!-- Summary of condition that work mode is off [CHAR LIMIT=NONE] -->
-    <string name="condition_work_summary">Apps, background sync, and other features related to your work profile are turned off.</string>
+    <string name="condition_work_summary">For apps &amp; notifications</string>
 
     <!-- Action label on device muted card - clicking action will turn on ringtone sound [CHAR LIMIT=50] -->
     <string name="condition_device_muted_action_turn_on_sound">Turn on sound</string>
@@ -9450,6 +9462,11 @@
     <string name="managed_profile_contact_search_title">Contact search</string>
     <!-- [CHAR LIMIT=NONE] The preference summary for enabling cross-profile remote contact search -->
     <string name="managed_profile_contact_search_summary">Allow contact searches by your organization to identify callers and contacts</string>
+    <!-- [CHAR LIMIT=60] The preference title for enabling cross profile calendar sync -->
+    <string name="cross_profile_calendar_title">Cross-profile calendar</string>
+    <!-- [CHAR LIMIT=NONE] The preference summary for enabling cross profile calendar sync -->
+    <string name="cross_profile_calendar_summary">Show work events on personal calendar</string>
+
 
     <!-- Time in hours -->
     <plurals name="hours">
@@ -10239,15 +10256,13 @@
     <!-- Message for Network connection error state Dialog [CHAR LIMIT=NONE] -->
     <string name="network_connection_errorstate_dialog_message">Something came up. The application has cancelled the request to choose a device.</string>
 
-    <!-- Summary for connected devices count in connected device slice. [CHAR LIMIT=NONE] -->
-    <plurals name="show_connected_devices">
+    <!-- Summary for bluetooth devices count in Bluetooth devices slice. [CHAR LIMIT=NONE] -->
+    <plurals name="show_bluetooth_devices">
         <item quantity="one"><xliff:g id="number_device_count">%1$d</xliff:g> device connected</item>
         <item quantity="other"><xliff:g id="number_device_count">%1$d</xliff:g> devices connected</item>
     </plurals>
-    <!-- Title for bluetooth connected devices in connected device slice. [CHAR LIMIT=NONE] -->
-    <string name="bluetooth_connected_devices">Bluetooth Devices</string>
-    <!-- Title for no connected devices in connected device slice. [CHAR LIMIT=NONE] -->
-    <string name="no_connected_devices">No connected devices</string>
+    <!-- Title for no bluetooth devices in Bluetooth devices slice. [CHAR LIMIT=NONE] -->
+    <string name="no_bluetooth_devices">No Bluetooth devices</string>
 
     <!-- Default title for the settings panel [CHAR LIMIT=NONE] -->
     <string name="settings_panel_title">Settings Panel</string>
diff --git a/res/values/styles.xml b/res/values/styles.xml
index 141426e..19ce333 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -461,8 +461,9 @@
     <style name="SearchBarStyle">
         <item name="android:layout_margin">@dimen/search_bar_margin</item>
         <item name="cardCornerRadius">8dp</item>
-        <item name="strokeColor">@color/homepage_card_stroke_color</item>
-        <item name="strokeWidth">1dp</item>
+        <item name="enforceMaterialTheme">true</item>
+        <item name="cardElevation">3dp</item>
+        <item name="shapeAppearance">@null</item>
     </style>
 
     <style name="ConditionCardBorderlessButton"
diff --git a/res/xml/development_settings.xml b/res/xml/development_settings.xml
index a0f019d..be45cd0 100644
--- a/res/xml/development_settings.xml
+++ b/res/xml/development_settings.xml
@@ -424,9 +424,6 @@
             android:summary="%s"
             android:title="@string/simulate_color_space" />
 
-        <Preference android:key="angle_enabled_app"
-            android:title="@string/angle_enabled_app" />
-
         <Preference android:key="updated_gfx_driver_dev_opt_in_app"
             android:summary="@string/updated_gfx_driver_dev_opt_in_app_summary"
             android:title="@string/updated_gfx_driver_dev_opt_in_app" />
diff --git a/res/xml/managed_profile_settings.xml b/res/xml/managed_profile_settings.xml
index ee1e4fa..bd44cc1 100644
--- a/res/xml/managed_profile_settings.xml
+++ b/res/xml/managed_profile_settings.xml
@@ -32,4 +32,11 @@
         settings:useAdditionalSummary="true"
         settings:controller="com.android.settings.accounts.ContactSearchPreferenceController"/>
 
+    <com.android.settingslib.RestrictedSwitchPreference
+        android:key="cross_profile_calendar"
+        android:summary="@string/cross_profile_calendar_summary"
+        android:title="@string/cross_profile_calendar_title"
+        settings:useAdditionalSummary="true"
+        settings:controller="com.android.settings.accounts.CrossProfileCalendarPreferenceController"/>
+
 </PreferenceScreen>
\ No newline at end of file
diff --git a/res/xml/wifi_configure_settings.xml b/res/xml/wifi_configure_settings.xml
index 8ec320a..15ab1aa 100644
--- a/res/xml/wifi_configure_settings.xml
+++ b/res/xml/wifi_configure_settings.xml
@@ -41,7 +41,8 @@
     <SwitchPreference
         android:key="wifi_cellular_data_fallback"
         android:title="@string/wifi_cellular_data_fallback_title"
-        android:summary="@string/wifi_cellular_data_fallback_summary" />
+        android:summary="@string/wifi_cellular_data_fallback_summary"
+        settings:controller="com.android.settings.wifi.CellularFallbackPreferenceController" />
 
     <Preference
         android:key="install_credentials"
diff --git a/src/com/android/settings/CryptKeeper.java b/src/com/android/settings/CryptKeeper.java
index ca54b07..05054b4 100644
--- a/src/com/android/settings/CryptKeeper.java
+++ b/src/com/android/settings/CryptKeeper.java
@@ -772,9 +772,10 @@
         if (imeSwitcher != null && hasMultipleEnabledIMEsOrSubtypes(imm, false)) {
             imeSwitcher.setVisibility(View.VISIBLE);
             imeSwitcher.setOnClickListener(new OnClickListener() {
-                    @Override
+                @Override
                 public void onClick(View v) {
-                    imm.showInputMethodPicker(false /* showAuxiliarySubtypes */);
+                    imm.showInputMethodPickerFromSystem(false /* showAuxiliarySubtypes */,
+                            v.getDisplay().getDisplayId());
                 }
             });
         }
diff --git a/src/com/android/settings/accessibility/AccessibilitySettings.java b/src/com/android/settings/accessibility/AccessibilitySettings.java
index d6590fa..76be66d 100644
--- a/src/com/android/settings/accessibility/AccessibilitySettings.java
+++ b/src/com/android/settings/accessibility/AccessibilitySettings.java
@@ -667,6 +667,8 @@
                     mToggleInversionPreference.getOrder() + 1);
             mToggleDisableAnimationsPreference.setOrder(
                     mToggleLargePointerIconPreference.getOrder() + 1);
+            findPreference(ACCESSIBILITY_CONTENT_TIMEOUT_PREFERENCE).setOrder(
+                    mToggleDisableAnimationsPreference.getOrder() + 1);
             mToggleInversionPreference.setSummary(R.string.summary_empty);
             displayCategory.addPreference(mToggleInversionPreference);
             displayCategory.addPreference(mDisplayDaltonizerPreferenceScreen);
diff --git a/src/com/android/settings/accounts/CrossProfileCalendarPreferenceController.java b/src/com/android/settings/accounts/CrossProfileCalendarPreferenceController.java
new file mode 100644
index 0000000..38c95dc
--- /dev/null
+++ b/src/com/android/settings/accounts/CrossProfileCalendarPreferenceController.java
@@ -0,0 +1,79 @@
+/*
+ * 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.accounts;
+
+import static android.provider.Settings.Secure.CROSS_PROFILE_CALENDAR_ENABLED;
+
+import android.content.Context;
+import android.os.UserHandle;
+import android.provider.Settings;
+
+import com.android.settings.core.BasePreferenceController;
+import com.android.settings.core.TogglePreferenceController;
+import com.android.settings.slices.SliceData;
+import com.android.settingslib.RestrictedLockUtils;
+import com.android.settingslib.RestrictedLockUtilsInternal;
+import com.android.settingslib.RestrictedSwitchPreference;
+
+import androidx.preference.Preference;
+
+public class CrossProfileCalendarPreferenceController extends TogglePreferenceController {
+
+    private UserHandle mManagedUser;
+
+    public CrossProfileCalendarPreferenceController(Context context, String key) {
+        super(context, key);
+    }
+
+    public void setManagedUser(UserHandle managedUser) {
+        mManagedUser = managedUser;
+    }
+
+    @Override
+    public int getAvailabilityStatus() {
+        return (mManagedUser != null) ? AVAILABLE : DISABLED_FOR_USER;
+    }
+
+    @Override
+    public void updateState(Preference preference) {
+        super.updateState(preference);
+        if (preference instanceof RestrictedSwitchPreference && mManagedUser != null) {
+            final RestrictedSwitchPreference pref = (RestrictedSwitchPreference) preference;
+            final RestrictedLockUtils.EnforcedAdmin enforcedAdmin =
+                    RestrictedLockUtilsInternal.getCrossProfileCalendarEnforcingAdmin(
+                            mContext, mManagedUser.getIdentifier());
+            pref.setDisabledByAdmin(enforcedAdmin);
+        }
+    }
+
+    @Override
+    public boolean isChecked() {
+        if (mManagedUser == null) {
+            return false;
+        }
+        return Settings.Secure.getIntForUser(mContext.getContentResolver(),
+                CROSS_PROFILE_CALENDAR_ENABLED, /* default= */ 0,
+                mManagedUser.getIdentifier()) == 1;
+    }
+
+    @Override
+    public boolean setChecked(boolean isChecked) {
+        if (mManagedUser == null) {
+            return false;
+        }
+        final int value = isChecked ? 1 : 0;
+        return Settings.Secure.putIntForUser(mContext.getContentResolver(),
+                CROSS_PROFILE_CALENDAR_ENABLED, value, mManagedUser.getIdentifier());
+    }
+}
\ No newline at end of file
diff --git a/src/com/android/settings/accounts/ManagedProfileSettings.java b/src/com/android/settings/accounts/ManagedProfileSettings.java
index 07e5845..dccd7f6 100644
--- a/src/com/android/settings/accounts/ManagedProfileSettings.java
+++ b/src/com/android/settings/accounts/ManagedProfileSettings.java
@@ -23,17 +23,25 @@
 import android.os.Bundle;
 import android.os.UserHandle;
 import android.os.UserManager;
+import android.provider.SearchIndexableResource;
 import android.util.Log;
 
 import com.android.internal.logging.nano.MetricsProto;
 import com.android.settings.R;
 import com.android.settings.Utils;
 import com.android.settings.dashboard.DashboardFragment;
+import com.android.settings.search.BaseSearchIndexProvider;
+import com.android.settings.search.Indexable;
+import com.android.settingslib.search.SearchIndexable;
+
+import java.util.ArrayList;
+import java.util.List;
 
 /**
  * Setting page for managed profile.
  * FIXME: It currently assumes there is only one managed profile.
  */
+@SearchIndexable
 public class ManagedProfileSettings extends DashboardFragment {
 
     private UserManager mUserManager;
@@ -63,6 +71,7 @@
         }
         use(WorkModePreferenceController.class).setManagedUser(mManagedUser);
         use(ContactSearchPreferenceController.class).setManagedUser(mManagedUser);
+        use(CrossProfileCalendarPreferenceController.class).setManagedUser(mManagedUser);
     }
 
     @Override
@@ -99,6 +108,23 @@
         return MetricsProto.MetricsEvent.ACCOUNTS_WORK_PROFILE_SETTINGS;
     }
 
+    public static final Indexable.SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
+            new BaseSearchIndexProvider() {
+                @Override
+                public List<SearchIndexableResource> getXmlResourcesToIndex(Context context,
+                        boolean enabled) {
+                    final ArrayList<SearchIndexableResource> result = new ArrayList<>();
+                    final SearchIndexableResource sir = new SearchIndexableResource(context);
+                    sir.xmlResId = R.xml.managed_profile_settings;
+                    result.add(sir);
+                    return result;
+                }
+                @Override
+                protected boolean isPageSearchEnabled(Context context) {
+                    return false;
+                }
+            };
+
     private class ManagedProfileBroadcastReceiver extends BroadcastReceiver {
 
         @Override
diff --git a/src/com/android/settings/bluetooth/BluetoothPermissionActivity.java b/src/com/android/settings/bluetooth/BluetoothPermissionActivity.java
index de8902a..19339cd 100644
--- a/src/com/android/settings/bluetooth/BluetoothPermissionActivity.java
+++ b/src/com/android/settings/bluetooth/BluetoothPermissionActivity.java
@@ -199,20 +199,7 @@
 
     private void onNegative() {
         if (DEBUG) Log.d(TAG, "onNegative");
-
-        boolean always = true;
-        if (mRequestType == BluetoothDevice.REQUEST_TYPE_MESSAGE_ACCESS) {
-            LocalBluetoothManager bluetoothManager = Utils.getLocalBtManager(this);
-            CachedBluetoothDeviceManager cachedDeviceManager =
-                    bluetoothManager.getCachedDeviceManager();
-            CachedBluetoothDevice cachedDevice = cachedDeviceManager.findDevice(mDevice);
-            if (cachedDevice == null) {
-                cachedDevice = cachedDeviceManager.addDevice(mDevice);
-            }
-            always = cachedDevice.checkAndIncreaseMessageRejectionCount();
-        }
-
-        sendReplyIntentToReceiver(false, always);
+        sendReplyIntentToReceiver(false, true);
     }
 
     private void sendReplyIntentToReceiver(final boolean allowed, final boolean always) {
diff --git a/src/com/android/settings/core/FeatureFlags.java b/src/com/android/settings/core/FeatureFlags.java
index daa1e7b..b350778 100644
--- a/src/com/android/settings/core/FeatureFlags.java
+++ b/src/com/android/settings/core/FeatureFlags.java
@@ -26,4 +26,5 @@
     public static final String MOBILE_NETWORK_V2 = "settings_mobile_network_v2";
     public static final String WIFI_MAC_RANDOMIZATION = "settings_wifi_mac_randomization";
     public static final String NETWORK_INTERNET_V2 = "settings_network_and_internet_v2";
+    public static final String WIFI_SHARING = "settings_wifi_sharing";
 }
diff --git a/src/com/android/settings/datausage/ChartDataUsagePreference.java b/src/com/android/settings/datausage/ChartDataUsagePreference.java
index 1c8eb52..17f23c4 100644
--- a/src/com/android/settings/datausage/ChartDataUsagePreference.java
+++ b/src/com/android/settings/datausage/ChartDataUsagePreference.java
@@ -95,9 +95,13 @@
         final SparseIntArray points = new SparseIntArray();
         points.put(0, 0);
 
+        final long now = System.currentTimeMillis();
         long totalData = 0;
         for (NetworkCycleData data : usageSummary) {
             final long startTime = data.getStartTime();
+            if (startTime > now) {
+                break;
+            }
             final long endTime = data.getEndTime();
 
             // increment by current bucket total
diff --git a/src/com/android/settings/development/AngleEnabledAppPreferenceController.java b/src/com/android/settings/development/AngleEnabledAppPreferenceController.java
deleted file mode 100644
index 3a7f6bf..0000000
--- a/src/com/android/settings/development/AngleEnabledAppPreferenceController.java
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
- * 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.development;
-
-import static com.android.settings.development.DevelopmentOptionsActivityRequestCodes
-        .REQUEST_CODE_ANGLE_ENABLED_APP;
-
-import android.app.Activity;
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageManager;
-import android.provider.Settings;
-import androidx.annotation.VisibleForTesting;
-import androidx.preference.Preference;
-
-import com.android.settings.R;
-import com.android.settings.core.PreferenceControllerMixin;
-import com.android.settingslib.development.DeveloperOptionsPreferenceController;
-
-public class AngleEnabledAppPreferenceController extends DeveloperOptionsPreferenceController
-        implements PreferenceControllerMixin, OnActivityResultListener {
-
-    private static final String ANGLE_ENABLED_APP_KEY = "angle_enabled_app";
-
-    private final DevelopmentSettingsDashboardFragment mFragment;
-    private final PackageManager mPackageManager;
-
-    public AngleEnabledAppPreferenceController(Context context,
-            DevelopmentSettingsDashboardFragment fragment) {
-        super(context);
-        mFragment = fragment;
-        mPackageManager = mContext.getPackageManager();
-    }
-
-    @Override
-    public String getPreferenceKey() {
-        return ANGLE_ENABLED_APP_KEY;
-    }
-
-    @Override
-    public boolean handlePreferenceTreeClick(Preference preference) {
-        if (ANGLE_ENABLED_APP_KEY.equals(preference.getKey())) {
-            // pass it on to settings
-            final Intent intent = getActivityStartIntent();
-            mFragment.startActivityForResult(intent, REQUEST_CODE_ANGLE_ENABLED_APP);
-            return true;
-        }
-        return false;
-    }
-
-    @Override
-    public void updateState(Preference preference) {
-        updatePreferenceSummary();
-    }
-
-    @Override
-    public boolean onActivityResult(int requestCode, int resultCode, Intent data) {
-        if (requestCode != REQUEST_CODE_ANGLE_ENABLED_APP || resultCode != Activity.RESULT_OK) {
-            return false;
-        }
-        Settings.Global.putString(mContext.getContentResolver(), Settings.Global.ANGLE_ENABLED_APP,
-                data.getAction());
-        updatePreferenceSummary();
-        return true;
-    }
-
-    @Override
-    protected void onDeveloperOptionsSwitchDisabled() {
-        super.onDeveloperOptionsSwitchDisabled();
-        mPreference.setSummary(mContext.getResources().getString(
-                R.string.angle_enabled_app_not_set));
-    }
-
-    @VisibleForTesting
-    Intent getActivityStartIntent() {
-        Intent intent = new Intent(mContext, AppPicker.class);
-        intent.putExtra(AppPicker.EXTRA_NON_SYSTEM, true /* value */);
-        return intent;
-    }
-
-    private void updatePreferenceSummary() {
-        final String angleEnabledApp = Settings.Global.getString(
-                mContext.getContentResolver(), Settings.Global.ANGLE_ENABLED_APP);
-        if (angleEnabledApp != null && angleEnabledApp.length() > 0) {
-            mPreference.setSummary(mContext.getResources().getString(
-                    R.string.angle_enabled_app_set,
-                    getAppLabel(angleEnabledApp)));
-        } else {
-            mPreference.setSummary(mContext.getResources().getString(
-                    R.string.angle_enabled_app_not_set));
-        }
-    }
-
-    private String getAppLabel(String angleEnabledApp) {
-        try {
-            final ApplicationInfo ai = mPackageManager.getApplicationInfo(angleEnabledApp,
-                    PackageManager.GET_DISABLED_COMPONENTS);
-            final CharSequence lab = mPackageManager.getApplicationLabel(ai);
-            return lab != null ? lab.toString() : angleEnabledApp;
-        } catch (PackageManager.NameNotFoundException e) {
-            return angleEnabledApp;
-        }
-    }
-}
diff --git a/src/com/android/settings/development/BluetoothA2dpHwOffloadPreferenceController.java b/src/com/android/settings/development/BluetoothA2dpHwOffloadPreferenceController.java
index 0fcec05..95e663b 100644
--- a/src/com/android/settings/development/BluetoothA2dpHwOffloadPreferenceController.java
+++ b/src/com/android/settings/development/BluetoothA2dpHwOffloadPreferenceController.java
@@ -66,6 +66,25 @@
         }
     }
 
+    @Override
+    protected void onDeveloperOptionsSwitchDisabled() {
+        super.onDeveloperOptionsSwitchDisabled();
+        final boolean offloadSupported =
+                SystemProperties.getBoolean(A2DP_OFFLOAD_SUPPORTED_PROPERTY, false);
+        if (offloadSupported) {
+            ((SwitchPreference) mPreference).setChecked(false);
+            SystemProperties.set(A2DP_OFFLOAD_DISABLED_PROPERTY, "false");
+        }
+    }
+
+    public boolean isDefaultValue() {
+        final boolean offloadSupported =
+                SystemProperties.getBoolean(A2DP_OFFLOAD_SUPPORTED_PROPERTY, false);
+        final boolean offloadDisabled =
+                    SystemProperties.getBoolean(A2DP_OFFLOAD_DISABLED_PROPERTY, false);
+        return offloadSupported ? !offloadDisabled : true;
+    }
+
     public void onA2dpHwDialogConfirmed() {
         final boolean offloadDisabled =
                 SystemProperties.getBoolean(A2DP_OFFLOAD_DISABLED_PROPERTY, false);
diff --git a/src/com/android/settings/development/DevelopmentOptionsActivityRequestCodes.java b/src/com/android/settings/development/DevelopmentOptionsActivityRequestCodes.java
index 3532a15..e65d2ad 100644
--- a/src/com/android/settings/development/DevelopmentOptionsActivityRequestCodes.java
+++ b/src/com/android/settings/development/DevelopmentOptionsActivityRequestCodes.java
@@ -26,7 +26,11 @@
 
     int REQUEST_MOCK_LOCATION_APP = 2;
 
-    int REQUEST_CODE_ANGLE_ENABLED_APP = 3;
+    int REQUEST_CODE_ANGLE_ALL_USE_ANGLE = 3;
 
-    int REQUEST_CODE_UPDATED_GFX_DRIVER_DEV_OPT_IN_APP = 4;
+    int REQUEST_CODE_ANGLE_DRIVER_PKGS = 4;
+
+    int REQUEST_CODE_ANGLE_DRIVER_VALUES = 5;
+
+    int REQUEST_CODE_UPDATED_GFX_DRIVER_DEV_OPT_IN_APP = 6;
 }
diff --git a/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java b/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java
index 762686a..aa9918c 100644
--- a/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java
+++ b/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java
@@ -221,7 +221,16 @@
             if (isChecked) {
                 EnableDevelopmentSettingWarningDialog.show(this /* host */);
             } else {
-                disableDeveloperOptions();
+                final BluetoothA2dpHwOffloadPreferenceController controller =
+                        getDevelopmentOptionsController(
+                                BluetoothA2dpHwOffloadPreferenceController.class);
+                // If A2DP hardware offload isn't default value, we must reboot after disable
+                // developer options. Show a dialog for the user to confirm.
+                if (controller == null || controller.isDefaultValue()) {
+                    disableDeveloperOptions();
+                } else {
+                    DisableDevSettingsDialogFragment.show(this /* host */);
+                }
             }
         }
     }
@@ -380,6 +389,15 @@
         mSwitchBar.setChecked(false);
     }
 
+    void onDisableDevelopmentOptionsConfirmed() {
+        disableDeveloperOptions();
+    }
+
+    void onDisableDevelopmentOptionsRejected() {
+        // Reset the toggle
+        mSwitchBar.setChecked(true);
+    }
+
     private static List<AbstractPreferenceController> buildPreferenceControllers(Context context,
             Activity activity, Lifecycle lifecycle, DevelopmentSettingsDashboardFragment fragment,
             BluetoothA2dpConfigStore bluetoothA2dpConfigStore) {
@@ -405,7 +423,6 @@
         controllers.add(new SelectDebugAppPreferenceController(context, fragment));
         controllers.add(new WaitForDebuggerPreferenceController(context));
         controllers.add(new EnableGpuDebugLayersPreferenceController(context));
-        controllers.add(new AngleEnabledAppPreferenceController(context, fragment));
         controllers.add(new UpdatedGfxDriverDevOptInPreferenceController(context, fragment));
         controllers.add(new VerifyAppsOverUsbPreferenceController(context));
         controllers.add(new LogdSizePreferenceController(context));
diff --git a/src/com/android/settings/development/DisableDevSettingsDialogFragment.java b/src/com/android/settings/development/DisableDevSettingsDialogFragment.java
new file mode 100644
index 0000000..9b3ba58
--- /dev/null
+++ b/src/com/android/settings/development/DisableDevSettingsDialogFragment.java
@@ -0,0 +1,88 @@
+/*
+ * 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.development;
+
+import android.app.Dialog;
+import android.content.DialogInterface;
+import android.os.Bundle;
+import android.os.PowerManager;
+import android.util.Log;
+import androidx.annotation.VisibleForTesting;
+import androidx.fragment.app.Fragment;
+
+import androidx.appcompat.app.AlertDialog;
+import androidx.fragment.app.FragmentManager;
+
+import com.android.internal.logging.nano.MetricsProto;
+import com.android.settings.R;
+import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
+
+public class DisableDevSettingsDialogFragment extends InstrumentedDialogFragment
+        implements DialogInterface.OnClickListener {
+
+    public static final String TAG = "DisableDevSettingDlg";
+
+    @VisibleForTesting
+    static DisableDevSettingsDialogFragment newInstance() {
+        final DisableDevSettingsDialogFragment dialog = new DisableDevSettingsDialogFragment();
+        return dialog;
+    }
+
+    public static void show(DevelopmentSettingsDashboardFragment host) {
+        final DisableDevSettingsDialogFragment dialog = new DisableDevSettingsDialogFragment();
+        dialog.setTargetFragment(host, 0 /* requestCode */);
+        final FragmentManager manager = host.getActivity().getSupportFragmentManager();
+        dialog.show(manager, TAG);
+    }
+
+    @Override
+    public int getMetricsCategory() {
+        return MetricsProto.MetricsEvent.DIALOG_DISABLE_DEVELOPMENT_OPTIONS;
+    }
+
+    @Override
+    public Dialog onCreateDialog(Bundle savedInstanceState) {
+        // Reuse the same text of disable_a2dp_hw_offload_dialog.
+        // The text is generic enough to be used for turning off Dev options.
+        return new AlertDialog.Builder(getActivity())
+                .setMessage(R.string.bluetooth_disable_a2dp_hw_offload_dialog_message)
+                .setTitle(R.string.bluetooth_disable_a2dp_hw_offload_dialog_title)
+                .setPositiveButton(
+                        R.string.bluetooth_disable_a2dp_hw_offload_dialog_confirm, this)
+                .setNegativeButton(
+                        R.string.bluetooth_disable_a2dp_hw_offload_dialog_cancel, this)
+                .create();
+    }
+
+    @Override
+    public void onClick(DialogInterface dialog, int which) {
+        Fragment fragment = getTargetFragment();
+        if (!(fragment instanceof DevelopmentSettingsDashboardFragment)){
+            Log.e(TAG, "getTargetFragment return unexpected type");
+        }
+
+        final DevelopmentSettingsDashboardFragment host =
+                (DevelopmentSettingsDashboardFragment) fragment;
+        if (which == DialogInterface.BUTTON_POSITIVE) {
+            host.onDisableDevelopmentOptionsConfirmed();
+            PowerManager pm = getContext().getSystemService(PowerManager.class);
+            pm.reboot(null);
+        } else {
+            host.onDisableDevelopmentOptionsRejected();
+        }
+    }
+}
diff --git a/src/com/android/settings/homepage/contextualcards/ContextualCardFeatureProviderImpl.java b/src/com/android/settings/homepage/contextualcards/ContextualCardFeatureProviderImpl.java
index e437e2b..32a86e8 100644
--- a/src/com/android/settings/homepage/contextualcards/ContextualCardFeatureProviderImpl.java
+++ b/src/com/android/settings/homepage/contextualcards/ContextualCardFeatureProviderImpl.java
@@ -16,8 +16,10 @@
 
 package com.android.settings.homepage.contextualcards;
 
+import android.annotation.NonNull;
 import android.content.Context;
 import android.content.Intent;
+import android.os.UserHandle;
 import android.text.TextUtils;
 import android.util.Log;
 
@@ -25,6 +27,7 @@
 import androidx.slice.widget.EventInfo;
 
 import com.android.settings.R;
+import com.android.settings.intelligence.ContextualCardProto.ContextualCardList;
 
 import java.util.List;
 
@@ -38,10 +41,6 @@
     // Contextual card shows, log card name and rank
     private static final int CONTEXTUAL_CARD_SHOW = 39;
 
-    // Contextual card is eligible to be shown, but doesn't rank high
-    // enough, log card name and score
-    private static final int CONTEXTUAL_CARD_NOT_SHOW = 40;
-
     // Contextual card is dismissed, log card name
     private static final int CONTEXTUAL_CARD_DISMISS = 41;
 
@@ -67,6 +66,11 @@
     // log type
     private static final String EXTRA_CONTEXTUALCARD_ACTION_TYPE = "type";
 
+    // displayed contextual cards
+    private static final String EXTRA_CONTEXTUALCARD_VISIBLE = "visible";
+
+    // hidden contextual cards
+    private static final String EXTRA_CONTEXTUALCARD_HIDDEN = "hidden";
 
     // Contextual card tap target
     private static final int TARGET_DEFAULT = 0;
@@ -82,6 +86,10 @@
 
     @Override
     public void logHomepageDisplay(Context context, Long latency) {
+        final Intent intent = new Intent();
+        intent.putExtra(EXTRA_CONTEXTUALCARD_ACTION_TYPE, CONTEXTUAL_HOME_SHOW);
+        intent.putExtra(EXTRA_LATENCY, latency);
+        sendBroadcast(context, intent);
     }
 
     @Override
@@ -94,8 +102,13 @@
     }
 
     @Override
-    public void logContextualCardDisplay(Context context, List<ContextualCard> showCards,
+    public void logContextualCardDisplay(Context context, List<ContextualCard> visibleCards,
             List<ContextualCard> hiddenCards) {
+        final Intent intent = new Intent();
+        intent.putExtra(EXTRA_CONTEXTUALCARD_ACTION_TYPE, CONTEXTUAL_CARD_SHOW);
+        intent.putExtra(EXTRA_CONTEXTUALCARD_VISIBLE, serialize(visibleCards));
+        intent.putExtra(EXTRA_CONTEXTUALCARD_HIDDEN, serialize(hiddenCards));
+        sendBroadcast(context, intent);
     }
 
     @Override
@@ -116,7 +129,7 @@
         final String action = context.getString(R.string.config_settingsintelligence_log_action);
         if (!TextUtils.isEmpty(action)) {
             intent.setAction(action);
-            context.sendBroadcast(intent);
+            context.sendBroadcastAsUser(intent, UserHandle.ALL);
         }
     }
 
@@ -133,4 +146,16 @@
                 return TARGET_DEFAULT;
         }
     }
+
+    @VisibleForTesting
+    @NonNull
+    byte[] serialize(List<ContextualCard> cards) {
+        final ContextualCardList.Builder builder = ContextualCardList.newBuilder();
+        cards.stream().forEach(card -> builder.addCard(
+                com.android.settings.intelligence.ContextualCardProto.ContextualCard.newBuilder()
+                        .setSliceUri(card.getSliceUri().toString())
+                        .setCardName(card.getName())
+                        .build()));
+        return builder.build().toByteArray();
+    }
 }
diff --git a/src/com/android/settings/homepage/contextualcards/ContextualCardLoader.java b/src/com/android/settings/homepage/contextualcards/ContextualCardLoader.java
index 3ef4653..e631d22 100644
--- a/src/com/android/settings/homepage/contextualcards/ContextualCardLoader.java
+++ b/src/com/android/settings/homepage/contextualcards/ContextualCardLoader.java
@@ -20,6 +20,9 @@
 
 import static androidx.slice.widget.SliceLiveData.SUPPORTED_SPECS;
 
+import static com.android.settings.slices.CustomSliceRegistry.BLUETOOTH_DEVICES_SLICE_URI;
+import static com.android.settings.slices.CustomSliceRegistry.WIFI_SLICE_URI;
+
 import android.content.ContentProviderClient;
 import android.content.ContentResolver;
 import android.content.Context;
@@ -34,7 +37,7 @@
 import androidx.annotation.VisibleForTesting;
 import androidx.slice.Slice;
 
-import com.android.settings.slices.CustomSliceRegistry;
+import com.android.settings.overlay.FeatureFactory;
 import com.android.settingslib.utils.AsyncLoaderCompat;
 
 import java.util.ArrayList;
@@ -103,27 +106,50 @@
         return getFinalDisplayableCards(result);
     }
 
+    // Get final displayed cards and log what cards will be displayed/hidden
     @VisibleForTesting
     List<ContextualCard> getFinalDisplayableCards(List<ContextualCard> candidates) {
-        List<ContextualCard> eligibleCards = filterEligibleCards(candidates);
-        eligibleCards = eligibleCards.stream().limit(DEFAULT_CARD_COUNT).collect(
-                Collectors.toList());
+        final List<ContextualCard> eligibleCards = filterEligibleCards(candidates);
+        final List<ContextualCard> visibleCards = new ArrayList<>();
+        final List<ContextualCard> hiddenCards = new ArrayList<>();
 
-        if (eligibleCards.size() <= 2 || getNumberOfLargeCard(eligibleCards) == 0) {
-            return eligibleCards;
+        final int size = eligibleCards.size();
+        for (int i = 0; i < size; i++) {
+            if (i < DEFAULT_CARD_COUNT) {
+                visibleCards.add(eligibleCards.get(i));
+            } else {
+                hiddenCards.add(eligibleCards.get(i));
+            }
         }
 
-        if (eligibleCards.size() == DEFAULT_CARD_COUNT) {
-            eligibleCards.remove(eligibleCards.size() - 1);
+        try {
+            // The maximum cards are four small cards OR
+            // one large card with two small cards OR
+            // two large cards
+            if (visibleCards.size() <= 2 || getNumberOfLargeCard(visibleCards) == 0) {
+                // four small cards
+                return visibleCards;
+            }
+
+            if (visibleCards.size() == DEFAULT_CARD_COUNT) {
+                hiddenCards.add(visibleCards.remove(visibleCards.size() - 1));
+            }
+
+            if (getNumberOfLargeCard(visibleCards) == 1) {
+                // One large card with two small cards
+                return visibleCards;
+            }
+
+            hiddenCards.add(visibleCards.remove(visibleCards.size() - 1));
+
+            // Two large cards
+            return visibleCards;
+        } finally {
+            final ContextualCardFeatureProvider contextualCardFeatureProvider =
+                    FeatureFactory.getFactory(mContext).getContextualCardFeatureProvider();
+            contextualCardFeatureProvider.logContextualCardDisplay(mContext, visibleCards,
+                    hiddenCards);
         }
-
-        if (getNumberOfLargeCard(eligibleCards) == 1) {
-            return eligibleCards;
-        }
-
-        eligibleCards.remove(eligibleCards.size() - 1);
-
-        return eligibleCards;
     }
 
     @VisibleForTesting
@@ -169,8 +195,8 @@
 
     private int getNumberOfLargeCard(List<ContextualCard> cards) {
         return (int) cards.stream()
-                .filter(card -> card.getSliceUri().equals(CustomSliceRegistry.WIFI_SLICE_URI)
-                        || card.getSliceUri().equals(CustomSliceRegistry.CONNECTED_DEVICE_SLICE_URI))
+                .filter(card -> card.getSliceUri().equals(WIFI_SLICE_URI)
+                        || card.getSliceUri().equals(BLUETOOTH_DEVICES_SLICE_URI))
                 .count();
     }
 
diff --git a/src/com/android/settings/homepage/contextualcards/ContextualCardManager.java b/src/com/android/settings/homepage/contextualcards/ContextualCardManager.java
index 5f397d7..28ad0d3 100644
--- a/src/com/android/settings/homepage/contextualcards/ContextualCardManager.java
+++ b/src/com/android/settings/homepage/contextualcards/ContextualCardManager.java
@@ -16,8 +16,7 @@
 
 package com.android.settings.homepage.contextualcards;
 
-import static com.android.settings.homepage.contextualcards.ContextualCardLoader
-        .CARD_CONTENT_LOADER_ID;
+import static com.android.settings.homepage.contextualcards.ContextualCardLoader.CARD_CONTENT_LOADER_ID;
 
 import static java.util.stream.Collectors.groupingBy;
 
@@ -33,6 +32,7 @@
 import androidx.loader.app.LoaderManager;
 import androidx.loader.content.Loader;
 
+import com.android.settings.overlay.FeatureFactory;
 import com.android.settingslib.core.lifecycle.Lifecycle;
 import com.android.settingslib.core.lifecycle.LifecycleObserver;
 
@@ -72,6 +72,7 @@
     private final List<LifecycleObserver> mLifecycleObservers;
 
     private ContextualCardUpdateListener mListener;
+    private long mStartTime;
 
     public ContextualCardManager(Context context, Lifecycle lifecycle) {
         mContext = context;
@@ -86,6 +87,7 @@
     }
 
     void loadContextualCards(ContextualCardsFragment fragment) {
+        mStartTime = System.currentTimeMillis();
         final CardContentLoaderCallbacks cardContentLoaderCallbacks =
                 new CardContentLoaderCallbacks(mContext);
         cardContentLoaderCallbacks.setListener(this);
@@ -168,6 +170,10 @@
     @Override
     public void onFinishCardLoading(List<ContextualCard> cards) {
         onContextualCardUpdated(cards.stream().collect(groupingBy(ContextualCard::getCardType)));
+        final long elapsedTime = System.currentTimeMillis() - mStartTime;
+        final ContextualCardFeatureProvider contextualCardFeatureProvider =
+                FeatureFactory.getFactory(mContext).getContextualCardFeatureProvider();
+        contextualCardFeatureProvider.logHomepageDisplay(mContext, elapsedTime);
     }
 
     public ControllerRendererPool getControllerRendererPool() {
diff --git a/src/com/android/settings/homepage/contextualcards/SettingsContextualCardProvider.java b/src/com/android/settings/homepage/contextualcards/SettingsContextualCardProvider.java
index 376bb83..d5500fb 100644
--- a/src/com/android/settings/homepage/contextualcards/SettingsContextualCardProvider.java
+++ b/src/com/android/settings/homepage/contextualcards/SettingsContextualCardProvider.java
@@ -40,8 +40,8 @@
                         .build();
         final ContextualCard connectedDeviceCard =
                 ContextualCard.newBuilder()
-                        .setSliceUri(CustomSliceRegistry.CONNECTED_DEVICE_SLICE_URI.toString())
-                        .setCardName(CustomSliceRegistry.CONNECTED_DEVICE_SLICE_URI.toString())
+                        .setSliceUri(CustomSliceRegistry.BLUETOOTH_DEVICES_SLICE_URI.toString())
+                        .setCardName(CustomSliceRegistry.BLUETOOTH_DEVICES_SLICE_URI.toString())
                         .setCardCategory(ContextualCard.Category.IMPORTANT)
                         .build();
         final ContextualCard lowStorageCard =
diff --git a/src/com/android/settings/homepage/contextualcards/slices/ConnectedDeviceSlice.java b/src/com/android/settings/homepage/contextualcards/slices/BluetoothDevicesSlice.java
similarity index 69%
rename from src/com/android/settings/homepage/contextualcards/slices/ConnectedDeviceSlice.java
rename to src/com/android/settings/homepage/contextualcards/slices/BluetoothDevicesSlice.java
index 4ee8ff5..ad8d4a6 100644
--- a/src/com/android/settings/homepage/contextualcards/slices/ConnectedDeviceSlice.java
+++ b/src/com/android/settings/homepage/contextualcards/slices/BluetoothDevicesSlice.java
@@ -41,6 +41,7 @@
 import com.android.settings.SubSettings;
 import com.android.settings.Utils;
 import com.android.settings.bluetooth.BluetoothDeviceDetailsFragment;
+import com.android.settings.bluetooth.BluetoothPairingDetail;
 import com.android.settings.connecteddevice.ConnectedDeviceDashboardFragment;
 import com.android.settings.core.SubSettingLauncher;
 import com.android.settings.slices.CustomSliceRegistry;
@@ -56,28 +57,27 @@
 import java.util.List;
 import java.util.stream.Collectors;
 
-/**
- * TODO(b/114807655): Contextual Home Page - Connected Device
- *
- * Show connected device info if one is currently connected. UI for connected device should
- * match Connected Devices > Currently Connected Devices
- *
- * TODO This class will be refactor for Bluetooth connected devices only.
- */
-public class ConnectedDeviceSlice implements CustomSliceable {
+public class BluetoothDevicesSlice implements CustomSliceable {
 
     /**
-     * To sort the Bluetooth devices by {@link CachedBluetoothDevice}.
-     * Refer compareTo method from {@link com.android.settings.bluetooth.BluetoothDevicePreference}.
+     * TODO(b/114807655): Contextual Home Page - Connected Device
+     * Re-design sorting for new rule:
+     * Sorting rule: Audio Streaming > Last connected > Recently connected.
      */
     private static final Comparator<CachedBluetoothDevice> COMPARATOR
             = Comparator.naturalOrder();
 
-    private static final String TAG = "ConnectedDeviceSlice";
+    /**
+     * Add the "Pair new device" in the end of slice, when the number of Bluetooth devices is less
+     * than {@link #DEFAULT_EXPANDED_ROW_COUNT}.
+     */
+    private static final int DEFAULT_EXPANDED_ROW_COUNT = 3;
+
+    private static final String TAG = "BluetoothDevicesSlice";
 
     private final Context mContext;
 
-    public ConnectedDeviceSlice(Context context) {
+    public BluetoothDevicesSlice(Context context) {
         mContext = context;
     }
 
@@ -94,47 +94,53 @@
 
     @Override
     public Uri getUri() {
-        return CustomSliceRegistry.CONNECTED_DEVICE_SLICE_URI;
+        return CustomSliceRegistry.BLUETOOTH_DEVICES_SLICE_URI;
     }
 
     @Override
     public Slice getSlice() {
         final IconCompat icon = IconCompat.createWithResource(mContext,
-                R.drawable.ic_homepage_connected_device);
-        final CharSequence title = mContext.getText(R.string.bluetooth_connected_devices);
-        final CharSequence titleNoConnectedDevices = mContext.getText(
-                R.string.no_connected_devices);
+                R.drawable.ic_settings_bluetooth);
+        final CharSequence title = mContext.getText(R.string.bluetooth_devices);
+        final CharSequence titleNoBluetoothDevices = mContext.getText(
+                R.string.no_bluetooth_devices);
         final PendingIntent primaryActionIntent = PendingIntent.getActivity(mContext, 0,
                 getIntent(), 0);
         final SliceAction primarySliceAction = SliceAction.createDeeplink(primaryActionIntent, icon,
                 ListBuilder.ICON_IMAGE, title);
         final ListBuilder listBuilder =
-                new ListBuilder(mContext, CustomSliceRegistry.CONNECTED_DEVICE_SLICE_URI,
+                new ListBuilder(mContext, CustomSliceRegistry.BLUETOOTH_DEVICES_SLICE_URI,
                         ListBuilder.INFINITY)
                         .setAccentColor(Utils.getColorAccentDefaultColor(mContext));
 
-        // Get row builders by connected devices, e.g. Bluetooth.
+        // Get row builders by Bluetooth devices.
         final List<ListBuilder.RowBuilder> rows = getBluetoothRowBuilder(primarySliceAction);
 
-        // Return a header with IsError flag, if no connected devices.
+        // Return a header with IsError flag, if no Bluetooth devices.
         if (rows.isEmpty()) {
             return listBuilder.setHeader(new ListBuilder.HeaderBuilder()
-                    .setTitle(titleNoConnectedDevices)
+                    .setTitle(titleNoBluetoothDevices)
                     .setPrimaryAction(primarySliceAction))
                     .setIsError(true)
                     .build();
         }
 
-        // According the number of connected devices to set sub title of header.
+        // According the number of Bluetooth devices to set sub title of header.
         listBuilder.setHeader(new ListBuilder.HeaderBuilder()
                 .setTitle(title)
                 .setSubtitle(getSubTitle(rows.size()))
                 .setPrimaryAction(primarySliceAction));
 
-        // Add rows.
+        // Add bluetooth device rows.
         for (ListBuilder.RowBuilder rowBuilder : rows) {
             listBuilder.addRow(rowBuilder);
         }
+
+        // Add "Pair new device" if need.
+        if (rows.size() < DEFAULT_EXPANDED_ROW_COUNT) {
+            listBuilder.addRow(getPairNewDeviceRowBuilder());
+        }
+
         return listBuilder.build();
     }
 
@@ -148,7 +154,7 @@
                 screenTitle,
                 MetricsProto.MetricsEvent.SLICE)
                 .setClassName(mContext.getPackageName(), SubSettings.class.getName())
-                .setData(CustomSliceRegistry.CONNECTED_DEVICE_SLICE_URI);
+                .setData(CustomSliceRegistry.BLUETOOTH_DEVICES_SLICE_URI);
     }
 
     @Override
@@ -161,25 +167,30 @@
     }
 
     @VisibleForTesting
-    List<CachedBluetoothDevice> getBluetoothConnectedDevices() {
-        final List<CachedBluetoothDevice> connectedBluetoothList = new ArrayList<>();
+    List<CachedBluetoothDevice> getBluetoothDevices() {
+        final List<CachedBluetoothDevice> bluetoothDeviceList = new ArrayList<>();
 
         // If Bluetooth is disable, skip to get the bluetooth devices.
         if (!BluetoothAdapter.getDefaultAdapter().isEnabled()) {
-            Log.i(TAG, "Cannot get Bluetooth connected devices, Bluetooth is disabled.");
-            return connectedBluetoothList;
+            Log.i(TAG, "Cannot get Bluetooth devices, Bluetooth is disabled.");
+            return bluetoothDeviceList;
         }
 
         // Get the Bluetooth devices from LocalBluetoothManager.
         final LocalBluetoothManager bluetoothManager =
                 com.android.settings.bluetooth.Utils.getLocalBtManager(mContext);
         if (bluetoothManager == null) {
-            Log.i(TAG, "Cannot get Bluetooth connected devices, Bluetooth is unsupported.");
-            return connectedBluetoothList;
+            Log.i(TAG, "Cannot get Bluetooth devices, Bluetooth is unsupported.");
+            return bluetoothDeviceList;
         }
         final Collection<CachedBluetoothDevice> cachedDevices =
                 bluetoothManager.getCachedDeviceManager().getCachedDevicesCopy();
 
+        /**
+         * TODO(b/114807655): Contextual Home Page - Connected Device
+         * Re-design to get all Bluetooth devices and sort them by new rule:
+         * Sorting rule: Audio Streaming > Last connected > Recently connected.
+         */
         // Get connected Bluetooth devices and sort them.
         return cachedDevices.stream().filter(device -> device.isConnected()).sorted(
                 COMPARATOR).collect(Collectors.toList());
@@ -204,25 +215,29 @@
     }
 
     @VisibleForTesting
-    IconCompat getConnectedDeviceIcon(CachedBluetoothDevice device) {
+    IconCompat getBluetoothDeviceIcon(CachedBluetoothDevice device) {
         final Pair<Drawable, String> pair = BluetoothUtils
                 .getBtClassDrawableWithDescription(mContext, device);
 
         if (pair.first != null) {
             return IconCompat.createWithBitmap(getBitmapFromVectorDrawable(pair.first));
         } else {
-            return IconCompat.createWithResource(mContext, R.drawable.ic_homepage_connected_device);
+            return IconCompat.createWithResource(mContext, R.drawable.ic_settings_bluetooth);
         }
     }
 
     private List<ListBuilder.RowBuilder> getBluetoothRowBuilder(SliceAction primarySliceAction) {
         final List<ListBuilder.RowBuilder> bluetoothRows = new ArrayList<>();
 
-        // According Bluetooth connected device to create row builders.
-        final List<CachedBluetoothDevice> bluetoothDevices = getBluetoothConnectedDevices();
+        /**
+         * TODO(b/114807655): Contextual Home Page - Connected Device
+         * Re-design to do action "activating" in primary action.
+         */
+        // According Bluetooth device to create row builders.
+        final List<CachedBluetoothDevice> bluetoothDevices = getBluetoothDevices();
         for (CachedBluetoothDevice bluetoothDevice : bluetoothDevices) {
             bluetoothRows.add(new ListBuilder.RowBuilder()
-                    .setTitleItem(getConnectedDeviceIcon(bluetoothDevice), ListBuilder.ICON_IMAGE)
+                    .setTitleItem(getBluetoothDeviceIcon(bluetoothDevice), ListBuilder.ICON_IMAGE)
                     .setTitle(bluetoothDevice.getName())
                     .setSubtitle(bluetoothDevice.getConnectionSummary())
                     .setPrimaryAction(primarySliceAction)
@@ -241,7 +256,31 @@
     }
 
     private CharSequence getSubTitle(int deviceCount) {
-        return mContext.getResources().getQuantityString(R.plurals.show_connected_devices,
+        return mContext.getResources().getQuantityString(R.plurals.show_bluetooth_devices,
                 deviceCount, deviceCount);
     }
+
+    private ListBuilder.RowBuilder getPairNewDeviceRowBuilder() {
+        final CharSequence title = mContext.getText(R.string.bluetooth_pairing_pref_title);
+        final IconCompat icon = IconCompat.createWithResource(mContext, R.drawable.ic_menu_add);
+        final SliceAction sliceAction = SliceAction.createDeeplink(
+                getPairNewDeviceIntent(),
+                IconCompat.createWithResource(mContext, R.drawable.ic_settings),
+                ListBuilder.ICON_IMAGE, title);
+
+        return new ListBuilder.RowBuilder()
+                .setTitleItem(icon, ListBuilder.ICON_IMAGE)
+                .setTitle(title)
+                .setPrimaryAction(sliceAction);
+    }
+
+    private PendingIntent getPairNewDeviceIntent() {
+        final Intent intent = new SubSettingLauncher(mContext)
+                .setDestination(BluetoothPairingDetail.class.getName())
+                .setTitleRes(R.string.bluetooth_pairing_page_title)
+                .setSourceMetricsCategory(SettingsEnums.BLUETOOTH_PAIRING)
+                .toIntent();
+
+        return PendingIntent.getActivity(mContext, 0  /* requestCode */, intent, 0  /* flags */);
+    }
 }
\ No newline at end of file
diff --git a/src/com/android/settings/homepage/contextualcards/slices/SliceContextualCardRenderer.java b/src/com/android/settings/homepage/contextualcards/slices/SliceContextualCardRenderer.java
index 267fe4d..be03c28 100644
--- a/src/com/android/settings/homepage/contextualcards/slices/SliceContextualCardRenderer.java
+++ b/src/com/android/settings/homepage/contextualcards/slices/SliceContextualCardRenderer.java
@@ -41,6 +41,7 @@
 import androidx.slice.widget.SliceView;
 
 import com.android.settings.R;
+import com.android.settings.homepage.contextualcards.CardContentProvider;
 import com.android.settings.homepage.contextualcards.ContextualCard;
 import com.android.settings.homepage.contextualcards.ContextualCardFeatureProvider;
 import com.android.settings.homepage.contextualcards.ContextualCardRenderer;
@@ -94,6 +95,8 @@
     public void bindView(RecyclerView.ViewHolder holder, ContextualCard card) {
         final SliceViewHolder cardHolder = (SliceViewHolder) holder;
         final Uri uri = card.getSliceUri();
+        //TODO(b/120629936): Take this out once blank card issue is fixed.
+        Log.d(TAG, "bindView - uri = " + uri);
 
         if (!ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) {
             Log.w(TAG, "Invalid uri, skipping slice: " + uri);
@@ -116,6 +119,11 @@
         sliceLiveData.observe(mLifecycleOwner, slice -> {
             if (slice == null) {
                 Log.w(TAG, "Slice is null");
+                mContext.getContentResolver().notifyChange(CardContentProvider.URI, null);
+                return;
+            } else {
+                //TODO(b/120629936): Take this out once blank card issue is fixed.
+                Log.d(TAG, "Slice callback - uri = " + slice.getUri());
             }
             cardHolder.sliceView.setSlice(slice);
         });
diff --git a/src/com/android/settings/location/LocationScanningPreferenceController.java b/src/com/android/settings/location/LocationScanningPreferenceController.java
index 9d1bdc0..2c05a39 100644
--- a/src/com/android/settings/location/LocationScanningPreferenceController.java
+++ b/src/com/android/settings/location/LocationScanningPreferenceController.java
@@ -17,6 +17,7 @@
 package com.android.settings.location;
 
 import android.content.Context;
+import android.provider.Settings;
 
 import androidx.annotation.VisibleForTesting;
 
@@ -25,11 +26,31 @@
 
 
 public class LocationScanningPreferenceController extends BasePreferenceController {
-
     @VisibleForTesting static final String KEY_LOCATION_SCANNING = "location_scanning";
+    private final Context mContext;
 
     public LocationScanningPreferenceController(Context context) {
         super(context, KEY_LOCATION_SCANNING);
+        mContext = context;
+    }
+
+    @Override
+    public CharSequence getSummary() {
+        final boolean wifiScanOn = Settings.Global.getInt(mContext.getContentResolver(),
+                Settings.Global.WIFI_SCAN_ALWAYS_AVAILABLE, 0) == 1;
+        final boolean bleScanOn = Settings.Global.getInt(mContext.getContentResolver(),
+                Settings.Global.BLE_SCAN_ALWAYS_AVAILABLE, 0) == 1;
+        int resId;
+        if (wifiScanOn && bleScanOn) {
+            resId = R.string.scanning_status_text_wifi_on_ble_on;
+        } else if (wifiScanOn && !bleScanOn) {
+            resId = R.string.scanning_status_text_wifi_on_ble_off;
+        } else if (!wifiScanOn && bleScanOn) {
+            resId = R.string.scanning_status_text_wifi_off_ble_on;
+        } else {
+            resId = R.string.scanning_status_text_wifi_off_ble_off;
+        }
+        return mContext.getString(resId);
     }
 
     @AvailabilityStatus
diff --git a/src/com/android/settings/network/SubscriptionUtil.java b/src/com/android/settings/network/SubscriptionUtil.java
new file mode 100644
index 0000000..cfe27db
--- /dev/null
+++ b/src/com/android/settings/network/SubscriptionUtil.java
@@ -0,0 +1,44 @@
+/*
+ * 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.network;
+
+import android.telephony.SubscriptionInfo;
+import android.telephony.SubscriptionManager;
+import android.text.TextUtils;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+public class SubscriptionUtil {
+    public static List<SubscriptionInfo> getAvailableSubscriptions(SubscriptionManager manager) {
+        List<SubscriptionInfo> subscriptions = manager.getAvailableSubscriptionInfoList();
+        if (subscriptions == null) {
+            subscriptions = new ArrayList<>();
+        }
+        // With some carriers such as Google Fi which provide a sort of virtual service that spans
+        // across multiple underlying networks, we end up with subscription entries for the
+        // underlying networks that need to be hidden from the user in the UI.
+        for (Iterator<SubscriptionInfo> iter = subscriptions.iterator(); iter.hasNext(); ) {
+            SubscriptionInfo info = iter.next();
+            if (TextUtils.isEmpty(info.getMncString())) {
+                iter.remove();
+            }
+        }
+        return subscriptions;
+    }
+}
diff --git a/src/com/android/settings/network/SubscriptionsChangeListener.java b/src/com/android/settings/network/SubscriptionsChangeListener.java
new file mode 100644
index 0000000..c3bb22b
--- /dev/null
+++ b/src/com/android/settings/network/SubscriptionsChangeListener.java
@@ -0,0 +1,97 @@
+/*
+ * 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.network;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.database.ContentObserver;
+import android.net.Uri;
+import android.os.Handler;
+import android.provider.Settings;
+import android.telephony.SubscriptionManager;
+import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener;
+
+import com.android.internal.telephony.TelephonyIntents;
+
+/** Helper class for listening to changes in availability of telephony subscriptions */
+public class SubscriptionsChangeListener extends ContentObserver {
+
+    public interface SubscriptionsChangeListenerClient {
+        void onAirplaneModeChanged(boolean airplaneModeEnabled);
+        void onSubscriptionsChanged();
+    }
+
+    private Context mContext;
+    private SubscriptionsChangeListenerClient mClient;
+    private SubscriptionManager mSubscriptionManager;
+    private OnSubscriptionsChangedListener mSubscriptionsChangedListener;
+    private Uri mAirplaneModeSettingUri;
+    private BroadcastReceiver mBroadcastReceiver;
+
+    public SubscriptionsChangeListener(Context context, SubscriptionsChangeListenerClient client) {
+        super(new Handler());
+        mContext = context;
+        mClient = client;
+        mSubscriptionManager = mContext.getSystemService(SubscriptionManager.class);
+        mSubscriptionsChangedListener = new OnSubscriptionsChangedListener() {
+            @Override
+            public void onSubscriptionsChanged() {
+                subscriptionsChangedCallback();
+            }
+        };
+        mAirplaneModeSettingUri = Settings.Global.getUriFor(Settings.Global.AIRPLANE_MODE_ON);
+        mBroadcastReceiver = new BroadcastReceiver() {
+            @Override
+            public void onReceive(Context context, Intent intent) {
+                subscriptionsChangedCallback();
+            }
+        };
+    }
+
+    public void start() {
+        mSubscriptionManager.addOnSubscriptionsChangedListener(mSubscriptionsChangedListener);
+        mContext.getContentResolver()
+                .registerContentObserver(mAirplaneModeSettingUri, false, this);
+        final IntentFilter radioTechnologyChangedFilter = new IntentFilter(
+                TelephonyIntents.ACTION_RADIO_TECHNOLOGY_CHANGED);
+        mContext.registerReceiver(mBroadcastReceiver, radioTechnologyChangedFilter);
+    }
+
+    public void stop() {
+        mSubscriptionManager.removeOnSubscriptionsChangedListener(mSubscriptionsChangedListener);
+        mContext.getContentResolver().unregisterContentObserver(this);
+        mContext.unregisterReceiver(mBroadcastReceiver);
+    }
+
+    public boolean isAirplaneModeOn() {
+        return Settings.Global.getInt(mContext.getContentResolver(),
+                Settings.Global.AIRPLANE_MODE_ON, 0) != 0;
+    }
+
+    private void subscriptionsChangedCallback() {
+        mClient.onSubscriptionsChanged();
+    }
+
+    @Override
+    public void onChange(boolean selfChange, Uri uri) {
+        if (uri.equals(mAirplaneModeSettingUri)) {
+            mClient.onAirplaneModeChanged(isAirplaneModeOn());
+        }
+    }
+}
diff --git a/src/com/android/settings/slices/CustomSliceManager.java b/src/com/android/settings/slices/CustomSliceManager.java
index 8f8ee96..4a9de15 100644
--- a/src/com/android/settings/slices/CustomSliceManager.java
+++ b/src/com/android/settings/slices/CustomSliceManager.java
@@ -29,7 +29,7 @@
 import com.android.settings.homepage.contextualcards.deviceinfo.EmergencyInfoSlice;
 import com.android.settings.homepage.contextualcards.deviceinfo.StorageSlice;
 import com.android.settings.homepage.contextualcards.slices.BatteryFixSlice;
-import com.android.settings.homepage.contextualcards.slices.ConnectedDeviceSlice;
+import com.android.settings.homepage.contextualcards.slices.BluetoothDevicesSlice;
 import com.android.settings.homepage.contextualcards.slices.LowStorageSlice;
 import com.android.settings.location.LocationSlice;
 import com.android.settings.wifi.WifiSlice;
@@ -106,7 +106,7 @@
     private void addSlices() {
         mUriMap.put(CustomSliceRegistry.BATTERY_FIX_SLICE_URI, BatteryFixSlice.class);
         mUriMap.put(CustomSliceRegistry.BATTERY_INFO_SLICE_URI, BatterySlice.class);
-        mUriMap.put(CustomSliceRegistry.CONNECTED_DEVICE_SLICE_URI, ConnectedDeviceSlice.class);
+        mUriMap.put(CustomSliceRegistry.BLUETOOTH_DEVICES_SLICE_URI, BluetoothDevicesSlice.class);
         mUriMap.put(CustomSliceRegistry.DATA_USAGE_SLICE_URI, DataUsageSlice.class);
         mUriMap.put(CustomSliceRegistry.DEVICE_INFO_SLICE_URI, DeviceInfoSlice.class);
         mUriMap.put(CustomSliceRegistry.EMERGENCY_INFO_SLICE_URI, EmergencyInfoSlice.class);
diff --git a/src/com/android/settings/slices/CustomSliceRegistry.java b/src/com/android/settings/slices/CustomSliceRegistry.java
index 80de3b2..1b8cffe 100644
--- a/src/com/android/settings/slices/CustomSliceRegistry.java
+++ b/src/com/android/settings/slices/CustomSliceRegistry.java
@@ -72,13 +72,13 @@
             .build();
 
     /**
-     * Backing Uri for Connected device Slice.
+     * Backing Uri for Bluetooth devices Slice.
      */
-    public static final Uri CONNECTED_DEVICE_SLICE_URI = new Uri.Builder()
+    public static final Uri BLUETOOTH_DEVICES_SLICE_URI = new Uri.Builder()
             .scheme(ContentResolver.SCHEME_CONTENT)
             .authority(SettingsSliceProvider.SLICE_AUTHORITY)
             .appendPath(SettingsSlicesContract.PATH_SETTING_ACTION)
-            .appendPath("connected_device")
+            .appendPath("bluetooth_devices")
             .build();
     /**
      * Backing Uri for the Data usage Slice.
diff --git a/src/com/android/settings/wifi/CellularFallbackPreferenceController.java b/src/com/android/settings/wifi/CellularFallbackPreferenceController.java
index a883826..cbb8fb8 100644
--- a/src/com/android/settings/wifi/CellularFallbackPreferenceController.java
+++ b/src/com/android/settings/wifi/CellularFallbackPreferenceController.java
@@ -18,62 +18,34 @@
 
 import android.content.Context;
 import android.provider.Settings;
-import android.text.TextUtils;
 
-import androidx.preference.Preference;
-import androidx.preference.SwitchPreference;
-
-import com.android.settings.core.PreferenceControllerMixin;
-import com.android.settingslib.core.AbstractPreferenceController;
+import com.android.settings.core.TogglePreferenceController;
 
 /**
- * {@link AbstractPreferenceController} that controls whether we should fall back to celluar when
+ * CellularFallbackPreferenceController controls whether we should fall back to celluar when
  * wifi is bad.
  */
-public class CellularFallbackPreferenceController extends AbstractPreferenceController
-        implements PreferenceControllerMixin {
+public class CellularFallbackPreferenceController extends TogglePreferenceController {
 
-    private static final String KEY_CELLULAR_FALLBACK = "wifi_cellular_data_fallback";
-
-
-    public CellularFallbackPreferenceController(Context context) {
-        super(context);
+    public CellularFallbackPreferenceController(Context context, String key) {
+        super(context, key);
     }
 
     @Override
-    public boolean isAvailable() {
-        return !avoidBadWifiConfig();
+    public int getAvailabilityStatus() {
+        return !avoidBadWifiConfig() ? AVAILABLE : UNSUPPORTED_ON_DEVICE;
     }
 
     @Override
-    public String getPreferenceKey() {
-        return KEY_CELLULAR_FALLBACK;
+    public boolean isChecked() {
+        return avoidBadWifiCurrentSettings();
     }
 
     @Override
-    public boolean handlePreferenceTreeClick(Preference preference) {
-        if (!TextUtils.equals(preference.getKey(), KEY_CELLULAR_FALLBACK)) {
-            return false;
-        }
-        if (!(preference instanceof SwitchPreference)) {
-            return false;
-        }
+    public boolean setChecked(boolean isChecked) {
         // On: avoid bad wifi. Off: prompt.
-        String settingName = Settings.Global.NETWORK_AVOID_BAD_WIFI;
-        Settings.Global.putString(mContext.getContentResolver(), settingName,
-                ((SwitchPreference) preference).isChecked() ? "1" : null);
-        return true;
-    }
-
-    @Override
-    public void updateState(Preference preference) {
-        final boolean currentSetting = avoidBadWifiCurrentSettings();
-        // TODO: can this ever be null? The return value of avoidBadWifiConfig() can only
-        // change if the resources change, but if that happens the activity will be recreated...
-        if (preference != null) {
-            SwitchPreference pref = (SwitchPreference) preference;
-            pref.setChecked(currentSetting);
-        }
+        return Settings.Global.putString(mContext.getContentResolver(),
+                Settings.Global.NETWORK_AVOID_BAD_WIFI, isChecked ? "1" : null);
     }
 
     private boolean avoidBadWifiConfig() {
@@ -85,4 +57,4 @@
         return "1".equals(Settings.Global.getString(mContext.getContentResolver(),
                 Settings.Global.NETWORK_AVOID_BAD_WIFI));
     }
-}
+}
\ No newline at end of file
diff --git a/src/com/android/settings/wifi/ConfigureWifiSettings.java b/src/com/android/settings/wifi/ConfigureWifiSettings.java
index 1d1c30c..8df4a41 100644
--- a/src/com/android/settings/wifi/ConfigureWifiSettings.java
+++ b/src/com/android/settings/wifi/ConfigureWifiSettings.java
@@ -85,7 +85,6 @@
         controllers.add(mUseOpenWifiPreferenceController);
         controllers.add(new WifiInfoPreferenceController(context, getSettingsLifecycle(),
                 wifiManager));
-        controllers.add(new CellularFallbackPreferenceController(context));
         controllers.add(new WifiP2pPreferenceController(context, getSettingsLifecycle(),
                 wifiManager));
         return controllers;
diff --git a/src/com/android/settings/wifi/WifiSlice.java b/src/com/android/settings/wifi/WifiSlice.java
index 2382abb..64e3fc3 100644
--- a/src/com/android/settings/wifi/WifiSlice.java
+++ b/src/com/android/settings/wifi/WifiSlice.java
@@ -37,7 +37,6 @@
 import androidx.core.graphics.drawable.IconCompat;
 import androidx.slice.Slice;
 import androidx.slice.builders.ListBuilder;
-import androidx.slice.builders.ListBuilder.RowBuilder;
 import androidx.slice.builders.SliceAction;
 
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
@@ -64,9 +63,11 @@
     static final int DEFAULT_EXPANDED_ROW_COUNT = 3;
 
     private final Context mContext;
+    private final WifiManager mWifiManager;
 
     public WifiSlice(Context context) {
         mContext = context;
+        mWifiManager = mContext.getSystemService(WifiManager.class);
     }
 
     @Override
@@ -100,7 +101,7 @@
         final ListBuilder listBuilder = new ListBuilder(mContext, WIFI_SLICE_URI,
                 ListBuilder.INFINITY)
                 .setAccentColor(color)
-                .addRow(new RowBuilder()
+                .addRow(new ListBuilder.RowBuilder()
                         .setTitle(title)
                         .setSubtitle(summary)
                         .addEndItem(toggleSliceAction)
@@ -110,18 +111,25 @@
             return listBuilder.build();
         }
 
-        List<AccessPoint> results = SliceBackgroundWorker.getInstance(mContext, this).getResults();
-        if (results == null) {
-            results = new ArrayList<>();
-        }
-        final int apCount = results.size();
+        final List<AccessPoint> results =
+                SliceBackgroundWorker.getInstance(mContext, this).getResults();
+
+        // Need a loading text when results are not ready.
+        boolean needLoadingRow = results == null;
+        final int apCount = needLoadingRow ? 0 : results.size();
+
         // Add AP rows
         final CharSequence placeholder = mContext.getText(R.string.summary_placeholder);
         for (int i = 0; i < DEFAULT_EXPANDED_ROW_COUNT; i++) {
             if (i < apCount) {
                 listBuilder.addRow(getAccessPointRow(results.get(i)));
+            } else if (needLoadingRow) {
+                listBuilder.addRow(new ListBuilder.RowBuilder()
+                        .setTitle(mContext.getText(R.string.wifi_empty_list_wifi_on))
+                        .setSubtitle(placeholder));
+                needLoadingRow = false;
             } else {
-                listBuilder.addRow(new RowBuilder()
+                listBuilder.addRow(new ListBuilder.RowBuilder()
                         .setTitle(placeholder)
                         .setSubtitle(placeholder));
             }
@@ -129,12 +137,12 @@
         return listBuilder.build();
     }
 
-    private RowBuilder getAccessPointRow(AccessPoint accessPoint) {
+    private ListBuilder.RowBuilder getAccessPointRow(AccessPoint accessPoint) {
         final String title = accessPoint.getConfigName();
         final IconCompat levelIcon = IconCompat.createWithResource(mContext,
                 com.android.settingslib.Utils.getWifiIconResource(accessPoint.getLevel()));
         final CharSequence apSummary = accessPoint.getSettingsSummary();
-        final RowBuilder rowBuilder = new RowBuilder()
+        final ListBuilder.RowBuilder rowBuilder = new ListBuilder.RowBuilder()
                 .setTitleItem(levelIcon, ListBuilder.ICON_IMAGE)
                 .setTitle(title)
                 .setSubtitle(!TextUtils.isEmpty(apSummary)
@@ -188,10 +196,9 @@
      */
     @Override
     public void onNotifyChange(Intent intent) {
-        final WifiManager wifiManager = mContext.getSystemService(WifiManager.class);
         final boolean newState = intent.getBooleanExtra(EXTRA_TOGGLE_STATE,
-                wifiManager.isWifiEnabled());
-        wifiManager.setWifiEnabled(newState);
+                mWifiManager.isWifiEnabled());
+        mWifiManager.setWifiEnabled(newState);
         // Do not notifyChange on Uri. The service takes longer to update the current value than it
         // does for the Slice to check the current value again. Let {@link SliceBroadcastRelay}
         // handle it.
@@ -211,26 +218,19 @@
     }
 
     private boolean isWifiEnabled() {
-        final WifiManager wifiManager = mContext.getSystemService(WifiManager.class);
-
-        switch (wifiManager.getWifiState()) {
+        switch (mWifiManager.getWifiState()) {
             case WifiManager.WIFI_STATE_ENABLED:
             case WifiManager.WIFI_STATE_ENABLING:
                 return true;
-            case WifiManager.WIFI_STATE_DISABLED:
-            case WifiManager.WIFI_STATE_DISABLING:
-            case WifiManager.WIFI_STATE_UNKNOWN:
             default:
                 return false;
         }
     }
 
     private CharSequence getSummary() {
-        final WifiManager wifiManager = mContext.getSystemService(WifiManager.class);
-
-        switch (wifiManager.getWifiState()) {
+        switch (mWifiManager.getWifiState()) {
             case WifiManager.WIFI_STATE_ENABLED:
-                final String ssid = WifiInfo.removeDoubleQuotes(wifiManager.getConnectionInfo()
+                final String ssid = WifiInfo.removeDoubleQuotes(mWifiManager.getConnectionInfo()
                         .getSSID());
                 if (TextUtils.equals(ssid, WifiSsid.NONE)) {
                     return mContext.getText(R.string.disconnected);
diff --git a/src/com/android/settings/wifi/details/WifiDetailPreferenceController.java b/src/com/android/settings/wifi/details/WifiDetailPreferenceController.java
index a676bfa..e1179f8 100644
--- a/src/com/android/settings/wifi/details/WifiDetailPreferenceController.java
+++ b/src/com/android/settings/wifi/details/WifiDetailPreferenceController.java
@@ -20,6 +20,7 @@
 import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
 
 import android.app.Activity;
+import android.app.KeyguardManager;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
@@ -40,6 +41,7 @@
 import android.net.wifi.WifiManager;
 import android.os.Handler;
 import android.text.TextUtils;
+import android.util.FeatureFlagUtils;
 import android.util.Log;
 import android.widget.ImageView;
 import android.widget.Toast;
@@ -54,8 +56,11 @@
 import com.android.internal.logging.nano.MetricsProto;
 import com.android.settings.R;
 import com.android.settings.Utils;
+import com.android.settings.core.FeatureFlags;
 import com.android.settings.core.PreferenceControllerMixin;
 import com.android.settings.widget.EntityHeaderController;
+import com.android.settings.wifi.dpp.WifiDppConfiguratorActivity;
+import com.android.settings.wifi.dpp.WifiDppUtils;
 import com.android.settings.wifi.WifiDialog;
 import com.android.settings.wifi.WifiDialog.WifiDialogListener;
 import com.android.settings.wifi.WifiUtils;
@@ -280,7 +285,10 @@
                 .setButton1Icon(R.drawable.ic_settings_delete)
                 .setButton1OnClickListener(view -> forgetNetwork())
                 .setButton2Text(R.string.wifi_sign_in_button_text)
-                .setButton2OnClickListener(view -> signIntoNetwork());
+                .setButton2OnClickListener(view -> signIntoNetwork())
+                .setButton3Text(R.string.share)
+                .setButton3Icon(R.drawable.ic_qrcode_24dp)
+                .setButton3OnClickListener(view -> shareNetwork());
 
         mSignalStrengthPref = screen.findPreference(KEY_SIGNAL_STRENGTH_PREF);
         mLinkSpeedPref = screen.findPreference(KEY_LINK_SPEED);
@@ -296,7 +304,7 @@
         mIpv6Category = (PreferenceCategory) screen.findPreference(KEY_IPV6_CATEGORY);
         mIpv6AddressPref = screen.findPreference(KEY_IPV6_ADDRESSES_PREF);
 
-        mSecurityPref.setSummary(mAccessPoint.getSecurityString(false /* concise */));
+        mSecurityPref.setSummary(mAccessPoint.getSecurityString(/* concise */ false));
     }
 
     private void setupEntityHeader(PreferenceScreen screen) {
@@ -425,7 +433,9 @@
 
     private void updateIpLayerInfo() {
         mButtonsPref.setButton2Visible(canSignIntoNetwork());
-        mButtonsPref.setVisible(canSignIntoNetwork() || canForgetNetwork());
+        mButtonsPref.setButton3Visible(isSharingNetworkEnabled());
+        mButtonsPref.setVisible(
+                canSignIntoNetwork() || canForgetNetwork() || isSharingNetworkEnabled());
 
         if (mNetwork == null || mLinkProperties == null) {
             mIpAddressPref.setVisible(false);
@@ -511,6 +521,13 @@
     }
 
     /**
+     * Returns whether the user can share the network represented by this preference with QR code.
+     */
+    private boolean isSharingNetworkEnabled() {
+        return FeatureFlagUtils.isEnabled(mContext, FeatureFlags.WIFI_SHARING);
+    }
+
+    /**
      * Forgets the wifi network associated with this preference.
      */
     private void forgetNetwork() {
@@ -529,6 +546,42 @@
     }
 
     /**
+     * Show QR code to share the network represented by this preference.
+     */
+    public void launchQRCodeGenerator() {
+        final Intent intent = new Intent(
+                WifiDppConfiguratorActivity.ACTION_CONFIGURATOR_QR_CODE_GENERATOR);
+        intent.putExtra(WifiDppUtils.EXTRA_WIFI_SECURITY,
+                mAccessPoint.getSecurityString(/* concise */ false));
+        intent.putExtra(WifiDppUtils.EXTRA_WIFI_SSID, mAccessPoint.getSsidStr());
+        mContext.startActivity(intent);
+    }
+
+    /**
+     * Share the wifi network with QR code.
+     */
+    private void shareNetwork() {
+        final KeyguardManager keyguardManager = (KeyguardManager) mContext.getSystemService(
+                Context.KEYGUARD_SERVICE);
+        if (keyguardManager.isKeyguardSecure()) {
+            // Show authentication screen to confirm credentials (pin, pattern or password) for
+            // the current user of the device.
+            final String description = String.format(
+                    mContext.getString(R.string.wifi_sharing_message),
+                    mAccessPoint.getSsidStr());
+            final Intent intent = keyguardManager.createConfirmDeviceCredentialIntent(
+                    mContext.getString(R.string.lockpassword_confirm_your_pattern_header),
+                    description);
+            if (intent != null) {
+                mFragment.startActivityForResult(intent,
+                        WifiNetworkDetailsFragment.REQUEST_CODE_CONFIRM_DEVICE_CREDENTIALS);
+            }
+        } else {
+            launchQRCodeGenerator();
+        }
+    }
+
+    /**
      * Sign in to the captive portal found on this wifi network associated with this preference.
      */
     private void signIntoNetwork() {
diff --git a/src/com/android/settings/wifi/details/WifiNetworkDetailsFragment.java b/src/com/android/settings/wifi/details/WifiNetworkDetailsFragment.java
index 7f0e8ee..9814486 100644
--- a/src/com/android/settings/wifi/details/WifiNetworkDetailsFragment.java
+++ b/src/com/android/settings/wifi/details/WifiNetworkDetailsFragment.java
@@ -17,8 +17,10 @@
 
 import static com.android.settings.wifi.WifiSettings.WIFI_DIALOG_ID;
 
+import android.app.Activity;
 import android.app.Dialog;
 import android.content.Context;
+import android.content.Intent;
 import android.net.ConnectivityManager;
 import android.net.wifi.WifiManager;
 import android.os.Bundle;
@@ -52,6 +54,8 @@
 
     private static final String TAG = "WifiNetworkDetailsFrg";
 
+    public static final int REQUEST_CODE_CONFIRM_DEVICE_CREDENTIALS = 1;
+
     private AccessPoint mAccessPoint;
     private WifiDetailPreferenceController mWifiDetailPreferenceController;
 
@@ -142,4 +146,14 @@
 
         return controllers;
     }
+
+    @Override
+    public void onActivityResult(int requestCode, int resultCode, Intent data) {
+        super.onActivityResult(requestCode, resultCode, data);
+
+        if (requestCode == REQUEST_CODE_CONFIRM_DEVICE_CREDENTIALS
+                && resultCode == Activity.RESULT_OK) {
+            mWifiDetailPreferenceController.launchQRCodeGenerator();
+        }
+    }
 }
diff --git a/tests/robotests/assets/grandfather_not_implementing_index_provider b/tests/robotests/assets/grandfather_not_implementing_index_provider
index e105dfc..ab06f75 100644
--- a/tests/robotests/assets/grandfather_not_implementing_index_provider
+++ b/tests/robotests/assets/grandfather_not_implementing_index_provider
@@ -7,7 +7,6 @@
 com.android.settings.accessibility.ToggleSelectToSpeakPreferenceFragmentForSetupWizard
 com.android.settings.accounts.AccountDetailDashboardFragment
 com.android.settings.accounts.AccountSyncSettings
-com.android.settings.accounts.ManagedProfileSettings
 com.android.settings.applications.appinfo.AppInfoDashboardFragment
 com.android.settings.applications.appinfo.DrawOverlayDetails
 com.android.settings.applications.appinfo.ExternalSourcesDetails
diff --git a/tests/robotests/src/com/android/settings/accounts/CrossProfileCalendarPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/accounts/CrossProfileCalendarPreferenceControllerTest.java
new file mode 100644
index 0000000..4469282
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/accounts/CrossProfileCalendarPreferenceControllerTest.java
@@ -0,0 +1,156 @@
+/*
+ * 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.accounts;
+
+import static android.provider.Settings.Secure.CROSS_PROFILE_CALENDAR_ENABLED;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import static org.robolectric.RuntimeEnvironment.application;
+
+import android.app.admin.DevicePolicyManager;
+import android.content.ComponentName;
+import android.content.Context;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.util.ArraySet;
+import android.util.Log;
+
+import com.android.settings.testutils.SettingsRobolectricTestRunner;
+import com.android.settingslib.RestrictedSwitchPreference;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.Shadows;
+import org.robolectric.annotation.Config;
+import org.robolectric.shadows.ShadowDevicePolicyManager;
+
+import java.util.Collections;
+import java.util.Set;
+
+@RunWith(SettingsRobolectricTestRunner.class)
+public class CrossProfileCalendarPreferenceControllerTest {
+
+    private static final String PREF_KEY = "cross_profile_calendar";
+    private static final int MANAGED_USER_ID = 10;
+    private static final String TEST_PACKAGE_NAME = "com.test";
+    private static final ComponentName TEST_COMPONENT_NAME = new ComponentName("test", "test");
+
+    @Mock
+    private UserHandle mManagedUser;
+
+    private RestrictedSwitchPreference mPreference;
+    private Context mContext;
+    private CrossProfileCalendarPreferenceController mController;
+    private ShadowDevicePolicyManager dpm;
+
+    @Before
+    public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+        mContext = spy(RuntimeEnvironment.application);
+        mController = new CrossProfileCalendarPreferenceController(mContext, PREF_KEY);
+        mController.setManagedUser(mManagedUser);
+        mPreference = spy(new RestrictedSwitchPreference(mContext));
+        dpm = Shadows.shadowOf(application.getSystemService(DevicePolicyManager.class));
+
+        when(mManagedUser.getIdentifier()).thenReturn(MANAGED_USER_ID);
+        doReturn(mContext).when(mContext).createPackageContextAsUser(
+                any(String.class), anyInt(), any(UserHandle.class));
+    }
+
+    @Test
+    public void getAvailabilityStatus_noManagedUser_DISABLED() {
+        mController.setManagedUser(null);
+
+        assertThat(mController.getAvailabilityStatus())
+                .isNotEqualTo(CrossProfileCalendarPreferenceController.AVAILABLE);
+    }
+
+    @Test
+    public void getAvailabilityStatus_hasManagedUser_AVAILABLE() {
+        mController.setManagedUser(mManagedUser);
+        assertThat(mController.getAvailabilityStatus())
+                .isEqualTo(CrossProfileCalendarPreferenceController.AVAILABLE);
+    }
+
+    @Test
+    public void updateStateToDisabled_isNotChecked() {
+        Settings.Secure.putIntForUser(mContext.getContentResolver(),
+                CROSS_PROFILE_CALENDAR_ENABLED, 0, mManagedUser.getIdentifier());
+
+        mController.updateState(mPreference);
+        assertThat(mPreference.isChecked()).isFalse();
+    }
+
+    @Test
+    public void updateStateToEnabled_isChecked() throws Exception {
+        // Put 0 first so we know the value is not originally 1.
+        Settings.Secure.putIntForUser(mContext.getContentResolver(),
+                CROSS_PROFILE_CALENDAR_ENABLED, 0, mManagedUser.getIdentifier());
+        mController.updateState(mPreference);
+        Settings.Secure.putIntForUser(mContext.getContentResolver(),
+                CROSS_PROFILE_CALENDAR_ENABLED, 1, mManagedUser.getIdentifier());
+
+        mController.updateState(mPreference);
+        assertThat(mPreference.isChecked()).isTrue();
+    }
+
+    @Test
+    public void updateState_noPackageAllowed_preferenceShouldBeDisabled() throws Exception {
+        dpm.setProfileOwner(TEST_COMPONENT_NAME);
+
+        mController.updateState(mPreference);
+        verify(mPreference).setDisabledByAdmin(any());
+    }
+
+    @Test
+    public void updateState_somePackagesAllowed_preferenceShouldNotBeDisabled() throws Exception {
+        dpm.setProfileOwner(TEST_COMPONENT_NAME);
+        dpm.addCrossProfileCalendarPackage(TEST_COMPONENT_NAME, TEST_PACKAGE_NAME);
+
+        mController.updateState(mPreference);
+        verify(mPreference).setDisabledByAdmin(null);
+    }
+
+    @Test
+    public void onPreferenceChangeToFalse_shouldUpdateProviderValue() {
+        mController.onPreferenceChange(mPreference, false);
+        assertThat(Settings.Secure.getIntForUser(mContext.getContentResolver(),
+                CROSS_PROFILE_CALENDAR_ENABLED, 1, mManagedUser.getIdentifier()))
+                .isEqualTo(0);
+    }
+
+    @Test
+    public void onPreferenceChangeToTrue_shouldUpdateProviderValue() {
+        // Change to false first so we know the value is not originally 1.
+        mController.onPreferenceChange(mPreference, false);
+
+        mController.onPreferenceChange(mPreference, true);
+        assertThat(Settings.Secure.getIntForUser(mContext.getContentResolver(),
+                CROSS_PROFILE_CALENDAR_ENABLED, 0, mManagedUser.getIdentifier()))
+                .isEqualTo(1);
+    }
+}
\ No newline at end of file
diff --git a/tests/robotests/src/com/android/settings/datausage/ChartDataUsagePreferenceTest.java b/tests/robotests/src/com/android/settings/datausage/ChartDataUsagePreferenceTest.java
index af56029..0f9aed1 100644
--- a/tests/robotests/src/com/android/settings/datausage/ChartDataUsagePreferenceTest.java
+++ b/tests/robotests/src/com/android/settings/datausage/ChartDataUsagePreferenceTest.java
@@ -37,11 +37,14 @@
 
 import java.util.ArrayList;
 import java.util.List;
+import java.util.concurrent.TimeUnit;
 
 @RunWith(SettingsRobolectricTestRunner.class)
 public class ChartDataUsagePreferenceTest {
 
+    // Test cycle start date, 20 Mar 2018 22:00: GMT
     private static final long TIMESTAMP_START = 1521583200000L;
+    // Test bucket end date, 22 Mar 2018 00:00:00
     private static final long TIMESTAMP_END = 1521676800000L;
 
     private List<NetworkCycleData> mNetworkCycleData;
@@ -55,8 +58,6 @@
 
         mContext = RuntimeEnvironment.application;
         mPreference = new ChartDataUsagePreference(mContext, null);
-        createTestNetworkData();
-        mPreference.setNetworkCycleData(mNetworkCycleChartData);
     }
 
     @Test
@@ -64,11 +65,13 @@
         final UsageView usageView = mock(UsageView.class);
         final ArgumentCaptor<SparseIntArray> pointsCaptor =
                 ArgumentCaptor.forClass(SparseIntArray.class);
+        createTestNetworkData();
+        mPreference.setNetworkCycleData(mNetworkCycleChartData);
 
         mPreference.calcPoints(usageView, mNetworkCycleData.subList(0, 5));
 
         verify(usageView).addPath(pointsCaptor.capture());
-        SparseIntArray points = pointsCaptor.getValue();
+        final SparseIntArray points = pointsCaptor.getValue();
         // the point should be normal usage data
         assertThat(points.valueAt(1)).isNotEqualTo(-1);
     }
@@ -78,16 +81,73 @@
         final UsageView usageView = mock(UsageView.class);
         final ArgumentCaptor<SparseIntArray> pointsCaptor =
                 ArgumentCaptor.forClass(SparseIntArray.class);
+        createTestNetworkData();
+        mPreference.setNetworkCycleData(mNetworkCycleChartData);
 
         mPreference.calcPoints(usageView, mNetworkCycleData.subList(2, 7));
 
         verify(usageView).addPath(pointsCaptor.capture());
-        SparseIntArray points = pointsCaptor.getValue();
+        final SparseIntArray points = pointsCaptor.getValue();
         // indicator that no data is available
         assertThat(points.keyAt(1)).isEqualTo(points.keyAt(2) - 1);
         assertThat(points.valueAt(1)).isEqualTo(-1);
     }
 
+    @Test
+    public void calcPoints_shouldNotDrawPointForFutureDate() {
+        final UsageView usageView = mock(UsageView.class);
+        final ArgumentCaptor<SparseIntArray> pointsCaptor =
+            ArgumentCaptor.forClass(SparseIntArray.class);
+        final long tonight = System.currentTimeMillis() + TimeUnit.HOURS.toMillis(12);
+        mNetworkCycleData = new ArrayList<>();
+        // add test usage data for last 5 days
+        mNetworkCycleData.add(createNetworkCycleData(
+            tonight - TimeUnit.DAYS.toMillis(5), tonight - TimeUnit.DAYS.toMillis(4), 743823454L));
+        mNetworkCycleData.add(createNetworkCycleData(
+            tonight - TimeUnit.DAYS.toMillis(4), tonight - TimeUnit.DAYS.toMillis(3), 64396L));
+        mNetworkCycleData.add(createNetworkCycleData(
+            tonight - TimeUnit.DAYS.toMillis(3), tonight - TimeUnit.DAYS.toMillis(2), 2832L));
+        mNetworkCycleData.add(createNetworkCycleData(
+            tonight - TimeUnit.DAYS.toMillis(2), tonight - TimeUnit.DAYS.toMillis(1), 83849690L));
+        mNetworkCycleData.add(createNetworkCycleData(
+            tonight - TimeUnit.DAYS.toMillis(1), tonight, 1883657L));
+        // add dummy usage data for next 5 days
+        mNetworkCycleData.add(createNetworkCycleData(
+            tonight, tonight + TimeUnit.DAYS.toMillis(1), 0L));
+        mNetworkCycleData.add(createNetworkCycleData(
+            tonight + TimeUnit.DAYS.toMillis(1), tonight + TimeUnit.DAYS.toMillis(2), 0L));
+        mNetworkCycleData.add(createNetworkCycleData(
+            tonight + TimeUnit.DAYS.toMillis(2), tonight + TimeUnit.DAYS.toMillis(3), 0L));
+        mNetworkCycleData.add(createNetworkCycleData(
+            tonight + TimeUnit.DAYS.toMillis(3), tonight + TimeUnit.DAYS.toMillis(4), 0L));
+        mNetworkCycleData.add(createNetworkCycleData(
+            tonight + TimeUnit.DAYS.toMillis(4), tonight + TimeUnit.DAYS.toMillis(5), 0L));
+        mNetworkCycleData.add(createNetworkCycleData(
+            tonight + TimeUnit.DAYS.toMillis(5), tonight + TimeUnit.DAYS.toMillis(6), 0L));
+
+        final NetworkCycleChartData.Builder builder = new NetworkCycleChartData.Builder();
+        builder.setUsageBuckets(mNetworkCycleData)
+            .setStartTime(tonight - TimeUnit.DAYS.toMillis(5))
+            .setEndTime(tonight + TimeUnit.DAYS.toMillis(6));
+        mNetworkCycleChartData = builder.build();
+        mPreference.setNetworkCycleData(mNetworkCycleChartData);
+
+        mPreference.calcPoints(usageView, mNetworkCycleData);
+
+        verify(usageView).addPath(pointsCaptor.capture());
+        final SparseIntArray points = pointsCaptor.getValue();
+        // should only have 7 points: 1 dummy point indicating the start of data, starting point 0,
+        // and 5 actual data point for each day
+        assertThat(points.size()).isEqualTo(7);
+        assertThat(points.keyAt(0)).isEqualTo(-1);
+        assertThat(points.keyAt(1)).isEqualTo(0);
+        assertThat(points.keyAt(2)).isEqualTo(TimeUnit.DAYS.toMinutes(1));
+        assertThat(points.keyAt(3)).isEqualTo(TimeUnit.DAYS.toMinutes(2));
+        assertThat(points.keyAt(4)).isEqualTo(TimeUnit.DAYS.toMinutes(3));
+        assertThat(points.keyAt(5)).isEqualTo(TimeUnit.DAYS.toMinutes(4));
+        assertThat(points.keyAt(6)).isEqualTo(TimeUnit.DAYS.toMinutes(5));
+    }
+
     private void createTestNetworkData() {
         mNetworkCycleData = new ArrayList<>();
         // create 10 arbitrary network data
diff --git a/tests/robotests/src/com/android/settings/development/AngleEnabledAppPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/development/AngleEnabledAppPreferenceControllerTest.java
deleted file mode 100644
index 03837c2..0000000
--- a/tests/robotests/src/com/android/settings/development/AngleEnabledAppPreferenceControllerTest.java
+++ /dev/null
@@ -1,138 +0,0 @@
-/*
- * 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.development;
-
-import static com.android.settings.development.DevelopmentOptionsActivityRequestCodes.REQUEST_CODE_ANGLE_ENABLED_APP;
-import static com.google.common.truth.Truth.assertThat;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.app.Activity;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.provider.Settings;
-
-import androidx.preference.Preference;
-import androidx.preference.PreferenceScreen;
-
-import com.android.settings.R;
-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.util.ReflectionHelpers;
-
-@RunWith(SettingsRobolectricTestRunner.class)
-public class AngleEnabledAppPreferenceControllerTest {
-
-    @Mock
-    private Preference mPreference;
-    @Mock
-    private PreferenceScreen mPreferenceScreen;
-    @Mock
-    private DevelopmentSettingsDashboardFragment mFragment;
-    @Mock
-    private PackageManager mPackageManager;
-
-    private Context mContext;
-    private AngleEnabledAppPreferenceController mController;
-
-    @Before
-    public void setup() {
-        MockitoAnnotations.initMocks(this);
-        mContext = RuntimeEnvironment.application;
-        mController = spy(new AngleEnabledAppPreferenceController(mContext, mFragment));
-        ReflectionHelpers
-            .setField(mController, "mPackageManager" /* field name */, mPackageManager);
-        when(mPreferenceScreen.findPreference(mController.getPreferenceKey()))
-            .thenReturn(mPreference);
-        mController.displayPreference(mPreferenceScreen);
-    }
-
-    @Test
-    public void handlePreferenceTreeClick_preferenceClicked_launchActivity() {
-        final Intent activityStartIntent = new Intent(mContext, AppPicker.class);
-        final String preferenceKey = mController.getPreferenceKey();
-        doReturn(activityStartIntent).when(mController).getActivityStartIntent();
-        when(mPreference.getKey()).thenReturn(preferenceKey);
-        mController.handlePreferenceTreeClick(mPreference);
-
-        verify(mFragment).startActivityForResult(activityStartIntent,
-                REQUEST_CODE_ANGLE_ENABLED_APP);
-    }
-
-    @Test
-    public void updateState_foobarAppSelected_shouldUpdateSummaryWithAngleEnabledAppLabel() {
-        final String angleEnabledApp = "foobar";
-        final ContentResolver contentResolver = mContext.getContentResolver();
-        Settings.Global.putString(contentResolver, Settings.Global.ANGLE_ENABLED_APP,
-                angleEnabledApp);
-        mController.updateState(mPreference);
-
-        verify(mPreference).setSummary(
-                mContext.getString(R.string.angle_enabled_app_set, angleEnabledApp));
-    }
-
-    @Test
-    public void updateState_noAppSelected_shouldUpdateSummaryWithNoAppSelected() {
-        final String angleEnabledApp = null;
-        final ContentResolver contentResolver = mContext.getContentResolver();
-        Settings.Global.putString(contentResolver, Settings.Global.ANGLE_ENABLED_APP,
-                angleEnabledApp);
-        mController.updateState(mPreference);
-
-        verify(mPreference).setSummary(
-            mContext.getString(R.string.angle_enabled_app_not_set));
-    }
-
-    @Test
-    public void onActivityResult_foobarAppSelected_shouldUpdateSummaryWithAngleEnabledLabel() {
-        Intent activityResultIntent = new Intent(mContext, AppPicker.class);
-        final String appLabel = "foobar";
-        activityResultIntent.setAction(appLabel);
-        final boolean result = mController
-            .onActivityResult(REQUEST_CODE_ANGLE_ENABLED_APP, Activity.RESULT_OK,
-                    activityResultIntent);
-
-        assertThat(result).isTrue();
-        verify(mPreference).setSummary(
-                mContext.getString(R.string.angle_enabled_app_set, appLabel));
-    }
-
-    @Test
-    public void onActivityResult_badRequestCode_shouldReturnFalse() {
-        assertThat(mController.onActivityResult(
-                -1 /* requestCode */, -1 /* resultCode */, null /* intent */)).isFalse();
-    }
-
-    @Test
-    public void onDeveloperOptionsSwitchDisabled_shouldDisablePreference() {
-        mController.onDeveloperOptionsSwitchDisabled();
-
-        assertThat(mPreference.isEnabled()).isFalse();
-        verify(mPreference).setSummary(
-                mContext.getString(R.string.angle_enabled_app_not_set));
-    }
-}
diff --git a/tests/robotests/src/com/android/settings/development/DevelopmentSettingsDashboardFragmentTest.java b/tests/robotests/src/com/android/settings/development/DevelopmentSettingsDashboardFragmentTest.java
index d2c9b65..5eb21bd 100644
--- a/tests/robotests/src/com/android/settings/development/DevelopmentSettingsDashboardFragmentTest.java
+++ b/tests/robotests/src/com/android/settings/development/DevelopmentSettingsDashboardFragmentTest.java
@@ -28,10 +28,15 @@
 import android.provider.SearchIndexableResource;
 import android.provider.Settings;
 
+import androidx.appcompat.app.AlertDialog;
+import androidx.fragment.app.FragmentActivity;
+
 import com.android.internal.logging.nano.MetricsProto;
 import com.android.settings.R;
 import com.android.settings.testutils.SettingsRobolectricTestRunner;
 import com.android.settings.testutils.shadow.SettingsShadowResources;
+import com.android.settings.testutils.shadow.SettingsShadowResourcesImpl;
+import com.android.settings.testutils.shadow.ShadowAlertDialogCompat;
 import com.android.settings.testutils.shadow.ShadowUserManager;
 import com.android.settings.widget.SwitchBar;
 import com.android.settings.widget.ToggleSwitch;
@@ -47,12 +52,14 @@
 import org.robolectric.annotation.Config;
 import org.robolectric.annotation.Implementation;
 import org.robolectric.annotation.Implements;
+import org.robolectric.shadows.androidx.fragment.FragmentController;
 import org.robolectric.util.ReflectionHelpers;
 
 import java.util.List;
 
 @RunWith(SettingsRobolectricTestRunner.class)
-@Config(shadows = ShadowUserManager.class)
+@Config(shadows = {ShadowUserManager.class, ShadowAlertDialogCompat.class,
+        SettingsShadowResourcesImpl.class})
 public class DevelopmentSettingsDashboardFragmentTest {
 
     private ToggleSwitch mSwitch;
@@ -179,6 +186,29 @@
     }
 
     @Test
+    @Config(shadows = ShadowDisableDevSettingsDialogFragment.class)
+    public void onSwitchChanged_turnOff_andOffloadIsNotDefaultValue_shouldShowWarningDialog() {
+        final BluetoothA2dpHwOffloadPreferenceController controller =
+                mock(BluetoothA2dpHwOffloadPreferenceController.class);
+        when(mDashboard.getContext()).thenReturn(mContext);
+        when(mDashboard.getDevelopmentOptionsController(
+                BluetoothA2dpHwOffloadPreferenceController.class)).thenReturn(controller);
+        when(controller.isDefaultValue()).thenReturn(false);
+        Settings.Global.putInt(mContext.getContentResolver(),
+                Settings.Global.DEVELOPMENT_SETTINGS_ENABLED, 1);
+
+        mDashboard.onSwitchChanged(mSwitch, false /* isChecked */);
+
+        AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog();
+        assertThat(dialog).isNotNull();
+        ShadowAlertDialogCompat shadowDialog = ShadowAlertDialogCompat.shadowOf(dialog);
+        assertThat(shadowDialog.getTitle()).isEqualTo(
+                mContext.getString(R.string.bluetooth_disable_a2dp_hw_offload_dialog_title));
+        assertThat(shadowDialog.getMessage()).isEqualTo(
+                mContext.getString(R.string.bluetooth_disable_a2dp_hw_offload_dialog_message));
+    }
+
+    @Test
     public void onOemUnlockDialogConfirmed_shouldCallControllerOemConfirmed() {
         final OemUnlockPreferenceController controller = mock(OemUnlockPreferenceController.class);
         doReturn(controller).when(mDashboard)
@@ -264,6 +294,18 @@
         }
     }
 
+    @Implements(DisableDevSettingsDialogFragment.class)
+    public static class ShadowDisableDevSettingsDialogFragment {
+
+        @Implementation
+        public static void show(DevelopmentSettingsDashboardFragment host) {
+            DisableDevSettingsDialogFragment mFragment =
+                    spy(DisableDevSettingsDialogFragment.newInstance());
+            FragmentController.setupFragment(mFragment, FragmentActivity.class,
+                    0 /* containerViewId */, null /* bundle */);
+        }
+    }
+
     @Implements(PictureColorModePreferenceController.class)
     public static class ShadowPictureColorModePreferenceController {
         @Implementation
diff --git a/tests/robotests/src/com/android/settings/homepage/contextualcards/ContextualCardFeatureProviderImplTest.java b/tests/robotests/src/com/android/settings/homepage/contextualcards/ContextualCardFeatureProviderImplTest.java
index 08631f7..b3f9411 100644
--- a/tests/robotests/src/com/android/settings/homepage/contextualcards/ContextualCardFeatureProviderImplTest.java
+++ b/tests/robotests/src/com/android/settings/homepage/contextualcards/ContextualCardFeatureProviderImplTest.java
@@ -16,13 +16,20 @@
 
 package com.android.settings.homepage.contextualcards;
 
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Matchers.any;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.verify;
 
 import android.content.Context;
 import android.content.Intent;
+import android.net.Uri;
+import android.os.UserHandle;
 
+import com.android.settings.intelligence.ContextualCardProto.ContextualCardList;
 import com.android.settings.testutils.SettingsRobolectricTestRunner;
 
 import org.junit.Before;
@@ -31,6 +38,9 @@
 import org.robolectric.RuntimeEnvironment;
 import org.robolectric.annotation.Config;
 
+import java.util.ArrayList;
+import java.util.List;
+
 @RunWith(SettingsRobolectricTestRunner.class)
 public class ContextualCardFeatureProviderImplTest {
 
@@ -48,7 +58,7 @@
         final Intent intent = new Intent();
         mImpl.sendBroadcast(mContext, intent);
 
-        verify(mContext, never()).sendBroadcast(intent);
+        verify(mContext, never()).sendBroadcastAsUser(intent, UserHandle.ALL);
     }
 
     @Test
@@ -57,6 +67,37 @@
         final Intent intent = new Intent();
         mImpl.sendBroadcast(mContext, intent);
 
-        verify(mContext).sendBroadcast(intent);
+        verify(mContext).sendBroadcastAsUser(intent, UserHandle.ALL);
+    }
+
+    @Test
+    @Config(qualifiers = "mcc999")
+    public void logContextualCardDisplay_hasAction_sendBroadcast() {
+        mImpl.logContextualCardDisplay(mContext, new ArrayList<>(), new ArrayList<>());
+
+        verify(mContext).sendBroadcastAsUser(any(Intent.class), any());
+    }
+
+    @Test
+    public void serialize_hasSizeTwo_returnSizeTwo() {
+        final List<ContextualCard> cards = new ArrayList<>();
+        cards.add(new ContextualCard.Builder()
+                .setName("name1")
+                .setSliceUri(Uri.parse("uri1"))
+                .build());
+        cards.add(new ContextualCard.Builder()
+                .setName("name2")
+                .setSliceUri(Uri.parse("uri2"))
+                .build());
+
+
+        final byte[] data = mImpl.serialize(cards);
+
+        try {
+            assertThat(ContextualCardList
+                    .parseFrom(data).getCardCount()).isEqualTo(cards.size());
+        } catch (Exception e) {
+            throw new RuntimeException(e.getMessage());
+        }
     }
 }
\ No newline at end of file
diff --git a/tests/robotests/src/com/android/settings/homepage/contextualcards/ContextualCardLoaderTest.java b/tests/robotests/src/com/android/settings/homepage/contextualcards/ContextualCardLoaderTest.java
index 4f50197..98943a0 100644
--- a/tests/robotests/src/com/android/settings/homepage/contextualcards/ContextualCardLoaderTest.java
+++ b/tests/robotests/src/com/android/settings/homepage/contextualcards/ContextualCardLoaderTest.java
@@ -162,7 +162,7 @@
         cards.add(new ContextualCard.Builder()
                 .setName("test_connected")
                 .setCardType(ContextualCard.CardType.SLICE)
-                .setSliceUri(CustomSliceRegistry.CONNECTED_DEVICE_SLICE_URI)
+                .setSliceUri(CustomSliceRegistry.BLUETOOTH_DEVICES_SLICE_URI)
                 .build());
         cards.add(new ContextualCard.Builder()
                 .setName("test_gesture")
diff --git a/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/BluetoothDevicesSliceTest.java b/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/BluetoothDevicesSliceTest.java
new file mode 100644
index 0000000..ac6557e
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/BluetoothDevicesSliceTest.java
@@ -0,0 +1,161 @@
+/*
+ * 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.homepage.contextualcards.slices;
+
+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.spy;
+import static org.mockito.Mockito.when;
+
+import android.app.PendingIntent;
+import android.content.Context;
+import android.content.Intent;
+import android.text.TextUtils;
+
+import androidx.core.graphics.drawable.IconCompat;
+import androidx.slice.Slice;
+import androidx.slice.SliceItem;
+import androidx.slice.SliceMetadata;
+import androidx.slice.SliceProvider;
+import androidx.slice.widget.SliceLiveData;
+
+import com.android.settings.R;
+import com.android.settings.testutils.SettingsRobolectricTestRunner;
+import com.android.settings.testutils.SliceTester;
+import com.android.settingslib.bluetooth.CachedBluetoothDevice;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RuntimeEnvironment;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@RunWith(SettingsRobolectricTestRunner.class)
+public class BluetoothDevicesSliceTest {
+
+    private static final String BLUETOOTH_MOCK_SUMMARY = "BluetoothSummary";
+    private static final String BLUETOOTH_MOCK_TITLE = "BluetoothTitle";
+
+    @Mock
+    private CachedBluetoothDevice mCachedBluetoothDevice;
+
+    private List<CachedBluetoothDevice> mBluetoothDeviceList;
+    private BluetoothDevicesSlice mBluetoothDevicesSlice;
+    private Context mContext;
+    private IconCompat mIcon;
+    private PendingIntent mDetailIntent;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        mContext = RuntimeEnvironment.application;
+
+        // Set-up specs for SliceMetadata.
+        SliceProvider.setSpecs(SliceLiveData.SUPPORTED_SPECS);
+
+        mBluetoothDevicesSlice = spy(new BluetoothDevicesSlice(mContext));
+
+        // Mock the icon and detail intent of Bluetooth.
+        mIcon = IconCompat.createWithResource(mContext, R.drawable.ic_settings_bluetooth);
+        mDetailIntent = PendingIntent.getActivity(mContext, 0, new Intent("test action"), 0);
+        doReturn(mIcon).when(mBluetoothDevicesSlice).getBluetoothDeviceIcon(any());
+        doReturn(mDetailIntent).when(mBluetoothDevicesSlice).getBluetoothDetailIntent(any());
+
+        // Initial Bluetooth device list.
+        mBluetoothDeviceList = new ArrayList<>();
+    }
+
+    @After
+    public void tearDown() {
+        if (!mBluetoothDeviceList.isEmpty()) {
+            mBluetoothDeviceList.clear();
+        }
+    }
+
+    @Test
+    public void getSlice_hasBluetoothDevices_shouldHaveBluetoothDevicesTitle() {
+        mockBluetoothDeviceList();
+        doReturn(mBluetoothDeviceList).when(mBluetoothDevicesSlice).getBluetoothDevices();
+
+        final Slice slice = mBluetoothDevicesSlice.getSlice();
+
+        final List<SliceItem> sliceItems = slice.getItems();
+        SliceTester.assertTitle(sliceItems, mContext.getString(R.string.bluetooth_devices));
+    }
+
+    @Test
+    public void getSlice_hasBluetoothDevices_shouldMatchBluetoothMockTitle() {
+        mockBluetoothDeviceList();
+        doReturn(mBluetoothDeviceList).when(mBluetoothDevicesSlice).getBluetoothDevices();
+
+        final Slice slice = mBluetoothDevicesSlice.getSlice();
+
+        final List<SliceItem> sliceItems = slice.getItems();
+        SliceTester.assertTitle(sliceItems, BLUETOOTH_MOCK_TITLE);
+    }
+
+    @Test
+    public void getSlice_hasBluetoothDevices_shouldHavePairNewDevice() {
+        mockBluetoothDeviceList();
+        doReturn(mBluetoothDeviceList).when(mBluetoothDevicesSlice).getBluetoothDevices();
+
+        final Slice slice = mBluetoothDevicesSlice.getSlice();
+
+        final List<SliceItem> sliceItems = slice.getItems();
+        SliceTester.assertTitle(sliceItems,
+                mContext.getString(R.string.bluetooth_pairing_pref_title));
+    }
+
+    @Test
+    public void getSlice_noBluetoothDevices_shouldHaveNoBluetoothDevicesTitle() {
+        doReturn(mBluetoothDeviceList).when(mBluetoothDevicesSlice).getBluetoothDevices();
+
+        final Slice slice = mBluetoothDevicesSlice.getSlice();
+
+        final List<SliceItem> sliceItems = slice.getItems();
+        SliceTester.assertTitle(sliceItems, mContext.getString(R.string.no_bluetooth_devices));
+    }
+
+    @Test
+    public void getSlice_noBluetoothDevices_shouldNotHavePairNewDevice() {
+        doReturn(mBluetoothDeviceList).when(mBluetoothDevicesSlice).getBluetoothDevices();
+
+        final Slice slice = mBluetoothDevicesSlice.getSlice();
+
+        final SliceMetadata metadata = SliceMetadata.from(mContext, slice);
+        assertThat(hasTitle(metadata,
+                mContext.getString(R.string.bluetooth_pairing_pref_title))).isFalse();
+    }
+
+    private void mockBluetoothDeviceList() {
+        doReturn(BLUETOOTH_MOCK_TITLE).when(mCachedBluetoothDevice).getName();
+        doReturn(BLUETOOTH_MOCK_SUMMARY).when(mCachedBluetoothDevice).getConnectionSummary();
+        mBluetoothDeviceList.add(mCachedBluetoothDevice);
+    }
+
+    private boolean hasTitle(SliceMetadata metadata, String title) {
+        final CharSequence sliceTitle = metadata.getTitle();
+        return TextUtils.equals(sliceTitle, title);
+    }
+}
\ No newline at end of file
diff --git a/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/ConnectedDeviceSliceTest.java b/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/ConnectedDeviceSliceTest.java
deleted file mode 100644
index 472d2ca..0000000
--- a/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/ConnectedDeviceSliceTest.java
+++ /dev/null
@@ -1,133 +0,0 @@
-/*
- * 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.homepage.contextualcards.slices;
-
-import static org.mockito.Matchers.any;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.when;
-
-import android.app.PendingIntent;
-import android.content.Context;
-import android.content.Intent;
-
-import androidx.core.graphics.drawable.IconCompat;
-import androidx.slice.Slice;
-import androidx.slice.SliceItem;
-import androidx.slice.SliceProvider;
-import androidx.slice.widget.SliceLiveData;
-
-import com.android.settings.R;
-import com.android.settings.testutils.SettingsRobolectricTestRunner;
-import com.android.settings.testutils.SliceTester;
-import com.android.settingslib.bluetooth.CachedBluetoothDevice;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-import org.robolectric.RuntimeEnvironment;
-
-import java.util.ArrayList;
-import java.util.List;
-
-@RunWith(SettingsRobolectricTestRunner.class)
-public class ConnectedDeviceSliceTest {
-
-    private static final String BLUETOOTH_SUMMARY = "BluetoothSummary";
-    private static final String BLUETOOTH_TITLE = "BluetoothTitle";
-
-    @Mock
-    private CachedBluetoothDevice mCachedBluetoothDevice;
-
-    private List<CachedBluetoothDevice> mBluetoothConnectedDeviceList;
-    private ConnectedDeviceSlice mConnectedDeviceSlice;
-    private Context mContext;
-    private IconCompat mIcon;
-    private PendingIntent mDetailIntent;
-
-    @Before
-    public void setUp() {
-        MockitoAnnotations.initMocks(this);
-        mContext = RuntimeEnvironment.application;
-
-        // Set-up specs for SliceMetadata.
-        SliceProvider.setSpecs(SliceLiveData.SUPPORTED_SPECS);
-
-        mConnectedDeviceSlice = spy(new ConnectedDeviceSlice(mContext));
-
-        // Mock the icon and detail intent of Bluetooth.
-        mIcon = IconCompat.createWithResource(mContext, R.drawable.ic_homepage_connected_device);
-        mDetailIntent = PendingIntent.getActivity(mContext, 0, new Intent("test action"), 0);
-        doReturn(mIcon).when(mConnectedDeviceSlice).getConnectedDeviceIcon(any());
-        doReturn(mDetailIntent).when(mConnectedDeviceSlice).getBluetoothDetailIntent(any());
-
-        // Initial Bluetooth connected device list.
-        mBluetoothConnectedDeviceList = new ArrayList<>();
-    }
-
-    @After
-    public void tearDown() {
-        if (!mBluetoothConnectedDeviceList.isEmpty()) {
-            mBluetoothConnectedDeviceList.clear();
-        }
-    }
-
-    @Test
-    public void getSlice_hasConnectedDevices_shouldHaveCorrectTitle() {
-        mockBluetoothDeviceList();
-        doReturn(mBluetoothConnectedDeviceList).when(
-                mConnectedDeviceSlice).getBluetoothConnectedDevices();
-
-        final Slice slice = mConnectedDeviceSlice.getSlice();
-
-        final List<SliceItem> sliceItems = slice.getItems();
-        SliceTester.assertTitle(sliceItems,
-                mContext.getString(R.string.bluetooth_connected_devices));
-    }
-
-    @Test
-    public void getSlice_hasConnectedDevices_shouldHaveCorrectContent() {
-        mockBluetoothDeviceList();
-        doReturn(mBluetoothConnectedDeviceList).when(
-                mConnectedDeviceSlice).getBluetoothConnectedDevices();
-
-        final Slice slice = mConnectedDeviceSlice.getSlice();
-
-        final List<SliceItem> sliceItems = slice.getItems();
-        SliceTester.assertTitle(sliceItems, BLUETOOTH_TITLE);
-    }
-
-    @Test
-    public void getSlice_noConnectedDevices_shouldHaveCorrectTitle() {
-        doReturn(mBluetoothConnectedDeviceList).when(
-                mConnectedDeviceSlice).getBluetoothConnectedDevices();
-
-        final Slice slice = mConnectedDeviceSlice.getSlice();
-
-        final List<SliceItem> sliceItems = slice.getItems();
-        SliceTester.assertTitle(sliceItems, mContext.getString(R.string.no_connected_devices));
-    }
-
-    private void mockBluetoothDeviceList() {
-        doReturn(BLUETOOTH_TITLE).when(mCachedBluetoothDevice).getName();
-        doReturn(BLUETOOTH_SUMMARY).when(mCachedBluetoothDevice).getConnectionSummary();
-        mBluetoothConnectedDeviceList.add(mCachedBluetoothDevice);
-    }
-}
\ No newline at end of file
diff --git a/tests/robotests/src/com/android/settings/location/LocationScanningPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/location/LocationScanningPreferenceControllerTest.java
index e25b226..994a8fd 100644
--- a/tests/robotests/src/com/android/settings/location/LocationScanningPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/location/LocationScanningPreferenceControllerTest.java
@@ -18,7 +18,11 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import android.content.Context;
+import android.provider.Settings;
+
 import com.android.settings.testutils.SettingsRobolectricTestRunner;
+import com.android.settings.R;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -28,22 +32,63 @@
 
 @RunWith(SettingsRobolectricTestRunner.class)
 public class LocationScanningPreferenceControllerTest {
+    private Context mContext;
+    private LocationScanningPreferenceController mController;
 
-  private LocationScanningPreferenceController mController;
+    @Before
+    public void setUp() {
+        mContext = RuntimeEnvironment.application;
+        mController = new LocationScanningPreferenceController(mContext);
+    }
 
-  @Before
-  public void setUp() {
-    mController = new LocationScanningPreferenceController(RuntimeEnvironment.application);
-  }
+    @Test
+    public void testLocationScanning_byDefault_shouldBeShown() {
+        assertThat(mController.isAvailable()).isTrue();
+    }
 
-  @Test
-  public void testLocationScanning_byDefault_shouldBeShown() {
-    assertThat(mController.isAvailable()).isTrue();
-  }
+    @Test
+    public void testLocationScanning_WifiOnBleOn() {
+        Settings.Global.putInt(mContext.getContentResolver(),
+                Settings.Global.WIFI_SCAN_ALWAYS_AVAILABLE, 1);
+        Settings.Global.putInt(mContext.getContentResolver(),
+                Settings.Global.BLE_SCAN_ALWAYS_AVAILABLE, 1);
+        assertThat(mController.getSummary()).isEqualTo(
+                mContext.getString(R.string.scanning_status_text_wifi_on_ble_on));
+    }
 
-  @Test
-  @Config(qualifiers = "mcc999")
-  public void testLocationScanning_ifDisabled_shouldNotBeShown() {
-    assertThat(mController.isAvailable()).isFalse();
-  }
+    @Test
+    public void testLocationScanning_WifiOnBleOff() {
+        Settings.Global.putInt(mContext.getContentResolver(),
+                Settings.Global.WIFI_SCAN_ALWAYS_AVAILABLE, 1);
+        Settings.Global.putInt(mContext.getContentResolver(),
+                Settings.Global.BLE_SCAN_ALWAYS_AVAILABLE, 0);
+        assertThat(mController.getSummary()).isEqualTo(
+                mContext.getString(R.string.scanning_status_text_wifi_on_ble_off));
+    }
+
+    @Test
+    public void testLocationScanning_WifiOffBleOn() {
+        Settings.Global.putInt(mContext.getContentResolver(),
+                Settings.Global.WIFI_SCAN_ALWAYS_AVAILABLE, 0);
+        Settings.Global.putInt(mContext.getContentResolver(),
+                Settings.Global.BLE_SCAN_ALWAYS_AVAILABLE, 1);
+        assertThat(mController.getSummary()).isEqualTo(
+                mContext.getString(R.string.scanning_status_text_wifi_off_ble_on));
+    }
+
+    @Test
+    public void testLocationScanning_WifiOffBleOff() {
+        Settings.Global.putInt(mContext.getContentResolver(),
+                Settings.Global.WIFI_SCAN_ALWAYS_AVAILABLE, 0);
+        Settings.Global.putInt(mContext.getContentResolver(),
+                Settings.Global.BLE_SCAN_ALWAYS_AVAILABLE, 0);
+        assertThat(mController.getSummary()).isEqualTo(
+                mContext.getString(R.string.scanning_status_text_wifi_off_ble_off));
+    }
+
+    @Test
+    @Config(qualifiers = "mcc999")
+    public void testLocationScanning_ifDisabled_shouldNotBeShown() {
+        assertThat(mController.isAvailable()).isFalse();
+    }
 }
\ No newline at end of file
diff --git a/tests/robotests/src/com/android/settings/network/SubscriptionUtilTest.java b/tests/robotests/src/com/android/settings/network/SubscriptionUtilTest.java
new file mode 100644
index 0000000..02e4024
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/network/SubscriptionUtilTest.java
@@ -0,0 +1,112 @@
+/*
+ * 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.network;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import android.telephony.SubscriptionInfo;
+import android.telephony.SubscriptionManager;
+
+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 java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+@RunWith(SettingsRobolectricTestRunner.class)
+public class SubscriptionUtilTest {
+    @Mock
+    private SubscriptionManager mManager;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+    }
+
+    @Test
+    public void getAvailableSubscriptions_nullInfoFromSubscriptionManager_nonNullResult() {
+        when(mManager.getAvailableSubscriptionInfoList()).thenReturn(null);
+        final List<SubscriptionInfo> subs = SubscriptionUtil.getAvailableSubscriptions(mManager);
+        assertThat(subs).isNotNull();
+        assertThat(subs).isEmpty();
+    }
+
+    @Test
+    public void getAvailableSubscriptions_oneSubscription_oneResult() {
+        final SubscriptionInfo info = mock(SubscriptionInfo.class);
+        when(info.getMncString()).thenReturn("fake1234");
+        when(mManager.getAvailableSubscriptionInfoList()).thenReturn(Arrays.asList(info));
+        final List<SubscriptionInfo> subs = SubscriptionUtil.getAvailableSubscriptions(mManager);
+        assertThat(subs).isNotNull();
+        assertThat(subs).hasSize(1);
+    }
+
+    @Test
+    public void getAvailableSubscriptions_twoSubscriptions_twoResults() {
+        final SubscriptionInfo info1 = mock(SubscriptionInfo.class);
+        final SubscriptionInfo info2 = mock(SubscriptionInfo.class);
+        when(info1.getMncString()).thenReturn("fake1234");
+        when(info2.getMncString()).thenReturn("fake5678");
+        when(mManager.getAvailableSubscriptionInfoList()).thenReturn(Arrays.asList(info1, info2));
+        final List<SubscriptionInfo> subs = SubscriptionUtil.getAvailableSubscriptions(mManager);
+        assertThat(subs).isNotNull();
+        assertThat(subs).hasSize(2);
+    }
+
+    @Test
+    public void getAvailableSubscriptions_oneSubWithHiddenNetworks_oneResult() {
+        final SubscriptionInfo info1 = mock(SubscriptionInfo.class);
+        final SubscriptionInfo info2 = mock(SubscriptionInfo.class);
+        final SubscriptionInfo info3 = mock(SubscriptionInfo.class);
+        when(info1.getSubscriptionId()).thenReturn(1);
+        when(info1.getMncString()).thenReturn("fake1234");
+        when(mManager.getAvailableSubscriptionInfoList()).thenReturn(
+                new ArrayList<>(Arrays.asList(info1, info2, info3)));
+        final List<SubscriptionInfo> subs = SubscriptionUtil.getAvailableSubscriptions(mManager);
+        assertThat(subs).isNotNull();
+        assertThat(subs).hasSize(1);
+        assertThat(subs.get(0).getSubscriptionId()).isEqualTo(1);
+    }
+
+    @Test
+    public void getAvailableSubscriptions_twoSubsWithHiddenNetworks_twoResults() {
+        final SubscriptionInfo info1 = mock(SubscriptionInfo.class);
+        final SubscriptionInfo info2 = mock(SubscriptionInfo.class);
+        final SubscriptionInfo info3 = mock(SubscriptionInfo.class);
+        final SubscriptionInfo info4 = mock(SubscriptionInfo.class);
+        when(info1.getSubscriptionId()).thenReturn(1);
+        when(info1.getMncString()).thenReturn("fake1234");
+        when(info4.getSubscriptionId()).thenReturn(4);
+        when(info4.getMncString()).thenReturn("fake5678");
+        when(mManager.getAvailableSubscriptionInfoList()).thenReturn(new ArrayList<>(
+                Arrays.asList(info1, info2, info3, info4)));
+        final List<SubscriptionInfo> subs = SubscriptionUtil.getAvailableSubscriptions(mManager);
+        assertThat(subs).isNotNull();
+        assertThat(subs).hasSize(2);
+        assertThat(subs.get(0).getSubscriptionId()).isEqualTo(1);
+        assertThat(subs.get(1).getSubscriptionId()).isEqualTo(4);
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/network/SubscriptionsChangeListenerTest.java b/tests/robotests/src/com/android/settings/network/SubscriptionsChangeListenerTest.java
new file mode 100644
index 0000000..88ea2ea
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/network/SubscriptionsChangeListenerTest.java
@@ -0,0 +1,129 @@
+/*
+ * 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.network;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.AdditionalMatchers.eq;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.BroadcastReceiver;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.database.ContentObserver;
+import android.net.Uri;
+import android.provider.Settings;
+import android.telephony.SubscriptionManager;
+
+import com.android.settings.network.SubscriptionsChangeListener.SubscriptionsChangeListenerClient;
+import com.android.settings.testutils.SettingsRobolectricTestRunner;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RuntimeEnvironment;
+
+@RunWith(SettingsRobolectricTestRunner.class)
+public class SubscriptionsChangeListenerTest {
+
+    @Mock
+    private SubscriptionsChangeListenerClient mClient;
+    @Mock
+    private SubscriptionManager mSubscriptionManager;
+
+    private Context mContext;
+    private SubscriptionsChangeListener mListener;
+    private Uri mAirplaneModeUri;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        mContext = spy(RuntimeEnvironment.application);
+        when(mContext.getSystemService(SubscriptionManager.class)).thenReturn(mSubscriptionManager);
+
+        mAirplaneModeUri = Settings.Global.getUriFor(Settings.Global.AIRPLANE_MODE_ON);
+    }
+
+    private void initListener(boolean alsoStart) {
+        mListener = new SubscriptionsChangeListener(mContext, mClient);
+        if (alsoStart) {
+            mListener.start();
+        }
+    }
+
+    @Test
+    public void whenStartNotCalled_noListeningWasSetup() {
+        final ContentResolver contentResolver = mock(ContentResolver.class);
+        when(mContext.getContentResolver()).thenReturn(contentResolver);
+        initListener(false);
+        verify(contentResolver, never()).registerContentObserver(any(Uri.class), anyBoolean(),
+                any(ContentObserver.class));
+        verify(mSubscriptionManager, never()).addOnSubscriptionsChangedListener(any());
+        verify(mContext, never()).registerReceiver(any(), any());
+    }
+
+    @Test
+    public void onSubscriptionsChangedEvent_subscriptionManagerFires_eventDeliveredToUs() {
+        initListener(true);
+        final ArgumentCaptor<SubscriptionManager.OnSubscriptionsChangedListener> captor =
+                ArgumentCaptor.forClass(SubscriptionManager.OnSubscriptionsChangedListener.class);
+        verify(mSubscriptionManager).addOnSubscriptionsChangedListener(captor.capture());
+        captor.getValue().onSubscriptionsChanged();
+        verify(mClient).onSubscriptionsChanged();
+    }
+
+    @Test
+    public void onSubscriptionsChangedEvent_radioTechnologyChangedBroadcast_eventDeliveredToUs() {
+        initListener(true);
+        final ArgumentCaptor<BroadcastReceiver> broadcastReceiverCaptor =
+                ArgumentCaptor.forClass(BroadcastReceiver.class);
+        verify(mContext).registerReceiver(broadcastReceiverCaptor.capture(), any());
+        broadcastReceiverCaptor.getValue().onReceive(mContext, null);
+        verify(mClient).onSubscriptionsChanged();
+    }
+
+    @Test
+    public void onAirplaneModeChangedEvent_becameTrue_eventFires() {
+        initListener(true);
+        Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.AIRPLANE_MODE_ON, 1);
+        mListener.onChange(false, mAirplaneModeUri);
+        verify(mClient).onAirplaneModeChanged(true);
+        assertThat(mListener.isAirplaneModeOn()).isTrue();
+    }
+
+    @Test
+    public void onAirplaneModeChangedEvent_becameFalse_eventFires() {
+        initListener(true);
+        Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.AIRPLANE_MODE_ON, 0);
+        mListener.onChange(false, mAirplaneModeUri);
+        verify(mClient).onAirplaneModeChanged(false);
+        assertThat(mListener.isAirplaneModeOn()).isFalse();
+    }
+
+}
diff --git a/tests/robotests/src/com/android/settings/testutils/SliceTester.java b/tests/robotests/src/com/android/settings/testutils/SliceTester.java
index 26eeb71..c0ffdcd 100644
--- a/tests/robotests/src/com/android/settings/testutils/SliceTester.java
+++ b/tests/robotests/src/com/android/settings/testutils/SliceTester.java
@@ -236,6 +236,7 @@
         assertKeywords(metadata, sliceData);
     }
 
+    // TODO(b/120592507): Clean up method of SliceTester
     public static void assertTitle(List<SliceItem> sliceItems, String title) {
         boolean hasTitle = false;
         for (SliceItem item : sliceItems) {
@@ -255,6 +256,7 @@
         assertThat(hasTitle).isTrue();
     }
 
+    // TODO(b/120592507): Clean up method of SliceTester
     private static void assertKeywords(SliceMetadata metadata, SliceData data) {
         final List<String> keywords = metadata.getSliceKeywords();
         final Set<String> expectedKeywords = Arrays.stream(data.getKeywords().split(","))
diff --git a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowRuntimePermissionPresenter.java b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowRuntimePermissionPresenter.java
index f11d9e8..e0576b2 100644
--- a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowRuntimePermissionPresenter.java
+++ b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowRuntimePermissionPresenter.java
@@ -17,7 +17,7 @@
 package com.android.settings.testutils.shadow;
 
 import android.content.Context;
-import android.content.pm.permission.RuntimePermissionPresenter;
+import android.permission.RuntimePermissionPresenter;
 
 import org.robolectric.annotation.Implementation;
 import org.robolectric.annotation.Implements;
diff --git a/tests/robotests/src/com/android/settings/wifi/CellularFallbackPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/wifi/CellularFallbackPreferenceControllerTest.java
index e12053c..91598c0 100644
--- a/tests/robotests/src/com/android/settings/wifi/CellularFallbackPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/wifi/CellularFallbackPreferenceControllerTest.java
@@ -33,6 +33,7 @@
 
 @RunWith(SettingsRobolectricTestRunner.class)
 public class CellularFallbackPreferenceControllerTest {
+    private static final String KEY_CELLULAR_FALLBACK = "wifi_cellular_data_fallback";
 
     @Mock(answer = Answers.RETURNS_DEEP_STUBS)
     private Context mContext;
@@ -42,7 +43,7 @@
     @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
-        mController = new CellularFallbackPreferenceController(mContext);
+        mController = new CellularFallbackPreferenceController(mContext, KEY_CELLULAR_FALLBACK);
     }
 
     @Test
diff --git a/tests/robotests/src/com/android/settings/wifi/WifiSliceTest.java b/tests/robotests/src/com/android/settings/wifi/WifiSliceTest.java
index 5ac25ed..cdd1664 100644
--- a/tests/robotests/src/com/android/settings/wifi/WifiSliceTest.java
+++ b/tests/robotests/src/com/android/settings/wifi/WifiSliceTest.java
@@ -53,14 +53,17 @@
 
     private Context mContext;
 
+    private WifiManager mWifiManager;
     private WifiSlice mWifiSlice;
 
     @Before
     public void setUp() {
         mContext = RuntimeEnvironment.application;
+        mWifiManager = mContext.getSystemService(WifiManager.class);
 
         // Set-up specs for SliceMetadata.
         SliceProvider.setSpecs(SliceLiveData.SUPPORTED_SPECS);
+        mWifiManager.setWifiEnabled(true);
 
         mWifiSlice = new WifiSlice(mContext);
     }
@@ -83,13 +86,30 @@
     }
 
     @Test
-    public void getWifiSlice_noAp_shouldReturnPlaceholder() {
+    public void getWifiSlice_wifiOff_shouldReturnSingleRow() {
+        mWifiManager.setWifiEnabled(false);
+
         final Slice wifiSlice = mWifiSlice.getSlice();
 
-        int rows = SliceQuery.findAll(wifiSlice, FORMAT_SLICE, HINT_LIST_ITEM,
+        final int rows = SliceQuery.findAll(wifiSlice, FORMAT_SLICE, HINT_LIST_ITEM,
                 null /* nonHints */).size();
+
+        // Title row
+        assertThat(rows).isEqualTo(1);
+    }
+
+    @Test
+    public void getWifiSlice_noAp_shouldReturnLoadingRow() {
+        final Slice wifiSlice = mWifiSlice.getSlice();
+
+        final int rows = SliceQuery.findAll(wifiSlice, FORMAT_SLICE, HINT_LIST_ITEM,
+                null /* nonHints */).size();
+        final List<SliceItem> sliceItems = wifiSlice.getItems();
+
         // All AP rows + title row
         assertThat(rows).isEqualTo(DEFAULT_EXPANDED_ROW_COUNT + 1);
+        // Has scanning text
+        SliceTester.assertTitle(sliceItems, mContext.getString(R.string.wifi_empty_list_wifi_on));
     }
 
     @Test
diff --git a/tests/robotests/src/com/android/settings/wifi/details/WifiDetailPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/wifi/details/WifiDetailPreferenceControllerTest.java
index 39215c1..eab9e51 100644
--- a/tests/robotests/src/com/android/settings/wifi/details/WifiDetailPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/wifi/details/WifiDetailPreferenceControllerTest.java
@@ -865,6 +865,12 @@
         when(pref.setButton2Visible(anyBoolean())).thenReturn(pref);
         when(pref.setButton2OnClickListener(any(View.OnClickListener.class))).thenReturn(pref);
 
+        when(pref.setButton3Text(anyInt())).thenReturn(pref);
+        when(pref.setButton3Icon(anyInt())).thenReturn(pref);
+        when(pref.setButton3Enabled(anyBoolean())).thenReturn(pref);
+        when(pref.setButton3Visible(anyBoolean())).thenReturn(pref);
+        when(pref.setButton3OnClickListener(any(View.OnClickListener.class))).thenReturn(pref);
+
         return pref;
     }
 }