Merge "Choose a pref key less likely to conflict"
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 7625e78..4bb1a8c 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -3124,6 +3124,18 @@
 
         <activity android:name=".homepage.contextualcards.ContextualCardFeedbackDialog"
                   android:theme="@android:style/Theme.DeviceDefault.Light.Dialog.Alert" />
+
+        <activity
+            android:name="Settings$WifiCallingDisclaimerActivity"
+            android:label="@string/wifi_calling_settings_title"
+            android:taskAffinity="com.android.settings">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.DEFAULT" />
+            </intent-filter>
+            <meta-data android:name="com.android.settings.FRAGMENT_CLASS"
+                android:value="com.android.settings.wifi.calling.WifiCallingDisclaimerFragment" />
+        </activity>
         <!-- This is the longest AndroidManifest.xml ever. -->
     </application>
 </manifest>
diff --git a/res/drawable/ic_notification_alert.xml b/res/drawable/ic_notification_alert.xml
new file mode 100644
index 0000000..07e7b48
--- /dev/null
+++ b/res/drawable/ic_notification_alert.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+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.
+-->
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+    <item
+        android:id="@+id/back">
+        <shape android:shape="oval">
+            <solid
+                android:color="@android:color/transparent" />
+            <size
+                android:height="48dp"
+                android:width="48dp"/>
+            <stroke android:width="1dp"
+                    android:color="@color/notification_alert_color"/>
+        </shape>
+    </item>
+    <item
+        android:id="@+id/fore"
+        android:gravity="center">
+        <vector
+            android:height="24dp"
+            android:width="24dp"
+            android:viewportHeight="24"
+            android:viewportWidth="24">
+            <path
+                android:fillColor="@color/notification_alert_color"
+                android:pathData="M7.58 4.08L6.15 2.65C3.75 4.48 2.17 7.3 2.03 10.5h2c.15-2.65 1.51-4.97 3.55-6.42zm12.39 6.42h2c-.15-3.2-1.73-6.02-4.12-7.85l-1.42 1.43c2.02 1.45 3.39 3.77 3.54 6.42zM18 11c0-3.07-1.64-5.64-4.5-6.32V4c0-.83-.67-1.5-1.5-1.5s-1.5.67-1.5 1.5v.68C7.63 5.36 6 7.92 6 11v5l-2 2v1h16v-1l-2-2v-5zm-6 11c.14 0 .27-.01.4-.04.65-.14 1.18-.58 1.44-1.18.1-.24.15-.5.15-.78h-4c.01 1.1.9 2 2.01 2z"/>
+        </vector>
+    </item>
+</layer-list>
\ No newline at end of file
diff --git a/res/drawable/ic_notification_block.xml b/res/drawable/ic_notification_block.xml
new file mode 100644
index 0000000..d4f0a2a
--- /dev/null
+++ b/res/drawable/ic_notification_block.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+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.
+-->
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+    <item
+        android:id="@+id/back">
+        <shape android:shape="oval">
+            <solid
+                android:color="@android:color/transparent" />
+            <size
+                android:height="48dp"
+                android:width="48dp"/>
+            <stroke android:width="1dp"
+                    android:color="@color/notification_block_color"/>
+        </shape>
+    </item>
+    <item
+        android:id="@+id/fore"
+        android:gravity="center">
+        <vector
+            android:height="24dp"
+            android:width="24dp"
+            android:viewportHeight="24"
+            android:viewportWidth="24">
+            <path
+                android:fillColor="@color/notification_block_color"
+                android:pathData="M12.0,2.0C6.48,2.0 2.0,6.48 2.0,12.0s4.48,10.0 10.0,10.0 10.0,-4.48 10.0,-10.0S17.52,2.0 12.0,2.0zM4.0,12.0c0.0,-4.42 3.58,-8.0 8.0,-8.0 1.85,0.0 3.5,0.63 4.9,1.69L5.69,16.9C4.63,15.55 4.0,13.85 4.0,12.0zm8.0,8.0c-1.85,0.0 -3.55,-0.63 -4.9,-1.69L18.31,7.1C19.37,8.45 20.0,10.15 20.0,12.0c0.0,4.42 -3.58,8.0 -8.0,8.0z"/>
+        </vector>
+    </item>
+</layer-list>
\ No newline at end of file
diff --git a/res/drawable/ic_notification_silence.xml b/res/drawable/ic_notification_silence.xml
new file mode 100644
index 0000000..673340f
--- /dev/null
+++ b/res/drawable/ic_notification_silence.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+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.
+-->
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+    <item
+        android:id="@+id/back">
+        <shape android:shape="oval">
+            <solid
+                android:color="@android:color/transparent" />
+            <size
+                android:height="48dp"
+                android:width="48dp"/>
+            <stroke android:width="1dp"
+                    android:color="@color/notification_silence_color"/>
+        </shape>
+    </item>
+    <item
+        android:id="@+id/fore"
+        android:gravity="center">
+        <vector
+            android:height="24dp"
+            android:width="24dp"
+            android:viewportHeight="24"
+            android:viewportWidth="24">
+            <path
+                android:fillColor="@color/notification_silence_color"
+                android:pathData="M20 18.69L7.84 6.14 5.27 3.49 4 4.76l2.8 2.8v.01c-.52.99-.8 2.16-.8 3.42v5l-2 2v1h13.73l2 2L21 19.72l-1-1.03zM12 22c1.11 0 2-.89 2-2h-4c0 1.11.89 2 2 2zm6-7.32V11c0-3.08-1.64-5.64-4.5-6.32V4c0-.83-.67-1.5-1.5-1.5s-1.5.67-1.5 1.5v.68c-.15.03-.29.08-.42.12-.1.03-.2.07-.3.11h-.01c-.01 0-.01 0-.02.01-.23.09-.46.2-.68.31 0 0-.01 0-.01.01L18 14.68z" />
+        </vector>
+    </item>
+</layer-list>
\ No newline at end of file
diff --git a/res/layout/notif_importance_preference.xml b/res/layout/notif_importance_preference.xml
new file mode 100644
index 0000000..5d79ff3
--- /dev/null
+++ b/res/layout/notif_importance_preference.xml
@@ -0,0 +1,104 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  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.
+  -->
+
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/app_entities_header"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:gravity="center"
+    android:orientation="horizontal">
+
+    <LinearLayout
+        android:id="@+id/block"
+        android:layout_width="0dp"
+        android:layout_weight="33.33"
+        android:layout_height="wrap_content"
+        android:layout_marginBottom="16dp"
+        android:layout_marginTop="16dp"
+        android:orientation="vertical"
+        android:gravity="center">
+
+        <ImageButton
+            android:id="@+id/block_icon"
+            android:layout_width="@dimen/notification_importance_toggle_size"
+            android:layout_height="@dimen/notification_importance_toggle_size"
+            android:background="?android:attr/selectableItemBackgroundBorderless"
+            android:src="@drawable/ic_notification_block"
+            android:contentDescription="@string/notification_block_title" />
+        <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/notification_block_title"
+            android:layout_marginTop="@dimen/notification_importance_toggle_marginTop"
+            android:layout_marginBottom="@dimen/notification_importance_toggle_marginBottom"
+            android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Subhead" />
+    </LinearLayout>
+
+    <LinearLayout
+        android:id="@+id/silence"
+        android:layout_width="0dp"
+        android:layout_weight="33.33"
+        android:layout_height="wrap_content"
+        android:layout_marginBottom="16dp"
+        android:layout_marginTop="16dp"
+        android:orientation="vertical"
+        android:gravity="center">
+
+        <ImageButton
+            android:id="@+id/silence_icon"
+            android:layout_width="@dimen/notification_importance_toggle_size"
+            android:layout_height="@dimen/notification_importance_toggle_size"
+            android:background="?android:attr/selectableItemBackgroundBorderless"
+            android:src="@drawable/ic_notification_silence"
+            android:contentDescription="@string/notification_silence_title" />
+        <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/notification_silence_title"
+            android:layout_marginTop="@dimen/notification_importance_toggle_marginTop"
+            android:layout_marginBottom="@dimen/notification_importance_toggle_marginBottom"
+            android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Subhead" />
+    </LinearLayout>
+
+    <LinearLayout
+        android:id="@+id/alert"
+        android:layout_width="0dp"
+        android:layout_weight="33.33"
+        android:layout_height="wrap_content"
+        android:layout_marginBottom="16dp"
+        android:layout_marginTop="16dp"
+        android:orientation="vertical"
+        android:gravity="center">
+
+        <ImageButton
+            android:id="@+id/alert_icon"
+            android:layout_width="@dimen/notification_importance_toggle_size"
+            android:layout_height="@dimen/notification_importance_toggle_size"
+            android:background="?android:attr/selectableItemBackgroundBorderless"
+            android:src="@drawable/ic_notification_alert"
+            android:contentDescription="@string/notification_alert_title" />
+        <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/notification_alert_title"
+            android:layout_marginTop="@dimen/notification_importance_toggle_marginTop"
+            android:layout_marginBottom="@dimen/notification_importance_toggle_marginBottom"
+            android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Subhead" />
+    </LinearLayout>
+
+</LinearLayout>
\ No newline at end of file
diff --git a/res/layout/wfc_disclaimer_fragment.xml b/res/layout/wfc_disclaimer_fragment.xml
new file mode 100644
index 0000000..00baae5
--- /dev/null
+++ b/res/layout/wfc_disclaimer_fragment.xml
@@ -0,0 +1,67 @@
+<?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.
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:orientation="vertical"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+
+    <TextView
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="16dp"
+        android:layout_marginStart="16dp"
+        android:layout_marginBottom="20dp"
+        android:textAppearance="?android:attr/textAppearanceLarge"
+        android:text="@string/wfc_disclaimer_title_text" />
+
+    <View
+        android:layout_width="match_parent"
+        android:layout_height="1dp"
+        android:background="?android:attr/listDivider" />
+
+    <androidx.recyclerview.widget.RecyclerView
+        android:id="@+id/disclaimer_item_list"
+        android:layout_width="match_parent"
+        android:layout_height="0dp"
+        android:layout_weight="1" />
+
+    <LinearLayout
+        android:orientation="horizontal"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content" >
+
+        <Button
+            android:id="@+id/disagree_button"
+            style="@style/DisclaimerNegativeButton"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_gravity="center_vertical"
+            android:text="@string/wfc_disclaimer_disagree_text" />
+
+        <Space
+            android:layout_width="0dp"
+            android:layout_height="match_parent"
+            android:layout_weight="1" />
+
+        <Button
+            android:id="@+id/agree_button"
+            style="@style/DisclaimerPositiveButton"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_gravity="center_vertical"
+            android:text="@string/wfc_disclaimer_agree_button_text" />
+    </LinearLayout>
+</LinearLayout>
diff --git a/res/layout/wfc_simple_disclaimer_item.xml b/res/layout/wfc_simple_disclaimer_item.xml
new file mode 100644
index 0000000..ee43182
--- /dev/null
+++ b/res/layout/wfc_simple_disclaimer_item.xml
@@ -0,0 +1,36 @@
+<?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.
+-->
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:paddingTop="16dp"
+    android:paddingBottom="20dp"
+    android:paddingStart="16dp"
+    android:paddingEnd="16dp"
+    android:gravity="center_vertical">
+    <TextView
+        android:id="@+id/disclaimer_title"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:textAppearance="@android:style/TextAppearance.Material.Subhead" />
+    <TextView
+        android:id="@+id/disclaimer_desc"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:textAppearance="@android:style/TextAppearance.Material.Body1"
+        android:textColor="?android:attr/textColorSecondary"
+        android:layout_below="@id/disclaimer_title" />
+</RelativeLayout>
\ No newline at end of file
diff --git a/res/values/colors.xml b/res/values/colors.xml
index 7b55a2b..0afd288 100644
--- a/res/values/colors.xml
+++ b/res/values/colors.xml
@@ -56,7 +56,7 @@
     <color name="material_blue_700">#3367D6</color>
     <color name="material_grey_100">#f5f5f5</color>
     <color name="material_grey_200">#ffffff</color>
-    <color name="switch_bar_background">#ff80868B</color>
+    <color name="switch_bar_background">#757575</color>
 
     <color name="message_text_incoming">#ffffffff</color>
     <color name="message_text_outgoing">#ff323232</color>
@@ -124,6 +124,11 @@
     <color name="face_anim_particle_color_4">#fffdd835</color> <!-- Material Yellow 600 -->
     <color name="face_anim_particle_error">#ff9e9e9e</color> <!-- Material Gray 500 -->
 
+    <!-- notification settings -->
+    <color name="notification_block_color">#ffff0000</color>
+    <color name="notification_silence_color">#fbbc04</color>
+    <color name="notification_alert_color">#30a751</color>
+
     <!-- launcher icon color -->
     <color name="icon_launcher_setting_color">@*android:color/accent_device_default_light</color>
 
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index a36d8ab..f5b6e95 100755
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -68,6 +68,9 @@
     <dimen name="notification_app_icon_size">64dp</dimen>
     <dimen name="notification_app_icon_badge_size">20dp</dimen>
     <dimen name="notification_app_icon_badge_margin">4dp</dimen>
+    <dimen name="notification_importance_toggle_size">48dp</dimen>
+    <dimen name="notification_importance_toggle_marginTop">8dp</dimen>
+    <dimen name="notification_importance_toggle_marginBottom">16dp</dimen>
     <dimen name="zen_schedule_rule_checkbox_padding">7dp</dimen>
     <dimen name="zen_schedule_day_margin">17dp</dimen>
 
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 2f33878..aa43f12 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -3022,14 +3022,14 @@
     <string name="status_prl_version">PRL version</string>
     <!-- About phone screen, title for MEID for multi-sim devices -->
     <string name="meid_multi_sim">MEID (sim slot %1$d)</string>
-    <!-- The status text when both Wi-Fi scanning and Bluetooth scanning are on. [CHAR LIMIT=120] -->
-    <string name="scanning_status_text_wifi_on_ble_on">Both Wi\u2011Fi and Bluetooth are allowed to determine location</string>
-    <!-- The status text when Wi-Fi scanning is on and Bluetooth scanning are off. [CHAR LIMIT=120] -->
-    <string name="scanning_status_text_wifi_on_ble_off">Only Wi\u2011Fi is allowed to determine location</string>
-    <!-- The status text when Wi-Fi scanning is off and Bluetooth scanning are on. [CHAR LIMIT=120] -->
-    <string name="scanning_status_text_wifi_off_ble_on">Only Bluetooth is allowed to determine location</string>
-    <!-- The status text when both Wi-Fi scanning and Bluetooth scanning are off. [CHAR LIMIT=120] -->
-    <string name="scanning_status_text_wifi_off_ble_off">Neither Wi\u2011Fi nor Bluetooth is allowed to determine location</string>
+    <!-- The status text when both Wi-Fi scanning and Bluetooth scanning are on. [CHAR LIMIT=100] -->
+    <string name="scanning_status_text_wifi_on_ble_on">Both Wi\u2011Fi and Bluetooth scanning are on</string>
+    <!-- The status text when Wi-Fi scanning is on and Bluetooth scanning are off. [CHAR LIMIT=100] -->
+    <string name="scanning_status_text_wifi_on_ble_off">Wi\u2011Fi scanning is on, Bluetooth scanning is off</string>
+    <!-- The status text when Wi-Fi scanning is off and Bluetooth scanning are on. [CHAR LIMIT=100] -->
+    <string name="scanning_status_text_wifi_off_ble_on">Bluetooth scanning is on, Wi\u2011Fi scanning is off</string>
+    <!-- The status text when both Wi-Fi scanning and Bluetooth scanning are off. [CHAR LIMIT=100] -->
+    <string name="scanning_status_text_wifi_off_ble_off">Both Wi\u2011Fi and Bluetooth scanning are off</string>
     <!-- About phone, status item title.  The phone MEID number of the current LTE/CDMA device. [CHAR LIMIT=30] -->
     <string name="status_meid_number">MEID</string>
     <!-- About phone, status item title.  The ICCID of the current LTE device. [CHAR LIMIT=30] -->
@@ -3754,13 +3754,25 @@
     <string name="location_app_level_permissions">App permission</string>
     <!-- Summary for app permission on Location settings page when location is off [CHAR LIMIT=NONE] -->
     <string name="location_app_permission_summary_location_off">Location is off</string>
-    <!-- Summary for Location settings when location is on, explaining how many apps have location permission [CHAR LIMIT=NONE]-->
+    <!--
+    Summary for Location settings when location is on, explaining how many apps have unlimited
+    location permission.
+
+    "Unlimited access" means the app can access the device location even when it's not being used
+    (on background), while "limited" means the app can only access the device location when the user
+    is using it (foreground only).
+
+    Please note that the distinction between singular and plural of this sentence only depends on
+    the quantity of "background_location_app_count" ("has" vs "have"). The quantity of
+    "total_location_app_count" is almost always greater than 1, so "apps" is always in plural form.
+
+    [CHAR LIMIT=NONE]-->
     <plurals name="location_app_permission_summary_location_on">
         <item quantity="one">
             <xliff:g id="background_location_app_count">%1$d</xliff:g>
             of
             <xliff:g id="total_location_app_count">%2$d</xliff:g>
-            app has unlimited access</item>
+            apps has unlimited access</item>
         <item quantity="other">
             <xliff:g id="background_location_app_count">%1$d</xliff:g>
             of
@@ -3771,8 +3783,12 @@
     <string name="location_category_recent_location_access">Recent location access</string>
     <!-- [CHAR LIMIT=30] Location settings screen, button to bring the user to view the details of recent location access -->
     <string name="location_recent_location_access_view_details">View details</string>
-    <!-- Location settings screen, displayed when there's no recent app accessing location -->
+    <!-- Location settings screen, displayed when there's no recent app accessing location
+      (for TV) [CHAR LIMIT=100] -->
     <string name="location_no_recent_apps">No apps have requested location recently</string>
+    <!-- Location settings screen, displayed when there's no recent app accessing location
+      (for phones and tablets) [CHAR LIMIT=100] -->
+    <string name="location_no_recent_accesses">No apps recently accessed location</string>
     <!-- [CHAR LIMIT=30] Location settings screen, recent location requests high battery use-->
     <string name="location_high_battery_use">High battery use</string>
     <!-- [CHAR LIMIT=30] Location settings screen, recent location requests low battery use-->
@@ -7771,7 +7787,7 @@
      summary on the channel page-->
 
     <!-- [CHAR LIMIT=100] Notification Importance title: min importance level title -->
-    <string name="notification_importance_min_title">Low</string>
+    <string name="notification_importance_min_title">Minimize</string>
 
     <!-- [CHAR LIMIT=100] Notification Importance title: low importance level title -->
     <string name="notification_importance_low_title">Medium</string>
@@ -7780,7 +7796,16 @@
     <string name="notification_importance_default_title">High</string>
 
     <!-- [CHAR LIMIT=100] Notification Importance title: high importance level title -->
-    <string name="notification_importance_high_title">Urgent</string>
+    <string name="notification_importance_high_title">Pop on screen</string>
+
+    <!-- [CHAR LIMIT=100] Notification Importance title -->
+    <string name="notification_block_title">Block</string>
+
+    <!-- [CHAR LIMIT=100] Notification Importance title -->
+    <string name="notification_silence_title">Show silently</string>
+
+    <!-- [CHAR LIMIT=100] Notification Importance title -->
+    <string name="notification_alert_title">Alert</string>
 
     <!-- [CHAR LIMIT=40] Notification importance title. This setting controls how notifications in older apps may alert the user (eg, sound, visual, vibrate). -->
     <string name="allow_interruption">Allow interruptions</string>
@@ -10758,6 +10783,15 @@
     <!-- Summary for represent which device is playing media [CHAR LIMIT=NONE] -->
     <string name="media_output_panel_summary_of_playing_device">Currently playing on <xliff:g id="device_name" example="Bose headphone">%1$s</xliff:g></string>
 
+    <!-- Label for the title on wfc disclaimer fragment. [CHAR LIMIT=40] -->
+    <string name="wfc_disclaimer_title_text">Important information</string>
+
+    <!-- Label for the agree button on wfc disclaimer fragment. [CHAR LIMIT=30] -->
+    <string name="wfc_disclaimer_agree_button_text">CONTINUE</string>
+
+    <!-- Label for the disagree button on wfc disclaimer fragment. [CHAR LIMIT=30] -->
+    <string name="wfc_disclaimer_disagree_text">NO THANKS</string>
+
     <!-- Message for forget passpoint dialog [CHAR LIMIT=none] -->
     <string name="forget_passpoint_dialog_message">You may lose access to any remaining time or data. Check with your provider before removing.</string>
 
diff --git a/res/values/styles.xml b/res/values/styles.xml
index 92a4098..8fde9a0 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -520,4 +520,17 @@
         <!-- Padding between content and the start icon is 8dp. -->
         <item name="contentStartPadding">8dp</item>
     </style>
+
+    <style name="DisclaimerPositiveButton" parent="@style/SudGlifButton.Primary">
+        <item name="android:layout_margin">16dp</item>
+        <item name="android:paddingStart">8dp</item>
+        <item name="android:paddingEnd">8dp</item>
+    </style>
+
+    <style name="DisclaimerNegativeButton" parent="@style/SudGlifButton.Secondary">
+        <item name="android:layout_margin">16dp</item>
+        <item name="android:paddingStart">8dp</item>
+        <item name="android:paddingEnd">8dp</item>
+    </style>
+
 </resources>
diff --git a/res/xml/channel_notification_settings.xml b/res/xml/channel_notification_settings.xml
index 45c8b1a..3158819 100644
--- a/res/xml/channel_notification_settings.xml
+++ b/res/xml/channel_notification_settings.xml
@@ -25,11 +25,6 @@
         android:order="1"
         android:layout="@layout/settings_entity_header" />
 
-    <com.android.settingslib.widget.LayoutPreference
-        android:key="block"
-        android:order="2"
-        android:layout="@layout/styled_switch_bar" />
-
     <!-- Importance toggle -->
     <com.android.settingslib.RestrictedSwitchPreference
         android:key="allow_sound"
@@ -38,10 +33,23 @@
         android:summary="@string/allow_interruption_summary" />
 
     <!-- Importance -->
-    <com.android.settings.RestrictedListPreference
+    <com.android.settings.notification.ImportancePreference
         android:key="importance"
-        android:order="10"
-        android:title="@string/notification_importance_title" />
+        android:order="4"
+        android:title="@string/notification_importance_title"
+        settings:allowDividerBelow="true"/>
+
+    <com.android.settingslib.RestrictedSwitchPreference
+        android:key="min_importance"
+        android:order="5"
+        settings:allowDividerAbove="true"
+        android:title="@string/notification_importance_min_title"/>
+
+    <com.android.settingslib.RestrictedSwitchPreference
+        android:key="high_importance"
+        android:order="6"
+        settings:allowDividerAbove="true"
+        android:title="@string/notification_importance_high_title"/>
 
     <PreferenceCategory
         android:key="channel_advanced"
@@ -113,6 +121,7 @@
 
     <com.android.settings.notification.NotificationFooterPreference
         android:key="block_desc"
-        android:order="110"/>
+        android:order="110"
+        settings:allowDividerAbove="false"/>
 
 </PreferenceScreen>
diff --git a/res/xml/mobile_network_list.xml b/res/xml/mobile_network_list.xml
index b72540f..c2baf46 100644
--- a/res/xml/mobile_network_list.xml
+++ b/res/xml/mobile_network_list.xml
@@ -16,11 +16,13 @@
 
 <PreferenceScreen
     xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:settings="http://schemas.android.com/apk/res-auto"
     android:key="mobile_network_list_screen"
     android:title="@string/network_settings_title">
 
     <Preference
         android:key="add_more"
+        settings:isPreferenceVisible="false"
         android:title="@string/mobile_network_list_add_more"
         android:icon="@drawable/ic_menu_add"
         android:order="100" >
diff --git a/src/com/android/settings/Settings.java b/src/com/android/settings/Settings.java
index fac4253..97ff613 100644
--- a/src/com/android/settings/Settings.java
+++ b/src/com/android/settings/Settings.java
@@ -159,6 +159,7 @@
     public static class WebViewAppPickerActivity extends SettingsActivity { /* empty */ }
     public static class AdvancedConnectedDeviceActivity extends SettingsActivity { /* empty */ }
     public static class BluetoothDeviceDetailActivity extends SettingsActivity { /* empty */ }
+    public static class WifiCallingDisclaimerActivity extends SettingsActivity { /* empty */ }
 
     // Top level categories for new IA
     public static class NetworkDashboardActivity extends SettingsActivity {}
diff --git a/src/com/android/settings/core/gateway/SettingsGateway.java b/src/com/android/settings/core/gateway/SettingsGateway.java
index 147d0be..ba64a80 100644
--- a/src/com/android/settings/core/gateway/SettingsGateway.java
+++ b/src/com/android/settings/core/gateway/SettingsGateway.java
@@ -135,6 +135,7 @@
 import com.android.settings.wifi.WifiAPITest;
 import com.android.settings.wifi.WifiInfo;
 import com.android.settings.wifi.WifiSettings;
+import com.android.settings.wifi.calling.WifiCallingDisclaimerFragment;
 import com.android.settings.wifi.calling.WifiCallingSettings;
 import com.android.settings.wifi.p2p.WifiP2pSettings;
 import com.android.settings.wifi.savedaccesspoints.SavedAccessPointsWifiSettings;
@@ -260,6 +261,7 @@
             ConnectedDeviceDashboardFragment.class.getName(),
             UsbDetailsFragment.class.getName(),
             AppAndNotificationDashboardFragment.class.getName(),
+            WifiCallingDisclaimerFragment.class.getName(),
             AccountDashboardFragment.class.getName(),
             EnterprisePrivacySettings.class.getName(),
             WebViewAppPicker.class.getName(),
diff --git a/src/com/android/settings/homepage/contextualcards/ContextualCardLoader.java b/src/com/android/settings/homepage/contextualcards/ContextualCardLoader.java
index 13564b5..ff2ee91 100644
--- a/src/com/android/settings/homepage/contextualcards/ContextualCardLoader.java
+++ b/src/com/android/settings/homepage/contextualcards/ContextualCardLoader.java
@@ -67,7 +67,8 @@
 
     @VisibleForTesting
     Uri mNotifyUri;
-    private Context mContext;
+
+    private final Context mContext;
 
     ContextualCardLoader(Context context) {
         super(context);
diff --git a/src/com/android/settings/homepage/contextualcards/ContextualCardManager.java b/src/com/android/settings/homepage/contextualcards/ContextualCardManager.java
index c829015..8f7e84a 100644
--- a/src/com/android/settings/homepage/contextualcards/ContextualCardManager.java
+++ b/src/com/android/settings/homepage/contextualcards/ContextualCardManager.java
@@ -109,13 +109,13 @@
         }
     }
 
-    void loadContextualCards(ContextualCardsFragment fragment) {
+    void loadContextualCards(LoaderManager loaderManager) {
         mStartTime = System.currentTimeMillis();
         final CardContentLoaderCallbacks cardContentLoaderCallbacks =
                 new CardContentLoaderCallbacks(mContext);
         cardContentLoaderCallbacks.setListener(this);
         // Use the cached data when navigating back to the first page and upon screen rotation.
-        LoaderManager.getInstance(fragment).initLoader(CARD_CONTENT_LOADER_ID, null /* bundle */,
+        loaderManager.initLoader(CARD_CONTENT_LOADER_ID, null /* bundle */,
                 cardContentLoaderCallbacks);
     }
 
diff --git a/src/com/android/settings/homepage/contextualcards/ContextualCardsFragment.java b/src/com/android/settings/homepage/contextualcards/ContextualCardsFragment.java
index e598e4c..72ddb50 100644
--- a/src/com/android/settings/homepage/contextualcards/ContextualCardsFragment.java
+++ b/src/com/android/settings/homepage/contextualcards/ContextualCardsFragment.java
@@ -19,16 +19,19 @@
 import static com.android.settings.homepage.contextualcards.ContextualCardsAdapter.SPAN_COUNT;
 
 import android.app.settings.SettingsEnums;
+import android.content.Context;
 import android.os.Bundle;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
 
+import androidx.loader.app.LoaderManager;
 import androidx.recyclerview.widget.GridLayoutManager;
 import androidx.recyclerview.widget.RecyclerView;
 
 import com.android.settings.R;
 import com.android.settings.core.InstrumentedFragment;
+import com.android.settings.overlay.FeatureFactory;
 
 public class ContextualCardsFragment extends InstrumentedFragment {
 
@@ -42,14 +45,19 @@
     @Override
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
-        mContextualCardManager = new ContextualCardManager(getContext(), getSettingsLifecycle(),
+        final Context context = getContext();
+        if (savedInstanceState == null) {
+            FeatureFactory.getFactory(context).getSlicesFeatureProvider().newUiSession();
+        }
+        mContextualCardManager = new ContextualCardManager(context, getSettingsLifecycle(),
                 savedInstanceState);
+
     }
 
     @Override
     public void onStart() {
         super.onStart();
-        mContextualCardManager.loadContextualCards(this);
+        mContextualCardManager.loadContextualCards(LoaderManager.getInstance(this));
     }
 
     @Override
diff --git a/src/com/android/settings/location/RecentLocationAccessPreferenceController.java b/src/com/android/settings/location/RecentLocationAccessPreferenceController.java
index 8a439b7..a76d381 100644
--- a/src/com/android/settings/location/RecentLocationAccessPreferenceController.java
+++ b/src/com/android/settings/location/RecentLocationAccessPreferenceController.java
@@ -74,6 +74,7 @@
         mController = AppEntitiesHeaderController.newInstance(mContext, view)
                 .setHeaderTitleRes(R.string.location_category_recent_location_access)
                 .setHeaderDetailsRes(R.string.location_recent_location_access_view_details)
+                .setHeaderEmptyRes(R.string.location_no_recent_accesses)
                 .setHeaderDetailsClickListener((View v) -> {
                     final Intent intent = new Intent(Intent.ACTION_REVIEW_PERMISSION_USAGE);
                     intent.putExtra(Intent.EXTRA_PERMISSION_NAME,
@@ -114,8 +115,6 @@
             for (; i < MAXIMUM_APP_COUNT; i++) {
                 mController.removeAppEntity(i);
             }
-        } else {
-            // If there's no item to display, add a "No recent apps" item.
         }
         mController.apply();
     }
diff --git a/src/com/android/settings/network/MobileNetworkListController.java b/src/com/android/settings/network/MobileNetworkListController.java
index 7de6cdd..79715e3 100644
--- a/src/com/android/settings/network/MobileNetworkListController.java
+++ b/src/com/android/settings/network/MobileNetworkListController.java
@@ -24,14 +24,10 @@
 import android.provider.Settings;
 import android.telephony.SubscriptionInfo;
 import android.telephony.SubscriptionManager;
+import android.telephony.euicc.EuiccManager;
 import android.util.ArrayMap;
 
-import androidx.lifecycle.Lifecycle;
-import androidx.lifecycle.LifecycleObserver;
-import androidx.lifecycle.OnLifecycleEvent;
-import androidx.preference.Preference;
-import androidx.preference.PreferenceScreen;
-
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.settings.R;
 import com.android.settings.network.telephony.MobileNetworkActivity;
 import com.android.settingslib.core.AbstractPreferenceController;
@@ -39,6 +35,12 @@
 import java.util.List;
 import java.util.Map;
 
+import androidx.lifecycle.Lifecycle;
+import androidx.lifecycle.LifecycleObserver;
+import androidx.lifecycle.OnLifecycleEvent;
+import androidx.preference.Preference;
+import androidx.preference.PreferenceScreen;
+
 /**
  * This populates the entries on a page which lists all available mobile subscriptions. Each entry
  * has the name of the subscription with some subtext giving additional detail, and clicking on the
@@ -48,6 +50,9 @@
         LifecycleObserver, SubscriptionsChangeListener.SubscriptionsChangeListenerClient {
     private static final String TAG = "MobileNetworkListCtlr";
 
+    @VisibleForTesting
+    static final String KEY_ADD_MORE = "add_more";
+
     private SubscriptionManager mSubscriptionManager;
     private SubscriptionsChangeListener mChangeListener;
     private PreferenceScreen mPreferenceScreen;
@@ -76,6 +81,8 @@
     public void displayPreference(PreferenceScreen screen) {
         super.displayPreference(screen);
         mPreferenceScreen = screen;
+        final EuiccManager euiccManager = mContext.getSystemService(EuiccManager.class);
+        mPreferenceScreen.findPreference(KEY_ADD_MORE).setVisible(euiccManager.isEnabled());
         update();
     }
 
@@ -93,7 +100,7 @@
         final List<SubscriptionInfo> subscriptions = SubscriptionUtil.getAvailableSubscriptions(
                 mSubscriptionManager);
         for (SubscriptionInfo info : subscriptions) {
-            int subId = info.getSubscriptionId();
+            final int subId = info.getSubscriptionId();
             Preference pref = existingPreferences.remove(subId);
             if (pref == null) {
                 pref = new Preference(mPreferenceScreen.getContext());
diff --git a/src/com/android/settings/network/MobileNetworkSummaryController.java b/src/com/android/settings/network/MobileNetworkSummaryController.java
index a1fef4c..56735ab 100644
--- a/src/com/android/settings/network/MobileNetworkSummaryController.java
+++ b/src/com/android/settings/network/MobileNetworkSummaryController.java
@@ -16,8 +16,6 @@
 
 package com.android.settings.network;
 
-import static android.telephony.TelephonyManager.MultiSimVariants.UNKNOWN;
-
 import static androidx.lifecycle.Lifecycle.Event.ON_PAUSE;
 import static androidx.lifecycle.Lifecycle.Event.ON_RESUME;
 
@@ -25,7 +23,6 @@
 import android.content.Intent;
 import android.telephony.SubscriptionInfo;
 import android.telephony.SubscriptionManager;
-import android.telephony.TelephonyManager;
 import android.telephony.euicc.EuiccManager;
 
 import com.android.settings.R;
@@ -52,7 +49,6 @@
 
     private SubscriptionManager mSubscriptionManager;
     private SubscriptionsChangeListener mChangeListener;
-    private TelephonyManager mTelephonyMgr;
     private EuiccManager mEuiccManager;
     private AddPreference mPreference;
 
@@ -74,7 +70,6 @@
     public MobileNetworkSummaryController(Context context, Lifecycle lifecycle) {
         super(context);
         mSubscriptionManager = context.getSystemService(SubscriptionManager.class);
-        mTelephonyMgr = mContext.getSystemService(TelephonyManager.class);
         mEuiccManager = mContext.getSystemService(EuiccManager.class);
         if (lifecycle != null) {
           mChangeListener = new SubscriptionsChangeListener(context, this);
@@ -124,48 +119,43 @@
         mContext.startActivity(intent);
     }
 
-    private boolean shouldShowAddButton() {
-        // The add button should only show up if the device is in multi-sim mode and the eSIM
-        // manager is enabled.
-        return mTelephonyMgr.getMultiSimConfiguration() != UNKNOWN && mEuiccManager.isEnabled();
-    }
-
     private void update() {
         if (mPreference == null) {
             return;
         }
-        final boolean showAddButton = shouldShowAddButton();
         refreshSummary(mPreference);
-        if (!showAddButton) {
-            mPreference.setOnAddClickListener(null);
-        } else {
-            mPreference.setAddWidgetEnabled(!mChangeListener.isAirplaneModeOn());
-            mPreference.setOnAddClickListener(p -> {
-                startAddSimFlow();
-            });
-        }
-        final List<SubscriptionInfo> subs = SubscriptionUtil.getAvailableSubscriptions(
-                mSubscriptionManager);
         mPreference.setOnPreferenceClickListener(null);
+        mPreference.setOnAddClickListener(null);
         mPreference.setFragment(null);
         mPreference.setEnabled(!mChangeListener.isAirplaneModeOn());
+
+        final List<SubscriptionInfo> subs = SubscriptionUtil.getAvailableSubscriptions(
+                mSubscriptionManager);
+
         if (subs.isEmpty()) {
-            if (showAddButton) {
-                mPreference.setEnabled(false);
-            } else if (mEuiccManager.isEnabled()) {
+            if (mEuiccManager.isEnabled()) {
                 mPreference.setOnPreferenceClickListener((Preference pref) -> {
                     startAddSimFlow();
                     return true;
                 });
             }
-        } else if (subs.size() == 1) {
-            mPreference.setOnPreferenceClickListener((Preference pref) -> {
-                final Intent intent = new Intent(mContext, MobileNetworkActivity.class);
-                mContext.startActivity(intent);
-                return true;
-            });
         } else {
-            mPreference.setFragment(MobileNetworkListFragment.class.getCanonicalName());
+            // We have one or more existing subscriptions, so we want the plus button if eSIM is
+            // supported.
+            if (mEuiccManager.isEnabled()) {
+                mPreference.setAddWidgetEnabled(!mChangeListener.isAirplaneModeOn());
+                mPreference.setOnAddClickListener(p -> startAddSimFlow());
+            }
+
+            if (subs.size() == 1) {
+                mPreference.setOnPreferenceClickListener((Preference pref) -> {
+                    final Intent intent = new Intent(mContext, MobileNetworkActivity.class);
+                    mContext.startActivity(intent);
+                    return true;
+                });
+            } else {
+                mPreference.setFragment(MobileNetworkListFragment.class.getCanonicalName());
+            }
         }
     }
 
diff --git a/src/com/android/settings/network/telephony/NetworkSelectSettings.java b/src/com/android/settings/network/telephony/NetworkSelectSettings.java
index 088bfbf..d70bd62 100644
--- a/src/com/android/settings/network/telephony/NetworkSelectSettings.java
+++ b/src/com/android/settings/network/telephony/NetworkSelectSettings.java
@@ -318,7 +318,8 @@
             // Try to get the network registration states
             ServiceState ss = mTelephonyManager.getServiceState();
             List<NetworkRegistrationState> networkList =
-                    ss.getNetworkRegistrationStates(AccessNetworkConstants.TransportType.WWAN);
+                    ss.getNetworkRegistrationStatesForTransportType(
+                            AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
             if (networkList == null || networkList.size() == 0) {
                 // Remove the connected network operators category
                 mConnectedPreferenceCategory.setVisible(false);
diff --git a/src/com/android/settings/notification/AppNotificationSettings.java b/src/com/android/settings/notification/AppNotificationSettings.java
index 9f5ece2..5fd26a6 100644
--- a/src/com/android/settings/notification/AppNotificationSettings.java
+++ b/src/com/android/settings/notification/AppNotificationSettings.java
@@ -152,6 +152,10 @@
                 context, mImportanceListener, mBackend));
         mControllers.add(new ImportancePreferenceController(
                 context, mImportanceListener, mBackend));
+        mControllers.add(new MinImportancePreferenceController(
+                context, mImportanceListener, mBackend));
+        mControllers.add(new HighImportancePreferenceController(
+                context, mImportanceListener, mBackend));
         mControllers.add(new SoundPreferenceController(context, this,
                 mImportanceListener, mBackend));
         mControllers.add(new LightsPreferenceController(context, mBackend));
diff --git a/src/com/android/settings/notification/ChannelNotificationSettings.java b/src/com/android/settings/notification/ChannelNotificationSettings.java
index f92e529..850fde2 100644
--- a/src/com/android/settings/notification/ChannelNotificationSettings.java
+++ b/src/com/android/settings/notification/ChannelNotificationSettings.java
@@ -94,9 +94,12 @@
     protected List<AbstractPreferenceController> createPreferenceControllers(Context context) {
         mControllers = new ArrayList<>();
         mControllers.add(new HeaderPreferenceController(context, this));
-        mControllers.add(new BlockPreferenceController(context, mImportanceListener, mBackend));
         mControllers.add(new ImportancePreferenceController(
                 context, mImportanceListener, mBackend));
+        mControllers.add(new MinImportancePreferenceController(
+                context, mImportanceListener, mBackend));
+        mControllers.add(new HighImportancePreferenceController(
+                context, mImportanceListener, mBackend));
         mControllers.add(new AllowSoundPreferenceController(
                 context, mImportanceListener, mBackend));
         mControllers.add(new SoundPreferenceController(context, this,
diff --git a/src/com/android/settings/notification/HighImportancePreferenceController.java b/src/com/android/settings/notification/HighImportancePreferenceController.java
new file mode 100644
index 0000000..fe843fd
--- /dev/null
+++ b/src/com/android/settings/notification/HighImportancePreferenceController.java
@@ -0,0 +1,84 @@
+/*
+ * 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 android.app.NotificationManager.IMPORTANCE_DEFAULT;
+import static android.app.NotificationManager.IMPORTANCE_HIGH;
+
+import android.app.NotificationChannel;
+import android.content.Context;
+
+import com.android.settings.core.PreferenceControllerMixin;
+import com.android.settingslib.RestrictedSwitchPreference;
+
+import androidx.preference.Preference;
+
+public class HighImportancePreferenceController extends NotificationPreferenceController
+        implements PreferenceControllerMixin, Preference.OnPreferenceChangeListener  {
+
+    private static final String KEY_IMPORTANCE = "high_importance";
+    private NotificationSettingsBase.ImportanceListener mImportanceListener;
+
+    public HighImportancePreferenceController(Context context,
+            NotificationSettingsBase.ImportanceListener importanceListener,
+            NotificationBackend backend) {
+        super(context, backend);
+        mImportanceListener = importanceListener;
+    }
+
+    @Override
+    public String getPreferenceKey() {
+        return KEY_IMPORTANCE;
+    }
+
+    @Override
+    public boolean isAvailable() {
+        if (!super.isAvailable()) {
+            return false;
+        }
+        if (mChannel == null) {
+            return false;
+        }
+        if (isDefaultChannel()) {
+           return false;
+        }
+        return mChannel.getImportance() >= IMPORTANCE_DEFAULT;
+    }
+
+    @Override
+    public void updateState(Preference preference) {
+        if (mAppRow!= null && mChannel != null) {
+            preference.setEnabled(mAdmin == null && isChannelConfigurable());
+
+            RestrictedSwitchPreference pref = (RestrictedSwitchPreference) preference;
+            pref.setChecked(mChannel.getImportance() >= IMPORTANCE_HIGH);
+        }
+    }
+
+    @Override
+    public boolean onPreferenceChange(Preference preference, Object newValue) {
+        if (mChannel != null) {
+            final boolean checked = (boolean) newValue;
+
+            mChannel.setImportance(checked ? IMPORTANCE_HIGH : IMPORTANCE_DEFAULT);
+            mChannel.lockFields(NotificationChannel.USER_LOCKED_IMPORTANCE);
+            saveChannel();
+            mImportanceListener.onImportanceChanged();
+        }
+        return true;
+    }
+}
diff --git a/src/com/android/settings/notification/ImportancePreference.java b/src/com/android/settings/notification/ImportancePreference.java
new file mode 100644
index 0000000..b8f3e45
--- /dev/null
+++ b/src/com/android/settings/notification/ImportancePreference.java
@@ -0,0 +1,172 @@
+/*
+ * 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 android.app.NotificationManager.IMPORTANCE_DEFAULT;
+import static android.app.NotificationManager.IMPORTANCE_HIGH;
+import static android.app.NotificationManager.IMPORTANCE_LOW;
+import static android.app.NotificationManager.IMPORTANCE_MIN;
+import static android.app.NotificationManager.IMPORTANCE_NONE;
+
+import android.content.Context;
+import android.graphics.Color;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.GradientDrawable;
+import android.graphics.drawable.LayerDrawable;
+import android.util.ArrayMap;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.ImageButton;
+
+import com.android.settingslib.R;
+
+import androidx.preference.Preference;
+import androidx.preference.PreferenceViewHolder;
+
+public class ImportancePreference extends Preference {
+
+    boolean mIsBlockable = true;
+    boolean mIsConfigurable = true;
+    int mImportance;
+    ImageButton blockButton;
+    ImageButton silenceButton;
+    ImageButton alertButton;
+    ArrayMap<ImageButton, Integer> mImageButtons = new ArrayMap<>();
+    Context mContext;
+
+    public ImportancePreference(Context context, AttributeSet attrs,
+            int defStyleAttr, int defStyleRes) {
+        super(context, attrs, defStyleAttr, defStyleRes);
+        init(context);
+    }
+
+    public ImportancePreference(Context context, AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+        init(context);
+    }
+
+    public ImportancePreference(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        init(context);
+    }
+
+    public ImportancePreference(Context context) {
+        super(context);
+        init(context);
+    }
+
+    private void init(Context context) {
+        mContext = context;
+        setLayoutResource(R.layout.notif_importance_preference);
+    }
+
+    public void setImportance(int importance) {
+        mImportance = importance;
+    }
+
+    public void setBlockable(boolean blockable) {
+        mIsBlockable = blockable;
+    }
+
+    public void setConfigurable(boolean configurable) {
+        mIsConfigurable = configurable;
+    }
+
+    @Override
+    public void onBindViewHolder(PreferenceViewHolder holder) {
+        super.onBindViewHolder(holder);
+
+        View blockView = holder.itemView.findViewById(R.id.block);
+        View alertView = holder.itemView.findViewById(R.id.alert);
+        View silenceView = holder.itemView.findViewById(R.id.silence);
+        if (!mIsBlockable) {
+            blockView.setVisibility(View.GONE);
+            if (mImportance == IMPORTANCE_NONE) {
+                mImportance = IMPORTANCE_LOW;
+                callChangeListener(IMPORTANCE_LOW);
+            }
+
+        }
+        blockButton = blockView.findViewById(R.id.block_icon);
+        silenceButton = silenceView.findViewById(R.id.silence_icon);
+        alertButton = alertView.findViewById(R.id.alert_icon);
+        mImageButtons.put(blockButton, mContext.getColor(R.color.notification_block_color));
+        mImageButtons.put(silenceButton, mContext.getColor(R.color.notification_silence_color));
+        mImageButtons.put(alertButton, mContext.getColor(R.color.notification_alert_color));
+
+        switch (mImportance) {
+            case IMPORTANCE_NONE:
+                colorizeImageButton(blockButton.getId());
+                if (!mIsConfigurable) {
+                    alertView.setVisibility(View.GONE);
+                    silenceView.setVisibility(View.GONE);
+                }
+                break;
+            case IMPORTANCE_MIN:
+            case IMPORTANCE_LOW:
+                colorizeImageButton(silenceButton.getId());
+                if (!mIsConfigurable) {
+                    alertView.setVisibility(View.GONE);
+                    blockView.setVisibility(View.GONE);
+                }
+                break;
+            case IMPORTANCE_HIGH:
+            default:
+                colorizeImageButton(alertButton.getId());
+                if (!mIsConfigurable) {
+                    blockView.setVisibility(View.GONE);
+                    silenceView.setVisibility(View.GONE);
+                }
+                break;
+        }
+
+        blockButton.setOnClickListener(v -> {
+            callChangeListener(IMPORTANCE_NONE);
+            colorizeImageButton(blockButton.getId());
+        });
+        silenceButton.setOnClickListener(v -> {
+            callChangeListener(IMPORTANCE_LOW);
+            colorizeImageButton(silenceButton.getId());
+        });
+        alertButton.setOnClickListener(v -> {
+            callChangeListener(IMPORTANCE_DEFAULT);
+            colorizeImageButton(alertButton.getId());
+        });
+    }
+
+    private void colorizeImageButton(int buttonId) {
+        if (mImageButtons != null) {
+            for (int i = 0; i < mImageButtons.size(); i++) {
+                final ImageButton imageButton = mImageButtons.keyAt(i);
+                final int color = mImageButtons.valueAt(i);
+                if (imageButton != null) {
+                    LayerDrawable drawable = (LayerDrawable) imageButton.getDrawable();
+                    Drawable foreground = drawable.findDrawableByLayerId(R.id.fore);
+                    GradientDrawable background =
+                            (GradientDrawable) drawable.findDrawableByLayerId(R.id.back);
+                    if (buttonId == imageButton.getId()) {
+                        foreground.setTint(Color.WHITE);
+                        background.setColor(color);
+                    } else {
+                        foreground.setTint(color);
+                        background.setColor(Color.TRANSPARENT);
+                    }
+                }
+            }
+        }
+    }
+}
diff --git a/src/com/android/settings/notification/ImportancePreferenceController.java b/src/com/android/settings/notification/ImportancePreferenceController.java
index 4c20a46..0955571 100644
--- a/src/com/android/settings/notification/ImportancePreferenceController.java
+++ b/src/com/android/settings/notification/ImportancePreferenceController.java
@@ -18,21 +18,15 @@
 
 import static android.app.NotificationChannel.USER_LOCKED_SOUND;
 import static android.app.NotificationManager.IMPORTANCE_DEFAULT;
-import static android.app.NotificationManager.IMPORTANCE_HIGH;
-import static android.app.NotificationManager.IMPORTANCE_MIN;
-import static android.app.NotificationManager.IMPORTANCE_UNSPECIFIED;
 
 import android.app.NotificationChannel;
-import android.app.NotificationManager;
 import android.content.Context;
 import android.media.RingtoneManager;
 
-import androidx.preference.Preference;
-
-import com.android.settings.R;
-import com.android.settings.RestrictedListPreference;
 import com.android.settings.core.PreferenceControllerMixin;
 
+import androidx.preference.Preference;
+
 public class ImportancePreferenceController extends NotificationPreferenceController
         implements PreferenceControllerMixin, Preference.OnPreferenceChangeListener  {
 
@@ -53,44 +47,33 @@
 
     @Override
     public boolean isAvailable() {
-        if (!super.isAvailable()) {
+        if (mAppRow == null) {
             return false;
         }
         if (mChannel == null) {
             return false;
         }
-        return !isDefaultChannel();
+        if (isDefaultChannel()) {
+            return false;
+        }
+        return true;
     }
 
     @Override
     public void updateState(Preference preference) {
         if (mAppRow!= null && mChannel != null) {
             preference.setEnabled(mAdmin == null && isChannelConfigurable());
-            preference.setSummary(getImportanceSummary(mChannel));
-
-            int importances = IMPORTANCE_HIGH - IMPORTANCE_MIN + 1;
-            CharSequence[] entries = new CharSequence[importances];
-            CharSequence[] values = new CharSequence[importances];
-
-            int index = 0;
-            for (int i = IMPORTANCE_HIGH; i >= IMPORTANCE_MIN; i--) {
-                NotificationChannel channel = new NotificationChannel("", "", i);
-                entries[index] = getImportanceSummary(channel);
-                values[index] = String.valueOf(i);
-                index++;
-            }
-
-            RestrictedListPreference pref = (RestrictedListPreference) preference;
-            pref.setEntries(entries);
-            pref.setEntryValues(values);
-            pref.setValue(String.valueOf(mChannel.getImportance()));
+            ImportancePreference pref = (ImportancePreference) preference;
+            pref.setBlockable(isChannelBlockable());
+            pref.setConfigurable(isChannelConfigurable());
+            pref.setImportance(mChannel.getImportance());
         }
     }
 
     @Override
     public boolean onPreferenceChange(Preference preference, Object newValue) {
         if (mChannel != null) {
-            final int importance = Integer.parseInt((String) newValue);
+            final int importance = (Integer) newValue;
 
             // If you are moving from an importance level without sound to one with sound,
             // but the sound you had selected was "Silence",
@@ -111,39 +94,4 @@
         }
         return true;
     }
-
-    protected String getImportanceSummary(NotificationChannel channel) {
-        String summary = "";
-        int importance = channel.getImportance();
-        switch (importance) {
-            case IMPORTANCE_UNSPECIFIED:
-                summary = mContext.getString(R.string.notification_importance_unspecified);
-                break;
-            case NotificationManager.IMPORTANCE_MIN:
-                summary = mContext.getString(R.string.notification_importance_min);
-                break;
-            case NotificationManager.IMPORTANCE_LOW:
-                summary = mContext.getString(R.string.notification_importance_low);
-                break;
-            case NotificationManager.IMPORTANCE_DEFAULT:
-                if (SoundPreferenceController.hasValidSound(channel)) {
-                    summary = mContext.getString(R.string.notification_importance_default);
-                } else {
-                    summary = mContext.getString(R.string.notification_importance_low);
-                }
-                break;
-            case NotificationManager.IMPORTANCE_HIGH:
-            case NotificationManager.IMPORTANCE_MAX:
-                if (SoundPreferenceController.hasValidSound(channel)) {
-                    summary = mContext.getString(R.string.notification_importance_high);
-                } else {
-                    summary = mContext.getString(R.string.notification_importance_high_silent);
-                }
-                break;
-            default:
-                return "";
-        }
-
-        return summary;
-    }
 }
diff --git a/src/com/android/settings/notification/MinImportancePreferenceController.java b/src/com/android/settings/notification/MinImportancePreferenceController.java
new file mode 100644
index 0000000..771ac60
--- /dev/null
+++ b/src/com/android/settings/notification/MinImportancePreferenceController.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.notification;
+
+import static android.app.NotificationManager.IMPORTANCE_LOW;
+import static android.app.NotificationManager.IMPORTANCE_MIN;
+
+import android.app.NotificationChannel;
+import android.content.Context;
+
+import com.android.settings.core.PreferenceControllerMixin;
+import com.android.settingslib.RestrictedSwitchPreference;
+
+import androidx.preference.Preference;
+
+public class MinImportancePreferenceController extends NotificationPreferenceController
+        implements PreferenceControllerMixin, Preference.OnPreferenceChangeListener  {
+
+    private static final String KEY_IMPORTANCE = "min_importance";
+    private NotificationSettingsBase.ImportanceListener mImportanceListener;
+
+    public MinImportancePreferenceController(Context context,
+            NotificationSettingsBase.ImportanceListener importanceListener,
+            NotificationBackend backend) {
+        super(context, backend);
+        mImportanceListener = importanceListener;
+    }
+
+    @Override
+    public String getPreferenceKey() {
+        return KEY_IMPORTANCE;
+    }
+
+    @Override
+    public boolean isAvailable() {
+        if (!super.isAvailable()) {
+            return false;
+        }
+        if (mChannel == null) {
+            return false;
+        }
+        if (isDefaultChannel()) {
+            return false;
+        }
+        return mChannel.getImportance() <= IMPORTANCE_LOW;
+    }
+
+    @Override
+    public void updateState(Preference preference) {
+        if (mAppRow!= null && mChannel != null) {
+            preference.setEnabled(mAdmin == null && isChannelConfigurable());
+
+            RestrictedSwitchPreference pref = (RestrictedSwitchPreference) preference;
+            pref.setChecked(mChannel.getImportance() == IMPORTANCE_MIN);
+        }
+    }
+
+    @Override
+    public boolean onPreferenceChange(Preference preference, Object newValue) {
+        if (mChannel != null) {
+            final boolean checked = (boolean) newValue;
+
+            mChannel.setImportance(checked ? IMPORTANCE_MIN : IMPORTANCE_LOW);
+            mChannel.lockFields(NotificationChannel.USER_LOCKED_IMPORTANCE);
+            saveChannel();
+            mImportanceListener.onImportanceChanged();
+        }
+        return true;
+    }
+}
diff --git a/src/com/android/settings/notification/ZenRulePreference.java b/src/com/android/settings/notification/ZenRulePreference.java
index 613eb1d..8bc602a 100644
--- a/src/com/android/settings/notification/ZenRulePreference.java
+++ b/src/com/android/settings/notification/ZenRulePreference.java
@@ -171,6 +171,9 @@
                 getSettingsActivity(rule, si);
         mIntent = AbstractZenModeAutomaticRulePreferenceController.getRuleIntent(action,
                 settingsActivity, mId);
+        if (mIntent.resolveActivity(mPm) == null) {
+            mIntent = null;
+        }
         setKey(mId);
     }
 
diff --git a/src/com/android/settings/slices/CustomSliceManager.java b/src/com/android/settings/slices/CustomSliceManager.java
deleted file mode 100644
index d0a65ba..0000000
--- a/src/com/android/settings/slices/CustomSliceManager.java
+++ /dev/null
@@ -1,60 +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.slices;
-
-import android.content.Context;
-import android.net.Uri;
-
-import java.util.Map;
-import java.util.WeakHashMap;
-
-/**
- * Manages custom {@link androidx.slice.Slice Slices}, which are all Slices not backed by
- * preferences.
- */
-public class CustomSliceManager {
-
-    private final Context mContext;
-    private final Map<Uri, CustomSliceable> mSliceableCache;
-
-    public CustomSliceManager(Context context) {
-        mContext = context.getApplicationContext();
-        mSliceableCache = new WeakHashMap<>();
-    }
-
-    /**
-     * Return a {@link CustomSliceable} associated to the Uri.
-     * <p>
-     * Do not change this method signature to accommodate for a special-case slicable - a context is
-     * the only thing that should be needed to create the object.
-     */
-    public CustomSliceable getSliceableFromUri(Uri uri) {
-        final Uri newUri = CustomSliceRegistry.removeParameterFromUri(uri);
-        if (mSliceableCache.containsKey(newUri)) {
-            return mSliceableCache.get(newUri);
-        }
-
-        final Class clazz = CustomSliceRegistry.getSliceClassByUri(newUri);
-        if (clazz == null) {
-            throw new IllegalArgumentException("No Slice found for uri: " + uri);
-        }
-
-        final CustomSliceable sliceable = CustomSliceable.createInstance(mContext, clazz);
-        mSliceableCache.put(newUri, sliceable);
-        return sliceable;
-    }
-}
diff --git a/src/com/android/settings/slices/CustomSliceRegistry.java b/src/com/android/settings/slices/CustomSliceRegistry.java
index ebdcdbf..9d88bc5 100644
--- a/src/com/android/settings/slices/CustomSliceRegistry.java
+++ b/src/com/android/settings/slices/CustomSliceRegistry.java
@@ -331,7 +331,7 @@
 
     /**
      * Returns {@code true} if {@param uri} is a valid Slice Uri handled by
-     * {@link CustomSliceManager}.
+     * {@link CustomSliceRegistry}.
      */
     public static boolean isValidUri(Uri uri) {
         return sUriToSlice.containsKey(removeParameterFromUri(uri));
@@ -339,7 +339,7 @@
 
     /**
      * Returns {@code true} if {@param action} is a valid intent action handled by
-     * {@link CustomSliceManager}.
+     * {@link CustomSliceRegistry}.
      */
     public static boolean isValidAction(String action) {
         return isValidUri(Uri.parse(action));
diff --git a/src/com/android/settings/slices/CustomSliceable.java b/src/com/android/settings/slices/CustomSliceable.java
index 8393d4c..93d08a2 100644
--- a/src/com/android/settings/slices/CustomSliceable.java
+++ b/src/com/android/settings/slices/CustomSliceable.java
@@ -110,7 +110,7 @@
         try {
             final Constructor<? extends CustomSliceable> constructor =
                     sliceable.getConstructor(Context.class);
-            final Object[] params = new Object[]{context};
+            final Object[] params = new Object[]{context.getApplicationContext()};
             return constructor.newInstance(params);
         } catch (NoSuchMethodException | InstantiationException |
                 IllegalArgumentException | InvocationTargetException | IllegalAccessException e) {
diff --git a/src/com/android/settings/slices/SettingsSliceProvider.java b/src/com/android/settings/slices/SettingsSliceProvider.java
index d019368..3187d10 100644
--- a/src/com/android/settings/slices/SettingsSliceProvider.java
+++ b/src/com/android/settings/slices/SettingsSliceProvider.java
@@ -118,9 +118,6 @@
     private static final KeyValueListParser KEY_VALUE_LIST_PARSER = new KeyValueListParser(',');
 
     @VisibleForTesting
-    CustomSliceManager mCustomSliceManager;
-
-    @VisibleForTesting
     SlicesDatabaseAccessor mSlicesDatabaseAccessor;
 
     @VisibleForTesting
@@ -140,15 +137,15 @@
         mSlicesDatabaseAccessor = new SlicesDatabaseAccessor(getContext());
         mSliceDataCache = new ConcurrentHashMap<>();
         mSliceWeakDataCache = new WeakHashMap<>();
-        mCustomSliceManager = FeatureFactory.getFactory(
-                getContext()).getSlicesFeatureProvider().getCustomSliceManager(getContext());
         return true;
     }
 
     @Override
     public void onSlicePinned(Uri sliceUri) {
         if (CustomSliceRegistry.isValidUri(sliceUri)) {
-            final CustomSliceable sliceable = mCustomSliceManager.getSliceableFromUri(sliceUri);
+            final Context context = getContext();
+            final CustomSliceable sliceable = FeatureFactory.getFactory(context)
+                    .getSlicesFeatureProvider().getSliceableFromUri(context, sliceUri);
             final IntentFilter filter = sliceable.getIntentFilter();
             if (filter != null) {
                 registerIntentToUri(filter, sliceUri);
@@ -195,9 +192,10 @@
             // Before adding a slice to {@link CustomSliceManager}, please get approval
             // from the Settings team.
             if (CustomSliceRegistry.isValidUri(sliceUri)) {
-                final CustomSliceable sliceable = mCustomSliceManager.getSliceableFromUri(
-                        sliceUri);
-                return sliceable.getSlice();
+                final Context context = getContext();
+                return FeatureFactory.getFactory(context)
+                        .getSlicesFeatureProvider().getSliceableFromUri(context, sliceUri)
+                        .getSlice();
             }
 
             if (CustomSliceRegistry.WIFI_CALLING_URI.equals(sliceUri)) {
diff --git a/src/com/android/settings/slices/SlicesFeatureProvider.java b/src/com/android/settings/slices/SlicesFeatureProvider.java
index 16a7424..ae94f29 100644
--- a/src/com/android/settings/slices/SlicesFeatureProvider.java
+++ b/src/com/android/settings/slices/SlicesFeatureProvider.java
@@ -1,6 +1,7 @@
 package com.android.settings.slices;
 
 import android.content.Context;
+import android.net.Uri;
 
 import com.android.settings.network.telephony.Enhanced4gLteSliceHelper;
 import com.android.settings.wifi.calling.WifiCallingSliceHelper;
@@ -15,6 +16,20 @@
     SliceDataConverter getSliceDataConverter(Context context);
 
     /**
+     * Starts a new UI session for the purpose of using Slices.
+     *
+     * A UI session is defined as an duration of time when user stays in a UI screen. Screen
+     * rotation does not break the continuation of session, going to a sub-page and coming out does
+     * not break the continuation either. Leaving the page and coming back breaks it.
+     */
+    void newUiSession();
+
+    /**
+     * Returns the token created in {@link #newUiSession}.
+     */
+    long getUiSessionToken();
+
+    /**
      * Asynchronous call to index the data used to build Slices.
      * If the data is already indexed, the data will not change.
      */
@@ -26,7 +41,14 @@
      */
     void indexSliceData(Context context);
 
-    CustomSliceManager getCustomSliceManager(Context context);
+
+    /**
+     * Return a {@link CustomSliceable} associated to the Uri.
+     * <p>
+     * Do not change this method signature to accommodate for a special-case sliceable - a context
+     * is the only thing that should be needed to create the object.
+     */
+    CustomSliceable getSliceableFromUri(Context context, Uri uri);
 
     /**
      * Gets new WifiCallingSliceHelper object
diff --git a/src/com/android/settings/slices/SlicesFeatureProviderImpl.java b/src/com/android/settings/slices/SlicesFeatureProviderImpl.java
index 44863ec..297f2c1 100644
--- a/src/com/android/settings/slices/SlicesFeatureProviderImpl.java
+++ b/src/com/android/settings/slices/SlicesFeatureProviderImpl.java
@@ -17,19 +17,23 @@
 package com.android.settings.slices;
 
 import android.content.Context;
+import android.net.Uri;
+import android.os.SystemClock;
 
 import com.android.settings.network.telephony.Enhanced4gLteSliceHelper;
 import com.android.settings.wifi.calling.WifiCallingSliceHelper;
 import com.android.settingslib.utils.ThreadUtils;
 
+import java.util.Random;
+
 /**
  * Manages Slices in Settings.
  */
 public class SlicesFeatureProviderImpl implements SlicesFeatureProvider {
 
+    private long mUiSessionToken;
     private SlicesIndexer mSlicesIndexer;
     private SliceDataConverter mSliceDataConverter;
-    private CustomSliceManager mCustomSliceManager;
 
     @Override
     public SliceDataConverter getSliceDataConverter(Context context) {
@@ -40,11 +44,13 @@
     }
 
     @Override
-    public CustomSliceManager getCustomSliceManager(Context context) {
-        if (mCustomSliceManager == null) {
-            mCustomSliceManager = new CustomSliceManager(context.getApplicationContext());
-        }
-        return mCustomSliceManager;
+    public void newUiSession() {
+        mUiSessionToken = SystemClock.elapsedRealtime();
+    }
+
+    @Override
+    public long getUiSessionToken() {
+        return mUiSessionToken;
     }
 
     @Override
@@ -69,6 +75,18 @@
         return new Enhanced4gLteSliceHelper(context);
     }
 
+    @Override
+    public CustomSliceable getSliceableFromUri(Context context, Uri uri) {
+        final Uri newUri = CustomSliceRegistry.removeParameterFromUri(uri);
+        final Class clazz = CustomSliceRegistry.getSliceClassByUri(newUri);
+        if (clazz == null) {
+            throw new IllegalArgumentException("No Slice found for uri: " + uri);
+        }
+
+        final CustomSliceable sliceable = CustomSliceable.createInstance(context, clazz);
+        return sliceable;
+    }
+
     private SlicesIndexer getSliceIndexer(Context context) {
         if (mSlicesIndexer == null) {
             mSlicesIndexer = new SlicesIndexer(context.getApplicationContext());
diff --git a/src/com/android/settings/wifi/calling/DisclaimerItem.java b/src/com/android/settings/wifi/calling/DisclaimerItem.java
new file mode 100644
index 0000000..6fd8b70
--- /dev/null
+++ b/src/com/android/settings/wifi/calling/DisclaimerItem.java
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.wifi.calling;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.os.PersistableBundle;
+import android.telephony.CarrierConfigManager;
+import android.util.Log;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+/**
+ * Interface to control disclaimer item from {@link WifiCallingDisclaimerFragment}.
+ */
+@VisibleForTesting
+public abstract class DisclaimerItem {
+    private static final String SHARED_PREFERENCES_NAME = "wfc_disclaimer_prefs";
+
+    protected final Context mContext;
+    protected final int mSubId;
+    private final CarrierConfigManager mCarrierConfigManager;
+
+    DisclaimerItem(Context context, int subId) {
+        mContext = context;
+        mSubId = subId;
+        mCarrierConfigManager = mContext.getSystemService(CarrierConfigManager.class);
+    }
+
+    /**
+     * Called by the {@link WifiCallingDisclaimerFragment} when a user has clicked the agree button.
+     */
+    void onAgreed() {
+        setBooleanSharedPrefs(getPrefKey(), true);
+    }
+
+    /**
+     * Checks whether the disclaimer item need to be displayed or not.
+     *
+     * @return Returns {@code true} if disclaimer item need to be displayed,
+     * {@code false} if not displayed.
+     */
+    boolean shouldShow() {
+        if (getBooleanSharedPrefs(getPrefKey(), false)) {
+            logd("shouldShow: false due to a user has already agreed.");
+            return false;
+        }
+        logd("shouldShow: true");
+        return true;
+    }
+
+    /**
+     * Gets the configuration values for a particular sub id.
+     *
+     * @return The {@link PersistableBundle} instance containing the config value for a
+     * particular phone id, or default values.
+     */
+    protected PersistableBundle getCarrierConfig() {
+        PersistableBundle config = mCarrierConfigManager.getConfigForSubId(mSubId);
+        if (config != null) {
+            return config;
+        }
+        // Return static default defined in CarrierConfigManager.
+        return CarrierConfigManager.getDefaultConfig();
+    }
+
+    protected void logd(String msg) {
+        Log.d(getName(), "[" + mSubId +  "] " + msg);
+    }
+
+    /**
+     * Gets a title id for disclaimer item.
+     *
+     * @return Title id for disclaimer item.
+     */
+    protected abstract int getTitleId();
+
+    /**
+     * Gets a message id for disclaimer item.
+     *
+     * @return Message id for disclaimer item.
+     */
+    protected abstract int getMessageId();
+
+    /**
+     * Gets a name of disclaimer item.
+     *
+     * @return Name of disclaimer item.
+     */
+    protected abstract String getName();
+
+    /**
+     * Gets a preference key to keep user's consent.
+     *
+     * @return Preference key to keep user's consent.
+     */
+    protected abstract String getPrefKey();
+
+    /**
+     * Gets the boolean value from shared preferences.
+     *
+     * @param key The key for the preference item.
+     * @param defValue Value to return if this preference does not exist.
+     * @return The boolean value of corresponding key, or defValue.
+     */
+    private boolean getBooleanSharedPrefs(String key, boolean defValue) {
+        SharedPreferences prefs = mContext.getSharedPreferences(SHARED_PREFERENCES_NAME,
+                Context.MODE_PRIVATE);
+        return prefs.getBoolean(key + mSubId, defValue);
+    }
+
+    /**
+     * Sets the boolean value to shared preferences.
+     *
+     * @param key The key for the preference item.
+     * @param value The value to be set for shared preferences.
+     */
+    private void setBooleanSharedPrefs(String key, boolean value) {
+        SharedPreferences prefs = mContext.getSharedPreferences(SHARED_PREFERENCES_NAME,
+                Context.MODE_PRIVATE);
+        prefs.edit().putBoolean(key + mSubId, value).apply();
+    }
+}
diff --git a/src/com/android/settings/wifi/calling/DisclaimerItemFactory.java b/src/com/android/settings/wifi/calling/DisclaimerItemFactory.java
new file mode 100644
index 0000000..6d8dc8f
--- /dev/null
+++ b/src/com/android/settings/wifi/calling/DisclaimerItemFactory.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.wifi.calling;
+
+import android.content.Context;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * Factory class to create disclaimer items list.
+ */
+@VisibleForTesting
+public final class DisclaimerItemFactory {
+
+    /**
+     * Creates disclaimer items list.
+     *
+     * @param context The application context
+     * @param subId The subscription id.
+     * @return The {@link DisclaimerItem} list instance, if there are no items, return empty list.
+     */
+    public static List<DisclaimerItem> create(Context context, int subId) {
+        List<DisclaimerItem> itemList = getDisclaimerItemList(context, subId);
+        Iterator itr = itemList.iterator();
+        while (itr.hasNext()) {
+            DisclaimerItem item = (DisclaimerItem) itr.next();
+            if (!item.shouldShow()) {
+                itr.remove();
+            }
+        }
+        return itemList;
+    }
+
+    private static List<DisclaimerItem> getDisclaimerItemList(Context context, int subId) {
+        List<DisclaimerItem> itemList = new ArrayList<DisclaimerItem>();
+
+        return itemList;
+    }
+}
diff --git a/src/com/android/settings/wifi/calling/DisclaimerItemListAdapter.java b/src/com/android/settings/wifi/calling/DisclaimerItemListAdapter.java
new file mode 100644
index 0000000..4b5d19c
--- /dev/null
+++ b/src/com/android/settings/wifi/calling/DisclaimerItemListAdapter.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.wifi.calling;
+
+import android.content.Context;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+import androidx.recyclerview.widget.RecyclerView;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.settings.R;
+
+import java.util.List;
+
+/**
+ * Adapter for disclaimer items list.
+ */
+public class DisclaimerItemListAdapter extends
+        RecyclerView.Adapter<DisclaimerItemListAdapter.DisclaimerItemViewHolder> {
+
+    private List<DisclaimerItem> mDisclaimerItemList;
+
+    public DisclaimerItemListAdapter(List<DisclaimerItem> list) {
+        mDisclaimerItemList = list;
+    }
+
+    @Override
+    public DisclaimerItemViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
+        LayoutInflater inflater = (LayoutInflater) parent.getContext().getSystemService(
+                Context.LAYOUT_INFLATER_SERVICE);
+        View view = inflater.inflate(R.layout.wfc_simple_disclaimer_item, null, false);
+        return new DisclaimerItemViewHolder(view);
+    }
+
+    @Override
+    public void onBindViewHolder(DisclaimerItemViewHolder holder, int position) {
+        holder.titleView.setText(mDisclaimerItemList.get(position).getTitleId());
+        holder.descriptionView.setText(mDisclaimerItemList.get(position).getMessageId());
+    }
+
+    @Override
+    public int getItemCount() {
+        return mDisclaimerItemList.size();
+    }
+
+    public static class DisclaimerItemViewHolder extends RecyclerView.ViewHolder {
+        @VisibleForTesting
+        static final int ID_DISCLAIMER_ITEM_TITLE = R.id.disclaimer_title;
+        @VisibleForTesting
+        static final int ID_DISCLAIMER_ITEM_DESCRIPTION = R.id.disclaimer_desc;
+
+        public final TextView titleView;
+        public final TextView descriptionView;
+
+        public DisclaimerItemViewHolder(View itemView) {
+            super(itemView);
+            titleView = itemView.findViewById(ID_DISCLAIMER_ITEM_TITLE);
+            descriptionView = itemView.findViewById(ID_DISCLAIMER_ITEM_DESCRIPTION);
+        }
+    }
+}
diff --git a/src/com/android/settings/wifi/calling/WifiCallingDisclaimerFragment.java b/src/com/android/settings/wifi/calling/WifiCallingDisclaimerFragment.java
new file mode 100644
index 0000000..7763226
--- /dev/null
+++ b/src/com/android/settings/wifi/calling/WifiCallingDisclaimerFragment.java
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.wifi.calling;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.telephony.SubscriptionManager;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Button;
+
+import androidx.recyclerview.widget.DividerItemDecoration;
+import androidx.recyclerview.widget.LinearLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
+import androidx.recyclerview.widget.RecyclerView.OnScrollListener;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.settings.R;
+import com.android.settings.core.InstrumentedFragment;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Fragment for displaying disclaimers for WFC.
+ */
+public class WifiCallingDisclaimerFragment extends InstrumentedFragment
+        implements View.OnClickListener {
+    private static final String TAG = "WifiCallingDisclaimerFragment";
+
+    private static final String STATE_IS_SCROLL_TO_BOTTOM = "state_is_scroll_to_bottom";
+
+    private List<DisclaimerItem> mDisclaimerItemList = new ArrayList<DisclaimerItem>();
+    private Button mAgreeButton;
+    private Button mDisagreeButton;
+    private boolean mScrollToBottom;
+
+    @Override
+    public int getMetricsCategory() {
+        return MetricsEvent.WIFI_CALLING;
+    }
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        final Bundle args = getArguments();
+        final int subId = (args != null) ? args.getInt(WifiCallingSettingsForSub.EXTRA_SUB_ID)
+                : SubscriptionManager.DEFAULT_SUBSCRIPTION_ID;
+
+        mDisclaimerItemList = DisclaimerItemFactory.create(getActivity(), subId);
+        if (mDisclaimerItemList.isEmpty()) {
+            finish(Activity.RESULT_OK);
+            return;
+        }
+
+        if (savedInstanceState != null) {
+            mScrollToBottom = savedInstanceState.getBoolean(
+                    STATE_IS_SCROLL_TO_BOTTOM, mScrollToBottom);
+        }
+    }
+
+    @Override
+    public View onCreateView(LayoutInflater inflater, ViewGroup container,
+            Bundle savedInstanceState) {
+
+        final View view = inflater.inflate(R.layout.wfc_disclaimer_fragment, container, false);
+
+        mAgreeButton = view.findViewById(R.id.agree_button);
+        mAgreeButton.setOnClickListener(this);
+        mDisagreeButton = view.findViewById(R.id.disagree_button);
+        mDisagreeButton.setOnClickListener(this);
+
+        final RecyclerView recyclerView = (RecyclerView) view.findViewById(
+                R.id.disclaimer_item_list);
+        recyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
+        recyclerView.setAdapter(new DisclaimerItemListAdapter(mDisclaimerItemList));
+
+        RecyclerView.ItemDecoration itemDecoration =
+                new DividerItemDecoration(getActivity(), DividerItemDecoration.VERTICAL);
+        recyclerView.addItemDecoration(itemDecoration);
+
+        recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
+            @Override
+            public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
+                super.onScrolled(recyclerView, dx, dy);
+                if (!recyclerView.canScrollVertically(1 /* scrolling down */)) {
+                    mScrollToBottom = true;
+                    updateButtonState();
+                    recyclerView.removeOnScrollListener(this);
+                }
+            }
+        });
+
+        return view;
+    }
+
+    @Override
+    public void onResume() {
+        super.onResume();
+        updateButtonState();
+    }
+
+    @Override
+    public void onSaveInstanceState(Bundle outState) {
+        super.onSaveInstanceState(outState);
+        outState.putBoolean(STATE_IS_SCROLL_TO_BOTTOM, mScrollToBottom);
+    }
+
+    private void updateButtonState() {
+        mAgreeButton.setEnabled(mScrollToBottom);
+    }
+
+    @Override
+    public void onClick(View v) {
+        if (v == mAgreeButton) {
+            for (DisclaimerItem item : mDisclaimerItemList) {
+                item.onAgreed();
+            }
+            finish(Activity.RESULT_OK);
+        } else if (v == mDisagreeButton) {
+            finish(Activity.RESULT_CANCELED);
+        }
+    }
+
+    @VisibleForTesting
+    void finish(int result) {
+        Activity activity = getActivity();
+        activity.setResult(result, null);
+        activity.finish();
+    }
+}
\ No newline at end of file
diff --git a/src/com/android/settings/wifi/calling/WifiCallingSettingsForSub.java b/src/com/android/settings/wifi/calling/WifiCallingSettingsForSub.java
index 625de38..525b59b 100644
--- a/src/com/android/settings/wifi/calling/WifiCallingSettingsForSub.java
+++ b/src/com/android/settings/wifi/calling/WifiCallingSettingsForSub.java
@@ -53,6 +53,7 @@
 import com.android.settings.SettingsActivity;
 import com.android.settings.SettingsPreferenceFragment;
 import com.android.settings.Utils;
+import com.android.settings.core.SubSettingLauncher;
 import com.android.settings.widget.SwitchBar;
 
 /**
@@ -69,9 +70,13 @@
     private static final String BUTTON_WFC_ROAMING_MODE = "wifi_calling_roaming_mode";
     private static final String PREFERENCE_EMERGENCY_ADDRESS = "emergency_address_key";
 
-    private static final int REQUEST_CHECK_WFC_EMERGENCY_ADDRESS = 1;
+    @VisibleForTesting
+    static final int REQUEST_CHECK_WFC_EMERGENCY_ADDRESS = 1;
+    @VisibleForTesting
+    static final int REQUEST_CHECK_WFC_DISCLAIMER = 2;
 
     public static final String EXTRA_LAUNCH_CARRIER_APP = "EXTRA_LAUNCH_CARRIER_APP";
+    public static final String EXTRA_SUB_ID = "EXTRA_SUB_ID";
 
     protected static final String FRAGMENT_BUNDLE_SUBID = "subId";
 
@@ -172,7 +177,7 @@
 
         mEmptyView = getView().findViewById(android.R.id.empty);
         setEmptyView(mEmptyView);
-        final Resources res = SubscriptionManager.getResourcesForSubId(getContext(), mSubId);
+        final Resources res = getResourcesForSubId();
         String emptyViewText = res.getString(R.string.wifi_calling_off_explanation,
                 res.getString(R.string.wifi_calling_off_explanation_2));
         mEmptyView.setText(emptyViewText);
@@ -416,14 +421,17 @@
             return;
         }
 
-        // Call address management activity before turning on WFC
-        Intent carrierAppIntent = getCarrierActivityIntent();
-        if (carrierAppIntent != null) {
-            carrierAppIntent.putExtra(EXTRA_LAUNCH_CARRIER_APP, LAUCH_APP_ACTIVATE);
-            startActivityForResult(carrierAppIntent, REQUEST_CHECK_WFC_EMERGENCY_ADDRESS);
-        } else {
-            updateWfcMode(true);
-        }
+        // Launch disclaimer fragment before turning on WFC
+        final Context context = getActivity();
+        final Bundle args = new Bundle();
+        args.putInt(EXTRA_SUB_ID, mSubId);
+        new SubSettingLauncher(context)
+                .setDestination(WifiCallingDisclaimerFragment.class.getName())
+                .setArguments(args)
+                .setTitleRes(R.string.wifi_calling_settings_title)
+                .setSourceMetricsCategory(getMetricsCategory())
+                .setResultListener(this, REQUEST_CHECK_WFC_DISCLAIMER)
+                .launch();
     }
 
     /*
@@ -476,12 +484,30 @@
 
         final Context context = getActivity();
 
-        if (requestCode == REQUEST_CHECK_WFC_EMERGENCY_ADDRESS) {
-            Log.d(TAG, "WFC emergency address activity result = " + resultCode);
+        Log.d(TAG, "WFC activity request = " + requestCode + " result = " + resultCode);
 
-            if (resultCode == Activity.RESULT_OK) {
-                updateWfcMode(true);
-            }
+        switch (requestCode) {
+            case REQUEST_CHECK_WFC_EMERGENCY_ADDRESS:
+                if (resultCode == Activity.RESULT_OK) {
+                    updateWfcMode(true);
+                }
+                break;
+            case REQUEST_CHECK_WFC_DISCLAIMER:
+                if (resultCode == Activity.RESULT_OK) {
+                    // Call address management activity before turning on WFC
+                    Intent carrierAppIntent = getCarrierActivityIntent();
+                    if (carrierAppIntent != null) {
+                        carrierAppIntent.putExtra(EXTRA_LAUNCH_CARRIER_APP, LAUCH_APP_ACTIVATE);
+                        startActivityForResult(carrierAppIntent,
+                                REQUEST_CHECK_WFC_EMERGENCY_ADDRESS);
+                    } else {
+                        updateWfcMode(true);
+                    }
+                }
+                break;
+            default:
+                Log.e(TAG, "Unexpected request: " + requestCode);
+                break;
         }
     }
 
@@ -568,4 +594,9 @@
         }
         return resId;
     }
+
+    @VisibleForTesting
+    Resources getResourcesForSubId() {
+        return SubscriptionManager.getResourcesForSubId(getContext(), mSubId, false);
+    }
 }
diff --git a/src/com/android/settings/wifi/slice/ContextualWifiSlice.java b/src/com/android/settings/wifi/slice/ContextualWifiSlice.java
index fa8c267..4a799d1 100644
--- a/src/com/android/settings/wifi/slice/ContextualWifiSlice.java
+++ b/src/com/android/settings/wifi/slice/ContextualWifiSlice.java
@@ -25,6 +25,7 @@
 import androidx.annotation.VisibleForTesting;
 import androidx.slice.Slice;
 
+import com.android.settings.overlay.FeatureFactory;
 import com.android.settings.slices.CustomSliceRegistry;
 import com.android.settings.slices.CustomSliceable;
 
@@ -35,7 +36,9 @@
 
     private static final String TAG = "ContextualWifiSlice";
     @VisibleForTesting
-    boolean mPreviouslyDisplayed;
+    static long sActiveUiSession = -1000;
+    @VisibleForTesting
+    static boolean sPreviouslyDisplayed;
 
     public ContextualWifiSlice(Context context) {
         super(context);
@@ -48,13 +51,19 @@
 
     @Override
     public Slice getSlice() {
-        if (!mPreviouslyDisplayed && !TextUtils.equals(getActiveSSID(), WifiSsid.NONE)) {
+        final long currentUiSession = FeatureFactory.getFactory(mContext)
+                .getSlicesFeatureProvider().getUiSessionToken();
+        if (currentUiSession != sActiveUiSession) {
+            sActiveUiSession = currentUiSession;
+            sPreviouslyDisplayed = false;
+        }
+        if (!sPreviouslyDisplayed && !TextUtils.equals(getActiveSSID(), WifiSsid.NONE)) {
             Log.d(TAG, "Wifi is connected, no point showing any suggestion.");
             return null;
         }
-        // Set mPreviouslyDisplayed to true - we will show *something* on the screen. So we should
+        // Set sPreviouslyDisplayed to true - we will show *something* on the screen. So we should
         // keep showing this card to keep UI stable, even if wifi connects to a network later.
-        mPreviouslyDisplayed = true;
+        sPreviouslyDisplayed = true;
 
         return super.getSlice();
     }
diff --git a/tests/robotests/src/com/android/settings/network/MobileNetworkListControllerTest.java b/tests/robotests/src/com/android/settings/network/MobileNetworkListControllerTest.java
index 1325650..10264ab 100644
--- a/tests/robotests/src/com/android/settings/network/MobileNetworkListControllerTest.java
+++ b/tests/robotests/src/com/android/settings/network/MobileNetworkListControllerTest.java
@@ -21,6 +21,7 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.times;
@@ -31,6 +32,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.telephony.SubscriptionInfo;
+import android.telephony.euicc.EuiccManager;
 
 import org.junit.After;
 import org.junit.Before;
@@ -51,6 +53,9 @@
 @RunWith(RobolectricTestRunner.class)
 public class MobileNetworkListControllerTest {
     @Mock
+    EuiccManager mEuiccManager;
+
+    @Mock
     private Lifecycle mLifecycle;
 
     @Mock
@@ -58,12 +63,17 @@
 
     private Context mContext;
     private MobileNetworkListController mController;
+    private Preference mAddMorePreference;
 
     @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
         mContext = spy(Robolectric.setupActivity(Activity.class));
+        when(mContext.getSystemService(EuiccManager.class)).thenReturn(mEuiccManager);
         when(mPreferenceScreen.getContext()).thenReturn(mContext);
+        mAddMorePreference = new Preference(mContext);
+        when(mPreferenceScreen.findPreference(MobileNetworkListController.KEY_ADD_MORE)).thenReturn(
+                mAddMorePreference);
         mController = new MobileNetworkListController(mContext, mLifecycle);
     }
 
@@ -79,6 +89,22 @@
     }
 
     @Test
+    public void displayPreference_eSimNotSupported_addMoreLinkNotVisible() {
+        when(mEuiccManager.isEnabled()).thenReturn(false);
+        mController.displayPreference(mPreferenceScreen);
+        mController.onResume();
+        assertThat(mAddMorePreference.isVisible()).isFalse();
+    }
+
+    @Test
+    public void displayPreference_eSimSupported_addMoreLinkIsVisible() {
+        when(mEuiccManager.isEnabled()).thenReturn(true);
+        mController.displayPreference(mPreferenceScreen);
+        mController.onResume();
+        assertThat(mAddMorePreference.isVisible()).isTrue();
+    }
+
+    @Test
     public void displayPreference_twoSubscriptions_correctlySetup() {
         final SubscriptionInfo sub1 = createMockSubscription(1, "sub1");
         final SubscriptionInfo sub2 = createMockSubscription(2, "sub2");
diff --git a/tests/robotests/src/com/android/settings/network/MobileNetworkSummaryControllerTest.java b/tests/robotests/src/com/android/settings/network/MobileNetworkSummaryControllerTest.java
index ba152b9..3404ca2 100644
--- a/tests/robotests/src/com/android/settings/network/MobileNetworkSummaryControllerTest.java
+++ b/tests/robotests/src/com/android/settings/network/MobileNetworkSummaryControllerTest.java
@@ -16,13 +16,9 @@
 
 package com.android.settings.network;
 
-import static android.telephony.TelephonyManager.MultiSimVariants.DSDS;
-import static android.telephony.TelephonyManager.MultiSimVariants.UNKNOWN;
-
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.ArgumentMatchers.isNull;
 import static org.mockito.ArgumentMatchers.notNull;
 import static org.mockito.Mockito.atLeastOnce;
 import static org.mockito.Mockito.mock;
@@ -37,7 +33,6 @@
 import android.net.ConnectivityManager;
 import android.provider.Settings;
 import android.telephony.SubscriptionInfo;
-import android.telephony.TelephonyManager;
 import android.telephony.euicc.EuiccManager;
 import android.text.TextUtils;
 
@@ -64,8 +59,6 @@
     @Mock
     private Lifecycle mLifecycle;
     @Mock
-    private TelephonyManager mTelephonyManager;
-    @Mock
     private EuiccManager mEuiccManager;
     @Mock
     private PreferenceScreen mPreferenceScreen;
@@ -78,9 +71,7 @@
     public void setUp() {
         MockitoAnnotations.initMocks(this);
         mContext = spy(Robolectric.setupActivity(Activity.class));
-        when(mContext.getSystemService(eq(TelephonyManager.class))).thenReturn(mTelephonyManager);
         when(mContext.getSystemService(EuiccManager.class)).thenReturn(mEuiccManager);
-        when(mTelephonyManager.getMultiSimConfiguration()).thenReturn(UNKNOWN);
         when(mEuiccManager.isEnabled()).thenReturn(true);
 
         mController = new MobileNetworkSummaryController(mContext, mLifecycle);
@@ -97,7 +88,7 @@
 
     @Test
     public void isAvailable_wifiOnlyMode_notAvailable() {
-        ConnectivityManager cm = mock(ConnectivityManager.class);
+        final ConnectivityManager cm = mock(ConnectivityManager.class);
         when(cm.isNetworkSupported(ConnectivityManager.TYPE_MOBILE)).thenReturn(false);
         when(mContext.getSystemService(ConnectivityManager.class)).thenReturn(cm);
         assertThat(mController.isAvailable()).isFalse();
@@ -212,24 +203,7 @@
     }
 
     @Test
-    public void addButton_noSubscriptionsSingleSimMode_noAddClickListener() {
-        mController.displayPreference(mPreferenceScreen);
-        mController.onResume();
-        verify(mPreference, never()).setOnAddClickListener(notNull());
-    }
-
-    @Test
-    public void addButton_oneSubscriptionSingleSimMode_noAddClickListener() {
-        final SubscriptionInfo sub1 = mock(SubscriptionInfo.class);
-        SubscriptionUtil.setAvailableSubscriptionsForTesting(Arrays.asList(sub1));
-        mController.displayPreference(mPreferenceScreen);
-        mController.onResume();
-        verify(mPreference, never()).setOnAddClickListener(notNull());
-    }
-
-    @Test
-    public void addButton_noSubscriptionsMultiSimModeNoEuiccMgr_noAddClickListener() {
-        when(mTelephonyManager.getMultiSimConfiguration()).thenReturn(DSDS);
+    public void addButton_noSubscriptionsNoEuiccMgr_noAddClickListener() {
         when(mEuiccManager.isEnabled()).thenReturn(false);
         mController.displayPreference(mPreferenceScreen);
         mController.onResume();
@@ -237,41 +211,43 @@
     }
 
     @Test
-    public void addButton_noSubscriptionsMultiSimMode_hasAddClickListenerAndPrefDisabled() {
-        when(mTelephonyManager.getMultiSimConfiguration()).thenReturn(DSDS);
-        mController.displayPreference(mPreferenceScreen);
-        mController.onResume();
-        assertThat(mPreference.isEnabled()).isFalse();
-        verify(mPreference, never()).setOnAddClickListener(isNull());
-        verify(mPreference).setOnAddClickListener(notNull());
-    }
-
-    @Test
-    public void addButton_oneSubscriptionMultiSimMode_hasAddClickListener() {
-        when(mTelephonyManager.getMultiSimConfiguration()).thenReturn(DSDS);
+    public void addButton_oneSubscriptionNoEuiccMgr_noAddClickListener() {
+        when(mEuiccManager.isEnabled()).thenReturn(false);
         final SubscriptionInfo sub1 = mock(SubscriptionInfo.class);
         SubscriptionUtil.setAvailableSubscriptionsForTesting(Arrays.asList(sub1));
         mController.displayPreference(mPreferenceScreen);
         mController.onResume();
-        verify(mPreference, never()).setOnAddClickListener(isNull());
+        verify(mPreference, never()).setOnAddClickListener(notNull());
+    }
+
+    @Test
+    public void addButton_noSubscriptions_noAddClickListener() {
+        mController.displayPreference(mPreferenceScreen);
+        mController.onResume();
+        verify(mPreference, never()).setOnAddClickListener(notNull());
+    }
+
+    @Test
+    public void addButton_oneSubscription_hasAddClickListener() {
+        final SubscriptionInfo sub1 = mock(SubscriptionInfo.class);
+        SubscriptionUtil.setAvailableSubscriptionsForTesting(Arrays.asList(sub1));
+        mController.displayPreference(mPreferenceScreen);
+        mController.onResume();
         verify(mPreference).setOnAddClickListener(notNull());
     }
 
     @Test
-    public void addButton_twoSubscriptionsMultiSimMode_hasAddClickListener() {
-        when(mTelephonyManager.getMultiSimConfiguration()).thenReturn(DSDS);
+    public void addButton_twoSubscriptions_hasAddClickListener() {
         final SubscriptionInfo sub1 = mock(SubscriptionInfo.class);
         final SubscriptionInfo sub2 = mock(SubscriptionInfo.class);
         SubscriptionUtil.setAvailableSubscriptionsForTesting(Arrays.asList(sub1, sub2));
         mController.displayPreference(mPreferenceScreen);
         mController.onResume();
-        verify(mPreference, never()).setOnAddClickListener(isNull());
         verify(mPreference).setOnAddClickListener(notNull());
     }
 
     @Test
     public void addButton_oneSubscriptionAirplaneModeTurnedOn_addButtonGetsDisabled() {
-        when(mTelephonyManager.getMultiSimConfiguration()).thenReturn(DSDS);
         final SubscriptionInfo sub1 = mock(SubscriptionInfo.class);
         SubscriptionUtil.setAvailableSubscriptionsForTesting(Arrays.asList(sub1));
         mController.displayPreference(mPreferenceScreen);
@@ -280,14 +256,13 @@
         Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.AIRPLANE_MODE_ON, 1);
         mController.onAirplaneModeChanged(true);
 
-        ArgumentCaptor<Boolean> captor = ArgumentCaptor.forClass(Boolean.class);
+        final ArgumentCaptor<Boolean> captor = ArgumentCaptor.forClass(Boolean.class);
         verify(mPreference, atLeastOnce()).setAddWidgetEnabled(captor.capture());
         assertThat(captor.getValue()).isFalse();
     }
 
     @Test
     public void onResume_oneSubscriptionAirplaneMode_isDisabled() {
-        when(mTelephonyManager.getMultiSimConfiguration()).thenReturn(DSDS);
         Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.AIRPLANE_MODE_ON, 1);
         final SubscriptionInfo sub1 = mock(SubscriptionInfo.class);
         SubscriptionUtil.setAvailableSubscriptionsForTesting(Arrays.asList(sub1));
@@ -296,7 +271,7 @@
 
         assertThat(mPreference.isEnabled()).isFalse();
 
-        ArgumentCaptor<Boolean> captor = ArgumentCaptor.forClass(Boolean.class);
+        final ArgumentCaptor<Boolean> captor = ArgumentCaptor.forClass(Boolean.class);
         verify(mPreference, atLeastOnce()).setAddWidgetEnabled(captor.capture());
         assertThat(captor.getValue()).isFalse();
     }
@@ -318,7 +293,6 @@
 
     @Test
     public void onAirplaneModeChanged_oneSubscriptionAirplaneModeGetsTurnedOff_isEnabled() {
-        when(mTelephonyManager.getMultiSimConfiguration()).thenReturn(DSDS);
         Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.AIRPLANE_MODE_ON, 1);
         final SubscriptionInfo sub1 = mock(SubscriptionInfo.class);
         SubscriptionUtil.setAvailableSubscriptionsForTesting(Arrays.asList(sub1));
@@ -332,7 +306,7 @@
 
         assertThat(mPreference.isEnabled()).isTrue();
 
-        ArgumentCaptor<Boolean> captor = ArgumentCaptor.forClass(Boolean.class);
+        final ArgumentCaptor<Boolean> captor = ArgumentCaptor.forClass(Boolean.class);
         verify(mPreference, atLeastOnce()).setAddWidgetEnabled(eq(false));
         verify(mPreference, atLeastOnce()).setAddWidgetEnabled(captor.capture());
         assertThat(captor.getValue()).isTrue();
diff --git a/tests/robotests/src/com/android/settings/notification/BlockPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/BlockPreferenceControllerTest.java
index 4f6944a..bdbf40a 100644
--- a/tests/robotests/src/com/android/settings/notification/BlockPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/notification/BlockPreferenceControllerTest.java
@@ -111,6 +111,26 @@
     }
 
     @Test
+    public void testIsAvailable_notIfChannelNonDefault() {
+        NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
+        appRow.systemApp = true;
+        NotificationChannel channel = mock(NotificationChannel.class);
+        when(channel.getImportance()).thenReturn(IMPORTANCE_HIGH);
+        mController.onResume(appRow, channel, null, null);
+        assertFalse(mController.isAvailable());
+    }
+
+    @Test
+    public void testIsAvailable_ifChannelDefault() {
+        NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
+        NotificationChannel channel = mock(NotificationChannel.class);
+        when(channel.getImportance()).thenReturn(IMPORTANCE_HIGH);
+        when(channel.getId()).thenReturn(DEFAULT_CHANNEL_ID);
+        mController.onResume(appRow, channel, null, null);
+        assertTrue(mController.isAvailable());
+    }
+
+    @Test
     public void testIsAvailable_notIfGroupNotBlockable() {
         NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
         appRow.systemApp = true;
diff --git a/tests/robotests/src/com/android/settings/notification/HighImportancePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/HighImportancePreferenceControllerTest.java
new file mode 100644
index 0000000..6e6dad4
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/notification/HighImportancePreferenceControllerTest.java
@@ -0,0 +1,199 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.notification;
+
+import static android.app.NotificationChannel.DEFAULT_CHANNEL_ID;
+import static android.app.NotificationManager.IMPORTANCE_DEFAULT;
+import static android.app.NotificationManager.IMPORTANCE_HIGH;
+import static android.app.NotificationManager.IMPORTANCE_NONE;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.app.NotificationChannel;
+import android.app.NotificationManager;
+import android.content.Context;
+import android.os.UserManager;
+
+import com.android.settingslib.RestrictedLockUtils;
+import com.android.settingslib.RestrictedSwitchPreference;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Answers;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.shadows.ShadowApplication;
+
+import androidx.preference.Preference;
+import androidx.preference.PreferenceScreen;
+
+@RunWith(RobolectricTestRunner.class)
+public class HighImportancePreferenceControllerTest {
+
+    private Context mContext;
+    @Mock
+    private NotificationManager mNm;
+    @Mock
+    private NotificationBackend mBackend;
+    @Mock
+    private NotificationSettingsBase.ImportanceListener mImportanceListener;
+    @Mock
+    private UserManager mUm;
+    @Mock(answer = Answers.RETURNS_DEEP_STUBS)
+    private PreferenceScreen mScreen;
+
+    private HighImportancePreferenceController mController;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        ShadowApplication shadowApplication = ShadowApplication.getInstance();
+        shadowApplication.setSystemService(Context.NOTIFICATION_SERVICE, mNm);
+        shadowApplication.setSystemService(Context.USER_SERVICE, mUm);
+        mContext = RuntimeEnvironment.application;
+        mController = spy(new HighImportancePreferenceController(
+                mContext, mImportanceListener, mBackend));
+    }
+
+    @Test
+    public void testNoCrashIfNoOnResume() {
+        mController.isAvailable();
+        mController.updateState(mock(Preference.class));
+    }
+
+    @Test
+    public void testIsAvailable_notIfNull() {
+        mController.onResume(null, null, null, null);
+        assertFalse(mController.isAvailable());
+    }
+
+    @Test
+    public void testIsAvailable_ifAppBlocked() {
+        NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
+        appRow.banned = true;
+        mController.onResume(appRow, mock(NotificationChannel.class), null, null);
+        assertFalse(mController.isAvailable());
+    }
+
+    @Test
+    public void testIsAvailable_notIfChannelBlocked() {
+        NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
+        NotificationChannel channel = mock(NotificationChannel.class);
+        when(channel.getImportance()).thenReturn(IMPORTANCE_NONE);
+        mController.onResume(appRow, channel, null, null);
+        assertFalse(mController.isAvailable());
+    }
+
+    @Test
+    public void testIsAvailable_notForDefaultChannel() {
+        NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
+        NotificationChannel channel = mock(NotificationChannel.class);
+        when(channel.getImportance()).thenReturn(IMPORTANCE_HIGH);
+        when(channel.getId()).thenReturn(DEFAULT_CHANNEL_ID);
+        mController.onResume(appRow, channel, null, null);
+        assertFalse(mController.isAvailable());
+    }
+
+    @Test
+    public void testIsAvailable() {
+        NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
+        NotificationChannel channel = mock(NotificationChannel.class);
+        when(channel.getImportance()).thenReturn(IMPORTANCE_DEFAULT);
+        mController.onResume(appRow, channel, null, null);
+        assertTrue(mController.isAvailable());
+    }
+
+    @Test
+    public void testUpdateState_disabledByAdmin() {
+        NotificationChannel channel = mock(NotificationChannel.class);
+        when(channel.getImportance()).thenReturn(IMPORTANCE_HIGH);
+        mController.onResume(new NotificationBackend.AppRow(), channel, null, mock(
+                RestrictedLockUtils.EnforcedAdmin.class));
+
+        Preference pref = new RestrictedSwitchPreference(mContext, null);
+        mController.updateState(pref);
+
+        assertFalse(pref.isEnabled());
+    }
+
+    @Test
+    public void testUpdateState_notConfigurable() {
+        String lockedId = "locked";
+        NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
+        appRow.lockedChannelId = lockedId;
+        NotificationChannel channel = mock(NotificationChannel.class);
+        when(channel.getId()).thenReturn(lockedId);
+        when(channel.getImportance()).thenReturn(IMPORTANCE_HIGH);
+        mController.onResume(appRow, channel, null, null);
+
+        Preference pref = new RestrictedSwitchPreference(mContext, null);
+        mController.updateState(pref);
+
+        assertFalse(pref.isEnabled());
+    }
+
+    @Test
+    public void testUpdateState_high() {
+        NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
+        NotificationChannel channel = new NotificationChannel("", "", IMPORTANCE_HIGH);
+        mController.onResume(appRow, channel, null, null);
+
+        RestrictedSwitchPreference pref = new RestrictedSwitchPreference(mContext);
+        mController.updateState(pref);
+
+        assertTrue(pref.isChecked());
+    }
+
+    @Test
+    public void testUpdateState_default() {
+        NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
+        NotificationChannel channel = new NotificationChannel("", "", IMPORTANCE_DEFAULT);
+        mController.onResume(appRow, channel, null, null);
+
+        RestrictedSwitchPreference pref = new RestrictedSwitchPreference(mContext);
+        mController.updateState(pref);
+
+        assertFalse(pref.isChecked());
+    }
+    
+    @Test
+    public void onPreferenceChange() {
+        NotificationChannel channel =
+                new NotificationChannel(DEFAULT_CHANNEL_ID, "a", IMPORTANCE_HIGH);
+        mController.onResume(new NotificationBackend.AppRow(), channel, null, null);
+
+        RestrictedSwitchPreference pref = new RestrictedSwitchPreference(mContext, null);
+        when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(pref);
+        mController.displayPreference(mScreen);
+        mController.updateState(pref);
+
+        mController.onPreferenceChange(pref, false);
+
+        assertEquals(IMPORTANCE_DEFAULT, channel.getImportance());
+        verify(mImportanceListener, times(1)).onImportanceChanged();
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/notification/ImportancePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/ImportancePreferenceControllerTest.java
index 99d3376..c180ace 100644
--- a/tests/robotests/src/com/android/settings/notification/ImportancePreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/notification/ImportancePreferenceControllerTest.java
@@ -27,8 +27,11 @@
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 
+import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
 import android.app.Notification;
@@ -36,12 +39,10 @@
 import android.app.NotificationManager;
 import android.content.Context;
 import android.os.UserManager;
-import android.text.TextUtils;
 
 import androidx.preference.Preference;
 import androidx.preference.PreferenceScreen;
 
-import com.android.settings.RestrictedListPreference;
 import com.android.settingslib.RestrictedLockUtils;
 
 import org.junit.Before;
@@ -95,20 +96,20 @@
     }
 
     @Test
-    public void testIsAvailable_notIfAppBlocked() {
+    public void testIsAvailable_ifAppBlocked() {
         NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
         appRow.banned = true;
         mController.onResume(appRow, mock(NotificationChannel.class), null, null);
-        assertFalse(mController.isAvailable());
+        assertTrue(mController.isAvailable());
     }
 
     @Test
-    public void testIsAvailable_notIfChannelBlocked() {
+    public void testIsAvailable_evenIfChannelBlocked() {
         NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
         NotificationChannel channel = mock(NotificationChannel.class);
         when(channel.getImportance()).thenReturn(IMPORTANCE_NONE);
         mController.onResume(appRow, channel, null, null);
-        assertFalse(mController.isAvailable());
+        assertTrue(mController.isAvailable());
     }
 
     @Test
@@ -137,11 +138,10 @@
         mController.onResume(new NotificationBackend.AppRow(), channel, null, mock(
                 RestrictedLockUtils.EnforcedAdmin.class));
 
-        Preference pref = new RestrictedListPreference(mContext, null);
+        Preference pref = new ImportancePreference(mContext, null);
         mController.updateState(pref);
 
         assertFalse(pref.isEnabled());
-        assertFalse(TextUtils.isEmpty(pref.getSummary()));
     }
 
     @Test
@@ -154,11 +154,10 @@
         when(channel.getImportance()).thenReturn(IMPORTANCE_HIGH);
         mController.onResume(appRow, channel, null, null);
 
-        Preference pref = new RestrictedListPreference(mContext, null);
+        Preference pref = new ImportancePreference(mContext, null);
         mController.updateState(pref);
 
         assertFalse(pref.isEnabled());
-        assertFalse(TextUtils.isEmpty(pref.getSummary()));
     }
 
     @Test
@@ -167,11 +166,12 @@
         NotificationChannel channel = new NotificationChannel("", "", IMPORTANCE_HIGH);
         mController.onResume(appRow, channel, null, null);
 
-        Preference pref = new RestrictedListPreference(mContext, null);
+        ImportancePreference pref = mock(ImportancePreference.class);
         mController.updateState(pref);
 
-        assertTrue(pref.isEnabled());
-        assertFalse(TextUtils.isEmpty(pref.getSummary()));
+        verify(pref, times(1)).setConfigurable(anyBoolean());
+        verify(pref, times(1)).setBlockable(anyBoolean());
+        verify(pref, times(1)).setImportance(IMPORTANCE_HIGH);
     }
     
     @Test
@@ -181,13 +181,12 @@
         channel.setSound(null, Notification.AUDIO_ATTRIBUTES_DEFAULT);
         mController.onResume(new NotificationBackend.AppRow(), channel, null, null);
 
-        RestrictedListPreference pref = new RestrictedListPreference(mContext, null);
+        ImportancePreference pref = new ImportancePreference(mContext, null);
         when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(pref);
         mController.displayPreference(mScreen);
         mController.updateState(pref);
 
-        pref.setValue(String.valueOf(IMPORTANCE_HIGH));
-        mController.onPreferenceChange(pref, pref.getValue());
+        mController.onPreferenceChange(pref, IMPORTANCE_HIGH);
 
         assertEquals(IMPORTANCE_HIGH, channel.getImportance());
         assertNotNull(channel.getSound());
@@ -200,13 +199,12 @@
         channel.setSound(null, Notification.AUDIO_ATTRIBUTES_DEFAULT);
         mController.onResume(new NotificationBackend.AppRow(), channel, null, null);
 
-        RestrictedListPreference pref = new RestrictedListPreference(mContext, null);
+        ImportancePreference pref = new ImportancePreference(mContext, null);
         when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(pref);
         mController.displayPreference(mScreen);
         mController.updateState(pref);
 
-        pref.setValue(String.valueOf(IMPORTANCE_LOW));
-        mController.onPreferenceChange(pref, pref.getValue());
+        mController.onPreferenceChange(pref, IMPORTANCE_LOW);
 
         assertEquals(IMPORTANCE_LOW, channel.getImportance());
         assertNull(channel.getSound());
diff --git a/tests/robotests/src/com/android/settings/notification/ImportancePreferenceTest.java b/tests/robotests/src/com/android/settings/notification/ImportancePreferenceTest.java
new file mode 100644
index 0000000..eebfbd1
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/notification/ImportancePreferenceTest.java
@@ -0,0 +1,192 @@
+/*
+ * 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 android.app.NotificationManager.IMPORTANCE_DEFAULT;
+import static android.app.NotificationManager.IMPORTANCE_LOW;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import android.content.Context;
+import android.graphics.Color;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.GradientDrawable;
+import android.graphics.drawable.LayerDrawable;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.ImageButton;
+import android.widget.LinearLayout;
+import android.widget.Switch;
+
+import com.android.settings.R;
+import com.android.settingslib.RestrictedLockUtils;
+
+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 ImportancePreferenceTest {
+
+    private Context mContext;
+
+    @Before
+    public void setUp() {
+        mContext = RuntimeEnvironment.application;
+    }
+
+    private GradientDrawable getBackground(ImageButton button) {
+        return (GradientDrawable) ((LayerDrawable) button.getDrawable())
+                .findDrawableByLayerId(R.id.back);
+    }
+
+    @Test
+    public void createNewPreference_shouldSetLayout() {
+        final ImportancePreference preference = new ImportancePreference(mContext);
+        assertThat(preference.getLayoutResource()).isEqualTo(
+                R.layout.notif_importance_preference);
+    }
+
+    @Test
+    public void onBindViewHolder_hideBlockNonBlockable() {
+        final ImportancePreference preference = new ImportancePreference(mContext);
+        final LayoutInflater inflater = LayoutInflater.from(mContext);
+        final PreferenceViewHolder holder = PreferenceViewHolder.createInstanceForTests(
+                inflater.inflate(R.layout.notif_importance_preference, null));
+
+        preference.setBlockable(false);
+        preference.setConfigurable(true);
+        preference.setImportance(IMPORTANCE_DEFAULT);
+        preference.onBindViewHolder(holder);
+
+        assertThat(holder.itemView.findViewById(R.id.block).getVisibility()).isEqualTo(View.GONE);
+    }
+
+    @Test
+    public void onBindViewHolder_hideNonSelectedNonConfigurable() {
+        final ImportancePreference preference = new ImportancePreference(mContext);
+        final LayoutInflater inflater = LayoutInflater.from(mContext);
+        PreferenceViewHolder holder = PreferenceViewHolder.createInstanceForTests(
+                inflater.inflate(R.layout.notif_importance_preference, null));
+
+        preference.setBlockable(true);
+        preference.setConfigurable(false);
+        preference.setImportance(IMPORTANCE_DEFAULT);
+        preference.onBindViewHolder(holder);
+
+        assertThat(holder.itemView.findViewById(R.id.block).getVisibility()).isEqualTo(View.GONE);
+        assertThat(holder.itemView.findViewById(R.id.silence).getVisibility()).isEqualTo(View.GONE);
+        assertThat(holder.itemView.findViewById(R.id.alert).getVisibility())
+                .isEqualTo(View.VISIBLE);
+
+        // other button
+        preference.setImportance(IMPORTANCE_LOW);
+        holder = PreferenceViewHolder.createInstanceForTests(
+                inflater.inflate(R.layout.notif_importance_preference, null));
+        preference.onBindViewHolder(holder);
+
+        assertThat(holder.itemView.findViewById(R.id.block).getVisibility()).isEqualTo(View.GONE);
+        assertThat(holder.itemView.findViewById(R.id.silence).getVisibility())
+                .isEqualTo(View.VISIBLE);
+        assertThat(holder.itemView.findViewById(R.id.alert).getVisibility())
+                .isEqualTo(View.GONE);
+    }
+
+    @Test
+    public void onBindViewHolder_selectButton() {
+        final ImportancePreference preference = new ImportancePreference(mContext);
+        final LayoutInflater inflater = LayoutInflater.from(mContext);
+        final PreferenceViewHolder holder = PreferenceViewHolder.createInstanceForTests(
+                inflater.inflate(R.layout.notif_importance_preference, null));
+
+        preference.setBlockable(true);
+        preference.setConfigurable(true);
+        preference.setImportance(IMPORTANCE_DEFAULT);
+
+        ImageButton blockButton = (ImageButton) holder.findViewById(R.id.block_icon);
+        ImageButton silenceButton = (ImageButton) holder.findViewById(R.id.silence_icon);
+        ImageButton alertButton = (ImageButton) holder.findViewById(R.id.alert_icon);
+
+        preference.onBindViewHolder(holder);
+
+        // selected has full color background. others are transparent
+        assertThat(getBackground(alertButton).getColor().getColors()[0]).isNotEqualTo(
+                Color.TRANSPARENT);
+        assertThat(getBackground(silenceButton).getColor().getColors()[0]).isEqualTo(
+                Color.TRANSPARENT);
+        assertThat(getBackground(blockButton).getColor().getColors()[0]).isEqualTo(
+                Color.TRANSPARENT);
+    }
+
+    @Test
+    public void onClick_changesUICallsListener() {
+        final ImportancePreference preference = spy(new ImportancePreference(mContext));
+        final LayoutInflater inflater = LayoutInflater.from(mContext);
+        final PreferenceViewHolder holder = PreferenceViewHolder.createInstanceForTests(
+                inflater.inflate(R.layout.notif_importance_preference, null));
+
+        preference.setBlockable(true);
+        preference.setConfigurable(true);
+        preference.setImportance(IMPORTANCE_DEFAULT);
+        preference.onBindViewHolder(holder);
+
+        ImageButton blockButton = (ImageButton) holder.findViewById(R.id.block_icon);
+        ImageButton silenceButton = (ImageButton) holder.findViewById(R.id.silence_icon);
+        ImageButton alertButton = (ImageButton) holder.findViewById(R.id.alert_icon);
+
+        silenceButton.callOnClick();
+
+        // selected has full color background. others are transparent
+        assertThat(getBackground(silenceButton).getColor().getColors()[0]).isNotEqualTo(
+                Color.TRANSPARENT);
+        assertThat(getBackground(alertButton).getColor().getColors()[0]).isEqualTo(
+                Color.TRANSPARENT);
+        assertThat(getBackground(blockButton).getColor().getColors()[0]).isEqualTo(
+                Color.TRANSPARENT);
+
+        verify(preference, times(1)).callChangeListener(IMPORTANCE_LOW);
+    }
+
+    @Test
+    public void onBindViewHolder_allButtonsVisible() {
+        final ImportancePreference preference = new ImportancePreference(mContext);
+        final LayoutInflater inflater = LayoutInflater.from(mContext);
+        final PreferenceViewHolder holder = PreferenceViewHolder.createInstanceForTests(
+                inflater.inflate(R.layout.notif_importance_preference, null));
+
+        preference.setBlockable(true);
+        preference.setConfigurable(true);
+        preference.onBindViewHolder(holder);
+
+        assertThat(holder.itemView.findViewById(R.id.block).getVisibility())
+                .isEqualTo(View.VISIBLE);
+        assertThat(holder.itemView.findViewById(R.id.silence).getVisibility())
+                .isEqualTo(View.VISIBLE);
+        assertThat(holder.itemView.findViewById(R.id.alert).getVisibility())
+                .isEqualTo(View.VISIBLE);
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/notification/MinImportancePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/MinImportancePreferenceControllerTest.java
new file mode 100644
index 0000000..28058a4
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/notification/MinImportancePreferenceControllerTest.java
@@ -0,0 +1,199 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.notification;
+
+import static android.app.NotificationChannel.DEFAULT_CHANNEL_ID;
+import static android.app.NotificationManager.IMPORTANCE_LOW;
+import static android.app.NotificationManager.IMPORTANCE_MIN;
+import static android.app.NotificationManager.IMPORTANCE_NONE;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.app.NotificationChannel;
+import android.app.NotificationManager;
+import android.content.Context;
+import android.os.UserManager;
+
+import com.android.settingslib.RestrictedLockUtils;
+import com.android.settingslib.RestrictedSwitchPreference;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Answers;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.shadows.ShadowApplication;
+
+import androidx.preference.Preference;
+import androidx.preference.PreferenceScreen;
+
+@RunWith(RobolectricTestRunner.class)
+public class MinImportancePreferenceControllerTest {
+
+    private Context mContext;
+    @Mock
+    private NotificationManager mNm;
+    @Mock
+    private NotificationBackend mBackend;
+    @Mock
+    private NotificationSettingsBase.ImportanceListener mImportanceListener;
+    @Mock
+    private UserManager mUm;
+    @Mock(answer = Answers.RETURNS_DEEP_STUBS)
+    private PreferenceScreen mScreen;
+
+    private MinImportancePreferenceController mController;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        ShadowApplication shadowApplication = ShadowApplication.getInstance();
+        shadowApplication.setSystemService(Context.NOTIFICATION_SERVICE, mNm);
+        shadowApplication.setSystemService(Context.USER_SERVICE, mUm);
+        mContext = RuntimeEnvironment.application;
+        mController = spy(new MinImportancePreferenceController(
+                mContext, mImportanceListener, mBackend));
+    }
+
+    @Test
+    public void testNoCrashIfNoOnResume() {
+        mController.isAvailable();
+        mController.updateState(mock(Preference.class));
+    }
+
+    @Test
+    public void testIsAvailable_notIfNull() {
+        mController.onResume(null, null, null, null);
+        assertFalse(mController.isAvailable());
+    }
+
+    @Test
+    public void testIsAvailable_ifAppBlocked() {
+        NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
+        appRow.banned = true;
+        mController.onResume(appRow, mock(NotificationChannel.class), null, null);
+        assertFalse(mController.isAvailable());
+    }
+
+    @Test
+    public void testIsAvailable_notIfChannelBlocked() {
+        NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
+        NotificationChannel channel = mock(NotificationChannel.class);
+        when(channel.getImportance()).thenReturn(IMPORTANCE_NONE);
+        mController.onResume(appRow, channel, null, null);
+        assertFalse(mController.isAvailable());
+    }
+
+    @Test
+    public void testIsAvailable_notForDefaultChannel() {
+        NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
+        NotificationChannel channel = mock(NotificationChannel.class);
+        when(channel.getImportance()).thenReturn(IMPORTANCE_LOW);
+        when(channel.getId()).thenReturn(DEFAULT_CHANNEL_ID);
+        mController.onResume(appRow, channel, null, null);
+        assertFalse(mController.isAvailable());
+    }
+
+    @Test
+    public void testIsAvailable() {
+        NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
+        NotificationChannel channel = mock(NotificationChannel.class);
+        when(channel.getImportance()).thenReturn(IMPORTANCE_LOW);
+        mController.onResume(appRow, channel, null, null);
+        assertTrue(mController.isAvailable());
+    }
+
+    @Test
+    public void testUpdateState_disabledByAdmin() {
+        NotificationChannel channel = mock(NotificationChannel.class);
+        when(channel.getImportance()).thenReturn(IMPORTANCE_LOW);
+        mController.onResume(new NotificationBackend.AppRow(), channel, null, mock(
+                RestrictedLockUtils.EnforcedAdmin.class));
+
+        Preference pref = new RestrictedSwitchPreference(mContext, null);
+        mController.updateState(pref);
+
+        assertFalse(pref.isEnabled());
+    }
+
+    @Test
+    public void testUpdateState_notConfigurable() {
+        String lockedId = "locked";
+        NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
+        appRow.lockedChannelId = lockedId;
+        NotificationChannel channel = mock(NotificationChannel.class);
+        when(channel.getId()).thenReturn(lockedId);
+        when(channel.getImportance()).thenReturn(IMPORTANCE_LOW);
+        mController.onResume(appRow, channel, null, null);
+
+        Preference pref = new RestrictedSwitchPreference(mContext, null);
+        mController.updateState(pref);
+
+        assertFalse(pref.isEnabled());
+    }
+
+    @Test
+    public void testUpdateState_min() {
+        NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
+        NotificationChannel channel = new NotificationChannel("", "", IMPORTANCE_MIN);
+        mController.onResume(appRow, channel, null, null);
+
+        RestrictedSwitchPreference pref = new RestrictedSwitchPreference(mContext);
+        mController.updateState(pref);
+
+        assertTrue(pref.isChecked());
+    }
+
+    @Test
+    public void testUpdateState_low() {
+        NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
+        NotificationChannel channel = new NotificationChannel("", "", IMPORTANCE_LOW);
+        mController.onResume(appRow, channel, null, null);
+
+        RestrictedSwitchPreference pref = new RestrictedSwitchPreference(mContext);
+        mController.updateState(pref);
+
+        assertFalse(pref.isChecked());
+    }
+    
+    @Test
+    public void onPreferenceChange() {
+        NotificationChannel channel =
+                new NotificationChannel(DEFAULT_CHANNEL_ID, "a", IMPORTANCE_LOW);
+        mController.onResume(new NotificationBackend.AppRow(), channel, null, null);
+
+        RestrictedSwitchPreference pref = new RestrictedSwitchPreference(mContext, null);
+        when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(pref);
+        mController.displayPreference(mScreen);
+        mController.updateState(pref);
+
+        mController.onPreferenceChange(pref, true);
+
+        assertEquals(IMPORTANCE_MIN, channel.getImportance());
+        verify(mImportanceListener, times(1)).onImportanceChanged();
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/slices/SettingsSliceProviderTest.java b/tests/robotests/src/com/android/settings/slices/SettingsSliceProviderTest.java
index a693f34..23025b2 100644
--- a/tests/robotests/src/com/android/settings/slices/SettingsSliceProviderTest.java
+++ b/tests/robotests/src/com/android/settings/slices/SettingsSliceProviderTest.java
@@ -135,7 +135,6 @@
         mProvider.mSliceWeakDataCache = new HashMap<>();
         mProvider.mSliceDataCache = new HashMap<>();
         mProvider.mSlicesDatabaseAccessor = new SlicesDatabaseAccessor(mContext);
-        mProvider.mCustomSliceManager = new CustomSliceManager(mContext);
         when(mProvider.getContext()).thenReturn(mContext);
 
         SlicesDatabaseHelper.getInstance(mContext).setIndexedState();
diff --git a/tests/robotests/src/com/android/settings/slices/SlicesDatabaseHelperTest.java b/tests/robotests/src/com/android/settings/slices/SlicesDatabaseHelperTest.java
index 0e92c05..96bca07 100644
--- a/tests/robotests/src/com/android/settings/slices/SlicesDatabaseHelperTest.java
+++ b/tests/robotests/src/com/android/settings/slices/SlicesDatabaseHelperTest.java
@@ -55,6 +55,7 @@
     @After
     public void cleanUp() {
         DatabaseTestUtils.clearDb(mContext);
+        mDatabase.close();
     }
 
     @Test
diff --git a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowDisclaimerItemFactory.java b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowDisclaimerItemFactory.java
new file mode 100644
index 0000000..c50d4f1
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowDisclaimerItemFactory.java
@@ -0,0 +1,41 @@
+/*
+ * 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.testutils.shadow;
+
+import android.content.Context;
+
+import com.android.settings.wifi.calling.DisclaimerItemFactory;
+import com.android.settings.wifi.calling.DisclaimerItem;
+
+import java.util.List;
+
+import org.robolectric.annotation.Implementation;
+import org.robolectric.annotation.Implements;
+
+@Implements(DisclaimerItemFactory.class)
+public final class ShadowDisclaimerItemFactory {
+    private static List<DisclaimerItem> sMockDisclaimerItemList;
+
+    public static void setDisclaimerItemList(List<DisclaimerItem> list) {
+        sMockDisclaimerItemList = list;
+    }
+
+    @Implementation
+    public static List<DisclaimerItem> create(Context context, int subId) {
+        return sMockDisclaimerItemList;
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/wifi/calling/DisclaimerItemListAdapterTest.java b/tests/robotests/src/com/android/settings/wifi/calling/DisclaimerItemListAdapterTest.java
new file mode 100644
index 0000000..4cfc9ba
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/wifi/calling/DisclaimerItemListAdapterTest.java
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.wifi.calling;
+
+import static com.android.settings.wifi.calling.DisclaimerItemListAdapter
+        .DisclaimerItemViewHolder.ID_DISCLAIMER_ITEM_TITLE;
+import static com.android.settings.wifi.calling.DisclaimerItemListAdapter
+        .DisclaimerItemViewHolder.ID_DISCLAIMER_ITEM_DESCRIPTION;
+import static org.mockito.Matchers.anyBoolean;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.anyObject;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+import com.android.settings.R;
+
+import java.util.ArrayList;
+import java.util.List;
+
+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;
+
+@RunWith(RobolectricTestRunner.class)
+public class DisclaimerItemListAdapterTest {
+
+    private static final int ITEM_POSITION = 0;
+    private static final int DISCLAIMER_TITLE_STRING_ID = 0;
+    private static final int DISCLAIMER_MESSAGE_STRING_ID = 1;
+
+    @Mock
+    private LayoutInflater mLayoutInflater;
+    @Mock
+    private TextView mTestView;
+    @Mock
+    private TextView mDescView;
+    @Mock
+    private View mView;
+    @Mock
+    private ViewGroup mViewGroup;
+    @Mock
+    private Context mContext;
+
+    private MockDisclaimerItem mDisclaimerItem;
+    private DisclaimerItemListAdapter mDisclaimerItemListAdapter;
+    private List<DisclaimerItem> mDisclaimerItemList = new ArrayList<>();
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+
+        mDisclaimerItem = spy(new MockDisclaimerItem(mContext, 0 /* subId */));
+        mDisclaimerItemList.add(mDisclaimerItem);
+
+        when(mLayoutInflater.inflate(anyInt(), anyObject(), anyBoolean())).thenReturn(mView);
+        when(mViewGroup.getContext()).thenReturn(mContext);
+        when(mViewGroup.getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE)).thenReturn(
+                mLayoutInflater);
+        when(mView.findViewById(ID_DISCLAIMER_ITEM_TITLE)).thenReturn(mTestView);
+        when(mView.findViewById(ID_DISCLAIMER_ITEM_DESCRIPTION)).thenReturn(mDescView);
+    }
+
+    @Test
+    public void onBindViewHolder_haveItem_shouldSetText() {
+        final DisclaimerItemListAdapter.DisclaimerItemViewHolder viewHolder =
+                new DisclaimerItemListAdapter.DisclaimerItemViewHolder(mView);
+
+        mDisclaimerItemListAdapter = new DisclaimerItemListAdapter(mDisclaimerItemList);
+        mDisclaimerItemListAdapter.onCreateViewHolder(mViewGroup, 0 /* viewType */);
+        mDisclaimerItemListAdapter.onBindViewHolder(viewHolder, ITEM_POSITION);
+
+        // Check the text is set when the DisclaimerItem exists.
+        verify(viewHolder.titleView).setText(DISCLAIMER_TITLE_STRING_ID);
+        verify(viewHolder.descriptionView).setText(DISCLAIMER_MESSAGE_STRING_ID);
+    }
+
+    private class MockDisclaimerItem extends DisclaimerItem {
+        MockDisclaimerItem(Context context, int subId) {
+            super(context, subId);
+        }
+
+        @Override
+        protected int getTitleId() {
+            return DISCLAIMER_TITLE_STRING_ID;
+        }
+
+        @Override
+        protected int getMessageId() {
+            return DISCLAIMER_MESSAGE_STRING_ID;
+        }
+
+        @Override
+        protected String getName() {
+            return "MockDisclaimerItem";
+        }
+
+        @Override
+        protected String getPrefKey() {
+            return "mock_pref_key";
+        }
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/wifi/calling/WifiCallingDisclaimerFragmentTest.java b/tests/robotests/src/com/android/settings/wifi/calling/WifiCallingDisclaimerFragmentTest.java
new file mode 100644
index 0000000..6c221e7
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/wifi/calling/WifiCallingDisclaimerFragmentTest.java
@@ -0,0 +1,180 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.wifi.calling;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyBoolean;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.anyObject;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.app.Activity;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.view.ViewGroup;
+import android.widget.Button;
+
+import androidx.recyclerview.widget.RecyclerView;
+import androidx.recyclerview.widget.RecyclerView.OnScrollListener;
+
+import com.android.settings.R;
+import com.android.settings.testutils.shadow.ShadowDisclaimerItemFactory;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.annotation.Config;
+import org.robolectric.Robolectric;
+import org.robolectric.RobolectricTestRunner;
+
+@RunWith(RobolectricTestRunner.class)
+@Config(shadows = ShadowDisclaimerItemFactory.class)
+public class WifiCallingDisclaimerFragmentTest {
+
+    @Mock
+    private Activity mActivity;
+    @Mock
+    private DisclaimerItem mDisclaimerItem;
+    @Mock
+    private LayoutInflater mLayoutInflater;
+    @Mock
+    private View mView;
+    @Mock
+    private ViewGroup mViewGroup;
+    @Mock
+    private Button mAgreeButton;
+    @Mock
+    private Button mDisagreeButton;
+    @Mock
+    private RecyclerView mRecyclerView;
+
+    @Captor
+    ArgumentCaptor<OnClickListener> mOnClickListenerCaptor;
+    @Captor
+    ArgumentCaptor<OnScrollListener> mOnScrollListenerCaptor;
+
+    private WifiCallingDisclaimerFragment mFragment;
+    private List<DisclaimerItem> mDisclaimerItemList = new ArrayList<>();
+    private List<DisclaimerItem> mEmptyDisclaimerItemList = new ArrayList<>();
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+
+        mActivity = Robolectric.setupActivity(Activity.class);
+        mFragment = spy(new WifiCallingDisclaimerFragment());
+
+        doReturn(mActivity).when(mFragment).getActivity();
+
+        when(mLayoutInflater.inflate(anyInt(), anyObject(), anyBoolean())).thenReturn(mView);
+        when(mView.findViewById(R.id.agree_button)).thenReturn(mAgreeButton);
+        when(mView.findViewById(R.id.disagree_button)).thenReturn(mDisagreeButton);
+        when(mView.findViewById(R.id.disclaimer_item_list)).thenReturn(mRecyclerView);
+        when(mView.getId()).thenReturn(R.id.agree_button);
+
+        mOnScrollListenerCaptor = ArgumentCaptor.forClass(OnScrollListener.class);
+        doNothing().when(mRecyclerView).addOnScrollListener(mOnScrollListenerCaptor.capture());
+        mOnClickListenerCaptor = ArgumentCaptor.forClass(OnClickListener.class);
+        doNothing().when(mAgreeButton).setOnClickListener(mOnClickListenerCaptor.capture());
+
+        mDisclaimerItemList.add(mDisclaimerItem);
+    }
+
+    @Test
+    public void onCreate_notHaveItem_shouldFinishFragment() {
+        ShadowDisclaimerItemFactory.setDisclaimerItemList(mEmptyDisclaimerItemList);
+
+        mFragment.onCreate(null /* savedInstanceState */);
+
+        // Check the fragment is finished when the DisclaimerItemList is empty.
+        verify(mFragment).finish(Activity.RESULT_OK);
+    }
+
+    @Test
+    public void onCreate_haveItem_shouldNotFinishFragment() {
+        ShadowDisclaimerItemFactory.setDisclaimerItemList(mDisclaimerItemList);
+
+        mFragment.onCreate(null /* savedInstanceState */);
+
+        // Check the fragment is not finished when the DisclaimerItemList is not empty.
+        verify(mFragment, never()).finish(Activity.RESULT_OK);
+    }
+
+    @Test
+    public void onScrolled_canNotScroll_shouldEnableAgreeButton() {
+        ShadowDisclaimerItemFactory.setDisclaimerItemList(mDisclaimerItemList);
+
+        when(mRecyclerView.canScrollVertically(1)).thenReturn(false);
+
+        mFragment.onCreate(null /* savedInstanceState */);
+        mFragment.onCreateView(mLayoutInflater, mViewGroup, null /* savedInstanceState */);
+
+        mOnScrollListenerCaptor.getValue().onScrolled(mRecyclerView, 0, 0);
+
+        // Check the agreeButton is enabled when the view is scrolled to the bottom end.
+        verify(mAgreeButton).setEnabled(true);
+        // Check the OnScrollListener is removed when the view is scrolled to the bottom end.
+        verify(mRecyclerView).removeOnScrollListener(any());
+    }
+
+    @Test
+    public void onScrolled_canScroll_shouldNotEnableAgreeButton() {
+        ShadowDisclaimerItemFactory.setDisclaimerItemList(mDisclaimerItemList);
+
+        when(mRecyclerView.canScrollVertically(1)).thenReturn(true);
+
+        mFragment.onCreate(null /* savedInstanceState */);
+        mFragment.onCreateView(mLayoutInflater, mViewGroup, null /* savedInstanceState */);
+
+        mOnScrollListenerCaptor.getValue().onScrolled(mRecyclerView, 0, 0);
+
+        // Check the agreeButton is not enabled when the view is not scrolled to the bottom end.
+        verify(mAgreeButton, never()).setEnabled(anyBoolean());
+        // Check the OnScrollListener is not removed when the view is not scrolled to
+        // the bottom end.
+        verify(mRecyclerView, never()).removeOnScrollListener(any());
+    }
+
+    @Test
+    public void onClick_agreeButton_shouldFinishFragment() {
+        ShadowDisclaimerItemFactory.setDisclaimerItemList(mDisclaimerItemList);
+
+        mFragment.onCreate(null /* savedInstanceState */);
+        mFragment.onCreateView(mLayoutInflater, mViewGroup, null /* savedInstanceState */);
+
+        mOnClickListenerCaptor.getValue().onClick(mAgreeButton);
+
+        // Check the onAgreed callback is called when "CONTINUE" button is clicked.
+        verify(mDisclaimerItem).onAgreed();
+        // Check the WFC disclaimer fragment is finished when "CONTINUE" button is clicked.
+        verify(mFragment).finish(Activity.RESULT_OK);
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/wifi/calling/WifiCallingSettingsForSubTest.java b/tests/robotests/src/com/android/settings/wifi/calling/WifiCallingSettingsForSubTest.java
index 70f1916..ae88231 100644
--- a/tests/robotests/src/com/android/settings/wifi/calling/WifiCallingSettingsForSubTest.java
+++ b/tests/robotests/src/com/android/settings/wifi/calling/WifiCallingSettingsForSubTest.java
@@ -16,11 +16,14 @@
 
 package com.android.settings.wifi.calling;
 
+import static com.android.settings.SettingsActivity.EXTRA_SHOW_FRAGMENT;
 import static com.google.common.truth.Truth.assertThat;
 
+import static junit.framework.Assert.assertEquals;
 import static org.mockito.Matchers.any;
 import static org.mockito.Matchers.anyBoolean;
 import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.eq;
 import static org.mockito.Mockito.doNothing;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.eq;
@@ -31,6 +34,8 @@
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
+import android.app.Activity;
+import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.os.Bundle;
@@ -41,18 +46,22 @@
 import android.view.View;
 import android.widget.TextView;
 
+import androidx.preference.Preference;
 import androidx.preference.PreferenceScreen;
 
 import com.android.ims.ImsConfig;
 import com.android.ims.ImsManager;
 import com.android.settings.R;
 import com.android.settings.SettingsActivity;
+import com.android.settings.testutils.FakeFeatureFactory;
+import com.android.settings.testutils.shadow.SettingsShadowResources;
 import com.android.settings.widget.SwitchBar;
 import com.android.settings.widget.ToggleSwitch;
 
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 import org.robolectric.RobolectricTestRunner;
@@ -63,6 +72,8 @@
 public class WifiCallingSettingsForSubTest {
     private static final String BUTTON_WFC_MODE = "wifi_calling_mode";
     private static final String BUTTON_WFC_ROAMING_MODE = "wifi_calling_roaming_mode";
+    private static final String TEST_EMERGENCY_ADDRESS_CARRIER_APP =
+            "com.android.settings/.wifi.calling.TestEmergencyAddressCarrierApp";
 
     private TestFragment mFragment;
     private Context mContext;
@@ -70,6 +81,7 @@
     private final PersistableBundle mBundle = new PersistableBundle();
 
     @Mock private static CarrierConfigManager sCarrierConfigManager;
+    @Mock private CarrierConfigManager mMockConfigManager;
     @Mock private ImsManager mImsManager;
     @Mock private TelephonyManager mTelephonyManager;
     @Mock private PreferenceScreen mPreferenceScreen;
@@ -80,6 +92,7 @@
     @Mock private ImsConfig mImsConfig;
     @Mock private ListWithEntrySummaryPreference mButtonWfcMode;
     @Mock private ListWithEntrySummaryPreference mButtonWfcRoamingMode;
+    @Mock private Preference mUpdateAddress;
 
     @Before
     public void setUp() throws Exception {
@@ -121,6 +134,11 @@
         doReturn(mBundle).when(sCarrierConfigManager).getConfigForSubId(anyInt());
         setDefaultCarrierConfigValues();
 
+        doReturn(sCarrierConfigManager).when(mActivity).getSystemService(
+                CarrierConfigManager.class);
+        doReturn(mContext.getResources()).when(mFragment).getResourcesForSubId();
+        doNothing().when(mFragment).startActivityForResult(any(Intent.class), anyInt());
+
         mFragment.onAttach(mContext);
         mFragment.onCreate(null);
         mFragment.onActivityCreated(null);
@@ -131,6 +149,9 @@
                 CarrierConfigManager.KEY_USE_WFC_HOME_NETWORK_MODE_IN_ROAMING_NETWORK_BOOL, false);
         mBundle.putBoolean(CarrierConfigManager.KEY_EDITABLE_WFC_MODE_BOOL, true);
         mBundle.putBoolean(CarrierConfigManager.KEY_EDITABLE_WFC_ROAMING_MODE_BOOL, true);
+        mBundle.putString(
+                CarrierConfigManager.KEY_WFC_EMERGENCY_ADDRESS_CARRIER_APP_STRING,
+                TEST_EMERGENCY_ADDRESS_CARRIER_APP);
     }
 
     @Test
@@ -259,6 +280,61 @@
                 eq(true));
     }
 
+    @Test
+    public void onSwitchChanged_enableSetting_shouldLaunchWfcDisclaimerFragment() {
+        ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
+
+        mFragment.onSwitchChanged(null, true);
+
+        // Check the WFC disclaimer fragment is launched.
+        verify(mFragment).startActivityForResult(intentCaptor.capture(),
+                eq(WifiCallingSettingsForSub.REQUEST_CHECK_WFC_DISCLAIMER));
+        Intent intent = intentCaptor.getValue();
+        assertThat(intent.getStringExtra(EXTRA_SHOW_FRAGMENT))
+                .isEqualTo(WifiCallingDisclaimerFragment.class.getName());
+    }
+
+    @Test
+    public void onActivityResult_finishWfcDisclaimerFragment_shouldLaunchCarrierActivity() {
+        ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
+
+        // Emulate the WfcDisclaimerActivity finish.
+        mFragment.onActivityResult(WifiCallingSettingsForSub.REQUEST_CHECK_WFC_DISCLAIMER,
+                Activity.RESULT_OK, null);
+
+        // Check the WFC emergency address activity is launched.
+        verify(mFragment).startActivityForResult(intentCaptor.capture(),
+                eq(WifiCallingSettingsForSub.REQUEST_CHECK_WFC_EMERGENCY_ADDRESS));
+        Intent intent = intentCaptor.getValue();
+        assertEquals(intent.getComponent(), ComponentName.unflattenFromString(
+                TEST_EMERGENCY_ADDRESS_CARRIER_APP));
+    }
+
+    @Test
+    public void onActivityResult_finishCarrierActivity_shouldShowWfcPreference() {
+        ReflectionHelpers.setField(mFragment, "mButtonWfcMode", mButtonWfcMode);
+        ReflectionHelpers.setField(mFragment, "mButtonWfcRoamingMode", mButtonWfcRoamingMode);
+        ReflectionHelpers.setField(mFragment, "mUpdateAddress", mUpdateAddress);
+
+        mFragment.onActivityResult(WifiCallingSettingsForSub.REQUEST_CHECK_WFC_EMERGENCY_ADDRESS,
+                Activity.RESULT_OK, null);
+
+        // Check the WFC preferences is added.
+        verify(mPreferenceScreen).addPreference(mButtonWfcMode);
+        verify(mPreferenceScreen).addPreference(mButtonWfcRoamingMode);
+        verify(mPreferenceScreen).addPreference(mUpdateAddress);
+        // Check the WFC enable request.
+        verify(mImsManager).setWfcSetting(true);
+    }
+
+    @Test
+    public void onSwitchChanged_disableSetting_shouldNotLaunchWfcDisclaimerFragment() {
+        mFragment.onSwitchChanged(null, false);
+
+        // Check the WFC disclaimer fragment is not launched.
+        verify(mFragment, never()).startActivityForResult(any(Intent.class), anyInt());
+    }
+
     protected class TestFragment extends WifiCallingSettingsForSub {
         @Override
         protected Object getSystemService(final String name) {
diff --git a/tests/robotests/src/com/android/settings/wifi/slice/ContextualWifiSliceTest.java b/tests/robotests/src/com/android/settings/wifi/slice/ContextualWifiSliceTest.java
index d681afe..520d988 100644
--- a/tests/robotests/src/com/android/settings/wifi/slice/ContextualWifiSliceTest.java
+++ b/tests/robotests/src/com/android/settings/wifi/slice/ContextualWifiSliceTest.java
@@ -36,6 +36,8 @@
 
 import com.android.settings.R;
 import com.android.settings.slices.CustomSliceRegistry;
+import com.android.settings.slices.SlicesFeatureProviderImpl;
+import com.android.settings.testutils.FakeFeatureFactory;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -52,11 +54,15 @@
     private ContentResolver mResolver;
     private WifiManager mWifiManager;
     private ContextualWifiSlice mWifiSlice;
+    private FakeFeatureFactory mFeatureFactory;
 
     @Before
     public void setUp() {
         mContext = spy(RuntimeEnvironment.application);
         mResolver = mock(ContentResolver.class);
+        mFeatureFactory = FakeFeatureFactory.setupForTest();
+        mFeatureFactory.slicesFeatureProvider = new SlicesFeatureProviderImpl();
+        mFeatureFactory.slicesFeatureProvider.newUiSession();
         doReturn(mResolver).when(mContext).getContentResolver();
         mWifiManager = mContext.getSystemService(WifiManager.class);
 
@@ -65,10 +71,28 @@
         mWifiManager.setWifiEnabled(true);
 
         mWifiSlice = new ContextualWifiSlice(mContext);
+        mWifiSlice.sPreviouslyDisplayed = false;
     }
 
     @Test
     public void getWifiSlice_hasActiveConnection_shouldReturnNull() {
+        mWifiSlice.sPreviouslyDisplayed = false;
+        final WifiConfiguration config = new WifiConfiguration();
+        config.SSID = "123";
+        mWifiManager.connect(config, null /* listener */);
+
+        final Slice wifiSlice = mWifiSlice.getSlice();
+
+        assertThat(wifiSlice).isNull();
+    }
+
+    @Test
+    public void getWifiSlice_newSession_hasActiveConnection_shouldReturnNull() {
+        // Session: use a non-active value
+        // previous displayed: yes
+        mWifiSlice.sPreviouslyDisplayed = true;
+        mWifiSlice.sActiveUiSession = ~mFeatureFactory.slicesFeatureProvider.getUiSessionToken();
+
         final WifiConfiguration config = new WifiConfiguration();
         config.SSID = "123";
         mWifiManager.connect(config, null /* listener */);
@@ -80,7 +104,8 @@
 
     @Test
     public void getWifiSlice_previousDisplayed_hasActiveConnection_shouldHaveTitleAndToggle() {
-        mWifiSlice.mPreviouslyDisplayed = true;
+        mWifiSlice.sActiveUiSession = mFeatureFactory.slicesFeatureProvider.getUiSessionToken();
+        mWifiSlice.sPreviouslyDisplayed = true;
         final WifiConfiguration config = new WifiConfiguration();
         config.SSID = "123";
         mWifiManager.connect(config, null /* listener */);
@@ -101,7 +126,8 @@
 
     @Test
     public void getWifiSlice_contextualWifiSlice_shouldReturnContextualWifiSliceUri() {
-        mWifiSlice.mPreviouslyDisplayed = true;
+        mWifiSlice.sActiveUiSession = mFeatureFactory.slicesFeatureProvider.getUiSessionToken();
+        mWifiSlice.sPreviouslyDisplayed = true;
 
         final Slice wifiSlice = mWifiSlice.getSlice();