Merge "Fix the preview couldn't be scrolled up and down when showing the scroll bar."
diff --git a/res/drawable/ic_check_24dp.xml b/res/drawable/ic_check_24dp.xml
new file mode 100644
index 0000000..5801e70
--- /dev/null
+++ b/res/drawable/ic_check_24dp.xml
@@ -0,0 +1,25 @@
+<!-- Copyright (C) 2022 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+        android:width="24dp"
+        android:height="24dp"
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0"
+        android:tint="?androidprv:attr/colorAccentPrimaryVariant">
+    <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
diff --git a/res/layout/accessibility_text_reading_reset_button_suw.xml b/res/layout/accessibility_text_reading_reset_button_suw.xml
deleted file mode 100644
index 97e12f3..0000000
--- a/res/layout/accessibility_text_reading_reset_button_suw.xml
+++ /dev/null
@@ -1,37 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-    Copyright (C) 2022 The Android Open Source Project
-
-    Licensed under the Apache License, Version 2.0 (the "License");
-    you may not use this file except in compliance with the License.
-    You may obtain a copy of the License at
-
-         http://www.apache.org/licenses/LICENSE-2.0
-
-    Unless required by applicable law or agreed to in writing, software
-    distributed under the License is distributed on an "AS IS" BASIS,
-    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-    See the License for the specific language governing permissions and
-    limitations under the License.
-  -->
-
-<FrameLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="match_parent"
-    android:layout_height="wrap_content"
-    android:minHeight="?android:attr/listPreferredItemHeight"
-    android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
-    android:paddingStart="?android:attr/listPreferredItemPaddingStart">
-
-    <Button
-        android:id="@+id/reset_button"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_gravity="center_vertical|start"
-        android:paddingVertical="14dp"
-        android:background="?android:attr/selectableItemBackground"
-        android:textColor="?android:attr/colorAccent"
-        android:textSize="16sp"
-        android:text="@string/accessibility_text_reading_reset_button_title"
-        android:fontFamily="@*android:string/config_bodyFontFamilyMedium" />
-</FrameLayout>
diff --git a/res/layout/dialog_sim_status.xml b/res/layout/dialog_sim_status.xml
index c169e58..4fc7f46 100644
--- a/res/layout/dialog_sim_status.xml
+++ b/res/layout/dialog_sim_status.xml
@@ -17,6 +17,7 @@
 
 <ScrollView
     xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
     android:layout_width="match_parent"
     android:layout_height="wrap_content">
     <LinearLayout
@@ -168,6 +169,11 @@
             android:layout_height="wrap_content"
             android:textIsSelectable="true"
             android:text="@string/device_info_not_available"/>
+        <ImageView
+            android:id="@+id/esim_id_qrcode"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            tools:ignore="ContentDescription" />
 
         <TextView
             style="@style/device_info_dialog_label"
diff --git a/res/layout/keyboard_layout_picker.xml b/res/layout/keyboard_layout_picker.xml
new file mode 100644
index 0000000..6b163da
--- /dev/null
+++ b/res/layout/keyboard_layout_picker.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2022 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:id="@+id/keyboard_layout_picker_container"
+    android:orientation="vertical">
+
+    <FrameLayout
+        android:id="@+id/keyboard_layout_title"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:elevation="1dp"
+        android:background="?android:attr/colorBackground"
+        android:outlineAmbientShadowColor="@android:color/transparent"
+        android:outlineSpotShadowColor="@android:color/transparent"/>
+
+    <FrameLayout
+        android:id="@+id/keyboard_layouts"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:background="?android:attr/colorBackground"/>
+
+</LinearLayout>
\ No newline at end of file
diff --git a/res/layout/preference_check_icon.xml b/res/layout/preference_check_icon.xml
new file mode 100644
index 0000000..5652ac6
--- /dev/null
+++ b/res/layout/preference_check_icon.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2022 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<ImageView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/keyboard_check_icon"
+    android:src="@drawable/ic_check_24dp"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:layout_centerVertical="true"
+    android:layout_marginHorizontal="16dp"/>
\ No newline at end of file
diff --git a/res/values/arrays.xml b/res/values/arrays.xml
index 442441d..4d9a001 100644
--- a/res/values/arrays.xml
+++ b/res/values/arrays.xml
@@ -1356,8 +1356,8 @@
         <item>1875000</item> <!-- 15Mbps == 1875000/s -->
     </string-array>
 
-    <!-- Array containing help message codes that should not be displayed
-         during fingerprint enrollment. -->
-    <integer-array name="fingerprint_acquired_ignore_list">
-    </integer-array>
+    <!-- An allowlist which packages won't show summary in battery usage screen.
+         [CHAR LIMIT=NONE] -->
+    <string-array name="allowlist_hide_summary_in_battery_usage" translatable="false">
+    </string-array>
 </resources>
diff --git a/res/values/config.xml b/res/values/config.xml
index e7efa6f..c9b5588 100755
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -624,4 +624,11 @@
     <!-- Whether sim related information is visible to the end user. -->
     <bool name="config_show_sim_info">true</bool>
 
+    <!-- In the case of receiving both help and progress message, display progress message. -->
+    <bool name="enrollment_progress_priority_over_help">false</bool>
+    <!-- Prioritize help message by their occurrence -->
+    <bool name="enrollment_prioritize_acquire_messages">false</bool>
+    <!-- Control messages displayed during enrollment -->
+    <bool name="enrollment_message_display_controller_flag">false</bool>
+
 </resources>
diff --git a/res/values/integers.xml b/res/values/integers.xml
index d110de2..530f987 100644
--- a/res/values/integers.xml
+++ b/res/values/integers.xml
@@ -26,4 +26,11 @@
     <integer name="suw_max_faces_enrollable">1</integer>
     <!-- Controls the maximum number of fingerprints enrollable during SUW -->
     <integer name="suw_max_fingerprints_enrollable">1</integer>
+
+    <!-- Minimum display time (in millis) for help messages in fingerprint enrollment. -->
+    <integer name="enrollment_help_minimum_time_display">0</integer>
+    <!-- Minimum display time (in millis) for progress messages in fingerprint enrollment. -->
+    <integer name="enrollment_progress_minimum_time_display">0</integer>
+    <!-- The time (in millis) to wait to collect messages in fingerprint enrollment before displaying it. -->
+    <integer name="enrollment_collect_time">0</integer>
 </resources>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index c73f3a5..1bdac77 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -1312,6 +1312,8 @@
 
     <!-- Title of device details screen [CHAR LIMIT=28]-->
     <string name="device_details_title">Device details</string>
+    <!-- Title for keyboard settings preferences. [CHAR LIMIT=50] -->
+    <string name="bluetooth_device_keyboard_settings_preference_title">Keyboard settings</string>
     <!-- Title of the item to show device MAC address -->
     <string name="bluetooth_device_mac_address">Device\'s Bluetooth address: <xliff:g id="address">%1$s</xliff:g></string>
     <!-- Title of the items to show multuple devices MAC address [CHAR LIMIT=NONE]-->
@@ -3641,8 +3643,8 @@
     <string name="available_virtual_keyboard_category">Available On-screen keyboard</string>
     <!-- Title for the button to trigger the 'Manage keyboards' preference sub-screen, where the user can turn on/off installed virtual keyboards.[CHAR LIMIT=35] -->
     <string name="add_virtual_keyboard">Manage on-screen keyboards</string>
-    <!-- Title for the 'keyboard assistance' preference category. [CHAR LIMIT=35] -->
-    <string name="keyboard_assistance_category">Keyboard assistance</string>
+    <!-- Title for the 'keyboard options' preference category. [CHAR LIMIT=35] -->
+    <string name="keyboard_options_category">Options</string>
     <!-- Title for the 'physical keyboard' settings screen. [CHAR LIMIT=35] -->
     <string name="physical_keyboard_title">Physical keyboard</string>
     <!-- Title for the 'show virtual keyboard' preference switch. [CHAR LIMIT=35] -->
@@ -3652,7 +3654,7 @@
     <!-- Title for the button to trigger the 'keyboard shortcuts helper' dialog. [CHAR LIMIT=35] -->
     <string name="keyboard_shortcuts_helper">Keyboard shortcuts</string>
     <!-- Summary text for the 'keyboard shortcuts helper' dialog. [CHAR LIMIT=100] -->
-    <string name="keyboard_shortcuts_helper_summary">Display available shortcuts</string>
+    <string name="keyboard_shortcuts_helper_summary">Show list of shortcuts</string>
     <!-- Title for the 'Work profile keyboards & tools' preference category inside Languages and inputs'. [CHAR LIMIT=50] -->
     <string name="language_and_input_for_work_category_title">Work profile keyboards &amp; tools</string>
     <!-- Title for the 'Virtual keyboards for work' preference. [CHAR LIMIT=45] -->
@@ -3687,6 +3689,8 @@
     <!-- Keyboard Layout Picker --> <skip />
     <!-- Title for the keyboard layout picker activity. [CHAR LIMIT=35] -->
     <string name="keyboard_layout_picker_title">Keyboard layouts</string>
+    <!-- Category title for the keyboard layout picker activity. [CHAR LIMIT=35] -->
+    <string name="keyboard_layout_picker_category_title">Physical keyboard layouts</string>
 
     <!-- User dictionary settings --><skip />
     <!-- User dictionary settings. The title of the list item to go into the Personal dictionary settings screen. [CHAR LIMIT=35] -->
@@ -3742,6 +3746,9 @@
     <!-- Title for built-in keyboard settings -->
     <string name="builtin_keyboard_settings_title">Physical keyboard</string>
 
+    <!-- Title for enabled locales keyboard layout page -->
+    <string name="enabled_locales_keyboard_layout">Layout</string>
+
     <!-- Title for the screen that lets the user choose a gadget to add to the home screen
          (or other screens that can host gadgets).  Note to translators: we're still determining
          the final name for Gadgets/Widgets, so please translate both for now. -->
@@ -6536,7 +6543,11 @@
     <string name="keywords_face_unlock">face, unlock, auth, sign in</string>
     <string name="keywords_biometric_unlock">face, unlock, auth, sign in, fingerprint, biometric</string>
     <string name="keywords_imei_info">imei, meid, min, prl version, imei sv</string>
-    <string name="keywords_sim_status">network, mobile network state, service state, signal strength, mobile network type, roaming, iccid, eid</string>
+    <string name="keywords_sim_status">network, mobile network state, service state, signal strength, mobile network type, roaming</string>
+    <string name="keywords_sim_status_esim">network, mobile network state, service state, signal strength, mobile network type, roaming, eid</string>
+    <string name="keywords_sim_status_iccid">network, mobile network state, service state, signal strength, mobile network type, roaming, iccid</string>
+    <string name="keywords_sim_status_iccid_esim">network, mobile network state, service state, signal strength, mobile network type, roaming, iccid, eid</string>
+    <string name="keywords_esim_eid">eid</string>
     <string name="keywords_model_and_hardware">serial number, hardware version</string>
     <string name="keywords_android_version">android security patch level, baseband version, kernel version</string>
     <!-- Search keywords for dark mode settings [CHAR LIMIT=NONE] -->
diff --git a/res/xml/bluetooth_device_details_fragment.xml b/res/xml/bluetooth_device_details_fragment.xml
index 5cd7c3a..c031960 100644
--- a/res/xml/bluetooth_device_details_fragment.xml
+++ b/res/xml/bluetooth_device_details_fragment.xml
@@ -88,6 +88,12 @@
             settings:controller="com.android.settings.accessibility.LiveCaptionPreferenceController"/>
     </PreferenceCategory>
 
+    <Preference
+        android:key="keyboard_settings"
+        android:persistent="false"
+        android:title="@string/bluetooth_device_keyboard_settings_preference_title"
+        settings:controller="com.android.settings.inputmethod.KeyboardSettingsPreferenceController"/>
+
     <com.android.settingslib.widget.FooterPreference
         android:key="device_details_footer"
         android:selectable="false"
diff --git a/res/xml/keyboard_settings.xml b/res/xml/keyboard_settings.xml
index bff1160..9a3ac1a 100644
--- a/res/xml/keyboard_settings.xml
+++ b/res/xml/keyboard_settings.xml
@@ -20,8 +20,7 @@
     xmlns:settings="http://schemas.android.com/apk/res-auto"
     android:title="@string/keyboard_settings">
     <PreferenceCategory
-        android:key="keyboards_category"
-        android:title="@string/keyboard_and_input_methods_category">
+        android:key="keyboards_category">
         <Preference
             android:key="virtual_keyboard_pref"
             android:title="@string/virtual_keyboard_category"
diff --git a/res/xml/keyboard_settings_enabled_locales_list.xml b/res/xml/keyboard_settings_enabled_locales_list.xml
new file mode 100644
index 0000000..06b8d5f
--- /dev/null
+++ b/res/xml/keyboard_settings_enabled_locales_list.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2022 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<PreferenceScreen
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:title="@string/physical_keyboard_title">
+    <PreferenceCategory
+        android:key="enabled_locales_keyboard_layout"
+        android:title="@string/enabled_locales_keyboard_layout">
+    </PreferenceCategory>
+</PreferenceScreen>
\ No newline at end of file
diff --git a/res/xml/new_keyboard_layout_picker_fragment.xml b/res/xml/new_keyboard_layout_picker_fragment.xml
new file mode 100644
index 0000000..0a76984
--- /dev/null
+++ b/res/xml/new_keyboard_layout_picker_fragment.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2022 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<PreferenceScreen
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:settings="http://schemas.android.com/apk/res-auto"
+    android:key="keyboard_layout_picker_list"
+    settings:controller="com.android.settings.inputmethod.NewKeyboardLayoutPickerController">
+</PreferenceScreen>
\ No newline at end of file
diff --git a/res/xml/new_keyboard_layout_picker_title.xml b/res/xml/new_keyboard_layout_picker_title.xml
new file mode 100644
index 0000000..cd03b91
--- /dev/null
+++ b/res/xml/new_keyboard_layout_picker_title.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2022 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<PreferenceScreen
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:key="keyboard_layout_picker_title">
+    <!-- Separate title from new_keyboard_layout_picker_fragment to avoid being moved to the top -->
+    <PreferenceCategory
+        android:key="keyboard_layout_picker_title"
+        android:title="@string/keyboard_layout_picker_category_title">
+    </PreferenceCategory>
+</PreferenceScreen>
\ No newline at end of file
diff --git a/res/xml/physical_keyboard_settings.xml b/res/xml/physical_keyboard_settings.xml
index 96946a9..54a5c65 100644
--- a/res/xml/physical_keyboard_settings.xml
+++ b/res/xml/physical_keyboard_settings.xml
@@ -19,8 +19,8 @@
     <!-- Additional preference screens are inserted here programmatically
          with low order values to set the key map of each attached keyboard. -->
     <PreferenceCategory
-        android:key="keyboard_assistance_category"
-        android:title="@string/keyboard_assistance_category">
+        android:key="keyboard_options_category"
+        android:title="@string/keyboard_options_category">
         <SwitchPreference
             android:key="show_virtual_keyboard_switch"
             android:title="@string/show_ime"
diff --git a/src/com/android/settings/accessibility/AccessibilitySettings.java b/src/com/android/settings/accessibility/AccessibilitySettings.java
index 23f8fd3..7b1500b 100644
--- a/src/com/android/settings/accessibility/AccessibilitySettings.java
+++ b/src/com/android/settings/accessibility/AccessibilitySettings.java
@@ -43,6 +43,7 @@
 import com.android.settings.overlay.FeatureFactory;
 import com.android.settings.search.BaseSearchIndexProvider;
 import com.android.settingslib.RestrictedPreference;
+import com.android.settingslib.core.AbstractPreferenceController;
 import com.android.settingslib.search.SearchIndexable;
 import com.android.settingslib.search.SearchIndexableRaw;
 
@@ -303,6 +304,7 @@
     void updateAllPreferences() {
         updateSystemPreferences();
         updateServicePreferences();
+        updatePreferencesState();
     }
 
     private void registerContentMonitors() {
@@ -478,6 +480,13 @@
         // Do nothing.
     }
 
+    private void updatePreferencesState() {
+        final List<AbstractPreferenceController> controllers = new ArrayList<>();
+        getPreferenceControllers().forEach(controllers::addAll);
+        controllers.forEach(controller -> controller.updateState(
+                findPreference(controller.getPreferenceKey())));
+    }
+
     public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
             new BaseSearchIndexProvider(R.xml.accessibility_settings) {
                 @Override
diff --git a/src/com/android/settings/accessibility/ColorAndMotionFragment.java b/src/com/android/settings/accessibility/ColorAndMotionFragment.java
index 7f55053..921aa4e 100644
--- a/src/com/android/settings/accessibility/ColorAndMotionFragment.java
+++ b/src/com/android/settings/accessibility/ColorAndMotionFragment.java
@@ -19,6 +19,7 @@
 import android.app.settings.SettingsEnums;
 import android.hardware.display.ColorDisplayManager;
 import android.os.Bundle;
+import android.os.Handler;
 import android.provider.Settings;
 
 import androidx.preference.Preference;
@@ -28,8 +29,12 @@
 import com.android.settings.R;
 import com.android.settings.dashboard.DashboardFragment;
 import com.android.settings.search.BaseSearchIndexProvider;
+import com.android.settingslib.core.AbstractPreferenceController;
 import com.android.settingslib.search.SearchIndexable;
 
+import java.util.ArrayList;
+import java.util.List;
+
 /** Accessibility settings for color and motion. */
 @SearchIndexable(forTarget = SearchIndexable.ALL & ~SearchIndexable.ARC)
 public class ColorAndMotionFragment extends DashboardFragment {
@@ -46,18 +51,48 @@
     private Preference mDisplayDaltonizerPreferenceScreen;
     private SwitchPreference mToggleDisableAnimationsPreference;
     private SwitchPreference mToggleLargePointerIconPreference;
+    private AccessibilitySettingsContentObserver mSettingsContentObserver;
+
+    private final List<String> mShortcutFeatureKeys = new ArrayList<>();
 
     @Override
     public int getMetricsCategory() {
         return SettingsEnums.ACCESSIBILITY_COLOR_AND_MOTION;
     }
 
-
     @Override
     public void onCreate(Bundle icicle) {
         super.onCreate(icicle);
         initializeAllPreferences();
         updateSystemPreferences();
+
+        mShortcutFeatureKeys.add(Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED);
+        mShortcutFeatureKeys.add(Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED);
+
+        mSettingsContentObserver = new AccessibilitySettingsContentObserver(new Handler());
+        mSettingsContentObserver.registerKeysToObserverCallback(mShortcutFeatureKeys,
+                key -> updatePreferencesState());
+    }
+
+    private void updatePreferencesState() {
+        final List<AbstractPreferenceController> controllers = new ArrayList<>();
+        getPreferenceControllers().forEach(controllers::addAll);
+        controllers.forEach(controller -> controller.updateState(
+                findPreference(controller.getPreferenceKey())));
+    }
+
+    @Override
+    public void onStart() {
+        super.onStart();
+
+        mSettingsContentObserver.register(getContentResolver());
+    }
+
+    @Override
+    public void onStop() {
+        super.onStop();
+
+        mSettingsContentObserver.unregister(getContentResolver());
     }
 
     @Override
diff --git a/src/com/android/settings/accessibility/PreviewSizeSeekBarController.java b/src/com/android/settings/accessibility/PreviewSizeSeekBarController.java
index 2078112..51a775e 100644
--- a/src/com/android/settings/accessibility/PreviewSizeSeekBarController.java
+++ b/src/com/android/settings/accessibility/PreviewSizeSeekBarController.java
@@ -25,6 +25,8 @@
 import com.android.settings.core.BasePreferenceController;
 import com.android.settings.widget.LabeledSeekBarPreference;
 
+import java.util.Optional;
+
 /**
  * The controller of {@link LabeledSeekBarPreference} that listens to display size and font size
  * settings changes and updates preview size threshold smoothly.
@@ -33,19 +35,24 @@
         TextReadingResetController.ResetStateListener {
     private final PreviewSizeData<? extends Number> mSizeData;
     private boolean mSeekByTouch;
-    private ProgressInteractionListener mInteractionListener;
+    private Optional<ProgressInteractionListener> mInteractionListener = Optional.empty();
     private LabeledSeekBarPreference mSeekBarPreference;
 
     private final SeekBar.OnSeekBarChangeListener mSeekBarChangeListener =
             new SeekBar.OnSeekBarChangeListener() {
                 @Override
                 public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
-                    mInteractionListener.notifyPreferenceChanged();
-
-                    if (!mSeekByTouch && mInteractionListener != null) {
-                        mInteractionListener.onProgressChanged();
+                    if (mInteractionListener.isEmpty()) {
+                        return;
                     }
 
+                    final ProgressInteractionListener interactionListener =
+                            mInteractionListener.get();
+                    interactionListener.notifyPreferenceChanged();
+
+                    if (!mSeekByTouch) {
+                        interactionListener.onProgressChanged();
+                    }
                 }
 
                 @Override
@@ -57,9 +64,7 @@
                 public void onStopTrackingTouch(SeekBar seekBar) {
                     mSeekByTouch = false;
 
-                    if (mInteractionListener != null) {
-                        mInteractionListener.onEndTrackingTouch();
-                    }
+                    mInteractionListener.ifPresent(ProgressInteractionListener::onEndTrackingTouch);
                 }
             };
 
@@ -70,7 +75,7 @@
     }
 
     void setInteractionListener(ProgressInteractionListener interactionListener) {
-        mInteractionListener = interactionListener;
+        mInteractionListener = Optional.ofNullable(interactionListener);
     }
 
     @Override
@@ -95,6 +100,10 @@
     public void resetState() {
         final int defaultProgress = mSizeData.getValues().indexOf(mSizeData.getDefaultValue());
         mSeekBarPreference.setProgress(defaultProgress);
+
+        // Immediately take the effect of updating the progress to avoid waiting for receiving
+        // the event to delay update.
+        mInteractionListener.ifPresent(ProgressInteractionListener::onProgressChanged);
     }
 
 
diff --git a/src/com/android/settings/accessibility/TextReadingPreferenceFragment.java b/src/com/android/settings/accessibility/TextReadingPreferenceFragment.java
index d1614ca..22bef28 100644
--- a/src/com/android/settings/accessibility/TextReadingPreferenceFragment.java
+++ b/src/com/android/settings/accessibility/TextReadingPreferenceFragment.java
@@ -18,11 +18,11 @@
 
 import static com.android.settings.accessibility.TextReadingResetController.ResetStateListener;
 
+import android.app.Activity;
 import android.app.Dialog;
 import android.app.settings.SettingsEnums;
 import android.content.Context;
 import android.content.DialogInterface;
-import android.content.Intent;
 import android.os.Bundle;
 import android.view.View;
 import android.widget.Toast;
@@ -44,7 +44,6 @@
 import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
 import java.util.List;
-import java.util.Set;
 import java.util.stream.Collectors;
 
 /**
@@ -55,8 +54,7 @@
 public class TextReadingPreferenceFragment extends DashboardFragment {
     public static final String EXTRA_LAUNCHED_FROM = "launched_from";
     private static final String TAG = "TextReadingPreferenceFragment";
-    private static final String CATEGORY_FOR_ANYTHING_ELSE =
-            "com.android.settings.suggested.category.DISPLAY_SETTINGS";
+    private static final String SETUP_WIZARD_PACKAGE = "setupwizard";
     static final String FONT_SIZE_KEY = "font_size";
     static final String DISPLAY_SIZE_KEY = "display_size";
     static final String BOLD_TEXT_KEY = "toggle_force_bold_text";
@@ -179,10 +177,8 @@
                 new TextReadingResetController(context, RESET_KEY,
                         v -> showDialog(DialogEnums.DIALOG_RESET_SETTINGS));
         resetController.setEntryPoint(mEntryPoint);
+        resetController.setVisible(!WizardManagerHelper.isAnySetupWizard(getIntent()));
         controllers.add(resetController);
-        if (WizardManagerHelper.isAnySetupWizard(getIntent())) {
-            resetController.setSetupWizardStyle();
-        }
 
         return controllers;
     }
@@ -230,6 +226,13 @@
         }
     }
 
+    protected boolean isCallingFromAnythingElseEntryPoint() {
+        final Activity activity = getActivity();
+        final String callingPackage = activity != null ? activity.getCallingPackage() : null;
+
+        return callingPackage != null && callingPackage.contains(SETUP_WIZARD_PACKAGE);
+    }
+
     @VisibleForTesting
     DisplaySizeData createDisplaySizeData(Context context) {
         return new DisplaySizeData(context);
@@ -242,14 +245,7 @@
             return;
         }
 
-        final Intent intent = getIntent();
-        if (intent == null) {
-            mEntryPoint = EntryPoint.UNKNOWN_ENTRY;
-            return;
-        }
-
-        final Set<String> categories = intent.getCategories();
-        mEntryPoint = categories != null && categories.contains(CATEGORY_FOR_ANYTHING_ELSE)
+        mEntryPoint = isCallingFromAnythingElseEntryPoint()
                 ? EntryPoint.SUW_ANYTHING_ELSE : EntryPoint.UNKNOWN_ENTRY;
     }
 
diff --git a/src/com/android/settings/accessibility/TextReadingPreferenceFragmentForSetupWizard.java b/src/com/android/settings/accessibility/TextReadingPreferenceFragmentForSetupWizard.java
index b025cf5..cdbfe5f 100644
--- a/src/com/android/settings/accessibility/TextReadingPreferenceFragmentForSetupWizard.java
+++ b/src/com/android/settings/accessibility/TextReadingPreferenceFragmentForSetupWizard.java
@@ -16,6 +16,10 @@
 
 package com.android.settings.accessibility;
 
+import static android.app.Activity.RESULT_CANCELED;
+
+import static com.android.settings.accessibility.AccessibilityDialogUtils.DialogEnums.DIALOG_RESET_SETTINGS;
+
 import android.app.settings.SettingsEnums;
 import android.graphics.drawable.Drawable;
 import android.os.Bundle;
@@ -28,9 +32,10 @@
 import com.android.settings.R;
 import com.android.settingslib.Utils;
 
+import com.google.android.setupcompat.template.FooterBarMixin;
+import com.google.android.setupcompat.template.FooterButton;
 import com.google.android.setupdesign.GlifPreferenceLayout;
 
-
 /**
  * A {@link androidx.preference.PreferenceFragmentCompat} that displays the settings page related
  * to the text and reading option in the SetupWizard.
@@ -48,6 +53,28 @@
         icon.setTintList(Utils.getColorAttr(getContext(), android.R.attr.colorPrimary));
         AccessibilitySetupWizardUtils.updateGlifPreferenceLayout(getContext(), layout, title,
                 /* description= */ null, icon);
+
+        final FooterBarMixin mixin = layout.getMixin(FooterBarMixin.class);
+        mixin.setSecondaryButton(
+                new FooterButton.Builder(getContext())
+                        .setText(R.string.accessibility_text_reading_reset_button_title)
+                        .setListener(l -> showDialog(DIALOG_RESET_SETTINGS))
+                        .setButtonType(FooterButton.ButtonType.CLEAR)
+                        .setTheme(R.style.SudGlifButton_Secondary)
+                        .build());
+
+        if (isCallingFromAnythingElseEntryPoint()) {
+            mixin.setPrimaryButton(
+                    new FooterButton.Builder(getContext())
+                            .setText(R.string.done)
+                            .setListener(l -> {
+                                setResult(RESULT_CANCELED);
+                                finish();
+                            })
+                            .setButtonType(FooterButton.ButtonType.DONE)
+                            .setTheme(R.style.SudGlifButton_Primary)
+                            .build());
+        }
     }
 
     @Override
diff --git a/src/com/android/settings/accessibility/TextReadingResetController.java b/src/com/android/settings/accessibility/TextReadingResetController.java
index 206090c..325052c 100644
--- a/src/com/android/settings/accessibility/TextReadingResetController.java
+++ b/src/com/android/settings/accessibility/TextReadingResetController.java
@@ -23,7 +23,6 @@
 import androidx.preference.PreferenceScreen;
 
 import com.android.settings.accessibility.TextReadingPreferenceFragment.EntryPoint;
-import com.android.settings.accessibility.TextReadingResetPreference.ButtonStyle;
 import com.android.settings.core.BasePreferenceController;
 import com.android.settings.core.instrumentation.SettingsStatsLog;
 
@@ -31,8 +30,7 @@
  * The controller of the reset button in the text and reading options page.
  */
 class TextReadingResetController extends BasePreferenceController {
-    @ButtonStyle
-    private int mButtonStyle;
+    private boolean mIsVisible;
     private final View.OnClickListener mOnResetClickListener;
 
     @EntryPoint
@@ -67,11 +65,11 @@
             }
         });
 
-        resetPreference.setSetupWizardStyle(mButtonStyle);
+        setVisible(screen, getPreferenceKey(), mIsVisible);
     }
 
-    void setSetupWizardStyle() {
-        mButtonStyle = ButtonStyle.SUW;
+    void setVisible(boolean isVisible) {
+        mIsVisible = isVisible;
     }
 
     /**
diff --git a/src/com/android/settings/accessibility/TextReadingResetPreference.java b/src/com/android/settings/accessibility/TextReadingResetPreference.java
index 64f3834..9518de2 100644
--- a/src/com/android/settings/accessibility/TextReadingResetPreference.java
+++ b/src/com/android/settings/accessibility/TextReadingResetPreference.java
@@ -20,15 +20,11 @@
 import android.util.AttributeSet;
 import android.view.View;
 
-import androidx.annotation.IntDef;
 import androidx.preference.Preference;
 import androidx.preference.PreferenceViewHolder;
 
 import com.android.settings.R;
 
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-
 /**
  * The preference which is used for resetting the status of all preferences in the display size
  * and text page.
@@ -36,20 +32,10 @@
 public class TextReadingResetPreference extends Preference {
     private View.OnClickListener mOnResetClickListener;
 
-    @Retention(RetentionPolicy.SOURCE)
-    @IntDef({
-            ButtonStyle.DEFAULT,
-            ButtonStyle.SUW,
-    })
-    @interface ButtonStyle {
-        int DEFAULT = 0;
-        int SUW = 1;
-    }
-
     public TextReadingResetPreference(Context context, AttributeSet attrs) {
         super(context, attrs);
 
-        setSetupWizardStyle(ButtonStyle.DEFAULT);
+        setLayoutResource(R.layout.accessibility_text_reading_reset_button);
     }
 
     @Override
@@ -60,13 +46,6 @@
         view.setOnClickListener(mOnResetClickListener);
     }
 
-    void setSetupWizardStyle(@ButtonStyle int style) {
-        final int layoutResId = (style == ButtonStyle.SUW)
-                ? R.layout.accessibility_text_reading_reset_button_suw
-                : R.layout.accessibility_text_reading_reset_button;
-        setLayoutResource(layoutResId);
-    }
-
     void setOnResetClickListener(View.OnClickListener resetClickListener) {
         mOnResetClickListener = resetClickListener;
     }
diff --git a/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrolling.java b/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrolling.java
index 3ab2f92..5b8cd68 100644
--- a/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrolling.java
+++ b/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrolling.java
@@ -352,8 +352,8 @@
 
     @Override
     protected BiometricEnrollSidecar getSidecar() {
-        final FingerprintEnrollSidecar sidecar = new FingerprintEnrollSidecar();
-        sidecar.setEnrollReason(FingerprintManager.ENROLL_ENROLL);
+        final FingerprintEnrollSidecar sidecar = new FingerprintEnrollSidecar(this,
+                FingerprintManager.ENROLL_ENROLL);
         return sidecar;
     }
 
diff --git a/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollFindSensor.java b/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollFindSensor.java
index 200b8c5..778ee5c 100644
--- a/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollFindSensor.java
+++ b/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollFindSensor.java
@@ -293,8 +293,8 @@
         mSidecar = (FingerprintEnrollSidecar) getSupportFragmentManager().findFragmentByTag(
                 FingerprintEnrollEnrolling.TAG_SIDECAR);
         if (mSidecar == null) {
-            mSidecar = new FingerprintEnrollSidecar();
-            mSidecar.setEnrollReason(FingerprintManager.ENROLL_FIND_SENSOR);
+            mSidecar = new FingerprintEnrollSidecar(this,
+                    FingerprintManager.ENROLL_FIND_SENSOR);
             getSupportFragmentManager().beginTransaction()
                     .add(mSidecar, FingerprintEnrollEnrolling.TAG_SIDECAR)
                     .commitAllowingStateLoss();
diff --git a/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollSidecar.java b/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollSidecar.java
index d1e512e..b3b9975 100644
--- a/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollSidecar.java
+++ b/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollSidecar.java
@@ -16,19 +16,19 @@
 
 package com.android.settings.biometrics.fingerprint;
 
+import static android.hardware.fingerprint.FingerprintManager.ENROLL_ENROLL;
+
 import android.app.Activity;
 import android.app.settings.SettingsEnums;
+import android.content.Context;
 import android.hardware.fingerprint.FingerprintManager;
+import android.os.SystemClock;
 import android.util.Log;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.settings.R;
 import com.android.settings.biometrics.BiometricEnrollSidecar;
 
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.Set;
-
 /**
  * Sidecar fragment to handle the state around fingerprint enrollment.
  */
@@ -37,19 +37,41 @@
 
     private FingerprintUpdater mFingerprintUpdater;
     private @FingerprintManager.EnrollReason int mEnrollReason;
-    private Set<Integer> mHelpIgnore;
+    private final MessageDisplayController mMessageDisplayController;
+    private final boolean mMessageDisplayControllerFlag;
+
+    /**
+     * Create a new FingerprintEnrollSidecar object.
+     * @param context associated context
+     * @param enrollReason reason for enrollment
+     */
+    public FingerprintEnrollSidecar(Context context,
+            @FingerprintManager.EnrollReason int enrollReason) {
+        mEnrollReason = enrollReason;
+
+        int helpMinimumDisplayTime = context.getResources().getInteger(
+                R.integer.enrollment_help_minimum_time_display);
+        int progressMinimumDisplayTime = context.getResources().getInteger(
+                R.integer.enrollment_progress_minimum_time_display);
+        boolean progressPriorityOverHelp = context.getResources().getBoolean(
+                R.bool.enrollment_progress_priority_over_help);
+        boolean prioritizeAcquireMessages = context.getResources().getBoolean(
+                R.bool.enrollment_prioritize_acquire_messages);
+        int collectTime = context.getResources().getInteger(
+                R.integer.enrollment_collect_time);
+        mMessageDisplayControllerFlag = context.getResources().getBoolean(
+                R.bool.enrollment_message_display_controller_flag);
+
+        mMessageDisplayController = new MessageDisplayController(context.getMainThreadHandler(),
+                mEnrollmentCallback, SystemClock.elapsedRealtimeClock(), helpMinimumDisplayTime,
+                progressMinimumDisplayTime, progressPriorityOverHelp, prioritizeAcquireMessages,
+                collectTime);
+    }
 
     @Override
     public void onAttach(Activity activity) {
         super.onAttach(activity);
         mFingerprintUpdater = new FingerprintUpdater(activity);
-        final int[] ignoreAcquiredInfo = getResources().getIntArray(
-                R.array.fingerprint_acquired_ignore_list);
-        mHelpIgnore = new HashSet<>();
-        for (int acquiredInfo: ignoreAcquiredInfo) {
-            mHelpIgnore.add(acquiredInfo);
-        }
-        mHelpIgnore = Collections.unmodifiableSet(mHelpIgnore);
     }
 
     @Override
@@ -62,8 +84,16 @@
                     getString(R.string.fingerprint_intro_error_unknown));
             return;
         }
-        mFingerprintUpdater.enroll(mToken, mEnrollmentCancel, mUserId, mEnrollmentCallback,
-                mEnrollReason);
+
+        if (mEnrollReason == ENROLL_ENROLL && mMessageDisplayControllerFlag) {
+            //API calls need to be processed for {@link FingerprintEnrollEnrolling}
+            mFingerprintUpdater.enroll(mToken, mEnrollmentCancel, mUserId,
+                    mMessageDisplayController, mEnrollReason);
+        } else {
+            //No processing required for {@link FingerprintEnrollFindSensor}
+            mFingerprintUpdater.enroll(mToken, mEnrollmentCancel, mUserId, mEnrollmentCallback,
+                    mEnrollReason);
+        }
     }
 
     public void setEnrollReason(@FingerprintManager.EnrollReason int enrollReason) {
@@ -80,9 +110,6 @@
 
         @Override
         public void onEnrollmentHelp(int helpMsgId, CharSequence helpString) {
-            if (mHelpIgnore.contains(helpMsgId)) {
-                return;
-            }
             FingerprintEnrollSidecar.super.onEnrollmentHelp(helpMsgId, helpString);
         }
 
diff --git a/src/com/android/settings/biometrics/fingerprint/MessageDisplayController.java b/src/com/android/settings/biometrics/fingerprint/MessageDisplayController.java
new file mode 100644
index 0000000..11f3ee3
--- /dev/null
+++ b/src/com/android/settings/biometrics/fingerprint/MessageDisplayController.java
@@ -0,0 +1,264 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.biometrics.fingerprint;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.hardware.fingerprint.FingerprintManager;
+import android.os.Handler;
+
+import java.time.Clock;
+import java.util.ArrayDeque;
+import java.util.Deque;
+import java.util.HashMap;
+
+/**
+ * Processes message provided from the enrollment callback and filters them based
+ * on the below configurable flags. This is primarily used to reduce the rate
+ * at which messages come through, which in turns eliminates UI flicker.
+ */
+public class MessageDisplayController extends FingerprintManager.EnrollmentCallback {
+
+    private final int mHelpMinimumDisplayTime;
+    private final int mProgressMinimumDisplayTime;
+    private final boolean mProgressPriorityOverHelp;
+    private final boolean mPrioritizeAcquireMessages;
+    private final int mCollectTime;
+    @NonNull
+    private final Deque<HelpMessage> mHelpMessageList;
+    @NonNull
+    private final Deque<ProgressMessage> mProgressMessageList;
+    @NonNull
+    private final Handler mHandler;
+    @NonNull
+    private final Clock mClock;
+    @NonNull
+    private final Runnable mDisplayMessageRunnable;
+
+    @Nullable
+    private ProgressMessage mLastProgressMessageDisplayed;
+    private boolean mMustDisplayProgress;
+    private boolean mWaitingForMessage;
+    @NonNull FingerprintManager.EnrollmentCallback mEnrollmentCallback;
+
+    private abstract static class Message {
+        long mTimeStamp = 0;
+        abstract void display();
+    }
+
+    private class HelpMessage extends Message {
+        private final int mHelpMsgId;
+        private final CharSequence mHelpString;
+
+        HelpMessage(int helpMsgId, CharSequence helpString) {
+            mHelpMsgId = helpMsgId;
+            mHelpString = helpString;
+            mTimeStamp = mClock.millis();
+        }
+
+        @Override
+        void display() {
+            mEnrollmentCallback.onEnrollmentHelp(mHelpMsgId, mHelpString);
+            mHandler.postDelayed(mDisplayMessageRunnable, mHelpMinimumDisplayTime);
+        }
+    }
+
+    private class ProgressMessage extends Message {
+        private final int mRemaining;
+
+        ProgressMessage(int remaining) {
+            mRemaining = remaining;
+            mTimeStamp = mClock.millis();
+        }
+
+        @Override
+        void display() {
+            mEnrollmentCallback.onEnrollmentProgress(mRemaining);
+            mLastProgressMessageDisplayed = this;
+            mHandler.postDelayed(mDisplayMessageRunnable, mProgressMinimumDisplayTime);
+        }
+    }
+
+    /**
+     * Creating a MessageDisplayController object.
+     * @param handler main handler to run message queue
+     * @param enrollmentCallback callback to display messages
+     * @param clock real time system clock
+     * @param helpMinimumDisplayTime the minimum duration (in millis) that
+*        a help message needs to be displayed for
+     * @param progressMinimumDisplayTime the minimum duration (in millis) that
+*        a progress message needs to be displayed for
+     * @param progressPriorityOverHelp if true, then progress message is displayed
+*        when both help and progress message APIs have been called
+     * @param prioritizeAcquireMessages if true, then displays the help message
+*        which has occurred the most after the last display message
+     * @param collectTime the waiting time (in millis) to collect messages when it is idle
+     */
+    public MessageDisplayController(@NonNull Handler handler,
+            FingerprintManager.EnrollmentCallback enrollmentCallback,
+            @NonNull Clock clock, int helpMinimumDisplayTime, int progressMinimumDisplayTime,
+            boolean progressPriorityOverHelp, boolean prioritizeAcquireMessages,
+            int collectTime) {
+        mClock = clock;
+        mWaitingForMessage = false;
+        mHelpMessageList = new ArrayDeque<>();
+        mProgressMessageList = new ArrayDeque<>();
+        mHandler = handler;
+        mEnrollmentCallback = enrollmentCallback;
+
+        mHelpMinimumDisplayTime = helpMinimumDisplayTime;
+        mProgressMinimumDisplayTime = progressMinimumDisplayTime;
+        mProgressPriorityOverHelp = progressPriorityOverHelp;
+        mPrioritizeAcquireMessages = prioritizeAcquireMessages;
+        mCollectTime = collectTime;
+
+        mDisplayMessageRunnable = () -> {
+            long timeStamp = mClock.millis();
+            Message messageToDisplay = getMessageToDisplay(timeStamp);
+
+            if (messageToDisplay != null) {
+                messageToDisplay.display();
+            } else {
+                mWaitingForMessage = true;
+            }
+        };
+
+        mHandler.postDelayed(mDisplayMessageRunnable, 0);
+    }
+
+    /**
+     * Adds help message to the queue to be processed later.
+     *
+     * @param helpMsgId message Id associated with the help message
+     * @param helpString string associated with the help message
+     */
+    @Override
+    public void onEnrollmentHelp(int helpMsgId, CharSequence helpString) {
+        mHelpMessageList.add(new HelpMessage(helpMsgId, helpString));
+
+        if (mWaitingForMessage) {
+            mWaitingForMessage = false;
+            mHandler.postDelayed(mDisplayMessageRunnable, mCollectTime);
+        }
+    }
+
+    /**
+     * Adds progress change message to the queue to be processed later.
+     *
+     * @param remaining remaining number of steps to complete enrollment
+     */
+    @Override
+    public void onEnrollmentProgress(int remaining) {
+        mProgressMessageList.add(new ProgressMessage(remaining));
+
+        if (mWaitingForMessage) {
+            mWaitingForMessage = false;
+            mHandler.postDelayed(mDisplayMessageRunnable, mCollectTime);
+        }
+    }
+
+    @Override
+    public void onEnrollmentError(int errMsgId, CharSequence errString) {
+        mEnrollmentCallback.onEnrollmentError(errMsgId, errString);
+    }
+
+    private Message getMessageToDisplay(long timeStamp) {
+        ProgressMessage progressMessageToDisplay = getProgressMessageToDisplay(timeStamp);
+        if (mMustDisplayProgress) {
+            mMustDisplayProgress = false;
+            if (progressMessageToDisplay != null) {
+                return progressMessageToDisplay;
+            }
+            if (mLastProgressMessageDisplayed != null) {
+                return mLastProgressMessageDisplayed;
+            }
+        }
+
+        Message helpMessageToDisplay = getHelpMessageToDisplay(timeStamp);
+        if (helpMessageToDisplay != null || progressMessageToDisplay != null) {
+            if (mProgressPriorityOverHelp && progressMessageToDisplay != null) {
+                return progressMessageToDisplay;
+            } else if (helpMessageToDisplay != null) {
+                if (progressMessageToDisplay != null) {
+                    mMustDisplayProgress = true;
+                    mLastProgressMessageDisplayed = progressMessageToDisplay;
+                }
+                return helpMessageToDisplay;
+            } else {
+                return progressMessageToDisplay;
+            }
+        } else {
+            return null;
+        }
+    }
+
+    private ProgressMessage getProgressMessageToDisplay(long timeStamp) {
+        ProgressMessage finalProgressMessage = null;
+        while (mProgressMessageList != null && !mProgressMessageList.isEmpty()) {
+            Message message = mProgressMessageList.peekFirst();
+            if (message.mTimeStamp <= timeStamp) {
+                ProgressMessage progressMessage = mProgressMessageList.pollFirst();
+                if (mLastProgressMessageDisplayed != null
+                        && mLastProgressMessageDisplayed.mRemaining == progressMessage.mRemaining) {
+                    continue;
+                }
+                finalProgressMessage = progressMessage;
+            } else {
+                break;
+            }
+        }
+
+        return finalProgressMessage;
+    }
+
+    private HelpMessage getHelpMessageToDisplay(long timeStamp) {
+        HashMap<CharSequence, Integer> messageCount = new HashMap<>();
+        HelpMessage finalHelpMessage = null;
+
+        while (mHelpMessageList != null && !mHelpMessageList.isEmpty()) {
+            Message message = mHelpMessageList.peekFirst();
+            if (message.mTimeStamp <= timeStamp) {
+                finalHelpMessage = mHelpMessageList.pollFirst();
+                CharSequence errString = finalHelpMessage.mHelpString;
+                messageCount.put(errString, messageCount.getOrDefault(errString, 0) + 1);
+            } else {
+                break;
+            }
+        }
+        if (mPrioritizeAcquireMessages) {
+            finalHelpMessage = prioritizeHelpMessageByCount(messageCount);
+        }
+
+        return finalHelpMessage;
+    }
+
+    private HelpMessage prioritizeHelpMessageByCount(HashMap<CharSequence, Integer> messageCount) {
+        int maxCount = 0;
+        CharSequence maxCountMessage = null;
+
+        for (CharSequence key :
+                messageCount.keySet()) {
+            if (maxCount < messageCount.get(key)) {
+                maxCountMessage = key;
+                maxCount = messageCount.get(key);
+            }
+        }
+
+        return maxCountMessage != null ? new HelpMessage(0 /* errMsgId */,
+                maxCountMessage) : null;
+    }
+}
diff --git a/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragment.java b/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragment.java
index 406ac69..f68cc40 100644
--- a/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragment.java
+++ b/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragment.java
@@ -47,6 +47,7 @@
 import com.android.settings.connecteddevice.stylus.StylusDevicesController;
 import com.android.settings.core.SettingsUIDeviceConfig;
 import com.android.settings.dashboard.RestrictedDashboardFragment;
+import com.android.settings.inputmethod.KeyboardSettingsPreferenceController;
 import com.android.settings.overlay.FeatureFactory;
 import com.android.settings.slices.BlockingSlicePrefController;
 import com.android.settings.slices.SlicePreferenceController;
@@ -171,6 +172,7 @@
         }
         use(AdvancedBluetoothDetailsHeaderController.class).init(mCachedDevice);
         use(LeAudioBluetoothDetailsHeaderController.class).init(mCachedDevice, mManager);
+        use(KeyboardSettingsPreferenceController.class).init(mCachedDevice, getActivity());
 
         final BluetoothFeatureProvider featureProvider = FeatureFactory.getFactory(
                 context).getBluetoothFeatureProvider();
diff --git a/src/com/android/settings/core/gateway/SettingsGateway.java b/src/com/android/settings/core/gateway/SettingsGateway.java
index 7904fdb..da81f6e 100644
--- a/src/com/android/settings/core/gateway/SettingsGateway.java
+++ b/src/com/android/settings/core/gateway/SettingsGateway.java
@@ -120,6 +120,7 @@
 import com.android.settings.inputmethod.AvailableVirtualKeyboardFragment;
 import com.android.settings.inputmethod.KeyboardLayoutPickerFragment;
 import com.android.settings.inputmethod.KeyboardSettings;
+import com.android.settings.inputmethod.NewKeyboardLayoutEnabledLocalesFragment;
 import com.android.settings.inputmethod.PhysicalKeyboardFragment;
 import com.android.settings.inputmethod.SpellCheckersSettings;
 import com.android.settings.inputmethod.UserDictionaryList;
@@ -214,6 +215,7 @@
             LanguageAndInputSettings.class.getName(),
             LanguageSettings.class.getName(),
             KeyboardSettings.class.getName(),
+            NewKeyboardLayoutEnabledLocalesFragment.class.getName(),
             SpellCheckersSettings.class.getName(),
             UserDictionaryList.class.getName(),
             UserDictionarySettings.class.getName(),
diff --git a/src/com/android/settings/deviceinfo/simstatus/SimStatusDialogController.java b/src/com/android/settings/deviceinfo/simstatus/SimStatusDialogController.java
index c093472..855cd12 100644
--- a/src/com/android/settings/deviceinfo/simstatus/SimStatusDialogController.java
+++ b/src/com/android/settings/deviceinfo/simstatus/SimStatusDialogController.java
@@ -22,6 +22,7 @@
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.Context;
+import android.content.DialogInterface;
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.ServiceConnection;
@@ -72,7 +73,8 @@
 /**
  * Controller for Sim Status information within the About Phone Settings page.
  */
-public class SimStatusDialogController implements LifecycleObserver {
+public class SimStatusDialogController implements LifecycleObserver,
+        DialogInterface.OnShowListener {
 
     private final static String TAG = "SimStatusDialogCtrl";
 
@@ -107,6 +109,8 @@
     @VisibleForTesting
     final static int EID_INFO_VALUE_ID = R.id.esim_id_value;
     @VisibleForTesting
+    final static int EID_INFO_QRCODE_ID = R.id.esim_id_qrcode;
+    @VisibleForTesting
     final static int IMS_REGISTRATION_STATE_LABEL_ID = R.id.ims_reg_state_label;
     @VisibleForTesting
     final static int IMS_REGISTRATION_STATE_VALUE_ID = R.id.ims_reg_state_value;
@@ -158,6 +162,7 @@
 
     private boolean mShowLatestAreaInfo;
     private boolean mIsRegisteredListener = false;
+    private AtomicReference<String> mEid = null;
 
     private final BroadcastReceiver mAreaInfoReceiver = new BroadcastReceiver() {
         @Override
@@ -264,6 +269,19 @@
     }
 
     /**
+     * Callback when dialog end of show().
+     */
+    public void onShow(DialogInterface dialog) {
+        if (mEid != null) {
+            String eidText = mEid.get();
+            if (eidText != null) {
+                // Present QR code after the completion of layout
+                mDialog.setQrCode(EID_INFO_QRCODE_ID, eidText);
+            }
+        }
+    }
+
+    /**
      * Deinitialization works
      */
     public void deinitialize() {
@@ -618,8 +636,8 @@
     @VisibleForTesting
     protected void requestForUpdateEid() {
         ThreadUtils.postOnBackgroundThread(() -> {
-            final AtomicReference<String> eid = getEid(mSlotIndex);
-            ThreadUtils.postOnMainThread(() -> updateEid(eid));
+            mEid = getEid(mSlotIndex);
+            ThreadUtils.postOnMainThread(() -> updateEid(mEid));
         });
     }
 
@@ -663,11 +681,20 @@
 
     @VisibleForTesting
     protected void updateEid(AtomicReference<String> eid) {
+        boolean removeQrCode = true;
         if (eid == null) {
             mDialog.removeSettingFromScreen(EID_INFO_LABEL_ID);
             mDialog.removeSettingFromScreen(EID_INFO_VALUE_ID);
-        } else if (eid.get() != null) {
-            mDialog.setText(EID_INFO_VALUE_ID, eid.get());
+            mDialog.removeSettingFromScreen(EID_INFO_QRCODE_ID);
+        } else {
+            String eidText = eid.get();
+            if (eidText != null) {
+                mDialog.setText(EID_INFO_VALUE_ID, eidText);
+                removeQrCode = (eidText == "");
+            }
+        }
+        if (removeQrCode) {
+            mDialog.removeSettingFromScreen(EID_INFO_QRCODE_ID);
         }
     }
 
diff --git a/src/com/android/settings/deviceinfo/simstatus/SimStatusDialogFragment.java b/src/com/android/settings/deviceinfo/simstatus/SimStatusDialogFragment.java
index 96acd43..3bd9b34 100644
--- a/src/com/android/settings/deviceinfo/simstatus/SimStatusDialogFragment.java
+++ b/src/com/android/settings/deviceinfo/simstatus/SimStatusDialogFragment.java
@@ -19,11 +19,14 @@
 import android.app.Dialog;
 import android.app.settings.SettingsEnums;
 import android.os.Bundle;
+import android.graphics.Bitmap;
 import android.text.TextUtils;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.WindowManager;
+import android.widget.ImageView;
 import android.widget.TextView;
+import android.util.Log;
 
 import androidx.appcompat.app.AlertDialog;
 import androidx.fragment.app.Fragment;
@@ -32,6 +35,7 @@
 import com.android.settings.R;
 import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
 import com.android.settings.deviceinfo.PhoneNumberUtil;
+import com.android.settingslib.qrcode.QrCodeGenerator;
 
 import java.util.Arrays;
 import java.util.stream.IntStream;
@@ -80,6 +84,7 @@
         Dialog dlg = builder.setView(mRootView).create();
         dlg.getWindow().setFlags(WindowManager.LayoutParams.FLAG_SECURE,
                 WindowManager.LayoutParams.FLAG_SECURE);
+        dlg.setOnShowListener(mController);
 
         return dlg;
     }
@@ -107,6 +112,10 @@
             .sorted().toArray();
 
     public void setText(int viewId, CharSequence text) {
+        setText(viewId, text, true);
+    }
+
+    public void setText(int viewId, CharSequence text, boolean enableCopy) {
         final TextView textView = mRootView.findViewById(viewId);
         if (textView == null) {
             return;
@@ -117,5 +126,21 @@
             text = PhoneNumberUtil.expandByTts(text);
         }
         textView.setText(text);
+        textView.setTextIsSelectable(enableCopy);
+    }
+
+    public void setQrCode(int viewId, String qrcodeText) {
+        ImageView qrCodeView = (ImageView) mRootView.findViewById(viewId);
+
+        Bitmap qrCodeBitmap = null;
+        try {
+            qrCodeBitmap = QrCodeGenerator.encodeQrCode(qrcodeText, qrCodeView.getWidth());
+        } catch (Exception exception) {
+            Log.w(TAG, "Error when presenting QR code in + " + qrCodeView, exception);
+        }
+        if (qrCodeBitmap == null) {
+            return;
+        }
+        qrCodeView.setImageBitmap(qrCodeBitmap);
     }
 }
diff --git a/src/com/android/settings/deviceinfo/simstatus/SimStatusPreferenceController.java b/src/com/android/settings/deviceinfo/simstatus/SimStatusPreferenceController.java
index b75853d..16f04df 100644
--- a/src/com/android/settings/deviceinfo/simstatus/SimStatusPreferenceController.java
+++ b/src/com/android/settings/deviceinfo/simstatus/SimStatusPreferenceController.java
@@ -31,6 +31,7 @@
 import com.android.settings.core.BasePreferenceController;
 import com.android.settings.network.SubscriptionUtil;
 import com.android.settingslib.Utils;
+import com.android.settingslib.search.SearchIndexableRaw;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -159,4 +160,28 @@
     Preference createNewPreference(Context context) {
         return new Preference(context);
     }
+
+    @Override
+    public void updateDynamicRawDataToIndex(List<SearchIndexableRaw> rawData) {
+        int simSlot = getSimSlotIndex();
+        SubscriptionInfo subInfo = getSubscriptionInfo(simSlot);
+        if (subInfo == null) {
+            /**
+             * Only add to search when SIM is active
+             * (presented in SIM Slot Status as availavle.)
+             */
+            return;
+        }
+
+        /* Have different search keywork when comes to eSIM */
+        int keywordId = subInfo.isEmbedded() ?
+                R.string.keywords_sim_status_esim : R.string.keywords_sim_status;
+
+        SearchIndexableRaw data = new SearchIndexableRaw(mContext);
+        data.key = getPreferenceKey();
+        data.title = getPreferenceTitle(simSlot);
+        data.screenTitle = mContext.getString(R.string.about_settings);
+        data.keywords = mContext.getString(keywordId).toString();
+        rawData.add(data);
+    }
 }
diff --git a/src/com/android/settings/fuelgauge/PowerUsageFeatureProvider.java b/src/com/android/settings/fuelgauge/PowerUsageFeatureProvider.java
index b17afa5..71d56ae 100644
--- a/src/com/android/settings/fuelgauge/PowerUsageFeatureProvider.java
+++ b/src/com/android/settings/fuelgauge/PowerUsageFeatureProvider.java
@@ -30,6 +30,11 @@
 public interface PowerUsageFeatureProvider {
 
     /**
+     * Check whether the battery usage button is enabled in the battery page
+     */
+    boolean isBatteryUsageEnabled(Context context);
+
+    /**
      * Check whether location setting is enabled
      */
     boolean isLocationSettingEnabled(String[] packages);
diff --git a/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImpl.java b/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImpl.java
index 856f86a..932b35d 100644
--- a/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImpl.java
+++ b/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImpl.java
@@ -66,6 +66,11 @@
     }
 
     @Override
+    public boolean isBatteryUsageEnabled(Context context) {
+        return true;
+    }
+
+    @Override
     public boolean isLocationSettingEnabled(String[] packages) {
         return false;
     }
diff --git a/src/com/android/settings/fuelgauge/batteryusage/DataProcessor.java b/src/com/android/settings/fuelgauge/batteryusage/DataProcessor.java
index 0f02d1c..ff139f0 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/DataProcessor.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/DataProcessor.java
@@ -84,8 +84,6 @@
             new BatteryHistEntry(new ContentValues());
 
     @VisibleForTesting
-    static final double PERCENTAGE_OF_TOTAL_THRESHOLD = 1f;
-    @VisibleForTesting
     static final int SELECTED_INDEX_ALL = BatteryChartViewModel.SELECTED_INDEX_ALL;
     @VisibleForTesting
     static final String CURRENT_TIME_BATTERY_HISTORY_PLACEHOLDER =
@@ -441,7 +439,7 @@
         insertAllUsageDiffData(resultMap);
         // Compute the apps number before purge. Must put before purgeLowPercentageAndFakeData.
         final int countOfAppBeforePurge = getCountOfApps(resultMap);
-        purgeLowPercentageAndFakeData(context, resultMap);
+        purgeFakeAndHiddenPackages(context, resultMap);
         // Compute the apps number after purge. Must put after purgeLowPercentageAndFakeData.
         final int countOfAppAfterPurge = getCountOfApps(resultMap);
         if (!isUsageMapValid(resultMap, hourlyBatteryLevelsPerDay)) {
@@ -536,7 +534,7 @@
 
         // Compute the apps number before purge. Must put before purgeLowPercentageAndFakeData.
         final int countOfAppBeforePurge = getCountOfApps(resultMap);
-        purgeLowPercentageAndFakeData(context, resultMap);
+        purgeFakeAndHiddenPackages(context, resultMap);
         // Compute the apps number after purge. Must put after purgeLowPercentageAndFakeData.
         final int countOfAppAfterPurge = getCountOfApps(resultMap);
 
@@ -1122,7 +1120,7 @@
     }
 
     // Removes low percentage data and fake usage data, which will be zero value.
-    private static void purgeLowPercentageAndFakeData(
+    private static void purgeFakeAndHiddenPackages(
             final Context context,
             final Map<Integer, Map<Integer, BatteryDiffData>> resultMap) {
         final Set<CharSequence> backgroundUsageTimeHideList =
@@ -1139,17 +1137,17 @@
                 if (diffEntryLists == null) {
                     return;
                 }
-                purgeLowPercentageAndFakeData(
+                purgeFakeAndHiddenPackages(
                         diffEntryLists.getAppDiffEntryList(), backgroundUsageTimeHideList,
                         notAllowShowEntryPackages);
-                purgeLowPercentageAndFakeData(
+                purgeFakeAndHiddenPackages(
                         diffEntryLists.getSystemDiffEntryList(), backgroundUsageTimeHideList,
                         notAllowShowEntryPackages);
             });
         });
     }
 
-    private static void purgeLowPercentageAndFakeData(
+    private static void purgeFakeAndHiddenPackages(
             final List<BatteryDiffEntry> entries,
             final Set<CharSequence> backgroundUsageTimeHideList,
             final CharSequence[] notAllowShowEntryPackages) {
@@ -1157,8 +1155,7 @@
         while (iterator.hasNext()) {
             final BatteryDiffEntry entry = iterator.next();
             final String packageName = entry.getPackageName();
-            if (entry.getPercentOfTotal() < PERCENTAGE_OF_TOTAL_THRESHOLD
-                    || ConvertUtils.FAKE_PACKAGE_NAME.equals(packageName)
+            if (ConvertUtils.FAKE_PACKAGE_NAME.equals(packageName)
                     || contains(packageName, notAllowShowEntryPackages)) {
                 iterator.remove();
             }
diff --git a/src/com/android/settings/fuelgauge/batteryusage/PowerGaugePreference.java b/src/com/android/settings/fuelgauge/batteryusage/PowerGaugePreference.java
index 5a4f672..4ab1f42 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/PowerGaugePreference.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/PowerGaugePreference.java
@@ -36,6 +36,8 @@
  */
 public class PowerGaugePreference extends AppPreference {
 
+    private static final double PERCENTAGE_TO_SHOW_THRESHOLD = 1f;
+
     private BatteryEntry mInfo;
     private BatteryDiffEntry mBatteryDiffEntry;
     private CharSequence mContentDescription;
@@ -75,7 +77,8 @@
 
     /** Sets the percent of total. */
     public void setPercent(double percentOfTotal) {
-        mProgress = Utils.formatPercentage(percentOfTotal, true);
+        mProgress = percentOfTotal < PERCENTAGE_TO_SHOW_THRESHOLD
+                ? "-" : Utils.formatPercentage(percentOfTotal, true);
         notifyChanged();
     }
 
diff --git a/src/com/android/settings/fuelgauge/batteryusage/PowerUsageSummary.java b/src/com/android/settings/fuelgauge/batteryusage/PowerUsageSummary.java
index f266492..dea2431 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/PowerUsageSummary.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/PowerUsageSummary.java
@@ -255,6 +255,8 @@
     void initPreference() {
         mBatteryUsagePreference = findPreference(KEY_BATTERY_USAGE);
         mBatteryUsagePreference.setSummary(getString(R.string.advanced_battery_preference_summary));
+        mBatteryUsagePreference.setVisible(
+                mPowerFeatureProvider.isBatteryUsageEnabled(getContext()));
 
         mHelpPreference = findPreference(KEY_BATTERY_ERROR);
         mHelpPreference.setVisible(false);
diff --git a/src/com/android/settings/homepage/TopLevelHighlightMixin.java b/src/com/android/settings/homepage/TopLevelHighlightMixin.java
index f361ed6..d9e646f 100644
--- a/src/com/android/settings/homepage/TopLevelHighlightMixin.java
+++ b/src/com/android/settings/homepage/TopLevelHighlightMixin.java
@@ -116,9 +116,14 @@
         }
 
         Log.d(TAG, "onCreateAdapter, pref key: " + mCurrentKey);
+
+        // Remove the animator to avoid a RecyclerView crash.
+        RecyclerView recyclerView = topLevelSettings.getListView();
+        recyclerView.setItemAnimator(null);
+
         mTopLevelAdapter = new HighlightableTopLevelPreferenceAdapter(
                 (SettingsHomepageActivity) topLevelSettings.getActivity(), preferenceScreen,
-                topLevelSettings.getListView(), mCurrentKey, scrollNeeded);
+                recyclerView, mCurrentKey, scrollNeeded);
         return mTopLevelAdapter;
     }
 
diff --git a/src/com/android/settings/inputmethod/KeyboardLayoutPickerController.java b/src/com/android/settings/inputmethod/KeyboardLayoutPickerController.java
index 4ac52bc..c6a0d75 100644
--- a/src/com/android/settings/inputmethod/KeyboardLayoutPickerController.java
+++ b/src/com/android/settings/inputmethod/KeyboardLayoutPickerController.java
@@ -154,6 +154,7 @@
             final SwitchPreference pref = new SwitchPreference(mScreen.getContext());
             pref.setTitle(layout.getLabel());
             pref.setSummary(layout.getCollection());
+            // TODO: Waiting for new API to use a prefix with special number to setKey
             pref.setKey(layout.getDescriptor());
             mScreen.addPreference(pref);
             mPreferenceMap.put(pref, layout);
diff --git a/src/com/android/settings/inputmethod/KeyboardLayoutPreference.java b/src/com/android/settings/inputmethod/KeyboardLayoutPreference.java
new file mode 100644
index 0000000..f9f858b
--- /dev/null
+++ b/src/com/android/settings/inputmethod/KeyboardLayoutPreference.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.inputmethod;
+
+import android.content.Context;
+import android.view.View;
+import android.widget.ImageView;
+
+import androidx.preference.Preference;
+import androidx.preference.PreferenceViewHolder;
+
+import com.android.settings.R;
+
+public class KeyboardLayoutPreference extends Preference {
+
+    private ImageView mCheckIcon;
+    private boolean mIsMark;
+
+    public KeyboardLayoutPreference(Context context, String layoutName, boolean defaultMark) {
+        super(context);
+        setWidgetLayoutResource(R.layout.preference_check_icon);
+        setTitle(layoutName);
+        mIsMark = defaultMark;
+    }
+
+    @Override
+    public void onBindViewHolder(PreferenceViewHolder holder) {
+        super.onBindViewHolder(holder);
+        mCheckIcon = (ImageView) holder.findViewById(R.id.keyboard_check_icon);
+        setCheckMark(mIsMark);
+    }
+
+    public void setCheckMark(boolean isMark) {
+        if (mCheckIcon != null) {
+            mCheckIcon.setVisibility(isMark ? View.VISIBLE : View.INVISIBLE);
+            mIsMark = isMark;
+        }
+    }
+}
diff --git a/src/com/android/settings/inputmethod/KeyboardPreferenceController.java b/src/com/android/settings/inputmethod/KeyboardPreferenceController.java
index 75351b1..adabec5 100644
--- a/src/com/android/settings/inputmethod/KeyboardPreferenceController.java
+++ b/src/com/android/settings/inputmethod/KeyboardPreferenceController.java
@@ -78,9 +78,9 @@
 
     @Override
     public int getAvailabilityStatus() {
-        boolean isFeatureOn = FeatureFlagUtils
-                .isEnabled(mContext, FeatureFlagUtils.SETTINGS_NEW_KEYBOARD_UI);
-        return isFeatureOn ? AVAILABLE : CONDITIONALLY_UNAVAILABLE;
+        return FeatureFlagUtils.isEnabled(mContext, FeatureFlagUtils.SETTINGS_NEW_KEYBOARD_UI)
+                ? AVAILABLE
+                : CONDITIONALLY_UNAVAILABLE;
     }
 
     private void updateSummary() {
diff --git a/src/com/android/settings/inputmethod/KeyboardSettingsPreferenceController.java b/src/com/android/settings/inputmethod/KeyboardSettingsPreferenceController.java
new file mode 100644
index 0000000..3b86c3f
--- /dev/null
+++ b/src/com/android/settings/inputmethod/KeyboardSettingsPreferenceController.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.inputmethod;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.Intent;
+import android.provider.Settings;
+import android.util.FeatureFlagUtils;
+
+import androidx.annotation.NonNull;
+import androidx.preference.Preference;
+
+import com.android.settings.Settings.PhysicalKeyboardActivity;
+import com.android.settings.core.BasePreferenceController;
+import com.android.settings.inputmethod.PhysicalKeyboardFragment.HardKeyboardDeviceInfo;
+import com.android.settingslib.bluetooth.CachedBluetoothDevice;
+
+import java.util.List;
+
+public class KeyboardSettingsPreferenceController extends BasePreferenceController {
+
+    private Context mContext;
+    private CachedBluetoothDevice mCachedDevice;
+    private Activity mActivity;
+
+    public KeyboardSettingsPreferenceController(Context context, String key) {
+        super(context, key);
+        mContext = context;
+    }
+
+    public void init(@NonNull CachedBluetoothDevice cachedDevice, @NonNull Activity activity) {
+        mCachedDevice = cachedDevice;
+        mActivity = activity;
+    }
+
+    @Override
+    public boolean handlePreferenceTreeClick(Preference preference) {
+        final Intent intent = new Intent(Settings.ACTION_HARD_KEYBOARD_SETTINGS);
+        intent.setClass(mContext, PhysicalKeyboardActivity.class);
+        intent.putExtra(PhysicalKeyboardFragment.EXTRA_BT_ADDRESS, mCachedDevice.getAddress());
+        mActivity.startActivityForResult(intent, 0);
+        return true;
+    }
+
+    @Override
+    public int getAvailabilityStatus() {
+        final List<HardKeyboardDeviceInfo> newHardKeyboards =
+                PhysicalKeyboardFragment.getHardKeyboards(mContext);
+        if (FeatureFlagUtils.isEnabled(mContext, FeatureFlagUtils.SETTINGS_NEW_KEYBOARD_UI)
+                && !newHardKeyboards.isEmpty()) {
+            for (HardKeyboardDeviceInfo hardKeyboardDeviceInfo : newHardKeyboards) {
+                if (mCachedDevice.getAddress() != null
+                        && hardKeyboardDeviceInfo.mBluetoothAddress != null
+                        && mCachedDevice.getAddress().equals(
+                                hardKeyboardDeviceInfo.mBluetoothAddress)) {
+                    return AVAILABLE;
+                }
+            }
+        }
+        return CONDITIONALLY_UNAVAILABLE;
+    }
+}
diff --git a/src/com/android/settings/inputmethod/NewKeyboardLayoutEnabledLocalesFragment.java b/src/com/android/settings/inputmethod/NewKeyboardLayoutEnabledLocalesFragment.java
new file mode 100644
index 0000000..5c0f88f
--- /dev/null
+++ b/src/com/android/settings/inputmethod/NewKeyboardLayoutEnabledLocalesFragment.java
@@ -0,0 +1,165 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.inputmethod;
+
+import android.app.settings.SettingsEnums;
+import android.content.Context;
+import android.hardware.input.InputDeviceIdentifier;
+import android.hardware.input.InputManager;
+import android.os.Bundle;
+import android.view.InputDevice;
+
+import androidx.preference.Preference;
+import androidx.preference.PreferenceCategory;
+
+import com.android.settings.R;
+import com.android.settings.core.SubSettingLauncher;
+import com.android.settings.dashboard.DashboardFragment;
+
+public class NewKeyboardLayoutEnabledLocalesFragment extends DashboardFragment
+        implements InputManager.InputDeviceListener {
+
+    private static final String TAG = "NewKeyboardLayoutEnabledLocalesFragment";
+    private static final String PREF_KEY_ENABLED_LOCALES = "enabled_locales_keyboard_layout";
+
+    static final String EXTRA_KEYBOARD_DEVICE_NAME = "extra_keyboard_device_name";
+
+    private InputManager mIm;
+    private InputDeviceIdentifier mInputDeviceIdentifier;
+    private int mInputDeviceId;
+    private Context mContext;
+
+    @Override
+    public void onActivityCreated(final Bundle icicle) {
+        super.onActivityCreated(icicle);
+
+        Bundle arguments = getArguments();
+        final String title = arguments.getString(EXTRA_KEYBOARD_DEVICE_NAME);
+        mInputDeviceIdentifier = arguments.getParcelable(
+                KeyboardLayoutPickerFragment.EXTRA_INPUT_DEVICE_IDENTIFIER);
+        getActivity().setTitle(title);
+        final PreferenceCategory category = findPreference(PREF_KEY_ENABLED_LOCALES);
+
+        // TODO(b/252816846): Need APIs to get the available keyboards from Inputmanager.
+        // For example: InputMethodManager.getEnabledInputMethodLocales()
+        //              InputManager.getKeyboardLayoutForLocale()
+        // Hardcode the default value for demo purpose
+        String[] keyboardLanguages = {"English (US)", "German (Germany)", "Spanish (Spain)"};
+        String[] keyboardLayouts = {"English (US)", "German", "Spanish"};
+        for (int i = 0; i < keyboardLanguages.length; i++) {
+            final Preference pref = new Preference(mContext);
+            String key = "keyboard_language_label_" + String.valueOf(i);
+            String keyboardLanguageTitle = keyboardLanguages[i];
+            String keyboardLanguageSummary = keyboardLayouts[i];
+            // TODO: Waiting for new API to use a prefix with special number to setKey
+            pref.setKey(key);
+            pref.setTitle(keyboardLanguageTitle);
+            pref.setSummary(keyboardLanguageSummary);
+            pref.setOnPreferenceClickListener(
+                    preference -> {
+                        showKeyboardLayoutPicker(
+                                keyboardLanguageTitle,
+                                keyboardLanguageSummary,
+                                mInputDeviceIdentifier);
+                        return true;
+                    });
+            category.addPreference(pref);
+        }
+    }
+
+    @Override
+    public void onInputDeviceAdded(int deviceId) {
+        // Do nothing.
+    }
+
+    @Override
+    public void onInputDeviceRemoved(int deviceId) {
+        if (mInputDeviceId >= 0 && deviceId == mInputDeviceId) {
+            getActivity().finish();
+        }
+    }
+
+    @Override
+    public void onInputDeviceChanged(int deviceId) {
+        if (mInputDeviceId >= 0 && deviceId == mInputDeviceId) {
+            // TODO(b/252816846): Need APIs to update the available keyboards.
+        }
+    }
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        mContext = getContext();
+        mIm = mContext.getSystemService(InputManager.class);
+        mInputDeviceId = -1;
+    }
+
+    @Override
+    public void onStart() {
+        super.onStart();
+        mIm.registerInputDeviceListener(this, null);
+        final InputDevice inputDevice =
+                mIm.getInputDeviceByDescriptor(mInputDeviceIdentifier.getDescriptor());
+        if (inputDevice == null) {
+            getActivity().finish();
+            return;
+        }
+        mInputDeviceId = inputDevice.getId();
+    }
+
+    @Override
+    public void onStop() {
+        super.onStop();
+        mIm.unregisterInputDeviceListener(this);
+        mInputDeviceId = -1;
+    }
+
+    @Override
+    public void onResume() {
+        super.onResume();
+        // TODO(b/252816846): Need APIs to get the available keyboards from Inputmanager.
+    }
+
+    @Override
+    protected String getLogTag() {
+        return TAG;
+    }
+
+    @Override
+    public int getMetricsCategory() {
+        return SettingsEnums.SETTINGS_KEYBOARDS_ENABLED_LOCALES;
+    }
+
+    @Override
+    protected int getPreferenceScreenResId() {
+        return R.xml.keyboard_settings_enabled_locales_list;
+    }
+
+    private void showKeyboardLayoutPicker(String language, String layout,
+            InputDeviceIdentifier inputDeviceIdentifier) {
+        Bundle arguments = new Bundle();
+        arguments.putParcelable(KeyboardLayoutPickerFragment.EXTRA_INPUT_DEVICE_IDENTIFIER,
+                inputDeviceIdentifier);
+        arguments.putString(NewKeyboardLayoutPickerFragment.EXTRA_TITLE, language);
+        arguments.putString(NewKeyboardLayoutPickerFragment.EXTRA_KEYBOARD_LAYOUT, layout);
+        new SubSettingLauncher(mContext)
+                .setSourceMetricsCategory(getMetricsCategory())
+                .setDestination(NewKeyboardLayoutPickerFragment.class.getName())
+                .setArguments(arguments)
+                .launch();
+    }
+}
diff --git a/src/com/android/settings/inputmethod/NewKeyboardLayoutPickerContent.java b/src/com/android/settings/inputmethod/NewKeyboardLayoutPickerContent.java
new file mode 100644
index 0000000..dc94306
--- /dev/null
+++ b/src/com/android/settings/inputmethod/NewKeyboardLayoutPickerContent.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.inputmethod;
+
+import android.app.settings.SettingsEnums;
+import android.content.Context;
+import android.hardware.input.InputDeviceIdentifier;
+import android.os.Bundle;
+
+import com.android.settings.R;
+import com.android.settings.dashboard.DashboardFragment;
+
+public class NewKeyboardLayoutPickerContent extends DashboardFragment {
+
+    private static final String TAG = "KeyboardLayoutPicker";
+
+    static final String EXTRA_TITLE = "keyboard_layout_picker_title";
+    static final String EXTRA_KEYBOARD_LAYOUT = "keyboard_layout";
+
+    /**
+     * Intent extra: The input device descriptor of the keyboard whose keyboard
+     * layout is to be changed.
+     */
+    public static final String EXTRA_INPUT_DEVICE_IDENTIFIER = "input_device_identifier";
+
+    @Override
+    public void onAttach(Context context) {
+        super.onAttach(context);
+
+        Bundle arguments = getArguments();
+        final String title = arguments.getString(EXTRA_TITLE);
+        final String layout = arguments.getString(EXTRA_KEYBOARD_LAYOUT);
+        final InputDeviceIdentifier inputDeviceIdentifier =
+                arguments.getParcelable(EXTRA_INPUT_DEVICE_IDENTIFIER);
+
+        if (inputDeviceIdentifier == null) {
+            getActivity().finish();
+        }
+        getActivity().setTitle(title);
+        use(NewKeyboardLayoutPickerController.class).initialize(this /*parent*/,
+                inputDeviceIdentifier, layout);
+    }
+
+    @Override
+    public int getMetricsCategory() {
+        // TODO: add new SettingsEnums SETTINGS_KEYBOARDS_LAYOUT_PICKER_CONTENT
+        return SettingsEnums.SETTINGS_KEYBOARDS_LAYOUT_PICKER;
+    }
+
+    @Override
+    protected String getLogTag() {
+        return TAG;
+    }
+
+    protected int getPreferenceScreenResId() {
+        return R.xml.new_keyboard_layout_picker_fragment;
+    }
+}
diff --git a/src/com/android/settings/inputmethod/NewKeyboardLayoutPickerController.java b/src/com/android/settings/inputmethod/NewKeyboardLayoutPickerController.java
new file mode 100644
index 0000000..4a598d5
--- /dev/null
+++ b/src/com/android/settings/inputmethod/NewKeyboardLayoutPickerController.java
@@ -0,0 +1,156 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.inputmethod;
+
+import android.content.Context;
+import android.hardware.input.InputDeviceIdentifier;
+import android.hardware.input.InputManager;
+import android.hardware.input.KeyboardLayout;
+import android.view.InputDevice;
+
+import androidx.fragment.app.Fragment;
+import androidx.preference.Preference;
+import androidx.preference.PreferenceScreen;
+
+import com.android.settings.core.BasePreferenceController;
+import com.android.settingslib.core.lifecycle.LifecycleObserver;
+import com.android.settingslib.core.lifecycle.events.OnStart;
+import com.android.settingslib.core.lifecycle.events.OnStop;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+
+public class NewKeyboardLayoutPickerController extends BasePreferenceController implements
+        InputManager.InputDeviceListener, LifecycleObserver, OnStart, OnStop {
+    private final InputManager mIm;
+    private final Map<KeyboardLayoutPreference, KeyboardLayout> mPreferenceMap;
+
+    private Fragment mParent;
+    private int mInputDeviceId;
+    private InputDeviceIdentifier mInputDeviceIdentifier;
+    private KeyboardLayout[] mKeyboardLayouts;
+    private PreferenceScreen mScreen;
+    private String mPreviousSelection;
+    private String mLayout;
+
+    public NewKeyboardLayoutPickerController(Context context, String key) {
+        super(context, key);
+        mIm = context.getSystemService(InputManager.class);
+        mInputDeviceId = -1;
+        mPreferenceMap = new HashMap<>();
+    }
+
+    public void initialize(Fragment parent, InputDeviceIdentifier inputDeviceIdentifier,
+            String layout) {
+        mLayout = layout;
+        mParent = parent;
+        mInputDeviceIdentifier = inputDeviceIdentifier;
+        mKeyboardLayouts = mIm.getKeyboardLayoutsForInputDevice(mInputDeviceIdentifier);
+        Arrays.sort(mKeyboardLayouts);
+    }
+
+    @Override
+    public void onStart() {
+        mIm.registerInputDeviceListener(this, null);
+        final InputDevice inputDevice =
+                mIm.getInputDeviceByDescriptor(mInputDeviceIdentifier.getDescriptor());
+        if (inputDevice == null) {
+            mParent.getActivity().finish();
+            return;
+        }
+        mInputDeviceId = inputDevice.getId();
+    }
+
+    @Override
+    public void onStop() {
+        mIm.unregisterInputDeviceListener(this);
+        mInputDeviceId = -1;
+    }
+
+    @Override
+    public void displayPreference(PreferenceScreen screen) {
+        super.displayPreference(screen);
+        mScreen = screen;
+        createPreferenceHierarchy();
+    }
+
+    @Override
+    public int getAvailabilityStatus() {
+        return AVAILABLE;
+    }
+
+    @Override
+    public boolean handlePreferenceTreeClick(Preference preference) {
+
+        if (!(preference instanceof KeyboardLayoutPreference)) {
+            return false;
+        }
+
+        final KeyboardLayoutPreference pref = (KeyboardLayoutPreference) preference;
+        // TODO(b/259530132): Need APIs to update the available keyboards for input device.
+        // For example:
+        // inputManager.setCurrentKeyboardLayoutForInputDevice(
+        //            InputDevice..., Userid..., ImeSubType ..., String keyboardLayoutDescriptor)
+        if (mPreviousSelection != null && !mPreviousSelection.equals(preference.getKey())) {
+            KeyboardLayoutPreference preSelectedPref = mScreen.findPreference(mPreviousSelection);
+            pref.setCheckMark(true);
+            preSelectedPref.setCheckMark(false);
+        }
+        mPreviousSelection = preference.getKey();
+        return true;
+    }
+
+    @Override
+    public void onInputDeviceAdded(int deviceId) {
+        // Do nothing.
+    }
+
+    @Override
+    public void onInputDeviceRemoved(int deviceId) {
+        if (mInputDeviceId >= 0 && deviceId == mInputDeviceId) {
+            mParent.getActivity().finish();
+        }
+    }
+
+    @Override
+    public void onInputDeviceChanged(int deviceId) {
+        if (mInputDeviceId >= 0 && deviceId == mInputDeviceId) {
+            updateCheckedState();
+        }
+    }
+
+    private void updateCheckedState() {
+        // TODO(b/259530132): Need API to update the keyboard language layout list.
+    }
+
+    private void createPreferenceHierarchy() {
+        for (KeyboardLayout layout : mKeyboardLayouts) {
+            final KeyboardLayoutPreference pref;
+            if (mLayout.equals(layout.getLabel())) {
+                pref = new KeyboardLayoutPreference(mScreen.getContext(), layout.getLabel(), true);
+                mPreviousSelection = layout.getLabel();
+            } else {
+                pref = new KeyboardLayoutPreference(mScreen.getContext(), layout.getLabel(), false);
+            }
+            // TODO: Waiting for new API to use a prefix with special number to setKey
+            pref.setKey(layout.getLabel());
+            mScreen.addPreference(pref);
+            mPreferenceMap.put(pref, layout);
+        }
+    }
+}
diff --git a/src/com/android/settings/inputmethod/NewKeyboardLayoutPickerFragment.java b/src/com/android/settings/inputmethod/NewKeyboardLayoutPickerFragment.java
new file mode 100644
index 0000000..c2f41a2
--- /dev/null
+++ b/src/com/android/settings/inputmethod/NewKeyboardLayoutPickerFragment.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.inputmethod;
+
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import androidx.fragment.app.Fragment;
+
+import com.android.settings.R;
+
+public class NewKeyboardLayoutPickerFragment extends Fragment {
+
+    static final String EXTRA_TITLE = "keyboard_layout_picker_title";
+    static final String EXTRA_KEYBOARD_LAYOUT = "keyboard_layout";
+
+    /**
+     * Intent extra: The input device descriptor of the keyboard whose keyboard
+     * layout is to be changed.
+     */
+    public static final String EXTRA_INPUT_DEVICE_IDENTIFIER = "input_device_identifier";
+
+    private ViewGroup mFragmentView;
+
+    @Override
+    public View onCreateView(LayoutInflater inflater, ViewGroup container,
+            Bundle savedInstanceState) {
+
+        mFragmentView = (ViewGroup) inflater.inflate(
+                R.layout.keyboard_layout_picker, container, false);
+        getActivity().getSupportFragmentManager()
+                .beginTransaction()
+                .replace(R.id.keyboard_layout_title, new NewKeyboardLayoutPickerTitle())
+                .commit();
+
+        NewKeyboardLayoutPickerContent fragment = new NewKeyboardLayoutPickerContent();
+        fragment.setArguments(getArguments());
+        getActivity().getSupportFragmentManager()
+                .beginTransaction()
+                .replace(R.id.keyboard_layouts, fragment)
+                .commit();
+
+        return mFragmentView;
+    }
+}
diff --git a/src/com/android/settings/inputmethod/NewKeyboardLayoutPickerTitle.java b/src/com/android/settings/inputmethod/NewKeyboardLayoutPickerTitle.java
new file mode 100644
index 0000000..abcad27
--- /dev/null
+++ b/src/com/android/settings/inputmethod/NewKeyboardLayoutPickerTitle.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.inputmethod;
+
+import android.app.settings.SettingsEnums;
+import android.content.Context;
+import android.os.Bundle;
+
+import com.android.settings.R;
+import com.android.settings.SettingsPreferenceFragment;
+import com.android.settings.search.BaseSearchIndexProvider;
+
+public class NewKeyboardLayoutPickerTitle extends SettingsPreferenceFragment {
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        addPreferencesFromResource(R.xml.new_keyboard_layout_picker_title);
+    }
+
+    @Override
+    public int getMetricsCategory() {
+        // TODO: add new SettingsEnums SETTINGS_KEYBOARDS_LAYOUT_PICKER_TITLE
+        return SettingsEnums.SETTINGS_KEYBOARDS_LAYOUT_PICKER;
+    }
+
+    public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
+            new BaseSearchIndexProvider(R.xml.new_keyboard_layout_picker_title) {
+                @Override
+                protected boolean isPageSearchEnabled(Context context) {
+                    return false;
+                }
+            };
+}
diff --git a/src/com/android/settings/inputmethod/PhysicalKeyboardFragment.java b/src/com/android/settings/inputmethod/PhysicalKeyboardFragment.java
index d7a208c..38ea840 100644
--- a/src/com/android/settings/inputmethod/PhysicalKeyboardFragment.java
+++ b/src/com/android/settings/inputmethod/PhysicalKeyboardFragment.java
@@ -33,6 +33,7 @@
 import android.provider.SearchIndexableResource;
 import android.provider.Settings.Secure;
 import android.text.TextUtils;
+import android.util.FeatureFlagUtils;
 import android.view.InputDevice;
 
 import androidx.preference.Preference;
@@ -45,6 +46,7 @@
 import com.android.settings.R;
 import com.android.settings.Settings;
 import com.android.settings.SettingsPreferenceFragment;
+import com.android.settings.core.SubSettingLauncher;
 import com.android.settings.search.BaseSearchIndexProvider;
 import com.android.settingslib.search.SearchIndexable;
 import com.android.settingslib.utils.ThreadUtils;
@@ -52,7 +54,9 @@
 import java.text.Collator;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 import java.util.Objects;
 
 @SearchIndexable
@@ -60,7 +64,7 @@
         implements InputManager.InputDeviceListener,
         KeyboardLayoutDialogFragment.OnSetupKeyboardLayoutsListener {
 
-    private static final String KEYBOARD_ASSISTANCE_CATEGORY = "keyboard_assistance_category";
+    private static final String KEYBOARD_OPTIONS_CATEGORY = "keyboard_options_category";
     private static final String SHOW_VIRTUAL_KEYBOARD_SWITCH = "show_virtual_keyboard_switch";
     private static final String KEYBOARD_SHORTCUTS_HELPER = "keyboard_shortcuts_helper";
 
@@ -74,17 +78,25 @@
     private SwitchPreference mShowVirtualKeyboardSwitch;
 
     private Intent mIntentWaitingForResult;
+    private boolean mIsNewKeyboardSettings;
+
+    static final String EXTRA_BT_ADDRESS = "extra_bt_address";
+    private String mBluetoothAddress;
 
     @Override
     public void onCreatePreferences(Bundle bundle, String s) {
         Activity activity = Preconditions.checkNotNull(getActivity());
+        mBluetoothAddress = activity.getIntent().getStringExtra(EXTRA_BT_ADDRESS);
         addPreferencesFromResource(R.xml.physical_keyboard_settings);
         mIm = Preconditions.checkNotNull(activity.getSystemService(InputManager.class));
         mKeyboardAssistanceCategory = Preconditions.checkNotNull(
-                (PreferenceCategory) findPreference(KEYBOARD_ASSISTANCE_CATEGORY));
+                (PreferenceCategory) findPreference(KEYBOARD_OPTIONS_CATEGORY));
         mShowVirtualKeyboardSwitch = Preconditions.checkNotNull(
                 (SwitchPreference) mKeyboardAssistanceCategory.findPreference(
                         SHOW_VIRTUAL_KEYBOARD_SWITCH));
+        mIsNewKeyboardSettings = FeatureFlagUtils.isEnabled(
+                getContext(), FeatureFlagUtils.SETTINGS_NEW_KEYBOARD_UI);
+        // TODO(b/247080921): Support shortcuts list & modifier keys
     }
 
     @Override
@@ -164,17 +176,55 @@
         preferenceScreen.addPreference(category);
 
         for (HardKeyboardDeviceInfo hardKeyboardDeviceInfo : newHardKeyboards) {
+
+            // if user go into this page from Connected devices entry, we should distinguish the
+            // user-selected keyboard from all enabled keyboards.
+            if (mBluetoothAddress != null
+                    && !mBluetoothAddress.equals(hardKeyboardDeviceInfo.mBluetoothAddress)) {
+                continue;
+            }
+
             // TODO(yukawa): Consider using com.android.settings.widget.GearPreference
             final Preference pref = new Preference(getPrefContext());
             pref.setTitle(hardKeyboardDeviceInfo.mDeviceName);
-            pref.setSummary(hardKeyboardDeviceInfo.mLayoutLabel);
-            pref.setOnPreferenceClickListener(preference -> {
-                showKeyboardLayoutDialog(hardKeyboardDeviceInfo.mDeviceIdentifier);
-                return true;
-            });
+            if (mIsNewKeyboardSettings) {
+                // TODO(b/252816846): Need InputMethodManager to provide the enabled locales.
+                // Hardcode Languages for demo until inputMethodManager provides the latest API.
+                // For example: InputMethodManager.getEnabledInputMethodLocales();
+                String[] keyboardLanguages =
+                        {"English (US)", "German (Germany)", "Spanish (Spain)"};
+                String[] keyboardLayouts = {"English (US)", "German", "Spanish"};
+                Map<String, String> keyboardMap = new HashMap<>();
+                for (int i = 0; i < keyboardLanguages.length; i++) {
+                    keyboardMap.put(keyboardLanguages[i], keyboardLayouts[i]);
+                }
+                if (!keyboardMap.isEmpty()) {
+                    String summary = keyboardMap.get(keyboardLanguages[0]);
+                    StringBuilder result = new StringBuilder(summary);
+                    for (int i = 1; i < keyboardLanguages.length; i++) {
+                        result.append(", ").append(keyboardMap.get(keyboardLanguages[i]));
+                    }
+                    pref.setSummary(result.toString());
+                } else {
+                    pref.setSummary(hardKeyboardDeviceInfo.mLayoutLabel);
+                }
+                pref.setOnPreferenceClickListener(
+                        preference -> {
+                            showEnabledLocalesKeyboardLayoutList(
+                                    hardKeyboardDeviceInfo.mDeviceName,
+                                    hardKeyboardDeviceInfo.mDeviceIdentifier);
+                            return true;
+                        });
+            } else {
+                pref.setSummary(hardKeyboardDeviceInfo.mLayoutLabel);
+                pref.setOnPreferenceClickListener(
+                        preference -> {
+                            showKeyboardLayoutDialog(hardKeyboardDeviceInfo.mDeviceIdentifier);
+                            return true;
+                        });
+            }
             category.addPreference(pref);
         }
-
         mKeyboardAssistanceCategory.setOrder(1);
         preferenceScreen.addPreference(mKeyboardAssistanceCategory);
         updateShowVirtualKeyboardSwitch();
@@ -187,6 +237,21 @@
         fragment.show(getActivity().getSupportFragmentManager(), "keyboardLayout");
     }
 
+    private void showEnabledLocalesKeyboardLayoutList(String keyboardName,
+            InputDeviceIdentifier inputDeviceIdentifier) {
+        // TODO(b/252816846: Need to get enabled locales.
+        Bundle arguments = new Bundle();
+        arguments.putParcelable(KeyboardLayoutPickerFragment.EXTRA_INPUT_DEVICE_IDENTIFIER,
+                inputDeviceIdentifier);
+        arguments.putString(NewKeyboardLayoutEnabledLocalesFragment.EXTRA_KEYBOARD_DEVICE_NAME,
+                keyboardName);
+        new SubSettingLauncher(getContext())
+                .setSourceMetricsCategory(getMetricsCategory())
+                .setDestination(NewKeyboardLayoutEnabledLocalesFragment.class.getName())
+                .setArguments(arguments)
+                .launch();
+    }
+
     private void registerShowVirtualKeyboardSettingsObserver() {
         unregisterShowVirtualKeyboardSettingsObserver();
         getActivity().getContentResolver().registerContentObserver(
@@ -277,7 +342,10 @@
                 continue;
             }
             keyboards.add(new HardKeyboardDeviceInfo(
-                    device.getName(), device.getIdentifier(), getLayoutLabel(device, context, im)));
+                    device.getName(),
+                    device.getIdentifier(),
+                    getLayoutLabel(device, context, im),
+                    device.getBluetoothAddress()));
         }
 
         // We intentionally don't reuse Comparator because Collator may not be thread-safe.
@@ -304,14 +372,18 @@
         public final InputDeviceIdentifier mDeviceIdentifier;
         @NonNull
         public final String mLayoutLabel;
+        @Nullable
+        public final String mBluetoothAddress;
 
         public HardKeyboardDeviceInfo(
                 @Nullable String deviceName,
                 @NonNull InputDeviceIdentifier deviceIdentifier,
-                @NonNull String layoutLabel) {
+                @NonNull String layoutLabel,
+                @Nullable String bluetoothAddress) {
             mDeviceName = TextUtils.emptyIfNull(deviceName);
             mDeviceIdentifier = deviceIdentifier;
             mLayoutLabel = layoutLabel;
+            mBluetoothAddress = bluetoothAddress;
         }
 
         @Override
@@ -331,6 +403,9 @@
             if (!TextUtils.equals(mLayoutLabel, that.mLayoutLabel)) {
                 return false;
             }
+            if (!TextUtils.equals(mBluetoothAddress, that.mBluetoothAddress)) {
+                return false;
+            }
 
             return true;
         }
diff --git a/src/com/android/settings/wifi/WifiUtils.java b/src/com/android/settings/wifi/WifiUtils.java
index a9010ac..68d8beb 100644
--- a/src/com/android/settings/wifi/WifiUtils.java
+++ b/src/com/android/settings/wifi/WifiUtils.java
@@ -96,7 +96,7 @@
      * @return true if Settings cannot modify the config due to lockDown.
      */
     public static boolean isNetworkLockedDown(Context context, WifiConfiguration config) {
-        if (config == null) {
+        if (context == null || config == null) {
             return false;
         }
 
diff --git a/tests/robotests/src/com/android/settings/accessibility/PreviewSizeSeekBarControllerTest.java b/tests/robotests/src/com/android/settings/accessibility/PreviewSizeSeekBarControllerTest.java
index fae61d6..31e0782 100644
--- a/tests/robotests/src/com/android/settings/accessibility/PreviewSizeSeekBarControllerTest.java
+++ b/tests/robotests/src/com/android/settings/accessibility/PreviewSizeSeekBarControllerTest.java
@@ -54,6 +54,9 @@
     @Mock
     private PreferenceScreen mPreferenceScreen;
 
+    @Mock
+    private PreviewSizeSeekBarController.ProgressInteractionListener mInteractionListener;
+
     @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
@@ -65,6 +68,8 @@
 
         mSeekBarPreference = spy(new LabeledSeekBarPreference(mContext, /* attrs= */ null));
         when(mPreferenceScreen.findPreference(anyString())).thenReturn(mSeekBarPreference);
+
+        mSeekBarController.setInteractionListener(mInteractionListener);
     }
 
     @Test
@@ -98,4 +103,12 @@
 
         assertThat(mSeekBarPreference.getProgress()).isEqualTo(defaultProgress);
     }
+
+    @Test
+    public void resetState_verifyOnProgressChanged() {
+        mSeekBarController.displayPreference(mPreferenceScreen);
+        mSeekBarController.resetState();
+
+        verify(mInteractionListener).onProgressChanged();
+    }
 }
diff --git a/tests/robotests/src/com/android/settings/accessibility/TextReadingPreferenceFragmentForSetupWizardTest.java b/tests/robotests/src/com/android/settings/accessibility/TextReadingPreferenceFragmentForSetupWizardTest.java
index 4813c80..7df24f1 100644
--- a/tests/robotests/src/com/android/settings/accessibility/TextReadingPreferenceFragmentForSetupWizardTest.java
+++ b/tests/robotests/src/com/android/settings/accessibility/TextReadingPreferenceFragmentForSetupWizardTest.java
@@ -20,6 +20,7 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.verify;
@@ -27,11 +28,13 @@
 import android.app.settings.SettingsEnums;
 import android.content.Context;
 
+import androidx.fragment.app.FragmentActivity;
 import androidx.test.core.app.ApplicationProvider;
 
 import com.android.settings.R;
 import com.android.settingslib.widget.LayoutPreference;
 
+import com.google.android.setupcompat.template.FooterBarMixin;
 import com.google.android.setupdesign.GlifPreferenceLayout;
 
 import org.junit.Before;
@@ -50,8 +53,16 @@
 
     @Rule
     public final MockitoRule mMockito = MockitoJUnit.rule();
+
     @Mock
     private GlifPreferenceLayout mGlifLayoutView;
+
+    @Mock
+    private FooterBarMixin mFooterBarMixin;
+
+    @Mock
+    private FragmentActivity mActivity;
+
     @Spy
     private final Context mContext = ApplicationProvider.getApplicationContext();
     private TextReadingPreferenceFragmentForSetupWizard mFragment;
@@ -61,13 +72,14 @@
         mFragment = spy(new TextReadingPreferenceFragmentForSetupWizard());
         final LayoutPreference resetPreference =
                 new LayoutPreference(mContext, R.layout.accessibility_text_reading_reset_button);
+        doReturn(mContext).when(mFragment).getContext();
         doReturn(resetPreference).when(mFragment).findPreference(RESET_KEY);
+        doReturn(mFooterBarMixin).when(mGlifLayoutView).getMixin(FooterBarMixin.class);
     }
 
     @Test
     public void setHeaderText_onViewCreated_verifyAction() {
         final String title = "title";
-        doReturn(mContext).when(mFragment).getContext();
         doReturn(title).when(mContext).getString(
                 R.string.accessibility_text_reading_options_title);
 
@@ -86,4 +98,21 @@
     public void getHelpResource_shouldNotHaveHelpResource() {
         assertThat(mFragment.getHelpResource()).isEqualTo(0);
     }
+
+    @Test
+    public void onViewCreated_verifySetSecondaryButton() {
+        mFragment.onViewCreated(mGlifLayoutView, null);
+
+        verify(mFooterBarMixin).setSecondaryButton(any());
+    }
+
+    @Test
+    public void onViewCreated_verifySetPrimaryButton() {
+        doReturn(mActivity).when(mFragment).getActivity();
+        doReturn("setupwizard").when(mActivity).getCallingPackage();
+
+        mFragment.onViewCreated(mGlifLayoutView, null);
+
+        verify(mFooterBarMixin).setPrimaryButton(any());
+    }
 }
diff --git a/tests/robotests/src/com/android/settings/accessibility/TextReadingResetControllerTest.java b/tests/robotests/src/com/android/settings/accessibility/TextReadingResetControllerTest.java
index 231c9ca..d5b138a 100644
--- a/tests/robotests/src/com/android/settings/accessibility/TextReadingResetControllerTest.java
+++ b/tests/robotests/src/com/android/settings/accessibility/TextReadingResetControllerTest.java
@@ -16,6 +16,8 @@
 
 package com.android.settings.accessibility;
 
+import static com.google.common.truth.Truth.assertThat;
+
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.verify;
@@ -70,4 +72,20 @@
 
         verify(mResetPreference).setOnResetClickListener(any(View.OnClickListener.class));
     }
+
+    @Test
+    public void setVisibleAsFalse_preferenceInvisible() {
+        mResetController.setVisible(false);
+        mResetController.displayPreference(mPreferenceScreen);
+
+        assertThat(mResetPreference.isVisible()).isFalse();
+    }
+
+    @Test
+    public void setVisibleAsTrue_preferenceVisible() {
+        mResetController.setVisible(true);
+        mResetController.displayPreference(mPreferenceScreen);
+
+        assertThat(mResetPreference.isVisible()).isTrue();
+    }
 }
diff --git a/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrollingTest.java b/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrollingTest.java
index f9d4445..596f3b2 100644
--- a/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrollingTest.java
+++ b/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrollingTest.java
@@ -18,7 +18,6 @@
 
 import static android.hardware.fingerprint.FingerprintSensorProperties.TYPE_POWER_BUTTON;
 import static android.hardware.fingerprint.FingerprintSensorProperties.TYPE_UDFPS_OPTICAL;
-import static android.hardware.fingerprint.FingerprintSensorProperties.TYPE_UNKNOWN;
 
 import static com.android.settings.biometrics.fingerprint.FingerprintEnrollEnrolling.KEY_STATE_PREVIOUS_ROTATION;
 import static com.android.settings.biometrics.fingerprint.FingerprintEnrollEnrolling.SFPS_STAGE_NO_ANIMATION;
@@ -31,7 +30,6 @@
 import static org.mockito.Mockito.anyString;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.eq;
-import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.times;
@@ -52,9 +50,6 @@
 import android.os.Vibrator;
 import android.view.Display;
 import android.view.Surface;
-import android.widget.TextView;
-
-import androidx.annotation.Nullable;
 
 import com.android.settings.R;
 import com.android.settings.testutils.FakeFeatureFactory;
@@ -106,42 +101,6 @@
     }
 
     @Test
-    public void fingerprintEnrollHelp_shouldShowHelpText() {
-        initializeActivityFor(TYPE_UNKNOWN);
-        TestFingerprintEnrollSidecar sidecar = new TestFingerprintEnrollSidecar();
-        Resources resources = mock(Resources.class);
-        doReturn(resources).when(mContext).getResources();
-        when(resources.getIntArray(R.array.fingerprint_acquired_ignore_list))
-                .thenReturn(new int[]{3});
-
-        sidecar.setListener(mActivity);
-        sidecar.onAttach(mActivity);
-        sidecar.mEnrollmentCallback.onEnrollmentHelp(5,
-                "Help message should be displayed.");
-
-        TextView errorText = mActivity.findViewById(R.id.error_text);
-        assertThat(errorText.getText()).isEqualTo("Help message should be displayed.");
-    }
-
-    @Test
-    public void fingerprintEnrollHelp_shouldNotShowHelpText() {
-        initializeActivityFor(TYPE_UNKNOWN);
-        TestFingerprintEnrollSidecar sidecar = new TestFingerprintEnrollSidecar();
-        Resources resources = mock(Resources.class);
-        doReturn(resources).when(mContext).getResources();
-        when(resources.getIntArray(R.array.fingerprint_acquired_ignore_list))
-                .thenReturn(new int[]{3});
-
-        sidecar.setListener(mActivity);
-        sidecar.onAttach(mActivity);
-        sidecar.mEnrollmentCallback.onEnrollmentHelp(3,
-                "Help message should not be displayed.");
-
-        TextView errorText = mActivity.findViewById(R.id.error_text);
-        assertThat(errorText.getText()).isEqualTo("");
-    }
-
-    @Test
     public void fingerprintUdfpsEnrollSuccessProgress_shouldNotVibrate() {
         initializeActivityFor(TYPE_UDFPS_OPTICAL);
 
@@ -389,12 +348,4 @@
 
         return callbackCaptor.getValue();
     }
-
-    private class TestFingerprintEnrollSidecar extends FingerprintEnrollSidecar {
-        @Nullable
-        @Override
-        public Context getContext() {
-            return mContext;
-        }
-    }
 }
diff --git a/tests/robotests/src/com/android/settings/biometrics/fingerprint/MessageDisplayControllerTest.java b/tests/robotests/src/com/android/settings/biometrics/fingerprint/MessageDisplayControllerTest.java
new file mode 100644
index 0000000..0fa0918
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/biometrics/fingerprint/MessageDisplayControllerTest.java
@@ -0,0 +1,219 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.biometrics.fingerprint;
+
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
+
+import android.hardware.fingerprint.FingerprintManager;
+import android.os.Handler;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.shadows.ShadowLooper;
+
+import java.time.Clock;
+import java.util.concurrent.TimeUnit;
+
+@RunWith(RobolectricTestRunner.class)
+public class MessageDisplayControllerTest {
+    @Rule
+    public final MockitoRule mockito = MockitoJUnit.rule();
+
+    private static final long START_TIME = 0L;
+    private static final int HELP_ID = 0;
+    private static final String HELP_MESSAGE = "Default Help Message";
+    private static final int REMAINING = 5;
+    private static final int HELP_MINIMUM_DISPLAY_TIME = 300;
+    private static final int PROGRESS_MINIMUM_DISPLAY_TIME = 250;
+    private static final int COLLECT_TIME = 100;
+
+    private MessageDisplayController mMessageDisplayController;
+    @Mock
+    private FingerprintManager.EnrollmentCallback mEnrollmentCallback;
+    @Mock
+    private Clock mClock;
+
+    @Before
+    public void setup() {
+        mMessageDisplayController = new MessageDisplayController(new Handler(), mEnrollmentCallback,
+                mClock,
+                HELP_MINIMUM_DISPLAY_TIME,   /* progressPriorityOverHelp */
+                PROGRESS_MINIMUM_DISPLAY_TIME,   /* prioritizeAcquireMessages */
+                false, false, COLLECT_TIME);
+    }
+
+    private void setMessageDisplayController(boolean progressPriorityOverHelp,
+            boolean prioritizeAcquireMessages) {
+        mMessageDisplayController = new MessageDisplayController(new Handler(), mEnrollmentCallback,
+                mClock, HELP_MINIMUM_DISPLAY_TIME, PROGRESS_MINIMUM_DISPLAY_TIME,
+                progressPriorityOverHelp, prioritizeAcquireMessages, COLLECT_TIME);
+    }
+
+    @Test
+    public void showsHelpMessageAfterCollectTime() {
+        when(mClock.millis()).thenReturn(START_TIME);
+
+        mMessageDisplayController.onEnrollmentHelp(HELP_ID, HELP_MESSAGE);
+        when(mClock.millis()).thenReturn((long) COLLECT_TIME);
+        ShadowLooper.idleMainLooper(COLLECT_TIME, TimeUnit.MILLISECONDS);
+
+        verify(mEnrollmentCallback).onEnrollmentHelp(HELP_ID, HELP_MESSAGE);
+        verifyNoMoreInteractions(mEnrollmentCallback);
+    }
+
+    @Test
+    public void showsProgressMessageAfterCollectTime() {
+        when(mClock.millis()).thenReturn(START_TIME);
+
+        mMessageDisplayController.onEnrollmentProgress(REMAINING);
+        when(mClock.millis()).thenReturn((long) COLLECT_TIME);
+        ShadowLooper.idleMainLooper(COLLECT_TIME, TimeUnit.MILLISECONDS);
+
+        verify(mEnrollmentCallback).onEnrollmentProgress(REMAINING);
+        verifyNoMoreInteractions(mEnrollmentCallback);
+    }
+
+    @Test
+    public void helpDisplayedForMinimumDisplayTime() {
+        when(mClock.millis()).thenReturn(START_TIME);
+
+        mMessageDisplayController.onEnrollmentHelp(HELP_ID, HELP_MESSAGE);
+        when(mClock.millis()).thenReturn((long) COLLECT_TIME);
+        ShadowLooper.idleMainLooper(COLLECT_TIME, TimeUnit.MILLISECONDS);
+
+        verify(mEnrollmentCallback).onEnrollmentHelp(HELP_ID, HELP_MESSAGE);
+
+        mMessageDisplayController.onEnrollmentProgress(REMAINING);
+
+        verifyNoMoreInteractions(mEnrollmentCallback);
+
+        when(mClock.millis()).thenReturn((long) (HELP_MINIMUM_DISPLAY_TIME + COLLECT_TIME));
+        ShadowLooper.idleMainLooper(HELP_MINIMUM_DISPLAY_TIME, TimeUnit.MILLISECONDS);
+
+        verify(mEnrollmentCallback).onEnrollmentProgress(REMAINING);
+    }
+
+    @Test
+    public void progressDisplayedForMinimumDisplayTime() {
+        when(mClock.millis()).thenReturn(START_TIME);
+
+        mMessageDisplayController.onEnrollmentProgress(REMAINING);
+        when(mClock.millis()).thenReturn((long) COLLECT_TIME);
+        ShadowLooper.idleMainLooper(COLLECT_TIME, TimeUnit.MILLISECONDS);
+
+        verify(mEnrollmentCallback).onEnrollmentProgress(REMAINING);
+
+        mMessageDisplayController.onEnrollmentHelp(HELP_ID, HELP_MESSAGE);
+
+        verifyNoMoreInteractions(mEnrollmentCallback);
+
+        when(mClock.millis()).thenReturn((long) (COLLECT_TIME + PROGRESS_MINIMUM_DISPLAY_TIME));
+        ShadowLooper.idleMainLooper(PROGRESS_MINIMUM_DISPLAY_TIME, TimeUnit.MILLISECONDS);
+
+        verify(mEnrollmentCallback).onEnrollmentHelp(HELP_ID, HELP_MESSAGE);
+    }
+
+    @Test
+    public void prioritizeHelpMessage_thenShowProgress() {
+        when(mClock.millis()).thenReturn(START_TIME);
+
+        mMessageDisplayController.onEnrollmentProgress(REMAINING);
+        mMessageDisplayController.onEnrollmentHelp(HELP_ID, HELP_MESSAGE);
+        when(mClock.millis()).thenReturn((long) COLLECT_TIME);
+        ShadowLooper.idleMainLooper(COLLECT_TIME, TimeUnit.MILLISECONDS);
+
+        verify(mEnrollmentCallback).onEnrollmentHelp(HELP_ID, HELP_MESSAGE);
+        verifyNoMoreInteractions(mEnrollmentCallback);
+
+        mMessageDisplayController.onEnrollmentHelp(HELP_ID, HELP_MESSAGE);
+        when(mClock.millis()).thenReturn((long) (COLLECT_TIME + HELP_MINIMUM_DISPLAY_TIME));
+        ShadowLooper.idleMainLooper(HELP_MINIMUM_DISPLAY_TIME, TimeUnit.MILLISECONDS);
+
+        verify(mEnrollmentCallback).onEnrollmentProgress(REMAINING);
+    }
+
+    @Test
+    public void prioritizeProgressOverHelp() {
+        when(mClock.millis()).thenReturn(START_TIME);
+        setMessageDisplayController(true /* progressPriorityOverHelp */,
+                false /* prioritizeAcquireMessages */);
+
+        mMessageDisplayController.onEnrollmentProgress(REMAINING);
+        mMessageDisplayController.onEnrollmentHelp(HELP_ID, HELP_MESSAGE);
+        when(mClock.millis()).thenReturn((long) COLLECT_TIME);
+        ShadowLooper.idleMainLooper(COLLECT_TIME, TimeUnit.MILLISECONDS);
+
+        verify(mEnrollmentCallback).onEnrollmentProgress(REMAINING);
+        verifyNoMoreInteractions(mEnrollmentCallback);
+    }
+
+    @Test
+    public void prioritizeHelpMessageByCount() {
+        String newHelpMessage = "New message";
+        when(mClock.millis()).thenReturn(START_TIME);
+        setMessageDisplayController(false /* progressPriorityOverHelp */,
+                true /* prioritizeAcquireMessages */);
+
+        mMessageDisplayController.onEnrollmentHelp(HELP_ID, HELP_MESSAGE);
+        mMessageDisplayController.onEnrollmentHelp(HELP_ID, HELP_MESSAGE);
+        mMessageDisplayController.onEnrollmentHelp(HELP_ID, newHelpMessage);
+        when(mClock.millis()).thenReturn((long) COLLECT_TIME);
+        ShadowLooper.idleMainLooper(COLLECT_TIME, TimeUnit.MILLISECONDS);
+
+        verify(mEnrollmentCallback).onEnrollmentHelp(HELP_ID, HELP_MESSAGE);
+        verifyNoMoreInteractions(mEnrollmentCallback);
+    }
+
+    @Test
+    public void ignoreSameProgress() {
+        int progressChange = REMAINING - 1;
+        when(mClock.millis()).thenReturn(START_TIME);
+        setMessageDisplayController(true /* progressPriorityOverHelp */,
+                false /* prioritizeAcquireMessages */);
+
+        mMessageDisplayController.onEnrollmentProgress(REMAINING);
+        mMessageDisplayController.onEnrollmentHelp(HELP_ID, HELP_MESSAGE);
+        when(mClock.millis()).thenReturn((long) COLLECT_TIME);
+        ShadowLooper.idleMainLooper(COLLECT_TIME, TimeUnit.MILLISECONDS);
+
+        verify(mEnrollmentCallback).onEnrollmentProgress(REMAINING);
+        verifyNoMoreInteractions(mEnrollmentCallback);
+
+        mMessageDisplayController.onEnrollmentProgress(REMAINING);
+        mMessageDisplayController.onEnrollmentHelp(HELP_ID, HELP_MESSAGE);
+        when(mClock.millis()).thenReturn((long) (COLLECT_TIME + PROGRESS_MINIMUM_DISPLAY_TIME));
+        ShadowLooper.idleMainLooper(PROGRESS_MINIMUM_DISPLAY_TIME, TimeUnit.MILLISECONDS);
+
+        verify(mEnrollmentCallback).onEnrollmentHelp(HELP_ID, HELP_MESSAGE);
+
+        mMessageDisplayController.onEnrollmentProgress(progressChange);
+        mMessageDisplayController.onEnrollmentHelp(HELP_ID, HELP_MESSAGE);
+        when(mClock.millis()).thenReturn((long) (COLLECT_TIME + PROGRESS_MINIMUM_DISPLAY_TIME
+                + HELP_MINIMUM_DISPLAY_TIME));
+        ShadowLooper.idleMainLooper(HELP_MINIMUM_DISPLAY_TIME, TimeUnit.MILLISECONDS);
+
+        verify(mEnrollmentCallback).onEnrollmentProgress(progressChange);
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/deviceinfo/simstatus/SimStatusPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/deviceinfo/simstatus/SimStatusPreferenceControllerTest.java
index 9d4956d..eea07fe 100644
--- a/tests/robotests/src/com/android/settings/deviceinfo/simstatus/SimStatusPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/deviceinfo/simstatus/SimStatusPreferenceControllerTest.java
@@ -16,6 +16,8 @@
 
 package com.android.settings.deviceinfo.simstatus;
 
+import static com.google.common.truth.Truth.assertThat;
+
 import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.mock;
@@ -26,6 +28,7 @@
 import android.content.Context;
 import android.content.res.Resources;
 import android.os.UserManager;
+import android.telephony.SubscriptionInfo;
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
 
@@ -37,6 +40,7 @@
 
 import com.android.settings.R;
 import com.android.settings.core.BasePreferenceController;
+import com.android.settingslib.search.SearchIndexableRaw;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -62,6 +66,10 @@
     @Mock
     private PreferenceScreen mScreen;
     @Mock
+    private SubscriptionManager mSubscriptionManager;
+    @Mock
+    private SubscriptionInfo mSubscriptionInfo;
+    @Mock
     private TelephonyManager mTelephonyManager;
     @Mock
     private UserManager mUserManager;
@@ -85,6 +93,8 @@
         when(mResources.getBoolean(R.bool.config_show_sim_info)).thenReturn(true);
 
         mockService(Context.TELEPHONY_SERVICE, TelephonyManager.class, mTelephonyManager);
+        mockService(Context.TELEPHONY_SUBSCRIPTION_SERVICE, SubscriptionManager.class,
+                mSubscriptionManager);
 
         mockService(Context.USER_SERVICE, UserManager.class, mUserManager);
         final List<Preference> preferencePool = new ArrayList<Preference>();
@@ -96,6 +106,10 @@
             public Preference createNewPreference(Context context) {
                 return preferencePool.remove(0);
             }
+            @Override
+            public int getSimSlotIndex() {
+                return 0;
+            }
         });
         doReturn(BasePreferenceController.AVAILABLE).when(mController).getAvailabilityStatus();
         when(mScreen.getContext()).thenReturn(mContext);
@@ -163,6 +177,47 @@
         verify(mFragment).getChildFragmentManager();
     }
 
+    @Test
+    public void updateDynamicRawDataToIndex_notAddToSearch_emptySimSlot() {
+        doReturn(null).when(mSubscriptionManager).getActiveSubscriptionInfoList();
+        SlotSimStatus slotSimStatus = new SlotSimStatus(mContext);
+        List<SearchIndexableRaw> rawData = new ArrayList<SearchIndexableRaw>();
+
+        mController.init(mFragment, slotSimStatus);
+        mController.updateDynamicRawDataToIndex(rawData);
+
+        assertThat(rawData.size()).isEqualTo(0);
+    }
+
+    @Test
+    public void updateDynamicRawDataToIndex_addToSearch_simInSimSlot() {
+        doReturn(false).when(mSubscriptionInfo).isEmbedded();
+        doReturn(List.of(mSubscriptionInfo)).when(mSubscriptionManager)
+                .getActiveSubscriptionInfoList();
+        SlotSimStatus slotSimStatus = new SlotSimStatus(mContext);
+        List<SearchIndexableRaw> rawData = new ArrayList<SearchIndexableRaw>();
+
+        mController.init(mFragment, slotSimStatus);
+        mController.updateDynamicRawDataToIndex(rawData);
+
+        assertThat(rawData.size()).isEqualTo(1);
+    }
+
+    @Test
+    public void updateDynamicRawDataToIndex_addEsimToSearch_esimInSimSlot() {
+        doReturn(true).when(mSubscriptionInfo).isEmbedded();
+        doReturn(List.of(mSubscriptionInfo)).when(mSubscriptionManager)
+                .getActiveSubscriptionInfoList();
+        SlotSimStatus slotSimStatus = new SlotSimStatus(mContext);
+        List<SearchIndexableRaw> rawData = new ArrayList<SearchIndexableRaw>();
+
+        mController.init(mFragment, slotSimStatus);
+        mController.updateDynamicRawDataToIndex(rawData);
+
+        assertThat(rawData.size()).isEqualTo(1);
+        assertThat(rawData.get(0).keywords.contains("eid")).isTrue();
+    }
+
     private <T> void mockService(String serviceName, Class<T> serviceClass, T service) {
         when(mContext.getSystemServiceName(serviceClass)).thenReturn(serviceName);
         when(mContext.getSystemService(serviceName)).thenReturn(service);
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImplTest.java b/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImplTest.java
index 648685a..ab61abc 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImplTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImplTest.java
@@ -63,6 +63,11 @@
     }
 
     @Test
+    public void testIsBatteryUsageEnabled_returnFalse() {
+        assertThat(mPowerFeatureProvider.isBatteryUsageEnabled(mContext)).isTrue();
+    }
+
+    @Test
     public void testIsTypeSystem_uidRoot_returnTrue() {
         assertThat(mPowerFeatureProvider.isTypeSystem(Process.ROOT_UID, null)).isTrue();
     }
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/PowerGaugePreferenceTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/PowerGaugePreferenceTest.java
index 5d599fe..e9573f1 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/PowerGaugePreferenceTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/PowerGaugePreferenceTest.java
@@ -104,4 +104,18 @@
         assertThat(mPreferenceViewHolder.findViewById(android.R.id.title).getContentDescription())
                 .isEqualTo(CONTENT_DESCRIPTION);
     }
+
+    @Test
+    public void setPercent_greaterThanThreshold_showNumber() {
+        mPowerGaugePreference.setPercent(99.5);
+
+        assertThat(mPowerGaugePreference.getPercent()).isEqualTo("100%");
+    }
+
+    @Test
+    public void setPercent_lessThanThreshold_showBar() {
+        mPowerGaugePreference.setPercent(0.95);
+
+        assertThat(mPowerGaugePreference.getPercent()).isEqualTo("-");
+    }
 }