Merge "Redesign zen visual effects screens" into pi-dev
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 38401e8..aae9b83 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -3179,6 +3179,9 @@
             android:exported="true"
             android:permission="android.permission.DUMP" />
 
+         <service android:name=".search.DeviceIndexUpdateJobService"
+            android:permission="android.permission.BIND_JOB_SERVICE" />
+
         <!-- Quick Settings tiles for Developer Options -->
         <service
             android:name=".development.qstile.DevelopmentTiles$ShowLayout"
diff --git a/res/anim/enrollment_fingerprint_background_1_path_animation.xml b/res/anim/enrollment_fingerprint_background_1_path_animation.xml
new file mode 100644
index 0000000..aed30c0
--- /dev/null
+++ b/res/anim/enrollment_fingerprint_background_1_path_animation.xml
@@ -0,0 +1,51 @@
+<?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.
+-->
+<set
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:ordering="sequentially" >
+    <set
+        android:ordering="together" >
+        <objectAnimator
+            android:duration="300"
+            android:propertyName="fillColor"
+            android:valueFrom="#000000"
+            android:valueTo="#4285F4"
+            android:valueType="intType"
+            android:interpolator="@android:interpolator/linear_out_slow_in" />
+        <objectAnimator
+            android:duration="300"
+            android:propertyName="fillAlpha"
+            android:valueFrom="0.07f"
+            android:valueTo="0.65f"
+            android:valueType="floatType" />
+    </set>
+    <set
+        android:ordering="together" >
+        <objectAnimator
+            android:duration="300"
+            android:propertyName="fillColor"
+            android:valueFrom="#4285F4"
+            android:valueTo="#000000"
+            android:valueType="intType"
+            android:interpolator="@android:interpolator/fast_out_slow_in" />
+        <objectAnimator
+            android:duration="300"
+            android:propertyName="fillAlpha"
+            android:valueFrom="0.65f"
+            android:valueTo="0.07f"
+            android:valueType="floatType" />
+    </set>
+</set>
diff --git a/res/anim/enrollment_fingerprint_background_2_path_animation.xml b/res/anim/enrollment_fingerprint_background_2_path_animation.xml
new file mode 100644
index 0000000..b24e1dd
--- /dev/null
+++ b/res/anim/enrollment_fingerprint_background_2_path_animation.xml
@@ -0,0 +1,51 @@
+<?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.
+-->
+<set
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:ordering="sequentially" >
+    <set
+        android:ordering="together" >
+        <objectAnimator
+            android:duration="300"
+            android:propertyName="fillColor"
+            android:valueFrom="#000000"
+            android:valueTo="#EA4335"
+            android:valueType="intType"
+            android:interpolator="@android:interpolator/linear_out_slow_in" />
+        <objectAnimator
+            android:duration="300"
+            android:propertyName="fillAlpha"
+            android:valueFrom="0.07f"
+            android:valueTo="0.65f"
+            android:valueType="floatType" />
+    </set>
+    <set
+        android:ordering="together" >
+        <objectAnimator
+            android:duration="300"
+            android:propertyName="fillColor"
+            android:valueFrom="#EA4335"
+            android:valueTo="#000000"
+            android:valueType="intType"
+            android:interpolator="@android:interpolator/fast_out_slow_in" />
+        <objectAnimator
+            android:duration="300"
+            android:propertyName="fillAlpha"
+            android:valueFrom="0.65f"
+            android:valueTo="0.07f"
+            android:valueType="floatType" />
+    </set>
+</set>
diff --git a/res/anim/enrollment_fingerprint_background_5_path_animation.xml b/res/anim/enrollment_fingerprint_background_5_path_animation.xml
new file mode 100644
index 0000000..aed30c0
--- /dev/null
+++ b/res/anim/enrollment_fingerprint_background_5_path_animation.xml
@@ -0,0 +1,51 @@
+<?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.
+-->
+<set
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:ordering="sequentially" >
+    <set
+        android:ordering="together" >
+        <objectAnimator
+            android:duration="300"
+            android:propertyName="fillColor"
+            android:valueFrom="#000000"
+            android:valueTo="#4285F4"
+            android:valueType="intType"
+            android:interpolator="@android:interpolator/linear_out_slow_in" />
+        <objectAnimator
+            android:duration="300"
+            android:propertyName="fillAlpha"
+            android:valueFrom="0.07f"
+            android:valueTo="0.65f"
+            android:valueType="floatType" />
+    </set>
+    <set
+        android:ordering="together" >
+        <objectAnimator
+            android:duration="300"
+            android:propertyName="fillColor"
+            android:valueFrom="#4285F4"
+            android:valueTo="#000000"
+            android:valueType="intType"
+            android:interpolator="@android:interpolator/fast_out_slow_in" />
+        <objectAnimator
+            android:duration="300"
+            android:propertyName="fillAlpha"
+            android:valueFrom="0.65f"
+            android:valueTo="0.07f"
+            android:valueType="floatType" />
+    </set>
+</set>
diff --git a/res/anim/enrollment_fingerprint_background_6_path_animation.xml b/res/anim/enrollment_fingerprint_background_6_path_animation.xml
new file mode 100644
index 0000000..5748f77
--- /dev/null
+++ b/res/anim/enrollment_fingerprint_background_6_path_animation.xml
@@ -0,0 +1,51 @@
+<?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.
+-->
+<set
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:ordering="sequentially" >
+    <set
+        android:ordering="together" >
+        <objectAnimator
+            android:duration="300"
+            android:propertyName="fillColor"
+            android:valueFrom="#000000"
+            android:valueTo="#FBBC04"
+            android:valueType="intType"
+            android:interpolator="@android:interpolator/linear_out_slow_in" />
+        <objectAnimator
+            android:duration="300"
+            android:propertyName="fillAlpha"
+            android:valueFrom="0.07f"
+            android:valueTo="0.65f"
+            android:valueType="floatType" />
+    </set>
+    <set
+        android:ordering="together" >
+        <objectAnimator
+            android:duration="300"
+            android:propertyName="fillColor"
+            android:valueFrom="#FBBC04"
+            android:valueTo="#000000"
+            android:valueType="intType"
+            android:interpolator="@android:interpolator/fast_out_slow_in" />
+        <objectAnimator
+            android:duration="300"
+            android:propertyName="fillAlpha"
+            android:valueFrom="0.65f"
+            android:valueTo="0.07f"
+            android:valueType="floatType" />
+    </set>
+</set>
diff --git a/res/anim/enrollment_fingerprint_background_7_path_animation.xml b/res/anim/enrollment_fingerprint_background_7_path_animation.xml
new file mode 100644
index 0000000..c458d32
--- /dev/null
+++ b/res/anim/enrollment_fingerprint_background_7_path_animation.xml
@@ -0,0 +1,51 @@
+<?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.
+-->
+<set
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:ordering="sequentially" >
+    <set
+        android:ordering="together" >
+        <objectAnimator
+            android:duration="300"
+            android:propertyName="fillColor"
+            android:valueFrom="#000000"
+            android:valueTo="#34A853"
+            android:valueType="intType"
+            android:interpolator="@android:interpolator/linear_out_slow_in" />
+        <objectAnimator
+            android:duration="300"
+            android:propertyName="fillAlpha"
+            android:valueFrom="0.07f"
+            android:valueTo="0.65f"
+            android:valueType="floatType" />
+    </set>
+    <set
+        android:ordering="together" >
+        <objectAnimator
+            android:duration="300"
+            android:propertyName="fillColor"
+            android:valueFrom="#34A853"
+            android:valueTo="#000000"
+            android:valueType="intType"
+            android:interpolator="@android:interpolator/fast_out_slow_in" />
+        <objectAnimator
+            android:duration="300"
+            android:propertyName="fillAlpha"
+            android:valueFrom="0.65f"
+            android:valueTo="0.07f"
+            android:valueType="floatType" />
+    </set>
+</set>
diff --git a/res/color/fingerprint_indicator_background_activated.xml b/res/color/fingerprint_indicator_background_activated.xml
deleted file mode 100644
index 32f5383..0000000
--- a/res/color/fingerprint_indicator_background_activated.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-    Copyright (C) 2015 The Android Open Source Project
-
-    Licensed under the Apache License, Version 2.0 (the "License");
-    you may not use this file except in compliance with the License.
-    You may obtain a copy of the License at
-
-        http://www.apache.org/licenses/LICENSE-2.0
-
-    Unless required by applicable law or agreed to in writing, software
-    distributed under the License is distributed on an "AS IS" BASIS,
-    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-    See the License for the specific language governing permissions and
-    limitations under the License.
--->
-
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:alpha="0.5" android:color="?android:attr/colorAccent" />
-</selector>
diff --git a/res/drawable-nodpi/color_mode_preview.jpg b/res/drawable-nodpi/color_mode_preview.jpg
new file mode 100644
index 0000000..51dedbf
--- /dev/null
+++ b/res/drawable-nodpi/color_mode_preview.jpg
Binary files differ
diff --git a/res/drawable-nodpi/gesture_swipe_up.png b/res/drawable-nodpi/gesture_swipe_up.png
index b9390d2..ef3610e 100644
--- a/res/drawable-nodpi/gesture_swipe_up.png
+++ b/res/drawable-nodpi/gesture_swipe_up.png
Binary files differ
diff --git a/res/drawable/enrollment_fingerprint_isolated.xml b/res/drawable/enrollment_fingerprint_isolated.xml
index de3965e..26451de 100644
--- a/res/drawable/enrollment_fingerprint_isolated.xml
+++ b/res/drawable/enrollment_fingerprint_isolated.xml
@@ -30,7 +30,7 @@
             <path
                 android:name="ridge_5_path"
                 android:pathData="M 24.9488677979,32.3508300781 c -1.81059265137,0.338500976562 -3.58520507812,0.447387695312 -4.62879943848,0.447387695312 c -4.12730407715,0.0 -8.05894470215,-0.96842956543 -11.5207061768,-3.45275878906 c -5.33699035645,-3.830078125 -8.56369018555,-10.0885009766 -8.56369018555,-17.1589355469"
-                android:strokeColor="#19000000"
+                android:strokeColor="#4DEA4335"
                 android:strokeWidth="5"
                 android:strokeLineCap="round"
                 android:trimPathEnd="0" />
@@ -40,7 +40,7 @@
             <path
                 android:name="ridge_7_path"
                 android:pathData="M -9.23379516602,40.8356933594 c -3.24549865723,-3.46032714844 -5.1540222168,-5.77195739746 -7.87710571289,-10.9068603516 c -2.76379394531,-5.21166992188 -4.04838562012,-11.3482666016 -4.04838562012,-17.6915283203 c 0.0,-11.6563720703 9.44940185547,-21.1059570312 21.1058959961,-21.1059570312 c 11.6564941406,0.0 21.1058959961,9.44958496094 21.1058959961,21.1059570312"
-                android:strokeColor="#19000000"
+                android:strokeColor="#4DFBBC04"
                 android:strokeWidth="5"
                 android:strokeLineCap="round"
                 android:trimPathEnd="0" />
@@ -50,7 +50,7 @@
             <path
                 android:name="ridge_6_path"
                 android:pathData="M -28.8249053955,28.5169677734 c -2.41259765625,-6.82202148438 -2.85319519043,-12.3121337891 -2.85319519043,-16.3226318359 c 0.0,-4.64868164062 0.792999267578,-9.06323242188 2.59269714355,-13.0396728516 c 4.96929931641,-10.9801025391 16.0211029053,-18.619140625 28.857208252,-18.619140625 c 17.4846954346,0.0 31.6587982178,14.1740722656 31.6587982178,31.6588134766 c 0.0,5.82824707031 -4.72470092773,10.5529785156 -10.5529022217,10.5529785156 c -5.82820129395,0.0 -10.5529937744,-4.72473144531 -10.5529937744,-10.5529785156 c 0.0,-5.82824707031 -4.72470092773,-10.5529785156 -10.5529022217,-10.5529785156 c -5.82820129395,0.0 -10.5529022217,4.72473144531 -10.5529022217,10.5529785156 c 0.0,8.17932128906 3.10879516602,15.5925292969 8.25030517578,21.0004882812 c 3.88919067383,4.09069824219 7.77758789062,6.64123535156 14.2838897705,8.52136230469"
-                android:strokeColor="#19000000"
+                android:strokeColor="#4D4285F4"
                 android:strokeWidth="5"
                 android:strokeLineCap="round"
                 android:trimPathStart="1" />
@@ -60,7 +60,7 @@
             <path
                 android:name="ridge_2_path"
                 android:pathData="M -34.4861907959,-11.6943359375 c 3.78790283203,-5.64636230469 8.36389160156,-9.94665527344 14.3594970703,-13.2164306641 c 5.99560546875,-3.26977539062 12.8716125488,-5.1279296875 20.1817016602,-5.1279296875 c 7.27980041504,0.0 14.129196167,1.84289550781 20.1071014404,5.08740234375 c 5.97790527344,3.24450683594 10.7957000732,7.759765625 14.5897064209,13.3666992188"
-                android:strokeColor="#19000000"
+                android:strokeColor="#4D34A853"
                 android:strokeWidth="5"
                 android:strokeLineCap="round"
                 android:trimPathStart="1" />
@@ -72,7 +72,7 @@
             <path
                 android:name="ridge_1_path"
                 android:pathData="M 121.472564697,107.859741211 c -7.39790344238,-4.03979492188 -15.2462921143,-6.34167480469 -24.3116912842,-6.34167480469 c -9.06539916992,0.0 -16.2951049805,2.40405273438 -23.12550354,6.34167480469"
-                android:strokeColor="#19000000"
+                android:strokeColor="#4D4285F4"
                 android:strokeWidth="5"
                 android:strokeLineCap="round"
                 android:trimPathEnd="0" />
diff --git a/res/drawable/fp_illustration.xml b/res/drawable/fp_illustration.xml
index 17ab4d2..8368d9b 100644
--- a/res/drawable/fp_illustration.xml
+++ b/res/drawable/fp_illustration.xml
@@ -19,7 +19,7 @@
 
     <item
         android:id="@+id/fingerprint_background"
-        android:drawable="@drawable/fp_illustration_enrollment" />
+        android:drawable="@drawable/fp_illustration_enrollment_animation" />
 
     <item
         android:id="@+id/fingerprint_animation"
diff --git a/res/drawable/fp_illustration_enrollment.xml b/res/drawable/fp_illustration_enrollment.xml
index 630c6bd..be98a87 100644
--- a/res/drawable/fp_illustration_enrollment.xml
+++ b/res/drawable/fp_illustration_enrollment.xml
@@ -22,19 +22,24 @@
         android:translateX="44"
         android:translateY="44">
         <path
-            android:fillColor="#FF000000"
+            android:name="background_5_path"
+            android:fillColor="#12000000"
             android:pathData="M67.74,11.59c-0.41,0.0 -0.82,-0.1 -1.2,-0.31c-7.44,-4.06 -15.0,-6.04 -23.11,-6.04c-7.92,0.0 -14.67,1.85 -21.88,6.01c-1.2,0.69 -2.73,0.28 -3.42,-0.92s-0.28,-2.72 0.92,-3.41c7.9,-4.55 15.65,-6.68 24.37,-6.68c8.97,0.0 17.32,2.17 25.51,6.65c1.21,0.66 1.66,2.18 1.0,3.39C69.48,11.12 68.62,11.59 67.74,11.59z"/>
         <path
-            android:fillColor="#FF000000"
+            android:name="background_7_path"
+            android:fillColor="#12000000"
             android:pathData="M9.25,34.74c-0.48,0.0 -0.96,-0.14 -1.39,-0.42c-1.15,-0.77 -1.45,-2.32 -0.68,-3.47c4.09,-6.09 9.3,-10.89 15.49,-14.27c6.52,-3.55 13.91,-5.43 21.38,-5.43c7.44,0.0 14.8,1.86 21.3,5.39c6.17,3.35 11.38,8.12 15.47,14.16c0.77,1.14 0.47,2.7 -0.67,3.47c-1.14,0.77 -2.7,0.47 -3.47,-0.67c-3.64,-5.38 -8.25,-9.61 -13.71,-12.57c-5.77,-3.13 -12.31,-4.78 -18.92,-4.78c-6.63,0.0 -13.2,1.67 -18.98,4.82c-5.48,2.99 -10.1,7.25 -13.73,12.66C10.85,34.35 10.06,34.74 9.25,34.74z"/>
         <path
-            android:fillColor="#FF000000"
+            android:name="background_6_path"
+            android:fillColor="#12000000"
             android:pathData="M34.76,86.82c-0.67,0.0 -1.33,-0.27 -1.82,-0.79c-3.49,-3.72 -5.51,-6.25 -8.26,-11.45c-2.84,-5.35 -4.34,-11.88 -4.34,-18.86c0.0,-13.02 10.59,-23.61 23.61,-23.61c13.02,0.0 23.61,10.59 23.61,23.61c0.0,1.38 -1.12,2.5 -2.5,2.5s-2.5,-1.12 -2.5,-2.5c0.0,-10.26 -8.35,-18.61 -18.61,-18.61c-10.26,0.0 -18.61,8.35 -18.61,18.61c0.0,6.17 1.3,11.89 3.76,16.52c2.62,4.94 4.37,7.04 7.49,10.37c0.94,1.01 0.89,2.59 -0.11,3.53C35.99,86.6 35.38,86.82 34.76,86.82z"/>
         <path
-            android:fillColor="#FF000000"
+            android:name="background_2_path"
+            android:fillColor="#12000000"
             android:pathData="M64.28,78.84c-4.99,0.0 -9.35,-1.32 -12.98,-3.92c-6.17,-4.43 -9.86,-11.6 -9.86,-19.19c0.0,-1.38 1.12,-2.5 2.5,-2.5s2.5,1.12 2.5,2.5c0.0,5.98 2.91,11.64 7.77,15.13c2.8,2.01 6.09,2.98 10.06,2.98c0.97,0.0 2.57,-0.11 4.17,-0.4c1.36,-0.25 2.66,0.64 2.92,2.0c0.25,1.36 -0.64,2.66 -2.0,2.92C66.93,78.8 64.86,78.84 64.28,78.84z"/>
         <path
-            android:fillColor="#FF000000"
+            android:name="background_1_path"
+            android:fillColor="#12000000"
             android:pathData="M55.92,87.75c-0.23,0.0 -0.46,-0.03 -0.7,-0.1c-6.6,-1.91 -10.92,-4.49 -15.4,-9.2c-5.76,-6.06 -8.94,-14.13 -8.94,-22.72c0.0,-7.2 5.86,-13.05 13.05,-13.05c7.2,0.0 13.05,5.86 13.05,13.05c0.0,4.44 3.61,8.05 8.05,8.05s8.05,-3.61 8.05,-8.05c0.0,-16.08 -13.08,-29.16 -29.16,-29.16c-11.43,0.0 -21.86,6.73 -26.58,17.15c-1.57,3.48 -2.37,7.52 -2.37,12.01c0.0,3.36 0.28,8.62 2.71,15.49c0.46,1.3 -0.22,2.73 -1.52,3.19c-1.3,0.46 -2.73,-0.22 -3.19,-1.52c-2.02,-5.7 -3.0,-11.31 -3.0,-17.16c0.0,-5.21 0.95,-9.94 2.82,-14.07c5.52,-12.2 17.74,-20.09 31.13,-20.09c18.83,0.0 34.16,15.32 34.16,34.16c0.0,7.2 -5.86,13.05 -13.05,13.05S52.0,62.92 52.0,55.73c0.0,-4.44 -3.61,-8.05 -8.05,-8.05s-8.05,3.61 -8.05,8.05c0.0,7.3 2.69,14.15 7.56,19.28c3.86,4.06 7.43,6.18 13.17,7.84c1.33,0.38 2.09,1.77 1.71,3.1C58.01,87.04 57.01,87.75 55.92,87.75z"/>
     </group>
 </vector>
diff --git a/res/drawable/fp_illustration_enrollment_animation.xml b/res/drawable/fp_illustration_enrollment_animation.xml
new file mode 100644
index 0000000..2e1bfd9
--- /dev/null
+++ b/res/drawable/fp_illustration_enrollment_animation.xml
@@ -0,0 +1,34 @@
+<?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.
+-->
+<animated-vector
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:drawable="@drawable/fp_illustration_enrollment" >
+    <target
+        android:name="background_5_path"
+        android:animation="@anim/enrollment_fingerprint_background_5_path_animation" />
+    <target
+        android:name="background_7_path"
+        android:animation="@anim/enrollment_fingerprint_background_7_path_animation" />
+    <target
+        android:name="background_6_path"
+        android:animation="@anim/enrollment_fingerprint_background_6_path_animation" />
+    <target
+        android:name="background_2_path"
+        android:animation="@anim/enrollment_fingerprint_background_2_path_animation" />
+    <target
+        android:name="background_1_path"
+        android:animation="@anim/enrollment_fingerprint_background_1_path_animation" />
+</animated-vector>
diff --git a/res/layout/color_mode_preview.xml b/res/layout/color_mode_preview.xml
index bcd385d..2838345 100644
--- a/res/layout/color_mode_preview.xml
+++ b/res/layout/color_mode_preview.xml
@@ -24,7 +24,7 @@
         android:paddingBottom="@dimen/color_mode_preview_padding_bottom"
         android:scaleType="centerCrop"
         android:cropToPadding="true"
-        android:src="@drawable/caption_background"
+        android:src="@drawable/color_mode_preview"
         android:contentDescription="@null" />
 
 </FrameLayout>
diff --git a/res/layout/data_usage_summary_preference.xml b/res/layout/data_usage_summary_preference.xml
index 1432c72..6af159a 100644
--- a/res/layout/data_usage_summary_preference.xml
+++ b/res/layout/data_usage_summary_preference.xml
@@ -34,7 +34,7 @@
         android:textColor="?android:attr/colorAccent"
         android:text="@string/data_usage_title" />
 
-    <LinearLayout
+    <com.android.settings.datausage.MeasurableLinearLayout
         android:id="@+id/usage_layout"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
@@ -61,7 +61,7 @@
             android:textAppearance="?android:attr/textAppearanceMedium"
             android:textSize="16sp" />
 
-    </LinearLayout>
+    </com.android.settings.datausage.MeasurableLinearLayout>
 
     <android.widget.ProgressBar
         android:id="@+id/determinateBar"
diff --git a/res/layout/settings_main_dashboard.xml b/res/layout/settings_main_dashboard.xml
index 10ff2ee..c430d6d 100644
--- a/res/layout/settings_main_dashboard.xml
+++ b/res/layout/settings_main_dashboard.xml
@@ -27,7 +27,7 @@
         android:id="@+id/search_bar_container"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
-        android:background="@color/suggestion_condition_background">
+        android:background="?android:attr/colorPrimary">
         <android.support.v7.widget.CardView
             android:id="@+id/search_bar"
             android:layout_width="match_parent"
diff --git a/res/raw/gesture_swipe_up.mp4 b/res/raw/gesture_swipe_up.mp4
index 16cbb2b..a8959e4 100644
--- a/res/raw/gesture_swipe_up.mp4
+++ b/res/raw/gesture_swipe_up.mp4
Binary files differ
diff --git a/res/values/colors.xml b/res/values/colors.xml
index 397d9e7..e5f7c27 100644
--- a/res/values/colors.xml
+++ b/res/values/colors.xml
@@ -48,7 +48,6 @@
     <color name="fingerprint_title_area_bg">?android:attr/colorAccent</color>
     <color name="fingerprint_title_color">#ffffffff</color>
     <color name="fingerprint_message_color">#de000000</color>
-    <color name="fingerprint_indicator_background_resting">#12000000</color>
 
     <color name="running_processes_system_ram">#ff384248</color>
     <color name="running_processes_free_ram">#ffced7db</color>
@@ -95,7 +94,7 @@
     <color name="usage_graph_dots">#B0BEC5</color>
 
     <!-- Gestures settings -->
-    <color name="gestures_setting_background_color">#f4f4f4</color>
+    <color name="gestures_setting_background_color">#ffffff</color>
 
     <color name="status_bar_color">#3c3c3c</color>
 
diff --git a/res/values/integers.xml b/res/values/integers.xml
index ac9a973..7a6e0aa 100644
--- a/res/values/integers.xml
+++ b/res/values/integers.xml
@@ -19,4 +19,5 @@
     <integer name="job_anomaly_clean_up">100</integer>
     <integer name="job_anomaly_config_update">101</integer>
     <integer name="job_anomaly_detection">102</integer>
-</resources>
\ No newline at end of file
+    <integer name="device_index_update">103</integer>
+</resources>
diff --git a/res/values/styles.xml b/res/values/styles.xml
index 6ca4715..9075891 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -474,7 +474,7 @@
     </style>
 
     <style name="SuggestionConditionStyle">
-        <item name="android:background">@color/suggestion_condition_background</item>
+        <item name="android:background">?android:attr/colorPrimary</item>
     </style>
 
     <style name="TextAppearance.SearchBar" parent="@android:style/TextAppearance.Material.Widget.Toolbar.Subtitle">
diff --git a/res/xml/assist_gesture_settings.xml b/res/xml/assist_gesture_settings.xml
index b2ceac9..7cbd483 100644
--- a/res/xml/assist_gesture_settings.xml
+++ b/res/xml/assist_gesture_settings.xml
@@ -30,6 +30,7 @@
         android:key="gesture_assist"
         android:title="@string/assist_gesture_title"
         app:keywords="@string/keywords_assist_gesture_launch"
-        app:controller="com.android.settings.gestures.AssistGestureSettingsPreferenceController" />
+        app:controller="com.android.settings.gestures.AssistGestureSettingsPreferenceController"
+        app:allowDividerAbove="true" />
 
 </PreferenceScreen>
diff --git a/res/xml/auto_brightness_detail.xml b/res/xml/auto_brightness_detail.xml
index 88c878a..8b683f1 100644
--- a/res/xml/auto_brightness_detail.xml
+++ b/res/xml/auto_brightness_detail.xml
@@ -33,6 +33,7 @@
         settings:keywords="@string/keywords_display_auto_brightness"
         settings:controller="com.android.settings.display.AutoBrightnessPreferenceController"
         settings:useAdminDisabledSummary="true"
-        settings:userRestriction="no_config_brightness" />
+        settings:userRestriction="no_config_brightness"
+        settings:allowDividerAbove="true" />
 
 </PreferenceScreen>
\ No newline at end of file
diff --git a/res/xml/double_tap_power_settings.xml b/res/xml/double_tap_power_settings.xml
index 6614899..c04a90b 100644
--- a/res/xml/double_tap_power_settings.xml
+++ b/res/xml/double_tap_power_settings.xml
@@ -31,6 +31,7 @@
         android:title="@string/double_tap_power_for_camera_title"
         android:summary="@string/double_tap_power_for_camera_summary"
         app:keywords="@string/keywords_gesture"
-        app:controller="com.android.settings.gestures.DoubleTapPowerPreferenceController" />
+        app:controller="com.android.settings.gestures.DoubleTapPowerPreferenceController"
+        app:allowDividerAbove="true" />
 
 </PreferenceScreen>
\ No newline at end of file
diff --git a/res/xml/double_tap_screen_settings.xml b/res/xml/double_tap_screen_settings.xml
index 4d2e168..2734143 100644
--- a/res/xml/double_tap_screen_settings.xml
+++ b/res/xml/double_tap_screen_settings.xml
@@ -31,6 +31,7 @@
         android:title="@string/ambient_display_title"
         android:summary="@string/ambient_display_summary"
         app:keywords="@string/keywords_gesture"
-        app:controller="com.android.settings.gestures.DoubleTapScreenPreferenceController" />
+        app:controller="com.android.settings.gestures.DoubleTapScreenPreferenceController"
+        app:allowDividerAbove="true" />
 
 </PreferenceScreen>
\ No newline at end of file
diff --git a/res/xml/double_twist_gesture_settings.xml b/res/xml/double_twist_gesture_settings.xml
index 1da862d..f91bd35 100644
--- a/res/xml/double_twist_gesture_settings.xml
+++ b/res/xml/double_twist_gesture_settings.xml
@@ -31,6 +31,7 @@
         android:title="@string/double_twist_for_camera_mode_title"
         android:summary="@string/double_twist_for_camera_mode_summary"
         app:keywords="@string/keywords_gesture"
-        app:controller="com.android.settings.gestures.DoubleTwistPreferenceController" />
+        app:controller="com.android.settings.gestures.DoubleTwistPreferenceController"
+        app:allowDividerAbove="true" />
 
 </PreferenceScreen>
\ No newline at end of file
diff --git a/res/xml/language_and_input.xml b/res/xml/language_and_input.xml
index d7fad7e..747d1b4 100644
--- a/res/xml/language_and_input.xml
+++ b/res/xml/language_and_input.xml
@@ -20,13 +20,13 @@
     xmlns:settings="http://schemas.android.com/apk/res-auto"
     android:key="language_and_input_settings_screen"
     android:title="@string/language_settings"
-    settings:initialExpandedChildrenCount="3" >
+    settings:initialExpandedChildrenCount="3">
 
     <Preference
         android:key="phone_language"
         android:title="@string/phone_language"
         android:icon="@drawable/ic_translate_24dp"
-        android:fragment="com.android.settings.localepicker.LocaleListEditor"/>
+        android:fragment="com.android.settings.localepicker.LocaleListEditor" />
 
     <PreferenceCategory
         android:key="keyboards_category"
@@ -34,12 +34,12 @@
         <Preference
             android:key="virtual_keyboard_pref"
             android:title="@string/virtual_keyboard_category"
-            android:fragment="com.android.settings.inputmethod.VirtualKeyboardFragment"/>
+            android:fragment="com.android.settings.inputmethod.VirtualKeyboardFragment" />
         <Preference
             android:key="physical_keyboard_pref"
             android:title="@string/physical_keyboard_title"
             android:summary="@string/summary_placeholder"
-            android:fragment="com.android.settings.inputmethod.PhysicalKeyboardFragment"/>
+            android:fragment="com.android.settings.inputmethod.PhysicalKeyboardFragment" />
     </PreferenceCategory>
 
     <PreferenceCategory
@@ -52,7 +52,7 @@
             android:key="spellcheckers_settings"
             android:title="@string/spellcheckers_settings_title"
             android:persistent="false"
-            android:fragment="com.android.settings.inputmethod.SpellCheckersSettings"/>
+            android:fragment="com.android.settings.inputmethod.SpellCheckersSettings" />
 
         <com.android.settings.widget.GearPreference
             android:key="default_autofill"
@@ -63,7 +63,7 @@
         <!-- User dictionary preference title and fragment will be set programmatically. -->
         <Preference
             android:key="key_user_dictionary_settings"
-            android:title="@string/user_dict_settings_title"/>
+            android:title="@string/user_dict_settings_title" />
     </PreferenceCategory>
 
     <PreferenceCategory
@@ -73,24 +73,19 @@
         <com.android.settings.PointerSpeedPreference
             android:key="pointer_speed"
             android:title="@string/pointer_speed"
-            android:dialogTitle="@string/pointer_speed"/>
+            android:dialogTitle="@string/pointer_speed" />
 
         <Preference
             android:key="tts_settings_summary"
             android:title="@string/tts_settings_title"
-            android:fragment="com.android.settings.tts.TextToSpeechSettings"/>
+            android:fragment="com.android.settings.tts.TextToSpeechSettings" />
 
     </PreferenceCategory>
 
-    <PreferenceCategory
-        android:key="game_controller_settings_category"
-        android:title="@string/game_controller_settings_category">
-
-        <SwitchPreference
-            android:key="vibrate_input_devices"
-            android:title="@string/vibrate_input_devices"
-            android:summary="@string/vibrate_input_devices_summary" />
-
-    </PreferenceCategory>
+    <SwitchPreference
+        android:key="vibrate_input_devices"
+        android:title="@string/vibrate_input_devices"
+        android:summary="@string/vibrate_input_devices_summary"
+        settings:controller="com.android.settings.inputmethod.GameControllerPreferenceController" />
 
 </PreferenceScreen>
diff --git a/res/xml/pick_up_gesture_settings.xml b/res/xml/pick_up_gesture_settings.xml
index ccf2d8a..47f707a 100644
--- a/res/xml/pick_up_gesture_settings.xml
+++ b/res/xml/pick_up_gesture_settings.xml
@@ -31,6 +31,7 @@
         android:title="@string/ambient_display_pickup_title"
         android:summary="@string/ambient_display_pickup_summary"
         app:keywords="@string/keywords_gesture"
-        app:controller="com.android.settings.gestures.PickupGesturePreferenceController" />
+        app:controller="com.android.settings.gestures.PickupGesturePreferenceController"
+        app:allowDividerAbove="true" />
 
 </PreferenceScreen>
\ No newline at end of file
diff --git a/res/xml/prevent_ringing_gesture_settings.xml b/res/xml/prevent_ringing_gesture_settings.xml
index 08146e4..5135664 100644
--- a/res/xml/prevent_ringing_gesture_settings.xml
+++ b/res/xml/prevent_ringing_gesture_settings.xml
@@ -32,6 +32,7 @@
         android:entries="@array/gesture_prevent_ringing_entries"
         android:entryValues="@array/gesture_prevent_ringing_values"
         app:controller="com.android.settings.gestures.PreventRingingPreferenceController"
-        app:keywords="@string/keywords_gesture" />
+        app:keywords="@string/keywords_gesture"
+        app:allowDividerAbove="true" />
 
 </PreferenceScreen>
\ No newline at end of file
diff --git a/res/xml/swipe_to_notification_settings.xml b/res/xml/swipe_to_notification_settings.xml
index 04dc0c7..b126170 100644
--- a/res/xml/swipe_to_notification_settings.xml
+++ b/res/xml/swipe_to_notification_settings.xml
@@ -30,6 +30,7 @@
         android:title="@string/fingerprint_swipe_for_notifications_title"
         android:summary="@string/fingerprint_swipe_for_notifications_summary"
         app:keywords="@string/keywords_gesture"
-        app:controller="com.android.settings.gestures.SwipeToNotificationPreferenceController" />
+        app:controller="com.android.settings.gestures.SwipeToNotificationPreferenceController"
+        app:allowDividerAbove="true" />
 
 </PreferenceScreen>
\ No newline at end of file
diff --git a/res/xml/swipe_up_gesture_settings.xml b/res/xml/swipe_up_gesture_settings.xml
index 0f1dc4a..cc1db16 100644
--- a/res/xml/swipe_up_gesture_settings.xml
+++ b/res/xml/swipe_up_gesture_settings.xml
@@ -31,6 +31,7 @@
         android:title="@string/swipe_up_to_switch_apps_title"
         android:summary="@string/swipe_up_to_switch_apps_summary"
         app:keywords="@string/keywords_gesture"
-        app:controller="com.android.settings.gestures.SwipeUpPreferenceController" />
+        app:controller="com.android.settings.gestures.SwipeUpPreferenceController"
+        app:allowDividerAbove="true" />
 
 </PreferenceScreen>
\ No newline at end of file
diff --git a/src/com/android/settings/AirplaneModeEnabler.java b/src/com/android/settings/AirplaneModeEnabler.java
index 11f1a28..f144096 100644
--- a/src/com/android/settings/AirplaneModeEnabler.java
+++ b/src/com/android/settings/AirplaneModeEnabler.java
@@ -20,6 +20,7 @@
 import android.content.Intent;
 import android.database.ContentObserver;
 import android.os.Handler;
+import android.os.Looper;
 import android.os.Message;
 import android.os.SystemProperties;
 import android.os.UserHandle;
@@ -51,7 +52,7 @@
         void onAirplaneModeChanged(boolean isAirplaneModeOn);
     }
 
-    private Handler mHandler = new Handler() {
+    private Handler mHandler = new Handler(Looper.getMainLooper()) {
         @Override
         public void handleMessage(Message msg) {
             switch (msg.what) {
@@ -62,7 +63,8 @@
         }
     };
 
-    private ContentObserver mAirplaneModeObserver = new ContentObserver(new Handler()) {
+    private ContentObserver mAirplaneModeObserver = new ContentObserver(
+            new Handler(Looper.getMainLooper())) {
         @Override
         public void onChange(boolean selfChange) {
             onAirplaneModeChanged();
diff --git a/src/com/android/settings/connecteddevice/ConnectedDeviceGroupController.java b/src/com/android/settings/connecteddevice/ConnectedDeviceGroupController.java
index 3a1aa05..47e3438 100644
--- a/src/com/android/settings/connecteddevice/ConnectedDeviceGroupController.java
+++ b/src/com/android/settings/connecteddevice/ConnectedDeviceGroupController.java
@@ -22,16 +22,19 @@
 import android.support.v7.preference.PreferenceGroup;
 import android.support.v7.preference.PreferenceScreen;
 
+import com.android.settings.bluetooth.BluetoothDeviceUpdater;
+import com.android.settings.bluetooth.ConnectedBluetoothDeviceUpdater;
+import com.android.settings.connecteddevice.dock.DockUpdater;
 import com.android.settings.connecteddevice.usb.ConnectedUsbDeviceUpdater;
 import com.android.settings.core.BasePreferenceController;
 import com.android.settings.core.PreferenceControllerMixin;
-import com.android.settings.bluetooth.BluetoothDeviceUpdater;
-import com.android.settings.bluetooth.ConnectedBluetoothDeviceUpdater;
-import com.android.settingslib.core.lifecycle.Lifecycle;
-import com.android.settingslib.core.lifecycle.LifecycleObserver;
 import com.android.settings.dashboard.DashboardFragment;
+import com.android.settings.overlay.DockUpdaterFeatureProvider;
+import com.android.settings.overlay.FeatureFactory;
 import com.android.settingslib.core.lifecycle.events.OnStart;
 import com.android.settingslib.core.lifecycle.events.OnStop;
+import com.android.settingslib.core.lifecycle.Lifecycle;
+import com.android.settingslib.core.lifecycle.LifecycleObserver;
 
 /**
  * Controller to maintain the {@link android.support.v7.preference.PreferenceGroup} for all
@@ -47,6 +50,7 @@
     PreferenceGroup mPreferenceGroup;
     private BluetoothDeviceUpdater mBluetoothDeviceUpdater;
     private ConnectedUsbDeviceUpdater mConnectedUsbDeviceUpdater;
+    private DockUpdater mConnectedDockUpdater;
 
     public ConnectedDeviceGroupController(Context context) {
         super(context, KEY);
@@ -56,12 +60,14 @@
     public void onStart() {
         mBluetoothDeviceUpdater.registerCallback();
         mConnectedUsbDeviceUpdater.registerCallback();
+        mConnectedDockUpdater.registerCallback();
     }
 
     @Override
     public void onStop() {
         mConnectedUsbDeviceUpdater.unregisterCallback();
         mBluetoothDeviceUpdater.unregisterCallback();
+        mConnectedDockUpdater.unregisterCallback();
     }
 
     @Override
@@ -74,6 +80,7 @@
             mBluetoothDeviceUpdater.setPrefContext(screen.getContext());
             mBluetoothDeviceUpdater.forceUpdate();
             mConnectedUsbDeviceUpdater.initUsbPreference(screen.getContext());
+            mConnectedDockUpdater.forceUpdate();
         }
     }
 
@@ -107,13 +114,22 @@
 
     @VisibleForTesting
     public void init(BluetoothDeviceUpdater bluetoothDeviceUpdater,
-            ConnectedUsbDeviceUpdater connectedUsbDeviceUpdater) {
+            ConnectedUsbDeviceUpdater connectedUsbDeviceUpdater,
+            DockUpdater connectedDockUpdater) {
+
         mBluetoothDeviceUpdater = bluetoothDeviceUpdater;
         mConnectedUsbDeviceUpdater = connectedUsbDeviceUpdater;
+        mConnectedDockUpdater = connectedDockUpdater;
     }
 
     public void init(DashboardFragment fragment) {
-        init(new ConnectedBluetoothDeviceUpdater(fragment.getContext(), fragment, this),
-                new ConnectedUsbDeviceUpdater(fragment.getContext(), fragment, this));
+        final Context context = fragment.getContext();
+        DockUpdaterFeatureProvider dockUpdaterFeatureProvider =
+                FeatureFactory.getFactory(context).getDockUpdaterFeatureProvider();
+        final DockUpdater connectedDockUpdater =
+                dockUpdaterFeatureProvider.getConnectedDockUpdater(context, this);
+        init(new ConnectedBluetoothDeviceUpdater(context, fragment, this),
+                new ConnectedUsbDeviceUpdater(context, fragment, this),
+                connectedDockUpdater);
     }
 }
diff --git a/src/com/android/settings/connecteddevice/SavedDeviceGroupController.java b/src/com/android/settings/connecteddevice/SavedDeviceGroupController.java
index b1f8360..f80c877 100644
--- a/src/com/android/settings/connecteddevice/SavedDeviceGroupController.java
+++ b/src/com/android/settings/connecteddevice/SavedDeviceGroupController.java
@@ -24,9 +24,12 @@
 
 import com.android.settings.bluetooth.BluetoothDeviceUpdater;
 import com.android.settings.bluetooth.SavedBluetoothDeviceUpdater;
+import com.android.settings.connecteddevice.dock.DockUpdater;
 import com.android.settings.core.BasePreferenceController;
 import com.android.settings.core.PreferenceControllerMixin;
 import com.android.settings.dashboard.DashboardFragment;
+import com.android.settings.overlay.DockUpdaterFeatureProvider;
+import com.android.settings.overlay.FeatureFactory;
 import com.android.settingslib.core.lifecycle.Lifecycle;
 import com.android.settingslib.core.lifecycle.LifecycleObserver;
 import com.android.settingslib.core.lifecycle.events.OnStart;
@@ -45,19 +48,27 @@
     @VisibleForTesting
     PreferenceGroup mPreferenceGroup;
     private BluetoothDeviceUpdater mBluetoothDeviceUpdater;
+    private DockUpdater mSavedDockUpdater;
 
     public SavedDeviceGroupController(Context context) {
         super(context, KEY);
+
+        DockUpdaterFeatureProvider dockUpdaterFeatureProvider =
+                FeatureFactory.getFactory(context).getDockUpdaterFeatureProvider();
+        mSavedDockUpdater =
+                dockUpdaterFeatureProvider.getSavedDockUpdater(context, this);
     }
 
     @Override
     public void onStart() {
         mBluetoothDeviceUpdater.registerCallback();
+        mSavedDockUpdater.registerCallback();
     }
 
     @Override
     public void onStop() {
         mBluetoothDeviceUpdater.unregisterCallback();
+        mSavedDockUpdater.unregisterCallback();
     }
 
     @Override
@@ -67,6 +78,7 @@
             mPreferenceGroup.setVisible(false);
             mBluetoothDeviceUpdater.setPrefContext(screen.getContext());
             mBluetoothDeviceUpdater.forceUpdate();
+            mSavedDockUpdater.forceUpdate();
         }
     }
 
@@ -105,6 +117,11 @@
 
     @VisibleForTesting
     public void setBluetoothDeviceUpdater(BluetoothDeviceUpdater bluetoothDeviceUpdater) {
-        mBluetoothDeviceUpdater  = bluetoothDeviceUpdater;
+        mBluetoothDeviceUpdater = bluetoothDeviceUpdater;
+    }
+
+    @VisibleForTesting
+    public void setSavedDockUpdater(DockUpdater savedDockUpdater) {
+        mSavedDockUpdater = savedDockUpdater;
     }
 }
diff --git a/src/com/android/settings/connecteddevice/dock/DockUpdater.java b/src/com/android/settings/connecteddevice/dock/DockUpdater.java
new file mode 100644
index 0000000..19ee732
--- /dev/null
+++ b/src/com/android/settings/connecteddevice/dock/DockUpdater.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+package com.android.settings.connecteddevice.dock;
+
+import android.content.Context;
+
+/**
+ * Update the dock devices. It notifies the upper level whether to add/remove the preference
+ * through {@link DevicePreferenceCallback}
+ */
+public interface DockUpdater {
+
+    /**
+     * Register the dock event callback and update the list
+     */
+    default void registerCallback() {
+    }
+
+    /**
+     * Unregister the dock event callback
+     */
+    default void unregisterCallback() {
+    }
+
+    /**
+     * Force to update the list of dock devices
+     */
+    default void forceUpdate() {
+    }
+}
diff --git a/src/com/android/settings/connecteddevice/dock/DockUpdaterFeatureProviderImpl.java b/src/com/android/settings/connecteddevice/dock/DockUpdaterFeatureProviderImpl.java
new file mode 100644
index 0000000..7cd2d50
--- /dev/null
+++ b/src/com/android/settings/connecteddevice/dock/DockUpdaterFeatureProviderImpl.java
@@ -0,0 +1,29 @@
+package com.android.settings.connecteddevice.dock;
+
+import android.content.Context;
+
+import com.android.settings.connecteddevice.DevicePreferenceCallback;
+import com.android.settings.connecteddevice.dock.DockUpdater;
+import com.android.settings.overlay.DockUpdaterFeatureProvider;
+
+/**
+ * Impl for {@link DockUpdaterFeatureProvider}
+ */
+public class DockUpdaterFeatureProviderImpl implements DockUpdaterFeatureProvider {
+
+    @Override
+    public DockUpdater getConnectedDockUpdater(Context context,
+            DevicePreferenceCallback devicePreferenceCallback) {
+        final DockUpdater updater = new DockUpdater() {
+        };
+        return updater;
+    }
+
+    @Override
+    public DockUpdater getSavedDockUpdater(Context context,
+            DevicePreferenceCallback devicePreferenceCallback) {
+        final DockUpdater updater = new DockUpdater() {
+        };
+        return updater;
+    }
+}
diff --git a/src/com/android/settings/dashboard/DashboardFeatureProviderImpl.java b/src/com/android/settings/dashboard/DashboardFeatureProviderImpl.java
index 82a5b9b..f403e05 100644
--- a/src/com/android/settings/dashboard/DashboardFeatureProviderImpl.java
+++ b/src/com/android/settings/dashboard/DashboardFeatureProviderImpl.java
@@ -258,10 +258,9 @@
                     Log.w(TAG, "Failed to get icon from uri " + uri);
                     return;
                 }
-                tile.icon = Icon.createWithResource(iconInfo.first, iconInfo.second);
+                final Icon icon = Icon.createWithResource(iconInfo.first, iconInfo.second);
                 ThreadUtils.postOnMainThread(() -> {
-                        preference.setIcon(tile.icon.loadDrawable(preference.getContext()));
-                        tile.icon = null;
+                            preference.setIcon(icon.loadDrawable(preference.getContext()));
                     }
                 );
             });
diff --git a/src/com/android/settings/datausage/DataUsageSummaryPreference.java b/src/com/android/settings/datausage/DataUsageSummaryPreference.java
index e5e83eb..969d6fd 100644
--- a/src/com/android/settings/datausage/DataUsageSummaryPreference.java
+++ b/src/com/android/settings/datausage/DataUsageSummaryPreference.java
@@ -227,6 +227,9 @@
                 TextUtils.expandTemplate(template, usageNumberText, usedResult.units);
         usageNumberField.setText(usageText);
 
+        final MeasurableLinearLayout layout =
+                (MeasurableLinearLayout) holder.findViewById(R.id.usage_layout);
+
         if (mHasMobileData && mNumPlans >= 0 && mDataplanSize > 0L) {
             TextView usageRemainingField = (TextView) holder.findViewById(R.id.data_remaining_view);
             long dataRemaining = mDataplanSize - mDataplanUse;
@@ -243,6 +246,9 @@
                 usageRemainingField.setTextColor(
                         Utils.getColorAttr(getContext(), android.R.attr.colorError));
             }
+            layout.setChildren(usageNumberField, usageRemainingField);
+        } else {
+            layout.setChildren(usageNumberField, null);
         }
     }
 
diff --git a/src/com/android/settings/datausage/MeasurableLinearLayout.java b/src/com/android/settings/datausage/MeasurableLinearLayout.java
new file mode 100644
index 0000000..f165be7
--- /dev/null
+++ b/src/com/android/settings/datausage/MeasurableLinearLayout.java
@@ -0,0 +1,47 @@
+package com.android.settings.datausage;
+
+import android.annotation.Nullable;
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.LinearLayout;
+
+public class MeasurableLinearLayout extends LinearLayout {
+    private View mFixedView;
+    private View mDisposableView;
+
+    public MeasurableLinearLayout(Context context) {
+        super(context, null);
+    }
+
+    public MeasurableLinearLayout(Context context, @Nullable AttributeSet attrs) {
+        super(context, attrs, 0);
+    }
+
+    public MeasurableLinearLayout(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr, 0);
+    }
+
+    public MeasurableLinearLayout(Context context, AttributeSet attrs,
+        int defStyleAttr, int defStyleRes) {
+        super(context, attrs, defStyleAttr, defStyleRes);
+    }
+
+    @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+        if (mDisposableView != null && getMeasuredWidth() - mFixedView.getMeasuredWidth()
+                < mDisposableView.getMeasuredWidth()) {
+            mDisposableView.setVisibility(GONE);
+            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+        } else if (mDisposableView != null && mDisposableView.getVisibility() != VISIBLE) {
+            mDisposableView.setVisibility(VISIBLE);
+            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+        }
+    }
+
+    public void setChildren(View fixedView, View disposableView) {
+        mFixedView = fixedView;
+        mDisposableView = disposableView;
+    }
+}
\ No newline at end of file
diff --git a/src/com/android/settings/deviceinfo/StorageWizardFormatProgress.java b/src/com/android/settings/deviceinfo/StorageWizardFormatProgress.java
index 0711907..3d654ef 100644
--- a/src/com/android/settings/deviceinfo/StorageWizardFormatProgress.java
+++ b/src/com/android/settings/deviceinfo/StorageWizardFormatProgress.java
@@ -91,7 +91,7 @@
                     storage.partitionPrivate(activity.mDisk.getId());
                     publishProgress(40);
 
-                    final VolumeInfo privateVol = activity.findFirstVolume(TYPE_PRIVATE, 5);
+                    final VolumeInfo privateVol = activity.findFirstVolume(TYPE_PRIVATE, 25);
                     final CompletableFuture<PersistableBundle> result = new CompletableFuture<>();
                     storage.benchmark(privateVol.getId(), new IVoldTaskListener.Stub() {
                         @Override
diff --git a/src/com/android/settings/deviceinfo/StorageWizardInit.java b/src/com/android/settings/deviceinfo/StorageWizardInit.java
index 0fc850b..b271d02 100644
--- a/src/com/android/settings/deviceinfo/StorageWizardInit.java
+++ b/src/com/android/settings/deviceinfo/StorageWizardInit.java
@@ -55,7 +55,6 @@
         if (!mDisk.isAdoptable()) {
             // If not adoptable, we only have one choice
             onNavigateExternal(null);
-            finish();
         } else if (!mIsPermittedToAdopt) {
             // TODO: Show a message about why this is disabled for guest and
             // that only an admin user can adopt an sd card.
@@ -77,6 +76,7 @@
             final Intent intent = new Intent(this, StorageWizardReady.class);
             intent.putExtra(DiskInfo.EXTRA_DISK_ID, mDisk.getId());
             startActivity(intent);
+            finish();
 
         } else {
             // Gotta format to get there
diff --git a/src/com/android/settings/deviceinfo/storage/StorageSummaryDonutPreference.java b/src/com/android/settings/deviceinfo/storage/StorageSummaryDonutPreference.java
index d653f7c..cea6809 100644
--- a/src/com/android/settings/deviceinfo/storage/StorageSummaryDonutPreference.java
+++ b/src/com/android/settings/deviceinfo/storage/StorageSummaryDonutPreference.java
@@ -71,6 +71,8 @@
     @Override
     public void onBindViewHolder(PreferenceViewHolder view) {
         super.onBindViewHolder(view);
+        view.itemView.setClickable(false);
+
         final DonutView donut = (DonutView) view.findViewById(R.id.donut);
         if (donut != null) {
             donut.setPercentage(mPercent);
diff --git a/src/com/android/settings/display/BrightnessLevelPreferenceController.java b/src/com/android/settings/display/BrightnessLevelPreferenceController.java
index bbd6f80..4bb0a99 100644
--- a/src/com/android/settings/display/BrightnessLevelPreferenceController.java
+++ b/src/com/android/settings/display/BrightnessLevelPreferenceController.java
@@ -13,6 +13,9 @@
  */
 package com.android.settings.display;
 
+import static com.android.settingslib.display.BrightnessUtils.GAMMA_SPACE_MAX;
+import static com.android.settingslib.display.BrightnessUtils.convertLinearToGamma;
+
 import android.content.ContentResolver;
 import android.content.Context;
 import android.database.ContentObserver;
@@ -63,12 +66,12 @@
     }
 
     private ContentObserver mBrightnessObserver =
-        new ContentObserver(new Handler(Looper.getMainLooper())) {
-            @Override
-            public void onChange(boolean selfChange) {
-                updatedSummary(mPreference);
-            }
-        };
+            new ContentObserver(new Handler(Looper.getMainLooper())) {
+                @Override
+                public void onChange(boolean selfChange) {
+                    updatedSummary(mPreference);
+                }
+            };
 
     public BrightnessLevelPreferenceController(Context context, Lifecycle lifecycle) {
         super(context);
@@ -103,6 +106,7 @@
     public void updateState(Preference preference) {
         updatedSummary(preference);
     }
+
     @Override
     public void onStart() {
         mContentResolver.registerContentObserver(BRIGHTNESS_URI, false, mBrightnessObserver);
@@ -122,15 +126,18 @@
     }
 
     private double getCurrentBrightness() {
+        final int value;
         if (isInVrMode()) {
-            final double value = System.getInt(mContentResolver, System.SCREEN_BRIGHTNESS_FOR_VR,
-                    mMaxBrightness);
-            return getPercentage(value, mMinVrBrightness, mMaxVrBrightness);
+            value = convertLinearToGamma(System.getInt(mContentResolver,
+                    System.SCREEN_BRIGHTNESS_FOR_VR, mMaxBrightness),
+                    mMinVrBrightness, mMaxVrBrightness);
         } else {
-            final double value = Settings.System.getInt(mContentResolver, System.SCREEN_BRIGHTNESS,
-                    mMinBrightness);
-            return getPercentage(value, mMinBrightness, mMaxBrightness);
+            value = convertLinearToGamma(Settings.System.getInt(mContentResolver,
+                    System.SCREEN_BRIGHTNESS, mMinBrightness),
+                    mMinBrightness, mMaxBrightness);
+
         }
+        return getPercentage(value, 0, GAMMA_SPACE_MAX);
     }
 
     private double getPercentage(double value, int min, int max) {
diff --git a/src/com/android/settings/fingerprint/FingerprintEnrollEnrolling.java b/src/com/android/settings/fingerprint/FingerprintEnrollEnrolling.java
index d89226c..f3c1486 100644
--- a/src/com/android/settings/fingerprint/FingerprintEnrollEnrolling.java
+++ b/src/com/android/settings/fingerprint/FingerprintEnrollEnrolling.java
@@ -97,9 +97,7 @@
     private FingerprintEnrollSidecar mSidecar;
     private boolean mAnimationCancelled;
     private AnimatedVectorDrawable mIconAnimationDrawable;
-    private Drawable mIconBackgroundDrawable;
-    private int mIndicatorBackgroundRestingColor;
-    private int mIndicatorBackgroundActivatedColor;
+    private AnimatedVectorDrawable mIconBackgroundBlinksDrawable;
     private boolean mRestoring;
     private Vibrator mVibrator;
 
@@ -120,7 +118,7 @@
         final LayerDrawable fingerprintDrawable = (LayerDrawable) mProgressBar.getBackground();
         mIconAnimationDrawable = (AnimatedVectorDrawable)
                 fingerprintDrawable.findDrawableByLayerId(R.id.fingerprint_animation);
-        mIconBackgroundDrawable =
+        mIconBackgroundBlinksDrawable = (AnimatedVectorDrawable)
                 fingerprintDrawable.findDrawableByLayerId(R.id.fingerprint_background);
         mIconAnimationDrawable.registerAnimationCallback(mIconAnimationCallback);
         mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(
@@ -147,11 +145,6 @@
                 return true;
             }
         });
-        mIndicatorBackgroundRestingColor
-                = getColor(R.color.fingerprint_indicator_background_resting);
-        mIndicatorBackgroundActivatedColor
-                = getColor(R.color.fingerprint_indicator_background_activated);
-        mIconBackgroundDrawable.setTint(mIndicatorBackgroundRestingColor);
         mRestoring = savedInstanceState != null;
     }
 
@@ -240,30 +233,7 @@
     }
 
     private void animateFlash() {
-        ValueAnimator anim = ValueAnimator.ofArgb(mIndicatorBackgroundRestingColor,
-                mIndicatorBackgroundActivatedColor);
-        final ValueAnimator.AnimatorUpdateListener listener =
-                new ValueAnimator.AnimatorUpdateListener() {
-            @Override
-            public void onAnimationUpdate(ValueAnimator animation) {
-                mIconBackgroundDrawable.setTint((Integer) animation.getAnimatedValue());
-            }
-        };
-        anim.addUpdateListener(listener);
-        anim.addListener(new AnimatorListenerAdapter() {
-            @Override
-            public void onAnimationEnd(Animator animation) {
-                ValueAnimator anim = ValueAnimator.ofArgb(mIndicatorBackgroundActivatedColor,
-                        mIndicatorBackgroundRestingColor);
-                anim.addUpdateListener(listener);
-                anim.setDuration(300);
-                anim.setInterpolator(mLinearOutSlowInInterpolator);
-                anim.start();
-            }
-        });
-        anim.setInterpolator(mFastOutSlowInInterpolator);
-        anim.setDuration(300);
-        anim.start();
+        mIconBackgroundBlinksDrawable.start();
     }
 
     private void launchFinish(byte[] token) {
diff --git a/src/com/android/settings/fuelgauge/SmartBatteryPreferenceController.java b/src/com/android/settings/fuelgauge/SmartBatteryPreferenceController.java
index 8b99a43..e222b91 100644
--- a/src/com/android/settings/fuelgauge/SmartBatteryPreferenceController.java
+++ b/src/com/android/settings/fuelgauge/SmartBatteryPreferenceController.java
@@ -52,15 +52,15 @@
     public void updateState(Preference preference) {
         super.updateState(preference);
         final boolean smartBatteryOn = Settings.Global.getInt(mContext.getContentResolver(),
-                Settings.Global.APP_STANDBY_ENABLED, ON) == ON;
+                Settings.Global.ADAPTIVE_BATTERY_MANAGEMENT_ENABLED, ON) == ON;
         ((SwitchPreference) preference).setChecked(smartBatteryOn);
     }
 
     @Override
     public boolean onPreferenceChange(Preference preference, Object newValue) {
         final boolean smartBatteryOn = (Boolean) newValue;
-        Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.APP_STANDBY_ENABLED,
-                smartBatteryOn ? ON : OFF);
+        Settings.Global.putInt(mContext.getContentResolver(),
+                Settings.Global.ADAPTIVE_BATTERY_MANAGEMENT_ENABLED, smartBatteryOn ? ON : OFF);
         return true;
     }
 }
diff --git a/src/com/android/settings/fuelgauge/batterysaver/AutoBatterySeekBarPreferenceController.java b/src/com/android/settings/fuelgauge/batterysaver/AutoBatterySeekBarPreferenceController.java
index 602d984..42b2920 100644
--- a/src/com/android/settings/fuelgauge/batterysaver/AutoBatterySeekBarPreferenceController.java
+++ b/src/com/android/settings/fuelgauge/batterysaver/AutoBatterySeekBarPreferenceController.java
@@ -26,6 +26,7 @@
 import android.support.v7.preference.Preference;
 import android.support.v7.preference.PreferenceScreen;
 import android.util.Log;
+import android.view.accessibility.AccessibilityNodeInfo;
 
 import com.android.settings.R;
 import com.android.settings.Utils;
@@ -61,6 +62,8 @@
         mPreference = (SeekBarPreference) screen.findPreference(
                 KEY_AUTO_BATTERY_SEEK_BAR);
         mPreference.setContinuousUpdates(true);
+        mPreference.setAccessibilityRangeInfoType(
+                AccessibilityNodeInfo.RangeInfo.RANGE_TYPE_PERCENT);
         updatePreference(mPreference);
     }
 
@@ -123,7 +126,10 @@
             preference.setVisible(true);
             preference.setTitle(mContext.getString(R.string.battery_saver_seekbar_title,
                     Utils.formatPercentage(level)));
-            ((SeekBarPreference) preference).setProgress(level);
+            SeekBarPreference seekBarPreference = (SeekBarPreference) preference;
+            seekBarPreference.setProgress(level);
+            seekBarPreference.setSeekBarContentDescription(
+                    mContext.getString(R.string.battery_saver_turn_on_automatically_title));
         }
     }
 
diff --git a/src/com/android/settings/fuelgauge/batterytip/AnomalyDetectionJobService.java b/src/com/android/settings/fuelgauge/batterytip/AnomalyDetectionJobService.java
index 7f6eb9b..0e4f9c3 100644
--- a/src/com/android/settings/fuelgauge/batterytip/AnomalyDetectionJobService.java
+++ b/src/com/android/settings/fuelgauge/batterytip/AnomalyDetectionJobService.java
@@ -143,7 +143,7 @@
             final int uid = extractUidFromStatsDimensionsValue(intentDimsValue);
             final boolean autoFeatureOn = powerUsageFeatureProvider.isSmartBatterySupported()
                     ? Settings.Global.getInt(contentResolver,
-                            Settings.Global.APP_STANDBY_ENABLED, ON) == ON
+                            Settings.Global.ADAPTIVE_BATTERY_MANAGEMENT_ENABLED, ON) == ON
                     : Settings.Global.getInt(contentResolver,
                             Settings.Global.APP_AUTO_RESTRICTION_ENABLED, ON) == ON;
             final String packageName = batteryUtils.getPackageName(uid);
diff --git a/src/com/android/settings/fuelgauge/batterytip/BatteryManagerPreferenceController.java b/src/com/android/settings/fuelgauge/batterytip/BatteryManagerPreferenceController.java
index be2ed84..64184ef 100644
--- a/src/com/android/settings/fuelgauge/batterytip/BatteryManagerPreferenceController.java
+++ b/src/com/android/settings/fuelgauge/batterytip/BatteryManagerPreferenceController.java
@@ -56,7 +56,7 @@
         super.updateState(preference);
         final int num = BatteryTipUtils.getRestrictedAppsList(mAppOpsManager, mUserManager).size();
         final String setting = mPowerUsageFeatureProvider.isSmartBatterySupported()
-                ? Settings.Global.APP_STANDBY_ENABLED
+                ? Settings.Global.ADAPTIVE_BATTERY_MANAGEMENT_ENABLED
                 : Settings.Global.APP_AUTO_RESTRICTION_ENABLED;
         final boolean featureOn =
                 Settings.Global.getInt(mContext.getContentResolver(), setting, ON) == ON;
diff --git a/src/com/android/settings/fuelgauge/batterytip/BatteryTipLoader.java b/src/com/android/settings/fuelgauge/batterytip/BatteryTipLoader.java
index 5efc04a..b9194b4 100644
--- a/src/com/android/settings/fuelgauge/batterytip/BatteryTipLoader.java
+++ b/src/com/android/settings/fuelgauge/batterytip/BatteryTipLoader.java
@@ -68,7 +68,8 @@
         final Context context = getContext();
 
         tips.add(new LowBatteryDetector(policy, batteryInfo).detect());
-        tips.add(new HighUsageDetector(context, policy, mBatteryStatsHelper).detect());
+        tips.add(new HighUsageDetector(context, policy, mBatteryStatsHelper,
+                batteryInfo.discharging).detect());
         tips.add(new SmartBatteryDetector(policy, context.getContentResolver()).detect());
         tips.add(new EarlyWarningDetector(policy, context).detect());
         tips.add(new SummaryDetector(policy, batteryInfo.averageTimeToDischarge).detect());
diff --git a/src/com/android/settings/fuelgauge/batterytip/detectors/HighUsageDetector.java b/src/com/android/settings/fuelgauge/batterytip/detectors/HighUsageDetector.java
index b511ee0..9624832 100644
--- a/src/com/android/settings/fuelgauge/batterytip/detectors/HighUsageDetector.java
+++ b/src/com/android/settings/fuelgauge/batterytip/detectors/HighUsageDetector.java
@@ -44,28 +44,29 @@
     private BatteryTipPolicy mPolicy;
     private BatteryStatsHelper mBatteryStatsHelper;
     private List<AppInfo> mHighUsageAppList;
-    private Context mContext;
     @VisibleForTesting
     HighUsageDataParser mDataParser;
     @VisibleForTesting
     BatteryUtils mBatteryUtils;
+    @VisibleForTesting
+    boolean mDischarging;
 
     public HighUsageDetector(Context context, BatteryTipPolicy policy,
-            BatteryStatsHelper batteryStatsHelper) {
-        mContext = context;
+            BatteryStatsHelper batteryStatsHelper, boolean discharging) {
         mPolicy = policy;
         mBatteryStatsHelper = batteryStatsHelper;
         mHighUsageAppList = new ArrayList<>();
         mBatteryUtils = BatteryUtils.getInstance(context);
         mDataParser = new HighUsageDataParser(mPolicy.highUsagePeriodMs,
                 mPolicy.highUsageBatteryDraining);
+        mDischarging = discharging;
     }
 
     @Override
     public BatteryTip detect() {
         final long lastFullChargeTimeMs = mBatteryUtils.calculateLastFullChargeTime(
                 mBatteryStatsHelper, System.currentTimeMillis());
-        if (mPolicy.highUsageEnabled) {
+        if (mPolicy.highUsageEnabled && mDischarging) {
             parseBatteryData();
             if (mDataParser.isDeviceHeavilyUsed() || mPolicy.testHighUsageTip) {
                 final List<BatterySipper> batterySippers = mBatteryStatsHelper.getUsageList();
diff --git a/src/com/android/settings/fuelgauge/batterytip/detectors/SmartBatteryDetector.java b/src/com/android/settings/fuelgauge/batterytip/detectors/SmartBatteryDetector.java
index ecd595e..a8d4981 100644
--- a/src/com/android/settings/fuelgauge/batterytip/detectors/SmartBatteryDetector.java
+++ b/src/com/android/settings/fuelgauge/batterytip/detectors/SmartBatteryDetector.java
@@ -39,7 +39,8 @@
     public BatteryTip detect() {
         // Show it if there is no other tips shown
         final boolean smartBatteryOff = Settings.Global.getInt(mContentResolver,
-                Settings.Global.APP_STANDBY_ENABLED, 1) == 0 || mPolicy.testSmartBatteryTip;
+                Settings.Global.ADAPTIVE_BATTERY_MANAGEMENT_ENABLED, 1) == 0
+                || mPolicy.testSmartBatteryTip;
         final int state =
                 smartBatteryOff ? BatteryTip.StateType.NEW : BatteryTip.StateType.INVISIBLE;
         return new SmartBatteryTip(state);
diff --git a/src/com/android/settings/inputmethod/GameControllerPreferenceController.java b/src/com/android/settings/inputmethod/GameControllerPreferenceController.java
index c4e998a..85aef63 100644
--- a/src/com/android/settings/inputmethod/GameControllerPreferenceController.java
+++ b/src/com/android/settings/inputmethod/GameControllerPreferenceController.java
@@ -19,38 +19,27 @@
 import android.content.Context;
 import android.hardware.input.InputManager;
 import android.provider.Settings;
-import android.support.annotation.VisibleForTesting;
-import android.support.v14.preference.SwitchPreference;
 import android.support.v7.preference.Preference;
 import android.support.v7.preference.PreferenceScreen;
-import android.text.TextUtils;
 import android.view.InputDevice;
 
-import com.android.settings.core.PreferenceControllerMixin;
 import com.android.settings.R;
-import com.android.settingslib.core.AbstractPreferenceController;
+import com.android.settings.core.PreferenceControllerMixin;
+import com.android.settings.core.TogglePreferenceController;
 import com.android.settingslib.core.lifecycle.LifecycleObserver;
 import com.android.settingslib.core.lifecycle.events.OnPause;
 import com.android.settingslib.core.lifecycle.events.OnResume;
 
-import java.util.List;
-
-public class GameControllerPreferenceController extends AbstractPreferenceController
+public class GameControllerPreferenceController extends TogglePreferenceController
         implements PreferenceControllerMixin, InputManager.InputDeviceListener, LifecycleObserver,
         OnResume, OnPause {
 
-    @VisibleForTesting
-    static final String PREF_KEY = "vibrate_input_devices";
-    private static final String CATEGORY_KEY = "game_controller_settings_category";
-
     private final InputManager mIm;
 
-    private PreferenceScreen mScreen;
-    private Preference mCategory;
     private Preference mPreference;
 
-    public GameControllerPreferenceController(Context context) {
-        super(context);
+    public GameControllerPreferenceController(Context context, String key) {
+        super(context, key);
         mIm = (InputManager) context.getSystemService(Context.INPUT_SERVICE);
     }
 
@@ -67,85 +56,61 @@
     @Override
     public void displayPreference(PreferenceScreen screen) {
         super.displayPreference(screen);
-        mScreen = screen;
-        mCategory = screen.findPreference(CATEGORY_KEY);
-        mPreference = screen.findPreference(PREF_KEY);
+        mPreference = screen.findPreference(getPreferenceKey());
     }
 
     @Override
-    public boolean isAvailable() {
+    @AvailabilityStatus
+    public int getAvailabilityStatus() {
         // If device explicitly wants to hide this, return early.
         if (!mContext.getResources().getBoolean(R.bool.config_show_vibrate_input_devices)) {
-            return false;
+            return DISABLED_UNSUPPORTED;
         }
 
         final int[] devices = mIm.getInputDeviceIds();
         for (int deviceId : devices) {
             InputDevice device = mIm.getInputDevice(deviceId);
             if (device != null && !device.isVirtual() && device.getVibrator().hasVibrator()) {
-                return true;
+                return AVAILABLE;
             }
         }
-        return false;
-    }
-
-    @Override
-    public boolean handlePreferenceTreeClick(Preference preference) {
-        if (TextUtils.equals(PREF_KEY, preference.getKey())) {
-            Settings.System.putInt(mContext.getContentResolver(),
-                    Settings.System.VIBRATE_INPUT_DEVICES,
-                    ((SwitchPreference) preference).isChecked() ? 1 : 0);
-            return true;
-        }
-        return false;
-    }
-
-    @Override
-    public String getPreferenceKey() {
-        return CATEGORY_KEY;
+        return DISABLED_UNSUPPORTED;
     }
 
     @Override
     public void updateState(Preference preference) {
+        super.updateState(preference);
         if (preference == null) {
             return;
         }
-        ((SwitchPreference) preference).setChecked(Settings.System.getInt(
-                mContext.getContentResolver(),
-                Settings.System.VIBRATE_INPUT_DEVICES, 1) > 0);
+        mPreference.setVisible(isAvailable());
     }
 
     @Override
-    public void updateNonIndexableKeys(List<String> keys) {
-        if (!isAvailable()) {
-            keys.add(CATEGORY_KEY);
-            keys.add(PREF_KEY);
-        }
+    public boolean isChecked() {
+        return Settings.System.getInt(
+                mContext.getContentResolver(),
+                Settings.System.VIBRATE_INPUT_DEVICES, 1) > 0;
+    }
+
+    @Override
+    public boolean setChecked(boolean isChecked) {
+        return Settings.System.putInt(mContext.getContentResolver(),
+                Settings.System.VIBRATE_INPUT_DEVICES, isChecked ? 1 : 0);
     }
 
     @Override
     public void onInputDeviceAdded(int deviceId) {
-        updateGameControllers();
+        updateState(mPreference);
     }
 
     @Override
     public void onInputDeviceRemoved(int deviceId) {
-        updateGameControllers();
+        updateState(mPreference);
     }
 
     @Override
     public void onInputDeviceChanged(int deviceId) {
-        updateGameControllers();
-    }
-
-    private void updateGameControllers() {
-        if (isAvailable()) {
-            mScreen.addPreference(mCategory);
-            updateState(mPreference);
-        } else {
-            if (mCategory != null) {
-                mScreen.removePreference(mCategory);
-            }
-        }
+        updateState(mPreference);
     }
 }
diff --git a/src/com/android/settings/language/LanguageAndInputSettings.java b/src/com/android/settings/language/LanguageAndInputSettings.java
index 126f3c8..73cfe27 100644
--- a/src/com/android/settings/language/LanguageAndInputSettings.java
+++ b/src/com/android/settings/language/LanguageAndInputSettings.java
@@ -35,7 +35,6 @@
 import com.android.settings.applications.defaultapps.DefaultAutofillPreferenceController;
 import com.android.settings.dashboard.DashboardFragment;
 import com.android.settings.dashboard.SummaryLoader;
-import com.android.settings.inputmethod.GameControllerPreferenceController;
 import com.android.settings.inputmethod.PhysicalKeyboardPreferenceController;
 import com.android.settings.inputmethod.SpellCheckerPreferenceController;
 import com.android.settings.inputmethod.VirtualKeyboardPreferenceController;
@@ -124,17 +123,6 @@
         controllers.add(new DefaultAutofillPreferenceController(context));
         controllers.add(new UserDictionaryPreferenceController(context));
 
-        // Game Controller
-        final GameControllerPreferenceController gameControllerPreferenceController
-                = new GameControllerPreferenceController(context);
-        if (lifecycle != null) {
-            lifecycle.addObserver(gameControllerPreferenceController);
-        }
-        controllers.add(gameControllerPreferenceController);
-        controllers.add(new PreferenceCategoryController(context,
-                KEY_GAME_CONTROLLER_CATEGORY).setChildren(
-                Arrays.asList(gameControllerPreferenceController)));
-
         return controllers;
     }
 
diff --git a/src/com/android/settings/network/AirplaneModePreferenceController.java b/src/com/android/settings/network/AirplaneModePreferenceController.java
index b4851e6..56c305d 100644
--- a/src/com/android/settings/network/AirplaneModePreferenceController.java
+++ b/src/com/android/settings/network/AirplaneModePreferenceController.java
@@ -27,9 +27,9 @@
 import com.android.internal.telephony.TelephonyIntents;
 import com.android.internal.telephony.TelephonyProperties;
 import com.android.settings.AirplaneModeEnabler;
+import com.android.settings.R;
 import com.android.settings.core.TogglePreferenceController;
 import com.android.settings.overlay.FeatureFactory;
-import com.android.settings.R;
 import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
 import com.android.settingslib.core.lifecycle.LifecycleObserver;
 import com.android.settingslib.core.lifecycle.events.OnPause;
@@ -54,6 +54,7 @@
     public AirplaneModePreferenceController(Context context, String key) {
         super(context, key);
         mMetricsFeatureProvider = FeatureFactory.getFactory(context).getMetricsFeatureProvider();
+        mAirplaneModeEnabler = new AirplaneModeEnabler(mContext, mMetricsFeatureProvider, this);
     }
 
     public void setFragment(Fragment hostFragment) {
@@ -81,7 +82,6 @@
         super.displayPreference(screen);
         if (isAvailable()) {
             mAirplaneModePreference = (SwitchPreference) screen.findPreference(getPreferenceKey());
-            mAirplaneModeEnabler = new AirplaneModeEnabler(mContext, mMetricsFeatureProvider, this);
         }
     }
 
@@ -96,15 +96,16 @@
         return isAvailable(mContext) ? AVAILABLE : DISABLED_UNSUPPORTED;
     }
 
+    @Override
     public void onResume() {
-        if (mAirplaneModeEnabler != null) {
+        if (isAvailable()) {
             mAirplaneModeEnabler.resume();
         }
     }
 
     @Override
     public void onPause() {
-        if (mAirplaneModeEnabler != null) {
+        if (isAvailable()) {
             mAirplaneModeEnabler.pause();
         }
     }
@@ -134,6 +135,8 @@
 
     @Override
     public void onAirplaneModeChanged(boolean isAirplaneModeOn) {
-        mAirplaneModePreference.setChecked(isAirplaneModeOn);
+        if (mAirplaneModePreference != null) {
+            mAirplaneModePreference.setChecked(isAirplaneModeOn);
+        }
     }
 }
diff --git a/src/com/android/settings/nfc/BaseNfcPreferenceController.java b/src/com/android/settings/nfc/BaseNfcPreferenceController.java
index b945738..33d75fa 100644
--- a/src/com/android/settings/nfc/BaseNfcPreferenceController.java
+++ b/src/com/android/settings/nfc/BaseNfcPreferenceController.java
@@ -67,7 +67,7 @@
 
     @Override
     public void updateNonIndexableKeys(List<String> keys) {
-        if (isAvailable()) {
+        if (!isAvailable()) {
             keys.add(getPreferenceKey());
         }
     }
diff --git a/src/com/android/settings/overlay/DockUpdaterFeatureProvider.java b/src/com/android/settings/overlay/DockUpdaterFeatureProvider.java
new file mode 100644
index 0000000..2a968e0
--- /dev/null
+++ b/src/com/android/settings/overlay/DockUpdaterFeatureProvider.java
@@ -0,0 +1,35 @@
+/*
+ * 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.overlay;
+
+import android.content.Context;
+
+import com.android.settings.connecteddevice.DevicePreferenceCallback;
+import com.android.settings.connecteddevice.dock.DockUpdater;
+
+/** Feature provider for the dock updater. */
+public interface DockUpdaterFeatureProvider {
+
+    /** Returns the DockUpdater of the connected dock device */
+    DockUpdater getConnectedDockUpdater(Context context,
+            DevicePreferenceCallback devicePreferenceCallback);
+
+    /** Returns the DockUpdater of the saved dock devices */
+    DockUpdater getSavedDockUpdater(Context context,
+            DevicePreferenceCallback devicePreferenceCallback);
+
+}
diff --git a/src/com/android/settings/overlay/FeatureFactory.java b/src/com/android/settings/overlay/FeatureFactory.java
index 110d204..72bac99 100644
--- a/src/com/android/settings/overlay/FeatureFactory.java
+++ b/src/com/android/settings/overlay/FeatureFactory.java
@@ -86,6 +86,8 @@
 
     public abstract DashboardFeatureProvider getDashboardFeatureProvider(Context context);
 
+    public abstract DockUpdaterFeatureProvider getDockUpdaterFeatureProvider();
+
     public abstract ApplicationFeatureProvider getApplicationFeatureProvider(Context context);
 
     public abstract LocaleFeatureProvider getLocaleFeatureProvider();
diff --git a/src/com/android/settings/overlay/FeatureFactoryImpl.java b/src/com/android/settings/overlay/FeatureFactoryImpl.java
index b652c66..d058b3b 100644
--- a/src/com/android/settings/overlay/FeatureFactoryImpl.java
+++ b/src/com/android/settings/overlay/FeatureFactoryImpl.java
@@ -29,6 +29,7 @@
 import com.android.settings.applications.ApplicationFeatureProviderImpl;
 import com.android.settings.bluetooth.BluetoothFeatureProvider;
 import com.android.settings.bluetooth.BluetoothFeatureProviderImpl;
+import com.android.settings.connecteddevice.dock.DockUpdaterFeatureProviderImpl;
 import com.android.settings.dashboard.DashboardFeatureProvider;
 import com.android.settings.dashboard.DashboardFeatureProviderImpl;
 import com.android.settings.dashboard.suggestions.SuggestionFeatureProvider;
@@ -63,6 +64,7 @@
     private ApplicationFeatureProvider mApplicationFeatureProvider;
     private MetricsFeatureProvider mMetricsFeatureProvider;
     private DashboardFeatureProviderImpl mDashboardFeatureProvider;
+    private DockUpdaterFeatureProvider mDockUpdaterFeatureProvider;
     private LocaleFeatureProvider mLocaleFeatureProvider;
     private EnterprisePrivacyFeatureProvider mEnterprisePrivacyFeatureProvider;
     private SearchFeatureProvider mSearchFeatureProvider;
@@ -106,6 +108,14 @@
     }
 
     @Override
+    public DockUpdaterFeatureProvider getDockUpdaterFeatureProvider() {
+        if (mDockUpdaterFeatureProvider == null) {
+            mDockUpdaterFeatureProvider = new DockUpdaterFeatureProviderImpl();
+        }
+        return mDockUpdaterFeatureProvider;
+    }
+
+    @Override
     public ApplicationFeatureProvider getApplicationFeatureProvider(Context context) {
         if (mApplicationFeatureProvider == null) {
             mApplicationFeatureProvider = new ApplicationFeatureProviderImpl(context,
diff --git a/src/com/android/settings/password/ChooseLockSettingsHelper.java b/src/com/android/settings/password/ChooseLockSettingsHelper.java
index cfc0ce8..4dafda6 100644
--- a/src/com/android/settings/password/ChooseLockSettingsHelper.java
+++ b/src/com/android/settings/password/ChooseLockSettingsHelper.java
@@ -284,8 +284,9 @@
         intent.putExtra(ConfirmDeviceCredentialBaseFragment.HEADER_TEXT, header);
         intent.putExtra(ConfirmDeviceCredentialBaseFragment.DETAILS_TEXT, message);
         intent.putExtra(ConfirmDeviceCredentialBaseFragment.ALLOW_FP_AUTHENTICATION, external);
+        // TODO: Remove dark theme and show_cancel_button options since they are no longer used
         intent.putExtra(ConfirmDeviceCredentialBaseFragment.DARK_THEME, false);
-        intent.putExtra(ConfirmDeviceCredentialBaseFragment.SHOW_CANCEL_BUTTON, external);
+        intent.putExtra(ConfirmDeviceCredentialBaseFragment.SHOW_CANCEL_BUTTON, false);
         intent.putExtra(ConfirmDeviceCredentialBaseFragment.SHOW_WHEN_LOCKED, external);
         intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_RETURN_CREDENTIALS, returnCredentials);
         intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_HAS_CHALLENGE, hasChallenge);
diff --git a/src/com/android/settings/search/DatabaseIndexingManager.java b/src/com/android/settings/search/DatabaseIndexingManager.java
index 0c02b67..8a18efa 100644
--- a/src/com/android/settings/search/DatabaseIndexingManager.java
+++ b/src/com/android/settings/search/DatabaseIndexingManager.java
@@ -59,6 +59,7 @@
 import android.text.TextUtils;
 import android.util.Log;
 
+import com.android.settings.overlay.FeatureFactory;
 import com.android.settings.search.indexing.IndexData;
 import com.android.settings.search.indexing.IndexDataConverter;
 import com.android.settings.search.indexing.PreIndexData;
diff --git a/src/com/android/settings/search/DeviceIndexFeatureProvider.java b/src/com/android/settings/search/DeviceIndexFeatureProvider.java
index 2273ffd..37978df 100644
--- a/src/com/android/settings/search/DeviceIndexFeatureProvider.java
+++ b/src/com/android/settings/search/DeviceIndexFeatureProvider.java
@@ -17,70 +17,57 @@
 import static com.android.settings.slices.SliceDeepLinkSpringBoard.INTENT;
 import static com.android.settings.slices.SliceDeepLinkSpringBoard.SETTINGS;
 
-import android.app.slice.SliceManager;
+import android.app.job.JobInfo;
+import android.app.job.JobScheduler;
+import android.content.ComponentName;
 import android.content.Context;
-import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
 import android.net.Uri;
+import android.os.Build;
 import android.provider.Settings;
-import android.util.Log;
 
+import com.android.settings.R;
 import com.android.settings.slices.SettingsSliceProvider;
 
+import java.util.List;
+import java.util.Objects;
+
 public interface DeviceIndexFeatureProvider {
 
-    // TODO: Remove this and index all action and intent slices through search index.
-    String[] ACTIONS_TO_INDEX = new String[]{
-            Settings.ACTION_WIFI_SETTINGS,
-            Settings.ACTION_BATTERY_SAVER_SETTINGS,
-            Settings.ACTION_BLUETOOTH_SETTINGS,
-            "android.intent.action.POWER_USAGE_SUMMARY",
-            Settings.ACTION_SOUND_SETTINGS,
-    };
 
     String TAG = "DeviceIndex";
 
     String INDEX_VERSION = "settings:index_version";
 
     // Increment when new items are added to ensure they get pushed to the device index.
-    int VERSION = 2;
+    String VERSION = Build.FINGERPRINT;
 
     boolean isIndexingEnabled();
 
-    void index(Context context, CharSequence title, Uri sliceUri, Uri launchUri);
+    void index(Context context, CharSequence title, Uri sliceUri, Uri launchUri,
+            List<String> keywords);
 
     default void updateIndex(Context context, boolean force) {
         if (!isIndexingEnabled()) return;
 
-        if (!force && Settings.Secure.getInt(context.getContentResolver(), INDEX_VERSION, -1)
-                == VERSION) {
+        if (!force && Objects.equals(
+                Settings.Secure.getString(context.getContentResolver(), INDEX_VERSION),  VERSION)) {
             // No need to update.
             return;
         }
 
-        PackageManager pm = context.getPackageManager();
-        for (String action : ACTIONS_TO_INDEX) {
-            Intent intent = new Intent(action);
-            intent.setPackage(context.getPackageName());
-            ResolveInfo activity = pm.resolveActivity(intent, PackageManager.GET_META_DATA);
-            if (activity == null) {
-                Log.e(TAG, "Unable to resolve " + action);
-                continue;
-            }
-            String sliceUri = activity.activityInfo.metaData
-                    .getString(SliceManager.SLICE_METADATA_KEY);
-            if (sliceUri != null) {
-                Log.d(TAG, "Intent: " + createDeepLink(intent.toUri(Intent.URI_ANDROID_APP_SCHEME)));
-                index(context, activity.activityInfo.loadLabel(pm),
-                        Uri.parse(sliceUri),
-                        Uri.parse(createDeepLink(intent.toUri(Intent.URI_ANDROID_APP_SCHEME))));
-            } else {
-                Log.e(TAG, "No slice uri found for " + activity.activityInfo.name);
-            }
-        }
+        ComponentName jobComponent = new ComponentName(context.getPackageName(),
+                DeviceIndexUpdateJobService.class.getName());
+        int jobId = context.getResources().getInteger(R.integer.device_index_update);
+        // Schedule a job so that we know it'll be able to complete, but try to run as
+        // soon as possible.
+        context.getSystemService(JobScheduler.class).schedule(
+                new JobInfo.Builder(jobId, jobComponent)
+                        .setPersisted(true)
+                        .setMinimumLatency(1)
+                        .setOverrideDeadline(1)
+                        .build());
 
-        Settings.Secure.putInt(context.getContentResolver(), INDEX_VERSION, VERSION);
+        Settings.Secure.putString(context.getContentResolver(), INDEX_VERSION, VERSION);
     }
 
     static String createDeepLink(String s) {
diff --git a/src/com/android/settings/search/DeviceIndexFeatureProviderImpl.java b/src/com/android/settings/search/DeviceIndexFeatureProviderImpl.java
index 4564fe6..7a11bd4 100644
--- a/src/com/android/settings/search/DeviceIndexFeatureProviderImpl.java
+++ b/src/com/android/settings/search/DeviceIndexFeatureProviderImpl.java
@@ -17,6 +17,8 @@
 import android.content.Context;
 import android.net.Uri;
 
+import java.util.List;
+
 public class DeviceIndexFeatureProviderImpl implements DeviceIndexFeatureProvider {
 
     @Override
@@ -25,7 +27,8 @@
     }
 
     @Override
-    public void index(Context context, CharSequence title, Uri sliceUri, Uri launchUri) {
+    public void index(Context context, CharSequence title, Uri sliceUri, Uri launchUri,
+            List<String> keywords) {
         // Not enabled by default.
     }
 }
diff --git a/src/com/android/settings/search/DeviceIndexUpdateJobService.java b/src/com/android/settings/search/DeviceIndexUpdateJobService.java
new file mode 100644
index 0000000..573dcdf
--- /dev/null
+++ b/src/com/android/settings/search/DeviceIndexUpdateJobService.java
@@ -0,0 +1,172 @@
+/*
+ * 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.search;
+
+import static android.app.slice.Slice.HINT_LARGE;
+import static android.app.slice.Slice.HINT_TITLE;
+import static android.app.slice.SliceItem.FORMAT_TEXT;
+
+import static com.android.settings.search.DeviceIndexFeatureProvider.createDeepLink;
+
+import android.app.job.JobParameters;
+import android.app.job.JobService;
+import android.content.ContentResolver;
+import android.content.Intent;
+import android.net.Uri;
+import android.net.Uri.Builder;
+import android.util.Log;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.settings.overlay.FeatureFactory;
+import com.android.settings.slices.SettingsSliceProvider;
+import com.android.settings.slices.SliceDeepLinkSpringBoard;
+
+import java.util.Collection;
+import java.util.concurrent.CountDownLatch;
+
+import androidx.slice.Slice;
+import androidx.slice.SliceItem;
+import androidx.slice.SliceManager;
+import androidx.slice.SliceManager.SliceCallback;
+import androidx.slice.SliceMetadata;
+import androidx.slice.core.SliceQuery;
+import androidx.slice.widget.ListContent;
+
+public class DeviceIndexUpdateJobService extends JobService {
+
+    private static final String TAG = "DeviceIndexUpdate";
+    private static final boolean DEBUG = false;
+    @VisibleForTesting
+    protected boolean mRunningJob;
+
+    @Override
+    public boolean onStartJob(JobParameters params) {
+        if (DEBUG) Log.d(TAG, "onStartJob");
+        mRunningJob = true;
+        Thread thread = new Thread(() -> updateIndex(params));
+        thread.setPriority(Thread.MIN_PRIORITY);
+        thread.start();
+        return true;
+    }
+
+    @Override
+    public boolean onStopJob(JobParameters params) {
+        if (DEBUG) Log.d(TAG, "onStopJob " + mRunningJob);
+        if (mRunningJob) {
+            mRunningJob = false;
+            return true;
+        }
+        return false;
+    }
+
+    @VisibleForTesting
+    protected void updateIndex(JobParameters params) {
+        if (DEBUG) Log.d(TAG, "Starting index");
+        DeviceIndexFeatureProvider indexProvider = FeatureFactory.getFactory(
+                this).getDeviceIndexFeatureProvider();
+        SliceManager manager = getSliceManager();
+        Uri baseUri = new Builder()
+                .scheme(ContentResolver.SCHEME_CONTENT)
+                .authority(SettingsSliceProvider.SLICE_AUTHORITY)
+                .build();
+        Collection<Uri> slices = manager.getSliceDescendants(baseUri);
+        if (DEBUG) Log.d(TAG, "Indexing " + slices.size() + " slices");
+
+        for (Uri slice : slices) {
+            if (!mRunningJob) {
+                return;
+            }
+            Slice loadedSlice = bindSliceSynchronous(manager, slice);
+            // TODO: Get Title APIs on SliceMetadata and use that.
+            SliceMetadata metaData = getMetadata(loadedSlice);
+            CharSequence title = findTitle(loadedSlice, metaData);
+            if (title != null) {
+                if (DEBUG) Log.d(TAG, "Indexing: " + slice + " " + title + " " + loadedSlice);
+                indexProvider.index(this, title, slice, Uri.parse(createDeepLink(
+                        new Intent(SliceDeepLinkSpringBoard.ACTION_VIEW_SLICE)
+                                .setPackage(getPackageName())
+                                .putExtra(SliceDeepLinkSpringBoard.EXTRA_SLICE, slice.toString())
+                                .toUri(Intent.URI_ANDROID_APP_SCHEME))),
+                        metaData.getSliceKeywords());
+            }
+        }
+        if (DEBUG) Log.d(TAG, "Done indexing");
+        jobFinished(params, false);
+    }
+
+    protected SliceManager getSliceManager() {
+        return SliceManager.getInstance(this);
+    }
+
+    protected SliceMetadata getMetadata(Slice loadedSlice) {
+        return SliceMetadata.from(this, loadedSlice);
+    }
+
+    protected CharSequence findTitle(Slice loadedSlice, SliceMetadata metaData) {
+        ListContent content = new ListContent(this, loadedSlice);
+        SliceItem headerItem = content.getHeaderItem();
+        if (headerItem == null) {
+            if (content.getRowItems().size() != 0) {
+                headerItem = content.getRowItems().get(0);
+            } else {
+                return null;
+            }
+        }
+        // Look for a title, then large text, then any text at all.
+        SliceItem title = SliceQuery.find(headerItem, FORMAT_TEXT, HINT_TITLE, null);
+        if (title != null) {
+            return title.getText();
+        }
+        title = SliceQuery.find(headerItem, FORMAT_TEXT, HINT_LARGE, null);
+        if (title != null) {
+            return title.getText();
+        }
+        title = SliceQuery.find(headerItem, FORMAT_TEXT);
+        if (title != null) {
+            return title.getText();
+        }
+        return null;
+    }
+
+    protected Slice bindSliceSynchronous(SliceManager manager, Uri slice) {
+        final Slice[] returnSlice = new Slice[1];
+        CountDownLatch latch = new CountDownLatch(1);
+        SliceCallback callback = new SliceCallback() {
+            @Override
+            public void onSliceUpdated(Slice s) {
+                try {
+                    SliceMetadata m = SliceMetadata.from(DeviceIndexUpdateJobService.this, s);
+                    if (m.getLoadingState() == SliceMetadata.LOADED_ALL) {
+                        returnSlice[0] = s;
+                        latch.countDown();
+                        manager.unregisterSliceCallback(slice, this);
+                    }
+                } catch (Exception e) {
+                    Log.w(TAG, slice + " cannot be indexed", e);
+                    returnSlice[0] = s;
+                }
+            }
+        };
+        // Register a callback until we get a loaded slice.
+        manager.registerSliceCallback(slice, callback);
+        // Trigger the first bind in case no loading is needed.
+        callback.onSliceUpdated(manager.bindSlice(slice));
+        try {
+            latch.await();
+        } catch (InterruptedException e) {
+        }
+        return returnSlice[0];
+    }
+}
diff --git a/src/com/android/settings/slices/SettingsSliceProvider.java b/src/com/android/settings/slices/SettingsSliceProvider.java
index 70e9d76..55ad6b0 100644
--- a/src/com/android/settings/slices/SettingsSliceProvider.java
+++ b/src/com/android/settings/slices/SettingsSliceProvider.java
@@ -16,6 +16,8 @@
 
 package com.android.settings.slices;
 
+import static android.Manifest.permission.READ_SEARCH_INDEXABLES;
+
 import android.app.PendingIntent;
 import android.app.slice.SliceManager;
 import android.content.ContentResolver;
@@ -24,11 +26,13 @@
 import android.graphics.drawable.Icon;
 import android.net.Uri;
 import android.net.wifi.WifiManager;
+import android.os.StrictMode;
 import android.provider.Settings;
 import android.provider.SettingsSlicesContract;
 import android.support.annotation.VisibleForTesting;
 import android.support.v4.graphics.drawable.IconCompat;
 import android.text.TextUtils;
+import android.util.ArrayMap;
 import android.util.Log;
 import android.util.Pair;
 
@@ -38,6 +42,7 @@
 import java.net.URISyntaxException;
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.WeakHashMap;
@@ -111,12 +116,18 @@
     SlicesDatabaseAccessor mSlicesDatabaseAccessor;
 
     @VisibleForTesting
+    Map<Uri, SliceData> mSliceWeakDataCache;
     Map<Uri, SliceData> mSliceDataCache;
 
+    public SettingsSliceProvider() {
+        super(READ_SEARCH_INDEXABLES);
+    }
+
     @Override
     public boolean onCreateSliceProvider() {
         mSlicesDatabaseAccessor = new SlicesDatabaseAccessor(getContext());
-        mSliceDataCache = new WeakHashMap<>();
+        mSliceDataCache = new ArrayMap<>();
+        mSliceWeakDataCache = new WeakHashMap<>();
         return true;
     }
 
@@ -132,7 +143,23 @@
     }
 
     @Override
+    public void onSlicePinned(Uri sliceUri) {
+        // Start warming the slice, we expect someone will want it soon.
+        loadSliceInBackground(sliceUri);
+    }
+
+    @Override
+    public void onSliceUnpinned(Uri sliceUri) {
+        mSliceDataCache.remove(sliceUri);
+    }
+
+    @Override
     public Slice onBindSlice(Uri sliceUri) {
+        // TODO: Remove this when all slices are not breaking strict mode
+        StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
+                .permitAll()
+                .build());
+
         String path = sliceUri.getPath();
         // If adding a new Slice, do not directly match Slice URIs.
         // Use {@link SlicesDatabaseAccessor}.
@@ -141,14 +168,16 @@
                 return createWifiSlice(sliceUri);
         }
 
-        SliceData cachedSliceData = mSliceDataCache.get(sliceUri);
+        SliceData cachedSliceData = mSliceWeakDataCache.get(sliceUri);
         if (cachedSliceData == null) {
             loadSliceInBackground(sliceUri);
             return getSliceStub(sliceUri);
         }
 
         // Remove the SliceData from the cache after it has been used to prevent a memory-leak.
-        mSliceDataCache.remove(sliceUri);
+        if (!mSliceDataCache.containsKey(sliceUri)) {
+            mSliceWeakDataCache.remove(sliceUri);
+        }
         return SliceBuilderUtils.buildSlice(getContext(), cachedSliceData);
     }
 
@@ -236,7 +265,12 @@
         long startBuildTime = System.currentTimeMillis();
 
         final SliceData sliceData = mSlicesDatabaseAccessor.getSliceDataFromUri(uri);
-        mSliceDataCache.put(uri, sliceData);
+        List<Uri> pinnedSlices = getContext().getSystemService(
+                SliceManager.class).getPinnedSlices();
+        if (pinnedSlices.contains(uri)) {
+            mSliceDataCache.put(uri, sliceData);
+        }
+        mSliceWeakDataCache.put(uri, sliceData);
         getContext().getContentResolver().notifyChange(uri, null /* content observer */);
 
         Log.d(TAG, "Built slice (" + uri + ") in: " +
@@ -255,7 +289,8 @@
      * {@link SliceData} is loaded from {@link SlicesDatabaseHelper.Tables#TABLE_SLICES_INDEX}.
      */
     private Slice getSliceStub(Uri uri) {
-        return new ListBuilder(getContext(), uri).build();
+        // TODO: Switch back to ListBuilder when slice loading states are fixed.
+        return new Slice.Builder(uri).build();
     }
 
     // TODO (b/70622039) remove this when the proper wifi slice is enabled.
diff --git a/src/com/android/settings/slices/SliceDeepLinkSpringBoard.java b/src/com/android/settings/slices/SliceDeepLinkSpringBoard.java
index fcb4525..d02431c 100644
--- a/src/com/android/settings/slices/SliceDeepLinkSpringBoard.java
+++ b/src/com/android/settings/slices/SliceDeepLinkSpringBoard.java
@@ -27,6 +27,8 @@
     private static final String TAG = "DeeplinkSpringboard";
     public static final String INTENT = "intent";
     public static final String SETTINGS = "settings";
+    public static final String ACTION_VIEW_SLICE = "com.android.settings.action.VIEW_SLICE";
+    public static final String EXTRA_SLICE = "slice";
 
     @Override
     protected void onCreate(Bundle savedInstanceState) {
@@ -39,7 +41,14 @@
         }
         try {
             Intent intent = parse(uri, getPackageName());
-            startActivity(intent);
+            if (ACTION_VIEW_SLICE.equals(intent.getAction())) {
+                // This shouldn't matter since the slice is shown instead of the device
+                // index caring about the launch uri.
+                Uri slice = Uri.parse(intent.getStringExtra(EXTRA_SLICE));
+                Log.e(TAG, "Slice intent launched: " + slice);
+            } else {
+                startActivity(intent);
+            }
             finish();
         } catch (URISyntaxException e) {
             Log.e(TAG, "Error decoding uri", e);
diff --git a/src/com/android/settings/slices/SlicesDatabaseAccessor.java b/src/com/android/settings/slices/SlicesDatabaseAccessor.java
index b095733..b14a716 100644
--- a/src/com/android/settings/slices/SlicesDatabaseAccessor.java
+++ b/src/com/android/settings/slices/SlicesDatabaseAccessor.java
@@ -89,6 +89,7 @@
      * @return a list of keys in the Slices database matching on {@param isPlatformSlice}.
      */
     public List<String> getSliceKeys(boolean isPlatformSlice) {
+        verifyIndexing();
         final String whereClause;
 
         if (isPlatformSlice) {
diff --git a/src/com/android/settings/widget/DonutView.java b/src/com/android/settings/widget/DonutView.java
index c5ac40b..00e7345 100644
--- a/src/com/android/settings/widget/DonutView.java
+++ b/src/com/android/settings/widget/DonutView.java
@@ -205,6 +205,8 @@
                             .getDimension(
                                     R.dimen.storage_donut_view_shrunken_label_text_size));
         }
+        setContentDescription(getContext().getString(
+                R.string.join_many_items_middle, mPercentString, mFullString));
         invalidate();
     }
 
diff --git a/src/com/android/settings/widget/SeekBarPreference.java b/src/com/android/settings/widget/SeekBarPreference.java
index 1ad4a20..85e0896 100644
--- a/src/com/android/settings/widget/SeekBarPreference.java
+++ b/src/com/android/settings/widget/SeekBarPreference.java
@@ -26,6 +26,7 @@
 import android.util.AttributeSet;
 import android.view.KeyEvent;
 import android.view.View;
+import android.view.accessibility.AccessibilityNodeInfo;
 import android.widget.SeekBar;
 import android.widget.SeekBar.OnSeekBarChangeListener;
 
@@ -48,6 +49,8 @@
 
     private SeekBar mSeekBar;
     private boolean mShouldBlink;
+    private int mAccessibilityRangeInfoType = AccessibilityNodeInfo.RangeInfo.RANGE_TYPE_INT;
+    private CharSequence mSeekBarContentDescription;
 
     public SeekBarPreference(
             Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
@@ -100,7 +103,9 @@
         mSeekBar.setProgress(mProgress);
         mSeekBar.setEnabled(isEnabled());
         final CharSequence title = getTitle();
-        if (!TextUtils.isEmpty(title)) {
+        if (!TextUtils.isEmpty(mSeekBarContentDescription)) {
+            mSeekBar.setContentDescription(mSeekBarContentDescription);
+        } else if (!TextUtils.isEmpty(title)) {
             mSeekBar.setContentDescription(title);
         }
         if (mSeekBar instanceof DefaultIndicatorSeekBar) {
@@ -119,6 +124,19 @@
                 mShouldBlink = false;
             });
         }
+        mSeekBar.setAccessibilityDelegate(new View.AccessibilityDelegate() {
+            @Override
+            public void onInitializeAccessibilityNodeInfo(View view, AccessibilityNodeInfo info) {
+                super.onInitializeAccessibilityNodeInfo(view, info);
+                // Update the range info with the correct type
+                AccessibilityNodeInfo.RangeInfo rangeInfo = info.getRangeInfo();
+                if (rangeInfo != null) {
+                    info.setRangeInfo(AccessibilityNodeInfo.RangeInfo.obtain(
+                                    mAccessibilityRangeInfoType, rangeInfo.getMin(),
+                                    rangeInfo.getMax(), rangeInfo.getCurrent()));
+                }
+            }
+        });
     }
 
     @Override
@@ -252,6 +270,24 @@
         }
     }
 
+    /**
+     * Specify the type of range this seek bar represents.
+     *
+     * @param rangeInfoType The type of range to be shared with accessibility
+     *
+     * @see android.view.accessibility.AccessibilityNodeInfo.RangeInfo
+     */
+    public void setAccessibilityRangeInfoType(int rangeInfoType) {
+        mAccessibilityRangeInfoType = rangeInfoType;
+    }
+
+    public void setSeekBarContentDescription(CharSequence contentDescription) {
+        mSeekBarContentDescription = contentDescription;
+        if (mSeekBar != null) {
+            mSeekBar.setContentDescription(contentDescription);
+        }
+    }
+
     @Override
     protected Parcelable onSaveInstanceState() {
         /*
diff --git a/src/com/android/settings/wifi/AppStateChangeWifiStateBridge.java b/src/com/android/settings/wifi/AppStateChangeWifiStateBridge.java
index 23d6b67..c643b8c 100644
--- a/src/com/android/settings/wifi/AppStateChangeWifiStateBridge.java
+++ b/src/com/android/settings/wifi/AppStateChangeWifiStateBridge.java
@@ -20,6 +20,7 @@
 import android.app.AppOpsManager;
 import android.content.Context;
 
+import com.android.internal.util.ArrayUtils;
 import com.android.settings.applications.AppStateAppOpsBridge;
 import com.android.settings.applications.AppStateAppOpsBridge.PermissionState;
 import com.android.settingslib.applications.ApplicationsState;
@@ -37,6 +38,7 @@
     private static final String TAG = "AppStateChangeWifiStateBridge";
     private static final int APP_OPS_OP_CODE = AppOpsManager.OP_CHANGE_WIFI_STATE;
     private static final String PM_CHANGE_WIFI_STATE = Manifest.permission.CHANGE_WIFI_STATE;
+    private static final String PM_NETWORK_SETTINGS = Manifest.permission.NETWORK_SETTINGS;
 
     private static final String[] PM_PERMISSIONS = {
             PM_CHANGE_WIFI_STATE
@@ -86,6 +88,17 @@
                 return false;
             }
             WifiSettingsState wifiSettingsState = (WifiSettingsState) info.extraInfo;
+            if (wifiSettingsState.packageInfo != null) {
+                final String[] requestedPermissions
+                        = wifiSettingsState.packageInfo.requestedPermissions;
+                if (ArrayUtils.contains(requestedPermissions, PM_NETWORK_SETTINGS)) {
+                    /*
+                     * NETWORK_SETTINGS permission trumps CHANGE_WIFI_CONFIG, so remove this from
+                     * the list.
+                    */
+                    return false;
+                }
+            }
             return wifiSettingsState.permissionDeclared;
         }
     };
diff --git a/src/com/android/settings/wifi/tether/WifiTetherSwitchBarController.java b/src/com/android/settings/wifi/tether/WifiTetherSwitchBarController.java
index bf203e6..f710613 100644
--- a/src/com/android/settings/wifi/tether/WifiTetherSwitchBarController.java
+++ b/src/com/android/settings/wifi/tether/WifiTetherSwitchBarController.java
@@ -91,10 +91,10 @@
 
     @Override
     public boolean onSwitchToggled(boolean isChecked) {
-        if (isChecked) {
-            startTether();
-        } else {
+        if (!isChecked) {
             stopTether();
+        } else if (!mWifiManager.isWifiApEnabled()) {
+            startTether();
         }
         return true;
     }
diff --git a/tests/robotests/src/com/android/settings/connecteddevice/ConnectedDeviceDashboardFragmentTest.java b/tests/robotests/src/com/android/settings/connecteddevice/ConnectedDeviceDashboardFragmentTest.java
index 0230540..9064179 100644
--- a/tests/robotests/src/com/android/settings/connecteddevice/ConnectedDeviceDashboardFragmentTest.java
+++ b/tests/robotests/src/com/android/settings/connecteddevice/ConnectedDeviceDashboardFragmentTest.java
@@ -78,7 +78,6 @@
         final List<String> niks = ConnectedDeviceDashboardFragment.SEARCH_INDEX_DATA_PROVIDER
                 .getNonIndexableKeys(mContext);
 
-        assertThat(niks).containsExactly(KEY_CONNECTED_DEVICES, KEY_AVAILABLE_DEVICES,
-                NfcPreferenceController.KEY_TOGGLE_NFC);
+        assertThat(niks).containsExactly(KEY_CONNECTED_DEVICES, KEY_AVAILABLE_DEVICES);
     }
 }
diff --git a/tests/robotests/src/com/android/settings/connecteddevice/ConnectedDeviceGroupControllerTest.java b/tests/robotests/src/com/android/settings/connecteddevice/ConnectedDeviceGroupControllerTest.java
index e3e11bc..3039895 100644
--- a/tests/robotests/src/com/android/settings/connecteddevice/ConnectedDeviceGroupControllerTest.java
+++ b/tests/robotests/src/com/android/settings/connecteddevice/ConnectedDeviceGroupControllerTest.java
@@ -19,6 +19,7 @@
 import static com.android.settings.core.BasePreferenceController.DISABLED_UNSUPPORTED;
 
 import static com.google.common.truth.Truth.assertThat;
+
 import static org.mockito.Matchers.anyString;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.spy;
@@ -34,6 +35,7 @@
 import android.support.v7.preference.PreferenceScreen;
 
 import com.android.settings.bluetooth.ConnectedBluetoothDeviceUpdater;
+import com.android.settings.connecteddevice.dock.DockUpdater;
 import com.android.settings.connecteddevice.usb.ConnectedUsbDeviceUpdater;
 import com.android.settings.dashboard.DashboardFragment;
 import com.android.settings.testutils.SettingsRobolectricTestRunner;
@@ -63,6 +65,8 @@
     @Mock
     private ConnectedUsbDeviceUpdater mConnectedUsbDeviceUpdater;
     @Mock
+    private DockUpdater mConnectedDockUpdater;
+    @Mock
     private PreferenceScreen mPreferenceScreen;
     @Mock(answer = Answers.RETURNS_DEEP_STUBS)
     private PreferenceManager mPreferenceManager;
@@ -87,8 +91,8 @@
         doReturn(mContext).when(mDashboardFragment).getContext();
 
         mConnectedDeviceGroupController = new ConnectedDeviceGroupController(mContext);
-        mConnectedDeviceGroupController
-                .init(mConnectedBluetoothDeviceUpdater, mConnectedUsbDeviceUpdater);
+        mConnectedDeviceGroupController.init(mConnectedBluetoothDeviceUpdater,
+                mConnectedUsbDeviceUpdater, mConnectedDockUpdater);
         mConnectedDeviceGroupController.mPreferenceGroup = mPreferenceGroup;
     }
 
@@ -136,6 +140,7 @@
         mConnectedDeviceGroupController.onStart();
         verify(mConnectedBluetoothDeviceUpdater).registerCallback();
         verify(mConnectedUsbDeviceUpdater).registerCallback();
+        verify(mConnectedDockUpdater).registerCallback();
     }
 
     @Test
@@ -144,6 +149,7 @@
         mConnectedDeviceGroupController.onStop();
         verify(mConnectedBluetoothDeviceUpdater).unregisterCallback();
         verify(mConnectedUsbDeviceUpdater).unregisterCallback();
+        verify(mConnectedDockUpdater).unregisterCallback();
     }
 
     @Test
diff --git a/tests/robotests/src/com/android/settings/connecteddevice/SavedDeviceGroupControllerTest.java b/tests/robotests/src/com/android/settings/connecteddevice/SavedDeviceGroupControllerTest.java
index 1b1b88d..71c1010 100644
--- a/tests/robotests/src/com/android/settings/connecteddevice/SavedDeviceGroupControllerTest.java
+++ b/tests/robotests/src/com/android/settings/connecteddevice/SavedDeviceGroupControllerTest.java
@@ -27,6 +27,7 @@
 import android.content.pm.PackageManager;
 import android.support.v7.preference.PreferenceManager;
 import com.android.settings.bluetooth.BluetoothDeviceUpdater;
+import com.android.settings.connecteddevice.dock.DockUpdater;
 import com.android.settings.dashboard.DashboardFragment;
 import com.android.settings.testutils.SettingsRobolectricTestRunner;
 import com.android.settingslib.core.lifecycle.Lifecycle;
@@ -47,6 +48,8 @@
     private DashboardFragment mDashboardFragment;
     @Mock
     private BluetoothDeviceUpdater mBluetoothDeviceUpdater;
+    @Mock
+    private DockUpdater mSavedDockUpdater;
     @Mock(answer = Answers.RETURNS_DEEP_STUBS)
     private PreferenceManager mPreferenceManager;
     @Mock
@@ -67,6 +70,7 @@
         doReturn(mPackageManager).when(mContext).getPackageManager();
         mSavedDeviceGroupController = new SavedDeviceGroupController(mContext);
         mSavedDeviceGroupController.setBluetoothDeviceUpdater(mBluetoothDeviceUpdater);
+        mSavedDeviceGroupController.setSavedDockUpdater(mSavedDockUpdater);
     }
 
     @Test
@@ -74,12 +78,14 @@
         // register the callback in onStart()
         mSavedDeviceGroupController.onStart();
         verify(mBluetoothDeviceUpdater).registerCallback();
+        verify(mSavedDockUpdater).registerCallback();
     }
     @Test
     public void testUnregister() {
         // unregister the callback in onStop()
         mSavedDeviceGroupController.onStop();
         verify(mBluetoothDeviceUpdater).unregisterCallback();
+        verify(mSavedDockUpdater).unregisterCallback();
     }
     @Test
     public void testGetAvailabilityStatus_noBluetoothFeature_returnUnSupported() {
@@ -93,4 +99,4 @@
         assertThat(mSavedDeviceGroupController.getAvailabilityStatus()).isEqualTo(
                 AVAILABLE);
     }
-}
\ No newline at end of file
+}
diff --git a/tests/robotests/src/com/android/settings/datausage/DataUsageSummaryPreferenceTest.java b/tests/robotests/src/com/android/settings/datausage/DataUsageSummaryPreferenceTest.java
index 876f5d1..c666d4e 100644
--- a/tests/robotests/src/com/android/settings/datausage/DataUsageSummaryPreferenceTest.java
+++ b/tests/robotests/src/com/android/settings/datausage/DataUsageSummaryPreferenceTest.java
@@ -17,6 +17,10 @@
 package com.android.settings.datausage;
 
 import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
 
 import android.app.Activity;
 import android.content.ComponentName;
@@ -82,13 +86,13 @@
     @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
-        mContext = RuntimeEnvironment.application;
+        mContext = spy(RuntimeEnvironment.application);
         mSummaryPreference = new DataUsageSummaryPreference(mContext, null /* attrs */);
         LayoutInflater inflater = LayoutInflater.from(mContext);
         View view = inflater.inflate(mSummaryPreference.getLayoutResource(), null /* root */,
                 false /* attachToRoot */);
 
-        mHolder = PreferenceViewHolder.createInstanceForTests(view);
+        mHolder = spy(PreferenceViewHolder.createInstanceForTests(view));
 
         final long now = System.currentTimeMillis();
         mCycleEnd = now + CYCLE_DURATION_MILLIS;
@@ -369,6 +373,7 @@
         bindViewHolder();
         assertThat(mDataUsed.getText().toString()).isEqualTo("1.00 MB used");
         assertThat(mDataRemaining.getText().toString()).isEqualTo("9.00 MB left");
+        assertThat(mDataRemaining.getVisibility()).isEqualTo(View.VISIBLE);
         final int colorId = Utils.getColorAttr(mContext, android.R.attr.colorAccent);
         assertThat(mDataRemaining.getCurrentTextColor()).isEqualTo(colorId);
     }
@@ -427,6 +432,46 @@
     }
 
     @Test
+    public void testSetUsageInfo_withOverflowStrings_dataRemainingNotShown() {
+        LayoutInflater inflater = LayoutInflater.from(mContext);
+        View view = inflater.inflate(mSummaryPreference.getLayoutResource(), null /* root */,
+                false /* attachToRoot */);
+
+        TextView dataUsed = spy(new TextView(mContext));
+        TextView dataRemaining = spy(new TextView(mContext));
+        doReturn(dataUsed).when(mHolder).findViewById(R.id.data_usage_view);
+        doReturn(dataRemaining).when(mHolder).findViewById(R.id.data_remaining_view);
+
+        mSummaryPreference.setUsageInfo(mCycleEnd, mUpdateTime, DUMMY_CARRIER, 1 /* numPlans */,
+                new Intent());
+        mSummaryPreference.setUsageNumbers(
+                BillingCycleSettings.MIB_IN_BYTES,
+                10 * BillingCycleSettings.MIB_IN_BYTES,
+                true /* hasMobileData */);
+
+        when(mContext.getResources()).thenCallRealMethod();
+        when(mContext.getText(R.string.data_used_formatted))
+                .thenReturn("^1 ^2 used with long trailing text");
+        when(mContext.getText(R.string.data_remaining)).thenReturn("^1 left");
+
+        bindViewHolder();
+
+        doReturn(500).when(dataUsed).getMeasuredWidth();
+        doReturn(500).when(dataRemaining).getMeasuredWidth();
+
+        assertThat(dataRemaining.getVisibility()).isEqualTo(View.VISIBLE);
+
+        MeasurableLinearLayout layout =
+                (MeasurableLinearLayout) mHolder.findViewById(R.id.usage_layout);
+        layout.measure(
+                View.MeasureSpec.makeMeasureSpec(800, View.MeasureSpec.EXACTLY),
+                View.MeasureSpec.makeMeasureSpec(1000, View.MeasureSpec.EXACTLY));
+
+        assertThat(dataUsed.getText().toString()).isEqualTo("1.00 MB used with long trailing text");
+        assertThat(dataRemaining.getVisibility()).isEqualTo(View.GONE);
+    }
+
+    @Test
     public void testSetWifiMode_withUsageInfo_dataUsageShown() {
         final int daysLeft = 3;
         final long cycleEnd = System.currentTimeMillis() + TimeUnit.DAYS.toMillis(daysLeft)
@@ -474,8 +519,8 @@
         mCycleTime = (TextView) mHolder.findViewById(R.id.cycle_left_time);
         mCarrierInfo = (TextView) mHolder.findViewById(R.id.carrier_and_update);
         mDataLimits = (TextView) mHolder.findViewById(R.id.data_limits);
-        mDataUsed = (TextView) mHolder.findViewById(R.id.data_usage_view);
-        mDataRemaining = (TextView) mHolder.findViewById(R.id.data_remaining_view);
+        mDataUsed = spy((TextView) mHolder.findViewById(R.id.data_usage_view));
+        mDataRemaining = spy((TextView) mHolder.findViewById(R.id.data_remaining_view));
         mLaunchButton = (Button) mHolder.findViewById(R.id.launch_mdp_app_button);
         mLabelBar = (LinearLayout) mHolder.findViewById(R.id.label_bar);
         mLabel1 = (TextView) mHolder.findViewById(R.id.text1);
diff --git a/tests/robotests/src/com/android/settings/display/BrightnessLevelPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/display/BrightnessLevelPreferenceControllerTest.java
index adc3b66..e29ded0 100644
--- a/tests/robotests/src/com/android/settings/display/BrightnessLevelPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/display/BrightnessLevelPreferenceControllerTest.java
@@ -122,7 +122,7 @@
 
         mController.updateState(mPreference);
 
-        verify(mPreference).setSummary("85%");
+        verify(mPreference).setSummary("97%");
     }
 
     @Test
@@ -135,7 +135,7 @@
 
         mController.updateState(mPreference);
 
-        verify(mPreference).setSummary("31%");
+        verify(mPreference).setSummary("78%");
     }
 
     @Test
@@ -148,7 +148,7 @@
 
         mController.updateState(mPreference);
 
-        verify(mPreference).setSummary("45%");
+        verify(mPreference).setSummary("85%");
     }
 
     @Test
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/SmartBatteryPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/fuelgauge/SmartBatteryPreferenceControllerTest.java
index fbbc6f9..b91c5e1 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/SmartBatteryPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/SmartBatteryPreferenceControllerTest.java
@@ -107,10 +107,12 @@
     }
 
     private void putSmartBatteryValue(int value) {
-        Settings.Global.putInt(mContentResolver, Settings.Global.APP_STANDBY_ENABLED, value);
+        Settings.Global.putInt(mContentResolver,
+                Settings.Global.ADAPTIVE_BATTERY_MANAGEMENT_ENABLED, value);
     }
 
     private int getSmartBatteryValue() {
-        return Settings.Global.getInt(mContentResolver, Settings.Global.APP_STANDBY_ENABLED, ON);
+        return Settings.Global.getInt(mContentResolver,
+                Settings.Global.ADAPTIVE_BATTERY_MANAGEMENT_ENABLED, ON);
     }
 }
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/BatteryManagerPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/BatteryManagerPreferenceControllerTest.java
index 37c8306..27c3e3a 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/BatteryManagerPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/BatteryManagerPreferenceControllerTest.java
@@ -71,8 +71,8 @@
     @Test
     public void updateState_smartBatteryOnWithoutRestriction_showSummary() {
         when(mFeatureFactory.powerUsageFeatureProvider.isSmartBatterySupported()).thenReturn(true);
-        Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.APP_STANDBY_ENABLED,
-                ON);
+        Settings.Global.putInt(mContext.getContentResolver(),
+                Settings.Global.ADAPTIVE_BATTERY_MANAGEMENT_ENABLED, ON);
 
         mController.updateState(mPreference);
 
@@ -82,8 +82,8 @@
     @Test
     public void updateState_smartBatteryOff_showSummary() {
         when(mFeatureFactory.powerUsageFeatureProvider.isSmartBatterySupported()).thenReturn(true);
-        Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.APP_STANDBY_ENABLED,
-                OFF);
+        Settings.Global.putInt(mContext.getContentResolver(),
+                Settings.Global.ADAPTIVE_BATTERY_MANAGEMENT_ENABLED, OFF);
 
         mController.updateState(mPreference);
 
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/detectors/HighUsageDetectorTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/detectors/HighUsageDetectorTest.java
index 2a2420d..d00cf87 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/detectors/HighUsageDetectorTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/detectors/HighUsageDetectorTest.java
@@ -30,6 +30,7 @@
 
 import com.android.internal.os.BatterySipper;
 import com.android.internal.os.BatteryStatsHelper;
+import com.android.settings.fuelgauge.BatteryInfo;
 import com.android.settings.fuelgauge.BatteryUtils;
 import com.android.settings.fuelgauge.batterytip.AppInfo;
 import com.android.settings.fuelgauge.batterytip.BatteryTipPolicy;
@@ -77,7 +78,8 @@
 
         mContext = RuntimeEnvironment.application;
         mPolicy = spy(new BatteryTipPolicy(mContext));
-        mHighUsageDetector = spy(new HighUsageDetector(mContext, mPolicy, mBatteryStatsHelper));
+        mHighUsageDetector = spy(new HighUsageDetector(mContext, mPolicy, mBatteryStatsHelper,
+                true /* mDischarging */));
         mHighUsageDetector.mBatteryUtils = mBatteryUtils;
         mHighUsageDetector.mDataParser = mDataParser;
         doNothing().when(mHighUsageDetector).parseBatteryData();
@@ -110,6 +112,15 @@
     }
 
     @Test
+    public void testDetect_deviceCharging_tipInvisible() {
+        ReflectionHelpers.setField(mPolicy, "highUsageEnabled", true);
+        doReturn(true).when(mDataParser).isDeviceHeavilyUsed();
+        mHighUsageDetector.mDischarging = false;
+
+        assertThat(mHighUsageDetector.detect().isVisible()).isFalse();
+    }
+
+    @Test
     public void testDetect_testFeatureOn_tipNew() {
         doReturn(false).when(mDataParser).isDeviceHeavilyUsed();
         ReflectionHelpers.setField(mPolicy, "testHighUsageTip", true);
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/detectors/SmartBatteryDetectorTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/detectors/SmartBatteryDetectorTest.java
index ad08a22..42d8822 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/detectors/SmartBatteryDetectorTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/detectors/SmartBatteryDetectorTest.java
@@ -61,14 +61,16 @@
 
     @Test
     public void testDetect_smartBatteryOff_tipVisible() {
-        Settings.Global.putInt(mContentResolver, Settings.Global.APP_STANDBY_ENABLED, 0);
+        Settings.Global.putInt(mContentResolver,
+                Settings.Global.ADAPTIVE_BATTERY_MANAGEMENT_ENABLED, 0);
 
         assertThat(mSmartBatteryDetector.detect().isVisible()).isTrue();
     }
 
     @Test
     public void testDetect_smartBatteryOn_tipInvisible() {
-        Settings.Global.putInt(mContentResolver, Settings.Global.APP_STANDBY_ENABLED, 1);
+        Settings.Global.putInt(mContentResolver,
+                Settings.Global.ADAPTIVE_BATTERY_MANAGEMENT_ENABLED, 1);
 
         assertThat(mSmartBatteryDetector.detect().isVisible()).isFalse();
     }
diff --git a/tests/robotests/src/com/android/settings/inputmethod/GameControllerPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/inputmethod/GameControllerPreferenceControllerTest.java
index bc4eca8..61283fa 100644
--- a/tests/robotests/src/com/android/settings/inputmethod/GameControllerPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/inputmethod/GameControllerPreferenceControllerTest.java
@@ -16,6 +16,8 @@
 
 package com.android.settings.inputmethod;
 
+import static com.android.settings.core.BasePreferenceController.AVAILABLE;
+import static com.android.settings.core.BasePreferenceController.DISABLED_UNSUPPORTED;
 import static com.google.common.truth.Truth.assertThat;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.spy;
@@ -37,10 +39,6 @@
 import org.robolectric.RuntimeEnvironment;
 import org.robolectric.annotation.Config;
 
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-
 @RunWith(SettingsRobolectricTestRunner.class)
 public class GameControllerPreferenceControllerTest {
 
@@ -57,7 +55,7 @@
         MockitoAnnotations.initMocks(this);
         mContext = spy(RuntimeEnvironment.application);
         when(mContext.getSystemService(Context.INPUT_SERVICE)).thenReturn(mInputManager);
-        mController = new GameControllerPreferenceController(mContext);
+        mController = new GameControllerPreferenceController(mContext, "test_key");
     }
 
     @Test
@@ -75,59 +73,59 @@
     }
 
     @Test
-    public void testIsAvailable_hasDeviceWithVibrator_shouldReturnTrue() {
-        when(mInputManager.getInputDeviceIds()).thenReturn(new int[]{1});
+    public void getAvailabilityStatus_hasDeviceWithVibrator_shouldReturnAvailable() {
+        when(mInputManager.getInputDeviceIds()).thenReturn(new int[] {1});
         when(mInputManager.getInputDevice(1)).thenReturn(mInputDevice);
         when(mInputDevice.isVirtual()).thenReturn(false);
         when(mInputDevice.getVibrator().hasVibrator()).thenReturn(true);
 
-        assertThat(mController.isAvailable()).isTrue();
+        assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE);
     }
 
     @Test
-    public void testIsAvailable_hasNoVibratingDevice_shouldReturnFalse() {
-        when(mInputManager.getInputDeviceIds()).thenReturn(new int[]{1});
+    public void getAvailabilityStatus_hasNoVibratingDevice_shouldReturnDisabled() {
+        when(mInputManager.getInputDeviceIds()).thenReturn(new int[] {1});
         when(mInputManager.getInputDevice(1)).thenReturn(mInputDevice);
         when(mInputDevice.isVirtual()).thenReturn(false);
         when(mInputDevice.getVibrator().hasVibrator()).thenReturn(false);
 
-        assertThat(mController.isAvailable()).isFalse();
+        assertThat(mController.getAvailabilityStatus()).isEqualTo(DISABLED_UNSUPPORTED);
     }
 
     @Test
-    public void testIsAvailable_hasNoPhysicalDevice_shouldReturnFalse() {
-        when(mInputManager.getInputDeviceIds()).thenReturn(new int[]{1});
+    public void getAvailabilityStatus_hasNoPhysicalDevice_shouldReturnDisabled() {
+        when(mInputManager.getInputDeviceIds()).thenReturn(new int[] {1});
         when(mInputManager.getInputDevice(1)).thenReturn(mInputDevice);
         when(mInputDevice.isVirtual()).thenReturn(true);
 
-        assertThat(mController.isAvailable()).isFalse();
+        assertThat(mController.getAvailabilityStatus()).isEqualTo(DISABLED_UNSUPPORTED);
     }
 
     @Test
-    public void testIsAvailable_hasNoDevice_shouldReturnFalse() {
-        when(mInputManager.getInputDeviceIds()).thenReturn(new int[]{});
+    public void getAvailabilityStatus_hasNoDevice_shouldReturnDisabled() {
+        when(mInputManager.getInputDeviceIds()).thenReturn(new int[] {});
 
-        assertThat(mController.isAvailable()).isFalse();
+        assertThat(mController.getAvailabilityStatus()).isEqualTo(DISABLED_UNSUPPORTED);
     }
 
     @Test
     @Config(qualifiers = "mcc999")
-    public void testIsAvailable_ifDisabled_shouldReturnFalse() {
-        mController = new GameControllerPreferenceController(mContext);
+    public void getAvailabilityStatus_ifDisabled_shouldReturnDisabled() {
+        mController = new GameControllerPreferenceController(mContext, "testkey");
 
-        assertThat(mController.isAvailable()).isFalse();
+        assertThat(mController.getAvailabilityStatus()).isEqualTo(DISABLED_UNSUPPORTED);
     }
 
     @Test
-    public void updateNonIndexableKeys_shouldIncludeCategoryAndPrefKeys() {
-        when(mInputManager.getInputDeviceIds()).thenReturn(new int[]{});
+    public void setChecked_toEnabled_shouldSetToSettingsProvider() {
+        mController.setChecked(true);
+        assertThat(mController.isChecked()).isTrue();
+    }
 
-        final List<String> nonIndexables = new ArrayList<>();
-        mController.updateNonIndexableKeys(nonIndexables);
-
-        assertThat(mController.isAvailable()).isFalse();
-        assertThat(nonIndexables).containsExactlyElementsIn(Arrays.asList(
-                GameControllerPreferenceController.PREF_KEY,
-                mController.getPreferenceKey()));
+    @Test
+    public void setChecked_toDisabled_shouldSetToSettingsProvider() {
+        mController.setChecked(true);
+        mController.setChecked(false);
+        assertThat(mController.isChecked()).isFalse();
     }
 }
diff --git a/tests/robotests/src/com/android/settings/nfc/AndroidBeamPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/nfc/AndroidBeamPreferenceControllerTest.java
index cb18b5a..df5bb64 100644
--- a/tests/robotests/src/com/android/settings/nfc/AndroidBeamPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/nfc/AndroidBeamPreferenceControllerTest.java
@@ -41,6 +41,9 @@
 import org.robolectric.RuntimeEnvironment;
 import org.robolectric.util.ReflectionHelpers;
 
+import java.util.ArrayList;
+import java.util.List;
+
 @RunWith(SettingsRobolectricTestRunner.class)
 public class AndroidBeamPreferenceControllerTest {
 
@@ -132,4 +135,24 @@
         mAndroidBeamController.onResume();
         assertThat(mAndroidBeamPreference.isEnabled()).isFalse();
     }
+
+    @Test
+    public void updateNonIndexableKeys_available_shouldNotUpdate() {
+        when(mNfcAdapter.isEnabled()).thenReturn(true);
+        final List<String> keys = new ArrayList<>();
+
+        mAndroidBeamController.updateNonIndexableKeys(keys);
+
+        assertThat(keys).isEmpty();
+    }
+
+    @Test
+    public void updateNonIndexableKeys_notAvailable_shouldUpdate() {
+        ReflectionHelpers.setField(mAndroidBeamController, "mNfcAdapter", null);
+        final List<String> keys = new ArrayList<>();
+
+        mAndroidBeamController.updateNonIndexableKeys(keys);
+
+        assertThat(keys).hasSize(1);
+    }
 }
diff --git a/tests/robotests/src/com/android/settings/nfc/NfcPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/nfc/NfcPreferenceControllerTest.java
index cd90820..802e199 100644
--- a/tests/robotests/src/com/android/settings/nfc/NfcPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/nfc/NfcPreferenceControllerTest.java
@@ -39,6 +39,9 @@
 import org.robolectric.RuntimeEnvironment;
 import org.robolectric.util.ReflectionHelpers;
 
+import java.util.ArrayList;
+import java.util.List;
+
 @RunWith(SettingsRobolectricTestRunner.class)
 public class NfcPreferenceControllerTest {
 
@@ -134,4 +137,24 @@
         mNfcController.onResume();
         assertThat(mNfcPreference.isChecked()).isFalse();
     }
+
+    @Test
+    public void updateNonIndexableKeys_available_shouldNotUpdate() {
+        when(mNfcAdapter.isEnabled()).thenReturn(true);
+        final List<String> keys = new ArrayList<>();
+
+        mNfcController.updateNonIndexableKeys(keys);
+
+        assertThat(keys).isEmpty();
+    }
+
+    @Test
+    public void updateNonIndexableKeys_notAvailable_shouldUpdate() {
+        ReflectionHelpers.setField(mNfcController, "mNfcAdapter", null);
+        final List<String> keys = new ArrayList<>();
+
+        mNfcController.updateNonIndexableKeys(keys);
+
+        assertThat(keys).hasSize(1);
+    }
 }
diff --git a/tests/robotests/src/com/android/settings/password/ChooseLockSettingsHelperTest.java b/tests/robotests/src/com/android/settings/password/ChooseLockSettingsHelperTest.java
index bcb154c..2a8c406 100644
--- a/tests/robotests/src/com/android/settings/password/ChooseLockSettingsHelperTest.java
+++ b/tests/robotests/src/com/android/settings/password/ChooseLockSettingsHelperTest.java
@@ -65,7 +65,7 @@
                 ConfirmDeviceCredentialBaseFragment.ALLOW_FP_AUTHENTICATION, false));
         assertFalse(startedIntent.getBooleanExtra(
                 ConfirmDeviceCredentialBaseFragment.DARK_THEME, false));
-        assertEquals(true, startedIntent.getBooleanExtra(
+        assertFalse(startedIntent.getBooleanExtra(
                 ConfirmDeviceCredentialBaseFragment.SHOW_CANCEL_BUTTON, false));
         assertEquals(true, startedIntent.getBooleanExtra(
                 ConfirmDeviceCredentialBaseFragment.SHOW_WHEN_LOCKED, false));
@@ -103,7 +103,7 @@
                 ConfirmDeviceCredentialBaseFragment.ALLOW_FP_AUTHENTICATION, false));
         assertFalse(startedIntent.getBooleanExtra(
                 ConfirmDeviceCredentialBaseFragment.DARK_THEME, false));
-        assertEquals(false, startedIntent.getBooleanExtra(
+        assertFalse(startedIntent.getBooleanExtra(
                 ConfirmDeviceCredentialBaseFragment.SHOW_CANCEL_BUTTON, false));
         assertEquals(false, startedIntent.getBooleanExtra(
                 ConfirmDeviceCredentialBaseFragment.SHOW_WHEN_LOCKED, false));
diff --git a/tests/robotests/src/com/android/settings/search/DeviceIndexFeatureProviderTest.java b/tests/robotests/src/com/android/settings/search/DeviceIndexFeatureProviderTest.java
index 25acc63..26c2830 100644
--- a/tests/robotests/src/com/android/settings/search/DeviceIndexFeatureProviderTest.java
+++ b/tests/robotests/src/com/android/settings/search/DeviceIndexFeatureProviderTest.java
@@ -16,12 +16,14 @@
 
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.Mockito.atLeastOnce;
+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.app.job.JobScheduler;
 
 import com.android.settings.testutils.FakeFeatureFactory;
 import com.android.settings.testutils.SettingsRobolectricTestRunner;
@@ -40,7 +42,7 @@
     @Before
     public void setUp() {
         FakeFeatureFactory.setupForTest();
-        mActivity = Robolectric.buildActivity(Activity.class).create().visible().get();
+        mActivity = spy(Robolectric.buildActivity(Activity.class).create().visible().get());
         mProvider = spy(new DeviceIndexFeatureProviderImpl());
     }
 
@@ -49,14 +51,16 @@
         when(mProvider.isIndexingEnabled()).thenReturn(false);
 
         mProvider.updateIndex(mActivity, false);
-        verify(mProvider, never()).index(any(), any(), any(), any());
+        verify(mProvider, never()).index(any(), any(), any(), any(), any());
     }
 
     @Test
     public void verifyIndexing() {
+        JobScheduler jobScheduler = mock(JobScheduler.class);
         when(mProvider.isIndexingEnabled()).thenReturn(true);
+        when(mActivity.getSystemService(JobScheduler.class)).thenReturn(jobScheduler);
 
         mProvider.updateIndex(mActivity, false);
-        verify(mProvider, atLeastOnce()).index(any(), any(), any(), any());
+        verify(jobScheduler).schedule(any());
     }
 }
diff --git a/tests/robotests/src/com/android/settings/search/DeviceIndexUpdateJobServiceTest.java b/tests/robotests/src/com/android/settings/search/DeviceIndexUpdateJobServiceTest.java
new file mode 100644
index 0000000..ec16893
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/search/DeviceIndexUpdateJobServiceTest.java
@@ -0,0 +1,146 @@
+/*
+ * 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.search;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.atLeast;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
+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.Activity;
+import android.content.ContentResolver;
+import android.net.Uri;
+
+import com.android.settings.slices.SettingsSliceProvider;
+import com.android.settings.testutils.FakeFeatureFactory;
+import com.android.settings.testutils.SettingsRobolectricTestRunner;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+import org.robolectric.Robolectric;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import androidx.slice.Slice;
+import androidx.slice.SliceManager;
+import androidx.slice.SliceMetadata;
+
+@RunWith(SettingsRobolectricTestRunner.class)
+public class DeviceIndexUpdateJobServiceTest {
+        private static final Uri BASE_URI = new Uri.Builder()
+                .scheme(ContentResolver.SCHEME_CONTENT)
+                .authority(SettingsSliceProvider.SLICE_AUTHORITY)
+                .build();
+
+    private Activity mActivity;
+    private DeviceIndexUpdateJobService mJob;
+    private SliceManager mSliceManager;
+
+    @Before
+    public void setup() {
+        FakeFeatureFactory.setupForTest();
+        mActivity = spy(Robolectric.buildActivity(Activity.class).create().visible().get());
+        mJob = spy(new DeviceIndexUpdateJobService());
+        mSliceManager = mock(SliceManager.class);
+
+        doReturn(mActivity.getPackageName()).when(mJob).getPackageName();
+        doReturn(mSliceManager).when(mJob).getSliceManager();
+        doNothing().when(mJob).jobFinished(null, false);
+    }
+
+    @Test
+    public void testGetsSlices() {
+        setSlices();
+
+        mJob.updateIndex(null);
+        verify(mSliceManager).getSliceDescendants(eq(BASE_URI));
+    }
+
+    @Test
+    public void testIndexesSlices() {
+        setSlices(genSlice("path1"), genSlice("path2"));
+
+        mJob.mRunningJob = true;
+        mJob.updateIndex(null);
+        verify(mSliceManager).getSliceDescendants(eq(BASE_URI));
+
+        DeviceIndexFeatureProvider indexFeatureProvider = FakeFeatureFactory.getFactory(mActivity)
+                .getDeviceIndexFeatureProvider();
+        verify(indexFeatureProvider, times(2)).index(any(), any(), any(), any(), any());
+    }
+
+    @Test
+    public void testDoNotIndexWithoutTitle() {
+        Slice testSlice = genSlice("path2");
+        setSlices(genSlice("path1"), testSlice);
+        doReturn(null).when(mJob).findTitle(testSlice, mJob.getMetadata(testSlice));
+
+        mJob.mRunningJob = true;
+        mJob.updateIndex(null);
+        verify(mSliceManager).getSliceDescendants(eq(BASE_URI));
+
+        DeviceIndexFeatureProvider indexFeatureProvider = FakeFeatureFactory.getFactory(mActivity)
+                .getDeviceIndexFeatureProvider();
+        verify(indexFeatureProvider, times(1)).index(any(), any(), any(), any(), any());
+    }
+
+    @Test
+    public void testStopIndexing() {
+        Slice testSlice = genSlice("path1");
+        setSlices(testSlice, genSlice("path2"));
+        mJob.mRunningJob = true;
+
+        doAnswer(invocation -> {
+            // Stop running after the first iteration
+            mJob.mRunningJob = false;
+            return testSlice;
+        }).when(mJob).bindSliceSynchronous(mSliceManager, testSlice.getUri());
+
+        mJob.updateIndex(null);
+        verify(mSliceManager).getSliceDescendants(eq(BASE_URI));
+
+        DeviceIndexFeatureProvider indexFeatureProvider = FakeFeatureFactory.getFactory(mActivity)
+                .getDeviceIndexFeatureProvider();
+        verify(indexFeatureProvider, times(1)).index(any(), any(), any(), any(), any());
+    }
+
+    private Slice genSlice(String path) {
+        return new Slice.Builder(BASE_URI.buildUpon().path(path).build()).build();
+    }
+
+    private void setSlices(Slice... slice) {
+        List<Uri> mUris = new ArrayList<>();
+        for (Slice slouse : slice) {
+            SliceMetadata m = mock(SliceMetadata.class);
+            mUris.add(slouse.getUri());
+            doReturn(slouse).when(mJob).bindSliceSynchronous(mSliceManager, slouse.getUri());
+            doReturn(m).when(mJob).getMetadata(slouse);
+            doReturn(slouse.getUri().getPath()).when(mJob).findTitle(slouse, m);
+        }
+        when(mSliceManager.getSliceDescendants(BASE_URI)).thenReturn(mUris);
+    }
+
+}
\ No newline at end of file
diff --git a/tests/robotests/src/com/android/settings/search/SearchIndexableResourcesTest.java b/tests/robotests/src/com/android/settings/search/SearchIndexableResourcesTest.java
index dcf68aa..eff95fe 100644
--- a/tests/robotests/src/com/android/settings/search/SearchIndexableResourcesTest.java
+++ b/tests/robotests/src/com/android/settings/search/SearchIndexableResourcesTest.java
@@ -27,6 +27,7 @@
 import android.text.TextUtils;
 
 import com.android.settings.testutils.FakeFeatureFactory;
+import com.android.settings.testutils.FakeIndexProvider;
 import com.android.settings.testutils.SettingsRobolectricTestRunner;
 import com.android.settings.wifi.WifiSettings;
 
diff --git a/tests/robotests/src/com/android/settings/slices/SettingsSliceProviderTest.java b/tests/robotests/src/com/android/settings/slices/SettingsSliceProviderTest.java
index b5399ea..0fda33e 100644
--- a/tests/robotests/src/com/android/settings/slices/SettingsSliceProviderTest.java
+++ b/tests/robotests/src/com/android/settings/slices/SettingsSliceProviderTest.java
@@ -21,9 +21,12 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.when;
 
+import android.app.slice.SliceManager;
 import android.content.ContentResolver;
 import android.content.ContentValues;
 import android.content.Context;
@@ -43,7 +46,9 @@
 
 import androidx.slice.Slice;
 
+import java.util.Arrays;
 import java.util.Collection;
+import java.util.Collections;
 import java.util.HashMap;
 
 /**
@@ -65,17 +70,22 @@
     private Context mContext;
     private SettingsSliceProvider mProvider;
     private SQLiteDatabase mDb;
+    private SliceManager mManager;
 
     @Before
     public void setUp() {
         mContext = spy(RuntimeEnvironment.application);
         mProvider = spy(new SettingsSliceProvider());
+        mProvider.mSliceWeakDataCache = new HashMap<>();
         mProvider.mSliceDataCache = new HashMap<>();
         mProvider.mSlicesDatabaseAccessor = new SlicesDatabaseAccessor(mContext);
         when(mProvider.getContext()).thenReturn(mContext);
 
         mDb = SlicesDatabaseHelper.getInstance(mContext).getWritableDatabase();
         SlicesDatabaseHelper.getInstance(mContext).setIndexedState();
+        mManager = mock(SliceManager.class);
+        when(mContext.getSystemService(SliceManager.class)).thenReturn(mManager);
+        when(mManager.getPinnedSlices()).thenReturn(Collections.emptyList());
     }
 
     @After
@@ -99,6 +109,30 @@
         Uri uri = SliceBuilderUtils.getUri(INTENT_PATH, false);
 
         mProvider.loadSlice(uri);
+        SliceData data = mProvider.mSliceWeakDataCache.get(uri);
+
+        assertThat(data.getKey()).isEqualTo(KEY);
+        assertThat(data.getTitle()).isEqualTo(TITLE);
+    }
+
+    @Test
+    public void testLoadSlice_doesntCacheWithoutPin() {
+        insertSpecialCase(KEY);
+        Uri uri = SliceBuilderUtils.getUri(INTENT_PATH, false);
+
+        mProvider.loadSlice(uri);
+        SliceData data = mProvider.mSliceDataCache.get(uri);
+
+        assertThat(data).isNull();
+    }
+
+    @Test
+    public void testLoadSlice_cachesWithPin() {
+        insertSpecialCase(KEY);
+        Uri uri = SliceBuilderUtils.getUri(INTENT_PATH, false);
+        when(mManager.getPinnedSlices()).thenReturn(Arrays.asList(uri));
+
+        mProvider.loadSlice(uri);
         SliceData data = mProvider.mSliceDataCache.get(uri);
 
         assertThat(data.getKey()).isEqualTo(KEY);
@@ -108,11 +142,23 @@
     @Test
     public void testLoadSlice_cachedEntryRemovedOnBuild() {
         SliceData data = getDummyData();
-        mProvider.mSliceDataCache.put(data.getUri(), data);
+        mProvider.mSliceWeakDataCache.put(data.getUri(), data);
         mProvider.onBindSlice(data.getUri());
         insertSpecialCase(data.getKey());
 
-        SliceData cachedData = mProvider.mSliceDataCache.get(data.getUri());
+        SliceData cachedData = mProvider.mSliceWeakDataCache.get(data.getUri());
+
+        assertThat(cachedData).isNull();
+    }
+
+    @Test
+    public void testLoadSlice_cachedEntryRemovedOnUnpin() {
+        SliceData data = getDummyData();
+        mProvider.mSliceDataCache.put(data.getUri(), data);
+        mProvider.onSliceUnpinned(data.getUri());
+        insertSpecialCase(data.getKey());
+
+        SliceData cachedData = mProvider.mSliceWeakDataCache.get(data.getUri());
 
         assertThat(cachedData).isNull();
     }
diff --git a/tests/robotests/src/com/android/settings/slices/SliceBroadcastReceiverTest.java b/tests/robotests/src/com/android/settings/slices/SliceBroadcastReceiverTest.java
index 0b6e4b5..c7bf043 100644
--- a/tests/robotests/src/com/android/settings/slices/SliceBroadcastReceiverTest.java
+++ b/tests/robotests/src/com/android/settings/slices/SliceBroadcastReceiverTest.java
@@ -31,7 +31,6 @@
 import android.content.ContentValues;
 import android.content.Context;
 import android.content.Intent;
-import android.database.ContentObserver;
 import android.database.sqlite.SQLiteDatabase;
 import android.net.Uri;
 import android.provider.Settings;
@@ -40,14 +39,13 @@
 
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.settings.core.BasePreferenceController;
-import com.android.settings.search.FakeIndexProvider;
+import com.android.settings.testutils.FakeIndexProvider;
 import com.android.settings.search.SearchFeatureProvider;
 import com.android.settings.search.SearchFeatureProviderImpl;
 import com.android.settings.testutils.DatabaseTestUtils;
 import com.android.settings.testutils.FakeFeatureFactory;
 import com.android.settings.testutils.FakeSliderController;
 import com.android.settings.testutils.FakeToggleController;
-import com.android.settings.testutils.FakeUnavailablePreferenceController;
 import com.android.settings.testutils.SettingsRobolectricTestRunner;
 
 import org.junit.After;
diff --git a/tests/robotests/src/com/android/settings/slices/SliceDataConverterTest.java b/tests/robotests/src/com/android/settings/slices/SliceDataConverterTest.java
index 2c87ac4..87ada36 100644
--- a/tests/robotests/src/com/android/settings/slices/SliceDataConverterTest.java
+++ b/tests/robotests/src/com/android/settings/slices/SliceDataConverterTest.java
@@ -33,7 +33,7 @@
 import com.android.settings.R;
 import com.android.settings.accessibility.AccessibilitySettings;
 import com.android.settings.accessibility.AccessibilitySlicePreferenceController;
-import com.android.settings.search.FakeIndexProvider;
+import com.android.settings.testutils.FakeIndexProvider;
 import com.android.settings.search.SearchFeatureProvider;
 import com.android.settings.search.SearchFeatureProviderImpl;
 import com.android.settings.testutils.FakeFeatureFactory;
diff --git a/tests/robotests/src/com/android/settings/slices/SlicesDatabaseAccessorTest.java b/tests/robotests/src/com/android/settings/slices/SlicesDatabaseAccessorTest.java
index 820f45c..1788d93 100644
--- a/tests/robotests/src/com/android/settings/slices/SlicesDatabaseAccessorTest.java
+++ b/tests/robotests/src/com/android/settings/slices/SlicesDatabaseAccessorTest.java
@@ -25,9 +25,13 @@
 import android.content.Context;
 import android.database.sqlite.SQLiteDatabase;
 import android.net.Uri;
+import android.view.accessibility.AccessibilityManager;
 
-import com.android.settings.search.FakeIndexProvider;
+import com.android.settings.testutils.FakeIndexProvider;
+import com.android.settings.search.SearchFeatureProvider;
+import com.android.settings.search.SearchFeatureProviderImpl;
 import com.android.settings.testutils.DatabaseTestUtils;
+import com.android.settings.testutils.FakeFeatureFactory;
 import com.android.settings.testutils.SettingsRobolectricTestRunner;
 
 import org.junit.After;
@@ -35,8 +39,15 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
+import org.robolectric.shadows.ShadowAccessibilityManager;
 
+import java.util.ArrayList;
 import java.util.List;
+import java.util.Locale;
+
+import org.robolectric.shadow.api.Shadow;
+
 
 @RunWith(SettingsRobolectricTestRunner.class)
 public class SlicesDatabaseAccessorTest {
@@ -157,6 +168,31 @@
         assertThat(keys).containsExactly(key);
     }
 
+    @Test
+    @Config(qualifiers = "mcc999")
+    public void getSliceKeys_indexesDatabase() {
+        // Force new indexing
+        Locale.setDefault(new Locale("ca"));
+        // Register the fake a11y Service
+        ShadowAccessibilityManager shadowAccessibilityManager = Shadow.extract(
+                RuntimeEnvironment.application.getSystemService(AccessibilityManager.class));
+        shadowAccessibilityManager.setInstalledAccessibilityServiceList(new ArrayList<>());
+        final SearchFeatureProvider provider = new SearchFeatureProviderImpl();
+        final SlicesFeatureProvider sliceProvider = spy(new SlicesFeatureProviderImpl());
+        final FakeFeatureFactory factory = FakeFeatureFactory.setupForTest();
+        factory.searchFeatureProvider = provider;
+        factory.slicesFeatureProvider = sliceProvider;
+        // Fake the indexable list.
+        provider.getSearchIndexableResources().getProviderValues().clear();
+        provider.getSearchIndexableResources().getProviderValues().add(
+                FakeIndexProvider.class);
+
+        final SlicesDatabaseAccessor accessor = new SlicesDatabaseAccessor(mContext);
+        final List<String> keys = accessor.getSliceKeys(true);
+
+        assertThat(keys).isNotEmpty();
+    }
+
     private void insertSpecialCase(String key) {
         insertSpecialCase(key, true);
     }
diff --git a/tests/robotests/src/com/android/settings/testutils/FakeFeatureFactory.java b/tests/robotests/src/com/android/settings/testutils/FakeFeatureFactory.java
index 8945af9..56df664 100644
--- a/tests/robotests/src/com/android/settings/testutils/FakeFeatureFactory.java
+++ b/tests/robotests/src/com/android/settings/testutils/FakeFeatureFactory.java
@@ -30,6 +30,7 @@
 import com.android.settings.fuelgauge.PowerUsageFeatureProvider;
 import com.android.settings.gestures.AssistGestureFeatureProvider;
 import com.android.settings.localepicker.LocaleFeatureProvider;
+import com.android.settings.overlay.DockUpdaterFeatureProvider;
 import com.android.settings.overlay.FeatureFactory;
 import com.android.settings.overlay.SupportFeatureProvider;
 import com.android.settings.overlay.SurveyFeatureProvider;
@@ -52,6 +53,7 @@
     public final MetricsFeatureProvider metricsFeatureProvider;
     public final PowerUsageFeatureProvider powerUsageFeatureProvider;
     public final DashboardFeatureProvider dashboardFeatureProvider;
+    public final DockUpdaterFeatureProvider dockUpdaterFeatureProvider;
     public final LocaleFeatureProvider localeFeatureProvider;
     public final ApplicationFeatureProvider applicationFeatureProvider;
     public final EnterprisePrivacyFeatureProvider enterprisePrivacyFeatureProvider;
@@ -61,11 +63,12 @@
     public final UserFeatureProvider userFeatureProvider;
     public final AssistGestureFeatureProvider assistGestureFeatureProvider;
     public final BluetoothFeatureProvider bluetoothFeatureProvider;
-    public final SlicesFeatureProvider slicesFeatureProvider;
-    public SearchFeatureProvider searchFeatureProvider;
     public final AccountFeatureProvider mAccountFeatureProvider;
     public final DeviceIndexFeatureProvider deviceIndexFeatureProvider;
 
+    public SlicesFeatureProvider slicesFeatureProvider;
+    public SearchFeatureProvider searchFeatureProvider;
+
     /**
      * Call this in {@code @Before} method of the test class to use fake factory.
      */
@@ -91,6 +94,7 @@
         metricsFeatureProvider = mock(MetricsFeatureProvider.class);
         powerUsageFeatureProvider = mock(PowerUsageFeatureProvider.class);
         dashboardFeatureProvider = mock(DashboardFeatureProvider.class);
+        dockUpdaterFeatureProvider = mock(DockUpdaterFeatureProvider.class);
         localeFeatureProvider = mock(LocaleFeatureProvider.class);
         applicationFeatureProvider = mock(ApplicationFeatureProvider.class);
         enterprisePrivacyFeatureProvider = mock(EnterprisePrivacyFeatureProvider.class);
@@ -132,6 +136,11 @@
     }
 
     @Override
+    public DockUpdaterFeatureProvider getDockUpdaterFeatureProvider() {
+        return dockUpdaterFeatureProvider;
+    }
+
+    @Override
     public ApplicationFeatureProvider getApplicationFeatureProvider(Context context) {
         return applicationFeatureProvider;
     }
diff --git a/tests/robotests/src/com/android/settings/search/FakeIndexProvider.java b/tests/robotests/src/com/android/settings/testutils/FakeIndexProvider.java
similarity index 92%
rename from tests/robotests/src/com/android/settings/search/FakeIndexProvider.java
rename to tests/robotests/src/com/android/settings/testutils/FakeIndexProvider.java
index e5f1631..c9177e1 100644
--- a/tests/robotests/src/com/android/settings/search/FakeIndexProvider.java
+++ b/tests/robotests/src/com/android/settings/testutils/FakeIndexProvider.java
@@ -15,12 +15,14 @@
  *
  */
 
-package com.android.settings.search;
+package com.android.settings.testutils;
 
 import android.content.Context;
 import android.provider.SearchIndexableResource;
 
 import com.android.settings.R;
+import com.android.settings.search.BaseSearchIndexProvider;
+import com.android.settings.search.Indexable;
 
 import java.util.ArrayList;
 import java.util.List;
diff --git a/tests/robotests/src/com/android/settings/wifi/AppStateChangeWifiStateBridgeTest.java b/tests/robotests/src/com/android/settings/wifi/AppStateChangeWifiStateBridgeTest.java
index a5ecd94..d49c019 100644
--- a/tests/robotests/src/com/android/settings/wifi/AppStateChangeWifiStateBridgeTest.java
+++ b/tests/robotests/src/com/android/settings/wifi/AppStateChangeWifiStateBridgeTest.java
@@ -16,6 +16,10 @@
 package com.android.settings.wifi;
 
 import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Mockito.mock;
+
+import android.content.pm.PackageInfo;
+import android.Manifest;
 
 import com.android.settings.testutils.SettingsRobolectricTestRunner;
 import com.android.settingslib.applications.ApplicationsState.AppEntry;
@@ -66,4 +70,14 @@
         mEntry.extraInfo = mState;
         assertThat(mFilter.filterApp(mEntry)).isFalse();
     }
+
+    @Test
+    public void testFilterApp_networkSettingsGranted_returnFalse() {
+        mState.permissionDeclared = true;
+        mState.packageInfo = mock(PackageInfo.class);
+        mState.packageInfo.requestedPermissions
+                = new String[]{ Manifest.permission.NETWORK_SETTINGS };
+        mEntry.extraInfo = mState;
+        assertThat(mFilter.filterApp(mEntry)).isFalse();
+    }
 }
diff --git a/tests/robotests/src/com/android/settings/wifi/tether/WifiTetherSwitchBarControllerTest.java b/tests/robotests/src/com/android/settings/wifi/tether/WifiTetherSwitchBarControllerTest.java
index 943a665..f5ac697 100644
--- a/tests/robotests/src/com/android/settings/wifi/tether/WifiTetherSwitchBarControllerTest.java
+++ b/tests/robotests/src/com/android/settings/wifi/tether/WifiTetherSwitchBarControllerTest.java
@@ -18,7 +18,15 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.never;
 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.content.Context;
@@ -68,7 +76,7 @@
     }
 
     @Test
-    public void testConstructor_airplaneModeOn_switchBarDisabled() {
+    public void constructor_airplaneModeOn_switchBarDisabled() {
         Settings.Global.putInt(RuntimeEnvironment.application.getContentResolver(),
                 Settings.Global.AIRPLANE_MODE_ON, 1);
 
@@ -79,7 +87,7 @@
     }
 
     @Test
-    public void testStartTether_fail_resetSwitchBar() {
+    public void startTether_fail_resetSwitchBar() {
         when(mNetworkPolicyManager.getRestrictBackground()).thenReturn(false);
 
         mController.startTether();
@@ -90,7 +98,7 @@
     }
 
     @Test
-    public void testOnDataSaverChanged_setsEnabledCorrectly() {
+    public void onDataSaverChanged_setsEnabledCorrectly() {
         assertThat(mSwitchBar.isEnabled()).isTrue();
 
         // try to turn data saver on
@@ -102,6 +110,19 @@
         when(mNetworkPolicyManager.getRestrictBackground()).thenReturn(false);
         mController.onDataSaverChanged(false);
         assertThat(mSwitchBar.isEnabled()).isTrue();
+    }
 
+    @Test
+    public void onSwitchToggled_onlyStartsTetherWhenNeeded() {
+        when(mWifiManager.isWifiApEnabled()).thenReturn(true);
+        mController.onSwitchToggled(true);
+
+        verify(mConnectivityManager, never()).startTethering(anyInt(), anyBoolean(), any(), any());
+
+        doReturn(false).when(mWifiManager).isWifiApEnabled();
+        mController.onSwitchToggled(true);
+
+        verify(mConnectivityManager, times(1))
+                .startTethering(anyInt(), anyBoolean(), any(), any());
     }
 }