Merge "Elicit ItemsData class and add DiffUtil.Callback"
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index a0814db..5721c74 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -2031,10 +2031,8 @@
         <!-- Bluetooth stuff -->
 
         <activity android:name=".bluetooth.BluetoothPairingDialog"
-                  android:label="@string/bluetooth_pairing_request"
                   android:excludeFromRecents="true"
-                  android:windowSoftInputMode="stateVisible|adjustResize"
-                  android:theme="@*android:style/Theme.DeviceDefault.Light.Dialog.Alert">
+                  android:theme="@android:style/Theme.DeviceDefault.Light.Dialog.NoActionBar">
             <intent-filter android:priority="1">
                 <action android:name="android.bluetooth.device.action.PAIRING_REQUEST" />
                 <category android:name="android.intent.category.DEFAULT" />
@@ -3071,6 +3069,18 @@
                        android:value="com.android.settings.datausage.DataUsageSummary"/>
         </activity-alias>
 
+        <activity android:name=".Settings$AppAndNotificationDashboardActivity"
+                  android:label="@string/app_and_notification_dashboard_title"
+                  android:icon="@drawable/ic_settings_applications">
+            <intent-filter android:priority="8">
+                <action android:name="com.android.settings.action.SETTINGS"/>
+            </intent-filter>
+            <meta-data android:name="com.android.settings.FRAGMENT_CLASS"
+                       android:value="com.android.settings.applications.AppAndNotificationDashboardFragment"/>
+            <meta-data android:name="com.android.settings.category"
+                       android:value="com.android.settings.category.ia.homepage"/>
+        </activity>
+
         <activity-alias android:name="BatteryDashboardAlias"
                         android:targetActivity="Settings$PowerUsageSummaryActivity">
             <intent-filter android:priority="7">
@@ -3095,10 +3105,23 @@
                        android:value="true" />
         </activity-alias>
 
+        <activity-alias android:name="SoundDashboardAlias"
+                        android:targetActivity="Settings$SoundSettingsActivity">
+            <intent-filter android:priority="5">
+                <action android:name="com.android.settings.action.SETTINGS" />
+            </intent-filter>
+            <meta-data android:name="com.android.settings.category"
+                       android:value="com.android.settings.category.ia.homepage" />
+            <meta-data android:name="com.android.settings.FRAGMENT_CLASS"
+                       android:value="com.android.settings.notification.SoundSettings" />
+            <meta-data android:name="com.android.settings.PRIMARY_PROFILE_CONTROLLED"
+                       android:value="true" />
+        </activity-alias>
+
         <activity android:name=".Settings$StorageDashboardActivity"
                   android:label="@string/storage_settings"
                   android:icon="@drawable/ic_settings_storage">
-            <intent-filter android:priority="5">
+            <intent-filter android:priority="4">
                 <action android:name="com.android.settings.action.SETTINGS" />
             </intent-filter>
             <meta-data android:name="com.android.settings.category"
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg
new file mode 100644
index 0000000..653380c
--- /dev/null
+++ b/PREUPLOAD.cfg
@@ -0,0 +1,4 @@
+[Hook Scripts]
+checkstyle_hook = ../../../development/tools/checkstyle/checkstyle.py --sha ${PREUPLOAD_COMMIT}
+                  -fw src/com/android/settings/print/
+
diff --git a/res/layout/battery_history_detail.xml b/res/layout/battery_history_detail.xml
index e254711..b782e39 100644
--- a/res/layout/battery_history_detail.xml
+++ b/res/layout/battery_history_detail.xml
@@ -14,54 +14,56 @@
      limitations under the License.
 -->
 
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<ScrollView
+    xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:settings="http://schemas.android.com/apk/res-auto"
     android:layout_width="match_parent"
-    android:layout_height="wrap_content"
-    android:paddingStart="?android:attr/listPreferredItemPaddingStart"
-    android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
-    android:orientation="vertical">
+    android:layout_height="match_parent">
 
     <LinearLayout
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
-        android:focusable="true"
+        android:paddingStart="?android:attr/listPreferredItemPaddingStart"
+        android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
         android:orientation="vertical">
-        <TextView
-            android:id="@+id/charge"
+
+        <LinearLayout
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
-            android:textAppearance="?android:attr/textAppearanceLarge"
-            android:textSize="36sp"
-            android:textColor="?android:attr/colorAccent" />
+            android:focusable="true"
+            android:orientation="vertical">
 
-        <TextView
-            android:id="@+id/estimation"
+            <TextView
+                android:id="@+id/charge"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:textAppearance="?android:attr/textAppearanceLarge"
+                android:textSize="36sp"
+                android:textColor="?android:attr/colorAccent"/>
+
+            <TextView
+                android:id="@+id/estimation"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:paddingBottom="8dp"
+                android:textAppearance="?android:attr/textAppearanceMedium"
+                android:textColor="?android:attr/textColorSecondary"/>
+
+            <com.android.settingslib.graph.UsageView
+                android:id="@+id/battery_usage"
+                android:layout_width="match_parent"
+                android:layout_height="141dp"
+                settings:sideLabels="@array/battery_labels"
+                android:colorAccent="?android:attr/colorAccent"
+                android:gravity="end"
+                settings:textColor="?android:attr/textColorSecondary"/>
+        </LinearLayout>
+
+        <View
             android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:paddingBottom="8dp"
-            android:textAppearance="?android:attr/textAppearanceMedium"
-            android:textColor="?android:attr/textColorSecondary" />
-
-        <com.android.settingslib.graph.UsageView
-            android:id="@+id/battery_usage"
-            android:layout_width="match_parent"
-            android:layout_height="141dp"
-            settings:sideLabels="@array/battery_labels"
-            android:colorAccent="?android:attr/colorAccent"
-            android:gravity="end"
-            settings:textColor="?android:attr/textColorSecondary" />
-    </LinearLayout>
-
-    <View
-        android:layout_width="match_parent"
-        android:layout_height="1dp"
-        android:layout_marginTop="2dp"
-        android:background="?android:attr/listDivider" />
-
-    <ScrollView
-        android:layout_width="match_parent"
-        android:layout_height="match_parent">
+            android:layout_height="1dp"
+            android:layout_marginTop="2dp"
+            android:background="?android:attr/listDivider"/>
 
         <LinearLayout
             android:layout_width="match_parent"
@@ -94,6 +96,6 @@
 
         </LinearLayout>
 
-    </ScrollView>
+    </LinearLayout>
 
-</LinearLayout>
+</ScrollView>
diff --git a/res/layout/bluetooth_pin_confirm.xml b/res/layout/bluetooth_pin_confirm.xml
index 1e5eb0b..33140d9 100644
--- a/res/layout/bluetooth_pin_confirm.xml
+++ b/res/layout/bluetooth_pin_confirm.xml
@@ -41,7 +41,7 @@
             android:text="@string/bluetooth_pairing_key_msg"
             android:visibility="gone"
             android:textAppearance="@android:style/TextAppearance.Material.Body1"
-            android:textColor="@*android:color/secondary_text_material_light"  />
+            android:textColor="@color/bluetooth_dialog_text_color"  />
 
         <TextView
             android:id="@+id/pairing_subhead"
@@ -64,7 +64,7 @@
             android:gravity="center_vertical"
             android:text="@string/bluetooth_enter_passkey_msg"
             android:textAppearance="@android:style/TextAppearance.Material.Subhead"
-            android:textColor="@*android:color/secondary_text_material_light"
+            android:textColor="@color/bluetooth_dialog_text_color"
             android:visibility="gone" />
 
         <CheckBox
@@ -74,7 +74,7 @@
             android:layout_marginStart="@dimen/bluetooth_dialog_padding"
             android:layout_marginEnd="@dimen/bluetooth_dialog_padding"
             android:textAppearance="@android:style/TextAppearance.Material.Body1"
-            android:textColor="@*android:color/secondary_text_material_light"  />
+            android:textColor="@color/bluetooth_dialog_text_color"  />
 
     </LinearLayout>
 
diff --git a/res/layout/expand_preference.xml b/res/layout/expand_preference.xml
new file mode 100644
index 0000000..640cda7
--- /dev/null
+++ b/res/layout/expand_preference.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright (C) 2016 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:background="@drawable/selectable_card_grey"
+    android:gravity="center_vertical"
+    android:minHeight="?android:attr/listPreferredItemHeight"
+    android:orientation="vertical"
+    android:paddingEnd="?android:attr/scrollbarSize">
+    <TextView
+        android:id="@android:id/title"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center"/>
+</LinearLayout>
\ No newline at end of file
diff --git a/res/layout/support_disclaimer_content.xml b/res/layout/support_disclaimer_content.xml
index d6697c3..196bef2 100644
--- a/res/layout/support_disclaimer_content.xml
+++ b/res/layout/support_disclaimer_content.xml
@@ -13,24 +13,27 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<LinearLayout
+<ScrollView
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
-    android:layout_height="wrap_content"
-    android:orientation="vertical"
-    android:padding="24dp">
-
-    <com.android.settings.widget.LinkTextView
-        android:id="@+id/support_disclaimer_text"
+    android:layout_height="wrap_content">
+    <LinearLayout
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
-        android:paddingBottom="24dp"/>
+        android:orientation="vertical"
+        android:padding="24dp">
 
-    <CheckBox
-        android:id="@+id/support_disclaimer_do_not_show_again"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:text="@string/support_disclaimer_do_not_show"
-        android:textColor="?android:attr/textColorSecondary"/>
+        <com.android.settings.widget.LinkTextView
+            android:id="@+id/support_disclaimer_text"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:paddingBottom="24dp"/>
 
-</LinearLayout>
+        <CheckBox
+            android:id="@+id/support_disclaimer_do_not_show_again"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:text="@string/support_disclaimer_do_not_show"
+            android:textColor="?android:attr/textColorSecondary"/>
+    </LinearLayout>
+</ScrollView>
diff --git a/res/layout/support_escalation_options.xml b/res/layout/support_escalation_options.xml
index b214561..63cc85d 100644
--- a/res/layout/support_escalation_options.xml
+++ b/res/layout/support_escalation_options.xml
@@ -42,7 +42,8 @@
         android:gravity="center_horizontal"
         android:orientation="horizontal">
         <LinearLayout
-            android:layout_width="wrap_content"
+            android:layout_width="0dp"
+            android:layout_weight="1"
             android:layout_height="wrap_content"
             android:layout_marginStart="8dp"
             android:layout_marginEnd="8dp"
@@ -63,7 +64,8 @@
                 android:textColor="?android:attr/textColorSecondary"/>
         </LinearLayout>
         <LinearLayout
-            android:layout_width="wrap_content"
+            android:layout_width="0dp"
+            android:layout_weight="1"
             android:layout_height="wrap_content"
             android:layout_marginStart="8dp"
             android:layout_marginEnd="8dp"
diff --git a/res/layout/support_tile.xml b/res/layout/support_tile.xml
index e5e49f4..e294868 100644
--- a/res/layout/support_tile.xml
+++ b/res/layout/support_tile.xml
@@ -34,7 +34,7 @@
         android:id="@+id/tile_title"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:singleLine="true"
+        android:maxLines="2"
         android:textAppearance="@style/TextAppearance.TileTitle"
         android:ellipsize="end"
         android:fadingEdge="horizontal"/>
diff --git a/res/values-am/strings.xml b/res/values-am/strings.xml
index 3429035..d820681 100644
--- a/res/values-am/strings.xml
+++ b/res/values-am/strings.xml
@@ -2280,20 +2280,13 @@
     <string name="vpn_disconnect" msgid="7426570492642111171">"ግንኙነት አቋርጥ"</string>
     <string name="vpn_version" msgid="1939804054179766249">"ሥሪት <xliff:g id="VERSION">%s</xliff:g>"</string>
     <string name="vpn_forget_long" msgid="2232239391189465752">"VPNን እርሳ"</string>
-    <!-- no translation found for vpn_replace_vpn_title (2963898301277610248) -->
-    <skip />
-    <!-- no translation found for vpn_set_vpn_title (4009987321156037267) -->
-    <skip />
-    <!-- no translation found for vpn_first_always_on_vpn_message (3025322109743675467) -->
-    <skip />
-    <!-- no translation found for vpn_replace_always_on_vpn_enable_message (2577928591361606641) -->
-    <skip />
-    <!-- no translation found for vpn_replace_always_on_vpn_disable_message (3011818750025879902) -->
-    <skip />
-    <!-- no translation found for vpn_replace_vpn_message (5611635724578812860) -->
-    <skip />
-    <!-- no translation found for vpn_turn_on (2363136869284273872) -->
-    <skip />
+    <string name="vpn_replace_vpn_title" msgid="2963898301277610248">"አሁን ያለው VPN ይተካ?"</string>
+    <string name="vpn_set_vpn_title" msgid="4009987321156037267">"ሁልጊዜ-የበራ VPN ይቀናበር?"</string>
+    <string name="vpn_first_always_on_vpn_message" msgid="3025322109743675467">"ይህን ቅንብር በማብራት VPN በተሳካ ሁኔታ እስኪገናኝ ድረስ የበይነመረብ ግንኙነት አይኖረዎትም"</string>
+    <string name="vpn_replace_always_on_vpn_enable_message" msgid="2577928591361606641">"የእርስዎ ነባር VPN ይተካል፣ እና VPN በተሳካ ሁኔታ እስኪገናኝ ድረስ የበይነመረብ ግንኙነት አይኖረዎትም"</string>
+    <string name="vpn_replace_always_on_vpn_disable_message" msgid="3011818750025879902">"አስቀድመው ሁልጊዜ ከበራ VPN ጋር ተገናኝተዋል። ከተለየ ጋር ከተገናኙ ነባሩ የእርስዎ VPN  ይተካል፣ እና የሁልጊዜ-በርቷል ሁነታ ይጠፋል።"</string>
+    <string name="vpn_replace_vpn_message" msgid="5611635724578812860">"አስቀድመው ከአንድ VPN ጋር ተገናኝተዋል። ከተለየ ጋር ከተገናኙ ነባሩ የእርስዎ VPN ይተካል።"</string>
+    <string name="vpn_turn_on" msgid="2363136869284273872">"አብራ"</string>
     <string name="vpn_cant_connect_title" msgid="4517706987875907511">"<xliff:g id="VPN_NAME">%1$s</xliff:g> መገናኘት አልቻለም"</string>
     <string name="vpn_cant_connect_message" msgid="2593197919352621279">"ይህ መተግበሪያ ሁልጊዜ-የሚበራ ቪፒኤን አይደግፍም።"</string>
     <string name="vpn_title" msgid="6317731879966640551">"VPN"</string>
@@ -2536,8 +2529,7 @@
     </plurals>
     <string name="network_dashboard_title" msgid="4771589228992391573">"አውታረ መረብ እና በይነመረብ"</string>
     <string name="connected_devices_dashboard_title" msgid="2355264951438890709">"የተገናኙ መሣሪያዎች"</string>
-    <!-- no translation found for system_dashboard_summary (6112602136713843779) -->
-    <skip />
+    <string name="system_dashboard_summary" msgid="6112602136713843779">"ቋንቋ፦ <xliff:g id="LANGUAGE">%1$s</xliff:g>"</string>
     <string name="search_results_title" msgid="1796252422574886932">"ቅንብሮች"</string>
     <string name="search_menu" msgid="6283419262313758339">"የፍለጋ ቅንብሮች"</string>
     <string name="query_hint_text" msgid="3350700807437473939">"የፍለጋ ቅንብሮች"</string>
diff --git a/res/values-ar/strings.xml b/res/values-ar/strings.xml
index b093f91..006af5a 100644
--- a/res/values-ar/strings.xml
+++ b/res/values-ar/strings.xml
@@ -2348,20 +2348,13 @@
     <string name="vpn_disconnect" msgid="7426570492642111171">"قطع الاتصال"</string>
     <string name="vpn_version" msgid="1939804054179766249">"الإصدار <xliff:g id="VERSION">%s</xliff:g>"</string>
     <string name="vpn_forget_long" msgid="2232239391189465752">"نسيان الشبكة الظاهرية الخاصة"</string>
-    <!-- no translation found for vpn_replace_vpn_title (2963898301277610248) -->
-    <skip />
-    <!-- no translation found for vpn_set_vpn_title (4009987321156037267) -->
-    <skip />
-    <!-- no translation found for vpn_first_always_on_vpn_message (3025322109743675467) -->
-    <skip />
-    <!-- no translation found for vpn_replace_always_on_vpn_enable_message (2577928591361606641) -->
-    <skip />
-    <!-- no translation found for vpn_replace_always_on_vpn_disable_message (3011818750025879902) -->
-    <skip />
-    <!-- no translation found for vpn_replace_vpn_message (5611635724578812860) -->
-    <skip />
-    <!-- no translation found for vpn_turn_on (2363136869284273872) -->
-    <skip />
+    <string name="vpn_replace_vpn_title" msgid="2963898301277610248">"هل تريد استبدال الشبكة الظاهرية الخاصة الحالية؟"</string>
+    <string name="vpn_set_vpn_title" msgid="4009987321156037267">"هل تريد تشغيل الشبكة الظاهرية الخاصة باستمرار؟"</string>
+    <string name="vpn_first_always_on_vpn_message" msgid="3025322109743675467">"‏عند تشغيل هذا الإعداد، لن تتمكن من الاتصال بالإنترنت إلا بعد أن ينجح اتصال الشبكة الظاهرية الخاصة (VPN)"</string>
+    <string name="vpn_replace_always_on_vpn_enable_message" msgid="2577928591361606641">"‏سيتم استبدال شبكتك الظاهرية الخاصة (VPN) الحالية ولن تتمكن من استخدام اتصال الإنترنت إلا بعد أن ينجح اتصال الشبكة الظاهرية الخاصة"</string>
+    <string name="vpn_replace_always_on_vpn_disable_message" msgid="3011818750025879902">"‏أنت متصل حاليًا بشبكة ظاهرية خاصة (VPN) مضبوطة على وضع التشغيل الدائم. وإذا اتصلت بشبكة ظاهرية خاصة أخرى، فسيتم استبدال شبكتك الظاهرية الخاصة الحالية، كما سيتم إيقاف وضع التشغيل الدائم."</string>
+    <string name="vpn_replace_vpn_message" msgid="5611635724578812860">"‏أنت متصل حاليًا بشبكة ظاهرية خاصة (VPN). وإذا اتصلت بشبكة ظاهرية خاصة أخرى، فسيتم استبدال شبكتك الظاهرية الخاصة الحالية."</string>
+    <string name="vpn_turn_on" msgid="2363136869284273872">"تشغيل"</string>
     <string name="vpn_cant_connect_title" msgid="4517706987875907511">"يتعذر الاتصال بـ <xliff:g id="VPN_NAME">%1$s</xliff:g>"</string>
     <string name="vpn_cant_connect_message" msgid="2593197919352621279">"‏لا يتوافق هذا التطبيق مع التشغيل الدائم للشبكة الظاهرية الخاصة (VPN)."</string>
     <string name="vpn_title" msgid="6317731879966640551">"VPN"</string>
@@ -2624,8 +2617,7 @@
     </plurals>
     <string name="network_dashboard_title" msgid="4771589228992391573">"الشبكة والإنترنت"</string>
     <string name="connected_devices_dashboard_title" msgid="2355264951438890709">"الأجهزة المرتبطة"</string>
-    <!-- no translation found for system_dashboard_summary (6112602136713843779) -->
-    <skip />
+    <string name="system_dashboard_summary" msgid="6112602136713843779">"اللغة: <xliff:g id="LANGUAGE">%1$s</xliff:g>"</string>
     <string name="search_results_title" msgid="1796252422574886932">"الإعدادات"</string>
     <string name="search_menu" msgid="6283419262313758339">"إعدادات البحث"</string>
     <string name="query_hint_text" msgid="3350700807437473939">"إعدادات البحث"</string>
diff --git a/res/values-be-rBY/strings.xml b/res/values-be-rBY/strings.xml
index a3f3b37..2850228 100644
--- a/res/values-be-rBY/strings.xml
+++ b/res/values-be-rBY/strings.xml
@@ -2314,20 +2314,13 @@
     <string name="vpn_disconnect" msgid="7426570492642111171">"Адключыць"</string>
     <string name="vpn_version" msgid="1939804054179766249">"Версія <xliff:g id="VERSION">%s</xliff:g>"</string>
     <string name="vpn_forget_long" msgid="2232239391189465752">"Забыць VPN"</string>
-    <!-- no translation found for vpn_replace_vpn_title (2963898301277610248) -->
-    <skip />
-    <!-- no translation found for vpn_set_vpn_title (4009987321156037267) -->
-    <skip />
-    <!-- no translation found for vpn_first_always_on_vpn_message (3025322109743675467) -->
-    <skip />
-    <!-- no translation found for vpn_replace_always_on_vpn_enable_message (2577928591361606641) -->
-    <skip />
-    <!-- no translation found for vpn_replace_always_on_vpn_disable_message (3011818750025879902) -->
-    <skip />
-    <!-- no translation found for vpn_replace_vpn_message (5611635724578812860) -->
-    <skip />
-    <!-- no translation found for vpn_turn_on (2363136869284273872) -->
-    <skip />
+    <string name="vpn_replace_vpn_title" msgid="2963898301277610248">"Замяніць існуючую VPN?"</string>
+    <string name="vpn_set_vpn_title" msgid="4009987321156037267">"Наладзіць заўсёды ўключаную VPN?"</string>
+    <string name="vpn_first_always_on_vpn_message" msgid="3025322109743675467">"Калі вы ўключыце гэту наладу, у вас не будзе падключэння да інтэрнэту, пакуль VPN паспяхова не падключыцца"</string>
+    <string name="vpn_replace_always_on_vpn_enable_message" msgid="2577928591361606641">"Ваша існуючая VPN будзе заменена, і ў вас не будзе падключэння да інтэрнэту, пакуль VPN паспяхова не падключыцца"</string>
+    <string name="vpn_replace_always_on_vpn_disable_message" msgid="3011818750025879902">"Вы ўжо падключаны да заўсёды ўключанай VPN. Калі вы падключыцеся да іншай, ваша існуючая VPN будзе заменена, а рэжым \"заўсёды ўключана\" будзе адключаны."</string>
+    <string name="vpn_replace_vpn_message" msgid="5611635724578812860">"Вы ўжо падключаны да VPN. Калі вы падключыцеся да іншай, ваша існуючая VPN будзе заменена."</string>
+    <string name="vpn_turn_on" msgid="2363136869284273872">"Уключыць"</string>
     <string name="vpn_cant_connect_title" msgid="4517706987875907511">"<xliff:g id="VPN_NAME">%1$s</xliff:g> не можа падключыцца"</string>
     <string name="vpn_cant_connect_message" msgid="2593197919352621279">"Гэта праграма не падтрымлівае пастаянна ўключаную VPN."</string>
     <string name="vpn_title" msgid="6317731879966640551">"VPN"</string>
@@ -2580,8 +2573,7 @@
     </plurals>
     <string name="network_dashboard_title" msgid="4771589228992391573">"Сетка і інтэрнэт"</string>
     <string name="connected_devices_dashboard_title" msgid="2355264951438890709">"Падключаныя прылады"</string>
-    <!-- no translation found for system_dashboard_summary (6112602136713843779) -->
-    <skip />
+    <string name="system_dashboard_summary" msgid="6112602136713843779">"Мова: <xliff:g id="LANGUAGE">%1$s</xliff:g>"</string>
     <string name="search_results_title" msgid="1796252422574886932">"Налады"</string>
     <string name="search_menu" msgid="6283419262313758339">"Налады пошуку"</string>
     <string name="query_hint_text" msgid="3350700807437473939">"Налады пошуку"</string>
diff --git a/res/values-bn-rBD/strings.xml b/res/values-bn-rBD/strings.xml
index 9b58e71..efd4d43 100644
--- a/res/values-bn-rBD/strings.xml
+++ b/res/values-bn-rBD/strings.xml
@@ -2280,20 +2280,13 @@
     <string name="vpn_disconnect" msgid="7426570492642111171">"সংযোগ বিচ্ছিন্ন করুন"</string>
     <string name="vpn_version" msgid="1939804054179766249">"<xliff:g id="VERSION">%s</xliff:g> সংস্করণ"</string>
     <string name="vpn_forget_long" msgid="2232239391189465752">"VPN সরিয়ে দিন"</string>
-    <!-- no translation found for vpn_replace_vpn_title (2963898301277610248) -->
-    <skip />
-    <!-- no translation found for vpn_set_vpn_title (4009987321156037267) -->
-    <skip />
-    <!-- no translation found for vpn_first_always_on_vpn_message (3025322109743675467) -->
-    <skip />
-    <!-- no translation found for vpn_replace_always_on_vpn_enable_message (2577928591361606641) -->
-    <skip />
-    <!-- no translation found for vpn_replace_always_on_vpn_disable_message (3011818750025879902) -->
-    <skip />
-    <!-- no translation found for vpn_replace_vpn_message (5611635724578812860) -->
-    <skip />
-    <!-- no translation found for vpn_turn_on (2363136869284273872) -->
-    <skip />
+    <string name="vpn_replace_vpn_title" msgid="2963898301277610248">"বিদ্যমান VPN প্রতিস্থাপন করতে চান?"</string>
+    <string name="vpn_set_vpn_title" msgid="4009987321156037267">"সর্বদা-চালু VPN সেট করতে চান?"</string>
+    <string name="vpn_first_always_on_vpn_message" msgid="3025322109743675467">"এই সেটিং চালু করলে, VPN সফলভাবে সংযুক্ত না হওয়া পর্যন্ত আপনার কাছে কোনো ইন্টারনেট সংযোগ থাকবে না"</string>
+    <string name="vpn_replace_always_on_vpn_enable_message" msgid="2577928591361606641">"আপনার বিদ্যমান VPN প্রতিস্থাপন করা হবে এবং VPN সফলভাবে সংযুক্ত না হওয়া পর্যন্ত আপনার কাছে কোনো ইন্টারনেট সংযোগ থাকবে না"</string>
+    <string name="vpn_replace_always_on_vpn_disable_message" msgid="3011818750025879902">"আপনি ইতিমধ্যেই একটি সর্বদা-চালু VPN এর সাথে সংযুক্ত রয়েছেন৷ আপনি যদি অন্য আরেকটিতে সংযোগ করেন তবে আপনার বিদ্যমান VPN প্রতিস্থাপন করা হবে এবং সর্বদা-চালু মোড বন্ধ হবে৷"</string>
+    <string name="vpn_replace_vpn_message" msgid="5611635724578812860">"আপনি ইতিমধ্যেই একটি VPN এর সাথে সংযুক্ত রয়েছেন৷ যদি আপনি অন্য আরেকটিতে সংযুক্ত করে থাকেন তবে আপনার বিদ্যমান VPN প্রতিস্থাপন করা হবে৷"</string>
+    <string name="vpn_turn_on" msgid="2363136869284273872">"চালু করুন"</string>
     <string name="vpn_cant_connect_title" msgid="4517706987875907511">"<xliff:g id="VPN_NAME">%1$s</xliff:g> সংযোগ করতে পারেনি"</string>
     <string name="vpn_cant_connect_message" msgid="2593197919352621279">"এই অ্যাপ্লিকেশানটি সর্বদা-চালু VPN সমর্থন করে না৷"</string>
     <string name="vpn_title" msgid="6317731879966640551">"VPN"</string>
@@ -2536,8 +2529,7 @@
     </plurals>
     <string name="network_dashboard_title" msgid="4771589228992391573">"নেটওয়ার্ক ও ইন্টারনেট"</string>
     <string name="connected_devices_dashboard_title" msgid="2355264951438890709">"সংযুক্ত ডিভাইস"</string>
-    <!-- no translation found for system_dashboard_summary (6112602136713843779) -->
-    <skip />
+    <string name="system_dashboard_summary" msgid="6112602136713843779">"ভাষা: <xliff:g id="LANGUAGE">%1$s</xliff:g>"</string>
     <string name="search_results_title" msgid="1796252422574886932">"সেটিংস"</string>
     <string name="search_menu" msgid="6283419262313758339">"অনুসন্ধান সেটিংস"</string>
     <string name="query_hint_text" msgid="3350700807437473939">"অনুসন্ধান সেটিংস"</string>
diff --git a/res/values-bs-rBA/strings.xml b/res/values-bs-rBA/strings.xml
index 82e1026..fc62859 100644
--- a/res/values-bs-rBA/strings.xml
+++ b/res/values-bs-rBA/strings.xml
@@ -2297,20 +2297,13 @@
     <string name="vpn_disconnect" msgid="7426570492642111171">"Prekini vezu"</string>
     <string name="vpn_version" msgid="1939804054179766249">"Verzija <xliff:g id="VERSION">%s</xliff:g>"</string>
     <string name="vpn_forget_long" msgid="2232239391189465752">"Zaboravi VPN"</string>
-    <!-- no translation found for vpn_replace_vpn_title (2963898301277610248) -->
-    <skip />
-    <!-- no translation found for vpn_set_vpn_title (4009987321156037267) -->
-    <skip />
-    <!-- no translation found for vpn_first_always_on_vpn_message (3025322109743675467) -->
-    <skip />
-    <!-- no translation found for vpn_replace_always_on_vpn_enable_message (2577928591361606641) -->
-    <skip />
-    <!-- no translation found for vpn_replace_always_on_vpn_disable_message (3011818750025879902) -->
-    <skip />
-    <!-- no translation found for vpn_replace_vpn_message (5611635724578812860) -->
-    <skip />
-    <!-- no translation found for vpn_turn_on (2363136869284273872) -->
-    <skip />
+    <string name="vpn_replace_vpn_title" msgid="2963898301277610248">"Želite li zamijeniti postojeću VPN?"</string>
+    <string name="vpn_set_vpn_title" msgid="4009987321156037267">"Želite li postaviti uvijek uključenu VPN?"</string>
+    <string name="vpn_first_always_on_vpn_message" msgid="3025322109743675467">"Ako uključite ovu postavku, nećete imati internet vezu dok se VPN ne poveže uspješno."</string>
+    <string name="vpn_replace_always_on_vpn_enable_message" msgid="2577928591361606641">"Vaša postojeća VPN će biti zamijenjena i nećete imati internet vezu dok se VPN ne poveže uspješno."</string>
+    <string name="vpn_replace_always_on_vpn_disable_message" msgid="3011818750025879902">"Već ste povezani na uvijek uključenu VPN. Ako se povežete na drugu mrežu, vaša postojeća VPN će biti zamijenjena, a uvijek uključeni način rada će biti isključen."</string>
+    <string name="vpn_replace_vpn_message" msgid="5611635724578812860">"Već ste povezani na VPN. Ako se povežete na drugu, postojeća VPN će biti zamijenjena."</string>
+    <string name="vpn_turn_on" msgid="2363136869284273872">"Uključi"</string>
     <string name="vpn_cant_connect_title" msgid="4517706987875907511">"<xliff:g id="VPN_NAME">%1$s</xliff:g> se ne može povezati"</string>
     <string name="vpn_cant_connect_message" msgid="2593197919352621279">"Ova aplikacija ne podržava uvijek aktivni VPN."</string>
     <string name="vpn_title" msgid="6317731879966640551">"VPN"</string>
@@ -2558,8 +2551,7 @@
     </plurals>
     <string name="network_dashboard_title" msgid="4771589228992391573">"Mreža i internet"</string>
     <string name="connected_devices_dashboard_title" msgid="2355264951438890709">"Povezani uređaji"</string>
-    <!-- no translation found for system_dashboard_summary (6112602136713843779) -->
-    <skip />
+    <string name="system_dashboard_summary" msgid="6112602136713843779">"Jezik: <xliff:g id="LANGUAGE">%1$s</xliff:g>"</string>
     <string name="search_results_title" msgid="1796252422574886932">"Postavke"</string>
     <string name="search_menu" msgid="6283419262313758339">"Postavke pretraživanja"</string>
     <string name="query_hint_text" msgid="3350700807437473939">"Postavke pretraživanja"</string>
diff --git a/res/values-da/strings.xml b/res/values-da/strings.xml
index d954292..368d244 100644
--- a/res/values-da/strings.xml
+++ b/res/values-da/strings.xml
@@ -2544,7 +2544,7 @@
     <string name="search_recents_queries_label" msgid="2128811638532309069">"Seneste søgninger"</string>
     <string name="search_results_label" msgid="4163304782363526148">"Resultater"</string>
     <string name="keywords_wifi" msgid="1395786161993828719">"wifi, wi-fi, netværksforbindelse"</string>
-    <string name="keywords_more_default_sms_app" msgid="2265154063220360784">"sms-besked, sms, beskeder, chat"</string>
+    <string name="keywords_more_default_sms_app" msgid="2265154063220360784">"sms, sende sms-beskeder, beskeder, chat"</string>
     <string name="keywords_more_mobile_networks" msgid="1538131503712402851">"mobil, mobilselskab, trådløs, data, 4g, 3g, 2g, lte"</string>
     <string name="keywords_wifi_calling" msgid="1784064367330122679">"wifi, wi-fi, ring op, opkald"</string>
     <string name="keywords_home" msgid="3626170808219458848">"starter"</string>
diff --git a/res/values-fi/strings.xml b/res/values-fi/strings.xml
index 83b131c..38af056 100644
--- a/res/values-fi/strings.xml
+++ b/res/values-fi/strings.xml
@@ -2280,20 +2280,13 @@
     <string name="vpn_disconnect" msgid="7426570492642111171">"Katkaise yhteys"</string>
     <string name="vpn_version" msgid="1939804054179766249">"Versio <xliff:g id="VERSION">%s</xliff:g>"</string>
     <string name="vpn_forget_long" msgid="2232239391189465752">"Unohda VPN"</string>
-    <!-- no translation found for vpn_replace_vpn_title (2963898301277610248) -->
-    <skip />
-    <!-- no translation found for vpn_set_vpn_title (4009987321156037267) -->
-    <skip />
-    <!-- no translation found for vpn_first_always_on_vpn_message (3025322109743675467) -->
-    <skip />
-    <!-- no translation found for vpn_replace_always_on_vpn_enable_message (2577928591361606641) -->
-    <skip />
-    <!-- no translation found for vpn_replace_always_on_vpn_disable_message (3011818750025879902) -->
-    <skip />
-    <!-- no translation found for vpn_replace_vpn_message (5611635724578812860) -->
-    <skip />
-    <!-- no translation found for vpn_turn_on (2363136869284273872) -->
-    <skip />
+    <string name="vpn_replace_vpn_title" msgid="2963898301277610248">"Korvataanko nykyinen VPN?"</string>
+    <string name="vpn_set_vpn_title" msgid="4009987321156037267">"Määritetäänkö aina käytössä oleva VPN?"</string>
+    <string name="vpn_first_always_on_vpn_message" msgid="3025322109743675467">"Jos otat tämän asetuksen käyttöön, et voi muodostaa internetyhteyttä ennen kuin VPN-yhteys on muodostettu."</string>
+    <string name="vpn_replace_always_on_vpn_enable_message" msgid="2577928591361606641">"Nykyinen VPN korvataan, etkä voi muodostaa internetyhteyttä ennen kuin VPN-yhteys on muodostettu."</string>
+    <string name="vpn_replace_always_on_vpn_disable_message" msgid="3011818750025879902">"Olet jo yhteydessä aina käytössä olevaan VPN-verkkoon. Jos muodostat yhteyden uuteen VPN:ään, nykyinen verkkosi korvataan ja aina käytössä ‑tila poistetaan käytöstä."</string>
+    <string name="vpn_replace_vpn_message" msgid="5611635724578812860">"Olet jo yhteydessä VPN-verkkoon. Jos muodostat yhteyden uuteen VPN:ään, nykyinen verkkosi korvataan."</string>
+    <string name="vpn_turn_on" msgid="2363136869284273872">"Ota käyttöön"</string>
     <string name="vpn_cant_connect_title" msgid="4517706987875907511">"Yhteyttä verkkoon <xliff:g id="VPN_NAME">%1$s</xliff:g> ei voi muodostaa"</string>
     <string name="vpn_cant_connect_message" msgid="2593197919352621279">"Sovellus ei tue aina käytössä olevaa VPN-yhteyttä."</string>
     <string name="vpn_title" msgid="6317731879966640551">"VPN"</string>
@@ -2536,8 +2529,7 @@
     </plurals>
     <string name="network_dashboard_title" msgid="4771589228992391573">"Verkko ja internet"</string>
     <string name="connected_devices_dashboard_title" msgid="2355264951438890709">"Yhdistetyt laitteet"</string>
-    <!-- no translation found for system_dashboard_summary (6112602136713843779) -->
-    <skip />
+    <string name="system_dashboard_summary" msgid="6112602136713843779">"Kieli: <xliff:g id="LANGUAGE">%1$s</xliff:g>"</string>
     <string name="search_results_title" msgid="1796252422574886932">"Asetukset"</string>
     <string name="search_menu" msgid="6283419262313758339">"Hakuasetukset"</string>
     <string name="query_hint_text" msgid="3350700807437473939">"Hakuasetukset"</string>
diff --git a/res/values-gl-rES/strings.xml b/res/values-gl-rES/strings.xml
index 3ecb47a..eaeb719 100644
--- a/res/values-gl-rES/strings.xml
+++ b/res/values-gl-rES/strings.xml
@@ -2280,20 +2280,13 @@
     <string name="vpn_disconnect" msgid="7426570492642111171">"Desconectar"</string>
     <string name="vpn_version" msgid="1939804054179766249">"Versión <xliff:g id="VERSION">%s</xliff:g>"</string>
     <string name="vpn_forget_long" msgid="2232239391189465752">"Esquecer perfil da VPN"</string>
-    <!-- no translation found for vpn_replace_vpn_title (2963898301277610248) -->
-    <skip />
-    <!-- no translation found for vpn_set_vpn_title (4009987321156037267) -->
-    <skip />
-    <!-- no translation found for vpn_first_always_on_vpn_message (3025322109743675467) -->
-    <skip />
-    <!-- no translation found for vpn_replace_always_on_vpn_enable_message (2577928591361606641) -->
-    <skip />
-    <!-- no translation found for vpn_replace_always_on_vpn_disable_message (3011818750025879902) -->
-    <skip />
-    <!-- no translation found for vpn_replace_vpn_message (5611635724578812860) -->
-    <skip />
-    <!-- no translation found for vpn_turn_on (2363136869284273872) -->
-    <skip />
+    <string name="vpn_replace_vpn_title" msgid="2963898301277610248">"Queres substituír a VPN existente?"</string>
+    <string name="vpn_set_vpn_title" msgid="4009987321156037267">"Queres definir a VPN sempre activada?"</string>
+    <string name="vpn_first_always_on_vpn_message" msgid="3025322109743675467">"Ao activar esta configuración, non terás conexión a Internet ata que se conecte a VPN correctamente"</string>
+    <string name="vpn_replace_always_on_vpn_enable_message" msgid="2577928591361606641">"A VPN existente substituirase e non terás conexión a Internet ata que se conecte a VPN correctamente"</string>
+    <string name="vpn_replace_always_on_vpn_disable_message" msgid="3011818750025879902">"Xa te conectaches a unha VPN sempre activada. Se te conectas a unha distinta, substituirase a VPN actual e desactivarase o modo de VPN sempre activada."</string>
+    <string name="vpn_replace_vpn_message" msgid="5611635724578812860">"Xa te conectaches a unha VPN. Se te conectas a unha distinta, substituirase a VPN actual."</string>
+    <string name="vpn_turn_on" msgid="2363136869284273872">"Activar"</string>
     <string name="vpn_cant_connect_title" msgid="4517706987875907511">"Non se pode conectar a <xliff:g id="VPN_NAME">%1$s</xliff:g>"</string>
     <string name="vpn_cant_connect_message" msgid="2593197919352621279">"Esta aplicación non é compatible con VPN que estean sempre activadas."</string>
     <string name="vpn_title" msgid="6317731879966640551">"VPN"</string>
@@ -2536,8 +2529,7 @@
     </plurals>
     <string name="network_dashboard_title" msgid="4771589228992391573">"Rede e Internet"</string>
     <string name="connected_devices_dashboard_title" msgid="2355264951438890709">"Dispositivos conectados"</string>
-    <!-- no translation found for system_dashboard_summary (6112602136713843779) -->
-    <skip />
+    <string name="system_dashboard_summary" msgid="6112602136713843779">"Idioma: <xliff:g id="LANGUAGE">%1$s</xliff:g>"</string>
     <string name="search_results_title" msgid="1796252422574886932">"Configuración"</string>
     <string name="search_menu" msgid="6283419262313758339">"Configuración de busca"</string>
     <string name="query_hint_text" msgid="3350700807437473939">"Configuración de busca"</string>
diff --git a/res/values-gu-rIN/strings.xml b/res/values-gu-rIN/strings.xml
index 98bdd00..72a4199 100644
--- a/res/values-gu-rIN/strings.xml
+++ b/res/values-gu-rIN/strings.xml
@@ -2282,20 +2282,13 @@
     <string name="vpn_disconnect" msgid="7426570492642111171">"ડિસ્કનેક્ટ કરો"</string>
     <string name="vpn_version" msgid="1939804054179766249">"સંસ્કરણ <xliff:g id="VERSION">%s</xliff:g>"</string>
     <string name="vpn_forget_long" msgid="2232239391189465752">"VPN ભૂલી ગયાં"</string>
-    <!-- no translation found for vpn_replace_vpn_title (2963898301277610248) -->
-    <skip />
-    <!-- no translation found for vpn_set_vpn_title (4009987321156037267) -->
-    <skip />
-    <!-- no translation found for vpn_first_always_on_vpn_message (3025322109743675467) -->
-    <skip />
-    <!-- no translation found for vpn_replace_always_on_vpn_enable_message (2577928591361606641) -->
-    <skip />
-    <!-- no translation found for vpn_replace_always_on_vpn_disable_message (3011818750025879902) -->
-    <skip />
-    <!-- no translation found for vpn_replace_vpn_message (5611635724578812860) -->
-    <skip />
-    <!-- no translation found for vpn_turn_on (2363136869284273872) -->
-    <skip />
+    <string name="vpn_replace_vpn_title" msgid="2963898301277610248">"અસ્તિત્વમાંની VPN ને બદલીએ?"</string>
+    <string name="vpn_set_vpn_title" msgid="4009987321156037267">"હંમેશાં ચાલુ VPN સેટ કરીએ?"</string>
+    <string name="vpn_first_always_on_vpn_message" msgid="3025322109743675467">"આ સેટિંગ ચાલુ કરવાથી, જ્યાં સુધી VPN સફળતાપૂર્વક કનેક્ટ ન થાય ત્યાં સુધી તમારી પાસે ઇન્ટરનેટ કનેક્શન હશે નહીં"</string>
+    <string name="vpn_replace_always_on_vpn_enable_message" msgid="2577928591361606641">"તમારા અસ્તિત્વમાંના VPN ને બદલવામાં આવશે અને VPN સફળતાપૂર્વક કનેક્ટ ન થાય ત્યાં સુધી તમારી પાસે ઇન્ટરનેટ કનેક્શન હશે નહીં"</string>
+    <string name="vpn_replace_always_on_vpn_disable_message" msgid="3011818750025879902">"તમે પહેલાંથી હંમેશાં-ચાલુ VPN થી કનેક્ટ થયેલ છો. જો તમે કોઈ બીજાથી કનેક્ટ કરો છો, તો તમારા અસ્તિત્વમાંના VPN ને બદલવામાં આવશે અને હંમેશાં-ચાલુ મોડ બંધ થઈ જશે."</string>
+    <string name="vpn_replace_vpn_message" msgid="5611635724578812860">"તમે પહેલાંથી VPN થી કનેક્ટ થયેલ છો. જો તમે કોઈ બીજાથી કનેક્ટ કરો છો, તો તમારા અસ્તિત્વમાંના VPN ને બદલવામાં આવશે."</string>
+    <string name="vpn_turn_on" msgid="2363136869284273872">"ચાલુ કરો"</string>
     <string name="vpn_cant_connect_title" msgid="4517706987875907511">"<xliff:g id="VPN_NAME">%1$s</xliff:g> થી કનેક્ટ કરી શકાતું નથી"</string>
     <string name="vpn_cant_connect_message" msgid="2593197919352621279">"આ ઍપ્લિકેશન હંમેશાં ચાલુ VPN નું સમર્થન કરતી નથી."</string>
     <string name="vpn_title" msgid="6317731879966640551">"VPN"</string>
@@ -2538,8 +2531,7 @@
     </plurals>
     <string name="network_dashboard_title" msgid="4771589228992391573">"નેટવર્ક અને ઇન્ટરનેટ"</string>
     <string name="connected_devices_dashboard_title" msgid="2355264951438890709">"કનેક્ટ થયેલ ઉપકરણો"</string>
-    <!-- no translation found for system_dashboard_summary (6112602136713843779) -->
-    <skip />
+    <string name="system_dashboard_summary" msgid="6112602136713843779">"ભાષા: <xliff:g id="LANGUAGE">%1$s</xliff:g>"</string>
     <string name="search_results_title" msgid="1796252422574886932">"સેટિંગ્સ"</string>
     <string name="search_menu" msgid="6283419262313758339">"શોધ સેટિંગ્સ"</string>
     <string name="query_hint_text" msgid="3350700807437473939">"શોધ સેટિંગ્સ"</string>
diff --git a/res/values-hy-rAM/strings.xml b/res/values-hy-rAM/strings.xml
index a629197..bcc7104 100644
--- a/res/values-hy-rAM/strings.xml
+++ b/res/values-hy-rAM/strings.xml
@@ -705,8 +705,8 @@
     <string name="wifi_more" msgid="3195296805089107950">"Ավելին"</string>
     <string name="wifi_setup_wps" msgid="8128702488486283957">"Ինքնուրույն կարգավորում (WPS)"</string>
     <string name="wifi_show_advanced" msgid="3409422789616520979">"Ընդլայնված ընտրանքներ"</string>
-    <string name="wifi_advanced_toggle_description_expanded" msgid="2380600578544493084">"Ընդլայնված ընտրանքների բացվող ցանկ: Կրկնակի հպեք՝ կոծկելու համար:"</string>
-    <string name="wifi_advanced_toggle_description_collapsed" msgid="1463812308429197263">"Ընդլայնված ընտրանքների բացվող ցանկ: Կրկնակի հպեք՝ ընդարձակելու համար:"</string>
+    <string name="wifi_advanced_toggle_description_expanded" msgid="2380600578544493084">"Ընդլայնված ընտրանքների իջնող ցանկ: Կրկնակի հպեք՝ կոծկելու համար:"</string>
+    <string name="wifi_advanced_toggle_description_collapsed" msgid="1463812308429197263">"Ընդլայնված ընտրանքների իջնող ցանկ: Կրկնակի հպեք՝ ընդարձակելու համար:"</string>
     <string name="wifi_wps_setup_title" msgid="8207552222481570175">"Wi‑Fi-ով պաշտպանված կարգավորում"</string>
     <string name="wifi_wps_setup_msg" msgid="315174329121275092">"WPS-ը մեկնարկում է..."</string>
     <string name="wifi_wps_onstart_pbc" msgid="817003360936932340">"Սեղմեք երթուղիչի «անվտանգ Wi‑Fi կարգավորում» կոճակը: Այն կարող է կոչվել «WPS» կամ նշված լինել այս նշանով՝"</string>
diff --git a/res/values-in/strings.xml b/res/values-in/strings.xml
index 09d3cac..db3723d 100644
--- a/res/values-in/strings.xml
+++ b/res/values-in/strings.xml
@@ -2280,20 +2280,13 @@
     <string name="vpn_disconnect" msgid="7426570492642111171">"Putuskan sambungan"</string>
     <string name="vpn_version" msgid="1939804054179766249">"Versi <xliff:g id="VERSION">%s</xliff:g>"</string>
     <string name="vpn_forget_long" msgid="2232239391189465752">"Lupakan VPN"</string>
-    <!-- no translation found for vpn_replace_vpn_title (2963898301277610248) -->
-    <skip />
-    <!-- no translation found for vpn_set_vpn_title (4009987321156037267) -->
-    <skip />
-    <!-- no translation found for vpn_first_always_on_vpn_message (3025322109743675467) -->
-    <skip />
-    <!-- no translation found for vpn_replace_always_on_vpn_enable_message (2577928591361606641) -->
-    <skip />
-    <!-- no translation found for vpn_replace_always_on_vpn_disable_message (3011818750025879902) -->
-    <skip />
-    <!-- no translation found for vpn_replace_vpn_message (5611635724578812860) -->
-    <skip />
-    <!-- no translation found for vpn_turn_on (2363136869284273872) -->
-    <skip />
+    <string name="vpn_replace_vpn_title" msgid="2963898301277610248">"Ganti VPN yang sudah ada?"</string>
+    <string name="vpn_set_vpn_title" msgid="4009987321156037267">"Setel VPN selalu aktif?"</string>
+    <string name="vpn_first_always_on_vpn_message" msgid="3025322109743675467">"Jika setelan ini diaktifkan, sambungan internet akan tersedia jika VPN berhasil terhubung"</string>
+    <string name="vpn_replace_always_on_vpn_enable_message" msgid="2577928591361606641">"VPN yang sudah ada akan digantikan, dan sambungan internet akan tersedia jika VPN berhasil terhubung"</string>
+    <string name="vpn_replace_always_on_vpn_disable_message" msgid="3011818750025879902">"Anda sudah terhubung ke VPN selalu aktif. Jika Anda terhubung ke VPN yang berbeda, VPN yang sudah ada akan digantikan, dan mode selalu aktif akan dinonaktifkan."</string>
+    <string name="vpn_replace_vpn_message" msgid="5611635724578812860">"Anda sudah terhubung ke VPN. Jika Anda terhubung ke VPN yang berbeda, VPN yang sudah ada akan digantikan."</string>
+    <string name="vpn_turn_on" msgid="2363136869284273872">"Aktifkan"</string>
     <string name="vpn_cant_connect_title" msgid="4517706987875907511">"<xliff:g id="VPN_NAME">%1$s</xliff:g> tidak dapat terhubung"</string>
     <string name="vpn_cant_connect_message" msgid="2593197919352621279">"Aplikasi ini tidak mendukung VPN yang selalu aktif."</string>
     <string name="vpn_title" msgid="6317731879966640551">"VPN"</string>
@@ -2536,8 +2529,7 @@
     </plurals>
     <string name="network_dashboard_title" msgid="4771589228992391573">"Jaringan &amp; Internet"</string>
     <string name="connected_devices_dashboard_title" msgid="2355264951438890709">"Perangkat yang terhubung"</string>
-    <!-- no translation found for system_dashboard_summary (6112602136713843779) -->
-    <skip />
+    <string name="system_dashboard_summary" msgid="6112602136713843779">"Bahasa: <xliff:g id="LANGUAGE">%1$s</xliff:g>"</string>
     <string name="search_results_title" msgid="1796252422574886932">"Setelan"</string>
     <string name="search_menu" msgid="6283419262313758339">"Setelan penelusuran"</string>
     <string name="query_hint_text" msgid="3350700807437473939">"Setelan penelusuran"</string>
diff --git a/res/values-kk-rKZ/strings.xml b/res/values-kk-rKZ/strings.xml
index 97fabcb..1d01165 100644
--- a/res/values-kk-rKZ/strings.xml
+++ b/res/values-kk-rKZ/strings.xml
@@ -2280,20 +2280,13 @@
     <string name="vpn_disconnect" msgid="7426570492642111171">"Ажырату"</string>
     <string name="vpn_version" msgid="1939804054179766249">"Нұсқасы: <xliff:g id="VERSION">%s</xliff:g>"</string>
     <string name="vpn_forget_long" msgid="2232239391189465752">"VPN ұмыту"</string>
-    <!-- no translation found for vpn_replace_vpn_title (2963898301277610248) -->
-    <skip />
-    <!-- no translation found for vpn_set_vpn_title (4009987321156037267) -->
-    <skip />
-    <!-- no translation found for vpn_first_always_on_vpn_message (3025322109743675467) -->
-    <skip />
-    <!-- no translation found for vpn_replace_always_on_vpn_enable_message (2577928591361606641) -->
-    <skip />
-    <!-- no translation found for vpn_replace_always_on_vpn_disable_message (3011818750025879902) -->
-    <skip />
-    <!-- no translation found for vpn_replace_vpn_message (5611635724578812860) -->
-    <skip />
-    <!-- no translation found for vpn_turn_on (2363136869284273872) -->
-    <skip />
+    <string name="vpn_replace_vpn_title" msgid="2963898301277610248">"Бар VPN қолданбасын ауыстыру керек пе?"</string>
+    <string name="vpn_set_vpn_title" msgid="4009987321156037267">"Әрқашан қосулы VPN режимін орнату"</string>
+    <string name="vpn_first_always_on_vpn_message" msgid="3025322109743675467">"Бұл параметрді іске қоссаңыз, VPN сәтті қосылғанша интернетке қосыла алмайсыз"</string>
+    <string name="vpn_replace_always_on_vpn_enable_message" msgid="2577928591361606641">"Қолданыстағы VPN желісі алмастырылады және VPN сәтті қосылғанша интернетке қосыла алмайсыз"</string>
+    <string name="vpn_replace_always_on_vpn_disable_message" msgid="3011818750025879902">"Сіз әрқашан қосулы VPN желісіне қосылдыңыз. Егер басқа желіге қосылсаңыз, қолданыстағы VPN желісі алмастырылады және әрқашан қосулы режим өшіріледі."</string>
+    <string name="vpn_replace_vpn_message" msgid="5611635724578812860">"Сіз VPN желісіне қосылдыңыз. Егер басқа желіге қосылсаңыз, қолданыстағы VPN желісі алмастырылады."</string>
+    <string name="vpn_turn_on" msgid="2363136869284273872">"Қосу"</string>
     <string name="vpn_cant_connect_title" msgid="4517706987875907511">"<xliff:g id="VPN_NAME">%1$s</xliff:g> қосыла алмайды"</string>
     <string name="vpn_cant_connect_message" msgid="2593197919352621279">"Бұл қолданба \"әрқашан қосулы\" VPN желісін қолдамайды."</string>
     <string name="vpn_title" msgid="6317731879966640551">"VPN (Виртуалды жеке желі)"</string>
@@ -2536,8 +2529,7 @@
     </plurals>
     <string name="network_dashboard_title" msgid="4771589228992391573">"Желі және интернет"</string>
     <string name="connected_devices_dashboard_title" msgid="2355264951438890709">"Қосылған құрылғылар"</string>
-    <!-- no translation found for system_dashboard_summary (6112602136713843779) -->
-    <skip />
+    <string name="system_dashboard_summary" msgid="6112602136713843779">"Тіл: <xliff:g id="LANGUAGE">%1$s</xliff:g>"</string>
     <string name="search_results_title" msgid="1796252422574886932">"Параметрлер"</string>
     <string name="search_menu" msgid="6283419262313758339">"Іздеу параметрлері"</string>
     <string name="query_hint_text" msgid="3350700807437473939">"Іздеу параметрлері"</string>
diff --git a/res/values-kn-rIN/strings.xml b/res/values-kn-rIN/strings.xml
index 63fa87b..1ad76f7 100644
--- a/res/values-kn-rIN/strings.xml
+++ b/res/values-kn-rIN/strings.xml
@@ -2280,20 +2280,13 @@
     <string name="vpn_disconnect" msgid="7426570492642111171">"ಸಂಪರ್ಕ ಕಡಿತಗೊಳಿಸು"</string>
     <string name="vpn_version" msgid="1939804054179766249">"<xliff:g id="VERSION">%s</xliff:g> ಆವೃತ್ತಿ"</string>
     <string name="vpn_forget_long" msgid="2232239391189465752">"VPN ಮರೆತುಬಿಡು"</string>
-    <!-- no translation found for vpn_replace_vpn_title (2963898301277610248) -->
-    <skip />
-    <!-- no translation found for vpn_set_vpn_title (4009987321156037267) -->
-    <skip />
-    <!-- no translation found for vpn_first_always_on_vpn_message (3025322109743675467) -->
-    <skip />
-    <!-- no translation found for vpn_replace_always_on_vpn_enable_message (2577928591361606641) -->
-    <skip />
-    <!-- no translation found for vpn_replace_always_on_vpn_disable_message (3011818750025879902) -->
-    <skip />
-    <!-- no translation found for vpn_replace_vpn_message (5611635724578812860) -->
-    <skip />
-    <!-- no translation found for vpn_turn_on (2363136869284273872) -->
-    <skip />
+    <string name="vpn_replace_vpn_title" msgid="2963898301277610248">"ಅಸ್ತಿತ್ವದಲ್ಲಿರುವ VPN ಸ್ಥಾನಾಂತರಿಸುವುದೇ?"</string>
+    <string name="vpn_set_vpn_title" msgid="4009987321156037267">"VPN ಯಾವಾಗಲೂ ಆನ್ ಆಗಿರುವಂತೆ ಹೊಂದಿಸುವುದೇ?"</string>
+    <string name="vpn_first_always_on_vpn_message" msgid="3025322109743675467">"ಈ ಸೆಟ್ಟಿಂಗ್ ಆನ್ ಮಾಡುವ ಮೂಲಕ, VPN ಯಶಸ್ವಿಯಾಗಿ ಸಂಪರ್ಕವಾಗುವವರೆಗೆ ನೀವು ಇಂಟರ್ನೆಟ್ ಸಂಪರ್ಕವನ್ನು ಹೊಂದುವುದಿಲ್ಲ"</string>
+    <string name="vpn_replace_always_on_vpn_enable_message" msgid="2577928591361606641">"ನಿಮ್ಮ ಅಸ್ತಿತ್ವದಲ್ಲಿರುವ VPN ಅನ್ನು ಸ್ಥಾನಾಂತರಿಸಲಾಗುವುದು ಮತ್ತು VPN ಯಶಸ್ವಿಯಾಗಿ ಸಂಪರ್ಕವಾಗುವವರೆಗೆ ನೀವು ಇಂಟರ್ನೆಟ್ ಸಂಪರ್ಕವನ್ನು ಹೊಂದುವುದಿಲ್ಲ"</string>
+    <string name="vpn_replace_always_on_vpn_disable_message" msgid="3011818750025879902">"ಯಾವಾಗಲೂ ಆನ್ ಆಗಿರುವ VPN ಗೆ ನೀವು ಈಗಾಗಲೇ ಸಂಪರ್ಕಗೊಂಡಿರುವಿರಿ. ನೀವು ಬೇರೊಂದಕ್ಕೆ ಸಂಪರ್ಕಗೊಂಡಲ್ಲಿ, ನಿಮ್ಮ ಅಸ್ತಿತ್ವದಲ್ಲಿರುವ VPN ಅನ್ನು ಸ್ಥಾನಾಂತರಿಸಲಾಗುವುದು ಮತ್ತು ಯಾವಾಗಲೂ ಆನ್ ಮೋಡ್‌ನಲ್ಲಿರುವುದನ್ನು ಆಫ್ ಮಾಡಲಾಗುತ್ತದೆ."</string>
+    <string name="vpn_replace_vpn_message" msgid="5611635724578812860">"ನೀವು ಈಗಾಗಲೇ VPN ಗೆ ಸಂಪರ್ಕ ಹೊಂದಿರುವಿರಿ. ಒಂದು ವೇಳೆ ನೀವು ಬೇರೊಂದಕ್ಕೆ ಸಂಪರ್ಕಗೊಂಡಲ್ಲಿ, ನಿಮ್ಮ ಅಸ್ತಿತ್ವದಲ್ಲಿರುವ VPN ಅನ್ನು ಸ್ಥಾನಾಂತರಿಸಲಾಗುವುದು."</string>
+    <string name="vpn_turn_on" msgid="2363136869284273872">"ಆನ್ ಮಾಡು"</string>
     <string name="vpn_cant_connect_title" msgid="4517706987875907511">"<xliff:g id="VPN_NAME">%1$s</xliff:g> ಸಂಪರ್ಕ ಸಾಧ್ಯವಿಲ್ಲ"</string>
     <string name="vpn_cant_connect_message" msgid="2593197919352621279">"ಈ ಅಪ್ಲಿಕೇಶನ್ ಯಾವಾಗಲೂ-ಆನ್ VPN ಬೆಂಬಲಿಸುವುದಿಲ್ಲ."</string>
     <string name="vpn_title" msgid="6317731879966640551">"VPN"</string>
@@ -2536,8 +2529,7 @@
     </plurals>
     <string name="network_dashboard_title" msgid="4771589228992391573">"ನೆಟ್‌ವರ್ಕ್ ಮತ್ತು ಇಂಟರ್ನೆಟ್"</string>
     <string name="connected_devices_dashboard_title" msgid="2355264951438890709">"ಸಂಪರ್ಕ ಹೊಂದಿರುವ ಸಾಧನಗಳು"</string>
-    <!-- no translation found for system_dashboard_summary (6112602136713843779) -->
-    <skip />
+    <string name="system_dashboard_summary" msgid="6112602136713843779">"ಭಾಷೆ: <xliff:g id="LANGUAGE">%1$s</xliff:g>"</string>
     <string name="search_results_title" msgid="1796252422574886932">"ಸೆಟ್ಟಿಂಗ್‌ಗಳು"</string>
     <string name="search_menu" msgid="6283419262313758339">"ಹುಡುಕಾಟ ಸೆಟ್ಟಿಂಗ್‌ಗಳು"</string>
     <string name="query_hint_text" msgid="3350700807437473939">"ಹುಡುಕಾಟ ಸೆಟ್ಟಿಂಗ್‌ಗಳು"</string>
diff --git a/res/values-ky-rKG/strings.xml b/res/values-ky-rKG/strings.xml
index 3310d53..8615106 100644
--- a/res/values-ky-rKG/strings.xml
+++ b/res/values-ky-rKG/strings.xml
@@ -2279,20 +2279,13 @@
     <string name="vpn_disconnect" msgid="7426570492642111171">"Ажыратуу"</string>
     <string name="vpn_version" msgid="1939804054179766249">"<xliff:g id="VERSION">%s</xliff:g> версиясы"</string>
     <string name="vpn_forget_long" msgid="2232239391189465752">"VPN профили унутулсун"</string>
-    <!-- no translation found for vpn_replace_vpn_title (2963898301277610248) -->
-    <skip />
-    <!-- no translation found for vpn_set_vpn_title (4009987321156037267) -->
-    <skip />
-    <!-- no translation found for vpn_first_always_on_vpn_message (3025322109743675467) -->
-    <skip />
-    <!-- no translation found for vpn_replace_always_on_vpn_enable_message (2577928591361606641) -->
-    <skip />
-    <!-- no translation found for vpn_replace_always_on_vpn_disable_message (3011818750025879902) -->
-    <skip />
-    <!-- no translation found for vpn_replace_vpn_message (5611635724578812860) -->
-    <skip />
-    <!-- no translation found for vpn_turn_on (2363136869284273872) -->
-    <skip />
+    <string name="vpn_replace_vpn_title" msgid="2963898301277610248">"Учурдагы VPN алмаштырылсынбы?"</string>
+    <string name="vpn_set_vpn_title" msgid="4009987321156037267">"Дайым иштеген VPN\'ди жөндөөбу?"</string>
+    <string name="vpn_first_always_on_vpn_message" msgid="3025322109743675467">"Бул орнотууну куйгүзүү менен VPN ийгиликтүү туташмайынча, интернетиңиз жок болуп турат"</string>
+    <string name="vpn_replace_always_on_vpn_enable_message" msgid="2577928591361606641">"Күйгүзулгөн VPN\'ңиз алмаштырылып, VPN ийгиликтүү туташмайынча, интернетиңиз жок болуп турат"</string>
+    <string name="vpn_replace_always_on_vpn_disable_message" msgid="3011818750025879902">"Дайым иштеген VPN кызматыңыз туташылган. Эгер башкасына туташсаңыз, учурдагы VPN алмаштырылып, дайым күйүк режими өчүрүлүп калат."</string>
+    <string name="vpn_replace_vpn_message" msgid="5611635724578812860">"VPN кызматы туташылган. Эгер башкасына туташсаңыз, учурдагы VPN өчүрүлөт."</string>
+    <string name="vpn_turn_on" msgid="2363136869284273872">"Күйгүзүү"</string>
     <string name="vpn_cant_connect_title" msgid="4517706987875907511">"<xliff:g id="VPN_NAME">%1$s</xliff:g> туташпай жатат"</string>
     <string name="vpn_cant_connect_message" msgid="2593197919352621279">"Бул колдонмо дайым иштеген VPN кызматына туташпайт."</string>
     <string name="vpn_title" msgid="6317731879966640551">"VPN"</string>
@@ -2535,8 +2528,7 @@
     </plurals>
     <string name="network_dashboard_title" msgid="4771589228992391573">"Тармак жана Интернет"</string>
     <string name="connected_devices_dashboard_title" msgid="2355264951438890709">"Туташкан түзмөктөр"</string>
-    <!-- no translation found for system_dashboard_summary (6112602136713843779) -->
-    <skip />
+    <string name="system_dashboard_summary" msgid="6112602136713843779">"Тили: <xliff:g id="LANGUAGE">%1$s</xliff:g>"</string>
     <string name="search_results_title" msgid="1796252422574886932">"Жөндөөлөр"</string>
     <string name="search_menu" msgid="6283419262313758339">"Издөө жөндөөлөрү"</string>
     <string name="query_hint_text" msgid="3350700807437473939">"Издөө жөндөөлөрү"</string>
diff --git a/res/values-lo-rLA/strings.xml b/res/values-lo-rLA/strings.xml
index cf7ec5f..6440bc2 100644
--- a/res/values-lo-rLA/strings.xml
+++ b/res/values-lo-rLA/strings.xml
@@ -2280,20 +2280,13 @@
     <string name="vpn_disconnect" msgid="7426570492642111171">"ຕັດການເຊື່ອມຕໍ່"</string>
     <string name="vpn_version" msgid="1939804054179766249">"ເວີ​ຊັນ <xliff:g id="VERSION">%s</xliff:g>"</string>
     <string name="vpn_forget_long" msgid="2232239391189465752">"ລືມ VPN"</string>
-    <!-- no translation found for vpn_replace_vpn_title (2963898301277610248) -->
-    <skip />
-    <!-- no translation found for vpn_set_vpn_title (4009987321156037267) -->
-    <skip />
-    <!-- no translation found for vpn_first_always_on_vpn_message (3025322109743675467) -->
-    <skip />
-    <!-- no translation found for vpn_replace_always_on_vpn_enable_message (2577928591361606641) -->
-    <skip />
-    <!-- no translation found for vpn_replace_always_on_vpn_disable_message (3011818750025879902) -->
-    <skip />
-    <!-- no translation found for vpn_replace_vpn_message (5611635724578812860) -->
-    <skip />
-    <!-- no translation found for vpn_turn_on (2363136869284273872) -->
-    <skip />
+    <string name="vpn_replace_vpn_title" msgid="2963898301277610248">"ຂຽນທັບ VPN ທີ່ມີຢູ່ກ່ອນແລ້ວຂອງທ່ານບໍ?"</string>
+    <string name="vpn_set_vpn_title" msgid="4009987321156037267">"Set always-on VPN?"</string>
+    <string name="vpn_first_always_on_vpn_message" msgid="3025322109743675467">"By turning on this setting, you won\'t have an Internet connection until the VPN successfully connects"</string>
+    <string name="vpn_replace_always_on_vpn_enable_message" msgid="2577928591361606641">"Your existing VPN will be replaced, and you won\'t have an Internet connection until the VPN successfully connects"</string>
+    <string name="vpn_replace_always_on_vpn_disable_message" msgid="3011818750025879902">"You\'re already connected to an always-on VPN. If you connect to a different one, your existing VPN will be replaced, and always-on mode will turn off."</string>
+    <string name="vpn_replace_vpn_message" msgid="5611635724578812860">"ທ່ານເຊື່ອມຕໍ່ຫາ VPN ຢູ່ກ່ອນແລ້ວ. ຫາກທ່ານເຊື່ອມຕໍ່ຫາອັນອື່ນອີກ, VPN ທີ່ມີຢູ່ແລ້ວຂອງທ່ານຈະຖືກແທນທີ່."</string>
+    <string name="vpn_turn_on" msgid="2363136869284273872">"ເປີດໃຊ້"</string>
     <string name="vpn_cant_connect_title" msgid="4517706987875907511">"<xliff:g id="VPN_NAME">%1$s</xliff:g> ບໍ່ສາມາດເຊື່ອມຕໍ່ໄດ້"</string>
     <string name="vpn_cant_connect_message" msgid="2593197919352621279">"ແອັບນີ້ບໍ່ຮອງຮັບ VPN ແບບເປີດຕະຫຼອດເວລາ."</string>
     <string name="vpn_title" msgid="6317731879966640551">"VPN"</string>
@@ -2536,8 +2529,7 @@
     </plurals>
     <string name="network_dashboard_title" msgid="4771589228992391573">"ເຄືອຂ່າຍ ແລະ ອິນເຕີເນັດ"</string>
     <string name="connected_devices_dashboard_title" msgid="2355264951438890709">"ອຸປະກອນທີ່ເຊື່ອມຕໍ່ແລ້ວ"</string>
-    <!-- no translation found for system_dashboard_summary (6112602136713843779) -->
-    <skip />
+    <string name="system_dashboard_summary" msgid="6112602136713843779">"Language: <xliff:g id="LANGUAGE">%1$s</xliff:g>"</string>
     <string name="search_results_title" msgid="1796252422574886932">"​ການ​ຕັ້ງ​ຄ່າ"</string>
     <string name="search_menu" msgid="6283419262313758339">"​ການ​ຕັ້ງ​ຄ່າ​ການ​ຊອກ​ຫາ"</string>
     <string name="query_hint_text" msgid="3350700807437473939">"​ການ​ຕັ້ງ​ຄ່າ​ການ​ຊອກ​ຫາ"</string>
diff --git a/res/values-mk-rMK/strings.xml b/res/values-mk-rMK/strings.xml
index 87ec149..cf570c5 100644
--- a/res/values-mk-rMK/strings.xml
+++ b/res/values-mk-rMK/strings.xml
@@ -2280,20 +2280,13 @@
     <string name="vpn_disconnect" msgid="7426570492642111171">"Исклучи"</string>
     <string name="vpn_version" msgid="1939804054179766249">"Верзија <xliff:g id="VERSION">%s</xliff:g>"</string>
     <string name="vpn_forget_long" msgid="2232239391189465752">"Заборави VPN"</string>
-    <!-- no translation found for vpn_replace_vpn_title (2963898301277610248) -->
-    <skip />
-    <!-- no translation found for vpn_set_vpn_title (4009987321156037267) -->
-    <skip />
-    <!-- no translation found for vpn_first_always_on_vpn_message (3025322109743675467) -->
-    <skip />
-    <!-- no translation found for vpn_replace_always_on_vpn_enable_message (2577928591361606641) -->
-    <skip />
-    <!-- no translation found for vpn_replace_always_on_vpn_disable_message (3011818750025879902) -->
-    <skip />
-    <!-- no translation found for vpn_replace_vpn_message (5611635724578812860) -->
-    <skip />
-    <!-- no translation found for vpn_turn_on (2363136869284273872) -->
-    <skip />
+    <string name="vpn_replace_vpn_title" msgid="2963898301277610248">"Да се замени постојната VPN?"</string>
+    <string name="vpn_set_vpn_title" msgid="4009987321156037267">"Да се постави „секогаш вклучена“ VPN?"</string>
+    <string name="vpn_first_always_on_vpn_message" msgid="3025322109743675467">"Ако ја вклучите поставкава, нема да имате интернет-врска сѐ додека VPN успешно се поврзе"</string>
+    <string name="vpn_replace_always_on_vpn_enable_message" msgid="2577928591361606641">"Вашата постојна VPN ќе се замени и нема да имате интернет-врска сѐ додека VPN успешно се поврзе"</string>
+    <string name="vpn_replace_always_on_vpn_disable_message" msgid="3011818750025879902">"Веќе сте поврзани на „секогаш вклучена“ VPN. Ако се поврзете на друга мрежа, вашата постојна VPN ќе се замени и режимот „секогаш вклучена“ ќе се исклучи."</string>
+    <string name="vpn_replace_vpn_message" msgid="5611635724578812860">"Веќе сте поврзани на VPN. Ако се поврзете на друга мрежа, вашата постојна VPN ќе се замени."</string>
+    <string name="vpn_turn_on" msgid="2363136869284273872">"Вклучете"</string>
     <string name="vpn_cant_connect_title" msgid="4517706987875907511">"<xliff:g id="VPN_NAME">%1$s</xliff:g> не може да се поврзе"</string>
     <string name="vpn_cant_connect_message" msgid="2593197919352621279">"Оваа апликација не поддржува постојано вклучен VPN."</string>
     <string name="vpn_title" msgid="6317731879966640551">"Виртуелна приватна мрежа (VPN)"</string>
@@ -2536,8 +2529,7 @@
     </plurals>
     <string name="network_dashboard_title" msgid="4771589228992391573">"Мрежа и Интернет"</string>
     <string name="connected_devices_dashboard_title" msgid="2355264951438890709">"Поврзани уреди"</string>
-    <!-- no translation found for system_dashboard_summary (6112602136713843779) -->
-    <skip />
+    <string name="system_dashboard_summary" msgid="6112602136713843779">"Јазик: <xliff:g id="LANGUAGE">%1$s</xliff:g>"</string>
     <string name="search_results_title" msgid="1796252422574886932">"Поставки"</string>
     <string name="search_menu" msgid="6283419262313758339">"Поставки за пребарување"</string>
     <string name="query_hint_text" msgid="3350700807437473939">"Поставки за пребарување"</string>
diff --git a/res/values-mn-rMN/strings.xml b/res/values-mn-rMN/strings.xml
index 88d7d15..6185bcd 100644
--- a/res/values-mn-rMN/strings.xml
+++ b/res/values-mn-rMN/strings.xml
@@ -1690,7 +1690,7 @@
     <string name="battery_history_minutes_no_seconds" msgid="7780294302606853082">"<xliff:g id="MINUTES">%1$d</xliff:g>м"</string>
     <string name="usage_stats_label" msgid="5890846333487083609">"Ашиглалтын статистик"</string>
     <string name="testing_usage_stats" msgid="7823048598893937339">"Ашиглалтын статистик"</string>
-    <string name="display_order_text" msgid="8592776965827565271">"Эрэмблэх:"</string>
+    <string name="display_order_text" msgid="8592776965827565271">"Эрэмбэлэх:"</string>
     <string name="app_name_label" msgid="5440362857006046193">"Апп"</string>
     <string name="last_time_used_label" msgid="8459441968795479307">"Ашигласан сүүлийн цаг"</string>
     <string name="usage_time_label" msgid="295954901452833058">"Ашиглалтын цаг"</string>
diff --git a/res/values-mr-rIN/strings.xml b/res/values-mr-rIN/strings.xml
index ee3aa95..d5bd82a 100644
--- a/res/values-mr-rIN/strings.xml
+++ b/res/values-mr-rIN/strings.xml
@@ -2280,20 +2280,13 @@
     <string name="vpn_disconnect" msgid="7426570492642111171">"‍डिस्कनेक्ट करा"</string>
     <string name="vpn_version" msgid="1939804054179766249">"आवृत्ती <xliff:g id="VERSION">%s</xliff:g>"</string>
     <string name="vpn_forget_long" msgid="2232239391189465752">"VPN विसरा"</string>
-    <!-- no translation found for vpn_replace_vpn_title (2963898301277610248) -->
-    <skip />
-    <!-- no translation found for vpn_set_vpn_title (4009987321156037267) -->
-    <skip />
-    <!-- no translation found for vpn_first_always_on_vpn_message (3025322109743675467) -->
-    <skip />
-    <!-- no translation found for vpn_replace_always_on_vpn_enable_message (2577928591361606641) -->
-    <skip />
-    <!-- no translation found for vpn_replace_always_on_vpn_disable_message (3011818750025879902) -->
-    <skip />
-    <!-- no translation found for vpn_replace_vpn_message (5611635724578812860) -->
-    <skip />
-    <!-- no translation found for vpn_turn_on (2363136869284273872) -->
-    <skip />
+    <string name="vpn_replace_vpn_title" msgid="2963898301277610248">"विद्यमान VPN पुनर्स्थित करायचे?"</string>
+    <string name="vpn_set_vpn_title" msgid="4009987321156037267">"नेहमी-चालू VPN सेट करायचे?"</string>
+    <string name="vpn_first_always_on_vpn_message" msgid="3025322109743675467">"हे सेटिंग चालू करून, VPN यशस्वीरित्या कनेक्ट करेपर्यंत आपल्याकडे इंटरनेट कनेक्शन असणार नाही"</string>
+    <string name="vpn_replace_always_on_vpn_enable_message" msgid="2577928591361606641">"आपले विद्यमान VPN पुनर्स्थित केले जाईल आणि VPN यशस्वीरित्या कनेक्ट करेपर्यंत आपल्याकडे इंटरनेट कनेक्शन असणार नाही"</string>
+    <string name="vpn_replace_always_on_vpn_disable_message" msgid="3011818750025879902">"आपण आधीपासून नेहमी-चालू VPN शी कनेक्ट केले आहे. आपण एका भिन्न VPN शी कनेक्ट केल्यास, आपले विद्यमान VPN पुनर्स्थित केले जाईल आणि नेहमी-चालू मोड बंद होईल."</string>
+    <string name="vpn_replace_vpn_message" msgid="5611635724578812860">"आपण आधीपासून एका VPN शी कनेक्ट केले आहे. आपण भिन्न VPN शी कनेक्ट केल्यास, आपले विद्यमान VPN बदलले जाईल."</string>
+    <string name="vpn_turn_on" msgid="2363136869284273872">"चालू करा"</string>
     <string name="vpn_cant_connect_title" msgid="4517706987875907511">"<xliff:g id="VPN_NAME">%1$s</xliff:g> कनेक्ट करू शकत नाही"</string>
     <string name="vpn_cant_connect_message" msgid="2593197919352621279">"हा अॅप नेहमी-चालू VPN ला समर्थन देत नाही."</string>
     <string name="vpn_title" msgid="6317731879966640551">"VPN"</string>
@@ -2536,8 +2529,7 @@
     </plurals>
     <string name="network_dashboard_title" msgid="4771589228992391573">"नेटवर्क आणि इंटरनेट"</string>
     <string name="connected_devices_dashboard_title" msgid="2355264951438890709">"कनेक्‍ट केलेले डिव्‍हाइसेस"</string>
-    <!-- no translation found for system_dashboard_summary (6112602136713843779) -->
-    <skip />
+    <string name="system_dashboard_summary" msgid="6112602136713843779">"भाषा: <xliff:g id="LANGUAGE">%1$s</xliff:g>"</string>
     <string name="search_results_title" msgid="1796252422574886932">"सेटिंग्ज"</string>
     <string name="search_menu" msgid="6283419262313758339">"शोध सेटिंग्ज"</string>
     <string name="query_hint_text" msgid="3350700807437473939">"शोध सेटिंग्ज"</string>
diff --git a/res/values-my-rMM/strings.xml b/res/values-my-rMM/strings.xml
index 4be666c..f905cf5 100644
--- a/res/values-my-rMM/strings.xml
+++ b/res/values-my-rMM/strings.xml
@@ -2280,20 +2280,13 @@
     <string name="vpn_disconnect" msgid="7426570492642111171">"ဆက်သွယ်မှု ဖြတ်ရန်"</string>
     <string name="vpn_version" msgid="1939804054179766249">"ဗားရှင်း <xliff:g id="VERSION">%s</xliff:g>"</string>
     <string name="vpn_forget_long" msgid="2232239391189465752">"VPN ကိုမေ့လိုက်ပါ"</string>
-    <!-- no translation found for vpn_replace_vpn_title (2963898301277610248) -->
-    <skip />
-    <!-- no translation found for vpn_set_vpn_title (4009987321156037267) -->
-    <skip />
-    <!-- no translation found for vpn_first_always_on_vpn_message (3025322109743675467) -->
-    <skip />
-    <!-- no translation found for vpn_replace_always_on_vpn_enable_message (2577928591361606641) -->
-    <skip />
-    <!-- no translation found for vpn_replace_always_on_vpn_disable_message (3011818750025879902) -->
-    <skip />
-    <!-- no translation found for vpn_replace_vpn_message (5611635724578812860) -->
-    <skip />
-    <!-- no translation found for vpn_turn_on (2363136869284273872) -->
-    <skip />
+    <string name="vpn_replace_vpn_title" msgid="2963898301277610248">"ရှိပြီးသား VPN ကိုအစားထိုးမလား။"</string>
+    <string name="vpn_set_vpn_title" msgid="4009987321156037267">"VPN ကို အမြဲတမ်းဖွင့်ထားရန် သတ်မှတ်မလား။"</string>
+    <string name="vpn_first_always_on_vpn_message" msgid="3025322109743675467">"ဤဆက်တင်ကို ဖွင့်ခြင်းဖြင့် VPN အောင်မြင်စွာ မချိတ်မချင်း သင့်တွင် အင်တာနက်ချိတ်ဆက်မှု ရှိမည်မဟုတ်ပါ"</string>
+    <string name="vpn_replace_always_on_vpn_enable_message" msgid="2577928591361606641">"သင်၏ လက်ရှိ VPN ကို အစားထိုးသွားမည်ဖြစ်၍ VPN အောင်မြင်စွာ မချိတ်မချင်း သင့်ထံတွင် အင်တာနက် ချိတ်ဆက်မှု ရှိမည်မဟုတ်ပါ"</string>
+    <string name="vpn_replace_always_on_vpn_disable_message" msgid="3011818750025879902">"သင်သည် အမြဲတမ်းဖွင့်ထားရသော VPN နှင့် ချိတ်ဆက်ပြီးသားဖြစ်သည်။ အခြားတစ်ခုနှင့် ချိတ်ဆက်လိုက်လျှင် လက်ရှိ VPN ကို အစားထိုးသွားမည်ဖြစ်၍ အမြဲဖွင့်ထားရသော မုဒ်သည် ပိတ်သွားပါမည်။"</string>
+    <string name="vpn_replace_vpn_message" msgid="5611635724578812860">"VPN သို့ ချိတ်ဆက်ပြီးသား ဖြစ်ပါသည်။ အခြားတစ်ခုသို့ ချိတ်ဆက်လျှင် လက်ရှိ VPN ကိုအစားထိုးသွားပါမည်။"</string>
+    <string name="vpn_turn_on" msgid="2363136869284273872">"ဖွင့်ရန်"</string>
     <string name="vpn_cant_connect_title" msgid="4517706987875907511">"<xliff:g id="VPN_NAME">%1$s</xliff:g> ချိတ်ဆက်၍မရပါ"</string>
     <string name="vpn_cant_connect_message" msgid="2593197919352621279">"ဤအက်ပ်သည် VPN အမြဲတမ်းဖွင့်ထားခြင်းကို ပံ့ပိုးမှုမရှိပါ။"</string>
     <string name="vpn_title" msgid="6317731879966640551">"VPN"</string>
@@ -2536,8 +2529,7 @@
     </plurals>
     <string name="network_dashboard_title" msgid="4771589228992391573">"ကွန်ရက်နှင့် အင်တာနက်"</string>
     <string name="connected_devices_dashboard_title" msgid="2355264951438890709">"ချိတ်ဆက်ထားသော စက်ပစ္စည်းများ"</string>
-    <!-- no translation found for system_dashboard_summary (6112602136713843779) -->
-    <skip />
+    <string name="system_dashboard_summary" msgid="6112602136713843779">"ဘာသာစကား - <xliff:g id="LANGUAGE">%1$s</xliff:g>"</string>
     <string name="search_results_title" msgid="1796252422574886932">"ဆက်တင်များ"</string>
     <string name="search_menu" msgid="6283419262313758339">"ရှာဖွေမှု ဆက်တင်များ"</string>
     <string name="query_hint_text" msgid="3350700807437473939">"ရှာဖွေမှု ဆက်တင်များ"</string>
diff --git a/res/values-nb/strings.xml b/res/values-nb/strings.xml
index 8270ac0..1b9a922 100644
--- a/res/values-nb/strings.xml
+++ b/res/values-nb/strings.xml
@@ -2280,20 +2280,13 @@
     <string name="vpn_disconnect" msgid="7426570492642111171">"Koble fra"</string>
     <string name="vpn_version" msgid="1939804054179766249">"Versjon <xliff:g id="VERSION">%s</xliff:g>"</string>
     <string name="vpn_forget_long" msgid="2232239391189465752">"Glem VPN-profilen"</string>
-    <!-- no translation found for vpn_replace_vpn_title (2963898301277610248) -->
-    <skip />
-    <!-- no translation found for vpn_set_vpn_title (4009987321156037267) -->
-    <skip />
-    <!-- no translation found for vpn_first_always_on_vpn_message (3025322109743675467) -->
-    <skip />
-    <!-- no translation found for vpn_replace_always_on_vpn_enable_message (2577928591361606641) -->
-    <skip />
-    <!-- no translation found for vpn_replace_always_on_vpn_disable_message (3011818750025879902) -->
-    <skip />
-    <!-- no translation found for vpn_replace_vpn_message (5611635724578812860) -->
-    <skip />
-    <!-- no translation found for vpn_turn_on (2363136869284273872) -->
-    <skip />
+    <string name="vpn_replace_vpn_title" msgid="2963898301277610248">"Vil du erstatte det nåværende VPN-et?"</string>
+    <string name="vpn_set_vpn_title" msgid="4009987321156037267">"Vil du angi alltid på-VPN?"</string>
+    <string name="vpn_first_always_on_vpn_message" msgid="3025322109743675467">"Ved å slå på denne innstillingen kommer du ikke til å ha Internett-tilkobling før VPN-tilkoblingen er opprettet."</string>
+    <string name="vpn_replace_always_on_vpn_enable_message" msgid="2577928591361606641">"Det eksisterende VPN-et ditt blir byttet ut, og du kommer ikke til å ha Internett-tilkobling før VPN-tilkoblingen er opprettet."</string>
+    <string name="vpn_replace_always_on_vpn_disable_message" msgid="3011818750025879902">"Du er allerede koblet til et alltid på-VPN. Hvis du kobler til et annet, blir det eksisterende VPN-et byttet ut, og alltid på-modus blir slått av."</string>
+    <string name="vpn_replace_vpn_message" msgid="5611635724578812860">"Du er allerede koblet til et VPN. Hvis du kobler til et nytt VPN, erstattes tilkoblingen til det nåværende VPN-et."</string>
+    <string name="vpn_turn_on" msgid="2363136869284273872">"Slå på"</string>
     <string name="vpn_cant_connect_title" msgid="4517706987875907511">"Kan ikke koble til <xliff:g id="VPN_NAME">%1$s</xliff:g>"</string>
     <string name="vpn_cant_connect_message" msgid="2593197919352621279">"Denne appen støtter ikke alltid-på VPN."</string>
     <string name="vpn_title" msgid="6317731879966640551">"VPN"</string>
@@ -2536,8 +2529,7 @@
     </plurals>
     <string name="network_dashboard_title" msgid="4771589228992391573">"Nettverk og Internett"</string>
     <string name="connected_devices_dashboard_title" msgid="2355264951438890709">"Tilkoblede enheter"</string>
-    <!-- no translation found for system_dashboard_summary (6112602136713843779) -->
-    <skip />
+    <string name="system_dashboard_summary" msgid="6112602136713843779">"Språk: <xliff:g id="LANGUAGE">%1$s</xliff:g>"</string>
     <string name="search_results_title" msgid="1796252422574886932">"Innstillinger"</string>
     <string name="search_menu" msgid="6283419262313758339">"Søkeinnstillinger"</string>
     <string name="query_hint_text" msgid="3350700807437473939">"Søkeinnstillinger"</string>
diff --git a/res/values-ne-rNP/strings.xml b/res/values-ne-rNP/strings.xml
index 4bc5ea9..d8c7a3e 100644
--- a/res/values-ne-rNP/strings.xml
+++ b/res/values-ne-rNP/strings.xml
@@ -2280,20 +2280,13 @@
     <string name="vpn_disconnect" msgid="7426570492642111171">"विच्छेदन गर्नुहोस्"</string>
     <string name="vpn_version" msgid="1939804054179766249">"संस्करण <xliff:g id="VERSION">%s</xliff:g>"</string>
     <string name="vpn_forget_long" msgid="2232239391189465752">"VPN लाई बिर्सनुहोस्"</string>
-    <!-- no translation found for vpn_replace_vpn_title (2963898301277610248) -->
-    <skip />
-    <!-- no translation found for vpn_set_vpn_title (4009987321156037267) -->
-    <skip />
-    <!-- no translation found for vpn_first_always_on_vpn_message (3025322109743675467) -->
-    <skip />
-    <!-- no translation found for vpn_replace_always_on_vpn_enable_message (2577928591361606641) -->
-    <skip />
-    <!-- no translation found for vpn_replace_always_on_vpn_disable_message (3011818750025879902) -->
-    <skip />
-    <!-- no translation found for vpn_replace_vpn_message (5611635724578812860) -->
-    <skip />
-    <!-- no translation found for vpn_turn_on (2363136869284273872) -->
-    <skip />
+    <string name="vpn_replace_vpn_title" msgid="2963898301277610248">"विद्यमान VPN लाई बदल्ने हो?"</string>
+    <string name="vpn_set_vpn_title" msgid="4009987321156037267">"सधैँ-सक्रिय VPN लाई सेट गर्ने हो?"</string>
+    <string name="vpn_first_always_on_vpn_message" msgid="3025322109743675467">"यो सेटिङलाई सक्रिय गरेर सफलतापूर्वक VPN जडान नहोउन्जेलसम्म तपाईंसँग इन्टरनेट जडान हुने छैन"</string>
+    <string name="vpn_replace_always_on_vpn_enable_message" msgid="2577928591361606641">"तपाईंको विद्यमान VPN लाई प्रतिस्थापन गरिने छ र सफलतापूर्वक VPN जडान नहोउन्जेल तपाईंसँग इन्टरनेट जडान हुने छैन"</string>
+    <string name="vpn_replace_always_on_vpn_disable_message" msgid="3011818750025879902">"तपाईँले पहिले नै एउटा सधैं-सक्रिय VPN मा जडान गर्नुभएको छ। तपाईंले अर्को कुनै VPN मा ज‍डान गर्नुभयो भने तपाईंको विद्यमान VPN लाई प्रतिस्थापन गरिनेछ र सधैं-सक्रिय मोड निष्क्रिय हुने छ।"</string>
+    <string name="vpn_replace_vpn_message" msgid="5611635724578812860">"तपाईँले पहिले नै एउटा VPN मा जडान गर्नुभएको छ। तपाईँले कुनै नयाँ VPN मा ज‍डान गर्नुभयो भने तपाईँको विद्यमान VPN लाई प्रतिस्थापन गरिनेछ।"</string>
+    <string name="vpn_turn_on" msgid="2363136869284273872">"सक्रिय गर्नुहोस्"</string>
     <string name="vpn_cant_connect_title" msgid="4517706987875907511">"<xliff:g id="VPN_NAME">%1$s</xliff:g> जडान गर्न सक्दैन"</string>
     <string name="vpn_cant_connect_message" msgid="2593197919352621279">"यस अनुप्रयोगले सधैँ सक्रिय रहने VPN लाई समर्थन गर्दैन।"</string>
     <string name="vpn_title" msgid="6317731879966640551">"VPN"</string>
@@ -2536,8 +2529,7 @@
     </plurals>
     <string name="network_dashboard_title" msgid="4771589228992391573">"नेटवर्क र इन्टरनेट"</string>
     <string name="connected_devices_dashboard_title" msgid="2355264951438890709">"जडान गरिएका यन्त्रहरू"</string>
-    <!-- no translation found for system_dashboard_summary (6112602136713843779) -->
-    <skip />
+    <string name="system_dashboard_summary" msgid="6112602136713843779">"भाषा: <xliff:g id="LANGUAGE">%1$s</xliff:g>"</string>
     <string name="search_results_title" msgid="1796252422574886932">"सेटिङहरू"</string>
     <string name="search_menu" msgid="6283419262313758339">"खोज सेटिङहरू"</string>
     <string name="query_hint_text" msgid="3350700807437473939">"खोज सेटिङहरू"</string>
diff --git a/res/values-pa-rIN/strings.xml b/res/values-pa-rIN/strings.xml
index 8bdd78e..7c58f2b 100644
--- a/res/values-pa-rIN/strings.xml
+++ b/res/values-pa-rIN/strings.xml
@@ -2280,20 +2280,13 @@
     <string name="vpn_disconnect" msgid="7426570492642111171">"ਡਿਸਕਨੈਕਟ ਕਰੋ"</string>
     <string name="vpn_version" msgid="1939804054179766249">"ਸੰਸਕਰਨ <xliff:g id="VERSION">%s</xliff:g>"</string>
     <string name="vpn_forget_long" msgid="2232239391189465752">"VPN ਨੂੰ ਛੱਡੋ"</string>
-    <!-- no translation found for vpn_replace_vpn_title (2963898301277610248) -->
-    <skip />
-    <!-- no translation found for vpn_set_vpn_title (4009987321156037267) -->
-    <skip />
-    <!-- no translation found for vpn_first_always_on_vpn_message (3025322109743675467) -->
-    <skip />
-    <!-- no translation found for vpn_replace_always_on_vpn_enable_message (2577928591361606641) -->
-    <skip />
-    <!-- no translation found for vpn_replace_always_on_vpn_disable_message (3011818750025879902) -->
-    <skip />
-    <!-- no translation found for vpn_replace_vpn_message (5611635724578812860) -->
-    <skip />
-    <!-- no translation found for vpn_turn_on (2363136869284273872) -->
-    <skip />
+    <string name="vpn_replace_vpn_title" msgid="2963898301277610248">"ਕੀ ਮੌਜੂਦਾ VPN ਨੂੰ ਤਬਦੀਲ ਕਰਨਾ ਹੈ?"</string>
+    <string name="vpn_set_vpn_title" msgid="4009987321156037267">"ਕੀ ਹਮੇਸ਼ਾ-ਚਾਲੂ VPN ਨੂੰ ਸੈੱਟ ਕਰਨਾ ਹੈ?"</string>
+    <string name="vpn_first_always_on_vpn_message" msgid="3025322109743675467">"ਇਸ ਸੈਟਿੰਗ ਨੂੰ ਚਾਲੂ ਕਰਨ ਨਾਲ, ਤੁਹਾਡੇ ਕੋਲ ਇੱਕ ਇੰਟਰਨੈੱਟ ਕਨੈਕਸ਼ਨ ਤਦ ਤੱਕ ਨਹੀਂ ਹੋਵੇਗਾ ਜਦ ਤੱਕ VPN ਸਫ਼ਲਤਾਪੂਰਵਕ ਕਨੈਕਟ ਨਹੀਂ ਹੋ ਜਾਂਦਾ"</string>
+    <string name="vpn_replace_always_on_vpn_enable_message" msgid="2577928591361606641">"ਤੁਹਾਡੇ ਮੌਜੂਦਾ VPN ਨੂੰ ਤਬਦੀਲ ਕਰ ਦਿੱਤਾ ਜਾਵੇਗਾ, ਅਤੇ ਤੁਹਾਡੇ ਕੋਲ ਤਦ ਤੱਕ ਇੱਕ ਇੰਟਰਨੈੱਟ ਕਨੈਕਸ਼ਨ ਨਹੀਂ ਹੋਵੇਗਾ ਜਦ ਤੱਕ VPN ਸਫ਼ਲਤਾਪੂਰਵਕ ਕਨੈਕਟ ਨਹੀਂ ਹੋ ਜਾਂਦਾ"</string>
+    <string name="vpn_replace_always_on_vpn_disable_message" msgid="3011818750025879902">"ਤੁਸੀਂ ਪਹਿਲਾਂ ਤੋਂ ਹਮੇਸ਼ਾ-ਚਾਲੂ VPN ਨਾਲ ਕਨੈਕਟ ਹੋ। ਜੇਕਰ ਤੁਸੀਂ ਕਿਸੇ ਹੋਰ ਨਾਲ ਕਨੈਕਟ ਹੁੰਦੇ ਹੋ, ਤਾਂ ਤੁਹਾਡੇ ਮੌਜੂਦਾ VPN ਨੂੰ ਤਬਦੀਲ ਕਰ ਦਿੱਤਾ ਜਾਵੇਗਾ, ਅਤੇ ਹਮੇਸ਼ਾ-ਚਾਲੂ ਮੋਡ ਬੰਦ ਹੋ ਜਾਵੇਗਾ।"</string>
+    <string name="vpn_replace_vpn_message" msgid="5611635724578812860">"ਤੁਸੀਂ ਪਹਿਲਾਂ ਤੋਂ ਹੀ ਕਿਸੇ VPN ਨਾਲ ਕਨੈਕਟ ਹੋ। ਜੇਕਰ ਤੁਸੀਂ ਕਿਸੇ ਹੋਰ ਨਾਲ ਕਨੈਕਟ ਹੁੰਦੇ ਹੋ, ਤਾਂ ਤੁਹਾਡੇ ਵਰਤਮਾਨ VPN ਨੂੰ ਤਬਦੀਲ ਕਰ ਦਿੱਤਾ ਜਾਵੇਗਾ।"</string>
+    <string name="vpn_turn_on" msgid="2363136869284273872">"ਚਾਲੂ ਕਰੋ"</string>
     <string name="vpn_cant_connect_title" msgid="4517706987875907511">"<xliff:g id="VPN_NAME">%1$s</xliff:g> ਨਾਲ ਕਨੈਕਟ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਦਾ"</string>
     <string name="vpn_cant_connect_message" msgid="2593197919352621279">"ਇਹ ਐਪ ਹਮੇਸ਼ਾਂ-ਚਾਲੂ ਰਹਿਣ ਵਾਲੇ VPN ਦਾ ਸਮਰਥਨ ਨਹੀਂ ਕਰਦੀ ਹੈ।"</string>
     <string name="vpn_title" msgid="6317731879966640551">"VPN"</string>
@@ -2536,8 +2529,7 @@
     </plurals>
     <string name="network_dashboard_title" msgid="4771589228992391573">"ਨੈੱਟਵਰਕ ਅਤੇ ਇੰਟਰਨੈੱਟ"</string>
     <string name="connected_devices_dashboard_title" msgid="2355264951438890709">"ਕਨੈਕਟ ਕੀਤੀਆਂ ਡੀਵਾਈਸਾਂ"</string>
-    <!-- no translation found for system_dashboard_summary (6112602136713843779) -->
-    <skip />
+    <string name="system_dashboard_summary" msgid="6112602136713843779">"ਭਾਸ਼ਾ: <xliff:g id="LANGUAGE">%1$s</xliff:g>"</string>
     <string name="search_results_title" msgid="1796252422574886932">"ਸੈਟਿੰਗਾਂ"</string>
     <string name="search_menu" msgid="6283419262313758339">"ਖੋਜ ਸੈੱਟਿੰਗਜ਼"</string>
     <string name="query_hint_text" msgid="3350700807437473939">"ਖੋਜ ਸੈਟਿੰਗਾਂ"</string>
diff --git a/res/values-pl/strings.xml b/res/values-pl/strings.xml
index 0a99207..cfe8a1e 100644
--- a/res/values-pl/strings.xml
+++ b/res/values-pl/strings.xml
@@ -2314,20 +2314,13 @@
     <string name="vpn_disconnect" msgid="7426570492642111171">"Odłącz"</string>
     <string name="vpn_version" msgid="1939804054179766249">"Wersja <xliff:g id="VERSION">%s</xliff:g>"</string>
     <string name="vpn_forget_long" msgid="2232239391189465752">"Zapomnij VPN"</string>
-    <!-- no translation found for vpn_replace_vpn_title (2963898301277610248) -->
-    <skip />
-    <!-- no translation found for vpn_set_vpn_title (4009987321156037267) -->
-    <skip />
-    <!-- no translation found for vpn_first_always_on_vpn_message (3025322109743675467) -->
-    <skip />
-    <!-- no translation found for vpn_replace_always_on_vpn_enable_message (2577928591361606641) -->
-    <skip />
-    <!-- no translation found for vpn_replace_always_on_vpn_disable_message (3011818750025879902) -->
-    <skip />
-    <!-- no translation found for vpn_replace_vpn_message (5611635724578812860) -->
-    <skip />
-    <!-- no translation found for vpn_turn_on (2363136869284273872) -->
-    <skip />
+    <string name="vpn_replace_vpn_title" msgid="2963898301277610248">"Zastąpić obecną sieć VPN?"</string>
+    <string name="vpn_set_vpn_title" msgid="4009987321156037267">"Ustawić stały VPN?"</string>
+    <string name="vpn_first_always_on_vpn_message" msgid="3025322109743675467">"Po włączeniu tego ustawienia utracisz połączenie internetowe do czasu nawiązania połączenia przez VPN"</string>
+    <string name="vpn_replace_always_on_vpn_enable_message" msgid="2577928591361606641">"Dotychczasowe połączenie VPN zostanie zastąpione i nie będziesz mieć połączenia internetowego do czasu połączenia z VPN"</string>
+    <string name="vpn_replace_always_on_vpn_disable_message" msgid="3011818750025879902">"Masz już połączenie ze stałą siecią VPN. Jeśli połączysz się z inną, obecna zostanie zastąpiona, a tryb stały zostanie wyłączony."</string>
+    <string name="vpn_replace_vpn_message" msgid="5611635724578812860">"Masz już połączenie z siecią VPN. Jeśli połączysz się z inną, obecna zostanie zastąpiona."</string>
+    <string name="vpn_turn_on" msgid="2363136869284273872">"Włącz"</string>
     <string name="vpn_cant_connect_title" msgid="4517706987875907511">"Nie można połączyć z siecią <xliff:g id="VPN_NAME">%1$s</xliff:g>"</string>
     <string name="vpn_cant_connect_message" msgid="2593197919352621279">"Ta aplikacja nie obsługuje łączenia tylko przez sieć VPN."</string>
     <string name="vpn_title" msgid="6317731879966640551">"VPN"</string>
@@ -2580,8 +2573,7 @@
     </plurals>
     <string name="network_dashboard_title" msgid="4771589228992391573">"Sieć i internet"</string>
     <string name="connected_devices_dashboard_title" msgid="2355264951438890709">"Połączone urządzenia"</string>
-    <!-- no translation found for system_dashboard_summary (6112602136713843779) -->
-    <skip />
+    <string name="system_dashboard_summary" msgid="6112602136713843779">"Język: <xliff:g id="LANGUAGE">%1$s</xliff:g>"</string>
     <string name="search_results_title" msgid="1796252422574886932">"Ustawienia"</string>
     <string name="search_menu" msgid="6283419262313758339">"Ustawienia wyszukiwania"</string>
     <string name="query_hint_text" msgid="3350700807437473939">"Ustawienia wyszukiwania"</string>
diff --git a/res/values-pt-rBR/strings.xml b/res/values-pt-rBR/strings.xml
index 22d144f..af8397b 100644
--- a/res/values-pt-rBR/strings.xml
+++ b/res/values-pt-rBR/strings.xml
@@ -2280,20 +2280,13 @@
     <string name="vpn_disconnect" msgid="7426570492642111171">"Desconectar"</string>
     <string name="vpn_version" msgid="1939804054179766249">"Versão <xliff:g id="VERSION">%s</xliff:g>"</string>
     <string name="vpn_forget_long" msgid="2232239391189465752">"Esquecer VPN"</string>
-    <!-- no translation found for vpn_replace_vpn_title (2963898301277610248) -->
-    <skip />
-    <!-- no translation found for vpn_set_vpn_title (4009987321156037267) -->
-    <skip />
-    <!-- no translation found for vpn_first_always_on_vpn_message (3025322109743675467) -->
-    <skip />
-    <!-- no translation found for vpn_replace_always_on_vpn_enable_message (2577928591361606641) -->
-    <skip />
-    <!-- no translation found for vpn_replace_always_on_vpn_disable_message (3011818750025879902) -->
-    <skip />
-    <!-- no translation found for vpn_replace_vpn_message (5611635724578812860) -->
-    <skip />
-    <!-- no translation found for vpn_turn_on (2363136869284273872) -->
-    <skip />
+    <string name="vpn_replace_vpn_title" msgid="2963898301277610248">"Substituir VPN já existente?"</string>
+    <string name="vpn_set_vpn_title" msgid="4009987321156037267">"Configurar VPN sempre ativa?"</string>
+    <string name="vpn_first_always_on_vpn_message" msgid="3025322109743675467">"Se você ativar esta configuração, sua conexão com a Internet não estará disponível até que a VPN se conecte"</string>
+    <string name="vpn_replace_always_on_vpn_enable_message" msgid="2577928591361606641">"Sua VPN já existente será substituída, e você não terá uma conexão com a Internet até que a VPN se conecte"</string>
+    <string name="vpn_replace_always_on_vpn_disable_message" msgid="3011818750025879902">"Você já está conectado a uma VPN sempre ativa. Caso se conecte a uma diferente, a VPN já existente será substituída, e o modo sempre ativo será desativado."</string>
+    <string name="vpn_replace_vpn_message" msgid="5611635724578812860">"Você já está conectado a uma VPN. Caso se conecte a uma diferente, a VPN já existente será substituída."</string>
+    <string name="vpn_turn_on" msgid="2363136869284273872">"Ativar"</string>
     <string name="vpn_cant_connect_title" msgid="4517706987875907511">"Não é possível conectar-se a <xliff:g id="VPN_NAME">%1$s</xliff:g>"</string>
     <string name="vpn_cant_connect_message" msgid="2593197919352621279">"Este app não é compatível com VPN sempre ativa."</string>
     <string name="vpn_title" msgid="6317731879966640551">"VPN"</string>
@@ -2536,8 +2529,7 @@
     </plurals>
     <string name="network_dashboard_title" msgid="4771589228992391573">"Rede e Internet"</string>
     <string name="connected_devices_dashboard_title" msgid="2355264951438890709">"Dispositivos conectados"</string>
-    <!-- no translation found for system_dashboard_summary (6112602136713843779) -->
-    <skip />
+    <string name="system_dashboard_summary" msgid="6112602136713843779">"Idioma: <xliff:g id="LANGUAGE">%1$s</xliff:g>"</string>
     <string name="search_results_title" msgid="1796252422574886932">"Configurações"</string>
     <string name="search_menu" msgid="6283419262313758339">"Configurações de pesquisa"</string>
     <string name="query_hint_text" msgid="3350700807437473939">"Configurações de pesquisa"</string>
diff --git a/res/values-pt-rPT/strings.xml b/res/values-pt-rPT/strings.xml
index a068bf7..283e7e0 100644
--- a/res/values-pt-rPT/strings.xml
+++ b/res/values-pt-rPT/strings.xml
@@ -2280,20 +2280,13 @@
     <string name="vpn_disconnect" msgid="7426570492642111171">"Desligar"</string>
     <string name="vpn_version" msgid="1939804054179766249">"Versão <xliff:g id="VERSION">%s</xliff:g>"</string>
     <string name="vpn_forget_long" msgid="2232239391189465752">"Esquecer VPN"</string>
-    <!-- no translation found for vpn_replace_vpn_title (2963898301277610248) -->
-    <skip />
-    <!-- no translation found for vpn_set_vpn_title (4009987321156037267) -->
-    <skip />
-    <!-- no translation found for vpn_first_always_on_vpn_message (3025322109743675467) -->
-    <skip />
-    <!-- no translation found for vpn_replace_always_on_vpn_enable_message (2577928591361606641) -->
-    <skip />
-    <!-- no translation found for vpn_replace_always_on_vpn_disable_message (3011818750025879902) -->
-    <skip />
-    <!-- no translation found for vpn_replace_vpn_message (5611635724578812860) -->
-    <skip />
-    <!-- no translation found for vpn_turn_on (2363136869284273872) -->
-    <skip />
+    <string name="vpn_replace_vpn_title" msgid="2963898301277610248">"Pretende substituir a VPN existente?"</string>
+    <string name="vpn_set_vpn_title" msgid="4009987321156037267">"Pretende definir a VPN como sempre ativa?"</string>
+    <string name="vpn_first_always_on_vpn_message" msgid="3025322109743675467">"Ao ativar esta definição, não terá uma ligação à Internet até a VPN estabelecer ligação com êxito"</string>
+    <string name="vpn_replace_always_on_vpn_enable_message" msgid="2577928591361606641">"A sua VPN existente será substituída e não terá uma ligação à Internet até a VPN estabelecer ligação com êxito"</string>
+    <string name="vpn_replace_always_on_vpn_disable_message" msgid="3011818750025879902">"Já está ligado a uma VPN sempre ativa. Se ligar a outra, a VPN existente será substituída e o modo sempre ativo será desativado."</string>
+    <string name="vpn_replace_vpn_message" msgid="5611635724578812860">"Já está ligado a uma VPN. Se ligar a outra, a VPN existente será substituída."</string>
+    <string name="vpn_turn_on" msgid="2363136869284273872">"Ativar"</string>
     <string name="vpn_cant_connect_title" msgid="4517706987875907511">"Não é possível ligar <xliff:g id="VPN_NAME">%1$s</xliff:g>"</string>
     <string name="vpn_cant_connect_message" msgid="2593197919352621279">"Esta aplicação não é compatível com uma VPN sempre ativada."</string>
     <string name="vpn_title" msgid="6317731879966640551">"VPN"</string>
@@ -2536,8 +2529,7 @@
     </plurals>
     <string name="network_dashboard_title" msgid="4771589228992391573">"Rede e Internet"</string>
     <string name="connected_devices_dashboard_title" msgid="2355264951438890709">"Dispositivos ligados"</string>
-    <!-- no translation found for system_dashboard_summary (6112602136713843779) -->
-    <skip />
+    <string name="system_dashboard_summary" msgid="6112602136713843779">"Idioma: <xliff:g id="LANGUAGE">%1$s</xliff:g>"</string>
     <string name="search_results_title" msgid="1796252422574886932">"Definições"</string>
     <string name="search_menu" msgid="6283419262313758339">"Definições de pesquisa"</string>
     <string name="query_hint_text" msgid="3350700807437473939">"Definições de pesquisa"</string>
diff --git a/res/values-pt/strings.xml b/res/values-pt/strings.xml
index 22d144f..af8397b 100644
--- a/res/values-pt/strings.xml
+++ b/res/values-pt/strings.xml
@@ -2280,20 +2280,13 @@
     <string name="vpn_disconnect" msgid="7426570492642111171">"Desconectar"</string>
     <string name="vpn_version" msgid="1939804054179766249">"Versão <xliff:g id="VERSION">%s</xliff:g>"</string>
     <string name="vpn_forget_long" msgid="2232239391189465752">"Esquecer VPN"</string>
-    <!-- no translation found for vpn_replace_vpn_title (2963898301277610248) -->
-    <skip />
-    <!-- no translation found for vpn_set_vpn_title (4009987321156037267) -->
-    <skip />
-    <!-- no translation found for vpn_first_always_on_vpn_message (3025322109743675467) -->
-    <skip />
-    <!-- no translation found for vpn_replace_always_on_vpn_enable_message (2577928591361606641) -->
-    <skip />
-    <!-- no translation found for vpn_replace_always_on_vpn_disable_message (3011818750025879902) -->
-    <skip />
-    <!-- no translation found for vpn_replace_vpn_message (5611635724578812860) -->
-    <skip />
-    <!-- no translation found for vpn_turn_on (2363136869284273872) -->
-    <skip />
+    <string name="vpn_replace_vpn_title" msgid="2963898301277610248">"Substituir VPN já existente?"</string>
+    <string name="vpn_set_vpn_title" msgid="4009987321156037267">"Configurar VPN sempre ativa?"</string>
+    <string name="vpn_first_always_on_vpn_message" msgid="3025322109743675467">"Se você ativar esta configuração, sua conexão com a Internet não estará disponível até que a VPN se conecte"</string>
+    <string name="vpn_replace_always_on_vpn_enable_message" msgid="2577928591361606641">"Sua VPN já existente será substituída, e você não terá uma conexão com a Internet até que a VPN se conecte"</string>
+    <string name="vpn_replace_always_on_vpn_disable_message" msgid="3011818750025879902">"Você já está conectado a uma VPN sempre ativa. Caso se conecte a uma diferente, a VPN já existente será substituída, e o modo sempre ativo será desativado."</string>
+    <string name="vpn_replace_vpn_message" msgid="5611635724578812860">"Você já está conectado a uma VPN. Caso se conecte a uma diferente, a VPN já existente será substituída."</string>
+    <string name="vpn_turn_on" msgid="2363136869284273872">"Ativar"</string>
     <string name="vpn_cant_connect_title" msgid="4517706987875907511">"Não é possível conectar-se a <xliff:g id="VPN_NAME">%1$s</xliff:g>"</string>
     <string name="vpn_cant_connect_message" msgid="2593197919352621279">"Este app não é compatível com VPN sempre ativa."</string>
     <string name="vpn_title" msgid="6317731879966640551">"VPN"</string>
@@ -2536,8 +2529,7 @@
     </plurals>
     <string name="network_dashboard_title" msgid="4771589228992391573">"Rede e Internet"</string>
     <string name="connected_devices_dashboard_title" msgid="2355264951438890709">"Dispositivos conectados"</string>
-    <!-- no translation found for system_dashboard_summary (6112602136713843779) -->
-    <skip />
+    <string name="system_dashboard_summary" msgid="6112602136713843779">"Idioma: <xliff:g id="LANGUAGE">%1$s</xliff:g>"</string>
     <string name="search_results_title" msgid="1796252422574886932">"Configurações"</string>
     <string name="search_menu" msgid="6283419262313758339">"Configurações de pesquisa"</string>
     <string name="query_hint_text" msgid="3350700807437473939">"Configurações de pesquisa"</string>
diff --git a/res/values-ro/strings.xml b/res/values-ro/strings.xml
index cb55d5d..b6d8dfa 100644
--- a/res/values-ro/strings.xml
+++ b/res/values-ro/strings.xml
@@ -2297,20 +2297,13 @@
     <string name="vpn_disconnect" msgid="7426570492642111171">"Deconectați-vă"</string>
     <string name="vpn_version" msgid="1939804054179766249">"Versiunea <xliff:g id="VERSION">%s</xliff:g>"</string>
     <string name="vpn_forget_long" msgid="2232239391189465752">"Eliminați profilul VPN"</string>
-    <!-- no translation found for vpn_replace_vpn_title (2963898301277610248) -->
-    <skip />
-    <!-- no translation found for vpn_set_vpn_title (4009987321156037267) -->
-    <skip />
-    <!-- no translation found for vpn_first_always_on_vpn_message (3025322109743675467) -->
-    <skip />
-    <!-- no translation found for vpn_replace_always_on_vpn_enable_message (2577928591361606641) -->
-    <skip />
-    <!-- no translation found for vpn_replace_always_on_vpn_disable_message (3011818750025879902) -->
-    <skip />
-    <!-- no translation found for vpn_replace_vpn_message (5611635724578812860) -->
-    <skip />
-    <!-- no translation found for vpn_turn_on (2363136869284273872) -->
-    <skip />
+    <string name="vpn_replace_vpn_title" msgid="2963898301277610248">"Înlocuiți rețeaua VPN existentă?"</string>
+    <string name="vpn_set_vpn_title" msgid="4009987321156037267">"Setați rețeaua VPN ca activată permanent?"</string>
+    <string name="vpn_first_always_on_vpn_message" msgid="3025322109743675467">"Dacă activați această setare, nu veți avea conexiune la internet până când nu se conectează rețeaua VPN."</string>
+    <string name="vpn_replace_always_on_vpn_enable_message" msgid="2577928591361606641">"Rețeaua VPN existentă va fi înlocuită și nu veți avea conexiune la internet până când nu se conectează rețeaua VPN."</string>
+    <string name="vpn_replace_always_on_vpn_disable_message" msgid="3011818750025879902">"V-ați conectat deja la o rețea VPN activată permanent. Dacă vă conectați la altă rețea, rețeaua VPN existentă va fi înlocuită și modul activat permanent va fi dezactivat."</string>
+    <string name="vpn_replace_vpn_message" msgid="5611635724578812860">"V-ați conectat deja la o rețea VPN. Dacă vă conectați la altă rețea, rețeaua VPN existentă va fi înlocuită."</string>
+    <string name="vpn_turn_on" msgid="2363136869284273872">"Activați"</string>
     <string name="vpn_cant_connect_title" msgid="4517706987875907511">"Nu vă puteți conecta la <xliff:g id="VPN_NAME">%1$s</xliff:g>"</string>
     <string name="vpn_cant_connect_message" msgid="2593197919352621279">"Această aplicație nu acceptă rețele VPN activate permanent."</string>
     <string name="vpn_title" msgid="6317731879966640551">"VPN"</string>
@@ -2558,8 +2551,7 @@
     </plurals>
     <string name="network_dashboard_title" msgid="4771589228992391573">"Rețea și internet"</string>
     <string name="connected_devices_dashboard_title" msgid="2355264951438890709">"Dispozitive conectate"</string>
-    <!-- no translation found for system_dashboard_summary (6112602136713843779) -->
-    <skip />
+    <string name="system_dashboard_summary" msgid="6112602136713843779">"Limba: <xliff:g id="LANGUAGE">%1$s</xliff:g>"</string>
     <string name="search_results_title" msgid="1796252422574886932">"Setări"</string>
     <string name="search_menu" msgid="6283419262313758339">"Setări de căutare"</string>
     <string name="query_hint_text" msgid="3350700807437473939">"Setări pentru căutare"</string>
diff --git a/res/values-ru/arrays.xml b/res/values-ru/arrays.xml
index e669210..1d9273c 100644
--- a/res/values-ru/arrays.xml
+++ b/res/values-ru/arrays.xml
@@ -475,6 +475,6 @@
   <string-array name="automatic_storage_management_days">
     <item msgid="687318592238852312">"Добавленные более 30 дней назад"</item>
     <item msgid="2900554746706302178">"Добавленные более 60 дней назад"</item>
-    <item msgid="5692284879054004388">"Добавленные более 60 дней назад"</item>
+    <item msgid="5692284879054004388">"Добавленные более 90 дней назад"</item>
   </string-array>
 </resources>
diff --git a/res/values-sq-rAL/strings.xml b/res/values-sq-rAL/strings.xml
index 482a90b..706efae 100644
--- a/res/values-sq-rAL/strings.xml
+++ b/res/values-sq-rAL/strings.xml
@@ -2280,20 +2280,13 @@
     <string name="vpn_disconnect" msgid="7426570492642111171">"Shkëpute"</string>
     <string name="vpn_version" msgid="1939804054179766249">"Versioni <xliff:g id="VERSION">%s</xliff:g>"</string>
     <string name="vpn_forget_long" msgid="2232239391189465752">"Harroje rrjetin VPN"</string>
-    <!-- no translation found for vpn_replace_vpn_title (2963898301277610248) -->
-    <skip />
-    <!-- no translation found for vpn_set_vpn_title (4009987321156037267) -->
-    <skip />
-    <!-- no translation found for vpn_first_always_on_vpn_message (3025322109743675467) -->
-    <skip />
-    <!-- no translation found for vpn_replace_always_on_vpn_enable_message (2577928591361606641) -->
-    <skip />
-    <!-- no translation found for vpn_replace_always_on_vpn_disable_message (3011818750025879902) -->
-    <skip />
-    <!-- no translation found for vpn_replace_vpn_message (5611635724578812860) -->
-    <skip />
-    <!-- no translation found for vpn_turn_on (2363136869284273872) -->
-    <skip />
+    <string name="vpn_replace_vpn_title" msgid="2963898301277610248">"Të zëvendësohet rrjeti ekzistues VPN?"</string>
+    <string name="vpn_set_vpn_title" msgid="4009987321156037267">"Të caktohet rrjeti VPN gjithmonë aktiv?"</string>
+    <string name="vpn_first_always_on_vpn_message" msgid="3025322109743675467">"Duke aktivizuar këtë cilësim, nuk do të kesh një lidhje interneti deri sa rrjeti VPN të lidhet me sukses"</string>
+    <string name="vpn_replace_always_on_vpn_enable_message" msgid="2577928591361606641">"Rrjeti yt ekzistues VPN do të zëvendësohet dhe nuk do të kesh një lidhje interneti deri sa rrjeti VPN të lidhet me sukses"</string>
+    <string name="vpn_replace_always_on_vpn_disable_message" msgid="3011818750025879902">"Je tashmë i lidhur me një rrjet VPN gjithmonë aktiv. Nëse je lidhur me një tjetër, rrjeti yt ekzistues VPN do të zëvendësohet dhe modaliteti gjithmonë aktiv do të çaktivizohet."</string>
+    <string name="vpn_replace_vpn_message" msgid="5611635724578812860">"Je tashmë i lidhur me një rrjet VPN. Nëse je lidhur me një tjetër, rrjeti yt ekzistues VPN do të zëvendësohet."</string>
+    <string name="vpn_turn_on" msgid="2363136869284273872">"Aktivizo"</string>
     <string name="vpn_cant_connect_title" msgid="4517706987875907511">"<xliff:g id="VPN_NAME">%1$s</xliff:g> nuk mund të lidhet"</string>
     <string name="vpn_cant_connect_message" msgid="2593197919352621279">"Ky aplikacion nuk mbështet VPN-në që është gjithmonë aktive."</string>
     <string name="vpn_title" msgid="6317731879966640551">"VPN"</string>
@@ -2536,8 +2529,7 @@
     </plurals>
     <string name="network_dashboard_title" msgid="4771589228992391573">"Rrjeti dhe interneti"</string>
     <string name="connected_devices_dashboard_title" msgid="2355264951438890709">"Pajisje të lidhura"</string>
-    <!-- no translation found for system_dashboard_summary (6112602136713843779) -->
-    <skip />
+    <string name="system_dashboard_summary" msgid="6112602136713843779">"Gjuha: <xliff:g id="LANGUAGE">%1$s</xliff:g>"</string>
     <string name="search_results_title" msgid="1796252422574886932">"Cilësimet"</string>
     <string name="search_menu" msgid="6283419262313758339">"Cilësimet e kërkimit"</string>
     <string name="query_hint_text" msgid="3350700807437473939">"Cilësimet e kërkimit"</string>
diff --git a/res/values-sw/strings.xml b/res/values-sw/strings.xml
index 0ee4606..297035f 100644
--- a/res/values-sw/strings.xml
+++ b/res/values-sw/strings.xml
@@ -2286,20 +2286,13 @@
     <string name="vpn_disconnect" msgid="7426570492642111171">"Kata muungnisho"</string>
     <string name="vpn_version" msgid="1939804054179766249">"Toleo la <xliff:g id="VERSION">%s</xliff:g>"</string>
     <string name="vpn_forget_long" msgid="2232239391189465752">"Ondoa VPN"</string>
-    <!-- no translation found for vpn_replace_vpn_title (2963898301277610248) -->
-    <skip />
-    <!-- no translation found for vpn_set_vpn_title (4009987321156037267) -->
-    <skip />
-    <!-- no translation found for vpn_first_always_on_vpn_message (3025322109743675467) -->
-    <skip />
-    <!-- no translation found for vpn_replace_always_on_vpn_enable_message (2577928591361606641) -->
-    <skip />
-    <!-- no translation found for vpn_replace_always_on_vpn_disable_message (3011818750025879902) -->
-    <skip />
-    <!-- no translation found for vpn_replace_vpn_message (5611635724578812860) -->
-    <skip />
-    <!-- no translation found for vpn_turn_on (2363136869284273872) -->
-    <skip />
+    <string name="vpn_replace_vpn_title" msgid="2963898301277610248">"Ungependa kubadilisha VPN iliyopo?"</string>
+    <string name="vpn_set_vpn_title" msgid="4009987321156037267">"Ungependa kuweka VPN iliyowashwa kila mara?"</string>
+    <string name="vpn_first_always_on_vpn_message" msgid="3025322109743675467">"Kwa kuwasha mIpangilio hii, hutapata muunganisho wa Intaneti hadi VPN itakapounganishwa"</string>
+    <string name="vpn_replace_always_on_vpn_enable_message" msgid="2577928591361606641">"Programu itaondoa VPN iliyopo, na hutaweza kuwa na muunganisho wa Intaneti hadi  VPN itakapounganishwa"</string>
+    <string name="vpn_replace_always_on_vpn_disable_message" msgid="3011818750025879902">"Tayari umeunganisha kwenye VPN ambayo imewashwa kila mara. Ikiwa utaunganisha kwenye programu tofauti, programu hiyo itaondoa VPN iliyopo na kuzima hali ya imewashwa kila mara."</string>
+    <string name="vpn_replace_vpn_message" msgid="5611635724578812860">"Tayari umeunganisha kwenye VPN. Ikiwa utaunganisha kwenye programu tofauti, programu hiyo itaondoa VPN iliyopo."</string>
+    <string name="vpn_turn_on" msgid="2363136869284273872">"Washa"</string>
     <string name="vpn_cant_connect_title" msgid="4517706987875907511">"Haiwezi kuunganisha <xliff:g id="VPN_NAME">%1$s</xliff:g>"</string>
     <string name="vpn_cant_connect_message" msgid="2593197919352621279">"Programu hii haitumii VPN iliyo katika hali ya kuwaka kila mara."</string>
     <string name="vpn_title" msgid="6317731879966640551">"VPN"</string>
@@ -2542,8 +2535,7 @@
     </plurals>
     <string name="network_dashboard_title" msgid="4771589228992391573">"Mtandao na Intaneti"</string>
     <string name="connected_devices_dashboard_title" msgid="2355264951438890709">"Vifaa vilivyounganishwa"</string>
-    <!-- no translation found for system_dashboard_summary (6112602136713843779) -->
-    <skip />
+    <string name="system_dashboard_summary" msgid="6112602136713843779">"Lugha: <xliff:g id="LANGUAGE">%1$s</xliff:g>"</string>
     <string name="search_results_title" msgid="1796252422574886932">"Mipangilio"</string>
     <string name="search_menu" msgid="6283419262313758339">"Mipangilio ya utafutaji"</string>
     <string name="query_hint_text" msgid="3350700807437473939">"Mipangilio ya utafutaji"</string>
diff --git a/res/values-sw400dp/dimens.xml b/res/values-sw400dp/dimens.xml
index 9c82d90..da58a9c 100755
--- a/res/values-sw400dp/dimens.xml
+++ b/res/values-sw400dp/dimens.xml
@@ -25,4 +25,7 @@
 
     <dimen name="setup_fingerprint_ring_radius">92dp</dimen>
     <dimen name="setup_fingerprint_progress_bar_size">192dp</dimen>
+
+    <dimen name="support_escalation_card_padding_start">56dp</dimen>
+    <dimen name="support_escalation_card_padding_end">56dp</dimen>
 </resources>
diff --git a/res/values-ta-rIN/strings.xml b/res/values-ta-rIN/strings.xml
index b8be56f..e23dd01 100644
--- a/res/values-ta-rIN/strings.xml
+++ b/res/values-ta-rIN/strings.xml
@@ -2280,20 +2280,13 @@
     <string name="vpn_disconnect" msgid="7426570492642111171">"தொடர்பைத் துண்டி"</string>
     <string name="vpn_version" msgid="1939804054179766249">"பதிப்பு <xliff:g id="VERSION">%s</xliff:g>"</string>
     <string name="vpn_forget_long" msgid="2232239391189465752">"VPNஐ நீக்கு"</string>
-    <!-- no translation found for vpn_replace_vpn_title (2963898301277610248) -->
-    <skip />
-    <!-- no translation found for vpn_set_vpn_title (4009987321156037267) -->
-    <skip />
-    <!-- no translation found for vpn_first_always_on_vpn_message (3025322109743675467) -->
-    <skip />
-    <!-- no translation found for vpn_replace_always_on_vpn_enable_message (2577928591361606641) -->
-    <skip />
-    <!-- no translation found for vpn_replace_always_on_vpn_disable_message (3011818750025879902) -->
-    <skip />
-    <!-- no translation found for vpn_replace_vpn_message (5611635724578812860) -->
-    <skip />
-    <!-- no translation found for vpn_turn_on (2363136869284273872) -->
-    <skip />
+    <string name="vpn_replace_vpn_title" msgid="2963898301277610248">"தற்போதுள்ள VPNஐ மாற்றியமைக்கவா?"</string>
+    <string name="vpn_set_vpn_title" msgid="4009987321156037267">"எப்போதும் இயங்கும் VPNஐ அமைக்கவா?"</string>
+    <string name="vpn_first_always_on_vpn_message" msgid="3025322109743675467">"இந்த அமைப்பை இயக்கினால், VPN இணைக்கப்படும் வரை இணைய இணைப்பு கிடைக்காது"</string>
+    <string name="vpn_replace_always_on_vpn_enable_message" msgid="2577928591361606641">"தற்போதுள்ள VPN மாற்றியமைக்கப்படும், மேலும் VPN இணைக்கப்படும் வரை இணைய இணைப்பு கிடைக்காது"</string>
+    <string name="vpn_replace_always_on_vpn_disable_message" msgid="3011818750025879902">"எப்போதும் இயங்கும் VPN உடன் ஏற்கனவே இணைத்துள்ளீர்கள். வேறொன்றுடன் இணைத்தால், அது தற்போதுள்ள VPNக்குப் பதிலாக மாற்றியமைக்கப்படும், மேலும் எப்போதும் இயங்கும் பயன்முறை முடக்கப்படும்."</string>
+    <string name="vpn_replace_vpn_message" msgid="5611635724578812860">"ஏற்கனவே ஒரு VPN உடன் இணைத்துள்ளீர்கள். வேறொன்றுடன் இணைத்தால், அது தற்போதுள்ள VPNக்குப் பதிலாக மாற்றியமைக்கப்படும்."</string>
+    <string name="vpn_turn_on" msgid="2363136869284273872">"இயக்கு"</string>
     <string name="vpn_cant_connect_title" msgid="4517706987875907511">"<xliff:g id="VPN_NAME">%1$s</xliff:g>ஐ இணைக்க முடியாது"</string>
     <string name="vpn_cant_connect_message" msgid="2593197919352621279">"இந்தப் பயன்பாடு எப்போதும் இயங்கும் VPNஐ ஆதரிக்கவில்லை."</string>
     <string name="vpn_title" msgid="6317731879966640551">"VPN"</string>
@@ -2536,8 +2529,7 @@
     </plurals>
     <string name="network_dashboard_title" msgid="4771589228992391573">"நெட்வொர்க் &amp; இணையம்"</string>
     <string name="connected_devices_dashboard_title" msgid="2355264951438890709">"இணைத்த சாதனங்கள்"</string>
-    <!-- no translation found for system_dashboard_summary (6112602136713843779) -->
-    <skip />
+    <string name="system_dashboard_summary" msgid="6112602136713843779">"மொழி: <xliff:g id="LANGUAGE">%1$s</xliff:g>"</string>
     <string name="search_results_title" msgid="1796252422574886932">"அமைப்பு"</string>
     <string name="search_menu" msgid="6283419262313758339">"தேடல் அமைப்புகள்"</string>
     <string name="query_hint_text" msgid="3350700807437473939">"தேடல் அமைப்பு"</string>
diff --git a/res/values-te-rIN/strings.xml b/res/values-te-rIN/strings.xml
index 879b1c6..2b6ea08 100644
--- a/res/values-te-rIN/strings.xml
+++ b/res/values-te-rIN/strings.xml
@@ -2280,20 +2280,13 @@
     <string name="vpn_disconnect" msgid="7426570492642111171">"డిస్‌కనెక్ట్ చేయి"</string>
     <string name="vpn_version" msgid="1939804054179766249">"సంస్కరణ <xliff:g id="VERSION">%s</xliff:g>"</string>
     <string name="vpn_forget_long" msgid="2232239391189465752">"VPNని విస్మరించు"</string>
-    <!-- no translation found for vpn_replace_vpn_title (2963898301277610248) -->
-    <skip />
-    <!-- no translation found for vpn_set_vpn_title (4009987321156037267) -->
-    <skip />
-    <!-- no translation found for vpn_first_always_on_vpn_message (3025322109743675467) -->
-    <skip />
-    <!-- no translation found for vpn_replace_always_on_vpn_enable_message (2577928591361606641) -->
-    <skip />
-    <!-- no translation found for vpn_replace_always_on_vpn_disable_message (3011818750025879902) -->
-    <skip />
-    <!-- no translation found for vpn_replace_vpn_message (5611635724578812860) -->
-    <skip />
-    <!-- no translation found for vpn_turn_on (2363136869284273872) -->
-    <skip />
+    <string name="vpn_replace_vpn_title" msgid="2963898301277610248">"ఇప్పటికే ఉన్న VPNని భర్తీ చేయాలా?"</string>
+    <string name="vpn_set_vpn_title" msgid="4009987321156037267">"ఎల్లప్పుడూ ఆన్‌లో ఉండే VPNని సెట్ చేయాలా?"</string>
+    <string name="vpn_first_always_on_vpn_message" msgid="3025322109743675467">"ఈ సెట్టింగ్‌ను ఆన్ చేస్తే, VPN విజయవంతంగా కనెక్ట్ అయ్యే వరకు మీకు ఇంటర్నెట్ కనెక్షన్ ఉండదు"</string>
+    <string name="vpn_replace_always_on_vpn_enable_message" msgid="2577928591361606641">"ఇప్పటికే ఉన్న మీ VPN భర్తీ చేయబడుతుంది మరియు VPN విజయవంతంగా కనెక్ట్ అయ్యే వరకు మీకు ఇంటర్నెట్ కనెక్షన్ ఉండదు"</string>
+    <string name="vpn_replace_always_on_vpn_disable_message" msgid="3011818750025879902">"మీరు ఇప్పటికే ఎల్లప్పుడూ ఆన్‌లో ఉండే VPNకి కనెక్ట్ అయ్యారు. మీరు వేరొక దానికి కనెక్ట్ చేస్తే, ఇప్పటికే ఉన్న మీ VPN భర్తీ చేయబడుతుంది మరియు ఎల్లప్పుడూ ఆన్‌లో ఉంచే మోడ్ ఆఫ్ చేయబడుతుంది."</string>
+    <string name="vpn_replace_vpn_message" msgid="5611635724578812860">"మీరు ఇప్పటికే VPNకి కనెక్ట్ అయ్యారు. మీరు వేరొక దానికి కనెక్ట్ చేస్తే, మీ ప్రస్తుత VPN భర్తీ చేయబడుతుంది."</string>
+    <string name="vpn_turn_on" msgid="2363136869284273872">"ఆన్ చేయి"</string>
     <string name="vpn_cant_connect_title" msgid="4517706987875907511">"<xliff:g id="VPN_NAME">%1$s</xliff:g>కి కనెక్ట్ కావడం సాధ్యపడదు"</string>
     <string name="vpn_cant_connect_message" msgid="2593197919352621279">"ఈ అనువర్తనం ఎల్లప్పుడూ ఆన్‌లో ఉండే VPNకు మద్దతివ్వదు."</string>
     <string name="vpn_title" msgid="6317731879966640551">"VPN"</string>
@@ -2536,8 +2529,7 @@
     </plurals>
     <string name="network_dashboard_title" msgid="4771589228992391573">"నెట్‌వర్క్ &amp; ఇంటర్నెట్"</string>
     <string name="connected_devices_dashboard_title" msgid="2355264951438890709">"కనెక్ట్ చేసిన పరికరాలు"</string>
-    <!-- no translation found for system_dashboard_summary (6112602136713843779) -->
-    <skip />
+    <string name="system_dashboard_summary" msgid="6112602136713843779">"భాష: <xliff:g id="LANGUAGE">%1$s</xliff:g>"</string>
     <string name="search_results_title" msgid="1796252422574886932">"సెట్టింగ్‌లు"</string>
     <string name="search_menu" msgid="6283419262313758339">"శోధన సెట్టింగ్‌లు"</string>
     <string name="query_hint_text" msgid="3350700807437473939">"శోధన సెట్టింగ్‌లు"</string>
diff --git a/res/values-uk/strings.xml b/res/values-uk/strings.xml
index 8adc8cb..1a785c5 100644
--- a/res/values-uk/strings.xml
+++ b/res/values-uk/strings.xml
@@ -2314,20 +2314,13 @@
     <string name="vpn_disconnect" msgid="7426570492642111171">"Відключити"</string>
     <string name="vpn_version" msgid="1939804054179766249">"Версія <xliff:g id="VERSION">%s</xliff:g>"</string>
     <string name="vpn_forget_long" msgid="2232239391189465752">"Забути мережу VPN"</string>
-    <!-- no translation found for vpn_replace_vpn_title (2963898301277610248) -->
-    <skip />
-    <!-- no translation found for vpn_set_vpn_title (4009987321156037267) -->
-    <skip />
-    <!-- no translation found for vpn_first_always_on_vpn_message (3025322109743675467) -->
-    <skip />
-    <!-- no translation found for vpn_replace_always_on_vpn_enable_message (2577928591361606641) -->
-    <skip />
-    <!-- no translation found for vpn_replace_always_on_vpn_disable_message (3011818750025879902) -->
-    <skip />
-    <!-- no translation found for vpn_replace_vpn_message (5611635724578812860) -->
-    <skip />
-    <!-- no translation found for vpn_turn_on (2363136869284273872) -->
-    <skip />
+    <string name="vpn_replace_vpn_title" msgid="2963898301277610248">"Замінити наявну мережу VPN?"</string>
+    <string name="vpn_set_vpn_title" msgid="4009987321156037267">"Увімкнути постійну мережу VPN?"</string>
+    <string name="vpn_first_always_on_vpn_message" msgid="3025322109743675467">"Якщо ввімкнути це налаштування, пристрій не матиме з’єднання з Інтернетом, доки не під’єднається мережа VPN"</string>
+    <string name="vpn_replace_always_on_vpn_enable_message" msgid="2577928591361606641">"Наявну мережу VPN буде замінено, а пристрій не матиме з’єднання з Інтернетом, доки не під’єднається мережа VPN"</string>
+    <string name="vpn_replace_always_on_vpn_disable_message" msgid="3011818750025879902">"Пристрій уже під’єднано до постійної мережі VPN. Якщо під’єднати його до іншої мережі, наявну мережу VPN буде замінено, а режим постійної мережі VPN буде вимкнено."</string>
+    <string name="vpn_replace_vpn_message" msgid="5611635724578812860">"Пристрій уже під’єднано до мережі VPN. Якщо під’єднати його до іншої мережі, наявну мережу VPN буде замінено."</string>
+    <string name="vpn_turn_on" msgid="2363136869284273872">"Увімкнути"</string>
     <string name="vpn_cant_connect_title" msgid="4517706987875907511">"Не вдається під’єднатися до мережі <xliff:g id="VPN_NAME">%1$s</xliff:g>"</string>
     <string name="vpn_cant_connect_message" msgid="2593197919352621279">"Цей додаток не підтримує постійну мережу VPN."</string>
     <string name="vpn_title" msgid="6317731879966640551">"VPN"</string>
@@ -2580,8 +2573,7 @@
     </plurals>
     <string name="network_dashboard_title" msgid="4771589228992391573">"Мережа й Інтернет"</string>
     <string name="connected_devices_dashboard_title" msgid="2355264951438890709">"Під’єднані пристрої"</string>
-    <!-- no translation found for system_dashboard_summary (6112602136713843779) -->
-    <skip />
+    <string name="system_dashboard_summary" msgid="6112602136713843779">"Мова: <xliff:g id="LANGUAGE">%1$s</xliff:g>"</string>
     <string name="search_results_title" msgid="1796252422574886932">"Налаштування"</string>
     <string name="search_menu" msgid="6283419262313758339">"Налаштування пошуку"</string>
     <string name="query_hint_text" msgid="3350700807437473939">"Налаштуваня пошуку"</string>
diff --git a/res/values-uz-rUZ/strings.xml b/res/values-uz-rUZ/strings.xml
index c356293..9f3269f 100644
--- a/res/values-uz-rUZ/strings.xml
+++ b/res/values-uz-rUZ/strings.xml
@@ -2280,20 +2280,13 @@
     <string name="vpn_disconnect" msgid="7426570492642111171">"Aloqani uzish"</string>
     <string name="vpn_version" msgid="1939804054179766249">"<xliff:g id="VERSION">%s</xliff:g> versiya"</string>
     <string name="vpn_forget_long" msgid="2232239391189465752">"VPNni o‘chirish"</string>
-    <!-- no translation found for vpn_replace_vpn_title (2963898301277610248) -->
-    <skip />
-    <!-- no translation found for vpn_set_vpn_title (4009987321156037267) -->
-    <skip />
-    <!-- no translation found for vpn_first_always_on_vpn_message (3025322109743675467) -->
-    <skip />
-    <!-- no translation found for vpn_replace_always_on_vpn_enable_message (2577928591361606641) -->
-    <skip />
-    <!-- no translation found for vpn_replace_always_on_vpn_disable_message (3011818750025879902) -->
-    <skip />
-    <!-- no translation found for vpn_replace_vpn_message (5611635724578812860) -->
-    <skip />
-    <!-- no translation found for vpn_turn_on (2363136869284273872) -->
-    <skip />
+    <string name="vpn_replace_vpn_title" msgid="2963898301277610248">"Mavjud VPN tarmog‘i almashtirilsinmi?"</string>
+    <string name="vpn_set_vpn_title" msgid="4009987321156037267">"Doimiy VPN o‘rnatilsinmi?"</string>
+    <string name="vpn_first_always_on_vpn_message" msgid="3025322109743675467">"Bu sozlama yoqilganda to VPN to‘liq ulanmaguncha internet ishlamaydi"</string>
+    <string name="vpn_replace_always_on_vpn_enable_message" msgid="2577928591361606641">"Mavjud VPN tarmog‘i almashtiriladi va to VPN to‘liq ulanmaguncha internet ishlamaydi"</string>
+    <string name="vpn_replace_always_on_vpn_disable_message" msgid="3011818750025879902">"Doimiy VPN tarmog‘iga allaqachon ulangansiz. Agar boshqasiga ulansangiz, mavjud VPN tarmog‘i almashtiriladi va doimiy rejim o‘chirib qo‘yiladi."</string>
+    <string name="vpn_replace_vpn_message" msgid="5611635724578812860">"Allaqachon VPN tarmog‘iga ulangan. Yangisiga ulansangiz, mavjud tarmoq almashtiriladi."</string>
+    <string name="vpn_turn_on" msgid="2363136869284273872">"Yoqish"</string>
     <string name="vpn_cant_connect_title" msgid="4517706987875907511">"“<xliff:g id="VPN_NAME">%1$s</xliff:g>” tarmog‘iga ulanib bo‘lmadi"</string>
     <string name="vpn_cant_connect_message" msgid="2593197919352621279">"Bu ilova doimiy VPN tarmog‘iga ulanishni qo‘llab-quvvatlamaydi."</string>
     <string name="vpn_title" msgid="6317731879966640551">"VPN"</string>
@@ -2534,10 +2527,9 @@
       <item quantity="other">%d ta yashirin elementni ko‘rsatish</item>
       <item quantity="one">%d ta yashirin elementni ko‘rsatish</item>
     </plurals>
-    <string name="network_dashboard_title" msgid="4771589228992391573">"Tarmoq va internet"</string>
+    <string name="network_dashboard_title" msgid="4771589228992391573">"Tarmoq va Internet"</string>
     <string name="connected_devices_dashboard_title" msgid="2355264951438890709">"Ulangan qurilmalar"</string>
-    <!-- no translation found for system_dashboard_summary (6112602136713843779) -->
-    <skip />
+    <string name="system_dashboard_summary" msgid="6112602136713843779">"Til: <xliff:g id="LANGUAGE">%1$s</xliff:g>"</string>
     <string name="search_results_title" msgid="1796252422574886932">"Sozlamalar"</string>
     <string name="search_menu" msgid="6283419262313758339">"Qidiruv sozlamalari"</string>
     <string name="query_hint_text" msgid="3350700807437473939">"Qidiruv sozlamalari"</string>
diff --git a/res/values-zu/strings.xml b/res/values-zu/strings.xml
index 4589b21..d34a4b7 100644
--- a/res/values-zu/strings.xml
+++ b/res/values-zu/strings.xml
@@ -2281,20 +2281,13 @@
     <string name="vpn_disconnect" msgid="7426570492642111171">"Nqamula"</string>
     <string name="vpn_version" msgid="1939804054179766249">"Inguqulo engu-<xliff:g id="VERSION">%s</xliff:g>"</string>
     <string name="vpn_forget_long" msgid="2232239391189465752">"Khohlwa i-VPN"</string>
-    <!-- no translation found for vpn_replace_vpn_title (2963898301277610248) -->
-    <skip />
-    <!-- no translation found for vpn_set_vpn_title (4009987321156037267) -->
-    <skip />
-    <!-- no translation found for vpn_first_always_on_vpn_message (3025322109743675467) -->
-    <skip />
-    <!-- no translation found for vpn_replace_always_on_vpn_enable_message (2577928591361606641) -->
-    <skip />
-    <!-- no translation found for vpn_replace_always_on_vpn_disable_message (3011818750025879902) -->
-    <skip />
-    <!-- no translation found for vpn_replace_vpn_message (5611635724578812860) -->
-    <skip />
-    <!-- no translation found for vpn_turn_on (2363136869284273872) -->
-    <skip />
+    <string name="vpn_replace_vpn_title" msgid="2963898301277610248">"Shintshanisa i-VPN ekhona?"</string>
+    <string name="vpn_set_vpn_title" msgid="4009987321156037267">"Setha i-VPN ehlala ivuliwe?"</string>
+    <string name="vpn_first_always_on_vpn_message" msgid="3025322109743675467">"Ngokuvula lesi silungiselelo, ngeke ube nokuxhumeka kwe-inthanethi kuze kuxhumeke i-VPN ngempumelelo"</string>
+    <string name="vpn_replace_always_on_vpn_enable_message" msgid="2577928591361606641">"I-VPN yakho ekhona izoshintshaniswa, futhi ngeke ube nokuxhumeka kwe-inthanethi i-VPN ize ixhumeke ngempumelelo"</string>
+    <string name="vpn_replace_always_on_vpn_disable_message" msgid="3011818750025879902">"Usuvele uxhumeke ku-VPN ehlala ivuliwe. Uma uxhumeka kwehlukile, i-VPN yakho ekhona izoshintshaniswa, futhi imodi yokuhlala ivuliwe izovalwa."</string>
+    <string name="vpn_replace_vpn_message" msgid="5611635724578812860">"Usuvele uxhumekile ku-VPN. Uma uxhua kwehlukile, i-VPN izoshintshaniswa."</string>
+    <string name="vpn_turn_on" msgid="2363136869284273872">"Vula"</string>
     <string name="vpn_cant_connect_title" msgid="4517706987875907511">"<xliff:g id="VPN_NAME">%1$s</xliff:g> ayikwazi ukuxhuma"</string>
     <string name="vpn_cant_connect_message" msgid="2593197919352621279">"Lolu hlelo lokusebenza alisekeli i-VPN ehlala ivulekile."</string>
     <string name="vpn_title" msgid="6317731879966640551">"I-VPN"</string>
@@ -2537,8 +2530,7 @@
     </plurals>
     <string name="network_dashboard_title" msgid="4771589228992391573">"Inethiwekhi ye-inthanethi"</string>
     <string name="connected_devices_dashboard_title" msgid="2355264951438890709">"Amadivayisi axhunyiwe"</string>
-    <!-- no translation found for system_dashboard_summary (6112602136713843779) -->
-    <skip />
+    <string name="system_dashboard_summary" msgid="6112602136713843779">"Ulimi: <xliff:g id="LANGUAGE">%1$s</xliff:g>"</string>
     <string name="search_results_title" msgid="1796252422574886932">"Izilungiselelo"</string>
     <string name="search_menu" msgid="6283419262313758339">"Izilungiselelo zokusesha"</string>
     <string name="query_hint_text" msgid="3350700807437473939">"Izilungiselelo zokusesha"</string>
diff --git a/res/values/colors.xml b/res/values/colors.xml
index 2b6a730..9f3dd5b 100644
--- a/res/values/colors.xml
+++ b/res/values/colors.xml
@@ -21,7 +21,7 @@
 
     <color name="material_empty_color_light">#FFCED7DB</color>
 
-
+    <color name="bluetooth_dialog_text_color">#8a000000</color>
 
     <color name="crypt_keeper_clock_background">#ff9a9a9a</color>
     <color name="crypt_keeper_clock_foreground">#ff666666</color>
diff --git a/res/values/config.xml b/res/values/config.xml
index 6d56e18..75d8697 100755
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -52,17 +52,10 @@
     <string name="gesture_double_twist_sensor_name" translatable="false"></string>
     <string name="gesture_double_twist_sensor_vendor" translatable="false"></string>
 
-    <!-- Pickup sensor name and vendor used by gesture setting -->
-    <string name="gesture_pickup_sensor_name" translatable="false"></string>
-    <string name="gesture_pickup_sensor_vendor" translatable="false"></string>
-
     <!-- When true enable gesture setting. -->
     <bool name="config_gesture_settings_enabled">false</bool>
 
     <!-- If the Storage Manager settings are enabled. -->
     <bool name="config_storage_manager_settings_enabled">false</bool>
 
-    <!-- When true show double-tap gesture setting. -->
-    <bool name="config_gesture_double_tap_settings_enabled">false</bool>
-
 </resources>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index ba15a19..b266f9c 100755
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -315,4 +315,8 @@
     <!-- Visible vertical space we want to show below password edittext field when ime is shown.
          The unit is sp as it is related to the text size of password requirement item. -->
     <dimen name="visible_vertical_space_below_password">20sp</dimen>
+
+    <!-- Padding for the escalation card in normal dimens -->
+    <dimen name="support_escalation_card_padding_start">40dp</dimen>
+    <dimen name="support_escalation_card_padding_end">40dp</dimen>
 </resources>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index a908c7a..8d6e5ff 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -5929,6 +5929,8 @@
     <string name="network_dashboard_title">Network &amp; Internet</string>
     <!-- Title for setting tile leading to Connected devices settings [CHAR LIMIT=40]-->
     <string name="connected_devices_dashboard_title">Connected devices</string>
+    <!-- Title for setting tile leading to Apps & Notification settings [CHAR LIMIT=40]-->
+    <string name="app_and_notification_dashboard_title">Apps &amp; notifications</string>
     <!-- Summary text for system preference tile, showing current display language of device [CHAR LIMIT=NONE]-->
     <string name="system_dashboard_summary">Language: <xliff:g id="language">%1$s</xliff:g></string>
 
diff --git a/res/values/styles.xml b/res/values/styles.xml
index 32c0b4d..fc37bb0 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -435,8 +435,8 @@
         <item name="android:background">@color/card_background_grey</item>
         <item name="android:gravity">center</item>
         <item name="android:minHeight">368dp</item>
-        <item name="android:paddingStart">56dp</item>
-        <item name="android:paddingEnd">56dp</item>
+        <item name="android:paddingStart">@dimen/support_escalation_card_padding_start</item>
+        <item name="android:paddingEnd">@dimen/support_escalation_card_padding_end</item>
     </style>
 
     <style name="FingerprintHeaderStyle" parent="android:style/TextAppearance.Material.Subhead">
diff --git a/res/values/themes.xml b/res/values/themes.xml
index b9f69cf..35d05fb 100644
--- a/res/values/themes.xml
+++ b/res/values/themes.xml
@@ -123,6 +123,7 @@
 
     <style name="SetupWizardAccessibilitySwitchBarTheme" parent="ThemeOverlay.SwitchBar.Settings">
         <item name="switchBarBackgroundColor">@color/material_blue_500</item>
+        <item name="android:colorControlActivated">@android:color/white</item>
     </style>
 
     <!-- Theme with no local references, used by AccountPreferenceBase where we have to inflate
diff --git a/res/xml/app_and_notification.xml b/res/xml/app_and_notification.xml
new file mode 100644
index 0000000..5da902f
--- /dev/null
+++ b/res/xml/app_and_notification.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright (C) 2016 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
+
+</PreferenceScreen>
\ No newline at end of file
diff --git a/src/com/android/settings/DevelopmentSettings.java b/src/com/android/settings/DevelopmentSettings.java
index 32aaaf0..b9bc439 100644
--- a/src/com/android/settings/DevelopmentSettings.java
+++ b/src/com/android/settings/DevelopmentSettings.java
@@ -1958,7 +1958,8 @@
             Settings.Global.putInt(getActivity().getContentResolver(),
                     Settings.Global.STAY_ON_WHILE_PLUGGED_IN,
                     mKeepScreenOn.isChecked() ?
-                            (BatteryManager.BATTERY_PLUGGED_AC | BatteryManager.BATTERY_PLUGGED_USB) : 0);
+                            (BatteryManager.BATTERY_PLUGGED_AC | BatteryManager.BATTERY_PLUGGED_USB
+                                    | BatteryManager.BATTERY_PLUGGED_WIRELESS) : 0);
         } else if (preference == mBtHciSnoopLog) {
             writeBtHciSnoopLogOptions();
         } else if (preference == mEnableOemUnlock && mEnableOemUnlock.isEnabled()) {
diff --git a/src/com/android/settings/Settings.java b/src/com/android/settings/Settings.java
index 91db7fa..bfecbbf 100644
--- a/src/com/android/settings/Settings.java
+++ b/src/com/android/settings/Settings.java
@@ -166,6 +166,7 @@
     // Top level categories for new IA
     public static class NetworkDashboardActivity extends SettingsActivity {}
     public static class ConnectedDeviceDashboardActivity extends SettingsActivity {}
+    public static class AppAndNotificationDashboardActivity extends SettingsActivity {}
     public static class StorageDashboardActivity extends SettingsActivity {}
     public static class SystemDashboardActivity extends SettingsActivity {}
     public static class SupportDashboardActivity extends SettingsActivity {}
diff --git a/src/com/android/settings/SettingsActivity.java b/src/com/android/settings/SettingsActivity.java
index 07f6ebf..5452f91 100644
--- a/src/com/android/settings/SettingsActivity.java
+++ b/src/com/android/settings/SettingsActivity.java
@@ -61,6 +61,7 @@
 import com.android.settings.accounts.AccountSyncSettings;
 import com.android.settings.accounts.ChooseAccountActivity;
 import com.android.settings.accounts.ManagedProfileSettings;
+import com.android.settings.applications.AppAndNotificationDashboardFragment;
 import com.android.settings.applications.AdvancedAppSettings;
 import com.android.settings.applications.DrawOverlayDetails;
 import com.android.settings.applications.InstalledAppDetails;
@@ -272,16 +273,17 @@
             // New IA
             // Home page
             Settings.NetworkDashboardActivity.class.getName(),
+            Settings.ConnectedDeviceDashboardActivity.class.getName(),
+            Settings.AppAndNotificationDashboardActivity.class.getName(),
             "com.android.settings.Settings.BatteryDashboardAlias",
             "com.android.settings.Settings.DisplayDashboardAlias",
+            "com.android.settings.Settings.SoundDashboardAlias",
             "com.android.settings.Settings.SecurityDashboardAlias",
             Settings.SystemDashboardActivity.class.getName(),
             Settings.SupportDashboardActivity.class.getName(),
             // Home page > Network & Internet
             "com.android.settings.Settings.WifiDashboardAlias",
             "com.android.settings.Settings.DataUsageDashboardAlias",
-            // Home page > Connected devices
-            Settings.ConnectedDeviceDashboardActivity.class.getName(),
             // Home page > System
             "com.android.settings.Settings.LanguageAndInputDashboardAlias",
             "com.android.settings.Settings.DateTimeDashboardAlias",
@@ -392,6 +394,7 @@
             SystemDashboardFragment.class.getName(),
             NetworkDashboardFragment.class.getName(),
             ConnectedDeviceDashboardFragment.class.getName(),
+            AppAndNotificationDashboardFragment.class.getName(),
     };
 
 
diff --git a/src/com/android/settings/Utils.java b/src/com/android/settings/Utils.java
index f8520d8..6f4482c 100644
--- a/src/com/android/settings/Utils.java
+++ b/src/com/android/settings/Utils.java
@@ -47,7 +47,9 @@
 import android.hardware.fingerprint.FingerprintManager;
 import android.net.ConnectivityManager;
 import android.net.LinkProperties;
+import android.net.Network;
 import android.net.Uri;
+import android.net.wifi.WifiManager;
 import android.os.BatteryManager;
 import android.os.Bundle;
 import android.os.IBinder;
@@ -235,10 +237,15 @@
      * @return the formatted and newline-separated IP addresses, or null if none.
      */
     public static String getWifiIpAddresses(Context context) {
-        ConnectivityManager cm = (ConnectivityManager)
+        WifiManager wifiManager = context.getSystemService(WifiManager.class);
+        Network currentNetwork = wifiManager.getCurrentNetwork();
+        if (currentNetwork != null) {
+            ConnectivityManager cm = (ConnectivityManager)
                 context.getSystemService(Context.CONNECTIVITY_SERVICE);
-        LinkProperties prop = cm.getLinkProperties(ConnectivityManager.TYPE_WIFI);
-        return formatIpAddresses(prop);
+            LinkProperties prop = cm.getLinkProperties(currentNetwork);
+            return formatIpAddresses(prop);
+        }
+        return null;
     }
 
     /**
diff --git a/src/com/android/settings/applications/AppAndNotificationDashboardFragment.java b/src/com/android/settings/applications/AppAndNotificationDashboardFragment.java
new file mode 100644
index 0000000..8630541
--- /dev/null
+++ b/src/com/android/settings/applications/AppAndNotificationDashboardFragment.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.applications;
+
+import android.content.Context;
+
+import com.android.settings.R;
+import com.android.settings.core.PreferenceController;
+import com.android.settings.dashboard.DashboardFragment;
+import com.android.settingslib.drawer.CategoryKey;
+
+import java.util.List;
+
+public class AppAndNotificationDashboardFragment extends DashboardFragment {
+
+    private static final String TAG = "AppAndNotifDashboard";
+
+    @Override
+    public int getMetricsCategory() {
+        return APP_AND_NOTIFICATION_CATEGORY_FRAGMENT;
+    }
+
+    @Override
+    protected String getCategoryKey() {
+        return CategoryKey.CATEGORY_APPS;
+    }
+
+    @Override
+    protected String getLogTag() {
+        return TAG;
+    }
+
+    @Override
+    protected int getPreferenceScreenResId() {
+        return R.xml.app_and_notification;
+    }
+
+    @Override
+    protected List<PreferenceController> getPreferenceControllers(Context context) {
+        return null;
+    }
+}
diff --git a/src/com/android/settings/bluetooth/BluetoothPairingController.java b/src/com/android/settings/bluetooth/BluetoothPairingController.java
new file mode 100644
index 0000000..38b30a8
--- /dev/null
+++ b/src/com/android/settings/bluetooth/BluetoothPairingController.java
@@ -0,0 +1,415 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.settings.bluetooth;
+
+import android.bluetooth.BluetoothClass;
+import android.bluetooth.BluetoothDevice;
+import android.content.Context;
+import android.content.Intent;
+import android.text.Editable;
+import android.util.Log;
+import android.widget.CompoundButton;
+import android.widget.CompoundButton.OnCheckedChangeListener;
+import com.android.settings.R;
+import com.android.settings.bluetooth.BluetoothPairingDialogFragment.BluetoothPairingDialogListener;
+import com.android.settingslib.bluetooth.LocalBluetoothManager;
+import com.android.settingslib.bluetooth.LocalBluetoothProfile;
+import java.util.Locale;
+
+/**
+ * A controller used by {@link BluetoothPairingDialog} to manage connection state while we try to
+ * pair with a bluetooth device. It includes methods that allow the
+ * {@link BluetoothPairingDialogFragment} to interrogate the current state as well.
+ */
+public class BluetoothPairingController implements OnCheckedChangeListener,
+        BluetoothPairingDialogListener {
+
+    private static final String TAG = "BTPairingController";
+
+    // Different types of dialogs we can map to
+    public static final int INVALID_DIALOG_TYPE = -1;
+    public static final int USER_ENTRY_DIALOG = 0;
+    public static final int CONFIRMATION_DIALOG = 1;
+    public static final int DISPLAY_PASSKEY_DIALOG = 2;
+
+    private static final int BLUETOOTH_PIN_MAX_LENGTH = 16;
+    private static final int BLUETOOTH_PASSKEY_MAX_LENGTH = 6;
+
+    // Bluetooth dependencies for the connection we are trying to establish
+    private LocalBluetoothManager mBluetoothManager;
+    private BluetoothDevice mDevice;
+    private int mType;
+    private String mUserInput;
+    private String mPasskeyFormatted;
+    private int mPasskey;
+    private String mDeviceName;
+    private LocalBluetoothProfile mPbapClientProfile;
+
+    /**
+     * Creates an instance of a BluetoothPairingController.
+     *
+     * @param intent - must contain {@link BluetoothDevice#EXTRA_PAIRING_VARIANT}, {@link
+     * BluetoothDevice#EXTRA_PAIRING_KEY}, and {@link BluetoothDevice#EXTRA_DEVICE}. Missing extra
+     * will lead to undefined behavior.
+     */
+    public BluetoothPairingController(Intent intent, Context context) {
+        mBluetoothManager = Utils.getLocalBtManager(context);
+        mDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
+
+        String message = "";
+        if (mBluetoothManager == null) {
+            throw new IllegalStateException("Could not obtain LocalBluetoothManager");
+        } else if (mDevice == null) {
+            throw new IllegalStateException("Could not find BluetoothDevice");
+        }
+
+        mType = intent.getIntExtra(BluetoothDevice.EXTRA_PAIRING_VARIANT, BluetoothDevice.ERROR);
+        mPasskey = intent.getIntExtra(BluetoothDevice.EXTRA_PAIRING_KEY, BluetoothDevice.ERROR);
+        mDeviceName = mBluetoothManager.getCachedDeviceManager().getName(mDevice);
+        mPbapClientProfile = mBluetoothManager.getProfileManager().getPbapClientProfile();
+        mPasskeyFormatted = formatKey(mPasskey);
+
+    }
+
+    @Override
+    public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
+        if (isChecked) {
+            mDevice.setPhonebookAccessPermission(BluetoothDevice.ACCESS_ALLOWED);
+        } else {
+            mDevice.setPhonebookAccessPermission(BluetoothDevice.ACCESS_REJECTED);
+        }
+    }
+
+    @Override
+    public void onDialogPositiveClick(BluetoothPairingDialogFragment dialog) {
+        if (getDialogType() == USER_ENTRY_DIALOG) {
+            onPair(mUserInput);
+        } else {
+            onPair(null);
+        }
+    }
+
+    @Override
+    public void onDialogNegativeClick(BluetoothPairingDialogFragment dialog) {
+        onCancel();
+    }
+
+    /**
+     * A method for querying which bluetooth pairing dialog fragment variant this device requires.
+     *
+     * @return - The dialog view variant needed for this device.
+     */
+    public int getDialogType() {
+        switch (mType) {
+            case BluetoothDevice.PAIRING_VARIANT_PIN:
+            case BluetoothDevice.PAIRING_VARIANT_PIN_16_DIGITS:
+            case BluetoothDevice.PAIRING_VARIANT_PASSKEY:
+                return USER_ENTRY_DIALOG;
+
+            case BluetoothDevice.PAIRING_VARIANT_PASSKEY_CONFIRMATION:
+            case BluetoothDevice.PAIRING_VARIANT_CONSENT:
+            case BluetoothDevice.PAIRING_VARIANT_OOB_CONSENT:
+                return CONFIRMATION_DIALOG;
+
+            case BluetoothDevice.PAIRING_VARIANT_DISPLAY_PASSKEY:
+            case BluetoothDevice.PAIRING_VARIANT_DISPLAY_PIN:
+                return DISPLAY_PASSKEY_DIALOG;
+
+            default:
+                return INVALID_DIALOG_TYPE;
+        }
+    }
+
+    /**
+     * @return - A string containing the name provided by the device.
+     */
+    public String getDeviceName() {
+        return mDeviceName;
+    }
+
+    /**
+     * A method for querying if the bluetooth device has a profile already set up on this device.
+     *
+     * @return - A boolean indicating if the device has previous knowledge of a profile for this
+     * device.
+     */
+    public boolean isProfileReady() {
+        return mPbapClientProfile != null && mPbapClientProfile.isProfileReady();
+    }
+
+    /**
+     * A method for querying if the bluetooth device has access to contacts on the device.
+     *
+     * @return - A boolean indicating if the bluetooth device has permission to access the device
+     * contacts
+     */
+    public boolean getContactSharingState() {
+        switch (mDevice.getPhonebookAccessPermission()) {
+            case BluetoothDevice.ACCESS_ALLOWED:
+                return true;
+            case BluetoothDevice.ACCESS_REJECTED:
+                return false;
+            default:
+                if (mDevice.getBluetoothClass().getDeviceClass()
+                        == BluetoothClass.Device.AUDIO_VIDEO_HANDSFREE) {
+                    return true;
+                }
+                return false;
+        }
+    }
+
+    /**
+     * A method for querying if the provided editable is a valid passkey/pin format for this device.
+     *
+     * @param s - The passkey/pin
+     * @return - A boolean indicating if the passkey/pin is of the correct format.
+     */
+    public boolean isPasskeyValid(Editable s) {
+        boolean requires16Digits = mType == BluetoothDevice.PAIRING_VARIANT_PIN_16_DIGITS;
+        return s.length() >= 16 && requires16Digits || s.length() > 0 && !requires16Digits;
+    }
+
+    /**
+     * A method for querying what message should be shown to the user as additional text in the
+     * dialog for this device. Returns -1 to indicate a device type that does not use this message.
+     *
+     * @return - The message ID to show the user.
+     */
+    public int getDeviceVariantMessageID() {
+        switch (mType) {
+            case BluetoothDevice.PAIRING_VARIANT_PIN_16_DIGITS:
+            case BluetoothDevice.PAIRING_VARIANT_PIN:
+                return R.string.bluetooth_enter_pin_other_device;
+
+            case BluetoothDevice.PAIRING_VARIANT_PASSKEY:
+                return R.string.bluetooth_enter_passkey_other_device;
+
+            default:
+                return -1;
+        }
+    }
+
+    /**
+     * A method for querying what message hint should be shown to the user as additional text in the
+     * dialog for this device. Returns -1 to indicate a device type that does not use this message.
+     *
+     * @return - The message ID to show the user.
+     */
+    public int getDeviceVariantMessageHint() {
+        switch (mType) {
+            case BluetoothDevice.PAIRING_VARIANT_PIN_16_DIGITS:
+                return R.string.bluetooth_pin_values_hint_16_digits;
+
+            case BluetoothDevice.PAIRING_VARIANT_PIN:
+            case BluetoothDevice.PAIRING_VARIANT_PASSKEY:
+                return R.string.bluetooth_pin_values_hint;
+
+            default:
+                return -1;
+        }
+    }
+
+    /**
+     * A method for querying the maximum passkey/pin length for this device.
+     *
+     * @return - An int indicating the maximum length
+     */
+    public int getDeviceMaxPasskeyLength() {
+        switch (mType) {
+            case BluetoothDevice.PAIRING_VARIANT_PIN_16_DIGITS:
+            case BluetoothDevice.PAIRING_VARIANT_PIN:
+                return BLUETOOTH_PIN_MAX_LENGTH;
+
+            case BluetoothDevice.PAIRING_VARIANT_PASSKEY:
+                return BLUETOOTH_PASSKEY_MAX_LENGTH;
+
+            default:
+                return 0;
+        }
+
+    }
+
+    /**
+     * A method for querying if the device uses an alphanumeric passkey.
+     *
+     * @return - a boolean indicating if the passkey can be alphanumeric.
+     */
+    public boolean pairingCodeIsAlphanumeric() {
+        switch (mType) {
+            case BluetoothDevice.PAIRING_VARIANT_PASSKEY:
+                return false;
+
+            default:
+                return true;
+        }
+    }
+
+    /**
+     * A method used by the dialogfragment to notify the controller that the dialog has been
+     * displayed for bluetooth device types that just care about it being displayed.
+     */
+    protected void notifyDialogDisplayed() {
+        // send an OK to the framework, indicating that the dialog has been displayed.
+        if (mType == BluetoothDevice.PAIRING_VARIANT_DISPLAY_PASSKEY) {
+            mDevice.setPairingConfirmation(true);
+        } else if (mType == BluetoothDevice.PAIRING_VARIANT_DISPLAY_PIN) {
+            byte[] pinBytes = BluetoothDevice.convertPinToBytes(mPasskeyFormatted);
+            mDevice.setPin(pinBytes);
+        }
+    }
+
+    /**
+     * A method for querying if this bluetooth device type has a key it would like displayed
+     * to the user.
+     *
+     * @return - A boolean indicating if a key exists which should be displayed to the user.
+     */
+    public boolean isDisplayPairingKeyVariant() {
+        switch (mType) {
+            case BluetoothDevice.PAIRING_VARIANT_DISPLAY_PASSKEY:
+            case BluetoothDevice.PAIRING_VARIANT_DISPLAY_PIN:
+            case BluetoothDevice.PAIRING_VARIANT_OOB_CONSENT:
+                return true;
+            default:
+                return false;
+        }
+    }
+
+    /**
+     * A method for querying if this bluetooth device type has other content it would like displayed
+     * to the user.
+     *
+     * @return - A boolean indicating if content exists which should be displayed to the user.
+     */
+    public boolean hasPairingContent() {
+        switch (mType) {
+            case BluetoothDevice.PAIRING_VARIANT_DISPLAY_PASSKEY:
+            case BluetoothDevice.PAIRING_VARIANT_DISPLAY_PIN:
+            case BluetoothDevice.PAIRING_VARIANT_PASSKEY_CONFIRMATION:
+                return true;
+
+            default:
+                return false;
+        }
+    }
+
+    /**
+     * A method for obtaining any additional content this bluetooth device has for displaying to the
+     * user.
+     *
+     * @return - A string containing the additional content, null if none exists.
+     * @see {@link BluetoothPairingController#hasPairingContent()}
+     */
+    public String getPairingContent() {
+        if (hasPairingContent()) {
+            return mPasskeyFormatted;
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * A method that exists to allow the fragment to update the controller with input the user has
+     * provided in the fragment.
+     *
+     * @param input - A string containing the user input.
+     */
+    protected void updateUserInput(String input) {
+        mUserInput = input;
+    }
+
+    /**
+     * Returns the provided passkey in a format that this device expects. Only works for numeric
+     * passkeys/pins.
+     *
+     * @param passkey - An integer containing the passkey to format.
+     * @return - A string containing the formatted passkey/pin
+     */
+    private String formatKey(int passkey) {
+        switch (mType) {
+            case BluetoothDevice.PAIRING_VARIANT_PASSKEY_CONFIRMATION:
+            case BluetoothDevice.PAIRING_VARIANT_DISPLAY_PASSKEY:
+                return String.format(Locale.US, "%06d", passkey);
+
+            case BluetoothDevice.PAIRING_VARIANT_DISPLAY_PIN:
+                return String.format("%04d", passkey);
+
+            default:
+                return null;
+        }
+    }
+
+    /**
+     * handles the necessary communication with the bluetooth device to establish a successful
+     * pairing
+     *
+     * @param passkey - The passkey we will attempt to pair to the device with.
+     */
+    private void onPair(String passkey) {
+        Log.d(TAG, "Pairing dialog accepted");
+        switch (mType) {
+            case BluetoothDevice.PAIRING_VARIANT_PIN:
+            case BluetoothDevice.PAIRING_VARIANT_PIN_16_DIGITS:
+                byte[] pinBytes = BluetoothDevice.convertPinToBytes(passkey);
+                if (pinBytes == null) {
+                    return;
+                }
+                mDevice.setPin(pinBytes);
+                break;
+
+            case BluetoothDevice.PAIRING_VARIANT_PASSKEY:
+                int pass = Integer.parseInt(passkey);
+                mDevice.setPasskey(pass);
+                break;
+
+            case BluetoothDevice.PAIRING_VARIANT_PASSKEY_CONFIRMATION:
+            case BluetoothDevice.PAIRING_VARIANT_CONSENT:
+                mDevice.setPairingConfirmation(true);
+                break;
+
+            case BluetoothDevice.PAIRING_VARIANT_DISPLAY_PASSKEY:
+            case BluetoothDevice.PAIRING_VARIANT_DISPLAY_PIN:
+                // Do nothing.
+                break;
+
+            case BluetoothDevice.PAIRING_VARIANT_OOB_CONSENT:
+                mDevice.setRemoteOutOfBandData();
+                break;
+
+            default:
+                Log.e(TAG, "Incorrect pairing type received");
+        }
+    }
+
+    /**
+     * A method for properly ending communication with the bluetooth device. Will be called by the
+     * {@link BluetoothPairingDialogFragment} when it is dismissed.
+     */
+    public void onCancel() {
+        Log.d(TAG, "Pairing dialog canceled");
+        mDevice.cancelPairingUserInput();
+    }
+
+    /**
+     * A method for checking if this device is equal to another device.
+     *
+     * @param device - The other device being compared to this device.
+     * @return - A boolean indicating if the devices were equal.
+     */
+    public boolean deviceEquals(BluetoothDevice device) {
+        return mDevice == device;
+    }
+}
diff --git a/src/com/android/settings/bluetooth/BluetoothPairingDialog.java b/src/com/android/settings/bluetooth/BluetoothPairingDialog.java
old mode 100755
new mode 100644
index 27cd532..ed63fcb
--- a/src/com/android/settings/bluetooth/BluetoothPairingDialog.java
+++ b/src/com/android/settings/bluetooth/BluetoothPairingDialog.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2008 The Android Open Source Project
+ * Copyright (C) 2016 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -16,65 +16,28 @@
 
 package com.android.settings.bluetooth;
 
-import android.bluetooth.BluetoothClass;
+import android.annotation.Nullable;
+import android.app.Activity;
 import android.bluetooth.BluetoothDevice;
-import android.bluetooth.BluetoothUuid;
 import android.content.BroadcastReceiver;
 import android.content.Context;
-import android.content.DialogInterface;
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.os.Bundle;
-import android.text.Editable;
-import android.text.InputFilter;
-import android.text.InputFilter.LengthFilter;
-import android.text.InputType;
-import android.text.SpannableString;
-import android.text.Spanned;
-import android.text.TextWatcher;
-import android.text.style.TtsSpan;
-import android.util.Log;
-import android.view.KeyEvent;
-import android.view.View;
-import android.widget.Button;
-import android.widget.CheckBox;
-import android.widget.CompoundButton;
-import android.widget.EditText;
-import android.widget.TextView;
-
-import com.android.internal.app.AlertActivity;
-import com.android.internal.app.AlertController;
-import com.android.settings.R;
-import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager;
-import com.android.settingslib.bluetooth.LocalBluetoothManager;
-import com.android.settingslib.bluetooth.LocalBluetoothProfile;
-
-import java.util.Locale;
 
 /**
  * BluetoothPairingDialog asks the user to enter a PIN / Passkey / simple confirmation
  * for pairing with a remote Bluetooth device. It is an activity that appears as a dialog.
  */
-public final class BluetoothPairingDialog extends AlertActivity implements
-        CompoundButton.OnCheckedChangeListener, DialogInterface.OnClickListener, TextWatcher {
-    private static final String TAG = "BluetoothPairingDialog";
+public final class BluetoothPairingDialog extends Activity {
+    public static final String FRAGMENT_TAG = "bluetooth.pairing.fragment";
 
-    private static final int BLUETOOTH_PIN_MAX_LENGTH = 16;
-    private static final int BLUETOOTH_PASSKEY_MAX_LENGTH = 6;
-
-    private LocalBluetoothManager mBluetoothManager;
-    private CachedBluetoothDeviceManager mCachedDeviceManager;
-    private BluetoothDevice mDevice;
-    private int mType;
-    private String mPairingKey;
-    private EditText mPairingView;
-    private Button mOkButton;
-    private LocalBluetoothProfile mPbapClientProfile;
+    private BluetoothPairingController mBluetoothPairingController;
     private boolean mReceiverRegistered;
 
     /**
      * Dismiss the dialog if the bond state changes to bonded or none,
-     * or if pairing was canceled for {@link #mDevice}.
+     * or if pairing was canceled for {@link BluetoothPairingController#mDevice}.
      */
     private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
         @Override
@@ -82,14 +45,14 @@
             String action = intent.getAction();
             if (BluetoothDevice.ACTION_BOND_STATE_CHANGED.equals(action)) {
                 int bondState = intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE,
-                                                   BluetoothDevice.ERROR);
+                        BluetoothDevice.ERROR);
                 if (bondState == BluetoothDevice.BOND_BONDED ||
                         bondState == BluetoothDevice.BOND_NONE) {
                     dismiss();
                 }
             } else if (BluetoothDevice.ACTION_PAIRING_CANCEL.equals(action)) {
                 BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
-                if (device == null || device.equals(mDevice)) {
+                if (device == null || mBluetoothPairingController.deviceEquals(device)) {
                     dismiss();
                 }
             }
@@ -97,72 +60,29 @@
     };
 
     @Override
-    protected void onCreate(Bundle savedInstanceState) {
+    protected void onCreate(@Nullable Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
+        boolean fragmentFound = true;
 
+        BluetoothPairingDialogFragment bluetoothFragment =
+                (BluetoothPairingDialogFragment) getFragmentManager()
+                        .findFragmentByTag(FRAGMENT_TAG);
         Intent intent = getIntent();
-        if (!intent.getAction().equals(BluetoothDevice.ACTION_PAIRING_REQUEST)) {
-            Log.e(TAG, "Error: this activity may be started only with intent " +
-                  BluetoothDevice.ACTION_PAIRING_REQUEST);
-            finish();
-            return;
+        mBluetoothPairingController = new BluetoothPairingController(intent, this);
+
+        // check if the fragment exists already
+        if (bluetoothFragment == null) {
+            fragmentFound = false;
+            bluetoothFragment = new BluetoothPairingDialogFragment();
         }
 
-        mBluetoothManager = Utils.getLocalBtManager(this);
-        if (mBluetoothManager == null) {
-            Log.e(TAG, "Error: BluetoothAdapter not supported by system");
-            finish();
-            return;
+        // set the controller
+        bluetoothFragment.setPairingController(mBluetoothPairingController);
+
+        // pass the fragment to the manager when it is created from scratch
+        if (!fragmentFound) {
+            bluetoothFragment.show(getFragmentManager(), FRAGMENT_TAG);
         }
-        mCachedDeviceManager = mBluetoothManager.getCachedDeviceManager();
-        mPbapClientProfile = mBluetoothManager.getProfileManager().getPbapClientProfile();
-
-        mDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
-        mType = intent.getIntExtra(BluetoothDevice.EXTRA_PAIRING_VARIANT, BluetoothDevice.ERROR);
-
-        switch (mType) {
-            case BluetoothDevice.PAIRING_VARIANT_PIN:
-            case BluetoothDevice.PAIRING_VARIANT_PIN_16_DIGITS:
-            case BluetoothDevice.PAIRING_VARIANT_PASSKEY:
-                createUserEntryDialog();
-                break;
-
-            case BluetoothDevice.PAIRING_VARIANT_PASSKEY_CONFIRMATION:
-                int passkey =
-                    intent.getIntExtra(BluetoothDevice.EXTRA_PAIRING_KEY, BluetoothDevice.ERROR);
-                if (passkey == BluetoothDevice.ERROR) {
-                    Log.e(TAG, "Invalid Confirmation Passkey received, not showing any dialog");
-                    return;
-                }
-                mPairingKey = String.format(Locale.US, "%06d", passkey);
-                createConfirmationDialog();
-                break;
-
-            case BluetoothDevice.PAIRING_VARIANT_CONSENT:
-            case BluetoothDevice.PAIRING_VARIANT_OOB_CONSENT:
-                createConsentDialog();
-                break;
-
-            case BluetoothDevice.PAIRING_VARIANT_DISPLAY_PASSKEY:
-            case BluetoothDevice.PAIRING_VARIANT_DISPLAY_PIN:
-                int pairingKey =
-                    intent.getIntExtra(BluetoothDevice.EXTRA_PAIRING_KEY, BluetoothDevice.ERROR);
-                if (pairingKey == BluetoothDevice.ERROR) {
-                    Log.e(TAG, "Invalid Confirmation Passkey or PIN received, not showing any dialog");
-                    return;
-                }
-                if (mType == BluetoothDevice.PAIRING_VARIANT_DISPLAY_PASSKEY) {
-                    mPairingKey = String.format("%06d", pairingKey);
-                } else {
-                    mPairingKey = String.format("%04d", pairingKey);
-                }
-                createDisplayPasskeyOrPinDialog();
-                break;
-
-            default:
-                Log.e(TAG, "Incorrect pairing type received, not showing any dialog");
-        }
-
         /*
          * Leave this registered through pause/resume since we still want to
          * finish the activity in the background if pairing is canceled.
@@ -172,210 +92,6 @@
         mReceiverRegistered = true;
     }
 
-    private void createUserEntryDialog() {
-        final AlertController.AlertParams p = mAlertParams;
-        p.mTitle = getString(R.string.bluetooth_pairing_request,
-                mCachedDeviceManager.getName(mDevice));
-        p.mView = createPinEntryView();
-        p.mPositiveButtonText = getString(android.R.string.ok);
-        p.mPositiveButtonListener = this;
-        p.mNegativeButtonText = getString(android.R.string.cancel);
-        p.mNegativeButtonListener = this;
-        setupAlert();
-
-        mOkButton = mAlert.getButton(BUTTON_POSITIVE);
-        mOkButton.setEnabled(false);
-    }
-
-    private View createPinEntryView() {
-        View view = getLayoutInflater().inflate(R.layout.bluetooth_pin_entry, null);
-        TextView messageViewCaptionHint = (TextView) view.findViewById(R.id.pin_values_hint);
-        TextView messageView2 = (TextView) view.findViewById(R.id.message_below_pin);
-        CheckBox alphanumericPin = (CheckBox) view.findViewById(R.id.alphanumeric_pin);
-        CheckBox contactSharing = (CheckBox) view.findViewById(
-                R.id.phonebook_sharing_message_entry_pin);
-        contactSharing.setText(getString(R.string.bluetooth_pairing_shares_phonebook,
-                mCachedDeviceManager.getName(mDevice)));
-        if (mPbapClientProfile != null && mPbapClientProfile.isProfileReady()) {
-            contactSharing.setVisibility(View.GONE);
-        }
-        if (mDevice.getPhonebookAccessPermission() == BluetoothDevice.ACCESS_ALLOWED) {
-            contactSharing.setChecked(true);
-        } else if (mDevice.getPhonebookAccessPermission() == BluetoothDevice.ACCESS_REJECTED){
-            contactSharing.setChecked(false);
-        } else {
-            if (mDevice.getBluetoothClass().getDeviceClass()
-                    == BluetoothClass.Device.AUDIO_VIDEO_HANDSFREE) {
-                contactSharing.setChecked(true);
-                mDevice.setPhonebookAccessPermission(BluetoothDevice.ACCESS_ALLOWED);
-            } else {
-                contactSharing.setChecked(false);
-                mDevice.setPhonebookAccessPermission(BluetoothDevice.ACCESS_REJECTED);
-            }
-        }
-
-        contactSharing.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
-            @Override
-            public void onCheckedChanged(CompoundButton compoundButton, boolean isChecked) {
-                if (isChecked) {
-                    mDevice.setPhonebookAccessPermission(BluetoothDevice.ACCESS_ALLOWED);
-                } else {
-                    mDevice.setPhonebookAccessPermission(BluetoothDevice.ACCESS_REJECTED);
-                }
-            }
-        });
-
-        mPairingView = (EditText) view.findViewById(R.id.text);
-        mPairingView.addTextChangedListener(this);
-        alphanumericPin.setOnCheckedChangeListener(this);
-
-        int messageId;
-        int messageIdHint = R.string.bluetooth_pin_values_hint;
-        int maxLength;
-        switch (mType) {
-            case BluetoothDevice.PAIRING_VARIANT_PIN_16_DIGITS:
-                messageIdHint = R.string.bluetooth_pin_values_hint_16_digits;
-                // FALLTHROUGH
-            case BluetoothDevice.PAIRING_VARIANT_PIN:
-                messageId = R.string.bluetooth_enter_pin_other_device;
-                // Maximum of 16 characters in a PIN
-                maxLength = BLUETOOTH_PIN_MAX_LENGTH;
-                break;
-
-            case BluetoothDevice.PAIRING_VARIANT_PASSKEY:
-                messageId = R.string.bluetooth_enter_passkey_other_device;
-                // Maximum of 6 digits for passkey
-                maxLength = BLUETOOTH_PASSKEY_MAX_LENGTH;
-                alphanumericPin.setVisibility(View.GONE);
-                break;
-
-            default:
-                Log.e(TAG, "Incorrect pairing type for createPinEntryView: " + mType);
-                return null;
-        }
-
-        messageViewCaptionHint.setText(messageIdHint);
-        messageView2.setText(messageId);
-        mPairingView.setInputType(InputType.TYPE_CLASS_NUMBER);
-        mPairingView.setFilters(new InputFilter[] {
-                new LengthFilter(maxLength) });
-
-        return view;
-    }
-
-    private View createView() {
-        View view = getLayoutInflater().inflate(R.layout.bluetooth_pin_confirm, null);
-        TextView pairingViewCaption = (TextView) view.findViewById(R.id.pairing_caption);
-        TextView pairingViewContent = (TextView) view.findViewById(R.id.pairing_subhead);
-        TextView messagePairing = (TextView) view.findViewById(R.id.pairing_code_message);
-        CheckBox contactSharing = (CheckBox) view.findViewById(
-                R.id.phonebook_sharing_message_confirm_pin);
-        contactSharing.setText(getString(R.string.bluetooth_pairing_shares_phonebook,
-                mCachedDeviceManager.getName(mDevice)));
-        if (mPbapClientProfile != null && mPbapClientProfile.isProfileReady()) {
-            contactSharing.setVisibility(View.GONE);
-        }
-        if (mDevice.getPhonebookAccessPermission() == BluetoothDevice.ACCESS_ALLOWED) {
-            contactSharing.setChecked(true);
-        } else if (mDevice.getPhonebookAccessPermission() == BluetoothDevice.ACCESS_REJECTED){
-            contactSharing.setChecked(false);
-        } else {
-            if (mDevice.getBluetoothClass().getDeviceClass()
-                    == BluetoothClass.Device.AUDIO_VIDEO_HANDSFREE) {
-                contactSharing.setChecked(true);
-                mDevice.setPhonebookAccessPermission(BluetoothDevice.ACCESS_ALLOWED);
-            } else {
-                contactSharing.setChecked(false);
-                mDevice.setPhonebookAccessPermission(BluetoothDevice.ACCESS_REJECTED);
-            }
-        }
-
-        contactSharing.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
-            @Override
-            public void onCheckedChanged(CompoundButton compoundButton, boolean isChecked) {
-                if (isChecked) {
-                    mDevice.setPhonebookAccessPermission(BluetoothDevice.ACCESS_ALLOWED);
-                } else {
-                    mDevice.setPhonebookAccessPermission(BluetoothDevice.ACCESS_REJECTED);
-                }
-            }
-        });
-
-        SpannableString pairingContent = null;
-        switch (mType) {
-            case BluetoothDevice.PAIRING_VARIANT_DISPLAY_PASSKEY:
-            case BluetoothDevice.PAIRING_VARIANT_DISPLAY_PIN:
-                messagePairing.setVisibility(View.VISIBLE);
-            case BluetoothDevice.PAIRING_VARIANT_PASSKEY_CONFIRMATION: {
-                pairingContent = new SpannableString(mPairingKey);
-                pairingContent.setSpan(new TtsSpan.DigitsBuilder(mPairingKey).build(),
-                        0, mPairingKey.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
-                break;
-            }
-            case BluetoothDevice.PAIRING_VARIANT_CONSENT:
-                messagePairing.setVisibility(view.GONE);
-                break;
-            case BluetoothDevice.PAIRING_VARIANT_OOB_CONSENT:
-                messagePairing.setVisibility(View.VISIBLE);
-                break;
-
-            default:
-                Log.e(TAG, "Incorrect pairing type received, not creating view");
-                return null;
-        }
-
-        if (pairingContent != null) {
-            pairingViewCaption.setVisibility(View.VISIBLE);
-            pairingViewContent.setVisibility(View.VISIBLE);
-            pairingViewContent.setText(pairingContent);
-        }
-
-        return view;
-    }
-
-    private void createConfirmationDialog() {
-        final AlertController.AlertParams p = mAlertParams;
-        p.mTitle = getString(R.string.bluetooth_pairing_request,
-                mCachedDeviceManager.getName(mDevice));
-        p.mView = createView();
-        p.mPositiveButtonText = getString(R.string.bluetooth_pairing_accept);
-        p.mPositiveButtonListener = this;
-        p.mNegativeButtonText = getString(R.string.bluetooth_pairing_decline);
-        p.mNegativeButtonListener = this;
-        setupAlert();
-    }
-
-    private void createConsentDialog() {
-        final AlertController.AlertParams p = mAlertParams;
-        p.mTitle = getString(R.string.bluetooth_pairing_request,
-                mCachedDeviceManager.getName(mDevice));
-        p.mView = createView();
-        p.mPositiveButtonText = getString(R.string.bluetooth_pairing_accept);
-        p.mPositiveButtonListener = this;
-        p.mNegativeButtonText = getString(R.string.bluetooth_pairing_decline);
-        p.mNegativeButtonListener = this;
-        setupAlert();
-    }
-
-    private void createDisplayPasskeyOrPinDialog() {
-        final AlertController.AlertParams p = mAlertParams;
-        p.mTitle = getString(R.string.bluetooth_pairing_request,
-                mCachedDeviceManager.getName(mDevice));
-        p.mView = createView();
-        p.mNegativeButtonText = getString(android.R.string.cancel);
-        p.mNegativeButtonListener = this;
-        setupAlert();
-
-        // Since its only a notification, send an OK to the framework,
-        // indicating that the dialog has been displayed.
-        if (mType == BluetoothDevice.PAIRING_VARIANT_DISPLAY_PASSKEY) {
-            mDevice.setPairingConfirmation(true);
-        } else if (mType == BluetoothDevice.PAIRING_VARIANT_DISPLAY_PIN) {
-            byte[] pinBytes = BluetoothDevice.convertPinToBytes(mPairingKey);
-            mDevice.setPin(pinBytes);
-        }
-    }
-
     @Override
     protected void onDestroy() {
         super.onDestroy();
@@ -385,95 +101,9 @@
         }
     }
 
-    public void afterTextChanged(Editable s) {
-        if (mOkButton != null) {
-            if (mType == BluetoothDevice.PAIRING_VARIANT_PIN_16_DIGITS) {
-                mOkButton.setEnabled(s.length() >= 16);
-            } else {
-                mOkButton.setEnabled(s.length() > 0);
-            }
-        }
-    }
-
-    private void onPair(String value) {
-        Log.i(TAG, "Pairing dialog accepted");
-        switch (mType) {
-            case BluetoothDevice.PAIRING_VARIANT_PIN:
-            case BluetoothDevice.PAIRING_VARIANT_PIN_16_DIGITS:
-                byte[] pinBytes = BluetoothDevice.convertPinToBytes(value);
-                if (pinBytes == null) {
-                    return;
-                }
-                mDevice.setPin(pinBytes);
-                break;
-
-            case BluetoothDevice.PAIRING_VARIANT_PASSKEY:
-                int passkey = Integer.parseInt(value);
-                mDevice.setPasskey(passkey);
-                break;
-
-            case BluetoothDevice.PAIRING_VARIANT_PASSKEY_CONFIRMATION:
-            case BluetoothDevice.PAIRING_VARIANT_CONSENT:
-                mDevice.setPairingConfirmation(true);
-                break;
-
-            case BluetoothDevice.PAIRING_VARIANT_DISPLAY_PASSKEY:
-            case BluetoothDevice.PAIRING_VARIANT_DISPLAY_PIN:
-                // Do nothing.
-                break;
-
-            case BluetoothDevice.PAIRING_VARIANT_OOB_CONSENT:
-                mDevice.setRemoteOutOfBandData();
-                break;
-
-            default:
-                Log.e(TAG, "Incorrect pairing type received");
-        }
-    }
-
-    private void onCancel() {
-        Log.i(TAG, "Pairing dialog canceled");
-        mDevice.cancelPairingUserInput();
-    }
-
-    public boolean onKeyDown(int keyCode, KeyEvent event) {
-        if (keyCode == KeyEvent.KEYCODE_BACK) {
-            onCancel();
-        }
-        return super.onKeyDown(keyCode,event);
-    }
-
-    public void onClick(DialogInterface dialog, int which) {
-        switch (which) {
-            case BUTTON_POSITIVE:
-                if (mPairingView != null) {
-                    onPair(mPairingView.getText().toString());
-                } else {
-                    onPair(null);
-                }
-                break;
-
-            case BUTTON_NEGATIVE:
-            default:
-                onCancel();
-                break;
-        }
-    }
-
-    /* Not used */
-    public void beforeTextChanged(CharSequence s, int start, int count, int after) {
-    }
-
-    /* Not used */
-    public void onTextChanged(CharSequence s, int start, int before, int count) {
-    }
-
-    public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
-        // change input type for soft keyboard to numeric or alphanumeric
-        if (isChecked) {
-            mPairingView.setInputType(InputType.TYPE_CLASS_TEXT);
-        } else {
-            mPairingView.setInputType(InputType.TYPE_CLASS_NUMBER);
+    private void dismiss() {
+        if (!isFinishing()) {
+            finish();
         }
     }
 }
diff --git a/src/com/android/settings/bluetooth/BluetoothPairingDialogFragment.java b/src/com/android/settings/bluetooth/BluetoothPairingDialogFragment.java
new file mode 100644
index 0000000..d4247c0
--- /dev/null
+++ b/src/com/android/settings/bluetooth/BluetoothPairingDialogFragment.java
@@ -0,0 +1,267 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.settings.bluetooth;
+
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.content.DialogInterface;
+import android.content.DialogInterface.OnClickListener;
+import android.os.Bundle;
+import android.text.Editable;
+import android.text.InputFilter;
+import android.text.InputFilter.LengthFilter;
+import android.text.InputType;
+import android.text.TextWatcher;
+import android.util.Log;
+import android.view.View;
+import android.widget.Button;
+import android.widget.CheckBox;
+import android.widget.EditText;
+import android.widget.TextView;
+import com.android.internal.logging.MetricsProto.MetricsEvent;
+import com.android.settings.R;
+import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
+
+/**
+ * A dialogFragment used by {@link BluetoothPairingDialog} to create an appropriately styled dialog
+ * for the bluetooth device.
+ */
+public class BluetoothPairingDialogFragment extends InstrumentedDialogFragment implements
+        TextWatcher, OnClickListener {
+
+    private static final String TAG = "BTPairingDialogFragment";
+
+    private AlertDialog.Builder mBuilder;
+    private BluetoothPairingController mPairingController;
+    private AlertDialog mDialog;
+    private EditText mPairingView;
+
+    /**
+     * The interface we expect a listener to implement. Typically this should be done by
+     * the controller.
+     */
+    public interface BluetoothPairingDialogListener {
+
+        void onDialogNegativeClick(BluetoothPairingDialogFragment dialog);
+
+        void onDialogPositiveClick(BluetoothPairingDialogFragment dialog);
+    }
+
+    @Override
+    public Dialog onCreateDialog(Bundle savedInstanceState) {
+        if (mPairingController == null) {
+            throw new IllegalStateException(
+                    "Must call setPairingController() before showing dialog");
+        }
+        mBuilder = new AlertDialog.Builder(getActivity());
+        mDialog = setupDialog();
+        mDialog.setCanceledOnTouchOutside(false);
+        return mDialog;
+    }
+
+    @Override
+    public void beforeTextChanged(CharSequence s, int start, int count, int after) {
+    }
+
+    @Override
+    public void onTextChanged(CharSequence s, int start, int before, int count) {
+    }
+
+    @Override
+    public void afterTextChanged(Editable s) {
+        // enable the positive button when we detect potentially valid input
+        Button positiveButton = mDialog.getButton(DialogInterface.BUTTON_POSITIVE);
+        if (positiveButton != null) {
+            positiveButton.setEnabled(mPairingController.isPasskeyValid(s));
+        }
+        // notify the controller about user input
+        mPairingController.updateUserInput(s.toString());
+    }
+
+    @Override
+    public void onClick(DialogInterface dialog, int which) {
+        if (which == DialogInterface.BUTTON_POSITIVE) {
+            mPairingController.onDialogPositiveClick(this);
+        } else if (which == DialogInterface.BUTTON_NEGATIVE) {
+            mPairingController.onDialogNegativeClick(this);
+        }
+    }
+
+    @Override
+    public int getMetricsCategory() {
+        return MetricsEvent.BLUETOOTH_DIALOG_FRAGMENT;
+    }
+
+    /**
+     * Sets the controller that the fragment should use. this method MUST be called
+     * before you try to show the dialog or an error will be thrown. An implementation
+     * of a pairing controller can be found at {@link BluetoothPairingController}.
+     */
+    public void setPairingController(BluetoothPairingController pairingController) {
+        mPairingController = pairingController;
+    }
+
+    /**
+     * Creates the appropriate type of dialog and returns it.
+     */
+    private AlertDialog setupDialog() {
+        AlertDialog dialog;
+        switch (mPairingController.getDialogType()) {
+            case BluetoothPairingController.USER_ENTRY_DIALOG:
+                dialog = createUserEntryDialog();
+                break;
+            case BluetoothPairingController.CONFIRMATION_DIALOG:
+                dialog = createConsentDialog();
+                break;
+            case BluetoothPairingController.DISPLAY_PASSKEY_DIALOG:
+                dialog = createDisplayPasskeyOrPinDialog();
+                break;
+            default:
+                dialog = null;
+                Log.e(TAG, "Incorrect pairing type received, not showing any dialog");
+        }
+        return dialog;
+    }
+
+    /**
+     * Returns a dialog with UI elements that allow a user to provide input.
+     */
+    private AlertDialog createUserEntryDialog() {
+        mBuilder.setTitle(getString(R.string.bluetooth_pairing_request,
+                mPairingController.getDeviceName()));
+        mBuilder.setView(createPinEntryView());
+        mBuilder.setPositiveButton(getString(android.R.string.ok), this);
+        mBuilder.setNegativeButton(getString(android.R.string.cancel), this);
+        AlertDialog dialog = mBuilder.create();
+        dialog.getButton(Dialog.BUTTON_POSITIVE).setEnabled(false);
+        return dialog;
+    }
+
+    /**
+     * Creates the custom view with UI elements for user input.
+     */
+    private View createPinEntryView() {
+        View view = getActivity().getLayoutInflater().inflate(R.layout.bluetooth_pin_entry, null);
+        TextView messageViewCaptionHint = (TextView) view.findViewById(R.id.pin_values_hint);
+        TextView messageView2 = (TextView) view.findViewById(R.id.message_below_pin);
+        CheckBox alphanumericPin = (CheckBox) view.findViewById(R.id.alphanumeric_pin);
+        CheckBox contactSharing = (CheckBox) view.findViewById(
+                R.id.phonebook_sharing_message_entry_pin);
+        contactSharing.setText(getString(R.string.bluetooth_pairing_shares_phonebook,
+                mPairingController.getDeviceName()));
+        EditText pairingView = (EditText) view.findViewById(R.id.text);
+
+        contactSharing.setVisibility(mPairingController.isProfileReady()
+                ? View.GONE : View.VISIBLE);
+        contactSharing.setOnCheckedChangeListener(mPairingController);
+        contactSharing.setChecked(mPairingController.getContactSharingState());
+
+        mPairingView = pairingView;
+
+        pairingView.addTextChangedListener(this);
+        alphanumericPin.setOnCheckedChangeListener((buttonView, isChecked) -> {
+            // change input type for soft keyboard to numeric or alphanumeric
+            if (isChecked) {
+                mPairingView.setInputType(InputType.TYPE_CLASS_TEXT);
+            } else {
+                mPairingView.setInputType(InputType.TYPE_CLASS_NUMBER);
+            }
+        });
+
+        int messageId = mPairingController.getDeviceVariantMessageID();
+        int messageIdHint = mPairingController.getDeviceVariantMessageHint();
+        int maxLength = mPairingController.getDeviceMaxPasskeyLength();
+        alphanumericPin.setVisibility(mPairingController.pairingCodeIsAlphanumeric()
+                ? View.VISIBLE : View.GONE);
+
+        messageViewCaptionHint.setText(messageIdHint);
+        messageView2.setText(messageId);
+        pairingView.setInputType(InputType.TYPE_CLASS_NUMBER);
+        pairingView.setFilters(new InputFilter[]{
+                new LengthFilter(maxLength)});
+
+        return view;
+    }
+
+    /**
+     * Creates a dialog with UI elements that allow the user to confirm a pairing request.
+     */
+    private AlertDialog createConfirmationDialog() {
+        mBuilder.setTitle(getString(R.string.bluetooth_pairing_request,
+                mPairingController.getDeviceName()));
+        mBuilder.setView(createView());
+        mBuilder.setPositiveButton(getString(R.string.bluetooth_pairing_accept),
+                this);
+        mBuilder.setNegativeButton(getString(R.string.bluetooth_pairing_decline),
+                this);
+        AlertDialog dialog = mBuilder.create();
+        return dialog;
+    }
+
+    /**
+     * Creates a dialog with UI elements that allow the user to consent to a pairing request.
+     */
+    private AlertDialog createConsentDialog() {
+        return createConfirmationDialog();
+    }
+
+    /**
+     * Creates a dialog that informs users of a pairing request and shows them the passkey/pin
+     * of the device.
+     */
+    private AlertDialog createDisplayPasskeyOrPinDialog() {
+        mBuilder.setTitle(getString(R.string.bluetooth_pairing_request,
+                mPairingController.getDeviceName()));
+        mBuilder.setView(createView());
+        mBuilder.setNegativeButton(getString(android.R.string.cancel), this);
+        AlertDialog dialog = mBuilder.create();
+
+        // Tell the controller the dialog has been created.
+        mPairingController.notifyDialogDisplayed();
+
+        return dialog;
+    }
+
+    /**
+     * Creates a custom view for dialogs which need to show users additional information but do
+     * not require user input.
+     */
+    private View createView() {
+        View view = getActivity().getLayoutInflater().inflate(R.layout.bluetooth_pin_confirm, null);
+        TextView pairingViewCaption = (TextView) view.findViewById(R.id.pairing_caption);
+        TextView pairingViewContent = (TextView) view.findViewById(R.id.pairing_subhead);
+        TextView messagePairing = (TextView) view.findViewById(R.id.pairing_code_message);
+        CheckBox contactSharing = (CheckBox) view.findViewById(
+                R.id.phonebook_sharing_message_confirm_pin);
+        contactSharing.setText(getString(R.string.bluetooth_pairing_shares_phonebook,
+                mPairingController.getDeviceName()));
+
+        contactSharing.setVisibility(
+                mPairingController.isProfileReady() ? View.GONE : View.VISIBLE);
+        contactSharing.setChecked(mPairingController.getContactSharingState());
+        contactSharing.setOnCheckedChangeListener(mPairingController);
+
+        messagePairing.setVisibility(mPairingController.isDisplayPairingKeyVariant()
+                ? View.VISIBLE : View.GONE);
+        if (mPairingController.hasPairingContent()) {
+            pairingViewCaption.setVisibility(View.VISIBLE);
+            pairingViewContent.setVisibility(View.VISIBLE);
+            pairingViewContent.setText(mPairingController.getPairingContent());
+        }
+        return view;
+    }
+
+}
diff --git a/src/com/android/settings/core/InstrumentedFragment.java b/src/com/android/settings/core/InstrumentedFragment.java
index 7297953..ca683e3 100644
--- a/src/com/android/settings/core/InstrumentedFragment.java
+++ b/src/com/android/settings/core/InstrumentedFragment.java
@@ -39,6 +39,7 @@
     protected final int STORAGE_CATEGORY_FRAGMENT = PLACEHOLDER_METRIC + 2;
     protected final int NETWORK_CATEGORY_FRAGMENT = PLACEHOLDER_METRIC + 3;
     protected final int CONNECTED_DEVICE_CATEGORY_FRAGMENT = PLACEHOLDER_METRIC + 4;
+    protected final int APP_AND_NOTIFICATION_CATEGORY_FRAGMENT = PLACEHOLDER_METRIC + 5;
 
     public InstrumentedFragment() {
         // Mixin that logs visibility change for activity.
diff --git a/src/com/android/settings/core/PreferenceController.java b/src/com/android/settings/core/PreferenceController.java
index 6eac2bd..8a4a245 100644
--- a/src/com/android/settings/core/PreferenceController.java
+++ b/src/com/android/settings/core/PreferenceController.java
@@ -50,7 +50,8 @@
     /**
      * Updates the current status of preference (summary, switch state, etc)
      */
-    public void updateState(PreferenceScreen screen) {
+    public void updateState(Preference preference) {
+
     }
 
     /**
@@ -73,6 +74,11 @@
     public abstract boolean handlePreferenceTreeClick(Preference preference);
 
     /**
+     * Returns the key for this preference.
+     */
+    public abstract String getPreferenceKey();
+
+    /**
      * Removes preference from screen.
      */
     protected final void removePreference(PreferenceScreen screen, String key) {
@@ -86,10 +92,4 @@
      * Returns true if preference is available (should be displayed)
      */
     protected abstract boolean isAvailable();
-
-    /**
-     * Returns the key for this preference.
-     */
-    protected abstract String getPreferenceKey();
-
 }
diff --git a/src/com/android/settings/core/lifecycle/ObservablePreferenceFragment.java b/src/com/android/settings/core/lifecycle/ObservablePreferenceFragment.java
index e9822af..dbce755 100644
--- a/src/com/android/settings/core/lifecycle/ObservablePreferenceFragment.java
+++ b/src/com/android/settings/core/lifecycle/ObservablePreferenceFragment.java
@@ -42,8 +42,8 @@
     @CallSuper
     @Override
     public void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
         mLifecycle.onCreate(savedInstanceState);
+        super.onCreate(savedInstanceState);
     }
 
     @CallSuper
diff --git a/src/com/android/settings/dashboard/DashboardFeatureProvider.java b/src/com/android/settings/dashboard/DashboardFeatureProvider.java
index 92154be..0a8dbbf 100644
--- a/src/com/android/settings/dashboard/DashboardFeatureProvider.java
+++ b/src/com/android/settings/dashboard/DashboardFeatureProvider.java
@@ -15,6 +15,7 @@
  */
 package com.android.settings.dashboard;
 
+import android.content.Context;
 import android.support.v7.preference.Preference;
 
 import com.android.settingslib.drawer.DashboardCategory;
@@ -53,4 +54,10 @@
      * Returns an unique string key for the tile.
      */
     String getDashboardKeyForTile(Tile tile);
+
+    /**
+     * Returns a {@link ProgressiveDisclosureMixin} for specified fragment.
+     */
+    ProgressiveDisclosureMixin getProgressiveDisclosureMixin(Context context,
+            DashboardFragment fragment);
 }
diff --git a/src/com/android/settings/dashboard/DashboardFeatureProviderImpl.java b/src/com/android/settings/dashboard/DashboardFeatureProviderImpl.java
index df3f6ef..ed0520a 100644
--- a/src/com/android/settings/dashboard/DashboardFeatureProviderImpl.java
+++ b/src/com/android/settings/dashboard/DashboardFeatureProviderImpl.java
@@ -72,4 +72,10 @@
         sb.append(component.getClassName());
         return sb.toString();
     }
+
+    @Override
+    public ProgressiveDisclosureMixin getProgressiveDisclosureMixin(Context context,
+            DashboardFragment fragment) {
+        return new ProgressiveDisclosureMixin(context, this, fragment);
+    }
 }
diff --git a/src/com/android/settings/dashboard/DashboardFragment.java b/src/com/android/settings/dashboard/DashboardFragment.java
index b895974..9ab8cf4 100644
--- a/src/com/android/settings/dashboard/DashboardFragment.java
+++ b/src/com/android/settings/dashboard/DashboardFragment.java
@@ -22,7 +22,9 @@
 import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
 import android.os.Bundle;
+import android.support.annotation.VisibleForTesting;
 import android.support.v7.preference.Preference;
+import android.support.v7.preference.PreferenceManager;
 import android.support.v7.preference.PreferenceScreen;
 import android.text.TextUtils;
 import android.util.ArrayMap;
@@ -41,6 +43,7 @@
 import com.android.settingslib.drawer.SettingsDrawerActivity;
 import com.android.settingslib.drawer.Tile;
 
+import java.util.ArrayList;
 import java.util.Collection;
 import java.util.List;
 import java.util.Map;
@@ -52,12 +55,14 @@
 public abstract class DashboardFragment extends SettingsPreferenceFragment
         implements SettingsDrawerActivity.CategoryListener, Indexable,
         SummaryLoader.SummaryConsumer {
+    private static final String TAG = "DashboardFragment";
 
     private final Map<Class, PreferenceController> mPreferenceControllers =
             new ArrayMap<>();
     private final Set<String> mDashboardTilePrefKeys = new ArraySet<>();
     private DashboardDividerDecoration mDividerDecoration;
 
+    protected ProgressiveDisclosureMixin mProgressiveDisclosureMixin;
     protected DashboardFeatureProvider mDashboardFeatureProvider;
     private boolean mListeningToCategoryChange;
     private SummaryLoader mSummaryLoader;
@@ -67,6 +72,9 @@
         super.onAttach(context);
         mDashboardFeatureProvider =
                 FeatureFactory.getFactory(context).getDashboardFeatureProvider(context);
+        mProgressiveDisclosureMixin = mDashboardFeatureProvider
+                .getProgressiveDisclosureMixin(context, this);
+        getLifecycle().addObserver(mProgressiveDisclosureMixin);
 
         final List<PreferenceController> controllers = getPreferenceControllers(context);
         if (controllers == null) {
@@ -78,6 +86,24 @@
     }
 
     @Override
+    public void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+        // Set ComparisonCallback so we get better animation when list changes.
+        getPreferenceManager().setPreferenceComparisonCallback(
+                new PreferenceManager.SimplePreferenceComparisonCallback());
+    }
+
+    @Override
+    public View onCreateView(LayoutInflater inflater, ViewGroup container,
+            Bundle savedInstanceState) {
+        final View view = super.onCreateView(inflater, container, savedInstanceState);
+        if (mDashboardFeatureProvider.isEnabled()) {
+            getListView().addItemDecoration(mDividerDecoration);
+        }
+        return view;
+    }
+
+    @Override
     public void onCategoriesChanged() {
         final DashboardCategory category =
                 mDashboardFeatureProvider.getTilesForCategory(getCategoryKey());
@@ -95,6 +121,18 @@
     }
 
     @Override
+    public void setDivider(Drawable divider) {
+        if (mDashboardFeatureProvider.isEnabled()) {
+            // Intercept divider and set it transparent so system divider decoration is disabled.
+            // We will use our decoration to draw divider more intelligently.
+            mDividerDecoration.setDivider(divider);
+            super.setDivider(new ColorDrawable(Color.TRANSPARENT));
+        } else {
+            super.setDivider(divider);
+        }
+    }
+
+    @Override
     public void onStart() {
         super.onStart();
         final DashboardCategory category =
@@ -116,7 +154,8 @@
     @Override
     public void notifySummaryChanged(Tile tile) {
         final String key = mDashboardFeatureProvider.getDashboardKeyForTile(tile);
-        final Preference pref = findPreference(key);
+        final Preference pref = mProgressiveDisclosureMixin.findPreference(
+                getPreferenceScreen(), key);
         if (pref == null) {
             Log.d(getLogTag(),
                     String.format("Can't find pref by key %s, skipping update summary %s/%s",
@@ -206,14 +245,57 @@
     }
 
     /**
-     * Displays dashboard tiles as preference.
+     * Update state of each preference managed by PreferenceController.
      */
-    private final void displayDashboardTiles(final String TAG, PreferenceScreen screen) {
+    private void updatePreferenceStates() {
+        Collection<PreferenceController> controllers = mPreferenceControllers.values();
+        final PreferenceScreen screen = getPreferenceScreen();
+        for (PreferenceController controller : controllers) {
+            final String key = controller.getPreferenceKey();
+
+            final Preference preference = mProgressiveDisclosureMixin.findPreference(screen, key);
+            if (preference == null) {
+                Log.d(TAG, "Cannot find preference with key " + key);
+                continue;
+            }
+            controller.updateState(preference);
+        }
+    }
+
+    /**
+     * Refresh all preference items, including both static prefs from xml, and dynamic items from
+     * DashboardCategory.
+     */
+    private void refreshAllPreferences(final String TAG) {
+        // First remove old preferences.
+        if (getPreferenceScreen() != null) {
+            // Intentionally do not cache PreferenceScreen because it will be recreated later.
+            getPreferenceScreen().removeAll();
+        }
+
+        // Add resource based tiles.
+        displayResourceTiles();
+
+        refreshDashboardTiles(TAG);
+
+        if (!mProgressiveDisclosureMixin.isCollapsed()
+                && mProgressiveDisclosureMixin.shouldCollapse(getPreferenceScreen())) {
+            mProgressiveDisclosureMixin.collapse(getPreferenceScreen());
+        }
+    }
+
+    /**
+     * Refresh preference items backed by DashboardCategory.
+     */
+    @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
+    void refreshDashboardTiles(final String TAG) {
+        final PreferenceScreen screen = getPreferenceScreen();
+
         final Context context = getContext();
         final DashboardCategory category =
                 mDashboardFeatureProvider.getTilesForCategory(getCategoryKey());
         if (category == null) {
-            Log.d(TAG, "NO dynamic tiles for " + TAG);
+            Log.d(TAG, "NO dashboard tiles for " + TAG);
             return;
         }
         List<Tile> tiles = category.tiles;
@@ -221,6 +303,9 @@
             Log.d(TAG, "tile list is empty, skipping category " + category.title);
             return;
         }
+        // Create a list to track which tiles are to be removed.
+        final List<String> remove = new ArrayList<>(mDashboardTilePrefKeys);
+
         // There are dashboard tiles, so we need to install SummaryLoader.
         if (mSummaryLoader != null) {
             mSummaryLoader.release();
@@ -234,91 +319,51 @@
                 Log.d(TAG, "tile does not contain a key, skipping " + tile);
                 continue;
             }
-            mDashboardTilePrefKeys.add(key);
-            final Preference pref = new DashboardTilePreference(context);
-            pref.setTitle(tile.title);
-            pref.setKey(key);
-            pref.setSummary(tile.summary);
-            if (tile.icon != null) {
-                pref.setIcon(tile.icon.loadDrawable(context));
+            if (mDashboardTilePrefKeys.contains(key)) {
+                // Have the key already, will rebind.
+                final Preference preference = mProgressiveDisclosureMixin.findPreference(
+                        screen, key);
+                bindPreferenceToTile(context, preference, tile, key);
+            } else {
+                // Don't have this key, add it.
+                final Preference pref = new DashboardTilePreference(context);
+                bindPreferenceToTile(context, pref, tile, key);
+                mProgressiveDisclosureMixin.addPreference(screen, pref);
+                mDashboardTilePrefKeys.add(key);
             }
-            final Bundle metadata = tile.metaData;
-            if (metadata != null) {
-                String clsName = metadata.getString(SettingsActivity.META_DATA_KEY_FRAGMENT_CLASS);
-                if (!TextUtils.isEmpty(clsName)) {
-                    pref.setFragment(clsName);
-                }
-            } else if (tile.intent != null) {
-                final Intent intent = new Intent(tile.intent);
-                pref.setOnPreferenceClickListener(preference -> {
-                    getActivity().startActivityForResult(intent, 0);
-                    return true;
-                });
+            remove.remove(key);
+        }
+        // Finally remove tiles that are gone.
+        for (String key : remove) {
+            mDashboardTilePrefKeys.remove(key);
+            mProgressiveDisclosureMixin.removePreference(screen, key);
+        }
+    }
+
+    @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
+    void bindPreferenceToTile(Context context, Preference pref, Tile tile, String key) {
+        pref.setTitle(tile.title);
+        pref.setKey(key);
+        pref.setSummary(tile.summary);
+        if (tile.icon != null) {
+            pref.setIcon(tile.icon.loadDrawable(context));
+        }
+        final Bundle metadata = tile.metaData;
+        if (metadata != null) {
+            String clsName = metadata.getString(SettingsActivity.META_DATA_KEY_FRAGMENT_CLASS);
+            if (!TextUtils.isEmpty(clsName)) {
+                pref.setFragment(clsName);
             }
-            // Use negated priority for order, because tile priority is based on intent-filter
-            // (larger value has higher priority). However pref order defines smaller value has
-            // higher priority.
-            pref.setOrder(-tile.priority);
-            screen.addPreference(pref);
+        } else if (tile.intent != null) {
+            final Intent intent = new Intent(tile.intent);
+            pref.setOnPreferenceClickListener(preference -> {
+                getActivity().startActivityForResult(intent, 0);
+                return true;
+            });
         }
-    }
-
-    @Override
-    public View onCreateView(LayoutInflater inflater, ViewGroup container,
-            Bundle savedInstanceState) {
-        final View view = super.onCreateView(inflater, container, savedInstanceState);
-        getListView().addItemDecoration(mDividerDecoration);
-        return view;
-    }
-
-    /**
-     * Update state of each preference managed by PreferenceController.
-     */
-    private void updatePreferenceStates() {
-        Collection<PreferenceController> controllers = mPreferenceControllers.values();
-        final PreferenceScreen screen = getPreferenceScreen();
-        for (PreferenceController controller : controllers) {
-            controller.updateState(screen);
-        }
-    }
-
-    @Override
-    public void setDivider(Drawable divider) {
-        // Intercept divider and set it transparent so system divider decoration is disabled.
-        // We will use our decoration to draw divider more intelligently.
-        mDividerDecoration.setDivider(divider);
-        super.setDivider(new ColorDrawable(Color.TRANSPARENT));
-    }
-
-    /**
-     * Refresh all preference items, including both static prefs from xml, and dynamic items from
-     * DashboardCategory.
-     */
-    private void refreshAllPreferences(final String TAG) {
-        // First remove old preferences.
-        final PreferenceScreen screen = getPreferenceScreen();
-        if (screen != null) {
-            screen.removeAll();
-        }
-
-        // Add resource based tiles.
-        displayResourceTiles();
-
-        refreshDashboardTiles(TAG);
-    }
-
-    /**
-     * Refresh preference items backed by DashboardCategory.
-     */
-    private void refreshDashboardTiles(final String TAG) {
-        final PreferenceScreen screen = getPreferenceScreen();
-        for (String key : mDashboardTilePrefKeys) {
-            final Preference pref = screen.findPreference(key);
-            if (pref != null) {
-                screen.removePreference(pref);
-            }
-        }
-        mDashboardTilePrefKeys.clear();
-        displayDashboardTiles(TAG, getPreferenceScreen());
+        // Use negated priority for order, because tile priority is based on intent-filter
+        // (larger value has higher priority). However pref order defines smaller value has
+        // higher priority.
+        pref.setOrder(-tile.priority);
     }
 }
diff --git a/src/com/android/settings/dashboard/ExpandPreference.java b/src/com/android/settings/dashboard/ExpandPreference.java
new file mode 100644
index 0000000..215bfc5
--- /dev/null
+++ b/src/com/android/settings/dashboard/ExpandPreference.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.dashboard;
+
+import android.content.Context;
+import android.support.v7.preference.Preference;
+import android.util.AttributeSet;
+
+import com.android.settings.R;
+
+public class ExpandPreference extends Preference {
+
+    public ExpandPreference(Context context, AttributeSet attrs,
+            int defStyleAttr, int defStyleRes) {
+        super(context, attrs, defStyleAttr, defStyleRes);
+        init();
+    }
+
+    public ExpandPreference(Context context, AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+        init();
+    }
+
+    public ExpandPreference(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        init();
+    }
+
+    public ExpandPreference(Context context) {
+        super(context);
+        init();
+    }
+
+    private void init() {
+        setLayoutResource(R.layout.expand_preference);
+        setTitle(R.string.wifi_more);
+        setOrder(999);
+    }
+}
diff --git a/src/com/android/settings/dashboard/ProgressiveDisclosureMixin.java b/src/com/android/settings/dashboard/ProgressiveDisclosureMixin.java
new file mode 100644
index 0000000..75251b3
--- /dev/null
+++ b/src/com/android/settings/dashboard/ProgressiveDisclosureMixin.java
@@ -0,0 +1,225 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.dashboard;
+
+import android.content.Context;
+import android.os.Bundle;
+import android.support.annotation.VisibleForTesting;
+import android.support.v14.preference.PreferenceFragment;
+import android.support.v7.preference.Preference;
+import android.support.v7.preference.PreferenceScreen;
+import android.text.TextUtils;
+import android.util.Log;
+
+import com.android.settings.core.lifecycle.LifecycleObserver;
+import com.android.settings.core.lifecycle.events.OnCreate;
+import com.android.settings.core.lifecycle.events.OnSaveInstanceState;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+public class ProgressiveDisclosureMixin implements Preference.OnPreferenceClickListener,
+        LifecycleObserver, OnCreate, OnSaveInstanceState {
+
+    private static final String TAG = "ProgressiveDisclosure";
+    private static final String STATE_USER_EXPANDED = "state_user_expanded";
+    private static final int DEFAULT_TILE_LIMIT = 3;
+
+    private int mTileLimit = DEFAULT_TILE_LIMIT;
+
+    private final DashboardFeatureProvider mDashboardFeatureProvider;
+    // Collapsed preference sorted by order.
+    private final List<Preference> mCollapsedPrefs = new ArrayList<>();
+    private final ExpandPreference mExpandButton;
+    private final PreferenceFragment mFragment;
+
+    private boolean mUserExpanded;
+
+    public ProgressiveDisclosureMixin(Context context,
+            DashboardFeatureProvider dashboardFeatureProvider, PreferenceFragment fragment) {
+        mFragment = fragment;
+        mExpandButton = new ExpandPreference(context);
+        mExpandButton.setOnPreferenceClickListener(this);
+        mDashboardFeatureProvider = dashboardFeatureProvider;
+    }
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        if (savedInstanceState != null) {
+            mUserExpanded = savedInstanceState.getBoolean(STATE_USER_EXPANDED, false);
+        }
+    }
+
+    @Override
+    public void onSaveInstanceState(Bundle outState) {
+        outState.putBoolean(STATE_USER_EXPANDED, mUserExpanded);
+    }
+
+    @Override
+    public boolean onPreferenceClick(Preference preference) {
+        if (preference instanceof ExpandPreference) {
+            final PreferenceScreen screen = mFragment.getPreferenceScreen();
+            if (screen != null) {
+                screen.removePreference(preference);
+                for (Preference pref : mCollapsedPrefs) {
+                    screen.addPreference(pref);
+                }
+                mCollapsedPrefs.clear();
+                mUserExpanded = true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Sets the threshold to start collapsing preferences when there are too many.
+     */
+    public void setTileLimit(int limit) {
+        mTileLimit = limit;
+    }
+
+    /**
+     * Whether the controller is in collapsed state.
+     */
+    public boolean isCollapsed() {
+        return !mCollapsedPrefs.isEmpty();
+    }
+
+    /**
+     * Whether the screen should be collapsed.
+     */
+    public boolean shouldCollapse(PreferenceScreen screen) {
+        return mDashboardFeatureProvider.isEnabled() && screen.getPreferenceCount() >= mTileLimit
+                && !mUserExpanded;
+    }
+
+    /**
+     * Collapse extra preferences and show a "More" button
+     */
+    public void collapse(PreferenceScreen screen) {
+        final int itemCount = screen.getPreferenceCount();
+        if (!shouldCollapse(screen)) {
+            return;
+        }
+        if (!mCollapsedPrefs.isEmpty()) {
+            Log.w(TAG, "collapsed list should ALWAYS BE EMPTY before collapsing!");
+        }
+
+        for (int i = itemCount - 1; i >= mTileLimit; i--) {
+            final Preference preference = screen.getPreference(i);
+            addToCollapsedList(preference);
+            screen.removePreference(preference);
+        }
+        screen.addPreference(mExpandButton);
+    }
+
+    /**
+     * Adds preference to screen. If there are too many preference on screen, adds it to
+     * collapsed list instead.
+     */
+    public void addPreference(PreferenceScreen screen, Preference pref) {
+        // Either add to screen, or to collapsed list.
+        if (isCollapsed()) {
+            // insert the preference to right position.
+            final int lastPreferenceIndex = screen.getPreferenceCount() - 2;
+            if (lastPreferenceIndex >= 0) {
+                final Preference lastPreference = screen.getPreference(lastPreferenceIndex);
+                if (lastPreference.getOrder() > pref.getOrder()) {
+                    // insert to screen and move the last pref to collapsed list.
+                    screen.removePreference(lastPreference);
+                    screen.addPreference(pref);
+                    addToCollapsedList(lastPreference);
+                } else {
+                    // Insert to collapsed list.
+                    addToCollapsedList(pref);
+                }
+            } else {
+                // Couldn't find last preference on screen, just add to collapsed list.
+                addToCollapsedList(pref);
+            }
+        } else if (shouldCollapse(screen)) {
+            // About to have too many tiles on scree, collapse and add pref to collapsed list.
+            screen.addPreference(pref);
+            collapse(screen);
+        } else {
+            // No need to collapse, add to screen directly.
+            screen.addPreference(pref);
+        }
+    }
+
+    /**
+     * Removes preference. If the preference is on screen, remove it from screen. If the
+     * preference is in collapsed list, remove it from list.
+     */
+    public void removePreference(PreferenceScreen screen, String key) {
+        // Try removing from screen.
+        final Preference preference = screen.findPreference(key);
+        if (preference != null) {
+            screen.removePreference(preference);
+            return;
+        }
+        // Didn't find on screen, try removing from collapsed list.
+        for (int i = 0; i < mCollapsedPrefs.size(); i++) {
+            final Preference pref = mCollapsedPrefs.get(i);
+            if (TextUtils.equals(key, pref.getKey())) {
+                mCollapsedPrefs.remove(pref);
+                if (mCollapsedPrefs.isEmpty()) {
+                    // Removed last element, remove expand button too.
+                    screen.removePreference(mExpandButton);
+                }
+                return;
+            }
+        }
+    }
+
+    /**
+     * Finds preference by key, either from screen or from collapsed list.
+     */
+    public Preference findPreference(PreferenceScreen screen, CharSequence key) {
+        Preference preference = screen.findPreference(key);
+        if (preference != null) {
+            return preference;
+        }
+        for (int i = 0; i < mCollapsedPrefs.size(); i++) {
+            final Preference pref = mCollapsedPrefs.get(i);
+            if (TextUtils.equals(key, pref.getKey())) {
+                return pref;
+            }
+        }
+        Log.d(TAG, "Cannot find preference with key " + key);
+        return null;
+    }
+
+    /**
+     * Add preference to collapsed list.
+     */
+    @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
+    void addToCollapsedList(Preference preference) {
+        // Insert preference based on it's order.
+        int insertionIndex = Collections.binarySearch(mCollapsedPrefs, preference);
+        if (insertionIndex < 0) {
+            insertionIndex = insertionIndex * -1 - 1;
+        }
+        mCollapsedPrefs.add(insertionIndex, preference);
+    }
+
+    @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
+    List<Preference> getCollapsedPrefs() {
+        return mCollapsedPrefs;
+    }
+}
diff --git a/src/com/android/settings/datausage/DataUsageSummary.java b/src/com/android/settings/datausage/DataUsageSummary.java
index e284bed..c99a4ab 100644
--- a/src/com/android/settings/datausage/DataUsageSummary.java
+++ b/src/com/android/settings/datausage/DataUsageSummary.java
@@ -77,6 +77,11 @@
     private int mDataUsageTemplate;
 
     @Override
+    protected int getHelpResource() {
+        return R.string.help_url_data_usage;
+    }
+
+    @Override
     public void onCreate(Bundle icicle) {
         super.onCreate(icicle);
 
diff --git a/src/com/android/settings/deviceinfo/AdditionalSystemUpdatePreferenceController.java b/src/com/android/settings/deviceinfo/AdditionalSystemUpdatePreferenceController.java
index 6dd6aba..7290250 100644
--- a/src/com/android/settings/deviceinfo/AdditionalSystemUpdatePreferenceController.java
+++ b/src/com/android/settings/deviceinfo/AdditionalSystemUpdatePreferenceController.java
@@ -40,7 +40,7 @@
     }
 
     @Override
-    protected String getPreferenceKey() {
+    public String getPreferenceKey() {
         return KEY_UPDATE_SETTING;
     }
 }
diff --git a/src/com/android/settings/deviceinfo/ManageStoragePreferenceController.java b/src/com/android/settings/deviceinfo/ManageStoragePreferenceController.java
index add4781..d4d53d4 100644
--- a/src/com/android/settings/deviceinfo/ManageStoragePreferenceController.java
+++ b/src/com/android/settings/deviceinfo/ManageStoragePreferenceController.java
@@ -33,7 +33,7 @@
     }
 
     @Override
-    protected String getPreferenceKey() {
+    public String getPreferenceKey() {
         return KEY_MANAGE_STORAGE;
     }
 
diff --git a/src/com/android/settings/deviceinfo/SystemUpdatePreferenceController.java b/src/com/android/settings/deviceinfo/SystemUpdatePreferenceController.java
index 449847a..e086a56 100644
--- a/src/com/android/settings/deviceinfo/SystemUpdatePreferenceController.java
+++ b/src/com/android/settings/deviceinfo/SystemUpdatePreferenceController.java
@@ -51,7 +51,7 @@
     }
 
     @Override
-    protected String getPreferenceKey() {
+    public String getPreferenceKey() {
         return KEY_SYSTEM_UPDATE_SETTINGS;
     }
 
diff --git a/src/com/android/settings/display/AutoBrightnessPreferenceController.java b/src/com/android/settings/display/AutoBrightnessPreferenceController.java
index 934ccf2..775e60c 100644
--- a/src/com/android/settings/display/AutoBrightnessPreferenceController.java
+++ b/src/com/android/settings/display/AutoBrightnessPreferenceController.java
@@ -17,7 +17,6 @@
 import android.provider.Settings;
 import android.support.v14.preference.SwitchPreference;
 import android.support.v7.preference.Preference;
-import android.support.v7.preference.PreferenceScreen;
 
 import com.android.settings.core.PreferenceController;
 
@@ -42,7 +41,7 @@
     }
 
     @Override
-    protected String getPreferenceKey() {
+    public String getPreferenceKey() {
         return KEY_AUTO_BRIGHTNESS;
     }
 
@@ -52,15 +51,10 @@
     }
 
     @Override
-    public void updateState(PreferenceScreen screen) {
-        final SwitchPreference preference =
-                (SwitchPreference) screen.findPreference(KEY_AUTO_BRIGHTNESS);
-        if (preference == null) {
-            return;
-        }
+    public void updateState(Preference preference) {
         int brightnessMode = Settings.System.getInt(mContext.getContentResolver(),
                 SCREEN_BRIGHTNESS_MODE, SCREEN_BRIGHTNESS_MODE_MANUAL);
-        preference.setChecked(brightnessMode != SCREEN_BRIGHTNESS_MODE_MANUAL);
+        ((SwitchPreference) preference).setChecked(brightnessMode != SCREEN_BRIGHTNESS_MODE_MANUAL);
     }
 
     @Override
diff --git a/src/com/android/settings/display/AutoRotatePreferenceController.java b/src/com/android/settings/display/AutoRotatePreferenceController.java
index f28e1d6..44d2158 100644
--- a/src/com/android/settings/display/AutoRotatePreferenceController.java
+++ b/src/com/android/settings/display/AutoRotatePreferenceController.java
@@ -17,7 +17,6 @@
 import android.content.res.Configuration;
 import android.support.v7.preference.DropDownPreference;
 import android.support.v7.preference.Preference;
-import android.support.v7.preference.PreferenceScreen;
 
 import com.android.internal.logging.MetricsProto;
 import com.android.internal.view.RotationPolicy;
@@ -38,14 +37,13 @@
     }
 
     @Override
-    protected String getPreferenceKey() {
+    public String getPreferenceKey() {
         return KEY_AUTO_ROTATE;
     }
 
     @Override
-    public void updateState(PreferenceScreen screen) {
-        final DropDownPreference rotatePreference =
-                (DropDownPreference) screen.findPreference(KEY_AUTO_ROTATE);
+    public void updateState(Preference preference) {
+        final DropDownPreference rotatePreference = (DropDownPreference) preference;
         final int rotateLockedResourceId;
         // The following block sets the string used when rotation is locked.
         // If the device locks specifically to portrait or landscape (rather than current
@@ -69,7 +67,6 @@
                 1 : 0);
     }
 
-
     @Override
     public boolean handlePreferenceTreeClick(Preference preference) {
         return false;
diff --git a/src/com/android/settings/display/CameraGesturePreferenceController.java b/src/com/android/settings/display/CameraGesturePreferenceController.java
index 98486c5..3f5d0de 100644
--- a/src/com/android/settings/display/CameraGesturePreferenceController.java
+++ b/src/com/android/settings/display/CameraGesturePreferenceController.java
@@ -18,7 +18,6 @@
 import android.provider.Settings;
 import android.support.v14.preference.SwitchPreference;
 import android.support.v7.preference.Preference;
-import android.support.v7.preference.PreferenceScreen;
 
 import com.android.settings.core.PreferenceController;
 
@@ -34,7 +33,7 @@
     }
 
     @Override
-    protected String getPreferenceKey() {
+    public String getPreferenceKey() {
         return KEY_CAMERA_GESTURE;
     }
 
@@ -44,14 +43,10 @@
     }
 
     @Override
-    public void updateState(PreferenceScreen screen) {
-        final SwitchPreference preference =
-                (SwitchPreference) screen.findPreference(KEY_CAMERA_GESTURE);
-        if (preference != null) {
-            int value = Settings.Secure.getInt(mContext.getContentResolver(),
-                    CAMERA_GESTURE_DISABLED, 0);
-            preference.setChecked(value == 0);
-        }
+    public void updateState(Preference preference) {
+        int value = Settings.Secure.getInt(mContext.getContentResolver(),
+                CAMERA_GESTURE_DISABLED, 0);
+        ((SwitchPreference) preference).setChecked(value == 0);
     }
 
     @Override
diff --git a/src/com/android/settings/display/DozePreferenceController.java b/src/com/android/settings/display/DozePreferenceController.java
index 9fcc807..bf5d8f3 100644
--- a/src/com/android/settings/display/DozePreferenceController.java
+++ b/src/com/android/settings/display/DozePreferenceController.java
@@ -19,7 +19,6 @@
 import android.provider.Settings;
 import android.support.v14.preference.SwitchPreference;
 import android.support.v7.preference.Preference;
-import android.support.v7.preference.PreferenceScreen;
 import android.text.TextUtils;
 
 import com.android.settings.core.PreferenceController;
@@ -42,7 +41,7 @@
     }
 
     @Override
-    protected String getPreferenceKey() {
+    public String getPreferenceKey() {
         return KEY_DOZE;
     }
 
@@ -55,13 +54,9 @@
     }
 
     @Override
-    public void updateState(PreferenceScreen screen) {
-        final SwitchPreference preference = (SwitchPreference) screen.findPreference(KEY_DOZE);
-        // Update doze if it is available.
-        if (preference != null) {
-            int value = Settings.Secure.getInt(mContext.getContentResolver(), DOZE_ENABLED, 1);
-            preference.setChecked(value != 0);
-        }
+    public void updateState(Preference preference) {
+        int value = Settings.Secure.getInt(mContext.getContentResolver(), DOZE_ENABLED, 1);
+        ((SwitchPreference) preference).setChecked(value != 0);
     }
 
     @Override
diff --git a/src/com/android/settings/display/FontSizePreferenceController.java b/src/com/android/settings/display/FontSizePreferenceController.java
index 9981fcd..fcd423d 100644
--- a/src/com/android/settings/display/FontSizePreferenceController.java
+++ b/src/com/android/settings/display/FontSizePreferenceController.java
@@ -17,7 +17,6 @@
 import android.content.res.Resources;
 import android.provider.Settings;
 import android.support.v7.preference.Preference;
-import android.support.v7.preference.PreferenceScreen;
 
 import com.android.settings.R;
 import com.android.settings.accessibility.ToggleFontSizePreferenceFragment;
@@ -37,16 +36,12 @@
     }
 
     @Override
-    protected String getPreferenceKey() {
+    public String getPreferenceKey() {
         return KEY_FONT_SIZE;
     }
 
     @Override
-    public void updateState(PreferenceScreen screen) {
-        final Preference preference = screen.findPreference(KEY_FONT_SIZE);
-        if (preference == null) {
-            return;
-        }
+    public void updateState(Preference preference) {
         final float currentScale = Settings.System.getFloat(mContext.getContentResolver(),
                 Settings.System.FONT_SCALE, 1.0f);
         final Resources res = mContext.getResources();
diff --git a/src/com/android/settings/display/LiftToWakePreferenceController.java b/src/com/android/settings/display/LiftToWakePreferenceController.java
index 0b573cf..c518f68 100644
--- a/src/com/android/settings/display/LiftToWakePreferenceController.java
+++ b/src/com/android/settings/display/LiftToWakePreferenceController.java
@@ -19,7 +19,6 @@
 import android.provider.Settings;
 import android.support.v14.preference.SwitchPreference;
 import android.support.v7.preference.Preference;
-import android.support.v7.preference.PreferenceScreen;
 
 import com.android.settings.core.PreferenceController;
 
@@ -41,7 +40,7 @@
     }
 
     @Override
-    protected String getPreferenceKey() {
+    public String getPreferenceKey() {
         return KEY_LIFT_TO_WAKE;
     }
 
@@ -58,13 +57,8 @@
     }
 
     @Override
-    public void updateState(PreferenceScreen screen) {
-        final SwitchPreference pref = (SwitchPreference) screen.findPreference(KEY_LIFT_TO_WAKE);
-        // Update lift-to-wake if it is available.
-        if (pref != null) {
-            int value =
-                    Settings.Secure.getInt(mContext.getContentResolver(), WAKE_GESTURE_ENABLED, 0);
-            pref.setChecked(value != 0);
-        }
+    public void updateState(Preference preference) {
+        int value = Settings.Secure.getInt(mContext.getContentResolver(), WAKE_GESTURE_ENABLED, 0);
+        ((SwitchPreference) preference).setChecked(value != 0);
     }
 }
diff --git a/src/com/android/settings/display/NightDisplayPreferenceController.java b/src/com/android/settings/display/NightDisplayPreferenceController.java
index d7191d2..c52df23 100644
--- a/src/com/android/settings/display/NightDisplayPreferenceController.java
+++ b/src/com/android/settings/display/NightDisplayPreferenceController.java
@@ -38,7 +38,7 @@
     }
 
     @Override
-    protected String getPreferenceKey() {
+    public String getPreferenceKey() {
         return KEY_NIGHT_DISPLAY;
     }
 }
diff --git a/src/com/android/settings/display/NightModePreferenceController.java b/src/com/android/settings/display/NightModePreferenceController.java
index 7b3c584..c0f0c17 100644
--- a/src/com/android/settings/display/NightModePreferenceController.java
+++ b/src/com/android/settings/display/NightModePreferenceController.java
@@ -40,7 +40,7 @@
     }
 
     @Override
-    protected String getPreferenceKey() {
+    public String getPreferenceKey() {
         return KEY_NIGHT_MODE;
     }
 
diff --git a/src/com/android/settings/display/ScreenSaverPreferenceController.java b/src/com/android/settings/display/ScreenSaverPreferenceController.java
index 6376fcf..64d9dec 100644
--- a/src/com/android/settings/display/ScreenSaverPreferenceController.java
+++ b/src/com/android/settings/display/ScreenSaverPreferenceController.java
@@ -15,7 +15,6 @@
 
 import android.content.Context;
 import android.support.v7.preference.Preference;
-import android.support.v7.preference.PreferenceScreen;
 
 import com.android.settings.DreamSettings;
 import com.android.settings.core.PreferenceController;
@@ -35,7 +34,7 @@
     }
 
     @Override
-    protected String getPreferenceKey() {
+    public String getPreferenceKey() {
         return KEY_SCREEN_SAVER;
     }
 
@@ -45,11 +44,7 @@
     }
 
     @Override
-    public void updateState(PreferenceScreen screen) {
-        final Preference preference = screen.findPreference(KEY_SCREEN_SAVER);
-        if (preference != null) {
-            preference.setSummary(
-                    DreamSettings.getSummaryTextWithDreamName(mContext));
-        }
+    public void updateState(Preference preference) {
+        preference.setSummary(DreamSettings.getSummaryTextWithDreamName(mContext));
     }
 }
diff --git a/src/com/android/settings/display/TapToWakePreferenceController.java b/src/com/android/settings/display/TapToWakePreferenceController.java
index 6d1681f..4c5aaa0 100644
--- a/src/com/android/settings/display/TapToWakePreferenceController.java
+++ b/src/com/android/settings/display/TapToWakePreferenceController.java
@@ -17,7 +17,6 @@
 import android.provider.Settings;
 import android.support.v14.preference.SwitchPreference;
 import android.support.v7.preference.Preference;
-import android.support.v7.preference.PreferenceScreen;
 
 import com.android.settings.core.PreferenceController;
 
@@ -31,7 +30,7 @@
     }
 
     @Override
-    protected String getPreferenceKey() {
+    public String getPreferenceKey() {
         return KEY_TAP_TO_WAKE;
     }
 
@@ -47,14 +46,10 @@
     }
 
     @Override
-    public void updateState(PreferenceScreen screen) {
-        final SwitchPreference preference =
-                (SwitchPreference) screen.findPreference(KEY_TAP_TO_WAKE);
-        if (preference != null) {
-            int value = Settings.Secure.getInt(
-                    mContext.getContentResolver(), Settings.Secure.DOUBLE_TAP_TO_WAKE, 0);
-            preference.setChecked(value != 0);
-        }
+    public void updateState(Preference preference) {
+        int value = Settings.Secure.getInt(
+                mContext.getContentResolver(), Settings.Secure.DOUBLE_TAP_TO_WAKE, 0);
+        ((SwitchPreference) preference).setChecked(value != 0);
     }
 
     @Override
diff --git a/src/com/android/settings/display/TimeoutPreferenceController.java b/src/com/android/settings/display/TimeoutPreferenceController.java
index 1295a47..8c73c31 100644
--- a/src/com/android/settings/display/TimeoutPreferenceController.java
+++ b/src/com/android/settings/display/TimeoutPreferenceController.java
@@ -18,7 +18,6 @@
 import android.os.UserHandle;
 import android.provider.Settings;
 import android.support.v7.preference.Preference;
-import android.support.v7.preference.PreferenceScreen;
 import android.util.Log;
 
 import com.android.settings.R;
@@ -48,7 +47,7 @@
     }
 
     @Override
-    protected String getPreferenceKey() {
+    public String getPreferenceKey() {
         return KEY_SCREEN_TIMEOUT;
     }
 
@@ -58,15 +57,11 @@
     }
 
     @Override
-    public void updateState(PreferenceScreen screen) {
-        final TimeoutListPreference preference =
-                (TimeoutListPreference) screen.findPreference(KEY_SCREEN_TIMEOUT);
-        if (preference == null) {
-            return;
-        }
+    public void updateState(Preference preference) {
+        final TimeoutListPreference timeoutListPreference = (TimeoutListPreference) preference;
         final long currentTimeout = Settings.System.getLong(mContext.getContentResolver(),
                 SCREEN_OFF_TIMEOUT, FALLBACK_SCREEN_TIMEOUT_VALUE);
-        preference.setValue(String.valueOf(currentTimeout));
+        timeoutListPreference.setValue(String.valueOf(currentTimeout));
         final DevicePolicyManager dpm = (DevicePolicyManager) mContext.getSystemService(
                 Context.DEVICE_POLICY_SERVICE);
         if (dpm != null) {
@@ -74,9 +69,9 @@
                     RestrictedLockUtils.checkIfMaximumTimeToLockIsSet(mContext);
             final long maxTimeout =
                     dpm.getMaximumTimeToLockForUserAndProfiles(UserHandle.myUserId());
-            preference.removeUnusableTimeouts(maxTimeout, admin);
+            timeoutListPreference.removeUnusableTimeouts(maxTimeout, admin);
         }
-        updateTimeoutPreferenceDescription(preference, currentTimeout);
+        updateTimeoutPreferenceDescription(timeoutListPreference, currentTimeout);
     }
 
     @Override
diff --git a/src/com/android/settings/display/VrDisplayPreferenceController.java b/src/com/android/settings/display/VrDisplayPreferenceController.java
index c340759..84d7462 100644
--- a/src/com/android/settings/display/VrDisplayPreferenceController.java
+++ b/src/com/android/settings/display/VrDisplayPreferenceController.java
@@ -19,7 +19,6 @@
 import android.provider.Settings;
 import android.support.v7.preference.DropDownPreference;
 import android.support.v7.preference.Preference;
-import android.support.v7.preference.PreferenceScreen;
 import android.util.Log;
 
 import com.android.settings.R;
@@ -42,18 +41,13 @@
     }
 
     @Override
-    protected String getPreferenceKey() {
+    public String getPreferenceKey() {
         return KEY_VR_DISPLAY_PREF;
     }
 
     @Override
-    public void updateState(PreferenceScreen screen) {
-        final DropDownPreference pref =
-                (DropDownPreference) screen.findPreference(KEY_VR_DISPLAY_PREF);
-        if (pref == null) {
-            Log.d(TAG, "Could not find VR display preference.");
-            return;
-        }
+    public void updateState(Preference preference) {
+        final DropDownPreference pref = (DropDownPreference) preference;
         pref.setEntries(new CharSequence[]{
                 mContext.getString(R.string.display_vr_pref_low_persistence),
                 mContext.getString(R.string.display_vr_pref_off),
diff --git a/src/com/android/settings/display/WallpaperPreferenceController.java b/src/com/android/settings/display/WallpaperPreferenceController.java
index 32e9abc..29415e9 100644
--- a/src/com/android/settings/display/WallpaperPreferenceController.java
+++ b/src/com/android/settings/display/WallpaperPreferenceController.java
@@ -16,7 +16,6 @@
 import android.content.Context;
 import android.os.UserHandle;
 import android.support.v7.preference.Preference;
-import android.support.v7.preference.PreferenceScreen;
 
 import com.android.settings.core.PreferenceController;
 import com.android.settingslib.RestrictedLockUtils;
@@ -38,13 +37,13 @@
     }
 
     @Override
-    protected String getPreferenceKey() {
+    public String getPreferenceKey() {
         return KEY_WALLPAPER;
     }
 
     @Override
-    public void updateState(PreferenceScreen screen) {
-        disablePreferenceIfManaged(screen);
+    public void updateState(Preference preference) {
+        disablePreferenceIfManaged((RestrictedPreference) preference);
     }
 
     @Override
@@ -52,9 +51,7 @@
         return false;
     }
 
-    private void disablePreferenceIfManaged(PreferenceScreen screen) {
-        final RestrictedPreference pref =
-                (RestrictedPreference) screen.findPreference(KEY_WALLPAPER);
+    private void disablePreferenceIfManaged(RestrictedPreference pref) {
         final String restriction = DISALLOW_SET_WALLPAPER;
         if (pref != null) {
             pref.setDisabledByAdmin(null);
diff --git a/src/com/android/settings/gestures/GestureSettings.java b/src/com/android/settings/gestures/GestureSettings.java
index ad9955c..a8f70d9 100644
--- a/src/com/android/settings/gestures/GestureSettings.java
+++ b/src/com/android/settings/gestures/GestureSettings.java
@@ -20,9 +20,8 @@
 import android.content.res.Resources;
 import android.hardware.Sensor;
 import android.hardware.SensorManager;
-import android.os.Build;
 import android.os.Bundle;
-import android.os.SystemProperties;
+import android.os.UserHandle;
 import android.provider.SearchIndexableResource;
 import android.provider.Settings.Secure;
 import android.support.v7.preference.Preference;
@@ -32,6 +31,7 @@
 import android.view.View;
 import android.view.ViewGroup;
 
+import com.android.internal.hardware.AmbientDisplayConfiguration;
 import com.android.internal.logging.MetricsProto.MetricsEvent;
 import com.android.settings.R;
 import com.android.settings.search.BaseSearchIndexProvider;
@@ -59,6 +59,8 @@
 
     private List<GesturePreference> mPreferences;
 
+    private AmbientDisplayConfiguration mAmbientConfig;
+
     @Override
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
@@ -76,16 +78,16 @@
         }
 
         // Ambient Display
-        boolean dozeEnabled = isDozeAvailable(context);
-        if (dozeEnabled && isPickupAvailable(context)) {
-            int pickup = Secure.getInt(getContentResolver(), Secure.DOZE_PULSE_ON_PICK_UP, 1);
-            addPreference(PREF_KEY_PICK_UP, pickup != 0);
+        mAmbientConfig = new AmbientDisplayConfiguration(context);
+        if (mAmbientConfig.pulseOnPickupAvailable()) {
+            boolean pickup = mAmbientConfig.pulseOnPickupEnabled(UserHandle.myUserId());
+            addPreference(PREF_KEY_PICK_UP, pickup);
         } else {
             removePreference(PREF_KEY_PICK_UP);
         }
-        if (dozeEnabled && isDoubleTapAvailable(context)) {
-            int doubleTap = Secure.getInt(getContentResolver(), Secure.DOZE_PULSE_ON_DOUBLE_TAP, 1);
-            addPreference(PREF_KEY_DOUBLE_TAP_SCREEN, doubleTap != 0);
+        if (mAmbientConfig.pulseOnDoubleTapAvailable()) {
+            boolean doubleTap = mAmbientConfig.pulseOnDoubleTapEnabled(UserHandle.myUserId());
+            addPreference(PREF_KEY_DOUBLE_TAP_SCREEN, doubleTap);
         } else {
             removePreference(PREF_KEY_DOUBLE_TAP_SCREEN);
         }
@@ -178,15 +180,6 @@
                 com.android.internal.R.bool.config_cameraDoubleTapPowerGestureEnabled);
     }
 
-    private static boolean isDozeAvailable(Context context) {
-        String name = Build.IS_DEBUGGABLE ? SystemProperties.get(DEBUG_DOZE_COMPONENT) : null;
-        if (TextUtils.isEmpty(name)) {
-            name = context.getResources().getString(
-                    com.android.internal.R.string.config_dozeComponent);
-        }
-        return !TextUtils.isEmpty(name);
-    }
-
     private static boolean isSystemUINavigationAvailable(Context context) {
         return context.getResources().getBoolean(
                 com.android.internal.R.bool.config_supportSystemNavigationKeys);
@@ -202,11 +195,6 @@
                 R.string.gesture_double_twist_sensor_vendor);
     }
 
-    private static boolean isPickupAvailable(Context context) {
-        return hasSensor(context, R.string.gesture_pickup_sensor_name,
-                R.string.gesture_pickup_sensor_vendor);
-    }
-
     private static boolean hasSensor(Context context, int nameResId, int vendorResId) {
         Resources resources = context.getResources();
         String name = resources.getString(nameResId);
@@ -223,11 +211,6 @@
         return false;
     }
 
-    private static boolean isDoubleTapAvailable(Context context) {
-        return context.getResources().getBoolean(
-                R.bool.config_gesture_double_tap_settings_enabled);
-    }
-
     private void addPreference(String key, boolean enabled) {
         GesturePreference preference = (GesturePreference) findPreference(key);
         preference.setChecked(enabled);
@@ -253,13 +236,15 @@
             @Override
             public List<String> getNonIndexableKeys(Context context) {
                 ArrayList<String> result = new ArrayList<String>();
+                AmbientDisplayConfiguration ambientConfig
+                        = new AmbientDisplayConfiguration(context);
                 if (!isCameraDoubleTapPowerGestureAvailable(context.getResources())) {
                     result.add(PREF_KEY_DOUBLE_TAP_POWER);
                 }
-                if (!isDozeAvailable(context) || !isPickupAvailable(context)) {
+                if (!ambientConfig.pulseOnPickupAvailable()) {
                     result.add(PREF_KEY_PICK_UP);
                 }
-                if (!isDozeAvailable(context) || !isDoubleTapAvailable(context)) {
+                if (!ambientConfig.pulseOnDoubleTapAvailable()) {
                     result.add(PREF_KEY_DOUBLE_TAP_SCREEN);
                 }
                 if (!isSystemUINavigationAvailable(context)) {
diff --git a/src/com/android/settings/network/AirplaneModePreferenceController.java b/src/com/android/settings/network/AirplaneModePreferenceController.java
index c99cd4d..bd1918f 100644
--- a/src/com/android/settings/network/AirplaneModePreferenceController.java
+++ b/src/com/android/settings/network/AirplaneModePreferenceController.java
@@ -92,7 +92,7 @@
     }
 
     @Override
-    protected String getPreferenceKey() {
+    public String getPreferenceKey() {
         return KEY_TOGGLE_AIRPLANE;
     }
 
diff --git a/src/com/android/settings/network/MobileNetworkPreferenceController.java b/src/com/android/settings/network/MobileNetworkPreferenceController.java
index 509c771..14dcf9e 100644
--- a/src/com/android/settings/network/MobileNetworkPreferenceController.java
+++ b/src/com/android/settings/network/MobileNetworkPreferenceController.java
@@ -52,7 +52,7 @@
     }
 
     @Override
-    protected String getPreferenceKey() {
+    public String getPreferenceKey() {
         return KEY_MOBILE_NETWORK_SETTINGS;
     }
 }
diff --git a/src/com/android/settings/network/MobilePlanPreferenceController.java b/src/com/android/settings/network/MobilePlanPreferenceController.java
index e62686f..8dfff15 100644
--- a/src/com/android/settings/network/MobilePlanPreferenceController.java
+++ b/src/com/android/settings/network/MobilePlanPreferenceController.java
@@ -120,7 +120,7 @@
         return isPrefAllowedForUser && isPrefAllowedOnDevice;
     }
     @Override
-    protected String getPreferenceKey() {
+    public String getPreferenceKey() {
         return KEY_MANAGE_MOBILE_PLAN;
     }
 
diff --git a/src/com/android/settings/network/NetworkResetPreferenceController.java b/src/com/android/settings/network/NetworkResetPreferenceController.java
index 2fe2038..b313cc0 100644
--- a/src/com/android/settings/network/NetworkResetPreferenceController.java
+++ b/src/com/android/settings/network/NetworkResetPreferenceController.java
@@ -43,7 +43,7 @@
     }
 
     @Override
-    protected String getPreferenceKey() {
+    public String getPreferenceKey() {
         return KEY_NETWORK_RESET;
     }
 }
diff --git a/src/com/android/settings/network/ProxyPreferenceController.java b/src/com/android/settings/network/ProxyPreferenceController.java
index 075b1f0..5feb5d0 100644
--- a/src/com/android/settings/network/ProxyPreferenceController.java
+++ b/src/com/android/settings/network/ProxyPreferenceController.java
@@ -54,7 +54,7 @@
     }
 
     @Override
-    protected String getPreferenceKey() {
+    public String getPreferenceKey() {
         return KEY_PROXY_SETTINGS;
     }
 }
diff --git a/src/com/android/settings/network/TetherPreferenceController.java b/src/com/android/settings/network/TetherPreferenceController.java
index b3d55fa..96f037b 100644
--- a/src/com/android/settings/network/TetherPreferenceController.java
+++ b/src/com/android/settings/network/TetherPreferenceController.java
@@ -83,7 +83,7 @@
     }
 
     @Override
-    protected String getPreferenceKey() {
+    public String getPreferenceKey() {
         return KEY_TETHER_SETTINGS;
     }
 }
diff --git a/src/com/android/settings/network/VpnPreferenceController.java b/src/com/android/settings/network/VpnPreferenceController.java
index 6e83826..0703ed3 100644
--- a/src/com/android/settings/network/VpnPreferenceController.java
+++ b/src/com/android/settings/network/VpnPreferenceController.java
@@ -65,7 +65,7 @@
     }
 
     @Override
-    protected String getPreferenceKey() {
+    public String getPreferenceKey() {
         return KEY_VPN_SETTINGS;
     }
 }
diff --git a/src/com/android/settings/network/WifiCallingPreferenceController.java b/src/com/android/settings/network/WifiCallingPreferenceController.java
index e733b67..61ab92e 100644
--- a/src/com/android/settings/network/WifiCallingPreferenceController.java
+++ b/src/com/android/settings/network/WifiCallingPreferenceController.java
@@ -56,7 +56,7 @@
     }
 
     @Override
-    protected String getPreferenceKey() {
+    public String getPreferenceKey() {
         return KEY_WFC_SETTINGS;
     }
 }
diff --git a/src/com/android/settings/nfc/NfcPreferenceController.java b/src/com/android/settings/nfc/NfcPreferenceController.java
index 0d31fe6..b7cd702 100644
--- a/src/com/android/settings/nfc/NfcPreferenceController.java
+++ b/src/com/android/settings/nfc/NfcPreferenceController.java
@@ -106,7 +106,7 @@
     }
 
     @Override
-    protected String getPreferenceKey() {
+    public String getPreferenceKey() {
         return null;
     }
 
diff --git a/tests/app/src/com/android/settings/tests/KeepOnScreenTest.java b/tests/app/src/com/android/settings/tests/KeepOnScreenTest.java
new file mode 100644
index 0000000..0b1308e
--- /dev/null
+++ b/tests/app/src/com/android/settings/tests/KeepOnScreenTest.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.tests;
+
+import android.app.Instrumentation;
+import android.content.Context;
+import android.content.Intent;
+import android.os.BatteryManager;
+import android.provider.Settings;
+import android.support.test.InstrumentationRegistry;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.runner.RunWith;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import org.junit.Test;
+import com.android.settings.R;
+
+import static android.support.test.espresso.Espresso.onView;
+import static android.support.test.espresso.action.ViewActions.click;
+import static android.support.test.espresso.matcher.ViewMatchers.*;
+import static junit.framework.Assert.assertEquals;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class KeepOnScreenTest {
+    private static int EXPECTED_FLAG = BatteryManager.BATTERY_PLUGGED_AC
+            | BatteryManager.BATTERY_PLUGGED_USB | BatteryManager.BATTERY_PLUGGED_WIRELESS;
+
+    @Test
+    public void testStayAwake_turnOn_StayAwakeWhileWirelessCharging() throws Exception{
+        Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
+        instrumentation.startActivitySync(new Intent(android.provider.Settings
+                .ACTION_APPLICATION_DEVELOPMENT_SETTINGS));
+
+        final Context targetContext = instrumentation.getTargetContext();
+        final int prevFlag = Settings.Global.getInt(targetContext.getContentResolver(), Settings
+                .Global.STAY_ON_WHILE_PLUGGED_IN);
+
+        // Turn on "Stay Awake" if needed
+        if (prevFlag == 0) {
+            onView(withText(R.string.keep_screen_on)).perform(click());
+        }
+
+        final int currentFlag = Settings.Global.getInt(targetContext.getContentResolver(), Settings
+                .Global.STAY_ON_WHILE_PLUGGED_IN);
+
+        assertEquals(EXPECTED_FLAG, currentFlag);
+
+        // Since this app doesn't have permission(and shouldn't have) to change global setting, we
+        // can only tearDown in this way
+        if (prevFlag != currentFlag) {
+            onView(withText(R.string.keep_screen_on)).perform(click());
+        }
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/UtilsTest.java b/tests/robotests/src/com/android/settings/UtilsTest.java
new file mode 100644
index 0000000..e486d31
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/UtilsTest.java
@@ -0,0 +1,69 @@
+package com.android.settings;
+
+import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.net.ConnectivityManager;
+import android.net.LinkAddress;
+import android.net.LinkProperties;
+import android.net.Network;
+import android.net.wifi.WifiManager;
+import java.net.InetAddress;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
+
+@RunWith(RobolectricTestRunner.class)
+@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
+public class UtilsTest {
+
+    private Context mContext;
+    @Mock private WifiManager wifiManager;
+    @Mock private Network network;
+    @Mock private ConnectivityManager connectivityManager;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+
+        mContext = spy(RuntimeEnvironment.application);
+        when(mContext.getSystemService(WifiManager.class)).thenReturn(wifiManager);
+        when(mContext.getSystemService(Context.CONNECTIVITY_SERVICE))
+            .thenReturn(connectivityManager);
+    }
+
+    @Test
+    public void testGetWifiIpAddresses_succeeds() throws Exception {
+        when(wifiManager.getCurrentNetwork()).thenReturn(network);
+        LinkAddress address = new LinkAddress(InetAddress.getByName("127.0.0.1"), 0);
+        LinkProperties lp = new LinkProperties();
+        lp.addLinkAddress(address);
+        when(connectivityManager.getLinkProperties(network)).thenReturn(lp);
+
+        assertThat(Utils.getWifiIpAddresses(mContext)).isEqualTo("127.0.0.1");
+    }
+
+    @Test
+    public void testGetWifiIpAddresses_nullLinkProperties() {
+        when(wifiManager.getCurrentNetwork()).thenReturn(network);
+        // Explicitly set the return value to null for readability sake.
+        when(connectivityManager.getLinkProperties(network)).thenReturn(null);
+
+        assertThat(Utils.getWifiIpAddresses(mContext)).isNull();
+    }
+
+    @Test
+    public void testGetWifiIpAddresses_nullNetwork() {
+        // Explicitly set the return value to null for readability sake.
+        when(wifiManager.getCurrentNetwork()).thenReturn(null);
+
+        assertThat(Utils.getWifiIpAddresses(mContext)).isNull();
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/core/PreferenceControllerTest.java b/tests/robotests/src/com/android/settings/core/PreferenceControllerTest.java
index ef03d5b..9a526b1 100644
--- a/tests/robotests/src/com/android/settings/core/PreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/core/PreferenceControllerTest.java
@@ -107,7 +107,7 @@
         }
 
         @Override
-        protected String getPreferenceKey() {
+        public String getPreferenceKey() {
             return KEY_PREF;
         }
     }
diff --git a/tests/robotests/src/com/android/settings/dashboard/DashboardFragmentTest.java b/tests/robotests/src/com/android/settings/dashboard/DashboardFragmentTest.java
index 432be56..e4222ce 100644
--- a/tests/robotests/src/com/android/settings/dashboard/DashboardFragmentTest.java
+++ b/tests/robotests/src/com/android/settings/dashboard/DashboardFragmentTest.java
@@ -16,10 +16,13 @@
 package com.android.settings.dashboard;
 
 import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.drawable.Icon;
 import android.os.Bundle;
 import android.support.v7.preference.Preference;
 import android.support.v7.preference.PreferenceScreen;
 
+import com.android.settings.SettingsActivity;
 import com.android.settings.TestConfig;
 import com.android.settings.core.PreferenceController;
 import com.android.settings.overlay.FeatureFactory;
@@ -44,6 +47,7 @@
 import static com.google.common.truth.Truth.assertThat;
 import static org.mockito.Matchers.any;
 import static org.mockito.Matchers.anyString;
+import static org.mockito.Matchers.eq;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.verify;
@@ -59,6 +63,8 @@
     private DashboardCategory mDashboardCategory;
     @Mock
     private FakeFeatureFactory mFakeFeatureFactory;
+    @Mock
+    private ProgressiveDisclosureMixin mDisclosureMixin;
     private TestFragment mTestFragment;
 
     @Before
@@ -69,9 +75,12 @@
         mDashboardCategory.tiles = new ArrayList<>();
         mDashboardCategory.tiles.add(new Tile());
         mTestFragment = new TestFragment(ShadowApplication.getInstance().getApplicationContext());
-        mTestFragment.onAttach(mContext);
+        when(mFakeFeatureFactory.dashboardFeatureProvider
+                .getProgressiveDisclosureMixin(any(Context.class), eq(mTestFragment)))
+                .thenReturn(mDisclosureMixin);
         when(mFakeFeatureFactory.dashboardFeatureProvider.getTilesForCategory(anyString()))
                 .thenReturn(mDashboardCategory);
+        mTestFragment.onAttach(ShadowApplication.getInstance().getApplicationContext());
     }
 
     @Test
@@ -87,11 +96,14 @@
 
     @Test
     public void displayTilesAsPreference_shouldAddTilesWithIntent() {
+        when(mFakeFeatureFactory.dashboardFeatureProvider.getTilesForCategory(anyString()))
+                .thenReturn(mDashboardCategory);
         when(mFakeFeatureFactory.dashboardFeatureProvider.getDashboardKeyForTile(any(Tile.class)))
                 .thenReturn("test_key");
         mTestFragment.onCreatePreferences(new Bundle(), "rootKey");
 
-        verify(mTestFragment.mScreen).addPreference(any(DashboardTilePreference.class));
+        verify(mDisclosureMixin).addPreference(any(PreferenceScreen.class),
+                any(DashboardTilePreference.class));
     }
 
     @Test
@@ -109,6 +121,27 @@
         verify(mTestFragment.mScreen, never()).addPreference(any(DashboardTilePreference.class));
     }
 
+    @Test
+    public void bindPreference_shouldBindAllData() {
+        final Preference preference = new Preference(
+                ShadowApplication.getInstance().getApplicationContext());
+        final Tile tile = new Tile();
+        tile.title = "title";
+        tile.summary = "summary";
+        tile.icon = Icon.createWithBitmap(Bitmap.createBitmap(1, 1, Bitmap.Config.RGB_565));
+        tile.metaData = new Bundle();
+        tile.metaData.putString(SettingsActivity.META_DATA_KEY_FRAGMENT_CLASS, "HI");
+        tile.priority = 10;
+        mTestFragment.bindPreferenceToTile(mContext, preference, tile, "123");
+
+        assertThat(preference.getTitle()).isEqualTo(tile.title);
+        assertThat(preference.getSummary()).isEqualTo(tile.summary);
+        assertThat(preference.getIcon()).isNotNull();
+        assertThat(preference.getFragment())
+                .isEqualTo(tile.metaData.getString(SettingsActivity.META_DATA_KEY_FRAGMENT_CLASS));
+        assertThat(preference.getOrder()).isEqualTo(-tile.priority);
+    }
+
     public static class TestPreferenceController extends PreferenceController {
 
         public TestPreferenceController(Context context) {
@@ -126,7 +159,7 @@
         }
 
         @Override
-        protected String getPreferenceKey() {
+        public String getPreferenceKey() {
             return null;
         }
 
@@ -139,7 +172,6 @@
     public static class TestFragment extends DashboardFragment {
 
         private final Context mContext;
-        @Mock
         public PreferenceScreen mScreen;
 
         public TestFragment(Context context) {
diff --git a/tests/robotests/src/com/android/settings/dashboard/ProgressiveDisclosureTest.java b/tests/robotests/src/com/android/settings/dashboard/ProgressiveDisclosureTest.java
new file mode 100644
index 0000000..be02596
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/dashboard/ProgressiveDisclosureTest.java
@@ -0,0 +1,259 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.dashboard;
+
+import android.content.Context;
+import android.support.v14.preference.PreferenceFragment;
+import android.support.v7.preference.Preference;
+import android.support.v7.preference.PreferenceScreen;
+
+import com.android.settings.TestConfig;
+import com.android.settings.overlay.FeatureFactory;
+import com.android.settings.testutils.FakeFeatureFactory;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Answers;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.annotation.Config;
+import org.robolectric.shadows.ShadowApplication;
+
+import java.util.List;
+
+import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+@RunWith(RobolectricTestRunner.class)
+@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
+public class ProgressiveDisclosureTest {
+
+    @Mock(answer = Answers.RETURNS_DEEP_STUBS)
+    private Context mContext;
+    @Mock
+    private FakeFeatureFactory mFakeFeatureFactory;
+    @Mock(answer = Answers.RETURNS_DEEP_STUBS)
+    private PreferenceFragment mPreferenceFragment;
+    private PreferenceScreen mScreen;
+    private Context mAppContext;
+    private Preference mPreference;
+
+    private ProgressiveDisclosureMixin mMixin;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        FakeFeatureFactory.setupForTest(mContext);
+        mScreen = mPreferenceFragment.getPreferenceScreen();
+        mAppContext = ShadowApplication.getInstance().getApplicationContext();
+        mFakeFeatureFactory = (FakeFeatureFactory) FeatureFactory.getFactory(mContext);
+        mMixin = new ProgressiveDisclosureMixin(mAppContext,
+                mFakeFeatureFactory.dashboardFeatureProvider, mPreferenceFragment);
+        mPreference = new Preference(mAppContext);
+        mPreference.setKey("test");
+        when(mFakeFeatureFactory.dashboardFeatureProvider.isEnabled()).thenReturn(true);
+    }
+
+    @Test
+    public void shouldNotCollapse_lessPreferenceThanLimit() {
+        when(mScreen.getPreferenceCount()).thenReturn(5);
+
+        mMixin.setTileLimit(10);
+
+        assertThat(mMixin.shouldCollapse(mScreen)).isFalse();
+    }
+
+    @Test
+    public void shouldCollapse_morePreferenceThanLimit() {
+        when(mFakeFeatureFactory.dashboardFeatureProvider.isEnabled()).thenReturn(true);
+        when(mScreen.getPreferenceCount()).thenReturn(5);
+
+        assertThat(mMixin.shouldCollapse(mScreen)).isTrue();
+    }
+
+    @Test
+    public void findPreference_prefInCollapsedList_shouldFindIt() {
+        when(mScreen.findPreference(anyString())).thenReturn(null);
+        mMixin.addToCollapsedList(mPreference);
+
+        Preference pref = mMixin.findPreference(mScreen, mPreference.getKey());
+
+        assertThat(pref).isNotNull();
+        assertThat(pref).isSameAs(mPreference);
+    }
+
+    @Test
+    public void findPreference_prefOnScreen_shouldFindIt() {
+        when(mScreen.findPreference(mPreference.getKey())).thenReturn(mPreference);
+
+        Preference pref = mMixin.findPreference(mScreen, mPreference.getKey());
+
+        assertThat(pref).isNotNull();
+        assertThat(pref).isSameAs(mPreference);
+    }
+
+    @Test
+    public void findPreference_prefNotInCollapsedListOrScreen_shouldNotFindIt() {
+        when(mScreen.findPreference(anyString())).thenReturn(null);
+        Preference pref = mMixin.findPreference(mScreen, mPreference.getKey());
+
+        assertThat(pref).isNull();
+    }
+
+    @Test
+    public void findPreference_prefRemovedFromCollapsedList_shouldNotFindIt() {
+        when(mScreen.findPreference(anyString())).thenReturn(null);
+        mMixin.addToCollapsedList(mPreference);
+        mMixin.removePreference(mPreferenceFragment.getPreferenceScreen(), mPreference.getKey());
+
+        Preference pref = mMixin.findPreference(mScreen, mPreference.getKey());
+
+        assertThat(pref).isNull();
+    }
+
+    @Test
+    public void removePreference_shouldRemoveOnScreenPreference() {
+        when(mScreen.findPreference(mPreference.getKey())).thenReturn(mPreference);
+
+        mMixin.removePreference(mScreen, mPreference.getKey());
+
+        verify(mScreen).removePreference(mPreference);
+    }
+
+    @Test
+    public void removeLastPreference_shouldRemoveExpandButtonToo() {
+        when(mScreen.findPreference(anyString())).thenReturn(null);
+        mMixin.addToCollapsedList(mPreference);
+        // Collapsed
+        assertThat(mMixin.isCollapsed()).isTrue();
+
+        mMixin.removePreference(mScreen, mPreference.getKey());
+
+        // Removing expand button
+        verify(mScreen).removePreference(any(Preference.class));
+        // No longer collapsed
+        assertThat(mMixin.isCollapsed()).isFalse();
+    }
+
+    @Test
+    public void collapse_shouldDoNothingIfNotCollapsible() {
+        final PreferenceScreen screen = mPreferenceFragment.getPreferenceScreen();
+        when(screen.getPreferenceCount()).thenReturn(5);
+        mMixin.setTileLimit(15);
+
+        mMixin.collapse(screen);
+        assertThat(mMixin.isCollapsed()).isFalse();
+        verify(screen, never()).addPreference(any(Preference.class));
+        verify(screen, never()).removePreference(any(Preference.class));
+    }
+
+    @Test
+    public void collapse_shouldRemovePrefAndAddExpandButton() {
+        final PreferenceScreen screen = mPreferenceFragment.getPreferenceScreen();
+        when(screen.getPreferenceCount()).thenReturn(5);
+        when(screen.getPreference(anyInt())).thenReturn(mPreference);
+        mMixin.setTileLimit(2);
+
+        mMixin.collapse(screen);
+
+        assertThat(mMixin.isCollapsed()).isTrue();
+        verify(screen).addPreference(any(ExpandPreference.class));
+        verify(screen, times(3)).removePreference(any(Preference.class));
+    }
+
+    @Test
+    public void addToCollapsedList_shouldAddInOrder() {
+        final Preference pref1 = new Preference(mAppContext);
+        final Preference pref2 = new Preference(mAppContext);
+        pref1.setOrder(10);
+        pref2.setOrder(20);
+
+        // Pref1 has lower order than pref2, but add pref2 first. The collapsed list should maintain
+        // items in increasing order.
+        mMixin.addToCollapsedList(pref2);
+        mMixin.addToCollapsedList(pref1);
+
+        List<Preference> collapsedList = mMixin.getCollapsedPrefs();
+        assertThat(collapsedList.get(0)).isSameAs(pref1);
+        assertThat(collapsedList.get(1)).isSameAs(pref2);
+    }
+
+    @Test
+    public void addPreferenceWhenCollapsed_noPrefOnScreen_shouldAddToList() {
+        // Add something to collapsed list so we are in collapsed state.
+        mMixin.addToCollapsedList(new Preference(mAppContext));
+        assertThat(mMixin.getCollapsedPrefs().size()).isEqualTo(1);
+
+        // Just 1 preference on screen: the more button
+        when(mScreen.getPreferenceCount()).thenReturn(1);
+        final Preference toBeAdded = new Preference(mAppContext);
+        toBeAdded.setOrder(100);
+        mMixin.addPreference(mScreen, toBeAdded);
+
+        // Should have 2 prefs in collapsed list now
+        assertThat(mMixin.getCollapsedPrefs().size()).isEqualTo(2);
+        assertThat(mMixin.getCollapsedPrefs().get(0)).isSameAs(toBeAdded);
+    }
+
+    @Test
+    public void addPreferenceWhenCollapsed_prefOrderLessThanLastOnScreen_shouldAddToScreen() {
+        final Preference lastPref = new Preference(mAppContext);
+        lastPref.setOrder(100);
+        // Add something to collapsed list so we are in collapsed state.
+        mMixin.addToCollapsedList(new Preference(mAppContext));
+        assertThat(mMixin.getCollapsedPrefs().size()).isEqualTo(1);
+        // 3 prefs on screen, 2 are real and the last one is more button.
+        when(mScreen.getPreferenceCount()).thenReturn(3);
+        when(mScreen.getPreference(1)).thenReturn(lastPref);
+
+        final Preference toBeAdded = new Preference(mAppContext);
+        toBeAdded.setOrder(50);
+        mMixin.addPreference(mScreen, toBeAdded);
+
+        verify(mScreen).removePreference(lastPref);
+        verify(mScreen).addPreference(toBeAdded);
+        assertThat(mMixin.getCollapsedPrefs().get(0)).isSameAs(lastPref);
+    }
+
+    @Test
+    public void addPreferenceWhenCollapsed_prefOrderMoreThanLastOnScreen_shouldAddToList() {
+        final Preference lastPref = new Preference(mAppContext);
+        lastPref.setOrder(100);
+        // Add something to collapsed list so we are in collapsed state.
+        mMixin.addToCollapsedList(new Preference(mAppContext));
+        assertThat(mMixin.getCollapsedPrefs().size()).isEqualTo(1);
+        // 3 prefs on screen, 2 are real and the last one is more button.
+        when(mScreen.getPreferenceCount()).thenReturn(3);
+        when(mScreen.getPreference(1)).thenReturn(lastPref);
+
+        final Preference toBeAdded = new Preference(mAppContext);
+        toBeAdded.setOrder(200);
+        mMixin.addPreference(mScreen, toBeAdded);
+
+        verify(mScreen, never()).removePreference(any(Preference.class));
+        verify(mScreen, never()).addPreference(any(Preference.class));
+        assertThat(mMixin.getCollapsedPrefs().get(0)).isSameAs(toBeAdded);
+    }
+}