Merge "[Settings] Code refactor for performance"
diff --git a/Android.bp b/Android.bp
index 37ddf93..b5dfe79 100644
--- a/Android.bp
+++ b/Android.bp
@@ -55,7 +55,11 @@
     ],
 
     srcs: ["src/**/*.java", "src/**/*.kt"],
-    resource_dirs: ["res", "res-product"],
+    resource_dirs: [
+        "res",
+        "res-export", // for external usage
+        "res-product",
+    ],
     static_libs: [
         "androidx-constraintlayout_constraintlayout",
         "androidx.slice_slice-builders",
diff --git a/res-export/.README.md b/res-export/.README.md
new file mode 100644
index 0000000..42b788e
--- /dev/null
+++ b/res-export/.README.md
@@ -0,0 +1,4 @@
+### Resources exported for external usage
+
+This folder contains the resources which is  **not** used by Settings, but is
+exported for external usage by other apps.
diff --git a/res-export/drawable/ic_find_device_disabled.xml b/res-export/drawable/ic_find_device_disabled.xml
new file mode 100644
index 0000000..21e92c9
--- /dev/null
+++ b/res-export/drawable/ic_find_device_disabled.xml
@@ -0,0 +1,25 @@
+<!--
+    Copyright (C) 2017 The Android Open Source Project
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+
+    <path
+        android:fillColor="#FFF44336"
+        android:pathData="M12,2C8.13,2 5,5.13 5,9c0,5.25 7,13 7,13s7,-7.75 7,-13C19,5.13 15.87,2 12,2zM7,9c0,-2.76 2.24,-5 5,-5s5,2.24 5,5c0,2.88 -2.88,7.19 -5,9.88C9.92,16.21 7,11.85 7,9zM11,13h2v2h-2V13zM13,6h-2v5h2V6z"/>
+</vector>
diff --git a/res-export/drawable/ic_find_device_enabled.xml b/res-export/drawable/ic_find_device_enabled.xml
new file mode 100644
index 0000000..614ac6d
--- /dev/null
+++ b/res-export/drawable/ic_find_device_enabled.xml
@@ -0,0 +1,25 @@
+<!--
+    Copyright (C) 2017 The Android Open Source Project
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+
+    <path
+        android:fillColor="#FF43A047"
+        android:pathData="M12,2C8.13,2 5,5.13 5,9c0,5.25 7,13 7,13s7,-7.75 7,-13C19,5.13 15.87,2 12,2zM7,9c0,-2.76 2.24,-5 5,-5s5,2.24 5,5c0,2.88 -2.88,7.19 -5,9.88C9.92,16.21 7,11.85 7,9zM14.5,9c0,1.38 -1.12,2.5 -2.5,2.5S9.5,10.38 9.5,9s1.12,-2.5 2.5,-2.5S14.5,7.62 14.5,9z"/>
+</vector>
diff --git a/res-export/drawable/ic_ota_update_available.xml b/res-export/drawable/ic_ota_update_available.xml
new file mode 100644
index 0000000..58412a2
--- /dev/null
+++ b/res-export/drawable/ic_ota_update_available.xml
@@ -0,0 +1,25 @@
+<!--
+    Copyright (C) 2017 The Android Open Source Project
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+
+    <path
+        android:fillColor="#FFD93025"
+        android:pathData="M17,1.01L7,1C5.9,1 5,1.9 5,3v18c0,1.1 0.9,2 2,2h10c1.1,0 2,-0.9 2,-2V3C19,1.9 18.1,1.01 17,1.01zM17,21H7l0,-1h10V21zM17,18H7V6h10V18zM7,4V3h10v1H7zM16,12.5l-4,4l-4,-4l1.41,-1.41L11,12.67V8.5V8h2v0.5v4.17l1.59,-1.59L16,12.5z"/>
+</vector>
diff --git a/res-export/drawable/ic_ota_update_current.xml b/res-export/drawable/ic_ota_update_current.xml
new file mode 100644
index 0000000..7b80a23
--- /dev/null
+++ b/res-export/drawable/ic_ota_update_current.xml
@@ -0,0 +1,25 @@
+<!--
+    Copyright (C) 2017 The Android Open Source Project
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+
+    <path
+        android:fillColor="#FF1E8E3E"
+        android:pathData="M17,1.01L7,1C5.9,1 5,1.9 5,3v18c0,1.1 0.9,2 2,2h10c1.1,0 2,-0.9 2,-2V3C19,1.9 18.1,1.01 17,1.01zM17,21H7l0,-1h10V21zM17,18H7V6h10V18zM7,4V3h10v1H7zM11.14,16l-3.84,-3.84l1.41,-1.42l2.43,2.42l4.16,-4.16l1.42,1.41L11.14,16z"/>
+</vector>
diff --git a/res-export/drawable/ic_ota_update_none.xml b/res-export/drawable/ic_ota_update_none.xml
new file mode 100644
index 0000000..0838ad3
--- /dev/null
+++ b/res-export/drawable/ic_ota_update_none.xml
@@ -0,0 +1,25 @@
+<!--
+    Copyright (C) 2017 The Android Open Source Project
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+
+    <path
+        android:fillColor="#FFD93025"
+        android:pathData="M17,1.01L7,1C5.9,1 5,1.9 5,3v18c0,1.1 0.9,2 2,2h10c1.1,0 2,-0.9 2,-2V3C19,1.9 18.1,1.01 17,1.01zM17,21H7l0,-1h10V21zM17,18H7V6h10V18zM7,4V3h10v1H7zM11,15h2v2h-2V15zM13,8h-2v5h2V8z"/>
+</vector>
diff --git a/res-export/drawable/ic_ota_update_stale.xml b/res-export/drawable/ic_ota_update_stale.xml
new file mode 100644
index 0000000..0838ad3
--- /dev/null
+++ b/res-export/drawable/ic_ota_update_stale.xml
@@ -0,0 +1,25 @@
+<!--
+    Copyright (C) 2017 The Android Open Source Project
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+
+    <path
+        android:fillColor="#FFD93025"
+        android:pathData="M17,1.01L7,1C5.9,1 5,1.9 5,3v18c0,1.1 0.9,2 2,2h10c1.1,0 2,-0.9 2,-2V3C19,1.9 18.1,1.01 17,1.01zM17,21H7l0,-1h10V21zM17,18H7V6h10V18zM7,4V3h10v1H7zM11,15h2v2h-2V15zM13,8h-2v5h2V8z"/>
+</vector>
diff --git a/res-export/drawable/ic_package_verifier_disabled.xml b/res-export/drawable/ic_package_verifier_disabled.xml
new file mode 100644
index 0000000..49fe0d3
--- /dev/null
+++ b/res-export/drawable/ic_package_verifier_disabled.xml
@@ -0,0 +1,25 @@
+<!--
+    Copyright (C) 2017 The Android Open Source Project
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+
+    <path
+        android:fillColor="#FFEF6C00"
+        android:pathData="M12,4.24l6,3v4.1c0,3.9 -2.55,7.5 -6,8.59c-3.45,-1.09 -6,-4.7 -6,-8.59v-4.1L12,4.24M12,2L4,6v5.33c0,4.93 3.41,9.55 8,10.67c4.59,-1.12 8,-5.73 8,-10.67V6L12,2L12,2zM11,15h2v2h-2V15zM13,8h-2v5h2V8z"/>
+</vector>
diff --git a/res-export/drawable/ic_package_verifier_enabled.xml b/res-export/drawable/ic_package_verifier_enabled.xml
new file mode 100644
index 0000000..1e09eee
--- /dev/null
+++ b/res-export/drawable/ic_package_verifier_enabled.xml
@@ -0,0 +1,25 @@
+<!--
+    Copyright (C) 2017 The Android Open Source Project
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+
+    <path
+        android:fillColor="#FF43A047"
+        android:pathData="M11.14,16l-3.84,-3.84l1.41,-1.42l2.43,2.42l4.16,-4.16l1.42,1.41L11.14,16zM12,4.24l6,3v4.1c0,3.9 -2.55,7.5 -6,8.59c-3.45,-1.09 -6,-4.7 -6,-8.59v-4.1L12,4.24M12,2L4,6v5.33c0,4.93 3.41,9.55 8,10.67c4.59,-1.12 8,-5.73 8,-10.67V6L12,2L12,2z"/>
+</vector>
diff --git a/res-export/drawable/ic_partial_system_update_current.xml b/res-export/drawable/ic_partial_system_update_current.xml
new file mode 100644
index 0000000..6e16592
--- /dev/null
+++ b/res-export/drawable/ic_partial_system_update_current.xml
@@ -0,0 +1,27 @@
+<!--
+Copyright (C) 2019 The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+android:width="24dp"
+android:height="24dp"
+android:viewportWidth="24.0"
+android:viewportHeight="24.0">
+<path
+    android:fillColor="#FF1E8E3E"
+    android:pathData="M17,18H7v-2.67l1.59,1.58L10,15.5l-3,-3l-1,-1l-4,4l1.41,1.42L5,15.33v4.17V20v1c0,1.1 0.9,2 2,2h10c1.1,0 2,-0.9 2,-2v-7h-2V18zM17,21H7v-1h10V21z"/>
+<path
+    android:fillColor="#FF1E8E3E"
+    android:pathData="M7,6h10v2.67l-1.59,-1.58L14,8.5l4,4l4,-4l-1.41,-1.42L19,8.67V4.5V4V3c0,-1.1 -0.9,-1.99 -2,-1.99L7,1C5.9,1 5,1.9 5,3v7h2V6zM7,3h10v1H7V3z"/>
+</vector>
diff --git a/res-export/drawable/ic_partial_system_update_stale.xml b/res-export/drawable/ic_partial_system_update_stale.xml
new file mode 100644
index 0000000..905187c
--- /dev/null
+++ b/res-export/drawable/ic_partial_system_update_stale.xml
@@ -0,0 +1,27 @@
+<!--
+Copyright (C) 2019 The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+android:width="24dp"
+android:height="24dp"
+android:viewportWidth="24.0"
+android:viewportHeight="24.0">
+<path
+    android:fillColor="#FFD93025"
+    android:pathData="M17,18H7v-2.67l1.59,1.58L10,15.5l-3,-3l-1,-1l-4,4l1.41,1.42L5,15.33v4.17V20v1c0,1.1 0.9,2 2,2h10c1.1,0 2,-0.9 2,-2v-7h-2V18zM17,21H7v-1h10V21z"/>
+<path
+    android:fillColor="#FFD93025"
+    android:pathData="M7,6h10v2.67l-1.59,-1.58L14,8.5l4,4l4,-4l-1.41,-1.42L19,8.67V4.5V4V3c0,-1.1 -0.9,-1.99 -2,-1.99L7,1C5.9,1 5,1.9 5,3v7h2V6zM7,3h10v1H7V3z"/>
+</vector>
diff --git a/res/drawable-night/ic_battery_status_protected_24dp.xml b/res/drawable-night/ic_battery_status_protected_24dp.xml
deleted file mode 100644
index 23386cb..0000000
--- a/res/drawable-night/ic_battery_status_protected_24dp.xml
+++ /dev/null
@@ -1,30 +0,0 @@
-<!--
-  ~ Copyright (C) 2022 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.
-  -->
-
-<vector
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:name="vector"
-    android:width="16dp"
-    android:height="16dp"
-    android:viewportWidth="16"
-    android:viewportHeight="16">
-    <path
-        android:name="path_1"
-        android:pathData="M 11.739 14.409 C 11.572 14.576 11.346 14.67 11.11 14.67 L 4.89 14.67 C 4.654 14.67 4.428 14.576 4.261 14.409 C 4.094 14.242 4 14.016 4 13.78 L 4 3.55 C 4 3.316 4.092 3.091 4.257 2.924 C 4.422 2.758 4.646 2.663 4.88 2.66 L 6.33 2.66 L 6.33 1.33 L 9.66 1.33 L 9.66 2.66 L 11.11 2.66 C 11.227 2.66 11.343 2.683 11.451 2.728 C 11.559 2.773 11.657 2.838 11.739 2.921 C 11.822 3.003 11.887 3.102 11.932 3.209 C 11.977 3.317 12 3.433 12 3.55 L 12 13.78 C 12 14.016 11.906 14.242 11.739 14.409 Z M 6 9 L 8.67 4 L 8.67 7.67 L 10 7.67 L 7.33 12.67 L 7.33 9 L 6 9 Z"
-        android:fillColor="#ffffff"
-        android:strokeWidth="1"
-        android:fillType="evenOdd"/>
-</vector>
\ No newline at end of file
diff --git a/res/drawable/ic_battery_dock_defender_untriggered_24dp.xml b/res/drawable/ic_battery_dock_defender_untriggered_24dp.xml
new file mode 100644
index 0000000..ba4d772
--- /dev/null
+++ b/res/drawable/ic_battery_dock_defender_untriggered_24dp.xml
@@ -0,0 +1,30 @@
+<!--
+  ~ Copyright (C) 2022 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.
+  -->
+
+<vector
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:name="vector"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+    <path
+        android:name="path"
+        android:pathData="M 18 20.673 C 18 21.027 17.859 21.367 17.609 21.617 C 17.359 21.867 17.019 22.008 16.665 22.008 L 7.335 22.008 C 6.981 22.008 6.641 21.867 6.391 21.617 C 6.141 21.367 6 21.027 6 20.673 L 6 5.328 C 6 4.977 6.139 4.639 6.386 4.389 C 6.633 4.139 6.969 3.997 7.32 3.993 L 9.495 3.993 L 9.495 1.998 L 14.49 1.998 L 14.49 3.993 L 16.665 3.993 C 16.84 3.993 17.014 4.028 17.176 4.095 C 17.338 4.162 17.485 4.26 17.609 4.384 C 17.733 4.508 17.831 4.655 17.898 4.817 C 17.965 4.979 18 5.153 18 5.328 L 18 20.673 Z M 9 13.503 L 13.005 6.003 L 13.005 11.508 L 15 11.508 L 10.995 19.008 L 10.995 13.503 L 9 13.503 Z"
+        android:strokeWidth="1"
+        android:fillColor="?android:attr/colorAccent"
+        android:fillType="evenOdd"/>
+</vector>
diff --git a/res/drawable/ic_battery_status_protected_24dp.xml b/res/drawable/ic_battery_status_protected_24dp.xml
index 8841710..b4de02f 100644
--- a/res/drawable/ic_battery_status_protected_24dp.xml
+++ b/res/drawable/ic_battery_status_protected_24dp.xml
@@ -17,14 +17,18 @@
 <vector
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:name="vector"
-    android:width="16dp"
-    android:height="16dp"
-    android:viewportWidth="16"
-    android:viewportHeight="16">
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
     <path
         android:name="path"
-        android:pathData="M 11.739 14.409 C 11.572 14.576 11.346 14.67 11.11 14.67 L 4.89 14.67 C 4.654 14.67 4.428 14.576 4.261 14.409 C 4.094 14.242 4 14.016 4 13.78 L 4 3.55 C 4 3.316 4.092 3.091 4.257 2.924 C 4.422 2.758 4.646 2.663 4.88 2.66 L 6.33 2.66 L 6.33 1.33 L 9.66 1.33 L 9.66 2.66 L 11.11 2.66 C 11.227 2.66 11.343 2.683 11.451 2.728 C 11.559 2.773 11.657 2.838 11.739 2.921 C 11.822 3.003 11.887 3.102 11.932 3.209 C 11.977 3.317 12 3.433 12 3.55 L 12 13.78 C 12 14.016 11.906 14.242 11.739 14.409 Z M 6 9 L 8.67 4 L 8.67 7.67 L 10 7.67 L 7.33 12.67 L 7.33 9 L 6 9 Z"
-        android:fillColor="#000000"
-        android:strokeWidth="1"
-        android:fillType="evenOdd"/>
-</vector>
\ No newline at end of file
+        android:pathData="M 12 11.493 L 18 9.243 L 18 5.328 C 18 4.593 17.4 3.993 16.665 3.993 L 14.49 3.993 L 14.49 1.998 L 9.495 1.998 L 9.495 3.993 L 7.32 3.993 C 6.585 3.993 5.985 4.593 5.985 5.328 L 5.985 20.673 C 5.985 21.408 6.585 22.008 7.32 22.008 L 13.365 22.008 C 12.495 20.583 12 18.918 12 17.193 L 12 11.493 Z M 7.995 6.003 L 15.99 6.003 L 15.99 9.003 L 7.995 9.003 L 7.995 6.003 Z"
+        android:fillColor="?android:attr/colorAccent"
+        android:strokeWidth="1"/>
+    <path
+        android:name="path_2"
+        android:pathData="M 19.005 10.998 L 14.01 12.873 L 14.01 17.178 C 14.01 20.328 16.14 23.283 19.005 24.003 C 21.87 23.283 24 20.343 24 17.178 L 24 12.873 L 19.005 10.998 Z"
+        android:fillColor="?android:attr/colorAccent"
+        android:strokeWidth="1"/>
+</vector>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 0cd0c86..5494acf 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -2697,6 +2697,16 @@
     <!-- SD card & phone storage settings screen, message on screen after user selects Reset network settings [CHAR LIMIT=NONE] -->
     <string name="reset_network_desc">This will reset all network settings, including:\n\n<li>Wi\u2011Fi</li>\n<li>Mobile data</li>\n<li>Bluetooth</li>"</string>
 
+    <!-- Reset Bluetooth and Wi-Fi Network -->
+    <!-- Dialog title to reset Bluetooth and Wi-Fi settings -->
+    <string name="reset_bluetooth_wifi_title">Reset Bluetooth &amp; Wi\u2011Fi</string>
+    <!-- Dialog context when reset Bluetooth and Wi-Fi settings [CHAR LIMIT=NONE] -->
+    <string name="reset_bluetooth_wifi_desc">This will reset all Wi\u2011Fi &amp; Bluetooth settings. You can\u2019t undo this action.</string>
+    <!-- Confirmation button text when reset Bluetooth and Wi-Fi settings [CHAR LIMIT=NONE] -->
+    <string name="reset_bluetooth_wifi_button_text">Reset</string>
+    <!-- Reset Bluetooth and Wi-Fi complete toast text [CHAR LIMIT=75] -->
+    <string name="reset_bluetooth_wifi_complete_toast">Bluetooth &amp; Wi\u2011Fi have been reset</string>
+
     <!-- Erase Euicc -->
     <!-- Confirmation button of dialog to confirm resetting user's app preferences [CHAR LIMIT=NONE] -->
     <string name="erase_euicc_data_button">Erase</string>
@@ -4987,6 +4997,8 @@
     <string name="battery_usage_for_background_time">Background: <xliff:g id="time">%s</xliff:g></string>
     <!-- [CHAR_LIMIT=NONE] Battery usage main screen footer for empty content -->
     <string name="battery_usage_screen_footer_empty">Battery usage data will be available in a few hours once fully charged</string>
+    <!-- [CHAR_LIMIT=NONE] Battery chart label for the current time. -->
+    <string name="battery_usage_chart_label_now">now</string>
     <!-- [CHAR_LIMIT=NONE] Accessibility content description for battery chart view. -->
     <string name="battery_usage_chart">Battery usage chart</string>
     <!-- [CHAR_LIMIT=NONE] Accessibility content description for daily battery chart view. -->
@@ -8074,6 +8086,8 @@
     <string name="memtag_reboot_no">Not now</string>
     <!-- [CHAR LIMIT=NONE] Label for Learn More link. -->
     <string name="memtag_learn_more">Learn more about Advanced memory protection.</string>
+    <!-- [CHAR LIMIT=NONE] Search keywords for Advanced memory protection option. -->
+    <string name="keywords_memtag" translatable="false">MTE, Memory Tagging Extension</string>
 
     <!-- Opening string on the dialog that prompts the user to confirm that they really want to delete their existing work profile. The administration app icon and name appear after the final colon. [CHAR LIMIT=NONE] -->
     <string name="opening_paragraph_delete_profile_unknown_company">This work profile is managed by:</string>
diff --git a/res/xml/reset_dashboard_fragment.xml b/res/xml/reset_dashboard_fragment.xml
index 25161a5..d2c8ca0 100644
--- a/res/xml/reset_dashboard_fragment.xml
+++ b/res/xml/reset_dashboard_fragment.xml
@@ -28,6 +28,14 @@
         settings:useAdminDisabledSummary="true"
         android:fragment="com.android.settings.ResetNetwork" />
 
+    <!-- Bluetooth and WiFi reset -->
+    <com.android.settingslib.RestrictedPreference
+        android:key="network_reset_bluetooth_wifi_pref"
+        android:title="@string/reset_bluetooth_wifi_title"
+        settings:userRestriction="no_network_reset"
+        settings:useAdminDisabledSummary="true"
+        settings:controller="com.android.settings.network.BluetoothWiFiResetPreferenceController" />
+
     <!-- Reset app preferences -->
     <Preference
         android:key="reset_app_prefs"
diff --git a/res/xml/security_advanced_settings.xml b/res/xml/security_advanced_settings.xml
index c8ed6db..c489597 100644
--- a/res/xml/security_advanced_settings.xml
+++ b/res/xml/security_advanced_settings.xml
@@ -112,6 +112,7 @@
         android:id="@+id/memtag_page"
         android:key="memtag_page"
         android:title="@string/memtag_title"
+        settings:keywords="@string/keywords_memtag"
         android:fragment="com.android.settings.security.MemtagPage"
         settings:controller="com.android.settings.security.MemtagPagePreferenceController" />
 
diff --git a/src/com/android/settings/bluetooth/BluetoothPairingService.java b/src/com/android/settings/bluetooth/BluetoothPairingService.java
index 9883e61..d8487e4 100644
--- a/src/com/android/settings/bluetooth/BluetoothPairingService.java
+++ b/src/com/android/settings/bluetooth/BluetoothPairingService.java
@@ -99,11 +99,8 @@
                 Log.d(TAG, "Notification cancel " + " (" +
                         mDevice.getName() + ")");
                 mDevice.cancelBondProcess();
-            } else {
-                int bondState = intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE,
-                        BluetoothDevice.ERROR);
-                Log.d(TAG, "Dismiss pairing for " + " (" +
-                        mDevice.getName() + "), BondState: " + bondState);
+            } else { // BluetoothDevice.ACTION_PAIRING_CANCEL
+                Log.d(TAG, "Dismiss pairing for " + " (" + mDevice.getName() + ")");
             }
 
             mNm.cancel(NOTIFICATION_ID);
diff --git a/src/com/android/settings/connecteddevice/stylus/StylusDevicesController.java b/src/com/android/settings/connecteddevice/stylus/StylusDevicesController.java
index 0081d87..bf2fdda 100644
--- a/src/com/android/settings/connecteddevice/stylus/StylusDevicesController.java
+++ b/src/com/android/settings/connecteddevice/stylus/StylusDevicesController.java
@@ -22,6 +22,7 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.provider.Settings;
+import android.provider.Settings.Secure;
 import android.util.Log;
 import android.view.InputDevice;
 
@@ -125,6 +126,8 @@
         pref.setTitle(mContext.getString(R.string.stylus_ignore_button));
         pref.setIcon(R.drawable.ic_block);
         pref.setOnPreferenceClickListener(this);
+        pref.setChecked(Settings.Secure.getInt(mContext.getContentResolver(),
+                Settings.Secure.STYLUS_BUTTONS_DISABLED, 0) == 1);
         return pref;
     }
 
@@ -147,7 +150,9 @@
                         ((SwitchPreference) preference).isChecked() ? 1 : 0);
                 break;
             case KEY_IGNORE_BUTTON:
-                // TODO(b/251199452): to turn off stylus button presses
+                Settings.Secure.putInt(mContext.getContentResolver(),
+                        Secure.STYLUS_BUTTONS_DISABLED,
+                        ((SwitchPreference) preference).isChecked() ? 1 : 0);
                 break;
         }
         return true;
diff --git a/src/com/android/settings/fuelgauge/batterytip/tips/DockDefenderTip.java b/src/com/android/settings/fuelgauge/batterytip/tips/DockDefenderTip.java
index 2ba3dcd..dae4af4 100644
--- a/src/com/android/settings/fuelgauge/batterytip/tips/DockDefenderTip.java
+++ b/src/com/android/settings/fuelgauge/batterytip/tips/DockDefenderTip.java
@@ -90,7 +90,8 @@
 
     @Override
     public int getIconId() {
-        return R.drawable.ic_battery_status_protected_24dp;
+        return mMode == DockDefenderMode.ACTIVE ? R.drawable.ic_battery_status_protected_24dp :
+                R.drawable.ic_battery_dock_defender_untriggered_24dp;
     }
 
     @Override
diff --git a/src/com/android/settings/fuelgauge/batteryusage/BatteryChartPreferenceController.java b/src/com/android/settings/fuelgauge/batteryusage/BatteryChartPreferenceController.java
index 7e1bb38..707c5b2 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/BatteryChartPreferenceController.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/BatteryChartPreferenceController.java
@@ -47,6 +47,8 @@
 import com.android.settingslib.core.lifecycle.events.OnResume;
 import com.android.settingslib.core.lifecycle.events.OnSaveInstanceState;
 
+import com.google.common.base.Objects;
+
 import java.util.ArrayList;
 import java.util.Calendar;
 import java.util.List;
@@ -238,7 +240,8 @@
                     hourlyBatteryLevelsPerDay.getLevels(),
                     hourlyBatteryLevelsPerDay.getTimestamps(),
                     BatteryChartViewModel.AxisLabelPosition.BETWEEN_TRAPEZOIDS,
-                    mHourlyChartLabelTextGenerator));
+                    mHourlyChartLabelTextGenerator.setLatestTimestamp(getLast(getLast(
+                            batteryLevelData.getHourlyBatteryLevelsPerDay()).getTimestamps()))));
         }
         refreshUi();
     }
@@ -514,6 +517,13 @@
         return allBatteryDiffData == null ? null : allBatteryDiffData.getAppDiffEntryList();
     }
 
+    private static <T> T getLast(List<T> list) {
+        if (list == null || list.isEmpty()) {
+            return null;
+        }
+        return list.get(list.size() - 1);
+    }
+
     /** Used for {@link AppBatteryPreferenceController}. */
     public static BatteryDiffEntry getAppBatteryUsageData(
             Context context, String packageName, int userId) {
@@ -553,18 +563,33 @@
 
     private final class HourlyChartLabelTextGenerator implements
             BatteryChartViewModel.LabelTextGenerator {
+        private Long mLatestTimestamp;
+
         @Override
         public String generateText(List<Long> timestamps, int index) {
+            if (Objects.equal(timestamps.get(index), mLatestTimestamp)) {
+                // Replaces the latest timestamp text to "now".
+                return mContext.getString(R.string.battery_usage_chart_label_now);
+            }
             return ConvertUtils.utcToLocalTimeHour(mContext, timestamps.get(index),
                     mIs24HourFormat);
         }
 
         @Override
         public String generateFullText(List<Long> timestamps, int index) {
+            if (Objects.equal(timestamps.get(index), mLatestTimestamp)) {
+                // Replaces the latest timestamp text to "now".
+                return mContext.getString(R.string.battery_usage_chart_label_now);
+            }
             return index == timestamps.size() - 1
                     ? generateText(timestamps, index)
                     : String.format("%s%s%s", generateText(timestamps, index),
-                            mIs24HourFormat ? "-" : " - ", generateText(timestamps, index + 1));
+                    mIs24HourFormat ? "-" : " - ", generateText(timestamps, index + 1));
+        }
+
+        public HourlyChartLabelTextGenerator setLatestTimestamp(Long latestTimestamp) {
+            this.mLatestTimestamp = latestTimestamp;
+            return this;
         }
     }
 }
diff --git a/src/com/android/settings/fuelgauge/batteryusage/DataProcessor.java b/src/com/android/settings/fuelgauge/batteryusage/DataProcessor.java
index 2827818..b510e5b 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/DataProcessor.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/DataProcessor.java
@@ -21,6 +21,7 @@
 import android.app.settings.SettingsEnums;
 import android.content.ContentValues;
 import android.content.Context;
+import android.content.Intent;
 import android.content.pm.PackageManager;
 import android.os.AsyncTask;
 import android.os.BatteryConsumer;
@@ -86,6 +87,12 @@
     static final double PERCENTAGE_OF_TOTAL_THRESHOLD = 1f;
     @VisibleForTesting
     static final int SELECTED_INDEX_ALL = BatteryChartViewModel.SELECTED_INDEX_ALL;
+    @VisibleForTesting
+    static final String CURRENT_TIME_BATTERY_HISTORY_PLACEHOLDER =
+            "CURRENT_TIME_BATTERY_HISTORY_PLACEHOLDER";
+
+    @VisibleForTesting
+    static long sFakeCurrentTimeMillis = 0;
 
     /** A callback listener when battery usage loading async task is executed. */
     public interface UsageMapAsyncResponse {
@@ -239,11 +246,12 @@
             return resultMap;
         }
         Collections.sort(rawTimestampList);
-        final List<Long> expectedTimestampList = getTimestampSlots(rawTimestampList);
+        final long currentTime = getCurrentTimeMillis();
+        final List<Long> expectedTimestampList = getTimestampSlots(rawTimestampList, currentTime);
         final boolean isFromFullCharge =
                 isFromFullCharge(batteryHistoryMap.get(rawTimestampList.get(0)));
         interpolateHistory(
-                context, rawTimestampList, expectedTimestampList, isFromFullCharge,
+                context, rawTimestampList, expectedTimestampList, currentTime, isFromFullCharge,
                 batteryHistoryMap, resultMap);
         Log.d(TAG, String.format("getHistoryMapWithExpectedTimestamps() size=%d in %d/ms",
                 resultMap.size(), (System.currentTimeMillis() - startTime)));
@@ -278,19 +286,16 @@
      * between start and end two even hour values.
      */
     @VisibleForTesting
-    static List<Long> getTimestampSlots(final List<Long> rawTimestampList) {
+    static List<Long> getTimestampSlots(final List<Long> rawTimestampList, final long currentTime) {
         final List<Long> timestampSlots = new ArrayList<>();
-        final int rawTimestampListSize = rawTimestampList.size();
-        // If timestamp number is smaller than 2, the following computation is not necessary.
-        if (rawTimestampListSize < MIN_TIMESTAMP_DATA_SIZE) {
+        if (rawTimestampList.isEmpty()) {
             return timestampSlots;
         }
         final long rawStartTimestamp = rawTimestampList.get(0);
-        final long rawEndTimestamp = rawTimestampList.get(rawTimestampListSize - 1);
         // No matter the start is from last full charge or 6 days ago, use the nearest even hour.
         final long startTimestamp = getNearestEvenHourTimestamp(rawStartTimestamp);
-        // Use the even hour before the raw end timestamp as the end.
-        final long endTimestamp = getLastEvenHourBeforeTimestamp(rawEndTimestamp);
+        // Use the first even hour after the current time as the end.
+        final long endTimestamp = getFirstEvenHourAfterTimestamp(currentTime);
         // If the start timestamp is later or equal the end one, return the empty list.
         if (startTimestamp >= endTimestamp) {
             return timestampSlots;
@@ -451,10 +456,7 @@
     @Nullable
     static BatteryDiffData generateBatteryDiffData(
             final Context context,
-            @Nullable final List<BatteryEntry> batteryEntryList,
-            final BatteryUsageStats batteryUsageStats) {
-        final List<BatteryHistEntry> batteryHistEntryList =
-                convertToBatteryHistEntry(batteryEntryList, batteryUsageStats);
+            final List<BatteryHistEntry> batteryHistEntryList) {
         if (batteryHistEntryList == null || batteryHistEntryList.isEmpty()) {
             Log.w(TAG, "batteryHistEntryList is null or empty in generateBatteryDiffData()");
             return null;
@@ -531,7 +533,7 @@
         final Map<Integer, BatteryDiffData> allUsageMap = new HashMap<>();
         // Always construct the map whether the value is null or not.
         allUsageMap.put(SELECTED_INDEX_ALL,
-                getBatteryDiffDataFromBatteryStatsService(context));
+                generateBatteryDiffData(context, getBatteryHistListFromFromStatsService(context)));
         resultMap.put(SELECTED_INDEX_ALL, allUsageMap);
 
         // Compute the apps number before purge. Must put before purgeLowPercentageAndFakeData.
@@ -545,24 +547,33 @@
     }
 
     @Nullable
-    private static BatteryDiffData getBatteryDiffDataFromBatteryStatsService(
+    private static List<BatteryHistEntry> getBatteryHistListFromFromStatsService(
             final Context context) {
-        BatteryDiffData batteryDiffData = null;
+        List<BatteryHistEntry> batteryHistEntryList = null;
         try {
             final BatteryUsageStats batteryUsageStats = getBatteryUsageStats(context);
             final List<BatteryEntry> batteryEntryList =
                     generateBatteryEntryListFromBatteryUsageStats(context, batteryUsageStats);
-            batteryDiffData = generateBatteryDiffData(context, batteryEntryList, batteryUsageStats);
+            batteryHistEntryList = convertToBatteryHistEntry(batteryEntryList, batteryUsageStats);
             closeBatteryUsageStats(batteryUsageStats);
         } catch (RuntimeException e) {
             Log.e(TAG, "load batteryUsageStats:" + e);
         }
 
-        return batteryDiffData;
+        return batteryHistEntryList;
     }
 
+    private static Map<String, BatteryHistEntry> getCurrentBatteryHistoryMapFromStatsService(
+            final Context context) {
+        final List<BatteryHistEntry> batteryHistEntryList =
+                getBatteryHistListFromFromStatsService(context);
+        return batteryHistEntryList == null ? new HashMap<>()
+                : batteryHistEntryList.stream().collect(Collectors.toMap(e -> e.getKey(), e -> e));
+    }
+
+    @VisibleForTesting
     @Nullable
-    private static List<BatteryHistEntry> convertToBatteryHistEntry(
+    static List<BatteryHistEntry> convertToBatteryHistEntry(
             @Nullable final List<BatteryEntry> batteryEntryList,
             final BatteryUsageStats batteryUsageStats) {
         if (batteryEntryList == null || batteryEntryList.isEmpty()) {
@@ -591,6 +602,7 @@
             Context context,
             final List<Long> rawTimestampList,
             final List<Long> expectedTimestampSlots,
+            final long currentTime,
             final boolean isFromFullCharge,
             final Map<Long, Map<String, BatteryHistEntry>> batteryHistoryMap,
             final Map<Long, Map<String, BatteryHistEntry>> resultMap) {
@@ -611,6 +623,17 @@
         final int expectedTimestampSlotsSize = expectedTimestampSlots.size();
         for (int index = startIndex; index < expectedTimestampSlotsSize; index++) {
             final long currentSlot = expectedTimestampSlots.get(index);
+            if (currentSlot > currentTime) {
+                // The slot timestamp is greater than the current time. Puts a placeholder first,
+                // then in the async task, loads the real time battery usage data from the battery
+                // stats service.
+                // If current time is odd hour, one placeholder is added. If the current hour is
+                // even hour, two placeholders are added. This is because the method
+                // insertHourlyUsageDiffDataPerSlot() requires continuing three hours data.
+                resultMap.put(currentSlot,
+                        Map.of(CURRENT_TIME_BATTERY_HISTORY_PLACEHOLDER, EMPTY_BATTERY_HIST_ENTRY));
+                continue;
+            }
             final boolean isStartOrEnd = index == 0 || index == expectedTimestampSlotsSize - 1;
             interpolateHistoryForSlot(
                     context, currentSlot, rawTimestampList, batteryHistoryMap, resultMap,
@@ -733,6 +756,13 @@
     }
 
     /**
+     * @return Returns the fist even hour timestamp after the given timestamp.
+     */
+    private static long getFirstEvenHourAfterTimestamp(long rawTimestamp) {
+        return getLastEvenHourBeforeTimestamp(rawTimestamp + DateUtils.HOUR_IN_MILLIS * 2);
+    }
+
+    /**
      * @return Returns the last even hour timestamp before the given timestamp.
      */
     private static long getLastEvenHourBeforeTimestamp(long rawTimestamp) {
@@ -809,6 +839,12 @@
                     + utcToLocalTime(context, timestamp));
             return null;
         }
+        // The current time battery history hasn't been loaded yet, returns the current battery
+        // level.
+        if (entryMap.containsKey(CURRENT_TIME_BATTERY_HISTORY_PLACEHOLDER)) {
+            final Intent intent = BatteryUtils.getBatteryIntent(context);
+            return BatteryStatus.getBatteryLevel(intent);
+        }
         // Averages the battery level in each time slot to avoid corner conditions.
         float batteryLevelCounter = 0;
         for (BatteryHistEntry entry : entryMap.values()) {
@@ -1394,6 +1430,10 @@
         return batteryDiffEntry;
     }
 
+    private static long getCurrentTimeMillis() {
+        return sFakeCurrentTimeMillis > 0 ? sFakeCurrentTimeMillis : System.currentTimeMillis();
+    }
+
     private static void logAppCountMetrics(
             Context context, final int countOfAppBeforePurge, final int countOfAppAfterPurge) {
         context = context.getApplicationContext();
@@ -1465,6 +1505,17 @@
                 return null;
             }
             final long startTime = System.currentTimeMillis();
+            // Loads the current battery usage data from the battery stats service and replaces the
+            // placeholder in mBatteryHistoryMap.
+            Map<String, BatteryHistEntry> currentBatteryHistoryMap =
+                    getCurrentBatteryHistoryMapFromStatsService(mApplicationContext);
+            for (Map.Entry<Long, Map<String, BatteryHistEntry>> mapEntry
+                    : mBatteryHistoryMap.entrySet()) {
+                if (mapEntry.getValue().containsKey(CURRENT_TIME_BATTERY_HISTORY_PLACEHOLDER)) {
+                    mapEntry.setValue(currentBatteryHistoryMap);
+                }
+            }
+
             final Map<Integer, Map<Integer, BatteryDiffData>> batteryUsageMap =
                     getBatteryUsageMap(
                             mApplicationContext, mHourlyBatteryLevelsPerDay, mBatteryHistoryMap);
diff --git a/src/com/android/settings/network/BluetoothWiFiResetPreferenceController.java b/src/com/android/settings/network/BluetoothWiFiResetPreferenceController.java
new file mode 100644
index 0000000..c469304
--- /dev/null
+++ b/src/com/android/settings/network/BluetoothWiFiResetPreferenceController.java
@@ -0,0 +1,173 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.network;
+
+import android.app.ProgressDialog;
+import android.app.settings.SettingsEnums;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.os.Looper;
+import android.text.TextUtils;
+import android.util.Log;
+import android.widget.Toast;
+
+import androidx.annotation.VisibleForTesting;
+import androidx.appcompat.app.AlertDialog;
+import androidx.preference.Preference;
+
+import com.android.settings.R;
+import com.android.settings.ResetNetworkRequest;
+import com.android.settings.core.BasePreferenceController;
+import com.android.settings.overlay.FeatureFactory;
+import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
+
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.atomic.AtomicReference;
+
+/**
+ * This is to show a preference regarding resetting Bluetooth and Wi-Fi.
+ */
+public class BluetoothWiFiResetPreferenceController extends BasePreferenceController
+        implements DialogInterface.OnClickListener, DialogInterface.OnDismissListener {
+
+    private static final String TAG = "BtWiFiResetPreferenceController";
+
+    private final NetworkResetRestrictionChecker mRestrictionChecker;
+
+    private DialogInterface mResetDialog;
+    private ProgressDialog mProgressDialog;
+    private ExecutorService mExecutorService;
+
+    /**
+     * Constructer.
+     * @param context Context
+     * @param preferenceKey is the key for Preference
+     */
+    public BluetoothWiFiResetPreferenceController(Context context, String preferenceKey) {
+        super(context, preferenceKey);
+
+        // restriction check
+        mRestrictionChecker = new NetworkResetRestrictionChecker(context);
+    }
+
+    @Override
+    public int getAvailabilityStatus() {
+        return mRestrictionChecker.hasUserRestriction() ?
+                CONDITIONALLY_UNAVAILABLE : AVAILABLE;
+    }
+
+    @Override
+    public boolean handlePreferenceTreeClick(Preference preference) {
+        if (!TextUtils.equals(preference.getKey(), getPreferenceKey())) {
+            return false;
+        }
+        buildResetDialog(preference);
+        return true;
+    }
+
+    /**
+     * This is a pop-up dialog showing detail of this reset option.
+     */
+    void buildResetDialog(Preference preference) {
+        if (mResetDialog != null) {
+            return;
+        }
+        mResetDialog = new AlertDialog.Builder(mContext)
+                .setTitle(R.string.reset_bluetooth_wifi_title)
+                .setMessage(R.string.reset_bluetooth_wifi_desc)
+                .setPositiveButton(R.string.reset_bluetooth_wifi_button_text, this)
+                .setNegativeButton(R.string.cancel, null /* OnClickListener */)
+                .setOnDismissListener(this)
+                .show();
+    }
+
+    public void onDismiss(DialogInterface dialog) {
+        if (mResetDialog == dialog) {
+            mResetDialog = null;
+        }
+    }
+
+    /**
+     * User pressed confirmation button, for starting reset operation.
+     */
+    public void onClick(DialogInterface dialog, int which) {
+        if (mResetDialog != dialog) {
+            return;
+        }
+
+        // User confirm the reset operation
+        MetricsFeatureProvider provider = FeatureFactory.getFactory(mContext)
+                .getMetricsFeatureProvider();
+        provider.action(mContext, SettingsEnums.RESET_BLUETOOTH_WIFI_CONFIRM, true);
+
+        // Non-cancelable progress dialog
+        mProgressDialog = getProgressDialog(mContext);
+        mProgressDialog.show();
+
+        // Run reset in background thread
+        mExecutorService = Executors.newSingleThreadExecutor();
+        mExecutorService.execute(() -> {
+            final AtomicReference<Exception> exceptionDuringReset =
+                    new AtomicReference<Exception>();
+            try {
+                resetOperation();
+            } catch (Exception exception) {
+                exceptionDuringReset.set(exception);
+            }
+            mContext.getMainExecutor().execute(() -> endOfReset(exceptionDuringReset.get()));
+        });
+    }
+
+    @VisibleForTesting
+    protected ProgressDialog getProgressDialog(Context context) {
+        final ProgressDialog progressDialog = new ProgressDialog(context);
+        progressDialog.setIndeterminate(true);
+        progressDialog.setCancelable(false);
+        progressDialog.setMessage(
+                context.getString(R.string.main_clear_progress_text));
+        return progressDialog;
+    }
+
+    @VisibleForTesting
+    protected void resetOperation() throws Exception {
+        new ResetNetworkRequest(
+                ResetNetworkRequest.RESET_WIFI_MANAGER |
+                ResetNetworkRequest.RESET_WIFI_P2P_MANAGER |
+                ResetNetworkRequest.RESET_BLUETOOTH_MANAGER
+        ).toResetNetworkOperationBuilder(mContext, Looper.getMainLooper())
+                .build().run();
+    }
+
+    @VisibleForTesting
+    protected void endOfReset(Exception exceptionDuringReset) {
+        if (mExecutorService != null) {
+            mExecutorService.shutdown();
+            mExecutorService = null;
+        }
+        if (mProgressDialog != null) {
+            mProgressDialog.dismiss();
+            mProgressDialog = null;
+        }
+        if (exceptionDuringReset == null) {
+            Toast.makeText(mContext, R.string.reset_bluetooth_wifi_complete_toast,
+                    Toast.LENGTH_SHORT).show();
+        } else {
+            Log.e(TAG, "Exception during reset", exceptionDuringReset);
+        }
+    }
+}
diff --git a/src/com/android/settings/privacy/PrivacyControlsFragment.java b/src/com/android/settings/privacy/PrivacyControlsFragment.java
index 1d9a4712..e40ed94 100644
--- a/src/com/android/settings/privacy/PrivacyControlsFragment.java
+++ b/src/com/android/settings/privacy/PrivacyControlsFragment.java
@@ -45,7 +45,7 @@
 
     @Override
     public int getMetricsCategory() {
-        return SettingsEnums.TOP_LEVEL_PRIVACY;
+        return SettingsEnums.PRIVACY_CONTROLS;
     }
 
     @Override
diff --git a/src/com/android/settings/spa/app/appinfo/AppPermissionSummary.kt b/src/com/android/settings/spa/app/appinfo/AppPermissionSummary.kt
index f73c35a..58edee6 100644
--- a/src/com/android/settings/spa/app/appinfo/AppPermissionSummary.kt
+++ b/src/com/android/settings/spa/app/appinfo/AppPermissionSummary.kt
@@ -37,19 +37,19 @@
     private val app: ApplicationInfo,
 ) : LiveData<AppPermissionSummaryState>() {
     private val userContext = context.asUser(app.userHandle)
-    private val packageManager = userContext.packageManager
+    private val userPackageManager = userContext.packageManager
 
     private val onPermissionsChangedListener = OnPermissionsChangedListener { uid ->
         if (uid == app.uid) update()
     }
 
     override fun onActive() {
-        packageManager.addOnPermissionsChangeListener(onPermissionsChangedListener)
+        userPackageManager.addOnPermissionsChangeListener(onPermissionsChangedListener)
         update()
     }
 
     override fun onInactive() {
-        packageManager.removeOnPermissionsChangeListener(onPermissionsChangedListener)
+        userPackageManager.removeOnPermissionsChangeListener(onPermissionsChangedListener)
     }
 
     private fun update() {
@@ -69,12 +69,10 @@
                 return
             }
             val labels = getDisplayLabels(additionalGrantedPermissionCount, grantedGroupLabels)
-            val summary = when {
-                labels.isEmpty() -> {
-                    context.getString(R.string.runtime_permissions_summary_no_permissions_granted)
-                }
-
-                else -> ListFormatter.getInstance().format(labels)
+            val summary = if (labels.isNotEmpty()) {
+                ListFormatter.getInstance().format(labels)
+            } else {
+                context.getString(R.string.runtime_permissions_summary_no_permissions_granted)
             }
             postValue(AppPermissionSummaryState(summary = summary, enabled = true))
         }
diff --git a/src/com/android/settings/users/UserSettings.java b/src/com/android/settings/users/UserSettings.java
index d883587..b66e2af 100644
--- a/src/com/android/settings/users/UserSettings.java
+++ b/src/com/android/settings/users/UserSettings.java
@@ -1582,6 +1582,7 @@
             openUserDetails(userInfo, false);
             return true;
         } else if (pref == mAddUser) {
+            mMetricsFeatureProvider.action(getActivity(), SettingsEnums.ACTION_USER_ADD);
             // If we allow both types, show a picker, otherwise directly go to
             // flow for full user.
             if (mUserCaps.mCanAddRestrictedProfile) {
diff --git a/tests/robotests/src/com/android/settings/connecteddevice/stylus/StylusDevicesControllerTest.java b/tests/robotests/src/com/android/settings/connecteddevice/stylus/StylusDevicesControllerTest.java
index f704f2d..b1ca911 100644
--- a/tests/robotests/src/com/android/settings/connecteddevice/stylus/StylusDevicesControllerTest.java
+++ b/tests/robotests/src/com/android/settings/connecteddevice/stylus/StylusDevicesControllerTest.java
@@ -32,6 +32,7 @@
 import android.content.pm.PackageManager;
 import android.os.UserHandle;
 import android.provider.Settings;
+import android.provider.Settings.Secure;
 import android.view.InputDevice;
 import android.view.inputmethod.InputMethodManager;
 
@@ -227,6 +228,42 @@
                 Settings.Global.STYLUS_HANDWRITING_ENABLED, -1)).isEqualTo(1);
     }
 
+    @Test
+    public void buttonsPreference_checkedWhenFlagTrue() {
+        Settings.Secure.putInt(mContext.getContentResolver(),
+                Settings.Secure.STYLUS_BUTTONS_DISABLED, 1);
+
+        showScreen(mController);
+        SwitchPreference buttonsPref = (SwitchPreference) mPreferenceContainer.getPreference(2);
+
+        assertThat(buttonsPref.isChecked()).isEqualTo(true);
+    }
+
+    @Test
+    public void buttonsPreference_uncheckedWhenFlagFalse() {
+        Settings.Secure.putInt(mContext.getContentResolver(),
+                Settings.Secure.STYLUS_BUTTONS_DISABLED, 0);
+
+        showScreen(mController);
+        SwitchPreference buttonsPref = (SwitchPreference) mPreferenceContainer.getPreference(2);
+
+        assertThat(buttonsPref.isChecked()).isEqualTo(false);
+    }
+
+    @Test
+    public void buttonsPreference_updatesFlagOnClick() {
+        Settings.Secure.putInt(mContext.getContentResolver(),
+                Settings.Secure.STYLUS_BUTTONS_DISABLED, 1);
+        showScreen(mController);
+        SwitchPreference buttonsPref = (SwitchPreference) mPreferenceContainer.getPreference(2);
+
+        buttonsPref.performClick();
+
+        assertThat(buttonsPref.isChecked()).isEqualTo(false);
+        assertThat(Settings.Secure.getInt(mContext.getContentResolver(),
+                Secure.STYLUS_BUTTONS_DISABLED, -1)).isEqualTo(0);
+    }
+
     private void showScreen(StylusDevicesController controller) {
         controller.displayPreference(mScreen);
     }
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/tips/DockDefenderTipTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/tips/DockDefenderTipTest.java
index d917d89..69d5477 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/tips/DockDefenderTipTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/tips/DockDefenderTipTest.java
@@ -109,12 +109,22 @@
     }
 
     @Test
-    public void testGetIconId() {
-        assertThat(mDockDefenderTipFutureBypass.getIconId()).isEqualTo(
+    public void testGetIconId_dockDefenderActive_getProtectedIcon() {
+        assertThat(mDockDefenderTipActive.getIconId()).isEqualTo(
                 R.drawable.ic_battery_status_protected_24dp);
     }
 
     @Test
+    public void testGetIconId_dockDefenderNotActive_getUntriggeredIcon() {
+        assertThat(mDockDefenderTipFutureBypass.getIconId()).isEqualTo(
+                R.drawable.ic_battery_dock_defender_untriggered_24dp);
+        assertThat(mDockDefenderTipTemporarilyBypassed.getIconId()).isEqualTo(
+                R.drawable.ic_battery_dock_defender_untriggered_24dp);
+        assertThat(mDockDefenderTipDisabled.getIconId()).isEqualTo(
+                R.drawable.ic_battery_dock_defender_untriggered_24dp);
+    }
+
+    @Test
     public void testUpdateState() {
         mDockDefenderTipTemporarilyBypassed.updateState(mDockDefenderTipDisabled);
 
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryChartPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryChartPreferenceControllerTest.java
index 42eb1c0..95e3bad 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryChartPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryChartPreferenceControllerTest.java
@@ -19,7 +19,9 @@
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.mockito.ArgumentMatchers.anyFloat;
+import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.any;
 import static org.mockito.Mockito.atLeast;
 import static org.mockito.Mockito.atLeastOnce;
@@ -30,7 +32,9 @@
 
 import android.content.ContentValues;
 import android.content.Context;
+import android.content.Intent;
 import android.content.res.Resources;
+import android.os.BatteryManager;
 import android.os.Bundle;
 import android.os.LocaleList;
 import android.text.format.DateUtils;
@@ -58,6 +62,8 @@
 @RunWith(RobolectricTestRunner.class)
 public final class BatteryChartPreferenceControllerTest {
     @Mock
+    private Intent mIntent;
+    @Mock
     private SettingsActivity mSettingsActivity;
     @Mock
     private BatteryHistEntry mBatteryHistEntry;
@@ -90,6 +96,9 @@
                 .when(mFeatureFactory.powerUsageFeatureProvider)
                 .getHideApplicationEntries(mContext);
         doReturn(mLayoutParams).when(mDailyChartView).getLayoutParams();
+        doReturn(mIntent).when(mContext).registerReceiver(any(), any());
+        doReturn(100).when(mIntent).getIntExtra(eq(BatteryManager.EXTRA_SCALE), anyInt());
+        doReturn(66).when(mIntent).getIntExtra(eq(BatteryManager.EXTRA_LEVEL), anyInt());
         setupHourlyChartViewAnimationMock();
         mBatteryChartPreferenceController = createController();
         mBatteryChartPreferenceController.mPrefContext = mContext;
@@ -144,10 +153,11 @@
         // Ignore fast refresh ui from the data processor callback.
         verify(mHourlyChartView, atLeast(0)).setViewModel(null);
         verify(mHourlyChartView, atLeastOnce()).setViewModel(new BatteryChartViewModel(
-                List.of(100, 97, 95),
+                List.of(100, 97, 95, 66),
                 List.of(1619251200000L /* 8 AM */,
                         1619258400000L /* 10 AM */,
-                        1619265600000L /* 12 PM */),
+                        1619265600000L /* 12 PM */,
+                        1619272800000L /* 2 PM */),
                 BatteryChartViewModel.AxisLabelPosition.BETWEEN_TRAPEZOIDS,
                 mBatteryChartPreferenceController.mHourlyChartLabelTextGenerator));
     }
@@ -159,12 +169,12 @@
         setupHourlyChartViewAnimationMock();
 
         BatteryChartViewModel expectedDailyViewModel = new BatteryChartViewModel(
-                List.of(100, 83, 59, 41),
+                List.of(100, 83, 59, 66),
                 // "Sat", "Sun", "Mon", "Mon"
                 List.of(1619251200000L /* Sat */,
                         1619308800000L /* Sun */,
                         1619395200000L /* Mon */,
-                        1619460000000L /* Mon */),
+                        1619467200000L /* Mon */),
                 BatteryChartViewModel.AxisLabelPosition.CENTER_OF_TRAPEZOIDS,
                 mBatteryChartPreferenceController.mDailyChartLabelTextGenerator);
 
@@ -244,7 +254,7 @@
         expectedDailyViewModel.setSelectedIndex(2);
         verify(mDailyChartView).setViewModel(expectedDailyViewModel);
         verify(mHourlyChartView).setViewModel(new BatteryChartViewModel(
-                List.of(59, 57, 55, 53, 51, 49, 47, 45, 43, 41),
+                List.of(59, 57, 55, 53, 51, 49, 47, 45, 43, 41, 66),
                 List.of(1619395200000L /* 12 AM */,
                         1619402400000L /* 2 AM */,
                         1619409600000L /* 4 AM */,
@@ -254,9 +264,11 @@
                         1619438400000L /* 12 PM */,
                         1619445600000L /* 2 PM */,
                         1619452800000L /* 4 PM */,
-                        1619460000000L /* 6 PM */),
+                        1619460000000L /* 6 PM */,
+                        1619467200000L /* 8 PM */),
                 BatteryChartViewModel.AxisLabelPosition.BETWEEN_TRAPEZOIDS,
                 mBatteryChartPreferenceController.mHourlyChartLabelTextGenerator));
+
     }
 
     @Test
@@ -364,7 +376,7 @@
         final int totalHour = BatteryChartPreferenceController.getTotalHours(batteryLevelData);
 
         // Only calculate the even hours.
-        assertThat(totalHour).isEqualTo(58);
+        assertThat(totalHour).isEqualTo(60);
     }
 
     private static Long generateTimestamp(int index) {
@@ -395,6 +407,8 @@
             entryMap.put("fake_entry_key" + index, entry);
             batteryHistoryMap.put(generateTimestamp(index), entryMap);
         }
+        DataProcessor.sFakeCurrentTimeMillis =
+                generateTimestamp(numOfHours - 1) + DateUtils.MINUTE_IN_MILLIS;
         return batteryHistoryMap;
     }
 
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/DataProcessorTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/DataProcessorTest.java
index 0926d14..ce6a917 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/DataProcessorTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/DataProcessorTest.java
@@ -18,7 +18,10 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.anyInt;
 import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.eq;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.verify;
@@ -27,7 +30,9 @@
 import android.app.settings.SettingsEnums;
 import android.content.ContentValues;
 import android.content.Context;
+import android.content.Intent;
 import android.os.BatteryConsumer;
+import android.os.BatteryManager;
 import android.os.BatteryUsageStats;
 import android.text.format.DateUtils;
 
@@ -63,6 +68,7 @@
     private MetricsFeatureProvider mMetricsFeatureProvider;
     private PowerUsageFeatureProvider mPowerUsageFeatureProvider;
 
+    @Mock private Intent mIntent;
     @Mock private BatteryUsageStats mBatteryUsageStats;
     @Mock private BatteryEntry mMockBatteryEntry1;
     @Mock private BatteryEntry mMockBatteryEntry2;
@@ -79,6 +85,10 @@
         mFeatureFactory = FakeFeatureFactory.setupForTest();
         mMetricsFeatureProvider = mFeatureFactory.metricsFeatureProvider;
         mPowerUsageFeatureProvider = mFeatureFactory.powerUsageFeatureProvider;
+
+        doReturn(mIntent).when(mContext).registerReceiver(any(), any());
+        doReturn(100).when(mIntent).getIntExtra(eq(BatteryManager.EXTRA_SCALE), anyInt());
+        doReturn(66).when(mIntent).getIntExtra(eq(BatteryManager.EXTRA_LEVEL), anyInt());
     }
 
     @Test
@@ -100,11 +110,15 @@
 
     @Test
     public void getBatteryLevelData_notEnoughData_returnNull() {
-        // The timestamps are within 1 hour.
-        final long[] timestamps = {1000000L, 2000000L, 3000000L};
+        // The timestamps and the current time are within half hour before an even hour.
+        final long[] timestamps = {
+                DateUtils.HOUR_IN_MILLIS * 2 - 300L,
+                DateUtils.HOUR_IN_MILLIS * 2 - 200L,
+                DateUtils.HOUR_IN_MILLIS * 2 - 100L};
         final int[] levels = {100, 99, 98};
         final Map<Long, Map<String, BatteryHistEntry>> batteryHistoryMap =
                 createHistoryMap(timestamps, levels);
+        DataProcessor.sFakeCurrentTimeMillis = timestamps[timestamps.length - 1];
 
         assertThat(DataProcessor.getBatteryLevelData(
                 mContext, /*handler=*/ null, batteryHistoryMap, /*asyncResponseDelegate=*/ null))
@@ -117,11 +131,12 @@
 
     @Test
     public void getBatteryLevelData_returnExpectedResult() {
-        // Timezone GMT+8: 2022-01-01 00:00:00, 2022-01-01 01:00:00, 2022-01-01 02:00:00
-        final long[] timestamps = {1640966400000L, 1640970000000L, 1640973600000L};
-        final int[] levels = {100, 99, 98};
+        // Timezone GMT+8: 2022-01-01 00:00:00, 2022-01-01 01:00:00
+        final long[] timestamps = {1640966400000L, 1640970000000L};
+        final int[] levels = {100, 99};
         final Map<Long, Map<String, BatteryHistEntry>> batteryHistoryMap =
                 createHistoryMap(timestamps, levels);
+        DataProcessor.sFakeCurrentTimeMillis = timestamps[timestamps.length - 1];
 
         final BatteryLevelData resultData =
                 DataProcessor.getBatteryLevelData(
@@ -130,8 +145,10 @@
                         batteryHistoryMap,
                         /*asyncResponseDelegate=*/ null);
 
-        final List<Long> expectedDailyTimestamps = List.of(timestamps[0], timestamps[2]);
-        final List<Integer> expectedDailyLevels = List.of(levels[0], levels[2]);
+        final List<Long> expectedDailyTimestamps = List.of(
+                1640966400000L,  // 2022-01-01 00:00:00
+                1640973600000L); // 2022-01-01 02:00:00
+        final List<Integer> expectedDailyLevels = List.of(100, 66);
         final List<List<Long>> expectedHourlyTimestamps = List.of(expectedDailyTimestamps);
         final List<List<Integer>> expectedHourlyLevels = List.of(expectedDailyLevels);
         verifyExpectedBatteryLevelData(
@@ -162,6 +179,7 @@
         final int[] levels = {100, 94, 90, 82, 50};
         final Map<Long, Map<String, BatteryHistEntry>> batteryHistoryMap =
                 createHistoryMap(timestamps, levels);
+        DataProcessor.sFakeCurrentTimeMillis = timestamps[timestamps.length - 1];
 
         final Map<Long, Map<String, BatteryHistEntry>> resultMap =
                 DataProcessor.getHistoryMapWithExpectedTimestamps(mContext, batteryHistoryMap);
@@ -172,14 +190,20 @@
                 1640970000000L, // 2022-01-01 01:00:00
                 1640973600000L, // 2022-01-01 02:00:00
                 1640977200000L, // 2022-01-01 03:00:00
-                1640980800000L  // 2022-01-01 04:00:00
+                1640980800000L, // 2022-01-01 04:00:00
+                1640984400000L, // 2022-01-01 05:00:00
+                1640988000000L  // 2022-01-01 06:00:00
         };
-        final int[] expectedLevels = {100, 94, 90, 84, 56};
+        final int[] expectedLevels = {100, 94, 90, 84, 56, 98, 98};
         assertThat(resultMap).hasSize(expectedLevels.length);
-        for (int index = 0; index < expectedLevels.length; index++) {
+        for (int index = 0; index < 5; index++) {
             assertThat(resultMap.get(expectedTimestamps[index]).get(FAKE_ENTRY_KEY).mBatteryLevel)
                     .isEqualTo(expectedLevels[index]);
         }
+        for (int index = 5; index < 7; index++) {
+            assertThat(resultMap.get(expectedTimestamps[index]).containsKey(
+                    DataProcessor.CURRENT_TIME_BATTERY_HISTORY_PLACEHOLDER)).isTrue();
+        }
     }
 
     @Test
@@ -188,6 +212,7 @@
         final int[] levels = {100};
         final Map<Long, Map<String, BatteryHistEntry>> batteryHistoryMap =
                 createHistoryMap(timestamps, levels);
+        DataProcessor.sFakeCurrentTimeMillis = timestamps[timestamps.length - 1];
 
         assertThat(
                 DataProcessor.getLevelDataThroughProcessedHistoryMap(mContext, batteryHistoryMap))
@@ -207,6 +232,7 @@
         final int[] levels = {100, 94, 90, 82, 50};
         final Map<Long, Map<String, BatteryHistEntry>> batteryHistoryMap =
                 createHistoryMap(timestamps, levels);
+        DataProcessor.sFakeCurrentTimeMillis = timestamps[timestamps.length - 1];
 
         final BatteryLevelData resultData =
                 DataProcessor.getLevelDataThroughProcessedHistoryMap(mContext, batteryHistoryMap);
@@ -239,6 +265,7 @@
         final int[] levels = {100, 94, 90, 82};
         final Map<Long, Map<String, BatteryHistEntry>> batteryHistoryMap =
                 createHistoryMap(timestamps, levels);
+        DataProcessor.sFakeCurrentTimeMillis = timestamps[timestamps.length - 1];
 
         final BatteryLevelData resultData =
                 DataProcessor.getLevelDataThroughProcessedHistoryMap(mContext, batteryHistoryMap);
@@ -290,8 +317,8 @@
 
     @Test
     public void getTimestampSlots_emptyRawList_returnEmptyList() {
-        final List<Long> resultList =
-                DataProcessor.getTimestampSlots(new ArrayList<>());
+        final List<Long> resultList = DataProcessor.getTimestampSlots(
+                new ArrayList<>(), 1641038400000L); // 2022-01-01 20:00:00
         assertThat(resultList).isEmpty();
     }
 
@@ -305,7 +332,7 @@
         final Calendar expectedStartCalendar = Calendar.getInstance();
         expectedStartCalendar.set(2022, 6, 5, 6, 0, 0); // 2022-07-05 06:00:00
         final Calendar expectedEndCalendar = Calendar.getInstance();
-        expectedEndCalendar.set(2022, 6, 5, 22, 0, 0); // 2022-07-05 22:00:00
+        expectedEndCalendar.set(2022, 6, 6, 0, 0, 0); // 2022-07-05 22:00:00
         verifyExpectedTimestampSlots(
                 startCalendar, endCalendar, expectedStartCalendar, expectedEndCalendar);
     }
@@ -320,7 +347,7 @@
         final Calendar expectedStartCalendar = Calendar.getInstance();
         expectedStartCalendar.set(2022, 6, 5, 6, 00, 00); // 2022-07-05 06:00:00
         final Calendar expectedEndCalendar = Calendar.getInstance();
-        expectedEndCalendar.set(2022, 6, 6, 20, 00, 00); // 2022-07-06 20:00:00
+        expectedEndCalendar.set(2022, 6, 6, 22, 00, 00); // 2022-07-06 20:00:00
         verifyExpectedTimestampSlots(
                 startCalendar, endCalendar, expectedStartCalendar, expectedEndCalendar);
     }
@@ -1110,8 +1137,8 @@
 
     @Test
     public void generateBatteryDiffData_emptyBatteryEntryList_returnNull() {
-        assertThat(DataProcessor.generateBatteryDiffData(
-                mContext, null, mBatteryUsageStats)).isNull();
+        assertThat(DataProcessor.generateBatteryDiffData(mContext,
+                DataProcessor.convertToBatteryHistEntry(null, mBatteryUsageStats))).isNull();
     }
 
     @Test
@@ -1161,8 +1188,8 @@
         doReturn(BatteryConsumer.POWER_COMPONENT_CAMERA)
                 .when(mMockBatteryEntry4).getPowerComponentId();
 
-        final BatteryDiffData batteryDiffData = DataProcessor.generateBatteryDiffData(
-                mContext, batteryEntryList, mBatteryUsageStats);
+        final BatteryDiffData batteryDiffData = DataProcessor.generateBatteryDiffData(mContext,
+                DataProcessor.convertToBatteryHistEntry(batteryEntryList, mBatteryUsageStats));
 
         assertBatteryDiffEntry(
                 batteryDiffData.getAppDiffEntryList().get(0), 0, /*uid=*/ 2L,
@@ -1284,16 +1311,15 @@
 
     private static void verifyExpectedTimestampSlots(
             final Calendar start,
-            final Calendar end,
+            final Calendar current,
             final Calendar expectedStart,
             final Calendar expectedEnd) {
         expectedStart.set(Calendar.MILLISECOND, 0);
         expectedEnd.set(Calendar.MILLISECOND, 0);
         final ArrayList<Long> timestampSlots = new ArrayList<>();
         timestampSlots.add(start.getTimeInMillis());
-        timestampSlots.add(end.getTimeInMillis());
         final List<Long> resultList =
-                DataProcessor.getTimestampSlots(timestampSlots);
+                DataProcessor.getTimestampSlots(timestampSlots, current.getTimeInMillis());
 
         for (int index = 0; index < resultList.size(); index++) {
             final long expectedTimestamp =
diff --git a/tests/robotests/src/com/android/settings/network/BluetoothWiFiResetPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/network/BluetoothWiFiResetPreferenceControllerTest.java
new file mode 100644
index 0000000..4714afe
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/network/BluetoothWiFiResetPreferenceControllerTest.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing `permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.network;
+
+import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Mockito.spy;
+
+import android.content.Context;
+
+import com.android.settings.R;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.shadows.ShadowToast;
+
+@RunWith(RobolectricTestRunner.class)
+public class BluetoothWiFiResetPreferenceControllerTest {
+
+    private static final String PREFERENCE_KEY = "network_reset_bluetooth_wifi_pref";
+
+    private Context mContext;
+    private BluetoothWiFiResetPreferenceController mTarget;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        mContext = spy(RuntimeEnvironment.application);
+
+        mTarget = spy(new BluetoothWiFiResetPreferenceController(mContext, PREFERENCE_KEY));
+    }
+
+    @Test
+    public void endOfReset_toastMessage_whenSuccess() {
+        mTarget.endOfReset(null);
+
+        assertThat(ShadowToast.getTextOfLatestToast()).isEqualTo(
+                mContext.getString(R.string.reset_bluetooth_wifi_complete_toast));
+    }
+
+}
diff --git a/tests/robotests/src/com/android/settings/spa/app/appinfo/AppPermissionSummaryTest.kt b/tests/robotests/src/com/android/settings/spa/app/appinfo/AppPermissionSummaryTest.kt
deleted file mode 100644
index ce1c1b7..0000000
--- a/tests/robotests/src/com/android/settings/spa/app/appinfo/AppPermissionSummaryTest.kt
+++ /dev/null
@@ -1,185 +0,0 @@
-/*
- * Copyright (C) 2022 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.spa.app.appinfo
-
-import android.content.Context
-import android.content.pm.ApplicationInfo
-import android.content.pm.PackageManager
-import androidx.lifecycle.LiveData
-import androidx.lifecycle.Observer
-import androidx.test.core.app.ApplicationProvider
-import com.android.settings.R
-import com.android.settingslib.applications.PermissionsSummaryHelper
-import com.android.settingslib.applications.PermissionsSummaryHelper.PermissionsResultCallback
-import com.google.common.truth.Truth.assertThat
-import java.util.concurrent.CountDownLatch
-import java.util.concurrent.TimeUnit
-import java.util.concurrent.TimeoutException
-import org.junit.Before
-import org.junit.Rule
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.mockito.Mock
-import org.mockito.Mockito.any
-import org.mockito.Mockito.doReturn
-import org.mockito.Mockito.eq
-import org.mockito.Mockito.never
-import org.mockito.Mockito.verify
-import org.mockito.Spy
-import org.mockito.junit.MockitoJUnit
-import org.mockito.junit.MockitoRule
-import org.robolectric.RobolectricTestRunner
-import org.robolectric.annotation.Config
-import org.robolectric.annotation.Implementation
-import org.robolectric.annotation.Implements
-import org.mockito.Mockito.`when` as whenever
-
-@RunWith(RobolectricTestRunner::class)
-@Config(shadows = [ShadowPermissionsSummaryHelper::class])
-class AppPermissionSummaryTest {
-
-    @JvmField
-    @Rule
-    val mockito: MockitoRule = MockitoJUnit.rule()
-
-    @Spy
-    private var context: Context = ApplicationProvider.getApplicationContext()
-
-    @Mock
-    private lateinit var packageManager: PackageManager
-
-    private lateinit var summaryLiveData: AppPermissionSummaryLiveData
-
-    @Before
-    fun setUp() {
-        doReturn(context).`when`(context).createContextAsUser(any(), eq(0))
-        whenever(context.packageManager).thenReturn(packageManager)
-
-        val app = ApplicationInfo().apply {
-            packageName = PACKAGE_NAME
-        }
-        summaryLiveData = AppPermissionSummaryLiveData(context, app)
-    }
-
-    @Test
-    fun permissionsChangeListener() {
-        summaryLiveData.getOrAwaitValue {
-            verify(packageManager).addOnPermissionsChangeListener(any())
-            verify(packageManager, never()).removeOnPermissionsChangeListener(any())
-        }
-        verify(packageManager).removeOnPermissionsChangeListener(any())
-    }
-
-    @Test
-    fun summary_noPermissionsRequested() {
-        ShadowPermissionsSummaryHelper.requestedPermissionCount = 0
-
-        val (summary, enabled) = summaryLiveData.getOrAwaitValue()!!
-
-        assertThat(summary).isEqualTo(
-            context.getString(R.string.runtime_permissions_summary_no_permissions_requested)
-        )
-        assertThat(enabled).isFalse()
-    }
-
-    @Test
-    fun summary_noPermissionsGranted() {
-        ShadowPermissionsSummaryHelper.requestedPermissionCount = 1
-        ShadowPermissionsSummaryHelper.grantedGroupLabels = emptyList()
-
-        val (summary, enabled) = summaryLiveData.getOrAwaitValue()!!
-
-        assertThat(summary).isEqualTo(
-            context.getString(R.string.runtime_permissions_summary_no_permissions_granted)
-        )
-        assertThat(enabled).isTrue()
-    }
-
-    @Test
-    fun onPermissionSummaryResult_hasRuntimePermission_shouldSetPermissionAsSummary() {
-        ShadowPermissionsSummaryHelper.requestedPermissionCount = 1
-        ShadowPermissionsSummaryHelper.grantedGroupLabels = listOf(PERMISSION)
-
-        val (summary, enabled) = summaryLiveData.getOrAwaitValue()!!
-
-        assertThat(summary).isEqualTo(PERMISSION)
-        assertThat(enabled).isTrue()
-    }
-
-    @Test
-    fun onPermissionSummaryResult_hasAdditionalPermission_shouldSetAdditionalSummary() {
-        ShadowPermissionsSummaryHelper.requestedPermissionCount = 5
-        ShadowPermissionsSummaryHelper.additionalGrantedPermissionCount = 2
-        ShadowPermissionsSummaryHelper.grantedGroupLabels = listOf(PERMISSION)
-
-        val (summary, enabled) = summaryLiveData.getOrAwaitValue()!!
-
-        assertThat(summary).isEqualTo("Storage and 2 additional permissions")
-        assertThat(enabled).isTrue()
-    }
-
-    companion object {
-        private const val PACKAGE_NAME = "packageName"
-        private const val PERMISSION = "Storage"
-    }
-}
-
-@Implements(PermissionsSummaryHelper::class)
-private object ShadowPermissionsSummaryHelper {
-    var requestedPermissionCount = 0
-    var additionalGrantedPermissionCount = 0
-    var grantedGroupLabels: List<CharSequence> = emptyList()
-
-    @Implementation
-    @JvmStatic
-    @Suppress("UNUSED_PARAMETER")
-    fun getPermissionSummary(context: Context, pkg: String, callback: PermissionsResultCallback) {
-        callback.onPermissionSummaryResult(
-            requestedPermissionCount,
-            additionalGrantedPermissionCount,
-            grantedGroupLabels,
-        )
-    }
-}
-
-private fun <T> LiveData<T>.getOrAwaitValue(
-    time: Long = 2,
-    timeUnit: TimeUnit = TimeUnit.SECONDS,
-    afterObserve: () -> Unit = {},
-): T? {
-    var data: T? = null
-    val latch = CountDownLatch(1)
-    val observer = Observer<T> { o ->
-        data = o
-        latch.countDown()
-    }
-    this.observeForever(observer)
-
-    afterObserve()
-
-    try {
-        // Don't wait indefinitely if the LiveData is not set.
-        if (!latch.await(time, timeUnit)) {
-            throw TimeoutException("LiveData value was never set.")
-        }
-
-    } finally {
-        this.removeObserver(observer)
-    }
-
-    return data
-}
diff --git a/tests/spa_unit/src/com/android/settings/spa/app/appinfo/AppLocalePreferenceTest.kt b/tests/spa_unit/src/com/android/settings/spa/app/appinfo/AppLocalePreferenceTest.kt
index b4545d4..82c9ee9 100644
--- a/tests/spa_unit/src/com/android/settings/spa/app/appinfo/AppLocalePreferenceTest.kt
+++ b/tests/spa_unit/src/com/android/settings/spa/app/appinfo/AppLocalePreferenceTest.kt
@@ -22,11 +22,9 @@
 import android.content.pm.PackageManager
 import androidx.compose.runtime.CompositionLocalProvider
 import androidx.compose.ui.platform.LocalContext
-import androidx.compose.ui.test.assertIsDisplayed
 import androidx.compose.ui.test.assertIsNotDisplayed
 import androidx.compose.ui.test.hasText
 import androidx.compose.ui.test.junit4.createComposeRule
-import androidx.compose.ui.test.onNodeWithText
 import androidx.compose.ui.test.onRoot
 import androidx.compose.ui.test.performClick
 import androidx.test.core.app.ApplicationProvider
@@ -47,7 +45,6 @@
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.mockito.ArgumentCaptor
-import org.mockito.ArgumentMatchers
 import org.mockito.Mock
 import org.mockito.Mockito.any
 import org.mockito.Mockito.doNothing
@@ -80,9 +77,8 @@
             .strictness(Strictness.LENIENT)
             .startMocking()
         whenever(context.packageManager).thenReturn(packageManager)
-        whenever(AppLocaleUtil.canDisplayLocaleUi(any(), ArgumentMatchers.eq(APP), any()))
-                .thenReturn(true)
-        whenever(AppLocaleDetails.getSummary(any(), ArgumentMatchers.eq(APP))).thenReturn(SUMMARY)
+        whenever(AppLocaleUtil.canDisplayLocaleUi(any(), eq(APP), any())).thenReturn(true)
+        whenever(AppLocaleDetails.getSummary(any(), eq(APP))).thenReturn(SUMMARY)
     }
 
     @After
@@ -92,8 +88,7 @@
 
     @Test
     fun whenCanNotDisplayLocalUi_notDisplayed() {
-        whenever(AppLocaleUtil.canDisplayLocaleUi(any(), ArgumentMatchers.eq(APP), any()))
-                .thenReturn(false)
+        whenever(AppLocaleUtil.canDisplayLocaleUi(any(), eq(APP), any())).thenReturn(false)
 
         setContent()
 
@@ -104,8 +99,9 @@
     fun whenCanDisplayLocalUi_displayed() {
         setContent()
 
-        composeTestRule.onNodeWithText(context.getString(R.string.app_locale_preference_title))
-            .assertIsDisplayed()
+        composeTestRule.waitUntilExists(
+            hasText(context.getString(R.string.app_locale_preference_title))
+        )
         composeTestRule.waitUntilExists(hasText(SUMMARY))
     }
 
diff --git a/tests/spa_unit/src/com/android/settings/spa/app/appinfo/AppPermissionSummaryTest.kt b/tests/spa_unit/src/com/android/settings/spa/app/appinfo/AppPermissionSummaryTest.kt
new file mode 100644
index 0000000..c82da1a
--- /dev/null
+++ b/tests/spa_unit/src/com/android/settings/spa/app/appinfo/AppPermissionSummaryTest.kt
@@ -0,0 +1,167 @@
+/*
+ * Copyright (C) 2022 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.spa.app.appinfo
+
+import android.content.Context
+import android.content.pm.ApplicationInfo
+import android.content.pm.PackageManager
+import androidx.arch.core.executor.testing.InstantTaskExecutorRule
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession
+import com.android.settings.R
+import com.android.settings.testutils.mockAsUser
+import com.android.settingslib.applications.PermissionsSummaryHelper
+import com.android.settingslib.applications.PermissionsSummaryHelper.PermissionsResultCallback
+import com.android.settingslib.spa.testutils.getOrAwaitValue
+import com.google.common.truth.Truth.assertThat
+import org.junit.After
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.Mockito.any
+import org.mockito.Mockito.doReturn
+import org.mockito.Mockito.eq
+import org.mockito.Mockito.never
+import org.mockito.Mockito.verify
+import org.mockito.MockitoSession
+import org.mockito.Spy
+import org.mockito.quality.Strictness
+import org.mockito.Mockito.`when` as whenever
+
+@RunWith(AndroidJUnit4::class)
+class AppPermissionSummaryTest {
+    @get:Rule
+    val instantTaskExecutorRule = InstantTaskExecutorRule()
+
+    private lateinit var mockSession: MockitoSession
+
+    @Spy
+    private var context: Context = ApplicationProvider.getApplicationContext()
+
+    @Mock
+    private lateinit var packageManager: PackageManager
+
+    private lateinit var summaryLiveData: AppPermissionSummaryLiveData
+
+    @Before
+    fun setUp() {
+        mockSession = mockitoSession()
+            .initMocks(this)
+            .mockStatic(PermissionsSummaryHelper::class.java)
+            .strictness(Strictness.LENIENT)
+            .startMocking()
+        context.mockAsUser()
+        whenever(context.packageManager).thenReturn(packageManager)
+
+        summaryLiveData = AppPermissionSummaryLiveData(context, APP)
+    }
+
+    private fun mockGetPermissionSummary(
+        requestedPermissionCount: Int = 0,
+        additionalGrantedPermissionCount: Int = 0,
+        grantedGroupLabels: List<CharSequence> = emptyList(),
+    ) {
+        whenever(PermissionsSummaryHelper.getPermissionSummary(any(), eq(PACKAGE_NAME), any()))
+            .thenAnswer {
+                val callback = it.arguments[2] as PermissionsResultCallback
+                callback.onPermissionSummaryResult(
+                    requestedPermissionCount,
+                    additionalGrantedPermissionCount,
+                    grantedGroupLabels,
+                )
+            }
+    }
+
+    @After
+    fun tearDown() {
+        mockSession.finishMocking()
+    }
+
+    @Test
+    fun permissionsChangeListener() {
+        mockGetPermissionSummary()
+
+        summaryLiveData.getOrAwaitValue {
+            verify(packageManager).addOnPermissionsChangeListener(any())
+            verify(packageManager, never()).removeOnPermissionsChangeListener(any())
+        }
+
+        verify(packageManager).removeOnPermissionsChangeListener(any())
+    }
+
+    @Test
+    fun summary_noPermissionsRequested() {
+        mockGetPermissionSummary(requestedPermissionCount = 0)
+
+        val (summary, enabled) = summaryLiveData.getOrAwaitValue()!!
+
+        assertThat(summary).isEqualTo(
+            context.getString(R.string.runtime_permissions_summary_no_permissions_requested)
+        )
+        assertThat(enabled).isFalse()
+    }
+
+    @Test
+    fun summary_noPermissionsGranted() {
+        mockGetPermissionSummary(requestedPermissionCount = 1, grantedGroupLabels = emptyList())
+
+        val (summary, enabled) = summaryLiveData.getOrAwaitValue()!!
+
+        assertThat(summary).isEqualTo(
+            context.getString(R.string.runtime_permissions_summary_no_permissions_granted)
+        )
+        assertThat(enabled).isTrue()
+    }
+
+    @Test
+    fun onPermissionSummaryResult_hasRuntimePermission_shouldSetPermissionAsSummary() {
+        mockGetPermissionSummary(
+            requestedPermissionCount = 1,
+            grantedGroupLabels = listOf(PERMISSION),
+        )
+
+        val (summary, enabled) = summaryLiveData.getOrAwaitValue()!!
+
+        assertThat(summary).isEqualTo(PERMISSION)
+        assertThat(enabled).isTrue()
+    }
+
+    @Test
+    fun onPermissionSummaryResult_hasAdditionalPermission_shouldSetAdditionalSummary() {
+        mockGetPermissionSummary(
+            requestedPermissionCount = 5,
+            additionalGrantedPermissionCount = 2,
+            grantedGroupLabels = listOf(PERMISSION),
+        )
+
+        val (summary, enabled) = summaryLiveData.getOrAwaitValue()!!
+
+        assertThat(summary).isEqualTo("Storage and 2 additional permissions")
+        assertThat(enabled).isTrue()
+    }
+
+    private companion object {
+        const val PACKAGE_NAME = "packageName"
+        const val PERMISSION = "Storage"
+        val APP = ApplicationInfo().apply {
+            packageName = PACKAGE_NAME
+        }
+    }
+}