Merge "Update api name"
am: f82f807e03

Change-Id: I20240365a45eb27bcfed019ac77e4e6bfe09d24d
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 7ca32f4..1e4d010 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -937,6 +937,24 @@
         </activity>
 
         <activity
+                android:name="Settings$DarkThemeSettingsActivity"
+                android:label="@string/dark_ui_auto_mode_title"
+                android:enabled="true">
+            <intent-filter android:priority="32">
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="com.android.settings.SHORTCUT" />
+            </intent-filter>
+            <intent-filter android:priority="1">
+                <action android:name="android.settings.DARK_THEME_SETTINGS" />
+                <category android:name="android.intent.category.DEFAULT" />
+            </intent-filter>
+            <meta-data android:name="com.android.settings.FRAGMENT_CLASS"
+                android:value="com.android.settings.display.darkmode.DarkModeSettingsFragment" />
+            <meta-data android:name="com.android.settings.PRIMARY_PROFILE_CONTROLLED"
+                android:value="true" />
+        </activity>
+
+        <activity
             android:name="Settings$NightDisplaySuggestionActivity"
             android:enabled="@*android:bool/config_nightDisplayAvailable"
             android:icon="@drawable/ic_suggestion_night_display">
diff --git a/res/layout/advanced_bt_entity_sub.xml b/res/layout/advanced_bt_entity_sub.xml
index 0f30583..f36379a 100644
--- a/res/layout/advanced_bt_entity_sub.xml
+++ b/res/layout/advanced_bt_entity_sub.xml
@@ -51,8 +51,9 @@
         android:orientation="horizontal">
         <ImageView
             android:id="@+id/bt_battery_icon"
-            android:layout_width="13dp"
-            android:layout_height="20dp"/>
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_gravity="center"/>
         <TextView
             android:id="@+id/bt_battery_summary"
             style="@style/TextAppearance.EntityHeaderSummary"
diff --git a/res/layout/battery_header.xml b/res/layout/battery_header.xml
index b3b699a..dca0972 100644
--- a/res/layout/battery_header.xml
+++ b/res/layout/battery_header.xml
@@ -44,16 +44,10 @@
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
             android:layout_marginTop="8dp"
-            android:minLines="2"
+            android:minLines="3"
             android:textAppearance="@android:style/TextAppearance.DeviceDefault.Small"/>
             android:textColor="?android:attr/textColorPrimary"/>
 
-        <TextView
-            android:id="@+id/summary2"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:textAppearance="@android:style/TextAppearance.DeviceDefault.Small"/>
-            android:textColor="?android:attr/textColorPrimary"/>
     </LinearLayout>
 
     <com.android.settings.fuelgauge.BatteryMeterView
diff --git a/res/layout/dark_ui_activation_button.xml b/res/layout/dark_ui_activation_button.xml
new file mode 100644
index 0000000..5f9eefc
--- /dev/null
+++ b/res/layout/dark_ui_activation_button.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright (C) 2019 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:minHeight="?android:attr/listPreferredItemHeight">
+
+    <Button
+        android:id="@+id/dark_ui_turn_on_button"
+        style="@style/ActionPrimaryButton"
+        android:layout_marginStart="@dimen/screen_margin_sides"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center_vertical" />
+
+    <Button
+        android:id="@+id/dark_ui_turn_off_button"
+        style="@style/ActionSecondaryButton"
+        android:layout_marginStart="@dimen/screen_margin_sides"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center_vertical" />
+
+</LinearLayout>
\ No newline at end of file
diff --git a/res/layout/face_enroll_introduction.xml b/res/layout/face_enroll_introduction.xml
index f551e36..55ac6f9 100644
--- a/res/layout/face_enroll_introduction.xml
+++ b/res/layout/face_enroll_introduction.xml
@@ -124,9 +124,9 @@
                     android:layout_width="24dp"
                     android:layout_height="wrap_content"/>
                 <TextView
+                    android:id="@+id/face_enroll_introduction_footer_part_2"
                     android:layout_width="match_parent"
-                    android:layout_height="wrap_content"
-                    android:text="@string/security_settings_face_enroll_introduction_footer_part_2"/>
+                    android:layout_height="wrap_content"/>
 
             </LinearLayout>
 
diff --git a/res/values/arrays.xml b/res/values/arrays.xml
index 68ad98c..b9a1939 100644
--- a/res/values/arrays.xml
+++ b/res/values/arrays.xml
@@ -100,6 +100,14 @@
         <item>1800000</item>
     </string-array>
 
+    <!-- Dark theme scheduling preferences  [CHAR LIMIT=NONE] -->
+    <string-array name="dark_ui_scheduler_preference_titles">
+        <!-- 1: None -->
+        <item>@string/dark_ui_auto_mode_never</item>
+        <!-- 2: Auto -->
+        <item>@string/dark_ui_auto_mode_auto</item>
+    </string-array>
+
     <!-- Security settings.  The delay after screen is turned off until device locks.
          These are shown in a list dialog. -->
     <string-array name="lock_after_timeout_entries">
diff --git a/res/values/config.xml b/res/values/config.xml
index 5eb55ae..e4b4812 100755
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -417,4 +417,7 @@
 
     <!-- "Show work policy info" intent action. TODO(b/134391103): Replace with final SystemAPI intent when it's available. -->
     <string name="config_work_policy_info_intent_action" translatable="false"/>
+
+    <!-- RTT setting intent action -->
+    <string name="config_rtt_setting_intent_action" translatable="false"></string>
 </resources>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 001578a..5ee7171 100755
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -414,4 +414,11 @@
 
     <!-- System navigation settings illustration height -->
     <dimen name="system_navigation_illustration_height">320dp</dimen>
+
+    <!-- Header title size of advanced bluetooth device -->
+    <dimen name="advanced_bluetooth_header_title_text_size">16sp</dimen>
+
+    <!-- Battery meter icon size of advanced bluetooth device -->
+    <dimen name="advanced_bluetooth_battery_meter_width">7.8dp</dimen>
+    <dimen name="advanced_bluetooth_battery_meter_height">13dp</dimen>
 </resources>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index d7f7862..92db0fb 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -827,7 +827,9 @@
     <!-- Button text in face settings which lets the user enroll their face [CHAR LIMIT=40] -->
     <string name="security_settings_face_settings_enroll">Set up face unlock</string>
     <!-- Text shown in face settings explaining what your face can be used for. [CHAR LIMIT=NONE] -->
-    <string name="security_settings_face_settings_footer">Use face unlock to unlock your device, sign in to apps, and confirm payments.\n\nKeep in mind:\nLooking at the phone can unlock it when you don\u2019t intend to.\n\nYour phone can be unlocked by someone else if it\u2019s held up to your face, even if your eyes are closed.\n\nYour phone can be unlocked by someone who looks a lot like you, say, an identical sibling.</string>
+    <string name="security_settings_face_settings_footer">Use face unlock to unlock your device, sign in to apps, and confirm payments.\n\nKeep in mind:\nLooking at the phone can unlock it when you don\u2019t intend to.\n\nYour phone can be unlocked by someone else if it\u2019s held up to your face while your eyes are open.\n\nYour phone can be unlocked by someone who looks a lot like you, say, an identical sibling.</string>
+    <!-- Text shown in face settings explaining what your face can be used for. Used when attention checking is not supported. [CHAR LIMIT=NONE] -->
+    <string name="security_settings_face_settings_footer_attention_not_supported">Use face unlock to unlock your device, sign in to apps, and confirm payments.\n\nKeep in mind:\nLooking at the phone can unlock it when you don\u2019t intend to.\n\nYour phone can be unlocked by someone else if it\u2019s held up to your face, even if your eyes are closed.\n\nYour phone can be unlocked by someone who looks a lot like you, say, an identical sibling.</string>
     <!-- Dialog title shown when the user removes an enrollment [CHAR LIMIT=35] -->
     <string name="security_settings_face_settings_remove_dialog_title">Delete face data?</string>
     <!-- Dialog contents shown when the user removes an enrollment [CHAR LIMIT=NONE] -->
@@ -2757,6 +2759,40 @@
     <!-- Night display slice screen, subtitle of intensity setting when night light is off. [CHAR LIMIT=30] -->
     <string name="night_display_not_currently_on">Night Light not currently on</string>
 
+    <!--    Dark ui screen-->
+    <!-- Display settings screen, activation button action for manual mode. [CHAR LIMIT=40] -->
+    <string name="dark_ui_activation_on_manual">Turn on now</string>
+    <!-- Display settings screen, deactivation button action for manual mode. [CHAR LIMIT=40] -->
+    <string name="dark_ui_activation_off_manual">Turn off now</string>
+    <!-- Display settings screen, activation button action for sunset-to-sunrise schedule [CHAR LIMIT=40] -->
+    <string name="dark_ui_activation_on_auto">Turn on until sunrise</string>
+    <!-- Display settings screen, deactivation button action for sunset-to-sunrise schedule [CHAR LIMIT=40] -->
+    <string name="dark_ui_activation_off_auto">Turn off until sunset</string>
+    <!-- Dark UI screen, setting option name to enable Dark UI [CHAR LIMIT=30] -->
+    <string name="dark_ui_title">Dark Mode</string>
+    <!-- Dark UI screen, setting option name to configure whether Dark UI turn on/off automatically. [CHAR LIMIT=30] -->
+    <string name="dark_ui_auto_mode_title">Schedule</string>
+    <!-- Dark UI screen, setting option value for Dark UI to *never* turn on/off automatically. [CHAR LIMIT=30] -->
+    <string name="dark_ui_auto_mode_never">None</string>
+    <!-- Dark UIscreen, setting option value for Dark UI to turn on/off automatically at sunset/sunrise. [CHAR LIMIT=32] -->
+    <string name="dark_ui_auto_mode_auto">Turns on from sunset to sunrise</string>
+    <!-- Dark UIscreen, setting option name controlling the current activation status. [CHAR LIMIT=30] -->
+    <string name="dark_ui_status_title">Status</string>
+    <!-- Display settings screen, summary format of Dark UI when off. [CHAR LIMIT=NONE] -->
+    <string name="dark_ui_summary_off">Off / <xliff:g name="auto_mode_summary" example="Never turn on automatically">%1$s</xliff:g></string>
+    <!-- Display settings screen, summary of Dark UI when off and will *never* turn on automatically. [CHAR LIMIT=NONE] -->
+    <string name="dark_ui_summary_off_auto_mode_never">Will never turn on automatically</string>
+    <!-- Display settings screen, summary of Dark UI when off and will turn on automatically at sunset. [CHAR LIMIT=NONE] -->
+    <string name="dark_ui_summary_off_auto_mode_auto">Will turn on automatically at sunset</string>
+    <!-- Display settings screen, summary format of Dark UI when on. [CHAR LIMIT=NONE] -->
+    <string name="dark_ui_summary_on">On / <xliff:g name="auto_mode_summary" example="Never turn off automatically">%1$s</xliff:g></string>
+    <!-- Display settings screen, summary of Dark UI when on and will *never* turn off automatically. [CHAR LIMIT=NONE] -->
+    <string name="dark_ui_summary_on_auto_mode_never">Will never turn off automatically</string>
+    <!-- Display settings screen, summary of Dark UI when on and will turn off automatically at sunrise. [CHAR LIMIT=NONE] -->
+    <string name="dark_ui_summary_on_auto_mode_auto">Will turn off automatically at sunrise</string>
+    <!-- Dark theme screen, description of Dark theme feature. [CHAR LIMIT=NONE] -->
+    <string name="dark_ui_text">Dark theme uses a black background to help keep battery alive longer on some screens. Dark theme schedules wait to turn on until your screen is off.</string>
+
     <!-- Sound & display settings screen, setting option name to change screen timeout -->
     <string name="screen_timeout">Screen timeout</string>
     <!-- Sound & display settings screen, setting option name to change screen timeout [CHAR LIMIT=30] -->
@@ -6880,6 +6916,7 @@
     <string name="help_url_connected_devices" translatable="false"></string>
     <string name="help_url_apps_and_notifications" translatable="false"></string>
     <string name="help_url_night_display" translatable="false"></string>
+    <string name="help_url_dark_theme" translatable="false"></string>
     <string name="help_url_screen_saver" translatable="false"></string>
     <string name="help_url_pickup_gesture" translatable="false"></string>
     <string name="help_url_storage_dashboard" translatable="false"></string>
@@ -9975,6 +10012,12 @@
     <!-- [CHAR_LIMIT=40] Positive button text in dark theme notification -->
     <string name="dark_ui_settings_dialog_acknowledge">Got it</string>
 
+    <!-- [CHAR_LIMIT=50] Title string in the dark theme slice(suggestion) -->
+    <string name="dark_theme_slice_title">Try Dark theme</string>
+
+    <!-- [CHAR_LIMIT=50] Subtitle string in the dark theme slice(suggestion) -->
+    <string name="dark_theme_slice_subtitle">Helps extend battery life</string>
+
     <!-- [CHAR LIMIT=60] Name of dev option to enable extra quick settings tiles -->
     <string name="quick_settings_developer_tiles">Quick settings developer tiles</string>
 
@@ -11237,5 +11280,13 @@
     <string name="work_policy_privacy_settings">Your work policy info</string>
     <!-- Summary for Enterprise Privacy settings, explaining what the user can expect to find under it [CHAR LIMIT=NONE]-->
     <string name="work_policy_privacy_settings_summary">Settings managed by your IT admin</string>
+    <!-- Title for RTT setting. [CHAR LIMIT=NONE] -->
+    <string name="rtt_settings_title"></string>
+    <!-- Subtext for showing the option of RTT setting. [CHAR LIMIT=NONE] -->
+    <string name="rtt_settings_no_visible"></string>
+    <!-- Subtext for showing the option of RTT setting. [CHAR LIMIT=NONE] -->
+    <string name="rtt_settings_visible_during_call"></string>
+    <!-- Subtext for showing the option of RTT setting. [CHAR LIMIT=NONE] -->
+    <string name="rtt_settings_always_visible"></string>
 
 </resources>
diff --git a/res/xml/dark_mode_settings.xml b/res/xml/dark_mode_settings.xml
new file mode 100644
index 0000000..9247a0c
--- /dev/null
+++ b/res/xml/dark_mode_settings.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<PreferenceScreen
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:settings="http://schemas.android.com/apk/res-auto"
+    android:title="@string/dark_ui_mode"
+    android:key="dark_ui_mode_screen"
+    settings:keywords="@string/keywords_dark_ui_mode">
+
+    <DropDownPreference
+        android:key="dark_ui_auto_mode"
+        android:title="@string/dark_ui_auto_mode_title"
+        android:summary="%s"
+        android:entries="@array/dark_ui_scheduler_preference_titles"
+        android:entryValues="@array/dark_ui_scheduler_preference_titles"
+        settings:controller="com.android.settings.display.darkmode.DarkModeScheduleSelectorController"
+        settings:keywords="@string/keywords_dark_ui_mode"/>
+
+    <com.android.settingslib.widget.LayoutPreference
+        android:key="dark_ui_activated"
+        android:title="@string/dark_ui_title"
+        android:selectable="false"
+        android:layout="@layout/dark_ui_activation_button"
+        settings:allowDividerBelow="true"
+        settings:controller="com.android.settings.display.darkmode.DarkModeActivationPreferenceController"
+        settings:keywords="@string/keywords_dark_ui_mode"/>
+
+    <com.android.settingslib.widget.FooterPreference
+            android:key="dark_ui_footer"
+            android:title="@string/dark_ui_text"
+            android:selectable="false"
+            settings:searchable="false"
+            settings:allowDividerAbove="true"/>
+
+</PreferenceScreen>
\ No newline at end of file
diff --git a/res/xml/display_settings.xml b/res/xml/display_settings.xml
index c45e6a2..9bc6710 100644
--- a/res/xml/display_settings.xml
+++ b/res/xml/display_settings.xml
@@ -31,6 +31,15 @@
         <intent android:action="com.android.intent.action.SHOW_BRIGHTNESS_DIALOG" />
     </com.android.settingslib.RestrictedPreference>
 
+    <com.android.settings.display.darkmode.DarkModePreference
+        android:key="dark_ui_mode"
+        android:title="@string/dark_ui_mode"
+        android:fragment="com.android.settings.display.darkmode.DarkModeSettingsFragment"
+        android:widgetLayout="@null"
+        settings:widgetLayout="@null"
+        settings:controller="com.android.settings.display.DarkUIPreferenceController"
+        settings:searchable="false"/>
+
     <com.android.settings.display.NightDisplayPreference
         android:key="night_display"
         android:title="@string/night_display_title"
@@ -54,13 +63,6 @@
         settings:controller="com.android.settings.display.WallpaperPreferenceController">
     </com.android.settingslib.RestrictedPreference>
 
-
-    <SwitchPreference
-        android:key="dark_ui_mode"
-        android:title="@string/dark_ui_mode"
-        settings:keywords="@string/keywords_dark_ui_mode"
-        settings:controller="com.android.settings.display.DarkUIPreferenceController"/>
-
     <!-- Cross-listed item, if you change this, also change it in power_usage_summary.xml -->
     <com.android.settings.display.TimeoutListPreference
         android:key="screen_timeout"
diff --git a/res/xml/privacy_dashboard_settings.xml b/res/xml/privacy_dashboard_settings.xml
index 3ac6f42..1dd609e 100644
--- a/res/xml/privacy_dashboard_settings.xml
+++ b/res/xml/privacy_dashboard_settings.xml
@@ -22,13 +22,6 @@
     android:title="@string/privacy_dashboard_title"
     settings:initialExpandedChildrenCount="4">
 
-    <!-- This preference isn't searchable, and user won't see title in this preference.
-         So, we just set empty text for title. -->
-    <com.android.settingslib.widget.BarChartPreference
-        android:key="permission_bar_chart"
-        android:title="@string/summary_placeholder"
-        settings:controller="com.android.settings.privacy.PermissionBarChartPreferenceController"/>
-
     <!-- Work Policy info -->
     <Preference
         android:key="work_policy_info"
diff --git a/res/xml/security_settings_face.xml b/res/xml/security_settings_face.xml
index 1561e8c..e613470 100644
--- a/res/xml/security_settings_face.xml
+++ b/res/xml/security_settings_face.xml
@@ -52,12 +52,23 @@
         android:key="security_settings_face_manage_category"
         android:title="@string/security_settings_face_settings_require_category">
         <SwitchPreference
+            android:key="security_settings_face_require_attention"
+            android:title="@string/security_settings_face_settings_require_attention"
+            android:summary="@string/security_settings_face_settings_require_attention_details"
+            app:keywords="@string/keywords_face_unlock"
+            app:controller="com.android.settings.biometrics.face.FaceSettingsAttentionPreferenceController"/>
+
+        <SwitchPreference
             android:key="security_settings_face_require_confirmation"
             android:title="@string/security_settings_face_settings_require_confirmation"
             android:summary="@string/security_settings_face_settings_require_confirmation_details"
             app:keywords="@string/keywords_face_unlock"
             app:controller="com.android.settings.biometrics.face.FaceSettingsConfirmPreferenceController"/>
+    </PreferenceCategory>
 
+    <PreferenceCategory
+        android:key="security_settings_face_button_category"
+        android:title="@string/security_settings_face_preference_title">
         <com.android.settingslib.widget.LayoutPreference
             android:key="security_settings_face_delete_faces_container"
             android:selectable="false"
@@ -66,7 +77,7 @@
         <com.android.settingslib.widget.LayoutPreference
             android:key="security_settings_face_enroll_faces_container"
             android:selectable="false"
-            android:layout="@layout/face_enroll_button " />
+            android:layout="@layout/face_enroll_button" />
     </PreferenceCategory>
 
     <PreferenceCategory
diff --git a/src/com/android/settings/DisplaySettings.java b/src/com/android/settings/DisplaySettings.java
index eb77d4a..06e4694 100644
--- a/src/com/android/settings/DisplaySettings.java
+++ b/src/com/android/settings/DisplaySettings.java
@@ -24,7 +24,6 @@
 import com.android.settings.dashboard.DashboardFragment;
 import com.android.settings.display.BrightnessLevelPreferenceController;
 import com.android.settings.display.CameraGesturePreferenceController;
-import com.android.settings.display.DarkUIPreferenceController;
 import com.android.settings.display.LiftToWakePreferenceController;
 import com.android.settings.display.NightDisplayPreferenceController;
 import com.android.settings.display.NightModePreferenceController;
@@ -67,7 +66,6 @@
     @Override
     public void onCreate(Bundle icicle) {
         super.onCreate(icicle);
-        use(DarkUIPreferenceController.class).setParentFragment(this);
     }
 
     @Override
diff --git a/src/com/android/settings/Settings.java b/src/com/android/settings/Settings.java
index ab59da4..e63edd7 100644
--- a/src/com/android/settings/Settings.java
+++ b/src/com/android/settings/Settings.java
@@ -52,6 +52,7 @@
     public static class LocalePickerActivity extends SettingsActivity { /* empty */ }
     public static class LanguageAndInputSettingsActivity extends SettingsActivity { /* empty */ }
     public static class UserDictionarySettingsActivity extends SettingsActivity { /* empty */ }
+    public static class DarkThemeSettingsActivity extends SettingsActivity { /* empty */ }
     public static class DisplaySettingsActivity extends SettingsActivity { /* empty */ }
     public static class NightDisplaySettingsActivity extends SettingsActivity { /* empty */ }
     public static class NightDisplaySuggestionActivity extends NightDisplaySettingsActivity { /* empty */ }
diff --git a/src/com/android/settings/biometrics/face/FaceEnrollIntroduction.java b/src/com/android/settings/biometrics/face/FaceEnrollIntroduction.java
index 5f164d6..073c7e6 100644
--- a/src/com/android/settings/biometrics/face/FaceEnrollIntroduction.java
+++ b/src/com/android/settings/biometrics/face/FaceEnrollIntroduction.java
@@ -26,6 +26,7 @@
 import com.android.settings.R;
 import com.android.settings.Utils;
 import com.android.settings.biometrics.BiometricEnrollIntroduction;
+import com.android.settings.overlay.FeatureFactory;
 import com.android.settings.password.ChooseLockSettingsHelper;
 import com.android.settingslib.RestrictedLockUtilsInternal;
 
@@ -40,12 +41,15 @@
     private static final String TAG = "FaceIntro";
 
     private FaceManager mFaceManager;
+    private FaceFeatureProvider mFaceFeatureProvider;
 
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
 
         mFaceManager = Utils.getFaceManagerOrNull(this);
+        mFaceFeatureProvider = FeatureFactory.getFactory(getApplicationContext())
+                .getFaceFeatureProvider();
 
         mFooterBarMixin = getLayout().getMixin(FooterBarMixin.class);
         if (WizardManagerHelper.isAnySetupWizard(getIntent())) {
@@ -87,6 +91,12 @@
                     });
         }
 
+        final TextView footer2 = findViewById(R.id.face_enroll_introduction_footer_part_2);
+        final int footer2TextResource =
+                mFaceFeatureProvider.isAttentionSupported(getApplicationContext())
+                        ? R.string.security_settings_face_enroll_introduction_footer_part_2
+                        : R.string.security_settings_face_settings_footer_attention_not_supported;
+        footer2.setText(footer2TextResource);
     }
 
     @Override
diff --git a/src/com/android/settings/biometrics/face/FaceFeatureProvider.java b/src/com/android/settings/biometrics/face/FaceFeatureProvider.java
new file mode 100644
index 0000000..26ea261
--- /dev/null
+++ b/src/com/android/settings/biometrics/face/FaceFeatureProvider.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.settings.biometrics.face;
+
+import android.content.Context;
+
+/** Feature provider for face unlock */
+public interface FaceFeatureProvider {
+    /** Returns true if attention checking is supported. */
+    boolean isAttentionSupported(Context context);
+}
diff --git a/src/com/android/settings/biometrics/face/FaceFeatureProviderImpl.java b/src/com/android/settings/biometrics/face/FaceFeatureProviderImpl.java
new file mode 100644
index 0000000..e508600
--- /dev/null
+++ b/src/com/android/settings/biometrics/face/FaceFeatureProviderImpl.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.settings.biometrics.face;
+
+import android.content.Context;
+import android.provider.Settings;
+
+public class FaceFeatureProviderImpl implements FaceFeatureProvider {
+
+    @Override
+    public boolean isAttentionSupported(Context context) {
+        return true;
+    }
+}
diff --git a/src/com/android/settings/biometrics/face/FaceSettings.java b/src/com/android/settings/biometrics/face/FaceSettings.java
index b8bb030..eeaa040 100644
--- a/src/com/android/settings/biometrics/face/FaceSettings.java
+++ b/src/com/android/settings/biometrics/face/FaceSettings.java
@@ -37,6 +37,7 @@
 import com.android.settings.SettingsActivity;
 import com.android.settings.Utils;
 import com.android.settings.dashboard.DashboardFragment;
+import com.android.settings.overlay.FeatureFactory;
 import com.android.settings.password.ChooseLockSettingsHelper;
 import com.android.settings.search.BaseSearchIndexProvider;
 import com.android.settingslib.core.AbstractPreferenceController;
@@ -60,13 +61,16 @@
     private FaceManager mFaceManager;
     private int mUserId;
     private byte[] mToken;
+    private FaceSettingsAttentionPreferenceController mAttentionController;
     private FaceSettingsRemoveButtonPreferenceController mRemoveController;
     private FaceSettingsEnrollButtonPreferenceController mEnrollController;
+    private FaceSettingsLockscreenBypassPreferenceController mLockscreenController;
     private List<AbstractPreferenceController> mControllers;
 
     private List<Preference> mTogglePreferences;
     private Preference mRemoveButton;
     private Preference mEnrollButton;
+    private FaceFeatureProvider mFaceFeatureProvider;
 
     private boolean mConfirmingPassword;
 
@@ -117,6 +121,7 @@
         mFaceManager = getPrefContext().getSystemService(FaceManager.class);
         mUserId = getActivity().getIntent().getIntExtra(
                 Intent.EXTRA_USER_ID, UserHandle.myUserId());
+        mFaceFeatureProvider = FeatureFactory.getFactory(getContext()).getFaceFeatureProvider();
 
         if (mUserManager.getUserInfo(mUserId).isManagedProfile()) {
             getActivity().setTitle(getActivity().getResources().getString(
@@ -125,18 +130,19 @@
 
         Preference keyguardPref = findPreference(FaceSettingsKeyguardPreferenceController.KEY);
         Preference appPref = findPreference(FaceSettingsAppPreferenceController.KEY);
+        Preference attentionPref = findPreference(FaceSettingsAttentionPreferenceController.KEY);
         Preference confirmPref = findPreference(FaceSettingsConfirmPreferenceController.KEY);
         Preference bypassPref =
-                findPreference(FaceSettingsLockscreenBypassPreferenceController.KEY);
+                findPreference(mLockscreenController.getPreferenceKey());
         mTogglePreferences = new ArrayList<>(
-                Arrays.asList(keyguardPref, appPref, confirmPref, bypassPref));
+                Arrays.asList(keyguardPref, appPref, attentionPref, confirmPref, bypassPref));
 
         mRemoveButton = findPreference(FaceSettingsRemoveButtonPreferenceController.KEY);
         mEnrollButton = findPreference(FaceSettingsEnrollButtonPreferenceController.KEY);
 
         // There is no better way to do this :/
         for (AbstractPreferenceController controller : mControllers) {
-            if (controller instanceof  FaceSettingsPreferenceController) {
+            if (controller instanceof FaceSettingsPreferenceController) {
                 ((FaceSettingsPreferenceController) controller).setUserId(mUserId);
             } else if (controller instanceof FaceSettingsEnrollButtonPreferenceController) {
                 ((FaceSettingsEnrollButtonPreferenceController) controller).setUserId(mUserId);
@@ -147,6 +153,7 @@
         // Don't show keyguard controller for work profile settings.
         if (mUserManager.isManagedProfile(mUserId)) {
             removePreference(FaceSettingsKeyguardPreferenceController.KEY);
+            removePreference(mLockscreenController.getPreferenceKey());
         }
 
         if (savedInstanceState != null) {
@@ -155,6 +162,14 @@
     }
 
     @Override
+    public void onAttach(Context context) {
+        super.onAttach(context);
+
+        mLockscreenController = use(FaceSettingsLockscreenBypassPreferenceController.class);
+        mLockscreenController.setUserId(mUserId);
+    }
+
+    @Override
     public void onResume() {
         super.onResume();
 
@@ -173,12 +188,17 @@
                 finish();
             }
         } else {
+            mAttentionController.setToken(mToken);
             mEnrollController.setToken(mToken);
         }
 
         final boolean hasEnrolled = mFaceManager.hasEnrolledTemplates(mUserId);
         mEnrollButton.setVisible(!hasEnrolled);
         mRemoveButton.setVisible(hasEnrolled);
+
+        if (!mFaceFeatureProvider.isAttentionSupported(getContext())) {
+            removePreference(FaceSettingsAttentionPreferenceController.KEY);
+        }
     }
 
     @Override
@@ -193,6 +213,7 @@
                     mToken = data.getByteArrayExtra(
                             ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN);
                     if (mToken != null) {
+                        mAttentionController.setToken(mToken);
                         mEnrollController.setToken(mToken);
                     }
                 }
@@ -236,7 +257,9 @@
         mControllers = buildPreferenceControllers(context, getSettingsLifecycle());
         // There's no great way of doing this right now :/
         for (AbstractPreferenceController controller : mControllers) {
-            if (controller instanceof FaceSettingsRemoveButtonPreferenceController) {
+            if (controller instanceof FaceSettingsAttentionPreferenceController) {
+                mAttentionController = (FaceSettingsAttentionPreferenceController) controller;
+            } else if (controller instanceof FaceSettingsRemoveButtonPreferenceController) {
                 mRemoveController = (FaceSettingsRemoveButtonPreferenceController) controller;
                 mRemoveController.setListener(mRemovalListener);
                 mRemoveController.setActivity((SettingsActivity) getActivity());
@@ -255,6 +278,7 @@
         controllers.add(new FaceSettingsVideoPreferenceController(context));
         controllers.add(new FaceSettingsKeyguardPreferenceController(context));
         controllers.add(new FaceSettingsAppPreferenceController(context));
+        controllers.add(new FaceSettingsAttentionPreferenceController(context));
         controllers.add(new FaceSettingsRemoveButtonPreferenceController(context));
         controllers.add(new FaceSettingsFooterPreferenceController(context));
         controllers.add(new FaceSettingsConfirmPreferenceController(context));
diff --git a/src/com/android/settings/biometrics/face/FaceSettingsFooterPreferenceController.java b/src/com/android/settings/biometrics/face/FaceSettingsFooterPreferenceController.java
index 838dc0d..c665467 100644
--- a/src/com/android/settings/biometrics/face/FaceSettingsFooterPreferenceController.java
+++ b/src/com/android/settings/biometrics/face/FaceSettingsFooterPreferenceController.java
@@ -23,6 +23,7 @@
 
 import com.android.settings.R;
 import com.android.settings.core.BasePreferenceController;
+import com.android.settings.overlay.FeatureFactory;
 import com.android.settings.utils.AnnotationSpan;
 import com.android.settingslib.HelpUtils;
 import com.android.settingslib.widget.FooterPreference;
@@ -34,8 +35,11 @@
 
     private static final String ANNOTATION_URL = "url";
 
+    private FaceFeatureProvider mProvider;
+
     public FaceSettingsFooterPreferenceController(Context context, String preferenceKey) {
         super(context, preferenceKey);
+        mProvider = FeatureFactory.getFactory(context).getFaceFeatureProvider();
     }
 
     public FaceSettingsFooterPreferenceController(Context context) {
@@ -55,7 +59,12 @@
                 mContext, mContext.getString(R.string.help_url_face), getClass().getName());
         final AnnotationSpan.LinkInfo linkInfo =
                 new AnnotationSpan.LinkInfo(mContext, ANNOTATION_URL, helpIntent);
+
+        final int footerRes = mProvider.isAttentionSupported(mContext)
+                ? R.string.security_settings_face_settings_footer
+                : R.string.security_settings_face_settings_footer_attention_not_supported;
+
         preference.setTitle(AnnotationSpan.linkify(
-                mContext.getText(R.string.security_settings_face_settings_footer), linkInfo));
+                mContext.getText(footerRes), linkInfo));
     }
 }
diff --git a/src/com/android/settings/biometrics/face/FaceSettingsLockscreenBypassPreferenceController.java b/src/com/android/settings/biometrics/face/FaceSettingsLockscreenBypassPreferenceController.java
index e717cb2..cef174d 100644
--- a/src/com/android/settings/biometrics/face/FaceSettingsLockscreenBypassPreferenceController.java
+++ b/src/com/android/settings/biometrics/face/FaceSettingsLockscreenBypassPreferenceController.java
@@ -30,8 +30,6 @@
 public class FaceSettingsLockscreenBypassPreferenceController
         extends FaceSettingsPreferenceController {
 
-    static final String KEY = "security_lockscreen_bypass";
-
     @VisibleForTesting
     protected FaceManager mFaceManager;
     private UserManager mUserManager;
diff --git a/src/com/android/settings/bluetooth/AdvancedBluetoothDetailsHeaderController.java b/src/com/android/settings/bluetooth/AdvancedBluetoothDetailsHeaderController.java
index 6817d0d..86196fd 100644
--- a/src/com/android/settings/bluetooth/AdvancedBluetoothDetailsHeaderController.java
+++ b/src/com/android/settings/bluetooth/AdvancedBluetoothDetailsHeaderController.java
@@ -60,6 +60,7 @@
 public class AdvancedBluetoothDetailsHeaderController extends BasePreferenceController implements
         LifecycleObserver, OnStart, OnStop, OnDestroy, CachedBluetoothDevice.Callback {
     private static final String TAG = "AdvancedBtHeaderCtrl";
+    private static final int LOW_BATTERY_LEVEL = 20;
 
     @VisibleForTesting
     LayoutPreference mLayoutPreference;
@@ -180,12 +181,18 @@
     Drawable createBtBatteryIcon(Context context, int level, boolean charging) {
         final BatteryMeterView.BatteryMeterDrawable drawable =
                 new BatteryMeterView.BatteryMeterDrawable(context,
-                        context.getColor(R.color.meter_background_color));
+                        context.getColor(R.color.meter_background_color),
+                        context.getResources().getDimensionPixelSize(
+                                R.dimen.advanced_bluetooth_battery_meter_width),
+                        context.getResources().getDimensionPixelSize(
+                                R.dimen.advanced_bluetooth_battery_meter_height));
         drawable.setBatteryLevel(level);
+        final int attr = level > LOW_BATTERY_LEVEL || charging
+                ? android.R.attr.colorControlNormal
+                : android.R.attr.colorError;
         drawable.setColorFilter(new PorterDuffColorFilter(
-                com.android.settings.Utils.getColorAttrDefaultColor(context,
-                        android.R.attr.colorControlNormal),
-                PorterDuff.Mode.SRC_IN));
+                com.android.settings.Utils.getColorAttrDefaultColor(context, attr),
+                PorterDuff.Mode.SRC));
         drawable.setCharging(charging);
 
         return drawable;
diff --git a/src/com/android/settings/bluetooth/BluetoothSliceBuilder.java b/src/com/android/settings/bluetooth/BluetoothSliceBuilder.java
index 18df872..5a4ee1f 100644
--- a/src/com/android/settings/bluetooth/BluetoothSliceBuilder.java
+++ b/src/com/android/settings/bluetooth/BluetoothSliceBuilder.java
@@ -136,6 +136,6 @@
         final Intent intent = new Intent(ACTION_BLUETOOTH_SLICE_CHANGED)
                 .setClass(context, SliceBroadcastReceiver.class);
         return PendingIntent.getBroadcast(context, 0 /* requestCode */, intent,
-                PendingIntent.FLAG_CANCEL_CURRENT);
+                PendingIntent.FLAG_UPDATE_CURRENT);
     }
 }
diff --git a/src/com/android/settings/core/SettingsBaseActivity.java b/src/com/android/settings/core/SettingsBaseActivity.java
index 5ff81d5..6e37b16 100644
--- a/src/com/android/settings/core/SettingsBaseActivity.java
+++ b/src/com/android/settings/core/SettingsBaseActivity.java
@@ -17,6 +17,7 @@
 
 import android.annotation.LayoutRes;
 import android.annotation.Nullable;
+import android.app.ActivityManager;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.Context;
@@ -26,6 +27,7 @@
 import android.content.res.TypedArray;
 import android.os.AsyncTask;
 import android.os.Bundle;
+import android.text.TextUtils;
 import android.util.ArraySet;
 import android.util.Log;
 import android.view.LayoutInflater;
@@ -61,6 +63,10 @@
     @Override
     protected void onCreate(@Nullable Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
+        if (isLockTaskModePinned() && !isSettingsRunOnTop()) {
+            Log.w(TAG, "Devices lock task mode pinned.");
+            finish();
+        }
         final long startTime = System.currentTimeMillis();
         getLifecycle().addObserver(new HideNonSystemOverlayMixin(this));
 
@@ -148,6 +154,20 @@
         }
     }
 
+    private boolean isLockTaskModePinned() {
+        final ActivityManager activityManager =
+            getApplicationContext().getSystemService(ActivityManager.class);
+        return activityManager.getLockTaskModeState() == ActivityManager.LOCK_TASK_MODE_PINNED;
+    }
+
+    private boolean isSettingsRunOnTop() {
+        final ActivityManager activityManager =
+            getApplicationContext().getSystemService(ActivityManager.class);
+        final String taskPkgName = activityManager.getRunningTasks(1 /* maxNum */)
+            .get(0 /* index */).baseActivity.getPackageName();
+        return TextUtils.equals(getPackageName(), taskPkgName);
+    }
+
     /**
      * @return whether or not the enabled state actually changed.
      */
diff --git a/src/com/android/settings/core/gateway/SettingsGateway.java b/src/com/android/settings/core/gateway/SettingsGateway.java
index 384f262..fd03697 100644
--- a/src/com/android/settings/core/gateway/SettingsGateway.java
+++ b/src/com/android/settings/core/gateway/SettingsGateway.java
@@ -74,6 +74,7 @@
 import com.android.settings.deviceinfo.firmwareversion.FirmwareVersionSettings;
 import com.android.settings.deviceinfo.legal.ModuleLicensesDashboard;
 import com.android.settings.display.NightDisplaySettings;
+import com.android.settings.display.darkmode.DarkModeSettingsFragment;
 import com.android.settings.dream.DreamSettings;
 import com.android.settings.enterprise.EnterprisePrivacySettings;
 import com.android.settings.fuelgauge.AdvancedPowerUsageDetail;
@@ -281,7 +282,8 @@
             PreviouslyConnectedDeviceDashboardFragment.class.getName(),
             BatterySaverScheduleSettings.class.getName(),
             MobileNetworkListFragment.class.getName(),
-            GlobalActionsPanelSettings.class.getName()
+            GlobalActionsPanelSettings.class.getName(),
+            DarkModeSettingsFragment.class.getName()
     };
 
     public static final String[] SETTINGS_FOR_RESTRICTED = {
diff --git a/src/com/android/settings/deviceinfo/firmwareversion/MainlineModuleVersionPreferenceController.java b/src/com/android/settings/deviceinfo/firmwareversion/MainlineModuleVersionPreferenceController.java
index fd54f19..95f3ae3 100644
--- a/src/com/android/settings/deviceinfo/firmwareversion/MainlineModuleVersionPreferenceController.java
+++ b/src/com/android/settings/deviceinfo/firmwareversion/MainlineModuleVersionPreferenceController.java
@@ -111,7 +111,7 @@
             try {
                 final SimpleDateFormat simpleDateFormat = new SimpleDateFormat(pattern,
                         Locale.getDefault());
-                simpleDateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
+                simpleDateFormat.setTimeZone(TimeZone.getDefault());
                 return Optional.of(simpleDateFormat.parse(text));
             } catch (ParseException e) {
                 // ignore and try next pattern
diff --git a/src/com/android/settings/display/DarkUIPreferenceController.java b/src/com/android/settings/display/DarkUIPreferenceController.java
index d3d30b5..98d9a69 100644
--- a/src/com/android/settings/display/DarkUIPreferenceController.java
+++ b/src/com/android/settings/display/DarkUIPreferenceController.java
@@ -21,6 +21,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.content.res.Configuration;
 import android.os.PowerManager;
 import android.provider.Settings;
 
@@ -28,7 +29,6 @@
 import androidx.fragment.app.Fragment;
 import androidx.preference.Preference;
 import androidx.preference.PreferenceScreen;
-import androidx.preference.SwitchPreference;
 
 import com.android.settings.R;
 import com.android.settings.core.TogglePreferenceController;
@@ -44,7 +44,7 @@
     public static final int DIALOG_SEEN = 1;
 
     @VisibleForTesting
-    SwitchPreference mPreference;
+    Preference mPreference;
 
     private UiModeManager mUiModeManager;
     private PowerManager mPowerManager;
@@ -68,7 +68,8 @@
 
     @Override
     public boolean isChecked() {
-        return mUiModeManager.getNightMode() == UiModeManager.MODE_NIGHT_YES;
+         return (mContext.getResources().getConfiguration().uiMode
+                 & Configuration.UI_MODE_NIGHT_YES) != 0;
     }
 
     @Override
@@ -90,17 +91,13 @@
                         Settings.Secure.DARK_MODE_DIALOG_SEEN, 0) == DIALOG_SEEN;
         if (!dialogSeen && isChecked) {
             showDarkModeDialog();
-            return false;
         }
-        mUiModeManager.setNightMode(isChecked
-                ? UiModeManager.MODE_NIGHT_YES
-                : UiModeManager.MODE_NIGHT_NO);
-        return true;
+        return mUiModeManager.setNightModeActivated(isChecked);
     }
 
     private void showDarkModeDialog() {
         final DarkUIInfoDialogFragment frag = new DarkUIInfoDialogFragment();
-        if (mFragment.getFragmentManager() != null) {
+        if (mFragment != null && mFragment.getFragmentManager() != null) {
             frag.show(mFragment.getFragmentManager(), getClass().getName());
         }
     }
@@ -113,12 +110,10 @@
         boolean isBatterySaver = isPowerSaveMode();
         mPreference.setEnabled(!isBatterySaver);
         if (isBatterySaver) {
-            int stringId = mUiModeManager.getNightMode() == UiModeManager.MODE_NIGHT_YES
+            int stringId = isChecked()
                     ? R.string.dark_ui_mode_disabled_summary_dark_theme_on
                     : R.string.dark_ui_mode_disabled_summary_dark_theme_off;
             mPreference.setSummary(mContext.getString(stringId));
-        } else {
-            mPreference.setSummary(null);
         }
     }
 
@@ -127,22 +122,17 @@
         return mPowerManager.isPowerSaveMode();
     }
 
-
-    @VisibleForTesting
-    void setUiModeManager(UiModeManager uiModeManager) {
-        mUiModeManager = uiModeManager;
-    }
-
-    public void setParentFragment(Fragment fragment) {
-        mFragment = fragment;
-    }
-
     @Override
     public void onStart() {
         mContext.registerReceiver(mReceiver,
                 new IntentFilter(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED));
     }
 
+    // used by AccessibilitySettings
+    public void setParentFragment(Fragment fragment) {
+        mFragment = fragment;
+    }
+
     @Override
     public void onStop() {
         mContext.unregisterReceiver(mReceiver);
diff --git a/src/com/android/settings/display/darkmode/DarkModeActivationPreferenceController.java b/src/com/android/settings/display/darkmode/DarkModeActivationPreferenceController.java
new file mode 100644
index 0000000..23f625f
--- /dev/null
+++ b/src/com/android/settings/display/darkmode/DarkModeActivationPreferenceController.java
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+package com.android.settings.display.darkmode;
+
+import android.app.UiModeManager;
+import android.content.Context;
+import android.content.res.Configuration;
+import android.os.PowerManager;
+import android.view.View;
+import android.widget.Button;
+import androidx.preference.Preference;
+import androidx.preference.PreferenceScreen;
+import com.android.settings.R;
+import com.android.settings.core.BasePreferenceController;
+import com.android.settingslib.widget.LayoutPreference;
+
+/**
+ * Controller for activate/deactivate night mode button
+ */
+public class DarkModeActivationPreferenceController extends BasePreferenceController {
+    private final UiModeManager mUiModeManager;
+    private PowerManager mPowerManager;
+    private Button mTurnOffButton;
+    private Button mTurnOnButton;
+
+    public DarkModeActivationPreferenceController(Context context,
+            String preferenceKey) {
+        super(context, preferenceKey);
+        mPowerManager = context.getSystemService(PowerManager.class);
+        mUiModeManager = context.getSystemService(UiModeManager.class);
+    }
+
+    @Override
+    public final void updateState(Preference preference) {
+
+        final boolean batterySaver = mPowerManager.isPowerSaveMode();
+        if (batterySaver) {
+            mTurnOnButton.setVisibility(View.GONE);
+            mTurnOffButton.setVisibility(View.GONE);
+            return;
+        }
+
+        final boolean active = (mContext.getResources().getConfiguration().uiMode
+                & Configuration.UI_MODE_NIGHT_YES) != 0;
+        updateNightMode(active);
+    }
+
+    private void updateNightMode(boolean active) {
+        final int autoMode = mUiModeManager.getNightMode();
+        String buttonText;
+
+        if (autoMode == UiModeManager.MODE_NIGHT_AUTO) {
+            buttonText = mContext.getString(active
+                    ? R.string.dark_ui_activation_off_auto
+                    : R.string.dark_ui_activation_on_auto);
+        } else {
+            buttonText = mContext.getString(active
+                    ? R.string.dark_ui_activation_off_manual
+                    : R.string.dark_ui_activation_on_manual);
+        }
+        if (active) {
+            mTurnOnButton.setVisibility(View.GONE);
+            mTurnOffButton.setVisibility(View.VISIBLE);
+            mTurnOffButton.setText(buttonText);
+        } else {
+            mTurnOnButton.setVisibility(View.VISIBLE);
+            mTurnOffButton.setVisibility(View.GONE);
+            mTurnOnButton.setText(buttonText);
+        }
+    }
+
+    @Override
+    public CharSequence getSummary() {
+        final boolean isActivated = (mContext.getResources().getConfiguration().uiMode
+                & Configuration.UI_MODE_NIGHT_YES) != 0;
+        final int autoMode = mUiModeManager.getNightMode();
+        if (autoMode == UiModeManager.MODE_NIGHT_AUTO) {
+            return mContext.getString(isActivated
+                    ? R.string.dark_ui_summary_on_auto_mode_auto
+                    : R.string.dark_ui_summary_off_auto_mode_auto);
+        } else {
+            return mContext.getString(isActivated
+                    ? R.string.dark_ui_summary_on_auto_mode_never
+                    : R.string.dark_ui_summary_off_auto_mode_never);
+        }
+    }
+
+    private final View.OnClickListener mListener = new View.OnClickListener() {
+        @Override
+        public void onClick(View v) {
+            final boolean active = (mContext.getResources().getConfiguration().uiMode
+                    & Configuration.UI_MODE_NIGHT_YES) != 0;
+            mUiModeManager.setNightModeActivated(!active);
+            updateNightMode(!active);
+        }
+    };
+
+    @Override
+    public void displayPreference(PreferenceScreen screen) {
+        super.displayPreference(screen);
+
+        final LayoutPreference preference = screen.findPreference(getPreferenceKey());
+        mTurnOnButton = preference.findViewById(R.id.dark_ui_turn_on_button);
+        mTurnOnButton.setOnClickListener(mListener);
+        mTurnOffButton = preference.findViewById(R.id.dark_ui_turn_off_button);
+        mTurnOffButton.setOnClickListener(mListener);
+    }
+
+    @Override
+    public int getAvailabilityStatus() {
+        return AVAILABLE;
+    }
+}
diff --git a/src/com/android/settings/display/darkmode/DarkModeObserver.java b/src/com/android/settings/display/darkmode/DarkModeObserver.java
new file mode 100644
index 0000000..4d0d7c5
--- /dev/null
+++ b/src/com/android/settings/display/darkmode/DarkModeObserver.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+package com.android.settings.display.darkmode;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.database.ContentObserver;
+import android.net.Uri;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.PowerManager;
+import android.provider.Settings;
+import android.util.Log;
+import com.android.internal.annotations.VisibleForTesting;
+
+/**
+ * Observes changes for dark night settings*/
+public class DarkModeObserver {
+    private static final String TAG = "DarkModeObserver";
+    private ContentObserver mContentObserver;
+    private final BroadcastReceiver mBatterySaverReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            mCallback.run();
+        }
+    };
+    private Runnable mCallback;
+    private Context mContext;
+
+    public DarkModeObserver(Context context) {
+        mContext = context;
+        mContentObserver = new ContentObserver(new Handler(Looper.getMainLooper())) {
+            @Override
+            public void onChange(boolean selfChange, Uri uri) {
+                super.onChange(selfChange, uri);
+                final String setting = uri == null ? null : uri.getLastPathSegment();
+                if (setting != null && mCallback != null) {
+                    switch (setting) {
+                        case Settings.Secure.UI_NIGHT_MODE:
+                            mCallback.run();
+                            break;
+                        default:
+                    }
+                }
+            }
+        };
+    }
+
+    /**
+     * subscribe callback when night mode changed in the database
+     *
+     * @param callback the callback that gets triggered when subscribed
+     */
+    public void subscribe(Runnable callback) {
+        callback.run();
+        mCallback = callback;
+        final Uri uri = Settings.Secure.getUriFor(Settings.Secure.UI_NIGHT_MODE);
+        mContext.getContentResolver().registerContentObserver(uri, false, mContentObserver);
+        final IntentFilter batteryFilter = new IntentFilter();
+        batteryFilter.addAction(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED);
+        mContext.registerReceiver(
+                mBatterySaverReceiver, batteryFilter);
+    }
+
+    /**
+     * unsubscribe from dark ui database changes
+     */
+    public void unsubscribe() {
+        mContext.getContentResolver().unregisterContentObserver(mContentObserver);
+        try {
+            mContext.unregisterReceiver(mBatterySaverReceiver);
+        } catch (IllegalArgumentException e) {
+            /* Ignore: unregistering an unregistered receiver */
+            Log.w(TAG, e.getMessage());
+        }
+        // NO-OP
+        mCallback = null;
+    }
+
+    @VisibleForTesting
+    protected void setContentObserver(ContentObserver co) {
+        mContentObserver = co;
+    }
+
+    @VisibleForTesting
+    protected ContentObserver getContentObserver() {
+        return mContentObserver;
+    }
+}
diff --git a/src/com/android/settings/display/darkmode/DarkModePreference.java b/src/com/android/settings/display/darkmode/DarkModePreference.java
new file mode 100644
index 0000000..c5fbded
--- /dev/null
+++ b/src/com/android/settings/display/darkmode/DarkModePreference.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+package com.android.settings.display.darkmode;
+
+import android.app.UiModeManager;
+import android.content.Context;
+import android.content.res.Configuration;
+import android.os.PowerManager;
+import android.util.AttributeSet;
+import com.android.settings.R;
+import com.android.settings.widget.MasterSwitchPreference;
+
+/**
+ * component for the display settings dark ui summary*/
+public class DarkModePreference extends MasterSwitchPreference {
+
+    private UiModeManager mUiModeManager;
+    private DarkModeObserver mDarkModeObserver;
+    private PowerManager mPowerManager;
+    private Runnable mCallback;
+
+    public DarkModePreference(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        mDarkModeObserver = new DarkModeObserver(context);
+        mUiModeManager = context.getSystemService(UiModeManager.class);
+        mPowerManager = context.getSystemService(PowerManager.class);
+        mCallback = () -> {
+            final boolean batterySaver = mPowerManager.isPowerSaveMode();
+            final boolean active = (getContext().getResources().getConfiguration().uiMode
+                    & Configuration.UI_MODE_NIGHT_YES) != 0;
+            setSwitchEnabled(!batterySaver);
+            updateSummary(batterySaver, active);
+        };
+        mDarkModeObserver.subscribe(mCallback);
+    }
+
+    @Override
+    public void onAttached() {
+        super.onAttached();
+        mDarkModeObserver.subscribe(mCallback);
+    }
+
+    @Override
+    public void onDetached() {
+        super.onDetached();
+        mDarkModeObserver.unsubscribe();
+    }
+
+    private void updateSummary(boolean batterySaver, boolean active) {
+        if (batterySaver) {
+            final int stringId = active ? R.string.dark_ui_mode_disabled_summary_dark_theme_on
+                    : R.string.dark_ui_mode_disabled_summary_dark_theme_off;
+            setSummary(getContext().getString(stringId));
+            return;
+        }
+        final boolean auto = mUiModeManager.getNightMode() == UiModeManager.MODE_NIGHT_AUTO;
+
+        String detail;
+        if (active) {
+            detail = getContext().getString(auto
+                    ? R.string.dark_ui_summary_on_auto_mode_auto
+                    : R.string.dark_ui_summary_on_auto_mode_never);
+        } else {
+            detail = getContext().getString(auto
+                    ? R.string.dark_ui_summary_off_auto_mode_auto
+                    : R.string.dark_ui_summary_off_auto_mode_never);
+        }
+        String summary = getContext().getString(active
+                ? R.string.dark_ui_summary_on
+                : R.string.dark_ui_summary_off, detail);
+
+        setSummary(summary);
+    }
+}
diff --git a/src/com/android/settings/display/darkmode/DarkModeScheduleSelectorController.java b/src/com/android/settings/display/darkmode/DarkModeScheduleSelectorController.java
new file mode 100644
index 0000000..d99c7bf
--- /dev/null
+++ b/src/com/android/settings/display/darkmode/DarkModeScheduleSelectorController.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+package com.android.settings.display.darkmode;
+
+import android.app.UiModeManager;
+import android.content.Context;
+import android.content.res.Configuration;
+import android.os.PowerManager;
+import androidx.preference.DropDownPreference;
+import androidx.preference.Preference;
+import androidx.preference.PreferenceScreen;
+import com.android.settings.R;
+import com.android.settings.core.BasePreferenceController;
+
+/**
+ * Controller for the dark ui option dropdown
+ */
+public class DarkModeScheduleSelectorController extends BasePreferenceController
+        implements Preference.OnPreferenceChangeListener {
+
+    private final UiModeManager mUiModeManager;
+    private PowerManager mPowerManager;
+    private DropDownPreference mPreference;
+    private String mCurrentMode;
+
+    public DarkModeScheduleSelectorController(Context context, String key) {
+        super(context, key);
+        mUiModeManager = context.getSystemService(UiModeManager.class);
+        mPowerManager = context.getSystemService(PowerManager.class);
+    }
+
+    @Override
+    public void displayPreference(PreferenceScreen screen) {
+        super.displayPreference(screen);
+
+        mPreference = screen.findPreference(getPreferenceKey());
+    }
+
+    @Override
+    public int getAvailabilityStatus() {
+        return BasePreferenceController.AVAILABLE;
+    }
+
+    @Override
+    public final void updateState(Preference preference) {
+        final boolean batterySaver = mPowerManager.isPowerSaveMode();
+        mPreference.setEnabled(!batterySaver);
+        mCurrentMode =
+                mUiModeManager.getNightMode() == UiModeManager.MODE_NIGHT_AUTO
+                ? mContext.getString(R.string.dark_ui_auto_mode_auto)
+                : mContext.getString(R.string.dark_ui_auto_mode_never);
+        mPreference.setValue(mCurrentMode);
+    }
+    @Override
+    public final boolean onPreferenceChange(Preference preference, Object newValue) {
+        String newMode = (String) newValue;
+        if (newMode == mCurrentMode) {
+            return false;
+        }
+        mCurrentMode = newMode;
+        if (mCurrentMode == mContext.getString(R.string.dark_ui_auto_mode_never)) {
+            boolean active = (mContext.getResources().getConfiguration().uiMode
+                    & Configuration.UI_MODE_NIGHT_YES) != 0;
+            int mode = active ? UiModeManager.MODE_NIGHT_YES
+                    : UiModeManager.MODE_NIGHT_NO;
+            mUiModeManager.setNightMode(mode);
+
+        } else if (mCurrentMode ==
+                mContext.getString(R.string.dark_ui_auto_mode_auto)) {
+            mUiModeManager.setNightMode(UiModeManager.MODE_NIGHT_AUTO);
+        }
+        return true;
+    }
+}
diff --git a/src/com/android/settings/display/darkmode/DarkModeSettingsFragment.java b/src/com/android/settings/display/darkmode/DarkModeSettingsFragment.java
new file mode 100644
index 0000000..045c2bb
--- /dev/null
+++ b/src/com/android/settings/display/darkmode/DarkModeSettingsFragment.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+package com.android.settings.display.darkmode;
+
+import android.content.Context;
+import android.os.Bundle;
+import android.app.settings.SettingsEnums;
+import com.android.settings.R;
+import com.android.settings.dashboard.DashboardFragment;
+import com.android.settings.search.BaseSearchIndexProvider;
+import com.android.settingslib.search.SearchIndexable;
+
+/**
+ * Settings screen for Dark UI Mode
+ */
+@SearchIndexable(forTarget = SearchIndexable.ALL & ~SearchIndexable.ARC)
+public class DarkModeSettingsFragment extends DashboardFragment {
+
+    private static final String TAG = "DarkModeSettingsFragment";
+    private DarkModeObserver mContentObserver;
+    private Runnable mCallback = () -> {
+        updatePreferenceStates();
+    };
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        final Context context = getContext();
+        mContentObserver = new DarkModeObserver(context);
+    }
+
+    @Override
+    public void onStart() {
+        super.onStart();
+        // Listen for changes only while visible.
+        mContentObserver.subscribe(mCallback);
+    }
+
+    @Override
+    public void onStop() {
+        super.onStop();
+        // Stop listening for state changes.
+        mContentObserver.unsubscribe();
+    }
+
+    @Override
+    protected int getPreferenceScreenResId() {
+        return R.xml.dark_mode_settings;
+    }
+
+    @Override
+    public int getHelpResource() {
+        return R.string.help_url_dark_theme;
+    }
+
+    @Override
+    protected String getLogTag() {
+        return TAG;
+    }
+
+    @Override
+    public int getMetricsCategory() {
+        return SettingsEnums.DARK_UI_SETTINGS;
+    }
+
+    public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
+            new BaseSearchIndexProvider();
+}
diff --git a/src/com/android/settings/fuelgauge/BatteryHeaderPreferenceController.java b/src/com/android/settings/fuelgauge/BatteryHeaderPreferenceController.java
index 3064d4f..bfa43d1 100644
--- a/src/com/android/settings/fuelgauge/BatteryHeaderPreferenceController.java
+++ b/src/com/android/settings/fuelgauge/BatteryHeaderPreferenceController.java
@@ -55,8 +55,6 @@
     TextView mBatteryPercentText;
     @VisibleForTesting
     TextView mSummary1;
-    @VisibleForTesting
-    TextView mSummary2;
 
     private Activity mActivity;
     private PreferenceFragmentCompat mHost;
@@ -90,7 +88,6 @@
                 .findViewById(R.id.battery_header_icon);
         mBatteryPercentText = mBatteryLayoutPref.findViewById(R.id.battery_percent);
         mSummary1 = mBatteryLayoutPref.findViewById(R.id.summary1);
-        mSummary2 = mBatteryLayoutPref.findViewById(R.id.summary2);
 
         quickUpdateHeaderPreference();
     }
@@ -115,9 +112,6 @@
         } else {
             mSummary1.setText(info.remainingLabel);
         }
-        // Clear this just to be sure we don't get UI jank on re-entering this view from another
-        // activity.
-        mSummary2.setText("");
 
         mBatteryMeterView.setBatteryLevel(info.batteryLevel);
         mBatteryMeterView.setCharging(!info.discharging);
diff --git a/src/com/android/settings/fuelgauge/BatteryMeterView.java b/src/com/android/settings/fuelgauge/BatteryMeterView.java
index dc30c28..d54f5a4 100644
--- a/src/com/android/settings/fuelgauge/BatteryMeterView.java
+++ b/src/com/android/settings/fuelgauge/BatteryMeterView.java
@@ -117,6 +117,13 @@
                     .getDimensionPixelSize(R.dimen.battery_meter_height);
         }
 
+        public BatteryMeterDrawable(Context context, int frameColor, int width, int height) {
+            super(context, frameColor);
+
+            mIntrinsicWidth = width;
+            mIntrinsicHeight = height;
+        }
+
         @Override
         public int getIntrinsicWidth() {
             return mIntrinsicWidth;
diff --git a/src/com/android/settings/fuelgauge/PowerUsageSummary.java b/src/com/android/settings/fuelgauge/PowerUsageSummary.java
index 880255b..d25c2d4 100644
--- a/src/com/android/settings/fuelgauge/PowerUsageSummary.java
+++ b/src/com/android/settings/fuelgauge/PowerUsageSummary.java
@@ -19,7 +19,6 @@
 import static com.android.settings.fuelgauge.BatteryBroadcastReceiver.BatteryUpdateType;
 
 import android.app.settings.SettingsEnums;
-import android.content.ContentResolver;
 import android.content.Context;
 import android.database.ContentObserver;
 import android.net.Uri;
@@ -27,7 +26,6 @@
 import android.os.Bundle;
 import android.os.Handler;
 import android.provider.SearchIndexableResource;
-import android.provider.Settings;
 import android.provider.Settings.Global;
 import android.text.format.Formatter;
 import android.view.Menu;
@@ -162,7 +160,6 @@
         final TextView percentRemaining =
                 mBatteryLayoutPref.findViewById(R.id.battery_percent);
         final TextView summary1 = mBatteryLayoutPref.findViewById(R.id.summary1);
-        final TextView summary2 = mBatteryLayoutPref.findViewById(R.id.summary2);
         BatteryInfo oldInfo = batteryInfos.get(0);
         BatteryInfo newInfo = batteryInfos.get(1);
         percentRemaining.setText(Utils.formatPercentage(oldInfo.batteryLevel));
@@ -170,14 +167,13 @@
         // set the text to the old estimate (copied from battery info). Note that this
         // can sometimes say 0 time remaining because battery stats requires the phone
         // be unplugged for a period of time before being willing ot make an estimate.
-        summary1.setText(mPowerFeatureProvider.getOldEstimateDebugString(
+        final String OldEstimateString = mPowerFeatureProvider.getOldEstimateDebugString(
                 Formatter.formatShortElapsedTime(getContext(),
-                        PowerUtil.convertUsToMs(oldInfo.remainingTimeUs))));
-
-        // for this one we can just set the string directly
-        summary2.setText(mPowerFeatureProvider.getEnhancedEstimateDebugString(
+                        PowerUtil.convertUsToMs(oldInfo.remainingTimeUs)));
+        final String NewEstimateString = mPowerFeatureProvider.getEnhancedEstimateDebugString(
                 Formatter.formatShortElapsedTime(getContext(),
-                        PowerUtil.convertUsToMs(newInfo.remainingTimeUs))));
+                        PowerUtil.convertUsToMs(newInfo.remainingTimeUs)));
+        summary1.setText(OldEstimateString + "\n" + NewEstimateString);
 
         batteryView.setBatteryLevel(oldInfo.batteryLevel);
         batteryView.setCharging(!oldInfo.discharging);
diff --git a/src/com/android/settings/homepage/SettingsHomepageActivity.java b/src/com/android/settings/homepage/SettingsHomepageActivity.java
index fa23101..5e6c54b 100644
--- a/src/com/android/settings/homepage/SettingsHomepageActivity.java
+++ b/src/com/android/settings/homepage/SettingsHomepageActivity.java
@@ -33,6 +33,7 @@
 
 import com.android.settings.R;
 import com.android.settings.accounts.AvatarViewMixin;
+import com.android.settings.core.HideNonSystemOverlayMixin;
 import com.android.settings.homepage.contextualcards.ContextualCardsFragment;
 import com.android.settings.overlay.FeatureFactory;
 
@@ -54,8 +55,8 @@
                 .initSearchToolbar(this /* activity */, toolbar, SettingsEnums.SETTINGS_HOMEPAGE);
 
         final ImageView avatarView = findViewById(R.id.account_avatar);
-        final AvatarViewMixin avatarViewMixin = new AvatarViewMixin(this, avatarView);
-        getLifecycle().addObserver(avatarViewMixin);
+        getLifecycle().addObserver(new AvatarViewMixin(this, avatarView));
+        getLifecycle().addObserver(new HideNonSystemOverlayMixin(this));
 
         if (!getSystemService(ActivityManager.class).isLowRamDevice()) {
             // Only allow contextual feature on high ram devices.
diff --git a/src/com/android/settings/homepage/contextualcards/ContextualCardLoader.java b/src/com/android/settings/homepage/contextualcards/ContextualCardLoader.java
index 6d3649d..5a04143 100644
--- a/src/com/android/settings/homepage/contextualcards/ContextualCardLoader.java
+++ b/src/com/android/settings/homepage/contextualcards/ContextualCardLoader.java
@@ -37,12 +37,11 @@
 import com.android.settings.overlay.FeatureFactory;
 import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
 import com.android.settingslib.utils.AsyncLoaderCompat;
+import com.android.settingslib.utils.ThreadUtils;
 
 import java.util.ArrayList;
 import java.util.List;
 import java.util.concurrent.ExecutionException;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
 import java.util.concurrent.Future;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeoutException;
@@ -56,7 +55,6 @@
     private static final String TAG = "ContextualCardLoader";
     private static final long ELIGIBILITY_CHECKER_TIMEOUT_MS = 250;
 
-    private final ExecutorService mExecutorService;
     private final ContentObserver mObserver = new ContentObserver(
             new Handler(Looper.getMainLooper())) {
         @Override
@@ -76,7 +74,6 @@
     ContextualCardLoader(Context context) {
         super(context);
         mContext = context.getApplicationContext();
-        mExecutorService = Executors.newCachedThreadPool();
     }
 
     @Override
@@ -163,8 +160,8 @@
         final List<Future<ContextualCard>> eligibleCards = new ArrayList<>();
 
         for (ContextualCard card : candidates) {
-            final EligibleCardChecker future = new EligibleCardChecker(mContext, card);
-            eligibleCards.add(mExecutorService.submit(future));
+            final EligibleCardChecker checker = new EligibleCardChecker(mContext, card);
+            eligibleCards.add(ThreadUtils.postOnBackgroundThread(checker));
         }
         // Collect future and eligible cards
         for (Future<ContextualCard> cardFuture : eligibleCards) {
diff --git a/src/com/android/settings/homepage/contextualcards/SettingsContextualCardProvider.java b/src/com/android/settings/homepage/contextualcards/SettingsContextualCardProvider.java
index 385f8cd..1494293 100644
--- a/src/com/android/settings/homepage/contextualcards/SettingsContextualCardProvider.java
+++ b/src/com/android/settings/homepage/contextualcards/SettingsContextualCardProvider.java
@@ -78,6 +78,12 @@
                         .setCardName(CustomSliceRegistry.FACE_ENROLL_SLICE_URI.toString())
                         .setCardCategory(ContextualCard.Category.DEFAULT)
                         .build();
+        final ContextualCard darkThemeCard =
+                ContextualCard.newBuilder()
+                        .setSliceUri(CustomSliceRegistry.DARK_THEME_SLICE_URI.toString())
+                        .setCardName(CustomSliceRegistry.DARK_THEME_SLICE_URI.toString())
+                        .setCardCategory(ContextualCard.Category.IMPORTANT)
+                        .build();
         final ContextualCardList cards = ContextualCardList.newBuilder()
                 .addCard(wifiCard)
                 .addCard(connectedDeviceCard)
@@ -86,6 +92,7 @@
                 .addCard(notificationChannelCard)
                 .addCard(contextualAdaptiveSleepCard)
                 .addCard(contextualFaceSettingsCard)
+                .addCard(darkThemeCard)
                 .build();
 
         return cards;
diff --git a/src/com/android/settings/homepage/contextualcards/conditional/ConditionManager.java b/src/com/android/settings/homepage/contextualcards/conditional/ConditionManager.java
index 66f6c81..1beac9b 100644
--- a/src/com/android/settings/homepage/contextualcards/conditional/ConditionManager.java
+++ b/src/com/android/settings/homepage/contextualcards/conditional/ConditionManager.java
@@ -23,13 +23,12 @@
 import androidx.annotation.VisibleForTesting;
 
 import com.android.settings.homepage.contextualcards.ContextualCard;
+import com.android.settingslib.utils.ThreadUtils;
 
 import java.util.ArrayList;
 import java.util.List;
 import java.util.concurrent.Callable;
 import java.util.concurrent.ExecutionException;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
 import java.util.concurrent.Future;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeoutException;
@@ -42,7 +41,6 @@
 
     private static final long DISPLAYABLE_CHECKER_TIMEOUT_MS = 20;
 
-    private final ExecutorService mExecutorService;
     private final Context mAppContext;
     private final ConditionListener mListener;
 
@@ -50,7 +48,6 @@
 
     public ConditionManager(Context context, ConditionListener listener) {
         mAppContext = context.getApplicationContext();
-        mExecutorService = Executors.newCachedThreadPool();
         mCardControllers = new ArrayList<>();
         mListener = listener;
         initCandidates();
@@ -64,8 +61,8 @@
         final List<Future<ContextualCard>> displayableCards = new ArrayList<>();
         // Check displayable future
         for (ConditionalCardController card : mCardControllers) {
-            final DisplayableChecker future = new DisplayableChecker(getController(card.getId()));
-            displayableCards.add(mExecutorService.submit(future));
+            final DisplayableChecker checker = new DisplayableChecker(getController(card.getId()));
+            displayableCards.add(ThreadUtils.postOnBackgroundThread(checker));
         }
         // Collect future and add displayable cards
         for (Future<ContextualCard> cardFuture : displayableCards) {
diff --git a/src/com/android/settings/homepage/contextualcards/slices/DarkThemeSlice.java b/src/com/android/settings/homepage/contextualcards/slices/DarkThemeSlice.java
new file mode 100644
index 0000000..1b7f003
--- /dev/null
+++ b/src/com/android/settings/homepage/contextualcards/slices/DarkThemeSlice.java
@@ -0,0 +1,185 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.settings.homepage.contextualcards.slices;
+
+import static androidx.slice.builders.ListBuilder.ICON_IMAGE;
+
+import static android.provider.Settings.Global.LOW_POWER_MODE;
+
+import android.annotation.ColorInt;
+import android.app.PendingIntent;
+import android.app.UiModeManager;
+import android.content.Context;
+import android.content.Intent;
+import android.content.res.Configuration;
+import android.database.ContentObserver;
+import android.net.Uri;
+import android.os.BatteryManager;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.PowerManager;
+import android.provider.Settings;
+import android.util.Log;
+
+import androidx.annotation.VisibleForTesting;
+import androidx.core.graphics.drawable.IconCompat;
+import androidx.slice.Slice;
+import androidx.slice.builders.ListBuilder;
+import androidx.slice.builders.SliceAction;
+
+import com.android.settings.R;
+import com.android.settings.Utils;
+import com.android.settings.overlay.FeatureFactory;
+import com.android.settings.slices.CustomSliceRegistry;
+import com.android.settings.slices.CustomSliceable;
+import com.android.settings.slices.SliceBackgroundWorker;
+
+import java.io.IOException;
+
+public class DarkThemeSlice implements CustomSliceable {
+    private static final String TAG = "DarkThemeSlice";
+    private static final int BATTERY_LEVEL_THRESHOLD = 50;
+    private static final int DELAY_TIME_EXECUTING_DARK_THEME = 200;
+
+    // Keep the slice even Dark theme mode changed when it is on HomePage
+    @VisibleForTesting
+    static boolean sKeepSliceShow;
+    @VisibleForTesting
+    static long sActiveUiSession = -1000;
+
+    private final Context mContext;
+    private final UiModeManager mUiModeManager;
+    private final PowerManager mPowerManager;
+
+    public DarkThemeSlice(Context context) {
+        mContext = context;
+        mUiModeManager = context.getSystemService(UiModeManager.class);
+        mPowerManager = context.getSystemService(PowerManager.class);
+    }
+
+    @Override
+    public Slice getSlice() {
+        final long currentUiSession = FeatureFactory.getFactory(mContext)
+                .getSlicesFeatureProvider().getUiSessionToken();
+        if (currentUiSession != sActiveUiSession) {
+            sActiveUiSession = currentUiSession;
+            sKeepSliceShow = false;
+        }
+        // Dark theme slice will disappear when battery saver is ON.
+        if (mPowerManager.isPowerSaveMode() || (!sKeepSliceShow && !isAvailable(mContext))) {
+            return new ListBuilder(mContext, CustomSliceRegistry.DARK_THEME_SLICE_URI,
+                    ListBuilder.INFINITY)
+                    .setIsError(true)
+                    .build();
+        }
+        sKeepSliceShow = true;
+        final PendingIntent toggleAction = getBroadcastIntent(mContext);
+        @ColorInt final int color = Utils.getColorAccentDefaultColor(mContext);
+        final IconCompat icon =
+                IconCompat.createWithResource(mContext, R.drawable.dark_theme);
+        return new ListBuilder(mContext, CustomSliceRegistry.DARK_THEME_SLICE_URI,
+                ListBuilder.INFINITY)
+                .setAccentColor(color)
+                .addRow(new ListBuilder.RowBuilder()
+                        .setTitle(mContext.getText(R.string.dark_theme_slice_title))
+                        .setTitleItem(icon, ICON_IMAGE)
+                        .setSubtitle(mContext.getText(R.string.dark_theme_slice_subtitle))
+                        .setPrimaryAction(
+                                SliceAction.createToggle(toggleAction, null /* actionTitle */,
+                                        isDarkThemeMode(mContext))))
+                .build();
+    }
+
+    @Override
+    public Uri getUri() {
+        return CustomSliceRegistry.DARK_THEME_SLICE_URI;
+    }
+
+    @Override
+    public void onNotifyChange(Intent intent) {
+        final boolean isChecked = intent.getBooleanExtra(android.app.slice.Slice.EXTRA_TOGGLE_STATE,
+                false);
+        // make toggle transition more smooth before dark theme takes effect
+        new Handler(Looper.getMainLooper()).postDelayed(() -> {
+            mUiModeManager.setNightModeActivated(isChecked);
+        }, DELAY_TIME_EXECUTING_DARK_THEME);
+    }
+
+    @Override
+    public Intent getIntent() {
+        return null;
+    }
+
+    @Override
+    public Class getBackgroundWorkerClass() {
+        return DarkThemeWorker.class;
+    }
+
+    @VisibleForTesting
+    boolean isAvailable(Context context) {
+        // checking dark theme mode.
+        if (isDarkThemeMode(context)) {
+            return false;
+        }
+
+        // checking the current battery level
+        final BatteryManager batteryManager = context.getSystemService(BatteryManager.class);
+        final int level = batteryManager.getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY);
+        Log.d(TAG, "battery level=" + level);
+        return level <= BATTERY_LEVEL_THRESHOLD;
+    }
+
+    @VisibleForTesting
+    boolean isDarkThemeMode(Context context) {
+        final int currentNightMode =
+                context.getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK;
+        return currentNightMode == Configuration.UI_MODE_NIGHT_YES;
+    }
+
+    public static class DarkThemeWorker extends SliceBackgroundWorker<Void> {
+        private final Context mContext;
+        private final ContentObserver mContentObserver =
+                new ContentObserver(new Handler(Looper.getMainLooper())) {
+                    @Override
+                    public void onChange(boolean bChanged) {
+                        if (mContext.getSystemService(PowerManager.class).isPowerSaveMode()) {
+                            notifySliceChange();
+                        }
+                    }
+                };
+
+        public DarkThemeWorker(Context context, Uri uri) {
+            super(context, uri);
+            mContext = context;
+        }
+
+        @Override
+        protected void onSlicePinned() {
+            mContext.getContentResolver().registerContentObserver(
+                    Settings.Global.getUriFor(LOW_POWER_MODE), false /* notifyForDescendants */,
+                    mContentObserver);
+        }
+
+        @Override
+        protected void onSliceUnpinned() {
+            mContext.getContentResolver().unregisterContentObserver(mContentObserver);
+        }
+
+        @Override
+        public void close() throws IOException {
+        }
+    }
+}
diff --git a/src/com/android/settings/homepage/contextualcards/slices/NotificationChannelSlice.java b/src/com/android/settings/homepage/contextualcards/slices/NotificationChannelSlice.java
index ff76779..bdf97a8 100644
--- a/src/com/android/settings/homepage/contextualcards/slices/NotificationChannelSlice.java
+++ b/src/com/android/settings/homepage/contextualcards/slices/NotificationChannelSlice.java
@@ -20,8 +20,6 @@
 import static android.app.NotificationManager.IMPORTANCE_NONE;
 import static android.app.slice.Slice.EXTRA_TOGGLE_STATE;
 
-import static com.android.settings.notification.ChannelListPreferenceController.ARG_FROM_SETTINGS;
-
 import android.app.Application;
 import android.app.NotificationChannel;
 import android.app.NotificationChannelGroup;
@@ -62,13 +60,12 @@
 import com.android.settingslib.RestrictedLockUtils;
 import com.android.settingslib.RestrictedLockUtilsInternal;
 import com.android.settingslib.applications.ApplicationsState;
+import com.android.settingslib.utils.ThreadUtils;
 
 import java.util.ArrayList;
 import java.util.Comparator;
 import java.util.List;
 import java.util.concurrent.ExecutionException;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
 import java.util.concurrent.Future;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeoutException;
@@ -135,7 +132,6 @@
             };
 
     protected final Context mContext;
-    private final ExecutorService mExecutorService;
     @VisibleForTesting
     NotificationBackend mNotificationBackend;
     private NotificationBackend.AppRow mAppRow;
@@ -145,7 +141,6 @@
     public NotificationChannelSlice(Context context) {
         mContext = context;
         mNotificationBackend = new NotificationBackend();
-        mExecutorService = Executors.newCachedThreadPool();
     }
 
     @Override
@@ -376,9 +371,9 @@
         // Create tasks to get notification data for multi-channel packages.
         final List<Future<NotificationBackend.AppRow>> appRowTasks = new ArrayList<>();
         for (PackageInfo packageInfo : packageInfoList) {
-            final NotificationMultiChannelAppRow future = new NotificationMultiChannelAppRow(
+            final NotificationMultiChannelAppRow appRow = new NotificationMultiChannelAppRow(
                     mContext, mNotificationBackend, packageInfo);
-            appRowTasks.add(mExecutorService.submit(future));
+            appRowTasks.add(ThreadUtils.postOnBackgroundThread(appRow));
         }
 
         // Get the package which has sent at least ~10 notifications and not turn off channels.
diff --git a/src/com/android/settings/network/telephony/MmsMessagePreferenceController.java b/src/com/android/settings/network/telephony/MmsMessagePreferenceController.java
index c1f2949..00f5ebc 100644
--- a/src/com/android/settings/network/telephony/MmsMessagePreferenceController.java
+++ b/src/com/android/settings/network/telephony/MmsMessagePreferenceController.java
@@ -22,11 +22,8 @@
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
 import android.telephony.data.ApnSetting;
-import android.util.Log;
 
-import androidx.preference.Preference;
 import androidx.preference.PreferenceScreen;
-import androidx.preference.SwitchPreference;
 
 import com.android.settings.network.MobileDataContentObserver;
 import com.android.settingslib.core.lifecycle.LifecycleObserver;
@@ -41,14 +38,14 @@
     private TelephonyManager mTelephonyManager;
     private SubscriptionManager mSubscriptionManager;
     private MobileDataContentObserver mMobileDataContentObserver;
-    private SwitchPreference mPreference;
+    private PreferenceScreen mScreen;
 
     public MmsMessagePreferenceController(Context context, String key) {
         super(context, key);
         mSubscriptionManager = context.getSystemService(SubscriptionManager.class);
         mMobileDataContentObserver = new MobileDataContentObserver(
                 new Handler(Looper.getMainLooper()));
-        mMobileDataContentObserver.setOnMobileDataChangedListener(()->updateState(mPreference));
+        mMobileDataContentObserver.setOnMobileDataChangedListener(()->refreshPreference());
     }
 
     @Override
@@ -79,15 +76,9 @@
     @Override
     public void displayPreference(PreferenceScreen screen) {
         super.displayPreference(screen);
-        mPreference = screen.findPreference(getPreferenceKey());
+        mScreen = screen;
     }
 
-    @Override
-    public void updateState(Preference preference) {
-        super.updateState(preference);
-        preference.setVisible(isAvailable());
-        ((SwitchPreference) preference).setChecked(isChecked());
-    }
 
     public void init(int subId) {
         mSubId = subId;
@@ -104,4 +95,10 @@
     public boolean isChecked() {
         return mTelephonyManager.isDataEnabledForApn(ApnSetting.TYPE_MMS);
     }
+
+    private void refreshPreference() {
+        if (mScreen != null) {
+            super.displayPreference(mScreen);
+        }
+    }
 }
diff --git a/src/com/android/settings/network/telephony/MobileNetworkUtils.java b/src/com/android/settings/network/telephony/MobileNetworkUtils.java
index a4fa845..bd9b709 100644
--- a/src/com/android/settings/network/telephony/MobileNetworkUtils.java
+++ b/src/com/android/settings/network/telephony/MobileNetworkUtils.java
@@ -228,16 +228,23 @@
         final String currentCountry = tm.getNetworkCountryIso().toLowerCase();
         final String supportedCountries =
                 Settings.Global.getString(cr, Settings.Global.EUICC_SUPPORTED_COUNTRIES);
+        final String unsupportedCountries =
+                Settings.Global.getString(cr, Settings.Global.EUICC_UNSUPPORTED_COUNTRIES);
+
         boolean inEsimSupportedCountries = false;
-        if (TextUtils.isEmpty(currentCountry)) {
-            inEsimSupportedCountries = true;
-        } else if (!TextUtils.isEmpty(supportedCountries)) {
-            final List<String> supportedCountryList =
-                    Arrays.asList(TextUtils.split(supportedCountries.toLowerCase(), ","));
-            if (supportedCountryList.contains(currentCountry)) {
-                inEsimSupportedCountries = true;
-            }
+
+        if (TextUtils.isEmpty(supportedCountries)) {
+            // White list is empty, use blacklist.
+            Log.d(TAG, "Using blacklist unsupportedCountries=" + unsupportedCountries);
+            inEsimSupportedCountries = !isEsimUnsupportedCountry(currentCountry,
+                    unsupportedCountries);
+        } else {
+            Log.d(TAG, "Using whitelist supportedCountries=" + supportedCountries);
+            inEsimSupportedCountries = isEsimSupportedCountry(currentCountry, supportedCountries);
         }
+
+        Log.d(TAG, "inEsimSupportedCountries=" + inEsimSupportedCountries);
+
         final boolean esimIgnoredDevice =
                 Arrays.asList(TextUtils.split(SystemProperties.get(KEY_ESIM_CID_IGNORE, ""), ","))
                         .contains(SystemProperties.get(KEY_CID, null));
@@ -613,4 +620,24 @@
         }
         return tm.getNetworkOperatorName();
     }
+
+    private static boolean isEsimSupportedCountry(String country, String countriesListString) {
+        if (TextUtils.isEmpty(country)) {
+            return true;
+        } else if (TextUtils.isEmpty(countriesListString)) {
+            return false;
+        }
+        final List<String> supportedCountries =
+                Arrays.asList(TextUtils.split(countriesListString.toLowerCase(), ","));
+        return supportedCountries.contains(country);
+    }
+
+    private static boolean isEsimUnsupportedCountry(String country, String countriesListString) {
+        if (TextUtils.isEmpty(country) || TextUtils.isEmpty(countriesListString)) {
+            return false;
+        }
+        final List<String> unsupportedCountries =
+                Arrays.asList(TextUtils.split(countriesListString.toLowerCase(), ","));
+        return unsupportedCountries.contains(country);
+    }
 }
diff --git a/src/com/android/settings/overlay/FeatureFactory.java b/src/com/android/settings/overlay/FeatureFactory.java
index d9af345..afbce09 100644
--- a/src/com/android/settings/overlay/FeatureFactory.java
+++ b/src/com/android/settings/overlay/FeatureFactory.java
@@ -26,6 +26,7 @@
 import com.android.settings.accounts.AccountFeatureProvider;
 import com.android.settings.applications.ApplicationFeatureProvider;
 import com.android.settings.aware.AwareFeatureProvider;
+import com.android.settings.biometrics.face.FaceFeatureProvider;
 import com.android.settings.bluetooth.BluetoothFeatureProvider;
 import com.android.settings.dashboard.DashboardFeatureProvider;
 import com.android.settings.dashboard.suggestions.SuggestionFeatureProvider;
@@ -133,6 +134,8 @@
 
     public abstract AwareFeatureProvider getAwareFeatureProvider();
 
+    public abstract FaceFeatureProvider getFaceFeatureProvider();
+
     public static final class FactoryNotFoundException extends RuntimeException {
         public FactoryNotFoundException(Throwable throwable) {
             super("Unable to create factory. Did you misconfigure Proguard?", throwable);
diff --git a/src/com/android/settings/overlay/FeatureFactoryImpl.java b/src/com/android/settings/overlay/FeatureFactoryImpl.java
index 2f9626d..29beb5b 100644
--- a/src/com/android/settings/overlay/FeatureFactoryImpl.java
+++ b/src/com/android/settings/overlay/FeatureFactoryImpl.java
@@ -30,6 +30,8 @@
 import com.android.settings.applications.ApplicationFeatureProviderImpl;
 import com.android.settings.aware.AwareFeatureProvider;
 import com.android.settings.aware.AwareFeatureProviderImpl;
+import com.android.settings.biometrics.face.FaceFeatureProvider;
+import com.android.settings.biometrics.face.FaceFeatureProviderImpl;
 import com.android.settings.bluetooth.BluetoothFeatureProvider;
 import com.android.settings.bluetooth.BluetoothFeatureProviderImpl;
 import com.android.settings.connecteddevice.dock.DockUpdaterFeatureProviderImpl;
@@ -84,6 +86,7 @@
     private ContextualCardFeatureProvider mContextualCardFeatureProvider;
     private BluetoothFeatureProvider mBluetoothFeatureProvider;
     private AwareFeatureProvider mAwareFeatureProvider;
+    private FaceFeatureProvider mFaceFeatureProvider;
 
     @Override
     public SupportFeatureProvider getSupportFeatureProvider(Context context) {
@@ -255,4 +258,12 @@
         }
         return mAwareFeatureProvider;
     }
+
+    @Override
+    public FaceFeatureProvider getFaceFeatureProvider() {
+        if (mFaceFeatureProvider == null) {
+            mFaceFeatureProvider = new FaceFeatureProviderImpl();
+        }
+        return mFaceFeatureProvider;
+    }
 }
diff --git a/src/com/android/settings/panel/SettingsPanelActivity.java b/src/com/android/settings/panel/SettingsPanelActivity.java
index 749a46e..8693186 100644
--- a/src/com/android/settings/panel/SettingsPanelActivity.java
+++ b/src/com/android/settings/panel/SettingsPanelActivity.java
@@ -32,6 +32,7 @@
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.settings.R;
+import com.android.settings.core.HideNonSystemOverlayMixin;
 
 /**
  * Dialog Activity to host Settings Slices.
@@ -62,6 +63,7 @@
     protected void onCreate(@Nullable Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         createOrUpdatePanel(true /* shouldForceCreation */);
+        getLifecycle().addObserver(new HideNonSystemOverlayMixin(this));
     }
 
     @Override
diff --git a/src/com/android/settings/privacy/PermissionBarChartPreferenceController.java b/src/com/android/settings/privacy/PermissionBarChartPreferenceController.java
deleted file mode 100644
index 28533df..0000000
--- a/src/com/android/settings/privacy/PermissionBarChartPreferenceController.java
+++ /dev/null
@@ -1,243 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.settings.privacy;
-
-import static android.Manifest.permission_group.CAMERA;
-import static android.Manifest.permission_group.LOCATION;
-import static android.Manifest.permission_group.MICROPHONE;
-
-import static java.util.concurrent.TimeUnit.DAYS;
-
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.graphics.drawable.Drawable;
-import android.os.Bundle;
-import android.permission.PermissionControllerManager;
-import android.permission.RuntimePermissionUsageInfo;
-import android.provider.DeviceConfig;
-import android.util.Log;
-import android.view.View;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.VisibleForTesting;
-import androidx.preference.PreferenceScreen;
-
-import com.android.settings.R;
-import com.android.settings.core.BasePreferenceController;
-import com.android.settingslib.Utils;
-import com.android.settingslib.core.lifecycle.LifecycleObserver;
-import com.android.settingslib.core.lifecycle.events.OnCreate;
-import com.android.settingslib.core.lifecycle.events.OnSaveInstanceState;
-import com.android.settingslib.core.lifecycle.events.OnStart;
-import com.android.settingslib.widget.BarChartInfo;
-import com.android.settingslib.widget.BarChartPreference;
-import com.android.settingslib.widget.BarViewInfo;
-
-import java.util.ArrayList;
-import java.util.List;
-
-
-public class PermissionBarChartPreferenceController extends BasePreferenceController implements
-        PermissionControllerManager.OnPermissionUsageResultCallback, LifecycleObserver, OnCreate,
-        OnStart, OnSaveInstanceState {
-
-    private static final String TAG = "BarChartPreferenceCtl";
-    private static final String KEY_PERMISSION_USAGE = "usage_infos";
-
-    @VisibleForTesting
-    List<RuntimePermissionUsageInfo> mOldUsageInfos;
-    private PackageManager mPackageManager;
-    private PrivacyDashboardFragment mParent;
-    private BarChartPreference mBarChartPreference;
-
-    public PermissionBarChartPreferenceController(Context context, String preferenceKey) {
-        super(context, preferenceKey);
-        mOldUsageInfos = new ArrayList<>();
-        mPackageManager = context.getPackageManager();
-    }
-
-    public void setFragment(PrivacyDashboardFragment fragment) {
-        mParent = fragment;
-    }
-
-    @Override
-    public void onCreate(Bundle savedInstanceState) {
-        if (savedInstanceState != null) {
-            mOldUsageInfos = savedInstanceState.getParcelableArrayList(KEY_PERMISSION_USAGE);
-        }
-    }
-
-    @Override
-    public void onSaveInstanceState(Bundle outState) {
-        outState.putParcelableList(KEY_PERMISSION_USAGE, mOldUsageInfos);
-    }
-
-    @Override
-    public int getAvailabilityStatus() {
-        return UNSUPPORTED_ON_DEVICE;
-    }
-
-    @Override
-    public void displayPreference(PreferenceScreen screen) {
-        super.displayPreference(screen);
-        mBarChartPreference = screen.findPreference(getPreferenceKey());
-
-        final BarChartInfo info = new BarChartInfo.Builder()
-                .setTitle(R.string.permission_bar_chart_title)
-                .setDetails(R.string.permission_bar_chart_details)
-                .setEmptyText(R.string.permission_bar_chart_empty_text)
-                .setDetailsOnClickListener((View v) -> {
-                    final Intent intent = new Intent(Intent.ACTION_REVIEW_PERMISSION_USAGE);
-                    intent.putExtra(Intent.EXTRA_DURATION_MILLIS, DAYS.toMillis(1));
-                    mContext.startActivity(intent);
-                })
-                .build();
-
-        mBarChartPreference.initializeBarChart(info);
-        if (!mOldUsageInfos.isEmpty()) {
-            mBarChartPreference.setBarViewInfos(createBarViews(mOldUsageInfos));
-        }
-    }
-
-    @Override
-    public void onStart() {
-        if (!isAvailable()) {
-            return;
-        }
-
-        // We don't hide chart when we have existing data.
-        mBarChartPreference.updateLoadingState(mOldUsageInfos.isEmpty() /* isLoading */);
-        // But we still need to hint user with progress bar that we are updating new usage data.
-        mParent.setLoadingEnabled(true /* enabled */);
-        retrievePermissionUsageData();
-    }
-
-    @Override
-    public void onPermissionUsageResult(@NonNull List<RuntimePermissionUsageInfo> usageInfos) {
-        usageInfos.sort((x, y) -> {
-            int usageDiff = y.getAppAccessCount() - x.getAppAccessCount();
-            if (usageDiff != 0) {
-                return usageDiff;
-            }
-            String xName = x.getName();
-            String yName = y.getName();
-            if (xName.equals(LOCATION)) {
-                return -1;
-            } else if (yName.equals(LOCATION)) {
-                return 1;
-            } else if (xName.equals(MICROPHONE)) {
-                return -1;
-            } else if (yName.equals(MICROPHONE)) {
-                return 1;
-            } else if (xName.equals(CAMERA)) {
-                return -1;
-            } else if (yName.equals(CAMERA)) {
-                return 1;
-            }
-            return x.getName().compareTo(y.getName());
-        });
-
-        // If the result is different, we need to update bar views.
-        if (!areSamePermissionGroups(usageInfos)) {
-            mBarChartPreference.setBarViewInfos(createBarViews(usageInfos));
-            mOldUsageInfos = usageInfos;
-        }
-
-        mBarChartPreference.updateLoadingState(false /* isLoading */);
-        mParent.setLoadingEnabled(false /* enabled */);
-    }
-
-    private void retrievePermissionUsageData() {
-        mContext.getSystemService(PermissionControllerManager.class).getPermissionUsages(
-                false /* countSystem */, (int) DAYS.toMillis(1),
-                mContext.getMainExecutor() /* executor */, this /* callback */);
-    }
-
-    private BarViewInfo[] createBarViews(List<RuntimePermissionUsageInfo> usageInfos) {
-        if (usageInfos.isEmpty()) {
-            return null;
-        }
-
-        final BarViewInfo[] barViewInfos = new BarViewInfo[
-                Math.min(BarChartPreference.MAXIMUM_BAR_VIEWS, usageInfos.size())];
-
-        for (int index = 0; index < barViewInfos.length; index++) {
-            final RuntimePermissionUsageInfo permissionGroupInfo = usageInfos.get(index);
-            final int count = permissionGroupInfo.getAppAccessCount();
-            final CharSequence permLabel = getPermissionGroupLabel(permissionGroupInfo.getName());
-
-            barViewInfos[index] = new BarViewInfo(
-                    getPermissionGroupIcon(permissionGroupInfo.getName()), count, permLabel,
-                    mContext.getResources().getQuantityString(R.plurals.permission_bar_chart_label,
-                            count, count), permLabel);
-
-            // Set the click listener for each bar view.
-            // The listener will navigate user to permission usage app.
-            barViewInfos[index].setClickListener((View v) -> {
-                final Intent intent = new Intent(Intent.ACTION_REVIEW_PERMISSION_USAGE);
-                intent.putExtra(Intent.EXTRA_PERMISSION_GROUP_NAME, permissionGroupInfo.getName());
-                intent.putExtra(Intent.EXTRA_DURATION_MILLIS, DAYS.toMillis(1));
-                mContext.startActivity(intent);
-            });
-        }
-
-        return barViewInfos;
-    }
-
-    private Drawable getPermissionGroupIcon(String permissionGroup) {
-        Drawable icon = null;
-        try {
-            icon = mPackageManager.getPermissionGroupInfo(permissionGroup, 0)
-                    .loadIcon(mPackageManager);
-            icon.setTintList(Utils.getColorAttr(mContext, android.R.attr.textColorSecondary));
-        } catch (PackageManager.NameNotFoundException e) {
-            Log.w(TAG, "Cannot find group icon for " + permissionGroup, e);
-        }
-
-        return icon;
-    }
-
-    private CharSequence getPermissionGroupLabel(String permissionGroup) {
-        CharSequence label = null;
-        try {
-            label = mPackageManager.getPermissionGroupInfo(permissionGroup, 0)
-                    .loadLabel(mPackageManager);
-        } catch (PackageManager.NameNotFoundException e) {
-            Log.w(TAG, "Cannot find group label for " + permissionGroup, e);
-        }
-
-        return label;
-    }
-
-    private boolean areSamePermissionGroups(List<RuntimePermissionUsageInfo> newUsageInfos) {
-        if (newUsageInfos.size() != mOldUsageInfos.size()) {
-            return false;
-        }
-
-        for (int index = 0; index < newUsageInfos.size(); index++) {
-            final RuntimePermissionUsageInfo newInfo = newUsageInfos.get(index);
-            final RuntimePermissionUsageInfo oldInfo = mOldUsageInfos.get(index);
-
-            if (!newInfo.getName().equals(oldInfo.getName()) ||
-                    newInfo.getAppAccessCount() != oldInfo.getAppAccessCount()) {
-                return false;
-            }
-        }
-        return true;
-    }
-}
diff --git a/src/com/android/settings/privacy/PrivacyDashboardFragment.java b/src/com/android/settings/privacy/PrivacyDashboardFragment.java
index fa21f9d..1869cff 100644
--- a/src/com/android/settings/privacy/PrivacyDashboardFragment.java
+++ b/src/com/android/settings/privacy/PrivacyDashboardFragment.java
@@ -18,14 +18,12 @@
 
 import android.app.settings.SettingsEnums;
 import android.content.Context;
-import android.os.Bundle;
 import android.provider.SearchIndexableResource;
 import android.view.View;
 
 import androidx.annotation.VisibleForTesting;
 
 import com.android.settings.R;
-import com.android.settings.Utils;
 import com.android.settings.dashboard.DashboardFragment;
 import com.android.settings.notification.LockScreenNotificationPreferenceController;
 import com.android.settings.search.BaseSearchIndexProvider;
@@ -75,34 +73,6 @@
         return buildPreferenceControllers(context, getSettingsLifecycle());
     }
 
-    @Override
-    public void onAttach(Context context) {
-        super.onAttach(context);
-        use(PermissionBarChartPreferenceController.class).setFragment(this /* fragment */);
-    }
-
-    @Override
-    public void onViewCreated(View view, Bundle savedInstanceState) {
-        super.onViewCreated(view, savedInstanceState);
-        Utils.setActionBarShadowAnimation(getActivity(), getSettingsLifecycle(), getListView());
-        initLoadingBar();
-    }
-
-    @VisibleForTesting
-    void initLoadingBar() {
-        mProgressHeader = setPinnedHeaderView(R.layout.progress_header);
-        mProgressAnimation = mProgressHeader.findViewById(R.id.progress_bar_animation);
-        setLoadingEnabled(false);
-    }
-
-    @VisibleForTesting
-    void setLoadingEnabled(boolean enabled) {
-        if (mProgressHeader != null && mProgressAnimation != null) {
-            mProgressHeader.setVisibility(enabled ? View.VISIBLE : View.INVISIBLE);
-            mProgressAnimation.setVisibility(enabled ? View.VISIBLE : View.INVISIBLE);
-        }
-    }
-
     private static List<AbstractPreferenceController> buildPreferenceControllers(
             Context context, Lifecycle lifecycle) {
         final List<AbstractPreferenceController> controllers = new ArrayList<>();
diff --git a/src/com/android/settings/slices/CustomSliceRegistry.java b/src/com/android/settings/slices/CustomSliceRegistry.java
index 946a9d3..42d81e9 100644
--- a/src/com/android/settings/slices/CustomSliceRegistry.java
+++ b/src/com/android/settings/slices/CustomSliceRegistry.java
@@ -37,6 +37,7 @@
 import com.android.settings.homepage.contextualcards.slices.BluetoothDevicesSlice;
 import com.android.settings.homepage.contextualcards.slices.ContextualAdaptiveSleepSlice;
 import com.android.settings.homepage.contextualcards.slices.ContextualNotificationChannelSlice;
+import com.android.settings.homepage.contextualcards.slices.DarkThemeSlice;
 import com.android.settings.homepage.contextualcards.slices.FaceSetupSlice;
 import com.android.settings.homepage.contextualcards.slices.LowStorageSlice;
 import com.android.settings.homepage.contextualcards.slices.NotificationChannelSlice;
@@ -342,6 +343,16 @@
             .appendPath("media_output_indicator")
             .build();
 
+    /**
+     * Backing Uri for the Dark theme Slice.
+     */
+    public static final Uri DARK_THEME_SLICE_URI = new Uri.Builder()
+            .scheme(ContentResolver.SCHEME_CONTENT)
+            .authority(SettingsSliceProvider.SLICE_AUTHORITY)
+            .appendPath(SettingsSlicesContract.PATH_SETTING_ACTION)
+            .appendPath("dark_theme")
+            .build();
+
     @VisibleForTesting
     static final Map<Uri, Class<? extends CustomSliceable>> sUriToSlice;
 
@@ -367,6 +378,7 @@
         sUriToSlice.put(NOTIFICATION_CHANNEL_SLICE_URI, NotificationChannelSlice.class);
         sUriToSlice.put(STORAGE_SLICE_URI, StorageSlice.class);
         sUriToSlice.put(WIFI_SLICE_URI, WifiSlice.class);
+        sUriToSlice.put(DARK_THEME_SLICE_URI, DarkThemeSlice.class);
     }
 
     public static Class<? extends CustomSliceable> getSliceClassByUri(Uri uri) {
diff --git a/src/com/android/settings/slices/CustomSliceable.java b/src/com/android/settings/slices/CustomSliceable.java
index 9566be1..92c604e 100644
--- a/src/com/android/settings/slices/CustomSliceable.java
+++ b/src/com/android/settings/slices/CustomSliceable.java
@@ -95,7 +95,7 @@
                 .setData(getUri())
                 .setClass(context, SliceBroadcastReceiver.class);
         return PendingIntent.getBroadcast(context, 0 /* requestCode */, intent,
-                PendingIntent.FLAG_CANCEL_CURRENT);
+                PendingIntent.FLAG_UPDATE_CURRENT);
     }
 
     @Override
diff --git a/src/com/android/settings/slices/SliceBuilderUtils.java b/src/com/android/settings/slices/SliceBuilderUtils.java
index b3ddc58..45da776 100644
--- a/src/com/android/settings/slices/SliceBuilderUtils.java
+++ b/src/com/android/settings/slices/SliceBuilderUtils.java
@@ -175,7 +175,7 @@
                 .putExtra(EXTRA_SLICE_KEY, data.getKey())
                 .putExtra(EXTRA_SLICE_PLATFORM_DEFINED, data.isPlatformDefined());
         return PendingIntent.getBroadcast(context, 0 /* requestCode */, intent,
-                PendingIntent.FLAG_CANCEL_CURRENT);
+                PendingIntent.FLAG_UPDATE_CURRENT);
     }
 
     /**
diff --git a/src/com/android/settings/wifi/NetworkRequestDialogFragment.java b/src/com/android/settings/wifi/NetworkRequestDialogFragment.java
index 4762403..ceda8a7 100644
--- a/src/com/android/settings/wifi/NetworkRequestDialogFragment.java
+++ b/src/com/android/settings/wifi/NetworkRequestDialogFragment.java
@@ -310,7 +310,7 @@
         mHandler.sendEmptyMessageDelayed(MESSAGE_STOP_SCAN_WIFI_LIST, DELAY_TIME_STOP_SCAN_MS);
 
         if (mFilterWifiTracker == null) {
-            mFilterWifiTracker = new FilterWifiTracker(getActivity(), getSettingsLifecycle());
+            mFilterWifiTracker = new FilterWifiTracker(getContext(), getSettingsLifecycle());
         }
         mFilterWifiTracker.onResume();
     }
@@ -476,11 +476,13 @@
     private final class FilterWifiTracker {
         private final List<String> mAccessPointKeys;
         private final WifiTracker mWifiTracker;
+        private final Context mContext;
 
         public FilterWifiTracker(Context context, Lifecycle lifecycle) {
             mWifiTracker = WifiTrackerFactory.create(context, mWifiListener,
                     lifecycle, /* includeSaved */ true, /* includeScans */ true);
             mAccessPointKeys = new ArrayList<>();
+            mContext = context;
         }
 
         /**
@@ -489,7 +491,7 @@
          */
         public void updateKeys(List<ScanResult> scanResults) {
             for (ScanResult scanResult : scanResults) {
-                final String key = AccessPoint.getKey(scanResult);
+                final String key = AccessPoint.getKey(mContext, scanResult);
                 if (!mAccessPointKeys.contains(key)) {
                     mAccessPointKeys.add(key);
                 }
diff --git a/src/com/android/settings/wifi/WifiConfigController.java b/src/com/android/settings/wifi/WifiConfigController.java
index 0aae89a..c924aaf 100644
--- a/src/com/android/settings/wifi/WifiConfigController.java
+++ b/src/com/android/settings/wifi/WifiConfigController.java
@@ -583,35 +583,6 @@
         }
     }
 
-    /**
-     * Special handling for WPA2/WPA3 and OWE in Transition mode: The key
-     * SECURITY_PSK_SAE_TRANSITION and SECURITY_OWE_TRANSITION are pseudo keys which result by the
-     * scan results, but never appears in the saved networks.
-     * A saved network is either WPA3 for supporting devices or WPA2 for non-supporting devices,
-     * or, OWE for supporting devices or Open for non-supporting devices.
-     *
-     * @param accessPointSecurity Access point current security type
-     * @return Converted security type (if required)
-     */
-    private int convertSecurityTypeForMatching(int accessPointSecurity) {
-        if (accessPointSecurity == AccessPoint.SECURITY_PSK_SAE_TRANSITION) {
-            if (mWifiManager.isWpa3SaeSupported()) {
-                return AccessPoint.SECURITY_SAE;
-            } else {
-                return AccessPoint.SECURITY_PSK;
-            }
-        }
-        if (accessPointSecurity == AccessPoint.SECURITY_OWE_TRANSITION) {
-            if (mWifiManager.isEnhancedOpenSupported()) {
-                return AccessPoint.SECURITY_OWE;
-            } else {
-                return AccessPoint.SECURITY_NONE;
-            }
-        }
-
-        return accessPointSecurity;
-    }
-
     public WifiConfiguration getConfig() {
         if (mMode == WifiConfigUiBase.MODE_VIEW) {
             return null;
@@ -634,8 +605,6 @@
 
         config.shared = mSharedCheckBox.isChecked();
 
-        mAccessPointSecurity = convertSecurityTypeForMatching(mAccessPointSecurity);
-
         switch (mAccessPointSecurity) {
             case AccessPoint.SECURITY_NONE:
                 config.allowedKeyManagement.set(KeyMgmt.NONE);
@@ -960,8 +929,7 @@
 
     private void showSecurityFields(boolean refreshEapMethods, boolean refreshCertificates) {
         if (mAccessPointSecurity == AccessPoint.SECURITY_NONE ||
-                mAccessPointSecurity == AccessPoint.SECURITY_OWE ||
-                mAccessPointSecurity == AccessPoint.SECURITY_OWE_TRANSITION) {
+                mAccessPointSecurity == AccessPoint.SECURITY_OWE) {
             mView.findViewById(R.id.security_fields).setVisibility(View.GONE);
             return;
         }
diff --git a/src/com/android/settings/wifi/WifiSettings.java b/src/com/android/settings/wifi/WifiSettings.java
index 8c4bfa2..4d3f230 100644
--- a/src/com/android/settings/wifi/WifiSettings.java
+++ b/src/com/android/settings/wifi/WifiSettings.java
@@ -494,9 +494,7 @@
                 if (isSavedNetwork) {
                     connect(mSelectedAccessPoint.getConfig(), isSavedNetwork);
                 } else if ((mSelectedAccessPoint.getSecurity() == AccessPoint.SECURITY_NONE) ||
-                        (mSelectedAccessPoint.getSecurity() == AccessPoint.SECURITY_OWE) ||
-                        (mSelectedAccessPoint.getSecurity()
-                                == AccessPoint.SECURITY_OWE_TRANSITION)) {
+                        (mSelectedAccessPoint.getSecurity() == AccessPoint.SECURITY_OWE)) {
                     /** Bypass dialog for unsecured networks */
                     mSelectedAccessPoint.generateOpenNetworkConfig();
                     connect(mSelectedAccessPoint.getConfig(), isSavedNetwork);
@@ -750,8 +748,7 @@
                 preference.setOrder(index);
                 if (mOpenSsid != null && mOpenSsid.equals(accessPoint.getSsidStr())
                         && (accessPoint.getSecurity() != AccessPoint.SECURITY_NONE &&
-                        accessPoint.getSecurity() != AccessPoint.SECURITY_OWE &&
-                        accessPoint.getSecurity() != AccessPoint.SECURITY_OWE_TRANSITION)) {
+                        accessPoint.getSecurity() != AccessPoint.SECURITY_OWE)) {
                     if (!accessPoint.isSaved() || isDisabledByWrongPassword(accessPoint)) {
                         onPreferenceTreeClick(preference);
                         mOpenSsid = null;
diff --git a/src/com/android/settings/wifi/WifiUtils.java b/src/com/android/settings/wifi/WifiUtils.java
index c4df567..9b3c1b3 100644
--- a/src/com/android/settings/wifi/WifiUtils.java
+++ b/src/com/android/settings/wifi/WifiUtils.java
@@ -268,8 +268,7 @@
         if (accessPoint.isOsuProvider()) {
             return CONNECT_TYPE_OSU_PROVISION;
         } else if ((accessPoint.getSecurity() == AccessPoint.SECURITY_NONE) ||
-                (accessPoint.getSecurity() == AccessPoint.SECURITY_OWE) ||
-                (accessPoint.getSecurity() == AccessPoint.SECURITY_OWE_TRANSITION)) {
+                (accessPoint.getSecurity() == AccessPoint.SECURITY_OWE)) {
             return CONNECT_TYPE_OPEN_NETWORK;
         } else if (accessPoint.isSaved() && config != null
                 && config.getNetworkSelectionStatus() != null
diff --git a/src/com/android/settings/wifi/dpp/WifiDppUtils.java b/src/com/android/settings/wifi/dpp/WifiDppUtils.java
index 2a958e8..fc1bc25 100644
--- a/src/com/android/settings/wifi/dpp/WifiDppUtils.java
+++ b/src/com/android/settings/wifi/dpp/WifiDppUtils.java
@@ -206,7 +206,7 @@
         setConfiguratorIntentExtra(intent, wifiManager, wifiConfiguration);
 
         // For a transition mode Wi-Fi AP, creates a QR code that's compatible with more devices
-        if (accessPoint.getSecurity() == AccessPoint.SECURITY_PSK_SAE_TRANSITION) {
+        if (accessPoint.isPskSaeTransitionMode()) {
             intent.putExtra(EXTRA_WIFI_SECURITY, WifiQrCode.SECURITY_WPA_PSK);
         }
 
@@ -406,7 +406,6 @@
                 }
                 break;
             case AccessPoint.SECURITY_PSK:
-            case AccessPoint.SECURITY_PSK_SAE_TRANSITION:
                 return true;
             default:
         }
@@ -419,8 +418,6 @@
             case AccessPoint.SECURITY_PSK:
             case AccessPoint.SECURITY_WEP:
             case AccessPoint.SECURITY_NONE:
-            case AccessPoint.SECURITY_PSK_SAE_TRANSITION:
-            case AccessPoint.SECURITY_OWE_TRANSITION:
                 return true;
             case AccessPoint.SECURITY_SAE:
                 if (wifiManager.isWpa3SaeSupported()) {
diff --git a/tests/robotests/src/com/android/settings/display/DarkUIPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/display/DarkUIPreferenceControllerTest.java
index 3659803..9924cb4 100644
--- a/tests/robotests/src/com/android/settings/display/DarkUIPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/display/DarkUIPreferenceControllerTest.java
@@ -16,25 +16,9 @@
 
 package com.android.settings.display;
 
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.mockito.Mockito.doReturn;
-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.content.Context;
-import android.os.Handler;
-import android.os.IPowerManager;
-import android.os.PowerManager;
-
 import androidx.fragment.app.Fragment;
-import androidx.preference.PreferenceScreen;
-import androidx.preference.SwitchPreference;
-
-import org.junit.Assert;
+import com.android.settings.display.darkmode.DarkModePreference;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -43,6 +27,10 @@
 import org.robolectric.RobolectricTestRunner;
 import org.robolectric.RuntimeEnvironment;
 
+import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.spy;
+
 @RunWith(RobolectricTestRunner.class)
 public class DarkUIPreferenceControllerTest {
 
@@ -57,7 +45,7 @@
         mContext = spy(RuntimeEnvironment.application);
         mController = spy(new DarkUIPreferenceController(mContext, "dark_ui_mode"));
         mController.setParentFragment(mFragment);
-        mController.mPreference = new SwitchPreference(mContext);
+        mController.mPreference = new DarkModePreference(mContext, null /* AttributeSet attrs */);
         mController.onStart();
     }
 
diff --git a/tests/robotests/src/com/android/settings/display/darkmode/DarkModeActivationPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/display/darkmode/DarkModeActivationPreferenceControllerTest.java
new file mode 100644
index 0000000..cd20ea2
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/display/darkmode/DarkModeActivationPreferenceControllerTest.java
@@ -0,0 +1,167 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+package com.android.settings.display.darkmode;
+
+import android.app.UiModeManager;
+import android.content.Context;
+import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.os.PowerManager;
+import android.view.View;
+import android.widget.Button;
+import androidx.preference.PreferenceScreen;
+import com.android.settings.R;
+import com.android.settingslib.widget.LayoutPreference;
+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 static org.junit.Assert.assertEquals;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import static org.mockito.Mockito.eq;
+
+@RunWith(RobolectricTestRunner.class)
+public class DarkModeActivationPreferenceControllerTest {
+    private DarkModeActivationPreferenceController mController;
+    private String mPreferenceKey = "key";
+    @Mock
+    private LayoutPreference mPreference;
+    @Mock
+    private PreferenceScreen mScreen;
+    @Mock
+    private Resources res;
+    @Mock
+    private Context mContext;
+    @Mock
+    private UiModeManager mService;
+    @Mock
+    private Button mTurnOffButton;
+    @Mock
+    private Button mTurnOnButton;
+    @Mock
+    private PowerManager mPM;
+
+    private Configuration configNightYes = new Configuration();
+    private Configuration configNightNo = new Configuration();;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        mService = mock(UiModeManager.class);
+        when(mContext.getResources()).thenReturn(res);
+        when(mContext.getSystemService(UiModeManager.class)).thenReturn(mService);
+        when(mContext.getSystemService(PowerManager.class)).thenReturn(mPM);
+        when(mScreen.findPreference(anyString())).thenReturn(mPreference);
+        when(mPreference.findViewById(
+                eq(R.id.dark_ui_turn_on_button))).thenReturn(mTurnOnButton);
+        when(mPreference.findViewById(
+                eq(R.id.dark_ui_turn_off_button))).thenReturn(mTurnOffButton);
+        when(mService.setNightModeActivated(anyBoolean())).thenReturn(true);
+        when(mContext.getString(
+                R.string.dark_ui_activation_off_auto)).thenReturn("off_auto");
+        when(mContext.getString(
+                R.string.dark_ui_activation_on_auto)).thenReturn("on_auto");
+        when(mContext.getString(
+                R.string.dark_ui_activation_off_manual)).thenReturn("off_manual");
+        when(mContext.getString(
+                R.string.dark_ui_activation_on_manual)).thenReturn("on_manual");
+        when(mContext.getString(
+                R.string.dark_ui_summary_off_auto_mode_auto)).thenReturn("summary_off_auto");
+        when(mContext.getString(
+                R.string.dark_ui_summary_on_auto_mode_auto)).thenReturn("summary_on_auto");
+        when(mContext.getString(
+                R.string.dark_ui_summary_off_auto_mode_never)).thenReturn("summary_off_manual");
+        when(mContext.getString(
+                R.string.dark_ui_summary_on_auto_mode_never)).thenReturn("summary_on_manual");
+        mController = new DarkModeActivationPreferenceController(mContext, mPreferenceKey);
+        mController.displayPreference(mScreen);
+        configNightNo.uiMode = Configuration.UI_MODE_NIGHT_NO;
+        configNightYes.uiMode = Configuration.UI_MODE_NIGHT_YES;
+    }
+
+    @Test
+    public void nightMode_toggleButton_offManual() {
+        when(mService.getNightMode()).thenReturn(UiModeManager.MODE_NIGHT_YES);
+        when(res.getConfiguration()).thenReturn(configNightYes);
+
+        mController.updateState(mPreference);
+
+        verify(mTurnOnButton).setVisibility(eq(View.GONE));
+        verify(mTurnOffButton).setVisibility(eq(View.VISIBLE));
+        verify(mTurnOffButton).setText(eq(mContext.getString(
+                R.string.dark_ui_activation_off_manual)));
+    }
+
+
+    @Test
+    public void nightMode_toggleButton_onAutoWhenModeIsYes() {
+        when(mService.getNightMode()).thenReturn(UiModeManager.MODE_NIGHT_YES);
+        when(res.getConfiguration()).thenReturn(configNightNo);
+
+        mController.updateState(mPreference);
+
+        verify(mTurnOffButton).setVisibility(eq(View.GONE));
+        verify(mTurnOnButton).setVisibility(eq(View.VISIBLE));
+        verify(mTurnOnButton).setText(eq(mContext.getString(
+                R.string.dark_ui_activation_on_manual)));
+    }
+
+    @Test
+    public void nightMode_toggleButton_onAutoWhenModeIsAuto() {
+        when(mService.getNightMode()).thenReturn(UiModeManager.MODE_NIGHT_AUTO);
+        when(res.getConfiguration()).thenReturn(configNightNo);
+
+        mController.updateState(mPreference);
+
+        verify(mTurnOffButton).setVisibility(eq(View.GONE));
+        verify(mTurnOnButton).setVisibility(eq(View.VISIBLE));
+        verify(mTurnOnButton).setText(eq(mContext.getString(
+                R.string.dark_ui_activation_on_auto)));
+    }
+
+    @Test
+    public void nightModeSummary_buttonText_onManual() {
+        when(mService.getNightMode()).thenReturn(UiModeManager.MODE_NIGHT_NO);
+        when(res.getConfiguration()).thenReturn(configNightYes);
+
+        assertEquals(mController.getSummary(), mContext.getString(
+                R.string.dark_ui_summary_on_auto_mode_never));
+    }
+
+    @Test
+    public void nightModeSummary_buttonText_offAuto() {
+        when(mService.getNightMode()).thenReturn(UiModeManager.MODE_NIGHT_AUTO);
+        when(res.getConfiguration()).thenReturn(configNightNo);
+
+        assertEquals(mController.getSummary(), mContext.getString(
+                R.string.dark_ui_summary_off_auto_mode_auto));
+    }
+
+    @Test
+    public void buttonVisisbility_hideButton_offWhenInPowerSaveMode() {
+        when(mPM.isPowerSaveMode()).thenReturn(true);
+        mController.updateState(mPreference);
+        verify(mTurnOffButton).setVisibility(eq(View.GONE));
+        verify(mTurnOnButton).setVisibility(eq(View.GONE));
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/display/darkmode/DarkModeObserverTest.java b/tests/robotests/src/com/android/settings/display/darkmode/DarkModeObserverTest.java
new file mode 100644
index 0000000..dfa8ba1
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/display/darkmode/DarkModeObserverTest.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+package com.android.settings.display.darkmode;
+
+import android.content.Context;
+import android.database.ContentObserver;
+import android.net.Uri;
+import android.provider.Settings;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
+
+
+@RunWith(RobolectricTestRunner.class)
+public class DarkModeObserverTest {
+    private Context mContext;
+    private ContentObserver mContentObserver;
+    private DarkModeObserver mDarkModeObserver;
+    private Runnable mCallback;
+    private Uri mUri = Settings.Secure.getUriFor(Settings.Secure.UI_NIGHT_MODE);
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        mContext = spy(RuntimeEnvironment.application);
+        mDarkModeObserver = new DarkModeObserver(mContext);
+        mContentObserver = mDarkModeObserver.getContentObserver();
+        mCallback = mock(Runnable.class);
+    }
+
+    @Test
+    public void callbackTest_subscribedCallbackCalled() {
+        mDarkModeObserver.subscribe(mCallback);
+        mContentObserver.onChange(false, mUri);
+        Mockito.verify(mCallback, times(2)).run();
+    }
+
+    @Test
+    public void callbackTest_unsubscribedCallNotbackCalled() {
+        mDarkModeObserver.subscribe(mCallback);
+        mContentObserver.onChange(false, mUri);
+        mDarkModeObserver.unsubscribe();
+        mContentObserver.onChange(false, mUri);
+        Mockito.verify(mCallback, times(2)).run();
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/display/darkmode/DarkModeScheduleSelectorControllerTest.java b/tests/robotests/src/com/android/settings/display/darkmode/DarkModeScheduleSelectorControllerTest.java
new file mode 100644
index 0000000..53be42c
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/display/darkmode/DarkModeScheduleSelectorControllerTest.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+package com.android.settings.display.darkmode;
+
+import android.app.UiModeManager;
+import android.content.Context;
+import android.os.PowerManager;
+import androidx.preference.DropDownPreference;
+import androidx.preference.PreferenceScreen;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+import com.android.settings.R;
+
+import static junit.framework.TestCase.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+@RunWith(RobolectricTestRunner.class)
+public class DarkModeScheduleSelectorControllerTest {
+    private DarkModeScheduleSelectorController mController;
+    private String mPreferenceKey = "key";
+    @Mock
+    private DropDownPreference mPreference;
+    @Mock
+    private PreferenceScreen mScreen;
+    private Context mContext;
+    @Mock
+    private UiModeManager mUiService;
+    @Mock
+    private PowerManager mPM;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        mContext = spy(RuntimeEnvironment.application);
+        when(mContext.getSystemService(UiModeManager.class)).thenReturn(mUiService);
+        when(mContext.getSystemService(PowerManager.class)).thenReturn(mPM);
+        when(mContext.getString(R.string.dark_ui_auto_mode_never)).thenReturn("never");
+        when(mContext.getString(R.string.dark_ui_auto_mode_auto)).thenReturn("auto");
+        mPreference = spy(new DropDownPreference(mContext));
+        when(mScreen.findPreference(anyString())).thenReturn(mPreference);
+        when(mUiService.setNightModeActivated(anyBoolean())).thenReturn(true);
+        mController = new DarkModeScheduleSelectorController(mContext, mPreferenceKey);
+    }
+
+    @Test
+    public void nightMode_preferenceChange_preferenceChangeTrueWhenChangedOnly() {
+        when(mUiService.getNightMode()).thenReturn(UiModeManager.MODE_NIGHT_YES);
+        mController.displayPreference(mScreen);
+        boolean changed = mController
+                .onPreferenceChange(mScreen, mContext.getString(R.string.dark_ui_auto_mode_auto));
+        assertTrue(changed);
+        changed = mController
+                .onPreferenceChange(mScreen, mContext.getString(R.string.dark_ui_auto_mode_auto));
+        assertFalse(changed);
+    }
+
+    @Test
+    public void nightMode_updateStateNone_dropDownValueChangedToNone() {
+        when(mUiService.getNightMode()).thenReturn(UiModeManager.MODE_NIGHT_YES);
+        mController.displayPreference(mScreen);
+        mController.updateState(mPreference);
+        verify(mPreference).setValue(mContext.getString(R.string.dark_ui_auto_mode_never));
+    }
+
+    @Test
+    public void nightMode_updateStateNone_dropDownValueChangedToAuto() {
+        when(mUiService.getNightMode()).thenReturn(UiModeManager.MODE_NIGHT_AUTO);
+        mController.displayPreference(mScreen);
+        mController.updateState(mPreference);
+        verify(mPreference).setValue(mContext.getString(R.string.dark_ui_auto_mode_auto));
+    }
+
+    @Test
+    public void batterySaver_dropDown_disabledSelector() {
+        when(mPM.isPowerSaveMode()).thenReturn(true);
+        mController.displayPreference(mScreen);
+        mController.updateState(mPreference);
+        verify(mPreference).setEnabled(eq(false));
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/BatteryHeaderPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/fuelgauge/BatteryHeaderPreferenceControllerTest.java
index 5be7274..63e8a80 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/BatteryHeaderPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/BatteryHeaderPreferenceControllerTest.java
@@ -85,7 +85,6 @@
     private BatteryMeterView mBatteryMeterView;
     private TextView mBatteryPercentText;
     private TextView mSummary;
-    private TextView mSummary2;
     private LayoutPreference mBatteryLayoutPref;
     private Intent mBatteryIntent;
     private LifecycleOwner mLifecycleOwner;
@@ -102,7 +101,6 @@
         mBatteryPercentText = new TextView(mContext);
         mSummary = new TextView(mContext);
         ShadowEntityHeaderController.setUseMock(mEntityHeaderController);
-        mSummary2 = new TextView(mContext);
 
         mBatteryIntent = new Intent();
         mBatteryIntent.putExtra(BatteryManager.EXTRA_LEVEL, BATTERY_LEVEL);
@@ -126,7 +124,6 @@
         mController.mBatteryMeterView = mBatteryMeterView;
         mController.mBatteryPercentText = mBatteryPercentText;
         mController.mSummary1 = mSummary;
-        mController.mSummary2 = mSummary2;
     }
 
     @After
@@ -190,7 +187,6 @@
     @Test
     public void quickUpdateHeaderPreference_onlyUpdateBatteryLevelAndChargingState() {
         mSummary.setText(BATTERY_STATUS);
-        mSummary2.setText(BATTERY_STATUS);
 
         mController.quickUpdateHeaderPreference();
 
@@ -198,7 +194,6 @@
         assertThat(mBatteryMeterView.getCharging()).isTrue();
         assertThat(mBatteryPercentText.getText().toString()).isEqualTo("60 %");
         assertThat(mSummary.getText()).isEqualTo(BATTERY_STATUS);
-        assertThat(mSummary2.getText()).isEqualTo(BATTERY_STATUS);
     }
 
     @Test
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageSummaryTest.java b/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageSummaryTest.java
index 4d77bdd..7839e1a 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageSummaryTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageSummaryTest.java
@@ -265,20 +265,17 @@
             }
         }).when(mFeatureFactory.powerUsageFeatureProvider).getEnhancedEstimateDebugString(any());
 
-        doReturn(new TextView(mRealContext)).when(mBatteryLayoutPref).findViewById(R.id.summary2);
         doReturn(new TextView(mRealContext)).when(mBatteryLayoutPref).findViewById(R.id.summary1);
         mFragment.onLongClick(new View(mRealContext));
         TextView summary1 = mFragment.mBatteryLayoutPref.findViewById(R.id.summary1);
-        TextView summary2 = mFragment.mBatteryLayoutPref.findViewById(R.id.summary2);
         Robolectric.flushBackgroundThreadScheduler();
-        assertThat(summary2.getText().toString()).contains(NEW_ML_EST_SUFFIX);
+        assertThat(summary1.getText().toString()).contains(NEW_ML_EST_SUFFIX);
         assertThat(summary1.getText().toString()).contains(OLD_EST_SUFFIX);
     }
 
     @Test
     public void debugMode() {
         doReturn(true).when(mFeatureFactory.powerUsageFeatureProvider).isEstimateDebugEnabled();
-        doReturn(new TextView(mRealContext)).when(mBatteryLayoutPref).findViewById(R.id.summary2);
 
         mFragment.restartBatteryInfoLoader();
         ArgumentCaptor<View.OnLongClickListener> listener = ArgumentCaptor.forClass(
diff --git a/tests/robotests/src/com/android/settings/homepage/SettingsHomepageActivityTest.java b/tests/robotests/src/com/android/settings/homepage/SettingsHomepageActivityTest.java
index dcb32c4..db12580 100644
--- a/tests/robotests/src/com/android/settings/homepage/SettingsHomepageActivityTest.java
+++ b/tests/robotests/src/com/android/settings/homepage/SettingsHomepageActivityTest.java
@@ -16,20 +16,42 @@
 
 package com.android.settings.homepage;
 
+import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS;
+
 import static com.google.common.truth.Truth.assertThat;
 
+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.os.Build;
 import android.view.View;
+import android.view.Window;
+import android.view.WindowManager;
 import android.widget.FrameLayout;
 
 import com.android.settings.R;
+import com.android.settings.core.HideNonSystemOverlayMixin;
+import com.android.settings.homepage.contextualcards.slices.BatteryFixSliceTest;
 
+import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.MockitoAnnotations;
 import org.robolectric.Robolectric;
 import org.robolectric.RobolectricTestRunner;
+import org.robolectric.android.controller.ActivityController;
+import org.robolectric.annotation.Config;
+import org.robolectric.util.ReflectionHelpers;
 
 @RunWith(RobolectricTestRunner.class)
 public class SettingsHomepageActivityTest {
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+    }
 
     @Test
     public void setHomepageContainerPaddingTop_shouldBeSetPaddingTop() {
@@ -55,4 +77,55 @@
 
         assertThat(frameLayout.getLayoutTransition()).isNotNull();
     }
+
+    @Test
+    @Config(shadows = {
+            BatteryFixSliceTest.ShadowBatteryStatsHelperLoader.class,
+            BatteryFixSliceTest.ShadowBatteryTipLoader.class
+    })
+    public void onStart_isNotDebuggable_shouldHideSystemOverlay() {
+        ReflectionHelpers.setStaticField(Build.class, "IS_DEBUGGABLE", false);
+
+        final ActivityController<SettingsHomepageActivity> activityController =
+                Robolectric.buildActivity(SettingsHomepageActivity.class).create();
+        final SettingsHomepageActivity activity = spy(activityController.get());
+        final Window window = mock(Window.class);
+        when(activity.getWindow()).thenReturn(window);
+        activity.getLifecycle().addObserver(new HideNonSystemOverlayMixin(activity));
+
+        activityController.start();
+
+        verify(window).addSystemFlags(SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS);
+    }
+
+    @Test
+    @Config(shadows = {
+            BatteryFixSliceTest.ShadowBatteryStatsHelperLoader.class,
+            BatteryFixSliceTest.ShadowBatteryTipLoader.class,
+    })
+    public void onStop_isNotDebuggable_shouldRemoveHideSystemOverlay() {
+        ReflectionHelpers.setStaticField(Build.class, "IS_DEBUGGABLE", false);
+
+        final ActivityController<SettingsHomepageActivity> activityController =
+                Robolectric.buildActivity(SettingsHomepageActivity.class).create();
+        final SettingsHomepageActivity activity = spy(activityController.get());
+        final Window window = mock(Window.class);
+        when(activity.getWindow()).thenReturn(window);
+        activity.getLifecycle().addObserver(new HideNonSystemOverlayMixin(activity));
+
+        activityController.start();
+
+        verify(window).addSystemFlags(SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS);
+
+        final WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams();
+        when(window.getAttributes()).thenReturn(layoutParams);
+
+        activityController.stop();
+        final ArgumentCaptor<WindowManager.LayoutParams> paramCaptor = ArgumentCaptor.forClass(
+                WindowManager.LayoutParams.class);
+
+        verify(window).setAttributes(paramCaptor.capture());
+        assertThat(paramCaptor.getValue().privateFlags
+                & SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS).isEqualTo(0);
+    }
 }
diff --git a/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/DarkThemeSliceTest.java b/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/DarkThemeSliceTest.java
new file mode 100644
index 0000000..1af7b2b
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/DarkThemeSliceTest.java
@@ -0,0 +1,171 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.homepage.contextualcards.slices;
+
+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.net.Uri;
+import android.os.BatteryManager;
+import android.os.PowerManager;
+
+import androidx.slice.Slice;
+import androidx.slice.SliceMetadata;
+import androidx.slice.SliceProvider;
+import androidx.slice.widget.SliceLiveData;
+
+import com.android.settings.R;
+import com.android.settings.slices.CustomSliceRegistry;
+import com.android.settings.slices.SlicesFeatureProviderImpl;
+import com.android.settings.testutils.FakeFeatureFactory;
+
+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 DarkThemeSliceTest {
+    @Mock
+    private BatteryManager mBatteryManager;
+    @Mock
+    private PowerManager mPowerManager;
+
+    private Context mContext;
+    private DarkThemeSlice mDarkThemeSlice;
+    private FakeFeatureFactory mFeatureFactory;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        mContext = spy(RuntimeEnvironment.application);
+        mFeatureFactory = FakeFeatureFactory.setupForTest();
+        mFeatureFactory.slicesFeatureProvider = new SlicesFeatureProviderImpl();
+        mFeatureFactory.slicesFeatureProvider.newUiSession();
+        doReturn(mPowerManager).when(mContext).getSystemService(PowerManager.class);
+        when(mPowerManager.isPowerSaveMode()).thenReturn(false);
+
+        // Set-up specs for SliceMetadata.
+        SliceProvider.setSpecs(SliceLiveData.SUPPORTED_SPECS);
+        mDarkThemeSlice = spy(new DarkThemeSlice(mContext));
+        mDarkThemeSlice.sKeepSliceShow = false;
+    }
+
+    @Test
+    public void getUri_shouldBeDarkThemeSliceUri() {
+        final Uri uri = mDarkThemeSlice.getUri();
+
+        assertThat(uri).isEqualTo(CustomSliceRegistry.DARK_THEME_SLICE_URI);
+    }
+
+    @Test
+    public void isAvailable_inDarkThemeMode_returnFalse() {
+        doReturn(true).when(mDarkThemeSlice).isDarkThemeMode(mContext);
+
+        assertThat(mDarkThemeSlice.isAvailable(mContext)).isFalse();
+    }
+
+    @Test
+    public void isAvailable_nonDarkThemeBatteryCapacityEq100_returnFalse() {
+        setBatteryCapacityLevel(100);
+
+        assertThat(mDarkThemeSlice.isAvailable(mContext)).isFalse();
+    }
+
+    @Test
+    public void isAvailable_nonDarkThemeBatteryCapacityLt50_returnTrue() {
+        setBatteryCapacityLevel(40);
+
+        assertThat(mDarkThemeSlice.isAvailable(mContext)).isTrue();
+    }
+
+    @Test
+    public void getSlice_batterySaver_returnErrorSlice() {
+        when(mPowerManager.isPowerSaveMode()).thenReturn(true);
+
+        final Slice mediaSlice = mDarkThemeSlice.getSlice();
+        final SliceMetadata metadata = SliceMetadata.from(mContext, mediaSlice);
+        assertThat(metadata.isErrorSlice()).isTrue();
+    }
+
+    @Test
+    public void getSlice_notAvailable_returnErrorSlice() {
+        doReturn(true).when(mDarkThemeSlice).isDarkThemeMode(mContext);
+
+        final Slice mediaSlice = mDarkThemeSlice.getSlice();
+        final SliceMetadata metadata = SliceMetadata.from(mContext, mediaSlice);
+        assertThat(metadata.isErrorSlice()).isTrue();
+    }
+
+    @Test
+    public void getSlice_newSession_notAvailable_returnErrorSlice() {
+        // previous displayed: yes
+        mDarkThemeSlice.sKeepSliceShow = true;
+        // Session: use original value + 1 to become a new session
+        mDarkThemeSlice.sActiveUiSession =
+                mFeatureFactory.slicesFeatureProvider.getUiSessionToken() + 1;
+
+        doReturn(true).when(mDarkThemeSlice).isDarkThemeMode(mContext);
+
+        final Slice mediaSlice = mDarkThemeSlice.getSlice();
+        final SliceMetadata metadata = SliceMetadata.from(mContext, mediaSlice);
+        assertThat(metadata.isErrorSlice()).isTrue();
+    }
+
+    @Test
+    public void getSlice_previouslyDisplayed_isAvailable_returnSlice() {
+        mDarkThemeSlice.sActiveUiSession =
+                mFeatureFactory.slicesFeatureProvider.getUiSessionToken();
+        mDarkThemeSlice.sKeepSliceShow = true;
+        setBatteryCapacityLevel(40);
+
+        assertThat(mDarkThemeSlice.getSlice()).isNotNull();
+    }
+
+    @Test
+    public void getSlice_isAvailable_returnSlice() {
+        setBatteryCapacityLevel(40);
+
+        assertThat(mDarkThemeSlice.getSlice()).isNotNull();
+    }
+
+    @Test
+    public void getSlice_isAvailable_showTitleSubtitle() {
+        setBatteryCapacityLevel(40);
+
+        final Slice slice = mDarkThemeSlice.getSlice();
+        final SliceMetadata metadata = SliceMetadata.from(mContext, slice);
+        assertThat(metadata.getTitle()).isEqualTo(
+                mContext.getString(R.string.dark_theme_slice_title));
+        assertThat(metadata.getSubtitle()).isEqualTo(
+                mContext.getString(R.string.dark_theme_slice_subtitle));
+    }
+
+    private void setBatteryCapacityLevel(int power_level) {
+        doReturn(false).when(mDarkThemeSlice).isDarkThemeMode(mContext);
+        doReturn(mBatteryManager).when(mContext).getSystemService(BatteryManager.class);
+        when(mBatteryManager.getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY))
+                .thenReturn(power_level);
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/panel/SettingsPanelActivityTest.java b/tests/robotests/src/com/android/settings/panel/SettingsPanelActivityTest.java
index 8ad2156..a4b7aa5 100644
--- a/tests/robotests/src/com/android/settings/panel/SettingsPanelActivityTest.java
+++ b/tests/robotests/src/com/android/settings/panel/SettingsPanelActivityTest.java
@@ -16,6 +16,8 @@
 
 package com.android.settings.panel;
 
+import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS;
+
 import static com.android.settings.panel.SettingsPanelActivity.KEY_MEDIA_PACKAGE_NAME;
 import static com.android.settings.panel.SettingsPanelActivity.KEY_PANEL_TYPE_ARGUMENT;
 
@@ -28,17 +30,23 @@
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
-import android.app.settings.SettingsEnums;
 import android.content.Intent;
-import android.view.MotionEvent;
+import android.os.Build;
+import android.view.Window;
+import android.view.WindowManager;
 
+import com.android.settings.core.HideNonSystemOverlayMixin;
 import com.android.settings.testutils.FakeFeatureFactory;
 
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.MockitoAnnotations;
 import org.robolectric.Robolectric;
 import org.robolectric.RobolectricTestRunner;
+import org.robolectric.android.controller.ActivityController;
+import org.robolectric.util.ReflectionHelpers;
 
 @RunWith(RobolectricTestRunner.class)
 public class SettingsPanelActivityTest {
@@ -50,6 +58,7 @@
 
     @Before
     public void setUp() {
+        MockitoAnnotations.initMocks(this);
         mFakeFeatureFactory = FakeFeatureFactory.setupForTest();
         mSettingsPanelActivity = spy(
                 Robolectric.buildActivity(FakeSettingsPanelActivity.class).create().get());
@@ -87,4 +96,47 @@
         assertThat(activity.mBundle.getString(KEY_PANEL_TYPE_ARGUMENT))
                 .isEqualTo("com.android.settings.panel.action.MEDIA_OUTPUT");
     }
+
+    @Test
+    public void onStart_isNotDebuggable_shouldHideSystemOverlay() {
+        ReflectionHelpers.setStaticField(Build.class, "IS_DEBUGGABLE", false);
+
+        final ActivityController<SettingsPanelActivity> activityController =
+                Robolectric.buildActivity(SettingsPanelActivity.class).create();
+        final SettingsPanelActivity activity = spy(activityController.get());
+        final Window window = mock(Window.class);
+        when(activity.getWindow()).thenReturn(window);
+        activity.getLifecycle().addObserver(new HideNonSystemOverlayMixin(activity));
+
+        activityController.start();
+
+        verify(window).addSystemFlags(SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS);
+    }
+
+    @Test
+    public void onStop_isNotDebuggable_shouldRemoveHideSystemOverlay() {
+        ReflectionHelpers.setStaticField(Build.class, "IS_DEBUGGABLE", false);
+
+        final ActivityController<SettingsPanelActivity> activityController =
+                Robolectric.buildActivity(SettingsPanelActivity.class).create();
+        final SettingsPanelActivity activity = spy(activityController.get());
+        final Window window = mock(Window.class);
+        when(activity.getWindow()).thenReturn(window);
+        activity.getLifecycle().addObserver(new HideNonSystemOverlayMixin(activity));
+
+        activityController.start();
+
+        verify(window).addSystemFlags(SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS);
+
+        final WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams();
+        when(window.getAttributes()).thenReturn(layoutParams);
+
+        activityController.stop();
+        final ArgumentCaptor<WindowManager.LayoutParams> paramCaptor = ArgumentCaptor.forClass(
+                WindowManager.LayoutParams.class);
+
+        verify(window).setAttributes(paramCaptor.capture());
+        assertThat(paramCaptor.getValue().privateFlags
+                & SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS).isEqualTo(0);
+    }
 }
diff --git a/tests/robotests/src/com/android/settings/privacy/PermissionBarChartPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/privacy/PermissionBarChartPreferenceControllerTest.java
deleted file mode 100644
index 1335db5..0000000
--- a/tests/robotests/src/com/android/settings/privacy/PermissionBarChartPreferenceControllerTest.java
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.settings.privacy;
-
-import static android.Manifest.permission_group.CALENDAR;
-import static android.Manifest.permission_group.CAMERA;
-import static android.Manifest.permission_group.CONTACTS;
-import static android.Manifest.permission_group.LOCATION;
-import static android.Manifest.permission_group.MICROPHONE;
-import static android.Manifest.permission_group.PHONE;
-import static android.Manifest.permission_group.SMS;
-
-import static com.android.settings.core.BasePreferenceController.AVAILABLE_UNSEARCHABLE;
-import static com.android.settings.core.BasePreferenceController.UNSUPPORTED_ON_DEVICE;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.Mockito.never;
-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.content.Context;
-import android.content.pm.UserInfo;
-import android.os.UserManager;
-import android.permission.RuntimePermissionUsageInfo;
-import android.provider.DeviceConfig;
-import android.view.accessibility.AccessibilityManager;
-
-import androidx.preference.PreferenceScreen;
-
-import com.android.internal.widget.LockPatternUtils;
-import com.android.settings.Utils;
-import com.android.settings.testutils.FakeFeatureFactory;
-import com.android.settings.testutils.shadow.ShadowDeviceConfig;
-import com.android.settings.testutils.shadow.ShadowPermissionControllerManager;
-import com.android.settings.testutils.shadow.ShadowUserManager;
-import com.android.settingslib.widget.BarChartInfo;
-import com.android.settingslib.widget.BarChartPreference;
-import com.android.settingslib.widget.BarViewInfo;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-import org.robolectric.RobolectricTestRunner;
-import org.robolectric.RuntimeEnvironment;
-import org.robolectric.annotation.Config;
-import org.robolectric.shadow.api.Shadow;
-import org.robolectric.shadows.ShadowAccessibilityManager;
-import org.robolectric.shadows.androidx.fragment.FragmentController;
-
-import java.util.ArrayList;
-import java.util.List;
-
-@RunWith(RobolectricTestRunner.class)
-@Config(shadows = {ShadowDeviceConfig.class, ShadowUserManager.class,
-        ShadowPermissionControllerManager.class})
-public class PermissionBarChartPreferenceControllerTest {
-
-    @Mock
-    private PreferenceScreen mScreen;
-    @Mock
-    private LockPatternUtils mLockPatternUtils;
-
-    private PermissionBarChartPreferenceController mController;
-    private BarChartPreference mPreference;
-    private PrivacyDashboardFragment mFragment;
-
-    @Before
-    public void setUp() {
-        MockitoAnnotations.initMocks(this);
-        final Context context = RuntimeEnvironment.application;
-        final UserManager userManager = context.getSystemService(UserManager.class);
-        final ShadowUserManager shadowUserManager = Shadow.extract(userManager);
-        final ShadowAccessibilityManager accessibilityManager = Shadow.extract(
-                AccessibilityManager.getInstance(context));
-        accessibilityManager.setEnabledAccessibilityServiceList(new ArrayList<>());
-        shadowUserManager.addProfile(new UserInfo(123, null, 0));
-        when(FakeFeatureFactory.setupForTest().securityFeatureProvider.getLockPatternUtils(
-                any(Context.class))).thenReturn(mLockPatternUtils);
-
-        mController = spy(new PermissionBarChartPreferenceController(context, "test_key"));
-        mFragment = spy(FragmentController.of(new PrivacyDashboardFragment())
-                .create().start().get());
-        mController.setFragment(mFragment);
-        mPreference = spy(new BarChartPreference(context));
-        when(mScreen.findPreference(mController.getPreferenceKey()))
-                .thenReturn((BarChartPreference) mPreference);
-    }
-
-    @After
-    public void tearDown() {
-        ShadowDeviceConfig.reset();
-    }
-
-    @Test
-    public void getAvailabilityStatus_permissionHubNotSet_shouldReturnUnsupported() {
-        // We have not yet set the property to show the Permissions Hub.
-        assertThat(mController.getAvailabilityStatus()).isEqualTo(UNSUPPORTED_ON_DEVICE);
-    }
-}
diff --git a/tests/robotests/src/com/android/settings/privacy/PrivacyDashboardFragmentTest.java b/tests/robotests/src/com/android/settings/privacy/PrivacyDashboardFragmentTest.java
deleted file mode 100644
index 80f3900..0000000
--- a/tests/robotests/src/com/android/settings/privacy/PrivacyDashboardFragmentTest.java
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.settings.privacy;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.content.Context;
-import android.content.pm.UserInfo;
-import android.os.Bundle;
-import android.os.UserManager;
-import android.permission.PermissionControllerManager;
-import android.view.View;
-import android.view.accessibility.AccessibilityManager;
-
-import com.android.internal.widget.LockPatternUtils;
-import com.android.settings.testutils.FakeFeatureFactory;
-import com.android.settings.testutils.shadow.ShadowPermissionControllerManager;
-import com.android.settings.testutils.shadow.ShadowUserManager;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-import org.robolectric.RobolectricTestRunner;
-import org.robolectric.RuntimeEnvironment;
-import org.robolectric.annotation.Config;
-import org.robolectric.shadow.api.Shadow;
-import org.robolectric.shadows.ShadowAccessibilityManager;
-import org.robolectric.shadows.androidx.fragment.FragmentController;
-
-import java.util.ArrayList;
-
-
-@RunWith(RobolectricTestRunner.class)
-@Config(shadows = {ShadowUserManager.class, ShadowPermissionControllerManager.class})
-public class PrivacyDashboardFragmentTest {
-
-    @Mock
-    private LockPatternUtils mLockPatternUtils;
-    @Mock
-    private PermissionControllerManager mPCM;
-
-    private Context mContext;
-    private PrivacyDashboardFragment mFragment;
-
-    @Before
-    public void setUp() {
-        MockitoAnnotations.initMocks(this);
-        mContext = RuntimeEnvironment.application;
-        final UserManager userManager = mContext.getSystemService(UserManager.class);
-        final ShadowUserManager shadowUserManager = Shadow.extract(userManager);
-        final ShadowAccessibilityManager accessibilityManager = Shadow.extract(
-                AccessibilityManager.getInstance(mContext));
-        accessibilityManager.setEnabledAccessibilityServiceList(new ArrayList<>());
-        shadowUserManager.addProfile(new UserInfo(123, null, 0));
-        when(FakeFeatureFactory.setupForTest().securityFeatureProvider.getLockPatternUtils(
-                any(Context.class))).thenReturn(mLockPatternUtils);
-        mFragment = spy(FragmentController.of(new PrivacyDashboardFragment())
-                .create().start().get());
-    }
-
-    @Test
-    public void onViewCreated_shouldSetActionBarShadowAnimation() {
-        mFragment.onViewCreated(new View(mContext), new Bundle());
-
-        assertThat(mFragment.getActivity().getActionBar().getElevation()).isEqualTo(0.f);
-    }
-
-    @Test
-    public void onViewCreated_shouldInitLinearProgressBar() {
-        mFragment.onViewCreated(new View(mContext), new Bundle());
-
-        verify(mFragment).initLoadingBar();
-    }
-
-    @Test
-    public void updateLinearProgressbar_isVisible_shouldShowProgressBar() {
-        mFragment.setLoadingEnabled(true /* enabled */);
-
-        assertThat(mFragment.mProgressHeader.getVisibility()).isEqualTo(View.VISIBLE);
-        assertThat(mFragment.mProgressAnimation.getVisibility()).isEqualTo(View.VISIBLE);
-    }
-
-    @Test
-    public void updateLinearProgressbar_isInVisible_shouldHideProgressBar() {
-        mFragment.setLoadingEnabled(false /* enabled */);
-
-        assertThat(mFragment.mProgressHeader.getVisibility()).isEqualTo(View.INVISIBLE);
-        assertThat(mFragment.mProgressAnimation.getVisibility()).isEqualTo(View.INVISIBLE);
-    }
-}
diff --git a/tests/robotests/src/com/android/settings/testutils/FakeFeatureFactory.java b/tests/robotests/src/com/android/settings/testutils/FakeFeatureFactory.java
index 2a12680..220209c 100644
--- a/tests/robotests/src/com/android/settings/testutils/FakeFeatureFactory.java
+++ b/tests/robotests/src/com/android/settings/testutils/FakeFeatureFactory.java
@@ -24,6 +24,7 @@
 import com.android.settings.accounts.AccountFeatureProvider;
 import com.android.settings.applications.ApplicationFeatureProvider;
 import com.android.settings.aware.AwareFeatureProvider;
+import com.android.settings.biometrics.face.FaceFeatureProvider;
 import com.android.settings.bluetooth.BluetoothFeatureProvider;
 import com.android.settings.dashboard.DashboardFeatureProvider;
 import com.android.settings.dashboard.suggestions.SuggestionFeatureProvider;
@@ -68,6 +69,7 @@
     public final ContextualCardFeatureProvider mContextualCardFeatureProvider;
     public final BluetoothFeatureProvider mBluetoothFeatureProvider;
     public final AwareFeatureProvider mAwareFeatureProvider;
+    public final FaceFeatureProvider mFaceFeatureProvider;
 
     public PanelFeatureProvider panelFeatureProvider;
     public SlicesFeatureProvider slicesFeatureProvider;
@@ -114,6 +116,7 @@
         panelFeatureProvider = mock(PanelFeatureProvider.class);
         mBluetoothFeatureProvider = mock(BluetoothFeatureProvider.class);
         mAwareFeatureProvider = mock(AwareFeatureProvider.class);
+        mFaceFeatureProvider = mock(FaceFeatureProvider.class);
     }
 
     @Override
@@ -215,4 +218,9 @@
     public AwareFeatureProvider getAwareFeatureProvider() {
         return mAwareFeatureProvider;
     }
+
+    @Override
+    public FaceFeatureProvider getFaceFeatureProvider() {
+        return mFaceFeatureProvider;
+    }
 }