Merge "Change intent filter string of NetworkRequestDialogActivity"
diff --git a/res/layout-land/fingerprint_enroll_enrolling.xml b/res/layout-land/fingerprint_enroll_enrolling.xml
index f96bdde..ba2c420 100644
--- a/res/layout-land/fingerprint_enroll_enrolling.xml
+++ b/res/layout-land/fingerprint_enroll_enrolling.xml
@@ -92,13 +92,6 @@
                     android:layout_height="0dp"
                     android:layout_weight="1" />
 
-                <Button
-                    android:id="@+id/skip_button"
-                    style="@style/SudGlifButton.Secondary"
-                    android:layout_width="wrap_content"
-                    android:layout_height="wrap_content"
-                    android:text="@string/security_settings_fingerprint_enroll_enrolling_skip" />
-
             </LinearLayout>
 
             <LinearLayout
diff --git a/res/layout-land/fingerprint_enroll_find_sensor.xml b/res/layout-land/fingerprint_enroll_find_sensor.xml
index f4c97a3..28d982e 100644
--- a/res/layout-land/fingerprint_enroll_find_sensor.xml
+++ b/res/layout-land/fingerprint_enroll_find_sensor.xml
@@ -83,14 +83,6 @@
                         android:layout_height="0dp"
                         android:layout_weight="1" />
 
-                    <Button
-                        style="@style/SetupWizardButton.Negative"
-                        android:id="@+id/skip_button"
-                        android:layout_width="wrap_content"
-                        android:layout_height="wrap_content"
-                        android:layout_marginTop="8dp"
-                        android:text="@string/skip_label" />
-
                 </LinearLayout>
 
             </ScrollView>
diff --git a/res/layout/slice_preference_layout.xml b/res/layout/slice_preference_layout.xml
index 4cea9c0..ae58901 100644
--- a/res/layout/slice_preference_layout.xml
+++ b/res/layout/slice_preference_layout.xml
@@ -25,5 +25,5 @@
     <androidx.slice.widget.SliceView
         android:id="@+id/slice_view"
         android:layout_width="match_parent"
-        android:layout_height="wrap_content"/>
+        android:layout_height="@dimen/slice_preference_group_height"/>
 </FrameLayout>
diff --git a/res/values/attrs.xml b/res/values/attrs.xml
index a88d6f6..b2d5468 100644
--- a/res/values/attrs.xml
+++ b/res/values/attrs.xml
@@ -72,6 +72,8 @@
         <attr name="platform_slice" format="boolean" />
         <!-- Whether or not dynamic summary text from PreferenceController is allowed when creating slice object, by default it's false. -->
         <attr name="allowDynamicSummaryInSlice" format="boolean" />
+        <!-- customized subtitle if it's an unavailable slice -->
+        <attr name="unavailableSliceSubtitle" format="string" />
     </declare-styleable>
 
     <declare-styleable name="PreferenceScreen">
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 1a3d6ff..8b535e3 100755
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -370,4 +370,6 @@
     <dimen name="qrcode_size">264dp</dimen>
     <dimen name="qrcode_preview_size">360dp</dimen>
 
+    <!-- Height for slice preference, which contains 6 items at most -->
+    <dimen name="slice_preference_group_height">360dp</dimen>
 </resources>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index d1c5dfb..bf0e8a5 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -927,10 +927,12 @@
     <string name="security_settings_face_settings_require_attention">Eyes open to unlock</string>
     <!-- Text shown on the details of a toggle which disables/enables face authentication, depending if the user's eyes are open. [CHAR LIMIT=70] -->
     <string name="security_settings_face_settings_require_attention_details">When using face authentication, your eyes must be open</string>
+    <!-- When authenticating in apps, always require confirmation (e.g. confirm button) after a face is authenticated. [CHAR LIMIT=50] -->
+    <string name="security_settings_face_settings_require_confirmation">Always require confirmation</string>
+    <!-- When authenticating in apps, always require confirmation (e.g. confirm button) after a face is authenticated. [CHAR LIMIT=70] -->
+    <string name="security_settings_face_settings_require_confirmation_details">When authenticating in apps, always require confirmation</string>
     <!-- Button text in face settings which removes the user's faces from the device [CHAR LIMIT=20] -->
     <string name="security_settings_face_settings_remove_face_data">Remove face data</string>
-    <!-- Text shown in face settings allowing the user to update/improve the enrolled face. This brings the user back to the enrollment flow. [CHAR LIMIT=30] -->
-    <string name="security_settings_face_settings_improve_face">Improve your face data</string>
     <!-- Text shown in face settings explaining what your face can be used for. [CHAR LIMIT=NONE] -->
     <string name="security_settings_face_settings_footer">Your face can be used to unlock your device and access apps.
         <annotation id="url">Learn more</annotation></string>
@@ -4689,7 +4691,9 @@
     <!-- Title for accessibility preference screen for configuring vibrations. -->
     <string name="accessibility_vibration_settings_title">Vibration</string>
     <!-- Title for accessibility preference for configuring notification vibrations. -->
-    <string name="accessibility_notification_vibration_title">Ring &amp; notification vibration</string>
+    <string name="accessibility_notification_vibration_title">Notification vibration</string>
+    <!-- Title for accessibility preference for configuring ring vibrations. [CHAR LIMIT=NONE] -->
+    <string name="accessibility_ring_vibration_title">Ring vibration</string>
     <!-- Title for accessibility preference for configuring touch feedback vibrations. -->
     <string name="accessibility_touch_vibration_title">Touch vibration</string>
     <!-- Used in the acessibilty service settings to control turning on/off the service entirely -->
@@ -4759,8 +4763,8 @@
         <item quantity="other">Very long delay (<xliff:g id="click_delay_label" example="200">%1$d</xliff:g> ms)</item>
     </plurals>
 
-    <!-- Summary for vibration settings preference when notification vibration and haptic feedback intensity are set. [CHAR LIMIT=32] -->
-    <string name="accessibility_vibration_summary">Ring <xliff:g id="summary_ring" example="Medium">%1$s</xliff:g>, touch <xliff:g id="summary_touch" example="High">%2$s</xliff:g></string>
+    <!-- Summary for vibration settings preference when notification vibration and haptic feedback intensity are set. [CHAR LIMIT=50] -->
+    <string name="accessibility_vibration_summary">Ring <xliff:g id="summary_ring" example="Medium">%1$s</xliff:g>, notification <xliff:g id="summary_notification" example="Low">%2$s</xliff:g>, touch <xliff:g id="summary_touch" example="High">%3$s</xliff:g></string>
 
     <!-- Summary for vibration settings preference when ring & notification are set to off-->
     <string name="accessibility_vibration_summary_off">Ring &amp; notification set to off</string>
@@ -7054,8 +7058,10 @@
     <!-- List of synonyms for touch vibration setting (where you get a haptic response for touching things on the screen), used to match in settings search [CHAR LIMIT=NONE] -->
     <string name="keywords_touch_vibration">haptics, vibrate, screen, sensitivity</string>
 
-    <!-- List of synonyms for ring and notification vibration setting (changes whether your phone vibrates when it rings), used to match in settings search [CHAR LIMIT=NONE] -->
-    <string name="keywords_ring_vibration">haptics, vibrate, phone, call, sensitivity</string>
+    <!-- List of synonyms for ring vibration setting (changes whether your phone vibrates when it rings), used to match in settings search [CHAR LIMIT=NONE] -->
+    <string name="keywords_ring_vibration">haptics, vibrate, phone, call, sensitivity, ring</string>
+    <!-- List of synonyms for notification vibration setting (changes whether your phone vibrates when it shows a notification), used to match in settings search [CHAR LIMIT=NONE] -->
+    <string name="keywords_notification_vibration">haptics, vibrate, sensitivity</string>
 
     <!-- NFC Wi-Fi pairing/setup strings-->
 
@@ -7141,7 +7147,7 @@
     <!-- Sound: Other sounds: Title for the option enabling touch sounds for screen locking sounds. [CHAR LIMIT=30] -->
     <string name="screen_locking_sounds_title">Screen locking sounds</string>
 
-    <!-- Sound: Other sounds: Title for the option enabling charging sounds and vibration. [CHAR LIMIT=30] -->
+    <!-- Sound: Other sounds: Title for the option enabling charging sounds and vibration. [CHAR LIMIT=50] -->
     <string name="charging_sounds_title">Charging sounds and vibration</string>
 
     <!-- Sound: Other sounds: Title for the option enabling docking sounds. [CHAR LIMIT=30] -->
@@ -7349,6 +7355,12 @@
     <!--  Do not disturb: Label for button that will turn off zen mode. [CHAR LIMIT=30] -->
     <string name="zen_mode_button_turn_off">Turn off now</string>
 
+    <!-- Setting title for controlling how caption text display in real time [CHAR LIMIT=40]-->
+    <string name="live_captions_title">Live Caption</string>
+
+    <!-- Setting summary for controlling how caption text display in real time [CHAR LIMIT=NONE]-->
+    <string name="live_captions_summary">Auto-convert on-device audio to captions</string>
+
     <!-- [CHAR LIMIT=110] Zen mode settings footer: Footer showing end time of DND -->
     <string name="zen_mode_settings_dnd_manual_end_time">Do Not Disturb is on until <xliff:g id="formatted_time" example="7:00 AM">%s</xliff:g></string>
 
@@ -10063,23 +10075,23 @@
     <!-- UI debug setting: ANGLE enabled app has been set [CHAR LIMIT=NONE] -->
     <string name="angle_enabled_app_set">ANGLE enabled application: <xliff:g id="app_name" example="com.company.app">%1$s</xliff:g></string>
 
-    <!-- Title for Game Update Packages dashboard where developers can configure apps to use GUP or not [CHAR LIMIT=50] -->
-    <string name="gup_dashboard_title">Game Update Packages Preferences</string>
-    <!-- Summary for Game Update Packages dashboard [CHAR LIMIT=50] -->
-    <string name="gup_dashboard_summary">Modify Game Update Packages settings</string>
-    <!-- Title for Game Update Packages preference [CHAR LIMIT=50] -->
+    <!-- Title for Game Update Package dashboard where developers can configure apps to use GUP or not [CHAR LIMIT=50] -->
+    <string name="gup_dashboard_title">Game Update Package Preferences</string>
+    <!-- Summary for Game Update Package dashboard [CHAR LIMIT=50] -->
+    <string name="gup_dashboard_summary">Modify Game Update Package settings</string>
+    <!-- Title for Game Update Package preference [CHAR LIMIT=50] -->
     <string name="gup_app_preference_title">Select Graphics Driver</string>
-    <!-- The default value for Game Update Packages preference [CHAR LIMIT=50] -->
+    <!-- The default value for Game Update Package preference [CHAR LIMIT=50] -->
     <string name="gup_app_preference_default">Default</string>
-    <!-- The gup value for Game Update Packages preference [CHAR LIMIT=50] -->
-    <string name="gup_app_preference_gup">Game Update Packages</string>
-    <!-- The native value for Game Update Packages preference [CHAR LIMIT=50] -->
-    <string name="gup_app_preference_native">Native Graphics Driver</string>
-    <!-- All the values for Game Update Packages preference [CHAR LIMIT=50] -->
+    <!-- The gup value for Game Update Package preference [CHAR LIMIT=50] -->
+    <string name="gup_app_preference_gup">Game Update Package</string>
+    <!-- The system value for Game Update Package preference [CHAR LIMIT=50] -->
+    <string name="gup_app_preference_system">System Graphics Driver</string>
+    <!-- All the values for Game Update Package preference [CHAR LIMIT=50] -->
     <string-array name="gup_app_preference_values">
         <item>@string/gup_app_preference_default</item>
         <item>@string/gup_app_preference_gup</item>
-        <item>@string/gup_app_preference_native</item>
+        <item>@string/gup_app_preference_system</item>
     </string-array>
 
     <!-- Slices Strings -->
@@ -10198,12 +10210,6 @@
     <!-- Homepage bottom menu. Title for display personalized Settings [CHAR LIMIT=30] -->
     <string name="homepage_personal_settings">Suggestions</string>
 
-    <!-- Setting Checkbox title whether to enable CBRS data. [CHAR LIMIT=40] -->
-    <string name="cbrs_data_switch">CBRS Data</string>
-
-    <!-- Title of implications of enabling CBRS Data -->
-    <string name="cbrs_data_switch_summary">CBRS Data</string>
-
     <!-- Available networks screen, name of button when user wants to select network manually [CHAR LIMIT=60] -->
     <string name="choose_network_title">Choose network</string>
     <!-- Available networks screen, text when no networks connected [CHAR LIMIT=60] -->
diff --git a/res/xml/accessibility_ring_vibration_settings.xml b/res/xml/accessibility_ring_vibration_settings.xml
new file mode 100644
index 0000000..078f76c
--- /dev/null
+++ b/res/xml/accessibility_ring_vibration_settings.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  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.
+  -->
+
+<PreferenceScreen
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:title="@string/accessibility_ring_vibration_title" />
diff --git a/res/xml/accessibility_settings.xml b/res/xml/accessibility_settings.xml
index cc07ce1..b3e1704 100644
--- a/res/xml/accessibility_settings.xml
+++ b/res/xml/accessibility_settings.xml
@@ -124,6 +124,12 @@
             android:key="audio_and_captions_category"
             android:title="@string/audio_and_captions_category_title">
 
+        <Preference
+            android:key="live_caption"
+            android:title="@string/live_captions_title"
+            android:summary="@string/live_captions_summary"
+            settings:controller="com.android.settings.accessibility.LiveCaptionPreferenceController"/>
+
         <SwitchPreference
                 android:key="toggle_master_mono"
                 android:title="@string/accessibility_toggle_master_mono_title"
diff --git a/res/xml/accessibility_vibration_settings.xml b/res/xml/accessibility_vibration_settings.xml
index b2b3596..dc2b16a 100644
--- a/res/xml/accessibility_vibration_settings.xml
+++ b/res/xml/accessibility_vibration_settings.xml
@@ -22,10 +22,17 @@
     android:title="@string/accessibility_vibration_settings_title">
 
     <Preference
+        android:fragment="com.android.settings.accessibility.RingVibrationPreferenceFragment"
+        android:key="ring_vibration_preference_screen"
+        android:title="@string/accessibility_ring_vibration_title"
+        settings:keywords="@string/keywords_ring_vibration"
+        app:controller="com.android.settings.accessibility.RingVibrationIntensityPreferenceController" />
+
+    <Preference
         android:fragment="com.android.settings.accessibility.NotificationVibrationPreferenceFragment"
         android:key="notification_vibration_preference_screen"
         android:title="@string/accessibility_notification_vibration_title"
-        settings:keywords="@string/keywords_ring_vibration"
+        settings:keywords="@string/keywords_notification_vibration"
         app:controller="com.android.settings.accessibility.NotificationVibrationIntensityPreferenceController" />
 
     <Preference
diff --git a/res/xml/bluetooth_device_details_fragment.xml b/res/xml/bluetooth_device_details_fragment.xml
index 90895f2..cf9fbf9 100644
--- a/res/xml/bluetooth_device_details_fragment.xml
+++ b/res/xml/bluetooth_device_details_fragment.xml
@@ -31,7 +31,7 @@
 
     <com.android.settings.slices.SlicePreference
         android:key="bt_device_slice"
-        settings:controller="com.android.settings.slices.SlicePreferenceController"
+        settings:controller="com.android.settings.slices.BlockingSlicePrefController"
         settings:allowDividerBelow="true"
         settings:allowDividerAbove="true"/>
 
diff --git a/res/xml/development_settings.xml b/res/xml/development_settings.xml
index a5e26f6..4cdab33 100644
--- a/res/xml/development_settings.xml
+++ b/res/xml/development_settings.xml
@@ -241,11 +241,6 @@
             android:title="@string/usb_default_label"/>
 
         <SwitchPreference
-            android:key="cbrs_data_switch"
-            android:title="@string/cbrs_data_switch"
-            android:summary="@string/cbrs_data_switch" />
-
-        <SwitchPreference
             android:key="bluetooth_show_devices_without_names"
             android:title="@string/bluetooth_show_devices_without_names"
             android:summary="@string/bluetooth_show_devices_without_names_summary" />
diff --git a/res/xml/security_settings_face.xml b/res/xml/security_settings_face.xml
index c202a6c..f5dde8b 100644
--- a/res/xml/security_settings_face.xml
+++ b/res/xml/security_settings_face.xml
@@ -47,13 +47,16 @@
         <SwitchPreference
             android:key="security_settings_face_require_attention"
             android:title="@string/security_settings_face_settings_require_attention"
+            android:summary="@string/security_settings_face_settings_require_attention_details"
             app:keywords="@string/keywords_face_unlock"
             app:controller="com.android.settings.biometrics.face.FaceSettingsAttentionPreferenceController"/>
 
-        <Preference
-            android:key="security_settings_face_improve"
-            android:title="@string/security_settings_face_settings_improve_face">
-        </Preference>
+        <SwitchPreference
+            android:key="security_settings_face_require_confirmation"
+            android:title="@string/security_settings_face_settings_require_confirmation"
+            android:summary="@string/security_settings_face_settings_require_confirmation_details"
+            app:keywords="@string/keywords_face_unlock"
+            app:controller="com.android.settings.biometrics.face.FaceSettingsConfirmPreferenceController"/>
 
         <com.android.settingslib.widget.LayoutPreference
             android:key="security_settings_face_delete_faces_container"
diff --git a/src/com/android/settings/accessibility/AccessibilitySettings.java b/src/com/android/settings/accessibility/AccessibilitySettings.java
index 76be66d..6f6149f 100644
--- a/src/com/android/settings/accessibility/AccessibilitySettings.java
+++ b/src/com/android/settings/accessibility/AccessibilitySettings.java
@@ -91,7 +91,7 @@
     private static final String CATEGORY_EXPERIMENTAL = "experimental_category";
     private static final String CATEGORY_DOWNLOADED_SERVICES = "user_installed_services_category";
 
-    private static final String[] CATEGORIES = new String[] {
+    private static final String[] CATEGORIES = new String[]{
             CATEGORY_SCREEN_READER, CATEGORY_AUDIO_AND_CAPTIONS, CATEGORY_DISPLAY,
             CATEGORY_INTERACTION_CONTROL, CATEGORY_EXPERIMENTAL, CATEGORY_DOWNLOADED_SERVICES
     };
@@ -132,7 +132,8 @@
             "accessibility_content_timeout_preference_fragment";
     private static final String ACCESSIBILITY_CONTROL_TIMEOUT_PREFERENCE =
             "accessibility_control_timeout_preference_fragment";
-
+    private static final String LIVE_CAPTION_PREFERENCE_KEY =
+            "live_caption";
 
     // Extras passed to sub-fragments.
     static final String EXTRA_PREFERENCE_KEY = "preference_key";
@@ -232,9 +233,11 @@
     private Preference mDisplayDaltonizerPreferenceScreen;
     private Preference mHearingAidPreference;
     private Preference mVibrationPreferenceScreen;
+    private Preference mLiveCaptionPreference;
     private SwitchPreference mToggleInversionPreference;
     private ColorInversionPreferenceController mInversionPreferenceController;
     private AccessibilityHearingAidPreferenceController mHearingAidPreferenceController;
+    private LiveCaptionPreferenceController mLiveCaptionPreferenceController;
 
     private int mLongPressTimeoutDefault;
 
@@ -293,6 +296,9 @@
                 (context, HEARING_AID_PREFERENCE);
         mHearingAidPreferenceController.setFragmentManager(getFragmentManager());
         getLifecycle().addObserver(mHearingAidPreferenceController);
+
+        mLiveCaptionPreferenceController = new LiveCaptionPreferenceController(context,
+                LIVE_CAPTION_PREFERENCE_KEY);
     }
 
     @Override
@@ -481,6 +487,10 @@
         // Captioning.
         mCaptioningPreferenceScreen = findPreference(CAPTIONING_PREFERENCE_SCREEN);
 
+        // Live caption
+        mLiveCaptionPreference = findPreference(LIVE_CAPTION_PREFERENCE_KEY);
+        mLiveCaptionPreferenceController.displayPreference(getPreferenceScreen());
+
         // Display magnification.
         mDisplayMagnificationPreferenceScreen = findPreference(
                 DISPLAY_MAGNIFICATION_PREFERENCE_SCREEN);
@@ -716,6 +726,8 @@
 
         mHearingAidPreferenceController.updateState(mHearingAidPreference);
 
+        mLiveCaptionPreferenceController.updateState(mLiveCaptionPreference);
+
         updateFeatureSummary(Settings.Secure.ACCESSIBILITY_CAPTIONING_ENABLED,
                 mCaptioningPreferenceScreen);
         updateFeatureSummary(Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED,
@@ -736,7 +748,6 @@
     }
 
     void updateAccessibilityTimeoutSummary(ContentResolver resolver, Preference pref) {
-
         String[] timeoutSummarys = getResources().getStringArray(
                 R.array.accessibility_timeout_summaries);
         int[] timeoutValues = getResources().getIntArray(
@@ -805,20 +816,35 @@
         pref.setSummary(entries[index]);
     }
 
-    @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
+    @VisibleForTesting
     void updateVibrationSummary(Preference pref) {
         final Context context = getContext();
         final Vibrator vibrator = context.getSystemService(Vibrator.class);
 
-        final int ringIntensity = Settings.System.getInt(context.getContentResolver(),
-                Settings.System.NOTIFICATION_VIBRATION_INTENSITY,
-                vibrator.getDefaultNotificationVibrationIntensity());
+        int ringIntensity = Settings.System.getInt(context.getContentResolver(),
+                Settings.System.RING_VIBRATION_INTENSITY,
+                vibrator.getDefaultRingVibrationIntensity());
+        if (Settings.System.getInt(context.getContentResolver(),
+                Settings.System.VIBRATE_WHEN_RINGING, 0) == 0) {
+            ringIntensity = Vibrator.VIBRATION_INTENSITY_OFF;
+        }
         CharSequence ringIntensityString =
                 VibrationIntensityPreferenceController.getIntensityString(context, ringIntensity);
 
-        final int touchIntensity = Settings.System.getInt(context.getContentResolver(),
+        int notificationIntensity = Settings.System.getInt(context.getContentResolver(),
+                Settings.System.NOTIFICATION_VIBRATION_INTENSITY,
+                vibrator.getDefaultNotificationVibrationIntensity());
+        CharSequence notificationIntensityString =
+                VibrationIntensityPreferenceController.getIntensityString(context,
+                        notificationIntensity);
+
+        int touchIntensity = Settings.System.getInt(context.getContentResolver(),
                 Settings.System.HAPTIC_FEEDBACK_INTENSITY,
                 vibrator.getDefaultHapticFeedbackIntensity());
+        if (Settings.System.getInt(context.getContentResolver(),
+                Settings.System.HAPTIC_FEEDBACK_ENABLED, 0) == 0) {
+            touchIntensity = Vibrator.VIBRATION_INTENSITY_OFF;
+        }
         CharSequence touchIntensityString =
                 VibrationIntensityPreferenceController.getIntensityString(context, touchIntensity);
 
@@ -826,12 +852,14 @@
             mVibrationPreferenceScreen = findPreference(VIBRATION_PREFERENCE_SCREEN);
         }
 
-        if (ringIntensity == touchIntensity) {
+        if (ringIntensity == touchIntensity && ringIntensity == notificationIntensity) {
             mVibrationPreferenceScreen.setSummary(ringIntensityString);
         } else {
             mVibrationPreferenceScreen.setSummary(
                     getString(R.string.accessibility_vibration_summary,
-                            ringIntensityString, touchIntensityString));
+                            ringIntensityString,
+                            notificationIntensityString,
+                            touchIntensityString));
         }
     }
 
diff --git a/src/com/android/settings/accessibility/HapticFeedbackIntensityPreferenceController.java b/src/com/android/settings/accessibility/HapticFeedbackIntensityPreferenceController.java
index 343ebb1..a2142a2 100644
--- a/src/com/android/settings/accessibility/HapticFeedbackIntensityPreferenceController.java
+++ b/src/com/android/settings/accessibility/HapticFeedbackIntensityPreferenceController.java
@@ -28,7 +28,8 @@
     static final String PREF_KEY = "touch_vibration_preference_screen";
 
     public HapticFeedbackIntensityPreferenceController(Context context) {
-        super(context, PREF_KEY, Settings.System.HAPTIC_FEEDBACK_INTENSITY);
+        super(context, PREF_KEY, Settings.System.HAPTIC_FEEDBACK_INTENSITY,
+                Settings.System.HAPTIC_FEEDBACK_ENABLED);
     }
 
     @Override
diff --git a/src/com/android/settings/accessibility/LiveCaptionPreferenceController.java b/src/com/android/settings/accessibility/LiveCaptionPreferenceController.java
new file mode 100644
index 0000000..94ee1c0
--- /dev/null
+++ b/src/com/android/settings/accessibility/LiveCaptionPreferenceController.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.accessibility;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+
+import androidx.annotation.VisibleForTesting;
+import androidx.preference.Preference;
+
+import com.android.settings.core.BasePreferenceController;
+
+import java.util.List;
+
+public class LiveCaptionPreferenceController extends BasePreferenceController {
+
+    @VisibleForTesting
+    static final Intent LIVE_CAPTION_INTENT = new Intent(
+            "com.android.settings.action.live_caption");
+
+    private final PackageManager mPackageManager;
+
+    public LiveCaptionPreferenceController(Context context, String preferenceKey) {
+        super(context, preferenceKey);
+        mPackageManager = context.getPackageManager();
+    }
+
+    @Override
+    public int getAvailabilityStatus() {
+        final List<ResolveInfo> resolved =
+                mPackageManager.queryIntentActivities(LIVE_CAPTION_INTENT, 0 /* flags */);
+        return resolved != null && !resolved.isEmpty()
+                ? AVAILABLE
+                : UNSUPPORTED_ON_DEVICE;
+    }
+
+    @Override
+    public void updateState(Preference preference) {
+        super.updateState(preference);
+        preference.setIntent(LIVE_CAPTION_INTENT);
+    }
+}
diff --git a/src/com/android/settings/accessibility/NotificationVibrationIntensityPreferenceController.java b/src/com/android/settings/accessibility/NotificationVibrationIntensityPreferenceController.java
index 4aff513..4ace4c6 100644
--- a/src/com/android/settings/accessibility/NotificationVibrationIntensityPreferenceController.java
+++ b/src/com/android/settings/accessibility/NotificationVibrationIntensityPreferenceController.java
@@ -28,7 +28,7 @@
     static final String PREF_KEY = "notification_vibration_preference_screen";
 
     public NotificationVibrationIntensityPreferenceController(Context context) {
-        super(context, PREF_KEY, Settings.System.NOTIFICATION_VIBRATION_INTENSITY);
+        super(context, PREF_KEY, Settings.System.NOTIFICATION_VIBRATION_INTENSITY, "");
     }
 
     @Override
diff --git a/src/com/android/settings/accessibility/NotificationVibrationPreferenceFragment.java b/src/com/android/settings/accessibility/NotificationVibrationPreferenceFragment.java
index 6804abc..ba7d51d 100644
--- a/src/com/android/settings/accessibility/NotificationVibrationPreferenceFragment.java
+++ b/src/com/android/settings/accessibility/NotificationVibrationPreferenceFragment.java
@@ -45,6 +45,11 @@
     }
 
     @Override
+    protected String getVibrationEnabledSetting() {
+        return "";
+    }
+
+    @Override
     protected int getPreviewVibrationAudioAttributesUsage() {
         return AudioAttributes.USAGE_NOTIFICATION;
     }
diff --git a/src/com/android/settings/accessibility/RingVibrationIntensityPreferenceController.java b/src/com/android/settings/accessibility/RingVibrationIntensityPreferenceController.java
new file mode 100644
index 0000000..818c414
--- /dev/null
+++ b/src/com/android/settings/accessibility/RingVibrationIntensityPreferenceController.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.accessibility;
+
+import android.content.Context;
+import android.provider.Settings;
+
+import androidx.annotation.VisibleForTesting;
+
+public class RingVibrationIntensityPreferenceController
+        extends VibrationIntensityPreferenceController {
+
+    @VisibleForTesting
+    static final String PREF_KEY = "ring_vibration_preference_screen";
+
+    public RingVibrationIntensityPreferenceController(Context context) {
+        super(context, PREF_KEY, Settings.System.RING_VIBRATION_INTENSITY,
+                Settings.System.VIBRATE_WHEN_RINGING);
+    }
+
+    @Override
+    public int getAvailabilityStatus() {
+        return AVAILABLE;
+    }
+
+    @Override
+    protected int getDefaultIntensity() {
+        return mVibrator.getDefaultRingVibrationIntensity();
+    }
+}
diff --git a/src/com/android/settings/accessibility/RingVibrationPreferenceFragment.java b/src/com/android/settings/accessibility/RingVibrationPreferenceFragment.java
new file mode 100644
index 0000000..df05231
--- /dev/null
+++ b/src/com/android/settings/accessibility/RingVibrationPreferenceFragment.java
@@ -0,0 +1,62 @@
+/*
+ * 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.accessibility;
+
+import android.media.AudioAttributes;
+import android.os.Vibrator;
+import android.provider.Settings;
+
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.settings.R;
+
+/**
+ * Fragment for picking accessibility shortcut service
+ */
+public class RingVibrationPreferenceFragment extends VibrationPreferenceFragment {
+    @Override
+    public int getMetricsCategory() {
+        return MetricsEvent.ACCESSIBILITY_VIBRATION_RING;
+    }
+
+    @Override
+    protected int getPreferenceScreenResId() {
+        return R.xml.accessibility_ring_vibration_settings;
+    }
+
+    /**
+     * Get the setting string of the vibration intensity setting this preference is dealing with.
+     */
+    @Override
+    protected String getVibrationIntensitySetting() {
+        return Settings.System.RING_VIBRATION_INTENSITY;
+    }
+
+    @Override
+    protected String getVibrationEnabledSetting() {
+        return Settings.System.VIBRATE_WHEN_RINGING;
+    }
+
+    @Override
+    protected int getPreviewVibrationAudioAttributesUsage() {
+        return AudioAttributes.USAGE_NOTIFICATION;
+    }
+
+    @Override
+    protected int getDefaultVibrationIntensity() {
+        Vibrator vibrator = getContext().getSystemService(Vibrator.class);
+        return vibrator.getDefaultRingVibrationIntensity();
+    }
+}
diff --git a/src/com/android/settings/accessibility/TouchVibrationPreferenceFragment.java b/src/com/android/settings/accessibility/TouchVibrationPreferenceFragment.java
index ba08a43..52fd069 100644
--- a/src/com/android/settings/accessibility/TouchVibrationPreferenceFragment.java
+++ b/src/com/android/settings/accessibility/TouchVibrationPreferenceFragment.java
@@ -45,6 +45,11 @@
     }
 
     @Override
+    protected String getVibrationEnabledSetting() {
+        return Settings.System.HAPTIC_FEEDBACK_ENABLED;
+    }
+
+    @Override
     protected int getDefaultVibrationIntensity() {
         Vibrator vibrator = getContext().getSystemService(Vibrator.class);
         return vibrator.getDefaultHapticFeedbackIntensity();
@@ -54,13 +59,4 @@
     protected int getPreviewVibrationAudioAttributesUsage() {
         return AudioAttributes.USAGE_ASSISTANCE_SONIFICATION;
     }
-
-    @Override
-    public void onVibrationIntensitySelected(int intensity) {
-        // We want to keep HAPTIC_FEEDBACK_ENABLED consistent with this setting since some
-        // applications check it directly before triggering their own haptic feedback.
-        final boolean hapticFeedbackEnabled = !(intensity == Vibrator.VIBRATION_INTENSITY_OFF);
-        Settings.System.putInt(getContext().getContentResolver(),
-                Settings.System.HAPTIC_FEEDBACK_ENABLED, hapticFeedbackEnabled ? 1 : 0);
-    }
 }
diff --git a/src/com/android/settings/accessibility/VibrationIntensityPreferenceController.java b/src/com/android/settings/accessibility/VibrationIntensityPreferenceController.java
index d9b1d79..e52f92d 100644
--- a/src/com/android/settings/accessibility/VibrationIntensityPreferenceController.java
+++ b/src/com/android/settings/accessibility/VibrationIntensityPreferenceController.java
@@ -39,14 +39,16 @@
     protected final Vibrator mVibrator;
     private final SettingObserver mSettingsContentObserver;
     private final String mSettingKey;
+    private final String mEnabledKey;
 
     private Preference mPreference;
 
     public VibrationIntensityPreferenceController(Context context, String prefkey,
-            String settingKey) {
+            String settingKey, String enabledKey) {
         super(context, prefkey);
         mVibrator = mContext.getSystemService(Vibrator.class);
         mSettingKey = settingKey;
+        mEnabledKey = enabledKey;
         mSettingsContentObserver = new SettingObserver(settingKey) {
             @Override
             public void onChange(boolean selfChange, Uri uri) {
@@ -78,7 +80,9 @@
     public CharSequence getSummary() {
         final int intensity = Settings.System.getInt(mContext.getContentResolver(),
                 mSettingKey, getDefaultIntensity());
-        return getIntensityString(mContext, intensity);
+        final boolean enabled = Settings.System.getInt(mContext.getContentResolver(),
+                mEnabledKey, 1) == 1;
+        return getIntensityString(mContext, enabled ? intensity : Vibrator.VIBRATION_INTENSITY_OFF);
    }
 
     public static CharSequence getIntensityString(Context context, int intensity) {
diff --git a/src/com/android/settings/accessibility/VibrationPreferenceFragment.java b/src/com/android/settings/accessibility/VibrationPreferenceFragment.java
index 1101611..648acad 100644
--- a/src/com/android/settings/accessibility/VibrationPreferenceFragment.java
+++ b/src/com/android/settings/accessibility/VibrationPreferenceFragment.java
@@ -26,6 +26,7 @@
 import android.os.VibrationEffect;
 import android.os.Vibrator;
 import android.provider.Settings;
+import android.text.TextUtils;
 import android.util.ArrayMap;
 import android.util.Log;
 
@@ -117,6 +118,11 @@
     protected abstract String getVibrationIntensitySetting();
 
     /**
+     * Get the setting string of the vibration enabledness setting this preference is dealing with.
+     */
+    protected abstract String getVibrationEnabledSetting();
+
+    /**
      * Get the default intensity for the desired setting.
      */
     protected abstract int getDefaultVibrationIntensity();
@@ -154,8 +160,13 @@
 
     @Override
     protected String getDefaultKey() {
-        final int vibrationIntensity = Settings.System.getInt(getContext().getContentResolver(),
+        int vibrationIntensity = Settings.System.getInt(getContext().getContentResolver(),
                 getVibrationIntensitySetting(), getDefaultVibrationIntensity());
+        final boolean vibrationEnabled = Settings.System.getInt(getContext().getContentResolver(),
+                getVibrationEnabledSetting(), 1) == 1;
+        if (!vibrationEnabled) {
+            vibrationIntensity = Vibrator.VIBRATION_INTENSITY_OFF;
+        }
         for (VibrationIntensityCandidateInfo candidate : mCandidates.values()) {
             final boolean matchesIntensity = candidate.getIntensity() == vibrationIntensity;
             final boolean matchesOn = candidate.getKey().equals(KEY_INTENSITY_ON)
@@ -174,8 +185,11 @@
             Log.e(TAG, "Tried to set unknown intensity (key=" + key + ")!");
             return false;
         }
-        Settings.System.putInt(getContext().getContentResolver(),
-                getVibrationIntensitySetting(), candidate.getIntensity());
+        if (candidate.getIntensity() != Vibrator.VIBRATION_INTENSITY_OFF ||
+                TextUtils.isEmpty(getVibrationEnabledSetting())) {
+            Settings.System.putInt(getContext().getContentResolver(),
+                    getVibrationIntensitySetting(), candidate.getIntensity());
+        }
         onVibrationIntensitySelected(candidate.getIntensity());
         return true;
     }
diff --git a/src/com/android/settings/biometrics/face/FaceSettings.java b/src/com/android/settings/biometrics/face/FaceSettings.java
index eb5e02b..84745d2 100644
--- a/src/com/android/settings/biometrics/face/FaceSettings.java
+++ b/src/com/android/settings/biometrics/face/FaceSettings.java
@@ -179,6 +179,7 @@
         controllers.add(new FaceSettingsAttentionPreferenceController(context));
         controllers.add(new FaceSettingsRemoveButtonPreferenceController(context));
         controllers.add(new FaceSettingsFooterPreferenceController(context));
+        controllers.add(new FaceSettingsConfirmPreferenceController(context));
         return controllers;
     }
 
diff --git a/src/com/android/settings/biometrics/face/FaceSettingsConfirmPreferenceController.java b/src/com/android/settings/biometrics/face/FaceSettingsConfirmPreferenceController.java
new file mode 100644
index 0000000..08740cf
--- /dev/null
+++ b/src/com/android/settings/biometrics/face/FaceSettingsConfirmPreferenceController.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.settings.biometrics.face;
+
+import static android.provider.Settings.Secure.FACE_UNLOCK_ALWAYS_REQUIRE_CONFIRMATION;
+
+import android.content.Context;
+import android.provider.Settings;
+
+import com.android.settings.core.TogglePreferenceController;
+
+/**
+ * Preference controller giving the user an option to always require confirmation.
+ */
+public class FaceSettingsConfirmPreferenceController extends TogglePreferenceController {
+
+    private static final String KEY = "security_settings_face_require_confirmation";
+
+    private static final int ON = 1;
+    private static final int OFF = 0;
+    private static final int DEFAULT = OFF;
+
+    public FaceSettingsConfirmPreferenceController(Context context) {
+        this(context, KEY);
+    }
+
+    public FaceSettingsConfirmPreferenceController(Context context,
+            String preferenceKey) {
+        super(context, preferenceKey);
+    }
+
+    @Override
+    public boolean isChecked() {
+        return Settings.Secure.getInt(mContext.getContentResolver(),
+                FACE_UNLOCK_ALWAYS_REQUIRE_CONFIRMATION, DEFAULT) == ON;
+    }
+
+    @Override
+    public boolean setChecked(boolean isChecked) {
+        return Settings.Secure.putInt(mContext.getContentResolver(),
+                FACE_UNLOCK_ALWAYS_REQUIRE_CONFIRMATION, isChecked ? ON : OFF);
+    }
+
+    @Override
+    public int getAvailabilityStatus() {
+        return AVAILABLE;
+    }
+}
diff --git a/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragment.java b/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragment.java
index 6ec419b..43de5a4 100644
--- a/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragment.java
+++ b/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragment.java
@@ -30,7 +30,7 @@
 import com.android.settings.core.FeatureFlags;
 import com.android.settings.dashboard.RestrictedDashboardFragment;
 import com.android.settings.overlay.FeatureFactory;
-import com.android.settings.slices.SlicePreferenceController;
+import com.android.settings.slices.BlockingSlicePrefController;
 import com.android.settingslib.bluetooth.CachedBluetoothDevice;
 import com.android.settingslib.bluetooth.LocalBluetoothManager;
 import com.android.settingslib.core.AbstractPreferenceController;
@@ -106,7 +106,7 @@
         if (FeatureFlagUtils.isEnabled(context, FeatureFlags.SLICE_INJECTION)) {
             final BluetoothFeatureProvider featureProvider = FeatureFactory.getFactory(context)
                     .getBluetoothFeatureProvider(context);
-            use(SlicePreferenceController.class).setSliceUri(
+            use(BlockingSlicePrefController.class).setSliceUri(
                     featureProvider.getBluetoothDeviceSettingsUri(mDeviceAddress));
         }
     }
diff --git a/src/com/android/settings/core/BasePreferenceController.java b/src/com/android/settings/core/BasePreferenceController.java
index facec4a..1c85009 100644
--- a/src/com/android/settings/core/BasePreferenceController.java
+++ b/src/com/android/settings/core/BasePreferenceController.java
@@ -106,6 +106,7 @@
 
 
     protected final String mPreferenceKey;
+    protected UiBlockListener mUiBlockListener;
 
     /**
      * Instantiate a controller as specified controller type and user-defined key.
@@ -289,4 +290,36 @@
      */
     public void updateRawDataToIndex(List<SearchIndexableRaw> rawData) {
     }
+
+    /**
+     * Set {@link UiBlockListener}
+     * @param uiBlockListener listener to set
+     */
+    public void setUiBlockListener(UiBlockListener uiBlockListener) {
+        mUiBlockListener = uiBlockListener;
+    }
+
+    /**
+     * Listener to invoke when background job is finished
+     */
+    public interface UiBlockListener {
+        /**
+         * To notify client that UI related background work is finished.
+         * (i.e. Slice is fully loaded.)
+         * @param controller Controller that contains background work
+         */
+        void onBlockerWorkFinished(BasePreferenceController controller);
+    }
+
+    /**
+     * Used for {@link BasePreferenceController} to decide whether it is ui blocker.
+     * If it is, entire UI will be invisible for a certain period until controller
+     * invokes {@link UiBlockListener}
+     *
+     * This won't block UI thread however has similar side effect. Please use it if you
+     * want to avoid janky animation(i.e. new preference is added in the middle of page).
+     *
+     * This music be used in {@link BasePreferenceController}
+     */
+    public interface UiBlocker {}
 }
\ No newline at end of file
diff --git a/src/com/android/settings/core/PreferenceXmlParserUtils.java b/src/com/android/settings/core/PreferenceXmlParserUtils.java
index ce5c505..db6cd41 100644
--- a/src/com/android/settings/core/PreferenceXmlParserUtils.java
+++ b/src/com/android/settings/core/PreferenceXmlParserUtils.java
@@ -72,9 +72,11 @@
             MetadataFlag.FLAG_NEED_PREF_SUMMARY,
             MetadataFlag.FLAG_NEED_PREF_ICON,
             MetadataFlag.FLAG_NEED_SEARCHABLE,
-            MetadataFlag.FLAG_ALLOW_DYNAMIC_SUMMARY_IN_SLICE})
+            MetadataFlag.FLAG_ALLOW_DYNAMIC_SUMMARY_IN_SLICE,
+            MetadataFlag.FLAG_UNAVAILABLE_SLICE_SUBTITLE})
     @Retention(RetentionPolicy.SOURCE)
     public @interface MetadataFlag {
+
         int FLAG_INCLUDE_PREF_SCREEN = 1;
         int FLAG_NEED_KEY = 1 << 1;
         int FLAG_NEED_PREF_TYPE = 1 << 2;
@@ -87,6 +89,7 @@
         int FLAG_NEED_SEARCHABLE = 1 << 9;
         int FLAG_ALLOW_DYNAMIC_SUMMARY_IN_SLICE = 1 << 10;
         int FLAG_NEED_PREF_APPEND = 1 << 11;
+        int FLAG_UNAVAILABLE_SLICE_SUBTITLE = 1 << 12;
     }
 
     public static final String METADATA_PREF_TYPE = "type";
@@ -101,6 +104,8 @@
     public static final String METADATA_ALLOW_DYNAMIC_SUMMARY_IN_SLICE =
             "allow_dynamic_summary_in_slice";
     public static final String METADATA_APPEND = "staticPreferenceLocation";
+    public static final String METADATA_UNAVAILABLE_SLICE_SUBTITLE =
+            "unavailable_slice_subtitle";
 
     private static final String ENTRIES_SEPARATOR = "|";
 
@@ -249,6 +254,10 @@
                 preferenceMetadata.putBoolean(METADATA_APPEND,
                         isAppended(preferenceScreenAttributes));
             }
+            if (hasFlag(flags, MetadataFlag.FLAG_UNAVAILABLE_SLICE_SUBTITLE)) {
+                preferenceMetadata.putString(METADATA_UNAVAILABLE_SLICE_SUBTITLE,
+                        getUnavailableSliceSubtitle(preferenceAttributes));
+            }
             metadata.add(preferenceMetadata);
 
             preferenceAttributes.recycle();
@@ -344,6 +353,11 @@
 
     private static boolean isAppended(TypedArray styledAttributes) {
         return styledAttributes.getInt(R.styleable.PreferenceScreen_staticPreferenceLocation,
-            PREPEND_VALUE) == APPEND_VALUE;
+                PREPEND_VALUE) == APPEND_VALUE;
     }
-}
+
+    private static String getUnavailableSliceSubtitle(TypedArray styledAttributes) {
+        return styledAttributes.getString(
+                R.styleable.Preference_unavailableSliceSubtitle);
+    }
+}
\ No newline at end of file
diff --git a/src/com/android/settings/dashboard/DashboardFragment.java b/src/com/android/settings/dashboard/DashboardFragment.java
index 1916110..11858a7 100644
--- a/src/com/android/settings/dashboard/DashboardFragment.java
+++ b/src/com/android/settings/dashboard/DashboardFragment.java
@@ -56,7 +56,8 @@
  */
 public abstract class DashboardFragment extends SettingsPreferenceFragment
         implements SettingsBaseActivity.CategoryListener, Indexable,
-        SummaryLoader.SummaryConsumer, PreferenceGroup.OnExpandButtonClickListener {
+        SummaryLoader.SummaryConsumer, PreferenceGroup.OnExpandButtonClickListener,
+        BasePreferenceController.UiBlockListener {
     private static final String TAG = "DashboardFragment";
 
     private final Map<Class, List<AbstractPreferenceController>> mPreferenceControllers =
@@ -67,6 +68,7 @@
     private DashboardTilePlaceholderPreferenceController mPlaceholderPreferenceController;
     private boolean mListeningToCategoryChange;
     private SummaryLoader mSummaryLoader;
+    private UiBlockerController mBlockerController;
 
     @Override
     public void onAttach(Context context) {
@@ -105,6 +107,22 @@
         for (AbstractPreferenceController controller : controllers) {
             addPreferenceController(controller);
         }
+
+        checkUiBlocker(controllers);
+    }
+
+    private void checkUiBlocker(List<AbstractPreferenceController> controllers) {
+        final List<String> keys = new ArrayList<>();
+        controllers
+                .stream()
+                .filter(controller -> controller instanceof BasePreferenceController.UiBlocker)
+                .forEach(controller -> {
+                    ((BasePreferenceController) controller).setUiBlockListener(this);
+                    keys.add(controller.getPreferenceKey());
+                });
+
+        mBlockerController = new UiBlockerController(keys);
+        mBlockerController.start(()->updatePreferenceVisibility());
     }
 
     @Override
@@ -319,10 +337,11 @@
      * DashboardCategory.
      */
     private void refreshAllPreferences(final String TAG) {
+        final PreferenceScreen screen = getPreferenceScreen();
         // First remove old preferences.
-        if (getPreferenceScreen() != null) {
+        if (screen != null) {
             // Intentionally do not cache PreferenceScreen because it will be recreated later.
-            getPreferenceScreen().removeAll();
+            screen.removeAll();
         }
 
         // Add resource based tiles.
@@ -335,6 +354,27 @@
             Log.d(TAG, "All preferences added, reporting fully drawn");
             activity.reportFullyDrawn();
         }
+
+        updatePreferenceVisibility();
+    }
+
+    private void updatePreferenceVisibility() {
+        final PreferenceScreen screen = getPreferenceScreen();
+        if (screen == null) {
+            return;
+        }
+
+        final boolean visible = mBlockerController.isBlockerFinished();
+        for (List<AbstractPreferenceController> controllerList :
+                mPreferenceControllers.values()) {
+            for (AbstractPreferenceController controller : controllerList) {
+                final String key = controller.getPreferenceKey();
+                final Preference preference = screen.findPreference(key);
+                if (preference != null) {
+                    preference.setVisible(visible && controller.isAvailable());
+                }
+            }
+        }
     }
 
     /**
@@ -413,4 +453,9 @@
         }
         mSummaryLoader.setListening(true);
     }
+
+    @Override
+    public void onBlockerWorkFinished(BasePreferenceController controller) {
+        mBlockerController.countDown(controller.getPreferenceKey());
+    }
 }
diff --git a/src/com/android/settings/dashboard/UiBlockerController.java b/src/com/android/settings/dashboard/UiBlockerController.java
new file mode 100644
index 0000000..eeb56e6
--- /dev/null
+++ b/src/com/android/settings/dashboard/UiBlockerController.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.dashboard;
+
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+
+import com.android.settings.core.BasePreferenceController;
+import com.android.settingslib.utils.ThreadUtils;
+
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Control ui blocker data and check whether it is finished
+ *
+ * @see BasePreferenceController.UiBlocker
+ * @see BasePreferenceController.OnUiBlockListener
+ */
+public class UiBlockerController {
+    private static final String TAG = "UiBlockerController";
+    private static final int TIMEOUT_MILLIS = 500;
+
+    private CountDownLatch mCountDownLatch;
+    private boolean mBlockerFinished;
+    private Set<String> mKeys;
+    private long mTimeoutMillis;
+
+    public UiBlockerController(@NonNull List<String> keys) {
+        this(keys, TIMEOUT_MILLIS);
+    }
+
+    public UiBlockerController(@NonNull List<String> keys, long timeout) {
+        mCountDownLatch = new CountDownLatch(keys.size());
+        mBlockerFinished = keys.isEmpty();
+        mKeys = new HashSet<>(keys);
+        mTimeoutMillis = timeout;
+    }
+
+    /**
+     * Start background thread, it will invoke {@code finishRunnable} if any condition is met
+     *
+     * 1. Waiting time exceeds {@link #mTimeoutMillis}
+     * 2. All background work that associated with {@link #mCountDownLatch} is finished
+     */
+    public boolean start(Runnable finishRunnable) {
+        if (mKeys.isEmpty()) {
+            // Don't need to run finishRunnable because it doesn't start
+            return false;
+        }
+        ThreadUtils.postOnBackgroundThread(() -> {
+            try {
+                mCountDownLatch.await(mTimeoutMillis, TimeUnit.MILLISECONDS);
+            } catch (InterruptedException e) {
+                Log.w(TAG, "interrupted");
+            }
+            mBlockerFinished = true;
+            ThreadUtils.postOnMainThread(finishRunnable);
+        });
+
+        return true;
+    }
+
+    /**
+     * Return {@code true} if all work finished
+     */
+    public boolean isBlockerFinished() {
+        return mBlockerFinished;
+    }
+
+    /**
+     * Count down latch by {@code key}. It only count down 1 time if same key count down multiple
+     * times.
+     */
+    public boolean countDown(String key) {
+        if (mKeys.remove(key)) {
+            mCountDownLatch.countDown();
+            return true;
+        }
+
+        return false;
+    }
+}
diff --git a/src/com/android/settings/development/CbrsDataSwitchPreferenceController.java b/src/com/android/settings/development/CbrsDataSwitchPreferenceController.java
deleted file mode 100644
index d5c78e8..0000000
--- a/src/com/android/settings/development/CbrsDataSwitchPreferenceController.java
+++ /dev/null
@@ -1,66 +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 android.content.Context;
-import android.util.Log;
-import android.telephony.TelephonyManager;
-
-import androidx.annotation.VisibleForTesting;
-import androidx.preference.SwitchPreference;
-import androidx.preference.Preference;
-
-import com.android.settings.core.PreferenceControllerMixin;
-import com.android.settingslib.development.DeveloperOptionsPreferenceController;
-
-public class CbrsDataSwitchPreferenceController extends DeveloperOptionsPreferenceController
-        implements Preference.OnPreferenceChangeListener, PreferenceControllerMixin {
-    private static final String CBRS_DATA_SWITCH_KEY = "cbrs_data_switch";
-    private static final String TAG = "CbrsDataSwitchPreferenceController";
-    private Context mContext;
-
-    private TelephonyManager mTelephonyManager;
-
-    public CbrsDataSwitchPreferenceController(Context context) {
-        super(context);
-        mContext = context;
-        mTelephonyManager = mContext.getSystemService(TelephonyManager.class);
-    }
-
-    @Override
-    public String getPreferenceKey() {
-        return CBRS_DATA_SWITCH_KEY;
-    }
-
-    @Override
-    public boolean isAvailable() {
-        return mTelephonyManager != null;
-    }
-
-    @Override
-    public boolean onPreferenceChange(Preference preference, Object newValue) {
-        boolean state = (Boolean)newValue;
-        return mTelephonyManager.setAlternativeNetworkState(state);
-    }
-
-    @Override
-    public void updateState(Preference preference) {
-        boolean state = mTelephonyManager.isAlternativeNetworkEnabled();
-        ((SwitchPreference) mPreference).setChecked(state);
-    }
-
-}
diff --git a/src/com/android/settings/development/ClearAdbKeysPreferenceController.java b/src/com/android/settings/development/ClearAdbKeysPreferenceController.java
index e1fda67..6613cfd 100644
--- a/src/com/android/settings/development/ClearAdbKeysPreferenceController.java
+++ b/src/com/android/settings/development/ClearAdbKeysPreferenceController.java
@@ -22,6 +22,7 @@
 import android.os.ServiceManager;
 import android.os.SystemProperties;
 import android.os.UserManager;
+import android.sysprop.AdbProperties;
 import android.text.TextUtils;
 import android.util.Log;
 
@@ -39,9 +40,6 @@
     private static final String TAG = "ClearAdbPrefCtrl";
     private static final String CLEAR_ADB_KEYS = "clear_adb_keys";
 
-    @VisibleForTesting
-    static final String RO_ADB_SECURE_PROPERTY_KEY = "ro.adb.secure";
-
     private final IAdbManager mAdbManager;
     private final DevelopmentSettingsDashboardFragment mFragment;
 
@@ -55,7 +53,7 @@
 
     @Override
     public boolean isAvailable() {
-        return SystemProperties.getBoolean(RO_ADB_SECURE_PROPERTY_KEY, false /* default */);
+        return AdbProperties.secure().orElse(false);
     }
 
     @Override
diff --git a/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java b/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java
index 725a195..2a9919a 100644
--- a/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java
+++ b/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java
@@ -481,7 +481,6 @@
         controllers.add(new SmsAccessRestrictionPreferenceController(context));
         controllers.add(new ShortcutManagerThrottlingPreferenceController(context));
         controllers.add(new EnableGnssRawMeasFullTrackingPreferenceController(context));
-        controllers.add(new CbrsDataSwitchPreferenceController(context));
         controllers.add(new DefaultLaunchPreferenceController(context, "running_apps"));
         controllers.add(new DefaultLaunchPreferenceController(context, "demo_mode"));
         controllers.add(new DefaultLaunchPreferenceController(context, "quick_settings_tiles"));
diff --git a/src/com/android/settings/development/gup/GupPreferenceController.java b/src/com/android/settings/development/gup/GupPreferenceController.java
index 7623144..d4cd2f1 100644
--- a/src/com/android/settings/development/gup/GupPreferenceController.java
+++ b/src/com/android/settings/development/gup/GupPreferenceController.java
@@ -48,7 +48,7 @@
     private final String mPreferenceTitle;
     private final String mPreferenceDefault;
     private final String mPreferenceGup;
-    private final String mPreferenceNative;
+    private final String mPreferenceSystem;
 
     private final List<AppInfo> mAppInfos;
     private final Set<String> mDevOptInApps;
@@ -62,7 +62,7 @@
         mPreferenceTitle = resources.getString(R.string.gup_app_preference_title);
         mPreferenceDefault = resources.getString(R.string.gup_app_preference_default);
         mPreferenceGup = resources.getString(R.string.gup_app_preference_gup);
-        mPreferenceNative = resources.getString(R.string.gup_app_preference_native);
+        mPreferenceSystem = resources.getString(R.string.gup_app_preference_system);
 
         // TODO: Move this task to background if there's potential ANR/Jank.
         // Update the UI when all the app infos are ready.
@@ -105,19 +105,18 @@
 
         // When user choose a new preference, update both Sets for
         // opt-in and opt-out apps. Then set the new summary text.
-        if (value.equals(mPreferenceNative)) {
+        if (value.equals(mPreferenceSystem)) {
             mDevOptInApps.remove(packageName);
             mDevOptOutApps.add(packageName);
-            listPref.setSummary(mPreferenceNative);
         } else if (value.equals(mPreferenceGup)) {
             mDevOptInApps.add(packageName);
             mDevOptOutApps.remove(packageName);
-            listPref.setSummary(mPreferenceGup);
         } else {
             mDevOptInApps.remove(packageName);
             mDevOptOutApps.remove(packageName);
-            listPref.setSummary(mPreferenceDefault);
         }
+        listPref.setValue(value);
+        listPref.setSummary(value);
 
         // Push the updated Sets for opt-in and opt-out apps to
         // corresponding Settings.Global.GUP_DEV_OPT_(IN|OUT)_APPS
@@ -189,8 +188,8 @@
         // Initialize preference default and summary with the opt in/out choices
         // from Settings.Global.GUP_DEV_OPT_(IN|OUT)_APPS
         if (mDevOptOutApps.contains(packageName)) {
-            listPreference.setValue(mPreferenceNative);
-            listPreference.setSummary(mPreferenceNative);
+            listPreference.setValue(mPreferenceSystem);
+            listPreference.setSummary(mPreferenceSystem);
         } else if (mDevOptInApps.contains(packageName)) {
             listPreference.setValue(mPreferenceGup);
             listPreference.setSummary(mPreferenceGup);
diff --git a/src/com/android/settings/notification/ChannelSummaryPreference.java b/src/com/android/settings/notification/ChannelSummaryPreference.java
new file mode 100644
index 0000000..c716038
--- /dev/null
+++ b/src/com/android/settings/notification/ChannelSummaryPreference.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.notification;
+
+import android.content.Context;
+import android.content.Intent;
+import android.view.View;
+import android.widget.CheckBox;
+
+import com.android.settings.R;
+import com.android.settingslib.TwoTargetPreference;
+
+import androidx.preference.PreferenceViewHolder;
+
+/**
+ * A custom preference that provides inline checkbox and tappable target.
+ */
+public class ChannelSummaryPreference extends TwoTargetPreference {
+
+    private Context mContext;
+    private Intent mIntent;
+    private CheckBox mCheckBox;
+    private boolean mChecked;
+    private boolean mEnableCheckBox = true;
+
+    public ChannelSummaryPreference(Context context) {
+        super(context);
+        setLayoutResource(R.layout.preference_checkable_two_target);
+        mContext = context;
+        setWidgetLayoutResource(R.layout.zen_rule_widget);
+    }
+
+    @Override
+    public void onBindViewHolder(PreferenceViewHolder view) {
+        super.onBindViewHolder(view);
+        View settingsWidget = view.findViewById(android.R.id.widget_frame);
+        View divider = view.findViewById(R.id.two_target_divider);
+        if (mIntent != null) {
+            divider.setVisibility(View.VISIBLE);
+            settingsWidget.setVisibility(View.VISIBLE);
+            settingsWidget.setOnClickListener(v -> mContext.startActivity(mIntent));
+        } else {
+            divider.setVisibility(View.GONE);
+            settingsWidget.setVisibility(View.GONE);
+            settingsWidget.setOnClickListener(null);
+        }
+
+        View checkboxContainer = view.findViewById(R.id.checkbox_container);
+        if (checkboxContainer != null) {
+            checkboxContainer.setOnClickListener(mOnCheckBoxClickListener);
+        }
+        mCheckBox = (CheckBox) view.findViewById(com.android.internal.R.id.checkbox);
+        if (mCheckBox != null) {
+            mCheckBox.setChecked(mChecked);
+            mCheckBox.setEnabled(mEnableCheckBox);
+        }
+    }
+
+    public boolean isChecked() {
+        return mChecked;
+    }
+
+    @Override
+    public void setIntent(Intent intent) {
+        mIntent = intent;
+    }
+
+    @Override
+    public void onClick() {
+        mOnCheckBoxClickListener.onClick(null);
+    }
+
+    public void setChecked(boolean checked) {
+        mChecked = checked;
+        if (mCheckBox != null) {
+            mCheckBox.setChecked(checked);
+        }
+    }
+
+    public void setCheckBoxEnabled(boolean enabled) {
+        mEnableCheckBox = enabled;
+        if (mCheckBox != null) {
+            mCheckBox.setEnabled(enabled);
+        }
+    }
+
+    private View.OnClickListener mOnCheckBoxClickListener = new View.OnClickListener() {
+        @Override
+        public void onClick(View v) {
+            if (mCheckBox != null && !mCheckBox.isEnabled()) {
+                return;
+            }
+            setChecked(!mChecked);
+            if (!callChangeListener(mChecked)) {
+                setChecked(!mChecked);
+            } else {
+                persistBoolean(mChecked);
+            }
+        }
+    };
+}
diff --git a/src/com/android/settings/notification/NotificationSettingsBase.java b/src/com/android/settings/notification/NotificationSettingsBase.java
index ed0b123..7053bb3 100644
--- a/src/com/android/settings/notification/NotificationSettingsBase.java
+++ b/src/com/android/settings/notification/NotificationSettingsBase.java
@@ -273,8 +273,7 @@
 
     protected Preference populateSingleChannelPrefs(PreferenceGroup parent,
             final NotificationChannel channel, final boolean groupBlocked) {
-        MasterCheckBoxPreference channelPref = new MasterCheckBoxPreference(
-                getPrefContext());
+        ChannelSummaryPreference channelPref = new ChannelSummaryPreference(getPrefContext());
         channelPref.setCheckBoxEnabled(mSuspendedAppsAdmin == null
                 && isChannelBlockable(channel)
                 && isChannelConfigurable(channel)
diff --git a/src/com/android/settings/notification/NotificationStation.java b/src/com/android/settings/notification/NotificationStation.java
index 116980f..91ebc88 100644
--- a/src/com/android/settings/notification/NotificationStation.java
+++ b/src/com/android/settings/notification/NotificationStation.java
@@ -372,7 +372,7 @@
             sb.append("\n")
                     .append(bold(getString(R.string.notification_log_details_sound)))
                     .append(delim);
-            if (channel.getImportance() == IMPORTANCE_UNSPECIFIED) {
+            if (channel == null || channel.getImportance() == IMPORTANCE_UNSPECIFIED) {
 
                 if (0 != (n.defaults & Notification.DEFAULT_SOUND)) {
                     sb.append(getString(R.string.notification_log_details_default));
@@ -387,7 +387,7 @@
             sb.append("\n")
                     .append(bold(getString(R.string.notification_log_details_vibrate)))
                     .append(delim);
-            if (channel.getImportance() == IMPORTANCE_UNSPECIFIED) {
+            if (channel == null || channel.getImportance() == IMPORTANCE_UNSPECIFIED) {
                 if (0 != (n.defaults & Notification.DEFAULT_VIBRATE)) {
                     sb.append(getString(R.string.notification_log_details_default));
                 } else if (n.vibrate != null) {
diff --git a/src/com/android/settings/slices/BlockingSlicePrefController.java b/src/com/android/settings/slices/BlockingSlicePrefController.java
new file mode 100644
index 0000000..94810c5
--- /dev/null
+++ b/src/com/android/settings/slices/BlockingSlicePrefController.java
@@ -0,0 +1,43 @@
+/*
+ * 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.slices;
+
+import android.content.Context;
+
+import androidx.slice.Slice;
+
+import com.android.settings.core.BasePreferenceController;
+
+/**
+ * The blocking slice preference controller. It will make whole page invisible for a certain time
+ * until {@link Slice} is fully loaded.
+ */
+public class BlockingSlicePrefController extends SlicePreferenceController implements
+        BasePreferenceController.UiBlocker {
+
+    public BlockingSlicePrefController(Context context, String preferenceKey) {
+        super(context, preferenceKey);
+    }
+
+    @Override
+    public void onChanged(Slice slice) {
+        super.onChanged(slice);
+        if (mUiBlockListener != null) {
+            mUiBlockListener.onBlockerWorkFinished(this);
+        }
+    }
+}
diff --git a/src/com/android/settings/slices/SliceBuilderUtils.java b/src/com/android/settings/slices/SliceBuilderUtils.java
index b2b8310..925306e 100644
--- a/src/com/android/settings/slices/SliceBuilderUtils.java
+++ b/src/com/android/settings/slices/SliceBuilderUtils.java
@@ -425,7 +425,10 @@
         final String title = data.getTitle();
         final Set<String> keywords = buildSliceKeywords(data);
         @ColorInt final int color = Utils.getColorAccentDefaultColor(context);
-        final CharSequence summary = context.getText(R.string.disabled_dependent_setting_summary);
+
+        final String customSubtitle = data.getUnavailableSliceSubtitle();
+        final CharSequence subtitle = !TextUtils.isEmpty(customSubtitle) ? customSubtitle
+                : context.getText(R.string.disabled_dependent_setting_summary);
         final IconCompat icon = getSafeIcon(context, data);
         final SliceAction primaryAction = SliceAction.createDeeplink(
                 getContentPendingIntent(context, data),
@@ -436,7 +439,7 @@
                 .addRow(new RowBuilder()
                         .setTitle(title)
                         .setTitleItem(icon, ListBuilder.ICON_IMAGE)
-                        .setSubtitle(summary)
+                        .setSubtitle(subtitle)
                         .setPrimaryAction(primaryAction))
                 .setKeywords(keywords)
                 .build();
diff --git a/src/com/android/settings/slices/SliceData.java b/src/com/android/settings/slices/SliceData.java
index 8705884..9d52d56 100644
--- a/src/com/android/settings/slices/SliceData.java
+++ b/src/com/android/settings/slices/SliceData.java
@@ -28,7 +28,6 @@
  * Note that {@link #mKey} is treated as a primary key for this class and determines equality.
  */
 public class SliceData {
-
     /**
      * Flags indicating the UI type of the Slice.
      */
@@ -76,6 +75,8 @@
 
     private final boolean mIsDynamicSummaryAllowed;
 
+    private final String mUnavailableSliceSubtitle;
+
     public String getKey() {
         return mKey;
     }
@@ -124,6 +125,10 @@
         return mIsDynamicSummaryAllowed;
     }
 
+    public String getUnavailableSliceSubtitle() {
+        return mUnavailableSliceSubtitle;
+    }
+
     private SliceData(Builder builder) {
         mKey = builder.mKey;
         mTitle = builder.mTitle;
@@ -137,6 +142,7 @@
         mSliceType = builder.mSliceType;
         mIsPlatformDefined = builder.mIsPlatformDefined;
         mIsDynamicSummaryAllowed = builder.mIsDynamicSummaryAllowed;
+        mUnavailableSliceSubtitle = builder.mUnavailableSliceSubtitle;
     }
 
     @Override
@@ -178,6 +184,8 @@
 
         private boolean mIsDynamicSummaryAllowed;
 
+        private String mUnavailableSliceSubtitle;
+
         public Builder setKey(String key) {
             mKey = key;
             return this;
@@ -238,6 +246,12 @@
             return this;
         }
 
+        public Builder setUnavailableSliceSubtitle(
+                String unavailableSliceSubtitle) {
+            mUnavailableSliceSubtitle = unavailableSliceSubtitle;
+            return this;
+        }
+
         public SliceData build() {
             if (TextUtils.isEmpty(mKey)) {
                 throw new InvalidSliceDataException("Key cannot be empty");
diff --git a/src/com/android/settings/slices/SliceDataConverter.java b/src/com/android/settings/slices/SliceDataConverter.java
index cb2980d..dcc8089 100644
--- a/src/com/android/settings/slices/SliceDataConverter.java
+++ b/src/com/android/settings/slices/SliceDataConverter.java
@@ -16,12 +16,12 @@
 
 package com.android.settings.slices;
 
-import static com.android.settings.core.PreferenceXmlParserUtils
-        .METADATA_ALLOW_DYNAMIC_SUMMARY_IN_SLICE;
+import static com.android.settings.core.PreferenceXmlParserUtils.METADATA_ALLOW_DYNAMIC_SUMMARY_IN_SLICE;
 import static com.android.settings.core.PreferenceXmlParserUtils.METADATA_CONTROLLER;
 import static com.android.settings.core.PreferenceXmlParserUtils.METADATA_ICON;
 import static com.android.settings.core.PreferenceXmlParserUtils.METADATA_KEY;
 import static com.android.settings.core.PreferenceXmlParserUtils.METADATA_PLATFORM_SLICE_FLAG;
+import static com.android.settings.core.PreferenceXmlParserUtils.METADATA_UNAVAILABLE_SLICE_SUBTITLE;
 import static com.android.settings.core.PreferenceXmlParserUtils.METADATA_SUMMARY;
 import static com.android.settings.core.PreferenceXmlParserUtils.METADATA_TITLE;
 
@@ -189,7 +189,8 @@
                             | MetadataFlag.FLAG_NEED_PREF_ICON
                             | MetadataFlag.FLAG_NEED_PREF_SUMMARY
                             | MetadataFlag.FLAG_NEED_PLATFORM_SLICE_FLAG
-                            | MetadataFlag.FLAG_ALLOW_DYNAMIC_SUMMARY_IN_SLICE);
+                            | MetadataFlag.FLAG_ALLOW_DYNAMIC_SUMMARY_IN_SLICE
+                            | MetadataFlag.FLAG_UNAVAILABLE_SLICE_SUBTITLE);
 
             for (Bundle bundle : metadata) {
                 // TODO (b/67996923) Non-controller Slices should become intent-only slices.
@@ -208,6 +209,8 @@
                 final boolean isPlatformSlice = bundle.getBoolean(METADATA_PLATFORM_SLICE_FLAG);
                 final boolean isDynamicSummaryAllowed = bundle.getBoolean(
                         METADATA_ALLOW_DYNAMIC_SUMMARY_IN_SLICE);
+                final String unavailableSliceSubtitle = bundle.getString(
+                        METADATA_UNAVAILABLE_SLICE_SUBTITLE);
 
                 final SliceData xmlSlice = new SliceData.Builder()
                         .setKey(key)
@@ -220,6 +223,7 @@
                         .setSliceType(sliceType)
                         .setPlatformDefined(isPlatformSlice)
                         .setDynamicSummaryAllowed(isDynamicSummaryAllowed)
+                        .setUnavailableSliceSubtitle(unavailableSliceSubtitle)
                         .build();
 
                 final BasePreferenceController controller =
diff --git a/src/com/android/settings/slices/SlicePreference.java b/src/com/android/settings/slices/SlicePreference.java
index 37a53f4..a88ae76 100644
--- a/src/com/android/settings/slices/SlicePreference.java
+++ b/src/com/android/settings/slices/SlicePreference.java
@@ -44,6 +44,7 @@
     private void init() {
         mSliceView = findViewById(R.id.slice_view);
         mSliceView.showTitleItems(true);
+        mSliceView.setScrollable(false);
     }
 
     public void onSliceUpdated(Slice slice) {
diff --git a/src/com/android/settings/slices/SlicePreferenceController.java b/src/com/android/settings/slices/SlicePreferenceController.java
index 8c751c8..d7fcc18 100644
--- a/src/com/android/settings/slices/SlicePreferenceController.java
+++ b/src/com/android/settings/slices/SlicePreferenceController.java
@@ -50,9 +50,7 @@
     @Override
     public void displayPreference(PreferenceScreen screen) {
         super.displayPreference(screen);
-
-        mSlicePreference = (SlicePreference) screen.findPreference(
-                getPreferenceKey());
+        mSlicePreference = screen.findPreference(getPreferenceKey());
     }
 
     @Override
diff --git a/src/com/android/settings/slices/SlicesDatabaseAccessor.java b/src/com/android/settings/slices/SlicesDatabaseAccessor.java
index c75f3ef..ae77dd2 100644
--- a/src/com/android/settings/slices/SlicesDatabaseAccessor.java
+++ b/src/com/android/settings/slices/SlicesDatabaseAccessor.java
@@ -50,6 +50,7 @@
             IndexColumns.PLATFORM_SLICE,
             IndexColumns.SLICE_TYPE,
             IndexColumns.ALLOW_DYNAMIC_SUMMARY_IN_SLICE,
+            IndexColumns.UNAVAILABLE_SLICE_SUBTITLE,
     };
 
     // Cursor value for boolean true
@@ -167,6 +168,8 @@
                 cursor.getColumnIndex(IndexColumns.ALLOW_DYNAMIC_SUMMARY_IN_SLICE)) == TRUE;
         int sliceType = cursor.getInt(
                 cursor.getColumnIndex(IndexColumns.SLICE_TYPE));
+        final String unavailableSliceSubtitle = cursor.getString(
+                cursor.getColumnIndex(IndexColumns.UNAVAILABLE_SLICE_SUBTITLE));
 
         if (isIntentOnly) {
             sliceType = SliceData.SliceType.INTENT;
@@ -185,6 +188,7 @@
                 .setPlatformDefined(isPlatformDefined)
                 .setSliceType(sliceType)
                 .setDynamicSummaryAllowed(isDynamicSummaryAllowed)
+                .setUnavailableSliceSubtitle(unavailableSliceSubtitle)
                 .build();
     }
 
diff --git a/src/com/android/settings/slices/SlicesDatabaseHelper.java b/src/com/android/settings/slices/SlicesDatabaseHelper.java
index e463099..8dc86fb 100644
--- a/src/com/android/settings/slices/SlicesDatabaseHelper.java
+++ b/src/com/android/settings/slices/SlicesDatabaseHelper.java
@@ -36,7 +36,7 @@
     private static final String DATABASE_NAME = "slices_index.db";
     private static final String SHARED_PREFS_TAG = "slices_shared_prefs";
 
-    private static final int DATABASE_VERSION = 3;
+    private static final int DATABASE_VERSION = 4;
 
     public interface Tables {
         String TABLE_SLICES_INDEX = "slices_index";
@@ -99,6 +99,11 @@
          * preference controller.
          */
         String ALLOW_DYNAMIC_SUMMARY_IN_SLICE = "allow_dynamic_summary_in_slice";
+
+        /**
+         * Customized subtitle if it's a unavailable slice
+         */
+        String UNAVAILABLE_SLICE_SUBTITLE = "unavailable_slice_subtitle";
     }
 
     private static final String CREATE_SLICES_TABLE =
@@ -125,6 +130,8 @@
                     IndexColumns.SLICE_TYPE +
                     ", " +
                     IndexColumns.ALLOW_DYNAMIC_SUMMARY_IN_SLICE +
+                    ", " +
+                    IndexColumns.UNAVAILABLE_SLICE_SUBTITLE +
                     ");";
 
     private final Context mContext;
@@ -151,7 +158,7 @@
     @Override
     public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
         if (oldVersion < DATABASE_VERSION) {
-            Log.d(TAG, "Reconstructing DB from " + oldVersion + "to " + newVersion);
+            Log.d(TAG, "Reconstructing DB from " + oldVersion + " to " + newVersion);
             reconstruct(db);
         }
     }
diff --git a/src/com/android/settings/slices/SlicesIndexer.java b/src/com/android/settings/slices/SlicesIndexer.java
index 0c39429..ec2be29 100644
--- a/src/com/android/settings/slices/SlicesIndexer.java
+++ b/src/com/android/settings/slices/SlicesIndexer.java
@@ -113,6 +113,8 @@
             values.put(IndexColumns.SLICE_TYPE, dataRow.getSliceType());
             values.put(IndexColumns.ALLOW_DYNAMIC_SUMMARY_IN_SLICE,
                     dataRow.isDynamicSummaryAllowed());
+            values.put(IndexColumns.UNAVAILABLE_SLICE_SUBTITLE,
+                    dataRow.getUnavailableSliceSubtitle());
 
             database.replaceOrThrow(Tables.TABLE_SLICES_INDEX, null /* nullColumnHack */,
                     values);
diff --git a/src/com/android/settings/wifi/WifiConfigController.java b/src/com/android/settings/wifi/WifiConfigController.java
index 67f59ea..26db583 100644
--- a/src/com/android/settings/wifi/WifiConfigController.java
+++ b/src/com/android/settings/wifi/WifiConfigController.java
@@ -621,7 +621,7 @@
                     config.requirePMF = true;
                     config.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.GCMP_256);
                     config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.GCMP_256);
-                    config.allowedGroupMgmtCiphers.set(WifiConfiguration.GroupMgmtCipher
+                    config.allowedGroupManagementCiphers.set(WifiConfiguration.GroupMgmtCipher
                             .BIP_GMAC_256);
                     config.allowedSuiteBCiphers.set(WifiConfiguration.SuiteBCipher.ECDHE_RSA);
                 }
diff --git a/src/com/android/settings/wifi/WifiUtils.java b/src/com/android/settings/wifi/WifiUtils.java
index 7970b2a..751fc91 100644
--- a/src/com/android/settings/wifi/WifiUtils.java
+++ b/src/com/android/settings/wifi/WifiUtils.java
@@ -196,7 +196,7 @@
                     config.requirePMF = true;
                     config.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.GCMP_256);
                     config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.GCMP_256);
-                    config.allowedGroupMgmtCiphers.set(WifiConfiguration.GroupMgmtCipher
+                    config.allowedGroupManagementCiphers.set(WifiConfiguration.GroupMgmtCipher
                             .BIP_GMAC_256);
                     config.allowedSuiteBCiphers.set(WifiConfiguration.SuiteBCipher.ECDHE_RSA);
                 }
diff --git a/tests/robotests/res/xml-mcc999/location_settings.xml b/tests/robotests/res/xml-mcc999/location_settings.xml
index 91e4c41..a25f36d 100644
--- a/tests/robotests/res/xml-mcc999/location_settings.xml
+++ b/tests/robotests/res/xml-mcc999/location_settings.xml
@@ -27,6 +27,7 @@
         settings:controller="com.android.settings.slices.FakePreferenceController"
         settings:keywords="a, b, c"
         settings:platform_slice="true"
-        settings:allowDynamicSummaryInSlice="true"/>
+        settings:allowDynamicSummaryInSlice="true"
+        settings:unavailableSliceSubtitle="subtitleOfUnavailableSlice"/>
 
 </PreferenceScreen>
\ No newline at end of file
diff --git a/tests/robotests/res/xml-mcc999/night_display_settings.xml b/tests/robotests/res/xml-mcc999/night_display_settings.xml
new file mode 100644
index 0000000..c23a2cf
--- /dev/null
+++ b/tests/robotests/res/xml-mcc999/night_display_settings.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  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.
+  -->
+
+<PreferenceScreen
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:settings="http://schemas.android.com/apk/res-auto"
+    android:key="fake_title_key"
+    android:title="screen_title">
+
+    <Preference
+        android:key="key1"
+        android:title="title"
+        android:icon="@drawable/ic_android"
+        android:summary="summary"
+        settings:controller="com.android.settings.slices.FakePreferenceController"
+        settings:keywords="keyword"
+        settings:platform_slice="true"/>
+
+    <Preference
+        android:key="key2"
+        android:title="title"
+        android:icon="@drawable/ic_android"
+        android:summary="summary"
+        settings:controller="com.android.settings.slices.FakePreferenceController"
+        settings:keywords="keyword"
+        settings:platform_slice="true"
+        settings:unavailableSliceSubtitle="subtitleOfUnavailable"/>
+
+</PreferenceScreen>
\ No newline at end of file
diff --git a/tests/robotests/src/com/android/settings/accessibility/LiveCaptionPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/accessibility/LiveCaptionPreferenceControllerTest.java
new file mode 100644
index 0000000..f6160b2
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/accessibility/LiveCaptionPreferenceControllerTest.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.accessibility;
+
+import static com.android.settings.core.BasePreferenceController.AVAILABLE;
+import static com.android.settings.core.BasePreferenceController.UNSUPPORTED_ON_DEVICE;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.content.pm.ResolveInfo;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.Shadows;
+import org.robolectric.shadows.ShadowPackageManager;
+
+import java.util.Collections;
+
+@RunWith(RobolectricTestRunner.class)
+public class LiveCaptionPreferenceControllerTest {
+
+    private LiveCaptionPreferenceController mController;
+
+    @Before
+    public void setUp() {
+        mController = new LiveCaptionPreferenceController(RuntimeEnvironment.application,
+                "test_key");
+    }
+
+    @Test
+    public void getAvailabilityStatus_canResolveIntent_shouldReturnAvailable() {
+        final ShadowPackageManager pm = Shadows.shadowOf(
+                RuntimeEnvironment.application.getPackageManager());
+        pm.addResolveInfoForIntent(LiveCaptionPreferenceController.LIVE_CAPTION_INTENT,
+                new ResolveInfo());
+
+        assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE);
+    }
+
+    @Test
+    public void getAvailabilityStatus_noResolveIntent_shouldReturnUnavailable() {
+        final ShadowPackageManager pm = Shadows.shadowOf(
+                RuntimeEnvironment.application.getPackageManager());
+        pm.setResolveInfosForIntent(LiveCaptionPreferenceController.LIVE_CAPTION_INTENT,
+                Collections.emptyList());
+
+        assertThat(mController.getAvailabilityStatus()).isEqualTo(UNSUPPORTED_ON_DEVICE);
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/accessibility/VibrationPreferenceFragmentTest.java b/tests/robotests/src/com/android/settings/accessibility/VibrationPreferenceFragmentTest.java
index 68d5e36..9f83f72 100644
--- a/tests/robotests/src/com/android/settings/accessibility/VibrationPreferenceFragmentTest.java
+++ b/tests/robotests/src/com/android/settings/accessibility/VibrationPreferenceFragmentTest.java
@@ -161,6 +161,11 @@
         }
 
         @Override
+        protected String getVibrationEnabledSetting() {
+            return "";
+        }
+
+        @Override
         protected int getDefaultVibrationIntensity() {
             return Vibrator.VIBRATION_INTENSITY_MEDIUM;
         }
diff --git a/tests/robotests/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragmentTest.java b/tests/robotests/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragmentTest.java
index 21d62bc..be77283 100644
--- a/tests/robotests/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragmentTest.java
+++ b/tests/robotests/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragmentTest.java
@@ -26,6 +26,8 @@
 import android.content.Context;
 import android.os.Bundle;
 
+import androidx.preference.PreferenceScreen;
+
 import com.android.settings.testutils.FakeFeatureFactory;
 import com.android.settingslib.bluetooth.CachedBluetoothDevice;
 import com.android.settingslib.bluetooth.LocalBluetoothManager;
@@ -49,9 +51,10 @@
 
     @Mock(answer = Answers.RETURNS_DEEP_STUBS)
     private CachedBluetoothDevice mCachedDevice;
-
     @Mock(answer = Answers.RETURNS_DEEP_STUBS)
     private LocalBluetoothManager mLocalManager;
+    @Mock
+    private PreferenceScreen mPreferenceScreen;
 
     @Before
     public void setUp() {
@@ -62,6 +65,7 @@
         mFragment = spy(BluetoothDeviceDetailsFragment.newInstance(TEST_ADDRESS));
         doReturn(mLocalManager).when(mFragment).getLocalBluetoothManager(any());
         doReturn(mCachedDevice).when(mFragment).getCachedDevice(any());
+        doReturn(mPreferenceScreen).when(mFragment).getPreferenceScreen();
 
         when(mCachedDevice.getAddress()).thenReturn(TEST_ADDRESS);
         Bundle args = new Bundle();
diff --git a/tests/robotests/src/com/android/settings/core/PreferenceXmlParserUtilsTest.java b/tests/robotests/src/com/android/settings/core/PreferenceXmlParserUtilsTest.java
index 9627a48..b8051a1 100644
--- a/tests/robotests/src/com/android/settings/core/PreferenceXmlParserUtilsTest.java
+++ b/tests/robotests/src/com/android/settings/core/PreferenceXmlParserUtilsTest.java
@@ -16,12 +16,12 @@
 
 package com.android.settings.core;
 
-import static com.android.settings.core.PreferenceXmlParserUtils
-        .METADATA_ALLOW_DYNAMIC_SUMMARY_IN_SLICE;
+import static com.android.settings.core.PreferenceXmlParserUtils.METADATA_ALLOW_DYNAMIC_SUMMARY_IN_SLICE;
 import static com.android.settings.core.PreferenceXmlParserUtils.METADATA_APPEND;
 import static com.android.settings.core.PreferenceXmlParserUtils.METADATA_KEY;
 import static com.android.settings.core.PreferenceXmlParserUtils.METADATA_KEYWORDS;
 import static com.android.settings.core.PreferenceXmlParserUtils.METADATA_SEARCHABLE;
+import static com.android.settings.core.PreferenceXmlParserUtils.METADATA_UNAVAILABLE_SLICE_SUBTITLE;
 
 import static com.google.common.truth.Truth.assertThat;
 
@@ -35,7 +35,6 @@
 import com.android.settings.R;
 import com.android.settings.core.PreferenceXmlParserUtils.MetadataFlag;
 
-import java.util.Objects;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -47,6 +46,7 @@
 
 import java.io.IOException;
 import java.util.List;
+import java.util.Objects;
 
 /**
  * These tests use a series of preferences that have specific attributes which are sometimes
@@ -320,7 +320,7 @@
     @Test
     @Config(qualifiers = "mcc999")
     public void extractMetadata_requestAppendProperty_shouldDefaultToFalse()
-        throws Exception {
+            throws Exception {
         final List<Bundle> metadata = PreferenceXmlParserUtils.extractMetadata(mContext,
                 R.xml.display_settings,
                 MetadataFlag.FLAG_INCLUDE_PREF_SCREEN | MetadataFlag.FLAG_NEED_PREF_APPEND);
@@ -333,7 +333,7 @@
     @Test
     @Config(qualifiers = "mcc999")
     public void extractMetadata_requestAppendProperty_shouldReturnCorrectValue()
-        throws Exception {
+            throws Exception {
         final List<Bundle> metadata = PreferenceXmlParserUtils.extractMetadata(mContext,
                 R.xml.battery_saver_schedule_settings,
                 MetadataFlag.FLAG_INCLUDE_PREF_SCREEN | MetadataFlag.FLAG_NEED_PREF_APPEND);
@@ -343,6 +343,46 @@
         }
     }
 
+    @Test
+    @Config(qualifiers = "mcc999")
+    public void extractMetadata_requestUnavailableSliceSubtitle_shouldDefaultNull()
+            throws Exception {
+        final List<Bundle> metadata = PreferenceXmlParserUtils.extractMetadata(mContext,
+                R.xml.night_display_settings,
+                MetadataFlag.FLAG_NEED_KEY | MetadataFlag.FLAG_UNAVAILABLE_SLICE_SUBTITLE);
+
+        boolean bundleWithKey1Found = false;
+        for (Bundle bundle : metadata) {
+            if (bundle.getString(METADATA_KEY).equals("key1")) {
+                assertThat(bundle.getString(METADATA_UNAVAILABLE_SLICE_SUBTITLE)).isNull();
+                bundleWithKey1Found = true;
+                break;
+            }
+        }
+        assertThat(bundleWithKey1Found).isTrue();
+    }
+
+    @Test
+    @Config(qualifiers = "mcc999")
+    public void extractMetadata_requestUnavailableSliceSubtitle_shouldReturnAttributeValue()
+            throws Exception {
+        final String expectedSubtitle = "subtitleOfUnavailable";
+        final List<Bundle> metadata = PreferenceXmlParserUtils.extractMetadata(mContext,
+                R.xml.night_display_settings,
+                MetadataFlag.FLAG_NEED_KEY | MetadataFlag.FLAG_UNAVAILABLE_SLICE_SUBTITLE);
+
+        boolean bundleWithKey2Found = false;
+        for (Bundle bundle : metadata) {
+            if (bundle.getString(METADATA_KEY).equals("key2")) {
+                assertThat(bundle.getString(METADATA_UNAVAILABLE_SLICE_SUBTITLE)).isEqualTo(
+                        expectedSubtitle);
+                bundleWithKey2Found = true;
+                break;
+            }
+        }
+        assertThat(bundleWithKey2Found).isTrue();
+    }
+
     /**
      * @param resId the ID for the XML preference
      * @return an XML resource parser that points to the start tag
diff --git a/tests/robotests/src/com/android/settings/development/CbrsDataSwitchPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/development/CbrsDataSwitchPreferenceControllerTest.java
deleted file mode 100644
index d955a6e..0000000
--- a/tests/robotests/src/com/android/settings/development/CbrsDataSwitchPreferenceControllerTest.java
+++ /dev/null
@@ -1,87 +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 org.mockito.Mockito.when;
-import static com.google.common.truth.Truth.assertThat;
-
-import android.content.Context;
-import android.telephony.TelephonyManager;
-
-import androidx.preference.PreferenceScreen;
-import androidx.preference.SwitchPreference;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-import org.robolectric.RobolectricTestRunner;
-import org.robolectric.RuntimeEnvironment;
-
-@RunWith(RobolectricTestRunner.class)
-public final class CbrsDataSwitchPreferenceControllerTest {
-
-    @Mock
-    private PreferenceScreen mPreferenceScreen;
-    private Context mContext;
-    private TelephonyManager mTelephonyManager;
-    private SwitchPreference mPreference;
-    private CbrsDataSwitchPreferenceController mController;
-
-    @Before
-    public void setUp() {
-        MockitoAnnotations.initMocks(this);
-        mContext = RuntimeEnvironment.application;
-        mController = new CbrsDataSwitchPreferenceController(mContext);
-        mPreference = new SwitchPreference(mContext);
-        when(mPreferenceScreen.findPreference(mController.getPreferenceKey()))
-            .thenReturn(mPreference);
-        mTelephonyManager = mContext.getSystemService(TelephonyManager.class);
-        mController.displayPreference(mPreferenceScreen);
-    }
-
-    @Test
-    public void onPreferenceChanged_settingEnabled_shouldEnableANAS() {
-        mController.onPreferenceChange(mPreference, true);
-
-        assertThat(mTelephonyManager.isAlternativeNetworkEnabled()).isTrue();
-    }
-
-    @Test
-    public void onPreferenceChanged_settingDisabled_shouldDisableANAS() {
-        mController.onPreferenceChange(mPreference, false);
-
-        assertThat(mTelephonyManager.isAlternativeNetworkEnabled()).isFalse();
-    }
-
-    @Test
-    public void updateState_settingEnabled_shouldEnablePreference() {
-        mTelephonyManager.setAlternativeNetworkState(true);
-        mController.updateState(mPreference);
-
-        assertThat(mPreference.isChecked()).isTrue();
-    }
-
-    @Test
-    public void updateState_settingDisabled_shouldDisablePreference() {
-        mTelephonyManager.setAlternativeNetworkState(false);
-        mController.updateState(mPreference);
-
-        assertThat(mPreference.isChecked()).isFalse();
-    }
-}
diff --git a/tests/robotests/src/com/android/settings/development/ClearAdbKeysPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/development/ClearAdbKeysPreferenceControllerTest.java
index 3dc6ad9..770dd60 100644
--- a/tests/robotests/src/com/android/settings/development/ClearAdbKeysPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/development/ClearAdbKeysPreferenceControllerTest.java
@@ -16,9 +16,6 @@
 
 package com.android.settings.development;
 
-import static com.android.settings.development.ClearAdbKeysPreferenceController
-        .RO_ADB_SECURE_PROPERTY_KEY;
-
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.mockito.Mockito.doReturn;
@@ -30,7 +27,7 @@
 import android.content.Context;
 import android.debug.IAdbManager;
 import android.os.RemoteException;
-import android.os.SystemProperties;
+import android.sysprop.AdbProperties;
 
 import androidx.fragment.app.Fragment;
 import androidx.preference.PreferenceScreen;
@@ -83,21 +80,21 @@
 
     @Test
     public void isAvailable_roAdbSecureEnabled_shouldBeTrue() {
-        SystemProperties.set(RO_ADB_SECURE_PROPERTY_KEY, Boolean.toString(true));
+        AdbProperties.secure(true);
 
         assertThat(mController.isAvailable()).isTrue();
     }
 
     @Test
     public void isAvailable_roAdbSecureDisabled_shouldBeFalse() {
-        SystemProperties.set(RO_ADB_SECURE_PROPERTY_KEY, Boolean.toString(false));
+        AdbProperties.secure(false);
 
         assertThat(mController.isAvailable()).isFalse();
     }
 
     @Test
     public void displayPreference_isNotAdminUser_preferenceShouldBeDisabled() {
-        SystemProperties.set(RO_ADB_SECURE_PROPERTY_KEY, Boolean.toString(true));
+        AdbProperties.secure(true);
         doReturn(false).when(mController).isAdminUser();
 
         mController.displayPreference(mScreen);
@@ -108,7 +105,7 @@
     @Test
     @Config(shadows = ShadowClearAdbKeysWarningDialog.class)
     public void handlePreferenceTreeClick_clearAdbKeysPreference_shouldShowWarningDialog() {
-        SystemProperties.set(RO_ADB_SECURE_PROPERTY_KEY, Boolean.toString(true));
+        AdbProperties.secure(true);
         doReturn(true).when(mController).isAdminUser();
         mController.displayPreference(mScreen);
         final String preferenceKey = mController.getPreferenceKey();
@@ -121,7 +118,7 @@
 
     @Test
     public void handlePreferenceTreeClick_notClearAdbKeysPreference_shouldReturnFalse() {
-        SystemProperties.set(RO_ADB_SECURE_PROPERTY_KEY, Boolean.toString(true));
+        AdbProperties.secure(true);
         doReturn(true).when(mController).isAdminUser();
         mController.displayPreference(mScreen);
         when(mPreference.getKey()).thenReturn("Some random key!!!");
@@ -132,7 +129,7 @@
 
     @Test
     public void handlePreferenceTreeClick_monkeyUser_shouldReturnFalse() {
-        SystemProperties.set(RO_ADB_SECURE_PROPERTY_KEY, Boolean.toString(true));
+        AdbProperties.secure(true);
         doReturn(true).when(mController).isAdminUser();
         ShadowUtils.setIsUserAMonkey(true);
         mController.displayPreference(mScreen);
@@ -146,7 +143,7 @@
 
     @Test
     public void onDeveloperOptionsSwitchEnabled_isAdminUser_shouldEnablePreference() {
-        SystemProperties.set(RO_ADB_SECURE_PROPERTY_KEY, Boolean.toString(true));
+        AdbProperties.secure(true);
         doReturn(true).when(mController).isAdminUser();
         mController.displayPreference(mScreen);
         mController.onDeveloperOptionsSwitchEnabled();
@@ -156,7 +153,7 @@
 
     @Test
     public void onDeveloperOptionsSwitchEnabled_isNotAdminUser_shouldNotEnablePreference() {
-        SystemProperties.set(RO_ADB_SECURE_PROPERTY_KEY, Boolean.toString(true));
+        AdbProperties.secure(true);
         doReturn(false).when(mController).isAdminUser();
         mController.displayPreference(mScreen);
         mController.onDeveloperOptionsSwitchEnabled();
diff --git a/tests/robotests/src/com/android/settings/development/MockLocationAppPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/development/MockLocationAppPreferenceControllerTest.java
index b0de024..73c0d8e 100644
--- a/tests/robotests/src/com/android/settings/development/MockLocationAppPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/development/MockLocationAppPreferenceControllerTest.java
@@ -74,7 +74,7 @@
         final AppOpsManager.PackageOps packageOps =
                 new AppOpsManager.PackageOps(appName, 0,
                         Collections.singletonList(createOpEntry(AppOpsManager.MODE_ALLOWED)));
-        when(mAppOpsManager.getPackagesForOps(any())).thenReturn(
+        when(mAppOpsManager.getPackagesForOps(any(int[].class))).thenReturn(
                 Collections.singletonList(packageOps));
 
         mController.updateState(mPreference);
@@ -84,7 +84,8 @@
 
     @Test
     public void updateState_noAppSelected_shouldSetSummaryToDefault() {
-        when(mAppOpsManager.getPackagesForOps(any())).thenReturn(Collections.emptyList());
+        when(mAppOpsManager.getPackagesForOps(any(int[].class)))
+                .thenReturn(Collections.emptyList());
 
         mController.updateState(mPreference);
 
@@ -101,7 +102,7 @@
         final AppOpsManager.PackageOps packageOps = new AppOpsManager.PackageOps(prevAppName, 0,
                 Collections.singletonList(createOpEntry(AppOpsManager.MODE_ALLOWED)));
 
-        when(mAppOpsManager.getPackagesForOps(any()))
+        when(mAppOpsManager.getPackagesForOps(any(int[].class)))
                 .thenReturn(Collections.singletonList(packageOps));
         when(mPackageManager.getApplicationInfo(anyString(),
                 eq(PackageManager.MATCH_DISABLED_COMPONENTS))).thenReturn(mApplicationInfo);
diff --git a/tests/robotests/src/com/android/settings/development/gup/GupPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/development/gup/GupPreferenceControllerTest.java
index 62e3475..d5e7a85 100644
--- a/tests/robotests/src/com/android/settings/development/gup/GupPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/development/gup/GupPreferenceControllerTest.java
@@ -52,7 +52,7 @@
 public class GupPreferenceControllerTest {
     private static final int DEFAULT = 0;
     private static final int GUP = 1;
-    private static final int NATIVE = 2;
+    private static final int SYSTEM = 2;
     private static final String TEST_APP_NAME = "testApp";
     private static final String TEST_PKG_NAME = "testPkg";
 
@@ -143,7 +143,7 @@
     }
 
     @Test
-    public void createPreference_configNative_shouldSetNativeAttributes() {
+    public void createPreference_configSystem_shouldSetSystemAttributes() {
         loadConfig("", TEST_PKG_NAME);
         final ListPreference preference =
                 mController.createListPreference(TEST_PKG_NAME, TEST_APP_NAME);
@@ -153,9 +153,9 @@
         assertThat(preference.getDialogTitle()).isEqualTo(mDialogTitle);
         assertThat(preference.getEntries()).isEqualTo(mValueList);
         assertThat(preference.getEntryValues()).isEqualTo(mValueList);
-        assertThat(preference.getEntry()).isEqualTo(mValueList[NATIVE]);
-        assertThat(preference.getValue()).isEqualTo(mValueList[NATIVE]);
-        assertThat(preference.getSummary()).isEqualTo(mValueList[NATIVE]);
+        assertThat(preference.getEntry()).isEqualTo(mValueList[SYSTEM]);
+        assertThat(preference.getValue()).isEqualTo(mValueList[SYSTEM]);
+        assertThat(preference.getSummary()).isEqualTo(mValueList[SYSTEM]);
     }
 
     @Test
@@ -165,6 +165,8 @@
                 mController.createListPreference(TEST_PKG_NAME, TEST_APP_NAME);
         mController.onPreferenceChange(preference, mValueList[DEFAULT]);
 
+        assertThat(preference.getEntry()).isEqualTo(mValueList[DEFAULT]);
+        assertThat(preference.getValue()).isEqualTo(mValueList[DEFAULT]);
         assertThat(preference.getSummary()).isEqualTo(mValueList[DEFAULT]);
         assertThat(Settings.Global.getString(mResolver, Settings.Global.GUP_DEV_OPT_IN_APPS))
                 .isEqualTo("");
@@ -179,6 +181,8 @@
                 mController.createListPreference(TEST_PKG_NAME, TEST_APP_NAME);
         mController.onPreferenceChange(preference, mValueList[GUP]);
 
+        assertThat(preference.getEntry()).isEqualTo(mValueList[GUP]);
+        assertThat(preference.getValue()).isEqualTo(mValueList[GUP]);
         assertThat(preference.getSummary()).isEqualTo(mValueList[GUP]);
         assertThat(Settings.Global.getString(mResolver, Settings.Global.GUP_DEV_OPT_IN_APPS))
                 .isEqualTo(TEST_PKG_NAME);
@@ -187,13 +191,15 @@
     }
 
     @Test
-    public void onPreferenceChange_selectNative_shouldUpdateAttributesAndSettingsGlobal() {
+    public void onPreferenceChange_selectSystem_shouldUpdateAttributesAndSettingsGlobal() {
         loadDefaultConfig();
         final ListPreference preference =
                 mController.createListPreference(TEST_PKG_NAME, TEST_APP_NAME);
-        mController.onPreferenceChange(preference, mValueList[NATIVE]);
+        mController.onPreferenceChange(preference, mValueList[SYSTEM]);
 
-        assertThat(preference.getSummary()).isEqualTo(mValueList[NATIVE]);
+        assertThat(preference.getEntry()).isEqualTo(mValueList[SYSTEM]);
+        assertThat(preference.getValue()).isEqualTo(mValueList[SYSTEM]);
+        assertThat(preference.getSummary()).isEqualTo(mValueList[SYSTEM]);
         assertThat(Settings.Global.getString(mResolver, Settings.Global.GUP_DEV_OPT_IN_APPS))
                 .isEqualTo("");
         assertThat(Settings.Global.getString(mResolver, Settings.Global.GUP_DEV_OPT_OUT_APPS))
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/RestrictAppPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/fuelgauge/RestrictAppPreferenceControllerTest.java
index 3746d64..368a93a 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/RestrictAppPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/RestrictAppPreferenceControllerTest.java
@@ -111,7 +111,7 @@
     @Test
     public void testUpdateState_oneApp_showCorrectSummary() {
         mPackageOpsList.add(mRestrictedPackageOps);
-        doReturn(mPackageOpsList).when(mAppOpsManager).getPackagesForOps(any());
+        doReturn(mPackageOpsList).when(mAppOpsManager).getPackagesForOps(any(int[].class));
 
         mRestrictAppPreferenceController.updateState(mPreference);
 
@@ -124,7 +124,7 @@
         mPackageOpsList.add(mRestrictedPackageOps);
         mPackageOpsList.add(mAllowedPackageOps);
         mPackageOpsList.add(mOtherUserPackageOps);
-        doReturn(mPackageOpsList).when(mAppOpsManager).getPackagesForOps(any());
+        doReturn(mPackageOpsList).when(mAppOpsManager).getPackagesForOps(any(int[].class));
 
         mRestrictAppPreferenceController.updateState(mPreference);
 
@@ -137,7 +137,7 @@
         // Two packageOps share same package name but different uid.
         mPackageOpsList.add(mRestrictedPackageOps);
         mPackageOpsList.add(mOtherUserPackageOps);
-        doReturn(mPackageOpsList).when(mAppOpsManager).getPackagesForOps(any());
+        doReturn(mPackageOpsList).when(mAppOpsManager).getPackagesForOps(any(int[].class));
 
         mRestrictAppPreferenceController.updateState(mPreference);
 
@@ -152,7 +152,7 @@
     @Test
     public void testUpdateState_zeroRestrictApp_inVisible() {
         mPackageOpsList.add(mAllowedPackageOps);
-        doReturn(mPackageOpsList).when(mAppOpsManager).getPackagesForOps(any());
+        doReturn(mPackageOpsList).when(mAppOpsManager).getPackagesForOps(any(int[].class));
 
         mRestrictAppPreferenceController.updateState(mPreference);
 
diff --git a/tests/robotests/src/com/android/settings/notification/ChannelSummaryPreferenceTest.java b/tests/robotests/src/com/android/settings/notification/ChannelSummaryPreferenceTest.java
new file mode 100644
index 0000000..408b2b6
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/notification/ChannelSummaryPreferenceTest.java
@@ -0,0 +1,169 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.notification;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+
+import android.content.Context;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.CheckBox;
+import android.widget.LinearLayout;
+
+import com.android.settings.R;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+
+import androidx.preference.Preference;
+import androidx.preference.PreferenceViewHolder;
+
+@RunWith(RobolectricTestRunner.class)
+public class ChannelSummaryPreferenceTest {
+
+    private Context mContext;
+
+    @Before
+    public void setUp() {
+        mContext = RuntimeEnvironment.application;
+    }
+
+    @Test
+    public void createNewPreference_shouldSetLayout() {
+        final ChannelSummaryPreference preference = new ChannelSummaryPreference(mContext);
+        assertThat(preference.getLayoutResource()).isEqualTo(
+                R.layout.preference_checkable_two_target);
+        assertThat(preference.getWidgetLayoutResource()).isEqualTo(
+                R.layout.zen_rule_widget);
+    }
+
+    @Test
+    public void setChecked_shouldUpdateButtonCheckedState() {
+        final ChannelSummaryPreference preference = new ChannelSummaryPreference(mContext);
+        final LayoutInflater inflater = LayoutInflater.from(mContext);
+        final PreferenceViewHolder holder = PreferenceViewHolder.createInstanceForTests(
+                inflater.inflate(R.layout.preference_checkable_two_target, null));
+        final LinearLayout widgetView = holder.itemView.findViewById(R.id.checkbox_container);
+        inflater.inflate(R.layout.preference_widget_checkbox, widgetView, true);
+        final CheckBox toggle = (CheckBox) holder.findViewById(com.android.internal.R.id.checkbox);
+        preference.onBindViewHolder(holder);
+
+        preference.setChecked(true);
+        assertThat(toggle.isChecked()).isTrue();
+
+        preference.setChecked(false);
+        assertThat(toggle.isChecked()).isFalse();
+    }
+
+    @Test
+    public void setCheckboxEnabled_shouldUpdateButtonEnabledState() {
+        final ChannelSummaryPreference preference = new ChannelSummaryPreference(mContext);
+        final LayoutInflater inflater = LayoutInflater.from(mContext);
+        final PreferenceViewHolder holder = PreferenceViewHolder.createInstanceForTests(
+                inflater.inflate(R.layout.preference_checkable_two_target, null));
+        final LinearLayout widgetView = holder.itemView.findViewById(R.id.checkbox_container);
+        inflater.inflate(R.layout.preference_widget_checkbox, widgetView, true);
+        final CheckBox toggle = (CheckBox) holder.findViewById(com.android.internal.R.id.checkbox);
+        preference.onBindViewHolder(holder);
+
+        preference.setCheckBoxEnabled(true);
+        assertThat(toggle.isEnabled()).isTrue();
+
+        preference.setCheckBoxEnabled(false);
+        assertThat(toggle.isEnabled()).isFalse();
+    }
+
+    @Test
+    public void setCheckBoxEnabled_shouldUpdateButtonEnabledState_beforeViewBound() {
+        final ChannelSummaryPreference preference = new ChannelSummaryPreference(mContext);
+        final LayoutInflater inflater = LayoutInflater.from(mContext);
+        final PreferenceViewHolder holder = PreferenceViewHolder.createInstanceForTests(
+                inflater.inflate(R.layout.preference_checkable_two_target, null));
+        final LinearLayout widgetView = holder.itemView.findViewById(R.id.checkbox_container);
+        inflater.inflate(R.layout.preference_widget_checkbox, widgetView, true);
+        final CheckBox toggle = (CheckBox) holder.findViewById(com.android.internal.R.id.checkbox);
+
+        preference.setCheckBoxEnabled(false);
+        preference.onBindViewHolder(holder);
+        assertThat(toggle.isEnabled()).isFalse();
+    }
+
+    @Test
+    public void clickWidgetView_shouldToggleButton() {
+        final ChannelSummaryPreference preference = new ChannelSummaryPreference(mContext);
+        final LayoutInflater inflater = LayoutInflater.from(mContext);
+        final PreferenceViewHolder holder = PreferenceViewHolder.createInstanceForTests(
+                inflater.inflate(R.layout.preference_checkable_two_target, null));
+        final LinearLayout widgetView = holder.itemView.findViewById(R.id.checkbox_container);
+        assertThat(widgetView).isNotNull();
+
+        inflater.inflate(R.layout.preference_widget_checkbox, widgetView, true);
+        final CheckBox toggle = (CheckBox) holder.findViewById(com.android.internal.R.id.checkbox);
+        preference.onBindViewHolder(holder);
+
+        widgetView.performClick();
+        assertThat(toggle.isChecked()).isTrue();
+
+        widgetView.performClick();
+        assertThat(toggle.isChecked()).isFalse();
+    }
+
+    @Test
+    public void clickWidgetView_shouldNotToggleButtonIfDisabled() {
+        final ChannelSummaryPreference preference = new ChannelSummaryPreference(mContext);
+        final LayoutInflater inflater = LayoutInflater.from(mContext);
+        final PreferenceViewHolder holder = PreferenceViewHolder.createInstanceForTests(
+                inflater.inflate(R.layout.preference_checkable_two_target, null));
+        final LinearLayout widgetView = holder.itemView.findViewById(R.id.checkbox_container);
+        assertThat(widgetView).isNotNull();
+
+        inflater.inflate(R.layout.preference_widget_checkbox, widgetView, true);
+        final CheckBox toggle = (CheckBox) holder.findViewById(com.android.internal.R.id.checkbox);
+        preference.onBindViewHolder(holder);
+        toggle.setEnabled(false);
+
+        widgetView.performClick();
+        assertThat(toggle.isChecked()).isFalse();
+    }
+
+    @Test
+    public void clickWidgetView_shouldNotifyPreferenceChanged() {
+        final ChannelSummaryPreference preference = new ChannelSummaryPreference(mContext);
+        final PreferenceViewHolder holder = PreferenceViewHolder.createInstanceForTests(
+                LayoutInflater.from(mContext).inflate(
+                        R.layout.preference_checkable_two_target, null));
+        final View widgetView = holder.findViewById(R.id.checkbox_container);
+        final Preference.OnPreferenceChangeListener
+                listener = mock(Preference.OnPreferenceChangeListener.class);
+        preference.setOnPreferenceChangeListener(listener);
+        preference.onBindViewHolder(holder);
+
+        preference.setChecked(false);
+        widgetView.performClick();
+        verify(listener).onPreferenceChange(preference, true);
+
+        preference.setChecked(true);
+        widgetView.performClick();
+        verify(listener).onPreferenceChange(preference, false);
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/slices/SliceBuilderUtilsTest.java b/tests/robotests/src/com/android/settings/slices/SliceBuilderUtilsTest.java
index 2d893a6..c2d1e93 100644
--- a/tests/robotests/src/com/android/settings/slices/SliceBuilderUtilsTest.java
+++ b/tests/robotests/src/com/android/settings/slices/SliceBuilderUtilsTest.java
@@ -449,7 +449,7 @@
                 R.drawable.ic_settings).toIcon().getResId();
         final SliceData data = getDummyData(FakeUnavailablePreferenceController.class,
                 SUMMARY, SliceData.SliceType.SWITCH, SCREEN_TITLE, 0 /* icon */,
-                IS_DYNAMIC_SUMMARY_ALLOWED);
+                IS_DYNAMIC_SUMMARY_ALLOWED, null /* unavailableSliceSubtitle */);
         Settings.Global.putInt(mContext.getContentResolver(),
                 FakeUnavailablePreferenceController.AVAILABILITY_KEY,
                 BasePreferenceController.DISABLED_DEPENDENT_SETTING);
@@ -518,33 +518,65 @@
         assertThat(actualIconResource).isEqualTo(settingsIcon);
     }
 
+    @Test
+    public void buildUnavailableSlice_customizeSubtitle_returnsSliceWithCustomizedSubtitle() {
+        final String subtitleOfUnavailableSlice = "subtitleOfUnavailableSlice";
+        final SliceData data = getDummyData(FakeUnavailablePreferenceController.class,
+                SUMMARY, SliceData.SliceType.SWITCH, SCREEN_TITLE, 0 /* icon */,
+                IS_DYNAMIC_SUMMARY_ALLOWED, subtitleOfUnavailableSlice);
+        Settings.Global.putInt(mContext.getContentResolver(),
+                FakeUnavailablePreferenceController.AVAILABILITY_KEY,
+                BasePreferenceController.DISABLED_DEPENDENT_SETTING);
+
+        final Slice slice = SliceBuilderUtils.buildSlice(mContext, data);
+
+        final SliceMetadata metadata = SliceMetadata.from(mContext, slice);
+        assertThat(metadata.getSubtitle()).isEqualTo(subtitleOfUnavailableSlice);
+    }
+
+    @Test
+    public void buildUnavailableSlice_notCustomizeSubtitle_returnsSliceWithDefaultSubtitle() {
+        final SliceData data = getDummyData(FakeUnavailablePreferenceController.class,
+                SliceData.SliceType.SWITCH);
+        Settings.Global.putInt(mContext.getContentResolver(),
+                FakeUnavailablePreferenceController.AVAILABILITY_KEY,
+                BasePreferenceController.DISABLED_DEPENDENT_SETTING);
+
+        final Slice slice = SliceBuilderUtils.buildSlice(mContext, data);
+
+        final SliceMetadata metadata = SliceMetadata.from(mContext, slice);
+        assertThat(metadata.getSubtitle()).isEqualTo(
+                mContext.getString(R.string.disabled_dependent_setting_summary));
+    }
+
     private SliceData getDummyData() {
         return getDummyData(TOGGLE_CONTROLLER, SUMMARY, SliceData.SliceType.SWITCH, SCREEN_TITLE,
-                ICON, IS_DYNAMIC_SUMMARY_ALLOWED);
+                ICON, IS_DYNAMIC_SUMMARY_ALLOWED, null /* unavailableSliceSubtitle */);
     }
 
     private SliceData getDummyData(boolean isDynamicSummaryAllowed) {
         return getDummyData(TOGGLE_CONTROLLER, SUMMARY, SliceData.SliceType.SWITCH, SCREEN_TITLE,
-                ICON, isDynamicSummaryAllowed);
+                ICON, isDynamicSummaryAllowed, null /* unavailableSliceSubtitle */);
     }
 
     private SliceData getDummyData(Class prefController, int sliceType, int icon) {
-        return getDummyData(TOGGLE_CONTROLLER, SUMMARY, SliceData.SliceType.SWITCH, SCREEN_TITLE,
-                icon, IS_DYNAMIC_SUMMARY_ALLOWED);
+        return getDummyData(prefController, SUMMARY, sliceType, SCREEN_TITLE,
+                icon, IS_DYNAMIC_SUMMARY_ALLOWED, null /* unavailableSliceSubtitle */);
     }
 
     private SliceData getDummyData(String summary, String screenTitle) {
         return getDummyData(TOGGLE_CONTROLLER, summary, SliceData.SliceType.SWITCH, screenTitle,
-                ICON, IS_DYNAMIC_SUMMARY_ALLOWED);
+                ICON, IS_DYNAMIC_SUMMARY_ALLOWED, null /* unavailableSliceSubtitle */);
     }
 
     private SliceData getDummyData(Class prefController, int sliceType) {
         return getDummyData(prefController, SUMMARY, sliceType, SCREEN_TITLE, ICON,
-                IS_DYNAMIC_SUMMARY_ALLOWED);
+                IS_DYNAMIC_SUMMARY_ALLOWED, null /* unavailableSliceSubtitle */);
     }
 
     private SliceData getDummyData(Class prefController, String summary, int sliceType,
-            String screenTitle, int icon, boolean isDynamicSummaryAllowed) {
+            String screenTitle, int icon, boolean isDynamicSummaryAllowed,
+            String unavailableSliceSubtitle) {
         return new SliceData.Builder()
                 .setKey(KEY)
                 .setTitle(TITLE)
@@ -557,6 +589,7 @@
                 .setPreferenceControllerClassName(prefController.getName())
                 .setSliceType(sliceType)
                 .setDynamicSummaryAllowed(isDynamicSummaryAllowed)
+                .setUnavailableSliceSubtitle(unavailableSliceSubtitle)
                 .build();
     }
 }
diff --git a/tests/robotests/src/com/android/settings/slices/SliceDataConverterTest.java b/tests/robotests/src/com/android/settings/slices/SliceDataConverterTest.java
index b935e76..7c1319c 100644
--- a/tests/robotests/src/com/android/settings/slices/SliceDataConverterTest.java
+++ b/tests/robotests/src/com/android/settings/slices/SliceDataConverterTest.java
@@ -125,6 +125,8 @@
         assertThat(fakeSlice.getSliceType()).isEqualTo(SliceData.SliceType.SLIDER);
         assertThat(fakeSlice.isPlatformDefined()).isTrue(); // from XML
         assertThat(fakeSlice.isDynamicSummaryAllowed()).isTrue(); // from XML
+        assertThat(fakeSlice.getUnavailableSliceSubtitle()).isEqualTo(
+                "subtitleOfUnavailableSlice"); // from XML
     }
 
     private void assertFakeA11ySlice(SliceData fakeSlice) {
diff --git a/tests/robotests/src/com/android/settings/slices/SliceDataTest.java b/tests/robotests/src/com/android/settings/slices/SliceDataTest.java
index 579af1f..b6c7af5 100644
--- a/tests/robotests/src/com/android/settings/slices/SliceDataTest.java
+++ b/tests/robotests/src/com/android/settings/slices/SliceDataTest.java
@@ -39,6 +39,7 @@
     private final int SLICE_TYPE = SliceData.SliceType.SWITCH;
     private final boolean IS_PLATFORM_DEFINED = true;
     private final boolean IS_DYNAMIC_SUMMARY_ALLOWED = true;
+    private final String UNAVAILABLE_SLICE_SUBTITLE = "subtitleOfUnavailableSlice";
 
     @Test
     public void testBuilder_buildsMatchingObject() {
@@ -54,7 +55,8 @@
                 .setPreferenceControllerClassName(PREF_CONTROLLER)
                 .setSliceType(SLICE_TYPE)
                 .setPlatformDefined(IS_PLATFORM_DEFINED)
-                .setDynamicSummaryAllowed(IS_DYNAMIC_SUMMARY_ALLOWED);
+                .setDynamicSummaryAllowed(IS_DYNAMIC_SUMMARY_ALLOWED)
+                .setUnavailableSliceSubtitle(UNAVAILABLE_SLICE_SUBTITLE);
 
         SliceData data = builder.build();
 
@@ -70,6 +72,7 @@
         assertThat(data.getSliceType()).isEqualTo(SLICE_TYPE);
         assertThat(data.isPlatformDefined()).isEqualTo(IS_PLATFORM_DEFINED);
         assertThat(data.isDynamicSummaryAllowed()).isEqualTo(IS_DYNAMIC_SUMMARY_ALLOWED);
+        assertThat(data.getUnavailableSliceSubtitle()).isEqualTo(UNAVAILABLE_SLICE_SUBTITLE);
     }
 
     @Test(expected = SliceData.InvalidSliceDataException.class)
diff --git a/tests/robotests/src/com/android/settings/slices/SlicesDatabaseAccessorTest.java b/tests/robotests/src/com/android/settings/slices/SlicesDatabaseAccessorTest.java
index f4b68a5..a657ede 100644
--- a/tests/robotests/src/com/android/settings/slices/SlicesDatabaseAccessorTest.java
+++ b/tests/robotests/src/com/android/settings/slices/SlicesDatabaseAccessorTest.java
@@ -109,12 +109,14 @@
         assertThat(data.getUri()).isNull();
         assertThat(data.getPreferenceController()).isEqualTo(FAKE_CONTROLLER_NAME);
         assertThat(data.isDynamicSummaryAllowed()).isFalse(); /* default value */
+        assertThat(data.getUnavailableSliceSubtitle()).isNull();
     }
 
     @Test
     public void testGetSliceDataFromKey_allowDynamicSummary_validSliceReturned() {
         String key = "key";
-        insertSpecialCase(key, true /* isPlatformSlice */, true /* isDynamicSummaryAllowed */);
+        insertSpecialCase(key, true /* isPlatformSlice */, true /* isDynamicSummaryAllowed */,
+                null /* customizedUnavailableSliceSubtitle */);
 
         SliceData data = mAccessor.getSliceDataFromKey(key);
 
@@ -133,7 +135,8 @@
     @Test
     public void testGetSliceDataFromKey_doNotAllowDynamicSummary_validSliceReturned() {
         String key = "key";
-        insertSpecialCase(key, true /* isPlatformSlice */, false /* isDynamicSummaryAllowed */);
+        insertSpecialCase(key, true /* isPlatformSlice */, false /* isDynamicSummaryAllowed */,
+                null /* customizedUnavailableSliceSubtitle */);
 
         SliceData data = mAccessor.getSliceDataFromKey(key);
 
@@ -243,16 +246,58 @@
         assertThat(keys).isNotEmpty();
     }
 
+    @Test
+    public void testGetSliceDataFromKey_defaultUnavailableSlice_validSliceReturned() {
+        String key = "key";
+        insertSpecialCase(key, true /* isPlatformSlice */, true /* isDynamicSummaryAllowed */,
+                null /* customizedUnavailableSliceSubtitle */);
+
+        SliceData data = mAccessor.getSliceDataFromKey(key);
+
+        assertThat(data.getKey()).isEqualTo(key);
+        assertThat(data.getTitle()).isEqualTo(FAKE_TITLE);
+        assertThat(data.getSummary()).isEqualTo(FAKE_SUMMARY);
+        assertThat(data.getScreenTitle()).isEqualTo(FAKE_SCREEN_TITLE);
+        assertThat(data.getKeywords()).isEqualTo(FAKE_KEYWORDS);
+        assertThat(data.getIconResource()).isEqualTo(FAKE_ICON);
+        assertThat(data.getFragmentClassName()).isEqualTo(FAKE_FRAGMENT_NAME);
+        assertThat(data.getUri()).isNull();
+        assertThat(data.getPreferenceController()).isEqualTo(FAKE_CONTROLLER_NAME);
+        assertThat(data.getUnavailableSliceSubtitle()).isNull();
+    }
+
+    @Test
+    public void testGetSliceDataFromKey_customizeSubtitleOfUnavailableSlice_validSliceReturned() {
+        String key = "key";
+        String subtitle = "subtitle";
+        insertSpecialCase(key, true /* isPlatformSlice */, true /* isDynamicSummaryAllowed */,
+                subtitle);
+
+        SliceData data = mAccessor.getSliceDataFromKey(key);
+
+        assertThat(data.getKey()).isEqualTo(key);
+        assertThat(data.getTitle()).isEqualTo(FAKE_TITLE);
+        assertThat(data.getSummary()).isEqualTo(FAKE_SUMMARY);
+        assertThat(data.getScreenTitle()).isEqualTo(FAKE_SCREEN_TITLE);
+        assertThat(data.getKeywords()).isEqualTo(FAKE_KEYWORDS);
+        assertThat(data.getIconResource()).isEqualTo(FAKE_ICON);
+        assertThat(data.getFragmentClassName()).isEqualTo(FAKE_FRAGMENT_NAME);
+        assertThat(data.getUri()).isNull();
+        assertThat(data.getPreferenceController()).isEqualTo(FAKE_CONTROLLER_NAME);
+        assertThat(data.getUnavailableSliceSubtitle()).isEqualTo(subtitle);
+    }
+
     private void insertSpecialCase(String key) {
         insertSpecialCase(key, true);
     }
 
     private void insertSpecialCase(String key, boolean isPlatformSlice) {
-        insertSpecialCase(key, isPlatformSlice, false /* isDynamicSummaryAllowed */);
+        insertSpecialCase(key, isPlatformSlice, false /* isDynamicSummaryAllowed */,
+                null /*customizedUnavailableSliceSubtitle*/);
     }
 
     private void insertSpecialCase(String key, boolean isPlatformSlice,
-            boolean isDynamicSummaryAllowed) {
+            boolean isDynamicSummaryAllowed, String customizedUnavailableSliceSubtitle) {
         ContentValues values = new ContentValues();
         values.put(SlicesDatabaseHelper.IndexColumns.KEY, key);
         values.put(SlicesDatabaseHelper.IndexColumns.TITLE, FAKE_TITLE);
@@ -266,6 +311,8 @@
         values.put(SlicesDatabaseHelper.IndexColumns.ALLOW_DYNAMIC_SUMMARY_IN_SLICE,
                 isDynamicSummaryAllowed);
         values.put(SlicesDatabaseHelper.IndexColumns.SLICE_TYPE, SliceData.SliceType.INTENT);
+        values.put(SlicesDatabaseHelper.IndexColumns.UNAVAILABLE_SLICE_SUBTITLE,
+                customizedUnavailableSliceSubtitle);
 
         mDb.replaceOrThrow(SlicesDatabaseHelper.Tables.TABLE_SLICES_INDEX, null, values);
     }
diff --git a/tests/robotests/src/com/android/settings/slices/SlicesDatabaseHelperTest.java b/tests/robotests/src/com/android/settings/slices/SlicesDatabaseHelperTest.java
index 2bc3443..0e92c05 100644
--- a/tests/robotests/src/com/android/settings/slices/SlicesDatabaseHelperTest.java
+++ b/tests/robotests/src/com/android/settings/slices/SlicesDatabaseHelperTest.java
@@ -74,6 +74,7 @@
                 IndexColumns.PLATFORM_SLICE,
                 IndexColumns.SLICE_TYPE,
                 IndexColumns.ALLOW_DYNAMIC_SUMMARY_IN_SLICE,
+                IndexColumns.UNAVAILABLE_SLICE_SUBTITLE,
         };
 
         assertThat(columnNames).isEqualTo(expectedNames);
diff --git a/tests/robotests/src/com/android/settings/slices/SlicesIndexerTest.java b/tests/robotests/src/com/android/settings/slices/SlicesIndexerTest.java
index 827c3f6..b63dfd9 100644
--- a/tests/robotests/src/com/android/settings/slices/SlicesIndexerTest.java
+++ b/tests/robotests/src/com/android/settings/slices/SlicesIndexerTest.java
@@ -55,6 +55,7 @@
     private final boolean PLATFORM_DEFINED = true;
     private final boolean IS_DYNAMIC_SUMMARY_ALLOWED = true;
     private final int SLICE_TYPE = SliceData.SliceType.SLIDER;
+    private final String UNAVAILABLE_SLICE_SUBTITLE = "subtitleOfUnavailableSlice";
 
     private Context mContext;
 
@@ -145,6 +146,9 @@
                         cursor.getColumnIndex(
                                 IndexColumns.ALLOW_DYNAMIC_SUMMARY_IN_SLICE)))
                         .isEqualTo(1 /* true */);
+                assertThat(cursor.getString(
+                        cursor.getColumnIndex(IndexColumns.UNAVAILABLE_SLICE_SUBTITLE)))
+                        .isEqualTo(UNAVAILABLE_SLICE_SUBTITLE);
                 cursor.moveToNext();
             }
         } finally {
@@ -179,7 +183,8 @@
                 .setPreferenceControllerClassName(PREF_CONTROLLER)
                 .setPlatformDefined(PLATFORM_DEFINED)
                 .setSliceType(SLICE_TYPE)
-                .setDynamicSummaryAllowed(IS_DYNAMIC_SUMMARY_ALLOWED);
+                .setDynamicSummaryAllowed(IS_DYNAMIC_SUMMARY_ALLOWED)
+                .setUnavailableSliceSubtitle(UNAVAILABLE_SLICE_SUBTITLE);
 
         for (int i = 0; i < KEYS.length; i++) {
             builder.setKey(KEYS[i]).setTitle(TITLES[i]);
diff --git a/tests/unit/src/com/android/settings/dashboard/UiBlockerControllerTest.java b/tests/unit/src/com/android/settings/dashboard/UiBlockerControllerTest.java
new file mode 100644
index 0000000..c3a7a4e
--- /dev/null
+++ b/tests/unit/src/com/android/settings/dashboard/UiBlockerControllerTest.java
@@ -0,0 +1,69 @@
+/*
+ * 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.dashboard;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.app.Instrumentation;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.MediumTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Arrays;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+@RunWith(AndroidJUnit4.class)
+@MediumTest
+public class UiBlockerControllerTest {
+    private static final long TIMEOUT = 600;
+    private static final String KEY_1 = "key1";
+    private static final String KEY_2 = "key2";
+
+    private Instrumentation mInstrumentation;
+    private UiBlockerController mSyncableController;
+
+    @Before
+    public void setUp() throws Exception {
+        mInstrumentation = InstrumentationRegistry.getInstrumentation();
+
+        mSyncableController = new UiBlockerController(Arrays.asList(KEY_1, KEY_2));
+    }
+
+    @Test
+    public void start_isSyncedReturnFalseUntilAllWorkDone() throws InterruptedException {
+        final CountDownLatch latch = new CountDownLatch(1);
+        mSyncableController.start(() -> latch.countDown());
+
+        // Return false at first
+        assertThat(mSyncableController.isBlockerFinished()).isFalse();
+
+        // Return false if only one job is done
+        mSyncableController.countDown(KEY_1);
+        assertThat(mSyncableController.isBlockerFinished()).isFalse();
+
+        // Return true if all jobs done
+        mSyncableController.countDown(KEY_2);
+        assertThat(latch.await(TIMEOUT, TimeUnit.MILLISECONDS)).isTrue();
+        assertThat(mSyncableController.isBlockerFinished()).isTrue();
+    }
+}
diff --git a/tests/unit/src/com/android/settings/vpn2/AppSettingsTest.java b/tests/unit/src/com/android/settings/vpn2/AppSettingsTest.java
index 1a9701d..014d8ea 100644
--- a/tests/unit/src/com/android/settings/vpn2/AppSettingsTest.java
+++ b/tests/unit/src/com/android/settings/vpn2/AppSettingsTest.java
@@ -57,23 +57,24 @@
         };
 
         // List with one package op
-        when(mAppOps.getOpsForPackage(eq(mockApp.uid), eq(mockApp.packageName), any()))
-                .thenReturn(Arrays.asList(new AppOpsManager.PackageOps[] {blankOps[0]}));
+        when(mAppOps.getOpsForPackage(eq(mockApp.uid), eq(mockApp.packageName),
+                any(int[].class))).thenReturn(Arrays.asList(
+                        new AppOpsManager.PackageOps[] {blankOps[0]}));
         assertTrue(appHasVpnPermission(mContext, mockApp));
 
         // List with more than one package op
-        when(mAppOps.getOpsForPackage(eq(mockApp.uid), eq(mockApp.packageName), any()))
-                .thenReturn(Arrays.asList(blankOps));
+        when(mAppOps.getOpsForPackage(eq(mockApp.uid), eq(mockApp.packageName),
+                any(int[].class))).thenReturn(Arrays.asList(blankOps));
         assertTrue(appHasVpnPermission(mContext, mockApp));
 
         // Empty list
-        when(mAppOps.getOpsForPackage(eq(mockApp.uid), eq(mockApp.packageName), any()))
-                .thenReturn(Collections.emptyList());
+        when(mAppOps.getOpsForPackage(eq(mockApp.uid), eq(mockApp.packageName),
+                any(int[].class))).thenReturn(Collections.emptyList());
         assertFalse(appHasVpnPermission(mContext, mockApp));
 
         // Null list (may be returned in place of an empty list)
-        when(mAppOps.getOpsForPackage(eq(mockApp.uid), eq(mockApp.packageName), any()))
-                .thenReturn(null);
+        when(mAppOps.getOpsForPackage(eq(mockApp.uid), eq(mockApp.packageName),
+                any(int[].class))).thenReturn(null);
         assertFalse(appHasVpnPermission(mContext, mockApp));
     }