Merge "Import translations. DO NOT MERGE ANYWHERE" into udc-dev
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 433d8b6..6aad2af 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -1358,7 +1358,7 @@
         <activity
             android:name="Settings$SmartAutoRotateSettingsActivity"
             android:label="@string/accelerometer_title"
-            android:icon="@drawable/ic_screen_rotation_24dp"
+            android:icon="@drawable/ic_screen_rotation"
             android:exported="true">
             <intent-filter android:priority="1">
                 <action android:name="android.settings.AUTO_ROTATE_SETTINGS" />
@@ -2955,13 +2955,6 @@
             </intent-filter>
         </activity>
 
-        <activity android:name=".bluetooth.RequestPermissionHelperActivity"
-                  android:label="@string/bluetooth_pairing_request"
-                  android:excludeFromRecents="true"
-                  android:permission="android.permission.BLUETOOTH_CONNECT"
-                  android:theme="@*android:style/Theme.DeviceDefault.Dialog.Alert.DayNight">
-        </activity>
-
         <service android:name=".bluetooth.BluetoothPairingService" />
 
         <receiver android:name=".bluetooth.BluetoothPairingRequest"
@@ -4826,6 +4819,22 @@
         </receiver>
 
         <activity
+            android:name=".notetask.shortcut.CreateNoteTaskShortcutActivity"
+            android:enabled="false"
+            android:exported="true"
+            android:excludeFromRecents="true"
+            android:resizeableActivity="false"
+            android:theme="@android:style/Theme.NoDisplay"
+            android:label="@string/note_task_button_label"
+            android:icon="@drawable/ic_note_task_shortcut_widget">
+
+            <intent-filter>
+                <action android:name="android.intent.action.CREATE_SHORTCUT" />
+                <category android:name="android.intent.category.DEFAULT" />
+            </intent-filter>
+        </activity>
+
+        <activity
             android:name="com.android.settings.bluetooth.QrCodeScanModeActivity"
             android:permission="android.permission.BLUETOOTH_CONNECT"
             android:exported="true">
diff --git a/OWNERS b/OWNERS
index 8938b64..6d4f95f 100644
--- a/OWNERS
+++ b/OWNERS
@@ -2,22 +2,18 @@
 android-settings-core-eng+gerrit@google.com
 
 # People who can approve changes for submission
-arcwang@google.com
 cantol@google.com
 chaohuiw@google.com
 chiujason@google.com
-cyl@google.com
+dswliu@google.com
 edgarwang@google.com
-llz@google.com
 millchen@google.com
 songchenxi@google.com
-stanleytfwang@google.com
 sunnyshao@google.com
 yantingyang@google.com
 ykhung@google.com
 
 # Emergency only
-lijun@google.com
 wangqi@google.com
 yanglu@google.com
 
diff --git a/color-check-baseline.xml b/color-check-baseline.xml
index 2fd63fc..509d9ae 100644
--- a/color-check-baseline.xml
+++ b/color-check-baseline.xml
@@ -4437,6 +4437,22 @@
         priority="4"
         summary="Using hardcoded color"
         explanation="Hardcoded color values are bad because theme changes cannot be uniformly applied.Instead use the theme specific colors such as `?android:attr/textColorPrimary` in attributes.&#xA;This ensures that a theme change from a light to a dark theme can be uniformlyapplied across the app."
+        errorLine1="            android:color=&quot;@color/homepage_display_background&quot; />"
+        errorLine2="            ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="res/drawable/ic_screen_rotation.xml"
+            line="24"
+            column="13"/>
+    </issue>
+
+    <issue
+        id="HardCodedColor"
+        severity="Error"
+        message="Avoid using hardcoded color"
+        category="Correctness"
+        priority="4"
+        summary="Using hardcoded color"
+        explanation="Hardcoded color values are bad because theme changes cannot be uniformly applied.Instead use the theme specific colors such as `?android:attr/textColorPrimary` in attributes.&#xA;This ensures that a theme change from a light to a dark theme can be uniformlyapplied across the app."
         errorLine1="    &lt;background android:drawable=&quot;@color/shortcut_background&quot;/>"
         errorLine2="                ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
diff --git a/res-product/values/strings.xml b/res-product/values/strings.xml
index 2f01c47..2a58f45 100644
--- a/res-product/values/strings.xml
+++ b/res-product/values/strings.xml
@@ -96,6 +96,12 @@
     <!-- Introduction detail message shown in face enrollment dialog when asking for parental consent [CHAR LIMIT=NONE]-->
     <string name="security_settings_face_enroll_introduction_consent_message_0" product="device">Allow your child to use their face to unlock their device</string>
     <!-- Introduction detail message shown in face enrollment dialog when asking for parental consent [CHAR LIMIT=NONE]-->
+    <string name="security_settings_face_enroll_introduction_consent_message_0_class3" product="default">Allow your child to use their face to unlock their phone or verify it\u2019s them. This happens when they sign in to apps, approve a purchase, and more.</string>
+    <!-- Introduction detail message shown in face enrollment dialog when asking for parental consent [CHAR LIMIT=NONE]-->
+    <string name="security_settings_face_enroll_introduction_consent_message_0_class3" product="tablet">Allow your child to use their face to unlock their tablet or verify it\u2019s them. This happens when they sign in to apps, approve a purchase, and more.</string>
+    <!-- Introduction detail message shown in face enrollment dialog when asking for parental consent [CHAR LIMIT=NONE]-->
+    <string name="security_settings_face_enroll_introduction_consent_message_0_class3" product="device">Allow your child to use their face to unlock their device or verify it\u2019s them. This happens when they sign in to apps, approve a purchase, and more.</string>
+    <!-- Introduction detail message shown in face enrollment dialog when asking for parental consent [CHAR LIMIT=NONE]-->
     <string name="security_settings_face_enroll_introduction_consent_message" product="default">Using your child\u2019s face to unlock their phone may be less secure than a strong pattern or PIN.</string>
     <!-- Introduction detail message shown in face enrollment dialog when asking for parental consent [CHAR LIMIT=NONE]-->
     <string name="security_settings_face_enroll_introduction_consent_message" product="tablet">Using your child\u2019s face to unlock their tablet may be less secure than a strong pattern or PIN.</string>
diff --git a/res/drawable/ic_check_24dp.xml b/res/drawable/ic_check_24dp.xml
index 9ac8021..0ed6b32 100644
--- a/res/drawable/ic_check_24dp.xml
+++ b/res/drawable/ic_check_24dp.xml
@@ -18,8 +18,8 @@
         android:height="24dp"
         android:viewportWidth="24.0"
         android:viewportHeight="24.0"
-        android:tint="?androidprv:attr/materialColorPrimaryContainer">
+        android:tint="?androidprv:attr/colorAccent">
     <path
         android:pathData="M9,16.17L4.83,12l-1.42,1.41L9,19 21,7l-1.41,-1.41z"
         android:fillColor="@android:color/white"/>
-</vector>
\ No newline at end of file
+</vector>
diff --git a/res/drawable/ic_note_task_shortcut_widget.xml b/res/drawable/ic_note_task_shortcut_widget.xml
new file mode 100644
index 0000000..e37c22a
--- /dev/null
+++ b/res/drawable/ic_note_task_shortcut_widget.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+  ~ Copyright (C) 2023 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:viewportHeight="24"
+    android:viewportWidth="24">
+    <path
+        android:fillAlpha="1"
+        android:fillColor="#636C6F"
+        android:fillType="nonZero"
+        android:pathData="M17.6258,4.96L19.0358,6.37L7.4058,18.01L5.9958,16.6L17.6258,4.96ZM16.1358,3.62L4.1258,15.63L3.0158,19.83C2.9058,20.45 3.3858,21 3.9958,21C4.0558,21 4.1058,21 4.1658,20.99L8.3658,19.88L20.3758,7.86C20.7758,7.46 20.9958,6.93 20.9958,6.37C20.9958,5.81 20.7758,5.28 20.3758,4.88L19.1058,3.61C18.7158,3.22 18.1858,3 17.6258,3C17.0658,3 16.5358,3.22 16.1358,3.62Z" />
+    <path
+        android:fillAlpha="1"
+        android:fillColor="#636C6F"
+        android:fillType="nonZero"
+        android:pathData="M20.1936,15.3369C20.3748,16.3837 19.9151,17.5414 18.8846,18.7597C19.1546,18.872 19.4576,18.9452 19.7724,18.9867C20.0839,19.0278 20.3683,19.0325 20.5749,19.0266C20.6772,19.0236 20.7578,19.0181 20.8101,19.0138C20.8362,19.0116 20.855,19.0097 20.8657,19.0085L20.8754,19.0074L20.875,19.0075C21.4217,18.9385 21.9214,19.325 21.9918,19.8718C22.0624,20.4195 21.6756,20.9208 21.1279,20.9914L21,19.9996C21.1279,20.9914 21.1265,20.9916 21.1265,20.9916L21.1249,20.9918L21.1211,20.9923L21.1107,20.9935L21.0795,20.997C21.0542,20.9998 21.0199,21.0032 20.9775,21.0067C20.8929,21.0138 20.7753,21.0216 20.6323,21.0257C20.3481,21.0339 19.9533,21.0279 19.5109,20.9695C18.873,20.8854 18.0393,20.6793 17.3106,20.1662C16.9605,20.3559 16.5876,20.4952 16.2299,20.6003C15.5742,20.7927 14.8754,20.8968 14.2534,20.9534C13.6801,21.0055 13.4553,21.0037 13.1015,21.0008C13.0689,21.0005 13.0352,21.0002 13,21H12.8594C12.8214,21.0002 12.785,21.0006 12.7504,21.0009C12.6524,21.0019 12.5683,21.0027 12.5,21H12.0562C12.0277,21.0003 12.0054,21.0006 11.9926,21.001L11.9751,21H9L11,19H11.9795C11.9929,18.9997 12.0064,18.9997 12.0199,19H12.4117C12.4534,18.9996 12.4864,18.9995 12.5,19H12.9675C12.977,18.9999 12.9878,18.9999 13,19C13.0446,19.0003 13.0859,19.0007 13.1249,19.0011C13.4259,19.0038 13.591,19.0054 14.0723,18.9616C14.6201,18.9118 15.1795,18.8242 15.6665,18.6813C15.753,18.6559 15.8346,18.6295 15.9114,18.6022C15.0315,17.2981 14.7125,16.1044 15.015,15.0829C15.4095,13.7511 16.6784,13.2418 17.7026,13.2864C18.7262,13.3309 19.954,13.9529 20.1936,15.3369ZM16.9327,15.6508C16.873,15.8523 16.8651,16.3878 17.4697,17.334C18.2007,16.4284 18.2585,15.8839 18.2229,15.6781C18.1939,15.5108 18.0297,15.3025 17.6157,15.2845C17.2025,15.2665 16.9885,15.4626 16.9327,15.6508Z" />
+</vector>
diff --git a/res/drawable/ic_screen_rotation.xml b/res/drawable/ic_screen_rotation.xml
new file mode 100644
index 0000000..f1bde27
--- /dev/null
+++ b/res/drawable/ic_screen_rotation.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright (C) 2023 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+
+    <item>
+        <com.android.settingslib.widget.AdaptiveIconShapeDrawable
+            android:width="@dimen/dashboard_tile_image_size"
+            android:height="@dimen/dashboard_tile_image_size"
+            android:color="@color/homepage_display_background" />
+    </item>
+
+    <item
+        android:width="@dimen/dashboard_tile_foreground_image_size"
+        android:height="@dimen/dashboard_tile_foreground_image_size"
+        android:start="@dimen/dashboard_tile_foreground_image_inset"
+        android:top="@dimen/dashboard_tile_foreground_image_inset"
+        android:drawable="@drawable/ic_screen_rotation_24dp" />
+</layer-list>
diff --git a/res/layout/locale_dialog.xml b/res/layout/locale_dialog.xml
index cbdb37e..480c0e2 100644
--- a/res/layout/locale_dialog.xml
+++ b/res/layout/locale_dialog.xml
@@ -21,7 +21,9 @@
     android:paddingStart="@dimen/admin_details_dialog_padding"
     android:paddingEnd="@dimen/admin_details_dialog_padding"
     android:paddingBottom="@dimen/admin_details_dialog_padding_bottom"
-    android:orientation="vertical">
+    android:orientation="vertical"
+    android:layoutDirection="locale"
+    android:textDirection="locale">
     <LinearLayout
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
@@ -41,7 +43,8 @@
             android:layout_height="wrap_content"
             android:layout_marginTop="16dp"
             android:gravity="center_horizontal"
-            android:textAppearance="@style/TextAppearance.AdminDialogTitle"/>
+            android:textAppearance="@style/TextAppearance.AdminDialogTitle"
+            android:textAlignment="textStart"/>
     </LinearLayout>
 
     <ScrollView
@@ -51,15 +54,16 @@
         <LinearLayout
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
+            android:gravity="center_horizontal"
             android:orientation="vertical">
             <TextView
                 android:id="@+id/dialog_msg"
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"
                 android:maxLength="200"
-                android:gravity="left"
                 android:autoLink="email|phone|web"
-                android:textColor="?android:attr/textColorSecondary"/>
+                android:textColor="?android:attr/textColorSecondary"
+                android:textAlignment="textStart"/>
         </LinearLayout>
     </ScrollView>
 </LinearLayout>
diff --git a/res/layout/modifier_key_picker_dialog.xml b/res/layout/modifier_key_picker_dialog.xml
index 6de3294..fd4d75e 100644
--- a/res/layout/modifier_key_picker_dialog.xml
+++ b/res/layout/modifier_key_picker_dialog.xml
@@ -14,94 +14,102 @@
      limitations under the License.
 -->
 
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-              xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
-              android:id="@+id/modifier_key_fragment_container"
-              android:orientation="vertical"
-              android:layout_width="match_parent"
-              android:layout_height="match_parent" >
+<ScrollView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+    android:id="@+id/modifier_key_fragment_scroll_view"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
 
-    <LinearLayout android:orientation="vertical"
-                  android:layout_width="match_parent"
-                  android:layout_height="match_parent"
-                  android:divider="?android:dividerHorizontal"
-                  android:showDividers="end" >
-        <TextView
-            android:id="@+id/modifier_key_picker_title"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_marginTop="24dip"
-            android:layout_marginBottom="8dip"
-            android:layout_gravity="center_horizontal"
-            android:singleLine="true"
-            android:textAppearance="?android:attr/textAppearanceLarge"
-            android:textColor="?android:attr/textColorPrimary"
-            android:text="@string/modifier_keys_picker_title"/>
+    <LinearLayout
+        android:id="@+id/modifier_key_fragment_container"
+        android:orientation="vertical"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent" >
 
-        <TextView
-            android:id="@+id/modifier_key_picker_summary"
-            android:layout_width="wrap_content"
+        <LinearLayout android:orientation="vertical"
+                      android:layout_width="match_parent"
+                      android:layout_height="wrap_content"
+                      android:divider="?android:dividerHorizontal"
+                      android:showDividers="end" >
+            <TextView
+                android:id="@+id/modifier_key_picker_title"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_marginTop="24dp"
+                android:layout_marginBottom="8dp"
+                android:layout_marginStart="16dp"
+                android:layout_marginEnd="16dp"
+                android:layout_gravity="center_horizontal"
+                android:textAppearance="?android:attr/textAppearanceLarge"
+                android:textColor="?android:attr/textColorPrimary"
+                android:text="@string/modifier_keys_picker_title"/>
+
+            <TextView
+                android:id="@+id/modifier_key_picker_summary"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_marginTop="8dp"
+                android:layout_marginBottom="16dp"
+                android:layout_marginStart="16dp"
+                android:layout_marginEnd="16dp"
+                android:layout_gravity="center_horizontal"
+                android:textAppearance="?android:attr/textAppearanceSmall"
+                android:textColor="?android:attr/textColorSecondary"/>
+        </LinearLayout>
+
+        <LinearLayout android:orientation="vertical"
+                      android:layout_width="match_parent"
+                      android:layout_height="wrap_content"
+                      android:divider="?android:dividerHorizontal"
+                      android:showDividers="end">
+            <ListView
+                android:id="@+id/modifier_key_picker"
+                android:layout_width="wrap_content"
+                android:layout_height="352dp"
+                android:divider="@null"
+                android:dividerHeight="8dp"
+                android:padding="16dp"
+                android:listSelector="@drawable/modifier_key_lisetview_background"
+            />
+        </LinearLayout>
+
+        <RelativeLayout
+            android:layout_width="match_parent"
             android:layout_height="wrap_content"
-            android:layout_marginTop="8dip"
-            android:layout_marginBottom="16dip"
-            android:layout_gravity="center_horizontal"
-            android:singleLine="true"
-            android:textAppearance="?android:attr/textAppearanceSmall"
-            android:textColor="?android:attr/textColorSecondary"/>
+            android:layout_marginStart="8dp"
+            android:layout_marginEnd="8dp"
+            android:layout_marginTop="6dp"
+            android:layout_marginBottom="6dp">
+
+            <Button
+                android:id="@+id/modifier_key_cancel_button"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_marginTop="6dp"
+                android:layout_marginBottom="6dp"
+                android:layout_marginStart="8dp"
+                android:layout_alignParentStart="true"
+                android:paddingVertical="14dp"
+                android:drawablePadding="9dp"
+                style="@style/ModifierKeyButtonCancel"
+                android:textColor="?android:attr/textColorPrimary"
+                android:text="@string/modifier_keys_cancel"/>
+
+            <Button
+                android:id="@+id/modifier_key_done_button"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_marginTop="6dp"
+                android:layout_marginBottom="6dp"
+                android:layout_marginEnd="8dp"
+                android:layout_alignParentEnd="true"
+                android:paddingVertical="14dp"
+                android:drawablePadding="9dp"
+                style="@style/ModifierKeyButtonDone"
+                android:textColor="?androidprv:attr/materialColorOnPrimary"
+                android:text="@string/modifier_keys_done"/>
+
+        </RelativeLayout>
     </LinearLayout>
-
-    <LinearLayout android:orientation="vertical"
-                  android:layout_width="match_parent"
-                  android:layout_height="match_parent"
-                  android:divider="?android:dividerHorizontal"
-                  android:showDividers="end">
-        <ListView
-            android:id="@+id/modifier_key_picker"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:divider="@null"
-            android:dividerHeight="8dp"
-            android:padding="16dip"
-            android:listSelector="@drawable/modifier_key_lisetview_background"
-        />
-    </LinearLayout>
-
-    <RelativeLayout
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_marginStart="8dip"
-        android:layout_marginEnd="8dip"
-        android:layout_marginTop="6dip"
-        android:layout_marginBottom="6dip"
-        android:layout_weight="1">
-
-        <Button
-            android:id="@+id/modifier_key_cancel_button"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_marginTop="6dip"
-            android:layout_marginBottom="6dip"
-            android:layout_marginStart="8dip"
-            android:layout_alignParentStart="true"
-            android:paddingVertical="14dp"
-            android:drawablePadding="9dp"
-            style="@style/ModifierKeyButtonCancel"
-            android:textColor="?android:attr/textColorPrimary"
-            android:text="@string/modifier_keys_cancel"/>
-
-        <Button
-            android:id="@+id/modifier_key_done_button"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_marginTop="6dip"
-            android:layout_marginBottom="6dip"
-            android:layout_marginEnd="8dip"
-            android:layout_alignParentEnd="true"
-            android:paddingVertical="14dp"
-            android:drawablePadding="9dp"
-            style="@style/ModifierKeyButtonDone"
-            android:textColor="?androidprv:attr/materialColorOnPrimary"
-            android:text="@string/modifier_keys_done"/>
-
-    </RelativeLayout>
-</LinearLayout>
\ No newline at end of file
+</ScrollView>
\ No newline at end of file
diff --git a/res/layout/modifier_key_reset_dialog.xml b/res/layout/modifier_key_reset_dialog.xml
index 11712bf..784b608 100644
--- a/res/layout/modifier_key_reset_dialog.xml
+++ b/res/layout/modifier_key_reset_dialog.xml
@@ -26,7 +26,6 @@
         android:layout_marginTop="24dip"
         android:layout_marginBottom="8dip"
         android:layout_gravity="center_horizontal"
-        android:singleLine="true"
         android:textAppearance="?android:attr/textAppearanceLarge"
         android:textColor="?android:attr/textColorPrimary"
         android:text="@string/modifier_keys_reset_title" />
@@ -39,7 +38,6 @@
         android:layout_marginBottom="16dip"
         android:layout_marginStart="32dip"
         android:layout_marginEnd="32dip"
-        android:gravity="center"
         android:layout_gravity="center_horizontal"
         android:textAppearance="?android:attr/textAppearanceSmall"
         android:textColor="?android:attr/textColorSecondary"
diff --git a/res/values-bs/arrays.xml b/res/values-bs/arrays.xml
index db8b862..2a21b78 100644
--- a/res/values-bs/arrays.xml
+++ b/res/values-bs/arrays.xml
@@ -265,7 +265,7 @@
     <item msgid="6749550886745567276">"Jačina zvuka zvona"</item>
     <item msgid="2218685029915863168">"Jačina zvuka medija"</item>
     <item msgid="4266577290496513640">"Jačina zvuka alarma"</item>
-    <item msgid="8608084169623998854">"Jačina zvuka za obavještenja"</item>
+    <item msgid="8608084169623998854">"Jačina zvuka obavještenja"</item>
     <item msgid="7948784184567841794">"Jačina zvuka za Bluetooth vezu"</item>
     <item msgid="1148968792599973150">"Drži aktivnim"</item>
     <item msgid="8482874682804856549">"Lokacija"</item>
diff --git a/res/values-hy/arrays.xml b/res/values-hy/arrays.xml
index 2bf9c67..fb38c9b 100644
--- a/res/values-hy/arrays.xml
+++ b/res/values-hy/arrays.xml
@@ -265,7 +265,7 @@
     <item msgid="6749550886745567276">"Զանգի բարձրություն"</item>
     <item msgid="2218685029915863168">"Մուլտիմեդիայի ձայնը"</item>
     <item msgid="4266577290496513640">"Զարթուցիչի ձայնի բարձրություն"</item>
-    <item msgid="8608084169623998854">"Ծանուցման ձայնի բարձրություն"</item>
+    <item msgid="8608084169623998854">"Ծանուցումների ձայնի ուժգնություն"</item>
     <item msgid="7948784184567841794">"Bluetooth-ի ձայնի բարձրություն"</item>
     <item msgid="1148968792599973150">"Արթուն պահել"</item>
     <item msgid="8482874682804856549">"Տեղադրություն"</item>
diff --git a/res/values-ne/arrays.xml b/res/values-ne/arrays.xml
index 992bd5b..cd9aba0 100644
--- a/res/values-ne/arrays.xml
+++ b/res/values-ne/arrays.xml
@@ -198,7 +198,7 @@
     <item msgid="6485000384018554920">"घन्टी मात्रा"</item>
     <item msgid="3378000878531336372">"मिडियाको भोल्युम"</item>
     <item msgid="5272927168355895681">"अलार्मको भोल्युम"</item>
-    <item msgid="4422070755065530548">"सूचना मात्रा"</item>
+    <item msgid="4422070755065530548">"सूचनाको भोल्युम"</item>
     <item msgid="3250654589277825306">"ब्लुटुथ मात्रा"</item>
     <item msgid="4212187233638382465">"जागा रहनुहोस्"</item>
     <item msgid="5099026183238335900">"स्थानको निरीक्षण गर्नुहोस्"</item>
diff --git a/res/values-or/arrays.xml b/res/values-or/arrays.xml
index e839050..8a319e5 100644
--- a/res/values-or/arrays.xml
+++ b/res/values-or/arrays.xml
@@ -196,8 +196,8 @@
     <item msgid="617344340943430125">"ମାଷ୍ଟର୍ ଭଲ୍ୟୁମ୍"</item>
     <item msgid="1249691739381713634">"ଭଏସ ଭଲ୍ୟୁମ"</item>
     <item msgid="6485000384018554920">"ରିଙ୍ଗ ଭଲ୍ୟୁମ୍"</item>
-    <item msgid="3378000878531336372">"ମିଡିଆ ଭଲ୍ୟୁମ୍‌"</item>
-    <item msgid="5272927168355895681">"ଆଲାରାମର ଭଲ୍ୟୁମ୍‌"</item>
+    <item msgid="3378000878531336372">"ମିଡିଆ ଭଲ୍ୟୁମ"</item>
+    <item msgid="5272927168355895681">"ଆଲାରାମ ଭଲ୍ୟୁମ"</item>
     <item msgid="4422070755065530548">"ବିଜ୍ଞପ୍ତି ଭଲ୍ୟୁମ୍"</item>
     <item msgid="3250654589277825306">"ବ୍ଲୁଟୂଥ୍‍‌ ଭଲ୍ୟୁମ୍‌"</item>
     <item msgid="4212187233638382465">"ଜାଗ୍ରତ ରଖନ୍ତୁ"</item>
@@ -263,7 +263,7 @@
     <item msgid="745291221457314879">"ମାଷ୍ଟର୍‌ ଭଲ୍ୟୁମ୍"</item>
     <item msgid="4722479281326245754">"ଭଏସ୍ ଭଲ୍ୟୁମ୍"</item>
     <item msgid="6749550886745567276">"ରିଙ୍ଗ ଭଲ୍ୟୁମ୍"</item>
-    <item msgid="2218685029915863168">"ମିଡିଆ ଭଲ୍ୟୁମ୍‌"</item>
+    <item msgid="2218685029915863168">"ମିଡିଆ ଭଲ୍ୟୁମ"</item>
     <item msgid="4266577290496513640">"ଆଲାରାମ୍ ଭଲ୍ୟୁମ୍"</item>
     <item msgid="8608084169623998854">"ବିଜ୍ଞପ୍ତି ଭଲ୍ୟୁମ୍‌"</item>
     <item msgid="7948784184567841794">"ବ୍ଲୁଟୂଥ୍‍‌ ଭଲ୍ୟୁମ୍‌"</item>
diff --git a/res/values-pa/arrays.xml b/res/values-pa/arrays.xml
index a2742e6..7a799af 100644
--- a/res/values-pa/arrays.xml
+++ b/res/values-pa/arrays.xml
@@ -198,7 +198,7 @@
     <item msgid="6485000384018554920">"ਰਿੰਗ ਦੀ ਅਵਾਜ਼"</item>
     <item msgid="3378000878531336372">"ਮੀਡੀਆ ਦੀ ਅਵਾਜ਼"</item>
     <item msgid="5272927168355895681">"ਅਲਾਰਮ ਦੀ ਅਵਾਜ਼"</item>
-    <item msgid="4422070755065530548">"ਸੂਚਨਾ ਵੌਲਿਊਮ"</item>
+    <item msgid="4422070755065530548">"ਸੂਚਨਾ ਦੀ ਅਵਾਜ਼"</item>
     <item msgid="3250654589277825306">"bluetooth ਵੌਲਿਊਮ"</item>
     <item msgid="4212187233638382465">"ਸਕਿਰਿਆ ਰੱਖੋ"</item>
     <item msgid="5099026183238335900">"ਨਿਰਧਾਰਿਤ ਸਥਾਨ ਦਾ ਨਿਰੀਖਣ ਕਰੋ"</item>
@@ -265,7 +265,7 @@
     <item msgid="6749550886745567276">"ਰਿੰਗ ਦੀ ਅਵਾਜ਼"</item>
     <item msgid="2218685029915863168">"ਮੀਡੀਆ ਦੀ ਅਵਾਜ਼"</item>
     <item msgid="4266577290496513640">"ਅਲਾਰਮ ਦੀ ਅਵਾਜ਼"</item>
-    <item msgid="8608084169623998854">"ਸੂਚਨਾ ਵੌਲਿਊਮ"</item>
+    <item msgid="8608084169623998854">"ਸੂਚਨਾ ਦੀ ਅਵਾਜ਼"</item>
     <item msgid="7948784184567841794">"Bluetooth ਵੌਲਿਊਮ"</item>
     <item msgid="1148968792599973150">"ਸਕਿਰਿਆ ਰੱਖੋ"</item>
     <item msgid="8482874682804856549">"ਟਿਕਾਣਾ"</item>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 844d8ce..bdf8000 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -427,6 +427,12 @@
     <string name="friday_first_day_of_week">Friday</string>
     <!-- The title of saturday for preference of first day of week. [CHAR LIMIT=50] -->
     <string name="saturday_first_day_of_week">Saturday</string>
+    <!-- Title for regional preference footer. [CHAR LIMIT=NONE] -->
+    <string name="title_regional_pref_footer">If an app doesn’t support regional preferences, the app will use its default locale settings.</string>
+    <!-- Description for text in regional preference footer. [CHAR LIMIT=NONE] -->
+    <string name="desc_regional_pref_footer_learn_more">Learn more about language preferences.</string>
+    <!-- TODO(b/277573274): Update the learn more url in the regional preference. -->
+    <string name="regional_pref_footer_learn_more_link" translatable="false">https://support.google.com/android</string>
 
     <!-- The title of the confirmation dialog shown when the user selects one / several languages and tries to remove them [CHAR LIMIT=60] -->
     <string name="dlg_remove_locales_title">{count, plural,
@@ -2061,6 +2067,10 @@
     <string name="wifi_hotspot_speed_summary_unavailable">Not available in your country or region</string>
     <!-- The footer message for switch screen resolution [CHAR LIMIT=NONE] -->
     <string name="wifi_hotspot_speed_footer">If your preferred frequency isn\u0027t available, your hotspot may use a different one. Hotspot security settings may change if you change the frequency.</string>
+    <!-- Summary for the Wi-Fi hotspot security unavailable [CHAR LIMIT=NONE] -->
+    <string name="wifi_hotspot_security_summary_unavailable">Not available with 6 GHz</string>
+    <!-- The footer message for Wi-Fi hotspot security settings [CHAR LIMIT=NONE] -->
+    <string name="wifi_hotspot_security_footer">Security settings may change if you change the hotspot’s frequency</string>
 
     <!-- Summary text when turning hotspot on -->
     <string name="wifi_tether_starting">Turning hotspot on\u2026</string>
@@ -6370,7 +6380,7 @@
     <!-- Title of preference to enable calling and SMS [CHAR LIMIT=45] -->
     <string name="user_enable_calling_sms">Turn on phone calls &amp; SMS</string>
     <!-- Title of preference to grant user admin privileges [CHAR LIMIT=45] -->
-    <string name="user_grant_admin">Give this user admin privileges</string>
+    <string name="user_grant_admin">Make this user an admin</string>
     <!-- Title of preference to remove the user [CHAR LIMIT=35] -->
     <string name="user_remove_user">Delete user</string>
     <!-- Title for confirmation of turning on calls and SMS [CHAR LIMIT=45] -->
@@ -6380,7 +6390,7 @@
     <!-- Title for confirmation of revoking admin privileges [CHAR LIMIT=45] -->
     <string name="user_revoke_admin_confirm_title">Remove admin privileges?</string>
     <!-- Message for confirmation of revoking admin privileges [CHAR LIMIT=none] -->
-    <string name="user_revoke_admin_confirm_message">Are you sure you want to remove this user\'s admin privileges?</string>
+    <string name="user_revoke_admin_confirm_message">If you remove admin privileges for this user, you or another admin can give them back later.</string>
     <!-- Title for the emergency info preference [CHAR LIMIT=40] -->
     <string name="emergency_info_title">Emergency information</string>
     <!-- Summary for the emergency info preference [CHAR LIMIT=40] -->
@@ -11898,6 +11908,12 @@
     <!-- Developer settings: Summary for disabling phantom process monitoring. [CHAR LIMIT=NONE]-->
     <string name="disable_phantom_process_monitor_summary">Disable restrictions on the system resource usage of the app child processes</string>
 
+    <!-- Developer settings: Title for force enabling Notes role. [CHAR LIMIT=50]-->
+    <string name="enable_notes_role_title">Force enable Notes role</string>
+    <!-- Developer settings: Summary for disabling phantom process monitoring. [CHAR LIMIT=NONE]-->
+    <string name="enable_notes_role_summary">Enable note-taking system integrations via the Notes role. If the Notes role is already enabled, does nothing.</string>
+
+
     <!-- BT LE Audio Device: Media Broadcast -->
     <!-- The title of the Media Broadcast Dialog [CHAR LIMIT=none] -->
     <string name="bluetooth_broadcast_dialog_title">Broadcast</string>
@@ -12041,4 +12057,7 @@
 
     <!-- Warning message when we try to dock an app not supporting multiple instances split into multiple sides [CHAR LIMIT=NONE] -->
     <string name="dock_multi_instances_not_supported_text">"This app can only be opened in 1 window"</string>
+
+    <!-- [CHAR LIMIT=30] Label used to open Note Task -->
+    <string name="note_task_button_label">Notetaking</string>
 </resources>
diff --git a/res/xml/development_settings.xml b/res/xml/development_settings.xml
index 9e1dbad..e7aac3e 100644
--- a/res/xml/development_settings.xml
+++ b/res/xml/development_settings.xml
@@ -713,6 +713,11 @@
             android:title="@string/disable_phantom_process_monitor_title"
             android:summary="@string/disable_phantom_process_monitor_summary" />
 
+        <SwitchPreference
+            android:key="force_enable_notes_role"
+            android:title="@string/enable_notes_role_title"
+            android:summary="@string/enable_notes_role_summary" />
+
     </PreferenceCategory>
 
     <PreferenceCategory
diff --git a/res/xml/regional_preference_main_page.xml b/res/xml/regional_preference_main_page.xml
index de9d3d8..27a1d83 100644
--- a/res/xml/regional_preference_main_page.xml
+++ b/res/xml/regional_preference_main_page.xml
@@ -66,4 +66,11 @@
             android:value="arg_value_language_select" />
     </Preference>
 
+    <com.android.settingslib.widget.FooterPreference
+        android:key="regional_pref_footer"
+        android:title="@string/title_regional_pref_footer"
+        android:selectable="false"
+        settings:searchable="false"
+        settings:controller="com.android.settings.regionalpreferences.RegionalFooterPreferenceController"/>
+
 </PreferenceScreen>
diff --git a/res/xml/security_settings_face.xml b/res/xml/security_settings_face.xml
index f0d0350..9fc8a1f 100644
--- a/res/xml/security_settings_face.xml
+++ b/res/xml/security_settings_face.xml
@@ -80,5 +80,6 @@
 
     <com.android.settingslib.widget.FooterPreference
         android:key="security_face_footer"
+        settings:searchable="false"
         settings:controller="com.android.settings.biometrics.face.FaceSettingsFooterPreferenceController" />
 </PreferenceScreen>
diff --git a/res/xml/wifi_hotspot_security.xml b/res/xml/wifi_hotspot_security.xml
new file mode 100644
index 0000000..3993d47
--- /dev/null
+++ b/res/xml/wifi_hotspot_security.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2023 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<PreferenceScreen
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:settings="http://schemas.android.com/apk/res-auto"
+    android:title="@string/wifi_security"
+    settings:searchable="false">
+
+    <com.android.settingslib.widget.SelectorWithWidgetPreference
+        android:key="wifi_hotspot_security_wpa3"
+        android:title="@string/wifi_security_sae"/>
+
+    <com.android.settingslib.widget.SelectorWithWidgetPreference
+        android:key="wifi_hotspot_security_wpa2_wpa3"
+        android:title="@string/wifi_security_psk_sae"/>
+
+    <com.android.settingslib.widget.SelectorWithWidgetPreference
+        android:key="wifi_hotspot_security_wpa2"
+        android:title="@string/wifi_security_wpa2"/>
+
+    <com.android.settingslib.widget.SelectorWithWidgetPreference
+        android:key="wifi_hotspot_security_none"
+        android:title="@string/wifi_security_none"/>
+
+    <com.android.settingslib.widget.FooterPreference
+        android:title="@string/wifi_hotspot_security_footer"/>
+
+</PreferenceScreen>
diff --git a/res/xml/wifi_tether_settings.xml b/res/xml/wifi_tether_settings.xml
index 3023a6e..a85d9ea 100644
--- a/res/xml/wifi_tether_settings.xml
+++ b/res/xml/wifi_tether_settings.xml
@@ -32,6 +32,13 @@
         android:entries="@array/wifi_tether_security"
         android:entryValues="@array/wifi_tether_security_values"/>
 
+    <Preference
+        android:key="wifi_hotspot_security"
+        android:title="@string/wifi_security"
+        android:summary="@string/summary_placeholder"
+        android:fragment="com.android.settings.wifi.tether.WifiHotspotSecuritySettings"
+        settings:isPreferenceVisible="@bool/config_show_wifi_hotspot_speed"/>
+
     <com.android.settings.widget.ValidatedEditTextPreference
         android:key="wifi_tether_network_password"
         android:persistent="false"
diff --git a/src/com/android/settings/Utils.java b/src/com/android/settings/Utils.java
index 388a510..68b1a48 100644
--- a/src/com/android/settings/Utils.java
+++ b/src/com/android/settings/Utils.java
@@ -134,6 +134,8 @@
 
     public static final String SETTINGS_PACKAGE_NAME = "com.android.settings";
 
+    public static final String SYSTEMUI_PACKAGE_NAME = "com.android.systemui";
+
     public static final String OS_PKG = "os";
 
     /**
diff --git a/src/com/android/settings/applications/AppStateOverlayBridge.java b/src/com/android/settings/applications/AppStateOverlayBridge.java
index 64a6ea1..2276b19 100644
--- a/src/com/android/settings/applications/AppStateOverlayBridge.java
+++ b/src/com/android/settings/applications/AppStateOverlayBridge.java
@@ -19,6 +19,7 @@
 import android.app.AppOpsManager;
 import android.content.Context;
 
+import com.android.settings.Utils;
 import com.android.settingslib.applications.ApplicationsState;
 import com.android.settingslib.applications.ApplicationsState.AppEntry;
 import com.android.settingslib.applications.ApplicationsState.AppFilter;
@@ -59,7 +60,7 @@
         private static final List<String> DISABLE_PACKAGE_LIST = new ArrayList<>();
 
         static {
-            DISABLE_PACKAGE_LIST.add("com.android.systemui");
+            DISABLE_PACKAGE_LIST.add(Utils.SYSTEMUI_PACKAGE_NAME);
         }
 
         public OverlayState(PermissionState permissionState) {
diff --git a/src/com/android/settings/applications/RecentAppStatsMixin.java b/src/com/android/settings/applications/RecentAppStatsMixin.java
index 6705b25..4e8f795 100644
--- a/src/com/android/settings/applications/RecentAppStatsMixin.java
+++ b/src/com/android/settings/applications/RecentAppStatsMixin.java
@@ -17,6 +17,7 @@
 package com.android.settings.applications;
 
 import static com.android.settings.Utils.SETTINGS_PACKAGE_NAME;
+import static com.android.settings.Utils.SYSTEMUI_PACKAGE_NAME;
 
 import android.app.Application;
 import android.app.usage.UsageStats;
@@ -76,7 +77,7 @@
                 "android",
                 "com.android.phone",
                 SETTINGS_PACKAGE_NAME,
-                "com.android.systemui",
+                SYSTEMUI_PACKAGE_NAME,
                 "com.android.providers.calendar",
                 "com.android.providers.media"
         ));
diff --git a/src/com/android/settings/applications/specialaccess/pictureinpicture/PictureInPictureSettings.java b/src/com/android/settings/applications/specialaccess/pictureinpicture/PictureInPictureSettings.java
index d794de6..3c90bf3 100644
--- a/src/com/android/settings/applications/specialaccess/pictureinpicture/PictureInPictureSettings.java
+++ b/src/com/android/settings/applications/specialaccess/pictureinpicture/PictureInPictureSettings.java
@@ -38,6 +38,7 @@
 import androidx.preference.PreferenceScreen;
 
 import com.android.settings.R;
+import com.android.settings.Utils;
 import com.android.settings.applications.AppInfoBase;
 import com.android.settings.search.BaseSearchIndexProvider;
 import com.android.settings.widget.EmptyTextSettings;
@@ -57,7 +58,7 @@
     static final List<String> IGNORE_PACKAGE_LIST = new ArrayList<>();
 
     static {
-        IGNORE_PACKAGE_LIST.add("com.android.systemui");
+        IGNORE_PACKAGE_LIST.add(Utils.SYSTEMUI_PACKAGE_NAME);
     }
 
     /**
diff --git a/src/com/android/settings/applications/specialaccess/turnscreenon/TurnScreenOnSettings.java b/src/com/android/settings/applications/specialaccess/turnscreenon/TurnScreenOnSettings.java
index 014971a..742831e 100644
--- a/src/com/android/settings/applications/specialaccess/turnscreenon/TurnScreenOnSettings.java
+++ b/src/com/android/settings/applications/specialaccess/turnscreenon/TurnScreenOnSettings.java
@@ -37,6 +37,7 @@
 import androidx.preference.PreferenceScreen;
 
 import com.android.settings.R;
+import com.android.settings.Utils;
 import com.android.settings.applications.AppInfoBase;
 import com.android.settings.search.BaseSearchIndexProvider;
 import com.android.settings.widget.EmptyTextSettings;
@@ -58,7 +59,7 @@
     static final List<String> IGNORE_PACKAGE_LIST = new ArrayList<>();
 
     static {
-        IGNORE_PACKAGE_LIST.add("com.android.systemui");
+        IGNORE_PACKAGE_LIST.add(Utils.SYSTEMUI_PACKAGE_NAME);
     }
 
     /**
diff --git a/src/com/android/settings/biometrics/BiometricNavigationUtils.java b/src/com/android/settings/biometrics/BiometricNavigationUtils.java
index 32d3a32..2d0744b 100644
--- a/src/com/android/settings/biometrics/BiometricNavigationUtils.java
+++ b/src/com/android/settings/biometrics/BiometricNavigationUtils.java
@@ -26,6 +26,9 @@
 import android.os.UserHandle;
 import android.os.UserManager;
 
+import androidx.activity.result.ActivityResultLauncher;
+import androidx.annotation.Nullable;
+
 import com.android.internal.app.UnlaunchableAppActivity;
 import com.android.settings.core.SettingsBaseActivity;
 import com.android.settingslib.RestrictedLockUtils;
@@ -49,15 +52,23 @@
      *
      * @param className The class name of Settings screen to launch.
      * @param extras    Extras to put into the launching {@link Intent}.
+     * @param launcher  Launcher to launch activity if non-quiet mode
      * @return true if the Settings screen is launching.
      */
-    public boolean launchBiometricSettings(Context context, String className, Bundle extras) {
+    public boolean launchBiometricSettings(Context context, String className, Bundle extras,
+            @Nullable ActivityResultLauncher<Intent> launcher) {
         final Intent quietModeDialogIntent = getQuietModeDialogIntent(context);
         if (quietModeDialogIntent != null) {
             context.startActivity(quietModeDialogIntent);
             return false;
         }
-        context.startActivity(getSettingsPageIntent(className, extras));
+
+        final Intent settingsPageIntent = getSettingsPageIntent(className, extras);
+        if (launcher != null) {
+            launcher.launch(settingsPageIntent);
+        } else {
+            context.startActivity(settingsPageIntent);
+        }
         return true;
     }
 
diff --git a/src/com/android/settings/biometrics/BiometricStatusPreferenceController.java b/src/com/android/settings/biometrics/BiometricStatusPreferenceController.java
index 76a23a5..2f9ae6b 100644
--- a/src/com/android/settings/biometrics/BiometricStatusPreferenceController.java
+++ b/src/com/android/settings/biometrics/BiometricStatusPreferenceController.java
@@ -17,10 +17,14 @@
 package com.android.settings.biometrics;
 
 import android.content.Context;
+import android.content.Intent;
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.text.TextUtils;
 
+import androidx.activity.result.ActivityResultLauncher;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
 import androidx.preference.Preference;
 
 import com.android.internal.widget.LockPatternUtils;
@@ -29,6 +33,8 @@
 import com.android.settings.core.BasePreferenceController;
 import com.android.settings.overlay.FeatureFactory;
 
+import java.lang.ref.WeakReference;
+
 public abstract class BiometricStatusPreferenceController extends BasePreferenceController {
 
     protected final UserManager mUm;
@@ -39,6 +45,8 @@
 
     private final BiometricNavigationUtils mBiometricNavigationUtils;
     private final ActiveUnlockStatusUtils mActiveUnlockStatusUtils;
+    @NonNull private WeakReference<ActivityResultLauncher<Intent>> mLauncherWeakReference =
+            new WeakReference<>(null);
 
     /**
      * @return true if the controller should be shown exclusively.
@@ -118,14 +126,31 @@
         preference.setSummary(getSummaryText());
     }
 
+    /**
+     * Set ActivityResultLauncher that will be used later during handlePreferenceTreeClick()
+     *
+     * @param preference the preference being compared
+     * @param launcher the ActivityResultLauncher
+     * @return {@code true} if matched preference.
+     */
+    public boolean setPreferenceTreeClickLauncher(@NonNull Preference preference,
+            @Nullable ActivityResultLauncher<Intent> launcher) {
+        if (!TextUtils.equals(preference.getKey(), getPreferenceKey())) {
+            return false;
+        }
+
+        mLauncherWeakReference = new WeakReference<>(launcher);
+        return true;
+    }
+
     @Override
     public boolean handlePreferenceTreeClick(Preference preference) {
         if (!TextUtils.equals(preference.getKey(), getPreferenceKey())) {
             return super.handlePreferenceTreeClick(preference);
         }
 
-        return mBiometricNavigationUtils.launchBiometricSettings(
-                preference.getContext(), getSettingsClassName(), preference.getExtras());
+        return mBiometricNavigationUtils.launchBiometricSettings(preference.getContext(),
+                getSettingsClassName(), preference.getExtras(), mLauncherWeakReference.get());
     }
 
     protected int getUserId() {
diff --git a/src/com/android/settings/biometrics/combination/BiometricsSettingsBase.java b/src/com/android/settings/biometrics/combination/BiometricsSettingsBase.java
index 7b02b9d..052b8cd 100644
--- a/src/com/android/settings/biometrics/combination/BiometricsSettingsBase.java
+++ b/src/com/android/settings/biometrics/combination/BiometricsSettingsBase.java
@@ -33,6 +33,9 @@
 import android.text.TextUtils;
 import android.util.Log;
 
+import androidx.activity.result.ActivityResult;
+import androidx.activity.result.ActivityResultLauncher;
+import androidx.activity.result.contract.ActivityResultContracts;
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 import androidx.annotation.StringRes;
@@ -42,14 +45,19 @@
 import com.android.settings.R;
 import com.android.settings.Utils;
 import com.android.settings.biometrics.BiometricEnrollBase;
+import com.android.settings.biometrics.BiometricStatusPreferenceController;
 import com.android.settings.biometrics.BiometricUtils;
 import com.android.settings.biometrics.BiometricsSplitScreenDialog;
 import com.android.settings.core.SettingsBaseActivity;
 import com.android.settings.dashboard.DashboardFragment;
 import com.android.settings.password.ChooseLockGeneric;
 import com.android.settings.password.ChooseLockSettingsHelper;
+import com.android.settingslib.core.AbstractPreferenceController;
 import com.android.settingslib.transition.SettingsTransitionHelper;
 
+import java.util.Collection;
+import java.util.List;
+
 /**
  * Base fragment with the confirming credential functionality for combined biometrics settings.
  */
@@ -78,6 +86,18 @@
     @Nullable private String mRetryPreferenceKey = null;
     @Nullable private Bundle mRetryPreferenceExtra = null;
 
+    private final ActivityResultLauncher<Intent> mFaceOrFingerprintPreferenceLauncher =
+            registerForActivityResult(new ActivityResultContracts.StartActivityForResult(),
+                    this::onFaceOrFingerprintPreferenceResult);
+
+    private void onFaceOrFingerprintPreferenceResult(@Nullable ActivityResult result) {
+        if (result != null && result.getResultCode() == BiometricEnrollBase.RESULT_TIMEOUT) {
+            // When "Face Unlock" or "Fingerprint Unlock" is closed due to entering onStop(),
+            // "Face & Fingerprint Unlock" shall also close itself and back to "Security" page.
+            finish();
+        }
+    }
+
     @Override
     public void onAttach(Context context) {
         super.onAttach(context);
@@ -165,7 +185,7 @@
                     extras.putByteArray(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN, token);
                     extras.putInt(BiometricEnrollBase.EXTRA_KEY_SENSOR_ID, sensorId);
                     extras.putLong(BiometricEnrollBase.EXTRA_KEY_CHALLENGE, challenge);
-                    super.onPreferenceTreeClick(preference);
+                    onFaceOrFingerprintPreferenceTreeClick(preference);
                 } catch (IllegalStateException e) {
                     if (retry) {
                         mRetryPreferenceKey = preference.getKey();
@@ -200,7 +220,7 @@
                     final Bundle extras = preference.getExtras();
                     extras.putByteArray(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN, token);
                     extras.putLong(BiometricEnrollBase.EXTRA_KEY_CHALLENGE, challenge);
-                    super.onPreferenceTreeClick(preference);
+                    onFaceOrFingerprintPreferenceTreeClick(preference);
                 } catch (IllegalStateException e) {
                     if (retry) {
                         mRetryPreferenceKey = preference.getKey();
@@ -224,6 +244,33 @@
         return BiometricUtils.requestGatekeeperHat(context, gkPwHandle, userId, challenge);
     }
 
+    /**
+     * Handle preference tree click action for "Face Unlock" or "Fingerprint Unlock" with a launcher
+     * because "Face & Fingerprint Unlock" has to close itself when it gets a specific activity
+     * error code.
+     *
+     * @param preference "Face Unlock" or "Fingerprint Unlock" preference.
+     */
+    private void onFaceOrFingerprintPreferenceTreeClick(@NonNull Preference preference) {
+        Collection<List<AbstractPreferenceController>> controllers = getPreferenceControllers();
+        for (List<AbstractPreferenceController> controllerList : controllers) {
+            for (AbstractPreferenceController controller : controllerList) {
+                if (controller instanceof BiometricStatusPreferenceController) {
+                    final BiometricStatusPreferenceController biometricController =
+                            (BiometricStatusPreferenceController) controller;
+                    if (biometricController.setPreferenceTreeClickLauncher(preference,
+                            mFaceOrFingerprintPreferenceLauncher)) {
+                        if (biometricController.handlePreferenceTreeClick(preference)) {
+                            writePreferenceClickMetric(preference);
+                        }
+                        biometricController.setPreferenceTreeClickLauncher(preference, null);
+                        return;
+                    }
+                }
+            }
+        }
+    }
+
     @Override
     public boolean onPreferenceTreeClick(Preference preference) {
         return onRetryPreferenceTreeClick(preference, true)
diff --git a/src/com/android/settings/biometrics/combination/CombinedBiometricStatusUtils.java b/src/com/android/settings/biometrics/combination/CombinedBiometricStatusUtils.java
index d3e8fa7..8cc6bc4 100644
--- a/src/com/android/settings/biometrics/combination/CombinedBiometricStatusUtils.java
+++ b/src/com/android/settings/biometrics/combination/CombinedBiometricStatusUtils.java
@@ -133,6 +133,19 @@
     }
 
     /**
+     * Returns the class name of the Settings page corresponding to combined biometric settings
+     * based on the current user.
+     */
+    public String getSettingsClassNameBasedOnUser() {
+        UserManager userManager = mContext.getSystemService(UserManager.class);
+        if (userManager != null && userManager.isProfile()) {
+            return getProfileSettingsClassName();
+        } else {
+            return getSettingsClassName();
+        }
+    }
+
+    /**
      * Returns the class name of the Settings page corresponding to combined biometric settings.
      */
     public String getSettingsClassName() {
diff --git a/src/com/android/settings/biometrics/face/FaceEnrollIntroduction.java b/src/com/android/settings/biometrics/face/FaceEnrollIntroduction.java
index 3e8c458..efd9753 100644
--- a/src/com/android/settings/biometrics/face/FaceEnrollIntroduction.java
+++ b/src/com/android/settings/biometrics/face/FaceEnrollIntroduction.java
@@ -592,6 +592,10 @@
         return data;
     }
 
+    protected boolean isFaceStrong() {
+        return mIsFaceStrong;
+    }
+
     private void onFaceStrengthChanged() {
         // Set up and show the "less secure" info section if necessary.
         if (!mIsFaceStrong && getResources().getBoolean(
diff --git a/src/com/android/settings/biometrics/face/FaceEnrollParentalConsent.java b/src/com/android/settings/biometrics/face/FaceEnrollParentalConsent.java
index a3a745d..aabbf6f 100644
--- a/src/com/android/settings/biometrics/face/FaceEnrollParentalConsent.java
+++ b/src/com/android/settings/biometrics/face/FaceEnrollParentalConsent.java
@@ -47,13 +47,14 @@
             R.string.security_settings_face_enroll_introduction_control_consent_title,
             R.string.security_settings_face_enroll_introduction_control_consent_message,
             R.string.security_settings_face_enroll_introduction_consent_message_0,
+            R.string.security_settings_face_enroll_introduction_consent_message_0_class3,
             R.string.security_settings_face_enroll_introduction_info_consent_less_secure
     };
 
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
-        setDescriptionText(R.string.security_settings_face_enroll_introduction_consent_message_0);
+        updateDescriptionText();
     }
 
     @Override
@@ -144,4 +145,16 @@
     public int getMetricsCategory() {
         return SettingsEnums.FACE_PARENTAL_CONSENT;
     }
+
+    @Override
+    protected void updateDescriptionText() {
+        super.updateDescriptionText();
+        if (isFaceStrong()) {
+            setDescriptionText(getString(
+                    R.string.security_settings_face_enroll_introduction_consent_message_0_class3));
+        } else {
+            setDescriptionText(
+                    R.string.security_settings_face_enroll_introduction_consent_message_0);
+        }
+    }
 }
diff --git a/src/com/android/settings/biometrics/face/FaceSettings.java b/src/com/android/settings/biometrics/face/FaceSettings.java
index cf2c09b..c300bae 100644
--- a/src/com/android/settings/biometrics/face/FaceSettings.java
+++ b/src/com/android/settings/biometrics/face/FaceSettings.java
@@ -325,6 +325,8 @@
                 mFaceManager.revokeChallenge(mSensorId, mUserId, mChallenge);
                 mToken = null;
             }
+            // Let parent "Face & Fingerprint Unlock" can use this error code to close itself.
+            setResult(RESULT_TIMEOUT);
             finish();
         }
     }
diff --git a/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollParentalConsent.java b/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollParentalConsent.java
index c33ae17..7f4142d 100644
--- a/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollParentalConsent.java
+++ b/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollParentalConsent.java
@@ -131,4 +131,12 @@
     public int getMetricsCategory() {
         return SettingsEnums.FINGERPRINT_PARENTAL_CONSENT;
     }
+
+
+    @Override
+    protected void updateDescriptionText() {
+        super.updateDescriptionText();
+        setDescriptionText(
+                R.string.security_settings_fingerprint_enroll_introduction_consent_message);
+    }
 }
diff --git a/src/com/android/settings/biometrics/fingerprint/FingerprintSettings.java b/src/com/android/settings/biometrics/fingerprint/FingerprintSettings.java
index 88a05c3..f60cd0c 100644
--- a/src/com/android/settings/biometrics/fingerprint/FingerprintSettings.java
+++ b/src/com/android/settings/biometrics/fingerprint/FingerprintSettings.java
@@ -669,6 +669,7 @@
         public void onStop() {
             super.onStop();
             if (!getActivity().isChangingConfigurations() && !mLaunchedConfirm && !mIsEnrolling) {
+                setResult(RESULT_TIMEOUT);
                 getActivity().finish();
             }
         }
@@ -874,6 +875,12 @@
             } else if (requestCode == AUTO_ADD_FIRST_FINGERPRINT_REQUEST) {
                 if (resultCode != RESULT_FINISHED || data == null) {
                     Log.d(TAG, "Add first fingerprint, fail or null data, result:" + resultCode);
+                    if (resultCode == BiometricEnrollBase.RESULT_TIMEOUT) {
+                        // If "Fingerprint Unlock" is closed because of timeout, notify result code
+                        // back because "Face & Fingerprint Unlock" has to close itself for timeout
+                        // case.
+                        setResult(resultCode);
+                    }
                     finish();
                     return;
                 }
diff --git a/src/com/android/settings/biometrics2/ui/view/FingerprintEnrollEnrollingIconTouchDialog.java b/src/com/android/settings/biometrics2/ui/view/FingerprintEnrollEnrollingIconTouchDialog.java
index e86d755..f4fe7ff 100644
--- a/src/com/android/settings/biometrics2/ui/view/FingerprintEnrollEnrollingIconTouchDialog.java
+++ b/src/com/android/settings/biometrics2/ui/view/FingerprintEnrollEnrollingIconTouchDialog.java
@@ -18,14 +18,11 @@
 
 import android.app.Dialog;
 import android.app.settings.SettingsEnums;
-import android.content.Context;
 import android.os.Bundle;
 
 import androidx.appcompat.app.AlertDialog;
-import androidx.lifecycle.ViewModelProvider;
 
 import com.android.settings.R;
-import com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollEnrollingViewModel;
 import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
 
 /**
@@ -33,15 +30,6 @@
  */
 public class FingerprintEnrollEnrollingIconTouchDialog extends InstrumentedDialogFragment {
 
-    private FingerprintEnrollEnrollingViewModel mViewModel;
-
-    @Override
-    public void onAttach(Context context) {
-        mViewModel = new ViewModelProvider(getActivity()).get(
-                FingerprintEnrollEnrollingViewModel.class);
-        super.onAttach(context);
-    }
-
     @Override
     public Dialog onCreateDialog(Bundle savedInstanceState) {
         AlertDialog.Builder builder = new AlertDialog.Builder(getActivity(),
@@ -50,10 +38,7 @@
                 .setMessage(R.string.security_settings_fingerprint_enroll_touch_dialog_message)
                 .setPositiveButton(
                         R.string.security_settings_fingerprint_enroll_dialog_ok,
-                        (dialog, which) -> {
-                            dialog.dismiss();
-                            mViewModel.onIconTouchDialogDismiss();
-                        });
+                        (dialog, which) -> dialog.dismiss());
         return builder.create();
     }
 
diff --git a/src/com/android/settings/biometrics2/ui/view/FingerprintEnrollmentActivity.java b/src/com/android/settings/biometrics2/ui/view/FingerprintEnrollmentActivity.java
index 62928af..d84ce61 100644
--- a/src/com/android/settings/biometrics2/ui/view/FingerprintEnrollmentActivity.java
+++ b/src/com/android/settings/biometrics2/ui/view/FingerprintEnrollmentActivity.java
@@ -27,7 +27,6 @@
 import static com.android.settings.biometrics2.ui.viewmodel.AutoCredentialViewModel.CREDENTIAL_IS_GENERATING_CHALLENGE;
 import static com.android.settings.biometrics2.ui.viewmodel.AutoCredentialViewModel.CREDENTIAL_VALID;
 import static com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollEnrollingViewModel.ErrorDialogData;
-import static com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollEnrollingViewModel.FINGERPRINT_ENROLL_ENROLLING_ACTION_DISMISS_ICON_TOUCH_DIALOG;
 import static com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollEnrollingViewModel.FINGERPRINT_ENROLL_ENROLLING_ACTION_DONE;
 import static com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollEnrollingViewModel.FINGERPRINT_ENROLL_ENROLLING_ACTION_SHOW_ICON_TOUCH_DIALOG;
 import static com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollEnrollingViewModel.FINGERPRINT_ENROLL_ENROLLING_CANCELED_BECAUSE_BACK_PRESSED;
@@ -518,10 +517,6 @@
                         SKIP_SETUP_FIND_FPS_DIALOG_TAG);
                 break;
             }
-            case FINGERPRINT_ENROLL_ENROLLING_ACTION_DISMISS_ICON_TOUCH_DIALOG: {
-                onSetActivityResult(new ActivityResult(BiometricEnrollBase.RESULT_TIMEOUT, null));
-                break;
-            }
             case FINGERPRINT_ENROLL_ENROLLING_CANCELED_BECAUSE_BACK_PRESSED: {
                 if (getSupportFragmentManager().getBackStackEntryCount() > 0) {
                     getSupportFragmentManager().popBackStack();
diff --git a/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollEnrollingViewModel.java b/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollEnrollingViewModel.java
index 025c58b..12584ee 100644
--- a/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollEnrollingViewModel.java
+++ b/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollEnrollingViewModel.java
@@ -61,24 +61,18 @@
     public static final int FINGERPRINT_ENROLL_ENROLLING_ACTION_SHOW_ICON_TOUCH_DIALOG = 1;
 
     /**
-     * Icon touch dialog dismiss
-     */
-    public static final int FINGERPRINT_ENROLL_ENROLLING_ACTION_DISMISS_ICON_TOUCH_DIALOG = 2;
-
-    /**
      * Has got latest cancelled event due to user skip
      */
-    public static final int FINGERPRINT_ENROLL_ENROLLING_CANCELED_BECAUSE_USER_SKIP = 3;
+    public static final int FINGERPRINT_ENROLL_ENROLLING_CANCELED_BECAUSE_USER_SKIP = 2;
 
     /**
      * Has got latest cancelled event due to back key
      */
-    public static final int FINGERPRINT_ENROLL_ENROLLING_CANCELED_BECAUSE_BACK_PRESSED = 4;
+    public static final int FINGERPRINT_ENROLL_ENROLLING_CANCELED_BECAUSE_BACK_PRESSED = 3;
 
     @IntDef(prefix = { "FINGERPRINT_ENROLL_ENROLLING_ACTION_" }, value = {
             FINGERPRINT_ENROLL_ENROLLING_ACTION_DONE,
             FINGERPRINT_ENROLL_ENROLLING_ACTION_SHOW_ICON_TOUCH_DIALOG,
-            FINGERPRINT_ENROLL_ENROLLING_ACTION_DISMISS_ICON_TOUCH_DIALOG,
             FINGERPRINT_ENROLL_ENROLLING_CANCELED_BECAUSE_USER_SKIP,
             FINGERPRINT_ENROLL_ENROLLING_CANCELED_BECAUSE_BACK_PRESSED
     })
@@ -116,7 +110,6 @@
     private final Vibrator mVibrator;
 
     private final MutableLiveData<Integer> mActionLiveData = new MutableLiveData<>();
-    private final MutableLiveData<Integer> mIconTouchDialogLiveData = new MutableLiveData<>();
     private final MutableLiveData<ErrorDialogData> mErrorDialogLiveData = new MutableLiveData<>();
     private final MutableLiveData<Integer> mErrorDialogActionLiveData = new MutableLiveData<>();
 
@@ -234,17 +227,6 @@
     }
 
     /**
-     * Icon touch dialog dismiss
-     */
-    public void onIconTouchDialogDismiss() {
-        final int action = FINGERPRINT_ENROLL_ENROLLING_ACTION_DISMISS_ICON_TOUCH_DIALOG;
-        if (DEBUG) {
-            Log.d(TAG, "onIconTouchDialogDismiss, post action " + action);
-        }
-        mActionLiveData.postValue(action);
-    }
-
-    /**
      * get enroll stage threshold
      */
     public float getEnrollStageThreshold(int index) {
diff --git a/src/com/android/settings/bluetooth/RequestPermissionActivity.java b/src/com/android/settings/bluetooth/RequestPermissionActivity.java
index 588bc73..620cfb0 100644
--- a/src/com/android/settings/bluetooth/RequestPermissionActivity.java
+++ b/src/com/android/settings/bluetooth/RequestPermissionActivity.java
@@ -42,6 +42,8 @@
 import com.android.settings.R;
 import com.android.settingslib.bluetooth.BluetoothDiscoverableTimeoutReceiver;
 
+import kotlin.Unit;
+
 import java.time.Duration;
 
 /**
@@ -100,12 +102,15 @@
 
                 case BluetoothAdapter.STATE_ON:
                 case BluetoothAdapter.STATE_TURNING_ON: {
-                    Intent intent = new Intent(this, RequestPermissionHelperActivity.class);
-                    intent.putExtra(RequestPermissionHelperActivity.EXTRA_APP_LABEL, mAppLabel);
-                    intent.setAction(RequestPermissionHelperActivity
-                                .ACTION_INTERNAL_REQUEST_BT_OFF);
-
-                    startActivityForResult(intent, 0);
+                    RequestPermissionHelper.INSTANCE.requestDisable(this, mAppLabel,
+                            () -> {
+                                onDisableConfirmed();
+                                return Unit.INSTANCE;
+                            },
+                            () -> {
+                                cancelAndFinish();
+                                return Unit.INSTANCE;
+                            });
                 } break;
 
                 default: {
@@ -126,18 +131,17 @@
                      * case via the broadcast receiver.
                      */
 
-                    /*
-                     * Start the helper activity to:
-                     * 1) ask the user about enabling bt AND discovery
-                     * 2) enable BT upon confirmation
-                     */
-                    Intent intent = new Intent(this, RequestPermissionHelperActivity.class);
-                    intent.setAction(RequestPermissionHelperActivity.ACTION_INTERNAL_REQUEST_BT_ON);
-                    intent.putExtra(RequestPermissionHelperActivity.EXTRA_APP_LABEL, mAppLabel);
-                    if (mRequest == REQUEST_ENABLE_DISCOVERABLE) {
-                        intent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, mTimeout);
-                    }
-                    startActivityForResult(intent, 0);
+                    // Start the helper activity to ask the user about enabling bt AND discovery
+                    RequestPermissionHelper.INSTANCE.requestEnable(this, mAppLabel,
+                            mRequest == REQUEST_ENABLE_DISCOVERABLE ? mTimeout : -1,
+                            () -> {
+                                onEnableConfirmed();
+                                return Unit.INSTANCE;
+                            },
+                            () -> {
+                                cancelAndFinish();
+                                return Unit.INSTANCE;
+                            });
                 } break;
 
                 case BluetoothAdapter.STATE_ON: {
@@ -202,42 +206,27 @@
         mDialog.show();
     }
 
-    @Override
-    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
-        if (resultCode != Activity.RESULT_OK) {
-            cancelAndFinish();
-            return;
+    private void onEnableConfirmed() {
+        mBluetoothAdapter.enable();
+        if (mBluetoothAdapter.getState() == BluetoothAdapter.STATE_ON) {
+            proceedAndFinish();
+        } else {
+            // If BT is not up yet, show "Turning on Bluetooth..."
+            mReceiver = new StateChangeReceiver();
+            registerReceiver(mReceiver, new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED));
+            createDialog();
         }
+    }
 
-        switch (mRequest) {
-            case REQUEST_ENABLE:
-            case REQUEST_ENABLE_DISCOVERABLE: {
-                if (mBluetoothAdapter.getState() == BluetoothAdapter.STATE_ON) {
-                    proceedAndFinish();
-                } else {
-                    // If BT is not up yet, show "Turning on Bluetooth..."
-                    mReceiver = new StateChangeReceiver();
-                    registerReceiver(mReceiver, new IntentFilter(
-                            BluetoothAdapter.ACTION_STATE_CHANGED));
-                    createDialog();
-                }
-            } break;
-
-            case REQUEST_DISABLE: {
-                if (mBluetoothAdapter.getState() == BluetoothAdapter.STATE_OFF) {
-                    proceedAndFinish();
-                } else {
-                    // If BT is not up yet, show "Turning off Bluetooth..."
-                    mReceiver = new StateChangeReceiver();
-                    registerReceiver(mReceiver, new IntentFilter(
-                            BluetoothAdapter.ACTION_STATE_CHANGED));
-                    createDialog();
-                }
-            } break;
-
-            default: {
-                cancelAndFinish();
-            } break;
+    private void onDisableConfirmed() {
+        mBluetoothAdapter.disable();
+        if (mBluetoothAdapter.getState() == BluetoothAdapter.STATE_OFF) {
+            proceedAndFinish();
+        } else {
+            // If BT is not up yet, show "Turning off Bluetooth..."
+            mReceiver = new StateChangeReceiver();
+            registerReceiver(mReceiver, new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED));
+            createDialog();
         }
     }
 
diff --git a/src/com/android/settings/bluetooth/RequestPermissionHelper.kt b/src/com/android/settings/bluetooth/RequestPermissionHelper.kt
new file mode 100644
index 0000000..000a7d1
--- /dev/null
+++ b/src/com/android/settings/bluetooth/RequestPermissionHelper.kt
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2023 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.content.Context
+import android.os.UserManager
+import androidx.appcompat.app.AlertDialog
+import com.android.settings.R
+import com.android.settingslib.spaprivileged.framework.common.devicePolicyManager
+import com.android.settingslib.spaprivileged.framework.common.userManager
+
+object RequestPermissionHelper {
+    fun requestEnable(
+        context: Context,
+        appLabel: CharSequence?,
+        timeout: Int,
+        onAllow: () -> Unit,
+        onDeny: () -> Unit,
+    ) {
+        if (context.resources.getBoolean(R.bool.auto_confirm_bluetooth_activation_dialog)) {
+            // Don't even show the dialog if configured this way
+            onAllow()
+            return
+        }
+        AlertDialog.Builder(context).apply {
+            setMessage(context.getEnableMessage(timeout, appLabel))
+            setPositiveButton(R.string.allow) { _, _ ->
+                if (context.isDisallowBluetooth()) onDeny() else onAllow()
+            }
+            setNegativeButton(R.string.deny) { _, _ -> onDeny() }
+            setOnCancelListener { onDeny() }
+        }.show()
+    }
+
+    fun requestDisable(
+        context: Context,
+        appLabel: CharSequence?,
+        onAllow: () -> Unit,
+        onDeny: () -> Unit,
+    ) {
+        if (context.resources.getBoolean(R.bool.auto_confirm_bluetooth_activation_dialog)) {
+            // Don't even show the dialog if configured this way
+            onAllow()
+            return
+        }
+        AlertDialog.Builder(context).apply {
+            setMessage(context.getDisableMessage(appLabel))
+            setPositiveButton(R.string.allow) { _, _ -> onAllow() }
+            setNegativeButton(R.string.deny) { _, _ -> onDeny() }
+            setOnCancelListener { onDeny() }
+        }.show()
+    }
+}
+
+// If Bluetooth is disallowed, don't try to enable it, show policy transparency message instead.
+private fun Context.isDisallowBluetooth() =
+    if (userManager.hasUserRestriction(UserManager.DISALLOW_BLUETOOTH)) {
+        devicePolicyManager.createAdminSupportIntent(UserManager.DISALLOW_BLUETOOTH)
+            ?.let { startActivity(it) }
+        true
+    } else false
+
+private fun Context.getEnableMessage(timeout: Int, name: CharSequence?): String = when {
+    timeout < 0 -> when (name) {
+        null -> getString(R.string.bluetooth_ask_enablement_no_name)
+        else -> getString(R.string.bluetooth_ask_enablement, name)
+    }
+
+    timeout == BluetoothDiscoverableEnabler.DISCOVERABLE_TIMEOUT_NEVER -> when (name) {
+        null -> getString(R.string.bluetooth_ask_enablement_and_lasting_discovery_no_name)
+        else -> getString(R.string.bluetooth_ask_enablement_and_lasting_discovery, name)
+    }
+
+    else -> when (name) {
+        null -> getString(R.string.bluetooth_ask_enablement_and_discovery_no_name, timeout)
+        else -> getString(R.string.bluetooth_ask_enablement_and_discovery, name, timeout)
+    }
+}
+
+private fun Context.getDisableMessage(name: CharSequence?): String =
+    when (name) {
+        null -> getString(R.string.bluetooth_ask_disablement_no_name)
+        else -> getString(R.string.bluetooth_ask_disablement, name)
+    }
diff --git a/src/com/android/settings/bluetooth/RequestPermissionHelperActivity.java b/src/com/android/settings/bluetooth/RequestPermissionHelperActivity.java
deleted file mode 100644
index 99ac928..0000000
--- a/src/com/android/settings/bluetooth/RequestPermissionHelperActivity.java
+++ /dev/null
@@ -1,178 +0,0 @@
-/*
- * Copyright (C) 2009 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.Activity;
-import android.app.admin.DevicePolicyManager;
-import android.bluetooth.BluetoothAdapter;
-import android.content.DialogInterface;
-import android.content.Intent;
-import android.os.Bundle;
-import android.os.UserManager;
-import android.util.Log;
-
-import com.android.internal.app.AlertActivity;
-import com.android.internal.app.AlertController;
-import com.android.settings.R;
-
-/**
- * RequestPermissionHelperActivity asks the user whether to toggle Bluetooth.
- *
- * TODO: This activity isn't needed - this should be folded in RequestPermissionActivity
- */
-public class RequestPermissionHelperActivity extends AlertActivity implements
-        DialogInterface.OnClickListener {
-    private static final String TAG = "RequestPermissionHelperActivity";
-
-    public static final String ACTION_INTERNAL_REQUEST_BT_ON =
-            "com.android.settings.bluetooth.ACTION_INTERNAL_REQUEST_BT_ON";
-
-    public static final String ACTION_INTERNAL_REQUEST_BT_OFF =
-            "com.android.settings.bluetooth.ACTION_INTERNAL_REQUEST_BT_OFF";
-
-    public static final String EXTRA_APP_LABEL =
-            "com.android.settings.bluetooth.extra.APP_LABEL";
-
-    private BluetoothAdapter mBluetoothAdapter;
-
-    private CharSequence mAppLabel;
-
-    private int mTimeout = -1;
-
-    private int mRequest;
-
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-
-        setResult(RESULT_CANCELED);
-
-        // Note: initializes mBluetoothAdapter and returns true on error
-        if (!parseIntent()) {
-            finish();
-            return;
-        }
-
-        if (getResources().getBoolean(R.bool.auto_confirm_bluetooth_activation_dialog)) {
-            // Don't even show the dialog if configured this way
-            onClick(null, BUTTON_POSITIVE);
-            dismiss();
-        }
-
-        createDialog();
-    }
-
-    void createDialog() {
-        final AlertController.AlertParams p = mAlertParams;
-
-        switch (mRequest) {
-            case RequestPermissionActivity.REQUEST_ENABLE: {
-                if (mTimeout < 0) {
-                    p.mMessage = mAppLabel != null
-                            ? getString(R.string.bluetooth_ask_enablement, mAppLabel)
-                            : getString(R.string.bluetooth_ask_enablement_no_name);
-                } else if (mTimeout == BluetoothDiscoverableEnabler.DISCOVERABLE_TIMEOUT_NEVER) {
-                    p.mMessage = mAppLabel != null
-                            ? getString(
-                                   R.string.bluetooth_ask_enablement_and_lasting_discovery,
-                                   mAppLabel)
-                            : getString(
-                                   R.string.bluetooth_ask_enablement_and_lasting_discovery_no_name);
-                } else {
-                    p.mMessage = mAppLabel != null
-                            ? getString(R.string.bluetooth_ask_enablement_and_discovery,
-                                    mAppLabel, mTimeout)
-                            : getString(R.string.bluetooth_ask_enablement_and_discovery_no_name,
-                                    mTimeout);
-                }
-            } break;
-
-            case RequestPermissionActivity.REQUEST_DISABLE: {
-                p.mMessage = mAppLabel != null
-                        ? getString(R.string.bluetooth_ask_disablement, mAppLabel)
-                        : getString(R.string.bluetooth_ask_disablement_no_name);
-            } break;
-        }
-
-        p.mPositiveButtonText = getString(R.string.allow);
-        p.mPositiveButtonListener = this;
-        p.mNegativeButtonText = getString(R.string.deny);
-
-        setupAlert();
-    }
-
-    public void onClick(DialogInterface dialog, int which) {
-        switch (mRequest) {
-            case RequestPermissionActivity.REQUEST_ENABLE:
-            case RequestPermissionActivity.REQUEST_ENABLE_DISCOVERABLE: {
-                UserManager userManager = getSystemService(UserManager.class);
-                if (userManager.hasUserRestriction(UserManager.DISALLOW_BLUETOOTH)) {
-                    // If Bluetooth is disallowed, don't try to enable it, show policy transparency
-                    // message instead.
-                    DevicePolicyManager dpm = getSystemService(DevicePolicyManager.class);
-                    Intent intent = dpm.createAdminSupportIntent(UserManager.DISALLOW_BLUETOOTH);
-                    if (intent != null) {
-                        startActivity(intent);
-                    }
-                } else {
-                    mBluetoothAdapter.enable();
-                    setResult(Activity.RESULT_OK);
-                }
-            } break;
-
-            case RequestPermissionActivity.REQUEST_DISABLE: {
-                mBluetoothAdapter.disable();
-                setResult(Activity.RESULT_OK);
-            } break;
-        }
-    }
-
-    /**
-     * Parse the received Intent and initialize mBluetoothAdapter.
-     * @return true if an error occurred; false otherwise
-     */
-    private boolean parseIntent() {
-        Intent intent = getIntent();
-        if (intent == null) {
-            return false;
-        }
-
-        String action = intent.getAction();
-        if (ACTION_INTERNAL_REQUEST_BT_ON.equals(action)) {
-            mRequest = RequestPermissionActivity.REQUEST_ENABLE;
-            if (intent.hasExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION)) {
-                // Value used for display purposes. Not range checking.
-                mTimeout = intent.getIntExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION,
-                        BluetoothDiscoverableEnabler.DEFAULT_DISCOVERABLE_TIMEOUT);
-            }
-        } else if (ACTION_INTERNAL_REQUEST_BT_OFF.equals(action)) {
-            mRequest = RequestPermissionActivity.REQUEST_DISABLE;
-        } else {
-            return false;
-        }
-
-        mAppLabel = getIntent().getCharSequenceExtra(EXTRA_APP_LABEL);
-
-        mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
-        if (mBluetoothAdapter == null) {
-            Log.e(TAG, "Error: there's a problem starting Bluetooth");
-            return false;
-        }
-
-        return true;
-    }
-}
diff --git a/src/com/android/settings/connecteddevice/BluetoothDashboardFragment.java b/src/com/android/settings/connecteddevice/BluetoothDashboardFragment.java
index b30aee4..66f2f1b 100644
--- a/src/com/android/settings/connecteddevice/BluetoothDashboardFragment.java
+++ b/src/com/android/settings/connecteddevice/BluetoothDashboardFragment.java
@@ -25,6 +25,7 @@
 
 import com.android.settings.R;
 import com.android.settings.SettingsActivity;
+import com.android.settings.Utils;
 import com.android.settings.bluetooth.BluetoothDeviceRenamePreferenceController;
 import com.android.settings.bluetooth.BluetoothSwitchPreferenceController;
 import com.android.settings.dashboard.DashboardFragment;
@@ -45,8 +46,6 @@
 
     private static final String TAG = "BluetoothDashboardFrag";
     private static final String KEY_BLUETOOTH_SCREEN_FOOTER = "bluetooth_screen_footer";
-    private static final String SETTINGS_PACKAGE_NAME = "com.android.settings";
-    private static final String SYSTEMUI_PACKAGE_NAME = "com.android.systemui";
     private static final String SLICE_ACTION = "com.android.settings.SEARCH_RESULT_TRAMPOLINE";
     private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
 
@@ -112,8 +111,8 @@
     @VisibleForTesting
     boolean isAlwaysDiscoverable(String callingAppPackageName, String action) {
         return TextUtils.equals(SLICE_ACTION, action) ? false
-            : TextUtils.equals(SETTINGS_PACKAGE_NAME, callingAppPackageName)
-                || TextUtils.equals(SYSTEMUI_PACKAGE_NAME, callingAppPackageName);
+            : TextUtils.equals(Utils.SETTINGS_PACKAGE_NAME, callingAppPackageName)
+                || TextUtils.equals(Utils.SYSTEMUI_PACKAGE_NAME, callingAppPackageName);
     }
 
     /**
diff --git a/src/com/android/settings/connecteddevice/ConnectedDeviceDashboardFragment.java b/src/com/android/settings/connecteddevice/ConnectedDeviceDashboardFragment.java
index 3c6077e..9286b81 100644
--- a/src/com/android/settings/connecteddevice/ConnectedDeviceDashboardFragment.java
+++ b/src/com/android/settings/connecteddevice/ConnectedDeviceDashboardFragment.java
@@ -28,6 +28,7 @@
 
 import com.android.settings.R;
 import com.android.settings.SettingsActivity;
+import com.android.settings.Utils;
 import com.android.settings.core.SettingsUIDeviceConfig;
 import com.android.settings.dashboard.DashboardFragment;
 import com.android.settings.search.BaseSearchIndexProvider;
@@ -38,7 +39,6 @@
 public class ConnectedDeviceDashboardFragment extends DashboardFragment {
 
     private static final String TAG = "ConnectedDeviceFrag";
-    private static final String SYSTEMUI_PACKAGE_NAME = "com.android.systemui";
     private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
     private static final String SLICE_ACTION = "com.android.settings.SEARCH_RESULT_TRAMPOLINE";
 
@@ -92,8 +92,8 @@
     @VisibleForTesting
     boolean isAlwaysDiscoverable(String callingAppPackageName, String action) {
         return TextUtils.equals(SLICE_ACTION, action) ? false
-                : TextUtils.equals(SETTINGS_PACKAGE_NAME, callingAppPackageName)
-                || TextUtils.equals(SYSTEMUI_PACKAGE_NAME, callingAppPackageName);
+                : TextUtils.equals(Utils.SETTINGS_PACKAGE_NAME, callingAppPackageName)
+                || TextUtils.equals(Utils.SYSTEMUI_PACKAGE_NAME, callingAppPackageName);
     }
 
     /**
diff --git a/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java b/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java
index 68fe08e..65d3be0 100644
--- a/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java
+++ b/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java
@@ -16,6 +16,7 @@
 
 package com.android.settings.development;
 
+import static android.provider.Settings.Global.DEVELOPMENT_SETTINGS_ENABLED;
 import static android.service.quicksettings.TileService.ACTION_QS_TILE_PREFERENCES;
 
 import android.app.Activity;
@@ -27,12 +28,18 @@
 import android.bluetooth.BluetoothProfile;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
+import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.database.ContentObserver;
+import android.net.Uri;
 import android.os.Bundle;
+import android.os.Handler;
+import android.os.Looper;
 import android.os.SystemProperties;
 import android.os.UserManager;
+import android.provider.Settings;
 import android.text.TextUtils;
 import android.util.Log;
 import android.view.LayoutInflater;
@@ -173,11 +180,48 @@
         }
     };
 
+    private final Uri mDevelopEnabled = Settings.Global.getUriFor(DEVELOPMENT_SETTINGS_ENABLED);
+    private final ContentObserver mDeveloperSettingsObserver = new ContentObserver(new Handler(
+            Looper.getMainLooper())) {
+
+        @Override
+        public void onChange(boolean selfChange, Uri uri) {
+            super.onChange(selfChange, uri);
+            final boolean developmentEnabledState =
+                    DevelopmentSettingsEnabler.isDevelopmentSettingsEnabled(getContext());
+            final boolean switchState = mSwitchBar.isChecked();
+
+            // when developer options is enabled, but it is disabled by other privilege apps like:
+            // adb command, we should disable all items and finish the activity.
+            if (developmentEnabledState != switchState) {
+                if (developmentEnabledState) {
+                    return;
+                }
+                disableDeveloperOptions();
+                getActivity().runOnUiThread(() -> finishFragment());
+            }
+        }
+    };
+
     public DevelopmentSettingsDashboardFragment() {
         super(UserManager.DISALLOW_DEBUGGING_FEATURES);
     }
 
     @Override
+    public void onStart() {
+        super.onStart();
+        final ContentResolver cr = getContext().getContentResolver();
+        cr.registerContentObserver(mDevelopEnabled, false, mDeveloperSettingsObserver);
+    }
+
+    @Override
+    public void onStop() {
+        super.onStop();
+        final ContentResolver cr = getContext().getContentResolver();
+        cr.unregisterContentObserver(mDeveloperSettingsObserver);
+    }
+
+    @Override
     public void onCreate(Bundle icicle) {
         super.onCreate(icicle);
         SearchMenuController.init(this);
@@ -689,6 +733,7 @@
         controllers.add(new PhantomProcessPreferenceController(context));
         controllers.add(new ContrastPreferenceController(
                 context, context.getSystemService(UiModeManager.class)));
+        controllers.add(new ForceEnableNotesRolePreferenceController(context));
 
         return controllers;
     }
diff --git a/src/com/android/settings/development/ForceEnableNotesRolePreferenceController.java b/src/com/android/settings/development/ForceEnableNotesRolePreferenceController.java
new file mode 100644
index 0000000..7821bec
--- /dev/null
+++ b/src/com/android/settings/development/ForceEnableNotesRolePreferenceController.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2023 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.
+ */
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.development;
+
+import static android.os.UserHandle.USER_CURRENT;
+
+import android.content.Context;
+import android.content.om.IOverlayManager;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+
+import androidx.preference.Preference;
+import androidx.preference.SwitchPreference;
+
+import com.android.internal.R;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.settings.core.PreferenceControllerMixin;
+import com.android.settingslib.development.DeveloperOptionsPreferenceController;
+
+public class ForceEnableNotesRolePreferenceController
+        extends DeveloperOptionsPreferenceController
+        implements Preference.OnPreferenceChangeListener, PreferenceControllerMixin {
+
+    private static final String NOTES_ROLE_ENABLED_KEY =
+            "force_enable_notes_role";
+
+    private static final String OVERLAY_PACKAGE_NAME =
+            "com.android.role.notes.enabled";
+
+    private final IOverlayManager mOverlayManager;
+
+    public ForceEnableNotesRolePreferenceController(Context context) {
+        super(context);
+        mOverlayManager = IOverlayManager.Stub.asInterface(
+                ServiceManager.getService(Context.OVERLAY_SERVICE));
+    }
+
+    @Override
+    public String getPreferenceKey() {
+        return NOTES_ROLE_ENABLED_KEY;
+    }
+
+    @Override
+    public boolean onPreferenceChange(Preference preference, Object newValue) {
+        setEnabled((boolean) newValue);
+        return true;
+    }
+
+    @Override
+    public void updateState(Preference preference) {
+        ((SwitchPreference) mPreference).setChecked(isEnabled());
+    }
+
+    @Override
+    protected void onDeveloperOptionsSwitchDisabled() {
+        super.onDeveloperOptionsSwitchDisabled();
+        ((SwitchPreference) mPreference).setChecked(false);
+        setEnabled(false);
+    }
+
+    @VisibleForTesting
+    protected boolean isEnabled() {
+        return mContext.getResources().getBoolean(R.bool.config_enableDefaultNotes);
+    }
+
+    @VisibleForTesting
+    protected void setEnabled(boolean enabled) {
+        try {
+            mOverlayManager.setEnabled(OVERLAY_PACKAGE_NAME, enabled, USER_CURRENT);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+}
diff --git a/src/com/android/settings/display/AmbientDisplayAlwaysOnPreferenceController.java b/src/com/android/settings/display/AmbientDisplayAlwaysOnPreferenceController.java
index bf81727..e0e25df 100644
--- a/src/com/android/settings/display/AmbientDisplayAlwaysOnPreferenceController.java
+++ b/src/com/android/settings/display/AmbientDisplayAlwaysOnPreferenceController.java
@@ -121,7 +121,7 @@
         final PowerManager powerManager = context.getSystemService(PowerManager.class);
         final PackageManager packageManager = context.getPackageManager();
         final String packageName = context.getString(
-                com.android.internal.R.string.config_defaultWellbeingPackage);
+                com.android.internal.R.string.config_systemWellbeing);
         try {
             uid = packageManager.getApplicationInfo(packageName, /* flags= */ 0).uid;
         } catch (PackageManager.NameNotFoundException e) {
diff --git a/src/com/android/settings/display/darkmode/BedtimeSettings.java b/src/com/android/settings/display/darkmode/BedtimeSettings.java
index 28121b2..5b9b4d2 100644
--- a/src/com/android/settings/display/darkmode/BedtimeSettings.java
+++ b/src/com/android/settings/display/darkmode/BedtimeSettings.java
@@ -37,7 +37,7 @@
         mContext = context;
         mPackageManager = context.getPackageManager();
         mWellbeingPackage = mContext.getResources().getString(
-                com.android.internal.R.string.config_defaultWellbeingPackage);
+                com.android.internal.R.string.config_systemWellbeing);
     }
 
     /**
diff --git a/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImpl.java b/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImpl.java
index ac72ced..496cfab 100644
--- a/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImpl.java
+++ b/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImpl.java
@@ -16,6 +16,8 @@
 
 package com.android.settings.fuelgauge;
 
+import static com.android.settings.Utils.SYSTEMUI_PACKAGE_NAME;
+
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.PackageManager;
@@ -35,9 +37,8 @@
 
     private static final String PACKAGE_CALENDAR_PROVIDER = "com.android.providers.calendar";
     private static final String PACKAGE_MEDIA_PROVIDER = "com.android.providers.media";
-    private static final String PACKAGE_SYSTEMUI = "com.android.systemui";
     private static final String[] PACKAGES_SYSTEM = {PACKAGE_MEDIA_PROVIDER,
-            PACKAGE_CALENDAR_PROVIDER, PACKAGE_SYSTEMUI};
+            PACKAGE_CALENDAR_PROVIDER, SYSTEMUI_PACKAGE_NAME};
 
     protected PackageManager mPackageManager;
     protected Context mContext;
diff --git a/src/com/android/settings/fuelgauge/batterytip/BatteryTipLoader.java b/src/com/android/settings/fuelgauge/batterytip/BatteryTipLoader.java
index e622f4c..8e9d485 100644
--- a/src/com/android/settings/fuelgauge/batterytip/BatteryTipLoader.java
+++ b/src/com/android/settings/fuelgauge/batterytip/BatteryTipLoader.java
@@ -72,7 +72,7 @@
                         .detect());
         tips.add(new BatteryDefenderDetector(batteryInfo, context).detect());
         tips.add(new DockDefenderDetector(batteryInfo, context).detect());
-        tips.add(new IncompatibleChargerDetector(context, batteryInfo).detect());
+        tips.add(new IncompatibleChargerDetector(context).detect());
         Collections.sort(tips);
         return tips;
     }
diff --git a/src/com/android/settings/fuelgauge/batterytip/detectors/IncompatibleChargerDetector.java b/src/com/android/settings/fuelgauge/batterytip/detectors/IncompatibleChargerDetector.java
index 483e37d..cfd9a2c 100644
--- a/src/com/android/settings/fuelgauge/batterytip/detectors/IncompatibleChargerDetector.java
+++ b/src/com/android/settings/fuelgauge/batterytip/detectors/IncompatibleChargerDetector.java
@@ -18,7 +18,6 @@
 import android.content.Context;
 import android.util.Log;
 
-import com.android.settings.fuelgauge.BatteryInfo;
 import com.android.settings.fuelgauge.batterytip.tips.BatteryTip;
 import com.android.settings.fuelgauge.batterytip.tips.IncompatibleChargerTip;
 import com.android.settingslib.Utils;
@@ -28,25 +27,17 @@
     private static final String TAG = "IncompatibleChargerDetector";
 
     private final Context mContext;
-    private final BatteryInfo mBatteryInfo;
 
-    public IncompatibleChargerDetector(Context context, BatteryInfo batteryInfo) {
+    public IncompatibleChargerDetector(Context context) {
         mContext = context;
-        mBatteryInfo = batteryInfo;
     }
 
     @Override
     public BatteryTip detect() {
-        int state = BatteryTip.StateType.INVISIBLE;
-        boolean isIncompatibleCharging = false;
-
-        // Check incompatible charging state if the device is plugged.
-        if (mBatteryInfo.pluggedStatus != 0) {
-            isIncompatibleCharging = Utils.containsIncompatibleChargers(mContext, TAG);
-            if (isIncompatibleCharging) {
-                state = BatteryTip.StateType.NEW;
-            }
-        }
+        final boolean isIncompatibleCharging =
+                Utils.containsIncompatibleChargers(mContext, TAG);
+        final int state = isIncompatibleCharging
+                ? BatteryTip.StateType.NEW : BatteryTip.StateType.INVISIBLE;
         Log.d(TAG, "detect() state= " + state + " isIncompatibleCharging: "
                 + isIncompatibleCharging);
         return new IncompatibleChargerTip(state);
diff --git a/src/com/android/settings/fuelgauge/batteryusage/BatteryChartPreferenceController.java b/src/com/android/settings/fuelgauge/batteryusage/BatteryChartPreferenceController.java
index d192e1a..67d3969 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/BatteryChartPreferenceController.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/BatteryChartPreferenceController.java
@@ -251,8 +251,7 @@
                     hourlyBatteryLevelsPerDay.getLevels(),
                     hourlyBatteryLevelsPerDay.getTimestamps(),
                     BatteryChartViewModel.AxisLabelPosition.BETWEEN_TRAPEZOIDS,
-                    mHourlyChartLabelTextGenerator.setLatestTimestamp(getLast(getLast(
-                            batteryLevelData.getHourlyBatteryLevelsPerDay()).getTimestamps()))));
+                    mHourlyChartLabelTextGenerator.updateSpecialCaseContext(batteryLevelData)));
         }
         refreshUi();
     }
@@ -296,6 +295,10 @@
         });
         mHourlyChartView = hourlyChartView;
         mHourlyChartView.setOnSelectListener(trapezoidIndex -> {
+            if (mDailyChartIndex == BatteryChartViewModel.SELECTED_INDEX_ALL) {
+                // This will happen when a daily slot and an hour slot are clicked together.
+                return;
+            }
             if (mHourlyChartIndex == trapezoidIndex) {
                 return;
             }
@@ -636,7 +639,11 @@
 
     private final class HourlyChartLabelTextGenerator implements
             BatteryChartViewModel.LabelTextGenerator {
-        private Long mLatestTimestamp;
+        private static final int FULL_CHARGE_BATTERY_LEVEL = 100;
+
+        private boolean mIsFromFullCharge;
+        private long mFistTimestamp;
+        private long mLatestTimestamp;
 
         @Override
         public String generateText(List<Long> timestamps, int index) {
@@ -644,24 +651,37 @@
                 // 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);
+            long timestamp = timestamps.get(index);
+            boolean showMinute = false;
+            if (Objects.equal(timestamp, mFistTimestamp)) {
+                if (mIsFromFullCharge) {
+                    showMinute = true;
+                } else {
+                    // starts from 7 days ago
+                    timestamp = TimestampUtils.getLastEvenHourTimestamp(timestamp);
+                }
+            }
+            return ConvertUtils.utcToLocalTimeHour(
+                    mContext, timestamp, mIs24HourFormat, showMinute);
         }
 
         @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)
                     : mContext.getString(R.string.battery_usage_timestamps_hyphen,
                             generateText(timestamps, index), generateText(timestamps, index + 1));
         }
 
-        public HourlyChartLabelTextGenerator setLatestTimestamp(Long latestTimestamp) {
-            this.mLatestTimestamp = latestTimestamp;
+        HourlyChartLabelTextGenerator updateSpecialCaseContext(
+                @NonNull final BatteryLevelData batteryLevelData) {
+            BatteryLevelData.PeriodBatteryLevelData firstDayLevelData =
+                    batteryLevelData.getHourlyBatteryLevelsPerDay().get(0);
+            this.mIsFromFullCharge =
+                    firstDayLevelData.getLevels().get(0) == FULL_CHARGE_BATTERY_LEVEL;
+            this.mFistTimestamp = firstDayLevelData.getTimestamps().get(0);
+            this.mLatestTimestamp = getLast(getLast(
+                    batteryLevelData.getHourlyBatteryLevelsPerDay()).getTimestamps());
             return this;
         }
     }
diff --git a/src/com/android/settings/fuelgauge/batteryusage/BatteryChartView.java b/src/com/android/settings/fuelgauge/batteryusage/BatteryChartView.java
index b17ccaa..445a5d1 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/BatteryChartView.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/BatteryChartView.java
@@ -16,6 +16,7 @@
 package com.android.settings.fuelgauge.batteryusage;
 
 import static com.android.settings.Utils.formatPercentage;
+import static com.android.settings.fuelgauge.batteryusage.BatteryChartViewModel.AxisLabelPosition.BETWEEN_TRAPEZOIDS;
 
 import static java.lang.Math.round;
 import static java.util.Objects.requireNonNull;
@@ -29,6 +30,7 @@
 import android.graphics.Path;
 import android.graphics.Rect;
 import android.os.Bundle;
+import android.util.ArraySet;
 import android.util.AttributeSet;
 import android.util.Log;
 import android.view.HapticFeedbackConstants;
@@ -52,13 +54,13 @@
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Locale;
+import java.util.Set;
 
 /** A widget component to draw chart graph. */
 public class BatteryChartView extends AppCompatImageView implements View.OnClickListener {
     private static final String TAG = "BatteryChartView";
 
     private static final int DIVIDER_COLOR = Color.parseColor("#CDCCC5");
-    private static final long UPDATE_STATE_DELAYED_TIME = 500L;
 
     /** A callback listener for selected group index is updated. */
     public interface OnSelectListener {
@@ -70,6 +72,7 @@
     private final Rect mIndent = new Rect();
     private final Rect[] mPercentageBounds = new Rect[]{new Rect(), new Rect(), new Rect()};
     private final List<Rect> mAxisLabelsBounds = new ArrayList<>();
+    private final Set<Integer> mLabelDrawnIndexes = new ArraySet<>();
 
     private BatteryChartViewModel mViewModel;
     private int mHoveredIndex = BatteryChartViewModel.SELECTED_INDEX_INVALID;
@@ -80,6 +83,7 @@
     private int mTrapezoidColor;
     private int mTrapezoidSolidColor;
     private int mTrapezoidHoverColor;
+    private int mDefaultTextColor;
     private int mTextPadding;
     private Paint mDividerPaint;
     private Paint mTrapezoidPaint;
@@ -134,6 +138,7 @@
             // Pre-draws the view first to load style atttributions into paint.
             textView.draw(new Canvas());
             mTextPaint = textView.getPaint();
+            mDefaultTextColor = mTextPaint.getColor();
         } else {
             mTextPaint = null;
         }
@@ -332,6 +337,7 @@
         final int height = getHeight() - mIndent.top - mIndent.bottom;
         // Draws the top divider line for 100% curve.
         float offsetY = mIndent.top + mDividerWidth * .5f;
+        mDividerPaint.setColor(DIVIDER_COLOR);
         canvas.drawLine(0, offsetY, width, offsetY, mDividerPaint);
         drawPercentage(canvas, /*index=*/ 0, offsetY);
 
@@ -351,6 +357,7 @@
     private void drawPercentage(Canvas canvas, int index, float offsetY) {
         if (mTextPaint != null) {
             mTextPaint.setTextAlign(Paint.Align.RIGHT);
+            mTextPaint.setColor(mDefaultTextColor);
             canvas.drawText(
                     mPercentages[index],
                     getWidth(),
@@ -367,18 +374,6 @@
         final float bottomY = getHeight() - mIndent.bottom;
         final float startY = bottomY - mDividerHeight;
         final float trapezoidSlotOffset = mTrapezoidHOffset + mDividerWidth * .5f;
-        // Draws each vertical dividers.
-        float startX = mDividerWidth * .5f;
-        for (int index = 0; index < dividerCount; index++) {
-            canvas.drawLine(startX, startY, startX, bottomY, mDividerPaint);
-            final float nextX = startX + mDividerWidth + unitWidth;
-            // Updates the trapezoid slots for drawing.
-            if (index < mTrapezoidSlots.length) {
-                mTrapezoidSlots[index].mLeft = round(startX + trapezoidSlotOffset);
-                mTrapezoidSlots[index].mRight = round(nextX - trapezoidSlotOffset);
-            }
-            startX = nextX;
-        }
         // Draws the axis label slot information.
         if (mViewModel != null) {
             final float baselineY = getHeight() - mTextPadding;
@@ -404,6 +399,26 @@
             }
             drawAxisLabels(canvas, axisLabelDisplayAreas, baselineY);
         }
+        // Draws each vertical dividers.
+        float startX = mDividerWidth * .5f;
+        for (int index = 0; index < dividerCount; index++) {
+            float dividerY = bottomY;
+            if (mViewModel.axisLabelPosition() == BETWEEN_TRAPEZOIDS
+                    && mLabelDrawnIndexes.contains(index)) {
+                mDividerPaint.setColor(mTrapezoidSolidColor);
+                dividerY += mDividerHeight / 4f;
+            } else {
+                mDividerPaint.setColor(DIVIDER_COLOR);
+            }
+            canvas.drawLine(startX, startY, startX, dividerY, mDividerPaint);
+            final float nextX = startX + mDividerWidth + unitWidth;
+            // Updates the trapezoid slots for drawing.
+            if (index < mTrapezoidSlots.length) {
+                mTrapezoidSlots[index].mLeft = round(startX + trapezoidSlotOffset);
+                mTrapezoidSlots[index].mRight = round(nextX - trapezoidSlotOffset);
+            }
+            startX = nextX;
+        }
     }
 
     /** Gets all the axis label texts displaying area positions if they are shown. */
@@ -432,9 +447,12 @@
 
     private void drawAxisLabels(Canvas canvas, final Rect[] displayAreas, final float baselineY) {
         final int lastIndex = displayAreas.length - 1;
+        mLabelDrawnIndexes.clear();
         // Suppose first and last labels are always able to draw.
         drawAxisLabelText(canvas, 0, displayAreas[0], baselineY);
+        mLabelDrawnIndexes.add(0);
         drawAxisLabelText(canvas, lastIndex, displayAreas[lastIndex], baselineY);
+        mLabelDrawnIndexes.add(lastIndex);
         drawAxisLabelsBetweenStartIndexAndEndIndex(canvas, displayAreas, 0, lastIndex, baselineY);
     }
 
@@ -458,6 +476,7 @@
                 return;
             }
             drawAxisLabelText(canvas, middleIndex, displayAreas[middleIndex], baselineY);
+            mLabelDrawnIndexes.add(middleIndex);
             drawAxisLabelsBetweenStartIndexAndEndIndex(
                     canvas, displayAreas, startIndex, middleIndex, baselineY);
             drawAxisLabelsBetweenStartIndexAndEndIndex(
@@ -471,7 +490,9 @@
                 return;
             }
             drawAxisLabelText(canvas, middleIndex1, displayAreas[middleIndex1], baselineY);
+            mLabelDrawnIndexes.add(middleIndex1);
             drawAxisLabelText(canvas, middleIndex2, displayAreas[middleIndex2], baselineY);
+            mLabelDrawnIndexes.add(middleIndex2);
             drawAxisLabelsBetweenStartIndexAndEndIndex(
                     canvas, displayAreas, startIndex, middleIndex1, baselineY);
             drawAxisLabelsBetweenStartIndexAndEndIndex(
@@ -488,12 +509,14 @@
 
     private void drawAxisLabelText(
             Canvas canvas, final int index, final Rect displayArea, final float baselineY) {
+        mTextPaint.setColor(mTrapezoidSolidColor);
         mTextPaint.setTextAlign(Paint.Align.CENTER);
         canvas.drawText(
                 mViewModel.getText(index),
                 displayArea.centerX(),
                 baselineY,
                 mTextPaint);
+        mLabelDrawnIndexes.add(index);
     }
 
     private void drawTrapezoids(Canvas canvas) {
diff --git a/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBreakdownController.java b/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBreakdownController.java
index 2121c60..cd1bdef 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBreakdownController.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBreakdownController.java
@@ -313,11 +313,8 @@
     @VisibleForTesting
     void removeAndCacheAllUnusedPreferences() {
         List<BatteryDiffEntry> entries = getBatteryDiffEntries();
-        Set<String> entryKeySet = new ArraySet<>();
-        for (BatteryDiffEntry entry : entries) {
-            entryKeySet.add(entry.getKey());
-        }
-
+        Set<String> entryKeySet = new ArraySet<>(entries.size());
+        entries.forEach(entry -> entryKeySet.add(entry.getKey()));
         final int prefsCount = mAppListPreferenceGroup.getPreferenceCount();
         for (int index = prefsCount - 1; index >= 0; index--) {
             final Preference pref = mAppListPreferenceGroup.getPreference(index);
diff --git a/src/com/android/settings/fuelgauge/batteryusage/ConvertUtils.java b/src/com/android/settings/fuelgauge/batteryusage/ConvertUtils.java
index c6c548f..2c98c4b 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/ConvertUtils.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/ConvertUtils.java
@@ -280,12 +280,12 @@
     }
 
     /** Converts UTC timestamp to local time hour data. */
-    public static String utcToLocalTimeHour(
-            final Context context, final long timestamp, final boolean is24HourFormat) {
+    public static String utcToLocalTimeHour(final Context context, final long timestamp,
+            final boolean is24HourFormat, final boolean showMinute) {
         final Locale locale = getLocale(context);
         // e.g. for 12-hour format: 9 PM
         // e.g. for 24-hour format: 09:00
-        final String skeleton = is24HourFormat ? "HHm" : "ha";
+        final String skeleton = is24HourFormat ? "HHm" : (showMinute ? "hma" : "ha");
         final String pattern = DateFormat.getBestDateTimePattern(locale, skeleton);
         return DateFormat.format(pattern, timestamp).toString();
     }
diff --git a/src/com/android/settings/fuelgauge/batteryusage/DataProcessor.java b/src/com/android/settings/fuelgauge/batteryusage/DataProcessor.java
index ec1a4be..9aee2f7 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/DataProcessor.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/DataProcessor.java
@@ -285,7 +285,6 @@
         final Map<Integer, Map<Integer, Map<Long, Map<String, List<AppUsagePeriod>>>>> resultMap =
                 new ArrayMap<>();
 
-        final long dailySize = hourlyBatteryLevelsPerDay.size();
         for (int dailyIndex = 0; dailyIndex < hourlyBatteryLevelsPerDay.size(); dailyIndex++) {
             final Map<Integer, Map<Long, Map<String, List<AppUsagePeriod>>>> dailyMap =
                     new ArrayMap<>();
@@ -294,21 +293,9 @@
                 continue;
             }
             final List<Long> timestamps = hourlyBatteryLevelsPerDay.get(dailyIndex).getTimestamps();
-            final long hourlySize = timestamps.size() - 1;
             for (int hourlyIndex = 0; hourlyIndex < timestamps.size() - 1; hourlyIndex++) {
-                // The start slot timestape is the near hour timestamp instead of the last full
-                // charge time. So use rawStartTimestamp instead of reading the timestamp from
-                // hourlyBatteryLevelsPerDay here.
-                final long startTimestamp =
-                        dailyIndex == 0 && hourlyIndex == 0 && !sDebug
-                                ? rawStartTimestamp : timestamps.get(hourlyIndex);
-                // The final slot is to show the data from last even hour until now but the
-                // timestamp in hourlyBatteryLevelsPerDay is not the real value. So use current
-                // timestamp instead of reading the timestamp from hourlyBatteryLevelsPerDay here.
-                final long endTimestamp =
-                        dailyIndex == dailySize - 1 && hourlyIndex == hourlySize - 1 && !sDebug
-                                ? System.currentTimeMillis() : timestamps.get(hourlyIndex + 1);
-
+                final long startTimestamp = timestamps.get(hourlyIndex);
+                final long endTimestamp = timestamps.get(hourlyIndex + 1);
                 // Gets the app usage event list for this hourly slot first.
                 final List<AppUsageEvent> hourlyAppUsageEventList =
                         getAppUsageEventListWithinTimeRangeWithBuffer(
@@ -463,11 +450,8 @@
         Collections.sort(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, currentTime, isFromFullCharge,
-                batteryHistoryMap, resultMap);
+                context, rawTimestampList, expectedTimestampList, batteryHistoryMap, resultMap);
         Log.d(TAG, String.format("getHistoryMapWithExpectedTimestamps() size=%d in %d/ms",
                 resultMap.size(), (System.currentTimeMillis() - startTime)));
         return resultMap;
@@ -496,8 +480,9 @@
     }
 
     /**
-     * Computes expected timestamp slots for last full charge, which will return hourly timestamps
-     * between start and end two even hour values.
+     * Computes expected timestamp slots. The start timestamp is the last full charge time.
+     * The end timestamp is current time. The middle timestamps are the sharp hour timestamps
+     * between the start and end timestamps.
      */
     @VisibleForTesting
     static List<Long> getTimestampSlots(final List<Long> rawTimestampList, final long currentTime) {
@@ -505,19 +490,18 @@
         if (rawTimestampList.isEmpty()) {
             return timestampSlots;
         }
-        final long rawStartTimestamp = rawTimestampList.get(0);
-        // 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 first even hour after the current time as the end.
-        final long endTimestamp = getFirstEvenHourAfterTimestamp(currentTime);
+        final long startTimestamp = rawTimestampList.get(0);
+        final long endTimestamp = currentTime;
         // If the start timestamp is later or equal the end one, return the empty list.
         if (startTimestamp >= endTimestamp) {
             return timestampSlots;
         }
-        for (long timestamp = startTimestamp; timestamp <= endTimestamp;
-                timestamp += DateUtils.HOUR_IN_MILLIS) {
+        timestampSlots.add(startTimestamp);
+        for (long timestamp = TimestampUtils.getNextHourTimestamp(startTimestamp);
+                timestamp < endTimestamp; timestamp += DateUtils.HOUR_IN_MILLIS) {
             timestampSlots.add(timestamp);
         }
+        timestampSlots.add(endTimestamp);
         return timestampSlots;
     }
 
@@ -539,35 +523,39 @@
         }
         final long startTime = timestampList.get(0);
         final long endTime = timestampList.get(timestampList.size() - 1);
-        // If the timestamp diff is smaller than MIN_TIME_SLOT, returns the empty list directly.
-        if (endTime - startTime < MIN_TIME_SLOT) {
-            return dailyTimestampList;
+        for (long timestamp = startTime; timestamp < endTime;
+                timestamp = TimestampUtils.getNextDayTimestamp(timestamp)) {
+            dailyTimestampList.add(timestamp);
         }
-        long nextDay = getTimestampOfNextDay(startTime);
-        // Only if the timestamp diff in the first day is bigger than MIN_TIME_SLOT, start from the
-        // first day. Otherwise, start from the second day.
-        if (nextDay - startTime >= MIN_TIME_SLOT) {
-            dailyTimestampList.add(startTime);
-        }
-        while (nextDay < endTime) {
-            dailyTimestampList.add(nextDay);
-            nextDay = getTimestampOfNextDay(nextDay);
-        }
-        final long lastDailyTimestamp = dailyTimestampList.get(dailyTimestampList.size() - 1);
-        // Only if the timestamp diff in the last day is bigger than MIN_TIME_SLOT, add the
-        // last day.
-        if (endTime - lastDailyTimestamp >= MIN_TIME_SLOT) {
-            dailyTimestampList.add(endTime);
-        }
-        // The dailyTimestampList must have the start and end timestamp, otherwise, return an empty
-        // list.
-        if (dailyTimestampList.size() < MIN_TIMESTAMP_DATA_SIZE) {
-            return new ArrayList<>();
-        }
+        dailyTimestampList.add(endTime);
         return dailyTimestampList;
     }
 
     @VisibleForTesting
+    static List<List<Long>> getHourlyTimestamps(final List<Long> dailyTimestamps) {
+        final List<List<Long>> hourlyTimestamps = new ArrayList<>();
+        if (dailyTimestamps.size() < MIN_DAILY_DATA_SIZE) {
+            return hourlyTimestamps;
+        }
+
+        for (int dailyIndex = 0; dailyIndex < dailyTimestamps.size() - 1; dailyIndex++) {
+            final List<Long> hourlyTimestampsPerDay = new ArrayList<>();
+            final long startTime = dailyTimestamps.get(dailyIndex);
+            final long endTime = dailyTimestamps.get(dailyIndex + 1);
+
+            hourlyTimestampsPerDay.add(startTime);
+            for (long timestamp = TimestampUtils.getNextEvenHourTimestamp(startTime);
+                    timestamp < endTime; timestamp += MIN_TIME_SLOT) {
+                hourlyTimestampsPerDay.add(timestamp);
+            }
+            hourlyTimestampsPerDay.add(endTime);
+
+            hourlyTimestamps.add(hourlyTimestampsPerDay);
+        }
+        return hourlyTimestamps;
+    }
+
+    @VisibleForTesting
     static boolean isFromFullCharge(@Nullable final Map<String, BatteryHistEntry> entryList) {
         if (entryList == null) {
             Log.d(TAG, "entryList is null in isFromFullCharge()");
@@ -603,30 +591,6 @@
     }
 
     /**
-     * @return Returns the timestamp for 00:00 1 day after the given timestamp based on local
-     * timezone.
-     */
-    @VisibleForTesting
-    static long getTimestampOfNextDay(long timestamp) {
-        return getTimestampWithDayDiff(timestamp, /*dayDiff=*/ 1);
-    }
-
-    /**
-     * Returns whether currentSlot will be used in daily chart.
-     */
-    @VisibleForTesting
-    static boolean isForDailyChart(final boolean isStartOrEnd, final long currentSlot) {
-        // The start and end timestamps will always be used in daily chart.
-        if (isStartOrEnd) {
-            return true;
-        }
-
-        // The timestamps for 00:00 will be used in daily chart.
-        final long startOfTheDay = getTimestampWithDayDiff(currentSlot, /*dayDiff=*/ 0);
-        return currentSlot == startOfTheDay;
-    }
-
-    /**
      * @return Returns the indexed battery usage data for each corresponding time slot.
      *
      * <p>There could be 2 cases of the returned value:</p>
@@ -725,9 +689,9 @@
     @VisibleForTesting
     @Nullable
     static Map<Long, Map<String, List<AppUsagePeriod>>> buildAppUsagePeriodList(
-            final List<AppUsageEvent> allAppUsageEvents, final List<BatteryEvent> batteryEventList,
+            final List<AppUsageEvent> appUsageEvents, final List<BatteryEvent> batteryEventList,
             final long startTime, final long endTime) {
-        if (allAppUsageEvents.isEmpty()) {
+        if (appUsageEvents.isEmpty()) {
             return null;
         }
 
@@ -735,7 +699,7 @@
         // use.
         final List<AppUsageEvent> deviceEvents = new ArrayList<>();
         final ArrayMap<Integer, List<AppUsageEvent>> usageEventsByInstanceId = new ArrayMap<>();
-        for (final AppUsageEvent event : allAppUsageEvents) {
+        for (final AppUsageEvent event : appUsageEvents) {
             final AppUsageEventType eventType = event.getType();
             if (eventType == AppUsageEventType.ACTIVITY_RESUMED
                     || eventType == AppUsageEventType.ACTIVITY_STOPPED) {
@@ -852,9 +816,11 @@
             final List<AppUsagePeriod> usagePeriodList,
             final List<BatteryEvent> batteryEventList) {
         final List<AppUsagePeriod> resultList = new ArrayList<>();
+        int index = 0;
         for (AppUsagePeriod inputPeriod : usagePeriodList) {
             long lastStartTime = inputPeriod.getStartTime();
-            for (BatteryEvent batteryEvent : batteryEventList) {
+            while (index < batteryEventList.size()) {
+                BatteryEvent batteryEvent = batteryEventList.get(index);
                 if (batteryEvent.getTimestamp() < inputPeriod.getStartTime()) {
                     // Because the batteryEventList has been sorted, here is to mark the power
                     // connection state when the usage period starts. If power is connected when
@@ -865,6 +831,7 @@
                     } else if (batteryEvent.getType() == BatteryEventType.POWER_DISCONNECTED) {
                         lastStartTime = inputPeriod.getStartTime();
                     }
+                    index++;
                     continue;
                 }
                 if (batteryEvent.getTimestamp() > inputPeriod.getEndTime()) {
@@ -883,6 +850,7 @@
                 } else if (batteryEvent.getType() == BatteryEventType.POWER_DISCONNECTED) {
                     lastStartTime = batteryEvent.getTimestamp();
                 }
+                index++;
             }
             if (lastStartTime != 0) {
                 resultList.add(AppUsagePeriod.newBuilder()
@@ -1180,43 +1148,22 @@
             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) {
         if (rawTimestampList.isEmpty() || expectedTimestampSlots.isEmpty()) {
             return;
         }
-        final long expectedStartTimestamp = expectedTimestampSlots.get(0);
-        final long rawStartTimestamp = rawTimestampList.get(0);
-        int startIndex = 0;
-        // If the expected start timestamp is full charge or earlier than what we have, use the
-        // first data of what we have directly. This should be OK because the expected start
-        // timestamp is the nearest even hour of the raw start timestamp, their time diff is no
-        // more than 1 hour.
-        if (isFromFullCharge || expectedStartTimestamp < rawStartTimestamp) {
-            startIndex = 1;
-            resultMap.put(expectedStartTimestamp, batteryHistoryMap.get(rawStartTimestamp));
-        }
         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,
-                    isStartOrEnd);
+        final long startTimestamp = expectedTimestampSlots.get(0);
+        final long endTimestamp = expectedTimestampSlots.get(expectedTimestampSlotsSize - 1);
+
+        resultMap.put(startTimestamp, batteryHistoryMap.get(startTimestamp));
+        for (int index = 1; index < expectedTimestampSlotsSize - 1; index++) {
+            interpolateHistoryForSlot(context, expectedTimestampSlots.get(index), rawTimestampList,
+                    batteryHistoryMap, resultMap);
         }
+        resultMap.put(endTimestamp,
+                Map.of(CURRENT_TIME_BATTERY_HISTORY_PLACEHOLDER, EMPTY_BATTERY_HIST_ENTRY));
     }
 
     private static void interpolateHistoryForSlot(
@@ -1224,8 +1171,7 @@
             final long currentSlot,
             final List<Long> rawTimestampList,
             final Map<Long, Map<String, BatteryHistEntry>> batteryHistoryMap,
-            final Map<Long, Map<String, BatteryHistEntry>> resultMap,
-            final boolean isStartOrEnd) {
+            final Map<Long, Map<String, BatteryHistEntry>> resultMap) {
         final long[] nearestTimestamps = findNearestTimestamp(rawTimestampList, currentSlot);
         final long lowerTimestamp = nearestTimestamps[0];
         final long upperTimestamp = nearestTimestamps[1];
@@ -1248,9 +1194,8 @@
             resultMap.put(currentSlot, new ArrayMap<>());
             return;
         }
-        interpolateHistoryForSlot(context,
-                currentSlot, lowerTimestamp, upperTimestamp, batteryHistoryMap, resultMap,
-                isStartOrEnd);
+        interpolateHistoryForSlot(
+                context, currentSlot, lowerTimestamp, upperTimestamp, batteryHistoryMap, resultMap);
     }
 
     private static void interpolateHistoryForSlot(
@@ -1259,8 +1204,7 @@
             final long lowerTimestamp,
             final long upperTimestamp,
             final Map<Long, Map<String, BatteryHistEntry>> batteryHistoryMap,
-            final Map<Long, Map<String, BatteryHistEntry>> resultMap,
-            final boolean isStartOrEnd) {
+            final Map<Long, Map<String, BatteryHistEntry>> resultMap) {
         final Map<String, BatteryHistEntry> lowerEntryDataMap =
                 batteryHistoryMap.get(lowerTimestamp);
         final Map<String, BatteryHistEntry> upperEntryDataMap =
@@ -1274,7 +1218,7 @@
         // Skips the booting-specific logics and always does interpolation for daily chart level
         // data.
         if (lowerTimestamp < upperEntryDataBootTimestamp
-                && !isForDailyChart(isStartOrEnd, currentSlot)) {
+                && !TimestampUtils.isMidnight(currentSlot)) {
             // Provides an opportunity to force align the slot directly.
             if ((upperTimestamp - currentSlot) < 10 * DateUtils.MINUTE_IN_MILLIS) {
                 log(context, "force align into the nearest slot", currentSlot, null);
@@ -1321,70 +1265,6 @@
         resultMap.put(currentSlot, newHistEntryMap);
     }
 
-    /**
-     * @return Returns the nearest even hour timestamp of the given timestamp.
-     */
-    private static long getNearestEvenHourTimestamp(long rawTimestamp) {
-        // If raw hour is even, the nearest even hour should be the even hour before raw
-        // start. The hour doesn't need to change and just set the minutes and seconds to 0.
-        // Otherwise, the nearest even hour should be raw hour + 1.
-        // For example, the nearest hour of 14:30:50 should be 14:00:00. While the nearest
-        // hour of 15:30:50 should be 16:00:00.
-        return getEvenHourTimestamp(rawTimestamp, /*addHourOfDay*/ 1);
-    }
-
-    /**
-     * @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) {
-        // If raw hour is even, the hour doesn't need to change as well.
-        // Otherwise, the even hour before raw end should be raw hour - 1.
-        // For example, the even hour before 14:30:50 should be 14:00:00. While the even
-        // hour before 15:30:50 should be 14:00:00.
-        return getEvenHourTimestamp(rawTimestamp, /*addHourOfDay*/ -1);
-    }
-
-    private static long getEvenHourTimestamp(long rawTimestamp, int addHourOfDay) {
-        final Calendar evenHourCalendar = Calendar.getInstance();
-        evenHourCalendar.setTimeInMillis(rawTimestamp);
-        // Before computing the evenHourCalendar, record raw hour based on local timezone.
-        final int rawHour = evenHourCalendar.get(Calendar.HOUR_OF_DAY);
-        if (rawHour % 2 != 0) {
-            evenHourCalendar.add(Calendar.HOUR_OF_DAY, addHourOfDay);
-        }
-        evenHourCalendar.set(Calendar.MINUTE, 0);
-        evenHourCalendar.set(Calendar.SECOND, 0);
-        evenHourCalendar.set(Calendar.MILLISECOND, 0);
-        return evenHourCalendar.getTimeInMillis();
-    }
-
-    private static List<List<Long>> getHourlyTimestamps(final List<Long> dailyTimestamps) {
-        final List<List<Long>> hourlyTimestamps = new ArrayList<>();
-        if (dailyTimestamps.size() < MIN_DAILY_DATA_SIZE) {
-            return hourlyTimestamps;
-        }
-
-        for (int dailyStartIndex = 0; dailyStartIndex < dailyTimestamps.size() - 1;
-                dailyStartIndex++) {
-            long currentTimestamp = dailyTimestamps.get(dailyStartIndex);
-            final long dailyEndTimestamp = dailyTimestamps.get(dailyStartIndex + 1);
-            final List<Long> hourlyTimestampsPerDay = new ArrayList<>();
-            while (currentTimestamp <= dailyEndTimestamp) {
-                hourlyTimestampsPerDay.add(currentTimestamp);
-                currentTimestamp += MIN_TIME_SLOT;
-            }
-            hourlyTimestamps.add(hourlyTimestampsPerDay);
-        }
-        return hourlyTimestamps;
-    }
-
     private static List<BatteryLevelData.PeriodBatteryLevelData> getHourlyPeriodBatteryLevelData(
             Context context,
             final Map<Long, Map<String, BatteryHistEntry>> processedBatteryHistoryMap,
@@ -1461,11 +1341,16 @@
                 final Long endTimestamp = hourlyTimestamps.get(hourlyIndex + 1);
                 final long slotDuration = endTimestamp - startTimestamp;
                 List<Map<String, BatteryHistEntry>> slotBatteryHistoryList = new ArrayList<>();
-                for (Long timestamp = startTimestamp; timestamp <= endTimestamp;
-                        timestamp += DateUtils.HOUR_IN_MILLIS) {
+                slotBatteryHistoryList.add(
+                        batteryHistoryMap.getOrDefault(startTimestamp, EMPTY_BATTERY_MAP));
+                for (Long timestamp = TimestampUtils.getNextHourTimestamp(startTimestamp);
+                        timestamp < endTimestamp; timestamp += DateUtils.HOUR_IN_MILLIS) {
                     slotBatteryHistoryList.add(
                             batteryHistoryMap.getOrDefault(timestamp, EMPTY_BATTERY_MAP));
                 }
+                slotBatteryHistoryList.add(
+                        batteryHistoryMap.getOrDefault(endTimestamp, EMPTY_BATTERY_MAP));
+
                 final BatteryDiffData hourlyBatteryDiffData =
                         insertHourlyUsageDiffDataPerSlot(
                                 context,
@@ -1938,16 +1823,6 @@
         return true;
     }
 
-    private static long getTimestampWithDayDiff(final long timestamp, final int dayDiff) {
-        final Calendar calendar = Calendar.getInstance();
-        calendar.setTimeInMillis(timestamp);
-        calendar.add(Calendar.DAY_OF_YEAR, dayDiff);
-        calendar.set(Calendar.HOUR_OF_DAY, 0);
-        calendar.set(Calendar.MINUTE, 0);
-        calendar.set(Calendar.SECOND, 0);
-        return calendar.getTimeInMillis();
-    }
-
     private static long getDiffValue(long v1, long v2) {
         return v2 > v1 ? v2 - v1 : 0;
     }
diff --git a/src/com/android/settings/fuelgauge/batteryusage/DatabaseUtils.java b/src/com/android/settings/fuelgauge/batteryusage/DatabaseUtils.java
index 84a39bb..0435e45 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/DatabaseUtils.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/DatabaseUtils.java
@@ -110,13 +110,7 @@
 
     // For testing only.
     @VisibleForTesting
-    static Supplier<Cursor> sFakeBatteryStateSupplier;
-    @VisibleForTesting
-    static Supplier<Cursor> sFakeAppUsageEventSupplier;
-    @VisibleForTesting
-    static Supplier<Cursor> sFakeAppUsageLatestTimestampSupplier;
-    @VisibleForTesting
-    static Supplier<Cursor> sFakeBatteryEventSupplier;
+    static Supplier<Cursor> sFakeSupplier;
 
     private DatabaseUtils() {
     }
@@ -340,7 +334,7 @@
             resolver.insert(BATTERY_EVENT_URI, contentValues);
             Log.d(TAG, "insert() battery event data into database: " + batteryEvent.toString());
         } catch (Exception e) {
-            Log.e(TAG, "insert() battery event data into database error:\n" + e);
+            Log.e(TAG, "insert() battery event data into database error:", e);
         }
         Log.d(TAG, String.format("sendBatteryEventData() in %d/ms",
                 (System.currentTimeMillis() - startTime)));
@@ -487,8 +481,8 @@
             Context context, final Uri appUsageLatestTimestampUri) {
         // We have already make sure the context here is with profile parent's user identity. Don't
         // need to check whether current user is work profile.
-        try (Cursor cursor = sFakeAppUsageLatestTimestampSupplier != null
-                ? sFakeAppUsageLatestTimestampSupplier.get()
+        try (Cursor cursor = sFakeSupplier != null
+                ? sFakeSupplier.get()
                 : context.getContentResolver().query(
                         appUsageLatestTimestampUri, null, null, null)) {
             if (cursor == null || cursor.getCount() == 0) {
@@ -514,8 +508,8 @@
         if (context == null) {
             return appUsageEventList;
         }
-        try (Cursor cursor = sFakeAppUsageEventSupplier != null
-                ? sFakeAppUsageEventSupplier.get()
+        try (Cursor cursor = sFakeSupplier != null
+                ? sFakeSupplier.get()
                 : context.getContentResolver().query(appUsageEventUri, null, null, null)) {
             if (cursor == null || cursor.getCount() == 0) {
                 return appUsageEventList;
@@ -540,8 +534,8 @@
         if (context == null) {
             return batteryEventList;
         }
-        try (Cursor cursor = sFakeBatteryEventSupplier != null
-                ? sFakeBatteryEventSupplier.get()
+        try (Cursor cursor = sFakeSupplier != null
+                ? sFakeSupplier.get()
                 : context.getContentResolver().query(batteryEventUri, null, null, null)) {
             if (cursor == null || cursor.getCount() == 0) {
                 return batteryEventList;
@@ -566,7 +560,7 @@
             return null;
         }
         final Map<Long, Map<String, BatteryHistEntry>> resultMap = new HashMap();
-        try (Cursor cursor = sFakeBatteryStateSupplier != null ? sFakeBatteryStateSupplier.get() :
+        try (Cursor cursor = sFakeSupplier != null ? sFakeSupplier.get() :
                      context.getContentResolver().query(batteryStateUri, null, null, null)) {
             if (cursor == null || cursor.getCount() == 0) {
                 return resultMap;
diff --git a/src/com/android/settings/fuelgauge/batteryusage/TimestampUtils.java b/src/com/android/settings/fuelgauge/batteryusage/TimestampUtils.java
new file mode 100644
index 0000000..594a0ef
--- /dev/null
+++ b/src/com/android/settings/fuelgauge/batteryusage/TimestampUtils.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2023 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.fuelgauge.batteryusage;
+
+import java.util.Calendar;
+
+/** A utility class for timestamp operations. */
+final class TimestampUtils {
+
+    static long getNextHourTimestamp(final long timestamp) {
+        final Calendar calendar = getSharpHourCalendar(timestamp);
+        calendar.add(Calendar.HOUR_OF_DAY, 1);
+        return calendar.getTimeInMillis();
+    }
+
+    static long getNextEvenHourTimestamp(final long timestamp) {
+        final Calendar calendar = getSharpHourCalendar(timestamp);
+        final int hour = calendar.get(Calendar.HOUR_OF_DAY);
+        calendar.add(Calendar.HOUR_OF_DAY, hour % 2 == 0 ? 2 : 1);
+        return calendar.getTimeInMillis();
+    }
+
+    static long getLastEvenHourTimestamp(final long timestamp) {
+        final Calendar calendar = getSharpHourCalendar(timestamp);
+        final int hour = calendar.get(Calendar.HOUR_OF_DAY);
+        calendar.add(Calendar.HOUR_OF_DAY, hour % 2 == 0 ? 0 : -1);
+        return calendar.getTimeInMillis();
+    }
+
+    static long getNextDayTimestamp(final long timestamp) {
+        final Calendar calendar = getSharpHourCalendar(timestamp);
+        calendar.add(Calendar.DAY_OF_YEAR, 1);
+        calendar.set(Calendar.HOUR_OF_DAY, 0);
+        return calendar.getTimeInMillis();
+    }
+
+    static boolean isMidnight(final long timestamp) {
+        final Calendar calendar = Calendar.getInstance();
+        calendar.setTimeInMillis(timestamp);
+        return calendar.get(Calendar.HOUR_OF_DAY) == 0
+                && calendar.get(Calendar.MINUTE) == 0
+                && calendar.get(Calendar.SECOND) == 0
+                && calendar.get(Calendar.MILLISECOND) == 0;
+    }
+
+    private static Calendar getSharpHourCalendar(final long timestamp) {
+        final Calendar calendar = Calendar.getInstance();
+        calendar.setTimeInMillis(timestamp);
+        calendar.set(Calendar.MINUTE, 0);
+        calendar.set(Calendar.SECOND, 0);
+        calendar.set(Calendar.MILLISECOND, 0);
+        return calendar;
+    }
+}
diff --git a/src/com/android/settings/inputmethod/ModifierKeysPickerDialogFragment.java b/src/com/android/settings/inputmethod/ModifierKeysPickerDialogFragment.java
index f1d7e7f..14578af 100644
--- a/src/com/android/settings/inputmethod/ModifierKeysPickerDialogFragment.java
+++ b/src/com/android/settings/inputmethod/ModifierKeysPickerDialogFragment.java
@@ -18,6 +18,7 @@
 
 import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG;
 
+import android.app.Activity;
 import android.app.AlertDialog;
 import android.app.Dialog;
 import android.content.Context;
@@ -52,11 +53,13 @@
 
 public class ModifierKeysPickerDialogFragment extends DialogFragment {
 
+    static final String DEFAULT_KEY = "default_key";
+    static final String SELECTION_KEY = "delection_key";
+
     private Preference mPreference;
     private String mKeyDefaultName;
     private String mKeyFocus;
-    private Context mContext;
-    private InputManager mIm;
+    private Activity mActivity;
 
     private List<int[]> mRemappableKeyList =
             new ArrayList<>(Arrays.asList(
@@ -67,36 +70,41 @@
 
     private Map<String, int[]> mRemappableKeyMap = new HashMap<>();
 
-    public ModifierKeysPickerDialogFragment() {
-    }
+    public ModifierKeysPickerDialogFragment() {}
 
-    public ModifierKeysPickerDialogFragment(Preference preference, InputManager inputManager) {
-        mPreference = preference;
-        mKeyDefaultName = preference.getTitle().toString();
-        mKeyFocus = preference.getSummary().toString();
-        mIm = inputManager;
+    @Override
+    public void onSaveInstanceState(Bundle savedInstanceState) {
+        savedInstanceState.putString(SELECTION_KEY, mKeyFocus);
+        super.onSaveInstanceState(savedInstanceState);
     }
 
     @Override
     public Dialog onCreateDialog(Bundle savedInstanceState) {
         super.onCreateDialog(savedInstanceState);
-        mContext = getActivity();
+
+        mActivity = getActivity();
+        InputManager inputManager = mActivity.getSystemService(InputManager.class);
+        mKeyDefaultName = getArguments().getString(DEFAULT_KEY);
+        mKeyFocus = getArguments().getString(SELECTION_KEY);
+        if (savedInstanceState != null) {
+            mKeyFocus = savedInstanceState.getString(SELECTION_KEY);
+        }
         List<String> modifierKeys = new ArrayList<String>(Arrays.asList(
-                mContext.getString(R.string.modifier_keys_caps_lock),
-                mContext.getString(R.string.modifier_keys_ctrl),
-                mContext.getString(R.string.modifier_keys_meta),
-                mContext.getString(R.string.modifier_keys_alt)));
+                mActivity.getString(R.string.modifier_keys_caps_lock),
+                mActivity.getString(R.string.modifier_keys_ctrl),
+                mActivity.getString(R.string.modifier_keys_meta),
+                mActivity.getString(R.string.modifier_keys_alt)));
         for (int i = 0; i < modifierKeys.size(); i++) {
             mRemappableKeyMap.put(modifierKeys.get(i), mRemappableKeyList.get(i));
         }
 
         View dialoglayout  =
-                LayoutInflater.from(mContext).inflate(R.layout.modifier_key_picker_dialog, null);
-        AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(mContext);
+                LayoutInflater.from(mActivity).inflate(R.layout.modifier_key_picker_dialog, null);
+        AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(mActivity);
         dialogBuilder.setView(dialoglayout);
 
         TextView summary = dialoglayout.findViewById(R.id.modifier_key_picker_summary);
-        CharSequence summaryText = mContext.getString(
+        CharSequence summaryText = mActivity.getString(
                 R.string.modifier_keys_picker_summary, mKeyDefaultName);
         summary.setText(summaryText);
 
@@ -119,14 +127,14 @@
             Spannable itemSummary;
             if (selectedItem.equals(mKeyDefaultName)) {
                 itemSummary = new SpannableString(
-                        mContext.getString(R.string.modifier_keys_default_summary));
+                        mActivity.getString(R.string.modifier_keys_default_summary));
                 itemSummary.setSpan(
                         new ForegroundColorSpan(getColorOfTextColorSecondary()),
                         0, itemSummary.length(), 0);
                 // Set keys to default.
                 int[] keys = mRemappableKeyMap.get(mKeyDefaultName);
                 for (int i = 0; i < keys.length; i++) {
-                    mIm.remapModifierKey(keys[i], keys[i]);
+                    inputManager.remapModifierKey(keys[i], keys[i]);
                 }
             } else {
                 itemSummary = new SpannableString(selectedItem);
@@ -136,29 +144,29 @@
                 int[] fromKeys = mRemappableKeyMap.get(mKeyDefaultName);
                 int[] toKeys = mRemappableKeyMap.get(selectedItem);
                 // CAPS_LOCK only one key, so always choose the left key for remapping.
-                if (isKeyCapsLock(mContext, mKeyDefaultName)) {
-                    mIm.remapModifierKey(fromKeys[0], toKeys[0]);
+                if (isKeyCapsLock(mActivity, mKeyDefaultName)) {
+                    inputManager.remapModifierKey(fromKeys[0], toKeys[0]);
                 }
                 // Remap KEY_LEFT and KEY_RIGHT to CAPS_LOCK.
-                if (!isKeyCapsLock(mContext, mKeyDefaultName)
-                        && isKeyCapsLock(mContext, selectedItem)) {
-                    mIm.remapModifierKey(fromKeys[0], toKeys[0]);
-                    mIm.remapModifierKey(fromKeys[1], toKeys[0]);
+                if (!isKeyCapsLock(mActivity, mKeyDefaultName)
+                        && isKeyCapsLock(mActivity, selectedItem)) {
+                    inputManager.remapModifierKey(fromKeys[0], toKeys[0]);
+                    inputManager.remapModifierKey(fromKeys[1], toKeys[0]);
                 }
                 // Auto handle left and right keys remapping.
-                if (!isKeyCapsLock(mContext, mKeyDefaultName)
-                        && !isKeyCapsLock(mContext, selectedItem)) {
-                    mIm.remapModifierKey(fromKeys[0], toKeys[0]);
-                    mIm.remapModifierKey(fromKeys[1], toKeys[1]);
+                if (!isKeyCapsLock(mActivity, mKeyDefaultName)
+                        && !isKeyCapsLock(mActivity, selectedItem)) {
+                    inputManager.remapModifierKey(fromKeys[0], toKeys[0]);
+                    inputManager.remapModifierKey(fromKeys[1], toKeys[1]);
                 }
             }
-            mPreference.setSummary(itemSummary);
-            modifierKeyDialog.dismiss();
+            dismiss();
+            mActivity.recreate();
         });
 
         Button cancelButton = dialoglayout.findViewById(R.id.modifier_key_cancel_button);
         cancelButton.setOnClickListener(v -> {
-            modifierKeyDialog.dismiss();
+            dismiss();
         });
 
         final Window window = modifierKeyDialog.getWindow();
@@ -207,16 +215,17 @@
         @Override
         public View getView(int i, View view, ViewGroup viewGroup) {
             if (view == null) {
-                view = LayoutInflater.from(mContext).inflate(R.layout.modifier_key_item, null);
+                view = LayoutInflater.from(mActivity).inflate(R.layout.modifier_key_item, null);
             }
             TextView textView = view.findViewById(R.id.modifier_key_text);
             ImageView checkIcon = view.findViewById(R.id.modifier_key_check_icon);
             textView.setText(mList.get(i));
             if (mCurrentItem == i) {
+                mKeyFocus = mList.get(i);
                 textView.setTextColor(getColorOfColorAccentPrimaryVariant());
                 checkIcon.setImageAlpha(255);
                 view.setBackground(
-                        mContext.getDrawable(R.drawable.modifier_key_lisetview_background));
+                        mActivity.getDrawable(R.drawable.modifier_key_lisetview_background));
             } else {
                 textView.setTextColor(getColorOfTextColorPrimary());
                 checkIcon.setImageAlpha(0);
@@ -235,15 +244,15 @@
     }
 
     private int getColorOfTextColorPrimary() {
-        return Utils.getColorAttrDefaultColor(mContext, android.R.attr.textColorPrimary);
+        return Utils.getColorAttrDefaultColor(mActivity, android.R.attr.textColorPrimary);
     }
 
     private int getColorOfTextColorSecondary() {
-        return Utils.getColorAttrDefaultColor(mContext, android.R.attr.textColorSecondary);
+        return Utils.getColorAttrDefaultColor(mActivity, android.R.attr.textColorSecondary);
     }
 
     private int getColorOfColorAccentPrimaryVariant() {
         return Utils.getColorAttrDefaultColor(
-                mContext, com.android.internal.R.attr.materialColorPrimaryContainer);
+                mActivity, com.android.internal.R.attr.materialColorPrimaryContainer);
     }
 }
diff --git a/src/com/android/settings/inputmethod/ModifierKeysPreferenceController.java b/src/com/android/settings/inputmethod/ModifierKeysPreferenceController.java
index 780a980..91caf29 100644
--- a/src/com/android/settings/inputmethod/ModifierKeysPreferenceController.java
+++ b/src/com/android/settings/inputmethod/ModifierKeysPreferenceController.java
@@ -18,12 +18,12 @@
 
 import android.content.Context;
 import android.hardware.input.InputManager;
+import android.os.Bundle;
 import android.text.Spannable;
 import android.text.SpannableString;
 import android.text.style.ForegroundColorSpan;
 import android.view.KeyEvent;
 
-import androidx.fragment.app.DialogFragment;
 import androidx.fragment.app.Fragment;
 import androidx.fragment.app.FragmentManager;
 import androidx.preference.Preference;
@@ -41,8 +41,8 @@
 
 public class ModifierKeysPreferenceController extends BasePreferenceController {
 
-    private static String KEY_TAG = "modifier_keys_dialog_tag";
-    private static String KEY_RESTORE_PREFERENCE = "modifier_keys_restore";
+    private static final String KEY_TAG = "modifier_keys_dialog_tag";
+    private static final String KEY_RESTORE_PREFERENCE = "modifier_keys_restore";
 
     private static final String KEY_PREFERENCE_CAPS_LOCK = "modifier_keys_caps_lock";
     private static final String KEY_PREFERENCE_CTRL = "modifier_keys_ctrl";
@@ -52,6 +52,7 @@
     private Fragment mParent;
     private FragmentManager mFragmentManager;
     private final InputManager mIm;
+    private PreferenceScreen mScreen;
 
     private final List<Integer> mRemappableKeys = new ArrayList<>(
             Arrays.asList(
@@ -82,40 +83,39 @@
     @Override
     public void displayPreference(PreferenceScreen screen) {
         super.displayPreference(screen);
-
         if (mParent == null) {
             return;
         }
+        mScreen = screen;
+        refreshUi();
+    }
 
+    private void refreshUi() {
         for (Map.Entry<Integer, Integer> entry : mIm.getModifierKeyRemapping().entrySet()) {
             int fromKey = entry.getKey();
             int toKey = entry.getValue();
             int index = mRemappableKeys.indexOf(toKey);
 
             if (isCtrl(fromKey) && mRemappableKeys.contains(toKey)) {
-                Preference preference = screen.findPreference(KEY_PREFERENCE_CTRL);
+                Preference preference = mScreen.findPreference(KEY_PREFERENCE_CTRL);
                 preference.setSummary(changeSummaryColor(mKeyNames[index]));
             }
 
             if (isMeta(fromKey) && mRemappableKeys.contains(toKey)) {
-                Preference preference = screen.findPreference(KEY_PREFERENCE_META);
+                Preference preference = mScreen.findPreference(KEY_PREFERENCE_META);
                 preference.setSummary(changeSummaryColor(mKeyNames[index]));
             }
 
             if (isAlt(fromKey) && mRemappableKeys.contains(toKey)) {
-                Preference preference = screen.findPreference(KEY_PREFERENCE_ALT);
+                Preference preference = mScreen.findPreference(KEY_PREFERENCE_ALT);
                 preference.setSummary(changeSummaryColor(mKeyNames[index]));
             }
 
             if (isCapLock(fromKey) && mRemappableKeys.contains(toKey)) {
-                Preference preference = screen.findPreference(KEY_PREFERENCE_CAPS_LOCK);
+                Preference preference = mScreen.findPreference(KEY_PREFERENCE_CAPS_LOCK);
                 preference.setSummary(changeSummaryColor(mKeyNames[index]));
             }
         }
-
-        // The dialog screen depends on the previous selected key's fragment.
-        // In the rotation scenario, we should remove the previous dialog screen first.
-        clearPreviousDialog();
     }
 
     @Override
@@ -133,19 +133,18 @@
     }
 
     private void showModifierKeysDialog(Preference preference) {
-        ModifierKeysPickerDialogFragment fragment =
-                new ModifierKeysPickerDialogFragment(preference, mIm);
-        fragment.setTargetFragment(mParent, 0);
-        fragment.show(mFragmentManager, KEY_TAG);
-    }
-
-    private void clearPreviousDialog() {
         mFragmentManager = mParent.getFragmentManager();
-        DialogFragment preKeysDialogFragment =
-                (DialogFragment) mFragmentManager.findFragmentByTag(KEY_TAG);
-        if (preKeysDialogFragment != null) {
-            preKeysDialogFragment.dismiss();
-        }
+        ModifierKeysPickerDialogFragment fragment = new ModifierKeysPickerDialogFragment();
+        fragment.setTargetFragment(mParent, 0);
+        Bundle bundle = new Bundle();
+        bundle.putString(
+                ModifierKeysPickerDialogFragment.DEFAULT_KEY,
+                preference.getTitle().toString());
+        bundle.putString(
+                ModifierKeysPickerDialogFragment.SELECTION_KEY,
+                preference.getSummary().toString());
+        fragment.setArguments(bundle);
+        fragment.show(mFragmentManager, KEY_TAG);
     }
 
     private Spannable changeSummaryColor(String summary) {
diff --git a/src/com/android/settings/inputmethod/ModifierKeysResetDialogFragment.java b/src/com/android/settings/inputmethod/ModifierKeysResetDialogFragment.java
index 4ca5ddd..755e9dd 100644
--- a/src/com/android/settings/inputmethod/ModifierKeysResetDialogFragment.java
+++ b/src/com/android/settings/inputmethod/ModifierKeysResetDialogFragment.java
@@ -18,25 +18,19 @@
 
 import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG;
 
+import android.app.Activity;
 import android.app.AlertDialog;
 import android.app.Dialog;
-import android.content.Context;
 import android.hardware.input.InputManager;
 import android.os.Bundle;
-import android.text.Spannable;
-import android.text.SpannableString;
-import android.text.style.ForegroundColorSpan;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.Window;
 import android.widget.Button;
 
 import androidx.fragment.app.DialogFragment;
-import androidx.preference.Preference;
-import androidx.preference.PreferenceScreen;
 
 import com.android.settings.R;
-import com.android.settingslib.Utils;
 
 public class ModifierKeysResetDialogFragment extends DialogFragment {
     private static final String MODIFIER_KEYS_CAPS_LOCK = "modifier_keys_caps_lock";
@@ -44,41 +38,36 @@
     private static final String MODIFIER_KEYS_META = "modifier_keys_meta";
     private static final String MODIFIER_KEYS_ALT = "modifier_keys_alt";
 
-    private PreferenceScreen mScreen;
-    private InputManager mIm;
     private String[] mKeys = {
             MODIFIER_KEYS_CAPS_LOCK,
             MODIFIER_KEYS_CTRL,
             MODIFIER_KEYS_META,
             MODIFIER_KEYS_ALT};
 
-    public ModifierKeysResetDialogFragment() {
-    }
-
-    public ModifierKeysResetDialogFragment(PreferenceScreen screen, InputManager inputManager) {
-        mScreen = screen;
-        mIm = inputManager;
-    }
+    public ModifierKeysResetDialogFragment() {}
 
     @Override
     public Dialog onCreateDialog(Bundle savedInstanceState) {
         super.onCreateDialog(savedInstanceState);
-        Context mContext = getActivity();
+
+        Activity activity = getActivity();
+        InputManager inputManager = activity.getSystemService(InputManager.class);
         View dialoglayout =
-                LayoutInflater.from(mContext).inflate(R.layout.modifier_key_reset_dialog, null);
-        AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(mContext);
+                LayoutInflater.from(activity).inflate(R.layout.modifier_key_reset_dialog, null);
+        AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(activity);
         dialogBuilder.setView(dialoglayout);
         AlertDialog modifierKeyResetDialog = dialogBuilder.create();
 
         Button restoreButton = dialoglayout.findViewById(R.id.modifier_key_reset_restore_button);
         restoreButton.setOnClickListener(v -> {
-            resetToDefault();
-            modifierKeyResetDialog.dismiss();
+            inputManager.clearAllModifierKeyRemappings();
+            dismiss();
+            activity.recreate();
         });
 
         Button cancelButton = dialoglayout.findViewById(R.id.modifier_key_reset_cancel_button);
         cancelButton.setOnClickListener(v -> {
-            modifierKeyResetDialog.dismiss();
+            dismiss();
         });
 
         final Window window = modifierKeyResetDialog.getWindow();
@@ -86,25 +75,4 @@
 
         return modifierKeyResetDialog;
     }
-
-    private void resetToDefault() {
-        Context mContext = getActivity();
-        for (int i = 0; i < mKeys.length; i++) {
-            Preference preference = mScreen.findPreference(mKeys[i]);
-            Spannable title = new SpannableString(
-                    mContext.getString(R.string.modifier_keys_default_summary));
-            title.setSpan(
-                    new ForegroundColorSpan(getColorOfTextColorSecondary()),
-                    0, title.length(), 0);
-            preference.setSummary(title);
-        }
-
-        if (mIm != null) {
-            mIm.clearAllModifierKeyRemappings();
-        }
-    }
-
-    private int getColorOfTextColorSecondary() {
-        return Utils.getColorAttrDefaultColor(getActivity(), android.R.attr.textColorSecondary);
-    }
 }
diff --git a/src/com/android/settings/inputmethod/ModifierKeysRestorePreferenceController.java b/src/com/android/settings/inputmethod/ModifierKeysRestorePreferenceController.java
index 4e72fbd..3171487 100644
--- a/src/com/android/settings/inputmethod/ModifierKeysRestorePreferenceController.java
+++ b/src/com/android/settings/inputmethod/ModifierKeysRestorePreferenceController.java
@@ -17,12 +17,10 @@
 package com.android.settings.inputmethod;
 
 import android.content.Context;
-import android.hardware.input.InputManager;
 import android.text.Spannable;
 import android.text.SpannableString;
 import android.text.style.ForegroundColorSpan;
 
-import androidx.fragment.app.DialogFragment;
 import androidx.fragment.app.Fragment;
 import androidx.fragment.app.FragmentManager;
 import androidx.preference.Preference;
@@ -34,16 +32,14 @@
 
 public class ModifierKeysRestorePreferenceController extends BasePreferenceController {
 
-    private static String KEY_TAG = "modifier_keys_dialog_tag";
+    private static final String KEY_TAG = "modifier_keys_restore_dialog_tag";
 
     private Fragment mParent;
     private FragmentManager mFragmentManager;
     private PreferenceScreen mScreen;
-    private final InputManager mIm;
 
     public ModifierKeysRestorePreferenceController(Context context, String key) {
         super(context, key);
-        mIm = context.getSystemService(InputManager.class);
     }
 
     public void setFragment(Fragment parent) {
@@ -57,9 +53,6 @@
             return;
         }
         mScreen = screen;
-        // The dialog screen depends on the previous selected key's fragment.
-        // In the rotation scenario, we should remove the previous dialog first.
-        clearPreviousDialog();
         setResetKeyColor();
     }
 
@@ -78,8 +71,8 @@
     }
 
     private void showResetDialog() {
-        ModifierKeysResetDialogFragment fragment =
-                new ModifierKeysResetDialogFragment(mScreen, mIm);
+        mFragmentManager = mParent.getFragmentManager();
+        ModifierKeysResetDialogFragment fragment = new ModifierKeysResetDialogFragment();
         fragment.setTargetFragment(mParent, 0);
         fragment.show(mFragmentManager, KEY_TAG);
     }
@@ -98,13 +91,4 @@
         return Utils.getColorAttrDefaultColor(
                 mParent.getActivity(), com.android.internal.R.attr.materialColorPrimaryContainer);
     }
-
-    private void clearPreviousDialog() {
-        mFragmentManager = mParent.getFragmentManager();
-        DialogFragment preResetDialogFragment =
-                (DialogFragment) mFragmentManager.findFragmentByTag(KEY_TAG);
-        if (preResetDialogFragment != null) {
-            preResetDialogFragment.dismiss();
-        }
-    }
 }
diff --git a/src/com/android/settings/localepicker/LocaleHelperPreferenceController.java b/src/com/android/settings/localepicker/LocaleHelperPreferenceController.java
index 05c7401..a639c9d 100644
--- a/src/com/android/settings/localepicker/LocaleHelperPreferenceController.java
+++ b/src/com/android/settings/localepicker/LocaleHelperPreferenceController.java
@@ -17,6 +17,8 @@
 package com.android.settings.localepicker;
 
 import android.content.Context;
+import android.content.Intent;
+import android.util.Log;
 
 import androidx.annotation.VisibleForTesting;
 import androidx.preference.PreferenceScreen;
@@ -65,10 +67,14 @@
     }
 
     private void openLocaleLearnMoreLink() {
-        mContext.startActivity(
-                HelpUtils.getHelpIntent(
-                        mContext,
-                        mContext.getString(R.string.link_locale_picker_footer_learn_more),
-                        /*backupContext=*/""));
+        Intent intent = HelpUtils.getHelpIntent(
+                mContext,
+                mContext.getString(R.string.link_locale_picker_footer_learn_more),
+                mContext.getClass().getName());
+        if (intent != null) {
+            mContext.startActivity(intent);
+        } else {
+            Log.w(TAG, "HelpIntent is null");
+        }
     }
 }
diff --git a/src/com/android/settings/network/SubscriptionUtil.java b/src/com/android/settings/network/SubscriptionUtil.java
index 9c4ac03..9d953bf 100644
--- a/src/com/android/settings/network/SubscriptionUtil.java
+++ b/src/com/android/settings/network/SubscriptionUtil.java
@@ -438,6 +438,7 @@
                 }
 
             }
+            Log.d(TAG, "getSelectableSubscriptionInfoList: " + selectableList);
             return selectableList;
         }
     }
diff --git a/src/com/android/settings/notetask/shortcut/CreateNoteTaskShortcutActivity.kt b/src/com/android/settings/notetask/shortcut/CreateNoteTaskShortcutActivity.kt
new file mode 100644
index 0000000..b984622
--- /dev/null
+++ b/src/com/android/settings/notetask/shortcut/CreateNoteTaskShortcutActivity.kt
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2023 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.notetask.shortcut
+
+import android.app.Activity
+import android.app.role.RoleManager
+import android.app.role.RoleManager.ROLE_NOTES
+import android.content.ComponentName
+import android.content.Context
+import android.content.Intent
+import android.content.pm.ShortcutInfo
+import android.content.pm.ShortcutManager
+import android.graphics.drawable.Icon
+import android.os.Bundle
+import android.os.PersistableBundle
+import android.os.UserHandle
+import androidx.activity.ComponentActivity
+import androidx.core.content.getSystemService
+import com.android.settings.R
+
+/**
+ * Activity responsible for create a shortcut for notes action. If the shortcut is enabled, a new
+ * shortcut will appear in the widget picker. If the shortcut is selected, the Activity here will be
+ * launched, creating a new shortcut for [CreateNoteTaskShortcutActivity], and will finish.
+ *
+ * @see <a
+ *   href="https://developer.android.com/develop/ui/views/launch/shortcuts/creating-shortcuts#custom-pinned">Creating
+ *   a custom shortcut activity</a>
+ */
+internal class CreateNoteTaskShortcutActivity : ComponentActivity() {
+
+    override fun onCreate(savedInstanceState: Bundle?) {
+        val roleManager = requireNotNull(getSystemService<RoleManager>())
+        val shortcutManager = requireNotNull(getSystemService<ShortcutManager>())
+
+        super.onCreate(savedInstanceState)
+
+        val shortcutInfo = roleManager.createNoteShortcutInfoAsUser(context = this, user)
+        val shortcutIntent = shortcutManager.createShortcutResultIntent(shortcutInfo)
+        setResult(Activity.RESULT_OK, shortcutIntent)
+
+        finish()
+    }
+
+    private companion object {
+
+        private const val SHORTCUT_ID = "note_task_shortcut_id"
+        private const val EXTRA_SHORTCUT_BADGE_OVERRIDE_PACKAGE =
+                "extra_shortcut_badge_override_package"
+        private const val ACTION_LAUNCH_NOTE_TASK = "com.android.systemui.action.LAUNCH_NOTE_TASK"
+
+        private fun RoleManager.createNoteShortcutInfoAsUser(
+                context: Context,
+                user: UserHandle,
+        ): ShortcutInfo? {
+            val systemUiComponent = context.getSystemUiComponent() ?: return null
+
+            val extras = PersistableBundle()
+            getDefaultRoleHolderAsUser(ROLE_NOTES, user)?.let { packageName ->
+                // Set custom app badge using the icon from ROLES_NOTES default app.
+                extras.putString(EXTRA_SHORTCUT_BADGE_OVERRIDE_PACKAGE, packageName)
+            }
+
+            val icon = Icon.createWithResource(context, R.drawable.ic_note_task_shortcut_widget)
+
+            val intent = Intent(ACTION_LAUNCH_NOTE_TASK).apply {
+                setPackage(systemUiComponent.packageName)
+            }
+
+            return ShortcutInfo.Builder(context, SHORTCUT_ID)
+                    .setIntent(intent)
+                    .setShortLabel(context.getString(R.string.note_task_button_label))
+                    .setLongLived(true)
+                    .setIcon(icon)
+                    .setExtras(extras)
+                    .build()
+        }
+
+        private fun RoleManager.getDefaultRoleHolderAsUser(
+                role: String,
+                user: UserHandle,
+        ): String? = getRoleHoldersAsUser(role, user).firstOrNull()
+
+        private fun Context.getSystemUiComponent(): ComponentName? {
+            val flattenName = getString(
+                    com.android.internal.R.string.config_systemUIServiceComponent)
+            check(flattenName.isNotEmpty()) {
+                "No 'com.android.internal.R.string.config_systemUIServiceComponent' resource"
+            }
+            return try {
+                ComponentName.unflattenFromString(flattenName)
+            } catch (e: RuntimeException) {
+                val message = "Invalid component name defined by 'com.android.internal.R.string." +
+                        "config_systemUIServiceComponent' resource: $flattenName"
+                throw IllegalStateException(message, e)
+            }
+        }
+    }
+}
diff --git a/src/com/android/settings/panel/PanelFeatureProviderImpl.java b/src/com/android/settings/panel/PanelFeatureProviderImpl.java
index 57a1ab0..71711f9 100644
--- a/src/com/android/settings/panel/PanelFeatureProviderImpl.java
+++ b/src/com/android/settings/panel/PanelFeatureProviderImpl.java
@@ -22,9 +22,9 @@
 import android.provider.Settings;
 import android.util.FeatureFlagUtils;
 
-public class PanelFeatureProviderImpl implements PanelFeatureProvider {
+import com.android.settings.Utils;
 
-    private static final String SYSTEMUI_PACKAGE_NAME = "com.android.systemui";
+public class PanelFeatureProviderImpl implements PanelFeatureProvider {
 
     @Override
     public PanelContent getPanel(Context context, Bundle bundle) {
@@ -42,7 +42,7 @@
                 // Redirect to the internet dialog in SystemUI.
                 Intent intent = new Intent(Settings.Panel.ACTION_INTERNET_CONNECTIVITY);
                 intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND)
-                        .setPackage(SYSTEMUI_PACKAGE_NAME);
+                        .setPackage(Utils.SYSTEMUI_PACKAGE_NAME);
                 context.sendBroadcast(intent);
                 return null;
             case Settings.Panel.ACTION_NFC:
@@ -55,7 +55,7 @@
                     // Redirect to the volume panel in SystemUI.
                     Intent volumeIntent = new Intent(Settings.Panel.ACTION_VOLUME);
                     volumeIntent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND).setPackage(
-                            SYSTEMUI_PACKAGE_NAME);
+                            Utils.SYSTEMUI_PACKAGE_NAME);
                     context.sendBroadcast(volumeIntent);
                     return null;
                 } else {
diff --git a/src/com/android/settings/regionalpreferences/RegionalFooterPreferenceController.java b/src/com/android/settings/regionalpreferences/RegionalFooterPreferenceController.java
new file mode 100644
index 0000000..6ba9d18
--- /dev/null
+++ b/src/com/android/settings/regionalpreferences/RegionalFooterPreferenceController.java
@@ -0,0 +1,74 @@
+/**
+ * Copyright (C) 2023 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.regionalpreferences;
+
+import android.content.Context;
+import android.content.Intent;
+import android.util.Log;
+
+import androidx.annotation.VisibleForTesting;
+import androidx.preference.PreferenceScreen;
+
+import com.android.settings.R;
+import com.android.settings.core.BasePreferenceController;
+import com.android.settingslib.HelpUtils;
+import com.android.settingslib.widget.FooterPreference;
+
+/**
+ * Preference controller for regional preference footer.
+ */
+public class RegionalFooterPreferenceController extends BasePreferenceController {
+
+    private static final String TAG = "RegionalFooterPreferenceController";
+
+    public RegionalFooterPreferenceController(Context context, String preferenceKey) {
+        super(context, preferenceKey);
+    }
+
+    @Override
+    public int getAvailabilityStatus() {
+        return AVAILABLE_UNSEARCHABLE;
+    }
+
+    @Override
+    public void displayPreference(PreferenceScreen screen) {
+        super.displayPreference(screen);
+        FooterPreference footerPreference = screen.findPreference(getPreferenceKey());
+        setupFooterPreference(footerPreference);
+    }
+
+    @VisibleForTesting
+    void setupFooterPreference(FooterPreference footerPreference) {
+        if (footerPreference != null) {
+            footerPreference.setLearnMoreAction(v -> openLocaleLearnMoreLink());
+            footerPreference.setLearnMoreText(mContext.getString(
+                    R.string.desc_regional_pref_footer_learn_more));
+        }
+    }
+
+    private void openLocaleLearnMoreLink() {
+        Intent intent = HelpUtils.getHelpIntent(
+                mContext,
+                mContext.getString(R.string.regional_pref_footer_learn_more_link),
+                mContext.getClass().getName());
+        if (intent != null) {
+            mContext.startActivity(intent);
+        } else {
+            Log.w(TAG, "HelpIntent is null");
+        }
+    }
+}
diff --git a/src/com/android/settings/safetycenter/BiometricsSafetySource.java b/src/com/android/settings/safetycenter/BiometricsSafetySource.java
index 1fe366d..74964ce 100644
--- a/src/com/android/settings/safetycenter/BiometricsSafetySource.java
+++ b/src/com/android/settings/safetycenter/BiometricsSafetySource.java
@@ -85,7 +85,7 @@
                     combinedBiometricStatusUtils.getSummary(),
                     createPendingIntent(context,
                             biometricNavigationUtils.getBiometricSettingsIntent(context,
-                                    combinedBiometricStatusUtils.getSettingsClassName(),
+                                    combinedBiometricStatusUtils.getSettingsClassNameBasedOnUser(),
                                     disablingAdmin, Bundle.EMPTY),
                             REQUEST_CODE_COMBINED_BIOMETRIC_SETTING),
                     disablingAdmin == null /* enabled */,
diff --git a/src/com/android/settings/sim/receivers/SimSlotChangeHandler.java b/src/com/android/settings/sim/receivers/SimSlotChangeHandler.java
index f6c9cc4..dabb088 100644
--- a/src/com/android/settings/sim/receivers/SimSlotChangeHandler.java
+++ b/src/com/android/settings/sim/receivers/SimSlotChangeHandler.java
@@ -43,7 +43,6 @@
 
 import com.google.common.collect.ImmutableList;
 
-import java.util.ArrayList;
 import java.util.List;
 import java.util.stream.Collectors;
 
@@ -100,6 +99,9 @@
 
         int lastRemovableSlotState = getLastRemovableSimSlotState(mContext);
         int currentRemovableSlotState = removableSlotInfo.getCardStateInfo();
+        Log.i(TAG,
+                "lastRemovableSlotState: " + lastRemovableSlotState + ",currentRemovableSlotState: "
+                        + currentRemovableSlotState);
         boolean isRemovableSimInserted =
                 lastRemovableSlotState == UiccSlotInfo.CARD_STATE_INFO_ABSENT
                         && currentRemovableSlotState == UiccSlotInfo.CARD_STATE_INFO_PRESENT;
@@ -259,7 +261,7 @@
         }
 
         List<SubscriptionInfo> subscriptionInfos = getAvailableRemovableSubscription();
-        if (subscriptionInfos == null || subscriptionInfos.get(0) == null) {
+        if (subscriptionInfos.isEmpty()) {
             Log.e(TAG, "Unable to find the removable subscriptionInfo. Do nothing.");
             return;
         }
@@ -275,6 +277,7 @@
     private void setRemovableSimSlotState(Context context, int state) {
         final SharedPreferences prefs = context.getSharedPreferences(EUICC_PREFS, MODE_PRIVATE);
         prefs.edit().putInt(KEY_REMOVABLE_SLOT_STATE, state).apply();
+        Log.d(TAG, "setRemovableSimSlotState: " + state);
     }
 
     private int getSuwRemovableSlotAction(Context context) {
@@ -332,13 +335,14 @@
     }
 
     protected List<SubscriptionInfo> getAvailableRemovableSubscription() {
-        List<SubscriptionInfo> subList = new ArrayList<>();
-        for (SubscriptionInfo info : SubscriptionUtil.getAvailableSubscriptions(mContext)) {
-            if (!info.isEmbedded()) {
-                subList.add(info);
-            }
-        }
-        return subList;
+        List<SubscriptionInfo> removableSubscriptions =
+                SubscriptionUtil.getAvailableSubscriptions(mContext);
+        return ImmutableList.copyOf(
+                removableSubscriptions.stream()
+                        // ToDo: This condition is for psim only. If device supports removable
+                        //  esim, it needs an new condition.
+                        .filter(sub -> !sub.isEmbedded())
+                        .collect(Collectors.toList()));
     }
 
     private void startChooseSimActivity(boolean psimInserted) {
diff --git a/src/com/android/settings/spa/SettingsSpaEnvironment.kt b/src/com/android/settings/spa/SettingsSpaEnvironment.kt
index c2716b6..455fe9f 100644
--- a/src/com/android/settings/spa/SettingsSpaEnvironment.kt
+++ b/src/com/android/settings/spa/SettingsSpaEnvironment.kt
@@ -17,6 +17,7 @@
 package com.android.settings.spa
 
 import android.content.Context
+import android.util.FeatureFlagUtils
 import com.android.settings.spa.app.AllAppListPageProvider
 import com.android.settings.spa.app.AppsMainPageProvider
 import com.android.settings.spa.app.appinfo.AppInfoSettingsProvider
@@ -43,6 +44,7 @@
 import com.android.settings.spa.system.SystemMainPageProvider
 import com.android.settingslib.spa.framework.common.SettingsPageProviderRepository
 import com.android.settingslib.spa.framework.common.SpaEnvironment
+import com.android.settingslib.spa.framework.common.SpaLogger
 import com.android.settingslib.spa.framework.common.createSettingsPage
 import com.android.settingslib.spaprivileged.template.app.TogglePermissionAppListProvider
 import com.android.settingslib.spaprivileged.template.app.TogglePermissionAppListTemplate
@@ -88,5 +90,8 @@
             ),
         )
     }
-    override val logger = SpaLogProvider
+    override val logger =
+        if (FeatureFlagUtils.isEnabled(context, FeatureFlagUtils.SETTINGS_ENABLE_SPA_METRICS))
+            SpaLogProvider
+        else object: SpaLogger {}
 }
diff --git a/src/com/android/settings/spa/system/AppLanguagesListModel.kt b/src/com/android/settings/spa/system/AppLanguagesListModel.kt
index 3141d68..942bcc4 100644
--- a/src/com/android/settings/spa/system/AppLanguagesListModel.kt
+++ b/src/com/android/settings/spa/system/AppLanguagesListModel.kt
@@ -33,8 +33,10 @@
 import com.android.settings.applications.appinfo.AppLocaleDetails
 import com.android.settings.localepicker.AppLocalePickerActivity
 import com.android.settingslib.spa.framework.util.filterItem
+import com.android.settingslib.spaprivileged.framework.common.asUser
 import com.android.settingslib.spaprivileged.model.app.AppListModel
 import com.android.settingslib.spaprivileged.model.app.AppRecord
+import com.android.settingslib.spaprivileged.model.app.userHandle
 import com.android.settingslib.spaprivileged.template.app.AppListItem
 import com.android.settingslib.spaprivileged.template.app.AppListItemModel
 import kotlinx.coroutines.Dispatchers
@@ -54,17 +56,18 @@
 
     override fun transform(userIdFlow: Flow<Int>, appListFlow: Flow<List<ApplicationInfo>>) =
         userIdFlow.map { userId ->
-            packageManager.queryIntentActivitiesAsUser(
+            userId to packageManager.queryIntentActivitiesAsUser(
                 AppLocaleUtil.LAUNCHER_ENTRY_INTENT,
                 PackageManager.ResolveInfoFlags.of(PackageManager.GET_META_DATA.toLong()),
                 userId,
             )
-        }.combine(appListFlow) { resolveInfos, appList ->
+        }.combine(appListFlow) { (userId, resolveInfos), appList ->
+            val userContext = context.asUser(UserHandle.of(userId))
             appList.map { app ->
                 AppLanguagesRecord(
                     app = app,
                     isAppLocaleSupported = AppLocaleUtil.canDisplayLocaleUi(
-                        context, app, resolveInfos
+                        userContext, app, resolveInfos
                     ),
                 )
             }
@@ -86,9 +89,7 @@
         }.collectAsStateWithLifecycle(initialValue = stringResource(R.string.summary_placeholder))
 
     private fun getSummary(app: ApplicationInfo): String =
-        AppLocaleDetails.getAppDefaultLocale(context, app.packageName)?.let {
-            AppLocaleDetails.getSummary(context, app).toString()
-        } ?: context.getString(R.string.preference_of_system_locale_summary)
+        AppLocaleDetails.getSummary(context, app).toString()
 
     @Composable
     override fun AppListItemModel<AppLanguagesRecord>.AppItem() {
@@ -96,8 +97,7 @@
             val intent = Intent(context, AppLocalePickerActivity::class.java).apply {
                 data = Uri.parse("package:${record.app.packageName}")
             }
-            val userHandle : UserHandle = UserHandle.getUserHandleForUid(record.app.uid)
-            context.startActivityAsUser(intent, userHandle)
+            context.startActivityAsUser(intent, record.app.userHandle)
         }
     }
 }
diff --git a/src/com/android/settings/support/SupportDashboardActivity.java b/src/com/android/settings/support/SupportDashboardActivity.java
index b8a22b9..4654858 100644
--- a/src/com/android/settings/support/SupportDashboardActivity.java
+++ b/src/com/android/settings/support/SupportDashboardActivity.java
@@ -17,7 +17,6 @@
 
 import android.app.Activity;
 import android.content.Context;
-import android.content.Intent;
 import android.os.Bundle;
 
 import com.android.settings.R;
@@ -37,6 +36,9 @@
 @SearchIndexable
 public class SupportDashboardActivity extends Activity implements Indexable {
 
+    public static final String ACTION_SUPPORT_SETTINGS =
+            "com.android.settings.action.SUPPORT_SETTINGS";
+
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
@@ -70,7 +72,7 @@
                     data.summaryOn = context.getString(R.string.support_summary);
                     data.intentTargetPackage = context.getPackageName();
                     data.intentTargetClass = SupportDashboardActivity.class.getName();
-                    data.intentAction = Intent.ACTION_MAIN;
+                    data.intentAction = ACTION_SUPPORT_SETTINGS;
                     data.key = SUPPORT_SEARCH_INDEX_KEY;
                     result.add(data);
 
diff --git a/src/com/android/settings/vpn2/ConfigDialog.java b/src/com/android/settings/vpn2/ConfigDialog.java
index be2a68e..036487d 100644
--- a/src/com/android/settings/vpn2/ConfigDialog.java
+++ b/src/com/android/settings/vpn2/ConfigDialog.java
@@ -653,10 +653,14 @@
                 profile.ipsecSecret = mIpsecSecret.getText().toString();
                 break;
 
+            case VpnProfile.TYPE_IKEV2_IPSEC_RSA:
+                if (mIpsecUserCert.getSelectedItemPosition() != 0) {
+                    profile.ipsecSecret = (String) mIpsecUserCert.getSelectedItem();
+                }
+                // fall through
             case VpnProfile.TYPE_L2TP_IPSEC_RSA:
                 profile.l2tpSecret = mL2tpSecret.getText().toString();
                 // fall through
-            case VpnProfile.TYPE_IKEV2_IPSEC_RSA: // fall through
             case VpnProfile.TYPE_IPSEC_XAUTH_RSA:
                 if (mIpsecUserCert.getSelectedItemPosition() != 0) {
                     profile.ipsecUserCert = (String) mIpsecUserCert.getSelectedItem();
diff --git a/src/com/android/settings/wifi/WifiConfigController2.java b/src/com/android/settings/wifi/WifiConfigController2.java
index 9a29c1c..f92b58f 100644
--- a/src/com/android/settings/wifi/WifiConfigController2.java
+++ b/src/com/android/settings/wifi/WifiConfigController2.java
@@ -592,28 +592,32 @@
             return null;
         }
 
-        WifiConfiguration config = new WifiConfiguration();
-
+        WifiConfiguration config;
         if (mWifiEntry == null) {
+            config = new WifiConfiguration();
             config.SSID = "\"" + mSsidView.getText().toString() + "\"";
             // If the user adds a network manually, assume that it is hidden.
             config.hiddenSSID = mHiddenSettingsSpinner.getSelectedItemPosition() == HIDDEN_NETWORK;
-        } else if (!mWifiEntry.isSaved()) {
-            config.SSID = "\"" + mWifiEntry.getTitle() + "\"";
+        } else if (mWifiEntry.isSaved()) {
+            config = new WifiConfiguration(mWifiEntry.getWifiConfiguration());
         } else {
-            config.networkId = mWifiEntry.getWifiConfiguration().networkId;
-            config.hiddenSSID = mWifiEntry.getWifiConfiguration().hiddenSSID;
+            config = new WifiConfiguration();
+            config.SSID = "\"" + mWifiEntry.getTitle() + "\"";
         }
 
         config.shared = mSharedCheckBox.isChecked();
 
         switch (mWifiEntrySecurity) {
             case WifiEntry.SECURITY_NONE:
-                config.setSecurityParams(WifiConfiguration.SECURITY_TYPE_OPEN);
+                if (mWifiEntry == null || !mWifiEntry.isSaved()) {
+                    config.setSecurityParams(WifiConfiguration.SECURITY_TYPE_OPEN);
+                }
                 break;
 
             case WifiEntry.SECURITY_WEP:
-                config.setSecurityParams(WifiConfiguration.SECURITY_TYPE_WEP);
+                if (mWifiEntry == null || !mWifiEntry.isSaved()) {
+                    config.setSecurityParams(WifiConfiguration.SECURITY_TYPE_WEP);
+                }
                 if (mPasswordView.length() != 0) {
                     int length = mPasswordView.length();
                     String password = mPasswordView.getText().toString();
@@ -628,7 +632,9 @@
                 break;
 
             case WifiEntry.SECURITY_PSK:
-                config.setSecurityParams(WifiConfiguration.SECURITY_TYPE_PSK);
+                if (mWifiEntry == null || !mWifiEntry.isSaved()) {
+                    config.setSecurityParams(WifiConfiguration.SECURITY_TYPE_PSK);
+                }
                 if (mPasswordView.length() != 0) {
                     String password = mPasswordView.getText().toString();
                     if (password.matches("[0-9A-Fa-f]{64}")) {
@@ -642,13 +648,16 @@
             case WifiEntry.SECURITY_EAP:
             case WifiEntry.SECURITY_EAP_WPA3_ENTERPRISE:
             case WifiEntry.SECURITY_EAP_SUITE_B:
-                if (mWifiEntrySecurity == WifiEntry.SECURITY_EAP_SUITE_B) {
-                    // allowedSuiteBCiphers will be set according to certificate type
-                    config.setSecurityParams(WifiConfiguration.SECURITY_TYPE_EAP_SUITE_B);
-                } else if (mWifiEntrySecurity == WifiEntry.SECURITY_EAP_WPA3_ENTERPRISE) {
-                    config.setSecurityParams(WifiConfiguration.SECURITY_TYPE_EAP_WPA3_ENTERPRISE);
-                } else {
-                    config.setSecurityParams(WifiConfiguration.SECURITY_TYPE_EAP);
+                if (mWifiEntry == null || !mWifiEntry.isSaved()) {
+                    if (mWifiEntrySecurity == WifiEntry.SECURITY_EAP_SUITE_B) {
+                        // allowedSuiteBCiphers will be set according to certificate type
+                        config.setSecurityParams(WifiConfiguration.SECURITY_TYPE_EAP_SUITE_B);
+                    } else if (mWifiEntrySecurity == WifiEntry.SECURITY_EAP_WPA3_ENTERPRISE) {
+                        config.setSecurityParams(
+                                WifiConfiguration.SECURITY_TYPE_EAP_WPA3_ENTERPRISE);
+                    } else {
+                        config.setSecurityParams(WifiConfiguration.SECURITY_TYPE_EAP);
+                    }
                 }
                 config.enterpriseConfig = new WifiEnterpriseConfig();
                 int eapMethod = mEapMethodSpinner.getSelectedItemPosition();
@@ -790,7 +799,9 @@
                 }
                 break;
             case WifiEntry.SECURITY_SAE:
-                config.setSecurityParams(WifiConfiguration.SECURITY_TYPE_SAE);
+                if (mWifiEntry == null || !mWifiEntry.isSaved()) {
+                    config.setSecurityParams(WifiConfiguration.SECURITY_TYPE_SAE);
+                }
                 if (mPasswordView.length() != 0) {
                     String password = mPasswordView.getText().toString();
                     config.preSharedKey = '"' + password + '"';
@@ -798,7 +809,9 @@
                 break;
 
             case WifiEntry.SECURITY_OWE:
-                config.setSecurityParams(WifiConfiguration.SECURITY_TYPE_OWE);
+                if (mWifiEntry == null || !mWifiEntry.isSaved()) {
+                    config.setSecurityParams(WifiConfiguration.SECURITY_TYPE_OWE);
+                }
                 break;
 
             default:
diff --git a/src/com/android/settings/wifi/factory/WifiFeatureProvider.java b/src/com/android/settings/wifi/factory/WifiFeatureProvider.java
index ea15c43..6612476 100644
--- a/src/com/android/settings/wifi/factory/WifiFeatureProvider.java
+++ b/src/com/android/settings/wifi/factory/WifiFeatureProvider.java
@@ -26,6 +26,7 @@
 import androidx.lifecycle.ViewModelStoreOwner;
 
 import com.android.settings.wifi.repository.WifiHotspotRepository;
+import com.android.settings.wifi.tether.WifiHotspotSecurityViewModel;
 import com.android.settings.wifi.tether.WifiHotspotSpeedViewModel;
 import com.android.settings.wifi.tether.WifiTetherViewModel;
 
@@ -85,6 +86,17 @@
     }
 
     /**
+     * Get WifiHotspotSecurityViewModel
+     */
+    public WifiHotspotSecurityViewModel getWifiHotspotSecurityViewModel(
+            @NotNull ViewModelStoreOwner owner) {
+        WifiHotspotSecurityViewModel viewModel =
+                new ViewModelProvider(owner).get(WifiHotspotSecurityViewModel.class);
+        verboseLog(TAG, "getWifiHotspotSecurityViewModel():" + viewModel);
+        return viewModel;
+    }
+
+    /**
      * Get WifiHotspotSpeedViewModel
      */
     public WifiHotspotSpeedViewModel getWifiHotspotSpeedViewModel(
diff --git a/src/com/android/settings/wifi/repository/WifiHotspotRepository.java b/src/com/android/settings/wifi/repository/WifiHotspotRepository.java
index ff6d883..91de482 100644
--- a/src/com/android/settings/wifi/repository/WifiHotspotRepository.java
+++ b/src/com/android/settings/wifi/repository/WifiHotspotRepository.java
@@ -19,6 +19,8 @@
 import static android.net.wifi.SoftApConfiguration.BAND_2GHZ;
 import static android.net.wifi.SoftApConfiguration.BAND_5GHZ;
 import static android.net.wifi.SoftApConfiguration.BAND_6GHZ;
+import static android.net.wifi.SoftApConfiguration.SECURITY_TYPE_OPEN;
+import static android.net.wifi.SoftApConfiguration.SECURITY_TYPE_WPA3_SAE;
 import static android.net.wifi.WifiAvailableChannel.OP_MODE_SAP;
 
 import android.content.Context;
@@ -81,6 +83,7 @@
     protected String mLastPassword;
     protected LastPasswordListener mLastPasswordListener = new LastPasswordListener();
 
+    protected MutableLiveData<Integer> mSecurityType;
     protected MutableLiveData<Integer> mSpeedType;
 
     protected Boolean mIsDualBand;
@@ -144,6 +147,7 @@
      * Refresh data from the SoftApConfiguration.
      */
     public void refresh() {
+        updateSecurityType();
         update6gAvailable();
         update5gAvailable();
         updateSpeedType();
@@ -163,10 +167,70 @@
     }
 
     /**
+     * Gets SecurityType LiveData
+     */
+    public LiveData<Integer> getSecurityType() {
+        if (mSecurityType == null) {
+            startAutoRefresh();
+            mSecurityType = new MutableLiveData<>();
+            updateSecurityType();
+            log("getSecurityType():" + mSecurityType.getValue());
+        }
+        return mSecurityType;
+    }
+
+    protected void updateSecurityType() {
+        if (mSecurityType == null) {
+            return;
+        }
+        SoftApConfiguration config = mWifiManager.getSoftApConfiguration();
+        int securityType = (config != null) ? config.getSecurityType() : SECURITY_TYPE_OPEN;
+        log("updateSecurityType(), securityType:" + securityType);
+        mSecurityType.setValue(securityType);
+    }
+
+    /**
+     * Sets SecurityType
+     *
+     * @param securityType the Wi-Fi hotspot security type.
+     */
+    public void setSecurityType(int securityType) {
+        log("setSecurityType():" + securityType);
+        if (mSecurityType == null) {
+            getSecurityType();
+        }
+        if (securityType == mSecurityType.getValue()) {
+            Log.w(TAG, "setSecurityType() is no changed! mSecurityType:"
+                    + mSecurityType.getValue());
+            return;
+        }
+        SoftApConfiguration config = mWifiManager.getSoftApConfiguration();
+        if (config == null) {
+            mSecurityType.setValue(SECURITY_TYPE_OPEN);
+            Log.e(TAG, "setSecurityType(), WifiManager#getSoftApConfiguration() return null!");
+            return;
+        }
+        SoftApConfiguration.Builder configBuilder = new SoftApConfiguration.Builder(config);
+        String passphrase = null;
+        if (securityType != SECURITY_TYPE_OPEN) {
+            passphrase = config.getPassphrase();
+            if (TextUtils.isEmpty(passphrase)) {
+                passphrase = generatePassword();
+            }
+        }
+        configBuilder.setPassphrase(passphrase, securityType);
+        setSoftApConfiguration(configBuilder.build());
+
+        mWifiManager.queryLastConfiguredTetheredApPassphraseSinceBoot(
+                mAppContext.getMainExecutor(), mLastPasswordListener);
+    }
+
+    /**
      * Gets SpeedType LiveData
      */
     public LiveData<Integer> getSpeedType() {
         if (mSpeedType == null) {
+            startAutoRefresh();
             mSpeedType = new MutableLiveData<>();
             updateSpeedType();
             log("getSpeedType():" + mSpeedType.getValue());
@@ -230,6 +294,10 @@
         if (speedType == SPEED_6GHZ) {
             log("setSpeedType(), setBand(BAND_2GHZ_5GHZ_6GHZ)");
             configBuilder.setBand(BAND_2GHZ_5GHZ_6GHZ);
+            if (config.getSecurityType() != SECURITY_TYPE_WPA3_SAE) {
+                log("setSpeedType(), setPassphrase(SECURITY_TYPE_WPA3_SAE)");
+                configBuilder.setPassphrase(generatePassword(), SECURITY_TYPE_WPA3_SAE);
+            }
         } else if (speedType == SPEED_5GHZ) {
             log("setSpeedType(), setBand(BAND_2GHZ_5GHZ)");
             configBuilder.setBand(BAND_2GHZ_5GHZ);
diff --git a/src/com/android/settings/wifi/tether/WifiHotspotSecuritySettings.java b/src/com/android/settings/wifi/tether/WifiHotspotSecuritySettings.java
new file mode 100644
index 0000000..8ff2689
--- /dev/null
+++ b/src/com/android/settings/wifi/tether/WifiHotspotSecuritySettings.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.wifi.tether;
+
+import android.app.settings.SettingsEnums;
+import android.os.Bundle;
+
+import androidx.lifecycle.LiveData;
+
+import com.android.settings.R;
+import com.android.settings.dashboard.DashboardFragment;
+import com.android.settings.overlay.FeatureFactory;
+import com.android.settingslib.widget.SelectorWithWidgetPreference;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Wi-Fi Hotspot Security Settings
+ */
+public class WifiHotspotSecuritySettings extends DashboardFragment implements
+        SelectorWithWidgetPreference.OnClickListener {
+    private static final String TAG = "WifiHotspotSecuritySettings";
+
+    protected WifiHotspotSecurityViewModel mWifiHotspotSecurityViewModel;
+    protected Map<Integer, SelectorWithWidgetPreference> mPreferenceMap = new HashMap<>();
+
+    @Override
+    public int getMetricsCategory() {
+        return SettingsEnums.WIFI_TETHER_SETTINGS;
+    }
+
+    @Override
+    protected int getPreferenceScreenResId() {
+        return R.xml.wifi_hotspot_security;
+    }
+
+    @Override
+    protected String getLogTag() {
+        return TAG;
+    }
+
+    @Override
+    public void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+        loadViewModel();
+    }
+
+    protected void loadViewModel() {
+        mWifiHotspotSecurityViewModel = FeatureFactory.getFactory(getContext())
+                .getWifiFeatureProvider().getWifiHotspotSecurityViewModel(this);
+        LiveData<List<WifiHotspotSecurityViewModel.ViewItem>> viewItemListData =
+                mWifiHotspotSecurityViewModel.getViewItemListData();
+        viewItemListData.observe(this, this::onViewItemListDataChanged);
+        // set the onRadioButtonClicked callback to related preference
+        for (WifiHotspotSecurityViewModel.ViewItem viewItem : viewItemListData.getValue()) {
+            SelectorWithWidgetPreference preference = findPreference(viewItem.mKey);
+            preference.setOnClickListener(this);
+        }
+    }
+
+    protected void onViewItemListDataChanged(
+            List<WifiHotspotSecurityViewModel.ViewItem> viewItems) {
+        log("onViewItemListDataChanged(), viewItems:" + viewItems);
+        for (WifiHotspotSecurityViewModel.ViewItem viewItem : viewItems) {
+            SelectorWithWidgetPreference preference = findPreference(viewItem.mKey);
+            if (preference == null) {
+                continue;
+            }
+            if (preference.isChecked() != viewItem.mIsChecked) {
+                preference.setChecked(viewItem.mIsChecked);
+            }
+            if (preference.isEnabled() != viewItem.mIsEnabled) {
+                preference.setEnabled(viewItem.mIsEnabled);
+                if (viewItem.mIsEnabled) {
+                    preference.setSummary(null);
+                } else {
+                    preference.setSummary(R.string.wifi_hotspot_security_summary_unavailable);
+                }
+            }
+        }
+    }
+
+    @Override
+    public void onRadioButtonClicked(SelectorWithWidgetPreference emiter) {
+        String key = emiter.getKey();
+        log("onRadioButtonClicked(), key:" + key);
+        if (key.isEmpty()) {
+            return;
+        }
+        mWifiHotspotSecurityViewModel.handleRadioButtonClicked(key);
+    }
+
+    private void log(String msg) {
+        FeatureFactory.getFactory(getContext()).getWifiFeatureProvider().verboseLog(TAG, msg);
+    }
+}
diff --git a/src/com/android/settings/wifi/tether/WifiHotspotSecurityViewModel.java b/src/com/android/settings/wifi/tether/WifiHotspotSecurityViewModel.java
new file mode 100644
index 0000000..422e40b
--- /dev/null
+++ b/src/com/android/settings/wifi/tether/WifiHotspotSecurityViewModel.java
@@ -0,0 +1,157 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.wifi.tether;
+
+import static android.net.wifi.SoftApConfiguration.SECURITY_TYPE_OPEN;
+import static android.net.wifi.SoftApConfiguration.SECURITY_TYPE_WPA2_PSK;
+import static android.net.wifi.SoftApConfiguration.SECURITY_TYPE_WPA3_SAE;
+import static android.net.wifi.SoftApConfiguration.SECURITY_TYPE_WPA3_SAE_TRANSITION;
+
+import static com.android.settings.wifi.repository.WifiHotspotRepository.SPEED_6GHZ;
+
+import android.app.Application;
+
+import androidx.lifecycle.AndroidViewModel;
+import androidx.lifecycle.LiveData;
+import androidx.lifecycle.MutableLiveData;
+import androidx.lifecycle.Observer;
+
+import com.android.settings.overlay.FeatureFactory;
+import com.android.settings.wifi.repository.WifiHotspotRepository;
+
+import org.jetbrains.annotations.NotNull;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Wi-Fi Hotspot Security View Model for {@link WifiHotspotSecuritySettings}
+ */
+public class WifiHotspotSecurityViewModel extends AndroidViewModel {
+    private static final String TAG = "WifiHotspotSecurityViewModel";
+
+    public static final String KEY_SECURITY_WPA3 = "wifi_hotspot_security_wpa3";
+    public static final String KEY_SECURITY_WPA2_WPA3 = "wifi_hotspot_security_wpa2_wpa3";
+    public static final String KEY_SECURITY_WPA2 = "wifi_hotspot_security_wpa2";
+    public static final String KEY_SECURITY_NONE = "wifi_hotspot_security_none";
+
+    protected Map<Integer, ViewItem> mViewItemMap = new HashMap<>();
+    protected MutableLiveData<List<ViewItem>> mViewInfoListData;
+
+    protected final WifiHotspotRepository mWifiHotspotRepository;
+    protected final Observer<Integer> mSecurityTypeObserver = st -> onSecurityTypeChanged(st);
+    protected final Observer<Integer> mSpeedTypeObserver = st -> onSpeedTypeChanged(st);
+
+    public WifiHotspotSecurityViewModel(
+            @NotNull Application application) {
+        super(application);
+        mViewItemMap.put(SECURITY_TYPE_WPA3_SAE, new ViewItem(KEY_SECURITY_WPA3));
+        mViewItemMap.put(SECURITY_TYPE_WPA3_SAE_TRANSITION, new ViewItem(KEY_SECURITY_WPA2_WPA3));
+        mViewItemMap.put(SECURITY_TYPE_WPA2_PSK, new ViewItem(KEY_SECURITY_WPA2));
+        mViewItemMap.put(SECURITY_TYPE_OPEN, new ViewItem(KEY_SECURITY_NONE));
+
+        mWifiHotspotRepository = FeatureFactory.getFactory(application).getWifiFeatureProvider()
+                .getWifiHotspotRepository();
+        mWifiHotspotRepository.getSecurityType().observeForever(mSecurityTypeObserver);
+        mWifiHotspotRepository.getSpeedType().observeForever(mSpeedTypeObserver);
+    }
+
+    @Override
+    protected void onCleared() {
+        mWifiHotspotRepository.getSecurityType().removeObserver(mSecurityTypeObserver);
+        mWifiHotspotRepository.getSpeedType().removeObserver(mSpeedTypeObserver);
+    }
+
+    protected void onSecurityTypeChanged(int securityType) {
+        log("onSecurityTypeChanged(), securityType:" + securityType);
+        for (Map.Entry<Integer, ViewItem> entry : mViewItemMap.entrySet()) {
+            entry.getValue().mIsChecked = entry.getKey().equals(securityType);
+        }
+        updateViewItemListData();
+    }
+
+    protected void onSpeedTypeChanged(Integer speedType) {
+        log("onSpeedTypeChanged(), speedType:" + speedType);
+        boolean isWpa3Only = (speedType == SPEED_6GHZ);
+        for (Map.Entry<Integer, ViewItem> entry : mViewItemMap.entrySet()) {
+            if (entry.getKey() != SECURITY_TYPE_WPA3_SAE) {
+                entry.getValue().mIsEnabled = !isWpa3Only;
+            }
+        }
+        updateViewItemListData();
+    }
+
+    /**
+     * Handle RadioButton Clicked
+     */
+    public void handleRadioButtonClicked(String key) {
+        log("handleRadioButtonClicked(), key:" + key);
+        for (Map.Entry<Integer, ViewItem> entry : mViewItemMap.entrySet()) {
+            ViewItem viewItem = entry.getValue();
+            if (viewItem.mKey.equals(key)) {
+                mWifiHotspotRepository.setSecurityType(entry.getKey());
+                return;
+            }
+        }
+    }
+
+    /**
+     * Gets ViewItemList LiveData
+     */
+    public LiveData<List<ViewItem>> getViewItemListData() {
+        if (mViewInfoListData == null) {
+            mViewInfoListData = new MutableLiveData<>();
+            updateViewItemListData();
+            log("getViewItemListData(), mViewInfoListData:" + mViewInfoListData.getValue());
+        }
+        return mViewInfoListData;
+    }
+
+    protected void updateViewItemListData() {
+        if (mViewInfoListData == null) {
+            return;
+        }
+        mViewInfoListData.setValue(mViewItemMap.values().stream().toList());
+    }
+
+    /**
+     * Wi-Fi Hotspot View Item
+     */
+    public static final class ViewItem {
+        String mKey;
+        boolean mIsChecked;
+        boolean mIsEnabled = true;
+
+        public ViewItem(String key) {
+            mKey = key;
+        }
+
+        @Override
+        public String toString() {
+            return new StringBuilder("ViewItem:{")
+                    .append("Key:").append(mKey)
+                    .append(",IsChecked:").append(mIsChecked)
+                    .append(",IsEnabled:").append(mIsEnabled)
+                    .append('}').toString();
+        }
+    }
+
+    private void log(String msg) {
+        FeatureFactory.getFactory(getApplication()).getWifiFeatureProvider().verboseLog(TAG, msg);
+    }
+}
diff --git a/src/com/android/settings/wifi/tether/WifiTetherSettings.java b/src/com/android/settings/wifi/tether/WifiTetherSettings.java
index 3a3691a..bdb1a2e 100644
--- a/src/com/android/settings/wifi/tether/WifiTetherSettings.java
+++ b/src/com/android/settings/wifi/tether/WifiTetherSettings.java
@@ -72,6 +72,8 @@
     static final String KEY_WIFI_TETHER_MAXIMIZE_COMPATIBILITY =
             WifiTetherMaximizeCompatibilityPreferenceController.PREF_KEY;
     @VisibleForTesting
+    static final String KEY_WIFI_HOTSPOT_SECURITY = "wifi_hotspot_security";
+    @VisibleForTesting
     static final String KEY_WIFI_HOTSPOT_SPEED = "wifi_hotspot_speed";
 
     private WifiTetherSwitchBarController mSwitchBarController;
@@ -91,6 +93,8 @@
     @VisibleForTesting
     WifiTetherViewModel mWifiTetherViewModel;
     @VisibleForTesting
+    Preference mWifiHotspotSecurity;
+    @VisibleForTesting
     Preference mWifiHotspotSpeed;
 
     static {
@@ -132,6 +136,10 @@
 
         mWifiTetherViewModel = FeatureFactory.getFactory(getContext()).getWifiFeatureProvider()
                 .getWifiTetherViewModel(this);
+        mWifiHotspotSecurity = findPreference(KEY_WIFI_HOTSPOT_SECURITY);
+        if (mWifiHotspotSecurity != null && mWifiHotspotSecurity.isVisible()) {
+            mWifiTetherViewModel.getSecuritySummary().observe(this, this::onSecuritySummaryChanged);
+        }
         mWifiHotspotSpeed = findPreference(KEY_WIFI_HOTSPOT_SPEED);
         if (mWifiHotspotSpeed != null && mWifiHotspotSpeed.isVisible()) {
             mWifiTetherViewModel.getSpeedSummary().observe(this, this::onSpeedSummaryChanged);
@@ -206,6 +214,10 @@
         }
     }
 
+    protected void onSecuritySummaryChanged(Integer securityResId) {
+        mWifiHotspotSecurity.setSummary(securityResId);
+    }
+
     protected void onSpeedSummaryChanged(Integer summaryResId) {
         mWifiHotspotSpeed.setSummary(summaryResId);
     }
diff --git a/src/com/android/settings/wifi/tether/WifiTetherViewModel.java b/src/com/android/settings/wifi/tether/WifiTetherViewModel.java
index 8cb74c3..6bb2cd5 100644
--- a/src/com/android/settings/wifi/tether/WifiTetherViewModel.java
+++ b/src/com/android/settings/wifi/tether/WifiTetherViewModel.java
@@ -16,11 +16,15 @@
 
 package com.android.settings.wifi.tether;
 
+import static android.net.wifi.SoftApConfiguration.SECURITY_TYPE_OPEN;
+import static android.net.wifi.SoftApConfiguration.SECURITY_TYPE_WPA2_PSK;
+import static android.net.wifi.SoftApConfiguration.SECURITY_TYPE_WPA3_SAE;
+import static android.net.wifi.SoftApConfiguration.SECURITY_TYPE_WPA3_SAE_TRANSITION;
+
 import static com.android.settings.wifi.repository.WifiHotspotRepository.SPEED_2GHZ;
 import static com.android.settings.wifi.repository.WifiHotspotRepository.SPEED_2GHZ_5GHZ;
 import static com.android.settings.wifi.repository.WifiHotspotRepository.SPEED_5GHZ;
 import static com.android.settings.wifi.repository.WifiHotspotRepository.SPEED_6GHZ;
-import static com.android.settings.wifi.repository.WifiHotspotRepository.SPEED_UNKNOWN;
 
 import android.app.Application;
 import android.net.wifi.SoftApConfiguration;
@@ -28,7 +32,7 @@
 import androidx.lifecycle.AndroidViewModel;
 import androidx.lifecycle.LiveData;
 import androidx.lifecycle.MutableLiveData;
-import androidx.lifecycle.Transformations;
+import androidx.lifecycle.Observer;
 
 import com.android.settings.R;
 import com.android.settings.overlay.FeatureFactory;
@@ -45,9 +49,19 @@
 public class WifiTetherViewModel extends AndroidViewModel {
     private static final String TAG = "WifiTetherViewModel";
 
-    protected static Map<Integer, Integer> sSpeedSummaryResMap = new HashMap<>();
+    static Map<Integer, Integer> sSecuritySummaryResMap = new HashMap<>();
+
     static {
-        sSpeedSummaryResMap.put(SPEED_UNKNOWN, R.string.summary_placeholder);
+        sSecuritySummaryResMap.put(SECURITY_TYPE_WPA3_SAE, R.string.wifi_security_sae);
+        sSecuritySummaryResMap.put(SECURITY_TYPE_WPA3_SAE_TRANSITION,
+                R.string.wifi_security_psk_sae);
+        sSecuritySummaryResMap.put(SECURITY_TYPE_WPA2_PSK, R.string.wifi_security_wpa2);
+        sSecuritySummaryResMap.put(SECURITY_TYPE_OPEN, R.string.wifi_security_none);
+    }
+
+    static Map<Integer, Integer> sSpeedSummaryResMap = new HashMap<>();
+
+    static {
         sSpeedSummaryResMap.put(SPEED_2GHZ, R.string.wifi_hotspot_speed_summary_2g);
         sSpeedSummaryResMap.put(SPEED_5GHZ, R.string.wifi_hotspot_speed_summary_5g);
         sSpeedSummaryResMap.put(SPEED_6GHZ, R.string.wifi_hotspot_speed_summary_6g);
@@ -55,18 +69,22 @@
     }
 
     protected final WifiHotspotRepository mWifiHotspotRepository;
+    protected MutableLiveData<Integer> mSecuritySummary;
     protected MutableLiveData<Integer> mSpeedSummary;
 
+    protected final Observer<Integer> mSecurityTypeObserver = st -> onSecurityTypeChanged(st);
+    protected final Observer<Integer> mSpeedTypeObserver = st -> onSpeedTypeChanged(st);
+
     public WifiTetherViewModel(@NotNull Application application) {
         super(application);
         mWifiHotspotRepository = FeatureFactory.getFactory(application).getWifiFeatureProvider()
                 .getWifiHotspotRepository();
-        mWifiHotspotRepository.setAutoRefresh(true);
     }
 
     @Override
     protected void onCleared() {
-        mWifiHotspotRepository.setAutoRefresh(false);
+        mWifiHotspotRepository.getSecurityType().removeObserver(mSecurityTypeObserver);
+        mWifiHotspotRepository.getSpeedType().removeObserver(mSpeedTypeObserver);
     }
 
     /**
@@ -86,17 +104,40 @@
     }
 
     /**
+     * Gets SecuritySummary LiveData
+     */
+    public LiveData<Integer> getSecuritySummary() {
+        if (mSecuritySummary == null) {
+            mSecuritySummary = new MutableLiveData<>();
+            mWifiHotspotRepository.getSecurityType().observeForever(mSecurityTypeObserver);
+        }
+        return mSecuritySummary;
+    }
+
+    protected void onSecurityTypeChanged(int securityType) {
+        int resId = R.string.summary_placeholder;
+        if (sSecuritySummaryResMap.containsKey(securityType)) {
+            resId = sSecuritySummaryResMap.get(securityType);
+        }
+        mSecuritySummary.setValue(resId);
+    }
+
+    /**
      * Gets SpeedSummary LiveData
      */
     public LiveData<Integer> getSpeedSummary() {
         if (mSpeedSummary == null) {
             mSpeedSummary = new MutableLiveData<>();
-            mWifiHotspotRepository.getSpeedType().observeForever(this::onSpeedTypeChanged);
+            mWifiHotspotRepository.getSpeedType().observeForever(mSpeedTypeObserver);
         }
-        return Transformations.distinctUntilChanged(mSpeedSummary);
+        return mSpeedSummary;
     }
 
     protected void onSpeedTypeChanged(Integer speedType) {
-        mSpeedSummary.setValue(sSpeedSummaryResMap.get(speedType));
+        int resId = R.string.summary_placeholder;
+        if (sSpeedSummaryResMap.containsKey(speedType)) {
+            resId = sSpeedSummaryResMap.get(speedType);
+        }
+        mSpeedSummary.setValue(resId);
     }
 }
diff --git a/tests/robotests/src/com/android/settings/bluetooth/RequestPermissionHelperTest.kt b/tests/robotests/src/com/android/settings/bluetooth/RequestPermissionHelperTest.kt
new file mode 100644
index 0000000..ce0792c
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/bluetooth/RequestPermissionHelperTest.kt
@@ -0,0 +1,247 @@
+/*
+ * Copyright (C) 2023 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 androidx.activity.ComponentActivity
+import com.android.settings.R
+import com.android.settings.testutils.shadow.ShadowAlertDialogCompat
+import com.google.common.truth.Truth.assertThat
+import org.junit.After
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mockito.spy
+import org.robolectric.RobolectricTestRunner
+import org.robolectric.android.controller.ActivityController
+import org.robolectric.annotation.Config
+import org.mockito.Mockito.`when` as whenever
+
+@RunWith(RobolectricTestRunner::class)
+@Config(shadows = [ShadowAlertDialogCompat::class])
+class RequestPermissionHelperTest {
+    private lateinit var activityController: ActivityController<ComponentActivity>
+
+    @Before
+    fun setUp() {
+        activityController =
+            ActivityController.of(ComponentActivity()).create().start().postCreate(null).resume()
+    }
+
+    @After
+    fun tearDown() {
+        activityController.pause().stop().destroy()
+    }
+
+    @Test
+    fun requestEnable_withAppLabelAndNoTimeout_hasCorrectMessage() {
+        val activity = activityController.get()
+        RequestPermissionHelper.requestEnable(
+            context = activity,
+            appLabel = "App Label",
+            timeout = -1,
+            onAllow = {},
+            onDeny = {},
+        )
+
+        assertLatestMessageIs("App Label wants to turn on Bluetooth")
+    }
+
+    @Test
+    fun requestEnable_withAppLabelAndZeroTimeout_hasCorrectMessage() {
+        val activity = activityController.get()
+        RequestPermissionHelper.requestEnable(
+            context = activity,
+            appLabel = "App Label",
+            timeout = 0,
+            onAllow = {},
+            onDeny = {},
+        )
+
+        assertLatestMessageIs(
+            "App Label wants to turn on Bluetooth and make your phone visible to other devices. " +
+                "You can change this later in Bluetooth settings."
+        )
+    }
+
+    @Test
+    fun requestEnable_withAppLabelAndNormalTimeout_hasCorrectMessage() {
+        val activity = activityController.get()
+        RequestPermissionHelper.requestEnable(
+            context = activity,
+            appLabel = "App Label",
+            timeout = 120,
+            onAllow = {},
+            onDeny = {},
+        )
+
+        assertLatestMessageIs(
+            "App Label wants to turn on Bluetooth and make your phone visible to other devices " +
+                "for 120 seconds."
+        )
+    }
+
+    @Test
+    fun requestEnable_withNoAppLabelAndNoTimeout_hasCorrectMessage() {
+        val activity = activityController.get()
+        RequestPermissionHelper.requestEnable(
+            context = activity,
+            appLabel = null,
+            timeout = -1,
+            onAllow = {},
+            onDeny = {},
+        )
+
+        assertLatestMessageIs("An app wants to turn on Bluetooth")
+    }
+
+    @Test
+    fun requestEnable_withNoAppLabelAndZeroTimeout_hasCorrectMessage() {
+        val activity = activityController.get()
+        RequestPermissionHelper.requestEnable(
+            context = activity,
+            appLabel = null,
+            timeout = 0,
+            onAllow = {},
+            onDeny = {},
+        )
+
+        assertLatestMessageIs(
+            "An app wants to turn on Bluetooth and make your phone visible to other devices. " +
+                "You can change this later in Bluetooth settings."
+        )
+    }
+
+    @Test
+    fun requestEnable_withNoAppLabelAndNormalTimeout_hasCorrectMessage() {
+        val activity = activityController.get()
+        RequestPermissionHelper.requestEnable(
+            context = activity,
+            appLabel = null,
+            timeout = 120,
+            onAllow = {},
+            onDeny = {},
+        )
+
+        assertLatestMessageIs(
+            "An app wants to turn on Bluetooth and make your phone visible to other devices for " +
+                "120 seconds."
+        )
+    }
+
+    @Test
+    fun requestEnable_whenAutoConfirm_onAllowIsCalled() {
+        val activity = getActivityWith(autoConfirm = true)
+        var onAllowCalled = false
+
+        RequestPermissionHelper.requestEnable(
+            context = activity,
+            appLabel = null,
+            timeout = -1,
+            onAllow = { onAllowCalled = true },
+            onDeny = {},
+        )
+
+        assertThat(onAllowCalled).isTrue()
+    }
+
+    @Test
+    fun requestEnable_whenNotAutoConfirm_onAllowIsNotCalledWhenRequest() {
+        val activity = getActivityWith(autoConfirm = false)
+        var onAllowCalled = false
+
+        RequestPermissionHelper.requestEnable(
+            context = activity,
+            appLabel = null,
+            timeout = -1,
+            onAllow = { onAllowCalled = true },
+            onDeny = {},
+        )
+
+        assertThat(onAllowCalled).isFalse()
+    }
+
+    @Test
+    fun requestDisable_withAppLabel_hasCorrectMessage() {
+        val activity = activityController.get()
+        RequestPermissionHelper.requestDisable(
+            context = activity,
+            appLabel = "App Label",
+            onAllow = {},
+            onDeny = {},
+        )
+
+        assertLatestMessageIs("App Label wants to turn off Bluetooth")
+    }
+
+    @Test
+    fun requestDisable_withNoAppLabel_hasCorrectMessage() {
+        val activity = activityController.get()
+        RequestPermissionHelper.requestDisable(
+            context = activity,
+            appLabel = null,
+            onAllow = {},
+            onDeny = {},
+        )
+
+        assertLatestMessageIs("An app wants to turn off Bluetooth")
+    }
+
+    @Test
+    fun requestDisable_whenAutoConfirm_onAllowIsCalled() {
+        val activity = getActivityWith(autoConfirm = true)
+        var onAllowCalled = false
+
+        RequestPermissionHelper.requestDisable(
+            context = activity,
+            appLabel = null,
+            onAllow = { onAllowCalled = true },
+            onDeny = {},
+        )
+
+        assertThat(onAllowCalled).isTrue()
+    }
+
+    @Test
+    fun requestDisable_whenNotAutoConfirm_onAllowIsNotCalledWhenRequest() {
+        val activity = getActivityWith(autoConfirm = false)
+        var onAllowCalled = false
+
+        RequestPermissionHelper.requestDisable(
+            context = activity,
+            appLabel = null,
+            onAllow = { onAllowCalled = true },
+            onDeny = {},
+        )
+
+        assertThat(onAllowCalled).isFalse()
+    }
+
+    private fun getActivityWith(autoConfirm: Boolean): ComponentActivity {
+        val activity = spy(activityController.get())
+        val spyResources = spy(activity.resources)
+        whenever(activity.resources).thenReturn(spyResources)
+        whenever(spyResources.getBoolean(R.bool.auto_confirm_bluetooth_activation_dialog))
+            .thenReturn(autoConfirm)
+        return activity
+    }
+
+    private fun assertLatestMessageIs(message: String) {
+        val dialog = ShadowAlertDialogCompat.getLatestAlertDialog()
+        val shadowDialog = ShadowAlertDialogCompat.shadowOf(dialog)
+        assertThat(shadowDialog.message.toString()).isEqualTo(message)
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/development/ForceEnableNotesRolePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/development/ForceEnableNotesRolePreferenceControllerTest.java
new file mode 100644
index 0000000..32a28fe
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/development/ForceEnableNotesRolePreferenceControllerTest.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.development;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import androidx.preference.PreferenceScreen;
+import androidx.preference.SwitchPreference;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+
+@RunWith(RobolectricTestRunner.class)
+public class ForceEnableNotesRolePreferenceControllerTest {
+
+    @Mock
+    private PreferenceScreen mScreen;
+    @Mock
+    private SwitchPreference mPreference;
+
+    private ForceEnableNotesRolePreferenceController mController;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        mController = new ForceEnableNotesRolePreferenceController(
+                RuntimeEnvironment.application) {
+            private boolean mEnabled;
+
+            protected boolean isEnabled() {
+                return mEnabled;
+            }
+
+            protected void setEnabled(boolean enabled) {
+                mEnabled = enabled;
+            }
+        };
+        when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(mPreference);
+        mController.displayPreference(mScreen);
+    }
+
+    @Test
+    public void updateState_enabled_preferenceShouldBeChecked() {
+        mController.setEnabled(true);
+        mController.updateState(mPreference);
+
+        verify(mPreference).setChecked(true);
+    }
+
+    @Test
+    public void updateState_disabled_preferenceShouldBeUnchecked() {
+        mController.setEnabled(false);
+        mController.updateState(mPreference);
+
+        verify(mPreference).setChecked(false);
+    }
+
+    @Test
+    public void onPreferenceChange_checked_shouldBeEnabled() {
+        mController.onPreferenceChange(mPreference, true);
+
+        assertTrue(mController.isEnabled());
+    }
+
+    @Test
+    public void onPreferenceChange_unchecked_shouldNotBeEnabled() {
+        mController.onPreferenceChange(mPreference, false);
+
+        assertFalse(mController.isEnabled());
+    }
+
+    @Test
+    public void onDeveloperOptionsSwitchDisabled_preferenceShouldNotBeEnabled() {
+        mController.onDeveloperOptionsSwitchDisabled();
+
+        assertFalse(mController.isEnabled());
+        verify(mPreference).setEnabled(false);
+        verify(mPreference).setChecked(false);
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/display/AmbientDisplayAlwaysOnPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/display/AmbientDisplayAlwaysOnPreferenceControllerTest.java
index 405ea12..3ad14e5 100644
--- a/tests/robotests/src/com/android/settings/display/AmbientDisplayAlwaysOnPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/display/AmbientDisplayAlwaysOnPreferenceControllerTest.java
@@ -74,7 +74,7 @@
         mController.setConfig(mConfig);
 
         mApplicationInfo.uid = 1;
-        when(mContext.getString(R.string.config_defaultWellbeingPackage)).thenReturn(TEST_PACKAGE);
+        when(mContext.getString(R.string.config_systemWellbeing)).thenReturn(TEST_PACKAGE);
 
         when(mContext.getPackageManager()).thenReturn(mPackageManager);
         doReturn(mApplicationInfo).when(mPackageManager).getApplicationInfo(
diff --git a/tests/robotests/src/com/android/settings/display/darkmode/DarkModeCustomBedtimePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/display/darkmode/DarkModeCustomBedtimePreferenceControllerTest.java
index 7f50568..85d6fab 100644
--- a/tests/robotests/src/com/android/settings/display/darkmode/DarkModeCustomBedtimePreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/display/darkmode/DarkModeCustomBedtimePreferenceControllerTest.java
@@ -77,7 +77,7 @@
         when(mContext.getSystemService(UiModeManager.class)).thenReturn(mService);
 
         when(mContext.getResources()).thenReturn(mResources);
-        when(mResources.getString(com.android.internal.R.string.config_defaultWellbeingPackage))
+        when(mResources.getString(com.android.internal.R.string.config_systemWellbeing))
                 .thenReturn("wellbeing");
 
         when(mScreen.findPreference(anyString())).thenReturn(mFooterPreference);
diff --git a/tests/robotests/src/com/android/settings/display/darkmode/DarkModeScheduleSelectorControllerTest.java b/tests/robotests/src/com/android/settings/display/darkmode/DarkModeScheduleSelectorControllerTest.java
index d776e5e..d95635e 100644
--- a/tests/robotests/src/com/android/settings/display/darkmode/DarkModeScheduleSelectorControllerTest.java
+++ b/tests/robotests/src/com/android/settings/display/darkmode/DarkModeScheduleSelectorControllerTest.java
@@ -84,7 +84,7 @@
         when(mContext.getSystemService(LocationManager.class)).thenReturn(mLocationManager);
         when(mContext.getResources()).thenReturn(mResources);
         when(mResources.getConfiguration()).thenReturn(mConfigNightNo);
-        when(mResources.getString(com.android.internal.R.string.config_defaultWellbeingPackage))
+        when(mResources.getString(com.android.internal.R.string.config_systemWellbeing))
                 .thenReturn("wellbeing");
 
         when(mContext.getString(R.string.dark_ui_auto_mode_never)).thenReturn("never");
diff --git a/tests/robotests/src/com/android/settings/dream/WhenToDreamPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/dream/WhenToDreamPreferenceControllerTest.java
index 6e687bb..e173add 100644
--- a/tests/robotests/src/com/android/settings/dream/WhenToDreamPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/dream/WhenToDreamPreferenceControllerTest.java
@@ -72,7 +72,7 @@
 
         mApplicationInfo.uid = 1;
         when(mContext.getString(
-                com.android.internal.R.string.config_defaultWellbeingPackage)).thenReturn(
+                com.android.internal.R.string.config_systemWellbeing)).thenReturn(
                 TEST_PACKAGE);
 
         when(mContext.getPackageManager()).thenReturn(mPackageManager);
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/detectors/IncompatibleChargerDetectorTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/detectors/IncompatibleChargerDetectorTest.java
index 1dfe6e2..9ababe7 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/detectors/IncompatibleChargerDetectorTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/detectors/IncompatibleChargerDetectorTest.java
@@ -25,7 +25,6 @@
 import android.hardware.usb.UsbPort;
 import android.hardware.usb.UsbPortStatus;
 
-import com.android.settings.fuelgauge.BatteryInfo;
 import com.android.settings.fuelgauge.batterytip.tips.BatteryTip;
 
 import org.junit.Before;
@@ -42,7 +41,6 @@
 @RunWith(RobolectricTestRunner.class)
 public final class IncompatibleChargerDetectorTest {
 
-    @Mock private BatteryInfo mBatteryInfo;
     @Mock private UsbPort mUsbPort;
     @Mock private UsbManager mUsbManager;
     @Mock private UsbPortStatus mUsbPortStatus;
@@ -55,14 +53,11 @@
         MockitoAnnotations.initMocks(this);
         mContext = spy(RuntimeEnvironment.application);
         when(mContext.getSystemService(UsbManager.class)).thenReturn(mUsbManager);
-        mIncompatibleChargerDetector =
-                new IncompatibleChargerDetector(mContext, mBatteryInfo);
+        mIncompatibleChargerDetector = new IncompatibleChargerDetector(mContext);
     }
 
     @Test
-    public void detect_unplugDevice_shouldNotShowTip() {
-        mBatteryInfo.pluggedStatus = 0;
-
+    public void detect_withoutIncompatibleCharger_shouldNotShowTip() {
         BatteryTip batteryTip = mIncompatibleChargerDetector.detect();
 
         assertThat(batteryTip.isVisible()).isFalse();
@@ -70,18 +65,7 @@
     }
 
     @Test
-    public void detect_plugDeviceWithoutIncompatibleCharger_shouldNotShowTip() {
-        mBatteryInfo.pluggedStatus = 1;
-
-        BatteryTip batteryTip = mIncompatibleChargerDetector.detect();
-
-        assertThat(batteryTip.isVisible()).isFalse();
-        assertThat(batteryTip.getState()).isEqualTo(BatteryTip.StateType.INVISIBLE);
-    }
-
-    @Test
-    public void detect_plugDeviceWithIncompatibleCharger_showTip() {
-        mBatteryInfo.pluggedStatus = 1;
+    public void detect_withIncompatibleCharger_showTip() {
         setupIncompatibleCharging();
 
         BatteryTip batteryTip = mIncompatibleChargerDetector.detect();
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 f18228b..9cebd19 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryChartPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryChartPreferenceControllerTest.java
@@ -150,11 +150,12 @@
         // 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, 66),
-                List.of(1619251200000L /* 8 AM */,
+                List.of(100, 99, 97, 95, 66),
+                List.of(1619247660000L /* 7:01 AM */,
+                        1619251200000L /* 8 AM */,
                         1619258400000L /* 10 AM */,
                         1619265600000L /* 12 PM */,
-                        1619272800000L /* 2 PM */),
+                        1619265720000L /* now (12:02 PM) */),
                 BatteryChartViewModel.AxisLabelPosition.BETWEEN_TRAPEZOIDS,
                 mBatteryChartPreferenceController.mHourlyChartLabelTextGenerator));
     }
@@ -168,10 +169,10 @@
         BatteryChartViewModel expectedDailyViewModel = new BatteryChartViewModel(
                 List.of(100, 83, 59, 66),
                 // "Sat", "Sun", "Mon", "Mon"
-                List.of(1619251200000L /* Sat */,
+                List.of(1619247660000L /* Sat */,
                         1619308800000L /* Sun */,
                         1619395200000L /* Mon */,
-                        1619467200000L /* Mon */),
+                        1619460120000L /* Mon */),
                 BatteryChartViewModel.AxisLabelPosition.CENTER_OF_TRAPEZOIDS,
                 mBatteryChartPreferenceController.mDailyChartLabelTextGenerator);
 
@@ -194,8 +195,9 @@
         expectedDailyViewModel.setSelectedIndex(0);
         verify(mDailyChartView).setViewModel(expectedDailyViewModel);
         verify(mHourlyChartView).setViewModel(new BatteryChartViewModel(
-                List.of(100, 97, 95, 93, 91, 89, 87, 85, 83),
-                List.of(1619251200000L /* 8 AM */,
+                List.of(100, 99, 97, 95, 93, 91, 89, 87, 85, 83),
+                List.of(1619247660000L /* 7:01 AM */,
+                        1619251200000L /* 8 AM */,
                         1619258400000L /* 10 AM */,
                         1619265600000L /* 12 PM */,
                         1619272800000L /* 2 PM */,
@@ -262,7 +264,7 @@
                         1619445600000L /* 2 PM */,
                         1619452800000L /* 4 PM */,
                         1619460000000L /* 6 PM */,
-                        1619467200000L /* 8 PM */),
+                        1619460120000L /* now (6:02 PM) */),
                 BatteryChartViewModel.AxisLabelPosition.BETWEEN_TRAPEZOIDS,
                 mBatteryChartPreferenceController.mHourlyChartLabelTextGenerator));
 
@@ -327,7 +329,7 @@
     public void selectedSlotText_onlyOneDayDataSelectAnHour_onlyHourText() {
         mBatteryChartPreferenceController.setBatteryHistoryMap(createBatteryHistoryMap(6));
         mBatteryChartPreferenceController.mDailyChartIndex = 0;
-        mBatteryChartPreferenceController.mHourlyChartIndex = 1;
+        mBatteryChartPreferenceController.mHourlyChartIndex = 2;
 
         assertThat(mBatteryChartPreferenceController.getSlotInformation()).isEqualTo(
                 "10 AM - 12 PM");
@@ -344,6 +346,36 @@
     }
 
     @Test
+    public void selectedSlotText_selectFirstSlot_withMinuteText() {
+        mBatteryChartPreferenceController.setBatteryHistoryMap(createBatteryHistoryMap(6));
+        mBatteryChartPreferenceController.mDailyChartIndex = 0;
+        mBatteryChartPreferenceController.mHourlyChartIndex = 0;
+
+        assertThat(mBatteryChartPreferenceController.getSlotInformation()).isEqualTo(
+                "7:01 AM - 8 AM");
+    }
+
+    @Test
+    public void selectedSlotText_selectLastSlot_withNowText() {
+        mBatteryChartPreferenceController.setBatteryHistoryMap(createBatteryHistoryMap(6));
+        mBatteryChartPreferenceController.mDailyChartIndex = 0;
+        mBatteryChartPreferenceController.mHourlyChartIndex = 3;
+
+        assertThat(mBatteryChartPreferenceController.getSlotInformation()).isEqualTo(
+                "12 PM - now");
+    }
+
+    @Test
+    public void selectedSlotText_selectOnlySlot_withMinuteAndNowText() {
+        mBatteryChartPreferenceController.setBatteryHistoryMap(createBatteryHistoryMap(1));
+        mBatteryChartPreferenceController.mDailyChartIndex = 0;
+        mBatteryChartPreferenceController.mHourlyChartIndex = 0;
+
+        assertThat(mBatteryChartPreferenceController.getSlotInformation()).isEqualTo(
+                "7:01 AM - now");
+    }
+
+    @Test
     public void onSaveInstanceState_restoreSelectedIndexAndExpandState() {
         final int expectedDailyIndex = 1;
         final int expectedHourlyIndex = 2;
@@ -373,7 +405,7 @@
         final int totalHour = BatteryChartPreferenceController.getTotalHours(batteryLevelData);
 
         // Only calculate the even hours.
-        assertThat(totalHour).isEqualTo(60);
+        assertThat(totalHour).isEqualTo(59);
     }
 
     private static Long generateTimestamp(int index) {
@@ -403,10 +435,14 @@
             final BatteryHistEntry entry = new BatteryHistEntry(values);
             final Map<String, BatteryHistEntry> entryMap = new HashMap<>();
             entryMap.put("fake_entry_key" + index, entry);
-            batteryHistoryMap.put(generateTimestamp(index), entryMap);
+            long timestamp = generateTimestamp(index);
+            if (index == 0) {
+                timestamp += DateUtils.MINUTE_IN_MILLIS;
+            }
+            batteryHistoryMap.put(timestamp, entryMap);
         }
         DataProcessor.sTestCurrentTimeMillis =
-                generateTimestamp(numOfHours - 1) + DateUtils.MINUTE_IN_MILLIS;
+                generateTimestamp(numOfHours - 1) + DateUtils.MINUTE_IN_MILLIS * 2;
         return batteryHistoryMap;
     }
 
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBreakdownControllerTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBreakdownControllerTest.java
index 16fec09..8d0a839 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBreakdownControllerTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBreakdownControllerTest.java
@@ -176,7 +176,7 @@
     }
 
     @Test
-    public void removeAndCacheAllUnusedPreferences_removePerf_buildCacheAndRemoveAllPreference() {
+    public void removeAndCacheAllUnusedPreferences_removePref_buildCacheAndRemoveAllPreference() {
         doReturn(1).when(mAppListPreferenceGroup).getPreferenceCount();
         doReturn(mPowerGaugePreference).when(mAppListPreferenceGroup).getPreference(0);
         doReturn(PREF_KEY2).when(mBatteryHistEntry).getKey();
@@ -193,7 +193,7 @@
     }
 
     @Test
-    public void removeAndCacheAllUnusedPreferences_keepPerf_KeepAllPreference() {
+    public void removeAndCacheAllUnusedPreferences_keepPref_KeepAllPreference() {
         doReturn(1).when(mAppListPreferenceGroup).getPreferenceCount();
         doReturn(mPowerGaugePreference).when(mAppListPreferenceGroup).getPreference(0);
         doReturn(PREF_KEY).when(mBatteryHistEntry).getKey();
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/DataProcessManagerTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/DataProcessManagerTest.java
index 753a7f7..b610cfb 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/DataProcessManagerTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/DataProcessManagerTest.java
@@ -102,7 +102,7 @@
                         AppUsageEventEntity.KEY_UID,
                         AppUsageEventEntity.KEY_PACKAGE_NAME,
                         AppUsageEventEntity.KEY_TIMESTAMP});
-        DatabaseUtils.sFakeAppUsageEventSupplier = () -> cursor;
+        DatabaseUtils.sFakeSupplier = () -> cursor;
         doReturn(true).when(mUserManager).isUserUnlocked(anyInt());
 
         mDataProcessManager.start();
@@ -171,7 +171,7 @@
         cursor.addRow(new Object[] {
                 AppUsageEventType.ACTIVITY_STOPPED.getNumber(), /*timestamp=*/ 6, /*userId=*/ 1,
                 /*instanceId=*/ 2, packageName});
-        DatabaseUtils.sFakeAppUsageEventSupplier = () -> cursor;
+        DatabaseUtils.sFakeSupplier = () -> cursor;
 
         final DataProcessManager dataProcessManager = new DataProcessManager(
                 mContext, /*handler=*/ null, /*rawStartTimestamp=*/ 2L,  /*callbackFunction=*/ null,
@@ -240,7 +240,7 @@
                         AppUsageEventEntity.KEY_TIMESTAMP});
         // Adds fake data into the cursor.
         cursor.addRow(new Object[] {101L, "app name1", 1001L});
-        DatabaseUtils.sFakeAppUsageEventSupplier = () -> cursor;
+        DatabaseUtils.sFakeSupplier = () -> cursor;
 
         mDataProcessManager.start();
 
@@ -263,7 +263,7 @@
     }
 
     @Test
-    public void getBatteryLevelData_notEnoughData_returnNull() {
+    public void getBatteryLevelData_allDataInOneHour_returnExpectedResult() {
         // The timestamps and the current time are within half hour before an even hour.
         final long[] timestamps = {
                 DateUtils.HOUR_IN_MILLIS * 2 - 300L,
@@ -274,9 +274,26 @@
                 createHistoryMap(timestamps, levels);
         DataProcessor.sTestCurrentTimeMillis = timestamps[timestamps.length - 1];
 
-        assertThat(DataProcessManager.getBatteryLevelData(
-                mContext, /*handler=*/ null, batteryHistoryMap, /*asyncResponseDelegate=*/ null))
-                .isNull();
+        final BatteryLevelData resultData =
+                DataProcessManager.getBatteryLevelData(
+                        mContext,
+                        /*handler=*/ null,
+                        batteryHistoryMap,
+                        /*asyncResponseDelegate=*/ null);
+
+
+        final List<Long> expectedDailyTimestamps = List.of(
+                DateUtils.HOUR_IN_MILLIS * 2 - 300L,
+                DateUtils.HOUR_IN_MILLIS * 2 - 100L);
+        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(
+                resultData,
+                expectedDailyTimestamps,
+                expectedDailyLevels,
+                expectedHourlyTimestamps,
+                expectedHourlyLevels);
     }
 
     @Test
@@ -297,7 +314,7 @@
 
         final List<Long> expectedDailyTimestamps = List.of(
                 1640966400000L,  // 2022-01-01 00:00:00
-                1640973600000L); // 2022-01-01 02:00:00
+                1640970000000L); // 2022-01-01 01: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);
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 66e48c0..ea2db86 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/DataProcessorTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/DataProcessorTest.java
@@ -42,7 +42,6 @@
 import android.os.Parcel;
 import android.os.RemoteException;
 import android.os.UserManager;
-import android.text.format.DateUtils;
 
 import com.android.settings.fuelgauge.PowerUsageFeatureProvider;
 import com.android.settings.testutils.FakeFeatureFactory;
@@ -409,24 +408,21 @@
 
         // Timezone GMT+8
         final long[] expectedTimestamps = {
-                1640966400000L, // 2022-01-01 00:00:00
+                1640966700000L, // 2022-01-01 00:05:00
                 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
-                1640984400000L, // 2022-01-01 05:00:00
-                1640988000000L  // 2022-01-01 06:00:00
+                1640981400000L  // 2022-01-01 04:10:00
         };
-        final int[] expectedLevels = {100, 94, 90, 84, 56, 98, 98};
+        final int[] expectedLevels = {100, 94, 90, 84, 56, 98};
         assertThat(resultMap).hasSize(expectedLevels.length);
-        for (int index = 0; index < 5; index++) {
+        for (int index = 0; index < expectedLevels.length - 1; 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();
-        }
+        assertThat(resultMap.get(expectedTimestamps[expectedLevels.length - 1]).containsKey(
+                DataProcessor.CURRENT_TIME_BATTERY_HISTORY_PLACEHOLDER)).isTrue();
     }
 
     @Test
@@ -589,7 +585,8 @@
                         1667782800000L, // 2022-11-06 17:00:00
                         1667790000000L, // 2022-11-06 19:00:00
                         1667797200000L, // 2022-11-06 21:00:00
-                        1667804400000L  // 2022-11-06 23:00:00
+                        1667804400000L, // 2022-11-06 23:00:00
+                        1667808000000L  // 2022-11-07 00:00:00
                 ),
                 List.of(
                         1667808000000L, // 2022-11-07 00:00:00
@@ -621,6 +618,7 @@
         expectedHourlyLevels2.add(null);
         expectedHourlyLevels2.add(null);
         expectedHourlyLevels2.add(null);
+        expectedHourlyLevels2.add(null);
         final List<Integer> expectedHourlyLevels3 = new ArrayList<>();
         expectedHourlyLevels3.add(null);
         expectedHourlyLevels3.add(null);
@@ -683,7 +681,8 @@
                         1647216000000L, // 2022-03-13 17:00:00
                         1647223200000L, // 2022-03-13 19:00:00
                         1647230400000L, // 2022-03-13 21:00:00
-                        1647237600000L  // 2022-03-13 23:00:00
+                        1647237600000L, // 2022-03-13 23:00:00
+                        1647241200000L  // 2022-03-14 00:00:00
                 ),
                 List.of(
                         1647241200000L, // 2022-03-14 00:00:00
@@ -708,6 +707,7 @@
         expectedHourlyLevels2.add(null);
         expectedHourlyLevels2.add(null);
         expectedHourlyLevels2.add(null);
+        expectedHourlyLevels2.add(null);
         final List<Integer> expectedHourlyLevels3 = new ArrayList<>();
         expectedHourlyLevels3.add(null);
         expectedHourlyLevels3.add(null);
@@ -736,49 +736,95 @@
     @Test
     public void getTimestampSlots_startWithEvenHour_returnExpectedResult() {
         final Calendar startCalendar = Calendar.getInstance();
+        startCalendar.clear();
         startCalendar.set(2022, 6, 5, 6, 30, 50); // 2022-07-05 06:30:50
+        final long startTimestamp = startCalendar.getTimeInMillis();
         final Calendar endCalendar = Calendar.getInstance();
+        endCalendar.clear();
         endCalendar.set(2022, 6, 5, 22, 30, 50); // 2022-07-05 22:30:50
+        final long endTimestamp = endCalendar.getTimeInMillis();
 
-        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, 6, 0, 0, 0); // 2022-07-05 22:00:00
-        verifyExpectedTimestampSlots(
-                startCalendar, endCalendar, expectedStartCalendar, expectedEndCalendar);
+        final Calendar calendar = Calendar.getInstance();
+        List<Long> expectedTimestamps = new ArrayList<>();
+        calendar.clear();
+        calendar.set(2022, 6, 5, 6, 30, 50); // 2022-07-05 06:30:50
+        expectedTimestamps.add(calendar.getTimeInMillis());
+        for (int hour = 7; hour <= 22; hour++) {
+            calendar.clear();
+            calendar.set(2022, 6, 5, hour, 0, 0); // 2022-07-05 <hour>:00:00
+            expectedTimestamps.add(calendar.getTimeInMillis());
+        }
+        calendar.clear();
+        calendar.set(2022, 6, 5, 22, 30, 50); // 2022-07-05 22:30:50
+        expectedTimestamps.add(calendar.getTimeInMillis());
+
+        verifyExpectedTimestampSlots(startTimestamp, endTimestamp, expectedTimestamps);
     }
 
     @Test
     public void getTimestampSlots_startWithOddHour_returnExpectedResult() {
         final Calendar startCalendar = Calendar.getInstance();
+        startCalendar.clear();
         startCalendar.set(2022, 6, 5, 5, 0, 50); // 2022-07-05 05:00:50
+        final long startTimestamp = startCalendar.getTimeInMillis();
         final Calendar endCalendar = Calendar.getInstance();
-        endCalendar.set(2022, 6, 6, 21, 0, 50); // 2022-07-06 21:00:50
+        endCalendar.clear();
+        endCalendar.set(2022, 6, 5, 21, 0, 50); // 2022-07-05 21:00:50
+        final long endTimestamp = endCalendar.getTimeInMillis();
 
-        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, 6, 22, 0, 0); // 2022-07-06 20:00:00
-        verifyExpectedTimestampSlots(
-                startCalendar, endCalendar, expectedStartCalendar, expectedEndCalendar);
+        final Calendar calendar = Calendar.getInstance();
+        List<Long> expectedTimestamps = new ArrayList<>();
+        calendar.clear();
+        calendar.set(2022, 6, 5, 5, 0, 50); // 2022-07-05 05:00:50
+        expectedTimestamps.add(calendar.getTimeInMillis());
+        for (int hour = 6; hour <= 21; hour++) {
+            calendar.clear();
+            calendar.set(2022, 6, 5, hour, 0, 0); // 2022-07-05 <hour>:00:00
+            expectedTimestamps.add(calendar.getTimeInMillis());
+        }
+        calendar.clear();
+        calendar.set(2022, 6, 5, 21, 0, 50); // 2022-07-05 21:00:50
+        expectedTimestamps.add(calendar.getTimeInMillis());
+
+        verifyExpectedTimestampSlots(startTimestamp, endTimestamp, expectedTimestamps);
     }
 
     @Test
     public void getDailyTimestamps_notEnoughData_returnEmptyList() {
         assertThat(DataProcessor.getDailyTimestamps(new ArrayList<>())).isEmpty();
         assertThat(DataProcessor.getDailyTimestamps(List.of(100L))).isEmpty();
-        assertThat(DataProcessor.getDailyTimestamps(List.of(100L, 5400000L))).isEmpty();
     }
 
     @Test
-    public void getDailyTimestamps_OneHourDataPerDay_returnEmptyList() {
+    public void getDailyTimestamps_allDataInOneHour_returnExpectedList() {
+        // Timezone GMT+8
+        final List<Long> timestamps = List.of(
+                1640970006000L, // 2022-01-01 01:00:06
+                1640973608000L  // 2022-01-01 01:00:08
+        );
+
+        final List<Long> expectedTimestamps = List.of(
+                1640970006000L, // 2022-01-01 01:00:06
+                1640973608000L  // 2022-01-01 01:00:08
+        );
+        assertThat(DataProcessor.getDailyTimestamps(timestamps)).isEqualTo(expectedTimestamps);
+    }
+
+    @Test
+    public void getDailyTimestamps_OneHourDataPerDay_returnExpectedList() {
         // Timezone GMT+8
         final List<Long> timestamps = List.of(
                 1641049200000L, // 2022-01-01 23:00:00
                 1641052800000L, // 2022-01-02 00:00:00
                 1641056400000L  // 2022-01-02 01:00:00
         );
-        assertThat(DataProcessor.getDailyTimestamps(timestamps)).isEmpty();
+
+        final List<Long> expectedTimestamps = List.of(
+                1641049200000L, // 2022-01-01 23:00:00
+                1641052800000L, // 2022-01-02 00:00:00
+                1641056400000L  // 2022-01-02 01:00:00
+        );
+        assertThat(DataProcessor.getDailyTimestamps(timestamps)).isEqualTo(expectedTimestamps);
     }
 
     @Test
@@ -830,6 +876,7 @@
         );
 
         final List<Long> expectedTimestamps = List.of(
+                1641049200000L, // 2022-01-01 23:00:00
                 1641052800000L, // 2022-01-02 00:00:00
                 1641139200000L, // 2022-01-03 00:00:00
                 1641225600000L, // 2022-01-04 00:00:00
@@ -871,7 +918,8 @@
                 1640988000000L, // 2022-01-01 06:00:00
                 1641052800000L, // 2022-01-02 00:00:00
                 1641139200000L, // 2022-01-03 00:00:00
-                1641225600000L  // 2022-01-04 00:00:00
+                1641225600000L, // 2022-01-04 00:00:00
+                1641229200000L  // 2022-01-04 01:00:00
         );
         assertThat(DataProcessor.getDailyTimestamps(timestamps)).isEqualTo(expectedTimestamps);
     }
@@ -923,27 +971,6 @@
     }
 
     @Test
-    public void getTimestampOfNextDay_returnExpectedResult() {
-        // 2021-02-28 06:00:00 => 2021-03-01 00:00:00
-        assertThat(DataProcessor.getTimestampOfNextDay(1614463200000L))
-                .isEqualTo(1614528000000L);
-        // 2021-12-31 16:00:00 => 2022-01-01 00:00:00
-        assertThat(DataProcessor.getTimestampOfNextDay(1640937600000L))
-                .isEqualTo(1640966400000L);
-    }
-
-    @Test
-    public void isForDailyChart_returnExpectedResult() {
-        assertThat(DataProcessor.isForDailyChart(/*isStartOrEnd=*/ true, 0L)).isTrue();
-        // 2022-01-01 00:00:00
-        assertThat(DataProcessor.isForDailyChart(/*isStartOrEnd=*/ false, 1640966400000L))
-                .isTrue();
-        // 2022-01-01 01:00:05
-        assertThat(DataProcessor.isForDailyChart(/*isStartOrEnd=*/ false, 1640970005000L))
-                .isFalse();
-    }
-
-    @Test
     public void getBatteryUsageMap_emptyHistoryMap_returnNull() {
         final List<BatteryLevelData.PeriodBatteryLevelData> hourlyBatteryLevelsPerDay =
                 new ArrayList<>();
@@ -2046,24 +2073,16 @@
     }
 
     private static void verifyExpectedTimestampSlots(
-            final Calendar start,
-            final Calendar current,
-            final Calendar expectedStart,
-            final Calendar expectedEnd) {
-        expectedStart.set(Calendar.MILLISECOND, 0);
-        expectedEnd.set(Calendar.MILLISECOND, 0);
+            final long startTimestamp,
+            final long currentTimestamp,
+            final List<Long> expectedTimestamps) {
         final ArrayList<Long> timestampSlots = new ArrayList<>();
-        timestampSlots.add(start.getTimeInMillis());
-        final List<Long> resultList =
-                DataProcessor.getTimestampSlots(timestampSlots, current.getTimeInMillis());
+        timestampSlots.add(startTimestamp);
 
-        for (int index = 0; index < resultList.size(); index++) {
-            final long expectedTimestamp =
-                    expectedStart.getTimeInMillis() + index * DateUtils.HOUR_IN_MILLIS;
-            assertThat(resultList.get(index)).isEqualTo(expectedTimestamp);
-        }
-        assertThat(resultList.get(resultList.size() - 1))
-                .isEqualTo(expectedEnd.getTimeInMillis());
+        final List<Long> resultList =
+                DataProcessor.getTimestampSlots(timestampSlots, currentTimestamp);
+
+        assertThat(resultList).isEqualTo(expectedTimestamps);
     }
 
     private static void assertBatteryDiffEntry(
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/DatabaseUtilsTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/DatabaseUtilsTest.java
index 20799d4..efce44e 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/DatabaseUtilsTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/DatabaseUtilsTest.java
@@ -261,7 +261,7 @@
     public void getAppUsageStartTimestampOfUser_emptyCursorContent_returnEarliestTimestamp() {
         final MatrixCursor cursor =
                 new MatrixCursor(new String[] {AppUsageEventEntity.KEY_TIMESTAMP});
-        DatabaseUtils.sFakeAppUsageLatestTimestampSupplier = () -> cursor;
+        DatabaseUtils.sFakeSupplier = () -> cursor;
 
         final long earliestTimestamp = 10001L;
         assertThat(DatabaseUtils.getAppUsageStartTimestampOfUser(
@@ -270,7 +270,7 @@
 
     @Test
     public void getAppUsageStartTimestampOfUser_nullCursor_returnEarliestTimestamp() {
-        DatabaseUtils.sFakeAppUsageLatestTimestampSupplier = () -> null;
+        DatabaseUtils.sFakeSupplier = () -> null;
         final long earliestTimestamp = 10001L;
         assertThat(DatabaseUtils.getAppUsageStartTimestampOfUser(
                 mContext, /*userId=*/ 0, earliestTimestamp)).isEqualTo(earliestTimestamp);
@@ -283,7 +283,7 @@
                 new MatrixCursor(new String[] {AppUsageEventEntity.KEY_TIMESTAMP});
         // Adds fake data into the cursor.
         cursor.addRow(new Object[] {returnedTimestamp});
-        DatabaseUtils.sFakeAppUsageLatestTimestampSupplier = () -> cursor;
+        DatabaseUtils.sFakeSupplier = () -> cursor;
 
         final long earliestTimestamp1 = 1001L;
         assertThat(DatabaseUtils.getAppUsageStartTimestampOfUser(
@@ -302,7 +302,7 @@
                         AppUsageEventEntity.KEY_PACKAGE_NAME,
                         AppUsageEventEntity.KEY_TIMESTAMP,
                         AppUsageEventEntity.KEY_APP_USAGE_EVENT_TYPE});
-        DatabaseUtils.sFakeAppUsageEventSupplier = () -> cursor;
+        DatabaseUtils.sFakeSupplier = () -> cursor;
 
         assertThat(DatabaseUtils.getAppUsageEventForUsers(
                 mContext,
@@ -313,7 +313,7 @@
 
     @Test
     public void getAppUsageEventForUsers_nullCursor_returnEmptyMap() {
-        DatabaseUtils.sFakeAppUsageEventSupplier = () -> null;
+        DatabaseUtils.sFakeSupplier = () -> null;
         assertThat(DatabaseUtils.getAppUsageEventForUsers(
                 mContext,
                 /*calendar=*/ null,
@@ -335,7 +335,7 @@
         cursor.addRow(new Object[] {101L, "app name2", timestamp2});
         cursor.addRow(new Object[] {101L, "app name3", timestamp2});
         cursor.addRow(new Object[] {101L, "app name4", timestamp2});
-        DatabaseUtils.sFakeAppUsageEventSupplier = () -> cursor;
+        DatabaseUtils.sFakeSupplier = () -> cursor;
 
         final List<AppUsageEvent> appUsageEventList = DatabaseUtils.getAppUsageEventForUsers(
                 mContext,
@@ -356,7 +356,7 @@
                         BatteryHistEntry.KEY_UID,
                         BatteryHistEntry.KEY_USER_ID,
                         BatteryHistEntry.KEY_TIMESTAMP});
-        DatabaseUtils.sFakeBatteryStateSupplier = () -> cursor;
+        DatabaseUtils.sFakeSupplier = () -> cursor;
 
         assertThat(DatabaseUtils.getHistoryMapSinceLastFullCharge(
                 mContext, /*calendar=*/ null)).isEmpty();
@@ -364,7 +364,7 @@
 
     @Test
     public void getHistoryMapSinceLastFullCharge_nullCursor_returnEmptyMap() {
-        DatabaseUtils.sFakeBatteryStateSupplier = () -> null;
+        DatabaseUtils.sFakeSupplier = () -> null;
         assertThat(DatabaseUtils.getHistoryMapSinceLastFullCharge(
                 mContext, /*calendar=*/ null)).isEmpty();
     }
@@ -383,7 +383,7 @@
                 "app name3", timestamp2, 3, ConvertUtils.CONSUMER_TYPE_UID_BATTERY});
         cursor.addRow(new Object[] {
                 "app name4", timestamp2, 4, ConvertUtils.CONSUMER_TYPE_UID_BATTERY});
-        DatabaseUtils.sFakeBatteryStateSupplier = () -> cursor;
+        DatabaseUtils.sFakeSupplier = () -> cursor;
 
         final Map<Long, Map<String, BatteryHistEntry>> batteryHistMap =
                 DatabaseUtils.getHistoryMapSinceLastFullCharge(
@@ -413,7 +413,7 @@
         doReturn(true).when(mUserManager).isManagedProfile();
         doReturn(UserHandle.SYSTEM).when(mUserManager).getProfileParent(UserHandle.CURRENT);
 
-        DatabaseUtils.sFakeBatteryStateSupplier = () -> getMatrixCursor();
+        DatabaseUtils.sFakeSupplier = () -> getMatrixCursor();
 
         final Map<Long, Map<String, BatteryHistEntry>> batteryHistMap =
                 DatabaseUtils.getHistoryMapSinceLastFullCharge(
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/TimestampUtilsTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/TimestampUtilsTest.java
new file mode 100644
index 0000000..23787c7
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/TimestampUtilsTest.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2023 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.fuelgauge.batteryusage;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
+
+import java.util.TimeZone;
+
+@RunWith(RobolectricTestRunner.class)
+public class TimestampUtilsTest {
+
+    @Before
+    public void setUp() {
+        TimeZone.setDefault(TimeZone.getTimeZone("GMT+8"));
+    }
+
+    @Test
+    public void getNextHourTimestamp_returnExpectedResult() {
+        // 2021-02-28 06:00:00 => 2021-02-28 07:00:00
+        assertThat(TimestampUtils.getNextHourTimestamp(1614463200000L))
+                .isEqualTo(1614466800000L);
+        // 2021-12-31 23:59:59 => 2022-01-01 00:00:00
+        assertThat(TimestampUtils.getNextHourTimestamp(16409663999999L))
+                .isEqualTo(16409664000000L);
+    }
+
+    @Test
+    public void getNextEvenHourTimestamp_returnExpectedResult() {
+        // 2021-02-28 06:00:00 => 2021-02-28 08:00:00
+        assertThat(TimestampUtils.getNextEvenHourTimestamp(1614463200000L))
+                .isEqualTo(1614470400000L);
+        // 2021-12-31 23:59:59 => 2022-01-01 00:00:00
+        assertThat(TimestampUtils.getNextEvenHourTimestamp(16409663999999L))
+                .isEqualTo(16409664000000L);
+    }
+
+    @Test
+    public void getLastEvenHourTimestamp_returnExpectedResult() {
+        // 2021-02-28 06:00:06 => 2021-02-28 06:00:00
+        assertThat(TimestampUtils.getLastEvenHourTimestamp(1614463206000L))
+                .isEqualTo(1614463200000L);
+        // 2021-12-31 23:59:59 => 2021-12-31 22:00:00
+        assertThat(TimestampUtils.getLastEvenHourTimestamp(16409663999999L))
+                .isEqualTo(16409656800000L);
+    }
+
+    @Test
+    public void getTimestampOfNextDay_returnExpectedResult() {
+        // 2021-02-28 06:00:00 => 2021-03-01 00:00:00
+        assertThat(TimestampUtils.getNextDayTimestamp(1614463200000L))
+                .isEqualTo(1614528000000L);
+        // 2021-12-31 16:00:00 => 2022-01-01 00:00:00
+        assertThat(TimestampUtils.getNextDayTimestamp(1640937600000L))
+                .isEqualTo(1640966400000L);
+    }
+
+    @Test
+    public void isMidnight_returnExpectedResult() {
+        // 2022-01-01 00:00:00
+        assertThat(TimestampUtils.isMidnight(1640966400000L)).isTrue();
+        // 2022-01-01 01:00:05
+        assertThat(TimestampUtils.isMidnight(1640970005000L)).isFalse();
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/support/SupportDashboardActivityTest.java b/tests/robotests/src/com/android/settings/support/SupportDashboardActivityTest.java
index 0124551..f510994 100644
--- a/tests/robotests/src/com/android/settings/support/SupportDashboardActivityTest.java
+++ b/tests/robotests/src/com/android/settings/support/SupportDashboardActivityTest.java
@@ -16,6 +16,8 @@
 
 package com.android.settings.support;
 
+import static com.android.settings.support.SupportDashboardActivity.ACTION_SUPPORT_SETTINGS;
+
 import static com.google.common.truth.Truth.assertThat;
 
 import android.content.Context;
@@ -59,7 +61,7 @@
                 mContext.getString(R.string.page_tab_title_support));
         assertThat(value.intentTargetPackage).isEqualTo(mContext.getPackageName());
         assertThat(value.intentTargetClass).isEqualTo(SupportDashboardActivity.class.getName());
-        assertThat(value.intentAction).isEqualTo(Intent.ACTION_MAIN);
+        assertThat(value.intentAction).isEqualTo(ACTION_SUPPORT_SETTINGS);
     }
 
     @Test
diff --git a/tests/robotests/src/com/android/settings/wifi/WifiConfigController2Test.java b/tests/robotests/src/com/android/settings/wifi/WifiConfigController2Test.java
index ad086b7..faaa0fa 100644
--- a/tests/robotests/src/com/android/settings/wifi/WifiConfigController2Test.java
+++ b/tests/robotests/src/com/android/settings/wifi/WifiConfigController2Test.java
@@ -470,7 +470,7 @@
 
     private void checkSavedMacRandomizedValue(int macRandomizedValue) {
         when(mWifiEntry.isSaved()).thenReturn(true);
-        final WifiConfiguration mockWifiConfig = mock(WifiConfiguration.class);
+        final WifiConfiguration mockWifiConfig = spy(new WifiConfiguration());
         when(mockWifiConfig.getIpConfiguration()).thenReturn(mock(IpConfiguration.class));
         when(mWifiEntry.getWifiConfiguration()).thenReturn(mockWifiConfig);
         mockWifiConfig.macRandomizationSetting = macRandomizedValue;
@@ -809,9 +809,10 @@
     private void setUpModifyingSavedPeapConfigController() {
         when(mWifiEntry.isSaved()).thenReturn(true);
         when(mWifiEntry.getSecurity()).thenReturn(WifiEntry.SECURITY_EAP);
-        final WifiConfiguration mockWifiConfig = mock(WifiConfiguration.class);
+        final WifiConfiguration mockWifiConfig = spy(new WifiConfiguration());
+        mockWifiConfig.setSecurityParams(WifiConfiguration.SECURITY_TYPE_EAP);
         when(mockWifiConfig.getIpConfiguration()).thenReturn(mock(IpConfiguration.class));
-        final WifiEnterpriseConfig mockWifiEnterpriseConfig = mock(WifiEnterpriseConfig.class);
+        final WifiEnterpriseConfig mockWifiEnterpriseConfig = spy(new WifiEnterpriseConfig());
         when(mockWifiEnterpriseConfig.getEapMethod()).thenReturn(Eap.PEAP);
         mockWifiConfig.enterpriseConfig = mockWifiEnterpriseConfig;
         when(mWifiEntry.getWifiConfiguration()).thenReturn(mockWifiConfig);
@@ -980,8 +981,8 @@
 
     private void setUpModifyingSavedCertificateConfigController(String savedCaCertificate,
             String savedUserCertificate) {
-        final WifiConfiguration mockWifiConfig = mock(WifiConfiguration.class);
-        final WifiEnterpriseConfig mockWifiEnterpriseConfig = mock(WifiEnterpriseConfig.class);
+        final WifiConfiguration mockWifiConfig = spy(new WifiConfiguration());
+        final WifiEnterpriseConfig mockWifiEnterpriseConfig = spy(new WifiEnterpriseConfig());
 
         mockWifiConfig.enterpriseConfig = mockWifiEnterpriseConfig;
         when(mWifiEntry.isSaved()).thenReturn(true);
diff --git a/tests/robotests/src/com/android/settings/wifi/tether/WifiTetherSettingsTest.java b/tests/robotests/src/com/android/settings/wifi/tether/WifiTetherSettingsTest.java
index 0c2bbf5..fb64023 100644
--- a/tests/robotests/src/com/android/settings/wifi/tether/WifiTetherSettingsTest.java
+++ b/tests/robotests/src/com/android/settings/wifi/tether/WifiTetherSettingsTest.java
@@ -156,6 +156,16 @@
     }
 
     @Test
+    public void onSecuritySummaryChanged_canNotShowWifiHotspot_returnFalse() {
+        int stringResId = R.string.wifi_security_sae;
+        mWifiTetherSettings.mWifiHotspotSecurity = mock(Preference.class);
+
+        mWifiTetherSettings.onSecuritySummaryChanged(stringResId);
+
+        verify(mWifiTetherSettings.mWifiHotspotSecurity).setSummary(stringResId);
+    }
+
+    @Test
     public void onSpeedSummaryChanged_canNotShowWifiHotspot_returnFalse() {
         int stringResId = R.string.wifi_hotspot_speed_summary_6g;
         mWifiTetherSettings.mWifiHotspotSpeed = mock(Preference.class);
diff --git a/tests/uitests/src/com/android/settings/biometrics2/ui/view/FingerprintEnrollmentActivityTest.java b/tests/uitests/src/com/android/settings/biometrics2/ui/view/FingerprintEnrollmentActivityTest.java
index cffc452..ae32651 100644
--- a/tests/uitests/src/com/android/settings/biometrics2/ui/view/FingerprintEnrollmentActivityTest.java
+++ b/tests/uitests/src/com/android/settings/biometrics2/ui/view/FingerprintEnrollmentActivityTest.java
@@ -33,6 +33,7 @@
 import android.support.test.uiautomator.UiObject2;
 import android.support.test.uiautomator.Until;
 
+import androidx.annotation.NonNull;
 import androidx.test.InstrumentationRegistry;
 import androidx.test.runner.AndroidJUnit4;
 
@@ -54,18 +55,25 @@
     private static final String SETTINGS_PACKAGE_NAME = "com.android.settings";
     private static final String ACTIVITY_CLASS_NAME =
             "com.android.settings.biometrics2.ui.view.FingerprintEnrollmentActivity";
-    public static final String EXTRA_IS_SETUP_FLOW = "isSetupFlow";
+    private static final String EXTRA_IS_SETUP_FLOW = "isSetupFlow";
+    private static final String EXTRA_SKIP_FIND_SENSOR = "skip_find_sensor";
     private static final String EXTRA_FROM_SETTINGS_SUMMARY = "from_settings_summary";
     private static final String EXTRA_PAGE_TRANSITION_TYPE = "page_transition_type";
     private static final String EXTRA_KEY_GK_PW_HANDLE = "gk_pw_handle";
     private static final String TEST_PIN = "1234";
 
+    private static final String UDFPS_ENROLLING_TITLE = "Touch & hold the fingerprint sensor";
+    private static final String SFPS_ENROLLING_TITLE =
+            "Lift, then touch. Move your finger slightly each time.";
+    private static final String RFPS_ENROLLING_TITLE = "Lift, then touch again";
+
     private UiDevice mDevice;
     private byte[] mToken = new byte[]{};
     private Context mContext;
     private boolean mFingerprintPropCallbackLaunched;
     private boolean mCanAssumeUdfps;
     private boolean mCanAssumeSfps;
+    private String mEnrollingTitle;
 
     private static final int IDLE_TIMEOUT = 10000;
 
@@ -94,6 +102,13 @@
                         final FingerprintSensorPropertiesInternal prop = list.get(0);
                         mCanAssumeUdfps = prop.isAnyUdfpsType();
                         mCanAssumeSfps = prop.isAnySidefpsType();
+                        if (mCanAssumeUdfps) {
+                            mEnrollingTitle = UDFPS_ENROLLING_TITLE;
+                        } else if (mCanAssumeSfps) {
+                            mEnrollingTitle = SFPS_ENROLLING_TITLE;
+                        } else {
+                            mEnrollingTitle = RFPS_ENROLLING_TITLE;
+                        }
                     }
                 });
 
@@ -106,8 +121,9 @@
     }
 
     @Test
-    public void testLaunchChooseLock() {
-        launchFingerprintEnrollActivity(false, null);
+    public void testIntroChooseLock() {
+        final Intent intent = newActivityIntent();
+        mContext.startActivity(intent);
         assertThat(mDevice.wait(Until.hasObject(By.text("Choose your backup screen lock method")),
                 IDLE_TIMEOUT)).isTrue();
     }
@@ -135,12 +151,12 @@
     }
 
     @Test
-    public void testLaunchWithGkPwHandle_withUdfps_clickStart() {
+    public void testIntroWithGkPwHandle_withUdfps_clickStart() {
         assumeTrue(mCanAssumeUdfps);
 
         LockScreenUtil.setLockscreen(LockScreenUtil.LockscreenType.PIN, TEST_PIN, true);
 
-        launchFingerprintEnrollActivityWithGkPwHandle(false);
+        launchIntroWithGkPwHandle(false);
 
         // Intro page
         verifyIntroPage();
@@ -159,17 +175,16 @@
         startBtn.click();
 
         // Enrolling page
-        assertThat(mDevice.wait(Until.hasObject(By.text("Touch & hold the fingerprint sensor")),
-                IDLE_TIMEOUT)).isTrue();
+        assertThat(mDevice.wait(Until.hasObject(By.text(mEnrollingTitle)), IDLE_TIMEOUT)).isTrue();
     }
 
     @Test
-    public void testLaunchWithGkPwHandle_withUdfps_clickLottie() {
+    public void testIntroWithGkPwHandle_withUdfps_clickLottie() {
         assumeTrue(mCanAssumeUdfps);
 
         LockScreenUtil.setLockscreen(LockScreenUtil.LockscreenType.PIN, TEST_PIN, true);
 
-        launchFingerprintEnrollActivityWithGkPwHandle(false);
+        launchIntroWithGkPwHandle(false);
 
         // Intro page
         verifyIntroPage();
@@ -188,17 +203,16 @@
         lottie.click();
 
         // Enrolling page
-        assertThat(mDevice.wait(Until.hasObject(By.text("Touch & hold the fingerprint sensor")),
-                IDLE_TIMEOUT)).isTrue();
+        assertThat(mDevice.wait(Until.hasObject(By.text(mEnrollingTitle)), IDLE_TIMEOUT)).isTrue();
     }
 
     @Test
-    public void testLaunchWithGkPwHandle_withSfps() {
+    public void testIntroWithGkPwHandle_withSfps() {
         assumeTrue(mCanAssumeSfps);
 
         LockScreenUtil.setLockscreen(LockScreenUtil.LockscreenType.PIN, TEST_PIN, true);
 
-        launchFingerprintEnrollActivityWithGkPwHandle(false);
+        launchIntroWithGkPwHandle(false);
 
         // Intro page
         verifyIntroPage();
@@ -216,12 +230,12 @@
     }
 
     @Test
-    public void testLaunchWithGkPwHandle_withRfps() {
+    public void testIntroWithGkPwHandle_withRfps() {
         assumeFalse(mCanAssumeUdfps || mCanAssumeSfps);
 
         LockScreenUtil.setLockscreen(LockScreenUtil.LockscreenType.PIN, TEST_PIN, true);
 
-        launchFingerprintEnrollActivityWithGkPwHandle(false);
+        launchIntroWithGkPwHandle(false);
 
         // Intro page
         verifyIntroPage();
@@ -241,10 +255,10 @@
     }
 
     @Test
-    public void testLaunchWithGkPwHandle_clickNoThanksInIntroPage() {
+    public void testIntroWithGkPwHandle_clickNoThanksInIntroPage() {
         LockScreenUtil.setLockscreen(LockScreenUtil.LockscreenType.PIN, TEST_PIN, true);
 
-        launchFingerprintEnrollActivityWithGkPwHandle(false);
+        launchIntroWithGkPwHandle(false);
 
         // Intro page
         verifyIntroPage();
@@ -258,10 +272,10 @@
     }
 
     @Test
-    public void testLaunchWithGkPwHandle_clickSkipInFindSensor() {
+    public void testIntroWithGkPwHandle_clickSkipInFindSensor() {
         LockScreenUtil.setLockscreen(LockScreenUtil.LockscreenType.PIN, TEST_PIN, true);
 
-        launchFingerprintEnrollActivityWithGkPwHandle(false);
+        launchIntroWithGkPwHandle(false);
 
         // Intro page
         verifyIntroPage();
@@ -282,10 +296,10 @@
     }
 
     @Test
-    public void testLaunchWithGkPwHandle_clickSkipAnywayInFindFpsDialog_whenIsSuw() {
+    public void testIntroWithGkPwHandle_clickSkipAnywayInFindFpsDialog_whenIsSuw() {
         LockScreenUtil.setLockscreen(LockScreenUtil.LockscreenType.PIN, TEST_PIN, true);
 
-        launchFingerprintEnrollActivityWithGkPwHandle(true);
+        launchIntroWithGkPwHandle(true);
 
         // Intro page
         verifyIntroPage();
@@ -315,10 +329,10 @@
     }
 
     @Test
-    public void testLaunchWithGkPwHandle_clickGoBackInFindFpsDialog_whenIsSuw() {
+    public void testIntroWithGkPwHandle_clickGoBackInFindFpsDialog_whenIsSuw() {
         LockScreenUtil.setLockscreen(LockScreenUtil.LockscreenType.PIN, TEST_PIN, true);
 
-        launchFingerprintEnrollActivityWithGkPwHandle(true);
+        launchIntroWithGkPwHandle(true);
 
         // Intro page
         verifyIntroPage();
@@ -346,43 +360,138 @@
     }
 
     @Test
-    public void testLaunchCheckPin() {
+    public void testIntroCheckPin() {
         LockScreenUtil.setLockscreen(LockScreenUtil.LockscreenType.PIN, TEST_PIN, true);
-        launchFingerprintEnrollActivity(false, null);
+        final Intent intent = newActivityIntent();
+        mContext.startActivity(intent);
         assertThat(mDevice.wait(Until.hasObject(By.text("Enter your device PIN to continue")),
                 IDLE_TIMEOUT)).isTrue();
     }
 
+    @Test
+    public void testEnrollingWithGkPwHandle() {
+        LockScreenUtil.setLockscreen(LockScreenUtil.LockscreenType.PIN, TEST_PIN, true);
+
+        launchEnrollingWithGkPwHandle();
+
+        // Enrolling screen
+        mDevice.waitForIdle();
+        assertThat(mDevice.wait(Until.hasObject(By.text(mEnrollingTitle)), IDLE_TIMEOUT)).isTrue();
+    }
+
+    @Test
+    public void testEnrollingIconTouchDialog_withSfps() {
+        assumeTrue(mCanAssumeSfps);
+
+        LockScreenUtil.setLockscreen(LockScreenUtil.LockscreenType.PIN, TEST_PIN, true);
+
+        launchEnrollingWithGkPwHandle();
+
+        // Enrolling screen
+        mDevice.waitForIdle();
+        assertThat(mDevice.wait(Until.hasObject(By.text(mEnrollingTitle)), IDLE_TIMEOUT)).isTrue();
+
+        final UiObject2 lottie = mDevice.findObject(By.res(SETTINGS_PACKAGE_NAME,
+                "illustration_lottie"));
+        assertThat(lottie).isNotNull();
+
+        lottie.click();
+        lottie.click();
+        lottie.click();
+
+        // IconTouchDialog
+        mDevice.waitForIdle();
+        assertThat(mDevice.wait(Until.hasObject(By.text("Touch the sensor instead")), IDLE_TIMEOUT))
+                .isTrue();
+        final UiObject2 okButton = mDevice.findObject(By.text("OK"));
+        assertThat(okButton).isNotNull();
+
+        okButton.click();
+
+        // Enrolling screen again
+        mDevice.waitForIdle();
+        assertThat(mDevice.wait(Until.hasObject(By.text(mEnrollingTitle)), IDLE_TIMEOUT)).isTrue();
+    }
+
+    @Test
+    public void testEnrollingIconTouchDialog_withRfps() {
+        assumeFalse(mCanAssumeUdfps || mCanAssumeSfps);
+
+        LockScreenUtil.setLockscreen(LockScreenUtil.LockscreenType.PIN, TEST_PIN, true);
+
+        launchEnrollingWithGkPwHandle();
+
+        // Enrolling screen
+        mDevice.waitForIdle();
+        assertThat(mDevice.wait(Until.hasObject(By.text(mEnrollingTitle)), IDLE_TIMEOUT)).isTrue();
+
+        final UiObject2 lottie = mDevice.findObject(By.res(SETTINGS_PACKAGE_NAME,
+                "fingerprint_progress_bar"));
+        assertThat(lottie).isNotNull();
+
+        lottie.click();
+        lottie.click();
+        lottie.click();
+
+        // IconTouchDialog
+        mDevice.waitForIdle();
+        assertThat(mDevice.wait(Until.hasObject(By.text("Whoops, that\u2019s not the sensor")),
+                IDLE_TIMEOUT)).isTrue();
+        final UiObject2 okButton = mDevice.findObject(By.text("OK"));
+        assertThat(okButton).isNotNull();
+
+        okButton.click();
+
+        // Enrolling screen again
+        mDevice.waitForIdle();
+        assertThat(mDevice.wait(Until.hasObject(By.text(mEnrollingTitle)), IDLE_TIMEOUT)).isTrue();
+    }
+
     @After
     public void tearDown() throws Exception {
         LockScreenUtil.resetLockscreen(TEST_PIN);
         mDevice.pressHome();
     }
 
-    private void launchFingerprintEnrollActivityWithGkPwHandle(boolean isSuw) {
+    private void launchIntroWithGkPwHandle(boolean isSuw) {
         LockPatternUtils lockPatternUtils = new LockPatternUtils(mContext);
         final LockscreenCredential lockscreenCredential = LockscreenCredential.createPin(TEST_PIN);
         final int userId = UserHandle.myUserId();
         final LockPatternChecker.OnVerifyCallback onVerifyCallback = (response, timeoutMs) -> {
-            launchFingerprintEnrollActivity(isSuw, response.getGatekeeperPasswordHandle());
+            final Intent intent = newActivityIntent();
+            if (isSuw) {
+                intent.putExtra(EXTRA_IS_SETUP_FLOW, true);
+            }
+            intent.putExtra(EXTRA_KEY_GK_PW_HANDLE, response.getGatekeeperPasswordHandle());
+            mContext.startActivity(intent);
         };
         LockPatternChecker.verifyCredential(lockPatternUtils, lockscreenCredential,
                 userId, LockPatternUtils.VERIFY_FLAG_REQUEST_GK_PW_HANDLE, onVerifyCallback);
     }
 
-    private void launchFingerprintEnrollActivity(boolean isSuw, Long gkPwHandle) {
+    private void launchEnrollingWithGkPwHandle() {
+        LockPatternUtils lockPatternUtils = new LockPatternUtils(mContext);
+        final LockscreenCredential lockscreenCredential = LockscreenCredential.createPin(TEST_PIN);
+        final int userId = UserHandle.myUserId();
+        final LockPatternChecker.OnVerifyCallback onVerifyCallback = (response, timeoutMs) -> {
+            final Intent intent = newActivityIntent();
+            intent.putExtra(EXTRA_SKIP_FIND_SENSOR, true);
+            intent.putExtra(EXTRA_KEY_GK_PW_HANDLE, response.getGatekeeperPasswordHandle());
+            mContext.startActivity(intent);
+        };
+        LockPatternChecker.verifyCredential(lockPatternUtils, lockscreenCredential,
+                userId, LockPatternUtils.VERIFY_FLAG_REQUEST_GK_PW_HANDLE, onVerifyCallback);
+    }
+
+    @NonNull
+    private Intent newActivityIntent() {
         Intent intent = new Intent();
         intent.setClassName(SETTINGS_PACKAGE_NAME, ACTIVITY_CLASS_NAME);
-        if (isSuw) {
-            intent.putExtra(EXTRA_IS_SETUP_FLOW, true);
-        }
         intent.putExtra(EXTRA_FROM_SETTINGS_SUMMARY, true);
         intent.putExtra(EXTRA_PAGE_TRANSITION_TYPE, 1);
         intent.putExtra(Intent.EXTRA_USER_ID, mContext.getUserId());
-        if (gkPwHandle != null) {
-            intent.putExtra(EXTRA_KEY_GK_PW_HANDLE, gkPwHandle);
-        }
         intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);
-        mContext.startActivity(intent);
+        return intent;
+
     }
 }
diff --git a/tests/unit/src/com/android/settings/biometrics/BiometricNavigationUtilsTest.java b/tests/unit/src/com/android/settings/biometrics/BiometricNavigationUtilsTest.java
index 395f88f..90652f0 100644
--- a/tests/unit/src/com/android/settings/biometrics/BiometricNavigationUtilsTest.java
+++ b/tests/unit/src/com/android/settings/biometrics/BiometricNavigationUtilsTest.java
@@ -20,6 +20,7 @@
 
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
@@ -33,6 +34,7 @@
 import android.os.UserManager;
 import android.provider.Settings;
 
+import androidx.activity.result.ActivityResultLauncher;
 import androidx.test.core.app.ApplicationProvider;
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 
@@ -55,6 +57,8 @@
 
     @Mock
     private UserManager mUserManager;
+    @Mock
+    private ActivityResultLauncher<Intent> mLauncher;
     private Context mContext;
     private BiometricNavigationUtils mBiometricNavigationUtils;
 
@@ -72,7 +76,7 @@
         when(mUserManager.isQuietModeEnabled(any())).thenReturn(true);
 
         mBiometricNavigationUtils.launchBiometricSettings(mContext, SETTINGS_CLASS_NAME,
-                Bundle.EMPTY);
+                Bundle.EMPTY, null);
 
         assertQuietModeDialogLaunchRequested();
     }
@@ -82,7 +86,17 @@
         when(mUserManager.isQuietModeEnabled(any())).thenReturn(true);
 
         assertThat(mBiometricNavigationUtils.launchBiometricSettings(
-                mContext, SETTINGS_CLASS_NAME, Bundle.EMPTY)).isFalse();
+                mContext, SETTINGS_CLASS_NAME, Bundle.EMPTY, null)).isFalse();
+    }
+
+    @Test
+    public void launchBiometricSettings_quietMode_withLauncher_notThroughLauncher() {
+        when(mUserManager.isQuietModeEnabled(any())).thenReturn(true);
+
+        mBiometricNavigationUtils.launchBiometricSettings(mContext, SETTINGS_CLASS_NAME,
+                Bundle.EMPTY, mLauncher);
+
+        verify(mLauncher, never()).launch(any(Intent.class));
     }
 
     @Test
@@ -90,7 +104,7 @@
         when(mUserManager.isQuietModeEnabled(any())).thenReturn(false);
 
         mBiometricNavigationUtils.launchBiometricSettings(
-                mContext, SETTINGS_CLASS_NAME, Bundle.EMPTY);
+                mContext, SETTINGS_CLASS_NAME, Bundle.EMPTY, null);
 
         assertSettingsPageLaunchRequested(false /* shouldContainExtras */);
     }
@@ -100,7 +114,7 @@
         when(mUserManager.isQuietModeEnabled(any())).thenReturn(false);
 
         assertThat(mBiometricNavigationUtils.launchBiometricSettings(
-                mContext, SETTINGS_CLASS_NAME, Bundle.EMPTY)).isTrue();
+                mContext, SETTINGS_CLASS_NAME, Bundle.EMPTY, null)).isTrue();
     }
 
     @Test
@@ -108,17 +122,29 @@
         when(mUserManager.isQuietModeEnabled(any())).thenReturn(false);
 
         final Bundle extras = createNotEmptyExtras();
-        mBiometricNavigationUtils.launchBiometricSettings(mContext, SETTINGS_CLASS_NAME, extras);
+        mBiometricNavigationUtils.launchBiometricSettings(
+                mContext, SETTINGS_CLASS_NAME, extras, null);
 
         assertSettingsPageLaunchRequested(true /* shouldContainExtras */);
     }
 
     @Test
+    public void launchBiometricSettings_noQuietMode_withLauncher_launchesThroughLauncher() {
+        when(mUserManager.isQuietModeEnabled(any())).thenReturn(false);
+
+        final Bundle extras = createNotEmptyExtras();
+        mBiometricNavigationUtils.launchBiometricSettings(
+                mContext, SETTINGS_CLASS_NAME, extras, mLauncher);
+
+        verify(mLauncher).launch(any(Intent.class));
+    }
+
+    @Test
     public void launchBiometricSettings_noQuietMode_withExtras_returnsTrue() {
         when(mUserManager.isQuietModeEnabled(any())).thenReturn(false);
 
         assertThat(mBiometricNavigationUtils.launchBiometricSettings(
-                mContext, SETTINGS_CLASS_NAME, createNotEmptyExtras())).isTrue();
+                mContext, SETTINGS_CLASS_NAME, createNotEmptyExtras(), null)).isTrue();
     }
 
     @Test
diff --git a/tests/unit/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollEnrollingViewModelTest.java b/tests/unit/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollEnrollingViewModelTest.java
index 4de1057..fb0937e 100644
--- a/tests/unit/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollEnrollingViewModelTest.java
+++ b/tests/unit/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollEnrollingViewModelTest.java
@@ -21,7 +21,6 @@
 import static android.hardware.fingerprint.FingerprintSensorProperties.TYPE_UDFPS_ULTRASONIC;
 
 import static com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollEnrollingViewModel.ErrorDialogData;
-import static com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollEnrollingViewModel.FINGERPRINT_ENROLL_ENROLLING_ACTION_DISMISS_ICON_TOUCH_DIALOG;
 import static com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollEnrollingViewModel.FINGERPRINT_ENROLL_ENROLLING_ACTION_SHOW_ICON_TOUCH_DIALOG;
 import static com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollEnrollingViewModel.FINGERPRINT_ENROLL_ENROLLING_CANCELED_BECAUSE_BACK_PRESSED;
 import static com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollEnrollingViewModel.FINGERPRINT_ENROLL_ENROLLING_CANCELED_BECAUSE_USER_SKIP;
@@ -103,10 +102,6 @@
         mViewModel.showIconTouchDialog();
         assertThat(actionLiveData.getValue()).isEqualTo(
                 FINGERPRINT_ENROLL_ENROLLING_ACTION_SHOW_ICON_TOUCH_DIALOG);
-
-        mViewModel.onIconTouchDialogDismiss();
-        assertThat(actionLiveData.getValue()).isEqualTo(
-                FINGERPRINT_ENROLL_ENROLLING_ACTION_DISMISS_ICON_TOUCH_DIALOG);
     }
 
     @Test
diff --git a/tests/unit/src/com/android/settings/regionalpreferences/RegionalFooterPreferenceControllerTest.java b/tests/unit/src/com/android/settings/regionalpreferences/RegionalFooterPreferenceControllerTest.java
new file mode 100644
index 0000000..f019793
--- /dev/null
+++ b/tests/unit/src/com/android/settings/regionalpreferences/RegionalFooterPreferenceControllerTest.java
@@ -0,0 +1,62 @@
+/**
+ * Copyright (C) 2023 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.regionalpreferences;
+
+import static org.mockito.Mockito.anyString;
+import static org.mockito.Mockito.verify;
+
+import android.content.Context;
+import android.os.Looper;
+
+import androidx.test.core.app.ApplicationProvider;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import com.android.settingslib.widget.FooterPreference;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@RunWith(AndroidJUnit4.class)
+public class RegionalFooterPreferenceControllerTest {
+
+    private static String KEY_FOOTER_PREFERENCE = "regional_pref_footer";
+    private Context mContext;
+    private RegionalFooterPreferenceController mRegionalFooterPreferenceController;
+
+    @Mock
+    private FooterPreference mMockFooterPreference;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        if (Looper.myLooper() == null) {
+            Looper.prepare();
+        }
+        mContext = ApplicationProvider.getApplicationContext();
+        mRegionalFooterPreferenceController = new RegionalFooterPreferenceController(mContext,
+                KEY_FOOTER_PREFERENCE);
+    }
+
+    @Test
+    public void setupFooterPreference_shouldSetAsTextInLearnMore() {
+        mRegionalFooterPreferenceController.setupFooterPreference(mMockFooterPreference);
+        verify(mMockFooterPreference).setLearnMoreText(anyString());
+    }
+}
diff --git a/tests/unit/src/com/android/settings/wifi/repository/WifiHotspotRepositoryTest.java b/tests/unit/src/com/android/settings/wifi/repository/WifiHotspotRepositoryTest.java
index b75f9fc..dbbdfec 100644
--- a/tests/unit/src/com/android/settings/wifi/repository/WifiHotspotRepositoryTest.java
+++ b/tests/unit/src/com/android/settings/wifi/repository/WifiHotspotRepositoryTest.java
@@ -18,7 +18,9 @@
 
 import static android.net.wifi.SoftApConfiguration.BAND_2GHZ;
 import static android.net.wifi.SoftApConfiguration.SECURITY_TYPE_OPEN;
+import static android.net.wifi.SoftApConfiguration.SECURITY_TYPE_WPA2_PSK;
 import static android.net.wifi.SoftApConfiguration.SECURITY_TYPE_WPA3_SAE;
+import static android.net.wifi.SoftApConfiguration.SECURITY_TYPE_WPA3_SAE_TRANSITION;
 import static android.net.wifi.WifiAvailableChannel.OP_MODE_SAP;
 
 import static com.android.settings.wifi.repository.WifiHotspotRepository.BAND_2GHZ_5GHZ;
@@ -32,6 +34,7 @@
 
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.atLeast;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.verify;
@@ -81,6 +84,8 @@
     @Mock
     WifiManager mWifiManager;
     @Mock
+    MutableLiveData<Integer> mSecurityType;
+    @Mock
     MutableLiveData<Integer> mSpeedType;
 
     WifiHotspotRepository mWifiHotspotRepository;
@@ -93,6 +98,7 @@
         doReturn(SPEED_6GHZ).when(mSpeedType).getValue();
 
         mWifiHotspotRepository = new WifiHotspotRepository(mContext, mWifiManager);
+        mWifiHotspotRepository.mSecurityType = mSecurityType;
         mWifiHotspotRepository.mSpeedType = mSpeedType;
         mWifiHotspotRepository.mCurrentCountryCode = WIFI_CURRENT_COUNTRY_CODE;
         mWifiHotspotRepository.mIsDualBand = true;
@@ -156,6 +162,7 @@
     @Test
     public void refresh_liveDataNotUsed_doNothing() {
         // If LiveData is not used then it's null.
+        mWifiHotspotRepository.mSecurityType = null;
         mWifiHotspotRepository.mSpeedType = null;
 
         mWifiHotspotRepository.refresh();
@@ -169,7 +176,7 @@
 
         mWifiHotspotRepository.refresh();
 
-        verify(mWifiManager).getSoftApConfiguration();
+        verify(mWifiManager, atLeast(1)).getSoftApConfiguration();
         verify(mSpeedType).setValue(anyInt());
     }
 
@@ -193,6 +200,105 @@
 
     @Test
     @UiThreadTest
+    public void getSecurityType_shouldNotReturnNull() {
+        // If LiveData is not used then it's null.
+        mWifiHotspotRepository.mSecurityType = null;
+        mockConfigSecurityType(SECURITY_TYPE_OPEN);
+
+        assertThat(mWifiHotspotRepository.getSecurityType()).isNotNull();
+    }
+
+    @Test
+    public void updateSecurityType_securityTypeOpen_setValueCorrectly() {
+        mockConfigSecurityType(SECURITY_TYPE_OPEN);
+
+        mWifiHotspotRepository.updateSecurityType();
+
+        verify(mSecurityType).setValue(SECURITY_TYPE_OPEN);
+    }
+
+    @Test
+    public void updateSecurityType_securityTypeWpa2_setValueCorrectly() {
+        mockConfigSecurityType(SECURITY_TYPE_WPA2_PSK);
+
+        mWifiHotspotRepository.updateSecurityType();
+
+        verify(mSecurityType).setValue(SECURITY_TYPE_WPA2_PSK);
+    }
+
+    @Test
+    public void updateSecurityType_securityTypeWpa2Wpa3_setValueCorrectly() {
+        mockConfigSecurityType(SECURITY_TYPE_WPA3_SAE_TRANSITION);
+
+        mWifiHotspotRepository.updateSecurityType();
+
+        verify(mSecurityType).setValue(SECURITY_TYPE_WPA3_SAE_TRANSITION);
+    }
+
+    @Test
+    public void updateSecurityType_securityTypeWpa3_setValueCorrectly() {
+        mockConfigSecurityType(SECURITY_TYPE_WPA3_SAE);
+
+        mWifiHotspotRepository.updateSecurityType();
+
+        verify(mSecurityType).setValue(SECURITY_TYPE_WPA3_SAE);
+    }
+
+    @Test
+    public void setSecurityType_sameValue_doNotSetConfig() {
+        mockConfigSecurityType(SECURITY_TYPE_WPA3_SAE);
+
+        mWifiHotspotRepository.setSecurityType(SECURITY_TYPE_WPA3_SAE);
+
+        verify(mWifiManager, never()).setSoftApConfiguration(any());
+    }
+
+    @Test
+    public void setSecurityType_wpa3ToWpa2Wpa3_setConfigCorrectly() {
+        mockConfigSecurityType(SECURITY_TYPE_WPA3_SAE);
+
+        mWifiHotspotRepository.setSecurityType(SECURITY_TYPE_WPA3_SAE_TRANSITION);
+
+        verify(mWifiManager).setSoftApConfiguration(mSoftApConfigCaptor.capture());
+        assertThat(mSoftApConfigCaptor.getValue().getSecurityType())
+                .isEqualTo(SECURITY_TYPE_WPA3_SAE_TRANSITION);
+    }
+
+    @Test
+    public void setSecurityType_Wpa2Wpa3ToWpa2_setConfigCorrectly() {
+        mockConfigSecurityType(SECURITY_TYPE_WPA3_SAE_TRANSITION);
+
+        mWifiHotspotRepository.setSecurityType(SECURITY_TYPE_WPA2_PSK);
+
+        verify(mWifiManager).setSoftApConfiguration(mSoftApConfigCaptor.capture());
+        assertThat(mSoftApConfigCaptor.getValue().getSecurityType())
+                .isEqualTo(SECURITY_TYPE_WPA2_PSK);
+    }
+
+    @Test
+    public void setSecurityType_Wpa2ToOpen_setConfigCorrectly() {
+        mockConfigSecurityType(SECURITY_TYPE_WPA2_PSK);
+
+        mWifiHotspotRepository.setSecurityType(SECURITY_TYPE_OPEN);
+
+        verify(mWifiManager).setSoftApConfiguration(mSoftApConfigCaptor.capture());
+        assertThat(mSoftApConfigCaptor.getValue().getSecurityType())
+                .isEqualTo(SECURITY_TYPE_OPEN);
+    }
+
+    @Test
+    public void setSecurityType_OpenToWpa3_setConfigCorrectly() {
+        mockConfigSecurityType(SECURITY_TYPE_OPEN);
+
+        mWifiHotspotRepository.setSecurityType(SECURITY_TYPE_WPA3_SAE);
+
+        verify(mWifiManager).setSoftApConfiguration(mSoftApConfigCaptor.capture());
+        assertThat(mSoftApConfigCaptor.getValue().getSecurityType())
+                .isEqualTo(SECURITY_TYPE_WPA3_SAE);
+    }
+
+    @Test
+    @UiThreadTest
     public void getSpeedType_shouldNotReturnNull() {
         // If LiveData is not used then it's null.
         mWifiHotspotRepository.mSpeedType = null;
@@ -312,8 +418,8 @@
     }
 
     @Test
-    public void setSpeedType_from2g5ghz_setConfigBandTo6ghzPreferred() {
-        mockGetSoftApConfiguration(SPEED_2GHZ_5GHZ);
+    public void setSpeedType_2g5ghzTo6ghz_setConfigBandTo6ghzPreferred() {
+        mockConfigSpeedType(SPEED_2GHZ_5GHZ);
 
         mWifiHotspotRepository.setSpeedType(SPEED_6GHZ);
 
@@ -322,8 +428,19 @@
     }
 
     @Test
-    public void setSpeedType_from6ghz_setConfigBandsTo2g5ghz() {
-        mockGetSoftApConfiguration(SPEED_6GHZ);
+    public void setSpeedType_2g5ghzTo6ghz_setConfigSecurityToWpa3() {
+        mockConfig(SPEED_2GHZ_5GHZ, SECURITY_TYPE_WPA3_SAE_TRANSITION);
+
+        mWifiHotspotRepository.setSpeedType(SPEED_6GHZ);
+
+        verify(mWifiManager).setSoftApConfiguration(mSoftApConfigCaptor.capture());
+        assertThat(mSoftApConfigCaptor.getValue().getSecurityType())
+                .isEqualTo(SECURITY_TYPE_WPA3_SAE);
+    }
+
+    @Test
+    public void setSpeedType_6ghzTo2g5ghz_setConfigBandsTo2g5ghz() {
+        mockConfigSpeedType(SPEED_6GHZ);
         mWifiHotspotRepository.mIsDualBand = true;
 
         mWifiHotspotRepository.setSpeedType(SPEED_2GHZ_5GHZ);
@@ -335,8 +452,8 @@
     }
 
     @Test
-    public void setSpeedType_from2ghz_setConfigBandTo5ghzPreferred() {
-        mockGetSoftApConfiguration(SPEED_2GHZ);
+    public void setSpeedType_2ghzTo5ghz_setConfigBandTo5ghzPreferred() {
+        mockConfigSpeedType(SPEED_2GHZ);
 
         mWifiHotspotRepository.setSpeedType(SPEED_5GHZ);
 
@@ -345,8 +462,8 @@
     }
 
     @Test
-    public void setSpeedType_from5ghz_setConfigBandTo6ghzPreferred() {
-        mockGetSoftApConfiguration(SPEED_5GHZ);
+    public void setSpeedType_5ghzTo6ghz_setConfigBandTo6ghzPreferred() {
+        mockConfigSpeedType(SPEED_5GHZ);
 
         mWifiHotspotRepository.setSpeedType(SPEED_6GHZ);
 
@@ -355,8 +472,8 @@
     }
 
     @Test
-    public void setSpeedType_from5gTo6ghz_setConfigBandTo2ghz() {
-        mockGetSoftApConfiguration(SPEED_6GHZ);
+    public void setSpeedType_6ghzTo2ghz_setConfigBandTo2ghz() {
+        mockConfigSpeedType(SPEED_6GHZ);
 
         mWifiHotspotRepository.setSpeedType(SPEED_2GHZ);
 
@@ -475,10 +592,24 @@
         assertThat(mWifiHotspotRepository.get6gAvailable()).isNotNull();
     }
 
-    private void mockGetSoftApConfiguration(int speedType) {
+    private void mockConfigSecurityType(int securityType) {
+        mockConfig(securityType, SPEED_2GHZ);
+    }
+
+    private void mockConfigSpeedType(int speedType) {
+        mockConfig(SECURITY_TYPE_WPA3_SAE, speedType);
+    }
+
+    private void mockConfig(int securityType, int speedType) {
+        SoftApConfiguration.Builder configBuilder = new SoftApConfiguration.Builder();
+        // Security Type
+        doReturn(securityType).when(mSecurityType).getValue();
+        String passphrase = (securityType == SECURITY_TYPE_OPEN) ? null : WIFI_PASSWORD;
+        configBuilder.setPassphrase(passphrase, securityType).build();
+
+        // Speed Type
         doReturn(speedType).when(mSpeedType).getValue();
         mWifiHotspotRepository.mIsDualBand = true;
-        SoftApConfiguration.Builder configBuilder = new SoftApConfiguration.Builder();
         if (speedType == SPEED_2GHZ) {
             mWifiHotspotRepository.mIsDualBand = false;
             configBuilder.setBand(BAND_2GHZ);
diff --git a/tests/unit/src/com/android/settings/wifi/tether/WifiHotspotSecuritySettingsTest.java b/tests/unit/src/com/android/settings/wifi/tether/WifiHotspotSecuritySettingsTest.java
new file mode 100644
index 0000000..511240e
--- /dev/null
+++ b/tests/unit/src/com/android/settings/wifi/tether/WifiHotspotSecuritySettingsTest.java
@@ -0,0 +1,173 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.wifi.tether;
+
+import static android.net.wifi.SoftApConfiguration.SECURITY_TYPE_OPEN;
+import static android.net.wifi.SoftApConfiguration.SECURITY_TYPE_WPA2_PSK;
+import static android.net.wifi.SoftApConfiguration.SECURITY_TYPE_WPA3_SAE;
+import static android.net.wifi.SoftApConfiguration.SECURITY_TYPE_WPA3_SAE_TRANSITION;
+
+import static com.android.settings.wifi.tether.WifiHotspotSecurityViewModel.KEY_SECURITY_NONE;
+import static com.android.settings.wifi.tether.WifiHotspotSecurityViewModel.KEY_SECURITY_WPA2;
+import static com.android.settings.wifi.tether.WifiHotspotSecurityViewModel.KEY_SECURITY_WPA2_WPA3;
+import static com.android.settings.wifi.tether.WifiHotspotSecurityViewModel.KEY_SECURITY_WPA3;
+
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import com.android.settingslib.widget.SelectorWithWidgetPreference;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class WifiHotspotSecuritySettingsTest {
+    @Rule
+    public final MockitoRule mMockitoRule = MockitoJUnit.rule();
+    @Mock
+    WifiHotspotSecurityViewModel mViewModel;
+    @Mock
+    SelectorWithWidgetPreference mRadioButtonWpa3;
+    @Mock
+    SelectorWithWidgetPreference mRadioButtonWpa2Wpa3;
+    @Mock
+    SelectorWithWidgetPreference mRadioButtonWpa2;
+    @Mock
+    SelectorWithWidgetPreference mRadioButtonNone;
+
+    Map<Integer, WifiHotspotSecurityViewModel.ViewItem> mViewItemMap = new HashMap<>();
+    WifiHotspotSecurityViewModel.ViewItem mViewItemWpa3 =
+            new WifiHotspotSecurityViewModel.ViewItem(KEY_SECURITY_WPA3);
+    WifiHotspotSecurityViewModel.ViewItem mViewItemWpa2Wpa3 =
+            new WifiHotspotSecurityViewModel.ViewItem(KEY_SECURITY_WPA2_WPA3);
+    WifiHotspotSecurityViewModel.ViewItem mViewItemWpa2 =
+            new WifiHotspotSecurityViewModel.ViewItem(KEY_SECURITY_WPA2);
+    WifiHotspotSecurityViewModel.ViewItem mViewItemNone =
+            new WifiHotspotSecurityViewModel.ViewItem(KEY_SECURITY_NONE);
+
+    WifiHotspotSecuritySettings mSettings;
+
+    @Before
+    public void setUp() {
+        mViewItemMap.put(SECURITY_TYPE_WPA3_SAE, mViewItemWpa3);
+        mViewItemMap.put(SECURITY_TYPE_WPA3_SAE_TRANSITION, mViewItemWpa2Wpa3);
+        mViewItemMap.put(SECURITY_TYPE_WPA2_PSK, mViewItemWpa2);
+        mViewItemMap.put(SECURITY_TYPE_OPEN, mViewItemNone);
+
+        when(mRadioButtonWpa3.getKey()).thenReturn(KEY_SECURITY_WPA3);
+        when(mRadioButtonWpa2Wpa3.getKey()).thenReturn(KEY_SECURITY_WPA2_WPA3);
+        when(mRadioButtonWpa2.getKey()).thenReturn(KEY_SECURITY_WPA2);
+        when(mRadioButtonNone.getKey()).thenReturn(KEY_SECURITY_NONE);
+
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(
+                () -> mSettings = spy(new WifiHotspotSecuritySettings()));
+        mSettings.mWifiHotspotSecurityViewModel = mViewModel;
+        when(mSettings.findPreference(KEY_SECURITY_WPA3)).thenReturn(mRadioButtonWpa3);
+        when(mSettings.findPreference(KEY_SECURITY_WPA2_WPA3)).thenReturn(mRadioButtonWpa2Wpa3);
+        when(mSettings.findPreference(KEY_SECURITY_WPA2)).thenReturn(mRadioButtonWpa2);
+        when(mSettings.findPreference(KEY_SECURITY_NONE)).thenReturn(mRadioButtonNone);
+    }
+
+    @Test
+    public void onViewItemListDataChanged_checkedWpa3_setViewItemCorrectly() {
+        mViewItemWpa3.mIsChecked = true;
+
+        mSettings.onViewItemListDataChanged(mViewItemMap.values().stream().toList());
+
+        verify(mRadioButtonWpa3).setChecked(true);
+    }
+
+    @Test
+    public void onViewItemListDataChanged_checkedWpa2Wpa3_setViewItemCorrectly() {
+        mViewItemWpa2Wpa3.mIsChecked = true;
+
+        mSettings.onViewItemListDataChanged(mViewItemMap.values().stream().toList());
+
+        verify(mRadioButtonWpa2Wpa3).setChecked(true);
+    }
+
+    @Test
+    public void onViewItemListDataChanged_checkedWpa2_setViewItemCorrectly() {
+        mViewItemWpa2.mIsChecked = true;
+
+        mSettings.onViewItemListDataChanged(mViewItemMap.values().stream().toList());
+
+        verify(mRadioButtonWpa2).setChecked(true);
+    }
+
+    @Test
+    public void onViewItemListDataChanged_checkedNone_setViewItemCorrectly() {
+        mViewItemNone.mIsChecked = true;
+
+        mSettings.onViewItemListDataChanged(mViewItemMap.values().stream().toList());
+
+        verify(mRadioButtonNone).setChecked(true);
+    }
+
+    @Test
+    public void onViewItemListDataChanged_enabledWpa3Only_setViewItemCorrectly() {
+        when(mRadioButtonWpa2Wpa3.isEnabled()).thenReturn(true);
+        when(mRadioButtonWpa2.isEnabled()).thenReturn(true);
+        when(mRadioButtonNone.isEnabled()).thenReturn(true);
+        mViewItemWpa2Wpa3.mIsEnabled = false;
+        mViewItemWpa2.mIsEnabled = false;
+        mViewItemNone.mIsEnabled = false;
+
+        mSettings.onViewItemListDataChanged(mViewItemMap.values().stream().toList());
+
+        verify(mRadioButtonWpa2Wpa3).setEnabled(false);
+        verify(mRadioButtonWpa2).setEnabled(false);
+        verify(mRadioButtonNone).setEnabled(false);
+    }
+
+    @Test
+    public void onRadioButtonClicked_clickedWpa3_setSecurityTypeCorrectly() {
+        mSettings.onRadioButtonClicked(mRadioButtonWpa3);
+
+        verify(mViewModel).handleRadioButtonClicked(KEY_SECURITY_WPA3);
+    }
+
+    @Test
+    public void onRadioButtonClicked_clickedWpa2Wpa3_setSecurityTypeCorrectly() {
+        mSettings.onRadioButtonClicked(mRadioButtonWpa2Wpa3);
+
+        verify(mViewModel).handleRadioButtonClicked(KEY_SECURITY_WPA2_WPA3);
+    }
+
+    @Test
+    public void onRadioButtonClicked_clickedWpa2_setSecurityTypeCorrectly() {
+        mSettings.onRadioButtonClicked(mRadioButtonWpa2);
+
+        verify(mViewModel).handleRadioButtonClicked(KEY_SECURITY_WPA2);
+    }
+
+    @Test
+    public void onRadioButtonClicked_clickedNone_setSecurityTypeCorrectly() {
+        mSettings.onRadioButtonClicked(mRadioButtonNone);
+
+        verify(mViewModel).handleRadioButtonClicked(KEY_SECURITY_NONE);
+    }
+}
diff --git a/tests/unit/src/com/android/settings/wifi/tether/WifiHotspotSecurityViewModelTest.java b/tests/unit/src/com/android/settings/wifi/tether/WifiHotspotSecurityViewModelTest.java
new file mode 100644
index 0000000..db768c7
--- /dev/null
+++ b/tests/unit/src/com/android/settings/wifi/tether/WifiHotspotSecurityViewModelTest.java
@@ -0,0 +1,211 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.wifi.tether;
+
+import static android.net.wifi.SoftApConfiguration.SECURITY_TYPE_OPEN;
+import static android.net.wifi.SoftApConfiguration.SECURITY_TYPE_WPA2_PSK;
+import static android.net.wifi.SoftApConfiguration.SECURITY_TYPE_WPA3_SAE;
+import static android.net.wifi.SoftApConfiguration.SECURITY_TYPE_WPA3_SAE_TRANSITION;
+
+import static com.android.settings.wifi.repository.WifiHotspotRepository.SPEED_2GHZ;
+import static com.android.settings.wifi.repository.WifiHotspotRepository.SPEED_2GHZ_5GHZ;
+import static com.android.settings.wifi.repository.WifiHotspotRepository.SPEED_5GHZ;
+import static com.android.settings.wifi.repository.WifiHotspotRepository.SPEED_6GHZ;
+import static com.android.settings.wifi.tether.WifiHotspotSecurityViewModel.KEY_SECURITY_NONE;
+import static com.android.settings.wifi.tether.WifiHotspotSecurityViewModel.KEY_SECURITY_WPA2;
+import static com.android.settings.wifi.tether.WifiHotspotSecurityViewModel.KEY_SECURITY_WPA2_WPA3;
+import static com.android.settings.wifi.tether.WifiHotspotSecurityViewModel.KEY_SECURITY_WPA3;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.app.Application;
+import android.content.Context;
+
+import androidx.lifecycle.MutableLiveData;
+import androidx.test.annotation.UiThreadTest;
+import androidx.test.core.app.ApplicationProvider;
+
+import com.android.settings.testutils.FakeFeatureFactory;
+import com.android.settings.wifi.repository.WifiHotspotRepository;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.Spy;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+
+@UiThreadTest
+public class WifiHotspotSecurityViewModelTest {
+    @Rule
+    public final MockitoRule mMockitoRule = MockitoJUnit.rule();
+    @Spy
+    Context mContext = ApplicationProvider.getApplicationContext();
+    @Mock
+    WifiHotspotRepository mWifiHotspotRepository;
+    @Mock
+    MutableLiveData<Integer> mSecurityType;
+    @Mock
+    MutableLiveData<Integer> mSpeedType;
+
+    WifiHotspotSecurityViewModel mViewModel;
+
+    @Before
+    public void setUp() {
+        FakeFeatureFactory featureFactory = FakeFeatureFactory.setupForTest();
+        when(featureFactory.getWifiFeatureProvider().getWifiHotspotRepository())
+                .thenReturn(mWifiHotspotRepository);
+        when(mWifiHotspotRepository.getSecurityType()).thenReturn(mSecurityType);
+        when(mWifiHotspotRepository.getSpeedType()).thenReturn(mSpeedType);
+
+        mViewModel = new WifiHotspotSecurityViewModel((Application) mContext);
+    }
+
+    @Test
+    public void constructor_observeDataAndSetAutoRefresh() {
+        verify(mSecurityType).observeForever(mViewModel.mSecurityTypeObserver);
+        verify(mSpeedType).observeForever(mViewModel.mSpeedTypeObserver);
+    }
+
+    @Test
+    public void onCleared_removeObserverData() {
+        mViewModel.onCleared();
+
+        verify(mSecurityType).removeObserver(mViewModel.mSecurityTypeObserver);
+        verify(mSpeedType).removeObserver(mViewModel.mSpeedTypeObserver);
+    }
+
+    @Test
+    public void onSecurityTypeChanged_securityTypeWpa3_setCheckedCorrectly() {
+        mViewModel.onSecurityTypeChanged(SECURITY_TYPE_WPA3_SAE);
+
+        assertItemChecked(true, false, false, false);
+    }
+
+    @Test
+    public void onSecurityTypeChanged_securityTypeWpa2Wpa3_setCheckedCorrectly() {
+        mViewModel.onSecurityTypeChanged(SECURITY_TYPE_WPA3_SAE_TRANSITION);
+
+        assertItemChecked(false, true, false, false);
+    }
+
+    @Test
+    public void onSecurityTypeChanged_securityTypeWpa2_setCheckedCorrectly() {
+        mViewModel.onSecurityTypeChanged(SECURITY_TYPE_WPA2_PSK);
+
+        assertItemChecked(false, false, true, false);
+    }
+
+    @Test
+    public void onSecurityTypeChanged_securityTypeNone_setCheckedCorrectly() {
+        mViewModel.onSecurityTypeChanged(SECURITY_TYPE_OPEN);
+
+        assertItemChecked(false, false, false, true);
+    }
+
+    @Test
+    public void onSpeedTypeChanged_speed6g_setEnabledCorrectly() {
+        mViewModel.onSpeedTypeChanged(SPEED_6GHZ);
+
+        assertItemEnabled(true, false, false, false);
+    }
+
+    @Test
+    public void onSpeedTypeChanged_speed2g5g_setEnabledCorrectly() {
+        mViewModel.onSpeedTypeChanged(SPEED_2GHZ_5GHZ);
+
+        assertItemEnabled(true, true, true, true);
+    }
+
+    @Test
+    public void onSpeedTypeChanged_speed5g_setEnabledCorrectly() {
+        mViewModel.onSpeedTypeChanged(SPEED_5GHZ);
+
+        assertItemEnabled(true, true, true, true);
+    }
+
+    @Test
+    public void onSpeedTypeChanged_speed2g_setEnabledCorrectly() {
+        mViewModel.onSpeedTypeChanged(SPEED_2GHZ);
+
+        assertItemEnabled(true, true, true, true);
+    }
+
+    @Test
+    public void handleRadioButtonClicked_keyWpa3_setSecurityTypeCorrectly() {
+        mViewModel.handleRadioButtonClicked(KEY_SECURITY_WPA3);
+
+        verify(mWifiHotspotRepository).setSecurityType(SECURITY_TYPE_WPA3_SAE);
+    }
+
+    @Test
+    public void handleRadioButtonClicked_keyWpa2Wpa3_setSecurityTypeCorrectly() {
+        mViewModel.handleRadioButtonClicked(KEY_SECURITY_WPA2_WPA3);
+
+        verify(mWifiHotspotRepository).setSecurityType(SECURITY_TYPE_WPA3_SAE_TRANSITION);
+    }
+
+    @Test
+    public void handleRadioButtonClicked_keyWpa2_setSecurityTypeCorrectly() {
+        mViewModel.handleRadioButtonClicked(KEY_SECURITY_WPA2);
+
+        verify(mWifiHotspotRepository).setSecurityType(SECURITY_TYPE_WPA2_PSK);
+    }
+
+    @Test
+    public void handleRadioButtonClicked_keyNone_setSecurityTypeCorrectly() {
+        mViewModel.handleRadioButtonClicked(KEY_SECURITY_NONE);
+
+        verify(mWifiHotspotRepository).setSecurityType(SECURITY_TYPE_OPEN);
+    }
+
+    @Test
+    public void getViewItemListData_shouldNotReturnNull() {
+        // Reset mViewInfoListData to trigger an update
+        mViewModel.mViewInfoListData = null;
+
+        assertThat(mViewModel.getViewItemListData()).isNotNull();
+    }
+
+    private void assertItemChecked(boolean checkedWpa3, boolean checkedWpa2Wpa3,
+            boolean checkedWpa2, boolean checkedNone) {
+        assertThat(mViewModel.mViewItemMap.get(SECURITY_TYPE_WPA3_SAE).mIsChecked)
+                .isEqualTo(checkedWpa3);
+        assertThat(mViewModel.mViewItemMap.get(SECURITY_TYPE_WPA3_SAE_TRANSITION).mIsChecked)
+                .isEqualTo(checkedWpa2Wpa3);
+        assertThat(mViewModel.mViewItemMap.get(SECURITY_TYPE_WPA2_PSK).mIsChecked)
+                .isEqualTo(checkedWpa2);
+        assertThat(mViewModel.mViewItemMap.get(SECURITY_TYPE_OPEN).mIsChecked)
+                .isEqualTo(checkedNone);
+    }
+
+    private void assertItemEnabled(boolean enabledWpa3, boolean enabledWpa2Wpa3,
+            boolean enabledWpa2, boolean enabledNone) {
+        assertThat(mViewModel.mViewItemMap.get(SECURITY_TYPE_WPA3_SAE).mIsEnabled)
+                .isEqualTo(enabledWpa3);
+        assertThat(mViewModel.mViewItemMap.get(SECURITY_TYPE_WPA3_SAE_TRANSITION).mIsEnabled)
+                .isEqualTo(enabledWpa2Wpa3);
+        assertThat(mViewModel.mViewItemMap.get(SECURITY_TYPE_WPA2_PSK).mIsEnabled)
+                .isEqualTo(enabledWpa2);
+        assertThat(mViewModel.mViewItemMap.get(SECURITY_TYPE_OPEN).mIsEnabled)
+                .isEqualTo(enabledNone);
+    }
+}
diff --git a/tests/unit/src/com/android/settings/wifi/tether/WifiTetherViewModelTest.java b/tests/unit/src/com/android/settings/wifi/tether/WifiTetherViewModelTest.java
index 6724dd5..4c8ce5b 100644
--- a/tests/unit/src/com/android/settings/wifi/tether/WifiTetherViewModelTest.java
+++ b/tests/unit/src/com/android/settings/wifi/tether/WifiTetherViewModelTest.java
@@ -52,6 +52,8 @@
     @Mock
     WifiHotspotRepository mWifiHotspotRepository;
     @Mock
+    MutableLiveData<Integer> mSecurityType;
+    @Mock
     MutableLiveData<Integer> mSpeedType;
 
     WifiTetherViewModel mViewModel;
@@ -63,21 +65,18 @@
         FakeFeatureFactory featureFactory = FakeFeatureFactory.setupForTest();
         when(featureFactory.getWifiFeatureProvider().getWifiHotspotRepository())
                 .thenReturn(mWifiHotspotRepository);
+        when(mWifiHotspotRepository.getSecurityType()).thenReturn(mSecurityType);
         when(mWifiHotspotRepository.getSpeedType()).thenReturn(mSpeedType);
 
         mViewModel = new WifiTetherViewModel(mApplication);
     }
 
     @Test
-    public void constructor_setAutoRefreshTrue() {
-        verify(mWifiHotspotRepository).setAutoRefresh(true);
-    }
-
-    @Test
     public void onCleared_setAutoRefreshFalse() {
         mViewModel.onCleared();
 
-        verify(mWifiHotspotRepository).setAutoRefresh(false);
+        verify(mSecurityType).removeObserver(mViewModel.mSecurityTypeObserver);
+        verify(mSpeedType).removeObserver(mViewModel.mSpeedTypeObserver);
     }
 
     @Test
@@ -98,11 +97,23 @@
 
     @Test
     @UiThreadTest
+    public void getSecuritySummary_returnNotNull() {
+        mViewModel.mSecuritySummary = null;
+
+        mViewModel.getSecuritySummary();
+
+        assertThat(mViewModel.mSecuritySummary).isNotNull();
+        verify(mSecurityType).observeForever(mViewModel.mSecurityTypeObserver);
+    }
+
+    @Test
+    @UiThreadTest
     public void getSpeedSummary_returnNotNull() {
         mViewModel.mSpeedSummary = null;
 
         mViewModel.getSpeedSummary();
 
         assertThat(mViewModel.mSpeedSummary).isNotNull();
+        verify(mSpeedType).observeForever(mViewModel.mSpeedTypeObserver);
     }
 }