Merge "Fix background inconsistency of the font size page in SUW" into sc-dev
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index c352694..9b11fe8 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -494,6 +494,22 @@
                        android:value="com.android.settings.biometrics.fingerprint.FingerprintSettings$FingerprintSettingsFragment" />
         </activity>
 
+        <activity android:name="Settings$CombinedBiometricSettingsActivity"
+                  android:label="@string/security_settings_biometric_preference_title"
+                  android:theme="@style/Theme.SubSettings"
+                  android:exported="false">
+            <meta-data android:name="com.android.settings.FRAGMENT_CLASS"
+                       android:value="com.android.settings.biometrics.combination.CombinedBiometricSettings" />
+        </activity>
+
+        <activity android:name="Settings$CombinedBiometricProfileSettingsActivity"
+                  android:label="@string/security_settings_biometric_preference_title"
+                  android:theme="@style/Theme.SubSettings"
+                  android:exported="false">
+            <meta-data android:name="com.android.settings.FRAGMENT_CLASS"
+                       android:value="com.android.settings.biometrics.combination.CombinedBiometricProfileSettings" />
+        </activity>
+
         <activity android:name=".bluetooth.DevicePickerActivity"
                 android:label="@string/device_picker"
                 android:configChanges="orientation|keyboardHidden|screenSize"
diff --git a/res/drawable/baseline_near_me.xml b/res/drawable/baseline_near_me.xml
deleted file mode 100644
index 343f970..0000000
--- a/res/drawable/baseline_near_me.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2021 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-          http://www.apache.org/licenses/LICENSE-2.0
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="24dp"
-    android:height="24dp"
-    android:viewportWidth="24"
-    android:viewportHeight="24"
-    android:tint="?attr/colorControlNormal">
-  <path
-      android:fillColor="@android:color/black"
-      android:pathData="M21,3L3,10.53v0.98l6.84,2.65L12.48,21h0.98L21,3z"/>
-</vector>
diff --git a/res/layout/apps_filter_spinner.xml b/res/layout/apps_filter_spinner.xml
index 13d8078..1de5705 100644
--- a/res/layout/apps_filter_spinner.xml
+++ b/res/layout/apps_filter_spinner.xml
@@ -36,7 +36,7 @@
         android:layout_width="56dp"
         android:layout_height="56dp"
         android:layout_marginTop="12dp"
-        android:layout_toRightOf="@id/filter_spinner"
+        android:layout_toEndOf="@id/filter_spinner"
         android:contentDescription="@string/configure"
         android:scaleType="center"
         android:src="@drawable/ic_apps_filter_settings_24dp"
diff --git a/res/layout/notification_history.xml b/res/layout/notification_history.xml
index fdcecb3..0b0e1d5 100644
--- a/res/layout/notification_history.xml
+++ b/res/layout/notification_history.xml
@@ -146,7 +146,6 @@
 
                     <androidx.recyclerview.widget.RecyclerView
                         android:id="@+id/notification_list"
-                        android:elevation="1dp"
                         android:background="@drawable/rounded_bg"
                         android:layout_width="match_parent"
                         android:layout_height="wrap_content"
@@ -170,7 +169,6 @@
                     android:paddingBottom="16dp" />
                 <androidx.recyclerview.widget.RecyclerView
                         android:id="@+id/notification_list"
-                        android:elevation="1dp"
                         android:background="@drawable/rounded_bg"
                         android:layout_width="match_parent"
                         android:layout_height="wrap_content"
@@ -194,7 +192,6 @@
                     android:id="@+id/apps"
                     android:layout_width="match_parent"
                     android:layout_height="wrap_content"
-                    android:elevation="1dp"
                     android:orientation="vertical"
                     android:background="@drawable/rounded_bg">
                     <!-- app based recycler views added here -->
diff --git a/res/layout/notification_history_app_layout.xml b/res/layout/notification_history_app_layout.xml
index 78f2ef4..7c6e5a3 100644
--- a/res/layout/notification_history_app_layout.xml
+++ b/res/layout/notification_history_app_layout.xml
@@ -26,9 +26,9 @@
         android:layout_width="match_parent"
         android:clipChildren="true"
         android:background="@drawable/button_ripple_radius"
-        android:paddingTop="24dp"
+        android:paddingTop="20dp"
         android:orientation="horizontal"
-        android:paddingBottom="22dp"
+        android:paddingBottom="18dp"
         android:paddingStart="16dp">
         <ImageView
             android:id="@+id/icon"
@@ -50,7 +50,7 @@
                 android:layout_height="wrap_content"
                 android:layout_width="wrap_content"
                 android:layout_gravity="center_vertical"
-                android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Notification"/>
+                android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Notification.Title"/>
             <TextView
                 android:id="@+id/count"
                 android:layout_height="wrap_content"
@@ -58,7 +58,7 @@
                 android:layout_gravity="start|center_vertical"
                 android:textDirection="locale"
                 android:paddingTop="4dp"
-                android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Notification.Title"/>
+                android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Notification"/>
         </LinearLayout>
 
         <include layout="@*android:layout/notification_expand_button"
diff --git a/res/layout/settings_collapsing_base_layout.xml b/res/layout/settings_collapsing_base_layout.xml
deleted file mode 100644
index 97d249c..0000000
--- a/res/layout/settings_collapsing_base_layout.xml
+++ /dev/null
@@ -1,68 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-     Copyright (C) 2021 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.
--->
-<androidx.coordinatorlayout.widget.CoordinatorLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:app="http://schemas.android.com/apk/res-auto"
-    android:id="@+id/content_parent"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:fitsSystemWindows="true">
-
-    <com.google.android.material.appbar.AppBarLayout
-        android:id="@+id/app_bar"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:fitsSystemWindows="true"
-        android:outlineAmbientShadowColor="@android:color/transparent"
-        android:outlineSpotShadowColor="@android:color/transparent"
-        android:background="@android:color/transparent"
-        android:theme="@style/Theme.CollapsingToolbar.Settings">
-
-        <com.google.android.material.appbar.CollapsingToolbarLayout
-            android:id="@+id/collapsing_toolbar"
-            android:layout_width="match_parent"
-            android:layout_height="@dimen/toolbar_one_line_height"
-            android:clipToPadding="false"
-            app:contentScrim="@color/color_surface_header"
-            app:maxLines="3"
-            app:layout_scrollFlags="scroll|exitUntilCollapsed|snap"
-            app:scrimAnimationDuration="50"
-            app:scrimVisibleHeightTrigger="@dimen/scrim_visible_height_trigger"
-            app:statusBarScrim="@empty"
-            app:titleCollapseMode="fade"
-            app:collapsedTitleTextAppearance="@style/ToolbarText.Collapsed"
-            app:expandedTitleTextAppearance="@style/ToolbarText.Expanded"
-            app:expandedTitleMarginStart="@dimen/expanded_title_margin_start"
-            app:expandedTitleMarginEnd="@dimen/expanded_title_margin_end"
-            app:toolbarId="@id/action_bar">
-
-            <Toolbar
-                android:id="@+id/action_bar"
-                android:layout_width="match_parent"
-                android:layout_height="?attr/actionBarSize"
-                android:theme="?android:attr/actionBarTheme"
-                app:layout_collapseMode="pin"/>
-
-        </com.google.android.material.appbar.CollapsingToolbarLayout>
-    </com.google.android.material.appbar.AppBarLayout>
-
-    <FrameLayout
-        android:id="@+id/content_frame"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        app:layout_behavior="@string/appbar_scrolling_view_behavior"/>
-</androidx.coordinatorlayout.widget.CoordinatorLayout>
\ No newline at end of file
diff --git a/res/values/config.xml b/res/values/config.xml
index a41e41b..b2323c2 100755
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -530,4 +530,24 @@
 
     <!-- Whether to show Smart Storage toggle -->
     <bool name="config_show_smart_storage_toggle">true</bool>
+
+    <!-- Display settings screen, Color mode options. Must be the same length and order as
+         config_color_mode_options_values below. Only the values that also appear in
+         frameworks/base/core/res/res/values/config.xml's config_availableColorModes are shown. -->
+    <string-array name="config_color_mode_options_strings" translatable="false">
+        <item>@string/color_mode_option_natural</item>
+        <item>@string/color_mode_option_boosted</item>
+        <item>@string/color_mode_option_saturated</item>
+        <item>@string/color_mode_option_automatic</item>
+    </string-array>
+
+    <!-- Display settings screen, Color mode options. Must be the same length and order as
+         config_color_mode_options_strings above. Only the values that also appear in
+         frameworks/base/core/res/res/values/config.xml's config_availableColorModes are shown. -->
+    <integer-array name="config_color_mode_options_values" translatable="false">
+        <item>0</item>
+        <item>1</item>
+        <item>2</item>
+        <item>3</item>
+    </integer-array>
 </resources>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 6047092..0aaf930 100755
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -443,15 +443,7 @@
     <!-- Battery usage chart view component -->
     <dimen name="chartview_divider_width">1dp</dimen>
     <dimen name="chartview_divider_height">4dp</dimen>
-    <dimen name="chartview_trapezoid_radius">2dp</dimen>
+    <dimen name="chartview_trapezoid_radius">3dp</dimen>
     <dimen name="chartview_trapezoid_margin_start">1dp</dimen>
     <dimen name="chartview_trapezoid_margin_bottom">2dp</dimen>
-
-    <!-- Collapsing toolbar layout dimensions -->
-    <dimen name="toolbar_one_line_height">226dp</dimen>
-    <dimen name="toolbar_two_lines_height">270dp</dimen>
-    <dimen name="toolbar_three_lines_height">314dp</dimen>
-    <dimen name="scrim_visible_height_trigger">174dp</dimen>
-    <dimen name="expanded_title_margin_start">24dp</dimen>
-    <dimen name="expanded_title_margin_end">24dp</dimen>
 </resources>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 1ca471f..ef5abb3 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -739,6 +739,8 @@
     <string name="security_dashboard_summary">Screen lock, fingerprint</string>
     <!-- Summary for Security settings when fingerprint is not supported [CHAR LIMIT=NONE]-->
     <string name="security_dashboard_summary_no_fingerprint">Screen lock</string>
+    <!-- Summary for Security settings when biometric unlock is supported [CHAR LIMIT=NONE] -->
+    <string name="security_dashboard_summary_biometric">Screen lock, biometric unlock, app security</string>
 
     <!-- Face enrollment and settings --><skip />
     <!-- Message shown in summary field when face unlock is set up. [CHAR LIMIT=40] -->
@@ -967,6 +969,22 @@
     <!-- Message shown in fingerprint security settings home screen. [CHAR LIMIT=NONE]-->
     <string name="security_settings_fingerprint_v2_home_screen">Use your fingerprint to unlock your phone or for authentication, like when you sign in to apps or approve a purchase\n\n<annotation id="url">Learn more</annotation></string>
 
+    <!-- Biometric settings --><skip />
+    <!-- Title shown for menu item that launches biometric settings. [CHAR LIMIT=66] -->
+    <string name="security_settings_biometric_preference_title">Face &amp; fingerprint unlock</string>
+    <!-- Message shown in summary field of biometric settings. [CHAR LIMIT=66] -->
+    <string name="security_settings_biometric_preference_summary">Face and fingerprint</string>
+    <!-- Introduction shown in face and fingerprint page to introduce the biometric feature. [CHAR LIMIT=NONE]-->
+    <string name="biometric_settings_intro">When you set up face unlock and fingerprint, your phone will ask for your fingerprint when you wear a mask or are in a dark area.</string>
+    <!-- Biometric category title - biometric options for unlocking the device. [CHAR LIMIT=50] -->
+    <string name="biometric_settings_category_ways_to_unlock">Ways to unlock</string>
+    <!-- Biometric category title - configuration options for using biometric to unlock the device or authenticate in apps. [CHAR LIMIT=50] -->
+    <string name="biometric_settings_category_ways_to_use">Use face and fingerprint to</string>
+    <!-- Text shown on a toggle which allows or disallows the device to use biometric for unlocking the device. [CHAR LIMIT=20] -->
+    <string name="biometric_settings_use_biometric_unlock_phone">Unlocking your phone</string>
+    <!-- Text shown on a toggle which allows or disallows the device to use biometric for authentication. [CHAR LIMIT=30] -->
+    <string name="biometric_settings_use_biometric_for_apps">Authentication in apps</string>
+
     <!-- Title of dialog shown when the user tries to skip setting up a screen lock, warning them of potential consequences of not doing so [CHAR LIMIT=30]-->
     <string name="lock_screen_intro_skip_title">Skip screen lock?</string>
     <!-- Dialog text shown when the user tries to skip setting up a screen lock, warning them of potential consequences of not doing so, including loss of factory reset protection. (tablet) [CHAR LIMIT=NONE] -->
@@ -4121,7 +4139,7 @@
     <!-- Description text for Bluetooth always scanning -->
     <string name="location_scanning_bluetooth_always_scanning_description">Allow apps and services to scan for nearby devices at any time, even when Bluetooth is off. This can be used, for example, to improve location-based features and services.</string>
     <!-- [CHAR LIMIT=60] Location Services preference title -->
-    <string name="location_services_preference_title">Manage location services</string>
+    <string name="location_services_preference_title">Location services</string>
     <!-- [CHAR LIMIT=60] Location Services screen, screen title -->
     <string name="location_services_screen_title">Location Services</string>
     <!-- [CHAR LIMIT=50] Location settings screen, sub category for location services for managed profile -->
@@ -5691,15 +5709,54 @@
     <!-- Title for the prompt shown as a placeholder if no accessibility services are installed. [CHAR LIMIT=50] -->
     <string name="accessibility_no_services_installed">No services installed</string>
 
-    <!-- Title for the acccessibility shortcut's summary if no service is selected for use with the shortcut. [CHAR LIMIT=50] -->
+    <!-- Title for the accessibility shortcut's summary if no service is selected for use with the shortcut. [CHAR LIMIT=50] -->
     <string name="accessibility_no_service_selected">No service selected</string>
 
     <!-- Default description for an accessibility service if the latter doesn't provide one. [CHAR LIMIT=NONE] -->
     <string name="accessibility_service_default_description">No description provided.</string>
 
-    <!-- Accessibility settings: button for lauching settings for an accessibility service -->
+    <!-- Accessibility settings: button for launching settings for an accessibility service -->
     <string name="settings_button">Settings</string>
 
+    <!-- List of synonyms used in the settings search bar to find the “Extra Dim” setting, which dims your screen. Title name is located at strings/reduce_bright_colors_preference_title. [CHAR LIMIT=NONE] -->
+    <string name="keywords_reduce_bright_colors">light sensitivity, photophobia, dark theme, migraine, headache, reading mode, night mode, reduce brightness, white point</string>
+    <!-- List of synonyms used in the settings search bar to find the “Accessibility”. [CHAR LIMIT=NONE] -->
+    <string name="keywords_accessibility">Ease of use, ease of access, assistance, assistive</string>
+    <!-- List of synonyms used in the settings search bar to find the “Magnification”. [CHAR LIMIT=NONE] -->
+    <string name="keywords_magnification">Window Magnifier, Zoom, Magnification, Low vision, Enlarge, make bigger</string>
+    <!-- List of synonyms used in the settings search bar to find the “TalkBack”. [CHAR LIMIT=NONE] -->
+    <string name="keywords_talkback">Screen reader, Voice Over, VoiceOver, Voice Assistance, Blind, Low Vision, TTS, text to speech, spoken feedback</string>
+    <!-- List of synonyms used in the settings search bar to find the “Live Caption”. [CHAR LIMIT=NONE] -->
+    <string name="keywords_live_caption">Captions, closed captions, CC, Live Transcribe, hard of hearing, hearing loss, CART, speech to text, subtitle</string>
+    <!-- List of synonyms used in the settings search bar to find the “Live Transcribe”. [CHAR LIMIT=NONE] -->
+    <string name="keywords_live_transcribe">Captions, closed captions, CC, Live Caption, hard of hearing, hearing loss, CART, speech to text, subtitle</string>
+    <!-- List of synonyms used in the settings search bar to find the “Sound Notifications”. [CHAR LIMIT=NONE] -->
+    <string name="keywords_sound_notifications">Notifications, hard of hearing, hearing loss, notify</string>
+    <!-- List of synonyms used in the settings search bar to find the “Sound Amplifier”. [CHAR LIMIT=NONE] -->
+    <string name="keywords_sound_amplifier">PSAP, amplify, sound amplification, hard of hearing, hearing loss, amplification</string>
+    <!-- List of synonyms used in the settings search bar to find the “Display size”. [CHAR LIMIT=NONE] -->
+    <string name="keywords_display_size">screen size, large screen</string>
+    <!-- List of synonyms used in the settings search bar to find the “Bold text”. [CHAR LIMIT=NONE] -->
+    <string name="keywords_bold_text">High contrast, low vision, bold font, bold face</string>
+    <!-- List of synonyms used in the settings search bar to find the “Select to Speak”. [CHAR LIMIT=NONE] -->
+    <string name="keywords_select_to_speak">Hear text, read aloud, speak screen, screen reader</string>
+    <!-- List of synonyms used in the settings search bar to find the “Color correction”. [CHAR LIMIT=NONE] -->
+    <string name="keywords_color_correction">adjust color </string>
+    <!-- List of synonyms used in the settings search bar to find the “Color inversion”. [CHAR LIMIT=NONE] -->
+    <string name="keywords_color_inversion">turn screen dark, turn screen light</string>
+    <!-- List of synonyms used in the settings search bar to find the “Accessibility Menu”. [CHAR LIMIT=NONE] -->
+    <string name="keywords_accessibility_menu">motor, quick menu, assistive menu, touch, dexterity</string>
+    <!-- List of synonyms used in the settings search bar to find the “Switch Access”. [CHAR LIMIT=NONE] -->
+    <string name="keywords_switch_access">motor, switch, hand, AT, assistive technology, paralysis, ALS, scanning, step scanning</string>
+    <!-- List of synonyms used in the settings search bar to find the “Autoclick(dwell timing)”. [CHAR LIMIT=NONE] -->
+    <string name="keywords_auto_click">motor, mouse</string>
+    <!-- List of synonyms used in the settings search bar to find the “Hearing aids”. [CHAR LIMIT=NONE] -->
+    <string name="keywords_hearing_aids">hard of hearing, hearing loss</string>
+    <!-- List of synonyms used in the settings search bar to find the “Real-time text (RTT)”. [CHAR LIMIT=NONE] -->
+    <string name="keywords_rtt">hard of hearing, hearing loss, captions, Teletype, tty</string>
+    <!-- List of synonyms used in the settings search bar to find the “Voice Access”. [CHAR LIMIT=NONE] -->
+    <string name="keywords_voice_access">voice, voice control, motor, hand, mic, microphone, dictation, talk, control</string>
+
     <!-- Printing settings -->
     <skip />
 
@@ -6255,8 +6312,39 @@
     <string name ="battery_detail_info_title">Since full charge</string>
     <!-- Title for the battery management group [CHAR LIMIT=40] -->
     <string name ="battery_detail_manage_title">Manage battery usage</string>
+
     <!-- Description for battery total and background usage time for an app, i.e. 1 hr 15 min total • 39 min background for past 24 hr. Note: ^1 and ^2 should be used in all translations [CHAR LIMIT=120] -->
     <string name="battery_total_and_background_usage"><xliff:g id="time" example="1 hr 15 min">^1</xliff:g> total • <xliff:g id="time" example="39 min">^2</xliff:g> background for past 24 hr</string>
+    <!-- Description for battery total and background usage time in a time period for an app, i.e. 1 hr 15 min total • 39 min background for 12 am-2 am. Note: ^1, ^2 and ^3 should be used in all translations [CHAR LIMIT=120] -->
+    <string name="battery_total_and_background_usage_with_period"><xliff:g id="time" example="1 hr 15 min">^1</xliff:g> total • <xliff:g id="time" example="39 min">^2</xliff:g> background for <xliff:g id="time_period" example="12 am-2 am">^3</xliff:g></string>
+
+    <!-- Description for battery total usage time is less than a minute for an app [CHAR LIMIT=120] -->
+    <string name="battery_total_usage_less_minute">Total less than a minute for past 24 hr</string>
+    <!-- Description for battery total usage time is less than a minute in a time period for an app, i.e. Total less than a minute for 12 am-2 am. Note: ^1 should be used in all translations[CHAR LIMIT=120] -->
+    <string name="battery_total_usage_less_minute_with_period">Total less than a minute for <xliff:g id="time_period" example="12 am-2 am">^1</xliff:g></string>
+
+    <!-- Description for battery background usage time is less than a minute for an app [CHAR LIMIT=120] -->
+    <string name="battery_background_usage_less_minute">Background less than a minute for past 24 hr</string>
+    <!-- Description for battery background usage time is less than a minute in a time period for an app, i.e. Background less than a minute for 12 am-2 am. Note: ^1 should be used in all translations[CHAR LIMIT=120] -->
+    <string name="battery_background_usage_less_minute_with_period">Background less than a minute for <xliff:g id="time_period" example="12 am-2 am">^1</xliff:g></string>
+
+    <!-- Description for battery total usage time for an app, i.e. 1 hr 15 min total for past 24 hr. Note: ^1 should be used in all translations [CHAR LIMIT=120] -->
+    <string name="battery_total_usage"><xliff:g id="time" example="1 hr 15 min">^1</xliff:g> total for past 24 hr</string>
+    <!-- Description for battery total usage time in a time period for an app, i.e. 1 hr 15 min total for 12 am-2 am. Note: ^1 and ^2 should be used in all translations [CHAR LIMIT=120] -->
+    <string name="battery_total_usage_with_period"><xliff:g id="time" example="1 hr 15 min">^1</xliff:g> total for <xliff:g id="time_period" example="12 am-2 am">^2</xliff:g></string>
+
+    <!-- Description for battery background usage time for an app, i.e. 1 hr 15 min background for past 24 hr. Note: ^1 should be used in all translations [CHAR LIMIT=120] -->
+    <string name="battery_background_usage"><xliff:g id="time" example="1 hr 15 min">^1</xliff:g> background for past 24 hr</string>
+    <!-- Description for battery background usage time in a time period for an app, i.e. 1 hr 15 min background for 12 am-2 am. Note: ^1 and ^2 should be used in all translations [CHAR LIMIT=120] -->
+    <string name="battery_background_usage_with_period"><xliff:g id="time" example="1 hr 15 min">^1</xliff:g> background for <xliff:g id="time_period" example="12 am-2 am">^2</xliff:g></string>
+
+    <!-- Description for battery total usage with background usage time less than a minute for an app, i.e. 1 hr 15 min total • background less than a minute for past 24 hr. Note: ^1 should be used in all translations [CHAR LIMIT=120] -->
+    <string name="battery_total_usage_and_background_less_minute_usage"><xliff:g id="time" example="1 hr 15 min">^1</xliff:g> total • background less than a minute for past 24 hr</string>
+    <!-- Description for battery total usage with background usage time less than a minute in a time period for an app, i.e. 1 hr 15 min total • background less than a minute for 12 am-2 am. Note: ^1 and ^2 should be used in all translations [CHAR LIMIT=120] -->
+    <string name="battery_total_usage_and_background_less_minute_usage_with_period"><xliff:g id="time" example="1 hr 15 min">^1</xliff:g> total • background less than a minute for <xliff:g id="time_period" example="12 am-2 am">^2</xliff:g></string>
+
+    <!-- Description for no any battery usage for past 24 hr [CHAR LIMIT=120] -->
+    <string name="battery_not_usage">No usage for past 24 hr</string>
 
     <!-- Graph subtext displayed to user when enhanced battery estimate is being used [CHAR LIMIT=120] -->
     <string name="advanced_battery_graph_subtext">Battery left estimate is based on your device usage</string>
@@ -7950,7 +8038,7 @@
     <string name="keywords_wifi_calling">wifi, wi-fi, call, calling</string>
     <string name="keywords_display">screen, touchscreen</string>
     <string name="keywords_display_brightness_level">dim screen, touchscreen, battery, bright</string>
-    <string name="keywords_display_night_display">dim screen, night, tint, night shift, brightness, screen color, colour, color</string>
+    <string name="keywords_display_night_display">dim screen, night, tint, night shift, brightness, screen color, colour, color, light sensitivity, photophobia, make darker, darken, dark mode, migraine</string>
     <string name="keywords_display_wallpaper">background, personalize, customize display</string>
     <string name="keywords_display_font_size">text size</string>
     <!-- Search keyword for "Cast" settings [CHAR_LIMIT=NONE]-->
@@ -7990,6 +8078,7 @@
     <string name="keywords_backup">backup, back up</string>
     <string name="keywords_assist_gesture_launch">gesture</string>
     <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_model_and_hardware">serial number, hardware version</string>
@@ -8015,6 +8104,9 @@
     <!-- Search keyword for fingerprint settings. [CHAR_LIMIT=NONE]-->
     <string name="keywords_fingerprint_settings">fingerprint, add fingerprint</string>
 
+    <!-- Search keyword for biometric settings. [CHAR_LIMIT=NONE]-->
+    <string name="keywords_biometric_settings">face, fingerprint, add fingerprint</string>
+
     <!-- Search keywords for adaptive brightness setting [CHAR LIMIT=NONE]-->
     <string name="keywords_display_auto_brightness">dim screen, touchscreen, battery, smart brightness, dynamic brightness, Auto brightness</string>
 
@@ -8076,10 +8168,7 @@
     <string name="keywords_add_language">add language, add a language</string>
 
     <!-- List of synonyms for the font size, used to match in settings search [CHAR LIMIT=NONE] -->
-    <string name="keywords_font_size">text size</string>
-
-    <!-- List of synonyms used in the settings search bar to find the “Extra Dim” setting, which dims your screen. Title name is located at strings/reduce_bright_colors_preference_title. [CHAR LIMIT=NONE] -->
-    <string name="keywords_reduce_bright_colors">light sensitivity, photophobia, dark theme, migraine, headache, reading mode, night mode, reduce brightness, white point</string>
+    <string name="keywords_font_size">text size, large print, large font, large text, low vision, make text bigger, font enlarger, font enlargement</string>
 
     <!-- Option title for the default sound, context based on screen -->
     <string name="default_sound">Default sound</string>
@@ -9056,6 +9145,10 @@
     <string name="notif_type_alerting_summary">Notifications that may ring or vibrate based on settings</string>
     <string name="notif_type_silent">Silent</string>
     <string name="notif_type_silent_summary">Notifications that never make sound or vibrations</string>
+    <!-- category header for apps allowed to read notifications. [CHAR LIMIT=45] -->
+    <string name="notification_listener_allowed">Allowed</string>
+    <!-- category header for apps not allowed to read notifications. [CHAR LIMIT=45] -->
+    <string name="notification_listener_not_allowed">Not allowed</string>
 
     <!-- Per notification listener, a list of apps whose notifications this listener cannot see -->
     <string name="notif_listener_excluded_app_title">See all apps</string>
@@ -13183,4 +13276,13 @@
 
     <!-- Label for button to not allow grant the permission for remote devices. [CHAR_LIMIT=50] -->
     <string name="request_manage_bluetooth_permission_dont_allow">Don\u2019t allow</string>
+
+    <!-- Title for UWB preference [CHAR_LIMIT=60] -->
+    <string name="uwb_settings_title">Ultra-WideBand (UWB)</string>
+
+    <!-- Summary for UWB preference. [CHAR_LIMIT=NONE]-->
+    <string name="uwb_settings_summary">Helps identify the relative position of nearby devices that have UWB</string>
+
+    <!-- Summary for UWB preference when airplane mode is disabled. [CHAR_LIMIT=NONE]-->
+    <string name="uwb_settings_summary_airplane_mode">Turn off Airplane mode to use UWB. </string>
 </resources>
diff --git a/res/values/styles.xml b/res/values/styles.xml
index e91ddcb..b27cc5d 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -787,7 +787,7 @@
         <item name="android:fontFamily">@*android:string/config_headlineFontFamily</item>
     </style>
 
-    <style name="HomepageTitleText" parent="ToolbarText.Expanded">
+    <style name="HomepageTitleText" parent="CollapsingToolbarTitle.Expanded">
         <item name="android:layout_width">wrap_content</item>
         <item name="android:layout_height">wrap_content</item>
         <item name="android:layout_marginBottom">@dimen/homepage_title_margin_bottom</item>
@@ -879,8 +879,4 @@
         <item name="android:textSize">16sp</item>
         <item name="android:textColor">?android:attr/textColorSecondary</item>
     </style>
-
-    <style name="ToolbarText.Collapsed" parent="CollapsingToolbarTitle.Collapsed"/>
-    <style name="ToolbarText.Expanded" parent="CollapsingToolbarTitle"/>
-    <style name="ToolbarText.MoreThanTwoLines" parent="CollapsingToolbarTitle.MoreThanTwoLines"/>
 </resources>
diff --git a/res/values/styles_preference.xml b/res/values/styles_preference.xml
index c162fc4..5ad553a 100644
--- a/res/values/styles_preference.xml
+++ b/res/values/styles_preference.xml
@@ -30,7 +30,6 @@
 
     <style name="PreferenceTheme.SetupWizard" parent="@style/SettingsPreferenceTheme">
         <item name="preferenceFragmentCompatStyle">@style/SetupWizardPreferenceFragmentStyle</item>
-        <item name="preferenceStyle">@style/Preference.Material</item>
     </style>
 
     <style name="ApnPreference" parent="@style/Preference.Material">
diff --git a/res/values/themes.xml b/res/values/themes.xml
index 5142d55..b5f71fa 100644
--- a/res/values/themes.xml
+++ b/res/values/themes.xml
@@ -258,5 +258,7 @@
     <style name="Theme.NotificationHistory" parent="@android:style/Theme.DeviceDefault.DayNight">
         <item name="android:windowActionBar">false</item>
         <item name="android:windowNoTitle">true</item>
+        <item name="android:navigationBarColor">@android:color/transparent</item>
+        <item name="android:statusBarColor">@android:color/transparent</item>
     </style>
 </resources>
diff --git a/res/xml/accessibility_settings.xml b/res/xml/accessibility_settings.xml
index ce3f4a2..6fa8b00 100644
--- a/res/xml/accessibility_settings.xml
+++ b/res/xml/accessibility_settings.xml
@@ -50,7 +50,8 @@
             android:icon="@drawable/ic_reduce_bright_colors"
             android:persistent="false"
             android:title="@string/reduce_bright_colors_preference_title"
-            settings:controller="com.android.settings.accessibility.ReduceBrightColorsPreferenceController"/>
+            settings:controller="com.android.settings.accessibility.ReduceBrightColorsPreferenceController"
+            settings:keywords="@string/keywords_reduce_bright_colors"/>
 
         <SwitchPreference
             android:key="dark_ui_mode_accessibility"
diff --git a/res/xml/app_notification_settings.xml b/res/xml/app_notification_settings.xml
index a801ae1..edf8cb9 100644
--- a/res/xml/app_notification_settings.xml
+++ b/res/xml/app_notification_settings.xml
@@ -26,7 +26,7 @@
     <com.android.settings.widget.SettingsMainSwitchPreference
         android:key="block" />
 
-    <com.android.settings.notification.app.NotificationFooterPreference
+    <com.android.settingslib.widget.FooterPreference
         android:key="block_desc" />
 
 
@@ -96,11 +96,11 @@
 
     </PreferenceCategory>
 
-    <com.android.settings.notification.app.NotificationFooterPreference
+    <com.android.settingslib.widget.FooterPreference
         android:key="desc"
         android:order="5000" />
 
-    <com.android.settings.notification.app.NotificationFooterPreference
+    <com.android.settingslib.widget.FooterPreference
         android:key="deleted"
         android:order="8000" />
 
diff --git a/res/xml/channel_notification_settings.xml b/res/xml/channel_notification_settings.xml
index 95f7944..97dcc26 100644
--- a/res/xml/channel_notification_settings.xml
+++ b/res/xml/channel_notification_settings.xml
@@ -116,11 +116,11 @@
         android:title="@string/app_settings_link"
         settings:allowDividerAbove="true"/>
 
-    <com.android.settings.notification.app.NotificationFooterPreference
+    <com.android.settingslib.widget.FooterPreference
         android:key="desc"
         android:order="100"/>
 
-    <com.android.settings.notification.app.NotificationFooterPreference
+    <com.android.settingslib.widget.FooterPreference
         android:key="block_desc"
         android:order="110"
         settings:allowDividerAbove="false"/>
diff --git a/res/xml/connected_devices_advanced.xml b/res/xml/connected_devices_advanced.xml
index 3ff7d99..85e4a76 100644
--- a/res/xml/connected_devices_advanced.xml
+++ b/res/xml/connected_devices_advanced.xml
@@ -65,6 +65,13 @@
         android:icon="@drawable/ic_folder_vd_theme_24"
         android:title="@string/bluetooth_show_files_received_via_bluetooth"/>
 
+    <SwitchPreference
+        android:key="uwb_settings"
+        android:title="@string/uwb_settings_title"
+        android:order="100"
+        android:summary="@string/summary_placeholder"
+        settings:controller="com.android.settings.uwb.UwbPreferenceController"/>
+
     <PreferenceCategory
         android:key="dashboard_tile_placeholder"
         android:order="-8"/>
diff --git a/res/xml/conversation_notification_settings.xml b/res/xml/conversation_notification_settings.xml
index ea555c2..7e475be 100644
--- a/res/xml/conversation_notification_settings.xml
+++ b/res/xml/conversation_notification_settings.xml
@@ -58,7 +58,7 @@
         android:summary="@string/demote_conversation_summary"
         settings:allowDividerAbove="true"/>
 
-    <com.android.settings.notification.app.NotificationFooterPreference
+    <com.android.settingslib.widget.FooterPreference
         android:key="block_desc"
         settings:allowDividerAbove="false"/>
 
diff --git a/res/xml/date_time_prefs.xml b/res/xml/date_time_prefs.xml
index 6fc0b25..47056df 100644
--- a/res/xml/date_time_prefs.xml
+++ b/res/xml/date_time_prefs.xml
@@ -53,11 +53,10 @@
         settings:keywords="@string/keywords_time_zone"/>
 
     <!-- This preference gets removed if location-based time zone detection is not supported -->
-    <com.android.settingslib.RestrictedSwitchPreference
+    <SwitchPreference
         android:key="location_time_zone_detection"
         android:title="@string/location_time_zone_detection_toggle_title"
         settings:controller="com.android.settings.datetime.LocationTimeZoneDetectionPreferenceController"
-        settings:userRestriction="no_config_date_time"
     />
 
     <PreferenceCategory
diff --git a/res/xml/location_settings.xml b/res/xml/location_settings.xml
index cae128b..a950b3a 100644
--- a/res/xml/location_settings.xml
+++ b/res/xml/location_settings.xml
@@ -27,14 +27,6 @@
         settings:controller=
             "com.android.settings.location.RecentLocationAccessPreferenceController"/>
 
-    <Preference
-        android:key="recent_location_access_see_all_button"
-        android:title="@string/location_recent_location_access_see_all"
-        android:icon="@drawable/ic_chevron_right_24dp"
-        android:fragment="com.android.settings.location.RecentLocationAccessSeeAllFragment"
-        settings:controller="com.android.settings.location.RecentLocationAccessSeeAllButtonPreferenceController"
-        settings:searchable="false"/>
-
     <PreferenceCategory
         android:key="location_advanced_settings"
         android:layout="@layout/preference_category_no_label"
@@ -65,7 +57,7 @@
         <Preference
             android:fragment="com.android.settings.location.LocationServices"
             android:key="location_services"
-            android:icon="@drawable/baseline_near_me"
+            android:icon="@drawable/ic_chevron_right_24dp"
             android:title="@string/location_services_preference_title"
             settings:controller="com.android.settings.location.LocationServicesPreferenceController"/>
 
diff --git a/res/xml/location_settings_personal.xml b/res/xml/location_settings_personal.xml
index 726a96c..a798899 100644
--- a/res/xml/location_settings_personal.xml
+++ b/res/xml/location_settings_personal.xml
@@ -28,14 +28,6 @@
         settings:controller=
             "com.android.settings.location.RecentLocationAccessPreferenceController"/>
 
-    <Preference
-        android:key="recent_location_access_see_all_button"
-        android:title="@string/location_recent_location_access_see_all"
-        android:icon="@drawable/ic_chevron_right_24dp"
-        android:fragment="com.android.settings.location.RecentLocationAccessSeeAllFragment"
-        settings:controller="com.android.settings.location.RecentLocationAccessSeeAllButtonPreferenceController"
-        settings:searchable="false"/>
-
     <!-- This preference category gets removed if new_recent_location_ui is disabled -->
     <Preference
         android:key="app_level_permissions"
diff --git a/res/xml/location_settings_workprofile.xml b/res/xml/location_settings_workprofile.xml
index 99ccf14..62ec0cb 100644
--- a/res/xml/location_settings_workprofile.xml
+++ b/res/xml/location_settings_workprofile.xml
@@ -28,15 +28,6 @@
         settings:controller=
             "com.android.settings.location.RecentLocationAccessPreferenceController"/>
 
-    <Preference
-        android:key="recent_location_access_see_all_button"
-        android:title="@string/location_recent_location_access_see_all"
-        android:icon="@drawable/ic_chevron_right_24dp"
-        android:fragment="com.android.settings.location.RecentLocationAccessSeeAllFragment"
-        settings:controller="com.android.settings.location.RecentLocationAccessSeeAllButtonPreferenceController"
-        settings:forWork="true"
-        settings:searchable="false"/>
-
     <com.android.settingslib.RestrictedSwitchPreference
         android:key="managed_profile_location_switch"
         android:title="@string/managed_profile_location_switch_title"
diff --git a/res/xml/notification_access_settings.xml b/res/xml/notification_access_settings.xml
index b523d7d..94c90b4 100644
--- a/res/xml/notification_access_settings.xml
+++ b/res/xml/notification_access_settings.xml
@@ -25,9 +25,9 @@
 
     <PreferenceCategory
         android:key="allowed"
-        android:title="@string/app_permission_summary_allowed"/>
+        android:title="@string/notification_listener_allowed"/>
 
     <PreferenceCategory
         android:key="not_allowed"
-        android:title="@string/app_permission_summary_not_allowed"/>
+        android:title="@string/notification_listener_not_allowed"/>
 </PreferenceScreen>
diff --git a/res/xml/notification_group_settings.xml b/res/xml/notification_group_settings.xml
index cbe23c6..e714759 100644
--- a/res/xml/notification_group_settings.xml
+++ b/res/xml/notification_group_settings.xml
@@ -31,9 +31,9 @@
         android:title="@string/app_settings_link"
         settings:allowDividerAbove="true"/>
 
-    <com.android.settings.notification.NotificationFooterPreference
+    <com.android.settingslib.widget.FooterPreference
         android:key="desc" />
 
-    <com.android.settings.notification.NotificationFooterPreference
+    <com.android.settingslib.widget.FooterPreference
         android:key="block_desc" />
 </PreferenceScreen>
diff --git a/res/xml/security_dashboard_settings.xml b/res/xml/security_dashboard_settings.xml
index fd9f318..be1f34c 100644
--- a/res/xml/security_dashboard_settings.xml
+++ b/res/xml/security_dashboard_settings.xml
@@ -55,6 +55,12 @@
             android:title="@string/security_settings_face_preference_title"
             android:summary="@string/summary_placeholder"
             settings:keywords="@string/keywords_face_settings" />
+
+        <Preference
+            android:key="biometric_settings"
+            android:title="@string/security_settings_biometric_preference_title"
+            android:summary="@string/summary_placeholder"
+            settings:keywords="@string/keywords_biometric_settings" />
     </PreferenceCategory>
 
     <!-- work profile security section -->
@@ -91,6 +97,11 @@
             android:title="@string/security_settings_face_preference_title"
             android:summary="@string/summary_placeholder" />
 
+        <Preference
+            android:key="biometric_settings_profile"
+            android:title="@string/security_settings_biometric_preference_title"
+            android:summary="@string/summary_placeholder" />
+
     </PreferenceCategory>
 
     <PreferenceCategory
diff --git a/res/xml/security_settings_combined_biometric.xml b/res/xml/security_settings_combined_biometric.xml
new file mode 100644
index 0000000..f7d0539
--- /dev/null
+++ b/res/xml/security_settings_combined_biometric.xml
@@ -0,0 +1,69 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<PreferenceScreen
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:settings="http://schemas.android.com/apk/res-auto"
+    android:title="@string/security_settings_biometric_preference_title">
+
+    <com.android.settingslib.widget.TopIntroPreference
+        android:title="@string/biometric_settings_intro" />
+
+    <PreferenceCategory
+        android:key="biometric_ways_to_unlock"
+        android:title="@string/biometric_settings_category_ways_to_unlock">
+
+        <Preference
+            android:key="biometric_fingerprint_settings"
+            android:title="@string/security_settings_fingerprint_preference_title"
+            android:summary="@string/summary_placeholder"
+            settings:keywords="@string/keywords_fingerprint_settings"
+            settings:controller="com.android.settings.biometrics.combination.BiometricFingerprintStatusPreferenceController" />
+
+        <Preference
+            android:key="biometric_face_settings"
+            android:title="@string/security_settings_face_preference_title"
+            android:summary="@string/summary_placeholder"
+            settings:keywords="@string/keywords_face_settings"
+            settings:controller="com.android.settings.biometrics.combination.BiometricFaceStatusPreferenceController" />
+
+    </PreferenceCategory>
+
+    <PreferenceCategory
+        android:key="biometric_ways_to_use"
+        android:title="@string/biometric_settings_category_ways_to_use">
+
+        <com.android.settingslib.RestrictedSwitchPreference
+            android:key="biometric_settings_biometric_keyguard"
+            android:title="@string/biometric_settings_use_biometric_unlock_phone"
+            settings:keywords="@string/keywords_biometric_unlock"
+            settings:controller="com.android.settings.biometrics.combination.BiometricSettingsKeyguardPreferenceController"/>
+
+        <SwitchPreference
+            android:key="biometric_settings_biometric_app"
+            android:title="@string/biometric_settings_use_biometric_for_apps"
+            settings:keywords="@string/keywords_biometric_unlock"
+            settings:controller="com.android.settings.biometrics.combination.BiometricSettingsAppPreferenceController"/>
+
+    </PreferenceCategory>
+
+    <SwitchPreference
+        android:key="biometric_setting_lockdown_enabled"
+        android:title="@string/lockdown_settings_title"
+        android:summary="@string/lockdown_settings_summary"
+        settings:controller="com.android.settings.security.LockdownButtonPreferenceController" />
+
+</PreferenceScreen>
\ No newline at end of file
diff --git a/res/xml/security_settings_combined_biometric_profile.xml b/res/xml/security_settings_combined_biometric_profile.xml
new file mode 100644
index 0000000..5711152
--- /dev/null
+++ b/res/xml/security_settings_combined_biometric_profile.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<PreferenceScreen
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:settings="http://schemas.android.com/apk/res-auto"
+    android:title="@string/security_settings_biometric_preference_title">
+
+    <com.android.settingslib.widget.TopIntroPreference
+        android:title="@string/biometric_settings_intro" />
+
+    <PreferenceCategory
+        android:key="biometric_ways_to_unlock"
+        android:title="@string/biometric_settings_category_ways_to_unlock">
+
+        <Preference
+            android:key="biometric_fingerprint_settings_profile"
+            android:title="@string/security_settings_fingerprint_preference_title"
+            android:summary="@string/summary_placeholder"
+            settings:keywords="@string/keywords_fingerprint_settings"
+            settings:controller="com.android.settings.biometrics.combination.BiometricFingerprintProfileStatusPreferenceController" />
+
+        <Preference
+            android:key="biometric_face_settings_profile"
+            android:title="@string/security_settings_face_preference_title"
+            android:summary="@string/summary_placeholder"
+            settings:keywords="@string/keywords_face_settings"
+            settings:controller="com.android.settings.biometrics.combination.BiometricFaceProfileStatusPreferenceController" />
+
+    </PreferenceCategory>
+
+    <PreferenceCategory
+        android:key="biometric_ways_to_use"
+        android:title="@string/biometric_settings_category_ways_to_use">
+
+        <SwitchPreference
+            android:key="biometric_settings_biometric_app_profile"
+            android:title="@string/biometric_settings_use_biometric_for_apps"
+            settings:keywords="@string/keywords_biometric_unlock"
+            settings:controller="com.android.settings.biometrics.combination.BiometricSettingsAppPreferenceController"/>
+
+    </PreferenceCategory>
+</PreferenceScreen>
\ No newline at end of file
diff --git a/res/xml/security_settings_face.xml b/res/xml/security_settings_face.xml
index 1fc1ca8..131f222 100644
--- a/res/xml/security_settings_face.xml
+++ b/res/xml/security_settings_face.xml
@@ -31,7 +31,8 @@
 
     <PreferenceCategory
         android:key="security_settings_face_unlock_category"
-        android:title="@string/security_settings_face_settings_use_face_category">
+        android:title="@string/security_settings_face_settings_use_face_category"
+        settings:controller="com.android.settings.biometrics.face.FaceUnlockCategoryPreferenceController">
         <com.android.settingslib.RestrictedSwitchPreference
             android:key="security_settings_face_keyguard"
             android:title="@string/security_settings_face_settings_use_face_unlock_phone"
@@ -66,6 +67,13 @@
             android:summary="@string/security_settings_face_settings_require_confirmation_details"
             settings:keywords="@string/keywords_face_unlock"
             settings:controller="com.android.settings.biometrics.face.FaceSettingsConfirmPreferenceController"/>
+
+        <com.android.settingslib.RestrictedSwitchPreference
+            android:key="biometric_settings_lockscreen_bypass"
+            android:title="@string/lockscreen_bypass_title"
+            android:summary="@string/lockscreen_bypass_summary"
+            settings:keywords="@string/keywords_lockscreen_bypass"
+            settings:controller="com.android.settings.biometrics.face.FaceSettingsLockscreenBypassPreferenceController" />
     </PreferenceCategory>
 
     <PreferenceCategory
diff --git a/src/com/android/settings/Settings.java b/src/com/android/settings/Settings.java
index 48793e9..c89402c 100644
--- a/src/com/android/settings/Settings.java
+++ b/src/com/android/settings/Settings.java
@@ -38,6 +38,8 @@
     public static class CreateShortcutActivity extends SettingsActivity { /* empty */ }
     public static class FaceSettingsActivity extends SettingsActivity { /* empty */ }
     public static class FingerprintSettingsActivity extends SettingsActivity { /* empty */ }
+    public static class CombinedBiometricSettingsActivity extends SettingsActivity { /* empty */ }
+    public static class CombinedBiometricProfileSettingsActivity extends SettingsActivity { /* empty */ }
     public static class TetherSettingsActivity extends SettingsActivity {
         // TODO(b/147675042): Clean the override up when we enable the new Fragment persistently.
         @Override
diff --git a/src/com/android/settings/Utils.java b/src/com/android/settings/Utils.java
index 391ee90..8418315 100644
--- a/src/com/android/settings/Utils.java
+++ b/src/com/android/settings/Utils.java
@@ -842,6 +842,13 @@
     }
 
     /**
+     * Return true if the device supports multiple biometrics authentications.
+     */
+    public static boolean isMultipleBiometricsSupported(Context context) {
+        return hasFingerprintHardware(context) && hasFaceHardware(context);
+    }
+
+    /**
      * Launches an intent which may optionally have a user id defined.
      * @param fragment Fragment to use to launch the activity.
      * @param intent Intent to launch.
diff --git a/src/com/android/settings/accessibility/AccessibilityEditDialogUtils.java b/src/com/android/settings/accessibility/AccessibilityEditDialogUtils.java
index 5402a9b..26c2313 100644
--- a/src/com/android/settings/accessibility/AccessibilityEditDialogUtils.java
+++ b/src/com/android/settings/accessibility/AccessibilityEditDialogUtils.java
@@ -26,6 +26,7 @@
 import android.graphics.drawable.Drawable;
 import android.text.Spannable;
 import android.text.SpannableString;
+import android.text.SpannableStringBuilder;
 import android.text.TextUtils;
 import android.text.method.LinkMovementMethod;
 import android.text.style.ImageSpan;
@@ -320,8 +321,13 @@
     }
 
     private static CharSequence retrieveSummary(Context context, int lineHeight) {
-        return AccessibilityUtil.isFloatingMenuEnabled(context)
-                ? getSummaryStringWithLink(context) : getSummaryStringWithIcon(context, lineHeight);
+        final SpannableStringBuilder sb = new SpannableStringBuilder();
+        if (!AccessibilityUtil.isFloatingMenuEnabled(context)) {
+            sb.append(getSummaryStringWithIcon(context, lineHeight));
+            sb.append("\n\n");
+        }
+        sb.append(getCustomizeAccessibilityButtonLink(context));
+        return sb;
     }
 
     private static int retrieveSoftwareShortcutImageResId(Context context) {
@@ -330,7 +336,7 @@
                 : R.drawable.accessibility_shortcut_type_software;
     }
 
-    private static CharSequence getSummaryStringWithLink(Context context) {
+    private static CharSequence getCustomizeAccessibilityButtonLink(Context context) {
         final View.OnClickListener linkListener = v -> new SubSettingLauncher(context)
                 .setDestination(AccessibilityButtonFragment.class.getName())
                 .setSourceMetricsCategory(
diff --git a/src/com/android/settings/biometrics/BiometricEnrollActivity.java b/src/com/android/settings/biometrics/BiometricEnrollActivity.java
index cede6a0..0a2e5fe 100644
--- a/src/com/android/settings/biometrics/BiometricEnrollActivity.java
+++ b/src/com/android/settings/biometrics/BiometricEnrollActivity.java
@@ -16,6 +16,9 @@
 
 package com.android.settings.biometrics;
 
+import static android.provider.Settings.ACTION_BIOMETRIC_ENROLL;
+import static android.provider.Settings.EXTRA_BIOMETRIC_AUTHENTICATORS_ALLOWED;
+
 import android.annotation.NonNull;
 import android.app.admin.DevicePolicyManager;
 import android.app.settings.SettingsEnums;
@@ -24,6 +27,7 @@
 import android.content.res.Resources;
 import android.hardware.biometrics.BiometricManager;
 import android.hardware.biometrics.BiometricManager.Authenticators;
+import android.hardware.biometrics.BiometricManager.BiometricError;
 import android.hardware.face.FaceManager;
 import android.hardware.face.FaceSensorPropertiesInternal;
 import android.hardware.fingerprint.FingerprintManager;
@@ -31,11 +35,11 @@
 import android.os.Bundle;
 import android.os.UserHandle;
 import android.os.UserManager;
-import android.provider.Settings;
 import android.util.Log;
 
 import androidx.annotation.Nullable;
 
+import com.android.internal.util.FrameworkStatsLog;
 import com.android.internal.widget.LockPatternUtils;
 import com.android.settings.R;
 import com.android.settings.SetupWizardUtils;
@@ -68,12 +72,14 @@
     public static final String EXTRA_SKIP_INTRO = "skip_intro";
 
     private static final String SAVED_STATE_CONFIRMING_CREDENTIALS = "confirming_credentials";
+    private static final String SAVED_STATE_ENROLL_ACTION_LOGGED = "enroll_action_logged";
     private static final String SAVED_STATE_GK_PW_HANDLE = "gk_pw_handle";
 
     public static final class InternalActivity extends BiometricEnrollActivity {}
 
     private int mUserId = UserHandle.myUserId();
     private boolean mConfirmingCredentials;
+    private boolean mIsEnrollActionLogged;
     private boolean mIsFaceEnrollable;
     private boolean mIsFingerprintEnrollable;
     @Nullable private Long mGkPwHandle;
@@ -91,15 +97,44 @@
         }
 
         if (savedInstanceState != null) {
-            mConfirmingCredentials = savedInstanceState
-                    .getBoolean(SAVED_STATE_CONFIRMING_CREDENTIALS, false);
+            mConfirmingCredentials = savedInstanceState.getBoolean(
+                    SAVED_STATE_CONFIRMING_CREDENTIALS, false);
+            mIsEnrollActionLogged = savedInstanceState.getBoolean(
+                    SAVED_STATE_ENROLL_ACTION_LOGGED, false);
             if (savedInstanceState.containsKey(SAVED_STATE_GK_PW_HANDLE)) {
                 mGkPwHandle = savedInstanceState.getLong(SAVED_STATE_GK_PW_HANDLE);
             }
         }
 
-        // Put the theme in the intent so it gets propagated to other activities in the flow
+        // Log a framework stats event if this activity was launched via intent action.
         final Intent intent = getIntent();
+        if (!mIsEnrollActionLogged && ACTION_BIOMETRIC_ENROLL.equals(intent.getAction())) {
+            mIsEnrollActionLogged = true;
+
+            // Get the current status for each authenticator type.
+            @BiometricError final int strongBiometricStatus;
+            @BiometricError final int weakBiometricStatus;
+            @BiometricError final int deviceCredentialStatus;
+            final BiometricManager bm = getSystemService(BiometricManager.class);
+            if (bm != null) {
+                strongBiometricStatus = bm.canAuthenticate(Authenticators.BIOMETRIC_STRONG);
+                weakBiometricStatus = bm.canAuthenticate(Authenticators.BIOMETRIC_WEAK);
+                deviceCredentialStatus = bm.canAuthenticate(Authenticators.DEVICE_CREDENTIAL);
+            } else {
+                strongBiometricStatus = BiometricManager.BIOMETRIC_ERROR_NO_HARDWARE;
+                weakBiometricStatus = BiometricManager.BIOMETRIC_ERROR_NO_HARDWARE;
+                deviceCredentialStatus = BiometricManager.BIOMETRIC_ERROR_NO_HARDWARE;
+            }
+
+            FrameworkStatsLog.write(FrameworkStatsLog.AUTH_ENROLL_ACTION_INVOKED,
+                    strongBiometricStatus == BiometricManager.BIOMETRIC_SUCCESS,
+                    weakBiometricStatus == BiometricManager.BIOMETRIC_SUCCESS,
+                    deviceCredentialStatus == BiometricManager.BIOMETRIC_SUCCESS,
+                    intent.hasExtra(EXTRA_BIOMETRIC_AUTHENTICATORS_ALLOWED),
+                    intent.getIntExtra(EXTRA_BIOMETRIC_AUTHENTICATORS_ALLOWED, 0));
+        }
+
+        // Put the theme in the intent so it gets propagated to other activities in the flow
         if (intent.getStringExtra(WizardManagerHelper.EXTRA_THEME) == null) {
             intent.putExtra(
                     WizardManagerHelper.EXTRA_THEME,
@@ -108,7 +143,7 @@
 
         // Default behavior is to enroll BIOMETRIC_WEAK or above. See ACTION_BIOMETRIC_ENROLL.
         final int authenticators = intent.getIntExtra(
-                Settings.EXTRA_BIOMETRIC_AUTHENTICATORS_ALLOWED, Authenticators.BIOMETRIC_WEAK);
+                EXTRA_BIOMETRIC_AUTHENTICATORS_ALLOWED, Authenticators.BIOMETRIC_WEAK);
 
         Log.d(TAG, "Authenticators: " + authenticators);
 
@@ -132,7 +167,7 @@
         } else {
             // If the caller is not setup wizard, and the user has something enrolled, finish.
             final BiometricManager bm = getSystemService(BiometricManager.class);
-            final @BiometricManager.BiometricError int result = bm.canAuthenticate(authenticators);
+            final @BiometricError int result = bm.canAuthenticate(authenticators);
             if (result != BiometricManager.BIOMETRIC_ERROR_NONE_ENROLLED) {
                 Log.e(TAG, "Unexpected result: " + result);
                 finish();
@@ -159,6 +194,7 @@
     protected void onSaveInstanceState(@NonNull Bundle outState) {
         super.onSaveInstanceState(outState);
         outState.putBoolean(SAVED_STATE_CONFIRMING_CREDENTIALS, mConfirmingCredentials);
+        outState.putBoolean(SAVED_STATE_ENROLL_ACTION_LOGGED, mIsEnrollActionLogged);
         if (mGkPwHandle != null) {
             outState.putLong(SAVED_STATE_GK_PW_HANDLE, mGkPwHandle);
         }
diff --git a/src/com/android/settings/biometrics/BiometricStatusPreferenceController.java b/src/com/android/settings/biometrics/BiometricStatusPreferenceController.java
index 2a3bfb2..70f0baf 100644
--- a/src/com/android/settings/biometrics/BiometricStatusPreferenceController.java
+++ b/src/com/android/settings/biometrics/BiometricStatusPreferenceController.java
@@ -122,6 +122,9 @@
         final String clazz = hasEnrolledBiometrics() ? getSettingsClassName()
                 : getEnrollClassName();
         intent.setClassName(SETTINGS_PACKAGE_NAME, clazz);
+        if (!preference.getExtras().isEmpty()) {
+            intent.putExtras(preference.getExtras());
+        }
         intent.putExtra(Intent.EXTRA_USER_ID, userId);
         intent.putExtra(EXTRA_FROM_SETTINGS_SUMMARY, true);
         context.startActivity(intent);
diff --git a/src/com/android/settings/biometrics/combination/BiometricFaceProfileStatusPreferenceController.java b/src/com/android/settings/biometrics/combination/BiometricFaceProfileStatusPreferenceController.java
new file mode 100644
index 0000000..1dbfa64
--- /dev/null
+++ b/src/com/android/settings/biometrics/combination/BiometricFaceProfileStatusPreferenceController.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2021 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.combination;
+
+import android.content.Context;
+import android.os.UserHandle;
+
+/**
+ * Preference controller for face settings within the biometrics settings page of work profile,
+ * that controls the ability to unlock the phone with face authentication.
+ */
+public class BiometricFaceProfileStatusPreferenceController extends
+        BiometricFaceStatusPreferenceController {
+
+    public BiometricFaceProfileStatusPreferenceController(Context context, String key) {
+        super(context, key);
+    }
+
+    @Override
+    protected boolean isUserSupported() {
+        return mProfileChallengeUserId != UserHandle.USER_NULL
+                && mLockPatternUtils.isSeparateProfileChallengeAllowed(mProfileChallengeUserId);
+    }
+
+    @Override
+    protected int getUserId() {
+        return mProfileChallengeUserId;
+    }
+}
diff --git a/src/com/android/settings/biometrics/combination/BiometricFaceStatusPreferenceController.java b/src/com/android/settings/biometrics/combination/BiometricFaceStatusPreferenceController.java
new file mode 100644
index 0000000..e4b210e
--- /dev/null
+++ b/src/com/android/settings/biometrics/combination/BiometricFaceStatusPreferenceController.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2021 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.combination;
+
+import android.content.Context;
+
+import com.android.settings.Utils;
+import com.android.settings.biometrics.face.FaceStatusPreferenceController;
+
+/**
+ * Preference controller for face settings within the biometrics settings page, that controls the
+ * ability to unlock the phone with face authentication.
+ */
+public class BiometricFaceStatusPreferenceController extends FaceStatusPreferenceController {
+
+    public BiometricFaceStatusPreferenceController(Context context, String key) {
+        super(context, key);
+    }
+
+    @Override
+    protected boolean isDeviceSupported() {
+        return Utils.hasFaceHardware(mContext);
+    }
+}
diff --git a/src/com/android/settings/biometrics/combination/BiometricFingerprintProfileStatusPreferenceController.java b/src/com/android/settings/biometrics/combination/BiometricFingerprintProfileStatusPreferenceController.java
new file mode 100644
index 0000000..5477c9d
--- /dev/null
+++ b/src/com/android/settings/biometrics/combination/BiometricFingerprintProfileStatusPreferenceController.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2021 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.combination;
+
+import android.content.Context;
+import android.os.UserHandle;
+
+/**
+ * Preference controller for fingerprint settings within the biometrics settings page, that controls
+ * the ability to unlock the phone with fingerprint.
+ */
+public class BiometricFingerprintProfileStatusPreferenceController extends
+        BiometricFingerprintStatusPreferenceController {
+
+    public BiometricFingerprintProfileStatusPreferenceController(Context context, String key) {
+        super(context, key);
+    }
+
+    @Override
+    protected boolean isUserSupported() {
+        return mProfileChallengeUserId != UserHandle.USER_NULL
+                && mLockPatternUtils.isSeparateProfileChallengeAllowed(mProfileChallengeUserId);
+    }
+
+    @Override
+    protected int getUserId() {
+        return mProfileChallengeUserId;
+    }
+}
diff --git a/src/com/android/settings/biometrics/combination/BiometricFingerprintStatusPreferenceController.java b/src/com/android/settings/biometrics/combination/BiometricFingerprintStatusPreferenceController.java
new file mode 100644
index 0000000..fd742ff
--- /dev/null
+++ b/src/com/android/settings/biometrics/combination/BiometricFingerprintStatusPreferenceController.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2021 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.combination;
+
+import android.content.Context;
+
+import com.android.settings.Utils;
+import com.android.settings.biometrics.fingerprint.FingerprintStatusPreferenceController;
+
+/**
+ * Preference controller for fingerprint settings within the biometrics settings page of work
+ * profile, that controls the ability to unlock the phone with fingerprint.
+ */
+public class BiometricFingerprintStatusPreferenceController extends
+        FingerprintStatusPreferenceController {
+
+    public BiometricFingerprintStatusPreferenceController(Context context, String key) {
+        super(context, key);
+    }
+
+    @Override
+    protected boolean isDeviceSupported() {
+        return Utils.hasFingerprintHardware(mContext);
+    }
+}
diff --git a/src/com/android/settings/biometrics/combination/BiometricSettingsAppPreferenceController.java b/src/com/android/settings/biometrics/combination/BiometricSettingsAppPreferenceController.java
new file mode 100644
index 0000000..9107e1b
--- /dev/null
+++ b/src/com/android/settings/biometrics/combination/BiometricSettingsAppPreferenceController.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2021 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.combination;
+
+import static android.provider.Settings.Secure.BIOMETRIC_APP_ENABLED;
+
+import android.app.admin.DevicePolicyManager;
+import android.content.Context;
+import android.hardware.face.FaceManager;
+import android.hardware.fingerprint.FingerprintManager;
+import android.provider.Settings;
+
+import com.android.settings.Utils;
+import com.android.settings.core.TogglePreferenceController;
+import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
+import com.android.settingslib.RestrictedLockUtilsInternal;
+
+/**
+ * Preference controller that controls whether the biometrics authentication to be used in apps.
+ */
+public class BiometricSettingsAppPreferenceController extends TogglePreferenceController {
+    private static final int ON = 1;
+    private static final int OFF = 0;
+    private static final int DEFAULT = ON;
+
+    private int mUserId;
+    private FaceManager mFaceManager;
+    private FingerprintManager mFingerprintManager;
+
+    public BiometricSettingsAppPreferenceController(Context context, String key) {
+        super(context, key);
+        mFaceManager = Utils.getFaceManagerOrNull(context);
+        mFingerprintManager = Utils.getFingerprintManagerOrNull(context);
+    }
+
+    protected EnforcedAdmin getRestrictingAdmin() {
+        return RestrictedLockUtilsInternal.checkIfKeyguardFeaturesDisabled(mContext,
+                DevicePolicyManager.KEYGUARD_DISABLE_BIOMETRICS, mUserId);
+    }
+
+    public void setUserId(int userId) {
+        mUserId = userId;
+    }
+
+    @Override
+    public boolean isChecked() {
+        return Settings.Secure.getIntForUser(mContext.getContentResolver(), BIOMETRIC_APP_ENABLED,
+                DEFAULT, mUserId) == ON;
+    }
+
+    @Override
+    public boolean setChecked(boolean isChecked) {
+        return Settings.Secure.putIntForUser(mContext.getContentResolver(), BIOMETRIC_APP_ENABLED,
+                isChecked ? ON : OFF, mUserId);
+    }
+
+    @Override
+    public int getAvailabilityStatus() {
+        if (mFaceManager == null || mFingerprintManager == null) {
+            return AVAILABLE_UNSEARCHABLE;
+        }
+        // This preference will be available only if the user has registered either face auth
+        // or fingerprint.
+        final boolean hasFaceEnrolledUser = mFaceManager.hasEnrolledTemplates(mUserId);
+        final boolean hasFingerprintEnrolledUser =
+                mFingerprintManager.hasEnrolledTemplates(mUserId);
+        if (hasFaceEnrolledUser || hasFingerprintEnrolledUser) {
+            return AVAILABLE;
+        } else {
+            return AVAILABLE_UNSEARCHABLE;
+        }
+    }
+}
diff --git a/src/com/android/settings/biometrics/combination/BiometricSettingsKeyguardPreferenceController.java b/src/com/android/settings/biometrics/combination/BiometricSettingsKeyguardPreferenceController.java
new file mode 100644
index 0000000..263134a
--- /dev/null
+++ b/src/com/android/settings/biometrics/combination/BiometricSettingsKeyguardPreferenceController.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2021 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.combination;
+
+import static android.provider.Settings.Secure.BIOMETRIC_KEYGUARD_ENABLED;
+
+import android.app.admin.DevicePolicyManager;
+import android.content.Context;
+import android.provider.Settings;
+
+import com.android.settings.core.TogglePreferenceController;
+import com.android.settingslib.RestrictedLockUtils;
+import com.android.settingslib.RestrictedLockUtilsInternal;
+
+/**
+ * Preference controller that controls whether the biometrics authentication to unlock the device.
+ */
+public class BiometricSettingsKeyguardPreferenceController extends TogglePreferenceController {
+    private static final int ON = 1;
+    private static final int OFF = 0;
+    private static final int DEFAULT = ON;
+
+    private int mUserId;
+
+    public BiometricSettingsKeyguardPreferenceController(Context context, String key) {
+        super(context, key);
+    }
+
+    protected RestrictedLockUtils.EnforcedAdmin getRestrictingAdmin() {
+        return RestrictedLockUtilsInternal.checkIfKeyguardFeaturesDisabled(mContext,
+                DevicePolicyManager.KEYGUARD_DISABLE_BIOMETRICS, mUserId);
+    }
+
+    public void setUserId(int userId) {
+        mUserId = userId;
+    }
+
+    @Override
+    public boolean isChecked() {
+        return Settings.Secure.getIntForUser(mContext.getContentResolver(),
+                BIOMETRIC_KEYGUARD_ENABLED, DEFAULT, mUserId) == ON;
+    }
+
+    @Override
+    public boolean setChecked(boolean isChecked) {
+        return Settings.Secure.putIntForUser(mContext.getContentResolver(),
+                BIOMETRIC_KEYGUARD_ENABLED, isChecked ? ON : OFF, mUserId);
+    }
+
+    @Override
+    public int getAvailabilityStatus() {
+        return getRestrictingAdmin() != null ? DISABLED_FOR_USER : AVAILABLE;
+    }
+}
diff --git a/src/com/android/settings/biometrics/combination/BiometricsSettingsBase.java b/src/com/android/settings/biometrics/combination/BiometricsSettingsBase.java
new file mode 100644
index 0000000..4260c7c
--- /dev/null
+++ b/src/com/android/settings/biometrics/combination/BiometricsSettingsBase.java
@@ -0,0 +1,197 @@
+/*
+ * Copyright (C) 2021 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.combination;
+
+import static android.app.Activity.RESULT_OK;
+
+import static com.android.settings.password.ChooseLockPattern.RESULT_FINISHED;
+
+import android.app.admin.DevicePolicyManager;
+import android.content.Context;
+import android.content.Intent;
+import android.hardware.face.FaceManager;
+import android.hardware.fingerprint.FingerprintManager;
+import android.os.Bundle;
+import android.os.UserHandle;
+import android.util.Log;
+
+import androidx.annotation.Nullable;
+import androidx.preference.Preference;
+
+import com.android.settings.R;
+import com.android.settings.Utils;
+import com.android.settings.biometrics.BiometricEnrollBase;
+import com.android.settings.biometrics.BiometricUtils;
+import com.android.settings.dashboard.DashboardFragment;
+import com.android.settings.password.ChooseLockGeneric;
+import com.android.settings.password.ChooseLockSettingsHelper;
+
+/**
+ * Base fragment with the confirming credential functionality for combined biometrics settings.
+ */
+public abstract class BiometricsSettingsBase extends DashboardFragment {
+
+    private static final int CONFIRM_REQUEST = 2001;
+    private static final int CHOOSE_LOCK_REQUEST = 2002;
+
+    private static final String SAVE_STATE_CONFIRM_CREDETIAL = "confirm_credential";
+
+    protected int mUserId;
+    protected long mFaceChallenge;
+    protected long mFingerprintChallenge;
+    protected int mFaceSensorId;
+    protected int mFingerprintSensorId;
+    protected long mGkPwHandle;
+    private boolean mConfirmCredential;
+    @Nullable private FaceManager mFaceManager;
+    @Nullable private FingerprintManager mFingerprintManager;
+
+    @Override
+    public void onAttach(Context context) {
+        super.onAttach(context);
+        mUserId = getActivity().getIntent().getIntExtra(Intent.EXTRA_USER_ID,
+                UserHandle.myUserId());
+    }
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        mFaceManager = Utils.getFaceManagerOrNull(getActivity());
+        mFingerprintManager = Utils.getFingerprintManagerOrNull(getActivity());
+
+        if (BiometricUtils.containsGatekeeperPasswordHandle(getIntent())) {
+            mGkPwHandle = BiometricUtils.getGatekeeperPasswordHandle(getIntent());
+        }
+
+        if (savedInstanceState != null) {
+            mConfirmCredential = savedInstanceState.getBoolean(SAVE_STATE_CONFIRM_CREDETIAL);
+            if (savedInstanceState.containsKey(
+                    ChooseLockSettingsHelper.EXTRA_KEY_REQUEST_GK_PW_HANDLE)) {
+                mGkPwHandle = savedInstanceState.getLong(
+                        ChooseLockSettingsHelper.EXTRA_KEY_REQUEST_GK_PW_HANDLE);
+            }
+        }
+
+        if (mGkPwHandle == 0L && !mConfirmCredential) {
+            mConfirmCredential = true;
+            launchChooseOrConfirmLock();
+        }
+    }
+
+    @Override
+    public void onDestroy() {
+        super.onDestroy();
+        if (getActivity().isFinishing()) {
+            mFaceManager.revokeChallenge(mFaceSensorId, mUserId, mFaceChallenge);
+            mFingerprintManager.revokeChallenge(mUserId, mFingerprintChallenge);
+            BiometricUtils.removeGatekeeperPasswordHandle(getActivity(), mGkPwHandle);
+        }
+    }
+
+    @Override
+    public boolean onPreferenceTreeClick(Preference preference) {
+        final String key = preference.getKey();
+        if (getFacePreferenceKey().equals(key)) {
+            final byte[] token = BiometricUtils.requestGatekeeperHat(getActivity(), mGkPwHandle,
+                    mUserId, mFaceChallenge);
+            final Bundle extras = preference.getExtras();
+            extras.putByteArray(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN, token);
+            extras.putInt(BiometricEnrollBase.EXTRA_KEY_SENSOR_ID, mFaceSensorId);
+            extras.putLong(BiometricEnrollBase.EXTRA_KEY_CHALLENGE, mFaceChallenge);
+        } else if (getFingerprintPreferenceKey().equals(key)) {
+            final byte[] token = BiometricUtils.requestGatekeeperHat(getActivity(), mGkPwHandle,
+                    mUserId, mFingerprintChallenge);
+            final Bundle extras = preference.getExtras();
+            extras.putByteArray(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN, token);
+            extras.putLong(BiometricEnrollBase.EXTRA_KEY_CHALLENGE, mFingerprintChallenge);
+        }
+        return super.onPreferenceTreeClick(preference);
+    }
+
+    @Override
+    public void onSaveInstanceState(Bundle outState) {
+        super.onSaveInstanceState(outState);
+        outState.putBoolean(SAVE_STATE_CONFIRM_CREDETIAL, mConfirmCredential);
+        if (mGkPwHandle != 0L) {
+            outState.putLong(ChooseLockSettingsHelper.EXTRA_KEY_REQUEST_GK_PW_HANDLE, mGkPwHandle);
+        }
+    }
+
+    @Override
+    public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
+        super.onActivityResult(requestCode, resultCode, data);
+        if (requestCode == CONFIRM_REQUEST || requestCode == CHOOSE_LOCK_REQUEST) {
+            mConfirmCredential = false;
+            if (resultCode == RESULT_FINISHED || resultCode == RESULT_OK) {
+                if (data != null && BiometricUtils.containsGatekeeperPasswordHandle(data)) {
+                    mGkPwHandle = BiometricUtils.getGatekeeperPasswordHandle(data);
+                    mFaceManager.generateChallenge((sensorId, challenge) -> {
+                        mFaceSensorId = sensorId;
+                        mFaceChallenge = challenge;
+                    });
+                    mFingerprintManager.generateChallenge(mUserId, (sensorId, challenge) -> {
+                        mFingerprintSensorId = sensorId;
+                        mFingerprintChallenge = challenge;
+                    });
+                } else {
+                    Log.d(getLogTag(), "Data null or GK PW missing.");
+                    finish();
+                }
+            } else {
+                Log.d(getLogTag(), "Password not confirmed.");
+                finish();
+            }
+        }
+    }
+
+    /**
+     * Get the preference key of face for passing through credential data to face settings.
+     */
+    public abstract String getFacePreferenceKey();
+
+    /**
+     * Get the preference key of face for passing through credential data to face settings.
+     */
+    public abstract String getFingerprintPreferenceKey();
+
+    private void launchChooseOrConfirmLock() {
+        final ChooseLockSettingsHelper.Builder builder =
+                new ChooseLockSettingsHelper.Builder(getActivity(), this)
+                        .setRequestCode(CONFIRM_REQUEST)
+                        .setTitle(getString(R.string.security_settings_biometric_preference_title))
+                        .setRequestGatekeeperPasswordHandle(true)
+                        .setForegroundOnly(true)
+                        .setReturnCredentials(true);
+        if (mUserId != UserHandle.USER_NULL) {
+            builder.setUserId(mUserId);
+        }
+        final boolean launched = builder.show();
+
+        if (!launched) {
+            Intent intent = BiometricUtils.getChooseLockIntent(getActivity(), getIntent());
+            intent.putExtra(ChooseLockGeneric.ChooseLockGenericFragment.MINIMUM_QUALITY_KEY,
+                    DevicePolicyManager.PASSWORD_QUALITY_SOMETHING);
+            intent.putExtra(ChooseLockGeneric.ChooseLockGenericFragment.HIDE_DISABLED_PREFS, true);
+            intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_REQUEST_GK_PW_HANDLE, true);
+            intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_FOR_BIOMETRICS, true);
+
+            if (mUserId != UserHandle.USER_NULL) {
+                intent.putExtra(Intent.EXTRA_USER_ID, mUserId);
+            }
+            startActivityForResult(intent, CHOOSE_LOCK_REQUEST);
+        }
+    }
+}
diff --git a/src/com/android/settings/biometrics/combination/CombinedBiometricProfileSettings.java b/src/com/android/settings/biometrics/combination/CombinedBiometricProfileSettings.java
new file mode 100644
index 0000000..08c934d
--- /dev/null
+++ b/src/com/android/settings/biometrics/combination/CombinedBiometricProfileSettings.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2021 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.combination;
+
+import android.app.settings.SettingsEnums;
+import android.content.Context;
+
+import com.android.settings.R;
+import com.android.settings.search.BaseSearchIndexProvider;
+
+/**
+ * Settings screen for multiple biometrics used in work profile.
+ */
+public class CombinedBiometricProfileSettings extends BiometricsSettingsBase {
+    private static final String TAG = "BiometricProfileSetting";
+    private static final String KEY_FACE_SETTINGS = "biometric_face_settings_profile";
+    private static final String KEY_FINGERPRINT_SETTINGS = "biometric_fingerprint_settings_profile";
+
+    @Override
+    public void onAttach(Context context) {
+        super.onAttach(context);
+        use(BiometricSettingsAppPreferenceController.class).setUserId(mUserId);
+    }
+
+    @Override
+    protected int getPreferenceScreenResId() {
+        return R.xml.security_settings_combined_biometric_profile;
+    }
+
+    @Override
+    public String getFacePreferenceKey() {
+        return KEY_FACE_SETTINGS;
+    }
+
+    @Override
+    public String getFingerprintPreferenceKey() {
+        return KEY_FINGERPRINT_SETTINGS;
+    }
+
+    @Override
+    protected String getLogTag() {
+        return TAG;
+    }
+
+    @Override
+    public int getMetricsCategory() {
+        return SettingsEnums.COMBINED_BIOMETRIC_PROFILE;
+    }
+
+    public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
+            new BaseSearchIndexProvider(R.xml.security_settings_combined_biometric_profile);
+}
diff --git a/src/com/android/settings/biometrics/combination/CombinedBiometricProfileStatusPreferenceController.java b/src/com/android/settings/biometrics/combination/CombinedBiometricProfileStatusPreferenceController.java
new file mode 100644
index 0000000..e9cbcd8
--- /dev/null
+++ b/src/com/android/settings/biometrics/combination/CombinedBiometricProfileStatusPreferenceController.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2021 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.combination;
+
+import android.content.Context;
+import android.os.UserHandle;
+
+import com.android.settings.Settings;
+
+/**
+ * Preference controller for biometrics settings page of work profile, controlling the ability to
+ * unlock the phone with face and fingerprint.
+ */
+public class CombinedBiometricProfileStatusPreferenceController extends
+        CombinedBiometricStatusPreferenceController {
+
+    private static final String KEY_BIOMETRIC_SETTINGS = "biometric_settings_profile";
+
+    public CombinedBiometricProfileStatusPreferenceController(Context context) {
+        super(context, KEY_BIOMETRIC_SETTINGS);
+    }
+
+    public CombinedBiometricProfileStatusPreferenceController(Context context, String key) {
+        super(context, key);
+    }
+
+    @Override
+    protected boolean isUserSupported() {
+        return mProfileChallengeUserId != UserHandle.USER_NULL
+                && mLockPatternUtils.isSeparateProfileChallengeAllowed(mProfileChallengeUserId);
+    }
+
+    @Override
+    protected int getUserId() {
+        return mProfileChallengeUserId;
+    }
+
+    @Override
+    protected String getSettingsClassName() {
+        return Settings.CombinedBiometricProfileSettingsActivity.class.getName();
+    }
+
+    @Override
+    protected String getEnrollClassName() {
+        return Settings.CombinedBiometricProfileSettingsActivity.class.getName();
+    }
+}
diff --git a/src/com/android/settings/biometrics/combination/CombinedBiometricSettings.java b/src/com/android/settings/biometrics/combination/CombinedBiometricSettings.java
new file mode 100644
index 0000000..9ebb62f
--- /dev/null
+++ b/src/com/android/settings/biometrics/combination/CombinedBiometricSettings.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2021 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.combination;
+
+import android.app.settings.SettingsEnums;
+import android.content.Context;
+
+import com.android.settings.R;
+import com.android.settings.search.BaseSearchIndexProvider;
+import com.android.settingslib.search.SearchIndexable;
+
+/**
+ * Settings screen for multiple biometrics.
+ */
+@SearchIndexable
+public class CombinedBiometricSettings extends BiometricsSettingsBase {
+    private static final String TAG = "BiometricSettings";
+    private static final String KEY_FACE_SETTINGS = "biometric_face_settings";
+    private static final String KEY_FINGERPRINT_SETTINGS = "biometric_fingerprint_settings";
+
+    @Override
+    public void onAttach(Context context) {
+        super.onAttach(context);
+        use(BiometricSettingsKeyguardPreferenceController.class).setUserId(mUserId);
+        use(BiometricSettingsAppPreferenceController.class).setUserId(mUserId);
+    }
+
+    @Override
+    protected int getPreferenceScreenResId() {
+        return R.xml.security_settings_combined_biometric;
+    }
+
+    @Override
+    public String getFacePreferenceKey() {
+        return KEY_FACE_SETTINGS;
+    }
+
+    @Override
+    public String getFingerprintPreferenceKey() {
+        return KEY_FINGERPRINT_SETTINGS;
+    }
+
+    @Override
+    protected String getLogTag() {
+        return TAG;
+    }
+
+    @Override
+    public int getMetricsCategory() {
+        return SettingsEnums.COMBINED_BIOMETRIC;
+    }
+
+    public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
+            new BaseSearchIndexProvider(R.xml.security_settings_combined_biometric);
+}
diff --git a/src/com/android/settings/biometrics/combination/CombinedBiometricStatusPreferenceController.java b/src/com/android/settings/biometrics/combination/CombinedBiometricStatusPreferenceController.java
new file mode 100644
index 0000000..c3db174
--- /dev/null
+++ b/src/com/android/settings/biometrics/combination/CombinedBiometricStatusPreferenceController.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2021 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.combination;
+
+import android.content.Context;
+
+import com.android.settings.R;
+import com.android.settings.Settings;
+import com.android.settings.Utils;
+import com.android.settings.biometrics.BiometricStatusPreferenceController;
+
+/**
+ * Preference controller for biometrics settings page controlling the ability to unlock the phone
+ * with face and fingerprint.
+ */
+public class CombinedBiometricStatusPreferenceController extends
+        BiometricStatusPreferenceController {
+    private static final String KEY_BIOMETRIC_SETTINGS = "biometric_settings";
+
+
+    public CombinedBiometricStatusPreferenceController(Context context) {
+        this(context, KEY_BIOMETRIC_SETTINGS);
+    }
+
+    public CombinedBiometricStatusPreferenceController(Context context, String key) {
+        super(context, key);
+    }
+
+    @Override
+    protected boolean isDeviceSupported() {
+        return Utils.hasFingerprintHardware(mContext) && Utils.hasFaceHardware(mContext);
+    }
+
+    @Override
+    protected boolean hasEnrolledBiometrics() {
+        return false;
+    }
+
+    @Override
+    protected String getSummaryTextEnrolled() {
+        return mContext.getString(R.string.security_settings_biometric_preference_summary);
+    }
+
+    @Override
+    protected String getSummaryTextNoneEnrolled() {
+        return mContext.getString(R.string.security_settings_biometric_preference_summary);
+    }
+
+    @Override
+    protected String getSettingsClassName() {
+        return Settings.CombinedBiometricSettingsActivity.class.getName();
+    }
+
+    @Override
+    protected String getEnrollClassName() {
+        return Settings.CombinedBiometricSettingsActivity.class.getName();
+    }
+}
diff --git a/src/com/android/settings/biometrics/face/FaceSettingsAppPreferenceController.java b/src/com/android/settings/biometrics/face/FaceSettingsAppPreferenceController.java
index bde146b..c296e56 100644
--- a/src/com/android/settings/biometrics/face/FaceSettingsAppPreferenceController.java
+++ b/src/com/android/settings/biometrics/face/FaceSettingsAppPreferenceController.java
@@ -78,6 +78,11 @@
 
     @Override
     public int getAvailabilityStatus() {
+        // When the device supports multiple biometrics auth, this preference will be hidden.
+        if (Utils.isMultipleBiometricsSupported(mContext)) {
+            return UNSUPPORTED_ON_DEVICE;
+        }
+
         if(mFaceManager == null){
             return AVAILABLE_UNSEARCHABLE;
         }
diff --git a/src/com/android/settings/biometrics/face/FaceSettingsKeyguardPreferenceController.java b/src/com/android/settings/biometrics/face/FaceSettingsKeyguardPreferenceController.java
index 8ee7ffd..342d786 100644
--- a/src/com/android/settings/biometrics/face/FaceSettingsKeyguardPreferenceController.java
+++ b/src/com/android/settings/biometrics/face/FaceSettingsKeyguardPreferenceController.java
@@ -70,7 +70,8 @@
 
     @Override
     public int getAvailabilityStatus() {
-        return AVAILABLE;
+        // When the device supports multiple biometrics auth, this preference will be unavailable.
+        return Utils.isMultipleBiometricsSupported(mContext) ? UNSUPPORTED_ON_DEVICE : AVAILABLE;
     }
 
     @Override
diff --git a/src/com/android/settings/biometrics/face/FaceSettingsLockscreenBypassPreferenceController.java b/src/com/android/settings/biometrics/face/FaceSettingsLockscreenBypassPreferenceController.java
index 0a2757b..2f0ef4f 100644
--- a/src/com/android/settings/biometrics/face/FaceSettingsLockscreenBypassPreferenceController.java
+++ b/src/com/android/settings/biometrics/face/FaceSettingsLockscreenBypassPreferenceController.java
@@ -26,6 +26,7 @@
 import androidx.preference.Preference;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.settings.Utils;
 import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
 import com.android.settingslib.RestrictedSwitchPreference;
 
@@ -82,6 +83,11 @@
 
     @Override
     public int getAvailabilityStatus() {
+        // When the device supports multiple biometrics auth, this preference will be shown
+        // in face unlock category.
+        if (Utils.isMultipleBiometricsSupported(mContext)) {
+            return AVAILABLE;
+        }
         if (mUserManager.isManagedProfile(UserHandle.myUserId())) {
             return UNSUPPORTED_ON_DEVICE;
         }
diff --git a/src/com/android/settings/biometrics/face/FaceStatusPreferenceController.java b/src/com/android/settings/biometrics/face/FaceStatusPreferenceController.java
index 94651d7..c2143c0 100644
--- a/src/com/android/settings/biometrics/face/FaceStatusPreferenceController.java
+++ b/src/com/android/settings/biometrics/face/FaceStatusPreferenceController.java
@@ -41,7 +41,7 @@
 
     @Override
     protected boolean isDeviceSupported() {
-        return FaceSettings.isFaceHardwareDetected(mContext);
+        return !Utils.isMultipleBiometricsSupported(mContext) && Utils.hasFaceHardware(mContext);
     }
 
     @Override
diff --git a/src/com/android/settings/biometrics/face/FaceUnlockCategoryPreferenceController.java b/src/com/android/settings/biometrics/face/FaceUnlockCategoryPreferenceController.java
new file mode 100644
index 0000000..d0debdf
--- /dev/null
+++ b/src/com/android/settings/biometrics/face/FaceUnlockCategoryPreferenceController.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2021 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.face;
+
+import android.content.Context;
+
+import com.android.settings.Utils;
+import com.android.settings.core.BasePreferenceController;
+
+/**
+ * Preference controller that controls the face unlock features to be shown / be hidden.
+ */
+public class FaceUnlockCategoryPreferenceController extends BasePreferenceController {
+
+    public FaceUnlockCategoryPreferenceController(Context context, String key) {
+        super(context, key);
+    }
+
+    @Override
+    public int getAvailabilityStatus() {
+        return Utils.isMultipleBiometricsSupported(mContext) ? UNSUPPORTED_ON_DEVICE : AVAILABLE;
+    }
+}
diff --git a/src/com/android/settings/biometrics/fingerprint/FingerprintStatusPreferenceController.java b/src/com/android/settings/biometrics/fingerprint/FingerprintStatusPreferenceController.java
index 0e1ccd7..e53dbc4 100644
--- a/src/com/android/settings/biometrics/fingerprint/FingerprintStatusPreferenceController.java
+++ b/src/com/android/settings/biometrics/fingerprint/FingerprintStatusPreferenceController.java
@@ -40,7 +40,8 @@
 
     @Override
     protected boolean isDeviceSupported() {
-        return mFingerprintManager != null && mFingerprintManager.isHardwareDetected();
+        return !Utils.isMultipleBiometricsSupported(mContext)
+                && Utils.hasFingerprintHardware(mContext);
     }
 
     @Override
diff --git a/src/com/android/settings/bluetooth/BluetoothPermissionActivity.java b/src/com/android/settings/bluetooth/BluetoothPermissionActivity.java
index 10acdb5..8794b08 100644
--- a/src/com/android/settings/bluetooth/BluetoothPermissionActivity.java
+++ b/src/com/android/settings/bluetooth/BluetoothPermissionActivity.java
@@ -32,6 +32,7 @@
 
 import androidx.preference.Preference;
 
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.app.AlertActivity;
 import com.android.internal.app.AlertController;
 import com.android.settings.R;
@@ -51,8 +52,6 @@
     private TextView messageView;
     private Button mOkButton;
     private BluetoothDevice mDevice;
-    private String mReturnPackage = null;
-    private String mReturnClass = null;
 
     private int mRequestType = 0;
     private BroadcastReceiver mReceiver = new BroadcastReceiver() {
@@ -89,8 +88,6 @@
         }
 
         mDevice = i.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
-        mReturnPackage = i.getStringExtra(BluetoothDevice.EXTRA_PACKAGE_NAME);
-        mReturnClass = i.getStringExtra(BluetoothDevice.EXTRA_CLASS_NAME);
         mRequestType = i.getIntExtra(BluetoothDevice.EXTRA_ACCESS_REQUEST_TYPE,
                                      BluetoothDevice.REQUEST_TYPE_PHONEBOOK_ACCESS);
 
@@ -202,14 +199,14 @@
         sendReplyIntentToReceiver(false, true);
     }
 
-    private void sendReplyIntentToReceiver(final boolean allowed, final boolean always) {
+    @VisibleForTesting
+    void sendReplyIntentToReceiver(final boolean allowed, final boolean always) {
         Intent intent = new Intent(BluetoothDevice.ACTION_CONNECTION_ACCESS_REPLY);
 
-        if (mReturnPackage != null && mReturnClass != null) {
-            intent.setClassName(mReturnPackage, mReturnClass);
+        if (DEBUG) {
+            Log.i(TAG, "sendReplyIntentToReceiver() Request type: " + mRequestType
+                    + " mReturnPackage");
         }
-        if (DEBUG) Log.i(TAG, "sendReplyIntentToReceiver() Request type: " + mRequestType +
-                " mReturnPackage" + mReturnPackage + " mReturnClass" + mReturnClass);
 
         intent.putExtra(BluetoothDevice.EXTRA_CONNECTION_ACCESS_RESULT,
                         allowed ? BluetoothDevice.CONNECTION_ACCESS_YES
diff --git a/src/com/android/settings/bluetooth/BluetoothPermissionRequest.java b/src/com/android/settings/bluetooth/BluetoothPermissionRequest.java
index 7fac4991c..66665f0 100644
--- a/src/com/android/settings/bluetooth/BluetoothPermissionRequest.java
+++ b/src/com/android/settings/bluetooth/BluetoothPermissionRequest.java
@@ -56,8 +56,6 @@
     Context mContext;
     int mRequestType;
     BluetoothDevice mDevice;
-    String mReturnPackage = null;
-    String mReturnClass = null;
 
     @Override
     public void onReceive(Context context, Intent intent) {
@@ -77,11 +75,10 @@
             mDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
             mRequestType = intent.getIntExtra(BluetoothDevice.EXTRA_ACCESS_REQUEST_TYPE,
                                                  BluetoothDevice.REQUEST_TYPE_PROFILE_CONNECTION);
-            mReturnPackage = intent.getStringExtra(BluetoothDevice.EXTRA_PACKAGE_NAME);
-            mReturnClass = intent.getStringExtra(BluetoothDevice.EXTRA_CLASS_NAME);
 
-            if (DEBUG) Log.d(TAG, "onReceive request type: " + mRequestType + " return "
-                    + mReturnPackage + "," + mReturnClass);
+            if (DEBUG) {
+                Log.d(TAG, "onReceive request type: " + mRequestType);
+            }
 
             // Even if the user has already made the choice, Bluetooth still may not know that if
             // the user preference data have not been migrated from Settings app's shared
@@ -110,8 +107,6 @@
             connectionAccessIntent.putExtra(BluetoothDevice.EXTRA_ACCESS_REQUEST_TYPE,
                                             mRequestType);
             connectionAccessIntent.putExtra(BluetoothDevice.EXTRA_DEVICE, mDevice);
-            connectionAccessIntent.putExtra(BluetoothDevice.EXTRA_PACKAGE_NAME, mReturnPackage);
-            connectionAccessIntent.putExtra(BluetoothDevice.EXTRA_CLASS_NAME, mReturnClass);
 
             String deviceAddress = mDevice != null ? mDevice.getAddress() : null;
             String deviceName = mDevice != null ? mDevice.getName() : null;
@@ -231,7 +226,7 @@
 
         LocalBluetoothManager bluetoothManager = Utils.getLocalBtManager(mContext);
         CachedBluetoothDeviceManager cachedDeviceManager =
-            bluetoothManager.getCachedDeviceManager();
+                bluetoothManager.getCachedDeviceManager();
         CachedBluetoothDevice cachedDevice = cachedDeviceManager.findDevice(mDevice);
         if (cachedDevice == null) {
             cachedDevice = cachedDeviceManager.addDevice(mDevice);
@@ -289,13 +284,9 @@
     private void sendReplyIntentToReceiver(final boolean allowed) {
         Intent intent = new Intent(BluetoothDevice.ACTION_CONNECTION_ACCESS_REPLY);
 
-        if (mReturnPackage != null && mReturnClass != null) {
-            intent.setClassName(mReturnPackage, mReturnClass);
-        }
-
         intent.putExtra(BluetoothDevice.EXTRA_CONNECTION_ACCESS_RESULT,
-                        allowed ? BluetoothDevice.CONNECTION_ACCESS_YES
-                                : BluetoothDevice.CONNECTION_ACCESS_NO);
+                allowed ? BluetoothDevice.CONNECTION_ACCESS_YES
+                        : BluetoothDevice.CONNECTION_ACCESS_NO);
         intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mDevice);
         intent.putExtra(BluetoothDevice.EXTRA_ACCESS_REQUEST_TYPE, mRequestType);
         mContext.sendBroadcast(intent, android.Manifest.permission.BLUETOOTH_ADMIN);
diff --git a/src/com/android/settings/bluetooth/DevicePickerFragment.java b/src/com/android/settings/bluetooth/DevicePickerFragment.java
index ab8eea5..f60183b 100644
--- a/src/com/android/settings/bluetooth/DevicePickerFragment.java
+++ b/src/com/android/settings/bluetooth/DevicePickerFragment.java
@@ -48,10 +48,10 @@
 
     @VisibleForTesting
     BluetoothProgressCategory mAvailableDevicesCategory;
+    @VisibleForTesting
+    Context mContext;
 
     private boolean mNeedAuth;
-    private String mLaunchPackage;
-    private String mLaunchClass;
     private boolean mScanAllowed;
 
     public DevicePickerFragment() {
@@ -64,8 +64,6 @@
         mNeedAuth = intent.getBooleanExtra(BluetoothDevicePicker.EXTRA_NEED_AUTH, false);
         setFilter(intent.getIntExtra(BluetoothDevicePicker.EXTRA_FILTER_TYPE,
                 BluetoothDevicePicker.FILTER_TYPE_ALL));
-        mLaunchPackage = intent.getStringExtra(BluetoothDevicePicker.EXTRA_LAUNCH_PACKAGE);
-        mLaunchClass = intent.getStringExtra(BluetoothDevicePicker.EXTRA_LAUNCH_CLASS);
         mAvailableDevicesCategory = (BluetoothProgressCategory) findPreference(KEY_BT_DEVICE_LIST);
     }
 
@@ -85,6 +83,7 @@
         getActivity().setTitle(getString(R.string.device_picker));
         UserManager um = (UserManager) getSystemService(Context.USER_SERVICE);
         mScanAllowed = !um.hasUserRestriction(DISALLOW_CONFIG_BLUETOOTH);
+        mContext = getContext();
         setHasOptionsMenu(true);
     }
 
@@ -190,9 +189,7 @@
     private void sendDevicePickedIntent(BluetoothDevice device) {
         Intent intent = new Intent(BluetoothDevicePicker.ACTION_DEVICE_SELECTED);
         intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
-        if (mLaunchPackage != null && mLaunchClass != null) {
-            intent.setClassName(mLaunchPackage, mLaunchClass);
-        }
-        getActivity().sendBroadcast(intent, Manifest.permission.BLUETOOTH_ADMIN);
+
+        mContext.sendBroadcast(intent, Manifest.permission.BLUETOOTH_ADMIN);
     }
 }
diff --git a/src/com/android/settings/core/SettingsBaseActivity.java b/src/com/android/settings/core/SettingsBaseActivity.java
index a9513ea..cf3cd50 100644
--- a/src/com/android/settings/core/SettingsBaseActivity.java
+++ b/src/com/android/settings/core/SettingsBaseActivity.java
@@ -50,8 +50,6 @@
 import com.google.android.setupcompat.util.WizardManagerHelper;
 import com.google.android.setupdesign.util.ThemeHelper;
 
-import java.lang.reflect.Field;
-import java.lang.reflect.Method;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
@@ -62,7 +60,6 @@
     protected static final boolean DEBUG_TIMING = false;
     private static final String TAG = "SettingsBaseActivity";
     private static final String DATA_SCHEME_PKG = "package";
-    private static final int TOOLBAR_MAX_LINE_NUMBER = 2;
 
     // Serves as a temporary list of tiles to ignore until we heard back from the PM that they
     // are disabled.
@@ -98,7 +95,7 @@
 
         if (FeatureFlagUtils.isEnabled(this, FeatureFlags.SILKY_HOME)
                 && isToolbarEnabled() && !isAnySetupWizard) {
-            super.setContentView(R.layout.settings_collapsing_base_layout);
+            super.setContentView(R.layout.collapsing_toolbar_base_layout);
             mCollapsingToolbarLayout = findViewById(R.id.collapsing_toolbar);
         } else {
             super.setContentView(R.layout.settings_base_layout);
@@ -111,7 +108,6 @@
             return;
         }
         setActionBar(toolbar);
-        initCollapsingToolbar();
 
         if (DEBUG_TIMING) {
             Log.d(TAG, "onCreate took " + (System.currentTimeMillis() - startTime) + " ms");
@@ -211,50 +207,6 @@
         return true;
     }
 
-    private void initCollapsingToolbar() {
-        if (mCollapsingToolbarLayout == null) {
-            return;
-        }
-        mCollapsingToolbarLayout.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
-            @Override
-            public void onLayoutChange(View v, int left, int top, int right, int bottom,
-                    int oldLeft, int oldTop, int oldRight, int oldBottom) {
-                v.removeOnLayoutChangeListener(this);
-                final int count = getLineCount();
-                if (count > TOOLBAR_MAX_LINE_NUMBER) {
-                    ViewGroup.LayoutParams lp = mCollapsingToolbarLayout.getLayoutParams();
-                    lp.height = getResources()
-                            .getDimensionPixelSize(R.dimen.toolbar_three_lines_height);
-                    mCollapsingToolbarLayout.setLayoutParams(lp);
-                } else if (count == TOOLBAR_MAX_LINE_NUMBER) {
-                    ViewGroup.LayoutParams lp = mCollapsingToolbarLayout.getLayoutParams();
-                    lp.height =
-                            getResources().getDimensionPixelSize(R.dimen.toolbar_two_lines_height);
-                    mCollapsingToolbarLayout.setLayoutParams(lp);
-                }
-            }
-        });
-    }
-
-    private int getLineCount() {
-        try {
-            final Class<?> toolbarClazz = mCollapsingToolbarLayout.getClass();
-            final Field textHelperField = toolbarClazz.getDeclaredField("collapsingTextHelper");
-            textHelperField.setAccessible(true);
-            final Object textHelperObj = textHelperField.get(mCollapsingToolbarLayout);
-
-            final Field layoutField = textHelperObj.getClass().getDeclaredField("textLayout");
-            layoutField.setAccessible(true);
-            final Object layoutObj = layoutField.get(textHelperObj);
-
-            final Method method = layoutObj.getClass().getDeclaredMethod("getLineCount");
-            return (int) method.invoke(layoutObj);
-        } catch (Exception e) {
-            return 0;
-        }
-    }
-
-
     private void onCategoriesChanged(Set<String> categories) {
         final int N = mCategoryListeners.size();
         for (int i = 0; i < N; i++) {
diff --git a/src/com/android/settings/core/gateway/SettingsGateway.java b/src/com/android/settings/core/gateway/SettingsGateway.java
index a6305cb..01c613a 100644
--- a/src/com/android/settings/core/gateway/SettingsGateway.java
+++ b/src/com/android/settings/core/gateway/SettingsGateway.java
@@ -63,6 +63,8 @@
 import com.android.settings.backup.PrivacySettings;
 import com.android.settings.backup.ToggleBackupSettingFragment;
 import com.android.settings.backup.UserBackupSettingsActivity;
+import com.android.settings.biometrics.combination.CombinedBiometricProfileSettings;
+import com.android.settings.biometrics.combination.CombinedBiometricSettings;
 import com.android.settings.biometrics.face.FaceSettings;
 import com.android.settings.biometrics.fingerprint.FingerprintSettings;
 import com.android.settings.bluetooth.BluetoothDeviceDetailsFragment;
@@ -222,6 +224,8 @@
             AssistGestureSettings.class.getName(),
             FaceSettings.class.getName(),
             FingerprintSettings.FingerprintSettingsFragment.class.getName(),
+            CombinedBiometricSettings.class.getName(),
+            CombinedBiometricProfileSettings.class.getName(),
             SwipeToNotificationSettings.class.getName(),
             DoubleTapPowerSettings.class.getName(),
             DoubleTapScreenSettings.class.getName(),
diff --git a/src/com/android/settings/development/qstile/DevelopmentTiles.java b/src/com/android/settings/development/qstile/DevelopmentTiles.java
index 16084c0..c55d0cb 100644
--- a/src/com/android/settings/development/qstile/DevelopmentTiles.java
+++ b/src/com/android/settings/development/qstile/DevelopmentTiles.java
@@ -371,7 +371,7 @@
             mContext = getApplicationContext();
             mSensorPrivacyManager = (SensorPrivacyManager) mContext.getSystemService(
                     Context.SENSOR_PRIVACY_SERVICE);
-            mIsEnabled = mSensorPrivacyManager.isSensorPrivacyEnabled();
+            mIsEnabled = mSensorPrivacyManager.isAllSensorPrivacyEnabled();
             mMetricsFeatureProvider = FeatureFactory.getFactory(
                     mContext).getMetricsFeatureProvider();
             mKeyguardManager = (KeyguardManager) mContext.getSystemService(
@@ -392,7 +392,7 @@
             mMetricsFeatureProvider.action(getApplicationContext(), SettingsEnums.QS_SENSOR_PRIVACY,
                     isEnabled);
             mIsEnabled = isEnabled;
-            mSensorPrivacyManager.setSensorPrivacy(isEnabled);
+            mSensorPrivacyManager.setAllSensorPrivacy(isEnabled);
         }
     }
 
diff --git a/src/com/android/settings/display/AdaptiveSleepCameraStatePreferenceController.java b/src/com/android/settings/display/AdaptiveSleepCameraStatePreferenceController.java
index 72a1c66..ba7a3ab 100644
--- a/src/com/android/settings/display/AdaptiveSleepCameraStatePreferenceController.java
+++ b/src/com/android/settings/display/AdaptiveSleepCameraStatePreferenceController.java
@@ -43,7 +43,7 @@
         mPreference.setPositiveButtonText(R.string.allow);
         mPrivacyManager = SensorPrivacyManager.getInstance(context);
         mPrivacyManager.addSensorPrivacyListener(CAMERA,
-                enabled -> updateVisibility());
+                (sensor, enabled) -> updateVisibility());
         mPreference.setPositiveButtonOnClickListener(p -> {
             mPrivacyManager.setSensorPrivacy(CAMERA, false);
         });
diff --git a/src/com/android/settings/display/ColorModePreferenceController.java b/src/com/android/settings/display/ColorModePreferenceController.java
index 7a43e5c..6cd4867 100644
--- a/src/com/android/settings/display/ColorModePreferenceController.java
+++ b/src/com/android/settings/display/ColorModePreferenceController.java
@@ -18,13 +18,10 @@
 
 import androidx.annotation.VisibleForTesting;
 
-import com.android.settings.R;
 import com.android.settings.core.BasePreferenceController;
 
 public class ColorModePreferenceController extends BasePreferenceController {
 
-    private ColorDisplayManager mColorDisplayManager;
-
     public ColorModePreferenceController(Context context, String key) {
         super(context, key);
     }
@@ -39,24 +36,11 @@
 
     @Override
     public CharSequence getSummary() {
-        final int colorMode = getColorDisplayManager().getColorMode();
-        if (colorMode == ColorDisplayManager.COLOR_MODE_AUTOMATIC) {
-            return mContext.getText(R.string.color_mode_option_automatic);
-        }
-        if (colorMode == ColorDisplayManager.COLOR_MODE_SATURATED) {
-            return mContext.getText(R.string.color_mode_option_saturated);
-        }
-        if (colorMode == ColorDisplayManager.COLOR_MODE_BOOSTED) {
-            return mContext.getText(R.string.color_mode_option_boosted);
-        }
-        return mContext.getText(R.string.color_mode_option_natural);
+        return ColorModeUtils.getColorModeMapping(mContext.getResources()).get(getColorMode());
     }
 
     @VisibleForTesting
-    ColorDisplayManager getColorDisplayManager() {
-        if (mColorDisplayManager == null) {
-            mColorDisplayManager = mContext.getSystemService(ColorDisplayManager.class);
-        }
-        return mColorDisplayManager;
+    public int getColorMode() {
+        return mContext.getSystemService(ColorDisplayManager.class).getColorMode();
     }
 }
diff --git a/src/com/android/settings/display/ColorModePreferenceFragment.java b/src/com/android/settings/display/ColorModePreferenceFragment.java
index c48c1d4..b8fa0b9 100644
--- a/src/com/android/settings/display/ColorModePreferenceFragment.java
+++ b/src/com/android/settings/display/ColorModePreferenceFragment.java
@@ -13,9 +13,17 @@
  */
 package com.android.settings.display;
 
+import static android.hardware.display.ColorDisplayManager.COLOR_MODE_AUTOMATIC;
+import static android.hardware.display.ColorDisplayManager.COLOR_MODE_BOOSTED;
+import static android.hardware.display.ColorDisplayManager.COLOR_MODE_NATURAL;
+import static android.hardware.display.ColorDisplayManager.COLOR_MODE_SATURATED;
+import static android.hardware.display.ColorDisplayManager.VENDOR_COLOR_MODE_RANGE_MAX;
+import static android.hardware.display.ColorDisplayManager.VENDOR_COLOR_MODE_RANGE_MIN;
+
 import android.app.settings.SettingsEnums;
 import android.content.ContentResolver;
 import android.content.Context;
+import android.content.res.Resources;
 import android.database.ContentObserver;
 import android.graphics.drawable.Drawable;
 import android.hardware.display.ColorDisplayManager;
@@ -36,28 +44,26 @@
 
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Map;
 
 @SuppressWarnings("WeakerAccess")
 @SearchIndexable
 public class ColorModePreferenceFragment extends RadioButtonPickerFragment {
 
-    @VisibleForTesting
-    static final String KEY_COLOR_MODE_NATURAL = "color_mode_natural";
-    @VisibleForTesting
-    static final String KEY_COLOR_MODE_BOOSTED = "color_mode_boosted";
-    @VisibleForTesting
-    static final String KEY_COLOR_MODE_SATURATED = "color_mode_saturated";
-    @VisibleForTesting
-    static final String KEY_COLOR_MODE_AUTOMATIC = "color_mode_automatic";
+    private static final String KEY_COLOR_MODE_PREFIX = "color_mode_";
+
+    private static final int COLOR_MODE_FALLBACK = COLOR_MODE_NATURAL;
 
     private ContentObserver mContentObserver;
     private ColorDisplayManager mColorDisplayManager;
+    private Resources mResources;
 
     @Override
     public void onAttach(Context context) {
         super.onAttach(context);
 
         mColorDisplayManager = context.getSystemService(ColorDisplayManager.class);
+        mResources = context.getResources();
 
         final ContentResolver cr = context.getContentResolver();
         mContentObserver = new ContentObserver(new Handler(Looper.getMainLooper())) {
@@ -81,11 +87,11 @@
 
     @Override
     public void onDetach() {
-        super.onDetach();
         if (mContentObserver != null) {
             getContext().getContentResolver().unregisterContentObserver(mContentObserver);
             mContentObserver = null;
         }
+        super.onDetach();
     }
 
     @Override
@@ -108,73 +114,73 @@
 
     @Override
     protected List<? extends CandidateInfo> getCandidates() {
-        final Context c = getContext();
-        final int[] availableColorModes = c.getResources().getIntArray(
-                com.android.internal.R.array.config_availableColorModes);
-
-        List<ColorModeCandidateInfo> candidates = new ArrayList<>();
-        if (availableColorModes != null) {
-            for (int colorMode : availableColorModes) {
-                if (colorMode == ColorDisplayManager.COLOR_MODE_NATURAL) {
-                    candidates.add(new ColorModeCandidateInfo(
-                                c.getText(R.string.color_mode_option_natural),
-                                KEY_COLOR_MODE_NATURAL, true /* enabled */));
-                } else if (colorMode == ColorDisplayManager.COLOR_MODE_BOOSTED) {
-                    candidates.add(new ColorModeCandidateInfo(
-                                c.getText(R.string.color_mode_option_boosted),
-                                KEY_COLOR_MODE_BOOSTED, true /* enabled */));
-                } else if (colorMode == ColorDisplayManager.COLOR_MODE_SATURATED) {
-                    candidates.add(new ColorModeCandidateInfo(
-                                c.getText(R.string.color_mode_option_saturated),
-                                KEY_COLOR_MODE_SATURATED, true /* enabled */));
-                } else if (colorMode == ColorDisplayManager.COLOR_MODE_AUTOMATIC) {
-                    candidates.add(new ColorModeCandidateInfo(
-                                c.getText(R.string.color_mode_option_automatic),
-                                KEY_COLOR_MODE_AUTOMATIC, true /* enabled */));
-                }
-            }
+        final Map<Integer, String> colorModesToSummaries =
+                ColorModeUtils.getColorModeMapping(mResources);
+        final List<ColorModeCandidateInfo> candidates = new ArrayList<>();
+        for (int colorMode : mResources.getIntArray(
+                com.android.internal.R.array.config_availableColorModes)) {
+            candidates.add(new ColorModeCandidateInfo(
+                    colorModesToSummaries.get(colorMode),
+                    getKeyForColorMode(colorMode),
+                    true /* enabled */));
         }
         return candidates;
     }
 
     @Override
     protected String getDefaultKey() {
-        final int colorMode = mColorDisplayManager.getColorMode();
-        if (colorMode == ColorDisplayManager.COLOR_MODE_AUTOMATIC) {
-            return KEY_COLOR_MODE_AUTOMATIC;
-        } else if (colorMode == ColorDisplayManager.COLOR_MODE_SATURATED) {
-            return KEY_COLOR_MODE_SATURATED;
-        } else if (colorMode == ColorDisplayManager.COLOR_MODE_BOOSTED) {
-            return KEY_COLOR_MODE_BOOSTED;
+        final int colorMode = getColorMode();
+        if (isValidColorMode(colorMode)) {
+            return getKeyForColorMode(colorMode);
         }
-        return KEY_COLOR_MODE_NATURAL;
+        return getKeyForColorMode(COLOR_MODE_FALLBACK);
     }
 
     @Override
     protected boolean setDefaultKey(String key) {
-        switch (key) {
-            case KEY_COLOR_MODE_NATURAL:
-                mColorDisplayManager.setColorMode(ColorDisplayManager.COLOR_MODE_NATURAL);
-                break;
-            case KEY_COLOR_MODE_BOOSTED:
-                mColorDisplayManager.setColorMode(ColorDisplayManager.COLOR_MODE_BOOSTED);
-                break;
-            case KEY_COLOR_MODE_SATURATED:
-                mColorDisplayManager.setColorMode(ColorDisplayManager.COLOR_MODE_SATURATED);
-                break;
-            case KEY_COLOR_MODE_AUTOMATIC:
-                mColorDisplayManager.setColorMode(ColorDisplayManager.COLOR_MODE_AUTOMATIC);
-                break;
+        int colorMode = Integer.parseInt(key.substring(key.lastIndexOf("_") + 1));
+        if (isValidColorMode(colorMode)) {
+            setColorMode(colorMode);
         }
         return true;
     }
 
+    /**
+     * Wraps ColorDisplayManager#getColorMode for substitution in testing.
+     */
+    @VisibleForTesting
+    public int getColorMode() {
+        return mColorDisplayManager.getColorMode();
+    }
+
+    /**
+     * Wraps ColorDisplayManager#setColorMode for substitution in testing.
+     */
+    @VisibleForTesting
+    public void setColorMode(int colorMode) {
+        mColorDisplayManager.setColorMode(colorMode);
+    }
+
     @Override
     public int getMetricsCategory() {
         return SettingsEnums.COLOR_MODE_SETTINGS;
     }
 
     @VisibleForTesting
+    String getKeyForColorMode(int colorMode) {
+        return KEY_COLOR_MODE_PREFIX + colorMode;
+    }
+
+    private boolean isValidColorMode(int colorMode) {
+        return colorMode == COLOR_MODE_NATURAL
+                || colorMode == COLOR_MODE_BOOSTED
+                || colorMode == COLOR_MODE_SATURATED
+                || colorMode == COLOR_MODE_AUTOMATIC
+                || (colorMode >= VENDOR_COLOR_MODE_RANGE_MIN
+                && colorMode <= VENDOR_COLOR_MODE_RANGE_MAX);
+    }
+
+    @VisibleForTesting
     static class ColorModeCandidateInfo extends CandidateInfo {
         private final CharSequence mLabel;
         private final String mKey;
diff --git a/src/com/android/settings/display/ColorModeUtils.java b/src/com/android/settings/display/ColorModeUtils.java
new file mode 100644
index 0000000..cdd978e
--- /dev/null
+++ b/src/com/android/settings/display/ColorModeUtils.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2021 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.display;
+
+import static android.hardware.display.ColorDisplayManager.COLOR_MODE_AUTOMATIC;
+import static android.hardware.display.ColorDisplayManager.COLOR_MODE_BOOSTED;
+import static android.hardware.display.ColorDisplayManager.COLOR_MODE_NATURAL;
+import static android.hardware.display.ColorDisplayManager.COLOR_MODE_SATURATED;
+import static android.hardware.display.ColorDisplayManager.VENDOR_COLOR_MODE_RANGE_MAX;
+import static android.hardware.display.ColorDisplayManager.VENDOR_COLOR_MODE_RANGE_MIN;
+
+import android.content.res.Resources;
+import android.util.ArrayMap;
+
+import com.android.settings.R;
+
+import java.util.Map;
+
+final class ColorModeUtils {
+
+    private ColorModeUtils() {
+        // Do not instantiate.
+    }
+
+    static Map<Integer, String> getColorModeMapping(Resources resources) {
+        final String[] colorModeOptionsStrings = resources.getStringArray(
+                R.array.config_color_mode_options_strings);
+        final int[] colorModeOptionsValues = resources.getIntArray(
+                R.array.config_color_mode_options_values);
+        if (colorModeOptionsStrings.length != colorModeOptionsValues.length) {
+            throw new RuntimeException("Color mode options of unequal length");
+        }
+
+        final Map<Integer, String> colorModesToSummaries = new ArrayMap<>();
+        for (int i = 0; i < colorModeOptionsValues.length; i++) {
+            final int colorMode = colorModeOptionsValues[i];
+            if (colorMode == COLOR_MODE_NATURAL
+                    || colorMode == COLOR_MODE_BOOSTED
+                    || colorMode == COLOR_MODE_SATURATED
+                    || colorMode == COLOR_MODE_AUTOMATIC
+                    || (colorMode >= VENDOR_COLOR_MODE_RANGE_MIN
+                    && colorMode <= VENDOR_COLOR_MODE_RANGE_MAX)) {
+                colorModesToSummaries.put(colorMode, colorModeOptionsStrings[i]);
+            }
+        }
+        return colorModesToSummaries;
+    }
+}
diff --git a/src/com/android/settings/display/ScreenTimeoutSettings.java b/src/com/android/settings/display/ScreenTimeoutSettings.java
index 444f8ef8..27e1e1b 100644
--- a/src/com/android/settings/display/ScreenTimeoutSettings.java
+++ b/src/com/android/settings/display/ScreenTimeoutSettings.java
@@ -111,9 +111,7 @@
         mPrivacyPreference.setLayoutResource(R.layout.preference_footer);
         mPrivacyManager = SensorPrivacyManager.getInstance(context);
         mPrivacyManager.addSensorPrivacyListener(CAMERA,
-                enabled -> {
-                    mAdaptiveSleepController.updatePreference();
-                });
+                (sensor, enabled) -> mAdaptiveSleepController.updatePreference());
     }
 
     @Override
diff --git a/src/com/android/settings/display/SmartAutoRotateCameraStateController.java b/src/com/android/settings/display/SmartAutoRotateCameraStateController.java
index 1480785..9e2a784 100644
--- a/src/com/android/settings/display/SmartAutoRotateCameraStateController.java
+++ b/src/com/android/settings/display/SmartAutoRotateCameraStateController.java
@@ -43,7 +43,7 @@
     public SmartAutoRotateCameraStateController(Context context, String key) {
         super(context, key);
         mPrivacyManager = SensorPrivacyManager.getInstance(context);
-        mPrivacyManager.addSensorPrivacyListener(CAMERA, enabled -> {
+        mPrivacyManager.addSensorPrivacyListener(CAMERA, (sensor, enabled) -> {
             mPreference.setVisible(enabled);
             updateState(mPreference);
         });
diff --git a/src/com/android/settings/display/SmartAutoRotateController.java b/src/com/android/settings/display/SmartAutoRotateController.java
index e3b2665..cf2a9a6 100644
--- a/src/com/android/settings/display/SmartAutoRotateController.java
+++ b/src/com/android/settings/display/SmartAutoRotateController.java
@@ -52,7 +52,8 @@
         super(context, preferenceKey);
         mMetricsFeatureProvider = FeatureFactory.getFactory(context).getMetricsFeatureProvider();
         mPrivacyManager = SensorPrivacyManager.getInstance(context);
-        mPrivacyManager.addSensorPrivacyListener(CAMERA, enabled -> updateState(mPreference));
+        mPrivacyManager
+                .addSensorPrivacyListener(CAMERA, (sensor, enabled) -> updateState(mPreference));
     }
 
     @Override
diff --git a/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetail.java b/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetail.java
index 432224d..3ef7c45 100644
--- a/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetail.java
+++ b/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetail.java
@@ -27,6 +27,7 @@
 import android.os.UserHandle;
 import android.text.Html;
 import android.text.TextUtils;
+import android.text.format.DateUtils;
 import android.util.Log;
 import android.view.View;
 
@@ -282,20 +283,8 @@
 
         final long foregroundTimeMs = bundle.getLong(EXTRA_FOREGROUND_TIME);
         final long backgroundTimeMs = bundle.getLong(EXTRA_BACKGROUND_TIME);
-        final long totalTimeMs = foregroundTimeMs + backgroundTimeMs;
-        //TODO(b/178197718) Refine the layout
-        controller.setSummary(TextUtils.expandTemplate(
-                getText(R.string.battery_total_and_background_usage),
-                StringUtil.formatElapsedTime(
-                        getContext(),
-                        totalTimeMs,
-                        /* withSeconds */ false,
-                        /* collapseTimeUnit */ false),
-                StringUtil.formatElapsedTime(
-                        getContext(),
-                        backgroundTimeMs,
-                        /* withSeconds */ false,
-                        /* collapseTimeUnit */ false)));
+        //TODO(b/178197718) Update layout to support multiple lines
+        controller.setSummary(getAppActiveTime(foregroundTimeMs, backgroundTimeMs));
 
         controller.done(context, true /* rebindActions */);
     }
@@ -388,4 +377,53 @@
     private void updatePreferenceState(RadioButtonPreference preference, String selectedKey) {
         preference.setChecked(selectedKey.equals(preference.getKey()));
     }
+
+    //TODO(b/178197718) Update method to support time period
+    private CharSequence getAppActiveTime(long foregroundTimeMs, long backgroundTimeMs) {
+        final long totalTimeMs = foregroundTimeMs + backgroundTimeMs;
+        final CharSequence usageTimeSummary;
+
+        if (totalTimeMs == 0) {
+            usageTimeSummary = getText(R.string.battery_not_usage);
+        // Shows background summary only if we don't have foreground usage time.
+        } else if (foregroundTimeMs == 0 && backgroundTimeMs != 0) {
+            usageTimeSummary = backgroundTimeMs < DateUtils.MINUTE_IN_MILLIS ?
+                    getText(R.string.battery_background_usage_less_minute) :
+                    TextUtils.expandTemplate(getText(R.string.battery_background_usage),
+                    StringUtil.formatElapsedTime(
+                            getContext(),
+                            backgroundTimeMs,
+                            /* withSeconds */ false,
+                            /* collapseTimeUnit */ false));
+        // Shows total usage summary only if total usage time is small.
+        } else if (totalTimeMs < DateUtils.MINUTE_IN_MILLIS) {
+            usageTimeSummary = getText(R.string.battery_total_usage_less_minute);
+        // Shows different total usage summary when background usage time is small.
+        } else if (backgroundTimeMs < DateUtils.MINUTE_IN_MILLIS) {
+            usageTimeSummary = TextUtils.expandTemplate(
+                    getText(backgroundTimeMs == 0 ?
+                            R.string.battery_total_usage :
+                            R.string.battery_total_usage_and_background_less_minute_usage),
+                    StringUtil.formatElapsedTime(
+                            getContext(),
+                            totalTimeMs,
+                            /* withSeconds */ false,
+                            /* collapseTimeUnit */ false));
+        // Shows default summary.
+        } else {
+            usageTimeSummary = TextUtils.expandTemplate(
+                    getText(R.string.battery_total_and_background_usage),
+                    StringUtil.formatElapsedTime(
+                            getContext(),
+                            totalTimeMs,
+                            /* withSeconds */ false,
+                            /* collapseTimeUnit */ false),
+                    StringUtil.formatElapsedTime(
+                            getContext(),
+                            backgroundTimeMs,
+                            /* withSeconds */ false,
+                            /* collapseTimeUnit */ false));
+        }
+        return usageTimeSummary;
+    }
 }
diff --git a/src/com/android/settings/fuelgauge/BatteryChartPreferenceController.java b/src/com/android/settings/fuelgauge/BatteryChartPreferenceController.java
index f12de01..7131f28 100644
--- a/src/com/android/settings/fuelgauge/BatteryChartPreferenceController.java
+++ b/src/com/android/settings/fuelgauge/BatteryChartPreferenceController.java
@@ -12,7 +12,6 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  *
- *
  */
 
 package com.android.settings.fuelgauge;
@@ -51,7 +50,7 @@
 /** Controls the update for chart graph and the list items. */
 public class BatteryChartPreferenceController extends AbstractPreferenceController
         implements PreferenceControllerMixin, LifecycleObserver, OnPause, OnDestroy,
-                BatteryChartView.OnSelectListener {
+                BatteryChartView.OnSelectListener, ExpandDividerPreference.OnExpandListener {
     private static final String TAG = "BatteryChartPreferenceController";
     private static final int CHART_KEY_ARRAY_SIZE = 25;
     private static final int CHART_LEVEL_ARRAY_SIZE = 13;
@@ -65,6 +64,7 @@
     @VisibleForTesting BatteryUtils mBatteryUtils;
     @VisibleForTesting PreferenceGroup mAppListPrefGroup;
     @VisibleForTesting BatteryChartView mBatteryChartView;
+    @VisibleForTesting ExpandDividerPreference mExpandDividerPreference;
 
     @VisibleForTesting int[] mBatteryHistoryLevels;
     @VisibleForTesting long[] mBatteryHistoryKeys;
@@ -76,9 +76,13 @@
     private final Handler mHandler = new Handler(Looper.getMainLooper());
     private final CharSequence[] mNotAllowShowSummaryPackages;
 
+    private boolean mIsExpanded = false;
+
     // Preference cache to avoid create new instance each time.
     @VisibleForTesting
     final Map<String, Preference> mPreferenceCache = new HashMap<>();
+    @VisibleForTesting
+    final List<BatteryDiffEntry> mSystemEntries = new ArrayList<>();
 
     public BatteryChartPreferenceController(
             Context context, String preferenceKey,
@@ -163,6 +167,12 @@
         refreshUi(trapezoidIndex, /*isForce=*/ false);
     }
 
+    @Override
+    public void onExpand(boolean isExpanded) {
+        mIsExpanded = isExpanded;
+        refreshExpandUi();
+    }
+
     void setBatteryHistoryMap(
             final Map<Long, List<BatteryHistEntry>> batteryHistoryMap) {
         mHandler.post(() -> setBatteryHistoryMapInner(batteryHistoryMap));
@@ -266,10 +276,10 @@
         }
         // Separates data into two groups and sort them individually.
         final List<BatteryDiffEntry> appEntries = new ArrayList<>();
-        final List<BatteryDiffEntry> systemEntries = new ArrayList<>();
+        mSystemEntries.clear();
         entries.forEach(entry -> {
             if (entry.isSystemEntry()) {
-                systemEntries.add(entry);
+                mSystemEntries.add(entry);
             } else {
                 appEntries.add(entry);
             }
@@ -279,11 +289,25 @@
             }
         });
         Collections.sort(appEntries, BatteryDiffEntry.COMPARATOR);
-        Collections.sort(systemEntries, BatteryDiffEntry.COMPARATOR);
+        Collections.sort(mSystemEntries, BatteryDiffEntry.COMPARATOR);
         Log.d(TAG, String.format("addAllPreferences() app=%d system=%d",
-            appEntries.size(), systemEntries.size()));
-        addPreferenceToScreen(appEntries);
-        addPreferenceToScreen(systemEntries);
+            appEntries.size(), mSystemEntries.size()));
+
+        // Adds app entries to the list if it is not empty.
+        if (!appEntries.isEmpty()) {
+            addPreferenceToScreen(appEntries);
+        }
+        // Adds the expabable divider if we have two sections data.
+        if (!appEntries.isEmpty() && !mSystemEntries.isEmpty()) {
+            if (mExpandDividerPreference == null) {
+                mExpandDividerPreference = new ExpandDividerPreference(mPrefContext);
+                mExpandDividerPreference.setOnExpandListener(this);
+            }
+            mExpandDividerPreference.setOrder(
+                mAppListPrefGroup.getPreferenceCount());
+            mAppListPrefGroup.addPreference(mExpandDividerPreference);
+        }
+        refreshExpandUi();
     }
 
     @VisibleForTesting
@@ -293,6 +317,7 @@
         }
         int prefIndex = mAppListPrefGroup.getPreferenceCount();
         for (BatteryDiffEntry entry : entries) {
+            boolean isAdded = false;
             final String appLabel = entry.getAppLabel();
             final Drawable appIcon = entry.getAppIcon();
             if (TextUtils.isEmpty(appLabel) || appIcon == null) {
@@ -300,8 +325,13 @@
                 continue;
             }
             final String prefKey = entry.mBatteryHistEntry.getKey();
-            PowerGaugePreference pref =
-                (PowerGaugePreference) mPreferenceCache.get(prefKey);
+            PowerGaugePreference pref = mAppListPrefGroup.findPreference(prefKey);
+            if (pref != null) {
+                isAdded = true;
+                Log.w(TAG, "preference should be removed for\n" + entry);
+            } else {
+                pref = (PowerGaugePreference) mPreferenceCache.get(prefKey);
+            }
             // Creates new innstance if cached preference is not found.
             if (pref == null) {
                 pref = new PowerGaugePreference(mPrefContext);
@@ -316,7 +346,9 @@
             // Sets the BatteryDiffEntry to preference for launching detailed page.
             pref.setBatteryDiffEntry(entry);
             setPreferenceSummary(pref, entry);
-            mAppListPrefGroup.addPreference(pref);
+            if (!isAdded) {
+                mAppListPrefGroup.addPreference(pref);
+            }
             prefIndex++;
         }
     }
@@ -337,6 +369,22 @@
         mAppListPrefGroup.removeAll();
     }
 
+    private void refreshExpandUi() {
+        if (mIsExpanded) {
+            addPreferenceToScreen(mSystemEntries);
+        } else {
+            // Removes and recycles all system entries to hide all of them.
+            for (BatteryDiffEntry entry : mSystemEntries) {
+                final String prefKey = entry.mBatteryHistEntry.getKey();
+                final Preference pref = mAppListPrefGroup.findPreference(prefKey);
+                if (pref != null) {
+                    mAppListPrefGroup.removePreference(pref);
+                    mPreferenceCache.put(pref.getKey(), pref);
+                }
+            }
+        }
+    }
+
     @VisibleForTesting
     void setPreferenceSummary(
             PowerGaugePreference preference, BatteryDiffEntry entry) {
diff --git a/src/com/android/settings/fuelgauge/BatteryChartView.java b/src/com/android/settings/fuelgauge/BatteryChartView.java
index 26eb3e4..f970072 100644
--- a/src/com/android/settings/fuelgauge/BatteryChartView.java
+++ b/src/com/android/settings/fuelgauge/BatteryChartView.java
@@ -97,8 +97,18 @@
     public void setLevels(int[] levels) {
         // We should provide trapezoid count + 1 data to draw all trapezoids.
         mLevels = levels.length == mTrapezoidCount + 1 ? levels : null;
-        setClickable(mLevels != null);
+        setClickable(false);
         invalidate();
+        if (mLevels == null) {
+            return;
+        }
+        // Sets the chart is clickable if there is at least one valid item in it.
+        for (int index = 0; index < mLevels.length; index++) {
+            if (mLevels[index] != 0) {
+                setClickable(true);
+                break;
+            }
+        }
     }
 
     /** Sets the selected group index to draw highlight effect. */
diff --git a/src/com/android/settings/fuelgauge/ConvertUtils.java b/src/com/android/settings/fuelgauge/ConvertUtils.java
index 30982da..2e8726e 100644
--- a/src/com/android/settings/fuelgauge/ConvertUtils.java
+++ b/src/com/android/settings/fuelgauge/ConvertUtils.java
@@ -71,6 +71,7 @@
 
     private static String sZoneId;
     private static SimpleDateFormat sSimpleDateFormat;
+    private static SimpleDateFormat sSimpleDateFormatForHour;
 
     private ConvertUtils() {}
 
@@ -139,10 +140,27 @@
             sZoneId = currentZoneId;
             sSimpleDateFormat =
                 new SimpleDateFormat("MMM dd,yyyy HH:mm:ss", Locale.ENGLISH);
+            sSimpleDateFormatForHour = null;
         }
         return sSimpleDateFormat.format(new Date(timestamp));
     }
 
+    /** Converts UTC timestamp to local time hour data. */
+    public static int utcToLocalTimeHour(long timestamp) {
+        final String currentZoneId = TimeZone.getDefault().getID();
+        if (!currentZoneId.equals(sZoneId) || sSimpleDateFormatForHour == null) {
+            sZoneId = currentZoneId;
+            sSimpleDateFormat = null;
+            sSimpleDateFormatForHour = new SimpleDateFormat("HH", Locale.ENGLISH);
+        }
+        try {
+            return Integer.parseInt(
+                sSimpleDateFormatForHour.format(new Date(timestamp)));
+        } catch (NumberFormatException e) {
+            return Integer.MIN_VALUE;
+        }
+    }
+
     /** Gets indexed battery usage data for each corresponding time slot. */
     public static Map<Integer, List<BatteryDiffEntry>> getIndexedUsageMap(
             final Context context,
diff --git a/src/com/android/settings/location/LocationPersonalSettings.java b/src/com/android/settings/location/LocationPersonalSettings.java
index 0553d96..ab392d6 100644
--- a/src/com/android/settings/location/LocationPersonalSettings.java
+++ b/src/com/android/settings/location/LocationPersonalSettings.java
@@ -51,7 +51,6 @@
 
         use(AppLocationPermissionPreferenceController.class).init(this);
         use(LocationSettingsFooterPreferenceController.class).init(this);
-        use(RecentLocationAccessSeeAllButtonPreferenceController.class).init(this);
 
         final int profileType = getArguments().getInt(ProfileSelectFragment.EXTRA_PROFILE);
         final RecentLocationAccessPreferenceController controller = use(
diff --git a/src/com/android/settings/location/LocationSettings.java b/src/com/android/settings/location/LocationSettings.java
index fe3cf30..093dc85 100644
--- a/src/com/android/settings/location/LocationSettings.java
+++ b/src/com/android/settings/location/LocationSettings.java
@@ -83,7 +83,6 @@
 
         use(AppLocationPermissionPreferenceController.class).init(this);
         use(RecentLocationAccessPreferenceController.class).init(this);
-        use(RecentLocationAccessSeeAllButtonPreferenceController.class).init(this);
         use(LocationForWorkPreferenceController.class).init(this);
         use(LocationSettingsFooterPreferenceController.class).init(this);
     }
diff --git a/src/com/android/settings/location/LocationWorkProfileSettings.java b/src/com/android/settings/location/LocationWorkProfileSettings.java
index 24c44f3..f50ba90 100644
--- a/src/com/android/settings/location/LocationWorkProfileSettings.java
+++ b/src/com/android/settings/location/LocationWorkProfileSettings.java
@@ -51,7 +51,6 @@
 
         use(AppLocationPermissionPreferenceController.class).init(this);
         use(LocationForWorkPreferenceController.class).init(this);
-        use(RecentLocationAccessSeeAllButtonPreferenceController.class).init(this);
         use(LocationSettingsFooterPreferenceController.class).init(this);
 
         final int profileType = getArguments().getInt(ProfileSelectFragment.EXTRA_PROFILE);
diff --git a/src/com/android/settings/location/RecentLocationAccessSeeAllButtonPreferenceController.java b/src/com/android/settings/location/RecentLocationAccessSeeAllButtonPreferenceController.java
deleted file mode 100644
index 68cde63..0000000
--- a/src/com/android/settings/location/RecentLocationAccessSeeAllButtonPreferenceController.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright 2021 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.location;
-
-import android.content.Context;
-
-import androidx.preference.Preference;
-import androidx.preference.PreferenceScreen;
-
-/**
- * Preference controller that handles the "See All" button for recent location access.
- */
-public class RecentLocationAccessSeeAllButtonPreferenceController extends
-        LocationBasePreferenceController {
-
-    private Preference mPreference;
-
-    /**
-     * Constructor of {@link RecentLocationAccessSeeAllButtonPreferenceController}.
-     */
-    public RecentLocationAccessSeeAllButtonPreferenceController(Context context, String key) {
-        super(context, key);
-    }
-
-    @Override
-    public void displayPreference(PreferenceScreen screen) {
-        super.displayPreference(screen);
-        mPreference = screen.findPreference(getPreferenceKey());
-    }
-
-    @Override
-    public void onLocationModeChanged(int mode, boolean restricted) {
-        boolean enabled = mLocationEnabler.isEnabled(mode);
-        mPreference.setVisible(enabled);
-    }
-}
diff --git a/src/com/android/settings/network/telephony/Enable2gPreferenceController.java b/src/com/android/settings/network/telephony/Enable2gPreferenceController.java
index cf08d10..d336cb4 100644
--- a/src/com/android/settings/network/telephony/Enable2gPreferenceController.java
+++ b/src/com/android/settings/network/telephony/Enable2gPreferenceController.java
@@ -72,7 +72,7 @@
     public int getAvailabilityStatus(int subId) {
         final PersistableBundle carrierConfig = mCarrierConfigManager.getConfigForSubId(subId);
         boolean visible =
-                subId != SubscriptionManager.INVALID_SUBSCRIPTION_ID
+                SubscriptionManager.isUsableSubscriptionId(subId)
                 && carrierConfig != null
                 && !carrierConfig.getBoolean(CarrierConfigManager.KEY_HIDE_ENABLE_2G)
                 && mTelephonyManager.isRadioInterfaceCapabilitySupported(
@@ -89,6 +89,9 @@
 
     @Override
     public boolean setChecked(boolean isChecked) {
+        if (!SubscriptionManager.isUsableSubscriptionId(mSubId)) {
+            return false;
+        }
         long currentlyAllowedNetworkTypes = mTelephonyManager.getAllowedNetworkTypesForReason(
                 mTelephonyManager.ALLOWED_NETWORK_TYPES_REASON_ENABLE_2G);
         boolean enabled = (currentlyAllowedNetworkTypes & BITMASK_2G) != 0;
diff --git a/src/com/android/settings/notification/NotificationAssistantPreferenceController.java b/src/com/android/settings/notification/NotificationAssistantPreferenceController.java
index 6237326..a46f164 100644
--- a/src/com/android/settings/notification/NotificationAssistantPreferenceController.java
+++ b/src/com/android/settings/notification/NotificationAssistantPreferenceController.java
@@ -77,11 +77,7 @@
     protected void setNotificationAssistantGranted(ComponentName cn) {
         if (Settings.Secure.getIntForUser(mContext.getContentResolver(),
                 Settings.Secure.NAS_SETTINGS_UPDATED, 0, mUserId) == 0) {
-            for (int profileId : mUserManager.getProfileIds(mUserId, false)) {
-                Settings.Secure.putIntForUser(mContext.getContentResolver(),
-                        Settings.Secure.NAS_SETTINGS_UPDATED, 1, profileId);
-            }
-            mNotificationBackend.resetDefaultNotificationAssistant(cn != null);
+            mNotificationBackend.setNASMigrationDoneAndResetDefault(mUserId, cn != null);
         }
         mNotificationBackend.setNotificationAssistantGranted(cn);
     }
diff --git a/src/com/android/settings/notification/NotificationBackend.java b/src/com/android/settings/notification/NotificationBackend.java
index b08d02c..e448dda 100644
--- a/src/com/android/settings/notification/NotificationBackend.java
+++ b/src/com/android/settings/notification/NotificationBackend.java
@@ -570,9 +570,9 @@
         }
     }
 
-    public void resetDefaultNotificationAssistant(boolean loadFromConfig) {
+    public void setNASMigrationDoneAndResetDefault(int userId, boolean loadFromConfig) {
         try {
-            sINM.resetDefaultNotificationAssistant(loadFromConfig);
+            sINM.setNASMigrationDoneAndResetDefault(userId, loadFromConfig);
         } catch (Exception e) {
             Log.w(TAG, "Error calling NoMan", e);
         }
diff --git a/src/com/android/settings/notification/app/NotificationFooterPreference.java b/src/com/android/settings/notification/app/NotificationFooterPreference.java
deleted file mode 100644
index 6f34cdd..0000000
--- a/src/com/android/settings/notification/app/NotificationFooterPreference.java
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.settings.notification.app;
-
-import android.content.Context;
-import android.text.method.LinkMovementMethod;
-import android.util.AttributeSet;
-import android.widget.TextView;
-
-import androidx.core.content.res.TypedArrayUtils;
-import androidx.preference.Preference;
-import androidx.preference.PreferenceViewHolder;
-
-import com.android.settingslib.R;
-
-/**
- * FooterPreference that can have any key or ordering.
- */
-public class NotificationFooterPreference extends Preference {
-
-    public NotificationFooterPreference(Context context, AttributeSet attrs) {
-        super(context, attrs, TypedArrayUtils.getAttr(
-                context, R.attr.footerPreferenceStyle, android.R.attr.preferenceStyle));
-        init();
-    }
-
-    public NotificationFooterPreference(Context context) {
-        this(context, null);
-    }
-
-    @Override
-    public void onBindViewHolder(PreferenceViewHolder holder) {
-        super.onBindViewHolder(holder);
-        TextView title = holder.itemView.findViewById(android.R.id.title);
-        title.setMovementMethod(new LinkMovementMethod());
-        title.setClickable(false);
-        title.setLongClickable(false);
-    }
-
-    private void init() {
-        setIcon(R.drawable.ic_info_outline_24dp);
-        setSelectable(false);
-    }
-}
diff --git a/src/com/android/settings/security/SecuritySettings.java b/src/com/android/settings/security/SecuritySettings.java
index 577144f..01cdba7 100644
--- a/src/com/android/settings/security/SecuritySettings.java
+++ b/src/com/android/settings/security/SecuritySettings.java
@@ -22,6 +22,8 @@
 import android.content.Intent;
 
 import com.android.settings.R;
+import com.android.settings.biometrics.combination.CombinedBiometricProfileStatusPreferenceController;
+import com.android.settings.biometrics.combination.CombinedBiometricStatusPreferenceController;
 import com.android.settings.biometrics.face.FaceProfileStatusPreferenceController;
 import com.android.settings.biometrics.face.FaceStatusPreferenceController;
 import com.android.settings.biometrics.fingerprint.FingerprintProfileStatusPreferenceController;
@@ -115,6 +117,7 @@
         final List<AbstractPreferenceController> securityPreferenceControllers = new ArrayList<>();
         securityPreferenceControllers.add(new FaceStatusPreferenceController(context));
         securityPreferenceControllers.add(new FingerprintStatusPreferenceController(context));
+        securityPreferenceControllers.add(new CombinedBiometricStatusPreferenceController(context));
         securityPreferenceControllers.add(new ChangeScreenLockPreferenceController(context, host));
         controllers.add(new PreferenceCategoryController(context, SECURITY_CATEGORY)
                 .setChildren(securityPreferenceControllers));
@@ -128,6 +131,8 @@
                 context, lifecycle));
         profileSecurityControllers.add(new FaceProfileStatusPreferenceController(context));
         profileSecurityControllers.add(new FingerprintProfileStatusPreferenceController(context));
+        profileSecurityControllers
+                .add(new CombinedBiometricProfileStatusPreferenceController(context));
         controllers.add(new PreferenceCategoryController(context, WORK_PROFILE_SECURITY_CATEGORY)
                 .setChildren(profileSecurityControllers));
         controllers.addAll(profileSecurityControllers);
diff --git a/src/com/android/settings/uwb/UwbPreferenceController.java b/src/com/android/settings/uwb/UwbPreferenceController.java
new file mode 100644
index 0000000..daadb63
--- /dev/null
+++ b/src/com/android/settings/uwb/UwbPreferenceController.java
@@ -0,0 +1,168 @@
+/*
+ * Copyright (C) 2021 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.uwb;
+
+import static androidx.lifecycle.Lifecycle.Event.ON_START;
+import static androidx.lifecycle.Lifecycle.Event.ON_STOP;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.PackageManager;
+import android.provider.Settings;
+import android.uwb.UwbManager;
+import android.uwb.UwbManager.AdapterStateCallback;
+
+import androidx.lifecycle.LifecycleObserver;
+import androidx.lifecycle.OnLifecycleEvent;
+import androidx.preference.Preference;
+import androidx.preference.PreferenceScreen;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.settings.R;
+import com.android.settings.core.TogglePreferenceController;
+
+import java.util.concurrent.Executor;
+import java.util.concurrent.Executors;
+
+/** Controller for "UWB" toggle. */
+public class UwbPreferenceController extends TogglePreferenceController implements
+        AdapterStateCallback, LifecycleObserver {
+    @VisibleForTesting
+    static final String KEY_UWB_SETTINGS = "uwb_settings";
+    @VisibleForTesting
+    UwbManager mUwbManager;
+    @VisibleForTesting
+    boolean mAirplaneModeOn;
+    @VisibleForTesting
+    private final BroadcastReceiver mAirplaneModeChangedReceiver;
+    private final Executor mExecutor;
+    private boolean mIsChecked = true;
+    boolean mRegisteredAdapterStateCallback = false;
+    private Preference mPreference;
+
+    public UwbPreferenceController(Context context, String key) {
+        super(context, key);
+        mExecutor = Executors.newSingleThreadExecutor();
+        mUwbManager = context.getSystemService(UwbManager.class);
+        mAirplaneModeOn = Settings.Global.getInt(mContext.getContentResolver(),
+                Settings.Global.AIRPLANE_MODE_ON, 0) == 1;
+        mAirplaneModeChangedReceiver = new BroadcastReceiver() {
+            @Override
+            public void onReceive(Context context, Intent intent) {
+                updateState(mPreference);
+            }
+        };
+    }
+
+    @VisibleForTesting
+    boolean isUwbSupportedOnDevice() {
+        return mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_UWB);
+    }
+
+    @Override
+    public int getAvailabilityStatus() {
+        if (!isUwbSupportedOnDevice()) {
+            return UNSUPPORTED_ON_DEVICE;
+        } else if (mAirplaneModeOn) {
+            return DISABLED_DEPENDENT_SETTING;
+        } else {
+            return AVAILABLE;
+        }
+    }
+
+    @Override
+    public void displayPreference(PreferenceScreen screen) {
+        super.displayPreference(screen);
+        mPreference = screen.findPreference(getPreferenceKey());
+    }
+
+    @Override
+    public boolean isChecked() {
+        //TODO(b/186075119): Update toggle state by assigning to the real value by default.
+        return mIsChecked;
+    }
+
+    @Override
+    public boolean setChecked(boolean isChecked) {
+        mIsChecked = isChecked;
+        mUwbManager.setUwbEnabled(isChecked);
+        return true;
+    }
+
+    @Override
+    public void onStateChanged(int state, int reason) {
+        // Only update toggle state from service the first time. Otherwise toggle state is
+        // changed from controller. For example, UWB is disabled if airplane mode is on but we do
+        // not want to change the preference for the user in this case.
+        if (!mRegisteredAdapterStateCallback) {
+            mIsChecked = state == STATE_ENABLED_ACTIVE || state == STATE_ENABLED_INACTIVE;
+            mRegisteredAdapterStateCallback = true;
+        }
+    }
+
+    /** Called when activity starts being displayed to user. */
+    @OnLifecycleEvent(ON_START)
+    public void onStart() {
+        if (isUwbSupportedOnDevice()) {
+            mUwbManager.registerAdapterStateCallback(mExecutor, this);
+        }
+        if (mAirplaneModeChangedReceiver != null) {
+            mContext.registerReceiver(mAirplaneModeChangedReceiver,
+                    new IntentFilter(Intent.ACTION_AIRPLANE_MODE_CHANGED));
+        }
+        refreshSummary(mPreference);
+    }
+
+    /** Called when activity stops being displayed to user. */
+    @OnLifecycleEvent(ON_STOP)
+    public void onStop() {
+        if (isUwbSupportedOnDevice()) {
+            mUwbManager.unregisterAdapterStateCallback(this);
+        }
+        if (mAirplaneModeChangedReceiver != null) {
+            mContext.unregisterReceiver(mAirplaneModeChangedReceiver);
+        }
+    }
+
+    @Override
+    public void updateState(Preference preference) {
+        super.updateState(preference);
+        mAirplaneModeOn = Settings.Global.getInt(mContext.getContentResolver(),
+                Settings.Global.AIRPLANE_MODE_ON, 0) == 1;
+        preference.setEnabled(!mAirplaneModeOn);
+        if (isUwbSupportedOnDevice()) {
+            if (mAirplaneModeOn) {
+                mUwbManager.setUwbEnabled(false);
+            } else {
+                mUwbManager.setUwbEnabled(mIsChecked);
+            }
+        }
+        refreshSummary(preference);
+    }
+
+    @Override
+    public CharSequence getSummary() {
+        if (mAirplaneModeOn) {
+            return mContext.getResources().getString(R.string.uwb_settings_summary_airplane_mode);
+        } else {
+            return mContext.getResources().getString(R.string.uwb_settings_summary);
+        }
+    }
+}
+
diff --git a/tests/robotests/src/com/android/settings/bluetooth/BluetoothPermissionActivityTest.java b/tests/robotests/src/com/android/settings/bluetooth/BluetoothPermissionActivityTest.java
new file mode 100644
index 0000000..35b8f1f
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/bluetooth/BluetoothPermissionActivityTest.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.bluetooth;
+
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+
+import android.content.Context;
+import android.content.Intent;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.util.ReflectionHelpers;
+
+@RunWith(RobolectricTestRunner.class)
+public class BluetoothPermissionActivityTest {
+
+    private BluetoothPermissionActivity mActivity;
+    private Context mContext;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        mContext = spy(RuntimeEnvironment.application);
+        mActivity = new BluetoothPermissionActivity();
+    }
+
+    @Test
+    public void sendBroadcastWithPermission() {
+        final ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
+        ReflectionHelpers.setField(mActivity, "mBase", mContext);
+
+        mActivity.sendReplyIntentToReceiver(true, true);
+
+        verify(mContext).sendBroadcast(intentCaptor.capture(),
+                eq("android.permission.BLUETOOTH_ADMIN"));
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/bluetooth/DevicePickerFragmentTest.java b/tests/robotests/src/com/android/settings/bluetooth/DevicePickerFragmentTest.java
index feaf683..d9e054d 100644
--- a/tests/robotests/src/com/android/settings/bluetooth/DevicePickerFragmentTest.java
+++ b/tests/robotests/src/com/android/settings/bluetooth/DevicePickerFragmentTest.java
@@ -16,28 +16,43 @@
 
 package com.android.settings.bluetooth;
 
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.bluetooth.BluetoothDevice;
+import android.content.Context;
+import android.content.Intent;
+
+import com.android.settingslib.bluetooth.CachedBluetoothDevice;
 
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
 
 @RunWith(RobolectricTestRunner.class)
 public class DevicePickerFragmentTest {
 
     @Mock
     private BluetoothProgressCategory mAvailableDevicesCategory;
+
     private DevicePickerFragment mFragment;
+    private Context mContext;
 
     @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
 
         mFragment = new DevicePickerFragment();
-
+        mContext = spy(RuntimeEnvironment.application);
+        mFragment.mContext = mContext;
         mFragment.mAvailableDevicesCategory = mAvailableDevicesCategory;
     }
 
@@ -49,4 +64,18 @@
 
         verify(mAvailableDevicesCategory).setProgress(true);
     }
+
+    @Test
+    public void sendBroadcastWithPermission() {
+        final CachedBluetoothDevice cachedDevice = mock(CachedBluetoothDevice.class);
+        final BluetoothDevice bluetoothDevice = mock(BluetoothDevice.class);
+        final ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
+        when(cachedDevice.getDevice()).thenReturn(bluetoothDevice);
+        mFragment.mSelectedDevice = bluetoothDevice;
+
+        mFragment.onDeviceBondStateChanged(cachedDevice, BluetoothDevice.BOND_BONDED);
+
+        verify(mContext).sendBroadcast(intentCaptor.capture(),
+                eq("android.permission.BLUETOOTH_ADMIN"));
+    }
 }
diff --git a/tests/robotests/src/com/android/settings/display/ColorModePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/display/ColorModePreferenceControllerTest.java
deleted file mode 100644
index cf7e34f..0000000
--- a/tests/robotests/src/com/android/settings/display/ColorModePreferenceControllerTest.java
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.settings.display;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.when;
-
-import android.content.Context;
-import android.hardware.display.ColorDisplayManager;
-
-import androidx.preference.Preference;
-
-import com.android.settings.R;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-import org.robolectric.RobolectricTestRunner;
-import org.robolectric.RuntimeEnvironment;
-
-@RunWith(RobolectricTestRunner.class)
-public class ColorModePreferenceControllerTest {
-
-    @Mock
-    private ColorDisplayManager mColorDisplayManager;
-
-    private Context mContext;
-    private Preference mPreference;
-    private ColorModePreferenceController mController;
-
-    @Before
-    public void setup() {
-        MockitoAnnotations.initMocks(this);
-        mContext = RuntimeEnvironment.application;
-        mController = spy(new ColorModePreferenceController(mContext, "test"));
-        mPreference = new Preference(mContext);
-        doReturn(mColorDisplayManager).when(mController).getColorDisplayManager();
-    }
-
-    @Test
-    public void updateState_colorModeAutomatic_shouldSetSummaryToAutomatic() {
-        when(mColorDisplayManager.getColorMode())
-                .thenReturn(ColorDisplayManager.COLOR_MODE_AUTOMATIC);
-
-        mController.updateState(mPreference);
-
-        assertThat(mPreference.getSummary())
-                .isEqualTo(mContext.getText(R.string.color_mode_option_automatic));
-    }
-
-    @Test
-    public void updateState_colorModeSaturated_shouldSetSummaryToSaturated() {
-        when(mColorDisplayManager.getColorMode())
-                .thenReturn(ColorDisplayManager.COLOR_MODE_SATURATED);
-
-        mController.updateState(mPreference);
-
-        assertThat(mPreference.getSummary())
-                .isEqualTo(mContext.getText(R.string.color_mode_option_saturated));
-    }
-
-    @Test
-    public void updateState_colorModeBoosted_shouldSetSummaryToBoosted() {
-        when(mColorDisplayManager.getColorMode())
-                .thenReturn(ColorDisplayManager.COLOR_MODE_BOOSTED);
-
-        mController.updateState(mPreference);
-
-        assertThat(mPreference.getSummary())
-                .isEqualTo(mContext.getText(R.string.color_mode_option_boosted));
-    }
-
-    @Test
-    public void updateState_colorModeNatural_shouldSetSummaryToNatural() {
-        when(mColorDisplayManager.getColorMode())
-                .thenReturn(ColorDisplayManager.COLOR_MODE_NATURAL);
-
-        mController.updateState(mPreference);
-
-        assertThat(mPreference.getSummary())
-                .isEqualTo(mContext.getText(R.string.color_mode_option_natural));
-    }
-}
diff --git a/tests/robotests/src/com/android/settings/display/ColorModePreferenceFragmentTest.java b/tests/robotests/src/com/android/settings/display/ColorModePreferenceFragmentTest.java
deleted file mode 100644
index 54e8e4d..0000000
--- a/tests/robotests/src/com/android/settings/display/ColorModePreferenceFragmentTest.java
+++ /dev/null
@@ -1,236 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.settings.display;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.Mockito.doNothing;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.hardware.display.ColorDisplayManager;
-import android.os.Bundle;
-
-import androidx.preference.Preference;
-import androidx.preference.PreferenceScreen;
-
-import com.android.internal.logging.nano.MetricsProto;
-import com.android.settings.R;
-import com.android.settings.testutils.shadow.SettingsShadowResources;
-import com.android.settingslib.widget.CandidateInfo;
-import com.android.settingslib.widget.LayoutPreference;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.ArgumentCaptor;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-import org.robolectric.RobolectricTestRunner;
-import org.robolectric.RuntimeEnvironment;
-import org.robolectric.annotation.Config;
-import org.robolectric.util.ReflectionHelpers;
-
-import java.util.List;
-
-@RunWith(RobolectricTestRunner.class)
-@Config(shadows = SettingsShadowResources.class)
-public class ColorModePreferenceFragmentTest {
-
-    private ColorModePreferenceFragment mFragment;
-
-    @Mock
-    private ColorDisplayManager mManager;
-
-    @Before
-    public void setup() {
-        MockitoAnnotations.initMocks(this);
-
-        mFragment = spy(new ColorModePreferenceFragment());
-        ReflectionHelpers.setField(mFragment, "mColorDisplayManager", mManager);
-    }
-
-    @After
-    public void tearDown() {
-        SettingsShadowResources.reset();
-    }
-
-    @Test
-    public void verifyMetricsConstant() {
-        assertThat(mFragment.getMetricsCategory())
-                .isEqualTo(MetricsProto.MetricsEvent.COLOR_MODE_SETTINGS);
-    }
-
-    @Test
-    public void getCandidates_all() {
-        when(mFragment.getContext()).thenReturn(RuntimeEnvironment.application);
-        SettingsShadowResources.overrideResource(
-                com.android.internal.R.array.config_availableColorModes, new int[]{
-                        ColorDisplayManager.COLOR_MODE_NATURAL,
-                        ColorDisplayManager.COLOR_MODE_BOOSTED,
-                        ColorDisplayManager.COLOR_MODE_SATURATED,
-                        ColorDisplayManager.COLOR_MODE_AUTOMATIC
-                });
-        List<? extends CandidateInfo> candidates = mFragment.getCandidates();
-
-        assertThat(candidates.size()).isEqualTo(4);
-        assertThat(candidates.get(0).getKey())
-                .isEqualTo(ColorModePreferenceFragment.KEY_COLOR_MODE_NATURAL);
-        assertThat(candidates.get(1).getKey())
-                .isEqualTo(ColorModePreferenceFragment.KEY_COLOR_MODE_BOOSTED);
-        assertThat(candidates.get(2).getKey())
-                .isEqualTo(ColorModePreferenceFragment.KEY_COLOR_MODE_SATURATED);
-        assertThat(candidates.get(3).getKey())
-                .isEqualTo(ColorModePreferenceFragment.KEY_COLOR_MODE_AUTOMATIC);
-    }
-
-    @Test
-    public void getCandidates_none() {
-        when(mFragment.getContext()).thenReturn(RuntimeEnvironment.application);
-        SettingsShadowResources.overrideResource(
-                com.android.internal.R.array.config_availableColorModes, null);
-        List<? extends CandidateInfo> candidates = mFragment.getCandidates();
-
-        assertThat(candidates.size()).isEqualTo(0);
-    }
-
-    @Test
-    public void getCandidates_withAutomatic() {
-        when(mFragment.getContext()).thenReturn(RuntimeEnvironment.application);
-        SettingsShadowResources.overrideResource(
-                com.android.internal.R.array.config_availableColorModes, new int[]{
-                        ColorDisplayManager.COLOR_MODE_NATURAL,
-                        ColorDisplayManager.COLOR_MODE_AUTOMATIC
-                });
-        List<? extends CandidateInfo> candidates = mFragment.getCandidates();
-
-        assertThat(candidates.size()).isEqualTo(2);
-        assertThat(candidates.get(0).getKey())
-                .isEqualTo(ColorModePreferenceFragment.KEY_COLOR_MODE_NATURAL);
-        assertThat(candidates.get(1).getKey())
-                .isEqualTo(ColorModePreferenceFragment.KEY_COLOR_MODE_AUTOMATIC);
-    }
-
-    @Test
-    public void getCandidates_withoutAutomatic() {
-        when(mFragment.getContext()).thenReturn(RuntimeEnvironment.application);
-        SettingsShadowResources.overrideResource(
-                com.android.internal.R.array.config_availableColorModes, new int[]{
-                        ColorDisplayManager.COLOR_MODE_NATURAL,
-                        ColorDisplayManager.COLOR_MODE_BOOSTED,
-                        ColorDisplayManager.COLOR_MODE_SATURATED,
-                });
-        List<? extends CandidateInfo> candidates = mFragment.getCandidates();
-
-        assertThat(candidates.size()).isEqualTo(3);
-        assertThat(candidates.get(0).getKey())
-                .isEqualTo(ColorModePreferenceFragment.KEY_COLOR_MODE_NATURAL);
-        assertThat(candidates.get(1).getKey())
-                .isEqualTo(ColorModePreferenceFragment.KEY_COLOR_MODE_BOOSTED);
-        assertThat(candidates.get(2).getKey())
-                .isEqualTo(ColorModePreferenceFragment.KEY_COLOR_MODE_SATURATED);
-    }
-
-    @Test
-    public void getKey_natural() {
-        when(mManager.getColorMode())
-            .thenReturn(ColorDisplayManager.COLOR_MODE_NATURAL);
-
-        assertThat(mFragment.getDefaultKey())
-                .isEqualTo(ColorModePreferenceFragment.KEY_COLOR_MODE_NATURAL);
-    }
-
-    @Test
-    public void getKey_boosted() {
-        when(mManager.getColorMode())
-            .thenReturn(ColorDisplayManager.COLOR_MODE_BOOSTED);
-
-        assertThat(mFragment.getDefaultKey())
-                .isEqualTo(ColorModePreferenceFragment.KEY_COLOR_MODE_BOOSTED);
-    }
-
-    @Test
-    public void getKey_saturated() {
-        when(mManager.getColorMode())
-            .thenReturn(ColorDisplayManager.COLOR_MODE_SATURATED);
-
-        assertThat(mFragment.getDefaultKey())
-            .isEqualTo(ColorModePreferenceFragment.KEY_COLOR_MODE_SATURATED);
-    }
-
-    @Test
-    public void getKey_automatic() {
-        when(mManager.getColorMode())
-            .thenReturn(ColorDisplayManager.COLOR_MODE_AUTOMATIC);
-
-        assertThat(mFragment.getDefaultKey())
-            .isEqualTo(ColorModePreferenceFragment.KEY_COLOR_MODE_AUTOMATIC);
-    }
-
-    @Test
-    public void setKey_natural() {
-        mFragment.setDefaultKey(ColorModePreferenceFragment.KEY_COLOR_MODE_NATURAL);
-        verify(mManager).setColorMode(ColorDisplayManager.COLOR_MODE_NATURAL);
-    }
-
-    @Test
-    public void setKey_boosted() {
-        mFragment.setDefaultKey(ColorModePreferenceFragment.KEY_COLOR_MODE_BOOSTED);
-        verify(mManager).setColorMode(ColorDisplayManager.COLOR_MODE_BOOSTED);
-    }
-
-    @Test
-    public void setKey_saturated() {
-        mFragment.setDefaultKey(ColorModePreferenceFragment.KEY_COLOR_MODE_SATURATED);
-        verify(mManager).setColorMode(ColorDisplayManager.COLOR_MODE_SATURATED);
-    }
-
-    @Test
-    public void setKey_automatic() {
-        mFragment.setDefaultKey(ColorModePreferenceFragment.KEY_COLOR_MODE_AUTOMATIC);
-        verify(mManager).setColorMode(ColorDisplayManager.COLOR_MODE_AUTOMATIC);
-    }
-
-    @Test
-    public void onCreatePreferences_useNewTitle_shouldAddColorModePreferences() {
-        when(mFragment.getContext()).thenReturn(RuntimeEnvironment.application);
-        doNothing().when(mFragment).addPreferencesFromResource(anyInt());
-        doNothing().when(mFragment).updateCandidates();
-
-        mFragment.onCreatePreferences(Bundle.EMPTY, null /* rootKey */);
-
-        verify(mFragment).addPreferencesFromResource(R.xml.color_mode_settings);
-    }
-
-    @Test
-    public void addStaticPreferences_shouldAddPreviewImage() {
-        PreferenceScreen mockPreferenceScreen = mock(PreferenceScreen.class);
-        LayoutPreference mockPreview = mock(LayoutPreference.class);
-
-        ArgumentCaptor<Preference> preferenceCaptor = ArgumentCaptor.forClass(Preference.class);
-
-        mFragment.configureAndInstallPreview(mockPreview, mockPreferenceScreen);
-        verify(mockPreview, times(1)).setSelectable(false);
-        verify(mockPreferenceScreen, times(1)).addPreference(preferenceCaptor.capture());
-
-        assertThat(preferenceCaptor.getValue()).isEqualTo(mockPreview);
-    }
-}
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetailTest.java b/tests/robotests/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetailTest.java
index a288c3a..dd10a9e 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetailTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetailTest.java
@@ -249,14 +249,122 @@
     }
 
     @Test
-    public void testInitHeader_hasCorrectSummary() {
-        mFragment.mAppEntry = null;
+    public void testInitHeader_noUsageTime_hasCorrectSummary() {
+        Bundle bundle = new Bundle(2);
+        bundle.putLong(AdvancedPowerUsageDetail.EXTRA_BACKGROUND_TIME, /* value */ 0);
+        bundle.putLong(AdvancedPowerUsageDetail.EXTRA_FOREGROUND_TIME, /* value */ 0);
+        when(mFragment.getArguments()).thenReturn(bundle);
+
         mFragment.initHeader();
 
         ArgumentCaptor<CharSequence> captor = ArgumentCaptor.forClass(CharSequence.class);
         verify(mEntityHeaderController).setSummary(captor.capture());
         assertThat(captor.getValue().toString())
-                .isEqualTo("0 min total • 0 min background for past 24 hr");
+                .isEqualTo("No usage for past 24 hr");
+    }
+
+    @Test
+    public void testInitHeader_backgroundTwoMinutesForegroundZero_hasCorrectSummary() {
+        final long backgroundTimeTwoMinutes = 120000;
+        final long foregroundTimeZero = 0;
+        Bundle bundle = new Bundle(2);
+        bundle.putLong(AdvancedPowerUsageDetail.EXTRA_BACKGROUND_TIME, backgroundTimeTwoMinutes);
+        bundle.putLong(AdvancedPowerUsageDetail.EXTRA_FOREGROUND_TIME, foregroundTimeZero);
+        when(mFragment.getArguments()).thenReturn(bundle);
+
+        mFragment.initHeader();
+
+        ArgumentCaptor<CharSequence> captor = ArgumentCaptor.forClass(CharSequence.class);
+        verify(mEntityHeaderController).setSummary(captor.capture());
+        assertThat(captor.getValue().toString())
+                .isEqualTo("2 min background for past 24 hr");
+    }
+
+    @Test
+    public void testInitHeader_backgroundLessThanAMinutesForegroundZero_hasCorrectSummary() {
+        final long backgroundTimeLessThanAMinute = 59999;
+        final long foregroundTimeZero = 0;
+        Bundle bundle = new Bundle(2);
+        bundle.putLong(
+                AdvancedPowerUsageDetail.EXTRA_BACKGROUND_TIME, backgroundTimeLessThanAMinute);
+        bundle.putLong(AdvancedPowerUsageDetail.EXTRA_FOREGROUND_TIME, foregroundTimeZero);
+        when(mFragment.getArguments()).thenReturn(bundle);
+
+        mFragment.initHeader();
+
+        ArgumentCaptor<CharSequence> captor = ArgumentCaptor.forClass(CharSequence.class);
+        verify(mEntityHeaderController).setSummary(captor.capture());
+        assertThat(captor.getValue().toString())
+                .isEqualTo("Background less than a minute for past 24 hr");
+    }
+
+    @Test
+    public void testInitHeader_totalUsageLessThanAMinutes_hasCorrectSummary() {
+        final long backgroundTimeLessThanHalfMinute = 20000;
+        final long foregroundTimeLessThanHalfMinute = 20000;
+        Bundle bundle = new Bundle(2);
+        bundle.putLong(
+                AdvancedPowerUsageDetail.EXTRA_BACKGROUND_TIME, backgroundTimeLessThanHalfMinute);
+        bundle.putLong(
+                AdvancedPowerUsageDetail.EXTRA_FOREGROUND_TIME, foregroundTimeLessThanHalfMinute);
+        when(mFragment.getArguments()).thenReturn(bundle);
+
+        mFragment.initHeader();
+
+        ArgumentCaptor<CharSequence> captor = ArgumentCaptor.forClass(CharSequence.class);
+        verify(mEntityHeaderController).setSummary(captor.capture());
+        assertThat(captor.getValue().toString())
+                .isEqualTo("Total less than a minute for past 24 hr");
+    }
+
+    @Test
+    public void testInitHeader_TotalAMinutesBackgroundLessThanAMinutes_hasCorrectSummary() {
+        final long backgroundTimeZero = 59999;
+        final long foregroundTimeTwoMinutes = 1;
+        Bundle bundle = new Bundle(2);
+        bundle.putLong(AdvancedPowerUsageDetail.EXTRA_BACKGROUND_TIME, backgroundTimeZero);
+        bundle.putLong(AdvancedPowerUsageDetail.EXTRA_FOREGROUND_TIME, foregroundTimeTwoMinutes);
+        when(mFragment.getArguments()).thenReturn(bundle);
+
+        mFragment.initHeader();
+
+        ArgumentCaptor<CharSequence> captor = ArgumentCaptor.forClass(CharSequence.class);
+        verify(mEntityHeaderController).setSummary(captor.capture());
+        assertThat(captor.getValue().toString())
+                .isEqualTo("1 min total • background less than a minute for past 24 hr");
+    }
+
+    @Test
+    public void testInitHeader_TotalAMinutesBackgroundZero_hasCorrectSummary() {
+        final long backgroundTimeZero = 0;
+        final long foregroundTimeAMinutes = 60000;
+        Bundle bundle = new Bundle(2);
+        bundle.putLong(AdvancedPowerUsageDetail.EXTRA_BACKGROUND_TIME, backgroundTimeZero);
+        bundle.putLong(AdvancedPowerUsageDetail.EXTRA_FOREGROUND_TIME, foregroundTimeAMinutes);
+        when(mFragment.getArguments()).thenReturn(bundle);
+
+        mFragment.initHeader();
+
+        ArgumentCaptor<CharSequence> captor = ArgumentCaptor.forClass(CharSequence.class);
+        verify(mEntityHeaderController).setSummary(captor.capture());
+        assertThat(captor.getValue().toString())
+                .isEqualTo("1 min total for past 24 hr");
+    }
+
+    @Test
+    public void testInitHeader_foregroundTwoMinutesBackgroundFourMinutes_hasCorrectSummary() {
+        final long backgroundTimeFourMinute = 240000;
+        final long foregroundTimeTwoMinutes = 120000;
+        Bundle bundle = new Bundle(2);
+        bundle.putLong(AdvancedPowerUsageDetail.EXTRA_BACKGROUND_TIME, backgroundTimeFourMinute);
+        bundle.putLong(AdvancedPowerUsageDetail.EXTRA_FOREGROUND_TIME, foregroundTimeTwoMinutes);
+        when(mFragment.getArguments()).thenReturn(bundle);
+        mFragment.initHeader();
+
+        ArgumentCaptor<CharSequence> captor = ArgumentCaptor.forClass(CharSequence.class);
+        verify(mEntityHeaderController).setSummary(captor.capture());
+        assertThat(captor.getValue().toString())
+                .isEqualTo("6 min total • 4 min background for past 24 hr");
     }
 
     @Test
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/BatteryChartPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/fuelgauge/BatteryChartPreferenceControllerTest.java
index c8bbba3..9f0ffb0 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/BatteryChartPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/BatteryChartPreferenceControllerTest.java
@@ -43,6 +43,7 @@
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 import org.robolectric.RobolectricTestRunner;
@@ -56,6 +57,8 @@
 
 @RunWith(RobolectricTestRunner.class)
 public final class BatteryChartPreferenceControllerTest {
+    private static final String PREF_KEY = "pref_key";
+    private static final String PREF_SUMMARY = "fake preference summary";
 
     @Mock private InstrumentedPreferenceFragment mFragment;
     @Mock private SettingsActivity mSettingsActivity;
@@ -119,10 +122,9 @@
 
     @Test
     public void testOnDestroy_clearPreferenceCache() {
-        final String prefKey = "preference fake key";
         // Ensures the testing environment is correct.
         mBatteryChartPreferenceController.mPreferenceCache.put(
-            prefKey, mPowerGaugePreference);
+            PREF_KEY, mPowerGaugePreference);
         assertThat(mBatteryChartPreferenceController.mPreferenceCache).hasSize(1);
 
         mBatteryChartPreferenceController.onDestroy();
@@ -230,17 +232,16 @@
     @Test
     public void testRemoveAndCacheAllPrefs_buildCacheAndRemoveAllPreference() {
         final int trapezoidIndex = 1;
-        final String prefKey = "preference fake key";
         doReturn(1).when(mAppListGroup).getPreferenceCount();
         doReturn(mPowerGaugePreference).when(mAppListGroup).getPreference(0);
-        doReturn(prefKey).when(mPowerGaugePreference).getKey();
+        doReturn(PREF_KEY).when(mPowerGaugePreference).getKey();
         // Ensures the testing data is correct.
         assertThat(mBatteryChartPreferenceController.mPreferenceCache).isEmpty();
 
         mBatteryChartPreferenceController.refreshUi(
             trapezoidIndex, /*isForce=*/ true);
 
-        assertThat(mBatteryChartPreferenceController.mPreferenceCache.get(prefKey))
+        assertThat(mBatteryChartPreferenceController.mPreferenceCache.get(PREF_KEY))
             .isEqualTo(mPowerGaugePreference);
         verify(mAppListGroup).removeAll();
     }
@@ -254,12 +255,12 @@
 
     @Test
     public void testAddPreferenceToScreen_addPreferenceIntoScreen() {
-        final String prefKey = "preference fake key";
         final String appLabel = "fake app label";
         doReturn(1).when(mAppListGroup).getPreferenceCount();
         doReturn(mDrawable).when(mBatteryDiffEntry).getAppIcon();
         doReturn(appLabel).when(mBatteryDiffEntry).getAppLabel();
-        doReturn(prefKey).when(mBatteryHistEntry).getKey();
+        doReturn(PREF_KEY).when(mBatteryHistEntry).getKey();
+        doReturn(null).when(mAppListGroup).findPreference(PREF_KEY);
 
         mBatteryChartPreferenceController.addPreferenceToScreen(
             Arrays.asList(mBatteryDiffEntry));
@@ -267,11 +268,11 @@
         // Verifies the preference cache.
         final PowerGaugePreference pref =
             (PowerGaugePreference) mBatteryChartPreferenceController.mPreferenceCache
-                .get(prefKey);
+                .get(PREF_KEY);
         assertThat(pref).isNotNull();
         // Verifies the added preference configuration.
         verify(mAppListGroup).addPreference(pref);
-        assertThat(pref.getKey()).isEqualTo(prefKey);
+        assertThat(pref.getKey()).isEqualTo(PREF_KEY);
         assertThat(pref.getTitle()).isEqualTo(appLabel);
         assertThat(pref.getIcon()).isEqualTo(mDrawable);
         assertThat(pref.getOrder()).isEqualTo(1);
@@ -280,6 +281,21 @@
     }
 
     @Test
+    public void testAddPreferenceToScreen_alreadyInScreen_notAddPreferenceAgain() {
+        final String appLabel = "fake app label";
+        doReturn(1).when(mAppListGroup).getPreferenceCount();
+        doReturn(mDrawable).when(mBatteryDiffEntry).getAppIcon();
+        doReturn(appLabel).when(mBatteryDiffEntry).getAppLabel();
+        doReturn(PREF_KEY).when(mBatteryHistEntry).getKey();
+        doReturn(mPowerGaugePreference).when(mAppListGroup).findPreference(PREF_KEY);
+
+        mBatteryChartPreferenceController.addPreferenceToScreen(
+            Arrays.asList(mBatteryDiffEntry));
+
+        verify(mAppListGroup, never()).addPreference(any());
+    }
+
+    @Test
     public void testHandlePreferenceTreeClick_notPowerGaugePreference_returnFalse() {
         assertThat(mBatteryChartPreferenceController.handlePreferenceTreeClick(mAppListGroup))
             .isFalse();
@@ -309,7 +325,7 @@
     @Test
     public void testSetPreferenceSummary_setNullContentIfTotalUsageTimeIsZero() {
         final PowerGaugePreference pref = new PowerGaugePreference(mContext);
-        pref.setSummary("fake preference summary");
+        pref.setSummary(PREF_SUMMARY);
 
         mBatteryChartPreferenceController.setPreferenceSummary(
             pref, createBatteryDiffEntry(
@@ -321,7 +337,7 @@
     @Test
     public void testSetPreferenceSummary_setBackgroundUsageTimeOnly() {
         final PowerGaugePreference pref = new PowerGaugePreference(mContext);
-        pref.setSummary("fake preference summary");
+        pref.setSummary(PREF_SUMMARY);
 
         mBatteryChartPreferenceController.setPreferenceSummary(
             pref, createBatteryDiffEntry(
@@ -333,7 +349,7 @@
     @Test
     public void testSetPreferenceSummary_setTotalUsageTimeLessThanAMinute() {
         final PowerGaugePreference pref = new PowerGaugePreference(mContext);
-        pref.setSummary("fake preference summary");
+        pref.setSummary(PREF_SUMMARY);
 
         mBatteryChartPreferenceController.setPreferenceSummary(
             pref, createBatteryDiffEntry(
@@ -345,7 +361,7 @@
     @Test
     public void testSetPreferenceSummary_setTotalTimeIfBackgroundTimeLessThanAMinute() {
         final PowerGaugePreference pref = new PowerGaugePreference(mContext);
-        pref.setSummary("fake preference summary");
+        pref.setSummary(PREF_SUMMARY);
 
         mBatteryChartPreferenceController.setPreferenceSummary(
             pref, createBatteryDiffEntry(
@@ -357,7 +373,7 @@
     @Test
     public void testSetPreferenceSummary_setTotalAndBackgroundUsageTime() {
         final PowerGaugePreference pref = new PowerGaugePreference(mContext);
-        pref.setSummary("fake preference summary");
+        pref.setSummary(PREF_SUMMARY);
 
         mBatteryChartPreferenceController.setPreferenceSummary(
             pref, createBatteryDiffEntry(
@@ -369,7 +385,7 @@
     @Test
     public void testSetPreferenceSummary_notAllowShownPackage_setSummayAsNull() {
         final PowerGaugePreference pref = new PowerGaugePreference(mContext);
-        pref.setSummary("fake preference summary");
+        pref.setSummary(PREF_SUMMARY);
         final BatteryDiffEntry batteryDiffEntry =
             spy(createBatteryDiffEntry(
                 /*foregroundUsageTimeInMs=*/ DateUtils.MINUTE_IN_MILLIS,
@@ -416,23 +432,54 @@
 
     @Test
     public void testValidateSlotTimestamp_returnExpectedResult() {
-        final List<Long> slotTimestampList =
+        final ArrayList<Long> slotTimestampList = new ArrayList<Long>(
             Arrays.asList(
                 Long.valueOf(0),
                 Long.valueOf(DateUtils.HOUR_IN_MILLIS),
                 Long.valueOf(DateUtils.HOUR_IN_MILLIS * 2 + DateUtils.MINUTE_IN_MILLIS),
-                Long.valueOf(DateUtils.HOUR_IN_MILLIS * 3 + DateUtils.MINUTE_IN_MILLIS * 2));
+                Long.valueOf(DateUtils.HOUR_IN_MILLIS * 3 + DateUtils.MINUTE_IN_MILLIS * 2)));
         // Verifies the testing data is correct before we added invalid data into it.
         assertThat(BatteryChartPreferenceController.validateSlotTimestamp(slotTimestampList))
             .isTrue();
 
         // Insert invalid timestamp into the list.
         slotTimestampList.add(
-            Long.valueOf(DateUtils.HOUR_IN_MILLIS * 4 + DateUtils.MINUTE_IN_MILLIS * 3));
+            Long.valueOf(DateUtils.HOUR_IN_MILLIS * 4 + DateUtils.MINUTE_IN_MILLIS * 6));
         assertThat(BatteryChartPreferenceController.validateSlotTimestamp(slotTimestampList))
             .isFalse();
     }
 
+    @Test
+    public void testOnExpand_expandedIsTrue_addSystemEntriesToPreferenceGroup() {
+        doReturn(1).when(mAppListGroup).getPreferenceCount();
+        mBatteryChartPreferenceController.mSystemEntries.add(mBatteryDiffEntry);
+        doReturn("label").when(mBatteryDiffEntry).getAppLabel();
+        doReturn(mDrawable).when(mBatteryDiffEntry).getAppIcon();
+        doReturn(PREF_KEY).when(mBatteryHistEntry).getKey();
+
+        mBatteryChartPreferenceController.onExpand(/*isExpanded=*/ true);
+
+        final ArgumentCaptor<Preference> captor = ArgumentCaptor.forClass(Preference.class);
+        verify(mAppListGroup).addPreference(captor.capture());
+        // Verifies the added preference.
+        assertThat(captor.getValue().getKey()).isEqualTo(PREF_KEY);
+    }
+
+    @Test
+    public void testOnExpand_expandedIsFalse_removeSystemEntriesFromPreferenceGroup() {
+        doReturn(PREF_KEY).when(mBatteryHistEntry).getKey();
+        doReturn(mPowerGaugePreference).when(mAppListGroup).findPreference(PREF_KEY);
+        mBatteryChartPreferenceController.mSystemEntries.add(mBatteryDiffEntry);
+        // Verifies the cache is empty first.
+        assertThat(mBatteryChartPreferenceController.mPreferenceCache).isEmpty();
+
+        mBatteryChartPreferenceController.onExpand(/*isExpanded=*/ false);
+
+        verify(mAppListGroup).findPreference(PREF_KEY);
+        verify(mAppListGroup).removePreference(mPowerGaugePreference);
+        assertThat(mBatteryChartPreferenceController.mPreferenceCache).hasSize(1);
+    }
+
     private static Map<Long, List<BatteryHistEntry>> createBatteryHistoryMap(int size) {
         final Map<Long, List<BatteryHistEntry>> batteryHistoryMap = new HashMap<>();
         for (int index = 0; index < size; index++) {
diff --git a/tests/robotests/src/com/android/settings/notification/NotificationAssistantPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/NotificationAssistantPreferenceControllerTest.java
index f6b72d9..9b45a98 100644
--- a/tests/robotests/src/com/android/settings/notification/NotificationAssistantPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/notification/NotificationAssistantPreferenceControllerTest.java
@@ -122,13 +122,13 @@
         assertEquals(1, Settings.Secure.getIntForUser(mContext.getContentResolver(),
                 Settings.Secure.NAS_SETTINGS_UPDATED, 0, 10));
         verify(mBackend, times(1))
-                .resetDefaultNotificationAssistant(eq(true));
+                .setNASMigrationDoneAndResetDefault(eq(0), eq(true));
 
         //Test user enable again, migration should not happen
         mPreferenceController.setNotificationAssistantGranted(mNASComponent);
         //Number of invocations should not increase
         verify(mBackend, times(1))
-                .resetDefaultNotificationAssistant(eq(true));
+                .setNASMigrationDoneAndResetDefault(eq(0), eq(true));
     }
 
     @Test
@@ -146,13 +146,13 @@
         assertEquals(0, Settings.Secure.getIntForUser(mContext.getContentResolver(),
                 Settings.Secure.NAS_SETTINGS_UPDATED, 0, 20));
         verify(mBackend, times(1))
-                .resetDefaultNotificationAssistant(eq(true));
+                .setNASMigrationDoneAndResetDefault(eq(0), eq(true));
 
         //Test user enable again, migration should not happen
         mPreferenceController.setNotificationAssistantGranted(mNASComponent);
         //Number of invocations should not increase
         verify(mBackend, times(1))
-                .resetDefaultNotificationAssistant(eq(true));
+                .setNASMigrationDoneAndResetDefault(eq(0), eq(true));
     }
 
     @Test
@@ -170,13 +170,13 @@
         assertEquals(1, Settings.Secure.getIntForUser(mContext.getContentResolver(),
                 Settings.Secure.NAS_SETTINGS_UPDATED, 0, 10));
         verify(mBackend, times(1))
-                .resetDefaultNotificationAssistant(eq(false));
+                .setNASMigrationDoneAndResetDefault(eq(0), eq(false));
 
         //Test user disable again, migration should not happen
         mPreferenceController.setChecked(false);
         //Number of invocations should not increase
         verify(mBackend, times(1))
-                .resetDefaultNotificationAssistant(eq(false));
+                .setNASMigrationDoneAndResetDefault(eq(0), eq(false));
     }
 
 }
diff --git a/tests/robotests/src/com/android/settings/uwb/UwbPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/uwb/UwbPreferenceControllerTest.java
new file mode 100644
index 0000000..00dc4df
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/uwb/UwbPreferenceControllerTest.java
@@ -0,0 +1,176 @@
+/*
+ * Copyright (C) 2021 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.uwb;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.clearInvocations;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.uwb.UwbManager;
+
+import com.android.settings.core.BasePreferenceController;
+
+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.RuntimeEnvironment;
+
+/** Unit tests for UWB preference toggle. */
+@RunWith(RobolectricTestRunner.class)
+public class UwbPreferenceControllerTest {
+    @Rule
+    public MockitoRule rule = MockitoJUnit.rule();
+
+    private Context mContext;
+    private PackageManager mPackageManager;
+    private UwbPreferenceController mController;
+
+    @Mock
+    private UwbManager mUwbManager;
+
+    @Before
+    public void setUp() {
+        mContext = spy(RuntimeEnvironment.application);
+        mPackageManager = spy(mContext.getPackageManager());
+        mController = new UwbPreferenceController(mContext, "uwb_settings");
+        mController.mUwbManager = mUwbManager;
+    }
+
+    @Test
+    public void getAvailabilityStatus_uwbDisabled_shouldReturnDisabled() {
+        doReturn(mPackageManager).when(mContext).getPackageManager();
+        doReturn(true).when(mPackageManager)
+                .hasSystemFeature(PackageManager.FEATURE_UWB);
+        mController.mAirplaneModeOn = true;
+
+        assertThat(mController.getAvailabilityStatus())
+                .isEqualTo(BasePreferenceController.DISABLED_DEPENDENT_SETTING);
+    }
+
+    @Test
+    public void getAvailabilityStatus_uwbShown_shouldReturnAvailable() {
+        doReturn(mPackageManager).when(mContext).getPackageManager();
+        doReturn(true).when(mPackageManager)
+                .hasSystemFeature(PackageManager.FEATURE_UWB);
+        mController.mAirplaneModeOn = false;
+
+        assertThat(mController.getAvailabilityStatus())
+                .isEqualTo(BasePreferenceController.AVAILABLE);
+    }
+
+    @Test
+    public void getAvailabilityStatus_uwbNotShown_shouldReturnUnsupported() {
+        doReturn(mPackageManager).when(mContext).getPackageManager();
+        doReturn(false).when(mPackageManager)
+                .hasSystemFeature(PackageManager.FEATURE_UWB);
+
+        assertThat(mController.getAvailabilityStatus())
+                .isEqualTo(BasePreferenceController.UNSUPPORTED_ON_DEVICE);
+    }
+
+    @Test
+    public void onStateChanged_stateNotRegistered_shouldUpdate() {
+        mController.mRegisteredAdapterStateCallback = false;
+        mController.onStateChanged(UwbManager.AdapterStateCallback.STATE_DISABLED,
+                UwbManager.AdapterStateCallback.STATE_CHANGED_REASON_SYSTEM_POLICY);
+
+        assertThat(mController.isChecked()).isFalse();
+    }
+
+    @Test
+    public void onStateChanged_stateRegistered_shouldNotUpdate() {
+        mController.mRegisteredAdapterStateCallback = true;
+        mController.onStateChanged(UwbManager.AdapterStateCallback.STATE_ENABLED_INACTIVE,
+                UwbManager.AdapterStateCallback.STATE_CHANGED_REASON_SYSTEM_POLICY);
+
+        assertThat(mController.isChecked()).isTrue();
+    }
+
+    @Test
+    public void isChecked_uwbEnabledInactive_shouldReturnTrue() {
+        doReturn(mPackageManager).when(mContext).getPackageManager();
+        doReturn(true).when(mPackageManager)
+                .hasSystemFeature(PackageManager.FEATURE_UWB);
+        mController.mRegisteredAdapterStateCallback = false;
+        mController.onStateChanged(UwbManager.AdapterStateCallback.STATE_ENABLED_INACTIVE,
+                UwbManager.AdapterStateCallback.STATE_CHANGED_REASON_SYSTEM_POLICY);
+
+        assertThat(mController.isChecked()).isTrue();
+    }
+
+    @Test
+    public void isChecked_uwbEnabledActive_shouldReturnTrue() {
+        doReturn(mPackageManager).when(mContext).getPackageManager();
+        doReturn(true).when(mPackageManager)
+                .hasSystemFeature(PackageManager.FEATURE_UWB);
+        mController.mRegisteredAdapterStateCallback = false;
+        mController.onStateChanged(UwbManager.AdapterStateCallback.STATE_ENABLED_ACTIVE,
+                UwbManager.AdapterStateCallback.STATE_CHANGED_REASON_SYSTEM_POLICY);
+
+        assertThat(mController.isChecked()).isTrue();
+    }
+
+    @Test
+    public void isChecked_uwbDisabled_shouldReturnFalse() {
+        doReturn(mPackageManager).when(mContext).getPackageManager();
+        doReturn(true).when(mPackageManager)
+                .hasSystemFeature(PackageManager.FEATURE_UWB);
+        mController.mRegisteredAdapterStateCallback = false;
+        mController.onStateChanged(UwbManager.AdapterStateCallback.STATE_DISABLED,
+                UwbManager.AdapterStateCallback.STATE_CHANGED_REASON_SYSTEM_POLICY);
+
+        assertThat(mController.isChecked()).isFalse();
+    }
+
+    @Test
+    public void setChecked_uwbDisabled_shouldEnableUwb() {
+        clearInvocations(mUwbManager);
+        doReturn(mPackageManager).when(mContext).getPackageManager();
+        doReturn(true).when(mPackageManager)
+                .hasSystemFeature(PackageManager.FEATURE_UWB);
+
+        mController.setChecked(true);
+
+        verify(mUwbManager).setUwbEnabled(true);
+        verify(mUwbManager, never()).setUwbEnabled(false);
+    }
+
+    @Test
+    public void setChecked_uwbEnabled_shouldDisableUwb() {
+        clearInvocations(mUwbManager);
+        doReturn(mPackageManager).when(mContext).getPackageManager();
+        doReturn(true).when(mPackageManager)
+                .hasSystemFeature(PackageManager.FEATURE_UWB);
+
+        mController.setChecked(false);
+
+        verify(mUwbManager).setUwbEnabled(false);
+        verify(mUwbManager, never()).setUwbEnabled(true);
+    }
+}
+
diff --git a/tests/unit/src/com/android/settings/display/ColorModePreferenceControllerTest.java b/tests/unit/src/com/android/settings/display/ColorModePreferenceControllerTest.java
new file mode 100644
index 0000000..e2f77fd
--- /dev/null
+++ b/tests/unit/src/com/android/settings/display/ColorModePreferenceControllerTest.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2021 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.display;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.hardware.display.ColorDisplayManager;
+
+import androidx.preference.Preference;
+import androidx.test.annotation.UiThreadTest;
+import androidx.test.core.app.ApplicationProvider;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class ColorModePreferenceControllerTest {
+
+    private Preference mPreference;
+    private ColorModePreferenceController mController;
+
+    @Before
+    public void setup() {
+        final Context context = spy(ApplicationProvider.getApplicationContext());
+        mController = spy(new ColorModePreferenceController(context, "test"));
+        mPreference = new Preference(context);
+        final Resources res = spy(context.getResources());
+        when(res.getIntArray(com.android.internal.R.array.config_availableColorModes)).thenReturn(
+                new int[]{
+                        ColorDisplayManager.COLOR_MODE_NATURAL,
+                        ColorDisplayManager.COLOR_MODE_BOOSTED,
+                        ColorDisplayManager.COLOR_MODE_SATURATED,
+                        ColorDisplayManager.COLOR_MODE_AUTOMATIC
+                });
+        doReturn(res).when(context).getResources();
+    }
+
+    @Test
+    @UiThreadTest
+    public void updateState_colorModeAutomatic_shouldSetSummaryToAutomatic() {
+        doReturn(ColorDisplayManager.COLOR_MODE_AUTOMATIC).when(mController).getColorMode();
+
+        mController.updateState(mPreference);
+
+        assertThat(mPreference.getSummary()).isEqualTo("Adaptive");
+    }
+
+    @Test
+    @UiThreadTest
+    public void updateState_colorModeSaturated_shouldSetSummaryToSaturated() {
+        doReturn(ColorDisplayManager.COLOR_MODE_SATURATED).when(mController).getColorMode();
+
+        mController.updateState(mPreference);
+
+        assertThat(mPreference.getSummary()).isEqualTo("Saturated");
+    }
+
+    @Test
+    public void updateState_colorModeBoosted_shouldSetSummaryToBoosted() {
+        doReturn(ColorDisplayManager.COLOR_MODE_BOOSTED).when(mController).getColorMode();
+
+        mController.updateState(mPreference);
+
+        assertThat(mPreference.getSummary()).isEqualTo("Boosted");
+    }
+
+    @Test
+    public void updateState_colorModeNatural_shouldSetSummaryToNatural() {
+        doReturn(ColorDisplayManager.COLOR_MODE_NATURAL).when(mController).getColorMode();
+
+        mController.updateState(mPreference);
+
+        assertThat(mPreference.getSummary()).isEqualTo("Natural");
+    }
+}
diff --git a/tests/unit/src/com/android/settings/display/ColorModePreferenceFragmentTest.java b/tests/unit/src/com/android/settings/display/ColorModePreferenceFragmentTest.java
new file mode 100644
index 0000000..cfdedc7
--- /dev/null
+++ b/tests/unit/src/com/android/settings/display/ColorModePreferenceFragmentTest.java
@@ -0,0 +1,235 @@
+/*
+ * Copyright (C) 2021 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.display;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.hardware.display.ColorDisplayManager;
+
+import androidx.test.annotation.UiThreadTest;
+import androidx.test.core.app.ApplicationProvider;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import com.android.internal.logging.nano.MetricsProto;
+import com.android.settingslib.widget.CandidateInfo;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.List;
+
+@RunWith(AndroidJUnit4.class)
+public class ColorModePreferenceFragmentTest {
+
+    private ColorModePreferenceFragment mFragment;
+
+    private Context mContext;
+
+    @Before
+    @UiThreadTest
+    public void setup() {
+        mContext = spy(ApplicationProvider.getApplicationContext());
+        mFragment = spy(new ColorModePreferenceFragment());
+        doNothing().when(mFragment).setColorMode(anyInt());
+    }
+
+    @Test
+    public void verifyMetricsConstant() {
+        assertThat(mFragment.getMetricsCategory())
+                .isEqualTo(MetricsProto.MetricsEvent.COLOR_MODE_SETTINGS);
+    }
+
+    @Test
+    @UiThreadTest
+    public void getCandidates_all() {
+        final Resources res = spy(mContext.getResources());
+        when(res.getIntArray(com.android.internal.R.array.config_availableColorModes)).thenReturn(
+                new int[]{
+                        ColorDisplayManager.COLOR_MODE_NATURAL,
+                        ColorDisplayManager.COLOR_MODE_BOOSTED,
+                        ColorDisplayManager.COLOR_MODE_SATURATED,
+                        ColorDisplayManager.COLOR_MODE_AUTOMATIC
+                });
+        doReturn(res).when(mContext).getResources();
+        mFragment.onAttach(mContext);
+
+        final List<? extends CandidateInfo> candidates = mFragment.getCandidates();
+
+        assertThat(candidates.size()).isEqualTo(4);
+        assertThat(candidates.get(0).getKey())
+                .isEqualTo(mFragment.getKeyForColorMode(ColorDisplayManager.COLOR_MODE_NATURAL));
+        assertThat(candidates.get(1).getKey())
+                .isEqualTo(mFragment.getKeyForColorMode(ColorDisplayManager.COLOR_MODE_BOOSTED));
+        assertThat(candidates.get(2).getKey())
+                .isEqualTo(mFragment.getKeyForColorMode(ColorDisplayManager.COLOR_MODE_SATURATED));
+        assertThat(candidates.get(3).getKey())
+                .isEqualTo(mFragment.getKeyForColorMode(ColorDisplayManager.COLOR_MODE_AUTOMATIC));
+    }
+
+    @Test
+    @UiThreadTest
+    public void getCandidates_none() {
+        final Resources res = spy(mContext.getResources());
+        when(res.getIntArray(com.android.internal.R.array.config_availableColorModes)).thenReturn(
+                new int[]{
+                });
+        doReturn(res).when(mContext).getResources();
+        mFragment.onAttach(mContext);
+
+        List<? extends CandidateInfo> candidates = mFragment.getCandidates();
+
+        assertThat(candidates.size()).isEqualTo(0);
+    }
+
+    @Test
+    @UiThreadTest
+    public void getCandidates_withAutomatic() {
+        final Resources res = spy(mContext.getResources());
+        when(res.getIntArray(com.android.internal.R.array.config_availableColorModes)).thenReturn(
+                new int[]{
+                        ColorDisplayManager.COLOR_MODE_NATURAL,
+                        ColorDisplayManager.COLOR_MODE_AUTOMATIC
+                });
+        doReturn(res).when(mContext).getResources();
+        mFragment.onAttach(mContext);
+
+        List<? extends CandidateInfo> candidates = mFragment.getCandidates();
+
+        assertThat(candidates.size()).isEqualTo(2);
+        assertThat(candidates.get(0).getKey())
+                .isEqualTo(mFragment.getKeyForColorMode(ColorDisplayManager.COLOR_MODE_NATURAL));
+        assertThat(candidates.get(1).getKey())
+                .isEqualTo(mFragment.getKeyForColorMode(ColorDisplayManager.COLOR_MODE_AUTOMATIC));
+    }
+
+    @Test
+    @UiThreadTest
+    public void getCandidates_withoutAutomatic() {
+        final Resources res = spy(mContext.getResources());
+        when(res.getIntArray(com.android.internal.R.array.config_availableColorModes)).thenReturn(
+                new int[]{
+                        ColorDisplayManager.COLOR_MODE_NATURAL,
+                        ColorDisplayManager.COLOR_MODE_BOOSTED,
+                        ColorDisplayManager.COLOR_MODE_SATURATED
+                });
+        doReturn(res).when(mContext).getResources();
+        mFragment.onAttach(mContext);
+
+        List<? extends CandidateInfo> candidates = mFragment.getCandidates();
+
+        assertThat(candidates.size()).isEqualTo(3);
+        assertThat(candidates.get(0).getKey())
+                .isEqualTo(mFragment.getKeyForColorMode(ColorDisplayManager.COLOR_MODE_NATURAL));
+        assertThat(candidates.get(1).getKey())
+                .isEqualTo(mFragment.getKeyForColorMode(ColorDisplayManager.COLOR_MODE_BOOSTED));
+        assertThat(candidates.get(2).getKey())
+                .isEqualTo(mFragment.getKeyForColorMode(ColorDisplayManager.COLOR_MODE_SATURATED));
+    }
+
+    @Test
+    @UiThreadTest
+    public void getKey_natural() {
+        doReturn(ColorDisplayManager.COLOR_MODE_NATURAL).when(mFragment).getColorMode();
+        mFragment.onAttach(mContext);
+
+        assertThat(mFragment.getDefaultKey())
+                .isEqualTo(mFragment.getKeyForColorMode(ColorDisplayManager.COLOR_MODE_NATURAL));
+    }
+
+    @Test
+    @UiThreadTest
+    public void getKey_boosted() {
+        doReturn(ColorDisplayManager.COLOR_MODE_BOOSTED).when(mFragment).getColorMode();
+        mFragment.onAttach(mContext);
+
+        assertThat(mFragment.getDefaultKey())
+                .isEqualTo(mFragment.getKeyForColorMode(ColorDisplayManager.COLOR_MODE_BOOSTED));
+    }
+
+    @Test
+    @UiThreadTest
+    public void getKey_saturated() {
+        doReturn(ColorDisplayManager.COLOR_MODE_SATURATED).when(mFragment).getColorMode();
+        mFragment.onAttach(mContext);
+
+        assertThat(mFragment.getDefaultKey())
+                .isEqualTo(mFragment.getKeyForColorMode(ColorDisplayManager.COLOR_MODE_SATURATED));
+    }
+
+    @Test
+    @UiThreadTest
+    public void getKey_automatic() {
+        doReturn(ColorDisplayManager.COLOR_MODE_AUTOMATIC).when(mFragment).getColorMode();
+        mFragment.onAttach(mContext);
+
+        assertThat(mFragment.getDefaultKey())
+                .isEqualTo(mFragment.getKeyForColorMode(ColorDisplayManager.COLOR_MODE_AUTOMATIC));
+    }
+
+    @Test
+    @UiThreadTest
+    public void setKey_natural() {
+        mFragment.onAttach(mContext);
+
+        mFragment.setDefaultKey(
+                mFragment.getKeyForColorMode(ColorDisplayManager.COLOR_MODE_NATURAL));
+
+        verify(mFragment).setColorMode(ColorDisplayManager.COLOR_MODE_NATURAL);
+    }
+
+    @Test
+    @UiThreadTest
+    public void setKey_boosted() {
+        mFragment.onAttach(mContext);
+
+        mFragment.setDefaultKey(
+                mFragment.getKeyForColorMode(ColorDisplayManager.COLOR_MODE_BOOSTED));
+
+        verify(mFragment).setColorMode(ColorDisplayManager.COLOR_MODE_BOOSTED);
+    }
+
+    @Test
+    @UiThreadTest
+    public void setKey_saturated() {
+        mFragment.onAttach(mContext);
+
+        mFragment.setDefaultKey(
+                mFragment.getKeyForColorMode(ColorDisplayManager.COLOR_MODE_SATURATED));
+
+        verify(mFragment).setColorMode(ColorDisplayManager.COLOR_MODE_SATURATED);
+    }
+
+    @Test
+    @UiThreadTest
+    public void setKey_automatic() {
+        mFragment.onAttach(mContext);
+
+        mFragment.setDefaultKey(
+                mFragment.getKeyForColorMode(ColorDisplayManager.COLOR_MODE_AUTOMATIC));
+
+        verify(mFragment).setColorMode(ColorDisplayManager.COLOR_MODE_AUTOMATIC);
+    }
+}
diff --git a/tests/unit/src/com/android/settings/network/telephony/Enable2gPreferenceControllerTest.java b/tests/unit/src/com/android/settings/network/telephony/Enable2gPreferenceControllerTest.java
index 293a19d..5ade979 100644
--- a/tests/unit/src/com/android/settings/network/telephony/Enable2gPreferenceControllerTest.java
+++ b/tests/unit/src/com/android/settings/network/telephony/Enable2gPreferenceControllerTest.java
@@ -48,6 +48,8 @@
     @Mock
     private TelephonyManager mTelephonyManager;
     @Mock
+    private TelephonyManager mInvalidTelephonyManager;
+    @Mock
     private CarrierConfigManager mCarrierConfigManager;
 
     private PersistableBundle mPersistableBundle;
@@ -65,6 +67,8 @@
               .thenReturn(mCarrierConfigManager);
 
         doReturn(mTelephonyManager).when(mTelephonyManager).createForSubscriptionId(SUB_ID);
+        doReturn(mInvalidTelephonyManager).when(mTelephonyManager).createForSubscriptionId(
+                SubscriptionManager.INVALID_SUBSCRIPTION_ID);
 
         mPersistableBundle = new PersistableBundle();
         doReturn(mPersistableBundle).when(mCarrierConfigManager).getConfigForSubId(SUB_ID);
@@ -121,6 +125,18 @@
     }
 
     @Test
+    public void setChecked_invalidSubIdAndIsCheckedTrue_returnFalse() {
+        mController.init(SubscriptionManager.INVALID_SUBSCRIPTION_ID);
+        assertThat(mController.setChecked(true)).isFalse();
+    }
+
+    @Test
+    public void setChecked_invalidSubIdAndIsCheckedFalse_returnFalse() {
+        mController.init(SubscriptionManager.INVALID_SUBSCRIPTION_ID);
+        assertThat(mController.setChecked(false)).isFalse();
+    }
+
+    @Test
     public void onPreferenceChange_update() {
         // Set "Enable 2G" flag to "on"
         when(mTelephonyManager.getAllowedNetworkTypesForReason(