Merge "Add ResetAppPreferences to AllAppListPage"
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 8791c92..eb69f6e 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -348,7 +348,7 @@
             android:exported="true"
             android:configChanges="orientation|keyboardHidden|screenSize">
             <intent-filter android:priority="1">
-                <action android:name="android.settings.MEMTAG_SETTINGS"/>
+                <action android:name="android.settings.ADVANCED_MEMORY_PROTECTION_SETTINGS"/>
                 <category android:name="android.intent.category.BROWSABLE" />
                 <category android:name="android.intent.category.DEFAULT"/>
             </intent-filter>
diff --git a/res/drawable-night/ic_battery_status_protected_24dp.xml b/res/drawable-night/ic_battery_status_protected_24dp.xml
new file mode 100644
index 0000000..23386cb
--- /dev/null
+++ b/res/drawable-night/ic_battery_status_protected_24dp.xml
@@ -0,0 +1,30 @@
+<!--
+  ~ Copyright (C) 2022 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<vector
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:name="vector"
+    android:width="16dp"
+    android:height="16dp"
+    android:viewportWidth="16"
+    android:viewportHeight="16">
+    <path
+        android:name="path_1"
+        android:pathData="M 11.739 14.409 C 11.572 14.576 11.346 14.67 11.11 14.67 L 4.89 14.67 C 4.654 14.67 4.428 14.576 4.261 14.409 C 4.094 14.242 4 14.016 4 13.78 L 4 3.55 C 4 3.316 4.092 3.091 4.257 2.924 C 4.422 2.758 4.646 2.663 4.88 2.66 L 6.33 2.66 L 6.33 1.33 L 9.66 1.33 L 9.66 2.66 L 11.11 2.66 C 11.227 2.66 11.343 2.683 11.451 2.728 C 11.559 2.773 11.657 2.838 11.739 2.921 C 11.822 3.003 11.887 3.102 11.932 3.209 C 11.977 3.317 12 3.433 12 3.55 L 12 13.78 C 12 14.016 11.906 14.242 11.739 14.409 Z M 6 9 L 8.67 4 L 8.67 7.67 L 10 7.67 L 7.33 12.67 L 7.33 9 L 6 9 Z"
+        android:fillColor="#ffffff"
+        android:strokeWidth="1"
+        android:fillType="evenOdd"/>
+</vector>
\ No newline at end of file
diff --git a/res/drawable/ic_battery_status_protected_24dp.xml b/res/drawable/ic_battery_status_protected_24dp.xml
new file mode 100644
index 0000000..8841710
--- /dev/null
+++ b/res/drawable/ic_battery_status_protected_24dp.xml
@@ -0,0 +1,30 @@
+<!--
+  ~ Copyright (C) 2022 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<vector
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:name="vector"
+    android:width="16dp"
+    android:height="16dp"
+    android:viewportWidth="16"
+    android:viewportHeight="16">
+    <path
+        android:name="path"
+        android:pathData="M 11.739 14.409 C 11.572 14.576 11.346 14.67 11.11 14.67 L 4.89 14.67 C 4.654 14.67 4.428 14.576 4.261 14.409 C 4.094 14.242 4 14.016 4 13.78 L 4 3.55 C 4 3.316 4.092 3.091 4.257 2.924 C 4.422 2.758 4.646 2.663 4.88 2.66 L 6.33 2.66 L 6.33 1.33 L 9.66 1.33 L 9.66 2.66 L 11.11 2.66 C 11.227 2.66 11.343 2.683 11.451 2.728 C 11.559 2.773 11.657 2.838 11.739 2.921 C 11.822 3.003 11.887 3.102 11.932 3.209 C 11.977 3.317 12 3.433 12 3.55 L 12 13.78 C 12 14.016 11.906 14.242 11.739 14.409 Z M 6 9 L 8.67 4 L 8.67 7.67 L 10 7.67 L 7.33 12.67 L 7.33 9 L 6 9 Z"
+        android:fillColor="#000000"
+        android:strokeWidth="1"
+        android:fillType="evenOdd"/>
+</vector>
\ No newline at end of file
diff --git a/res/layout-land/choose_lock_pattern_common.xml b/res/layout-land/choose_lock_pattern_common.xml
new file mode 100644
index 0000000..a2cf2e6
--- /dev/null
+++ b/res/layout-land/choose_lock_pattern_common.xml
@@ -0,0 +1,81 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+    Copyright (C) 2014 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.
+-->
+
+<!-- Used in phone portrait and tablet, as referenced in alias.xml. -->
+<com.google.android.setupdesign.GlifLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/setup_wizard_layout"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:icon="@drawable/ic_lock">
+
+    <!-- takes up all space above button bar at bottom -->
+    <com.android.internal.widget.LinearLayoutWithDefaultTouchRecepient
+        android:id="@+id/topLayout"
+        style="@style/SudContentFrame"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:gravity="center"
+        android:clipChildren="false"
+        android:clipToPadding="false"
+        android:orientation="vertical"
+        android:paddingLeft="0dp"
+        android:paddingRight="0dp">
+
+        <TextView
+            android:id="@+id/headerText"
+            style="@style/SudDescription.Glif"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:minLines="2"
+            android:gravity="center"
+            android:paddingStart="?attr/sudMarginStart"
+            android:paddingEnd="?attr/sudMarginEnd"
+            android:fontFamily="@*android:string/config_headlineFontFamily" />
+
+        <com.google.android.setupdesign.view.FillContentLayout
+            style="@style/LockPatternContainerStyle"
+            android:layout_width="wrap_content"
+            android:layout_height="0dp"
+            android:layout_weight="1">
+
+            <com.android.internal.widget.LockPatternView
+                android:id="@+id/lockPattern"
+                android:layout_width="match_parent"
+                android:layout_height="match_parent"
+                android:layout_gravity="center"/>
+
+        </com.google.android.setupdesign.view.FillContentLayout>
+
+        <TextView android:id="@+id/footerText"
+                  android:layout_width="wrap_content"
+                  android:layout_height="wrap_content"
+                  android:layout_gravity="center_horizontal"
+                  android:minHeight="24dp"
+                  android:textSize="14sp"
+                  android:visibility="gone"/>
+
+        <Button
+            android:id="@+id/screen_lock_options"
+            style="@style/SudGlifButton.Tertiary"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/setup_lock_settings_options_button_label"
+            android:visibility="gone"/>
+    </com.android.internal.widget.LinearLayoutWithDefaultTouchRecepient>
+
+</com.google.android.setupdesign.GlifLayout>
diff --git a/res/layout-land/confirm_lock_pattern_base.xml b/res/layout-land/confirm_lock_pattern_base.xml
new file mode 100644
index 0000000..f79fc72
--- /dev/null
+++ b/res/layout-land/confirm_lock_pattern_base.xml
@@ -0,0 +1,95 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 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.
+-->
+<com.google.android.setupdesign.GlifLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/setup_wizard_layout"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:icon="@drawable/ic_enterprise">
+
+    <com.android.internal.widget.LinearLayoutWithDefaultTouchRecepient
+        android:id="@+id/topLayout"
+        android:orientation="vertical"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent">
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:orientation="vertical"
+            android:paddingBottom="24dp">
+
+            <Button
+                android:id="@+id/cancelButton"
+                style="@style/SudGlifButton.Secondary"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_marginStart="?attr/sudMarginStart"
+                android:layout_marginEnd="?attr/sudMarginEnd"
+                android:layout_marginBottom="80dp"
+                android:text="@string/cancel" />
+
+            <Button
+                android:id="@+id/forgotButton"
+                style="@style/SudGlifButton.Secondary"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_marginStart="?attr/sudMarginStart"
+                android:layout_marginEnd="?attr/sudMarginEnd"
+                android:layout_gravity="center"
+                android:visibility="gone" />
+
+        </LinearLayout>
+
+        <LinearLayout
+            style="@style/SudContentFrame"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:orientation="vertical"
+            android:gravity="center"
+            android:paddingLeft="0dp"
+            android:paddingRight="0dp">
+
+            <com.google.android.setupdesign.view.FillContentLayout
+                style="@style/LockPatternContainerStyle"
+                android:layout_width="wrap_content"
+                android:layout_height="0dp"
+                android:layout_weight="1">
+
+                <com.android.internal.widget.LockPatternView
+                    android:id="@+id/lockPattern"
+                    android:layout_width="match_parent"
+                    android:layout_height="match_parent"
+                    android:layout_gravity="center" />
+
+            </com.google.android.setupdesign.view.FillContentLayout>
+
+            <TextView
+                style="@style/TextAppearance.ErrorText"
+                android:accessibilityLiveRegion="polite"
+                android:id="@+id/errorText"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_gravity="center_horizontal"
+                android:paddingStart="?attr/sudMarginStart"
+                android:paddingEnd="?attr/sudMarginEnd"
+                android:layout_marginTop="12dp"
+                android:gravity="center_vertical"/>
+
+        </LinearLayout>
+
+    </com.android.internal.widget.LinearLayoutWithDefaultTouchRecepient>
+</com.google.android.setupdesign.GlifLayout>
diff --git a/res/layout-land/confirm_lock_pattern_normal_base.xml b/res/layout-land/confirm_lock_pattern_normal_base.xml
new file mode 100644
index 0000000..ced0e2c
--- /dev/null
+++ b/res/layout-land/confirm_lock_pattern_normal_base.xml
@@ -0,0 +1,77 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<com.google.android.setupdesign.GlifLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/setup_wizard_layout"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:icon="@drawable/ic_lock">
+
+    <com.android.internal.widget.LinearLayoutWithDefaultTouchRecepient
+        android:id="@+id/topLayout"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:orientation="vertical">
+
+        <LinearLayout
+            style="@style/SudContentFrame"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:orientation="vertical"
+            android:gravity="center"
+            android:paddingLeft="0dp"
+            android:paddingRight="0dp">
+
+            <com.google.android.setupdesign.view.FillContentLayout
+                style="@style/LockPatternContainerStyle"
+                android:layout_width="wrap_content"
+                android:layout_height="0dp"
+                android:layout_weight="1">
+
+                <com.android.internal.widget.LockPatternView
+                    android:id="@+id/lockPattern"
+                    android:layout_width="match_parent"
+                    android:layout_height="match_parent"
+                    android:layout_gravity="center" />
+
+            </com.google.android.setupdesign.view.FillContentLayout>
+
+            <TextView
+                style="@style/TextAppearance.ErrorText"
+                android:accessibilityLiveRegion="polite"
+                android:id="@+id/errorText"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_gravity="center_horizontal"
+                android:layout_marginStart="?attr/sudMarginStart"
+                android:layout_marginEnd="?attr/sudMarginEnd"
+                android:gravity="center_vertical"/>
+
+            <Button
+                android:id="@+id/cancelButton"
+                style="@style/SudGlifButton.Secondary"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_marginStart="?attr/sudMarginStart"
+                android:layout_marginEnd="?attr/sudMarginEnd"
+                android:layout_marginBottom="80dp"
+                android:text="@string/cancel" />
+
+        </LinearLayout>
+
+    </com.android.internal.widget.LinearLayoutWithDefaultTouchRecepient>
+
+</com.google.android.setupdesign.GlifLayout>
diff --git a/res/layout/choose_lock_pattern_common.xml b/res/layout/choose_lock_pattern_common.xml
index 2dd8cd5..b63b2c6 100644
--- a/res/layout/choose_lock_pattern_common.xml
+++ b/res/layout/choose_lock_pattern_common.xml
@@ -51,13 +51,12 @@
             style="@style/LockPatternContainerStyle"
             android:layout_width="wrap_content"
             android:layout_height="0dp"
-            android:minHeight="@dimen/choose_lockscreen_min_height"
             android:layout_weight="1">
 
             <com.android.internal.widget.LockPatternView
                 android:id="@+id/lockPattern"
-                android:layout_width="match_parent"
-                android:layout_height="match_parent"
+                android:layout_width="@dimen/biometric_auth_pattern_view_size"
+                android:layout_height="@dimen/biometric_auth_pattern_view_size"
                 android:layout_gravity="center"/>
 
         </com.google.android.setupdesign.view.FillContentLayout>
@@ -66,7 +65,7 @@
                   android:layout_width="wrap_content"
                   android:layout_height="wrap_content"
                   android:layout_gravity="center_horizontal"
-                  android:minHeight="50dip"
+                  android:minHeight="24dp"
                   android:textSize="14sp"
                   android:visibility="gone"/>
 
diff --git a/res/layout/confirm_lock_pattern_base.xml b/res/layout/confirm_lock_pattern_base.xml
index 15c6121..5b19105 100644
--- a/res/layout/confirm_lock_pattern_base.xml
+++ b/res/layout/confirm_lock_pattern_base.xml
@@ -67,13 +67,12 @@
                 style="@style/LockPatternContainerStyle"
                 android:layout_width="wrap_content"
                 android:layout_height="0dp"
-                android:minHeight="@dimen/choose_lockscreen_min_height"
                 android:layout_weight="1">
 
                 <com.android.internal.widget.LockPatternView
                     android:id="@+id/lockPattern"
-                    android:layout_width="match_parent"
-                    android:layout_height="match_parent"
+                    android:layout_width="@dimen/biometric_auth_pattern_view_size"
+                    android:layout_height="@dimen/biometric_auth_pattern_view_size"
                     android:layout_gravity="center" />
 
             </com.google.android.setupdesign.view.FillContentLayout>
diff --git a/res/layout/confirm_lock_pattern_normal_base.xml b/res/layout/confirm_lock_pattern_normal_base.xml
index 7fd6172..5d1ca7c 100644
--- a/res/layout/confirm_lock_pattern_normal_base.xml
+++ b/res/layout/confirm_lock_pattern_normal_base.xml
@@ -39,13 +39,12 @@
                 style="@style/LockPatternContainerStyle"
                 android:layout_width="wrap_content"
                 android:layout_height="0dp"
-                android:minHeight="@dimen/choose_lockscreen_min_height"
                 android:layout_weight="1">
 
                 <com.android.internal.widget.LockPatternView
                     android:id="@+id/lockPattern"
-                    android:layout_width="match_parent"
-                    android:layout_height="match_parent"
+                    android:layout_width="@dimen/biometric_auth_pattern_view_size"
+                    android:layout_height="@dimen/biometric_auth_pattern_view_size"
                     android:layout_gravity="center" />
 
             </com.google.android.setupdesign.view.FillContentLayout>
diff --git a/res/values-land/dimens.xml b/res/values-land/dimens.xml
new file mode 100755
index 0000000..644486d
--- /dev/null
+++ b/res/values-land/dimens.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2022 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<resources>
+    <!-- Lock pattern view size, align sysui biometric_auth_pattern_view_size -->
+    <dimen name="biometric_auth_pattern_view_size">248dp</dimen>
+    <dimen name="biometric_auth_pattern_view_max_size">348dp</dimen>
+
+</resources>
diff --git a/res/values-land/styles.xml b/res/values-land/styles.xml
new file mode 100644
index 0000000..e6fb332
--- /dev/null
+++ b/res/values-land/styles.xml
@@ -0,0 +1,28 @@
+<!--
+  ~ Copyright (C) 2022 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<resources>
+    <style name="LockPatternContainerStyle">
+        <item name="android:maxHeight">@dimen/biometric_auth_pattern_view_max_size</item>
+        <item name="android:maxWidth">@dimen/biometric_auth_pattern_view_max_size</item>
+        <item name="android:minHeight">@dimen/biometric_auth_pattern_view_size</item>
+        <item name="android:minWidth">@dimen/biometric_auth_pattern_view_size</item>
+        <item name="android:gravity">center</item>
+        <item name="android:paddingBottom">0dp</item>
+        <item name="android:paddingHorizontal">0dp</item>
+        <item name="android:paddingTop">0dp</item>
+    </style>
+</resources>
\ No newline at end of file
diff --git a/res/values-sw360dp/dimens.xml b/res/values-sw360dp/dimens.xml
index 9ea65ba..4d0bcf7 100755
--- a/res/values-sw360dp/dimens.xml
+++ b/res/values-sw360dp/dimens.xml
@@ -17,4 +17,7 @@
 
 <resources>
     <dimen name="fingerprint_find_sensor_graphic_size">240dp</dimen>
+
+    <!-- Lock pattern view size, align sysui biometric_auth_pattern_view_size -->
+    <dimen name="biometric_auth_pattern_view_size">298dp</dimen>
 </resources>
diff --git a/res/values-sw392dp-land/dimens.xml b/res/values-sw392dp-land/dimens.xml
new file mode 100755
index 0000000..920a0ec
--- /dev/null
+++ b/res/values-sw392dp-land/dimens.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2022 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<resources>
+    <!-- Lock pattern view size, align sysui biometric_auth_pattern_view_size -->
+    <dimen name="biometric_auth_pattern_view_size">248dp</dimen>
+    <dimen name="biometric_auth_pattern_view_max_size">248dp</dimen>
+
+</resources>
diff --git a/res/values-sw392dp/dimens.xml b/res/values-sw392dp/dimens.xml
new file mode 100755
index 0000000..f90d4ee
--- /dev/null
+++ b/res/values-sw392dp/dimens.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2022 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<resources>
+    <!-- Lock pattern view size, align sysui biometric_auth_pattern_view_size -->
+    <dimen name="biometric_auth_pattern_view_size">298dp</dimen>
+
+</resources>
diff --git a/res/values-sw410dp-land/dimens.xml b/res/values-sw410dp-land/dimens.xml
new file mode 100755
index 0000000..644486d
--- /dev/null
+++ b/res/values-sw410dp-land/dimens.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2022 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<resources>
+    <!-- Lock pattern view size, align sysui biometric_auth_pattern_view_size -->
+    <dimen name="biometric_auth_pattern_view_size">248dp</dimen>
+    <dimen name="biometric_auth_pattern_view_max_size">348dp</dimen>
+
+</resources>
diff --git a/res/values-sw410dp/dimens.xml b/res/values-sw410dp/dimens.xml
new file mode 100755
index 0000000..5120e4a
--- /dev/null
+++ b/res/values-sw410dp/dimens.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2022 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<resources>
+    <!-- Lock pattern view size, align sysui biometric_auth_pattern_view_size -->
+    <dimen name="biometric_auth_pattern_view_size">348dp</dimen>
+
+</resources>
diff --git a/res/values-sw600dp-land/dimens.xml b/res/values-sw600dp-land/dimens.xml
index 3a88386..f9ed868 100755
--- a/res/values-sw600dp-land/dimens.xml
+++ b/res/values-sw600dp-land/dimens.xml
@@ -18,4 +18,7 @@
     <dimen name="screen_margin_sides">128dip</dimen>
 
     <dimen name="confirm_credentials_top_margin">24dp</dimen>
+
+    <!-- Lock pattern view size, align sysui biometric_auth_pattern_view_size -->
+    <dimen name="biometric_auth_pattern_view_size">298dp</dimen>
 </resources>
diff --git a/res/values-sw600dp/dimens.xml b/res/values-sw600dp/dimens.xml
index 0fcf9d4..88621e6 100755
--- a/res/values-sw600dp/dimens.xml
+++ b/res/values-sw600dp/dimens.xml
@@ -31,4 +31,7 @@
     <dimen name="confirm_credentials_top_margin">64dp</dimen>
 
     <dimen name="settings_panel_width">560dp</dimen>
+
+    <!-- Lock pattern view size, align sysui biometric_auth_pattern_view_size -->
+    <dimen name="biometric_auth_pattern_view_size">348dp</dimen>
 </resources>
diff --git a/res/values-sw720dp/dimens.xml b/res/values-sw720dp/dimens.xml
index e730fcc..6480d48 100644
--- a/res/values-sw720dp/dimens.xml
+++ b/res/values-sw720dp/dimens.xml
@@ -22,4 +22,7 @@
     <!-- SwitchBar sub settings margin start / end -->
     <dimen name="switchbar_subsettings_margin_start">80dp</dimen>
     <dimen name="switchbar_subsettings_margin_end">80dp</dimen>
+
+    <!-- Lock pattern view size, align sysui biometric_auth_pattern_view_size -->
+    <dimen name="biometric_auth_pattern_view_size">348dp</dimen>
 </resources>
diff --git a/res/values-sw800dp/dimens.xml b/res/values-sw800dp/dimens.xml
new file mode 100644
index 0000000..48392ef
--- /dev/null
+++ b/res/values-sw800dp/dimens.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2022 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<resources>
+
+    <!-- Lock pattern view size, align sysui biometric_auth_pattern_view_size -->
+    <dimen name="biometric_auth_pattern_view_size">348dp</dimen>
+</resources>
diff --git a/res/values/arrays.xml b/res/values/arrays.xml
index d5aa267..46114cb 100644
--- a/res/values/arrays.xml
+++ b/res/values/arrays.xml
@@ -105,11 +105,16 @@
         <item>1800000</item>
     </string-array>
 
+    <!-- NOTE: if you change this, you must also add the corresponding scale key and lookup table to
+         frameworks/base/core/java/android/content/res/FontScaleLookupTableFactory.java -->
     <string-array name="entryvalues_font_size" translatable="false">
         <item>0.85</item>
         <item>1.0</item>
         <item>1.15</item>
         <item>1.30</item>
+        <item>1.50</item>
+        <item>1.80</item>
+        <item>2.0</item>
     </string-array>
 
     <!-- Wi-Fi settings -->
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index c5ad20f..5dff948 100755
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -171,6 +171,10 @@
     <item name="face_preview_scale" format="float" type="dimen">1.0</item>
     <dimen name="face_enroll_intro_illustration_margin_bottom">0dp</dimen>
 
+    <!-- Lock pattern view size, align sysui biometric_auth_pattern_view_size -->
+    <dimen name="biometric_auth_pattern_view_size">348dp</dimen>
+    <dimen name="biometric_auth_pattern_view_max_size">@dimen/biometric_auth_pattern_view_size</dimen>
+
     <!-- Confirm device credentials -->
     <dimen name="confirm_credentials_side_margin">16dp</dimen>
     <dimen name="confirm_credentials_top_margin">16dp</dimen>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 2cfec6e..d91cb88 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -4682,8 +4682,18 @@
     <string name="battery_tip_limited_temporarily_title">Charging is paused</string>
     <!-- Summary for the battery limited temporarily tip [CHAR LIMIT=NONE] -->
     <string name="battery_tip_limited_temporarily_summary">Protecting battery to extend battery lifespan</string>
-    <!-- Summary for the battery limited temporarily extra tip [CHAR LIMIT=NONE] -->
-    <string name="battery_tip_limited_temporarily_extra_summary"><xliff:g id="percent" example="10%">%1$s</xliff:g></string>
+    <!-- Title for the battery dock defender future bypass tip [CHAR LIMIT=NONE] -->
+    <string name="battery_tip_dock_defender_future_bypass_title">Charging to <xliff:g id="percent" example="10%">%1$s</xliff:g> to protect the battery</string>
+    <!-- Summary for the battery dock defender future bypass tip [CHAR LIMIT=NONE] -->
+    <string name="battery_tip_dock_defender_future_bypass_summary">When your tablet is docked, charging will be paused at <xliff:g id="percent" example="10%">%1$s</xliff:g> to extend battery lifespan</string>
+    <!-- Title for the battery dock defender active tip [CHAR LIMIT=NONE] -->
+    <string name="battery_tip_dock_defender_active_title">Charging paused to protect battery</string>
+    <!-- Summary for the battery dock defender active tip [CHAR LIMIT=NONE] -->
+    <string name="battery_tip_dock_defender_active_summary">When your tablet is docked, charging is paused at <xliff:g id="percent" example="10%">%1$s</xliff:g> to extend battery lifespan</string>
+    <!-- Title for the battery dock defender temporarily bypassed tip [CHAR LIMIT=NONE] -->
+    <string name="battery_tip_dock_defender_temporarily_bypassed_title">Charging to full</string>
+    <!-- Summary for the battery dock defender temporarily bypassed tip [CHAR LIMIT=NONE] -->
+    <string name="battery_tip_dock_defender_temporarily_bypassed_summary">To protect your battery, charging will be paused at <xliff:g id="percent" example="10%">%1$s</xliff:g> the next time your tablet is docked</string>
     <!-- Content description for the battery limited temporarily tip secondary button [CHAR LIMIT=NONE] -->
     <string name="battery_tip_limited_temporarily_sec_button_content_description">Learn more about charging is paused</string>
     <!-- Text of battery limited temporarily tip resume charge button. [CHAR LIMIT=NONE] -->
@@ -6366,6 +6376,9 @@
     <string name="app_default_dashboard_title">Default apps</string>
     <!-- Title for setting tile leading to App Clones menu under the Apps page [CHAR LIMIT=40] -->
     <string name="cloned_apps_dashboard_title">Cloned Apps</string>
+    <!-- Description for introduction of the cloned apps page [CHAR LIMIT=NONE]-->
+    <string name="desc_cloned_apps_intro_text">Create a second instance of an app so that you can use two accounts at the same time.</string>
+    <string name="cloned_apps_summary"><xliff:g id="cloned_apps_count">%1$s</xliff:g> cloned, <xliff:g id="allowed_apps_count">%2$d</xliff:g> available to clone</string>
     <!-- Summary text for system preference title, showing important setting items under system setting [CHAR LIMIT=NONE]-->
     <string name="system_dashboard_summary">Languages, gestures, time, backup</string>
     <!-- Summary text for language preference title, showing important setting items under language setting [CHAR LIMIT=NONE]-->
@@ -10479,7 +10492,10 @@
     <!-- Title for the button to reboot with MTE enabled. [CHAR LIMIT=NONE] -->
     <string name="reboot_with_mte_title">Reboot with MTE</string>
     <string name="reboot_with_mte_message">System will reboot and allow to experiment with Memory Tagging Extension (MTE). MTE may negatively impact system performance and stability. Will be reset on next subsequent reboot.</string>
+    <!-- Subtext for button if MTE is not enabled through Advanced memory protection. -->
     <string name="reboot_with_mte_summary">Try MTE for a single boot for app development</string>
+    <!-- Subtext for button if MTE is already enabled through Advanced memory protection.
+         The string for "Advanced memory protection" needs to match "memtag_toggle" above -->
     <string name="reboot_with_mte_already_enabled">MTE is enabled through Advanced memory protection</string>
     <!-- Toast that is shown when the user initiates capturing a heap dump for the system server. [CHAR LIMIT=NONE] -->
     <string name="capturing_system_heap_dump_message">Capturing system heap dump</string>
@@ -11263,6 +11279,11 @@
     <!-- Developer Settings: Dialog ListPreference option to disable network bandwidth ingress rate limit [CHAR LIMIT=none] -->
     <string name="ingress_rate_limit_no_limit_entry">No limit</string>
 
+    <!-- Developer settings: Title for disabling phantom process monitoring. [CHAR LIMIT=50]-->
+    <string name="disable_phantom_process_monitor_title">Disable child process restrictions</string>
+    <!-- Developer settings: Summary for disabling phantom process monitoring. [CHAR LIMIT=NONE]-->
+    <string name="disable_phantom_process_monitor_summary">Disable restrictions on the system resource usage of the app child processes</string>
+
     <!-- BT LE Audio Device: Media Broadcast -->
     <!-- The title of the Media Broadcast Dialog [CHAR LIMIT=none] -->
     <string name="bluetooth_broadcast_dialog_title">Broadcast</string>
diff --git a/res/values/styles.xml b/res/values/styles.xml
index 591d800..2597543 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -399,10 +399,11 @@
     </style>
 
     <style name="LockPatternContainerStyle">
-        <item name="android:maxHeight">620dp</item>
-        <item name="android:maxWidth">620dp</item>
-        <item name="android:minHeight">0dp</item>
-        <item name="android:minWidth">0dp</item>
+        <item name="android:gravity">center</item>
+        <item name="android:maxHeight">@dimen/biometric_auth_pattern_view_max_size</item>
+        <item name="android:maxWidth">@dimen/biometric_auth_pattern_view_max_size</item>
+        <item name="android:minHeight">@dimen/biometric_auth_pattern_view_size</item>
+        <item name="android:minWidth">@dimen/biometric_auth_pattern_view_size</item>
         <item name="android:paddingBottom">0dp</item>
         <item name="android:paddingHorizontal">0dp</item>
         <item name="android:paddingTop">0dp</item>
diff --git a/res/xml/apps.xml b/res/xml/apps.xml
index 8fb72e8..ae51bae 100644
--- a/res/xml/apps.xml
+++ b/res/xml/apps.xml
@@ -65,6 +65,7 @@
     <Preference
         android:key="cloned_apps"
         android:title="@string/cloned_apps_dashboard_title"
+        android:summary="@string/summary_placeholder"
         android:order="-995"
         settings:controller="com.android.settings.applications.ClonedAppsPreferenceController"
         android:fragment="com.android.settings.applications.manageapplications.ManageApplications">
diff --git a/res/xml/conversation_notification_settings.xml b/res/xml/conversation_notification_settings.xml
index af82140..9078e2d 100644
--- a/res/xml/conversation_notification_settings.xml
+++ b/res/xml/conversation_notification_settings.xml
@@ -25,6 +25,9 @@
         android:layout="@layout/settings_entity_header"
         settings:allowDividerBelow="true"/>
 
+    <com.android.settings.widget.SettingsMainSwitchPreference
+        android:key="block" />
+
     <!-- important conversation -->
     <com.android.settings.notification.app.ConversationPriorityPreference
         android:key="priority"
diff --git a/res/xml/development_settings.xml b/res/xml/development_settings.xml
index a0640f5..9e864b8 100644
--- a/res/xml/development_settings.xml
+++ b/res/xml/development_settings.xml
@@ -672,6 +672,12 @@
         <Preference
             android:key="reset_shortcut_manager_throttling"
             android:title="@string/reset_shortcut_manager_throttling" />
+
+        <SwitchPreference
+            android:key="disable_phantom_process_monitor"
+            android:title="@string/disable_phantom_process_monitor_title"
+            android:summary="@string/disable_phantom_process_monitor_summary" />
+
     </PreferenceCategory>
 
     <PreferenceCategory
diff --git a/src/com/android/settings/Utils.java b/src/com/android/settings/Utils.java
index e57a32d..8622251 100644
--- a/src/com/android/settings/Utils.java
+++ b/src/com/android/settings/Utils.java
@@ -165,6 +165,11 @@
             "app_hibernation_targets_pre_s_apps";
 
     /**
+     * Whether or not Cloned Apps menu is available in Apps page. Default is false.
+     */
+    public static final String PROPERTY_CLONED_APPS_ENABLED = "cloned_apps_enabled";
+
+    /**
      * Finds a matching activity for a preference's intent. If a matching
      * activity is not found, it will remove the preference.
      *
@@ -1252,4 +1257,17 @@
     public static int getHomepageIconColorHighlight(Context context) {
         return context.getColor(R.color.accent_select_primary_text);
     }
+
+    /**
+     * Returns user id of clone profile if present, else returns -1.
+     */
+    public static int getCloneUserId(Context context) {
+        UserManager userManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
+        for (UserHandle userHandle : userManager.getUserProfiles()) {
+            if (userManager.getUserInfo(userHandle.getIdentifier()).isCloneProfile()) {
+                return userHandle.getIdentifier();
+            }
+        }
+        return -1;
+    }
 }
diff --git a/src/com/android/settings/accessibility/AccessibilityHearingAidPreferenceController.java b/src/com/android/settings/accessibility/AccessibilityHearingAidPreferenceController.java
index 4e93389..34289dd 100644
--- a/src/com/android/settings/accessibility/AccessibilityHearingAidPreferenceController.java
+++ b/src/com/android/settings/accessibility/AccessibilityHearingAidPreferenceController.java
@@ -19,7 +19,9 @@
 import android.app.settings.SettingsEnums;
 import android.bluetooth.BluetoothAdapter;
 import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothHapClient;
 import android.bluetooth.BluetoothHearingAid;
+import android.bluetooth.BluetoothLeAudio;
 import android.bluetooth.BluetoothProfile;
 import android.content.BroadcastReceiver;
 import android.content.Context;
@@ -41,6 +43,8 @@
 import com.android.settingslib.bluetooth.BluetoothCallback;
 import com.android.settingslib.bluetooth.CachedBluetoothDevice;
 import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager;
+import com.android.settingslib.bluetooth.HapClientProfile;
+import com.android.settingslib.bluetooth.HearingAidInfo;
 import com.android.settingslib.bluetooth.HearingAidProfile;
 import com.android.settingslib.bluetooth.LocalBluetoothManager;
 import com.android.settingslib.bluetooth.LocalBluetoothProfileManager;
@@ -48,9 +52,12 @@
 import com.android.settingslib.core.lifecycle.events.OnStart;
 import com.android.settingslib.core.lifecycle.events.OnStop;
 
+import java.util.ArrayList;
 import java.util.List;
+import java.util.Set;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.FutureTask;
+import java.util.stream.Collectors;
 
 /**
  * Controller that shows and updates the bluetooth device name
@@ -64,23 +71,7 @@
     private final BroadcastReceiver mHearingAidChangedReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
-            if (BluetoothHearingAid.ACTION_CONNECTION_STATE_CHANGED.equals(intent.getAction())) {
-                final int state = intent.getIntExtra(BluetoothHearingAid.EXTRA_STATE,
-                        BluetoothHearingAid.STATE_DISCONNECTED);
-                if (state == BluetoothHearingAid.STATE_CONNECTED) {
-                    updateState(mHearingAidPreference);
-                } else {
-                    mHearingAidPreference
-                            .setSummary(R.string.accessibility_hearingaid_not_connected_summary);
-                }
-            } else if (BluetoothAdapter.ACTION_STATE_CHANGED.equals(intent.getAction())) {
-                final int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE,
-                        BluetoothAdapter.ERROR);
-                if (state != BluetoothAdapter.STATE_ON) {
-                    mHearingAidPreference
-                            .setSummary(R.string.accessibility_hearingaid_not_connected_summary);
-                }
-            }
+            updateState(mHearingAidPreference);
         }
     };
 
@@ -107,17 +98,24 @@
 
     @Override
     public int getAvailabilityStatus() {
-        return isHearingAidProfileSupported() ? AVAILABLE : UNSUPPORTED_ON_DEVICE;
+        return isHearingAidSupported() ? AVAILABLE : UNSUPPORTED_ON_DEVICE;
     }
 
     @Override
     public void onStart() {
         IntentFilter filter = new IntentFilter();
         filter.addAction(BluetoothHearingAid.ACTION_CONNECTION_STATE_CHANGED);
+        filter.addAction(BluetoothHapClient.ACTION_HAP_CONNECTION_STATE_CHANGED);
+        filter.addAction(BluetoothLeAudio.ACTION_LE_AUDIO_CONNECTION_STATE_CHANGED);
         filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
         mContext.registerReceiver(mHearingAidChangedReceiver, filter);
         mLocalBluetoothManager.getEventManager().registerCallback(this);
-        mProfileManager.addServiceListener(this);
+        // Can't get connected hearing aids when hearing aids related profiles are not ready. The
+        // profiles will be ready after the services are connected. Needs to add listener and
+        // updates the information when all hearing aids related services are connected.
+        if (isAnyHearingAidRelatedProfilesNotReady()) {
+            mProfileManager.addServiceListener(this);
+        }
     }
 
     @Override
@@ -143,6 +141,9 @@
 
     @Override
     public CharSequence getSummary() {
+        if (mBluetoothAdapter == null || !mBluetoothAdapter.isEnabled()) {
+            return mContext.getText(R.string.accessibility_hearingaid_not_connected_summary);
+        }
         final CachedBluetoothDevice device = getConnectedHearingAidDevice();
         if (device == null) {
             return mContext.getText(R.string.accessibility_hearingaid_not_connected_summary);
@@ -150,24 +151,40 @@
 
         final int connectedNum = getConnectedHearingAidDeviceNum();
         final CharSequence name = device.getName();
-        final int side = device.getDeviceSide();
-        final CachedBluetoothDevice subDevice = device.getSubDevice();
         if (connectedNum > 1) {
             return mContext.getString(R.string.accessibility_hearingaid_more_device_summary, name);
         }
+
+        // Check if another side of LE audio hearing aid is connected as a pair
+        final Set<CachedBluetoothDevice> memberDevices = device.getMemberDevice();
+        if (memberDevices.stream().anyMatch(m -> m.isConnected())) {
+            return mContext.getString(
+                    R.string.accessibility_hearingaid_left_and_right_side_device_summary,
+                    name);
+        }
+
+        // Check if another side of ASHA hearing aid is connected as a pair
+        final CachedBluetoothDevice subDevice = device.getSubDevice();
         if (subDevice != null && subDevice.isConnected()) {
             return mContext.getString(
                     R.string.accessibility_hearingaid_left_and_right_side_device_summary, name);
         }
-        if (side == HearingAidProfile.DeviceSide.SIDE_INVALID) {
+
+        final int side = device.getDeviceSide();
+        if (side == HearingAidInfo.DeviceSide.SIDE_LEFT_AND_RIGHT) {
             return mContext.getString(
-                    R.string.accessibility_hearingaid_active_device_summary, name);
+                    R.string.accessibility_hearingaid_left_and_right_side_device_summary, name);
+        } else if (side == HearingAidInfo.DeviceSide.SIDE_LEFT) {
+            return mContext.getString(
+                    R.string.accessibility_hearingaid_left_side_device_summary, name);
+        } else if (side == HearingAidInfo.DeviceSide.SIDE_RIGHT) {
+            return mContext.getString(
+                    R.string.accessibility_hearingaid_right_side_device_summary, name);
         }
-        return (side == HearingAidProfile.DeviceSide.SIDE_LEFT)
-                ? mContext.getString(
-                        R.string.accessibility_hearingaid_left_side_device_summary, name)
-                : mContext.getString(
-                        R.string.accessibility_hearingaid_right_side_device_summary, name);
+
+        // Invalid side
+        return mContext.getString(
+                R.string.accessibility_hearingaid_active_device_summary, name);
     }
 
     @Override
@@ -183,10 +200,7 @@
 
     @Override
     public void onServiceConnected() {
-        // Every registered ProfileService will callback. So we need to use isProfileReady() to
-        // check is the HearingAidService callback here, not other service.
-        // When hearing aids service connected, updating the UI.
-        if (mProfileManager.getHearingAidProfile().isProfileReady()) {
+        if (!isAnyHearingAidRelatedProfilesNotReady()) {
             updateState(mHearingAidPreference);
             mProfileManager.removeServiceListener(this);
         }
@@ -203,38 +217,51 @@
 
     @VisibleForTesting
     CachedBluetoothDevice getConnectedHearingAidDevice() {
-        if (!isHearingAidProfileSupported()) {
-            return null;
-        }
-
-        final HearingAidProfile hearingAidProfile = mProfileManager.getHearingAidProfile();
-        final List<BluetoothDevice> deviceList = hearingAidProfile.getConnectedDevices();
-        for (BluetoothDevice obj : deviceList) {
-            if (!mCachedDeviceManager.isSubDevice(obj)) {
-                return mCachedDeviceManager.findDevice(obj);
-            }
-        }
-        return null;
+        final List<BluetoothDevice> deviceList = getConnectedHearingAidDeviceList();
+        return deviceList.isEmpty() ? null : mCachedDeviceManager.findDevice(deviceList.get(0));
     }
 
     private int getConnectedHearingAidDeviceNum() {
-        if (!isHearingAidProfileSupported()) {
-            return 0;
-        }
-
-        final HearingAidProfile hearingAidProfile = mProfileManager.getHearingAidProfile();
-        final List<BluetoothDevice> deviceList = hearingAidProfile.getConnectedDevices();
-        return (int) deviceList.stream()
-                .filter(device -> !mCachedDeviceManager.isSubDevice(device))
-                .count();
+        return getConnectedHearingAidDeviceList().size();
     }
 
-    private boolean isHearingAidProfileSupported() {
+    private List<BluetoothDevice> getConnectedHearingAidDeviceList() {
+        if (!isHearingAidSupported()) {
+            return new ArrayList<>();
+        }
+        final List<BluetoothDevice> deviceList = new ArrayList<>();
+        final HapClientProfile hapClientProfile = mProfileManager.getHapClientProfile();
+        if (hapClientProfile != null) {
+            deviceList.addAll(hapClientProfile.getConnectedDevices());
+        }
+        final HearingAidProfile hearingAidProfile = mProfileManager.getHearingAidProfile();
+        if (hearingAidProfile != null) {
+            deviceList.addAll(hearingAidProfile.getConnectedDevices());
+        }
+        return deviceList.stream()
+                .distinct()
+                .filter(d -> !mCachedDeviceManager.isSubDevice(d)).collect(Collectors.toList());
+    }
+
+    private boolean isHearingAidSupported() {
         if (mBluetoothAdapter == null || !mBluetoothAdapter.isEnabled()) {
             return false;
         }
         final List<Integer> supportedList = mBluetoothAdapter.getSupportedProfiles();
-        return supportedList.contains(BluetoothProfile.HEARING_AID);
+        return supportedList.contains(BluetoothProfile.HEARING_AID)
+                || supportedList.contains(BluetoothProfile.HAP_CLIENT);
+    }
+
+    private boolean isAnyHearingAidRelatedProfilesNotReady() {
+        HearingAidProfile hearingAidProfile = mProfileManager.getHearingAidProfile();
+        if (hearingAidProfile != null && !hearingAidProfile.isProfileReady()) {
+            return true;
+        }
+        HapClientProfile hapClientProfile = mProfileManager.getHapClientProfile();
+        if (hapClientProfile != null && !hapClientProfile.isProfileReady()) {
+            return true;
+        }
+        return false;
     }
 
     private LocalBluetoothManager getLocalBluetoothManager() {
diff --git a/src/com/android/settings/accessibility/HearingAidUtils.java b/src/com/android/settings/accessibility/HearingAidUtils.java
index dcbac5b..42484f9 100644
--- a/src/com/android/settings/accessibility/HearingAidUtils.java
+++ b/src/com/android/settings/accessibility/HearingAidUtils.java
@@ -23,7 +23,7 @@
 
 import com.android.settings.bluetooth.HearingAidPairingDialogFragment;
 import com.android.settingslib.bluetooth.CachedBluetoothDevice;
-import com.android.settingslib.bluetooth.HearingAidProfile;
+import com.android.settingslib.bluetooth.HearingAidInfo;
 
 /** Provides utility methods related hearing aids. */
 public final class HearingAidUtils {
@@ -40,8 +40,8 @@
      */
     public static void launchHearingAidPairingDialog(FragmentManager fragmentManager,
             @NonNull CachedBluetoothDevice device) {
-        if (device.isConnectedHearingAidDevice()
-                && device.getDeviceMode() == HearingAidProfile.DeviceMode.MODE_BINAURAL
+        if (device.isConnectedAshaHearingAidDevice()
+                && device.getDeviceMode() == HearingAidInfo.DeviceMode.MODE_BINAURAL
                 && device.getSubDevice() == null) {
             launchHearingAidPairingDialogInternal(fragmentManager, device);
         }
@@ -49,7 +49,7 @@
 
     private static void launchHearingAidPairingDialogInternal(FragmentManager fragmentManager,
             @NonNull CachedBluetoothDevice device) {
-        if (device.getDeviceSide() == HearingAidProfile.DeviceSide.SIDE_INVALID) {
+        if (device.getDeviceSide() == HearingAidInfo.DeviceSide.SIDE_INVALID) {
             Log.w(TAG, "Can not launch hearing aid pairing dialog for invalid side");
             return;
         }
diff --git a/src/com/android/settings/applications/AppStateClonedAppsBridge.java b/src/com/android/settings/applications/AppStateClonedAppsBridge.java
new file mode 100644
index 0000000..7feaa3b
--- /dev/null
+++ b/src/com/android/settings/applications/AppStateClonedAppsBridge.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.applications;
+
+import static android.content.pm.PackageManager.GET_ACTIVITIES;
+
+import static com.android.settingslib.applications.ApplicationsState.AppEntry;
+import static com.android.settingslib.applications.ApplicationsState.AppFilter;
+
+import android.content.Context;
+import android.util.Log;
+
+import com.android.settings.Utils;
+import com.android.settingslib.applications.ApplicationsState;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Filter to display only allowlisted apps on Cloned Apps page.
+ */
+public class AppStateClonedAppsBridge extends AppStateBaseBridge{
+
+    private static final String TAG = "ClonedAppsBridge";
+
+    private final Context mContext;
+    private final List<String> mAllowedApps;
+    private List<String> mCloneProfileApps = new ArrayList<>();
+
+    public AppStateClonedAppsBridge(Context context, ApplicationsState appState,
+            Callback callback) {
+        super(appState, callback);
+        mContext = context;
+        mAllowedApps = Arrays.asList(mContext.getResources()
+                .getStringArray(com.android.internal.R.array.cloneable_apps));
+
+        int cloneUserId = Utils.getCloneUserId(mContext);
+        if (cloneUserId != -1) {
+            mCloneProfileApps = mContext.getPackageManager()
+                    .getInstalledPackagesAsUser(GET_ACTIVITIES,
+                            cloneUserId).stream().map(x -> x.packageName).toList();
+        }
+    }
+
+    @Override
+    protected void loadAllExtraInfo() {
+        final List<ApplicationsState.AppEntry> allApps = mAppSession.getAllApps();
+        for (int i = 0; i < allApps.size(); i++) {
+            ApplicationsState.AppEntry app = allApps.get(i);
+            this.updateExtraInfo(app, app.info.packageName, app.info.uid);
+        }
+    }
+
+    @Override
+    protected void updateExtraInfo(AppEntry app, String pkg, int uid) {
+        // Display package if allowlisted but not yet cloned.
+        // Or if the app is present in clone profile alongwith being in allowlist.
+        if (mAllowedApps.contains(pkg) && ((!mCloneProfileApps.contains(pkg) || (app.isCloned)))) {
+            app.extraInfo = Boolean.TRUE;
+        } else {
+            app.extraInfo = Boolean.FALSE;
+        }
+    }
+
+    public static final AppFilter FILTER_APPS_CLONE =
+            new AppFilter() {
+                @Override
+                public void init() {
+                }
+
+                @Override
+                public boolean filterApp(AppEntry entry) {
+                    if (entry.extraInfo == null) {
+                        Log.d(TAG, "[" + entry.info.packageName + "]" + " has No extra info.");
+                        return false;
+                    }
+                    return (Boolean) entry.extraInfo;
+                }
+            };
+}
diff --git a/src/com/android/settings/applications/ClonedAppsPreferenceController.java b/src/com/android/settings/applications/ClonedAppsPreferenceController.java
index 76ccf06..96fad6b 100644
--- a/src/com/android/settings/applications/ClonedAppsPreferenceController.java
+++ b/src/com/android/settings/applications/ClonedAppsPreferenceController.java
@@ -16,31 +16,100 @@
 
 package com.android.settings.applications;
 
-import static com.android.settings.core.SettingsUIDeviceConfig.CLONED_APPS_ENABLED;
+import static android.content.pm.PackageManager.GET_ACTIVITIES;
+
+import static com.android.settings.Utils.PROPERTY_CLONED_APPS_ENABLED;
 
 import android.content.Context;
+import android.os.AsyncTask;
+import android.os.UserHandle;
 import android.provider.DeviceConfig;
 
+import androidx.lifecycle.Lifecycle;
+import androidx.lifecycle.LifecycleObserver;
+import androidx.lifecycle.OnLifecycleEvent;
+import androidx.preference.Preference;
+import androidx.preference.PreferenceScreen;
+
+import com.android.settings.R;
+import com.android.settings.Utils;
 import com.android.settings.core.BasePreferenceController;
 
+import java.util.Arrays;
+import java.util.List;
+
 /**
  * A preference controller handling the logic for updating the summary of cloned apps.
  */
-public class ClonedAppsPreferenceController extends BasePreferenceController {
+public class ClonedAppsPreferenceController extends BasePreferenceController
+        implements LifecycleObserver {
+    private Preference mPreference;
+    private Context mContext;
 
     public ClonedAppsPreferenceController(Context context, String preferenceKey) {
         super(context, preferenceKey);
+        mContext = context;
     }
 
     @Override
-    public CharSequence getSummary() {
-        // todo(b/249916469): Update summary once we have mechanism of allowlisting available
-        //  for cloned apps.
-        return null;
-    }
-    @Override
     public int getAvailabilityStatus() {
-        return DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_SETTINGS_UI,
-                CLONED_APPS_ENABLED, false) ? AVAILABLE : UNSUPPORTED_ON_DEVICE;
+        return DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_APP_CLONING,
+                PROPERTY_CLONED_APPS_ENABLED, false) ? AVAILABLE : UNSUPPORTED_ON_DEVICE;
+    }
+
+    @Override
+    public void displayPreference(PreferenceScreen screen) {
+        super.displayPreference(screen);
+        mPreference = screen.findPreference(getPreferenceKey());
+    }
+    /**
+     * On lifecycle resume event.
+     */
+    @OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
+    public void onResume() {
+        updatePreferenceSummary();
+    }
+
+    private void updatePreferenceSummary() {
+        new AsyncTask<Void, Void, Integer[]>() {
+
+            @Override
+            protected Integer[] doInBackground(Void... unused) {
+                // Get list of allowlisted cloneable apps.
+                List<String> cloneableApps = Arrays.asList(
+                        mContext.getResources().getStringArray(
+                                com.android.internal.R.array.cloneable_apps));
+                List<String> primaryUserApps = mContext.getPackageManager()
+                        .getInstalledPackagesAsUser(GET_ACTIVITIES,
+                                UserHandle.myUserId()).stream().map(x -> x.packageName).toList();
+                // Count number of installed apps in system user.
+                int availableAppsCount = (int) cloneableApps.stream()
+                        .filter(x -> primaryUserApps.contains(x)).count();
+
+                int cloneUserId = Utils.getCloneUserId(mContext);
+                if (cloneUserId == -1) {
+                    return new Integer[]{0, availableAppsCount};
+                }
+                // Get all apps in clone profile if present.
+                List<String> cloneProfileApps = mContext.getPackageManager()
+                        .getInstalledPackagesAsUser(GET_ACTIVITIES,
+                                cloneUserId).stream().map(x -> x.packageName).toList();
+                // Count number of allowlisted app present in clone profile.
+                int clonedAppsCount = (int) cloneableApps.stream()
+                        .filter(x -> cloneProfileApps.contains(x)).count();
+
+                return new Integer[]{clonedAppsCount, availableAppsCount - clonedAppsCount};
+            }
+
+            @Override
+            protected void onPostExecute(Integer[] countInfo) {
+                updateSummary(countInfo[0], countInfo[1]);
+            }
+        }.execute();
+    }
+
+    private void updateSummary(int clonedAppsCount, int availableAppsCount) {
+        mPreference.setSummary(mContext.getResources().getString(
+                R.string.cloned_apps_summary, clonedAppsCount, availableAppsCount));
     }
 }
diff --git a/src/com/android/settings/applications/RecentAppStatsMixin.java b/src/com/android/settings/applications/RecentAppStatsMixin.java
index 03b2203..6705b25 100644
--- a/src/com/android/settings/applications/RecentAppStatsMixin.java
+++ b/src/com/android/settings/applications/RecentAppStatsMixin.java
@@ -34,7 +34,6 @@
 import androidx.annotation.NonNull;
 import androidx.annotation.VisibleForTesting;
 
-import com.android.settings.Utils;
 import com.android.settingslib.applications.AppUtils;
 import com.android.settingslib.applications.ApplicationsState;
 import com.android.settingslib.core.lifecycle.LifecycleObserver;
@@ -49,6 +48,7 @@
 import java.util.Map;
 import java.util.Optional;
 import java.util.Set;
+import java.util.stream.Collectors;
 
 /**
  * A helper class that loads recent app data in the background and sends it in a callback to a
@@ -65,10 +65,8 @@
     private final int mMaximumApps;
     private final Context mContext;
     private final PackageManager mPm;
+    private final UserManager mUserManager;
     private final PowerManager mPowerManager;
-    private final int mWorkUserId;
-    private final UsageStatsManager mPersonalUsageStatsManager;
-    private final Optional<UsageStatsManager> mWorkUsageStatsManager;
     private final ApplicationsState mApplicationsState;
     private final List<RecentAppStatsListener> mAppStatsListeners;
     private Calendar mCalendar;
@@ -89,13 +87,7 @@
         mMaximumApps = maximumApps;
         mPm = mContext.getPackageManager();
         mPowerManager = mContext.getSystemService(PowerManager.class);
-        final UserManager userManager = mContext.getSystemService(UserManager.class);
-        mWorkUserId = Utils.getManagedProfileId(userManager, UserHandle.myUserId());
-        mPersonalUsageStatsManager = mContext.getSystemService(UsageStatsManager.class);
-        final UserHandle workUserHandle = Utils.getManagedProfile(userManager);
-        mWorkUsageStatsManager = Optional.ofNullable(workUserHandle).map(
-                handle -> mContext.createContextAsUser(handle, /* flags */ 0)
-                        .getSystemService(UsageStatsManager.class));
+        mUserManager = mContext.getSystemService(UserManager.class);
         mApplicationsState = ApplicationsState.getInstance(
                 (Application) mContext.getApplicationContext());
         mRecentApps = new ArrayList<>();
@@ -122,34 +114,34 @@
         mCalendar = Calendar.getInstance();
         mCalendar.add(Calendar.DAY_OF_YEAR, -1);
 
-        final int personalUserId = UserHandle.myUserId();
-        final List<UsageStats> personalStats =
-                getRecentAppsStats(mPersonalUsageStatsManager, personalUserId);
-        final List<UsageStats> workStats = mWorkUsageStatsManager
-                .map(statsManager -> getRecentAppsStats(statsManager, mWorkUserId))
-                .orElse(new ArrayList<>());
+        List<UsageStatsWrapper> usageStatsAllUsers = new ArrayList<>();
 
-        // Both lists are already sorted, so we can create a sorted merge in linear time
-        int personal = 0;
-        int work = 0;
-        while (personal < personalStats.size() && work < workStats.size()
-                && mRecentApps.size() < limit) {
-            UsageStats currentPersonal = personalStats.get(personal);
-            UsageStats currentWork = workStats.get(work);
-            if (currentPersonal.getLastTimeUsed() > currentWork.getLastTimeUsed()) {
-                mRecentApps.add(new UsageStatsWrapper(currentPersonal, personalUserId));
-                personal++;
+        List<UserHandle> profiles = mUserManager.getUserProfiles();
+        for (UserHandle userHandle : profiles) {
+            int userId = userHandle.getIdentifier();
+
+            final Optional<UsageStatsManager> usageStatsManager;
+            if (userHandle.getIdentifier() == UserHandle.myUserId()) {
+                usageStatsManager = Optional.ofNullable(userHandle).map(
+                        handle -> mContext.getSystemService(UsageStatsManager.class));
             } else {
-                mRecentApps.add(new UsageStatsWrapper(currentWork, mWorkUserId));
-                work++;
+                usageStatsManager = Optional.ofNullable(userHandle).map(
+                        handle -> mContext.createContextAsUser(handle, /* flags */ 0)
+                                .getSystemService(UsageStatsManager.class));
             }
+
+            List<UsageStats> profileStats = usageStatsManager
+                    .map(statsManager -> getRecentAppsStats(statsManager, userId))
+                    .orElse(new ArrayList<>());
+            usageStatsAllUsers.addAll(profileStats.stream()
+                        .map(usageStats-> new UsageStatsWrapper(usageStats, userId))
+                        .collect(Collectors.toList()));
         }
-        while (personal < personalStats.size() && mRecentApps.size() < limit) {
-            mRecentApps.add(new UsageStatsWrapper(personalStats.get(personal++), personalUserId));
-        }
-        while (work < workStats.size() && mRecentApps.size() < limit) {
-            mRecentApps.add(new UsageStatsWrapper(workStats.get(work++), mWorkUserId));
-        }
+
+        // Sort apps by latest timestamp.
+        usageStatsAllUsers.sort(
+                Comparator.comparingLong(a -> -1 * a.mUsageStats.getLastTimeUsed()));
+        mRecentApps.addAll(usageStatsAllUsers.stream().limit(limit).collect(Collectors.toList()));
     }
 
     private List<UsageStats> getRecentAppsStats(UsageStatsManager usageStatsManager, int userId) {
diff --git a/src/com/android/settings/applications/manageapplications/AppFilterRegistry.java b/src/com/android/settings/applications/manageapplications/AppFilterRegistry.java
index b48bdbb..1e6ecd8 100644
--- a/src/com/android/settings/applications/manageapplications/AppFilterRegistry.java
+++ b/src/com/android/settings/applications/manageapplications/AppFilterRegistry.java
@@ -21,6 +21,7 @@
 import com.android.settings.R;
 import com.android.settings.applications.AppStateAlarmsAndRemindersBridge;
 import com.android.settings.applications.AppStateAppBatteryUsageBridge;
+import com.android.settings.applications.AppStateClonedAppsBridge;
 import com.android.settings.applications.AppStateInstallAppsBridge;
 import com.android.settings.applications.AppStateLocaleBridge;
 import com.android.settings.applications.AppStateLongBackgroundTasksBridge;
@@ -63,6 +64,7 @@
                 FILTER_APPS_BATTERY_OPTIMIZED,
                 FILTER_APPS_BATTERY_RESTRICTED,
                 FILTER_LONG_BACKGROUND_TASKS,
+                FILTER_APPS_CLONE,
             })
     @interface FilterType {}
 
@@ -92,8 +94,9 @@
     public static final int FILTER_APPS_BATTERY_OPTIMIZED = 22;
     public static final int FILTER_APPS_BATTERY_RESTRICTED = 23;
     public static final int FILTER_LONG_BACKGROUND_TASKS = 24;
-    // Next id: 25. If you add an entry here, please change NUM_FILTER_ENTRIES.
-    private static final int NUM_FILTER_ENTRIES = 25;
+    public static final int FILTER_APPS_CLONE = 25;
+    // Next id: 26. If you add an entry here, please change NUM_FILTER_ENTRIES.
+    private static final int NUM_FILTER_ENTRIES = 26;
 
     private static AppFilterRegistry sRegistry;
 
@@ -251,10 +254,15 @@
                 AppStateLongBackgroundTasksBridge.FILTER_LONG_JOBS_APPS,
                 FILTER_LONG_BACKGROUND_TASKS,
                 R.string.long_background_tasks_title);
+
+        // Apps that are cloneable or cloned.
+        mFilters[FILTER_APPS_CLONE] =
+                new AppFilterItem(
+                        AppStateClonedAppsBridge.FILTER_APPS_CLONE,
+                        FILTER_APPS_CLONE,
+                        R.string.cloned_apps_dashboard_title);
     }
 
-
-
     public static AppFilterRegistry getInstance() {
         if (sRegistry == null) {
             sRegistry = new AppFilterRegistry();
@@ -291,6 +299,8 @@
                 return FILTER_APPS_BATTERY_OPTIMIZED;
             case ManageApplications.LIST_TYPE_LONG_BACKGROUND_TASKS:
                 return FILTER_LONG_BACKGROUND_TASKS;
+            case ManageApplications.LIST_TYPE_CLONED_APPS:
+                return FILTER_APPS_CLONE;
             default:
                 return FILTER_APPS_ALL;
         }
diff --git a/src/com/android/settings/applications/manageapplications/ApplicationViewHolder.java b/src/com/android/settings/applications/manageapplications/ApplicationViewHolder.java
index d1d286d..f3f4b0f 100644
--- a/src/com/android/settings/applications/manageapplications/ApplicationViewHolder.java
+++ b/src/com/android/settings/applications/manageapplications/ApplicationViewHolder.java
@@ -16,6 +16,9 @@
 
 package com.android.settings.applications.manageapplications;
 
+import static com.android.settings.applications.manageapplications.ManageApplications.LIST_TYPE_CLONED_APPS;
+
+import android.content.Context;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.graphics.drawable.Drawable;
@@ -49,6 +52,8 @@
     @VisibleForTesting
     final Switch mSwitch;
 
+    private static int sListType;
+
     private final ImageView mAppIcon;
 
     ApplicationViewHolder(View itemView) {
@@ -65,15 +70,31 @@
         return newView(parent, false /* twoTarget */);
     }
 
+    static View newView(ViewGroup parent , boolean twoTarget, int listType, Context context) {
+        sListType = listType;
+        return newView(parent, twoTarget);
+    }
+
     static View newView(ViewGroup parent, boolean twoTarget) {
         ViewGroup view = (ViewGroup) LayoutInflater.from(parent.getContext())
                 .inflate(R.layout.preference_app, parent, false);
         final ViewGroup widgetFrame = view.findViewById(android.R.id.widget_frame);
         if (twoTarget) {
             if (widgetFrame != null) {
-                LayoutInflater.from(parent.getContext())
-                        .inflate(R.layout.preference_widget_primary_switch, widgetFrame, true);
-
+                if (sListType == LIST_TYPE_CLONED_APPS) {
+                    LayoutInflater.from(parent.getContext())
+                            .inflate(R.layout.preference_widget_add, widgetFrame, true);
+                    //todo(b/259022623): Invoke the clone backend flow i.e.
+                    // i) upon onclick of add icon, create new clone profile the first time
+                    // and clone an app.
+                    // ii) Show progress bar while app is being cloned
+                    // iii) And upon onClick of trash icon, delete the cloned app instance
+                    // from clone profile.
+                    // iv) Log metrics
+                } else {
+                    LayoutInflater.from(parent.getContext())
+                            .inflate(R.layout.preference_widget_primary_switch, widgetFrame, true);
+                }
                 View divider = LayoutInflater.from(parent.getContext()).inflate(
                         R.layout.preference_two_target_divider, view, false);
                 // second to last, before widget frame
diff --git a/src/com/android/settings/applications/manageapplications/ManageApplications.java b/src/com/android/settings/applications/manageapplications/ManageApplications.java
index 4701d0d..ce92459 100644
--- a/src/com/android/settings/applications/manageapplications/ManageApplications.java
+++ b/src/com/android/settings/applications/manageapplications/ManageApplications.java
@@ -92,6 +92,7 @@
 import com.android.settings.Settings.AlarmsAndRemindersActivity;
 import com.android.settings.Settings.AppBatteryUsageActivity;
 import com.android.settings.Settings.ChangeWifiStateActivity;
+import com.android.settings.Settings.ClonedAppsListActivity;
 import com.android.settings.Settings.HighPowerApplicationsActivity;
 import com.android.settings.Settings.LongBackgroundTasksActivity;
 import com.android.settings.Settings.ManageExternalSourcesActivity;
@@ -109,6 +110,7 @@
 import com.android.settings.applications.AppStateAppBatteryUsageBridge;
 import com.android.settings.applications.AppStateAppOpsBridge.PermissionState;
 import com.android.settings.applications.AppStateBaseBridge;
+import com.android.settings.applications.AppStateClonedAppsBridge;
 import com.android.settings.applications.AppStateInstallAppsBridge;
 import com.android.settings.applications.AppStateLocaleBridge;
 import com.android.settings.applications.AppStateLongBackgroundTasksBridge;
@@ -250,6 +252,7 @@
     public static final int LIST_TYPE_APPS_LOCALE = 14;
     public static final int LIST_TYPE_BATTERY_OPTIMIZATION = 15;
     public static final int LIST_TYPE_LONG_BACKGROUND_TASKS = 16;
+    public static final int LIST_TYPE_CLONED_APPS = 17;
 
     // List types that should show instant apps.
     public static final Set<Integer> LIST_TYPES_WITH_INSTANT = new ArraySet<>(Arrays.asList(
@@ -544,6 +547,8 @@
                 return SettingsEnums.BATTERY_OPTIMIZED_APPS_LIST;
             case LIST_TYPE_LONG_BACKGROUND_TASKS:
                 return SettingsEnums.LONG_BACKGROUND_TASKS;
+            case LIST_TYPE_CLONED_APPS:
+                return SettingsEnums.CLONED_APPS;
             default:
                 return SettingsEnums.PAGE_UNKNOWN;
         }
@@ -554,12 +559,19 @@
         super.onStart();
         updateView();
         if (mApplications != null) {
-            mApplications.resume(mSortOrder);
             mApplications.updateLoading();
         }
     }
 
     @Override
+    public void onResume() {
+        super.onResume();
+        if (mApplications != null) {
+            mApplications.resume(mSortOrder);
+        }
+    }
+
+    @Override
     public void onSaveInstanceState(Bundle outState) {
         super.onSaveInstanceState(outState);
         mResetAppsHelper.onSaveInstanceState(outState);
@@ -577,11 +589,16 @@
     }
 
     @Override
-    public void onStop() {
-        super.onStop();
+    public void onPause() {
+        super.onPause();
         if (mApplications != null) {
             mApplications.pause();
         }
+    }
+
+    @Override
+    public void onStop() {
+        super.onStop();
         if (mResetAppsHelper != null) {
             mResetAppsHelper.stop();
         }
@@ -798,9 +815,11 @@
                 && mSortOrder != R.id.sort_order_size);
 
         mOptionsMenu.findItem(R.id.show_system).setVisible(!mShowSystem
-                && mListType != LIST_TYPE_HIGH_POWER && mListType != LIST_TYPE_APPS_LOCALE);
+                && mListType != LIST_TYPE_HIGH_POWER && mListType != LIST_TYPE_APPS_LOCALE
+                && mListType != LIST_TYPE_CLONED_APPS);
         mOptionsMenu.findItem(R.id.hide_system).setVisible(mShowSystem
-                && mListType != LIST_TYPE_HIGH_POWER && mListType != LIST_TYPE_APPS_LOCALE);
+                && mListType != LIST_TYPE_HIGH_POWER && mListType != LIST_TYPE_APPS_LOCALE
+                && mListType != LIST_TYPE_CLONED_APPS);
 
         mOptionsMenu.findItem(R.id.reset_app_preferences).setVisible(mListType == LIST_TYPE_MAIN);
 
@@ -983,6 +1002,8 @@
             screenTitle = R.string.app_battery_usage_title;
         } else if (className.equals(LongBackgroundTasksActivity.class.getName())) {
             screenTitle = R.string.long_background_tasks_title;
+        } else if (className.equals(ClonedAppsListActivity.class.getName())) {
+            screenTitle = R.string.cloned_apps_dashboard_title;
         } else {
             if (screenTitle == -1) {
                 screenTitle = R.string.all_apps;
@@ -1111,6 +1132,7 @@
         private static final int VIEW_TYPE_APP = 0;
         private static final int VIEW_TYPE_EXTRA_VIEW = 1;
         private static final int VIEW_TYPE_APP_HEADER = 2;
+        private static final int VIEW_TYPE_TWO_TARGET = 3;
 
         private final ApplicationsState mState;
         private final ApplicationsState.Session mSession;
@@ -1188,6 +1210,8 @@
                 mExtraInfoBridge = new AppStateAppBatteryUsageBridge(mContext, mState, this);
             } else if (mManageApplications.mListType == LIST_TYPE_LONG_BACKGROUND_TASKS) {
                 mExtraInfoBridge = new AppStateLongBackgroundTasksBridge(mContext, mState, this);
+            } else if (mManageApplications.mListType == LIST_TYPE_CLONED_APPS) {
+                mExtraInfoBridge = new AppStateClonedAppsBridge(mContext, mState, this);
             } else {
                 mExtraInfoBridge = null;
             }
@@ -1301,6 +1325,14 @@
                         R.string.desc_app_locale_selection_supported);
             } else if (mManageApplications.mListType == LIST_TYPE_NOTIFICATION) {
                 view = ApplicationViewHolder.newView(parent, true /* twoTarget */);
+            } else if (mManageApplications.mListType == LIST_TYPE_CLONED_APPS
+                    && viewType == VIEW_TYPE_APP_HEADER) {
+                view = ApplicationViewHolder.newHeader(parent,
+                        R.string.desc_cloned_apps_intro_text);
+            } else if (mManageApplications.mListType == LIST_TYPE_CLONED_APPS
+                    && viewType == VIEW_TYPE_TWO_TARGET) {
+                view = ApplicationViewHolder.newView(
+                        parent, true, LIST_TYPE_CLONED_APPS, mContext);
             } else {
                 view = ApplicationViewHolder.newView(parent, false /* twoTarget */);
             }
@@ -1309,8 +1341,11 @@
 
         @Override
         public int getItemViewType(int position) {
-            if (position == 0 && mManageApplications.mListType == LIST_TYPE_APPS_LOCALE) {
+            if (position == 0 && (mManageApplications.mListType == LIST_TYPE_APPS_LOCALE
+                    || mManageApplications.mListType == LIST_TYPE_CLONED_APPS)) {
                 return VIEW_TYPE_APP_HEADER;
+            } else if (mManageApplications.mListType == LIST_TYPE_CLONED_APPS) {
+                return VIEW_TYPE_TWO_TARGET;
             }
             return VIEW_TYPE_APP;
         }
@@ -1570,7 +1605,8 @@
         @Override
         public int getItemCount() {
             int count = getApplicationCount();
-            if (count != 0 && mManageApplications.mListType == LIST_TYPE_APPS_LOCALE) {
+            if (count != 0 && (mManageApplications.mListType == LIST_TYPE_APPS_LOCALE
+                    || mManageApplications.mListType == LIST_TYPE_CLONED_APPS)) {
                 count++;
             }
             return count;
@@ -1720,6 +1756,9 @@
                 case LIST_TYPE_LONG_BACKGROUND_TASKS:
                     holder.setSummary(LongBackgroundTasksDetails.getSummary(mContext, entry));
                     break;
+                case LIST_TYPE_CLONED_APPS:
+                    holder.setSummary(null);
+                    break;
                 default:
                     holder.updateSizeText(entry, mManageApplications.mInvalidSizeStr, mWhichSize);
                     break;
@@ -1741,6 +1780,9 @@
                         holder.setSummary(null);
                     }
                     break;
+                case LIST_TYPE_CLONED_APPS:
+                    //todo(b/259022623): Attach onClick listener here.
+                    break;
             }
         }
 
@@ -1754,7 +1796,7 @@
         public static int getApplicationPosition(int listType, int position) {
             int applicationPosition = position;
             // Adjust position due to header added.
-            if (listType == LIST_TYPE_APPS_LOCALE) {
+            if (listType == LIST_TYPE_APPS_LOCALE || listType == LIST_TYPE_CLONED_APPS) {
                 applicationPosition = position > 0 ? position - 1 : RecyclerView.NO_POSITION;
             }
             return applicationPosition;
diff --git a/src/com/android/settings/applications/manageapplications/ManageApplicationsUtil.kt b/src/com/android/settings/applications/manageapplications/ManageApplicationsUtil.kt
index 544b68d..c869fc5 100644
--- a/src/com/android/settings/applications/manageapplications/ManageApplicationsUtil.kt
+++ b/src/com/android/settings/applications/manageapplications/ManageApplicationsUtil.kt
@@ -21,6 +21,7 @@
 import com.android.settings.Settings.AlarmsAndRemindersActivity
 import com.android.settings.Settings.AppBatteryUsageActivity
 import com.android.settings.Settings.ChangeWifiStateActivity
+import com.android.settings.Settings.ClonedAppsListActivity
 import com.android.settings.Settings.GamesStorageActivity
 import com.android.settings.Settings.HighPowerApplicationsActivity
 import com.android.settings.Settings.LongBackgroundTasksActivity
@@ -38,6 +39,7 @@
 import com.android.settings.applications.manageapplications.ManageApplications.LIST_TYPE_ALARMS_AND_REMINDERS
 import com.android.settings.applications.manageapplications.ManageApplications.LIST_TYPE_APPS_LOCALE
 import com.android.settings.applications.manageapplications.ManageApplications.LIST_TYPE_BATTERY_OPTIMIZATION
+import com.android.settings.applications.manageapplications.ManageApplications.LIST_TYPE_CLONED_APPS
 import com.android.settings.applications.manageapplications.ManageApplications.LIST_TYPE_GAMES
 import com.android.settings.applications.manageapplications.ManageApplications.LIST_TYPE_HIGH_POWER
 import com.android.settings.applications.manageapplications.ManageApplications.LIST_TYPE_LONG_BACKGROUND_TASKS
@@ -81,6 +83,7 @@
         AppLocaleDetails::class to LIST_TYPE_APPS_LOCALE,
         AppBatteryUsageActivity::class to LIST_TYPE_BATTERY_OPTIMIZATION,
         LongBackgroundTasksActivity::class to LIST_TYPE_LONG_BACKGROUND_TASKS,
+        ClonedAppsListActivity::class to LIST_TYPE_CLONED_APPS,
     )
 
     @JvmField
diff --git a/src/com/android/settings/applications/specialaccess/pictureinpicture/PictureInPictureDetails.java b/src/com/android/settings/applications/specialaccess/pictureinpicture/PictureInPictureDetails.java
index 3dd428b..1c322ff 100644
--- a/src/com/android/settings/applications/specialaccess/pictureinpicture/PictureInPictureDetails.java
+++ b/src/com/android/settings/applications/specialaccess/pictureinpicture/PictureInPictureDetails.java
@@ -84,7 +84,7 @@
 
     @Override
     public int getMetricsCategory() {
-        return SettingsEnums.SETTINGS_MANAGE_PICTURE_IN_PICTURE;
+        return SettingsEnums.SETTINGS_MANAGE_PICTURE_IN_PICTURE_DETAIL;
     }
 
     /**
diff --git a/src/com/android/settings/bluetooth/AvailableMediaBluetoothDeviceUpdater.java b/src/com/android/settings/bluetooth/AvailableMediaBluetoothDeviceUpdater.java
index 3d8e148..c3d3b82 100644
--- a/src/com/android/settings/bluetooth/AvailableMediaBluetoothDeviceUpdater.java
+++ b/src/com/android/settings/bluetooth/AvailableMediaBluetoothDeviceUpdater.java
@@ -72,7 +72,7 @@
             }
             // If device is Hearing Aid or LE Audio, it is compatible with HFP and A2DP.
             // It would show in Available Devices group.
-            if (cachedDevice.isConnectedHearingAidDevice()
+            if (cachedDevice.isConnectedAshaHearingAidDevice()
                     || cachedDevice.isConnectedLeAudioDevice()) {
                 Log.d(TAG, "isFilterMatched() device : " +
                         cachedDevice.getName() + ", the profile is connected.");
diff --git a/src/com/android/settings/bluetooth/BluetoothDetailsPairOtherController.java b/src/com/android/settings/bluetooth/BluetoothDetailsPairOtherController.java
index e07b0ed..188b4ad 100644
--- a/src/com/android/settings/bluetooth/BluetoothDetailsPairOtherController.java
+++ b/src/com/android/settings/bluetooth/BluetoothDetailsPairOtherController.java
@@ -25,7 +25,7 @@
 import com.android.settings.applications.SpacePreference;
 import com.android.settings.core.SubSettingLauncher;
 import com.android.settingslib.bluetooth.CachedBluetoothDevice;
-import com.android.settingslib.bluetooth.HearingAidProfile;
+import com.android.settingslib.bluetooth.HearingAidInfo;
 import com.android.settingslib.core.lifecycle.Lifecycle;
 import com.android.settingslib.widget.ButtonPreference;
 
@@ -78,7 +78,7 @@
 
     private void updateButtonPreferenceTitle(ButtonPreference preference) {
         final int side = mCachedDevice.getDeviceSide();
-        final int stringRes = (side == HearingAidProfile.DeviceSide.SIDE_LEFT)
+        final int stringRes = (side == HearingAidInfo.DeviceSide.SIDE_LEFT)
                 ? R.string.bluetooth_pair_right_ear_button
                 : R.string.bluetooth_pair_left_ear_button;
 
@@ -103,16 +103,16 @@
     }
 
     private boolean isBinauralMode(CachedBluetoothDevice cachedDevice) {
-        return cachedDevice.getDeviceMode() == HearingAidProfile.DeviceMode.MODE_BINAURAL;
+        return cachedDevice.getDeviceMode() == HearingAidInfo.DeviceMode.MODE_BINAURAL;
     }
 
     private boolean isOnlyOneSideConnected(CachedBluetoothDevice cachedDevice) {
-        if (!cachedDevice.isConnectedHearingAidDevice()) {
+        if (!cachedDevice.isConnectedAshaHearingAidDevice()) {
             return false;
         }
 
         final CachedBluetoothDevice subDevice = cachedDevice.getSubDevice();
-        if (subDevice != null && subDevice.isConnectedHearingAidDevice()) {
+        if (subDevice != null && subDevice.isConnectedAshaHearingAidDevice()) {
             return false;
         }
 
diff --git a/src/com/android/settings/bluetooth/ConnectedBluetoothDeviceUpdater.java b/src/com/android/settings/bluetooth/ConnectedBluetoothDeviceUpdater.java
index 5c3dda3..46c4fc3 100644
--- a/src/com/android/settings/bluetooth/ConnectedBluetoothDeviceUpdater.java
+++ b/src/com/android/settings/bluetooth/ConnectedBluetoothDeviceUpdater.java
@@ -72,7 +72,7 @@
             }
             // If device is Hearing Aid or LE Audio, it is compatible with HFP and A2DP.
             // It would not show in Connected Devices group.
-            if (cachedDevice.isConnectedHearingAidDevice()
+            if (cachedDevice.isConnectedAshaHearingAidDevice()
                     || cachedDevice.isConnectedLeAudioDevice()) {
                 return false;
             }
diff --git a/src/com/android/settings/bluetooth/HearingAidPairingDialogFragment.java b/src/com/android/settings/bluetooth/HearingAidPairingDialogFragment.java
index 5ae7c17..acbfd92 100644
--- a/src/com/android/settings/bluetooth/HearingAidPairingDialogFragment.java
+++ b/src/com/android/settings/bluetooth/HearingAidPairingDialogFragment.java
@@ -31,7 +31,7 @@
 import com.android.settings.core.SubSettingLauncher;
 import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
 import com.android.settingslib.bluetooth.CachedBluetoothDevice;
-import com.android.settingslib.bluetooth.HearingAidProfile;
+import com.android.settingslib.bluetooth.HearingAidInfo;
 import com.android.settingslib.bluetooth.LocalBluetoothManager;
 
 /**
@@ -95,10 +95,10 @@
     public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
         final int deviceSide = mDevice.getDeviceSide();
         final int titleId = R.string.bluetooth_pair_other_ear_dialog_title;
-        final int messageId = (deviceSide == HearingAidProfile.DeviceSide.SIDE_LEFT)
+        final int messageId = (deviceSide == HearingAidInfo.DeviceSide.SIDE_LEFT)
                         ? R.string.bluetooth_pair_other_ear_dialog_left_ear_message
                         : R.string.bluetooth_pair_other_ear_dialog_right_ear_message;
-        final int pairBtnId = (deviceSide == HearingAidProfile.DeviceSide.SIDE_LEFT)
+        final int pairBtnId = (deviceSide == HearingAidInfo.DeviceSide.SIDE_LEFT)
                         ? R.string.bluetooth_pair_other_ear_dialog_right_ear_positive_button
                         : R.string.bluetooth_pair_other_ear_dialog_left_ear_positive_button;
 
@@ -120,7 +120,7 @@
     @Override
     public void onDeviceAttributesChanged() {
         final CachedBluetoothDevice subDevice = mDevice.getSubDevice();
-        if (subDevice != null && subDevice.isConnectedHearingAidDevice()) {
+        if (subDevice != null && subDevice.isConnectedAshaHearingAidDevice()) {
             this.dismiss();
         }
     }
diff --git a/src/com/android/settings/core/SettingsUIDeviceConfig.java b/src/com/android/settings/core/SettingsUIDeviceConfig.java
index 5689067..94074df 100644
--- a/src/com/android/settings/core/SettingsUIDeviceConfig.java
+++ b/src/com/android/settings/core/SettingsUIDeviceConfig.java
@@ -42,9 +42,4 @@
      * {@code true} whether or not event_log for generic actions is enabled. Default is true.
      */
     public static final String GENERIC_EVENT_LOGGING_ENABLED = "event_logging_enabled";
-
-    /**
-     * {@code true} if Cloned Apps menu is available in Apps page. Default is false.
-     */
-    public static final String CLONED_APPS_ENABLED = "cloned_apps_enabled";
 }
diff --git a/src/com/android/settings/dashboard/profileselector/ProfileSelectStorageFragment.java b/src/com/android/settings/dashboard/profileselector/ProfileSelectStorageFragment.java
index c99b169..5babf30 100644
--- a/src/com/android/settings/dashboard/profileselector/ProfileSelectStorageFragment.java
+++ b/src/com/android/settings/dashboard/profileselector/ProfileSelectStorageFragment.java
@@ -17,6 +17,7 @@
 package com.android.settings.dashboard.profileselector;
 
 import android.app.Activity;
+import android.app.settings.SettingsEnums;
 import android.content.Context;
 import android.os.Bundle;
 import android.os.UserHandle;
@@ -41,7 +42,6 @@
 import com.android.settings.deviceinfo.storage.StorageSelectionPreferenceController;
 import com.android.settings.deviceinfo.storage.StorageUsageProgressBarPreferenceController;
 import com.android.settings.deviceinfo.storage.StorageUtils;
-import com.android.settingslib.core.instrumentation.Instrumentable;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -323,7 +323,7 @@
 
     @Override
     public int getMetricsCategory() {
-        return Instrumentable.METRICS_CATEGORY_UNKNOWN;
+        return SettingsEnums.SETTINGS_STORAGE_PROFILE_SELECTOR;
     }
 
     @Override
diff --git a/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java b/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java
index 4cd3475..8ff2336 100644
--- a/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java
+++ b/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java
@@ -656,6 +656,7 @@
         controllers.add(new StylusHandwritingPreferenceController(context));
         controllers.add(new IngressRateLimitPreferenceController((context)));
         controllers.add(new BackAnimationPreferenceController(context, fragment));
+        controllers.add(new PhantomProcessPreferenceController(context));
 
         return controllers;
     }
diff --git a/src/com/android/settings/development/PhantomProcessPreferenceController.java b/src/com/android/settings/development/PhantomProcessPreferenceController.java
new file mode 100644
index 0000000..b277fe1
--- /dev/null
+++ b/src/com/android/settings/development/PhantomProcessPreferenceController.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.development;
+
+import static android.util.FeatureFlagUtils.SETTINGS_ENABLE_MONITOR_PHANTOM_PROCS;
+
+import android.content.Context;
+import android.util.FeatureFlagUtils;
+import android.util.Log;
+
+import androidx.preference.Preference;
+import androidx.preference.SwitchPreference;
+
+import com.android.settings.core.PreferenceControllerMixin;
+import com.android.settingslib.development.DeveloperOptionsPreferenceController;
+
+/**
+ * PreferenceController for MockModem
+ */
+public class PhantomProcessPreferenceController extends
+        DeveloperOptionsPreferenceController implements Preference.OnPreferenceChangeListener,
+        PreferenceControllerMixin {
+
+    private static final String TAG = "PhantomProcessPreferenceController";
+    private static final String DISABLE_PHANTOM_PROCESS_MONITOR_KEY =
+            "disable_phantom_process_monitor";
+
+    public PhantomProcessPreferenceController(Context context) {
+        super(context);
+    }
+
+    @Override
+    public String getPreferenceKey() {
+        return DISABLE_PHANTOM_PROCESS_MONITOR_KEY;
+    }
+
+    @Override
+    public boolean onPreferenceChange(Preference preference, Object newValue) {
+        final boolean isEnabled = (Boolean) newValue; // true means we're disabling this flag.
+        try {
+            FeatureFlagUtils.setEnabled(mContext,
+                    SETTINGS_ENABLE_MONITOR_PHANTOM_PROCS,
+                    !isEnabled);
+        } catch (RuntimeException e) {
+            Log.e(TAG, "Fail to set feature flag: " + e.getMessage());
+        }
+        return true;
+    }
+
+    @Override
+    public void updateState(Preference preference) {
+        try {
+            final boolean isEnabled = !FeatureFlagUtils.isEnabled(mContext,
+                    SETTINGS_ENABLE_MONITOR_PHANTOM_PROCS);
+            ((SwitchPreference) mPreference).setChecked(isEnabled);
+        } catch (RuntimeException e) {
+            Log.e(TAG, "Fail to get feature flag: " + e.getMessage());
+        }
+    }
+
+    @Override
+    protected void onDeveloperOptionsSwitchDisabled() {
+        super.onDeveloperOptionsSwitchDisabled();
+        try {
+            FeatureFlagUtils.setEnabled(mContext,
+                    SETTINGS_ENABLE_MONITOR_PHANTOM_PROCS,
+                    true /* Enable the monitoring */);
+            ((SwitchPreference) mPreference).setChecked(false);
+        } catch (RuntimeException e) {
+            Log.e(TAG, "Fail to set feature flag: " + e.getMessage());
+        }
+    }
+}
diff --git a/src/com/android/settings/fuelgauge/BatteryBroadcastReceiver.java b/src/com/android/settings/fuelgauge/BatteryBroadcastReceiver.java
index 558e0bf..665be1f 100644
--- a/src/com/android/settings/fuelgauge/BatteryBroadcastReceiver.java
+++ b/src/com/android/settings/fuelgauge/BatteryBroadcastReceiver.java
@@ -98,6 +98,7 @@
         final IntentFilter intentFilter = new IntentFilter();
         intentFilter.addAction(Intent.ACTION_BATTERY_CHANGED);
         intentFilter.addAction(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED);
+        intentFilter.addAction(BatteryUtils.BYPASS_DOCK_DEFENDER_ACTION);
 
         final Intent intent = mContext.registerReceiver(this, intentFilter);
         updateBatteryStatus(intent, true /* forceUpdate */);
@@ -132,6 +133,8 @@
                 mBatteryHealth = batteryHealth;
             } else if (PowerManager.ACTION_POWER_SAVE_MODE_CHANGED.equals(intent.getAction())) {
                 mBatteryListener.onBatteryChanged(BatteryUpdateType.BATTERY_SAVER);
+            } else if (BatteryUtils.BYPASS_DOCK_DEFENDER_ACTION.equals(intent.getAction())) {
+                mBatteryListener.onBatteryChanged(BatteryUpdateType.BATTERY_STATUS);
             }
         }
     }
diff --git a/src/com/android/settings/fuelgauge/BatteryInfo.java b/src/com/android/settings/fuelgauge/BatteryInfo.java
index ab89b94..ce441c8 100644
--- a/src/com/android/settings/fuelgauge/BatteryInfo.java
+++ b/src/com/android/settings/fuelgauge/BatteryInfo.java
@@ -33,15 +33,17 @@
 import androidx.annotation.WorkerThread;
 
 import com.android.internal.os.BatteryStatsHistoryIterator;
+import com.android.settings.R;
 import com.android.settings.Utils;
 import com.android.settings.overlay.FeatureFactory;
 import com.android.settings.widget.UsageView;
-import com.android.settingslib.R;
 import com.android.settingslib.fuelgauge.Estimate;
 import com.android.settingslib.fuelgauge.EstimateKt;
 import com.android.settingslib.utils.PowerUtil;
 import com.android.settingslib.utils.StringUtil;
 
+import java.text.NumberFormat;
+
 public class BatteryInfo {
     private static final String TAG = "BatteryInfo";
 
@@ -49,6 +51,7 @@
     public CharSequence remainingLabel;
     public int batteryLevel;
     public int batteryStatus;
+    public int pluggedStatus;
     public boolean discharging = true;
     public boolean isOverheated;
     public long remainingTimeUs = 0;
@@ -253,7 +256,8 @@
         info.mBatteryUsageStats = batteryUsageStats;
         info.batteryLevel = Utils.getBatteryLevel(batteryBroadcast);
         info.batteryPercentString = Utils.formatPercentage(info.batteryLevel);
-        info.mCharging = batteryBroadcast.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0) != 0;
+        info.pluggedStatus = batteryBroadcast.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0);
+        info.mCharging = info.pluggedStatus != 0;
         info.averageTimeToDischarge = estimate.getAverageDischargeTime();
         info.isOverheated = batteryBroadcast.getIntExtra(
                 BatteryManager.EXTRA_HEALTH, BatteryManager.BATTERY_HEALTH_UNKNOWN)
@@ -280,25 +284,37 @@
                 BatteryManager.BATTERY_STATUS_UNKNOWN);
         info.discharging = false;
         info.suggestionLabel = null;
-        if (info.isOverheated && status != BatteryManager.BATTERY_STATUS_FULL) {
+        int dockDefenderMode = BatteryUtils.getCurrentDockDefenderMode(context, info);
+        if ((info.isOverheated && status != BatteryManager.BATTERY_STATUS_FULL
+                && dockDefenderMode == BatteryUtils.DockDefenderMode.DISABLED)
+                || dockDefenderMode == BatteryUtils.DockDefenderMode.ACTIVE) {
+            // Battery defender active, battery charging paused
             info.remainingLabel = null;
             int chargingLimitedResId = R.string.power_charging_limited;
-            info.chargeLabel =
-                context.getString(chargingLimitedResId, info.batteryPercentString);
-        } else if (chargeTimeMs > 0 && status != BatteryManager.BATTERY_STATUS_FULL) {
+            info.chargeLabel = context.getString(chargingLimitedResId, info.batteryPercentString);
+        } else if ((chargeTimeMs > 0 && status != BatteryManager.BATTERY_STATUS_FULL
+                && dockDefenderMode == BatteryUtils.DockDefenderMode.DISABLED)
+                || dockDefenderMode == BatteryUtils.DockDefenderMode.TEMPORARILY_BYPASSED) {
+            // Battery is charging to full
             info.remainingTimeUs = PowerUtil.convertMsToUs(chargeTimeMs);
-            final CharSequence timeString = StringUtil.formatElapsedTime(
-                    context,
-                    PowerUtil.convertUsToMs(info.remainingTimeUs),
-                    false /* withSeconds */,
+            final CharSequence timeString = StringUtil.formatElapsedTime(context,
+                    (double) PowerUtil.convertUsToMs(info.remainingTimeUs), false /* withSeconds */,
                     true /* collapseTimeUnit */);
             int resId = R.string.power_charging_duration;
-            info.remainingLabel = context.getString(
-                    R.string.power_remaining_charging_duration_only, timeString);
+            info.remainingLabel = context.getString(R.string.power_remaining_charging_duration_only,
+                    timeString);
             info.chargeLabel = context.getString(resId, info.batteryPercentString, timeString);
+        } else if (dockDefenderMode == BatteryUtils.DockDefenderMode.FUTURE_BYPASS) {
+            // Dock defender will be triggered in the future, charging will be paused at 90%.
+            final int extraValue = context.getResources().getInteger(
+                    R.integer.config_battery_extra_tip_value);
+            final String extraPercentage = NumberFormat.getPercentInstance().format(
+                    extraValue * 0.01f);
+            info.chargeLabel = context.getString(R.string.power_charging_future_paused,
+                    info.batteryPercentString, extraPercentage);
         } else {
-            final String chargeStatusLabel =
-                    Utils.getBatteryStatus(context, batteryBroadcast, compactStatus);
+            final String chargeStatusLabel = Utils.getBatteryStatus(context, batteryBroadcast,
+                    compactStatus);
             info.remainingLabel = null;
             info.chargeLabel = info.batteryLevel == 100 ? info.batteryPercentString :
                     resources.getString(R.string.power_charging, info.batteryPercentString,
diff --git a/src/com/android/settings/fuelgauge/BatteryUtils.java b/src/com/android/settings/fuelgauge/BatteryUtils.java
index c5a8b00..8bf5e16 100644
--- a/src/com/android/settings/fuelgauge/BatteryUtils.java
+++ b/src/com/android/settings/fuelgauge/BatteryUtils.java
@@ -33,6 +33,7 @@
 import android.os.SystemClock;
 import android.os.UidBatteryConsumer;
 import android.os.UserHandle;
+import android.provider.Settings;
 import android.util.Base64;
 import android.util.Log;
 
@@ -76,6 +77,11 @@
     /** Special UID for aggregated other users. */
     public static final long UID_OTHER_USERS = Long.MIN_VALUE;
 
+    /** Flag to check if the dock defender mode has been temporarily bypassed */
+    public static final String SETTINGS_GLOBAL_DOCK_DEFENDER_BYPASS = "dock_defender_bypass";
+
+    public static final String BYPASS_DOCK_DEFENDER_ACTION = "battery.dock.defender.bypass";
+
     @Retention(RetentionPolicy.SOURCE)
     @IntDef({StatusType.SCREEN_USAGE,
             StatusType.FOREGROUND,
@@ -89,6 +95,18 @@
         int ALL = 3;
     }
 
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef({DockDefenderMode.FUTURE_BYPASS,
+            DockDefenderMode.ACTIVE,
+            DockDefenderMode.TEMPORARILY_BYPASSED,
+            DockDefenderMode.DISABLED})
+    public @interface DockDefenderMode {
+        int FUTURE_BYPASS = 0;
+        int ACTIVE = 1;
+        int TEMPORARILY_BYPASSED = 2;
+        int DISABLED = 3;
+    }
+
     private static final String TAG = "BatteryUtils";
 
     private static BatteryUtils sInstance;
@@ -584,12 +602,20 @@
                 /*receiver=*/ null, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
     }
 
-    /** Gets the battery level from the intent. */
-    public static int getBatteryLevel(Intent intent) {
-        final int level = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1);
-        final int scale = intent.getIntExtra(BatteryManager.EXTRA_SCALE, 0);
-        return scale == 0
-                ? -1 /*invalid battery level*/
-                : Math.round((level / (float) scale) * 100f);
+    /** Gets the current dock defender mode */
+    public static int getCurrentDockDefenderMode(Context context, BatteryInfo batteryInfo) {
+        if (batteryInfo.pluggedStatus == BatteryManager.BATTERY_PLUGGED_DOCK) {
+            if (Settings.Global.getInt(context.getContentResolver(),
+                    SETTINGS_GLOBAL_DOCK_DEFENDER_BYPASS, 0) == 1) {
+                return DockDefenderMode.TEMPORARILY_BYPASSED;
+            } else if (batteryInfo.isOverheated && FeatureFactory.getFactory(context)
+                    .getPowerUsageFeatureProvider(context)
+                    .isExtraDefend()) {
+                return DockDefenderMode.ACTIVE;
+            } else if (!batteryInfo.isOverheated) {
+                return DockDefenderMode.FUTURE_BYPASS;
+            }
+        }
+        return DockDefenderMode.DISABLED;
     }
 }
diff --git a/src/com/android/settings/fuelgauge/PowerUsageFeatureProvider.java b/src/com/android/settings/fuelgauge/PowerUsageFeatureProvider.java
index 2faacb7..b17afa5 100644
--- a/src/com/android/settings/fuelgauge/PowerUsageFeatureProvider.java
+++ b/src/com/android/settings/fuelgauge/PowerUsageFeatureProvider.java
@@ -133,7 +133,7 @@
     /**
      * Gets a intent for one time bypass charge limited to resume charging.
      */
-    Intent getResumeChargeIntent();
+    Intent getResumeChargeIntent(boolean isDockDefender);
 
     /**
      * Returns {@link Set} for hidding applications background usage time.
diff --git a/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImpl.java b/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImpl.java
index ff1edec..856f86a 100644
--- a/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImpl.java
+++ b/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImpl.java
@@ -142,7 +142,7 @@
     }
 
     @Override
-    public Intent getResumeChargeIntent() {
+    public Intent getResumeChargeIntent(boolean isDockDefender) {
         return null;
     }
 
diff --git a/src/com/android/settings/fuelgauge/batterytip/BatteryTipLoader.java b/src/com/android/settings/fuelgauge/batterytip/BatteryTipLoader.java
index 95145ba..7bdc5d5 100644
--- a/src/com/android/settings/fuelgauge/batterytip/BatteryTipLoader.java
+++ b/src/com/android/settings/fuelgauge/batterytip/BatteryTipLoader.java
@@ -24,6 +24,7 @@
 import com.android.settings.fuelgauge.BatteryInfo;
 import com.android.settings.fuelgauge.BatteryUtils;
 import com.android.settings.fuelgauge.batterytip.detectors.BatteryDefenderDetector;
+import com.android.settings.fuelgauge.batterytip.detectors.DockDefenderDetector;
 import com.android.settings.fuelgauge.batterytip.detectors.EarlyWarningDetector;
 import com.android.settings.fuelgauge.batterytip.detectors.HighUsageDetector;
 import com.android.settings.fuelgauge.batterytip.detectors.LowBatteryDetector;
@@ -74,6 +75,7 @@
         tips.add(new EarlyWarningDetector(policy, context).detect());
         tips.add(new BatteryDefenderDetector(
                 batteryInfo, context.getApplicationContext()).detect());
+        tips.add(new DockDefenderDetector(batteryInfo, context.getApplicationContext()).detect());
         Collections.sort(tips);
         return tips;
     }
diff --git a/src/com/android/settings/fuelgauge/batterytip/detectors/BatteryDefenderDetector.java b/src/com/android/settings/fuelgauge/batterytip/detectors/BatteryDefenderDetector.java
index 87d4a0b..08df2e4 100644
--- a/src/com/android/settings/fuelgauge/batterytip/detectors/BatteryDefenderDetector.java
+++ b/src/com/android/settings/fuelgauge/batterytip/detectors/BatteryDefenderDetector.java
@@ -37,11 +37,10 @@
 
     @Override
     public BatteryTip detect() {
-        if (mBatteryInfo.isOverheated) {
-            final boolean extraDefend = FeatureFactory.getFactory(mContext)
-                    .getPowerUsageFeatureProvider(mContext)
-                    .isExtraDefend();
-            return new BatteryDefenderTip(BatteryTip.StateType.NEW, extraDefend);
+        if (mBatteryInfo.isOverheated && !FeatureFactory.getFactory(mContext)
+                .getPowerUsageFeatureProvider(mContext)
+                .isExtraDefend()) {
+            return new BatteryDefenderTip(BatteryTip.StateType.NEW);
         }
         return new BatteryDefenderTip(BatteryTip.StateType.INVISIBLE);
     }
diff --git a/src/com/android/settings/fuelgauge/batterytip/detectors/DockDefenderDetector.java b/src/com/android/settings/fuelgauge/batterytip/detectors/DockDefenderDetector.java
new file mode 100644
index 0000000..8a839d3
--- /dev/null
+++ b/src/com/android/settings/fuelgauge/batterytip/detectors/DockDefenderDetector.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.fuelgauge.batterytip.detectors;
+
+import android.content.Context;
+
+import com.android.settings.fuelgauge.BatteryInfo;
+import com.android.settings.fuelgauge.BatteryUtils;
+import com.android.settings.fuelgauge.batterytip.tips.BatteryTip;
+import com.android.settings.fuelgauge.batterytip.tips.DockDefenderTip;
+
+/**
+ * Detect whether the dock defender mode is enabled.
+ */
+public class DockDefenderDetector implements BatteryTipDetector {
+    private final BatteryInfo mBatteryInfo;
+    private final Context mContext;
+
+    public DockDefenderDetector(BatteryInfo batteryInfo, Context context) {
+        mBatteryInfo = batteryInfo;
+        mContext = context;
+    }
+
+    @Override
+    public BatteryTip detect() {
+        int mode = BatteryUtils.getCurrentDockDefenderMode(mContext, mBatteryInfo);
+        return new DockDefenderTip(
+                mode != BatteryUtils.DockDefenderMode.DISABLED
+                        ? BatteryTip.StateType.NEW
+                        : BatteryTip.StateType.INVISIBLE,
+                mode);
+    }
+
+}
diff --git a/src/com/android/settings/fuelgauge/batterytip/tips/BatteryDefenderTip.java b/src/com/android/settings/fuelgauge/batterytip/tips/BatteryDefenderTip.java
index 2fb5650..1ccc29c 100644
--- a/src/com/android/settings/fuelgauge/batterytip/tips/BatteryDefenderTip.java
+++ b/src/com/android/settings/fuelgauge/batterytip/tips/BatteryDefenderTip.java
@@ -32,24 +32,15 @@
 import com.android.settingslib.HelpUtils;
 import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
 
-import java.text.NumberFormat;
-
 /**
  * Tip to show current battery is overheated
  */
 public class BatteryDefenderTip extends BatteryTip {
 
     private static final String TAG = "BatteryDefenderTip";
-    private boolean mExtraDefend = false;
 
     public BatteryDefenderTip(@StateType int state) {
-        this(state, false);
-    }
-
-    public BatteryDefenderTip(@StateType int state, boolean extraDefend) {
-        super(TipType.BATTERY_DEFENDER, state, true /* showDialog */);
-        mExtraDefend = extraDefend;
-        mShowDialog = false;
+        super(TipType.BATTERY_DEFENDER, state, false /* showDialog */);
     }
 
     private BatteryDefenderTip(Parcel in) {
@@ -63,14 +54,6 @@
 
     @Override
     public CharSequence getSummary(Context context) {
-        if (mExtraDefend) {
-            final int extraValue = context.getResources()
-                    .getInteger(R.integer.config_battery_extra_tip_value);
-            final String extraPercentage = NumberFormat.getPercentInstance()
-                    .format(extraValue * 0.01f);
-            return context.getString(
-                    R.string.battery_tip_limited_temporarily_extra_summary, extraPercentage);
-        }
         return context.getString(R.string.battery_tip_limited_temporarily_summary);
     }
 
@@ -131,7 +114,7 @@
         final Intent intent =
                 FeatureFactory.getFactory(context)
                         .getPowerUsageFeatureProvider(context)
-                        .getResumeChargeIntent();
+                        .getResumeChargeIntent(false);
         if (intent != null) {
             context.sendBroadcast(intent);
         }
diff --git a/src/com/android/settings/fuelgauge/batterytip/tips/BatteryTip.java b/src/com/android/settings/fuelgauge/batterytip/tips/BatteryTip.java
index 5aee029..fcf5e09 100644
--- a/src/com/android/settings/fuelgauge/batterytip/tips/BatteryTip.java
+++ b/src/com/android/settings/fuelgauge/batterytip/tips/BatteryTip.java
@@ -58,7 +58,8 @@
             TipType.REDUCED_BATTERY,
             TipType.LOW_BATTERY,
             TipType.REMOVE_APP_RESTRICTION,
-            TipType.BATTERY_DEFENDER})
+            TipType.BATTERY_DEFENDER,
+            TipType.DOCK_DEFENDER})
     public @interface TipType {
         int SMART_BATTERY_MANAGER = 0;
         int APP_RESTRICTION = 1;
@@ -69,6 +70,7 @@
         int SUMMARY = 6;
         int REMOVE_APP_RESTRICTION = 7;
         int BATTERY_DEFENDER = 8;
+        int DOCK_DEFENDER = 9;
     }
 
     @VisibleForTesting
@@ -78,12 +80,13 @@
         TIP_ORDER.append(TipType.BATTERY_SAVER, 0);
         TIP_ORDER.append(TipType.LOW_BATTERY, 1);
         TIP_ORDER.append(TipType.BATTERY_DEFENDER, 2);
-        TIP_ORDER.append(TipType.APP_RESTRICTION, 3);
-        TIP_ORDER.append(TipType.HIGH_DEVICE_USAGE, 4);
-        TIP_ORDER.append(TipType.SUMMARY, 5);
-        TIP_ORDER.append(TipType.SMART_BATTERY_MANAGER, 6);
-        TIP_ORDER.append(TipType.REDUCED_BATTERY, 7);
-        TIP_ORDER.append(TipType.REMOVE_APP_RESTRICTION, 8);
+        TIP_ORDER.append(TipType.DOCK_DEFENDER, 3);
+        TIP_ORDER.append(TipType.APP_RESTRICTION, 4);
+        TIP_ORDER.append(TipType.HIGH_DEVICE_USAGE, 5);
+        TIP_ORDER.append(TipType.SUMMARY, 6);
+        TIP_ORDER.append(TipType.SMART_BATTERY_MANAGER, 7);
+        TIP_ORDER.append(TipType.REDUCED_BATTERY, 8);
+        TIP_ORDER.append(TipType.REMOVE_APP_RESTRICTION, 9);
     }
 
     private static final String KEY_PREFIX = "key_battery_tip";
diff --git a/src/com/android/settings/fuelgauge/batterytip/tips/DockDefenderTip.java b/src/com/android/settings/fuelgauge/batterytip/tips/DockDefenderTip.java
new file mode 100644
index 0000000..2ba3dcd
--- /dev/null
+++ b/src/com/android/settings/fuelgauge/batterytip/tips/DockDefenderTip.java
@@ -0,0 +1,192 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.fuelgauge.batterytip.tips;
+
+import android.app.settings.SettingsEnums;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Parcel;
+import android.util.Log;
+
+import androidx.preference.Preference;
+
+import com.android.settings.R;
+import com.android.settings.fuelgauge.BatteryUtils;
+import com.android.settings.fuelgauge.BatteryUtils.DockDefenderMode;
+import com.android.settings.overlay.FeatureFactory;
+import com.android.settings.widget.CardPreference;
+import com.android.settingslib.HelpUtils;
+import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
+
+import java.text.NumberFormat;
+
+/**
+ * Tip to show dock defender status
+ */
+public class DockDefenderTip extends BatteryTip {
+    private static final String TAG = "DockDefenderTip";
+    private int mMode;
+
+    public DockDefenderTip(@StateType int state, @DockDefenderMode int mode) {
+        super(TipType.DOCK_DEFENDER, state, false);
+        mMode = mode;
+    }
+
+    private DockDefenderTip(Parcel in) {
+        super(in);
+    }
+
+    public int getMode() {
+        return mMode;
+    }
+
+    @Override
+    public CharSequence getTitle(Context context) {
+        switch (mMode) {
+            case DockDefenderMode.FUTURE_BYPASS:
+                return context.getString(R.string.battery_tip_dock_defender_future_bypass_title,
+                        getExtraPercentage(context));
+            case DockDefenderMode.ACTIVE:
+                return context.getString(R.string.battery_tip_dock_defender_active_title);
+            case DockDefenderMode.TEMPORARILY_BYPASSED:
+                return context.getString(
+                        R.string.battery_tip_dock_defender_temporarily_bypassed_title);
+            default:
+                return null;
+        }
+    }
+
+    @Override
+    public CharSequence getSummary(Context context) {
+        switch (mMode) {
+            case DockDefenderMode.FUTURE_BYPASS:
+                return context.getString(R.string.battery_tip_dock_defender_future_bypass_summary,
+                        getExtraPercentage(context));
+            case DockDefenderMode.ACTIVE:
+                return context.getString(R.string.battery_tip_dock_defender_active_summary,
+                        getExtraPercentage(context));
+            case DockDefenderMode.TEMPORARILY_BYPASSED:
+                return context.getString(
+                        R.string.battery_tip_dock_defender_temporarily_bypassed_summary,
+                        getExtraPercentage(context));
+            default:
+                return null;
+        }
+    }
+
+    @Override
+    public int getIconId() {
+        return R.drawable.ic_battery_status_protected_24dp;
+    }
+
+    @Override
+    public void updateState(BatteryTip tip) {
+        mState = tip.mState;
+        if (tip instanceof DockDefenderTip) {
+            mMode = ((DockDefenderTip) tip).mMode;
+        }
+    }
+
+    @Override
+    public void log(Context context, MetricsFeatureProvider metricsFeatureProvider) {
+        metricsFeatureProvider.action(context, SettingsEnums.ACTION_DOCK_DEFENDER_TIP,
+                mState);
+    }
+
+    @Override
+    public void updatePreference(Preference preference) {
+        super.updatePreference(preference);
+        final Context context = preference.getContext();
+
+        CardPreference cardPreference = castToCardPreferenceSafely(preference);
+        if (cardPreference == null) {
+            Log.e(TAG, "cast Preference to CardPreference failed");
+            return;
+        }
+
+        cardPreference.setSelectable(false);
+        switch (mMode) {
+            case DockDefenderMode.FUTURE_BYPASS:
+            case DockDefenderMode.ACTIVE:
+                cardPreference.setPrimaryButtonText(
+                        context.getString(R.string.battery_tip_charge_to_full_button));
+                cardPreference.setPrimaryButtonClickListener(unused -> {
+                    resumeCharging(context);
+                    mMode = DockDefenderMode.TEMPORARILY_BYPASSED;
+                    context.sendBroadcast(new Intent().setAction(
+                            BatteryUtils.BYPASS_DOCK_DEFENDER_ACTION).setPackage(
+                            context.getPackageName()).addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
+                            | Intent.FLAG_RECEIVER_FOREGROUND));
+                    updatePreference(preference);
+                });
+                cardPreference.setPrimaryButtonVisible(true);
+                break;
+            case DockDefenderMode.TEMPORARILY_BYPASSED:
+                cardPreference.setPrimaryButtonVisible(false);
+                break;
+            default:
+                cardPreference.setVisible(false);
+                return;
+        }
+
+        cardPreference.setSecondaryButtonText(context.getString(R.string.learn_more));
+        //TODO: update helper string
+        cardPreference.setSecondaryButtonClickListener(
+                button -> button.startActivityForResult(
+                        HelpUtils.getHelpIntent(
+                                context,
+                                context.getString(R.string.help_url_battery_defender),
+                                /* backupContext */ ""), /* requestCode */ 0));
+        cardPreference.setSecondaryButtonVisible(true);
+        cardPreference.setSecondaryButtonContentDescription(context.getString(
+                R.string.battery_tip_limited_temporarily_sec_button_content_description));
+
+    }
+
+    private CardPreference castToCardPreferenceSafely(Preference preference) {
+        return preference instanceof CardPreference ? (CardPreference) preference : null;
+    }
+
+    private void resumeCharging(Context context) {
+        final Intent intent =
+                FeatureFactory.getFactory(context)
+                        .getPowerUsageFeatureProvider(context)
+                        .getResumeChargeIntent(true);
+        if (intent != null) {
+            context.sendBroadcast(intent);
+        }
+
+        Log.i(TAG, "send resume charging broadcast intent=" + intent);
+    }
+
+    private String getExtraPercentage(Context context) {
+        final int extraValue = context.getResources()
+                .getInteger(R.integer.config_battery_extra_tip_value);
+        return NumberFormat.getPercentInstance()
+                .format(extraValue * 0.01f);
+    }
+
+    public static final Creator CREATOR = new Creator() {
+        public BatteryTip createFromParcel(Parcel in) {
+            return new DockDefenderTip(in);
+        }
+
+        public BatteryTip[] newArray(int size) {
+            return new DockDefenderTip[size];
+        }
+    };
+}
diff --git a/src/com/android/settings/fuelgauge/batteryusage/BatteryChartPreferenceController.java b/src/com/android/settings/fuelgauge/batteryusage/BatteryChartPreferenceController.java
index 124d4b4..90610f8 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/BatteryChartPreferenceController.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/BatteryChartPreferenceController.java
@@ -629,6 +629,7 @@
             PowerGaugePreference preference, BatteryDiffEntry entry) {
         final long foregroundUsageTimeInMs = entry.mForegroundUsageTimeInMs;
         final long backgroundUsageTimeInMs = entry.mBackgroundUsageTimeInMs;
+        // TODO: update this value after the new API for foreground service is completed.
         final long totalUsageTimeInMs = foregroundUsageTimeInMs + backgroundUsageTimeInMs;
         String usageTimeSummary = null;
         // Not shows summary for some system components without usage time.
diff --git a/src/com/android/settings/fuelgauge/batteryusage/BatteryDiffEntry.java b/src/com/android/settings/fuelgauge/batteryusage/BatteryDiffEntry.java
index 3fb75c3..32711bf 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/BatteryDiffEntry.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/BatteryDiffEntry.java
@@ -52,8 +52,13 @@
             (a, b) -> Double.compare(b.getPercentOfTotal(), a.getPercentOfTotal());
 
     public long mForegroundUsageTimeInMs;
+    public long mForegroundServiceUsageTimeInMs;
     public long mBackgroundUsageTimeInMs;
     public double mConsumePower;
+    public double mForegroundUsageConsumePower;
+    public double mForegroundServiceUsageConsumePower;
+    public double mBackgroundUsageConsumePower;
+    public double mCachedUsageConsumePower;
     // A BatteryHistEntry corresponding to this diff usage data.
     public final BatteryHistEntry mBatteryHistEntry;
 
@@ -78,12 +83,22 @@
     public BatteryDiffEntry(
             Context context,
             long foregroundUsageTimeInMs,
+            long foregroundServiceUsageTimeInMs,
             long backgroundUsageTimeInMs,
             double consumePower,
+            double foregroundUsageConsumePower,
+            double foregroundServiceUsageConsumePower,
+            double backgroundUsageConsumePower,
+            double cachedUsageConsumePower,
             BatteryHistEntry batteryHistEntry) {
         mContext = context;
         mConsumePower = consumePower;
+        mForegroundUsageConsumePower = foregroundUsageConsumePower;
+        mForegroundServiceUsageConsumePower = foregroundServiceUsageConsumePower;
+        mBackgroundUsageConsumePower = backgroundUsageConsumePower;
+        mCachedUsageConsumePower = cachedUsageConsumePower;
         mForegroundUsageTimeInMs = foregroundUsageTimeInMs;
+        mForegroundServiceUsageTimeInMs = foregroundServiceUsageTimeInMs;
         mBackgroundUsageTimeInMs = backgroundUsageTimeInMs;
         mBatteryHistEntry = batteryHistEntry;
         mUserManager = context.getSystemService(UserManager.class);
@@ -106,8 +121,13 @@
         return new BatteryDiffEntry(
                 this.mContext,
                 this.mForegroundUsageTimeInMs,
+                this.mForegroundServiceUsageTimeInMs,
                 this.mBackgroundUsageTimeInMs,
                 this.mConsumePower,
+                this.mForegroundUsageConsumePower,
+                this.mForegroundServiceUsageConsumePower,
+                this.mBackgroundUsageConsumePower,
+                this.mCachedUsageConsumePower,
                 this.mBatteryHistEntry /*same instance*/);
     }
 
@@ -361,10 +381,19 @@
                         mAppLabel, mValidForRestriction))
                 .append(String.format("\n\tconsume=%.2f%% %f/%f",
                         mPercentOfTotal, mConsumePower, mTotalConsumePower))
-                .append(String.format("\n\tforeground:%s background:%s",
-                        StringUtil.formatElapsedTime(mContext, mForegroundUsageTimeInMs,
+                .append(String.format("\n\tconsume power= foreground:%f foregroundService:%f",
+                        mForegroundUsageConsumePower, mForegroundServiceUsageConsumePower))
+                .append(String.format("\n\tconsume power= background:%f cached:%f",
+                        mBackgroundUsageConsumePower, mCachedUsageConsumePower))
+                .append(String.format("\n\ttime= foreground:%s foregroundService:%s background:%s",
+                        StringUtil.formatElapsedTime(mContext, (double) mForegroundUsageTimeInMs,
                                 /*withSeconds=*/ true, /*collapseTimeUnit=*/ false),
-                        StringUtil.formatElapsedTime(mContext, mBackgroundUsageTimeInMs,
+                        StringUtil.formatElapsedTime(
+                                mContext,
+                                (double) mForegroundServiceUsageTimeInMs,
+                                /*withSeconds=*/ true,
+                                /*collapseTimeUnit=*/ false),
+                        StringUtil.formatElapsedTime(mContext, (double) mBackgroundUsageTimeInMs,
                                 /*withSeconds=*/ true, /*collapseTimeUnit=*/ false)))
                 .append(String.format("\n\tpackage:%s|%s uid:%d userId:%d",
                         mBatteryHistEntry.mPackageName, getPackageName(),
diff --git a/src/com/android/settings/fuelgauge/batteryusage/BatteryEntry.java b/src/com/android/settings/fuelgauge/batteryusage/BatteryEntry.java
index cb870f4..36a9248 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/BatteryEntry.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/BatteryEntry.java
@@ -26,6 +26,7 @@
 import android.content.pm.UserInfo;
 import android.graphics.drawable.Drawable;
 import android.os.BatteryConsumer;
+import android.os.BatteryConsumer.Dimensions;
 import android.os.Process;
 import android.os.RemoteException;
 import android.os.UidBatteryConsumer;
@@ -39,7 +40,6 @@
 import com.android.settings.fuelgauge.BatteryUtils;
 import com.android.settingslib.Utils;
 
-import java.util.ArrayList;
 import java.util.Comparator;
 import java.util.HashMap;
 import java.util.Locale;
@@ -73,9 +73,24 @@
     private static final String TAG = "BatteryEntry";
     private static final String PACKAGE_SYSTEM = "android";
 
-    static final HashMap<String, UidToDetail> sUidCache = new HashMap<>();
+    static final int BATTERY_USAGE_INDEX_FOREGROUND = 0;
+    static final int BATTERY_USAGE_INDEX_FOREGROUND_SERVICE = 1;
+    static final int BATTERY_USAGE_INDEX_BACKGROUND = 2;
+    static final int BATTERY_USAGE_INDEX_CACHED = 3;
 
-    static final ArrayList<BatteryEntry> sRequestQueue = new ArrayList<BatteryEntry>();
+    static final Dimensions[] BATTERY_DIMENSIONS = new Dimensions[] {
+            new Dimensions(
+                    BatteryConsumer.POWER_COMPONENT_ANY, BatteryConsumer.PROCESS_STATE_FOREGROUND),
+            new Dimensions(
+                    BatteryConsumer.POWER_COMPONENT_ANY,
+                    BatteryConsumer.PROCESS_STATE_FOREGROUND_SERVICE),
+            new Dimensions(
+                    BatteryConsumer.POWER_COMPONENT_ANY, BatteryConsumer.PROCESS_STATE_BACKGROUND),
+            new Dimensions(
+                    BatteryConsumer.POWER_COMPONENT_ANY, BatteryConsumer.PROCESS_STATE_CACHED),
+    };
+
+    static final HashMap<String, UidToDetail> sUidCache = new HashMap<>();
 
     static Locale sCurrentLocale = null;
 
@@ -97,6 +112,7 @@
     private final int mPowerComponentId;
     private long mUsageDurationMs;
     private long mTimeInForegroundMs;
+    private long mTimeInForegroundServiceMs;
     private long mTimeInBackgroundMs;
 
     public String mName;
@@ -105,6 +121,10 @@
     public double mPercent;
     private String mDefaultPackageName;
     private double mConsumedPower;
+    private double mConsumedPowerInForeground;
+    private double mConsumedPowerInForegroundService;
+    private double mConsumedPowerInBackground;
+    private double mConsumedPowerInCached;
 
     static class UidToDetail {
         String mName;
@@ -156,8 +176,19 @@
             getQuickNameIconForUid(uid, packages, loadDataInBackground);
             mTimeInForegroundMs =
                     uidBatteryConsumer.getTimeInStateMs(UidBatteryConsumer.STATE_FOREGROUND);
+            //TODO: update this to the correct API after the new API is completed.
+            mTimeInForegroundServiceMs =
+                    uidBatteryConsumer.getTimeInStateMs(UidBatteryConsumer.STATE_FOREGROUND);
             mTimeInBackgroundMs =
                     uidBatteryConsumer.getTimeInStateMs(UidBatteryConsumer.STATE_BACKGROUND);
+            mConsumedPowerInForeground = safeGetConsumedPower(
+                    uidBatteryConsumer, BATTERY_DIMENSIONS[BATTERY_USAGE_INDEX_FOREGROUND]);
+            mConsumedPowerInForegroundService = safeGetConsumedPower(
+                    uidBatteryConsumer, BATTERY_DIMENSIONS[BATTERY_USAGE_INDEX_FOREGROUND_SERVICE]);
+            mConsumedPowerInBackground = safeGetConsumedPower(
+                    uidBatteryConsumer, BATTERY_DIMENSIONS[BATTERY_USAGE_INDEX_BACKGROUND]);
+            mConsumedPowerInCached = safeGetConsumedPower(
+                    uidBatteryConsumer, BATTERY_DIMENSIONS[BATTERY_USAGE_INDEX_CACHED]);
         } else if (batteryConsumer instanceof UserBatteryConsumer) {
             mUid = Process.INVALID_UID;
             mConsumerType = ConvertUtils.CONSUMER_TYPE_USER_BATTERY;
@@ -396,7 +427,7 @@
         return mUid;
     }
 
-    /** Returns foreground foreground time/ms that is attributed to this entry. */
+    /** Returns foreground time/ms that is attributed to this entry. */
     public long getTimeInForegroundMs() {
         if (mBatteryConsumer instanceof UidBatteryConsumer) {
             return mTimeInForegroundMs;
@@ -405,6 +436,15 @@
         }
     }
 
+    /** Returns foreground service time/ms that is attributed to this entry. */
+    public long getTimeInForegroundServiceMs() {
+        if (mBatteryConsumer instanceof UidBatteryConsumer) {
+            return mTimeInForegroundServiceMs;
+        } else {
+            return 0;
+        }
+    }
+
     /** Returns background activity time/ms that is attributed to this entry. */
     public long getTimeInBackgroundMs() {
         if (mBatteryConsumer instanceof UidBatteryConsumer) {
@@ -422,6 +462,53 @@
     }
 
     /**
+     * Returns amount of power (in milli-amp-hours) used in foreground that is attributed to this
+     * entry.
+     */
+    public double getConsumedPowerInForeground() {
+        if (mBatteryConsumer instanceof UidBatteryConsumer) {
+            return mConsumedPowerInForeground;
+        } else {
+            return 0;
+        }
+    }
+
+    /**
+     * Returns amount of power (in milli-amp-hours) used in foreground service that is attributed to
+     * this entry.
+     */
+    public double getConsumedPowerInForegroundService() {
+        if (mBatteryConsumer instanceof UidBatteryConsumer) {
+            return mConsumedPowerInForegroundService;
+        } else {
+            return 0;
+        }
+    }
+
+    /**
+     * Returns amount of power (in milli-amp-hours) used in background that is attributed to this
+     * entry.
+     */
+    public double getConsumedPowerInBackground() {
+        if (mBatteryConsumer instanceof UidBatteryConsumer) {
+            return mConsumedPowerInBackground;
+        } else {
+            return 0;
+        }
+    }
+
+    /**
+     * Returns amount of power (in milli-amp-hours) used in cached that is attributed to this entry.
+     */
+    public double getConsumedPowerInCached() {
+        if (mBatteryConsumer instanceof UidBatteryConsumer) {
+            return mConsumedPowerInCached;
+        } else {
+            return 0;
+        }
+    }
+
+    /**
      * Adds the consumed power of the supplied BatteryConsumer to this entry. Also
      * uses its package with highest drain, if necessary.
      */
@@ -431,8 +518,19 @@
             UidBatteryConsumer uidBatteryConsumer = (UidBatteryConsumer) batteryConsumer;
             mTimeInForegroundMs += uidBatteryConsumer.getTimeInStateMs(
                     UidBatteryConsumer.STATE_FOREGROUND);
+            //TODO: update this to the correct API after the new API is completed.
+            mTimeInForegroundServiceMs += uidBatteryConsumer.getTimeInStateMs(
+                    UidBatteryConsumer.STATE_FOREGROUND);
             mTimeInBackgroundMs += uidBatteryConsumer.getTimeInStateMs(
                     UidBatteryConsumer.STATE_BACKGROUND);
+            mConsumedPowerInForeground += safeGetConsumedPower(
+                    uidBatteryConsumer, BATTERY_DIMENSIONS[BATTERY_USAGE_INDEX_FOREGROUND]);
+            mConsumedPowerInForegroundService += safeGetConsumedPower(
+                    uidBatteryConsumer, BATTERY_DIMENSIONS[BATTERY_USAGE_INDEX_FOREGROUND_SERVICE]);
+            mConsumedPowerInBackground += safeGetConsumedPower(
+                    uidBatteryConsumer, BATTERY_DIMENSIONS[BATTERY_USAGE_INDEX_BACKGROUND]);
+            mConsumedPowerInCached += safeGetConsumedPower(
+                    uidBatteryConsumer, BATTERY_DIMENSIONS[BATTERY_USAGE_INDEX_CACHED]);
             if (mDefaultPackageName == null) {
                 mDefaultPackageName = uidBatteryConsumer.getPackageWithHighestDrain();
             }
@@ -533,4 +631,14 @@
     public static boolean isSystemUid(int uid) {
         return uid == Process.SYSTEM_UID;
     }
+
+    private static double safeGetConsumedPower(
+            final UidBatteryConsumer uidBatteryConsumer, final Dimensions dimension) {
+        try {
+            return uidBatteryConsumer.getConsumedPower(dimension);
+        } catch (IllegalArgumentException e) {
+            Log.e(TAG, "safeGetConsumedPower failed:" + e);
+            return 0.0d;
+        }
+    }
 }
diff --git a/src/com/android/settings/fuelgauge/batteryusage/BatteryHistEntry.java b/src/com/android/settings/fuelgauge/batteryusage/BatteryHistEntry.java
index d26927b..5cd63e8 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/BatteryHistEntry.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/BatteryHistEntry.java
@@ -50,8 +50,13 @@
     // Records the battery usage relative information.
     public final double mTotalPower;
     public final double mConsumePower;
+    public final double mForegroundUsageConsumePower;
+    public final double mForegroundServiceUsageConsumePower;
+    public final double mBackgroundUsageConsumePower;
+    public final double mCachedUsageConsumePower;
     public final double mPercentOfTotal;
     public final long mForegroundUsageTimeInMs;
+    public final long mForegroundServiceUsageTimeInMs;
     public final long mBackgroundUsageTimeInMs;
     @BatteryConsumer.PowerComponent
     public final int mDrainType;
@@ -79,8 +84,14 @@
         mZoneId = batteryInformation.getZoneId();
         mTotalPower = batteryInformation.getTotalPower();
         mConsumePower = batteryInformation.getConsumePower();
+        mForegroundUsageConsumePower = batteryInformation.getForegroundUsageConsumePower();
+        mForegroundServiceUsageConsumePower =
+                batteryInformation.getForegroundServiceUsageConsumePower();
+        mBackgroundUsageConsumePower = batteryInformation.getBackgroundUsageConsumePower();
+        mCachedUsageConsumePower = batteryInformation.getCachedUsageConsumePower();
         mPercentOfTotal = batteryInformation.getPercentOfTotal();
         mForegroundUsageTimeInMs = batteryInformation.getForegroundUsageTimeInMs();
+        mForegroundServiceUsageTimeInMs = batteryInformation.getForegroundServiceUsageTimeInMs();
         mBackgroundUsageTimeInMs = batteryInformation.getBackgroundUsageTimeInMs();
         mDrainType = batteryInformation.getDrainType();
         final DeviceBatteryState deviceBatteryState = batteryInformation.getDeviceBatteryState();
@@ -103,8 +114,14 @@
         mZoneId = batteryInformation.getZoneId();
         mTotalPower = batteryInformation.getTotalPower();
         mConsumePower = batteryInformation.getConsumePower();
+        mForegroundUsageConsumePower = batteryInformation.getForegroundUsageConsumePower();
+        mForegroundServiceUsageConsumePower =
+                batteryInformation.getForegroundServiceUsageConsumePower();
+        mBackgroundUsageConsumePower = batteryInformation.getBackgroundUsageConsumePower();
+        mCachedUsageConsumePower = batteryInformation.getCachedUsageConsumePower();
         mPercentOfTotal = batteryInformation.getPercentOfTotal();
         mForegroundUsageTimeInMs = batteryInformation.getForegroundUsageTimeInMs();
+        mForegroundServiceUsageTimeInMs = batteryInformation.getForegroundServiceUsageTimeInMs();
         mBackgroundUsageTimeInMs = batteryInformation.getBackgroundUsageTimeInMs();
         mDrainType = batteryInformation.getDrainType();
         final DeviceBatteryState deviceBatteryState = batteryInformation.getDeviceBatteryState();
@@ -119,7 +136,12 @@
             long timestamp,
             double totalPower,
             double consumePower,
+            double foregroundUsageConsumePower,
+            double foregroundServiceUsageConsumePower,
+            double backgroundUsageConsumePower,
+            double cachedUsageConsumePower,
             long foregroundUsageTimeInMs,
+            long foregroundServiceUsageTimeInMs,
             long backgroundUsageTimeInMs,
             int batteryLevel) {
         mUid = fromEntry.mUid;
@@ -132,8 +154,13 @@
         mZoneId = fromEntry.mZoneId;
         mTotalPower = totalPower;
         mConsumePower = consumePower;
+        mForegroundUsageConsumePower = foregroundUsageConsumePower;
+        mForegroundServiceUsageConsumePower = foregroundServiceUsageConsumePower;
+        mBackgroundUsageConsumePower = backgroundUsageConsumePower;
+        mCachedUsageConsumePower = cachedUsageConsumePower;
         mPercentOfTotal = fromEntry.mPercentOfTotal;
         mForegroundUsageTimeInMs = foregroundUsageTimeInMs;
+        mForegroundServiceUsageTimeInMs = foregroundServiceUsageTimeInMs;
         mBackgroundUsageTimeInMs = backgroundUsageTimeInMs;
         mDrainType = fromEntry.mDrainType;
         mConsumerType = fromEntry.mConsumerType;
@@ -190,9 +217,15 @@
                         mPackageName, mAppLabel, mUid, mUserId, mIsHidden))
                 .append(String.format("\n\ttimestamp=%s|zoneId=%s|bootTimestamp=%d",
                         recordAtDateTime, mZoneId, Duration.ofMillis(mBootTimestamp).getSeconds()))
-                .append(String.format("\n\tusage=%f|total=%f|consume=%f|elapsedTime=%d|%d",
-                        mPercentOfTotal, mTotalPower, mConsumePower,
+                .append(String.format("\n\tusage=%f|total=%f|consume=%f",
+                        mPercentOfTotal, mTotalPower, mConsumePower))
+                .append(String.format("\n\tforeground=%f|foregroundService=%f",
+                        mForegroundUsageConsumePower, mForegroundServiceUsageConsumePower))
+                .append(String.format("\n\tbackground=%f|cached=%f",
+                        mBackgroundUsageConsumePower, mCachedUsageConsumePower))
+                .append(String.format("\n\telapsedTime=%d|%d|%d",
                         Duration.ofMillis(mForegroundUsageTimeInMs).getSeconds(),
+                        Duration.ofMillis(mForegroundServiceUsageTimeInMs).getSeconds(),
                         Duration.ofMillis(mBackgroundUsageTimeInMs).getSeconds()))
                 .append(String.format("\n\tdrainType=%d|consumerType=%d",
                         mDrainType, mConsumerType))
@@ -267,17 +300,45 @@
                 lowerHistEntry == null ? 0 : lowerHistEntry.mConsumePower,
                 upperHistEntry.mConsumePower,
                 ratio);
+        final double foregroundUsageConsumePower = interpolate(
+                lowerHistEntry == null ? 0 : lowerHistEntry.mForegroundUsageConsumePower,
+                upperHistEntry.mForegroundUsageConsumePower,
+                ratio);
+        final double foregroundServiceUsageConsumePower = interpolate(
+                lowerHistEntry == null ? 0 : lowerHistEntry.mForegroundServiceUsageConsumePower,
+                upperHistEntry.mForegroundServiceUsageConsumePower,
+                ratio);
+        final double backgroundUsageConsumePower = interpolate(
+                lowerHistEntry == null ? 0 : lowerHistEntry.mBackgroundUsageConsumePower,
+                upperHistEntry.mBackgroundUsageConsumePower,
+                ratio);
+        final double cachedUsageConsumePower = interpolate(
+                lowerHistEntry == null ? 0 : lowerHistEntry.mCachedUsageConsumePower,
+                upperHistEntry.mCachedUsageConsumePower,
+                ratio);
         final double foregroundUsageTimeInMs = interpolate(
-                lowerHistEntry == null ? 0 : lowerHistEntry.mForegroundUsageTimeInMs,
-                upperHistEntry.mForegroundUsageTimeInMs,
+                (double) (lowerHistEntry == null ? 0 : lowerHistEntry.mForegroundUsageTimeInMs),
+                (double) upperHistEntry.mForegroundUsageTimeInMs,
+                ratio);
+        final double foregroundServiceUsageTimeInMs = interpolate(
+                (double) (lowerHistEntry == null
+                        ? 0
+                        : lowerHistEntry.mForegroundServiceUsageTimeInMs),
+                (double) upperHistEntry.mForegroundServiceUsageTimeInMs,
                 ratio);
         final double backgroundUsageTimeInMs = interpolate(
-                lowerHistEntry == null ? 0 : lowerHistEntry.mBackgroundUsageTimeInMs,
-                upperHistEntry.mBackgroundUsageTimeInMs,
+                (double) (lowerHistEntry == null ? 0 : lowerHistEntry.mBackgroundUsageTimeInMs),
+                (double) upperHistEntry.mBackgroundUsageTimeInMs,
                 ratio);
         // Checks whether there is any abnormal cases!
         if (upperHistEntry.mConsumePower < consumePower
+                || upperHistEntry.mForegroundUsageConsumePower < foregroundUsageConsumePower
+                || upperHistEntry.mForegroundServiceUsageConsumePower
+                < foregroundServiceUsageConsumePower
+                || upperHistEntry.mBackgroundUsageConsumePower < backgroundUsageConsumePower
+                || upperHistEntry.mCachedUsageConsumePower < cachedUsageConsumePower
                 || upperHistEntry.mForegroundUsageTimeInMs < foregroundUsageTimeInMs
+                || upperHistEntry.mForegroundServiceUsageTimeInMs < foregroundServiceUsageTimeInMs
                 || upperHistEntry.mBackgroundUsageTimeInMs < backgroundUsageTimeInMs) {
             if (DEBUG) {
                 Log.w(TAG, String.format(
@@ -299,7 +360,12 @@
                 /*timestamp=*/ slotTimestamp,
                 totalPower,
                 consumePower,
+                foregroundUsageConsumePower,
+                foregroundServiceUsageConsumePower,
+                backgroundUsageConsumePower,
+                cachedUsageConsumePower,
                 Math.round(foregroundUsageTimeInMs),
+                Math.round(foregroundServiceUsageTimeInMs),
                 Math.round(backgroundUsageTimeInMs),
                 (int) Math.round(batteryLevel));
     }
diff --git a/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBroadcastReceiver.java b/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBroadcastReceiver.java
index 4eaa154..817d367 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBroadcastReceiver.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBroadcastReceiver.java
@@ -80,6 +80,6 @@
         }
 
         mFetchBatteryUsageData = true;
-        BatteryUsageDataLoader.enqueueWork(context);
+        BatteryUsageDataLoader.enqueueWork(context, /*isFullChargeStart=*/ true);
     }
 }
diff --git a/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageContentProvider.java b/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageContentProvider.java
index 5680414..4827f8f 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageContentProvider.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageContentProvider.java
@@ -40,9 +40,8 @@
 public class BatteryUsageContentProvider extends ContentProvider {
     private static final String TAG = "BatteryUsageContentProvider";
 
-    // TODO: Updates the duration to a more reasonable value for since-last-full-charge.
     @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
-    public static final Duration QUERY_DURATION_HOURS = Duration.ofHours(28);
+    public static final Duration QUERY_DURATION_HOURS = Duration.ofDays(6);
 
     @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
     public static final String QUERY_KEY_TIMESTAMP = "timestamp";
@@ -141,7 +140,7 @@
         final long timestamp = mClock.millis();
         Cursor cursor = null;
         try {
-            cursor = mBatteryStateDao.getCursorAfter(firstTimestamp);
+            cursor = mBatteryStateDao.getCursorSinceLastFullCharge(firstTimestamp);
         } catch (RuntimeException e) {
             Log.e(TAG, "query() from:" + uri + " error:" + e);
         }
diff --git a/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageDataLoader.java b/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageDataLoader.java
index c944eca..3cb5465 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageDataLoader.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageDataLoader.java
@@ -37,15 +37,15 @@
     private BatteryUsageDataLoader() {
     }
 
-    static void enqueueWork(Context context) {
+    static void enqueueWork(final Context context, final boolean isFullChargeStart) {
         AsyncTask.execute(() -> {
             Log.d(TAG, "loadUsageDataSafely() in the AsyncTask");
-            loadUsageDataSafely(context.getApplicationContext());
+            loadUsageDataSafely(context.getApplicationContext(), isFullChargeStart);
         });
     }
 
     @VisibleForTesting
-    static void loadUsageData(Context context) {
+    static void loadUsageData(final Context context, final boolean isFullChargeStart) {
         final long start = System.currentTimeMillis();
         final BatteryUsageStats batteryUsageStats = DataProcessor.getBatteryUsageStats(context);
         final List<BatteryEntry> batteryEntryList =
@@ -60,13 +60,14 @@
 
         // Uploads the BatteryEntry data into SettingsIntelligence.
         DatabaseUtils.sendBatteryEntryData(
-                context, batteryEntryList, batteryUsageStats);
+                context, batteryEntryList, batteryUsageStats, isFullChargeStart);
         DataProcessor.closeBatteryUsageStats(batteryUsageStats);
     }
 
-    private static void loadUsageDataSafely(Context context) {
+    private static void loadUsageDataSafely(
+            final Context context, final boolean isFullChargeStart) {
         try {
-            loadUsageData(context);
+            loadUsageData(context, isFullChargeStart);
         } catch (RuntimeException e) {
             Log.e(TAG, "loadUsageData:" + e);
         }
diff --git a/src/com/android/settings/fuelgauge/batteryusage/ConvertUtils.java b/src/com/android/settings/fuelgauge/batteryusage/ConvertUtils.java
index 7f3dc31..0c7b4ab 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/ConvertUtils.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/ConvertUtils.java
@@ -23,46 +23,22 @@
 import android.os.Build;
 import android.os.LocaleList;
 import android.os.UserHandle;
-import android.os.UserManager;
 import android.text.format.DateFormat;
-import android.text.format.DateUtils;
-import android.util.ArraySet;
 import android.util.Base64;
-import android.util.Log;
 
 import androidx.annotation.VisibleForTesting;
 
-import com.android.settings.Utils;
 import com.android.settings.fuelgauge.BatteryUtils;
-import com.android.settings.overlay.FeatureFactory;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
-import java.time.Duration;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.List;
 import java.util.Locale;
-import java.util.Map;
-import java.util.Set;
 import java.util.TimeZone;
 
 /** A utility class to convert data into another types. */
 public final class ConvertUtils {
-    private static final boolean DEBUG = false;
     private static final String TAG = "ConvertUtils";
-    private static final Map<String, BatteryHistEntry> EMPTY_BATTERY_MAP = new HashMap<>();
-    private static final BatteryHistEntry EMPTY_BATTERY_HIST_ENTRY =
-            new BatteryHistEntry(new ContentValues());
-    // Maximum total time value for each slot cumulative data at most 2 hours.
-    private static final float TOTAL_TIME_THRESHOLD = DateUtils.HOUR_IN_MILLIS * 2;
 
-    @VisibleForTesting
-    static double PERCENTAGE_OF_TOTAL_THRESHOLD = 1f;
-
-    /** Invalid system battery consumer drain type. */
-    public static final int INVALID_DRAIN_TYPE = -1;
     /** A fake package name to represent no BatteryEntry data. */
     public static final String FAKE_PACKAGE_NAME = "fake_package";
 
@@ -92,7 +68,8 @@
             final int batteryStatus,
             final int batteryHealth,
             final long bootTimestamp,
-            final long timestamp) {
+            final long timestamp,
+            final boolean isFullChargeStart) {
         final ContentValues values = new ContentValues();
         if (entry != null && batteryUsageStats != null) {
             values.put(BatteryHistEntry.KEY_UID, Long.valueOf(entry.getUid()));
@@ -106,6 +83,8 @@
             values.put(BatteryHistEntry.KEY_PACKAGE_NAME, FAKE_PACKAGE_NAME);
         }
         values.put(BatteryHistEntry.KEY_TIMESTAMP, Long.valueOf(timestamp));
+        values.put(BatteryHistEntry.KEY_IS_FULL_CHARGE_CYCLE_START,
+                Boolean.valueOf(isFullChargeStart));
         final BatteryInformation batteryInformation =
                 constructBatteryInformation(
                         entry,
@@ -163,7 +142,8 @@
                         /*batteryStatus=*/ 0,
                         /*batteryHealth=*/ 0,
                         /*bootTimestamp=*/ 0,
-                        /*timestamp=*/ 0));
+                        /*timestamp=*/ 0,
+                        /*isFullChargeStart=*/ false));
     }
 
     /** Converts UTC timestamp to human readable local time string. */
@@ -194,167 +174,15 @@
         return DateFormat.format(pattern, timestamp).toString();
     }
 
-    /** Gets indexed battery usage data for each corresponding time slot. */
-    public static Map<Integer, List<BatteryDiffEntry>> getIndexedUsageMap(
-            final Context context,
-            final int timeSlotSize,
-            final long[] batteryHistoryKeys,
-            final Map<Long, Map<String, BatteryHistEntry>> batteryHistoryMap,
-            final boolean purgeLowPercentageAndFakeData) {
-        if (batteryHistoryMap == null || batteryHistoryMap.isEmpty()) {
-            return new HashMap<>();
-        }
-        final Map<Integer, List<BatteryDiffEntry>> resultMap = new HashMap<>();
-        // Each time slot usage diff data =
-        //     Math.abs(timestamp[i+2] data - timestamp[i+1] data) +
-        //     Math.abs(timestamp[i+1] data - timestamp[i] data);
-        // since we want to aggregate every two hours data into a single time slot.
-        final int timestampStride = 2;
-        for (int index = 0; index < timeSlotSize; index++) {
-            final Long currentTimestamp =
-                    Long.valueOf(batteryHistoryKeys[index * timestampStride]);
-            final Long nextTimestamp =
-                    Long.valueOf(batteryHistoryKeys[index * timestampStride + 1]);
-            final Long nextTwoTimestamp =
-                    Long.valueOf(batteryHistoryKeys[index * timestampStride + 2]);
-            // Fetches BatteryHistEntry data from corresponding time slot.
-            final Map<String, BatteryHistEntry> currentBatteryHistMap =
-                    batteryHistoryMap.getOrDefault(currentTimestamp, EMPTY_BATTERY_MAP);
-            final Map<String, BatteryHistEntry> nextBatteryHistMap =
-                    batteryHistoryMap.getOrDefault(nextTimestamp, EMPTY_BATTERY_MAP);
-            final Map<String, BatteryHistEntry> nextTwoBatteryHistMap =
-                    batteryHistoryMap.getOrDefault(nextTwoTimestamp, EMPTY_BATTERY_MAP);
-            // We should not get the empty list since we have at least one fake data to record
-            // the battery level and status in each time slot, the empty list is used to
-            // represent there is no enough data to apply interpolation arithmetic.
-            if (currentBatteryHistMap.isEmpty()
-                    || nextBatteryHistMap.isEmpty()
-                    || nextTwoBatteryHistMap.isEmpty()) {
-                resultMap.put(Integer.valueOf(index), new ArrayList<BatteryDiffEntry>());
-                continue;
-            }
-
-            // Collects all keys in these three time slot records as all populations.
-            final Set<String> allBatteryHistEntryKeys = new ArraySet<>();
-            allBatteryHistEntryKeys.addAll(currentBatteryHistMap.keySet());
-            allBatteryHistEntryKeys.addAll(nextBatteryHistMap.keySet());
-            allBatteryHistEntryKeys.addAll(nextTwoBatteryHistMap.keySet());
-
-            double totalConsumePower = 0.0;
-            final List<BatteryDiffEntry> batteryDiffEntryList = new ArrayList<>();
-            // Adds a specific time slot BatteryDiffEntry list into result map.
-            resultMap.put(Integer.valueOf(index), batteryDiffEntryList);
-
-            // Calculates all packages diff usage data in a specific time slot.
-            for (String key : allBatteryHistEntryKeys) {
-                final BatteryHistEntry currentEntry =
-                        currentBatteryHistMap.getOrDefault(key, EMPTY_BATTERY_HIST_ENTRY);
-                final BatteryHistEntry nextEntry =
-                        nextBatteryHistMap.getOrDefault(key, EMPTY_BATTERY_HIST_ENTRY);
-                final BatteryHistEntry nextTwoEntry =
-                        nextTwoBatteryHistMap.getOrDefault(key, EMPTY_BATTERY_HIST_ENTRY);
-                // Cumulative values is a specific time slot for a specific app.
-                long foregroundUsageTimeInMs =
-                        getDiffValue(
-                                currentEntry.mForegroundUsageTimeInMs,
-                                nextEntry.mForegroundUsageTimeInMs,
-                                nextTwoEntry.mForegroundUsageTimeInMs);
-                long backgroundUsageTimeInMs =
-                        getDiffValue(
-                                currentEntry.mBackgroundUsageTimeInMs,
-                                nextEntry.mBackgroundUsageTimeInMs,
-                                nextTwoEntry.mBackgroundUsageTimeInMs);
-                double consumePower =
-                        getDiffValue(
-                                currentEntry.mConsumePower,
-                                nextEntry.mConsumePower,
-                                nextTwoEntry.mConsumePower);
-                // Excludes entry since we don't have enough data to calculate.
-                if (foregroundUsageTimeInMs == 0
-                        && backgroundUsageTimeInMs == 0
-                        && consumePower == 0) {
-                    continue;
-                }
-                final BatteryHistEntry selectedBatteryEntry =
-                        selectBatteryHistEntry(currentEntry, nextEntry, nextTwoEntry);
-                if (selectedBatteryEntry == null) {
-                    continue;
-                }
-                // Forces refine the cumulative value since it may introduce deviation
-                // error since we will apply the interpolation arithmetic.
-                final float totalUsageTimeInMs =
-                        foregroundUsageTimeInMs + backgroundUsageTimeInMs;
-                if (totalUsageTimeInMs > TOTAL_TIME_THRESHOLD) {
-                    final float ratio = TOTAL_TIME_THRESHOLD / totalUsageTimeInMs;
-                    if (DEBUG) {
-                        Log.w(TAG, String.format("abnormal usage time %d|%d for:\n%s",
-                                Duration.ofMillis(foregroundUsageTimeInMs).getSeconds(),
-                                Duration.ofMillis(backgroundUsageTimeInMs).getSeconds(),
-                                currentEntry));
-                    }
-                    foregroundUsageTimeInMs =
-                            Math.round(foregroundUsageTimeInMs * ratio);
-                    backgroundUsageTimeInMs =
-                            Math.round(backgroundUsageTimeInMs * ratio);
-                    consumePower = consumePower * ratio;
-                }
-                totalConsumePower += consumePower;
-                batteryDiffEntryList.add(
-                        new BatteryDiffEntry(
-                                context,
-                                foregroundUsageTimeInMs,
-                                backgroundUsageTimeInMs,
-                                consumePower,
-                                selectedBatteryEntry));
-            }
-            // Sets total consume power data into all BatteryDiffEntry in the same slot.
-            for (BatteryDiffEntry diffEntry : batteryDiffEntryList) {
-                diffEntry.setTotalConsumePower(totalConsumePower);
-            }
-        }
-        insert24HoursData(BatteryChartViewModel.SELECTED_INDEX_ALL, resultMap);
-        resolveMultiUsersData(context, resultMap);
-        if (purgeLowPercentageAndFakeData) {
-            purgeLowPercentageAndFakeData(context, resultMap);
-        }
-        return resultMap;
-    }
-
     @VisibleForTesting
-    static void resolveMultiUsersData(
-            final Context context,
-            final Map<Integer, List<BatteryDiffEntry>> indexedUsageMap) {
-        final int currentUserId = context.getUserId();
-        final UserHandle userHandle =
-                Utils.getManagedProfile(context.getSystemService(UserManager.class));
-        final int workProfileUserId =
-                userHandle != null ? userHandle.getIdentifier() : Integer.MIN_VALUE;
-        // Loops for all BatteryDiffEntry in the different slots.
-        for (List<BatteryDiffEntry> entryList : indexedUsageMap.values()) {
-            double consumePowerFromOtherUsers = 0f;
-            double consumePercentageFromOtherUsers = 0f;
-            final Iterator<BatteryDiffEntry> iterator = entryList.iterator();
-            while (iterator.hasNext()) {
-                final BatteryDiffEntry entry = iterator.next();
-                final BatteryHistEntry batteryHistEntry = entry.mBatteryHistEntry;
-                if (batteryHistEntry.mConsumerType != CONSUMER_TYPE_UID_BATTERY) {
-                    continue;
-                }
-                // Whether the BatteryHistEntry represents the current user data?
-                if (batteryHistEntry.mUserId == currentUserId
-                        || batteryHistEntry.mUserId == workProfileUserId) {
-                    continue;
-                }
-                // Removes and aggregates non-current users data from the list.
-                iterator.remove();
-                consumePowerFromOtherUsers += entry.mConsumePower;
-                consumePercentageFromOtherUsers += entry.getPercentOfTotal();
-            }
-            if (consumePercentageFromOtherUsers != 0) {
-                entryList.add(createOtherUsersEntry(context, consumePowerFromOtherUsers,
-                        consumePercentageFromOtherUsers));
-            }
+    static Locale getLocale(Context context) {
+        if (context == null) {
+            return Locale.getDefault();
         }
+        final LocaleList locales =
+                context.getResources().getConfiguration().getLocales();
+        return locales != null && !locales.isEmpty() ? locales.get(0)
+                : Locale.getDefault();
     }
 
     private static BatteryInformation constructBatteryInformation(
@@ -383,121 +211,18 @@
                     .setAppLabel(entry.getLabel() != null ? entry.getLabel() : "")
                     .setTotalPower(batteryUsageStats.getConsumedPower())
                     .setConsumePower(entry.getConsumedPower())
+                    .setForegroundUsageConsumePower(entry.getConsumedPowerInForeground())
+                    .setForegroundServiceUsageConsumePower(
+                            entry.getConsumedPowerInForegroundService())
+                    .setBackgroundUsageConsumePower(entry.getConsumedPowerInBackground())
+                    .setCachedUsageConsumePower(entry.getConsumedPowerInCached())
                     .setPercentOfTotal(entry.mPercent)
                     .setDrainType(entry.getPowerComponentId())
                     .setForegroundUsageTimeInMs(entry.getTimeInForegroundMs())
+                    .setForegroundServiceUsageTimeInMs(entry.getTimeInForegroundServiceMs())
                     .setBackgroundUsageTimeInMs(entry.getTimeInBackgroundMs());
         }
 
         return batteryInformationBuilder.build();
     }
-
-    private static void insert24HoursData(
-            final int desiredIndex,
-            final Map<Integer, List<BatteryDiffEntry>> indexedUsageMap) {
-        final Map<String, BatteryDiffEntry> resultMap = new HashMap<>();
-        double totalConsumePower = 0f;
-        // Loops for all BatteryDiffEntry and aggregate them together.
-        for (List<BatteryDiffEntry> entryList : indexedUsageMap.values()) {
-            for (BatteryDiffEntry entry : entryList) {
-                final String key = entry.mBatteryHistEntry.getKey();
-                final BatteryDiffEntry oldBatteryDiffEntry = resultMap.get(key);
-                // Creates new BatteryDiffEntry if we don't have it.
-                if (oldBatteryDiffEntry == null) {
-                    resultMap.put(key, entry.clone());
-                } else {
-                    // Sums up some fields data into the existing one.
-                    oldBatteryDiffEntry.mForegroundUsageTimeInMs +=
-                            entry.mForegroundUsageTimeInMs;
-                    oldBatteryDiffEntry.mBackgroundUsageTimeInMs +=
-                            entry.mBackgroundUsageTimeInMs;
-                    oldBatteryDiffEntry.mConsumePower += entry.mConsumePower;
-                }
-                totalConsumePower += entry.mConsumePower;
-            }
-        }
-        final List<BatteryDiffEntry> resultList = new ArrayList<>(resultMap.values());
-        // Sets total 24 hours consume power data into all BatteryDiffEntry.
-        for (BatteryDiffEntry entry : resultList) {
-            entry.setTotalConsumePower(totalConsumePower);
-        }
-        indexedUsageMap.put(Integer.valueOf(desiredIndex), resultList);
-    }
-
-    // Removes low percentage data and fake usage data, which will be zero value.
-    private static void purgeLowPercentageAndFakeData(
-            final Context context,
-            final Map<Integer, List<BatteryDiffEntry>> indexedUsageMap) {
-        final Set<CharSequence> backgroundUsageTimeHideList =
-                FeatureFactory.getFactory(context)
-                        .getPowerUsageFeatureProvider(context)
-                        .getHideBackgroundUsageTimeSet(context);
-        for (List<BatteryDiffEntry> entries : indexedUsageMap.values()) {
-            final Iterator<BatteryDiffEntry> iterator = entries.iterator();
-            while (iterator.hasNext()) {
-                final BatteryDiffEntry entry = iterator.next();
-                if (entry.getPercentOfTotal() < PERCENTAGE_OF_TOTAL_THRESHOLD
-                        || FAKE_PACKAGE_NAME.equals(entry.getPackageName())) {
-                    iterator.remove();
-                }
-                final String packageName = entry.getPackageName();
-                if (packageName != null
-                        && !backgroundUsageTimeHideList.isEmpty()
-                        && backgroundUsageTimeHideList.contains(packageName)) {
-                    entry.mBackgroundUsageTimeInMs = 0;
-                }
-            }
-        }
-    }
-
-    private static long getDiffValue(long v1, long v2, long v3) {
-        return (v2 > v1 ? v2 - v1 : 0) + (v3 > v2 ? v3 - v2 : 0);
-    }
-
-    private static double getDiffValue(double v1, double v2, double v3) {
-        return (v2 > v1 ? v2 - v1 : 0) + (v3 > v2 ? v3 - v2 : 0);
-    }
-
-    private static BatteryHistEntry selectBatteryHistEntry(
-            BatteryHistEntry entry1,
-            BatteryHistEntry entry2,
-            BatteryHistEntry entry3) {
-        if (entry1 != null && entry1 != EMPTY_BATTERY_HIST_ENTRY) {
-            return entry1;
-        } else if (entry2 != null && entry2 != EMPTY_BATTERY_HIST_ENTRY) {
-            return entry2;
-        } else {
-            return entry3 != null && entry3 != EMPTY_BATTERY_HIST_ENTRY
-                    ? entry3 : null;
-        }
-    }
-
-    @VisibleForTesting
-    static Locale getLocale(Context context) {
-        if (context == null) {
-            return Locale.getDefault();
-        }
-        final LocaleList locales =
-                context.getResources().getConfiguration().getLocales();
-        return locales != null && !locales.isEmpty() ? locales.get(0)
-                : Locale.getDefault();
-    }
-
-    private static BatteryDiffEntry createOtherUsersEntry(
-            Context context, double consumePower, double consumePercentage) {
-        final ContentValues values = new ContentValues();
-        values.put(BatteryHistEntry.KEY_UID, BatteryUtils.UID_OTHER_USERS);
-        values.put(BatteryHistEntry.KEY_USER_ID, BatteryUtils.UID_OTHER_USERS);
-        values.put(BatteryHistEntry.KEY_CONSUMER_TYPE, CONSUMER_TYPE_UID_BATTERY);
-        // We will show the percentage for the "other users" item only, the aggregated
-        // running time information is useless for users to identify individual apps.
-        final BatteryDiffEntry batteryDiffEntry = new BatteryDiffEntry(
-                context,
-                /*foregroundUsageTimeInMs=*/ 0,
-                /*backgroundUsageTimeInMs=*/ 0,
-                consumePower,
-                new BatteryHistEntry(values));
-        batteryDiffEntry.setTotalConsumePower(100 * consumePower / consumePercentage);
-        return batteryDiffEntry;
-    }
 }
diff --git a/src/com/android/settings/fuelgauge/batteryusage/DataProcessor.java b/src/com/android/settings/fuelgauge/batteryusage/DataProcessor.java
index 14d6ea9..0a4ac7c 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/DataProcessor.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/DataProcessor.java
@@ -87,9 +87,6 @@
     @VisibleForTesting
     static final int SELECTED_INDEX_ALL = BatteryChartViewModel.SELECTED_INDEX_ALL;
 
-    /** A fake package name to represent no BatteryEntry data. */
-    public static final String FAKE_PACKAGE_NAME = "fake_package";
-
     /** A callback listener when battery usage loading async task is executed. */
     public interface UsageMapAsyncResponse {
         /** The callback function when batteryUsageMap is loaded. */
@@ -174,7 +171,11 @@
     @Nullable
     public static BatteryUsageStats getBatteryUsageStats(final Context context) {
         final BatteryUsageStatsQuery batteryUsageStatsQuery =
-                new BatteryUsageStatsQuery.Builder().includeBatteryHistory().build();
+                new BatteryUsageStatsQuery
+                        .Builder()
+                        .includeBatteryHistory()
+                        .includeProcessStateData()
+                        .build();
         return context.getSystemService(BatteryStatsManager.class)
                 .getBatteryUsageStats(batteryUsageStatsQuery);
     }
@@ -478,8 +479,13 @@
                 final BatteryDiffEntry currentBatteryDiffEntry = new BatteryDiffEntry(
                         context,
                         entry.mForegroundUsageTimeInMs,
+                        entry.mForegroundServiceUsageTimeInMs,
                         entry.mBackgroundUsageTimeInMs,
                         entry.mConsumePower,
+                        entry.mForegroundUsageConsumePower,
+                        entry.mForegroundServiceUsageConsumePower,
+                        entry.mBackgroundUsageConsumePower,
+                        entry.mCachedUsageConsumePower,
                         entry);
                 if (currentBatteryDiffEntry.isSystemEntry()) {
                     systemEntries.add(currentBatteryDiffEntry);
@@ -567,10 +573,12 @@
         return batteryEntryList.stream()
                 .filter(entry -> {
                     final long foregroundMs = entry.getTimeInForegroundMs();
+                    final long foregroundServiceMs = entry.getTimeInForegroundServiceMs();
                     final long backgroundMs = entry.getTimeInBackgroundMs();
                     return entry.getConsumedPower() > 0
                             || (entry.getConsumedPower() == 0
-                            && (foregroundMs != 0 || backgroundMs != 0));
+                            && (foregroundMs != 0 || foregroundServiceMs != 0
+                            || backgroundMs != 0));
                 })
                 .map(entry -> ConvertUtils.convertToBatteryHistEntry(
                                 entry,
@@ -691,9 +699,14 @@
             if (lowerEntry != null) {
                 final boolean invalidForegroundUsageTime =
                         lowerEntry.mForegroundUsageTimeInMs > upperEntry.mForegroundUsageTimeInMs;
+                final boolean invalidForegroundServiceUsageTime =
+                        lowerEntry.mForegroundServiceUsageTimeInMs
+                                > upperEntry.mForegroundServiceUsageTimeInMs;
                 final boolean invalidBackgroundUsageTime =
                         lowerEntry.mBackgroundUsageTimeInMs > upperEntry.mBackgroundUsageTimeInMs;
-                if (invalidForegroundUsageTime || invalidBackgroundUsageTime) {
+                if (invalidForegroundUsageTime
+                        || invalidForegroundServiceUsageTime
+                        || invalidBackgroundUsageTime) {
                     newHistEntryMap.put(entryKey, upperEntry);
                     log(context, "abnormal reset condition is found", currentSlot, upperEntry);
                     continue;
@@ -924,6 +937,11 @@
                             currentEntry.mForegroundUsageTimeInMs,
                             nextEntry.mForegroundUsageTimeInMs,
                             nextTwoEntry.mForegroundUsageTimeInMs);
+            long foregroundServiceUsageTimeInMs =
+                    getDiffValue(
+                            currentEntry.mForegroundServiceUsageTimeInMs,
+                            nextEntry.mForegroundServiceUsageTimeInMs,
+                            nextTwoEntry.mForegroundServiceUsageTimeInMs);
             long backgroundUsageTimeInMs =
                     getDiffValue(
                             currentEntry.mBackgroundUsageTimeInMs,
@@ -934,8 +952,29 @@
                             currentEntry.mConsumePower,
                             nextEntry.mConsumePower,
                             nextTwoEntry.mConsumePower);
+            double foregroundUsageConsumePower =
+                    getDiffValue(
+                            currentEntry.mForegroundUsageConsumePower,
+                            nextEntry.mForegroundUsageConsumePower,
+                            nextTwoEntry.mForegroundUsageConsumePower);
+            double foregroundServiceUsageConsumePower =
+                    getDiffValue(
+                            currentEntry.mForegroundServiceUsageConsumePower,
+                            nextEntry.mForegroundServiceUsageConsumePower,
+                            nextTwoEntry.mForegroundServiceUsageConsumePower);
+            double backgroundUsageConsumePower =
+                    getDiffValue(
+                            currentEntry.mBackgroundUsageConsumePower,
+                            nextEntry.mBackgroundUsageConsumePower,
+                            nextTwoEntry.mBackgroundUsageConsumePower);
+            double cachedUsageConsumePower =
+                    getDiffValue(
+                            currentEntry.mCachedUsageConsumePower,
+                            nextEntry.mCachedUsageConsumePower,
+                            nextTwoEntry.mCachedUsageConsumePower);
             // Excludes entry since we don't have enough data to calculate.
             if (foregroundUsageTimeInMs == 0
+                    && foregroundServiceUsageTimeInMs == 0
                     && backgroundUsageTimeInMs == 0
                     && consumePower == 0) {
                 continue;
@@ -947,6 +986,7 @@
             }
             // Forces refine the cumulative value since it may introduce deviation error since we
             // will apply the interpolation arithmetic.
+            // TODO: update this value after the new API for foreground service is completed.
             final float totalUsageTimeInMs =
                     foregroundUsageTimeInMs + backgroundUsageTimeInMs;
             if (totalUsageTimeInMs > TOTAL_HOURLY_TIME_THRESHOLD) {
@@ -959,9 +999,15 @@
                 }
                 foregroundUsageTimeInMs =
                         Math.round(foregroundUsageTimeInMs * ratio);
+                foregroundServiceUsageTimeInMs =
+                        Math.round(foregroundServiceUsageTimeInMs * ratio);
                 backgroundUsageTimeInMs =
                         Math.round(backgroundUsageTimeInMs * ratio);
                 consumePower = consumePower * ratio;
+                foregroundUsageConsumePower = foregroundUsageConsumePower * ratio;
+                foregroundServiceUsageConsumePower = foregroundServiceUsageConsumePower * ratio;
+                backgroundUsageConsumePower = backgroundUsageConsumePower * ratio;
+                cachedUsageConsumePower = cachedUsageConsumePower * ratio;
             }
             totalConsumePower += consumePower;
 
@@ -973,8 +1019,13 @@
                 final BatteryDiffEntry currentBatteryDiffEntry = new BatteryDiffEntry(
                         context,
                         foregroundUsageTimeInMs,
+                        foregroundServiceUsageTimeInMs,
                         backgroundUsageTimeInMs,
                         consumePower,
+                        foregroundUsageConsumePower,
+                        foregroundServiceUsageConsumePower,
+                        backgroundUsageConsumePower,
+                        cachedUsageConsumePower,
                         selectedBatteryEntry);
                 if (currentBatteryDiffEntry.isSystemEntry()) {
                     systemEntries.add(currentBatteryDiffEntry);
@@ -1054,9 +1105,16 @@
             // Sums up some field data into the existing one.
             oldBatteryDiffEntry.mForegroundUsageTimeInMs +=
                     entry.mForegroundUsageTimeInMs;
+            oldBatteryDiffEntry.mForegroundServiceUsageTimeInMs +=
+                    entry.mForegroundServiceUsageTimeInMs;
             oldBatteryDiffEntry.mBackgroundUsageTimeInMs +=
                     entry.mBackgroundUsageTimeInMs;
             oldBatteryDiffEntry.mConsumePower += entry.mConsumePower;
+            oldBatteryDiffEntry.mForegroundUsageConsumePower += entry.mForegroundUsageConsumePower;
+            oldBatteryDiffEntry.mForegroundServiceUsageConsumePower
+                    += entry.mForegroundServiceUsageConsumePower;
+            oldBatteryDiffEntry.mBackgroundUsageConsumePower += entry.mBackgroundUsageConsumePower;
+            oldBatteryDiffEntry.mCachedUsageConsumePower += entry.mCachedUsageConsumePower;
         }
     }
 
@@ -1097,7 +1155,7 @@
             final BatteryDiffEntry entry = iterator.next();
             final String packageName = entry.getPackageName();
             if (entry.getPercentOfTotal() < PERCENTAGE_OF_TOTAL_THRESHOLD
-                    || FAKE_PACKAGE_NAME.equals(packageName)
+                    || ConvertUtils.FAKE_PACKAGE_NAME.equals(packageName)
                     || contains(packageName, notAllowShowEntryPackages)) {
                 iterator.remove();
             }
@@ -1346,8 +1404,13 @@
         final BatteryDiffEntry batteryDiffEntry = new BatteryDiffEntry(
                 context,
                 /*foregroundUsageTimeInMs=*/ 0,
+                /*foregroundServiceUsageTimeInMs=*/ 0,
                 /*backgroundUsageTimeInMs=*/ 0,
                 consumePower,
+                /*foregroundUsageConsumePower=*/ 0,
+                /*foregroundServiceUsageConsumePower=*/ 0,
+                /*backgroundUsageConsumePower=*/ 0,
+                /*cachedUsageConsumePower=*/ 0,
                 new BatteryHistEntry(values));
         return batteryDiffEntry;
     }
diff --git a/src/com/android/settings/fuelgauge/batteryusage/DatabaseUtils.java b/src/com/android/settings/fuelgauge/batteryusage/DatabaseUtils.java
index 7efd152..fdcbb4a 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/DatabaseUtils.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/DatabaseUtils.java
@@ -19,7 +19,6 @@
 import android.content.ContentValues;
 import android.content.Context;
 import android.content.Intent;
-import android.content.SharedPreferences;
 import android.content.pm.PackageManager;
 import android.database.Cursor;
 import android.net.Uri;
@@ -50,8 +49,6 @@
 /** A utility class to operate battery usage database. */
 public final class DatabaseUtils {
     private static final String TAG = "DatabaseUtils";
-    private static final String PREF_FILE_NAME = "battery_module_preference";
-    private static final String PREF_FULL_CHARGE_TIMESTAMP_KEY = "last_full_charge_timestamp_key";
     /** Key for query parameter timestamp used in BATTERY_CONTENT_URI **/
     private static final String QUERY_KEY_TIMESTAMP = "timestamp";
     /** Clear memory threshold for device booting phase. **/
@@ -89,8 +86,8 @@
     public static Map<Long, Map<String, BatteryHistEntry>> getHistoryMapSinceLastFullCharge(
             Context context, Calendar calendar) {
         final long startTime = System.currentTimeMillis();
-        final long lastFullChargeTimestamp =
-                getStartTimestampForLastFullCharge(context, calendar);
+        final long sixDaysAgoTimestamp = getTimestampSixDaysAgo(calendar);
+        Log.d(TAG, "sixDayAgoTimestamp: " + sixDaysAgoTimestamp);
         // Builds the content uri everytime to avoid cache.
         final Uri batteryStateUri =
                 new Uri.Builder()
@@ -98,7 +95,7 @@
                         .authority(AUTHORITY)
                         .appendPath(BATTERY_STATE_TABLE)
                         .appendQueryParameter(
-                                QUERY_KEY_TIMESTAMP, Long.toString(lastFullChargeTimestamp))
+                                QUERY_KEY_TIMESTAMP, Long.toString(sixDaysAgoTimestamp))
                         .build();
 
         final Map<Long, Map<String, BatteryHistEntry>> resultMap =
@@ -142,9 +139,10 @@
     }
 
     static List<ContentValues> sendBatteryEntryData(
-            Context context,
-            List<BatteryEntry> batteryEntryList,
-            BatteryUsageStats batteryUsageStats) {
+            final Context context,
+            final List<BatteryEntry> batteryEntryList,
+            final BatteryUsageStats batteryUsageStats,
+            final boolean isFullChargeStart) {
         final long startTime = System.currentTimeMillis();
         final Intent intent = BatteryUtils.getBatteryIntent(context);
         if (intent == null) {
@@ -152,7 +150,7 @@
             clearMemory();
             return null;
         }
-        final int batteryLevel = BatteryUtils.getBatteryLevel(intent);
+        final int batteryLevel = BatteryStatus.getBatteryLevel(intent);
         final int batteryStatus = intent.getIntExtra(
                 BatteryManager.EXTRA_STATUS, BatteryManager.BATTERY_STATUS_UNKNOWN);
         final int batteryHealth = intent.getIntExtra(
@@ -167,15 +165,20 @@
             batteryEntryList.stream()
                     .filter(entry -> {
                         final long foregroundMs = entry.getTimeInForegroundMs();
+                        final long foregroundServiceMs = entry.getTimeInForegroundServiceMs();
                         final long backgroundMs = entry.getTimeInBackgroundMs();
                         if (entry.getConsumedPower() == 0
-                                && (foregroundMs != 0 || backgroundMs != 0)) {
+                                && (foregroundMs != 0
+                                || foregroundServiceMs != 0
+                                || backgroundMs != 0)) {
                             Log.w(TAG, String.format(
-                                    "no consumed power but has running time for %s time=%d|%d",
-                                    entry.getLabel(), foregroundMs, backgroundMs));
+                                    "no consumed power but has running time for %s time=%d|%d|%d",
+                                    entry.getLabel(), foregroundMs, foregroundServiceMs,
+                                    backgroundMs));
                         }
                         return entry.getConsumedPower() != 0
                                 || foregroundMs != 0
+                                || foregroundServiceMs != 0
                                 || backgroundMs != 0;
                     })
                     .forEach(entry -> valuesList.add(
@@ -186,7 +189,8 @@
                                     batteryStatus,
                                     batteryHealth,
                                     snapshotBootTimestamp,
-                                    snapshotTimestamp)));
+                                    snapshotTimestamp,
+                                    isFullChargeStart)));
         }
 
         int size = 1;
@@ -197,6 +201,8 @@
             valuesList.toArray(valuesArray);
             try {
                 size = resolver.bulkInsert(BATTERY_CONTENT_URI, valuesArray);
+                Log.d(TAG, "insert() data into database with isFullChargeStart:"
+                        + isFullChargeStart);
             } catch (Exception e) {
                 Log.e(TAG, "bulkInsert() data into database error:\n" + e);
             }
@@ -210,15 +216,18 @@
                             batteryStatus,
                             batteryHealth,
                             snapshotBootTimestamp,
-                            snapshotTimestamp);
+                            snapshotTimestamp,
+                            isFullChargeStart);
             try {
                 resolver.insert(BATTERY_CONTENT_URI, contentValues);
+                Log.d(TAG, "insert() data into database with isFullChargeStart:"
+                        + isFullChargeStart);
+
             } catch (Exception e) {
                 Log.e(TAG, "insert() data into database error:\n" + e);
             }
             valuesList.add(contentValues);
         }
-        saveLastFullChargeTimestampPref(context, batteryStatus, batteryLevel, snapshotTimestamp);
         resolver.notifyChange(BATTERY_CONTENT_URI, /*observer=*/ null);
         Log.d(TAG, String.format("sendBatteryEntryData() size=%d in %d/ms",
                 size, (System.currentTimeMillis() - startTime)));
@@ -226,42 +235,6 @@
         return valuesList;
     }
 
-    @VisibleForTesting
-    static void saveLastFullChargeTimestampPref(
-            Context context, int batteryStatus, int batteryLevel, long timestamp) {
-        // Updates the SharedPreference only when timestamp is valid and phone is full charge.
-        if (!BatteryStatus.isCharged(batteryStatus, batteryLevel)) {
-            return;
-        }
-
-        final boolean success =
-                getSharedPreferences(context)
-                        .edit()
-                        .putLong(PREF_FULL_CHARGE_TIMESTAMP_KEY, timestamp)
-                        .commit();
-        if (!success) {
-            Log.w(TAG, "saveLastFullChargeTimestampPref() fail: value=" + timestamp);
-        }
-    }
-
-    @VisibleForTesting
-    static long getLastFullChargeTimestampPref(Context context) {
-        return getSharedPreferences(context).getLong(PREF_FULL_CHARGE_TIMESTAMP_KEY, 0);
-    }
-
-    /**
-     * Returns the start timestamp for "since last full charge" battery usage chart.
-     * If the last full charge happens within the last 7 days, returns the timestamp of last full
-     * charge. Otherwise, returns the timestamp for 00:00 6 days before the calendar date.
-     */
-    @VisibleForTesting
-    static long getStartTimestampForLastFullCharge(
-            Context context, Calendar calendar) {
-        final long lastFullChargeTimestamp = getLastFullChargeTimestampPref(context);
-        final long sixDayAgoTimestamp = getTimestampSixDaysAgo(calendar);
-        return Math.max(lastFullChargeTimestamp, sixDayAgoTimestamp);
-    }
-
     private static Map<Long, Map<String, BatteryHistEntry>> loadHistoryMapFromContentProvider(
             Context context, Uri batteryStateUri) {
         final boolean isWorkProfileUser = isWorkProfile(context);
@@ -296,6 +269,11 @@
                 }
                 batteryHistEntryMap.put(key, entry);
             }
+            try {
+                cursor.close();
+            } catch (Exception e) {
+                Log.e(TAG, "cursor.close() failed", e);
+            }
         }
         return resultMap;
     }
@@ -313,13 +291,6 @@
         }, CLEAR_MEMORY_DELAYED_MS);
     }
 
-    private static SharedPreferences getSharedPreferences(Context context) {
-        return context
-                .getApplicationContext() // ensures we bind it with application
-                .createDeviceProtectedStorageContext()
-                .getSharedPreferences(PREF_FILE_NAME, Context.MODE_PRIVATE);
-    }
-
     /** Returns the timestamp for 00:00 6 days before the calendar date. */
     private static long getTimestampSixDaysAgo(Calendar calendar) {
         Calendar startCalendar =
diff --git a/src/com/android/settings/fuelgauge/batteryusage/PeriodicJobReceiver.java b/src/com/android/settings/fuelgauge/batteryusage/PeriodicJobReceiver.java
index d2345ab..fddf01b 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/PeriodicJobReceiver.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/PeriodicJobReceiver.java
@@ -39,7 +39,7 @@
             Log.w(TAG, "do not refresh job for work profile action=" + action);
             return;
         }
-        BatteryUsageDataLoader.enqueueWork(context);
+        BatteryUsageDataLoader.enqueueWork(context, /*isFullChargeStart=*/ false);
         Log.d(TAG, "refresh periodic job from action=" + action);
         PeriodicJobManager.getInstance(context).refreshJob();
         DatabaseUtils.clearExpiredDataIfNeeded(context);
diff --git a/src/com/android/settings/fuelgauge/batteryusage/db/BatteryStateDao.java b/src/com/android/settings/fuelgauge/batteryusage/db/BatteryStateDao.java
index b1afa6b..936d5e0 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/db/BatteryStateDao.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/db/BatteryStateDao.java
@@ -41,9 +41,11 @@
     @Query("SELECT * FROM BatteryState WHERE timestamp > :timestamp ORDER BY timestamp DESC")
     List<BatteryState> getAllAfter(long timestamp);
 
-    /** Gets the {@link Cursor} of all recorded data from a specific timestamp. */
-    @Query("SELECT * FROM BatteryState WHERE timestamp >= :timestamp ORDER BY timestamp DESC")
-    Cursor getCursorAfter(long timestamp);
+    /** Gets the {@link Cursor} of all recorded data since last full charge within 7 days. */
+    @Query("SELECT * FROM BatteryState WHERE timestamp >= :timestampSixDaysAgo AND timestamp >= "
+            + "(SELECT MAX(timestamp) FROM BatteryState WHERE isFullChargeCycleStart = 1)"
+            + " ORDER BY timestamp ASC")
+    Cursor getCursorSinceLastFullCharge(long timestampSixDaysAgo);
 
     /** Get the count of distinct timestamp after a specific timestamp. */
     @Query("SELECT COUNT(DISTINCT timestamp) FROM BatteryState WHERE timestamp > :timestamp")
diff --git a/src/com/android/settings/homepage/SettingsHomepageActivity.java b/src/com/android/settings/homepage/SettingsHomepageActivity.java
index 038216f..fc0c68e 100644
--- a/src/com/android/settings/homepage/SettingsHomepageActivity.java
+++ b/src/com/android/settings/homepage/SettingsHomepageActivity.java
@@ -27,6 +27,8 @@
 import android.app.settings.SettingsEnums;
 import android.content.ComponentName;
 import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.content.pm.PackageManager;
 import android.content.pm.UserInfo;
 import android.content.res.Configuration;
 import android.os.Bundle;
@@ -66,6 +68,7 @@
 import com.android.settings.core.FeatureFlags;
 import com.android.settings.homepage.contextualcards.ContextualCardsFragment;
 import com.android.settings.overlay.FeatureFactory;
+import com.android.settings.password.PasswordUtils;
 import com.android.settings.safetycenter.SafetyCenterManagerWrapper;
 import com.android.settingslib.Utils;
 import com.android.settingslib.core.lifecycle.HideNonSystemOverlayMixin;
@@ -461,6 +464,32 @@
             finish();
             return;
         }
+
+        if (!TextUtils.equals(PasswordUtils.getCallingAppPackageName(getActivityToken()),
+                getPackageName())) {
+            ActivityInfo targetActivityInfo = null;
+            try {
+                targetActivityInfo = getPackageManager().getActivityInfo(targetComponentName,
+                        /* flags= */ 0);
+            } catch (PackageManager.NameNotFoundException e) {
+                Log.e(TAG, "Failed to get target ActivityInfo: " + e);
+                finish();
+                return;
+            }
+
+            if (!targetActivityInfo.exported) {
+                Log.e(TAG, "Must not launch an unexported Actvity for deep link");
+                finish();
+                return;
+            }
+
+            if (!isCallingAppPermitted(targetActivityInfo.permission)) {
+                Log.e(TAG, "Calling app must have the permission of deep link Activity");
+                finish();
+                return;
+            }
+        }
+
         targetIntent.setComponent(targetComponentName);
 
         // To prevent launchDeepLinkIntentToRight again for configuration change.
@@ -498,6 +527,12 @@
         }
     }
 
+    @VisibleForTesting
+    boolean isCallingAppPermitted(String permission) {
+        return TextUtils.isEmpty(permission) || PasswordUtils.isCallingAppPermitted(
+                this, getActivityToken(), permission);
+    }
+
     private String getHighlightMenuKey() {
         final Intent intent = getIntent();
         if (intent != null && TextUtils.equals(intent.getAction(),
diff --git a/src/com/android/settings/network/telephony/AutoDataSwitchPreferenceController.java b/src/com/android/settings/network/telephony/AutoDataSwitchPreferenceController.java
index f4543f5..ea2a9ec 100644
--- a/src/com/android/settings/network/telephony/AutoDataSwitchPreferenceController.java
+++ b/src/com/android/settings/network/telephony/AutoDataSwitchPreferenceController.java
@@ -22,8 +22,10 @@
 import android.content.Context;
 import android.os.Handler;
 import android.os.Looper;
+import android.telephony.SubscriptionInfo;
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
+import android.util.Log;
 
 import androidx.lifecycle.LifecycleObserver;
 import androidx.lifecycle.OnLifecycleEvent;
@@ -36,6 +38,8 @@
 import com.android.settings.network.MobileDataContentObserver;
 import com.android.settings.network.SubscriptionsChangeListener;
 
+import java.util.List;
+
 /**
  * Controls whether switch mobile data to the non-default SIM if the non-default SIM has better
  * availability.
@@ -45,39 +49,88 @@
  * signal/connectivity.
  * If this feature is enabled, data will be temporarily enabled on the non-default data SIM,
  * including during any voice calls.
+ *
+ * Showing this preference in the default data sim UI.
  */
 public class AutoDataSwitchPreferenceController extends TelephonyTogglePreferenceController
         implements LifecycleObserver,
         SubscriptionsChangeListener.SubscriptionsChangeListenerClient {
+    private static final String TAG = "AutoDataSwitchPreferenceController";
 
     private SwitchPreference mPreference;
     private SubscriptionsChangeListener mChangeListener;
     private TelephonyManager mManager;
     private MobileDataContentObserver mMobileDataContentObserver;
     private PreferenceScreen mScreen;
+    private SubscriptionManager mSubscriptionManager;
+    private List<SubscriptionInfo> mSubInfoList;
 
     public AutoDataSwitchPreferenceController(Context context,
             String preferenceKey) {
         super(context, preferenceKey);
+        mSubscriptionManager = mContext.getSystemService(SubscriptionManager.class);
     }
 
     void init(int subId) {
         this.mSubId = subId;
-        mManager = mContext.getSystemService(TelephonyManager.class).createForSubscriptionId(subId);
+        if (renewSubscriptionInfoList()) {
+            // If the subscriptionInfos are changed, then
+            mManager = mContext.getSystemService(TelephonyManager.class)
+                    .createForSubscriptionId(getNonDdsSubId());
+        }
+        if (mMobileDataContentObserver == null) {
+            mMobileDataContentObserver = new MobileDataContentObserver(
+                    new Handler(Looper.getMainLooper()));
+            mMobileDataContentObserver.setOnMobileDataChangedListener(() -> {
+                mManager = mContext.getSystemService(TelephonyManager.class)
+                        .createForSubscriptionId(getNonDdsSubId());
+                refreshPreference();
+            });
+        }
+    }
+
+    private void renewTelephonyComponent() {
+        if (renewSubscriptionInfoList()) {
+            // If the subscriptionInfos are changed, then
+            if (mMobileDataContentObserver != null) {
+                mMobileDataContentObserver.unRegister(mContext);
+            }
+        }
+        if (mSubInfoList == null) {
+            Log.d(TAG, "mSubInfoList is null. Stop to register the listener");
+            return;
+        }
+        if (mMobileDataContentObserver != null) {
+            for (SubscriptionInfo subInfo : mSubInfoList) {
+                mMobileDataContentObserver.register(mContext, subInfo.getSubscriptionId());
+            }
+        }
+        mManager = mContext.getSystemService(TelephonyManager.class)
+                .createForSubscriptionId(getNonDdsSubId());
+    }
+
+    /**
+     * Renew the subscriptionInfoList if the subscriptionInfos are changed.
+     * @return true if the subscriptionInfos are changed. Otherwise, return false.
+     */
+    private boolean renewSubscriptionInfoList() {
+        final List<SubscriptionInfo> newSubInfoList =
+                mSubscriptionManager.getActiveSubscriptionInfoList();
+        if ((newSubInfoList == null && mSubInfoList == null)
+                || (mSubInfoList != null && mSubInfoList.equals(newSubInfoList))) {
+            return false;
+        }
+        mSubInfoList = newSubInfoList;
+        return true;
     }
 
     @OnLifecycleEvent(ON_RESUME)
     public void onResume() {
+        renewTelephonyComponent();
         if (mChangeListener == null) {
             mChangeListener = new SubscriptionsChangeListener(mContext, this);
         }
         mChangeListener.start();
-        if (mMobileDataContentObserver == null) {
-            mMobileDataContentObserver = new MobileDataContentObserver(
-                    new Handler(Looper.getMainLooper()));
-            mMobileDataContentObserver.setOnMobileDataChangedListener(() -> refreshPreference());
-        }
-        mMobileDataContentObserver.register(mContext, mSubId);
     }
 
     @OnLifecycleEvent(ON_PAUSE)
@@ -105,6 +158,10 @@
 
     @Override
     public boolean setChecked(boolean isChecked) {
+        if (mManager == null) {
+            Log.d(TAG, "mManager is null.");
+            return false;
+        }
         mManager.setMobileDataPolicyEnabled(
                 TelephonyManager.MOBILE_DATA_POLICY_AUTO_DATA_SWITCH,
                 isChecked);
@@ -119,7 +176,8 @@
     @Override
     public int getAvailabilityStatus(int subId) {
         if (!SubscriptionManager.isValidSubscriptionId(subId)
-                || SubscriptionManager.getDefaultDataSubscriptionId() == subId
+                || SubscriptionManager.getDefaultDataSubscriptionId() != subId
+                || !SubscriptionManager.isValidSubscriptionId(getNonDdsSubId())
                 || (!hasMobileData())) {
             return CONDITIONALLY_UNAVAILABLE;
         }
@@ -136,10 +194,12 @@
     }
 
     @Override
-    public void onAirplaneModeChanged(boolean airplaneModeEnabled) {}
+    public void onAirplaneModeChanged(boolean airplaneModeEnabled) {
+    }
 
     @Override
     public void onSubscriptionsChanged() {
+        renewTelephonyComponent();
         updateState(mPreference);
     }
 
@@ -152,4 +212,23 @@
             super.displayPreference(mScreen);
         }
     }
+
+    private int getNonDdsSubId() {
+        int ddsSubId = SubscriptionManager.getDefaultDataSubscriptionId();
+        Log.d(TAG, "DDS SubId: " + ddsSubId);
+
+        if (ddsSubId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
+            return SubscriptionManager.INVALID_SUBSCRIPTION_ID;
+        }
+
+        if (mSubInfoList == null) {
+            return SubscriptionManager.INVALID_SUBSCRIPTION_ID;
+        }
+
+        return mSubInfoList.stream()
+                .mapToInt(subInfo -> subInfo.getSubscriptionId())
+                .filter(subId -> subId != ddsSubId)
+                .findFirst()
+                .orElse(SubscriptionManager.INVALID_SUBSCRIPTION_ID);
+    }
 }
diff --git a/src/com/android/settings/nfc/DefaultPaymentSettings.java b/src/com/android/settings/nfc/DefaultPaymentSettings.java
index 5224d92..ddac08b 100644
--- a/src/com/android/settings/nfc/DefaultPaymentSettings.java
+++ b/src/com/android/settings/nfc/DefaultPaymentSettings.java
@@ -58,7 +58,7 @@
 
     @Override
     public int getMetricsCategory() {
-        return SettingsEnums.NFC_PAYMENT;
+        return SettingsEnums.NFC_DEFAULT_PAYMENT;
     }
 
     @Override
diff --git a/src/com/android/settings/notification/app/ConversationNotificationSettings.java b/src/com/android/settings/notification/app/ConversationNotificationSettings.java
index ec9c65f..b452309 100644
--- a/src/com/android/settings/notification/app/ConversationNotificationSettings.java
+++ b/src/com/android/settings/notification/app/ConversationNotificationSettings.java
@@ -83,6 +83,7 @@
     protected List<AbstractPreferenceController> createPreferenceControllers(Context context) {
         mControllers = new ArrayList<>();
         mControllers.add(new ConversationHeaderPreferenceController(context, this));
+        mControllers.add(new BlockPreferenceController(context, mDependentFieldListener, mBackend));
         mControllers.add(new ConversationPriorityPreferenceController(
                 context, mBackend, mDependentFieldListener));
         mControllers.add(new HighImportancePreferenceController(
diff --git a/src/com/android/settings/password/ChooseLockPattern.java b/src/com/android/settings/password/ChooseLockPattern.java
index c39ef66..07c533f 100644
--- a/src/com/android/settings/password/ChooseLockPattern.java
+++ b/src/com/android/settings/password/ChooseLockPattern.java
@@ -215,6 +215,7 @@
         private FooterButton mNextButton;
         @VisibleForTesting protected LockscreenCredential mChosenPattern;
         private ColorStateList mDefaultHeaderColorList;
+        private View mSudContent;
 
         /**
          * The patten used during the help screen to show how to draw a pattern.
@@ -537,6 +538,10 @@
             );
             mSkipOrClearButton = mixin.getSecondaryButton();
             mNextButton = mixin.getPrimaryButton();
+            // TODO(b/243008023) Workaround for Glif layout on 2 panel choose lock settings.
+            mSudContent = layout.findViewById(R.id.sud_layout_content);
+            mSudContent.setPadding(mSudContent.getPaddingLeft(), 0, mSudContent.getPaddingRight(),
+                    0);
 
             return layout;
         }
diff --git a/src/com/android/settings/password/ConfirmLockPattern.java b/src/com/android/settings/password/ConfirmLockPattern.java
index 1062d94..b4f0aa3 100644
--- a/src/com/android/settings/password/ConfirmLockPattern.java
+++ b/src/com/android/settings/password/ConfirmLockPattern.java
@@ -100,6 +100,7 @@
         private CountDownTimer mCountdownTimer;
 
         private GlifLayout mGlifLayout;
+        private View mSudContent;
 
         // caller-supplied text for various prompts
         private CharSequence mHeaderText;
@@ -129,7 +130,10 @@
             mGlifLayout = view.findViewById(R.id.setup_wizard_layout);
             mLockPatternView = (LockPatternView) view.findViewById(R.id.lockPattern);
             mErrorTextView = (TextView) view.findViewById(R.id.errorText);
-
+            // TODO(b/243008023) Workaround for Glif layout on 2 panel choose lock settings.
+            mSudContent = mGlifLayout.findViewById(R.id.sud_layout_content);
+            mSudContent.setPadding(mSudContent.getPaddingLeft(), 0, mSudContent.getPaddingRight(),
+                    0);
             mIsManagedProfile = UserManager.get(getActivity()).isManagedProfile(mEffectiveUserId);
 
             // make it so unhandled touch events within the unlock screen go to the
diff --git a/src/com/android/settings/spa/app/AllAppList.kt b/src/com/android/settings/spa/app/AllAppList.kt
index f5e2e97..ba7c300 100644
--- a/src/com/android/settings/spa/app/AllAppList.kt
+++ b/src/com/android/settings/spa/app/AllAppList.kt
@@ -47,7 +47,7 @@
 
     fun buildInjectEntry() = SettingsEntryBuilder
         .createInject(owner = SettingsPage.create(name))
-        .setIsAllowSearch(true)
+        .setSearchDataFn { null }
         .setUiLayoutFn {
             Preference(object : PreferenceModel {
                 override val title = stringResource(R.string.all_apps)
diff --git a/src/com/android/settings/spa/app/AppsMain.kt b/src/com/android/settings/spa/app/AppsMain.kt
index 6fcc480..4b47278 100644
--- a/src/com/android/settings/spa/app/AppsMain.kt
+++ b/src/com/android/settings/spa/app/AppsMain.kt
@@ -49,7 +49,7 @@
     }
 
     fun buildInjectEntry() =
-        SettingsEntryBuilder.createInject(owner = owner).setIsAllowSearch(false)
+        SettingsEntryBuilder.createInject(owner = owner)
             .setUiLayoutFn {
                 Preference(object : PreferenceModel {
                     override val title = stringResource(R.string.apps_dashboard_title)
diff --git a/src/com/android/settings/spa/app/appinfo/AppButtons.kt b/src/com/android/settings/spa/app/appinfo/AppButtons.kt
index 06016fc..cbe2f1a 100644
--- a/src/com/android/settings/spa/app/appinfo/AppButtons.kt
+++ b/src/com/android/settings/spa/app/appinfo/AppButtons.kt
@@ -21,23 +21,21 @@
 import androidx.compose.runtime.collectAsState
 import androidx.compose.runtime.remember
 import com.android.settingslib.applications.AppUtils
-import com.android.settingslib.spa.framework.compose.collectAsStateWithLifecycle
 import com.android.settingslib.spa.widget.button.ActionButton
 import com.android.settingslib.spa.widget.button.ActionButtons
-import com.android.settingslib.spaprivileged.model.app.isSystemModule
-import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.flow.flow
 import kotlinx.coroutines.flow.map
-import kotlinx.coroutines.withContext
 
 @Composable
 fun AppButtons(packageInfoPresenter: PackageInfoPresenter) {
+    if (remember(packageInfoPresenter) { packageInfoPresenter.isMainlineModule() }) return
     val presenter = remember { AppButtonsPresenter(packageInfoPresenter) }
-    if (!presenter.isAvailableFlow.collectAsStateWithLifecycle(initialValue = false).value) return
     presenter.Dialogs()
     ActionButtons(actionButtons = presenter.rememberActionsButtons().value)
 }
 
+private fun PackageInfoPresenter.isMainlineModule(): Boolean =
+    AppUtils.isMainlineModule(userPackageManager, packageName)
+
 private class AppButtonsPresenter(private val packageInfoPresenter: PackageInfoPresenter) {
     private val appLaunchButton = AppLaunchButton(packageInfoPresenter)
     private val appInstallButton = AppInstallButton(packageInfoPresenter)
@@ -46,15 +44,6 @@
     private val appClearButton = AppClearButton(packageInfoPresenter)
     private val appForceStopButton = AppForceStopButton(packageInfoPresenter)
 
-    val isAvailableFlow = flow { emit(isAvailable()) }
-
-    private suspend fun isAvailable(): Boolean = withContext(Dispatchers.IO) {
-        !packageInfoPresenter.userPackageManager.isSystemModule(packageInfoPresenter.packageName) &&
-            !AppUtils.isMainlineModule(
-                packageInfoPresenter.userPackageManager, packageInfoPresenter.packageName
-            )
-    }
-
     @Composable
     fun rememberActionsButtons() = remember {
         packageInfoPresenter.flow.map { packageInfo ->
diff --git a/src/com/android/settings/spa/app/appinfo/PackageInfoPresenter.kt b/src/com/android/settings/spa/app/appinfo/PackageInfoPresenter.kt
index 26d2760..cb74388 100644
--- a/src/com/android/settings/spa/app/appinfo/PackageInfoPresenter.kt
+++ b/src/com/android/settings/spa/app/appinfo/PackageInfoPresenter.kt
@@ -16,7 +16,6 @@
 
 package com.android.settings.spa.app.appinfo
 
-import android.app.ActivityManager
 import android.app.settings.SettingsEnums
 import android.content.Context
 import android.content.Intent
@@ -29,8 +28,10 @@
 import androidx.compose.runtime.Composable
 import com.android.settings.overlay.FeatureFactory
 import com.android.settingslib.spa.framework.compose.LocalNavController
+import com.android.settingslib.spaprivileged.framework.common.activityManager
 import com.android.settingslib.spaprivileged.framework.common.asUser
 import com.android.settingslib.spaprivileged.framework.compose.DisposableBroadcastReceiverAsUser
+import com.android.settingslib.spaprivileged.model.app.IPackageManagers
 import com.android.settingslib.spaprivileged.model.app.PackageManagers
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.Dispatchers
@@ -48,6 +49,7 @@
     val packageName: String,
     val userId: Int,
     private val coroutineScope: CoroutineScope,
+    private val packageManagers: IPackageManagers = PackageManagers,
 ) {
     private val metricsFeatureProvider = FeatureFactory.getFactory(context).metricsFeatureProvider
     private val userHandle = UserHandle.of(userId)
@@ -134,9 +136,8 @@
     fun forceStop() {
         logAction(SettingsEnums.ACTION_APP_FORCE_STOP)
         coroutineScope.launch(Dispatchers.Default) {
-            val activityManager = context.getSystemService(ActivityManager::class.java)!!
             Log.d(TAG, "Stopping package $packageName")
-            activityManager.forceStopPackageAsUser(packageName, userId)
+            context.activityManager.forceStopPackageAsUser(packageName, userId)
             notifyChange()
         }
     }
@@ -146,11 +147,9 @@
     }
 
     private fun getPackageInfo() =
-        PackageManagers.getPackageInfoAsUser(
+        packageManagers.getPackageInfoAsUser(
             packageName = packageName,
-            flags = PackageManager.MATCH_DISABLED_COMPONENTS or
-                PackageManager.GET_SIGNATURES or
-                PackageManager.GET_PERMISSIONS,
+            flags = PackageManager.MATCH_DISABLED_COMPONENTS or PackageManager.GET_PERMISSIONS,
             userId = userId,
         )
 }
diff --git a/src/com/android/settings/spa/app/specialaccess/SpecialAppAccess.kt b/src/com/android/settings/spa/app/specialaccess/SpecialAppAccess.kt
index f7dea34..5602649 100644
--- a/src/com/android/settings/spa/app/specialaccess/SpecialAppAccess.kt
+++ b/src/com/android/settings/spa/app/specialaccess/SpecialAppAccess.kt
@@ -49,8 +49,7 @@
         })
     }
 
-    fun buildInjectEntry() =
-        SettingsEntryBuilder.createInject(owner = SettingsPage.create(name)).setIsAllowSearch(false)
+    fun buildInjectEntry() = SettingsEntryBuilder.createInject(owner = SettingsPage.create(name))
 
     override fun buildEntry(arguments: Bundle?): List<SettingsEntry> {
         val owner = SettingsPage.create(name, parameter = parameter, arguments = arguments)
diff --git a/src/com/android/settings/spa/notification/NotificationMain.kt b/src/com/android/settings/spa/notification/NotificationMain.kt
index 5a0634c..2324dd8 100644
--- a/src/com/android/settings/spa/notification/NotificationMain.kt
+++ b/src/com/android/settings/spa/notification/NotificationMain.kt
@@ -49,7 +49,7 @@
     }
 
     fun buildInjectEntry(): SettingsEntryBuilder {
-        return SettingsEntryBuilder.createInject(owner = owner).setIsAllowSearch(false)
+        return SettingsEntryBuilder.createInject(owner = owner)
             .setUiLayoutFn {
                 Preference(object : PreferenceModel {
                     override val title = stringResource(R.string.configure_notification_settings)
diff --git a/src/com/android/settings/spa/system/SystemMain.kt b/src/com/android/settings/spa/system/SystemMain.kt
index a004103..6e07a19 100644
--- a/src/com/android/settings/spa/system/SystemMain.kt
+++ b/src/com/android/settings/spa/system/SystemMain.kt
@@ -49,7 +49,7 @@
     }
 
     fun buildInjectEntry(): SettingsEntryBuilder {
-        return SettingsEntryBuilder.createInject(owner = owner).setIsAllowSearch(false)
+        return SettingsEntryBuilder.createInject(owner = owner)
             .setUiLayoutFn {
                 Preference(object : PreferenceModel {
                     override val title = stringResource(R.string.header_category_system)
diff --git a/src/com/android/settings/wifi/p2p/WifiP2pSettings.java b/src/com/android/settings/wifi/p2p/WifiP2pSettings.java
index c0febe2..c2111d6 100644
--- a/src/com/android/settings/wifi/p2p/WifiP2pSettings.java
+++ b/src/com/android/settings/wifi/p2p/WifiP2pSettings.java
@@ -76,7 +76,7 @@
 
     private final IntentFilter mIntentFilter = new IntentFilter();
     @VisibleForTesting WifiP2pManager mWifiP2pManager;
-    @VisibleForTesting WifiP2pManager.Channel mChannel;
+    @VisibleForTesting static WifiP2pManager.Channel sChannel;
     @VisibleForTesting OnClickListener mRenameListener;
     @VisibleForTesting OnClickListener mDisconnectListener;
     @VisibleForTesting OnClickListener mCancelConnectListener;
@@ -150,8 +150,8 @@
                 // Requesting our own device info as an app holding the NETWORK_SETTINGS permission
                 // ensures that the MAC address will be available in the result.
                 if (DBG) Log.d(TAG, "This device changed. Requesting device info.");
-                if (mWifiP2pManager != null && mChannel != null) {
-                    mWifiP2pManager.requestDeviceInfo(mChannel, WifiP2pSettings.this);
+                if (mWifiP2pManager != null && sChannel != null) {
+                    mWifiP2pManager.requestDeviceInfo(sChannel, WifiP2pSettings.this);
                 }
             } else if (WifiP2pManager.WIFI_P2P_DISCOVERY_CHANGED_ACTION.equals(action)) {
                 int discoveryState = intent.getIntExtra(WifiP2pManager.EXTRA_DISCOVERY_STATE,
@@ -163,8 +163,8 @@
                     updateSearchMenu(false);
                 }
             } else if (WifiP2pManager.ACTION_WIFI_P2P_PERSISTENT_GROUPS_CHANGED.equals(action)) {
-                if (mWifiP2pManager != null && mChannel != null) {
-                    mWifiP2pManager.requestPersistentGroupInfo(mChannel, WifiP2pSettings.this);
+                if (mWifiP2pManager != null && sChannel != null) {
+                    mWifiP2pManager.requestPersistentGroupInfo(sChannel, WifiP2pSettings.this);
                 }
             }
         }
@@ -239,7 +239,7 @@
             @Override
             public void onClick(DialogInterface dialog, int which) {
                 if (which == DialogInterface.BUTTON_POSITIVE) {
-                    if (mWifiP2pManager != null && mChannel != null) {
+                    if (mWifiP2pManager != null && sChannel != null) {
                         String name = mDeviceNameText.getText().toString();
                         if (name != null) {
                             for (int i = 0; i < name.length(); i++) {
@@ -253,7 +253,7 @@
                                 }
                             }
                         }
-                        mWifiP2pManager.setDeviceName(mChannel,
+                        mWifiP2pManager.setDeviceName(sChannel,
                                 mDeviceNameText.getText().toString(),
                                 new WifiP2pManager.ActionListener() {
                             public void onSuccess() {
@@ -275,8 +275,8 @@
             @Override
             public void onClick(DialogInterface dialog, int which) {
                 if (which == DialogInterface.BUTTON_POSITIVE) {
-                    if (mWifiP2pManager != null && mChannel != null) {
-                        mWifiP2pManager.removeGroup(mChannel, new WifiP2pManager.ActionListener() {
+                    if (mWifiP2pManager != null && sChannel != null) {
+                        mWifiP2pManager.removeGroup(sChannel, new WifiP2pManager.ActionListener() {
                             public void onSuccess() {
                                 if (DBG) Log.d(TAG, " remove group success");
                             }
@@ -294,8 +294,8 @@
             @Override
             public void onClick(DialogInterface dialog, int which) {
                 if (which == DialogInterface.BUTTON_POSITIVE) {
-                    if (mWifiP2pManager != null && mChannel != null) {
-                        mWifiP2pManager.cancelConnect(mChannel,
+                    if (mWifiP2pManager != null && sChannel != null) {
+                        mWifiP2pManager.cancelConnect(sChannel,
                                 new WifiP2pManager.ActionListener() {
                             public void onSuccess() {
                                 if (DBG) Log.d(TAG, " cancel connect success");
@@ -314,10 +314,10 @@
             @Override
             public void onClick(DialogInterface dialog, int which) {
                 if (which == DialogInterface.BUTTON_POSITIVE) {
-                    if (mWifiP2pManager != null && mChannel != null) {
+                    if (mWifiP2pManager != null && sChannel != null) {
                         if (mSelectedGroup != null) {
                             if (DBG) Log.d(TAG, " deleting group " + mSelectedGroup.getGroupName());
-                            mWifiP2pManager.deletePersistentGroup(mChannel,
+                            mWifiP2pManager.deletePersistentGroup(sChannel,
                                     mSelectedGroup.getNetworkId(),
                                     new WifiP2pManager.ActionListener() {
                                         public void onSuccess() {
@@ -357,8 +357,8 @@
         if (mWifiP2pManager != null && initChannel()) {
             // Register receiver after make sure channel exist
             getActivity().registerReceiver(mReceiver, mIntentFilter);
-            mWifiP2pManager.requestPeers(mChannel, WifiP2pSettings.this);
-            mWifiP2pManager.requestDeviceInfo(mChannel, WifiP2pSettings.this);
+            mWifiP2pManager.requestPeers(sChannel, WifiP2pSettings.this);
+            mWifiP2pManager.requestDeviceInfo(sChannel, WifiP2pSettings.this);
             mIsIgnoreInitConnectionInfoCallback = false;
         }
     }
@@ -366,12 +366,12 @@
     @Override
     public void onStop() {
         super.onStop();
-        if (mWifiP2pManager != null && mChannel != null) {
-            mWifiP2pManager.stopPeerDiscovery(mChannel, null);
+        if (mWifiP2pManager != null && sChannel != null) {
+            mWifiP2pManager.stopPeerDiscovery(sChannel, null);
             if (!mLastGroupFormed) {
                 // Close the channel when p2p doesn't connected.
-                mChannel.close();
-                mChannel = null;
+                sChannel.close();
+                sChannel = null;
             }
         }
         getActivity().unregisterReceiver(mReceiver);
@@ -445,8 +445,8 @@
                         config.wps.setup = WpsInfo.DISPLAY;
                     }
                 }
-                if (mWifiP2pManager != null && mChannel != null) {
-                    mWifiP2pManager.connect(mChannel, config,
+                if (mWifiP2pManager != null && sChannel != null) {
+                    mWifiP2pManager.connect(sChannel, config,
                             new WifiP2pManager.ActionListener() {
                                 public void onSuccess() {
                                     if (DBG) Log.d(TAG, " connect success");
@@ -617,9 +617,9 @@
     }
 
     private void onDeviceAvailable() {
-        mWifiP2pManager.requestNetworkInfo(mChannel, networkInfo -> {
-            if (mChannel == null) return;
-            mWifiP2pManager.requestConnectionInfo(mChannel, wifip2pinfo -> {
+        mWifiP2pManager.requestNetworkInfo(sChannel, networkInfo -> {
+            if (sChannel == null) return;
+            mWifiP2pManager.requestConnectionInfo(sChannel, wifip2pinfo -> {
                 if (!mIsIgnoreInitConnectionInfoCallback) {
                     if (networkInfo.isConnected()) {
                         if (DBG) {
@@ -652,8 +652,8 @@
     }
 
     private void startSearch() {
-        if (mWifiP2pManager != null && mChannel != null && !mWifiP2pSearching) {
-            mWifiP2pManager.discoverPeers(mChannel, new WifiP2pManager.ActionListener() {
+        if (mWifiP2pManager != null && sChannel != null && !mWifiP2pSearching) {
+            mWifiP2pManager.discoverPeers(sChannel, new WifiP2pManager.ActionListener() {
                 public void onSuccess() {
                 }
                 public void onFailure(int reason) {
@@ -664,14 +664,14 @@
     }
 
     private boolean initChannel() {
-        if (mChannel != null) {
+        if (sChannel != null) {
             return true;
         }
         if (mWifiP2pManager != null) {
-            mChannel = mWifiP2pManager.initialize(getActivity().getApplicationContext(),
+            sChannel = mWifiP2pManager.initialize(getActivity().getApplicationContext(),
                     getActivity().getMainLooper(), null);
         }
-        if (mChannel == null) {
+        if (sChannel == null) {
             Log.e(TAG, "Failed to set up connection with wifi p2p service");
             return false;
         }
diff --git a/tests/robotests/src/com/android/settings/accessibility/AccessibilityHearingAidPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/accessibility/AccessibilityHearingAidPreferenceControllerTest.java
index dc37d23..62d09e1 100644
--- a/tests/robotests/src/com/android/settings/accessibility/AccessibilityHearingAidPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/accessibility/AccessibilityHearingAidPreferenceControllerTest.java
@@ -27,6 +27,7 @@
 import android.app.Activity;
 import android.bluetooth.BluetoothAdapter;
 import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothHapClient;
 import android.bluetooth.BluetoothHearingAid;
 import android.bluetooth.BluetoothProfile;
 import android.content.BroadcastReceiver;
@@ -44,6 +45,8 @@
 import com.android.settingslib.bluetooth.BluetoothEventManager;
 import com.android.settingslib.bluetooth.CachedBluetoothDevice;
 import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager;
+import com.android.settingslib.bluetooth.HapClientProfile;
+import com.android.settingslib.bluetooth.HearingAidInfo;
 import com.android.settingslib.bluetooth.HearingAidProfile;
 import com.android.settingslib.bluetooth.LocalBluetoothManager;
 import com.android.settingslib.bluetooth.LocalBluetoothProfileManager;
@@ -61,13 +64,16 @@
 import org.robolectric.shadows.ShadowApplication;
 
 import java.util.ArrayList;
+import java.util.HashSet;
 import java.util.List;
+import java.util.Set;
 
 /** Tests for {@link AccessibilityHearingAidPreferenceController}. */
 @RunWith(RobolectricTestRunner.class)
 @Config(shadows = {ShadowBluetoothAdapter.class, ShadowBluetoothUtils.class})
 public class AccessibilityHearingAidPreferenceControllerTest {
     private static final String TEST_DEVICE_ADDRESS = "00:A1:A1:A1:A1:A1";
+    private static final String TEST_DEVICE_ADDRESS_2 = "00:A2:A2:A2:A2:A2";
     private static final String TEST_DEVICE_NAME = "TEST_HEARING_AID_BT_DEVICE_NAME";
     private static final String HEARING_AID_PREFERENCE = "hearing_aid_preference";
 
@@ -93,6 +99,8 @@
     private LocalBluetoothProfileManager mLocalBluetoothProfileManager;
     @Mock
     private HearingAidProfile mHearingAidProfile;
+    @Mock
+    private HapClientProfile mHapClientProfile;
 
     @Before
     public void setUp() {
@@ -115,10 +123,11 @@
     }
 
     @Test
-    public void getSummary_connectedHearingAidRightSide_connectedRightSideSummary() {
+    public void getSummary_connectedAshaHearingAidRightSide_connectedRightSideSummary() {
         when(mCachedBluetoothDevice.getDeviceSide()).thenReturn(
-                HearingAidProfile.DeviceSide.SIDE_RIGHT);
+                HearingAidInfo.DeviceSide.SIDE_RIGHT);
         when(mHearingAidProfile.getConnectedDevices()).thenReturn(generateHearingAidDeviceList());
+
         mPreferenceController.onStart();
         Intent intent = new Intent(BluetoothHearingAid.ACTION_CONNECTION_STATE_CHANGED);
         intent.putExtra(BluetoothHearingAid.EXTRA_STATE, BluetoothHearingAid.STATE_CONNECTED);
@@ -129,12 +138,13 @@
     }
 
     @Test
-    public void getSummary_connectedHearingAidBothSide_connectedBothSideSummary() {
+    public void getSummary_connectedAshaHearingAidBothSide_connectedBothSideSummary() {
         when(mCachedBluetoothDevice.getDeviceSide()).thenReturn(
-                HearingAidProfile.DeviceSide.SIDE_LEFT);
+                HearingAidInfo.DeviceSide.SIDE_LEFT);
         when(mCachedSubBluetoothDevice.isConnected()).thenReturn(true);
         when(mCachedBluetoothDevice.getSubDevice()).thenReturn(mCachedSubBluetoothDevice);
         when(mHearingAidProfile.getConnectedDevices()).thenReturn(generateHearingAidDeviceList());
+
         mPreferenceController.onStart();
         Intent intent = new Intent(BluetoothHearingAid.ACTION_CONNECTION_STATE_CHANGED);
         intent.putExtra(BluetoothHearingAid.EXTRA_STATE, BluetoothHearingAid.STATE_CONNECTED);
@@ -145,13 +155,75 @@
     }
 
     @Test
-    public void getSummary_connectedMultipleHearingAids_connectedBothSideSummary() {
+    public void getSummary_connectedLeAudioHearingAidLeftSide_connectedLeftSideSummary() {
         when(mCachedBluetoothDevice.getDeviceSide()).thenReturn(
-                HearingAidProfile.DeviceSide.SIDE_LEFT);
+                HearingAidInfo.DeviceSide.SIDE_LEFT);
+        when(mCachedBluetoothDevice.getMemberDevice()).thenReturn(new HashSet<>());
+        when(mHapClientProfile.getConnectedDevices()).thenReturn(generateHearingAidDeviceList());
+
+        mPreferenceController.onStart();
+        Intent intent = new Intent(BluetoothHapClient.ACTION_HAP_CONNECTION_STATE_CHANGED);
+        intent.putExtra(BluetoothHearingAid.EXTRA_STATE, BluetoothHapClient.STATE_CONNECTED);
+        sendIntent(intent);
+
+        assertThat(mHearingAidPreference.getSummary().toString().contentEquals(
+                "TEST_HEARING_AID_BT_DEVICE_NAME, left only")).isTrue();
+    }
+
+    @Test
+    public void getSummary_connectedLeAudioHearingAidRightSide_connectedRightSideSummary() {
+        when(mCachedBluetoothDevice.getDeviceSide()).thenReturn(
+                HearingAidInfo.DeviceSide.SIDE_RIGHT);
+        when(mCachedBluetoothDevice.getMemberDevice()).thenReturn(new HashSet<>());
+        when(mHapClientProfile.getConnectedDevices()).thenReturn(generateHearingAidDeviceList());
+
+        mPreferenceController.onStart();
+        Intent intent = new Intent(BluetoothHapClient.ACTION_HAP_CONNECTION_STATE_CHANGED);
+        intent.putExtra(BluetoothHearingAid.EXTRA_STATE, BluetoothHapClient.STATE_CONNECTED);
+        sendIntent(intent);
+
+        assertThat(mHearingAidPreference.getSummary().toString().contentEquals(
+                "TEST_HEARING_AID_BT_DEVICE_NAME, right only")).isTrue();
+    }
+
+    @Test
+    public void getSummary_connectedLeAudioHearingAidLeftAndRightSide_connectedSummary() {
+        when(mCachedBluetoothDevice.getDeviceSide()).thenReturn(
+                HearingAidInfo.DeviceSide.SIDE_LEFT_AND_RIGHT);
+        when(mCachedBluetoothDevice.getMemberDevice()).thenReturn(new HashSet<>());
+        when(mHapClientProfile.getConnectedDevices()).thenReturn(generateHearingAidDeviceList());
+
+        mPreferenceController.onStart();
+        Intent intent = new Intent(BluetoothHapClient.ACTION_HAP_CONNECTION_STATE_CHANGED);
+        intent.putExtra(BluetoothHearingAid.EXTRA_STATE, BluetoothHapClient.STATE_CONNECTED);
+        sendIntent(intent);
+
+        assertThat(mHearingAidPreference.getSummary().toString().contentEquals(
+                "TEST_HEARING_AID_BT_DEVICE_NAME, left and right")).isTrue();
+    }
+
+    @Test
+    public void getSummary_connectedLeAudioHearingAidBothSide_connectedBothSideSummary() {
+        when(mCachedBluetoothDevice.getMemberDevice()).thenReturn(generateMemberDevices());
         when(mCachedSubBluetoothDevice.isConnected()).thenReturn(true);
-        when(mCachedBluetoothDevice.getSubDevice()).thenReturn(mCachedSubBluetoothDevice);
+        when(mHapClientProfile.getConnectedDevices()).thenReturn(generateHearingAidDeviceList());
+
+        mPreferenceController.onStart();
+        Intent intent = new Intent(BluetoothHapClient.ACTION_HAP_CONNECTION_STATE_CHANGED);
+        intent.putExtra(BluetoothHearingAid.EXTRA_STATE, BluetoothHapClient.STATE_CONNECTED);
+        sendIntent(intent);
+
+        assertThat(mHearingAidPreference.getSummary().toString()).isEqualTo(
+                "TEST_HEARING_AID_BT_DEVICE_NAME, left and right");
+    }
+
+    @Test
+    public void getSummary_connectedMultipleHearingAids_connectedMultipleDevicesSummary() {
+        when(mCachedBluetoothDevice.getDeviceSide()).thenReturn(
+                HearingAidInfo.DeviceSide.SIDE_LEFT);
         when(mHearingAidProfile.getConnectedDevices()).thenReturn(
                 generateMultipleHearingAidDeviceList());
+
         mPreferenceController.onStart();
         Intent intent = new Intent(BluetoothHearingAid.ACTION_CONNECTION_STATE_CHANGED);
         intent.putExtra(BluetoothHearingAid.EXTRA_STATE, BluetoothHearingAid.STATE_CONNECTED);
@@ -162,17 +234,6 @@
     }
 
     @Test
-    public void getSummary_disconnectedHearingAid_disconnectedSummary() {
-        mPreferenceController.onStart();
-        Intent intent = new Intent(BluetoothHearingAid.ACTION_CONNECTION_STATE_CHANGED);
-        intent.putExtra(BluetoothHearingAid.EXTRA_STATE, BluetoothHearingAid.STATE_DISCONNECTED);
-        sendIntent(intent);
-
-        assertThat(mHearingAidPreference.getSummary()).isEqualTo(
-                mContext.getText(R.string.accessibility_hearingaid_not_connected_summary));
-    }
-
-    @Test
     public void getSummary_bluetoothOff_disconnectedSummary() {
         mPreferenceController.onStart();
         Intent intent = new Intent(BluetoothAdapter.ACTION_STATE_CHANGED);
@@ -208,8 +269,29 @@
     }
 
     @Test
-    public void onNotSupportHearingAidProfile_isNotAvailable() {
-        //clear bluetooth supported profile
+    public void onSupportHearingAidProfile_isAvailable() {
+        mShadowBluetoothAdapter.clearSupportedProfiles();
+        mShadowBluetoothAdapter.addSupportedProfiles(BluetoothProfile.HEARING_AID);
+        mPreferenceController = new AccessibilityHearingAidPreferenceController(mContext,
+                HEARING_AID_PREFERENCE);
+        mPreferenceController.setPreference(mHearingAidPreference);
+
+        assertThat(mPreferenceController.isAvailable()).isTrue();
+    }
+
+    @Test
+    public void onSupportHapClientProfile_isAvailable() {
+        mShadowBluetoothAdapter.clearSupportedProfiles();
+        mShadowBluetoothAdapter.addSupportedProfiles(BluetoothProfile.HAP_CLIENT);
+        mPreferenceController = new AccessibilityHearingAidPreferenceController(mContext,
+                HEARING_AID_PREFERENCE);
+        mPreferenceController.setPreference(mHearingAidPreference);
+
+        assertThat(mPreferenceController.isAvailable()).isTrue();
+    }
+
+    @Test
+    public void onNotSupportAnyHearingAidRelatedProfile_isNotAvailable() {
         mShadowBluetoothAdapter.clearSupportedProfiles();
         mPreferenceController = new AccessibilityHearingAidPreferenceController(mContext,
                 HEARING_AID_PREFERENCE);
@@ -231,11 +313,11 @@
     @Config(shadows = ShadowAlertDialogCompat.class)
     public void onActiveDeviceChanged_hearingAidProfile_launchHearingAidPairingDialog() {
         final FragmentActivity mActivity = Robolectric.setupActivity(FragmentActivity.class);
-        when(mCachedBluetoothDevice.isConnectedHearingAidDevice()).thenReturn(true);
+        when(mCachedBluetoothDevice.isConnectedAshaHearingAidDevice()).thenReturn(true);
         when(mCachedBluetoothDevice.getDeviceMode()).thenReturn(
-                HearingAidProfile.DeviceMode.MODE_BINAURAL);
+                HearingAidInfo.DeviceMode.MODE_BINAURAL);
         when(mCachedBluetoothDevice.getDeviceSide()).thenReturn(
-                HearingAidProfile.DeviceSide.SIDE_LEFT);
+                HearingAidInfo.DeviceSide.SIDE_LEFT);
         mPreferenceController.setFragmentManager(mActivity.getSupportFragmentManager());
 
         mPreferenceController.onActiveDeviceChanged(mCachedBluetoothDevice,
@@ -246,27 +328,38 @@
     }
 
     @Test
-    public void onServiceConnected_updateSummary() {
-        mPreferenceController.onStart();
-        when(mCachedBluetoothDevice.isConnectedHearingAidDevice()).thenReturn(true);
-        when(mCachedBluetoothDevice.getDeviceMode()).thenReturn(
-                HearingAidProfile.DeviceMode.MODE_BINAURAL);
+    public void onServiceConnected_onHearingAidProfileConnected_updateSummary() {
         when(mCachedBluetoothDevice.getDeviceSide()).thenReturn(
-                HearingAidProfile.DeviceSide.SIDE_LEFT);
+                HearingAidInfo.DeviceSide.SIDE_LEFT);
         when(mHearingAidProfile.getConnectedDevices()).thenReturn(generateHearingAidDeviceList());
 
+        mPreferenceController.onStart();
         mPreferenceController.onServiceConnected();
 
         assertThat(mHearingAidPreference.getSummary().toString()).isEqualTo(
                 "TEST_HEARING_AID_BT_DEVICE_NAME, left only");
     }
 
+    @Test
+    public void onServiceConnected_onHapClientProfileConnected_updateSummary() {
+        when(mCachedBluetoothDevice.getDeviceSide()).thenReturn(
+                HearingAidInfo.DeviceSide.SIDE_RIGHT);
+        when(mHapClientProfile.getConnectedDevices()).thenReturn(generateHearingAidDeviceList());
+
+        mPreferenceController.onStart();
+        mPreferenceController.onServiceConnected();
+
+        assertThat(mHearingAidPreference.getSummary().toString()).isEqualTo(
+                "TEST_HEARING_AID_BT_DEVICE_NAME, right only");
+    }
+
     private void setupEnvironment() {
         ShadowBluetoothUtils.sLocalBluetoothManager = mLocalBluetoothManager;
         mLocalBluetoothManager = Utils.getLocalBtManager(mContext);
         mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
         mShadowBluetoothAdapter = Shadow.extract(mBluetoothAdapter);
         mShadowBluetoothAdapter.addSupportedProfiles(BluetoothProfile.HEARING_AID);
+        mShadowBluetoothAdapter.addSupportedProfiles(BluetoothProfile.HAP_CLIENT);
         mBluetoothDevice = mBluetoothAdapter.getRemoteDevice(TEST_DEVICE_ADDRESS);
         mBluetoothAdapter.enable();
 
@@ -274,10 +367,12 @@
         when(mLocalBluetoothManager.getCachedDeviceManager()).thenReturn(mCachedDeviceManager);
         when(mLocalBluetoothManager.getProfileManager()).thenReturn(mLocalBluetoothProfileManager);
         when(mLocalBluetoothProfileManager.getHearingAidProfile()).thenReturn(mHearingAidProfile);
+        when(mLocalBluetoothProfileManager.getHapClientProfile()).thenReturn(mHapClientProfile);
+        when(mHearingAidProfile.isProfileReady()).thenReturn(true);
+        when(mHapClientProfile.isProfileReady()).thenReturn(true);
         when(mCachedDeviceManager.findDevice(mBluetoothDevice)).thenReturn(mCachedBluetoothDevice);
         when(mCachedBluetoothDevice.getAddress()).thenReturn(TEST_DEVICE_ADDRESS);
         when(mCachedBluetoothDevice.getName()).thenReturn(TEST_DEVICE_NAME);
-        when(mHearingAidProfile.isProfileReady()).thenReturn(true);
     }
 
     private void sendIntent(Intent intent) {
@@ -293,9 +388,16 @@
     }
 
     private List<BluetoothDevice> generateMultipleHearingAidDeviceList() {
+        // Generates different Bluetooth devices for testing multiple devices
         final List<BluetoothDevice> deviceList = new ArrayList<>(2);
         deviceList.add(mBluetoothDevice);
-        deviceList.add(mBluetoothDevice);
+        deviceList.add(mBluetoothAdapter.getRemoteDevice(TEST_DEVICE_ADDRESS_2));
         return deviceList;
     }
+
+    private Set<CachedBluetoothDevice> generateMemberDevices() {
+        final Set<CachedBluetoothDevice> memberDevices = new HashSet<>();
+        memberDevices.add(mCachedSubBluetoothDevice);
+        return memberDevices;
+    }
 }
diff --git a/tests/robotests/src/com/android/settings/accessibility/HearingAidPairingDialogFragmentTest.java b/tests/robotests/src/com/android/settings/accessibility/HearingAidPairingDialogFragmentTest.java
index bda60d4..033bad3 100644
--- a/tests/robotests/src/com/android/settings/accessibility/HearingAidPairingDialogFragmentTest.java
+++ b/tests/robotests/src/com/android/settings/accessibility/HearingAidPairingDialogFragmentTest.java
@@ -48,7 +48,7 @@
 import com.android.settings.testutils.shadow.ShadowBluetoothUtils;
 import com.android.settingslib.bluetooth.CachedBluetoothDevice;
 import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager;
-import com.android.settingslib.bluetooth.HearingAidProfile;
+import com.android.settingslib.bluetooth.HearingAidInfo;
 import com.android.settingslib.bluetooth.LocalBluetoothManager;
 
 import org.junit.Before;
@@ -104,7 +104,7 @@
     @Test
     public void newInstance_deviceSideRight_argumentSideRight() {
         when(mCachedBluetoothDevice.getDeviceSide()).thenReturn(
-                HearingAidProfile.DeviceSide.SIDE_RIGHT);
+                HearingAidInfo.DeviceSide.SIDE_RIGHT);
         final AlertDialog dialog = (AlertDialog) mFragment.onCreateDialog(Bundle.EMPTY);
         dialog.show();
 
@@ -143,8 +143,8 @@
     }
 
     @Test
-    public void onDeviceAttributesChanged_subHearingAidDeviceConnected_dialogDismiss() {
-        when(mCachedSubBluetoothDevice.isConnectedHearingAidDevice()).thenReturn(true);
+    public void onDeviceAttributesChanged_subAshaHearingAidDeviceConnected_dialogDismiss() {
+        when(mCachedSubBluetoothDevice.isConnectedAshaHearingAidDevice()).thenReturn(true);
         when(mCachedBluetoothDevice.getSubDevice()).thenReturn(mCachedSubBluetoothDevice);
 
         mFragment.onDeviceAttributesChanged();
diff --git a/tests/robotests/src/com/android/settings/accessibility/HearingAidUtilsTest.java b/tests/robotests/src/com/android/settings/accessibility/HearingAidUtilsTest.java
index 6fdd210..b909a66 100644
--- a/tests/robotests/src/com/android/settings/accessibility/HearingAidUtilsTest.java
+++ b/tests/robotests/src/com/android/settings/accessibility/HearingAidUtilsTest.java
@@ -36,7 +36,7 @@
 import com.android.settings.testutils.shadow.ShadowBluetoothUtils;
 import com.android.settingslib.bluetooth.CachedBluetoothDevice;
 import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager;
-import com.android.settingslib.bluetooth.HearingAidProfile;
+import com.android.settingslib.bluetooth.HearingAidInfo;
 import com.android.settingslib.bluetooth.LocalBluetoothManager;
 
 import org.junit.Before;
@@ -86,8 +86,8 @@
     }
 
     @Test
-    public void launchHearingAidPairingDialog_deviceNotConnectedHearingAid_noDialog() {
-        when(mCachedBluetoothDevice.isConnectedHearingAidDevice()).thenReturn(false);
+    public void launchHearingAidPairingDialog_deviceIsNotConnectedAshaHearingAid_noDialog() {
+        when(mCachedBluetoothDevice.isConnectedAshaHearingAidDevice()).thenReturn(false);
 
         HearingAidUtils.launchHearingAidPairingDialog(mFragmentManager, mCachedBluetoothDevice);
 
@@ -96,10 +96,10 @@
     }
 
     @Test
-    public void launchHearingAidPairingDialog_deviceIsModeMonaural_noDialog() {
-        when(mCachedBluetoothDevice.isConnectedHearingAidDevice()).thenReturn(true);
+    public void launchHearingAidPairingDialog_deviceIsMonauralMode_noDialog() {
+        when(mCachedBluetoothDevice.isConnectedAshaHearingAidDevice()).thenReturn(true);
         when(mCachedBluetoothDevice.getDeviceMode()).thenReturn(
-                HearingAidProfile.DeviceMode.MODE_MONAURAL);
+                HearingAidInfo.DeviceMode.MODE_MONAURAL);
 
         HearingAidUtils.launchHearingAidPairingDialog(mFragmentManager, mCachedBluetoothDevice);
 
@@ -109,9 +109,9 @@
 
     @Test
     public void launchHearingAidPairingDialog_deviceHasSubDevice_noDialog() {
-        when(mCachedBluetoothDevice.isConnectedHearingAidDevice()).thenReturn(true);
+        when(mCachedBluetoothDevice.isConnectedAshaHearingAidDevice()).thenReturn(true);
         when(mCachedBluetoothDevice.getDeviceMode()).thenReturn(
-                HearingAidProfile.DeviceMode.MODE_BINAURAL);
+                HearingAidInfo.DeviceMode.MODE_BINAURAL);
         when(mCachedBluetoothDevice.getSubDevice()).thenReturn(mSubCachedBluetoothDevice);
 
         HearingAidUtils.launchHearingAidPairingDialog(mFragmentManager, mCachedBluetoothDevice);
@@ -122,11 +122,11 @@
 
     @Test
     public void launchHearingAidPairingDialog_deviceIsInvalidSide_noDialog() {
-        when(mCachedBluetoothDevice.isConnectedHearingAidDevice()).thenReturn(true);
+        when(mCachedBluetoothDevice.isConnectedAshaHearingAidDevice()).thenReturn(true);
         when(mCachedBluetoothDevice.getDeviceMode()).thenReturn(
-                HearingAidProfile.DeviceMode.MODE_BINAURAL);
+                HearingAidInfo.DeviceMode.MODE_BINAURAL);
         when(mCachedBluetoothDevice.getDeviceSide()).thenReturn(
-                HearingAidProfile.DeviceSide.SIDE_INVALID);
+                HearingAidInfo.DeviceSide.SIDE_INVALID);
 
         HearingAidUtils.launchHearingAidPairingDialog(mFragmentManager, mCachedBluetoothDevice);
 
@@ -136,11 +136,11 @@
 
     @Test
     public void launchHearingAidPairingDialog_dialogShown() {
-        when(mCachedBluetoothDevice.isConnectedHearingAidDevice()).thenReturn(true);
+        when(mCachedBluetoothDevice.isConnectedAshaHearingAidDevice()).thenReturn(true);
         when(mCachedBluetoothDevice.getDeviceMode()).thenReturn(
-                HearingAidProfile.DeviceMode.MODE_BINAURAL);
+                HearingAidInfo.DeviceMode.MODE_BINAURAL);
         when(mCachedBluetoothDevice.getDeviceSide()).thenReturn(
-                HearingAidProfile.DeviceSide.SIDE_LEFT);
+                HearingAidInfo.DeviceSide.SIDE_LEFT);
 
         HearingAidUtils.launchHearingAidPairingDialog(mFragmentManager, mCachedBluetoothDevice);
 
diff --git a/tests/robotests/src/com/android/settings/applications/ClonedAppsPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/applications/ClonedAppsPreferenceControllerTest.java
index 9e30d60..828d88d 100644
--- a/tests/robotests/src/com/android/settings/applications/ClonedAppsPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/applications/ClonedAppsPreferenceControllerTest.java
@@ -16,7 +16,7 @@
 
 package com.android.settings.applications;
 
-import static android.provider.DeviceConfig.NAMESPACE_SETTINGS_UI;
+import static android.provider.DeviceConfig.NAMESPACE_APP_CLONING;
 
 import static com.android.settings.core.BasePreferenceController.AVAILABLE;
 
@@ -29,7 +29,7 @@
 
 import androidx.test.core.app.ApplicationProvider;
 
-import com.android.settings.core.SettingsUIDeviceConfig;
+import com.android.settings.Utils;
 import com.android.settings.testutils.shadow.ShadowDeviceConfig;
 
 import org.junit.Before;
@@ -54,7 +54,7 @@
 
     @Test
     public void getAvailabilityStatus_featureNotEnabled_shouldNotReturnAvailable() {
-        DeviceConfig.setProperty(NAMESPACE_SETTINGS_UI, SettingsUIDeviceConfig.CLONED_APPS_ENABLED,
+        DeviceConfig.setProperty(NAMESPACE_APP_CLONING, Utils.PROPERTY_CLONED_APPS_ENABLED,
                 "false", true /* makeDefault */);
 
         assertThat(mController.getAvailabilityStatus()).isNotEqualTo(AVAILABLE);
@@ -62,10 +62,9 @@
 
     @Test
     public void getAvailabilityStatus_featureEnabled_shouldReturnAvailable() {
-        DeviceConfig.setProperty(NAMESPACE_SETTINGS_UI, SettingsUIDeviceConfig.CLONED_APPS_ENABLED,
+        DeviceConfig.setProperty(NAMESPACE_APP_CLONING, Utils.PROPERTY_CLONED_APPS_ENABLED,
                 "true", true /* makeDefault */);
 
         assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE);
     }
-
 }
diff --git a/tests/robotests/src/com/android/settings/applications/RecentAppStatsMixinTest.java b/tests/robotests/src/com/android/settings/applications/RecentAppStatsMixinTest.java
index 6b94bce..4fb0c05 100644
--- a/tests/robotests/src/com/android/settings/applications/RecentAppStatsMixinTest.java
+++ b/tests/robotests/src/com/android/settings/applications/RecentAppStatsMixinTest.java
@@ -53,12 +53,16 @@
 import org.robolectric.util.ReflectionHelpers;
 
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.List;
-import java.util.Optional;
 
 @RunWith(RobolectricTestRunner.class)
 public class RecentAppStatsMixinTest {
 
+    private static final UserHandle NORMAL_USER = UserHandle.SYSTEM;
+    private static final UserHandle CLONE_USER = new UserHandle(2222);
+    private static final UserHandle WORK_USER = new UserHandle(3333);
+
     @Mock
     private UsageStatsManager mUsageStatsManager;
     @Mock
@@ -75,24 +79,33 @@
     private ApplicationInfo mApplicationInfo;
     @Mock
     private PowerManager mPowerManager;
+    @Mock
+    private UsageStatsManager mCloneUsageStatsManager;
+    @Mock
+    Context mMockContext;
+
+    private Context mContext;
 
     private RecentAppStatsMixin mRecentAppStatsMixin;
 
     @Before
-    public void setUp() {
+    public void setUp() throws PackageManager.NameNotFoundException {
         MockitoAnnotations.initMocks(this);
-        final Context context = spy(RuntimeEnvironment.application);
-        when(context.getApplicationContext()).thenReturn(context);
+        mContext = spy(RuntimeEnvironment.application);
+        when(mContext.getApplicationContext()).thenReturn(mContext);
         ReflectionHelpers.setStaticField(ApplicationsState.class, "sInstance", mAppState);
-        doReturn(mUsageStatsManager).when(context).getSystemService(Context.USAGE_STATS_SERVICE);
-        doReturn(mUserManager).when(context).getSystemService(Context.USER_SERVICE);
-        doReturn(mPackageManager).when(context).getPackageManager();
-        doReturn(mPowerManager).when(context).getSystemService(PowerManager.class);
+        doReturn(mUsageStatsManager).when(mContext).getSystemService(UsageStatsManager.class);
+        doReturn(mUserManager).when(mContext).getSystemService(Context.USER_SERVICE);
+        doReturn(mPackageManager).when(mContext).getPackageManager();
+        doReturn(mPowerManager).when(mContext).getSystemService(PowerManager.class);
         when(mUserManager.getProfileIdsWithDisabled(anyInt())).thenReturn(new int[]{});
 
-        mRecentAppStatsMixin = new RecentAppStatsMixin(context, 3 /* maximumApps */);
-        ReflectionHelpers.setField(mRecentAppStatsMixin, "mWorkUsageStatsManager",
-                Optional.of(mWorkUsageStatsManager));
+        doReturn(mMockContext).when(mContext).createContextAsUser(any(), anyInt());
+        doReturn(mMockContext).when(mContext).createPackageContextAsUser(any(), anyInt(), any());
+        when(mUserManager.getUserProfiles())
+                .thenReturn(new ArrayList<>(Arrays.asList(NORMAL_USER)));
+
+        mRecentAppStatsMixin = new RecentAppStatsMixin(mContext, 3 /* maximumApps */);
     }
 
     @Test
@@ -336,6 +349,10 @@
                 .thenReturn(mAppEntry);
         when(mPackageManager.resolveActivityAsUser(any(Intent.class), anyInt(), anyInt()))
                 .thenReturn(new ResolveInfo());
+        when(mUserManager.getUserProfiles())
+                .thenReturn(new ArrayList<>(Arrays.asList(NORMAL_USER, WORK_USER)));
+        when(mMockContext.getSystemService(UsageStatsManager.class))
+                .thenReturn(mWorkUsageStatsManager);
         // personal app stats
         when(mUsageStatsManager.queryUsageStats(anyInt(), anyLong(), anyLong()))
                 .thenReturn(personalStats);
@@ -356,7 +373,8 @@
     }
 
     @Test
-    public void loadDisplayableRecentApps_usePersonalAndWorkApps_shouldBeUniquePerProfile() {
+    public void loadDisplayableRecentApps_usePersonalAndWorkApps_shouldBeUniquePerProfile()
+            throws PackageManager.NameNotFoundException {
         final String firstAppPackageName = "app1.pkg.class";
         final String secondAppPackageName = "app2.pkg.class";
         final List<UsageStats> personalStats = new ArrayList<>();
@@ -383,6 +401,10 @@
 
         when(mAppState.getEntry(anyString(), anyInt()))
                 .thenReturn(mAppEntry);
+        when(mUserManager.getUserProfiles())
+                .thenReturn(new ArrayList<>(Arrays.asList(NORMAL_USER, WORK_USER)));
+        when(mMockContext.getSystemService(UsageStatsManager.class))
+                .thenReturn(mWorkUsageStatsManager);
         when(mPackageManager.resolveActivityAsUser(any(Intent.class), anyInt(), anyInt()))
                 .thenReturn(new ResolveInfo());
         // personal app stats
@@ -405,4 +427,63 @@
         assertThat(mRecentAppStatsMixin.mRecentApps.get(2).mUsageStats.mPackageName).isEqualTo(
                 secondAppPackageName);
     }
+
+    @Test
+    public void loadDisplayableRecentApps_multipleProfileApps_shouldBeSortedByLastTimeUse()
+            throws PackageManager.NameNotFoundException {
+        final List<UsageStats> personalStats = new ArrayList<>();
+        final UsageStats stats1 = new UsageStats();
+        final UsageStats stats2 = new UsageStats();
+        stats1.mLastTimeUsed = System.currentTimeMillis();
+        stats1.mPackageName = "personal.pkg.class";
+        personalStats.add(stats1);
+
+        stats2.mLastTimeUsed = System.currentTimeMillis() - 5000;
+        stats2.mPackageName = "personal.pkg.class2";
+        personalStats.add(stats2);
+
+        final List<UsageStats> workStats = new ArrayList<>();
+        final UsageStats stat3 = new UsageStats();
+        stat3.mLastTimeUsed = System.currentTimeMillis() - 2000;
+        stat3.mPackageName = "work.pkg.class3";
+        workStats.add(stat3);
+
+        final List<UsageStats> cloneStats = new ArrayList<>();
+        final UsageStats stat4 = new UsageStats();
+        stat4.mLastTimeUsed = System.currentTimeMillis() - 1000;
+        stat4.mPackageName = "clone.pkg.class4";
+        cloneStats.add(stat4);
+
+        when(mAppState.getEntry(anyString(), anyInt()))
+                .thenReturn(mAppEntry);
+        when(mUserManager.getUserProfiles())
+                .thenReturn(new ArrayList<>(Arrays.asList(NORMAL_USER, CLONE_USER, WORK_USER)));
+        when(mMockContext.getSystemService(UsageStatsManager.class))
+                .thenReturn(mCloneUsageStatsManager, mWorkUsageStatsManager);
+        when(mPackageManager.resolveActivityAsUser(any(Intent.class), anyInt(), anyInt()))
+                .thenReturn(new ResolveInfo());
+        // personal app stats
+        when(mUsageStatsManager.queryUsageStats(anyInt(), anyLong(), anyLong()))
+                .thenReturn(personalStats);
+        // work app stats
+        when(mWorkUsageStatsManager.queryUsageStats(anyInt(), anyLong(), anyLong()))
+                .thenReturn(workStats);
+        // clone app stats
+        when(mCloneUsageStatsManager.queryUsageStats(anyInt(), anyLong(), anyLong()))
+                .thenReturn(cloneStats);
+
+        mAppEntry.info = mApplicationInfo;
+
+        mRecentAppStatsMixin.loadDisplayableRecentApps(4);
+
+        assertThat(mRecentAppStatsMixin.mRecentApps.size()).isEqualTo(4);
+        assertThat(mRecentAppStatsMixin.mRecentApps.get(0).mUsageStats.mPackageName).isEqualTo(
+                "personal.pkg.class");
+        assertThat(mRecentAppStatsMixin.mRecentApps.get(1).mUsageStats.mPackageName).isEqualTo(
+                "clone.pkg.class4");
+        assertThat(mRecentAppStatsMixin.mRecentApps.get(2).mUsageStats.mPackageName).isEqualTo(
+                "work.pkg.class3");
+        assertThat(mRecentAppStatsMixin.mRecentApps.get(3).mUsageStats.mPackageName).isEqualTo(
+                "personal.pkg.class2");
+    }
 }
diff --git a/tests/robotests/src/com/android/settings/bluetooth/AvailableMediaBluetoothDeviceUpdaterTest.java b/tests/robotests/src/com/android/settings/bluetooth/AvailableMediaBluetoothDeviceUpdaterTest.java
index 4427127..0b06f3e 100644
--- a/tests/robotests/src/com/android/settings/bluetooth/AvailableMediaBluetoothDeviceUpdaterTest.java
+++ b/tests/robotests/src/com/android/settings/bluetooth/AvailableMediaBluetoothDeviceUpdaterTest.java
@@ -205,12 +205,11 @@
     }
 
     @Test
-    public void onProfileConnectionStateChanged_hearingAidDeviceConnected_notInCall_addPreference()
-    {
+    public void onProfileConnectionStateChanged_ashaHearingAidConnected_notInCall_addPreference() {
         mAudioManager.setMode(AudioManager.MODE_NORMAL);
         when(mBluetoothDeviceUpdater.
                 isDeviceConnected(any(CachedBluetoothDevice.class))).thenReturn(true);
-        when(mCachedBluetoothDevice.isConnectedHearingAidDevice()).thenReturn(true);
+        when(mCachedBluetoothDevice.isConnectedAshaHearingAidDevice()).thenReturn(true);
 
         mBluetoothDeviceUpdater.onProfileConnectionStateChanged(mCachedBluetoothDevice,
                 BluetoothProfile.STATE_CONNECTED, BluetoothProfile.HEARING_AID);
@@ -219,11 +218,11 @@
     }
 
     @Test
-    public void onProfileConnectionStateChanged_hearingAidDeviceConnected_inCall_addPreference() {
+    public void onProfileConnectionStateChanged_ashaHearingAidConnected_inCall_addPreference() {
         mAudioManager.setMode(AudioManager.MODE_IN_CALL);
         when(mBluetoothDeviceUpdater.
                 isDeviceConnected(any(CachedBluetoothDevice.class))).thenReturn(true);
-        when(mCachedBluetoothDevice.isConnectedHearingAidDevice()).thenReturn(true);
+        when(mCachedBluetoothDevice.isConnectedAshaHearingAidDevice()).thenReturn(true);
 
         mBluetoothDeviceUpdater.onProfileConnectionStateChanged(mCachedBluetoothDevice,
                 BluetoothProfile.STATE_CONNECTED, BluetoothProfile.HEARING_AID);
diff --git a/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsPairOtherControllerTest.java b/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsPairOtherControllerTest.java
index ae47698..090fb0c 100644
--- a/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsPairOtherControllerTest.java
+++ b/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsPairOtherControllerTest.java
@@ -23,7 +23,7 @@
 import com.android.settings.R;
 import com.android.settings.applications.SpacePreference;
 import com.android.settingslib.bluetooth.CachedBluetoothDevice;
-import com.android.settingslib.bluetooth.HearingAidProfile;
+import com.android.settingslib.bluetooth.HearingAidInfo;
 import com.android.settingslib.widget.ButtonPreference;
 
 import org.junit.Rule;
@@ -62,7 +62,7 @@
 
     @Test
     public void init_leftSideDevice_rightSideButtonTitle() {
-        when(mCachedDevice.getDeviceSide()).thenReturn(HearingAidProfile.DeviceSide.SIDE_LEFT);
+        when(mCachedDevice.getDeviceSide()).thenReturn(HearingAidInfo.DeviceSide.SIDE_LEFT);
 
         mController.init(mScreen);
 
@@ -72,7 +72,7 @@
 
     @Test
     public void init_rightSideDevice_leftSideButtonTitle() {
-        when(mCachedDevice.getDeviceSide()).thenReturn(HearingAidProfile.DeviceSide.SIDE_RIGHT);
+        when(mCachedDevice.getDeviceSide()).thenReturn(HearingAidInfo.DeviceSide.SIDE_RIGHT);
 
         mController.init(mScreen);
 
@@ -81,8 +81,8 @@
     }
 
     @Test
-    public void init_isNotConnectedHearingAidDevice_notVisiblePreference() {
-        when(mCachedDevice.isConnectedHearingAidDevice()).thenReturn(false);
+    public void init_isNotConnectedAshaHearingAidDevice_notVisiblePreference() {
+        when(mCachedDevice.isConnectedAshaHearingAidDevice()).thenReturn(false);
 
         mController.init(mScreen);
 
@@ -91,35 +91,35 @@
     }
 
     @Test
-    public void isAvailable_isNotConnectedHearingAidDevice_notAvailable() {
-        when(mCachedDevice.isConnectedHearingAidDevice()).thenReturn(false);
+    public void isAvailable_isNotConnectedAshaHearingAidDevice_notAvailable() {
+        when(mCachedDevice.isConnectedAshaHearingAidDevice()).thenReturn(false);
 
         assertThat(mController.isAvailable()).isFalse();
     }
 
     @Test
-    public void isAvailable_notConnectedHearingAidDevice_notAvailable() {
-        when(mCachedDevice.isConnectedHearingAidDevice()).thenReturn(true);
-        when(mCachedDevice.getDeviceMode()).thenReturn(HearingAidProfile.DeviceMode.MODE_MONAURAL);
+    public void isAvailable_isConnectedAshaHearingAidDevice_isMonaural_notAvailable() {
+        when(mCachedDevice.isConnectedAshaHearingAidDevice()).thenReturn(true);
+        when(mCachedDevice.getDeviceMode()).thenReturn(HearingAidInfo.DeviceMode.MODE_MONAURAL);
 
         assertThat(mController.isAvailable()).isFalse();
     }
 
     @Test
-    public void isAvailable_subDeviceIsConnectedHearingAidDevice_notAvailable() {
-        when(mCachedDevice.isConnectedHearingAidDevice()).thenReturn(true);
-        when(mCachedDevice.getDeviceMode()).thenReturn(HearingAidProfile.DeviceMode.MODE_BINAURAL);
-        when(mSubCachedDevice.isConnectedHearingAidDevice()).thenReturn(true);
+    public void isAvailable_subDeviceIsConnectedAshaHearingAidDevice_notAvailable() {
+        when(mCachedDevice.isConnectedAshaHearingAidDevice()).thenReturn(true);
+        when(mCachedDevice.getDeviceMode()).thenReturn(HearingAidInfo.DeviceMode.MODE_BINAURAL);
+        when(mSubCachedDevice.isConnectedAshaHearingAidDevice()).thenReturn(true);
         when(mCachedDevice.getSubDevice()).thenReturn(mSubCachedDevice);
 
         assertThat(mController.isAvailable()).isFalse();
     }
 
     @Test
-    public void isAvailable_subDeviceNotConnectedHearingAidDevice_available() {
-        when(mCachedDevice.isConnectedHearingAidDevice()).thenReturn(true);
-        when(mCachedDevice.getDeviceMode()).thenReturn(HearingAidProfile.DeviceMode.MODE_BINAURAL);
-        when(mSubCachedDevice.isConnectedHearingAidDevice()).thenReturn(false);
+    public void isAvailable_subDeviceIsNotConnectedAshaHearingAidDevice_available() {
+        when(mCachedDevice.isConnectedAshaHearingAidDevice()).thenReturn(true);
+        when(mCachedDevice.getDeviceMode()).thenReturn(HearingAidInfo.DeviceMode.MODE_BINAURAL);
+        when(mSubCachedDevice.isConnectedAshaHearingAidDevice()).thenReturn(false);
         when(mCachedDevice.getSubDevice()).thenReturn(mSubCachedDevice);
 
         assertThat(mController.isAvailable()).isTrue();
@@ -127,8 +127,8 @@
 
     @Test
     public void isAvailable_subDeviceNotExist_available() {
-        when(mCachedDevice.isConnectedHearingAidDevice()).thenReturn(true);
-        when(mCachedDevice.getDeviceMode()).thenReturn(HearingAidProfile.DeviceMode.MODE_BINAURAL);
+        when(mCachedDevice.isConnectedAshaHearingAidDevice()).thenReturn(true);
+        when(mCachedDevice.getDeviceMode()).thenReturn(HearingAidInfo.DeviceMode.MODE_BINAURAL);
         when(mCachedDevice.getSubDevice()).thenReturn(null);
 
         assertThat(mController.isAvailable()).isTrue();
@@ -136,7 +136,7 @@
 
     @Test
     public void refresh_leftSideDevice_leftSideButtonTitle() {
-        when(mCachedDevice.getDeviceSide()).thenReturn(HearingAidProfile.DeviceSide.SIDE_RIGHT);
+        when(mCachedDevice.getDeviceSide()).thenReturn(HearingAidInfo.DeviceSide.SIDE_RIGHT);
         mController.init(mScreen);
 
         mController.refresh();
@@ -146,8 +146,8 @@
     }
 
     @Test
-    public void refresh_isNotConnectedHearingAidDevice_notVisiblePreference() {
-        when(mCachedDevice.isConnectedHearingAidDevice()).thenReturn(false);
+    public void refresh_isNotConnectedAshaHearingAidDevice_notVisiblePreference() {
+        when(mCachedDevice.isConnectedAshaHearingAidDevice()).thenReturn(false);
         mController.init(mScreen);
 
         mController.refresh();
diff --git a/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsRelatedToolsControllerTest.java b/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsRelatedToolsControllerTest.java
index 31d6397..b0a3433 100644
--- a/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsRelatedToolsControllerTest.java
+++ b/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsRelatedToolsControllerTest.java
@@ -89,7 +89,7 @@
     }
 
     @Test
-    public void isAvailable_notHearingAidDevice_notAvailable() {
+    public void isAvailable_isNotHearingAidDevice_notAvailable() {
         when(mCachedDevice.isHearingAidDevice()).thenReturn(false);
 
         assertThat(mController.isAvailable()).isFalse();
diff --git a/tests/robotests/src/com/android/settings/bluetooth/ConnectedBluetoothDeviceUpdaterTest.java b/tests/robotests/src/com/android/settings/bluetooth/ConnectedBluetoothDeviceUpdaterTest.java
index 7472dc1..1f90981 100644
--- a/tests/robotests/src/com/android/settings/bluetooth/ConnectedBluetoothDeviceUpdaterTest.java
+++ b/tests/robotests/src/com/android/settings/bluetooth/ConnectedBluetoothDeviceUpdaterTest.java
@@ -218,12 +218,12 @@
     }
 
     @Test
-    public void onProfileConnectionStateChanged_hearingAidDeviceConnected_inCall_removePreference()
+    public void onProfileConnectionStateChanged_ashaHearingAidConnected_inCall_removePreference()
     {
         mAudioManager.setMode(AudioManager.MODE_IN_CALL);
         when(mBluetoothDeviceUpdater.
                 isDeviceConnected(any(CachedBluetoothDevice.class))).thenReturn(true);
-        when(mCachedBluetoothDevice.isConnectedHearingAidDevice()).thenReturn(true);
+        when(mCachedBluetoothDevice.isConnectedAshaHearingAidDevice()).thenReturn(true);
 
         mBluetoothDeviceUpdater.onProfileConnectionStateChanged(mCachedBluetoothDevice,
                 BluetoothProfile.STATE_CONNECTED, BluetoothProfile.HEARING_AID);
@@ -232,12 +232,12 @@
     }
 
     @Test
-    public void onProfileConnectionStateChanged_hearingAidDeviceConnected_notInCall_removePreference
-            () {
+    public void onProfileConnectionStateChanged_ashaHearingAidConnected_notInCall_removePreference()
+    {
         mAudioManager.setMode(AudioManager.MODE_NORMAL);
         when(mBluetoothDeviceUpdater.
                 isDeviceConnected(any(CachedBluetoothDevice.class))).thenReturn(true);
-        when(mCachedBluetoothDevice.isConnectedHearingAidDevice()).thenReturn(true);
+        when(mCachedBluetoothDevice.isConnectedAshaHearingAidDevice()).thenReturn(true);
 
         mBluetoothDeviceUpdater.onProfileConnectionStateChanged(mCachedBluetoothDevice,
                 BluetoothProfile.STATE_CONNECTED, BluetoothProfile.HEARING_AID);
diff --git a/tests/robotests/src/com/android/settings/connecteddevice/AvailableMediaDeviceGroupControllerTest.java b/tests/robotests/src/com/android/settings/connecteddevice/AvailableMediaDeviceGroupControllerTest.java
index 2b62503..60265e9 100644
--- a/tests/robotests/src/com/android/settings/connecteddevice/AvailableMediaDeviceGroupControllerTest.java
+++ b/tests/robotests/src/com/android/settings/connecteddevice/AvailableMediaDeviceGroupControllerTest.java
@@ -52,7 +52,7 @@
 import com.android.settingslib.bluetooth.BluetoothEventManager;
 import com.android.settingslib.bluetooth.CachedBluetoothDevice;
 import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager;
-import com.android.settingslib.bluetooth.HearingAidProfile;
+import com.android.settingslib.bluetooth.HearingAidInfo;
 import com.android.settingslib.bluetooth.LocalBluetoothManager;
 
 import org.junit.Before;
@@ -244,11 +244,11 @@
     @Test
     @Config(shadows = ShadowAlertDialogCompat.class)
     public void onActiveDeviceChanged_hearingAidProfile_launchHearingAidPairingDialog() {
-        when(mCachedBluetoothDevice.isConnectedHearingAidDevice()).thenReturn(true);
+        when(mCachedBluetoothDevice.isConnectedAshaHearingAidDevice()).thenReturn(true);
         when(mCachedBluetoothDevice.getDeviceMode()).thenReturn(
-                HearingAidProfile.DeviceMode.MODE_BINAURAL);
+                HearingAidInfo.DeviceMode.MODE_BINAURAL);
         when(mCachedBluetoothDevice.getDeviceSide()).thenReturn(
-                HearingAidProfile.DeviceSide.SIDE_LEFT);
+                HearingAidInfo.DeviceSide.SIDE_LEFT);
         mAvailableMediaDeviceGroupController.init(mDashboardFragment);
 
         mAvailableMediaDeviceGroupController.onActiveDeviceChanged(mCachedBluetoothDevice,
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/BatteryBroadcastReceiverTest.java b/tests/robotests/src/com/android/settings/fuelgauge/BatteryBroadcastReceiverTest.java
index 867d8f4..79bd84b 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/BatteryBroadcastReceiverTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/BatteryBroadcastReceiverTest.java
@@ -55,6 +55,7 @@
     private BatteryBroadcastReceiver mBatteryBroadcastReceiver;
     private Context mContext;
     private Intent mChargingIntent;
+    private Intent mDockDefenderBypassIntent;
 
     @Before
     public void setUp() {
@@ -72,6 +73,8 @@
         mChargingIntent.putExtra(BatteryManager.EXTRA_SCALE, BATTERY_INTENT_SCALE);
         mChargingIntent
                 .putExtra(BatteryManager.EXTRA_STATUS, BatteryManager.BATTERY_STATUS_CHARGING);
+        mDockDefenderBypassIntent = new Intent(BatteryUtils.BYPASS_DOCK_DEFENDER_ACTION);
+
     }
 
     @Test
@@ -131,6 +134,13 @@
     }
 
     @Test
+    public void testOnReceive_dockDefenderBypassed_listenerInvoked() {
+        mBatteryBroadcastReceiver.onReceive(mContext, mDockDefenderBypassIntent);
+
+        verify(mBatteryListener).onBatteryChanged(BatteryUpdateType.BATTERY_STATUS);
+    }
+
+    @Test
     public void testRegister_updateBatteryStatus() {
         doReturn(mChargingIntent).when(mContext).registerReceiver(any(), any());
 
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/BatteryInfoTest.java b/tests/robotests/src/com/android/settings/fuelgauge/BatteryInfoTest.java
index 6bf6135..284dbe3 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/BatteryInfoTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/BatteryInfoTest.java
@@ -36,6 +36,7 @@
 import android.os.BatteryStats;
 import android.os.BatteryUsageStats;
 import android.os.SystemClock;
+import android.provider.Settings;
 import android.util.SparseIntArray;
 
 import com.android.internal.os.BatteryStatsHistoryIterator;
@@ -66,6 +67,7 @@
     private static final String STATUS_CHARGING_NO_TIME = "50% - charging";
     private static final String STATUS_CHARGING_TIME = "50% - 0 min left until full";
     private static final String STATUS_NOT_CHARGING = "Not charging";
+    private static final String STATUS_CHARGING_FUTURE_BYPASS = "50% - Charging to 12%";
     private static final long REMAINING_TIME_NULL = -1;
     private static final long REMAINING_TIME = 2;
     // Strings are defined in frameworks/base/packages/SettingsLib/res/values/strings.xml
@@ -97,6 +99,10 @@
         mDisChargingBatteryBroadcast = BatteryTestUtils.getDischargingIntent();
 
         mChargingBatteryBroadcast = BatteryTestUtils.getChargingIntent();
+
+        doReturn(false).when(mFeatureFactory.powerUsageFeatureProvider).isExtraDefend();
+        Settings.Global.putInt(mContext.getContentResolver(),
+                BatteryUtils.SETTINGS_GLOBAL_DOCK_DEFENDER_BYPASS, 0);
     }
 
     @Test
@@ -231,6 +237,7 @@
         BatteryInfo info = BatteryInfo.getBatteryInfo(mContext, mChargingBatteryBroadcast,
                 mBatteryUsageStats, MOCK_ESTIMATE, SystemClock.elapsedRealtime() * 1000,
                 false /* shortString */);
+
         assertThat(info.remainingTimeUs).isEqualTo(TEST_CHARGE_TIME_REMAINING);
         assertThat(info.remainingLabel.toString())
                 .isEqualTo(TEST_CHARGE_TIME_REMAINING_STRINGIFIED);
@@ -265,6 +272,62 @@
         assertThat(info.chargeLabel.toString()).contains(expectedString);
     }
 
+    @Test
+    public void testGetBatteryInfo_dockDefenderActive_updateChargeString() {
+        final String expectedString =
+                mContext.getString(R.string.battery_tip_limited_temporarily_title);
+        doReturn(TEST_CHARGE_TIME_REMAINING / 1000)
+                .when(mBatteryUsageStats).getChargeTimeRemainingMs();
+        doReturn(true).when(mFeatureFactory.powerUsageFeatureProvider).isExtraDefend();
+        Intent intent = BatteryTestUtils.getCustomBatteryIntent(BatteryManager.BATTERY_PLUGGED_DOCK,
+                        50 /* level */,
+                        100 /* scale */,
+                        BatteryManager.BATTERY_STATUS_CHARGING)
+                .putExtra(BatteryManager.EXTRA_HEALTH, BatteryManager.BATTERY_HEALTH_OVERHEAT);
+
+        BatteryInfo info = BatteryInfo.getBatteryInfo(mContext, intent,
+                mBatteryUsageStats, MOCK_ESTIMATE, SystemClock.elapsedRealtime() * 1000,
+                false /* shortString */);
+
+        assertThat(info.chargeLabel.toString()).contains(expectedString);
+    }
+
+    @Test
+    public void testGetBatteryInfo_dockDefenderTemporarilyBypassed_updateChargeLabel() {
+        doReturn(REMAINING_TIME).when(mBatteryUsageStats).getChargeTimeRemainingMs();
+        mChargingBatteryBroadcast
+                .putExtra(BatteryManager.EXTRA_HEALTH, BatteryManager.BATTERY_HEALTH_GOOD);
+        Settings.Global.putInt(mContext.getContentResolver(),
+                BatteryUtils.SETTINGS_GLOBAL_DOCK_DEFENDER_BYPASS, 1);
+
+        BatteryInfo info = BatteryInfo.getBatteryInfo(mContext,
+                BatteryTestUtils.getCustomBatteryIntent(BatteryManager.BATTERY_PLUGGED_DOCK,
+                        50 /* level */,
+                        100 /* scale */,
+                        BatteryManager.BATTERY_STATUS_CHARGING),
+                mBatteryUsageStats, MOCK_ESTIMATE, SystemClock.elapsedRealtime() * 1000,
+                false /* shortString */);
+
+        assertThat(info.chargeLabel.toString()).contains(STATUS_CHARGING_TIME);
+    }
+
+    @Test
+    public void testGetBatteryInfo_dockDefenderFutureBypass_updateChargeLabel() {
+        doReturn(false).when(mFeatureFactory.powerUsageFeatureProvider).isExtraDefend();
+        mChargingBatteryBroadcast
+                .putExtra(BatteryManager.EXTRA_HEALTH, BatteryManager.BATTERY_HEALTH_GOOD);
+
+        BatteryInfo info = BatteryInfo.getBatteryInfo(mContext,
+                BatteryTestUtils.getCustomBatteryIntent(BatteryManager.BATTERY_PLUGGED_DOCK,
+                        50 /* level */,
+                        100 /* scale */,
+                        BatteryManager.BATTERY_STATUS_CHARGING),
+                mBatteryUsageStats, MOCK_ESTIMATE, SystemClock.elapsedRealtime() * 1000,
+                false /* shortString */);
+
+        assertThat(info.chargeLabel.toString()).contains(STATUS_CHARGING_FUTURE_BYPASS);
+    }
+
     // Make our battery stats return a sequence of battery events.
     private void mockBatteryStatsHistory() {
         // Mock out new data every time iterateBatteryStatsHistory is called.
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImplTest.java b/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImplTest.java
index 66a5e7f..648685a 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImplTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImplTest.java
@@ -132,7 +132,12 @@
     }
 
     @Test
-    public void testGetResumeChargeIntent_returnNull() {
-        assertThat(mPowerFeatureProvider.getResumeChargeIntent()).isNull();
+    public void testGetResumeChargeIntentWithoutDockDefender_returnNull() {
+        assertThat(mPowerFeatureProvider.getResumeChargeIntent(false)).isNull();
+    }
+
+    @Test
+    public void testGetResumeChargeIntentWithDockDefender_returnNull() {
+        assertThat(mPowerFeatureProvider.getResumeChargeIntent(true)).isNull();
     }
 }
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/BatteryTipLoaderTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/BatteryTipLoaderTest.java
index 95280b6..6d3965e 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/BatteryTipLoaderTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/BatteryTipLoaderTest.java
@@ -53,6 +53,7 @@
             BatteryTip.TipType.BATTERY_SAVER,
             BatteryTip.TipType.LOW_BATTERY,
             BatteryTip.TipType.BATTERY_DEFENDER,
+            BatteryTip.TipType.DOCK_DEFENDER,
             BatteryTip.TipType.HIGH_DEVICE_USAGE,
             BatteryTip.TipType.SMART_BATTERY_MANAGER};
     @Mock(answer = Answers.RETURNS_DEEP_STUBS)
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/detectors/BatteryDefenderDetectorTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/detectors/BatteryDefenderDetectorTest.java
index 90e7ad7..f81a4be 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/detectors/BatteryDefenderDetectorTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/detectors/BatteryDefenderDetectorTest.java
@@ -18,10 +18,15 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+
 import androidx.test.core.app.ApplicationProvider;
 
 import com.android.settings.fuelgauge.BatteryInfo;
 import com.android.settings.fuelgauge.batterytip.tips.BatteryTip;
+import com.android.settings.testutils.FakeFeatureFactory;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -36,6 +41,9 @@
     @Mock
     private BatteryInfo mBatteryInfo;
     private BatteryDefenderDetector mBatteryDefenderDetector;
+    private Context mContext;
+
+    private FakeFeatureFactory mFakeFeatureFactory;
 
     @Before
     public void setUp() {
@@ -43,20 +51,42 @@
 
         mBatteryInfo.discharging = false;
 
+        mContext = ApplicationProvider.getApplicationContext();
+
         mBatteryDefenderDetector = new BatteryDefenderDetector(
-            mBatteryInfo, ApplicationProvider.getApplicationContext());
+            mBatteryInfo, mContext);
+
+        mFakeFeatureFactory = FakeFeatureFactory.setupForTest();
     }
 
     @Test
-    public void testDetect_notOverheated_tipInvisible() {
+    public void testDetect_notOverheatedNotExtraDefend_tipInvisible() {
         mBatteryInfo.isOverheated = false;
+        when(mFakeFeatureFactory.powerUsageFeatureProvider.isExtraDefend()).thenReturn(false);
 
         assertThat(mBatteryDefenderDetector.detect().isVisible()).isFalse();
     }
 
     @Test
-    public void testDetect_isOverheated_tipNew() {
+    public void testDetect_notOverheatedIsExtraDefend_tipInvisible() {
+        mBatteryInfo.isOverheated = false;
+        when(mFakeFeatureFactory.powerUsageFeatureProvider.isExtraDefend()).thenReturn(true);
+
+        assertThat(mBatteryDefenderDetector.detect().isVisible()).isFalse();
+    }
+
+    @Test
+    public void testDetect_isOverheatedIsExtraDefend_tipInvisible() {
+        mBatteryInfo.isOverheated = false;
+        when(mFakeFeatureFactory.powerUsageFeatureProvider.isExtraDefend()).thenReturn(true);
+
+        assertThat(mBatteryDefenderDetector.detect().isVisible()).isFalse();
+    }
+
+    @Test
+    public void testDetect_isOverheatedNotExtraDefend_tipNew() {
         mBatteryInfo.isOverheated = true;
+        when(mFakeFeatureFactory.powerUsageFeatureProvider.isExtraDefend()).thenReturn(false);
 
         assertThat(mBatteryDefenderDetector.detect().getState())
                 .isEqualTo(BatteryTip.StateType.NEW);
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/detectors/DockDefenderDetectorTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/detectors/DockDefenderDetectorTest.java
new file mode 100644
index 0000000..9652a00
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/detectors/DockDefenderDetectorTest.java
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.fuelgauge.batterytip.detectors;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.refEq;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.spy;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.BatteryManager;
+import android.provider.Settings;
+
+import androidx.test.core.app.ApplicationProvider;
+
+import com.android.settings.fuelgauge.BatteryInfo;
+import com.android.settings.fuelgauge.BatteryUtils;
+import com.android.settings.fuelgauge.batterytip.tips.BatteryTip;
+import com.android.settings.fuelgauge.batterytip.tips.DockDefenderTip;
+import com.android.settings.testutils.BatteryTestUtils;
+import com.android.settings.testutils.FakeFeatureFactory;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
+
+@RunWith(RobolectricTestRunner.class)
+public class DockDefenderDetectorTest {
+
+    private BatteryInfo mBatteryInfo;
+    private DockDefenderDetector mDockDefenderDetector;
+    private Context mContext;
+    private FakeFeatureFactory mFakeFeatureFactory;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        mContext = spy(ApplicationProvider.getApplicationContext());
+        mBatteryInfo = new BatteryInfo();
+        mBatteryInfo.pluggedStatus = BatteryManager.BATTERY_PLUGGED_DOCK;
+        mDockDefenderDetector = new DockDefenderDetector(mBatteryInfo, mContext);
+        Intent intent = BatteryTestUtils.getCustomBatteryIntent(BatteryManager.BATTERY_PLUGGED_DOCK,
+                50 /* level */, 100 /* scale */, BatteryManager.BATTERY_STATUS_CHARGING);
+        doReturn(intent).when(mContext).registerReceiver(eq(null),
+                refEq(new IntentFilter(Intent.ACTION_BATTERY_CHANGED)));
+
+        Settings.Global.putInt(mContext.getContentResolver(),
+                BatteryUtils.SETTINGS_GLOBAL_DOCK_DEFENDER_BYPASS, 0);
+        mFakeFeatureFactory = FakeFeatureFactory.setupForTest();
+    }
+
+    @Test
+    public void testDetect_dockDefenderTemporarilyBypassed() {
+        Settings.Global.putInt(mContext.getContentResolver(),
+                BatteryUtils.SETTINGS_GLOBAL_DOCK_DEFENDER_BYPASS, 1);
+
+        BatteryTip batteryTip = mDockDefenderDetector.detect();
+
+        assertTrue(batteryTip instanceof DockDefenderTip);
+        assertEquals(((DockDefenderTip) batteryTip).getMode(),
+                BatteryUtils.DockDefenderMode.TEMPORARILY_BYPASSED);
+    }
+
+    @Test
+    public void testDetect_dockDefenderActive() {
+        mBatteryInfo.isOverheated = true;
+        doReturn(true).when(mFakeFeatureFactory.powerUsageFeatureProvider).isExtraDefend();
+
+        BatteryTip batteryTip = mDockDefenderDetector.detect();
+
+        assertTrue(batteryTip instanceof DockDefenderTip);
+        assertEquals(((DockDefenderTip) batteryTip).getMode(),
+                BatteryUtils.DockDefenderMode.ACTIVE);
+    }
+
+    @Test
+    public void testDetect_dockDefenderFutureBypass() {
+        mBatteryInfo.isOverheated = false;
+        doReturn(false).when(mFakeFeatureFactory.powerUsageFeatureProvider).isExtraDefend();
+
+        BatteryTip batteryTip = mDockDefenderDetector.detect();
+
+        assertTrue(batteryTip instanceof DockDefenderTip);
+        assertEquals(((DockDefenderTip) batteryTip).getMode(),
+                BatteryUtils.DockDefenderMode.FUTURE_BYPASS);
+    }
+
+    @Test
+    public void testDetect_overheatedTrue_dockDefenderDisabled() {
+        mBatteryInfo.isOverheated = true;
+        doReturn(false).when(mFakeFeatureFactory.powerUsageFeatureProvider).isExtraDefend();
+
+        BatteryTip batteryTip = mDockDefenderDetector.detect();
+
+        assertTrue(batteryTip instanceof DockDefenderTip);
+        assertEquals(((DockDefenderTip) batteryTip).getMode(),
+                BatteryUtils.DockDefenderMode.DISABLED);
+    }
+
+    @Test
+    public void testDetect_pluggedInAC_dockDefenderDisabled() {
+        mBatteryInfo.pluggedStatus = BatteryManager.BATTERY_PLUGGED_AC;
+
+        BatteryTip batteryTip = mDockDefenderDetector.detect();
+
+        assertTrue(batteryTip instanceof DockDefenderTip);
+        assertEquals(((DockDefenderTip) batteryTip).getMode(),
+                BatteryUtils.DockDefenderMode.DISABLED);
+    }
+
+    @Test
+    public void testDetect_overheatedTrueAndDockDefenderNotTriggered_dockDefenderDisabled() {
+        doReturn(false).when(mFakeFeatureFactory.powerUsageFeatureProvider).isExtraDefend();
+        mBatteryInfo.isOverheated = true;
+
+        BatteryTip batteryTip = mDockDefenderDetector.detect();
+
+        assertTrue(batteryTip instanceof DockDefenderTip);
+        assertEquals(((DockDefenderTip) batteryTip).getMode(),
+                BatteryUtils.DockDefenderMode.DISABLED);
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/tips/BatteryDefenderTipTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/tips/BatteryDefenderTipTest.java
index 6bd6b26..8b6033a 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/tips/BatteryDefenderTipTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/tips/BatteryDefenderTipTest.java
@@ -79,20 +79,12 @@
     }
 
     @Test
-    public void getSummary_notExtraDefended_showNonExtraDefendedSummary() {
+    public void getSummary_showSummary() {
         assertThat(mBatteryDefenderTip.getSummary(mContext))
                 .isEqualTo(mContext.getString(R.string.battery_tip_limited_temporarily_summary));
     }
 
     @Test
-    public void getSummary_extraDefended_showExtraDefendedSummary() {
-        BatteryDefenderTip defenderTip = new BatteryDefenderTip(
-                BatteryTip.StateType.NEW, /* extraDefended= */ true);
-
-        assertThat(defenderTip.getSummary(mContext).toString()).isEqualTo("12%");
-    }
-
-    @Test
     public void getIcon_showIcon() {
         assertThat(mBatteryDefenderTip.getIconId())
                 .isEqualTo(R.drawable.ic_battery_status_good_24dp);
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/tips/DockDefenderTipTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/tips/DockDefenderTipTest.java
new file mode 100644
index 0000000..d917d89
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/tips/DockDefenderTipTest.java
@@ -0,0 +1,195 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.fuelgauge.batterytip.tips;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+
+import android.app.settings.SettingsEnums;
+import android.content.Context;
+import android.util.Log;
+
+import androidx.preference.Preference;
+import androidx.test.core.app.ApplicationProvider;
+
+import com.android.settings.R;
+import com.android.settings.fuelgauge.BatteryUtils;
+import com.android.settings.testutils.FakeFeatureFactory;
+import com.android.settings.widget.CardPreference;
+import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
+
+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.shadows.ShadowLog;
+
+import java.text.NumberFormat;
+
+@RunWith(RobolectricTestRunner.class)
+public class DockDefenderTipTest {
+    private Context mContext;
+    private DockDefenderTip mDockDefenderTipFutureBypass;
+    private DockDefenderTip mDockDefenderTipActive;
+    private DockDefenderTip mDockDefenderTipTemporarilyBypassed;
+    private DockDefenderTip mDockDefenderTipDisabled;
+    private FakeFeatureFactory mFeatureFactory;
+    private MetricsFeatureProvider mMetricsFeatureProvider;
+
+    @Mock
+    private Preference mPreference;
+    @Mock
+    private CardPreference mCardPreference;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+
+        mContext = ApplicationProvider.getApplicationContext();
+        mFeatureFactory = FakeFeatureFactory.setupForTest();
+        mMetricsFeatureProvider = mFeatureFactory.metricsFeatureProvider;
+
+        mDockDefenderTipFutureBypass = new DockDefenderTip(BatteryTip.StateType.NEW,
+                BatteryUtils.DockDefenderMode.FUTURE_BYPASS);
+        mDockDefenderTipActive = new DockDefenderTip(BatteryTip.StateType.NEW,
+                BatteryUtils.DockDefenderMode.ACTIVE);
+        mDockDefenderTipTemporarilyBypassed = new DockDefenderTip(BatteryTip.StateType.NEW,
+                BatteryUtils.DockDefenderMode.TEMPORARILY_BYPASSED);
+        mDockDefenderTipDisabled = new DockDefenderTip(BatteryTip.StateType.INVISIBLE,
+                BatteryUtils.DockDefenderMode.DISABLED);
+
+        doReturn(mContext).when(mPreference).getContext();
+        doReturn(mContext).when(mCardPreference).getContext();
+    }
+
+    @Test
+    public void testGetTitle() {
+        assertThat(mDockDefenderTipFutureBypass.getTitle(mContext).toString()).isEqualTo(
+                mContext.getString(R.string.battery_tip_dock_defender_future_bypass_title,
+                        getExtraPercentage(mContext)));
+        assertThat(mDockDefenderTipActive.getTitle(mContext).toString()).isEqualTo(
+                mContext.getString(R.string.battery_tip_dock_defender_active_title));
+        assertThat(mDockDefenderTipTemporarilyBypassed.getTitle(mContext).toString()).isEqualTo(
+                mContext.getString(R.string.battery_tip_dock_defender_temporarily_bypassed_title));
+        assertThat(mDockDefenderTipDisabled.getTitle(mContext)).isNull();
+    }
+
+    @Test
+    public void testGetSummary() {
+        assertThat(mDockDefenderTipFutureBypass.getSummary(mContext).toString()).isEqualTo(
+                mContext.getString(R.string.battery_tip_dock_defender_future_bypass_summary,
+                        getExtraPercentage(mContext)));
+        assertThat(mDockDefenderTipActive.getSummary(mContext).toString()).isEqualTo(
+                mContext.getString(R.string.battery_tip_dock_defender_active_summary,
+                        getExtraPercentage(mContext)));
+        assertThat(mDockDefenderTipTemporarilyBypassed.getSummary(mContext).toString()).isEqualTo(
+                mContext.getString(R.string.battery_tip_dock_defender_temporarily_bypassed_summary,
+                        getExtraPercentage(mContext)));
+        assertThat(mDockDefenderTipDisabled.getSummary(mContext)).isNull();
+    }
+
+    @Test
+    public void testGetIconId() {
+        assertThat(mDockDefenderTipFutureBypass.getIconId()).isEqualTo(
+                R.drawable.ic_battery_status_protected_24dp);
+    }
+
+    @Test
+    public void testUpdateState() {
+        mDockDefenderTipTemporarilyBypassed.updateState(mDockDefenderTipDisabled);
+
+        assertThat(mDockDefenderTipTemporarilyBypassed.getState()).isEqualTo(
+                BatteryTip.StateType.INVISIBLE);
+        assertThat(mDockDefenderTipTemporarilyBypassed.getMode()).isEqualTo(
+                BatteryUtils.DockDefenderMode.DISABLED);
+    }
+
+    @Test
+    public void testLog() {
+        mDockDefenderTipActive.log(mContext, mMetricsFeatureProvider);
+
+        verify(mMetricsFeatureProvider).action(mContext, SettingsEnums.ACTION_DOCK_DEFENDER_TIP,
+                mDockDefenderTipActive.getState());
+    }
+
+
+    @Test
+    public void testUpdatePreference_dockDefenderTipFutureBypass() {
+        mDockDefenderTipFutureBypass.updatePreference(mCardPreference);
+
+        verify(mCardPreference).setPrimaryButtonVisible(true);
+        verify(mCardPreference).setPrimaryButtonText(
+                mContext.getString(R.string.battery_tip_charge_to_full_button));
+        verifySecondaryButton();
+    }
+
+    @Test
+    public void testUpdatePreference_dockDefenderTipActive() {
+        mDockDefenderTipActive.updatePreference(mCardPreference);
+
+        verify(mCardPreference).setPrimaryButtonVisible(true);
+        verify(mCardPreference).setPrimaryButtonText(
+                mContext.getString(R.string.battery_tip_charge_to_full_button));
+        verifySecondaryButton();
+    }
+
+    @Test
+    public void testUpdatePreference_dockDefenderTipTemporarilyBypassed() {
+        mDockDefenderTipTemporarilyBypassed.updatePreference(mCardPreference);
+
+        verify(mCardPreference).setPrimaryButtonVisible(false);
+        verify(mCardPreference, never()).setPrimaryButtonText(any());
+        verifySecondaryButton();
+    }
+
+    private void verifySecondaryButton() {
+        verify(mCardPreference).setSecondaryButtonText(mContext.getString(R.string.learn_more));
+        verify(mCardPreference).setSecondaryButtonVisible(true);
+        verify(mCardPreference).setSecondaryButtonContentDescription(mContext.getString(
+                R.string.battery_tip_limited_temporarily_sec_button_content_description));
+    }
+
+    @Test
+    public void updatePreference_castFail_logErrorMessage() {
+        mDockDefenderTipActive.updatePreference(mPreference);
+
+        assertThat(getLastErrorLog()).isEqualTo("cast Preference to CardPreference failed");
+    }
+
+    private String getLastErrorLog() {
+        return ShadowLog.getLogsForTag(DockDefenderTip.class.getSimpleName()).stream().filter(
+                log -> log.type == Log.ERROR).reduce((first, second) -> second).orElse(
+                createErrorLog("No Error Log")).msg;
+    }
+
+    private ShadowLog.LogItem createErrorLog(String msg) {
+        return new ShadowLog.LogItem(Log.ERROR, "tag", msg, null);
+    }
+
+    private String getExtraPercentage(Context context) {
+        final int extraValue = context.getResources().getInteger(
+                R.integer.config_battery_extra_tip_value);
+        return NumberFormat.getPercentInstance().format(extraValue * 0.01f);
+    }
+
+}
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryChartPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryChartPreferenceControllerTest.java
index fad5c2c..5c84997 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryChartPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryChartPreferenceControllerTest.java
@@ -127,8 +127,13 @@
         mBatteryDiffEntry = new BatteryDiffEntry(
                 mContext,
                 /*foregroundUsageTimeInMs=*/ 1,
+                /*foregroundServiceUsageTimeInMs=*/ 3,
                 /*backgroundUsageTimeInMs=*/ 2,
                 /*consumePower=*/ 3,
+                /*foregroundUsageConsumePower=*/ 0,
+                /*foregroundServiceUsageConsumePower=*/ 1,
+                /*backgroundUsageConsumePower=*/ 2,
+                /*cachedUsageConsumePower=*/ 0,
                 mBatteryHistEntry);
         mBatteryDiffEntry = spy(mBatteryDiffEntry);
         // Adds fake testing data.
@@ -458,6 +463,7 @@
         mBatteryChartPreferenceController.setPreferenceSummary(
                 pref, createBatteryDiffEntry(
                         /*foregroundUsageTimeInMs=*/ 0,
+                        /*foregroundServiceUsageTimeInMs=*/ 0,
                         /*backgroundUsageTimeInMs=*/ 0));
         assertThat(pref.getSummary()).isNull();
     }
@@ -470,6 +476,7 @@
         mBatteryChartPreferenceController.setPreferenceSummary(
                 pref, createBatteryDiffEntry(
                         /*foregroundUsageTimeInMs=*/ 0,
+                        /*foregroundServiceUsageTimeInMs=*/ 0,
                         /*backgroundUsageTimeInMs=*/ DateUtils.MINUTE_IN_MILLIS));
         assertThat(pref.getSummary()).isEqualTo("Background: 1 min");
     }
@@ -482,6 +489,7 @@
         mBatteryChartPreferenceController.setPreferenceSummary(
                 pref, createBatteryDiffEntry(
                         /*foregroundUsageTimeInMs=*/ 100,
+                        /*foregroundServiceUsageTimeInMs=*/ 200,
                         /*backgroundUsageTimeInMs=*/ 200));
         assertThat(pref.getSummary()).isEqualTo("Total: less than a min");
     }
@@ -494,6 +502,7 @@
         mBatteryChartPreferenceController.setPreferenceSummary(
                 pref, createBatteryDiffEntry(
                         /*foregroundUsageTimeInMs=*/ DateUtils.MINUTE_IN_MILLIS,
+                        /*foregroundServiceUsageTimeInMs=*/ 100,
                         /*backgroundUsageTimeInMs=*/ 200));
         assertThat(pref.getSummary())
                 .isEqualTo("Total: 1 min\nBackground: less than a min");
@@ -507,6 +516,7 @@
         mBatteryChartPreferenceController.setPreferenceSummary(
                 pref, createBatteryDiffEntry(
                         /*foregroundUsageTimeInMs=*/ DateUtils.MINUTE_IN_MILLIS,
+                        /*foregroundServiceUsageTimeInMs=*/ DateUtils.MINUTE_IN_MILLIS,
                         /*backgroundUsageTimeInMs=*/ DateUtils.MINUTE_IN_MILLIS));
         assertThat(pref.getSummary()).isEqualTo("Total: 2 min\nBackground: 1 min");
     }
@@ -717,10 +727,13 @@
     }
 
     private BatteryDiffEntry createBatteryDiffEntry(
-            long foregroundUsageTimeInMs, long backgroundUsageTimeInMs) {
+            long foregroundUsageTimeInMs, long foregroundServiceUsageTimeInMs,
+            long backgroundUsageTimeInMs) {
         return new BatteryDiffEntry(
-                mContext, foregroundUsageTimeInMs, backgroundUsageTimeInMs,
-                /*consumePower=*/ 0, mBatteryHistEntry);
+                mContext, foregroundUsageTimeInMs, foregroundServiceUsageTimeInMs,
+                backgroundUsageTimeInMs, /*consumePower=*/ 0, /*foregroundUsageConsumePower=*/ 0,
+                /*foregroundServiceUsageConsumePower=*/ 0, /*backgroundUsageConsumePower=*/ 0,
+                /*cachedUsageConsumePower=*/ 0, mBatteryHistEntry);
     }
 
     private BatteryChartPreferenceController createController() {
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryDiffEntryTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryDiffEntryTest.java
index 79c5a1c..0090436 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryDiffEntryTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryDiffEntryTest.java
@@ -96,8 +96,13 @@
                 new BatteryDiffEntry(
                         mContext,
                         /*foregroundUsageTimeInMs=*/ 10001L,
+                        /*foregroundServiceUsageTimeInMs=*/ 10002L,
                         /*backgroundUsageTimeInMs=*/ 20002L,
                         /*consumePower=*/ 22.0,
+                        /*foregroundUsageConsumePower=*/ 10.0,
+                        /*foregroundServiceUsageConsumePower=*/ 10.0,
+                        /*backgroundUsageConsumePower=*/ 1.0,
+                        /*cachedUsageConsumePower=*/ 1.0,
                         /*batteryHistEntry=*/ null);
         entry.setTotalConsumePower(100.0);
 
@@ -110,8 +115,13 @@
                 new BatteryDiffEntry(
                         mContext,
                         /*foregroundUsageTimeInMs=*/ 10001L,
+                        /*foregroundServiceUsageTimeInMs=*/ 10002L,
                         /*backgroundUsageTimeInMs=*/ 20002L,
                         /*consumePower=*/ 22.0,
+                        /*foregroundUsageConsumePower=*/ 10.0,
+                        /*foregroundServiceUsageConsumePower=*/ 10.0,
+                        /*backgroundUsageConsumePower=*/ 1.0,
+                        /*cachedUsageConsumePower=*/ 1.0,
                         /*batteryHistEntry=*/ null);
         entry.setTotalConsumePower(0);
 
@@ -483,8 +493,13 @@
         return new BatteryDiffEntry(
                 mContext,
                 /*foregroundUsageTimeInMs=*/ 0,
+                /*foregroundServiceUsageTimeInMs=*/ 0,
                 /*backgroundUsageTimeInMs=*/ 0,
                 /*consumePower=*/ 0,
+                /*foregroundUsageConsumePower=*/ 0,
+                /*foregroundServiceUsageConsumePower=*/ 0,
+                /*backgroundUsageConsumePower=*/ 0,
+                /*cachedUsageConsumePower=*/ 0,
                 new BatteryHistEntry(values));
     }
 
@@ -493,8 +508,13 @@
         final BatteryDiffEntry entry = new BatteryDiffEntry(
                 mContext,
                 /*foregroundUsageTimeInMs=*/ 0,
+                /*foregroundServiceUsageTimeInMs=*/ 0,
                 /*backgroundUsageTimeInMs=*/ 0,
                 consumePower,
+                /*foregroundUsageConsumePower=*/ 0,
+                /*foregroundServiceUsageConsumePower=*/ 0,
+                /*backgroundUsageConsumePower=*/ 0,
+                /*cachedUsageConsumePower=*/ 0,
                 batteryHistEntry);
         entry.setTotalConsumePower(100.0);
         return entry;
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryHistEntryTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryHistEntryTest.java
index d7a5503..848265a 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryHistEntryTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryHistEntryTest.java
@@ -57,8 +57,13 @@
         when(mMockBatteryEntry.isHidden()).thenReturn(true);
         when(mBatteryUsageStats.getConsumedPower()).thenReturn(5.1);
         when(mMockBatteryEntry.getConsumedPower()).thenReturn(1.1);
+        when(mMockBatteryEntry.getConsumedPowerInForeground()).thenReturn(1.2);
+        when(mMockBatteryEntry.getConsumedPowerInForegroundService()).thenReturn(1.3);
+        when(mMockBatteryEntry.getConsumedPowerInBackground()).thenReturn(1.4);
+        when(mMockBatteryEntry.getConsumedPowerInCached()).thenReturn(1.5);
         mMockBatteryEntry.mPercent = 0.3;
         when(mMockBatteryEntry.getTimeInForegroundMs()).thenReturn(1234L);
+        when(mMockBatteryEntry.getTimeInForegroundServiceMs()).thenReturn(3456L);
         when(mMockBatteryEntry.getTimeInBackgroundMs()).thenReturn(5689L);
         when(mMockBatteryEntry.getPowerComponentId()).thenReturn(expectedType);
         when(mMockBatteryEntry.getConsumerType())
@@ -71,7 +76,8 @@
                         /*batteryStatus=*/ BatteryManager.BATTERY_STATUS_FULL,
                         /*batteryHealth=*/ BatteryManager.BATTERY_HEALTH_COLD,
                         /*bootTimestamp=*/ 101L,
-                        /*timestamp=*/ 10001L);
+                        /*timestamp=*/ 10001L,
+                        /*isFullChargeStart=*/ false);
 
         assertBatteryHistEntry(
                 new BatteryHistEntry(values),
@@ -93,7 +99,12 @@
                         /*timestamp=*/ 10001L,
                         /*totalPower=*/ 5.1,
                         /*consumePower=*/ 1.1,
+                        /*foregroundUsageConsumePower=*/ 1.2,
+                        /*foregroundServiceUsageConsumePower=*/ 1.3,
+                        /*backgroundUsageConsumePower=*/ 1.4,
+                        /*cachedUsageConsumePower=*/ 1.5,
                         /*foregroundUsageTimeInMs=*/ 1234L,
+                        /*foregroundServiceUsageTimeInMs=*/ 3456L,
                         /*backgroundUsageTimeInMs=*/ 5689L,
                         /*batteryLevel=*/ 12),
                 /*drainType=*/ 3,
@@ -177,7 +188,12 @@
                 lowerTimestamp,
                 /*totalPower=*/ 50,
                 /*consumePower=*/ 10,
+                /*foregroundUsageConsumePower=*/ 1,
+                /*foregroundServiceUsageConsumePower=*/ 2,
+                /*backgroundUsageConsumePower=*/ 3,
+                /*cachedUsageConsumePower=*/ 4,
                 /*foregroundUsageTimeInMs=*/ 100,
+                /*foregroundServiceUsageTimeInMs=*/ 150,
                 /*backgroundUsageTimeInMs=*/ 200,
                 /*batteryLevel=*/ 90);
         final BatteryHistEntry upperHistEntry = createBatteryHistEntry(
@@ -185,7 +201,12 @@
                 upperTimestamp,
                 /*totalPower=*/ 80,
                 /*consumePower=*/ 20,
+                /*foregroundUsageConsumePower=*/ 4,
+                /*foregroundServiceUsageConsumePower=*/ 5,
+                /*backgroundUsageConsumePower=*/ 6,
+                /*cachedUsageConsumePower=*/ 5,
                 /*foregroundUsageTimeInMs=*/ 200,
+                /*foregroundServiceUsageTimeInMs=*/ 250,
                 /*backgroundUsageTimeInMs=*/ 300,
                 /*batteryLevel=*/ 80);
 
@@ -203,7 +224,12 @@
                 /*timestamp=*/ slotTimestamp,
                 /*totalPower=*/ 50 + 0.5 * (80 - 50),
                 /*consumePower=*/ 10 + 0.5 * (20 - 10),
+                /*foregroundUsageConsumePower=*/ 1 + 0.5 * (4 - 1),
+                /*foregroundServiceUsageConsumePower=*/ 2 + 0.5 * (5 - 2),
+                /*backgroundUsageConsumePower=*/ 3 + 0.5 * (6 - 3),
+                /*cachedUsageConsumePower=*/ 4 + 0.5 * (5 - 4),
                 /*foregroundUsageTimeInMs=*/ Math.round(100 + 0.5 * (200 - 100)),
+                /*foregroundServiceUsageTimeInMs=*/ Math.round(150 + 0.5 * (250 - 150)),
                 /*backgroundUsageTimeInMs=*/ Math.round(200 + 0.5 * (300 - 200)),
                 /*batteryLevel=*/ (int) Math.round(90 + 0.5 * (80 - 90)));
     }
@@ -212,14 +238,18 @@
     public void testInterpolate_withoutLowerEntryData_returnExpectedResult() {
         final long slotTimestamp = 200L;
         final long upperTimestamp = 300L;
-        final long lowerTimestamp = 100L;
         final double ratio = 0.5;
         final BatteryHistEntry upperHistEntry = createBatteryHistEntry(
                 /*bootTimestamp=*/ 1200L,
                 upperTimestamp,
                 /*totalPower=*/ 80,
                 /*consumePower=*/ 20,
+                /*foregroundUsageConsumePower=*/ 4,
+                /*foregroundServiceUsageConsumePower=*/ 5,
+                /*backgroundUsageConsumePower=*/ 6,
+                /*cachedUsageConsumePower=*/ 5,
                 /*foregroundUsageTimeInMs=*/ 200,
+                /*foregroundServiceUsageTimeInMs=*/ 250,
                 /*backgroundUsageTimeInMs=*/ 300,
                 /*batteryLevel=*/ 80);
 
@@ -237,7 +267,12 @@
                 /*timestamp=*/ slotTimestamp,
                 /*totalPower=*/ 0.5 * 80,
                 /*consumePower=*/ 0.5 * 20,
+                /*foregroundUsageConsumePower=*/ 0.5 * 4,
+                /*foregroundServiceUsageConsumePower=*/ 0.5 * 5,
+                /*backgroundUsageConsumePower=*/ 0.5 * 6,
+                /*cachedUsageConsumePower=*/ 0.5 * 5,
                 /*foregroundUsageTimeInMs=*/ Math.round(0.5 * 200),
+                /*foregroundServiceUsageTimeInMs=*/ Math.round(0.5 * 250),
                 /*backgroundUsageTimeInMs=*/ Math.round(0.5 * 300),
                 /*batteryLevel=*/ upperHistEntry.mBatteryLevel);
     }
@@ -261,7 +296,12 @@
                 /*timestamp=*/ 10001L,
                 /*totalPower=*/ 5.1,
                 /*consumePower=*/ 1.1,
+                /*foregroundUsageConsumePower=*/ 1.2,
+                /*foregroundServiceUsageConsumePower=*/ 1.3,
+                /*backgroundUsageConsumePower=*/ 1.4,
+                /*cachedUsageConsumePower=*/ 1.5,
                 /*foregroundUsageTimeInMs=*/ 1234L,
+                /*foregroundServiceUsageTimeInMs=*/ 3456L,
                 /*backgroundUsageTimeInMs=*/ 5689L,
                 /*batteryLevel=*/ 12);
     }
@@ -274,7 +314,12 @@
             long timestamp,
             double totalPower,
             double consumePower,
+            double foregroundUsageConsumePower,
+            double foregroundServiceUsageConsumePower,
+            double backgroundUsageConsumePower,
+            double cachedUsageConsumePower,
             long foregroundUsageTimeInMs,
+            long foregroundServiceUsageTimeInMs,
             long backgroundUsageTimeInMs,
             int batteryLevel) {
         assertThat(entry.isValidEntry()).isTrue();
@@ -289,8 +334,15 @@
         assertThat(entry.mZoneId).isEqualTo(TimeZone.getDefault().getID());
         assertThat(entry.mTotalPower).isEqualTo(totalPower);
         assertThat(entry.mConsumePower).isEqualTo(consumePower);
+        assertThat(entry.mForegroundUsageConsumePower).isEqualTo(foregroundUsageConsumePower);
+        assertThat(entry.mForegroundServiceUsageConsumePower)
+                .isEqualTo(foregroundServiceUsageConsumePower);
+        assertThat(entry.mBackgroundUsageConsumePower).isEqualTo(backgroundUsageConsumePower);
+        assertThat(entry.mCachedUsageConsumePower).isEqualTo(cachedUsageConsumePower);
         assertThat(entry.mPercentOfTotal).isEqualTo(percentOfTotal);
         assertThat(entry.mForegroundUsageTimeInMs).isEqualTo(foregroundUsageTimeInMs);
+        assertThat(entry.mForegroundServiceUsageTimeInMs)
+                .isEqualTo(foregroundServiceUsageTimeInMs);
         assertThat(entry.mBackgroundUsageTimeInMs).isEqualTo(backgroundUsageTimeInMs);
         assertThat(entry.mDrainType).isEqualTo(drainType);
         assertThat(entry.mConsumerType)
@@ -307,7 +359,12 @@
             long timestamp,
             double totalPower,
             double consumePower,
+            double foregroundUsageConsumePower,
+            double foregroundServiceUsageConsumePower,
+            double backgroundUsageConsumePower,
+            double cachedUsageConsumePower,
             long foregroundUsageTimeInMs,
+            long foregroundServiceUsageTimeInMs,
             long backgroundUsageTimeInMs,
             int batteryLevel) {
         final MatrixCursor cursor = new MatrixCursor(
@@ -335,9 +392,14 @@
                         .setAppLabel("Settings")
                         .setTotalPower(totalPower)
                         .setConsumePower(consumePower)
+                        .setForegroundUsageConsumePower(foregroundUsageConsumePower)
+                        .setForegroundServiceUsageConsumePower(foregroundServiceUsageConsumePower)
+                        .setBackgroundUsageConsumePower(backgroundUsageConsumePower)
+                        .setCachedUsageConsumePower(cachedUsageConsumePower)
                         .setPercentOfTotal(0.3)
                         .setDrainType(3)
                         .setForegroundUsageTimeInMs(foregroundUsageTimeInMs)
+                        .setForegroundServiceUsageTimeInMs(foregroundServiceUsageTimeInMs)
                         .setBackgroundUsageTimeInMs(backgroundUsageTimeInMs)
                         .build();
         cursor.addRow(
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBroadcastReceiverTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBroadcastReceiverTest.java
index 513dfdf..addfd9b 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBroadcastReceiverTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBroadcastReceiverTest.java
@@ -132,6 +132,7 @@
     private static Intent getBatteryIntent(int level, int status) {
         final Intent intent = new Intent(Intent.ACTION_BATTERY_CHANGED);
         intent.putExtra(BatteryManager.EXTRA_LEVEL, level);
+        intent.putExtra(BatteryManager.EXTRA_SCALE, 100);
         intent.putExtra(BatteryManager.EXTRA_STATUS, status);
         return intent;
     }
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageContentProviderTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageContentProviderTest.java
index 361c596..d6e7737 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageContentProviderTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageContentProviderTest.java
@@ -49,6 +49,9 @@
 @RunWith(RobolectricTestRunner.class)
 public final class BatteryUsageContentProviderTest {
     private static final Uri VALID_BATTERY_STATE_CONTENT_URI = DatabaseUtils.BATTERY_CONTENT_URI;
+    private static final String PACKAGE_NAME1 = "com.android.settings1";
+    private static final String PACKAGE_NAME2 = "com.android.settings2";
+    private static final String PACKAGE_NAME3 = "com.android.settings3";
 
     private Context mContext;
     private BatteryUsageContentProvider mProvider;
@@ -118,31 +121,60 @@
     public void query_batteryState_returnsExpectedResult() throws Exception {
         mProvider.onCreate();
         final Duration currentTime = Duration.ofHours(52);
-        final long expiredTimeCutoff = currentTime.toMillis()
-                - BatteryUsageContentProvider.QUERY_DURATION_HOURS.toMillis();
-        testQueryBatteryState(currentTime, expiredTimeCutoff, /*hasQueryTimestamp=*/ false);
+        final long expiredTimeCutoff = currentTime.toMillis() - 3;
+
+        final Cursor cursor = insertBatteryState(currentTime, Long.toString(expiredTimeCutoff));
+
+        // Verifies the result not include expired data.
+        assertThat(cursor.getCount()).isEqualTo(3);
+        final int packageNameIndex = cursor.getColumnIndex("packageName");
+        // Verifies the first data package name.
+        cursor.moveToFirst();
+        final String actualPackageName1 = cursor.getString(packageNameIndex);
+        assertThat(actualPackageName1).isEqualTo(PACKAGE_NAME1);
+        // Verifies the second data package name.
+        cursor.moveToNext();
+        final String actualPackageName2 = cursor.getString(packageNameIndex);
+        assertThat(actualPackageName2).isEqualTo(PACKAGE_NAME2);
+        // Verifies the third data package name.
+        cursor.moveToNext();
+        final String actualPackageName3 = cursor.getString(packageNameIndex);
+        assertThat(actualPackageName3).isEqualTo(PACKAGE_NAME3);
+        cursor.close();
+        // Verifies the broadcast intent.
+        TimeUnit.SECONDS.sleep(1);
+        final List<Intent> intents = Shadows.shadowOf((Application) mContext).getBroadcastIntents();
+        assertThat(intents).hasSize(1);
+        assertThat(intents.get(0).getAction()).isEqualTo(
+                BootBroadcastReceiver.ACTION_PERIODIC_JOB_RECHECK);
     }
 
     @Test
     public void query_batteryStateTimestamp_returnsExpectedResult() throws Exception {
         mProvider.onCreate();
         final Duration currentTime = Duration.ofHours(52);
-        final long expiredTimeCutoff = currentTime.toMillis() - Duration.ofHours(10).toMillis();
-        testQueryBatteryState(currentTime, expiredTimeCutoff, /*hasQueryTimestamp=*/ true);
-    }
+        final long expiredTimeCutoff = currentTime.toMillis() - 1;
 
-    @Test
-    public void query_incorrectParameterFormat_returnsExpectedResult() throws Exception {
-        mProvider.onCreate();
-        final Duration currentTime = Duration.ofHours(52);
-        final long expiredTimeCutoff =
-                currentTime.toMillis()
-                        - BatteryUsageContentProvider.QUERY_DURATION_HOURS.toMillis();
-        testQueryBatteryState(
-                currentTime,
-                expiredTimeCutoff,
-                /*hasQueryTimestamp=*/ false,
-                /*customParameter=*/ "invalid number format");
+        final Cursor cursor = insertBatteryState(currentTime, Long.toString(expiredTimeCutoff));
+
+        // Verifies the result not include expired data.
+        assertThat(cursor.getCount()).isEqualTo(2);
+        final int packageNameIndex = cursor.getColumnIndex("packageName");
+        // Verifies the first data package name.
+        cursor.moveToFirst();
+        final String actualPackageName1 = cursor.getString(packageNameIndex);
+        assertThat(actualPackageName1).isEqualTo(PACKAGE_NAME2);
+        // Verifies the third data package name.
+        cursor.moveToNext();
+        final String actualPackageName2 = cursor.getString(packageNameIndex);
+        assertThat(actualPackageName2).isEqualTo(PACKAGE_NAME3);
+        cursor.close();
+        // Verifies the broadcast intent.
+        TimeUnit.SECONDS.sleep(1);
+        final List<Intent> intents = Shadows.shadowOf((Application) mContext).getBroadcastIntents();
+        assertThat(intents).hasSize(1);
+        assertThat(intents.get(0).getAction()).isEqualTo(
+                BootBroadcastReceiver.ACTION_PERIODIC_JOB_RECHECK);
     }
 
     @Test
@@ -164,8 +196,13 @@
                         .setBootTimestamp(101L)
                         .setTotalPower(99)
                         .setConsumePower(9)
+                        .setForegroundUsageConsumePower(1)
+                        .setForegroundServiceUsageConsumePower(2)
+                        .setBackgroundUsageConsumePower(3)
+                        .setCachedUsageConsumePower(3)
                         .setPercentOfTotal(0.9)
                         .setForegroundUsageTimeInMs(1000)
+                        .setForegroundServiceUsageTimeInMs(1500)
                         .setBackgroundUsageTimeInMs(2000)
                         .setDrainType(1)
                         .build();
@@ -247,54 +284,32 @@
                                 /*strings=*/ null));
     }
 
-    private void testQueryBatteryState(
-            Duration currentTime, long expiredTimeCutoff, boolean hasQueryTimestamp)
-            throws Exception {
-        testQueryBatteryState(currentTime, expiredTimeCutoff, hasQueryTimestamp, null);
-    }
-
-    private void testQueryBatteryState(
+    private Cursor insertBatteryState(
             Duration currentTime,
-            long expiredTimeCutoff,
-            boolean hasQueryTimestamp,
-            String customParameter)
+            String queryTimestamp)
             throws Exception {
         mProvider.onCreate();
         final FakeClock fakeClock = new FakeClock();
         fakeClock.setCurrentTime(currentTime);
         mProvider.setClock(fakeClock);
-        // Inserts some expired testing data.
-        BatteryTestUtils.insertDataToBatteryStateDatabase(
-                mContext, expiredTimeCutoff - 1, "com.android.sysui1");
-        BatteryTestUtils.insertDataToBatteryStateDatabase(
-                mContext, expiredTimeCutoff - 2, "com.android.sysui2");
-        BatteryTestUtils.insertDataToBatteryStateDatabase(
-                mContext, expiredTimeCutoff - 3, "com.android.sysui3");
+        final long currentTimestamp = currentTime.toMillis();
         // Inserts some valid testing data.
-        final String packageName1 = "com.android.settings1";
-        final String packageName2 = "com.android.settings2";
-        final String packageName3 = "com.android.settings3";
         BatteryTestUtils.insertDataToBatteryStateDatabase(
-                mContext, currentTime.toMillis(), packageName1);
+                mContext, currentTimestamp - 2, PACKAGE_NAME1,
+                /*isFullChargeStart=*/ true);
         BatteryTestUtils.insertDataToBatteryStateDatabase(
-                mContext, expiredTimeCutoff + 2, packageName2);
+                mContext, currentTimestamp - 1, PACKAGE_NAME2);
         BatteryTestUtils.insertDataToBatteryStateDatabase(
-                mContext, expiredTimeCutoff, packageName3);
+                mContext, currentTimestamp, PACKAGE_NAME3);
 
-        final Uri.Builder builder =
+        final Uri batteryStateQueryContentUri =
                 new Uri.Builder()
                         .scheme(ContentResolver.SCHEME_CONTENT)
                         .authority(DatabaseUtils.AUTHORITY)
-                        .appendPath(DatabaseUtils.BATTERY_STATE_TABLE);
-        if (customParameter != null) {
-            builder.appendQueryParameter(
-                    BatteryUsageContentProvider.QUERY_KEY_TIMESTAMP, customParameter);
-        } else if (hasQueryTimestamp) {
-            builder.appendQueryParameter(
-                    BatteryUsageContentProvider.QUERY_KEY_TIMESTAMP,
-                    Long.toString(expiredTimeCutoff));
-        }
-        final Uri batteryStateQueryContentUri = builder.build();
+                        .appendPath(DatabaseUtils.BATTERY_STATE_TABLE)
+                        .appendQueryParameter(
+                                BatteryUsageContentProvider.QUERY_KEY_TIMESTAMP, queryTimestamp)
+                        .build();
 
         final Cursor cursor =
                 mProvider.query(
@@ -304,27 +319,6 @@
                         /*strings1=*/ null,
                         /*s1=*/ null);
 
-        // Verifies the result not include expired data.
-        assertThat(cursor.getCount()).isEqualTo(3);
-        final int packageNameIndex = cursor.getColumnIndex("packageName");
-        // Verifies the first data package name.
-        cursor.moveToFirst();
-        final String actualPackageName1 = cursor.getString(packageNameIndex);
-        assertThat(actualPackageName1).isEqualTo(packageName1);
-        // Verifies the second data package name.
-        cursor.moveToNext();
-        final String actualPackageName2 = cursor.getString(packageNameIndex);
-        assertThat(actualPackageName2).isEqualTo(packageName2);
-        // Verifies the third data package name.
-        cursor.moveToNext();
-        final String actualPackageName3 = cursor.getString(packageNameIndex);
-        assertThat(actualPackageName3).isEqualTo(packageName3);
-        cursor.close();
-        // Verifies the broadcast intent.
-        TimeUnit.SECONDS.sleep(1);
-        final List<Intent> intents = Shadows.shadowOf((Application) mContext).getBroadcastIntents();
-        assertThat(intents).hasSize(1);
-        assertThat(intents.get(0).getAction()).isEqualTo(
-                BootBroadcastReceiver.ACTION_PERIODIC_JOB_RECHECK);
+        return cursor;
     }
 }
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageDataLoaderTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageDataLoaderTest.java
index 9c0604d..9aeff79 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageDataLoaderTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageDataLoaderTest.java
@@ -82,7 +82,7 @@
                 .thenReturn(mBatteryUsageStats);
         BatteryUsageDataLoader.sFakeBatteryEntryListSupplier = () -> batteryEntryList;
 
-        BatteryUsageDataLoader.loadUsageData(mContext);
+        BatteryUsageDataLoader.loadUsageData(mContext, /*isFullChargeStart=*/ false);
 
         final int queryFlags = mStatsQueryCaptor.getValue().getFlags();
         assertThat(queryFlags
@@ -97,7 +97,7 @@
                 .thenReturn(mBatteryUsageStats);
         BatteryUsageDataLoader.sFakeBatteryEntryListSupplier = () -> null;
 
-        BatteryUsageDataLoader.loadUsageData(mContext);
+        BatteryUsageDataLoader.loadUsageData(mContext, /*isFullChargeStart=*/ false);
 
         verify(mMockContentResolver).insert(any(), any());
     }
@@ -106,9 +106,9 @@
     public void loadUsageData_emptyBatteryEntryList_insertFakeDataIntoProvider() {
         when(mBatteryStatsManager.getBatteryUsageStats(mStatsQueryCaptor.capture()))
                 .thenReturn(mBatteryUsageStats);
-        BatteryUsageDataLoader.sFakeBatteryEntryListSupplier = () -> new ArrayList<BatteryEntry>();
+        BatteryUsageDataLoader.sFakeBatteryEntryListSupplier = () -> new ArrayList<>();
 
-        BatteryUsageDataLoader.loadUsageData(mContext);
+        BatteryUsageDataLoader.loadUsageData(mContext, /*isFullChargeStart=*/ false);
 
         verify(mMockContentResolver).insert(any(), any());
     }
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/ConvertUtilsTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/ConvertUtilsTest.java
index dd8c536..9a43557 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/ConvertUtilsTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/ConvertUtilsTest.java
@@ -26,11 +26,6 @@
 import android.os.BatteryUsageStats;
 import android.os.LocaleList;
 import android.os.UserHandle;
-import android.text.format.DateUtils;
-
-import com.android.settings.fuelgauge.BatteryUtils;
-import com.android.settings.fuelgauge.PowerUsageFeatureProvider;
-import com.android.settings.testutils.FakeFeatureFactory;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -40,13 +35,7 @@
 import org.robolectric.RobolectricTestRunner;
 import org.robolectric.RuntimeEnvironment;
 
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
 import java.util.Locale;
-import java.util.Map;
 import java.util.TimeZone;
 
 @RunWith(RobolectricTestRunner.class)
@@ -59,15 +48,10 @@
     @Mock
     private BatteryEntry mMockBatteryEntry;
 
-    private FakeFeatureFactory mFeatureFactory;
-    private PowerUsageFeatureProvider mPowerUsageFeatureProvider;
-
     @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
         mContext = spy(RuntimeEnvironment.application);
-        mFeatureFactory = FakeFeatureFactory.setupForTest();
-        mPowerUsageFeatureProvider = mFeatureFactory.powerUsageFeatureProvider;
     }
 
     @Test
@@ -80,8 +64,13 @@
         when(mMockBatteryEntry.isHidden()).thenReturn(true);
         when(mBatteryUsageStats.getConsumedPower()).thenReturn(5.1);
         when(mMockBatteryEntry.getConsumedPower()).thenReturn(1.1);
+        when(mMockBatteryEntry.getConsumedPowerInForeground()).thenReturn(1.2);
+        when(mMockBatteryEntry.getConsumedPowerInForegroundService()).thenReturn(1.3);
+        when(mMockBatteryEntry.getConsumedPowerInBackground()).thenReturn(1.4);
+        when(mMockBatteryEntry.getConsumedPowerInCached()).thenReturn(1.5);
         mMockBatteryEntry.mPercent = 0.3;
         when(mMockBatteryEntry.getTimeInForegroundMs()).thenReturn(1234L);
+        when(mMockBatteryEntry.getTimeInForegroundServiceMs()).thenReturn(3456L);
         when(mMockBatteryEntry.getTimeInBackgroundMs()).thenReturn(5689L);
         when(mMockBatteryEntry.getPowerComponentId()).thenReturn(expectedType);
         when(mMockBatteryEntry.getConsumerType())
@@ -95,7 +84,8 @@
                         /*batteryStatus=*/ BatteryManager.BATTERY_STATUS_FULL,
                         /*batteryHealth=*/ BatteryManager.BATTERY_HEALTH_COLD,
                         /*bootTimestamp=*/ 101L,
-                        /*timestamp=*/ 10001L);
+                        /*timestamp=*/ 10001L,
+                        /*isFullChargeStart=*/ true);
         final BatteryInformation batteryInformation =
                 ConvertUtils.getBatteryInformation(
                         values, BatteryHistEntry.KEY_BATTERY_INFORMATION);
@@ -109,14 +99,20 @@
         assertThat(values.getAsLong(BatteryHistEntry.KEY_TIMESTAMP)).isEqualTo(10001L);
         assertThat(values.getAsInteger(BatteryHistEntry.KEY_CONSUMER_TYPE))
                 .isEqualTo(ConvertUtils.CONSUMER_TYPE_SYSTEM_BATTERY);
+        assertThat(values.getAsBoolean(BatteryHistEntry.KEY_IS_FULL_CHARGE_CYCLE_START)).isTrue();
         assertThat(batteryInformation.getAppLabel()).isEqualTo("Settings");
         assertThat(batteryInformation.getIsHidden()).isTrue();
         assertThat(batteryInformation.getBootTimestamp()).isEqualTo(101L);
         assertThat(batteryInformation.getZoneId()).isEqualTo(TimeZone.getDefault().getID());
         assertThat(batteryInformation.getTotalPower()).isEqualTo(5.1);
         assertThat(batteryInformation.getConsumePower()).isEqualTo(1.1);
+        assertThat(batteryInformation.getForegroundUsageConsumePower()).isEqualTo(1.2);
+        assertThat(batteryInformation.getForegroundServiceUsageConsumePower()).isEqualTo(1.3);
+        assertThat(batteryInformation.getBackgroundUsageConsumePower()).isEqualTo(1.4);
+        assertThat(batteryInformation.getCachedUsageConsumePower()).isEqualTo(1.5);
         assertThat(batteryInformation.getPercentOfTotal()).isEqualTo(0.3);
         assertThat(batteryInformation.getForegroundUsageTimeInMs()).isEqualTo(1234L);
+        assertThat(batteryInformation.getForegroundServiceUsageTimeInMs()).isEqualTo(3456L);
         assertThat(batteryInformation.getBackgroundUsageTimeInMs()).isEqualTo(5689L);
         assertThat(batteryInformation.getDrainType()).isEqualTo(expectedType);
         assertThat(deviceBatteryState.getBatteryLevel()).isEqualTo(12);
@@ -136,7 +132,8 @@
                         /*batteryStatus=*/ BatteryManager.BATTERY_STATUS_FULL,
                         /*batteryHealth=*/ BatteryManager.BATTERY_HEALTH_COLD,
                         /*bootTimestamp=*/ 101L,
-                        /*timestamp=*/ 10001L);
+                        /*timestamp=*/ 10001L,
+                        /*isFullChargeStart=*/ false);
 
         final BatteryInformation batteryInformation =
                 ConvertUtils.getBatteryInformation(
@@ -144,6 +141,7 @@
         final DeviceBatteryState deviceBatteryState = batteryInformation.getDeviceBatteryState();
         assertThat(batteryInformation.getBootTimestamp()).isEqualTo(101L);
         assertThat(batteryInformation.getZoneId()).isEqualTo(TimeZone.getDefault().getID());
+        assertThat(values.getAsBoolean(BatteryHistEntry.KEY_IS_FULL_CHARGE_CYCLE_START)).isFalse();
         assertThat(deviceBatteryState.getBatteryLevel()).isEqualTo(12);
         assertThat(deviceBatteryState.getBatteryStatus())
                 .isEqualTo(BatteryManager.BATTERY_STATUS_FULL);
@@ -165,8 +163,13 @@
         when(mMockBatteryEntry.isHidden()).thenReturn(true);
         when(mBatteryUsageStats.getConsumedPower()).thenReturn(5.1);
         when(mMockBatteryEntry.getConsumedPower()).thenReturn(1.1);
+        when(mMockBatteryEntry.getConsumedPowerInForeground()).thenReturn(1.2);
+        when(mMockBatteryEntry.getConsumedPowerInForegroundService()).thenReturn(1.3);
+        when(mMockBatteryEntry.getConsumedPowerInBackground()).thenReturn(1.4);
+        when(mMockBatteryEntry.getConsumedPowerInCached()).thenReturn(1.5);
         mMockBatteryEntry.mPercent = 0.3;
         when(mMockBatteryEntry.getTimeInForegroundMs()).thenReturn(1234L);
+        when(mMockBatteryEntry.getTimeInForegroundServiceMs()).thenReturn(3456L);
         when(mMockBatteryEntry.getTimeInBackgroundMs()).thenReturn(5689L);
         when(mMockBatteryEntry.getPowerComponentId()).thenReturn(expectedType);
         when(mMockBatteryEntry.getConsumerType())
@@ -192,9 +195,15 @@
                 .isEqualTo(TimeZone.getDefault().getID());
         assertThat(batteryHistEntry.mTotalPower).isEqualTo(5.1);
         assertThat(batteryHistEntry.mConsumePower).isEqualTo(1.1);
+        assertThat(batteryHistEntry.mForegroundUsageConsumePower).isEqualTo(1.2);
+        assertThat(batteryHistEntry.mForegroundServiceUsageConsumePower).isEqualTo(1.3);
+        assertThat(batteryHistEntry.mBackgroundUsageConsumePower).isEqualTo(1.4);
+        assertThat(batteryHistEntry.mCachedUsageConsumePower).isEqualTo(1.5);
         assertThat(batteryHistEntry.mPercentOfTotal).isEqualTo(0.3);
         assertThat(batteryHistEntry.mForegroundUsageTimeInMs)
                 .isEqualTo(1234L);
+        assertThat(batteryHistEntry.mForegroundServiceUsageTimeInMs)
+                .isEqualTo(3456L);
         assertThat(batteryHistEntry.mBackgroundUsageTimeInMs)
                 .isEqualTo(5689L);
         assertThat(batteryHistEntry.mDrainType).isEqualTo(expectedType);
@@ -226,194 +235,6 @@
     }
 
     @Test
-    public void getIndexedUsageMap_nullOrEmptyHistoryMap_returnEmptyCollection() {
-        final int timeSlotSize = 2;
-        final long[] batteryHistoryKeys = new long[]{101L, 102L, 103L, 104L, 105L};
-
-        assertThat(ConvertUtils.getIndexedUsageMap(
-                mContext, timeSlotSize, batteryHistoryKeys,
-                /*batteryHistoryMap=*/ null, /*purgeLowPercentageAndFakeData=*/ true))
-                .isEmpty();
-        assertThat(ConvertUtils.getIndexedUsageMap(
-                mContext, timeSlotSize, batteryHistoryKeys,
-                new HashMap<Long, Map<String, BatteryHistEntry>>(),
-                /*purgeLowPercentageAndFakeData=*/ true))
-                .isEmpty();
-    }
-
-    @Test
-    public void getIndexedUsageMap_returnsExpectedResult() {
-        // Creates the fake testing data.
-        final int timeSlotSize = 2;
-        final long[] batteryHistoryKeys = new long[]{generateTimestamp(0), generateTimestamp(1),
-                generateTimestamp(2), generateTimestamp(3), generateTimestamp(4)};
-        final Map<Long, Map<String, BatteryHistEntry>> batteryHistoryMap =
-                new HashMap<>();
-        final BatteryHistEntry fakeEntry = createBatteryHistEntry(
-                ConvertUtils.FAKE_PACKAGE_NAME, "fake_label", 0, 0L, 0L, 0L);
-        // Adds the index = 0 data.
-        Map<String, BatteryHistEntry> entryMap = new HashMap<>();
-        BatteryHistEntry entry = createBatteryHistEntry(
-                "package1", "label1", 5.0, 1L, 10L, 20L);
-        entryMap.put(entry.getKey(), entry);
-        entryMap.put(fakeEntry.getKey(), fakeEntry);
-        batteryHistoryMap.put(Long.valueOf(batteryHistoryKeys[0]), entryMap);
-        // Adds the index = 1 data.
-        entryMap = new HashMap<>();
-        entryMap.put(fakeEntry.getKey(), fakeEntry);
-        batteryHistoryMap.put(Long.valueOf(batteryHistoryKeys[1]), entryMap);
-        // Adds the index = 2 data.
-        entryMap = new HashMap<>();
-        entry = createBatteryHistEntry(
-                "package2", "label2", 10.0, 2L, 15L, 25L);
-        entryMap.put(entry.getKey(), entry);
-        entryMap.put(fakeEntry.getKey(), fakeEntry);
-        batteryHistoryMap.put(Long.valueOf(batteryHistoryKeys[2]), entryMap);
-        // Adds the index = 3 data.
-        entryMap = new HashMap<>();
-        entry = createBatteryHistEntry(
-                "package2", "label2", 15.0, 2L, 25L, 35L);
-        entryMap.put(entry.getKey(), entry);
-        entry = createBatteryHistEntry(
-                "package3", "label3", 5.0, 3L, 5L, 5L);
-        entryMap.put(entry.getKey(), entry);
-        entryMap.put(fakeEntry.getKey(), fakeEntry);
-        batteryHistoryMap.put(Long.valueOf(batteryHistoryKeys[3]), entryMap);
-        // Adds the index = 4 data.
-        entryMap = new HashMap<>();
-        entry = createBatteryHistEntry(
-                "package2", "label2", 30.0, 2L, 30L, 40L);
-        entryMap.put(entry.getKey(), entry);
-        entry = createBatteryHistEntry(
-                "package2", "label2", 75.0, 4L, 40L, 50L);
-        entryMap.put(entry.getKey(), entry);
-        entry = createBatteryHistEntry(
-                "package3", "label3", 5.0, 3L, 5L, 5L);
-        entryMap.put(entry.getKey(), entry);
-        entryMap.put(fakeEntry.getKey(), fakeEntry);
-        batteryHistoryMap.put(Long.valueOf(batteryHistoryKeys[4]), entryMap);
-
-        final Map<Integer, List<BatteryDiffEntry>> resultMap =
-                ConvertUtils.getIndexedUsageMap(
-                        mContext, timeSlotSize, batteryHistoryKeys, batteryHistoryMap,
-                        /*purgeLowPercentageAndFakeData=*/ false);
-
-        assertThat(resultMap).hasSize(3);
-        // Verifies the first timestamp result.
-        List<BatteryDiffEntry> entryList = resultMap.get(Integer.valueOf(0));
-        assertThat(entryList).hasSize(1);
-        assertBatteryDiffEntry(entryList.get(0), 100, 15L, 25L);
-        // Verifies the second timestamp result.
-        entryList = resultMap.get(Integer.valueOf(1));
-        assertThat(entryList).hasSize(3);
-        assertBatteryDiffEntry(entryList.get(1), 5, 5L, 5L);
-        assertBatteryDiffEntry(entryList.get(2), 75, 40L, 50L);
-        assertBatteryDiffEntry(entryList.get(0), 20, 15L, 15L);
-        // Verifies the last 24 hours aggregate result.
-        entryList = resultMap.get(Integer.valueOf(-1));
-        assertThat(entryList).hasSize(3);
-        assertBatteryDiffEntry(entryList.get(1), 4, 5L, 5L);
-        assertBatteryDiffEntry(entryList.get(2), 68, 40L, 50L);
-        assertBatteryDiffEntry(entryList.get(0), 27, 30L, 40L);
-
-        // Test getIndexedUsageMap() with purged data.
-        ConvertUtils.PERCENTAGE_OF_TOTAL_THRESHOLD = 50;
-        final Map<Integer, List<BatteryDiffEntry>> purgedResultMap =
-                ConvertUtils.getIndexedUsageMap(
-                        mContext, timeSlotSize, batteryHistoryKeys, batteryHistoryMap,
-                        /*purgeLowPercentageAndFakeData=*/ true);
-
-        assertThat(purgedResultMap).hasSize(3);
-        // Verifies the first timestamp result.
-        entryList = purgedResultMap.get(Integer.valueOf(0));
-        assertThat(entryList).hasSize(1);
-        // Verifies the second timestamp result.
-        entryList = purgedResultMap.get(Integer.valueOf(1));
-        assertThat(entryList).hasSize(1);
-        assertBatteryDiffEntry(entryList.get(0), 75, 40L, 50L);
-        // Verifies the last 24 hours aggregate result.
-        entryList = purgedResultMap.get(Integer.valueOf(-1));
-        assertThat(entryList).hasSize(1);
-        // Verifies the fake data is cleared out.
-        assertThat(entryList.get(0).getPackageName())
-                .isNotEqualTo(ConvertUtils.FAKE_PACKAGE_NAME);
-    }
-
-    @Test
-    public void getIndexedUsageMap_usageTimeExceed_returnsExpectedResult() {
-        final int timeSlotSize = 1;
-        final long[] batteryHistoryKeys = new long[]{101L, 102L, 103L};
-        final Map<Long, Map<String, BatteryHistEntry>> batteryHistoryMap =
-                new HashMap<>();
-        final BatteryHistEntry fakeEntry = createBatteryHistEntry(
-                ConvertUtils.FAKE_PACKAGE_NAME, "fake_label", 0, 0L, 0L, 0L);
-        // Adds the index = 0 data.
-        Map<String, BatteryHistEntry> entryMap = new HashMap<>();
-        entryMap.put(fakeEntry.getKey(), fakeEntry);
-        batteryHistoryMap.put(Long.valueOf(batteryHistoryKeys[0]), entryMap);
-        // Adds the index = 1 data.
-        entryMap = new HashMap<>();
-        entryMap.put(fakeEntry.getKey(), fakeEntry);
-        batteryHistoryMap.put(Long.valueOf(batteryHistoryKeys[1]), entryMap);
-        // Adds the index = 2 data.
-        entryMap = new HashMap<>();
-        final BatteryHistEntry entry = createBatteryHistEntry(
-                "package3", "label3", 500, 5L, 3600000L, 7200000L);
-        entryMap.put(entry.getKey(), entry);
-        batteryHistoryMap.put(Long.valueOf(batteryHistoryKeys[2]), entryMap);
-
-        final Map<Integer, List<BatteryDiffEntry>> purgedResultMap =
-                ConvertUtils.getIndexedUsageMap(
-                        mContext, timeSlotSize, batteryHistoryKeys, batteryHistoryMap,
-                        /*purgeLowPercentageAndFakeData=*/ true);
-
-        assertThat(purgedResultMap).hasSize(2);
-        final List<BatteryDiffEntry> entryList = purgedResultMap.get(0);
-        assertThat(entryList).hasSize(1);
-        // Verifies the clipped usage time.
-        final float ratio = (float) (7200) / (float) (3600 + 7200);
-        final BatteryDiffEntry resultEntry = entryList.get(0);
-        assertThat(resultEntry.mForegroundUsageTimeInMs)
-                .isEqualTo(Math.round(entry.mForegroundUsageTimeInMs * ratio));
-        assertThat(resultEntry.mBackgroundUsageTimeInMs)
-                .isEqualTo(Math.round(entry.mBackgroundUsageTimeInMs * ratio));
-        assertThat(resultEntry.mConsumePower)
-                .isEqualTo(entry.mConsumePower * ratio);
-    }
-
-    @Test
-    public void getIndexedUsageMap_hideBackgroundUsageTime_returnsExpectedResult() {
-        final long[] batteryHistoryKeys = new long[]{101L, 102L, 103L};
-        final Map<Long, Map<String, BatteryHistEntry>> batteryHistoryMap = new HashMap<>();
-        final BatteryHistEntry fakeEntry = createBatteryHistEntry(
-                ConvertUtils.FAKE_PACKAGE_NAME, "fake_label", 0, 0L, 0L, 0L);
-        // Adds the index = 0 data.
-        Map<String, BatteryHistEntry> entryMap = new HashMap<>();
-        entryMap.put(fakeEntry.getKey(), fakeEntry);
-        batteryHistoryMap.put(Long.valueOf(batteryHistoryKeys[0]), entryMap);
-        // Adds the index = 1 data.
-        entryMap = new HashMap<>();
-        entryMap.put(fakeEntry.getKey(), fakeEntry);
-        batteryHistoryMap.put(Long.valueOf(batteryHistoryKeys[1]), entryMap);
-        // Adds the index = 2 data.
-        entryMap = new HashMap<>();
-        final BatteryHistEntry entry = createBatteryHistEntry(
-                "package3", "label3", 500, 5L, 3600000L, 7200000L);
-        entryMap.put(entry.getKey(), entry);
-        batteryHistoryMap.put(Long.valueOf(batteryHistoryKeys[2]), entryMap);
-        when(mPowerUsageFeatureProvider.getHideBackgroundUsageTimeSet(mContext))
-                .thenReturn(new HashSet(Arrays.asList((CharSequence) "package3")));
-
-        final Map<Integer, List<BatteryDiffEntry>> purgedResultMap =
-                ConvertUtils.getIndexedUsageMap(
-                        mContext, /*timeSlotSize=*/ 1, batteryHistoryKeys, batteryHistoryMap,
-                        /*purgeLowPercentageAndFakeData=*/ true);
-
-        final BatteryDiffEntry resultEntry = purgedResultMap.get(0).get(0);
-        assertThat(resultEntry.mBackgroundUsageTimeInMs).isEqualTo(0);
-    }
-
-    @Test
     public void getLocale_nullContext_returnDefaultLocale() {
         assertThat(ConvertUtils.getLocale(/*context=*/ null))
                 .isEqualTo(Locale.getDefault());
@@ -430,113 +251,4 @@
         mContext.getResources().getConfiguration().setLocales(new LocaleList());
         assertThat(ConvertUtils.getLocale(mContext)).isEqualTo(Locale.getDefault());
     }
-
-    @Test
-    public void resolveMultiUsersData_replaceOtherUsersItemWithExpectedEntry() {
-        final int currentUserId = mContext.getUserId();
-        final Map<Integer, List<BatteryDiffEntry>> entryMap = new HashMap<>();
-        // Without other users time slot.
-        entryMap.put(0, Arrays.asList(
-                createBatteryDiffEntry(
-                        currentUserId,
-                        ConvertUtils.CONSUMER_TYPE_UID_BATTERY,
-                        /*consumePercentage=*/ 50)));
-        // With other users time slot.
-        final List<BatteryDiffEntry> withOtherUsersList = new ArrayList<>();
-        entryMap.put(1, withOtherUsersList);
-        withOtherUsersList.add(
-                createBatteryDiffEntry(
-                        currentUserId + 1,
-                        ConvertUtils.CONSUMER_TYPE_SYSTEM_BATTERY,
-                        /*consumePercentage=*/ 20));
-        withOtherUsersList.add(
-                createBatteryDiffEntry(
-                        currentUserId + 2,
-                        ConvertUtils.CONSUMER_TYPE_UID_BATTERY,
-                        /*consumePercentage=*/ 30));
-        withOtherUsersList.add(
-                createBatteryDiffEntry(
-                        currentUserId + 3,
-                        ConvertUtils.CONSUMER_TYPE_UID_BATTERY,
-                        /*consumePercentage=*/ 40));
-
-        ConvertUtils.resolveMultiUsersData(mContext, entryMap);
-
-        assertThat(entryMap.get(0).get(0).getPercentOfTotal()).isEqualTo(50);
-        // Asserts with other users items.
-        final List<BatteryDiffEntry> entryList = entryMap.get(1);
-        assertThat(entryList).hasSize(2);
-        assertBatteryDiffEntry(
-                entryList.get(0),
-                currentUserId + 1,
-                /*uid=*/ 0,
-                ConvertUtils.CONSUMER_TYPE_SYSTEM_BATTERY,
-                /*consumePercentage=*/ 20);
-        assertBatteryDiffEntry(
-                entryList.get(1),
-                BatteryUtils.UID_OTHER_USERS,
-                BatteryUtils.UID_OTHER_USERS,
-                ConvertUtils.CONSUMER_TYPE_UID_BATTERY,
-                /*consumePercentage=*/ 70);
-    }
-
-    private BatteryDiffEntry createBatteryDiffEntry(
-            long userId, int counsumerType, double consumePercentage) {
-        final ContentValues values = new ContentValues();
-        values.put(BatteryHistEntry.KEY_USER_ID, userId);
-        values.put(BatteryHistEntry.KEY_CONSUMER_TYPE, counsumerType);
-        final BatteryDiffEntry batteryDiffEntry =
-                new BatteryDiffEntry(
-                        mContext,
-                        /*foregroundUsageTimeInMs=*/ 0,
-                        /*backgroundUsageTimeInMs=*/ 0,
-                        /*consumePower=*/ consumePercentage,
-                        new BatteryHistEntry(values));
-        batteryDiffEntry.setTotalConsumePower(100f);
-        return batteryDiffEntry;
-    }
-
-    private static BatteryHistEntry createBatteryHistEntry(
-            String packageName, String appLabel, double consumePower,
-            long uid, long foregroundUsageTimeInMs, long backgroundUsageTimeInMs) {
-        // Only insert required fields.
-        final BatteryInformation batteryInformation =
-                BatteryInformation
-                        .newBuilder()
-                        .setAppLabel(appLabel)
-                        .setConsumePower(consumePower)
-                        .setForegroundUsageTimeInMs(foregroundUsageTimeInMs)
-                        .setBackgroundUsageTimeInMs(backgroundUsageTimeInMs)
-                        .build();
-        final ContentValues values = new ContentValues();
-        values.put(BatteryHistEntry.KEY_PACKAGE_NAME, packageName);
-        values.put(BatteryHistEntry.KEY_UID, Long.valueOf(uid));
-        values.put(BatteryHistEntry.KEY_CONSUMER_TYPE,
-                Integer.valueOf(ConvertUtils.CONSUMER_TYPE_UID_BATTERY));
-        values.put(BatteryHistEntry.KEY_BATTERY_INFORMATION,
-                ConvertUtils.convertBatteryInformationToString(batteryInformation));
-        return new BatteryHistEntry(values);
-    }
-
-    private static void assertBatteryDiffEntry(
-            BatteryDiffEntry entry, long userId, long uid, int counsumerType,
-            double consumePercentage) {
-        assertThat(entry.mBatteryHistEntry.mUid).isEqualTo(uid);
-        assertThat(entry.mBatteryHistEntry.mUserId).isEqualTo(userId);
-        assertThat(entry.mBatteryHistEntry.mConsumerType).isEqualTo(counsumerType);
-        assertThat(entry.getPercentOfTotal()).isEqualTo(consumePercentage);
-    }
-
-    private static void assertBatteryDiffEntry(
-            BatteryDiffEntry entry, int percentOfTotal,
-            long foregroundUsageTimeInMs, long backgroundUsageTimeInMs) {
-        assertThat((int) entry.getPercentOfTotal()).isEqualTo(percentOfTotal);
-        assertThat(entry.mForegroundUsageTimeInMs).isEqualTo(foregroundUsageTimeInMs);
-        assertThat(entry.mBackgroundUsageTimeInMs).isEqualTo(backgroundUsageTimeInMs);
-    }
-
-    private static Long generateTimestamp(int index) {
-        // "2021-04-23 07:00:00 UTC" + index hours
-        return 1619247600000L + index * DateUtils.HOUR_IN_MILLIS;
-    }
 }
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/DataProcessorTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/DataProcessorTest.java
index 7d68140..cdfed06 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/DataProcessorTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/DataProcessorTest.java
@@ -532,15 +532,21 @@
         final Map<Long, Map<String, BatteryHistEntry>> batteryHistoryMap = new HashMap<>();
         final int currentUserId = mContext.getUserId();
         final BatteryHistEntry fakeEntry = createBatteryHistEntry(
-                ConvertUtils.FAKE_PACKAGE_NAME, "fake_label", /*consumePower=*/ 0, /*uid=*/ 0L,
-                currentUserId, ConvertUtils.CONSUMER_TYPE_UID_BATTERY,
-                /*foregroundUsageTimeInMs=*/ 0L, /*backgroundUsageTimeInMs=*/ 0L);
+                ConvertUtils.FAKE_PACKAGE_NAME, "fake_label", /*consumePower=*/ 0,
+                /*foregroundUsageConsumePower=*/ 0, /*foregroundServiceUsageConsumePower=*/ 0,
+                /*backgroundUsageConsumePower=*/ 0, /*cachedUsageConsumePower=*/ 0,
+                /*uid=*/ 0L, currentUserId, ConvertUtils.CONSUMER_TYPE_UID_BATTERY,
+                /*foregroundUsageTimeInMs=*/ 0L, /*foregroundServiceUsageTimeInMs=*/ 0L,
+                /*backgroundUsageTimeInMs=*/ 0L);
         // Adds the index = 0 data.
         Map<String, BatteryHistEntry> entryMap = new HashMap<>();
         BatteryHistEntry entry = createBatteryHistEntry(
-                "package1", "label1", /*consumePower=*/ 5.0, /*uid=*/ 1L, currentUserId,
+                "package1", "label1", /*consumePower=*/ 5.0,
+                /*foregroundUsageConsumePower=*/ 2, /*foregroundServiceUsageConsumePower=*/ 0,
+                /*backgroundUsageConsumePower=*/ 3, /*cachedUsageConsumePower=*/ 0,
+                /*uid=*/ 1L, currentUserId,
                 ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 10L,
-                /*backgroundUsageTimeInMs=*/ 20L);
+                /*foregroundServiceUsageTimeInMs=*/ 10L, /*backgroundUsageTimeInMs=*/ 20L);
         entryMap.put(entry.getKey(), entry);
         entryMap.put(fakeEntry.getKey(), fakeEntry);
         batteryHistoryMap.put(batteryHistoryKeys[0], entryMap);
@@ -551,47 +557,68 @@
         // Adds the index = 2 data.
         entryMap = new HashMap<>();
         entry = createBatteryHistEntry(
-                "package2", "label2", /*consumePower=*/ 20.0, /*uid=*/ 2L, currentUserId,
+                "package2", "label2", /*consumePower=*/ 20.0,
+                /*foregroundUsageConsumePower=*/ 5, /*foregroundServiceUsageConsumePower=*/ 5,
+                /*backgroundUsageConsumePower=*/ 5, /*cachedUsageConsumePower=*/ 5,
+                /*uid=*/ 2L, currentUserId,
                 ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 15L,
-                25L);
+                /*foregroundServiceUsageTimeInMs=*/ 15L, /*backgroundUsageTimeInMs=*/ 25L);
         entryMap.put(entry.getKey(), entry);
         entryMap.put(fakeEntry.getKey(), fakeEntry);
         batteryHistoryMap.put(batteryHistoryKeys[2], entryMap);
         // Adds the index = 3 data.
         entryMap = new HashMap<>();
         entry = createBatteryHistEntry(
-                "package2", "label2", /*consumePower=*/ 40.0, /*uid=*/ 2L, currentUserId,
+                "package2", "label2", /*consumePower=*/ 40.0,
+                /*foregroundUsageConsumePower=*/ 8, /*foregroundServiceUsageConsumePower=*/ 8,
+                /*backgroundUsageConsumePower=*/ 8, /*cachedUsageConsumePower=*/ 8,
+                /*uid=*/ 2L, currentUserId,
                 ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 25L,
-                /*backgroundUsageTimeInMs=*/ 35L);
+                /*foregroundServiceUsageTimeInMs=*/ 25L, /*backgroundUsageTimeInMs=*/ 35L);
         entryMap.put(entry.getKey(), entry);
         entry = createBatteryHistEntry(
-                "package2", "label2", /*consumePower=*/ 10.0, /*uid=*/ 3L, currentUserId,
+                "package2", "label2", /*consumePower=*/ 10.0,
+                /*foregroundUsageConsumePower=*/ 4, /*foregroundServiceUsageConsumePower=*/ 2,
+                /*backgroundUsageConsumePower=*/ 2, /*cachedUsageConsumePower=*/ 2,
+                /*uid=*/ 3L, currentUserId,
                 ConvertUtils.CONSUMER_TYPE_SYSTEM_BATTERY, /*foregroundUsageTimeInMs=*/ 40L,
-                /*backgroundUsageTimeInMs=*/ 50L);
+                /*foregroundServiceUsageTimeInMs=*/ 40L, /*backgroundUsageTimeInMs=*/ 50L);
         entryMap.put(entry.getKey(), entry);
         entry = createBatteryHistEntry(
-                "package3", "label3", /*consumePower=*/ 15.0, /*uid=*/ 4L, currentUserId,
+                "package3", "label3", /*consumePower=*/ 15.0,
+                /*foregroundUsageConsumePower=*/ 6, /*foregroundServiceUsageConsumePower=*/ 3,
+                /*backgroundUsageConsumePower=*/ 3, /*cachedUsageConsumePower=*/ 3,
+                /*uid=*/ 4L, currentUserId,
                 ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 5L,
-                /*backgroundUsageTimeInMs=*/ 5L);
+                /*foregroundServiceUsageTimeInMs=*/ 5L, /*backgroundUsageTimeInMs=*/ 5L);
         entryMap.put(entry.getKey(), entry);
         entryMap.put(fakeEntry.getKey(), fakeEntry);
         batteryHistoryMap.put(batteryHistoryKeys[3], entryMap);
         // Adds the index = 4 data.
         entryMap = new HashMap<>();
         entry = createBatteryHistEntry(
-                "package2", "label2", /*consumePower=*/ 40.0, /*uid=*/ 2L, currentUserId,
+                "package2", "label2", /*consumePower=*/ 40.0,
+                /*foregroundUsageConsumePower=*/ 14, /*foregroundServiceUsageConsumePower=*/ 9,
+                /*backgroundUsageConsumePower=*/ 9, /*cachedUsageConsumePower=*/ 8,
+                /*uid=*/ 2L, currentUserId,
                 ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 30L,
-                /*backgroundUsageTimeInMs=*/ 40L);
+                /*foregroundServiceUsageTimeInMs=*/ 30L, /*backgroundUsageTimeInMs=*/ 40L);
         entryMap.put(entry.getKey(), entry);
         entry = createBatteryHistEntry(
-                "package2", "label2", /*consumePower=*/ 20.0, /*uid=*/ 3L, currentUserId,
+                "package2", "label2", /*consumePower=*/ 20.0,
+                /*foregroundUsageConsumePower=*/ 5, /*foregroundServiceUsageConsumePower=*/ 5,
+                /*backgroundUsageConsumePower=*/ 5, /*cachedUsageConsumePower=*/ 5,
+                /*uid=*/ 3L, currentUserId,
                 ConvertUtils.CONSUMER_TYPE_SYSTEM_BATTERY, /*foregroundUsageTimeInMs=*/ 50L,
-                /*backgroundUsageTimeInMs=*/ 60L);
+                /*foregroundServiceUsageTimeInMs=*/ 50L, /*backgroundUsageTimeInMs=*/ 60L);
         entryMap.put(entry.getKey(), entry);
         entry = createBatteryHistEntry(
-                "package3", "label3", /*consumePower=*/ 40.0, /*uid=*/ 4L, currentUserId,
+                "package3", "label3", /*consumePower=*/ 40.0,
+                /*foregroundUsageConsumePower=*/ 8, /*foregroundServiceUsageConsumePower=*/ 8,
+                /*backgroundUsageConsumePower=*/ 8, /*cachedUsageConsumePower=*/ 8,
+                /*uid=*/ 4L, currentUserId,
                 ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 5L,
-                /*backgroundUsageTimeInMs=*/ 5L);
+                /*foregroundServiceUsageTimeInMs=*/ 5L, /*backgroundUsageTimeInMs=*/ 5L);
         entryMap.put(entry.getKey(), entry);
         entryMap.put(fakeEntry.getKey(), fakeEntry);
         batteryHistoryMap.put(batteryHistoryKeys[4], entryMap);
@@ -619,33 +646,54 @@
         assertBatteryDiffEntry(
                 resultDiffData.getAppDiffEntryList().get(0), currentUserId, /*uid=*/ 2L,
                 ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*consumePercentage=*/ 40.0,
-                /*foregroundUsageTimeInMs=*/ 30, /*backgroundUsageTimeInMs=*/ 40);
+                /*foregroundUsageConsumePower=*/ 14, /*foregroundServiceUsageConsumePower=*/ 9,
+                /*backgroundUsageConsumePower=*/ 9, /*cachedUsageConsumePower=*/ 8,
+                /*foregroundUsageTimeInMs=*/ 30, /*foregroundServiceUsageTimeInMs=*/ 30,
+                /*backgroundUsageTimeInMs=*/ 40);
         assertBatteryDiffEntry(
                 resultDiffData.getAppDiffEntryList().get(1), currentUserId, /*uid=*/ 4L,
                 ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*consumePercentage=*/ 40.0,
-                /*foregroundUsageTimeInMs=*/ 5, /*backgroundUsageTimeInMs=*/ 5);
+                /*foregroundUsageConsumePower=*/ 8, /*foregroundServiceUsageConsumePower=*/ 8,
+                /*backgroundUsageConsumePower=*/ 8, /*cachedUsageConsumePower=*/ 8,
+                /*foregroundUsageTimeInMs=*/ 5, /*foregroundServiceUsageTimeInMs=*/ 5,
+                /*backgroundUsageTimeInMs=*/ 5);
         assertBatteryDiffEntry(
                 resultDiffData.getSystemDiffEntryList().get(0), currentUserId, /*uid=*/ 3L,
                 ConvertUtils.CONSUMER_TYPE_SYSTEM_BATTERY, /*consumePercentage=*/ 20.0,
-                /*foregroundUsageTimeInMs=*/ 50, /*backgroundUsageTimeInMs=*/ 60);
+                /*foregroundUsageConsumePower=*/ 5, /*foregroundServiceUsageConsumePower=*/ 5,
+                /*backgroundUsageConsumePower=*/ 5, /*cachedUsageConsumePower=*/ 5,
+                /*foregroundUsageTimeInMs=*/ 50, /*foregroundServiceUsageTimeInMs=*/ 50,
+                /*backgroundUsageTimeInMs=*/ 60);
         resultDiffData = resultMap.get(0).get(DataProcessor.SELECTED_INDEX_ALL);
         assertBatteryDiffEntry(
                 resultDiffData.getAppDiffEntryList().get(0), currentUserId, /*uid=*/ 2L,
                 ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*consumePercentage=*/ 100.0,
-                /*foregroundUsageTimeInMs=*/ 15, /*backgroundUsageTimeInMs=*/ 25);
+                /*foregroundUsageConsumePower=*/ 5, /*foregroundServiceUsageConsumePower=*/ 5,
+                /*backgroundUsageConsumePower=*/ 5, /*cachedUsageConsumePower=*/ 5,
+                /*foregroundUsageTimeInMs=*/ 15, /*foregroundServiceUsageTimeInMs=*/ 15,
+                /*backgroundUsageTimeInMs=*/ 25);
         resultDiffData = resultMap.get(1).get(DataProcessor.SELECTED_INDEX_ALL);
         assertBatteryDiffEntry(
                 resultDiffData.getAppDiffEntryList().get(0), currentUserId, /*uid=*/ 4L,
                 ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*consumePercentage=*/ 50.0,
-                /*foregroundUsageTimeInMs=*/ 5, /*backgroundUsageTimeInMs=*/ 5);
+                /*foregroundUsageConsumePower=*/ 8, /*foregroundServiceUsageConsumePower=*/ 8,
+                /*backgroundUsageConsumePower=*/ 8, /*cachedUsageConsumePower=*/ 8,
+                /*foregroundUsageTimeInMs=*/ 5, /*foregroundServiceUsageTimeInMs=*/ 5,
+                /*backgroundUsageTimeInMs=*/ 5);
         assertBatteryDiffEntry(
                 resultDiffData.getAppDiffEntryList().get(1), currentUserId, /*uid=*/ 2L,
                 ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*consumePercentage=*/ 25.0,
-                /*foregroundUsageTimeInMs=*/ 15, /*backgroundUsageTimeInMs=*/ 15);
+                /*foregroundUsageConsumePower=*/ 9, /*foregroundServiceUsageConsumePower=*/ 4,
+                /*backgroundUsageConsumePower=*/ 4, /*cachedUsageConsumePower=*/ 3,
+                /*foregroundUsageTimeInMs=*/ 15, /*foregroundServiceUsageTimeInMs=*/ 15,
+                /*backgroundUsageTimeInMs=*/ 15);
         assertBatteryDiffEntry(
                 resultDiffData.getSystemDiffEntryList().get(0), currentUserId, /*uid=*/ 3L,
                 ConvertUtils.CONSUMER_TYPE_SYSTEM_BATTERY, /*consumePercentage=*/ 25.0,
-                /*foregroundUsageTimeInMs=*/ 50, /*backgroundUsageTimeInMs=*/ 60);
+                /*foregroundUsageConsumePower=*/ 5, /*foregroundServiceUsageConsumePower=*/ 5,
+                /*backgroundUsageConsumePower=*/ 5, /*cachedUsageConsumePower=*/ 5,
+                /*foregroundUsageTimeInMs=*/ 50, /*foregroundServiceUsageTimeInMs=*/ 50,
+                /*backgroundUsageTimeInMs=*/ 60);
         verify(mMetricsFeatureProvider)
                 .action(mContext.getApplicationContext(),
                         SettingsEnums.ACTION_BATTERY_USAGE_SHOWN_APP_COUNT,
@@ -668,55 +716,82 @@
         // Adds the index = 0 data.
         Map<String, BatteryHistEntry> entryMap = new HashMap<>();
         BatteryHistEntry entry = createBatteryHistEntry(
-                "package1", "label1", /*consumePower=*/ 5.0, /*uid=*/ 1L, currentUserId,
+                "package1", "label1", /*consumePower=*/ 5.0,
+                /*foregroundUsageConsumePower=*/ 5, /*foregroundServiceUsageConsumePower=*/ 0,
+                /*backgroundUsageConsumePower=*/ 0, /*cachedUsageConsumePower=*/ 0,
+                /*uid=*/ 1L, currentUserId,
                 ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 10L,
-                /*backgroundUsageTimeInMs=*/ 20L);
+                /*foregroundServiceUsageTimeInMs=*/ 10L, /*backgroundUsageTimeInMs=*/ 20L);
         entryMap.put(entry.getKey(), entry);
         entry = createBatteryHistEntry(
-                "package1", "label1", /*consumePower=*/ 10.0, /*uid=*/ 2L, currentUserId + 1,
+                "package1", "label1", /*consumePower=*/ 10.0,
+                /*foregroundUsageConsumePower=*/ 7, /*foregroundServiceUsageConsumePower=*/ 1,
+                /*backgroundUsageConsumePower=*/ 1, /*cachedUsageConsumePower=*/ 1,
+                /*uid=*/ 2L, currentUserId + 1,
                 ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 10L,
-                /*backgroundUsageTimeInMs=*/ 20L);
+                /*foregroundServiceUsageTimeInMs=*/ 10L, /*backgroundUsageTimeInMs=*/ 20L);
         entryMap.put(entry.getKey(), entry);
         entry = createBatteryHistEntry(
-                "package2", "label2", /*consumePower=*/ 5.0, /*uid=*/ 3L, currentUserId + 2,
+                "package2", "label2", /*consumePower=*/ 5.0,
+                /*foregroundUsageConsumePower=*/ 5, /*foregroundServiceUsageConsumePower=*/ 0,
+                /*backgroundUsageConsumePower=*/ 0, /*cachedUsageConsumePower=*/ 0,
+                /*uid=*/ 3L, currentUserId + 2,
                 ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 20L,
-                /*backgroundUsageTimeInMs=*/ 30L);
+                /*foregroundServiceUsageTimeInMs=*/ 20L, /*backgroundUsageTimeInMs=*/ 30L);
         entryMap.put(entry.getKey(), entry);
         batteryHistoryMap.put(batteryHistoryKeys[0], entryMap);
         // Adds the index = 1 data.
         entryMap = new HashMap<>();
         entry = createBatteryHistEntry(
-                "package1", "label1", /*consumePower=*/ 15.0, /*uid=*/ 1L, currentUserId,
+                "package1", "label1", /*consumePower=*/ 15.0,
+                /*foregroundUsageConsumePower=*/ 9, /*foregroundServiceUsageConsumePower=*/ 2,
+                /*backgroundUsageConsumePower=*/ 2, /*cachedUsageConsumePower=*/ 2,
+                /*uid=*/ 1L, currentUserId,
                 ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 20L,
-                /*backgroundUsageTimeInMs=*/ 30L);
+                /*foregroundServiceUsageTimeInMs=*/ 20L, /*backgroundUsageTimeInMs=*/ 30L);
         entryMap.put(entry.getKey(), entry);
         entry = createBatteryHistEntry(
-                "package1", "label1", /*consumePower=*/ 30.0, /*uid=*/ 2L, currentUserId + 1,
+                "package1", "label1", /*consumePower=*/ 30.0,
+                /*foregroundUsageConsumePower=*/ 20, /*foregroundServiceUsageConsumePower=*/ 6,
+                /*backgroundUsageConsumePower=*/ 2, /*cachedUsageConsumePower=*/ 2,
+                /*uid=*/ 2L, currentUserId + 1,
                 ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 10L,
-                /*backgroundUsageTimeInMs=*/ 20L);
+                /*foregroundServiceUsageTimeInMs=*/ 10L, /*backgroundUsageTimeInMs=*/ 20L);
         entryMap.put(entry.getKey(), entry);
         entry = createBatteryHistEntry(
-                "package2", "label2", /*consumePower=*/ 15.0, /*uid=*/ 3L, currentUserId + 2,
+                "package2", "label2", /*consumePower=*/ 15.0,
+                /*foregroundUsageConsumePower=*/ 10, /*foregroundServiceUsageConsumePower=*/ 5,
+                /*backgroundUsageConsumePower=*/ 0, /*cachedUsageConsumePower=*/ 0,
+                /*uid=*/ 3L, currentUserId + 2,
                 ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 30L,
-                /*backgroundUsageTimeInMs=*/ 30L);
+                /*foregroundServiceUsageTimeInMs=*/ 30L, /*backgroundUsageTimeInMs=*/ 30L);
         entryMap.put(entry.getKey(), entry);
         batteryHistoryMap.put(batteryHistoryKeys[1], entryMap);
         // Adds the index = 2 data.
         entryMap = new HashMap<>();
         entry = createBatteryHistEntry(
-                "package1", "label1", /*consumePower=*/ 25.0, /*uid=*/ 1L, currentUserId,
+                "package1", "label1", /*consumePower=*/ 25.0,
+                /*foregroundUsageConsumePower=*/ 10, /*foregroundServiceUsageConsumePower=*/ 5,
+                /*backgroundUsageConsumePower=*/ 5, /*cachedUsageConsumePower=*/ 5,
+                /*uid=*/ 1L, currentUserId,
                 ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 20L,
-                /*backgroundUsageTimeInMs=*/ 30L);
+                /*foregroundServiceUsageTimeInMs=*/ 25L, /*backgroundUsageTimeInMs=*/ 30L);
         entryMap.put(entry.getKey(), entry);
         entry = createBatteryHistEntry(
-                "package1", "label1", /*consumePower=*/ 50.0, /*uid=*/ 2L, currentUserId + 1,
+                "package1", "label1", /*consumePower=*/ 50.0,
+                /*foregroundUsageConsumePower=*/ 20, /*foregroundServiceUsageConsumePower=*/ 10,
+                /*backgroundUsageConsumePower=*/ 10, /*cachedUsageConsumePower=*/ 10,
+                /*uid=*/ 2L, currentUserId + 1,
                 ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 20L,
-                /*backgroundUsageTimeInMs=*/ 20L);
+                /*foregroundServiceUsageTimeInMs=*/ 25L, /*backgroundUsageTimeInMs=*/ 20L);
         entryMap.put(entry.getKey(), entry);
         entry = createBatteryHistEntry(
-                "package2", "label2", /*consumePower=*/ 25.0, /*uid=*/ 3L, currentUserId + 2,
+                "package2", "label2", /*consumePower=*/ 25.0,
+                /*foregroundUsageConsumePower=*/ 10, /*foregroundServiceUsageConsumePower=*/ 10,
+                /*backgroundUsageConsumePower=*/ 5, /*cachedUsageConsumePower=*/ 0,
+                /*uid=*/ 3L, currentUserId + 2,
                 ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 30L,
-                /*backgroundUsageTimeInMs=*/ 30L);
+                /*foregroundServiceUsageTimeInMs=*/ 35L, /*backgroundUsageTimeInMs=*/ 30L);
         entryMap.put(entry.getKey(), entry);
         batteryHistoryMap.put(batteryHistoryKeys[2], entryMap);
         final List<BatteryLevelData.PeriodBatteryLevelData> hourlyBatteryLevelsPerDay =
@@ -737,11 +812,17 @@
         assertBatteryDiffEntry(
                 resultDiffData.getAppDiffEntryList().get(0), currentUserId, /*uid=*/ 1L,
                 ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*consumePercentage=*/ 25.0,
-                /*foregroundUsageTimeInMs=*/ 10, /*backgroundUsageTimeInMs=*/ 10);
+                /*foregroundUsageConsumePower=*/ 5, /*foregroundServiceUsageConsumePower=*/ 5,
+                /*backgroundUsageConsumePower=*/ 5, /*cachedUsageConsumePower=*/ 5,
+                /*foregroundUsageTimeInMs=*/ 10, /*foregroundServiceUsageTimeInMs=*/ 15,
+                /*backgroundUsageTimeInMs=*/ 10);
         assertBatteryDiffEntry(
                 resultDiffData.getSystemDiffEntryList().get(0), BatteryUtils.UID_OTHER_USERS,
                 /*uid=*/ BatteryUtils.UID_OTHER_USERS, ConvertUtils.CONSUMER_TYPE_UID_BATTERY,
-                /*consumePercentage=*/ 75.0, /*foregroundUsageTimeInMs=*/ 0,
+                /*consumePercentage=*/ 75.0,
+                /*foregroundUsageConsumePower=*/ 0, /*foregroundServiceUsageConsumePower=*/ 0,
+                /*backgroundUsageConsumePower=*/ 0, /*cachedUsageConsumePower=*/ 0,
+                /*foregroundUsageTimeInMs=*/ 0, /*foregroundServiceUsageTimeInMs=*/ 0,
                 /*backgroundUsageTimeInMs=*/ 0);
         assertThat(resultMap.get(0).get(0)).isNotNull();
         assertThat(resultMap.get(0).get(DataProcessor.SELECTED_INDEX_ALL)).isNotNull();
@@ -767,24 +848,34 @@
         // Adds the index = 0 data.
         Map<String, BatteryHistEntry> entryMap = new HashMap<>();
         BatteryHistEntry entry = createBatteryHistEntry(
-                "package1", "label1", /*consumePower=*/ 0, /*uid=*/ 1L, currentUserId,
+                "package1", "label1", /*consumePower=*/ 0,
+                /*foregroundUsageConsumePower=*/ 0, /*foregroundServiceUsageConsumePower=*/ 0,
+                /*backgroundUsageConsumePower=*/ 0, /*cachedUsageConsumePower=*/ 0,
+                /*uid=*/ 1L, currentUserId,
                 ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 0L,
-                /*backgroundUsageTimeInMs=*/ 0L);
+                /*foregroundServiceUsageTimeInMs=*/ 0L, /*backgroundUsageTimeInMs=*/ 0L);
         entryMap.put(entry.getKey(), entry);
         batteryHistoryMap.put(batteryHistoryKeys[0], entryMap);
         // Adds the index = 1 data.
         entryMap = new HashMap<>();
         entry = createBatteryHistEntry(
-                "package1", "label1", /*consumePower=*/ 0, /*uid=*/ 1L, currentUserId,
+                "package1", "label1", /*consumePower=*/ 0,
+                /*foregroundUsageConsumePower=*/ 0, /*foregroundServiceUsageConsumePower=*/ 0,
+                /*backgroundUsageConsumePower=*/ 0, /*cachedUsageConsumePower=*/ 0,
+                /*uid=*/ 1L, currentUserId,
                 ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 0L,
-                /*backgroundUsageTimeInMs=*/ 0L);
+                /*foregroundServiceUsageTimeInMs=*/ 0L, /*backgroundUsageTimeInMs=*/ 0L);
         entryMap.put(entry.getKey(), entry);
         batteryHistoryMap.put(batteryHistoryKeys[1], entryMap);
         // Adds the index = 2 data.
         entryMap = new HashMap<>();
         entry = createBatteryHistEntry(
-                "package1", "label1", /*consumePower=*/ 500.0, /*uid=*/ 1L, currentUserId,
+                "package1", "label1", /*consumePower=*/ 500.0,
+                /*foregroundUsageConsumePower=*/ 200, /*foregroundServiceUsageConsumePower=*/ 100,
+                /*backgroundUsageConsumePower=*/ 100, /*cachedUsageConsumePower=*/ 100,
+                /*uid=*/ 1L, currentUserId,
                 ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 3600000L,
+                /*foregroundServiceUsageTimeInMs=*/ 1800000L,
                 /*backgroundUsageTimeInMs=*/ 7200000L);
         entryMap.put(entry.getKey(), entry);
         batteryHistoryMap.put(batteryHistoryKeys[2], entryMap);
@@ -808,10 +899,20 @@
         final BatteryDiffEntry resultEntry = resultDiffData.getAppDiffEntryList().get(0);
         assertThat(resultEntry.mForegroundUsageTimeInMs)
                 .isEqualTo(Math.round(entry.mForegroundUsageTimeInMs * ratio));
+        assertThat(resultEntry.mForegroundServiceUsageTimeInMs)
+                .isEqualTo(Math.round(entry.mForegroundServiceUsageTimeInMs * ratio));
         assertThat(resultEntry.mBackgroundUsageTimeInMs)
                 .isEqualTo(Math.round(entry.mBackgroundUsageTimeInMs * ratio));
         assertThat(resultEntry.mConsumePower)
                 .isEqualTo(entry.mConsumePower * ratio);
+        assertThat(resultEntry.mForegroundUsageConsumePower)
+                .isEqualTo(entry.mForegroundUsageConsumePower * ratio);
+        assertThat(resultEntry.mForegroundServiceUsageConsumePower)
+                .isEqualTo(entry.mForegroundServiceUsageConsumePower * ratio);
+        assertThat(resultEntry.mBackgroundUsageConsumePower)
+                .isEqualTo(entry.mBackgroundUsageConsumePower * ratio);
+        assertThat(resultEntry.mCachedUsageConsumePower)
+                .isEqualTo(entry.mCachedUsageConsumePower * ratio);
         assertThat(resultMap.get(0).get(0)).isNotNull();
         assertThat(resultMap.get(0).get(DataProcessor.SELECTED_INDEX_ALL)).isNotNull();
         verify(mMetricsFeatureProvider)
@@ -836,40 +937,58 @@
         // Adds the index = 0 data.
         Map<String, BatteryHistEntry> entryMap = new HashMap<>();
         BatteryHistEntry entry = createBatteryHistEntry(
-                "package1", "label1", /*consumePower=*/ 0, /*uid=*/ 1L, currentUserId,
+                "package1", "label1", /*consumePower=*/ 0,
+                /*foregroundUsageConsumePower=*/ 0, /*foregroundServiceUsageConsumePower=*/ 0,
+                /*backgroundUsageConsumePower=*/ 0, /*cachedUsageConsumePower=*/ 0,
+                /*uid=*/ 1L, currentUserId,
                 ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 0L,
-                /*backgroundUsageTimeInMs=*/ 0L);
+                /*foregroundServiceUsageTimeInMs=*/ 0L, /*backgroundUsageTimeInMs=*/ 0L);
         entryMap.put(entry.getKey(), entry);
         entry = createBatteryHistEntry(
-                "package2", "label2", /*consumePower=*/ 0, /*uid=*/ 2L, currentUserId,
+                "package2", "label2", /*consumePower=*/ 0,
+                /*foregroundUsageConsumePower=*/ 0, /*foregroundServiceUsageConsumePower=*/ 0,
+                /*backgroundUsageConsumePower=*/ 0, /*cachedUsageConsumePower=*/ 0,
+                /*uid=*/ 2L, currentUserId,
                 ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 0L,
-                /*backgroundUsageTimeInMs=*/ 0L);
+                /*foregroundServiceUsageTimeInMs=*/ 0L, /*backgroundUsageTimeInMs=*/ 0L);
         entryMap.put(entry.getKey(), entry);
         batteryHistoryMap.put(batteryHistoryKeys[0], entryMap);
         // Adds the index = 1 data.
         entryMap = new HashMap<>();
         entry = createBatteryHistEntry(
-                "package1", "label1", /*consumePower=*/ 0, /*uid=*/ 1L, currentUserId,
+                "package1", "label1", /*consumePower=*/ 0,
+                /*foregroundUsageConsumePower=*/ 0, /*foregroundServiceUsageConsumePower=*/ 0,
+                /*backgroundUsageConsumePower=*/ 0, /*cachedUsageConsumePower=*/ 0,
+                /*uid=*/ 1L, currentUserId,
                 ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 0L,
-                /*backgroundUsageTimeInMs=*/ 0L);
+                /*foregroundServiceUsageTimeInMs=*/ 0L, /*backgroundUsageTimeInMs=*/ 0L);
         entryMap.put(entry.getKey(), entry);
         entry = createBatteryHistEntry(
-                "package2", "label2", /*consumePower=*/ 0, /*uid=*/ 2L, currentUserId,
+                "package2", "label2", /*consumePower=*/ 0,
+                /*foregroundUsageConsumePower=*/ 0, /*foregroundServiceUsageConsumePower=*/ 0,
+                /*backgroundUsageConsumePower=*/ 0, /*cachedUsageConsumePower=*/ 0,
+                /*uid=*/ 2L, currentUserId,
                 ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 0L,
-                /*backgroundUsageTimeInMs=*/ 0L);
+                /*foregroundServiceUsageTimeInMs=*/ 0L, /*backgroundUsageTimeInMs=*/ 0L);
         entryMap.put(entry.getKey(), entry);
         batteryHistoryMap.put(batteryHistoryKeys[1], entryMap);
         // Adds the index = 2 data.
         entryMap = new HashMap<>();
         entry = createBatteryHistEntry(
-                "package1", "label1", /*consumePower=*/ 10.0, /*uid=*/ 1L, currentUserId,
+                "package1", "label1", /*consumePower=*/ 10.0,
+                /*foregroundUsageConsumePower=*/ 5, /*foregroundServiceUsageConsumePower=*/ 5,
+                /*backgroundUsageConsumePower=*/ 0, /*cachedUsageConsumePower=*/ 0,
+                /*uid=*/ 1L, currentUserId,
                 ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 10L,
-                /*backgroundUsageTimeInMs=*/ 20L);
+                /*foregroundServiceUsageTimeInMs=*/ 15L, /*backgroundUsageTimeInMs=*/ 20L);
         entryMap.put(entry.getKey(), entry);
         entry = createBatteryHistEntry(
-                "package2", "label2", /*consumePower=*/ 10.0, /*uid=*/ 2L, currentUserId,
+                "package2", "label2", /*consumePower=*/ 10.0,
+                /*foregroundUsageConsumePower=*/ 0, /*foregroundServiceUsageConsumePower=*/ 0,
+                /*backgroundUsageConsumePower=*/ 5, /*cachedUsageConsumePower=*/ 5,
+                /*uid=*/ 2L, currentUserId,
                 ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 10L,
-                /*backgroundUsageTimeInMs=*/ 20L);
+                /*foregroundServiceUsageTimeInMs=*/ 15L, /*backgroundUsageTimeInMs=*/ 20L);
         entryMap.put(entry.getKey(), entry);
         batteryHistoryMap.put(batteryHistoryKeys[2], entryMap);
         final List<BatteryLevelData.PeriodBatteryLevelData> hourlyBatteryLevelsPerDay =
@@ -892,7 +1011,10 @@
         assertBatteryDiffEntry(
                 resultDiffData.getAppDiffEntryList().get(0), currentUserId, /*uid=*/ 2L,
                 ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*consumePercentage=*/ 50.0,
-                /*foregroundUsageTimeInMs=*/ 10, /*backgroundUsageTimeInMs=*/ 20);
+                /*foregroundUsageConsumePower=*/ 0, /*foregroundServiceUsageConsumePower=*/ 0,
+                /*backgroundUsageConsumePower=*/ 5, /*cachedUsageConsumePower=*/ 5,
+                /*foregroundUsageTimeInMs=*/ 10, /*foregroundServiceUsageTimeInMs=*/ 15,
+                /*backgroundUsageTimeInMs=*/ 20);
         verify(mMetricsFeatureProvider)
                 .action(mContext.getApplicationContext(),
                         SettingsEnums.ACTION_BATTERY_USAGE_SHOWN_APP_COUNT,
@@ -915,40 +1037,58 @@
         // Adds the index = 0 data.
         Map<String, BatteryHistEntry> entryMap = new HashMap<>();
         BatteryHistEntry entry = createBatteryHistEntry(
-                "package1", "label1", /*consumePower=*/ 0, /*uid=*/ 1L, currentUserId,
+                "package1", "label1", /*consumePower=*/ 0,
+                /*foregroundUsageConsumePower=*/ 0, /*foregroundServiceUsageConsumePower=*/ 0,
+                /*backgroundUsageConsumePower=*/ 0, /*cachedUsageConsumePower=*/ 0,
+                /*uid=*/ 1L, currentUserId,
                 ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 0L,
-                /*backgroundUsageTimeInMs=*/ 0L);
+                /*foregroundServiceUsageTimeInMs=*/ 0L, /*backgroundUsageTimeInMs=*/ 0L);
         entryMap.put(entry.getKey(), entry);
         entry = createBatteryHistEntry(
-                "package2", "label2", /*consumePower=*/ 0, /*uid=*/ 2L, currentUserId,
+                "package2", "label2", /*consumePower=*/ 0,
+                /*foregroundUsageConsumePower=*/ 0, /*foregroundServiceUsageConsumePower=*/ 0,
+                /*backgroundUsageConsumePower=*/ 0, /*cachedUsageConsumePower=*/ 0,
+                /*uid=*/ 2L, currentUserId,
                 ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 0L,
-                /*backgroundUsageTimeInMs=*/ 0L);
+                /*foregroundServiceUsageTimeInMs=*/ 0L, /*backgroundUsageTimeInMs=*/ 0L);
         entryMap.put(entry.getKey(), entry);
         batteryHistoryMap.put(batteryHistoryKeys[0], entryMap);
         // Adds the index = 1 data.
         entryMap = new HashMap<>();
         entry = createBatteryHistEntry(
-                "package1", "label1", /*consumePower=*/ 0, /*uid=*/ 1L, currentUserId,
+                "package1", "label1", /*consumePower=*/ 0,
+                /*foregroundUsageConsumePower=*/ 0, /*foregroundServiceUsageConsumePower=*/ 0,
+                /*backgroundUsageConsumePower=*/ 0, /*cachedUsageConsumePower=*/ 0,
+                /*uid=*/ 1L, currentUserId,
                 ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 0L,
-                /*backgroundUsageTimeInMs=*/ 0L);
+                /*foregroundServiceUsageTimeInMs=*/ 0L, /*backgroundUsageTimeInMs=*/ 0L);
         entryMap.put(entry.getKey(), entry);
         entry = createBatteryHistEntry(
-                "package2", "label2", /*consumePower=*/ 0, /*uid=*/ 2L, currentUserId,
+                "package2", "label2", /*consumePower=*/ 0,
+                /*foregroundUsageConsumePower=*/ 0, /*foregroundServiceUsageConsumePower=*/ 0,
+                /*backgroundUsageConsumePower=*/ 0, /*cachedUsageConsumePower=*/ 0,
+                /*uid=*/ 2L, currentUserId,
                 ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 0L,
-                /*backgroundUsageTimeInMs=*/ 0L);
+                /*foregroundServiceUsageTimeInMs=*/ 0L, /*backgroundUsageTimeInMs=*/ 0L);
         entryMap.put(entry.getKey(), entry);
         batteryHistoryMap.put(batteryHistoryKeys[1], entryMap);
         // Adds the index = 2 data.
         entryMap = new HashMap<>();
         entry = createBatteryHistEntry(
-                "package1", "label1", /*consumePower=*/ 10.0, /*uid=*/ 1L, currentUserId,
+                "package1", "label1", /*consumePower=*/ 10.0,
+                /*foregroundUsageConsumePower=*/ 5, /*foregroundServiceUsageConsumePower=*/ 5,
+                /*backgroundUsageConsumePower=*/ 0, /*cachedUsageConsumePower=*/ 0,
+                /*uid=*/ 1L, currentUserId,
                 ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 10L,
-                /*backgroundUsageTimeInMs=*/ 20L);
+                /*foregroundServiceUsageTimeInMs=*/ 15L, /*backgroundUsageTimeInMs=*/ 20L);
         entryMap.put(entry.getKey(), entry);
         entry = createBatteryHistEntry(
-                "package2", "label2", /*consumePower=*/ 10.0, /*uid=*/ 2L, currentUserId,
+                "package2", "label2", /*consumePower=*/ 10.0,
+                /*foregroundUsageConsumePower=*/ 0, /*foregroundServiceUsageConsumePower=*/ 0,
+                /*backgroundUsageConsumePower=*/ 5, /*cachedUsageConsumePower=*/ 5,
+                /*uid=*/ 2L, currentUserId,
                 ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 10L,
-                /*backgroundUsageTimeInMs=*/ 20L);
+                /*foregroundServiceUsageTimeInMs=*/ 15L, /*backgroundUsageTimeInMs=*/ 20L);
         entryMap.put(entry.getKey(), entry);
         batteryHistoryMap.put(batteryHistoryKeys[2], entryMap);
         final List<BatteryLevelData.PeriodBatteryLevelData> hourlyBatteryLevelsPerDay =
@@ -996,22 +1136,42 @@
         batteryEntryList.add(mMockBatteryEntry3);
         batteryEntryList.add(mMockBatteryEntry4);
         doReturn(0.0).when(mMockBatteryEntry1).getConsumedPower();
+        doReturn(0.0).when(mMockBatteryEntry1).getConsumedPowerInForeground();
+        doReturn(0.0).when(mMockBatteryEntry1).getConsumedPowerInForegroundService();
+        doReturn(0.0).when(mMockBatteryEntry1).getConsumedPowerInBackground();
+        doReturn(0.0).when(mMockBatteryEntry1).getConsumedPowerInCached();
         doReturn(30L).when(mMockBatteryEntry1).getTimeInForegroundMs();
+        doReturn(20L).when(mMockBatteryEntry1).getTimeInForegroundServiceMs();
         doReturn(40L).when(mMockBatteryEntry1).getTimeInBackgroundMs();
         doReturn(1).when(mMockBatteryEntry1).getUid();
         doReturn(ConvertUtils.CONSUMER_TYPE_UID_BATTERY).when(mMockBatteryEntry1).getConsumerType();
         doReturn(0.5).when(mMockBatteryEntry2).getConsumedPower();
+        doReturn(0.5).when(mMockBatteryEntry2).getConsumedPowerInForeground();
+        doReturn(0.0).when(mMockBatteryEntry2).getConsumedPowerInForegroundService();
+        doReturn(0.0).when(mMockBatteryEntry2).getConsumedPowerInBackground();
+        doReturn(0.0).when(mMockBatteryEntry2).getConsumedPowerInCached();
         doReturn(20L).when(mMockBatteryEntry2).getTimeInForegroundMs();
+        doReturn(30L).when(mMockBatteryEntry2).getTimeInForegroundServiceMs();
         doReturn(20L).when(mMockBatteryEntry2).getTimeInBackgroundMs();
         doReturn(2).when(mMockBatteryEntry2).getUid();
         doReturn(ConvertUtils.CONSUMER_TYPE_UID_BATTERY).when(mMockBatteryEntry2).getConsumerType();
         doReturn(0.0).when(mMockBatteryEntry3).getConsumedPower();
+        doReturn(0.0).when(mMockBatteryEntry3).getConsumedPowerInForeground();
+        doReturn(0.0).when(mMockBatteryEntry3).getConsumedPowerInForegroundService();
+        doReturn(0.0).when(mMockBatteryEntry3).getConsumedPowerInBackground();
+        doReturn(0.0).when(mMockBatteryEntry3).getConsumedPowerInCached();
         doReturn(0L).when(mMockBatteryEntry3).getTimeInForegroundMs();
+        doReturn(0L).when(mMockBatteryEntry3).getTimeInForegroundServiceMs();
         doReturn(0L).when(mMockBatteryEntry3).getTimeInBackgroundMs();
         doReturn(3).when(mMockBatteryEntry3).getUid();
         doReturn(ConvertUtils.CONSUMER_TYPE_UID_BATTERY).when(mMockBatteryEntry3).getConsumerType();
         doReturn(1.5).when(mMockBatteryEntry4).getConsumedPower();
+        doReturn(0.9).when(mMockBatteryEntry4).getConsumedPowerInForeground();
+        doReturn(0.2).when(mMockBatteryEntry4).getConsumedPowerInForegroundService();
+        doReturn(0.3).when(mMockBatteryEntry4).getConsumedPowerInBackground();
+        doReturn(0.1).when(mMockBatteryEntry4).getConsumedPowerInCached();
         doReturn(10L).when(mMockBatteryEntry4).getTimeInForegroundMs();
+        doReturn(15L).when(mMockBatteryEntry4).getTimeInForegroundServiceMs();
         doReturn(10L).when(mMockBatteryEntry4).getTimeInBackgroundMs();
         doReturn(4).when(mMockBatteryEntry4).getUid();
         doReturn(ConvertUtils.CONSUMER_TYPE_SYSTEM_BATTERY)
@@ -1025,15 +1185,24 @@
         assertBatteryDiffEntry(
                 batteryDiffData.getAppDiffEntryList().get(0), 0, /*uid=*/ 2L,
                 ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*consumePercentage=*/ 25.0,
-                /*foregroundUsageTimeInMs=*/ 20, /*backgroundUsageTimeInMs=*/ 20);
+                /*foregroundUsageConsumePower=*/ 0.5, /*foregroundServiceUsageConsumePower=*/ 0,
+                /*backgroundUsageConsumePower=*/ 0, /*cachedUsageConsumePower=*/ 0,
+                /*foregroundUsageTimeInMs=*/ 20, /*foregroundServiceUsageTimeInMs=*/ 30,
+                /*backgroundUsageTimeInMs=*/ 20);
         assertBatteryDiffEntry(
                 batteryDiffData.getAppDiffEntryList().get(1), 0, /*uid=*/ 1L,
                 ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*consumePercentage=*/ 0.0,
-                /*foregroundUsageTimeInMs=*/ 30, /*backgroundUsageTimeInMs=*/ 40);
+                /*foregroundUsageConsumePower=*/ 0, /*foregroundServiceUsageConsumePower=*/ 0,
+                /*backgroundUsageConsumePower=*/ 0, /*cachedUsageConsumePower=*/ 0,
+                /*foregroundUsageTimeInMs=*/ 30, /*foregroundServiceUsageTimeInMs=*/ 20,
+                /*backgroundUsageTimeInMs=*/ 40);
         assertBatteryDiffEntry(
                 batteryDiffData.getSystemDiffEntryList().get(0), 0, /*uid=*/ 4L,
                 ConvertUtils.CONSUMER_TYPE_SYSTEM_BATTERY, /*consumePercentage=*/ 75.0,
-                /*foregroundUsageTimeInMs=*/ 10, /*backgroundUsageTimeInMs=*/ 10);
+                /*foregroundUsageConsumePower=*/ 0.9, /*foregroundServiceUsageConsumePower=*/ 0.2,
+                /*backgroundUsageConsumePower=*/ 0.3, /*cachedUsageConsumePower=*/ 0.1,
+                /*foregroundUsageTimeInMs=*/ 10, /*foregroundServiceUsageTimeInMs=*/ 15,
+                /*backgroundUsageTimeInMs=*/ 10);
     }
 
     private static Map<Long, Map<String, BatteryHistEntry>> createHistoryMap(
@@ -1068,15 +1237,24 @@
 
     private static BatteryHistEntry createBatteryHistEntry(
             final String packageName, final String appLabel, final double consumePower,
+            final double foregroundUsageConsumePower,
+            final double foregroundServiceUsageConsumePower,
+            final double backgroundUsageConsumePower, final double cachedUsageConsumePower,
             final long uid, final long userId, final int consumerType,
-            final long foregroundUsageTimeInMs, final long backgroundUsageTimeInMs) {
+            final long foregroundUsageTimeInMs, final long foregroundServiceUsageTimeInMs,
+            final long backgroundUsageTimeInMs) {
         // Only insert required fields.
         final BatteryInformation batteryInformation =
                 BatteryInformation
                         .newBuilder()
                         .setAppLabel(appLabel)
                         .setConsumePower(consumePower)
+                        .setForegroundUsageConsumePower(foregroundUsageConsumePower)
+                        .setForegroundServiceUsageConsumePower(foregroundServiceUsageConsumePower)
+                        .setBackgroundUsageConsumePower(backgroundUsageConsumePower)
+                        .setCachedUsageConsumePower(cachedUsageConsumePower)
                         .setForegroundUsageTimeInMs(foregroundUsageTimeInMs)
+                        .setForegroundServiceUsageTimeInMs(foregroundServiceUsageTimeInMs)
                         .setBackgroundUsageTimeInMs(backgroundUsageTimeInMs)
                         .build();
         final ContentValues values = new ContentValues();
@@ -1152,12 +1330,23 @@
     private static void assertBatteryDiffEntry(
             final BatteryDiffEntry entry, final long userId, final long uid,
             final int consumerType, final double consumePercentage,
-            final long foregroundUsageTimeInMs, final long backgroundUsageTimeInMs) {
+            final double foregroundUsageConsumePower,
+            final double foregroundServiceUsageConsumePower,
+            final double backgroundUsageConsumePower, final double cachedUsageConsumePower,
+            final long foregroundUsageTimeInMs, final long foregroundServiceUsageTimeInMs,
+            final long backgroundUsageTimeInMs) {
         assertThat(entry.mBatteryHistEntry.mUserId).isEqualTo(userId);
         assertThat(entry.mBatteryHistEntry.mUid).isEqualTo(uid);
         assertThat(entry.mBatteryHistEntry.mConsumerType).isEqualTo(consumerType);
         assertThat(entry.getPercentOfTotal()).isEqualTo(consumePercentage);
+        assertThat(entry.mForegroundUsageConsumePower).isEqualTo(foregroundUsageConsumePower);
+        assertThat(entry.mForegroundServiceUsageConsumePower)
+                .isEqualTo(foregroundServiceUsageConsumePower);
+        assertThat(entry.mBackgroundUsageConsumePower).isEqualTo(backgroundUsageConsumePower);
+        assertThat(entry.mCachedUsageConsumePower).isEqualTo(cachedUsageConsumePower);
         assertThat(entry.mForegroundUsageTimeInMs).isEqualTo(foregroundUsageTimeInMs);
+        assertThat(entry.mForegroundServiceUsageTimeInMs)
+                .isEqualTo(foregroundServiceUsageTimeInMs);
         assertThat(entry.mBackgroundUsageTimeInMs).isEqualTo(backgroundUsageTimeInMs);
     }
 }
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/DatabaseUtilsTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/DatabaseUtilsTest.java
index d140ec1..0c66267 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/DatabaseUtilsTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/DatabaseUtilsTest.java
@@ -46,7 +46,6 @@
 import org.robolectric.Shadows;
 
 import java.util.ArrayList;
-import java.util.Calendar;
 import java.util.List;
 import java.util.Map;
 
@@ -99,7 +98,8 @@
         doReturn(null).when(mContext).registerReceiver(any(), any());
         assertThat(
                 DatabaseUtils.sendBatteryEntryData(
-                        mContext, /*batteryEntryList=*/ null, mBatteryUsageStats))
+                        mContext, /*batteryEntryList=*/ null, mBatteryUsageStats,
+                        /*isFullChargeStart=*/ false))
                 .isNull();
     }
 
@@ -118,7 +118,8 @@
 
         final List<ContentValues> valuesList =
                 DatabaseUtils.sendBatteryEntryData(
-                        mContext, batteryEntryList, mBatteryUsageStats);
+                        mContext, batteryEntryList, mBatteryUsageStats,
+                        /*isFullChargeStart=*/ false);
 
         assertThat(valuesList).hasSize(2);
         // Verifies the ContentValues content.
@@ -141,7 +142,8 @@
                 DatabaseUtils.sendBatteryEntryData(
                         mContext,
                         new ArrayList<>(),
-                        mBatteryUsageStats);
+                        mBatteryUsageStats,
+                        /*isFullChargeStart=*/ false);
 
         assertThat(valuesList).hasSize(1);
         verifyFakeContentValues(valuesList.get(0));
@@ -159,7 +161,8 @@
                 DatabaseUtils.sendBatteryEntryData(
                         mContext,
                         /*batteryEntryList=*/ null,
-                        mBatteryUsageStats);
+                        mBatteryUsageStats,
+                        /*isFullChargeStart=*/ false);
 
         assertThat(valuesList).hasSize(1);
         verifyFakeContentValues(valuesList.get(0));
@@ -177,7 +180,8 @@
                 DatabaseUtils.sendBatteryEntryData(
                         mContext,
                         /*batteryEntryList=*/ null,
-                        /*batteryUsageStats=*/ null);
+                        /*batteryUsageStats=*/ null,
+                        /*isFullChargeStart=*/ false);
 
         assertThat(valuesList).hasSize(1);
         verifyFakeContentValues(valuesList.get(0));
@@ -258,88 +262,6 @@
         assertThat(batteryHistMap).isEmpty();
     }
 
-    @Test
-    public void saveLastFullChargeTimestampPref_notFullCharge_returnsFalse() {
-        DatabaseUtils.saveLastFullChargeTimestampPref(
-                mContext,
-                BatteryManager.BATTERY_STATUS_UNKNOWN,
-                /* level */ 10,
-                /* timestamp */ 1);
-        assertThat(DatabaseUtils.getLastFullChargeTimestampPref(mContext)).isEqualTo(0);
-    }
-
-    @Test
-    public void saveLastFullChargeTimestampPref_fullStatus_returnsTrue() {
-        long expectedTimestamp = 1;
-        DatabaseUtils.saveLastFullChargeTimestampPref(
-                mContext,
-                BatteryManager.BATTERY_STATUS_FULL,
-                /* level */ 10,
-                /* timestamp */ expectedTimestamp);
-        assertThat(DatabaseUtils.getLastFullChargeTimestampPref(mContext))
-                .isEqualTo(expectedTimestamp);
-    }
-
-    @Test
-    public void saveLastFullChargeTimestampPref_level100_returnsTrue() {
-        long expectedTimestamp = 1;
-        DatabaseUtils.saveLastFullChargeTimestampPref(
-                mContext,
-                BatteryManager.BATTERY_STATUS_UNKNOWN,
-                /* level */ 100,
-                /* timestamp */ expectedTimestamp);
-        assertThat(DatabaseUtils.getLastFullChargeTimestampPref(mContext))
-                .isEqualTo(expectedTimestamp);
-    }
-
-    @Test
-    public void getStartTimestampForLastFullCharge_noTimestampPreference_returnsSixDaysAgo() {
-        Calendar currentCalendar = Calendar.getInstance();
-        currentCalendar.set(2022, 6, 5, 6, 30, 50); // 2022-07-05 06:30:50
-        Calendar expectedCalendar = Calendar.getInstance();
-        expectedCalendar.set(2022, 5, 29, 0, 0, 0); // 2022-06-29 00:00:00
-        expectedCalendar.set(Calendar.MILLISECOND, 0);
-
-        assertThat(DatabaseUtils.getStartTimestampForLastFullCharge(mContext, currentCalendar))
-                .isEqualTo(expectedCalendar.getTimeInMillis());
-    }
-
-    @Test
-    public void getStartTimestampForLastFullCharge_lastFullChargeEarlier_returnsSixDaysAgo() {
-        Calendar lastFullCalendar = Calendar.getInstance();
-        lastFullCalendar.set(2021, 11, 25, 6, 30, 50); // 2021-12-25 06:30:50
-        DatabaseUtils.saveLastFullChargeTimestampPref(
-                mContext,
-                BatteryManager.BATTERY_STATUS_UNKNOWN,
-                /* level */ 100,
-                /* timestamp */ lastFullCalendar.getTimeInMillis());
-        Calendar currentCalendar = Calendar.getInstance();
-        currentCalendar.set(2022, 0, 2, 6, 30, 50); // 2022-01-02 06:30:50
-        Calendar expectedCalendar = Calendar.getInstance();
-        expectedCalendar.set(2021, 11, 27, 0, 0, 0); // 2021-12-27 00:00:00
-        expectedCalendar.set(Calendar.MILLISECOND, 0);
-
-        assertThat(DatabaseUtils.getStartTimestampForLastFullCharge(mContext, currentCalendar))
-                .isEqualTo(expectedCalendar.getTimeInMillis());
-    }
-
-    @Test
-    public void getStartTimestampForLastFullCharge_lastFullChargeLater_returnsLastFullCharge() {
-        Calendar lastFullCalendar = Calendar.getInstance();
-        lastFullCalendar.set(2022, 6, 1, 6, 30, 50); // 2022-07-01 06:30:50
-        long expectedTimestamp = lastFullCalendar.getTimeInMillis();
-        DatabaseUtils.saveLastFullChargeTimestampPref(
-                mContext,
-                BatteryManager.BATTERY_STATUS_UNKNOWN,
-                /* level */ 100,
-                /* timestamp */ expectedTimestamp);
-        Calendar currentCalendar = Calendar.getInstance();
-        currentCalendar.set(2022, 6, 5, 6, 30, 50); // 2022-07-05 06:30:50
-
-        assertThat(DatabaseUtils.getStartTimestampForLastFullCharge(mContext, currentCalendar))
-                .isEqualTo(expectedTimestamp);
-    }
-
     private static void verifyContentValues(double consumedPower, ContentValues values) {
         final BatteryInformation batteryInformation =
                 ConvertUtils.getBatteryInformation(
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/db/BatteryStateDaoTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/db/BatteryStateDaoTest.java
index 5a22763..33735b3 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/db/BatteryStateDaoTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/db/BatteryStateDaoTest.java
@@ -53,10 +53,13 @@
         mContext = ApplicationProvider.getApplicationContext();
         mDatabase = BatteryTestUtils.setUpBatteryStateDatabase(mContext);
         mBatteryStateDao = mDatabase.batteryStateDao();
-        BatteryTestUtils.insertDataToBatteryStateDatabase(mContext, TIMESTAMP3, PACKAGE_NAME3);
-        BatteryTestUtils.insertDataToBatteryStateDatabase(mContext, TIMESTAMP2, PACKAGE_NAME2);
         BatteryTestUtils.insertDataToBatteryStateDatabase(
-                mContext, TIMESTAMP1, PACKAGE_NAME1, /*multiple=*/ true);
+                mContext, TIMESTAMP3, PACKAGE_NAME3);
+        BatteryTestUtils.insertDataToBatteryStateDatabase(
+                mContext, TIMESTAMP2, PACKAGE_NAME2);
+        BatteryTestUtils.insertDataToBatteryStateDatabase(
+                mContext, TIMESTAMP1, PACKAGE_NAME1, /*multiple=*/ true,
+                /*isFullChargeStart=*/ true);
     }
 
     @After
@@ -75,16 +78,26 @@
     }
 
     @Test
-    public void batteryStateDao_getCursorAfter() throws Exception {
-        final Cursor cursor = mBatteryStateDao.getCursorAfter(TIMESTAMP2);
-        assertThat(cursor.getCount()).isEqualTo(2);
-        assertThat(cursor.getColumnCount()).isEqualTo(CURSOR_COLUMN_SIZE);
+    public void batteryStateDao_getCursorSinceLastFullCharge() throws Exception {
+        final Cursor cursor1 = mBatteryStateDao.getCursorSinceLastFullCharge(TIMESTAMP1);
+        assertThat(cursor1.getCount()).isEqualTo(3);
+        assertThat(cursor1.getColumnCount()).isEqualTo(CURSOR_COLUMN_SIZE);
         // Verifies the queried first battery state.
-        cursor.moveToFirst();
-        assertThat(cursor.getString(3 /*packageName*/)).isEqualTo(PACKAGE_NAME3);
+        cursor1.moveToFirst();
+        assertThat(cursor1.getString(3 /*packageName*/)).isEqualTo(PACKAGE_NAME1);
         // Verifies the queried second battery state.
-        cursor.moveToNext();
-        assertThat(cursor.getString(3 /*packageName*/)).isEqualTo(PACKAGE_NAME2);
+        cursor1.moveToNext();
+        assertThat(cursor1.getString(3 /*packageName*/)).isEqualTo(PACKAGE_NAME2);
+        // Verifies the queried third battery state.
+        cursor1.moveToNext();
+        assertThat(cursor1.getString(3 /*packageName*/)).isEqualTo(PACKAGE_NAME3);
+
+        final Cursor cursor2 = mBatteryStateDao.getCursorSinceLastFullCharge(TIMESTAMP3);
+        assertThat(cursor2.getCount()).isEqualTo(1);
+        assertThat(cursor2.getColumnCount()).isEqualTo(CURSOR_COLUMN_SIZE);
+        // Verifies the queried first battery state.
+        cursor2.moveToFirst();
+        assertThat(cursor2.getString(3 /*packageName*/)).isEqualTo(PACKAGE_NAME3);
     }
 
     @Test
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/db/BatteryStateTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/db/BatteryStateTest.java
index 5482065..002e4fd 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/db/BatteryStateTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/db/BatteryStateTest.java
@@ -56,9 +56,14 @@
                         .setAppLabel("Settings")
                         .setTotalPower(100)
                         .setConsumePower(3)
+                        .setForegroundUsageConsumePower(0)
+                        .setForegroundServiceUsageConsumePower(1)
+                        .setBackgroundUsageConsumePower(2)
+                        .setCachedUsageConsumePower(3)
                         .setPercentOfTotal(10)
                         .setDrainType(1)
                         .setForegroundUsageTimeInMs(60000)
+                        .setForegroundServiceUsageTimeInMs(30000)
                         .setBackgroundUsageTimeInMs(10000)
                         .build();
     }
diff --git a/tests/robotests/src/com/android/settings/homepage/SettingsHomepageActivityTest.java b/tests/robotests/src/com/android/settings/homepage/SettingsHomepageActivityTest.java
index 719ce28..60f153c 100644
--- a/tests/robotests/src/com/android/settings/homepage/SettingsHomepageActivityTest.java
+++ b/tests/robotests/src/com/android/settings/homepage/SettingsHomepageActivityTest.java
@@ -20,6 +20,8 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.spy;
@@ -39,9 +41,11 @@
 import com.android.settings.R;
 import com.android.settings.dashboard.suggestions.SuggestionFeatureProviderImpl;
 import com.android.settings.testutils.shadow.ShadowActivityEmbeddingUtils;
+import com.android.settings.testutils.shadow.ShadowPasswordUtils;
 import com.android.settings.testutils.shadow.ShadowUserManager;
 import com.android.settingslib.core.lifecycle.HideNonSystemOverlayMixin;
 
+import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -68,6 +72,11 @@
         MockitoAnnotations.initMocks(this);
     }
 
+    @After
+    public void tearDown() {
+        ShadowPasswordUtils.reset();
+    }
+
     @Test
     public void launch_shouldHaveAnimationForIaFragment() {
         final SettingsHomepageActivity activity = Robolectric.buildActivity(
@@ -205,6 +214,32 @@
         verify(activity).initSplitPairRules();
     }
 
+    @Test
+    @Config(shadows = {ShadowPasswordUtils.class})
+    public void isCallingAppPermitted_emptyPermission_returnTrue() {
+        SettingsHomepageActivity homepageActivity = spy(new SettingsHomepageActivity());
+
+        assertTrue(homepageActivity.isCallingAppPermitted(""));
+    }
+
+    @Test
+    @Config(shadows = {ShadowPasswordUtils.class})
+    public void isCallingAppPermitted_noGrantedPermission_returnFalse() {
+        SettingsHomepageActivity homepageActivity = spy(new SettingsHomepageActivity());
+
+        assertFalse(homepageActivity.isCallingAppPermitted("android.permission.TEST"));
+    }
+
+    @Test
+    @Config(shadows = {ShadowPasswordUtils.class})
+    public void isCallingAppPermitted_grantedPermission_returnTrue() {
+        SettingsHomepageActivity homepageActivity = spy(new SettingsHomepageActivity());
+        String permission = "android.permission.TEST";
+        ShadowPasswordUtils.addGrantedPermission(permission);
+
+        assertTrue(homepageActivity.isCallingAppPermitted(permission));
+    }
+
     @Implements(SuggestionFeatureProviderImpl.class)
     public static class ShadowSuggestionFeatureProviderImpl {
 
diff --git a/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/BluetoothDevicesSliceTest.java b/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/BluetoothDevicesSliceTest.java
index 2d5a0e9..b09fa7d 100644
--- a/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/BluetoothDevicesSliceTest.java
+++ b/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/BluetoothDevicesSliceTest.java
@@ -191,7 +191,7 @@
     public void getSlice_hasAvailableMediaDevice_shouldBuildPrimaryBluetoothAction() {
         mockBluetoothDeviceList(1);
         when(mBluetoothDeviceList.get(0).getDevice().isConnected()).thenReturn(true);
-        doReturn(true).when(mBluetoothDeviceList.get(0)).isConnectedHearingAidDevice();
+        doReturn(true).when(mBluetoothDeviceList.get(0)).isConnectedAshaHearingAidDevice();
         doReturn(mBluetoothDeviceList).when(mBluetoothDevicesSlice).getPairedBluetoothDevices();
 
         mBluetoothDevicesSlice.getSlice();
diff --git a/tests/robotests/src/com/android/settings/network/telephony/AutoDataSwitchPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/network/telephony/AutoDataSwitchPreferenceControllerTest.java
index 758d6b0..32657a4 100644
--- a/tests/robotests/src/com/android/settings/network/telephony/AutoDataSwitchPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/network/telephony/AutoDataSwitchPreferenceControllerTest.java
@@ -28,13 +28,18 @@
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.when;
+import static org.robolectric.Shadows.shadowOf;
 
 import android.content.Context;
+import android.telephony.SubscriptionInfo;
+import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
 
 import androidx.preference.PreferenceScreen;
 import androidx.preference.SwitchPreference;
 
+import com.google.common.collect.ImmutableList;
+
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -56,10 +61,15 @@
     private TelephonyManager mTelephonyManager;
     @Mock
     private PreferenceScreen mPreferenceScreen;
+    @Mock
+    private SubscriptionInfo mSubscriptionInfo1;
+    @Mock
+    private SubscriptionInfo mSubscriptionInfo2;
 
     private Context mContext;
     private SwitchPreference mSwitchPreference;
     private AutoDataSwitchPreferenceController mController;
+    private ShadowSubscriptionManager mShadowSubscriptionManager;
 
     @Before
     public void setUp() {
@@ -69,6 +79,11 @@
         when(mTelephonyManager.createForSubscriptionId(anyInt())).thenReturn(mTelephonyManager);
         mSwitchPreference = new SwitchPreference(mContext);
         when(mPreferenceScreen.findPreference(PREF_KEY)).thenReturn(mSwitchPreference);
+        when(mSubscriptionInfo1.getSubscriptionId()).thenReturn(SUB_ID_1);
+        when(mSubscriptionInfo2.getSubscriptionId()).thenReturn(SUB_ID_2);
+        mShadowSubscriptionManager = shadowOf(mContext.getSystemService(SubscriptionManager.class));
+        mShadowSubscriptionManager.setActiveSubscriptionInfoList(ImmutableList.of(
+                mSubscriptionInfo1, mSubscriptionInfo2));
         mController = new AutoDataSwitchPreferenceController(mContext, PREF_KEY) {
             @Override
             protected boolean hasMobileData() {
@@ -90,18 +105,9 @@
     }
 
     @Test
-    public void displayPreference_defaultForData_notAvailable() {
+    public void displayPreference_defaultForData_available() {
         ShadowSubscriptionManager.setDefaultDataSubscriptionId(SUB_ID_1);
-
-        mController.displayPreference(mPreferenceScreen);
-
-        assertThat(mController.isAvailable()).isFalse();
-        assertThat(mSwitchPreference.isVisible()).isFalse();
-    }
-
-    @Test
-    public void  displayPreference_notDefaultForData_available() {
-        ShadowSubscriptionManager.setDefaultDataSubscriptionId(SUB_ID_2);
+        mController.init(SUB_ID_1);
 
         mController.displayPreference(mPreferenceScreen);
 
@@ -110,23 +116,22 @@
     }
 
     @Test
-    public void onSubscriptionsChanged_becomesDefaultForData_notAvailable() {
+    public void  displayPreference_notDefaultForData_notAvailable() {
         ShadowSubscriptionManager.setDefaultDataSubscriptionId(SUB_ID_2);
 
         mController.displayPreference(mPreferenceScreen);
-        ShadowSubscriptionManager.setDefaultDataSubscriptionId(SUB_ID_1);
-        mController.onSubscriptionsChanged();
 
         assertThat(mController.isAvailable()).isFalse();
         assertThat(mSwitchPreference.isVisible()).isFalse();
     }
 
     @Test
-    public void onSubscriptionsChanged_noLongerDefaultForData_available() {
-        ShadowSubscriptionManager.setDefaultDataSubscriptionId(SUB_ID_1);
+    public void onSubscriptionsChanged_becomesDefaultForData_available() {
+        ShadowSubscriptionManager.setDefaultDataSubscriptionId(SUB_ID_2);
+        mController.init(SUB_ID_1);
 
         mController.displayPreference(mPreferenceScreen);
-        ShadowSubscriptionManager.setDefaultDataSubscriptionId(SUB_ID_2);
+        ShadowSubscriptionManager.setDefaultDataSubscriptionId(SUB_ID_1);
         mController.onSubscriptionsChanged();
 
         assertThat(mController.isAvailable()).isTrue();
@@ -134,22 +139,38 @@
     }
 
     @Test
-    public void getAvailabilityStatus_mobileDataChangWithDefaultDataSubId_returnUnavailable() {
+    public void onSubscriptionsChanged_noLongerDefaultForData_notAvailable() {
         ShadowSubscriptionManager.setDefaultDataSubscriptionId(SUB_ID_1);
+        mController.init(SUB_ID_1);
+
+        mController.displayPreference(mPreferenceScreen);
+        ShadowSubscriptionManager.setDefaultDataSubscriptionId(SUB_ID_2);
+        mController.onSubscriptionsChanged();
+
+        assertThat(mController.isAvailable()).isFalse();
+        assertThat(mSwitchPreference.isVisible()).isFalse();
+    }
+
+    @Test
+    public void getAvailabilityStatus_mobileDataChangWithDefaultDataSubId_returnAvailable() {
+        ShadowSubscriptionManager.setDefaultDataSubscriptionId(SUB_ID_1);
+        mController.init(SUB_ID_1);
 
         mController.refreshPreference();
 
         assertThat(mController.getAvailabilityStatus(SUB_ID_1))
-                .isEqualTo(CONDITIONALLY_UNAVAILABLE);
+                .isEqualTo(AVAILABLE);
     }
 
     @Test
-    public void getAvailabilityStatus_mobileDataChangWithoutDefaultDataSubId_returnAvailable() {
+    public void getAvailabilityStatus_mobileDataChangWithoutDefaultDataSubId_returnUnavailable() {
         ShadowSubscriptionManager.setDefaultDataSubscriptionId(SUB_ID_1);
+        mController.init(SUB_ID_1);
 
         mController.displayPreference(mPreferenceScreen);
         mController.refreshPreference();
 
-        assertThat(mController.getAvailabilityStatus(SUB_ID_2)).isEqualTo(AVAILABLE);
+        assertThat(mController.getAvailabilityStatus(SUB_ID_2)).isEqualTo(
+                CONDITIONALLY_UNAVAILABLE);
     }
 }
diff --git a/tests/robotests/src/com/android/settings/testutils/BatteryTestUtils.java b/tests/robotests/src/com/android/settings/testutils/BatteryTestUtils.java
index 9023cc5..485caef 100644
--- a/tests/robotests/src/com/android/settings/testutils/BatteryTestUtils.java
+++ b/tests/robotests/src/com/android/settings/testutils/BatteryTestUtils.java
@@ -72,12 +72,21 @@
     /** Inserts a fake data into the database for testing. */
     public static void insertDataToBatteryStateDatabase(
             Context context, long timestamp, String packageName) {
-        insertDataToBatteryStateDatabase(context, timestamp, packageName, /*multiple=*/ false);
+        insertDataToBatteryStateDatabase(
+                context, timestamp, packageName, /*multiple=*/ false, /*isFullChargeStart=*/ false);
     }
 
     /** Inserts a fake data into the database for testing. */
     public static void insertDataToBatteryStateDatabase(
-            Context context, long timestamp, String packageName, boolean multiple) {
+            Context context, long timestamp, String packageName, boolean isFullChargeStart) {
+        insertDataToBatteryStateDatabase(
+                context, timestamp, packageName, /*multiple=*/ false, isFullChargeStart);
+    }
+
+    /** Inserts a fake data into the database for testing. */
+    public static void insertDataToBatteryStateDatabase(
+            Context context, long timestamp, String packageName, boolean multiple,
+            boolean isFullChargeStart) {
         DeviceBatteryState deviceBatteryState =
                 DeviceBatteryState
                         .newBuilder()
@@ -113,7 +122,7 @@
                         packageName,
                         timestamp,
                         /*consumerType=*/ 2,
-                        /*isFullChargeCycleStart=*/ false,
+                        isFullChargeStart,
                         ConvertUtils.convertBatteryInformationToString(batteryInformation),
                         "");
         BatteryStateDao dao =
@@ -125,7 +134,7 @@
         }
     }
 
-    private static Intent getCustomBatteryIntent(int plugged, int level, int scale, int status) {
+    public static Intent getCustomBatteryIntent(int plugged, int level, int scale, int status) {
         Intent intent = new Intent();
         intent.putExtra(BatteryManager.EXTRA_PLUGGED, plugged);
         intent.putExtra(BatteryManager.EXTRA_LEVEL, level);
diff --git a/tests/robotests/src/com/android/settings/wifi/p2p/WifiP2pSettingsTest.java b/tests/robotests/src/com/android/settings/wifi/p2p/WifiP2pSettingsTest.java
index 7c88d8f..cbf1aa5 100644
--- a/tests/robotests/src/com/android/settings/wifi/p2p/WifiP2pSettingsTest.java
+++ b/tests/robotests/src/com/android/settings/wifi/p2p/WifiP2pSettingsTest.java
@@ -338,7 +338,7 @@
     public void onStop_notLastGroupFormed_shouldCloseChannel() {
         mFragment.onStop();
 
-        assertThat(mFragment.mChannel).isNull();
+        assertThat(mFragment.sChannel).isNull();
     }
 
     @Test
@@ -355,7 +355,7 @@
         verify(mWifiP2pManager, times(1)).stopPeerDiscovery(any(), any());
 
         mFragment.onStart();
-        assertThat(mFragment.mChannel).isNotNull();
+        assertThat(mFragment.sChannel).isNotNull();
     }
 
     @Test
@@ -526,7 +526,7 @@
 
     @Test
     public void onCreateView_withNullP2pManager_shouldGetP2pManagerAgain() {
-        mFragment.mChannel = null; // Reset channel to re-test onCreateView flow
+        mFragment.sChannel = null; // Reset channel to re-test onCreateView flow
         mFragment.mWifiP2pManager = null;
 
         mFragment.onCreateView(LayoutInflater.from(mContext), null, new Bundle());
@@ -537,7 +537,7 @@
     @Test
     public void onCreateView_withNullChannel_shouldSetP2pManagerNull() {
         doReturn(null).when(mWifiP2pManager).initialize(any(), any(), any());
-        mFragment.mChannel = null; // Reset channel to re-test onCreateView flow
+        mFragment.sChannel = null; // Reset channel to re-test onCreateView flow
         mFragment.onCreateView(LayoutInflater.from(mContext), null, new Bundle());
 
         assertThat(mFragment.mWifiP2pManager).isNull();
diff --git a/tests/spa_unit/src/com/android/settings/spa/app/appinfo/AppAllServicesPreferenceTest.kt b/tests/spa_unit/src/com/android/settings/spa/app/appinfo/AppAllServicesPreferenceTest.kt
index 41f57af..291c9d1 100644
--- a/tests/spa_unit/src/com/android/settings/spa/app/appinfo/AppAllServicesPreferenceTest.kt
+++ b/tests/spa_unit/src/com/android/settings/spa/app/appinfo/AppAllServicesPreferenceTest.kt
@@ -63,8 +63,7 @@
 
 @RunWith(AndroidJUnit4::class)
 class AppAllServicesPreferenceTest {
-    @JvmField
-    @Rule
+    @get:Rule
     val mockito: MockitoRule = MockitoJUnit.rule()
 
     @get:Rule
diff --git a/tests/spa_unit/src/com/android/settings/spa/app/appinfo/AppButtonRepositoryTest.kt b/tests/spa_unit/src/com/android/settings/spa/app/appinfo/AppButtonRepositoryTest.kt
index 4e1b1b6..49b60fb 100644
--- a/tests/spa_unit/src/com/android/settings/spa/app/appinfo/AppButtonRepositoryTest.kt
+++ b/tests/spa_unit/src/com/android/settings/spa/app/appinfo/AppButtonRepositoryTest.kt
@@ -40,8 +40,7 @@
 @RunWith(AndroidJUnit4::class)
 class AppButtonRepositoryTest {
 
-    @JvmField
-    @Rule
+    @get:Rule
     val mockito: MockitoRule = MockitoJUnit.rule()
 
     @Spy
diff --git a/tests/spa_unit/src/com/android/settings/spa/app/appinfo/AppButtonsTest.kt b/tests/spa_unit/src/com/android/settings/spa/app/appinfo/AppButtonsTest.kt
index 0ca4f67..8faf5c9 100644
--- a/tests/spa_unit/src/com/android/settings/spa/app/appinfo/AppButtonsTest.kt
+++ b/tests/spa_unit/src/com/android/settings/spa/app/appinfo/AppButtonsTest.kt
@@ -18,12 +18,8 @@
 
 import android.content.Context
 import android.content.pm.ApplicationInfo
-import android.content.pm.ModuleInfo
 import android.content.pm.PackageInfo
 import android.content.pm.PackageManager
-import android.content.pm.PackageManager.NameNotFoundException
-import androidx.compose.runtime.LaunchedEffect
-import androidx.compose.runtime.rememberCoroutineScope
 import androidx.compose.ui.test.assertIsDisplayed
 import androidx.compose.ui.test.assertIsNotDisplayed
 import androidx.compose.ui.test.junit4.createComposeRule
@@ -33,16 +29,13 @@
 import com.android.dx.mockito.inline.extended.ExtendedMockito
 import com.android.settingslib.applications.AppUtils
 import com.android.settingslib.spa.testutils.delay
-import kotlinx.coroutines.flow.flowOf
-import kotlinx.coroutines.flow.stateIn
+import kotlinx.coroutines.flow.MutableStateFlow
 import org.junit.After
 import org.junit.Before
 import org.junit.Rule
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.mockito.Mock
-import org.mockito.Mockito.doReturn
-import org.mockito.Mockito.doThrow
 import org.mockito.MockitoSession
 import org.mockito.Spy
 import org.mockito.quality.Strictness
@@ -74,7 +67,6 @@
         whenever(packageInfoPresenter.context).thenReturn(context)
         whenever(packageInfoPresenter.packageName).thenReturn(PACKAGE_NAME)
         whenever(packageInfoPresenter.userPackageManager).thenReturn(packageManager)
-        doThrow(NameNotFoundException()).`when`(packageManager).getModuleInfo(PACKAGE_NAME, 0)
         whenever(packageManager.getPackageInfo(PACKAGE_NAME, 0)).thenReturn(PACKAGE_INFO)
         whenever(AppUtils.isMainlineModule(packageManager, PACKAGE_NAME)).thenReturn(false)
     }
@@ -85,15 +77,6 @@
     }
 
     @Test
-    fun isSystemModule_notDisplayed() {
-        doReturn(ModuleInfo()).`when`(packageManager).getModuleInfo(PACKAGE_NAME, 0)
-
-        setContent()
-
-        composeTestRule.onRoot().assertIsNotDisplayed()
-    }
-
-    @Test
     fun isMainlineModule_notDisplayed() {
         whenever(AppUtils.isMainlineModule(packageManager, PACKAGE_NAME)).thenReturn(true)
 
@@ -110,12 +93,8 @@
     }
 
     private fun setContent() {
+        whenever(packageInfoPresenter.flow).thenReturn(MutableStateFlow(PACKAGE_INFO))
         composeTestRule.setContent {
-            val scope = rememberCoroutineScope()
-            LaunchedEffect(Unit) {
-                whenever(packageInfoPresenter.flow).thenReturn(flowOf(PACKAGE_INFO).stateIn(scope))
-            }
-
             AppButtons(packageInfoPresenter)
         }
 
diff --git a/tests/spa_unit/src/com/android/settings/spa/app/appinfo/AppOpenByDefaultPreferenceTest.kt b/tests/spa_unit/src/com/android/settings/spa/app/appinfo/AppOpenByDefaultPreferenceTest.kt
index a402a02..05a6753 100644
--- a/tests/spa_unit/src/com/android/settings/spa/app/appinfo/AppOpenByDefaultPreferenceTest.kt
+++ b/tests/spa_unit/src/com/android/settings/spa/app/appinfo/AppOpenByDefaultPreferenceTest.kt
@@ -35,6 +35,7 @@
 import androidx.test.core.app.ApplicationProvider
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import com.android.settings.R
+import com.android.settings.testutils.mockAsUser
 import com.android.settingslib.spaprivileged.framework.common.domainVerificationManager
 import org.junit.Before
 import org.junit.Rule
@@ -51,8 +52,7 @@
 
 @RunWith(AndroidJUnit4::class)
 class AppOpenByDefaultPreferenceTest {
-    @JvmField
-    @Rule
+    @get:Rule
     val mockito: MockitoRule = MockitoJUnit.rule()
 
     @get:Rule
@@ -76,7 +76,7 @@
     @Before
     fun setUp() {
         whenever(context.packageManager).thenReturn(packageManager)
-        doReturn(context).`when`(context).createContextAsUser(any(), anyInt())
+        context.mockAsUser()
         whenever(context.domainVerificationManager).thenReturn(domainVerificationManager)
         whenever(allowedUserState.isLinkHandlingAllowed).thenReturn(true)
         whenever(notAllowedUserState.isLinkHandlingAllowed).thenReturn(false)
diff --git a/tests/spa_unit/src/com/android/settings/spa/app/appinfo/AppSettingsPreferenceTest.kt b/tests/spa_unit/src/com/android/settings/spa/app/appinfo/AppSettingsPreferenceTest.kt
index 7c6dfce..d39555a 100644
--- a/tests/spa_unit/src/com/android/settings/spa/app/appinfo/AppSettingsPreferenceTest.kt
+++ b/tests/spa_unit/src/com/android/settings/spa/app/appinfo/AppSettingsPreferenceTest.kt
@@ -56,8 +56,7 @@
 
 @RunWith(AndroidJUnit4::class)
 class AppSettingsPreferenceTest {
-    @JvmField
-    @Rule
+    @get:Rule
     val mockito: MockitoRule = MockitoJUnit.rule()
 
     @get:Rule
diff --git a/tests/spa_unit/src/com/android/settings/spa/app/appinfo/AppStoragePreferenceTest.kt b/tests/spa_unit/src/com/android/settings/spa/app/appinfo/AppStoragePreferenceTest.kt
index 47f553b..4754bb2 100644
--- a/tests/spa_unit/src/com/android/settings/spa/app/appinfo/AppStoragePreferenceTest.kt
+++ b/tests/spa_unit/src/com/android/settings/spa/app/appinfo/AppStoragePreferenceTest.kt
@@ -24,12 +24,14 @@
 import androidx.compose.ui.platform.LocalContext
 import androidx.compose.ui.test.assertIsDisplayed
 import androidx.compose.ui.test.assertIsNotDisplayed
+import androidx.compose.ui.test.hasText
 import androidx.compose.ui.test.junit4.createComposeRule
 import androidx.compose.ui.test.onNodeWithText
 import androidx.compose.ui.test.onRoot
 import androidx.test.core.app.ApplicationProvider
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import com.android.settings.R
+import com.android.settingslib.spa.testutils.waitUntilExists
 import com.android.settingslib.spaprivileged.framework.common.storageStatsManager
 import java.util.UUID
 import org.junit.Before
@@ -46,8 +48,7 @@
 
 @RunWith(AndroidJUnit4::class)
 class AppStoragePreferenceTest {
-    @JvmField
-    @Rule
+    @get:Rule
     val mockito: MockitoRule = MockitoJUnit.rule()
 
     @get:Rule
@@ -71,11 +72,7 @@
     fun notInstalledApp_notDisplayed() {
         val notInstalledApp = ApplicationInfo()
 
-        composeTestRule.setContent {
-            CompositionLocalProvider(LocalContext provides context) {
-                AppStoragePreference(notInstalledApp)
-            }
-        }
+        setContent(notInstalledApp)
 
         composeTestRule.onRoot().assertIsNotDisplayed()
     }
@@ -88,15 +85,11 @@
             storageUuid = STORAGE_UUID
         }
 
-        composeTestRule.setContent {
-            CompositionLocalProvider(LocalContext provides context) {
-                AppStoragePreference(internalApp)
-            }
-        }
+        setContent(internalApp)
 
         composeTestRule.onNodeWithText(context.getString(R.string.storage_settings_for_app))
             .assertIsDisplayed()
-        composeTestRule.onNodeWithText("123 B used in internal storage").assertIsDisplayed()
+        composeTestRule.waitUntilExists(hasText("123 B used in internal storage"))
     }
 
     @Test
@@ -107,15 +100,19 @@
             storageUuid = STORAGE_UUID
         }
 
-        composeTestRule.setContent {
-            CompositionLocalProvider(LocalContext provides context) {
-                AppStoragePreference(externalApp)
-            }
-        }
+        setContent(externalApp)
 
         composeTestRule.onNodeWithText(context.getString(R.string.storage_settings_for_app))
             .assertIsDisplayed()
-        composeTestRule.onNodeWithText("123 B used in external storage").assertIsDisplayed()
+        composeTestRule.waitUntilExists(hasText("123 B used in external storage"))
+    }
+
+    private fun setContent(app: ApplicationInfo) {
+        composeTestRule.setContent {
+            CompositionLocalProvider(LocalContext provides context) {
+                AppStoragePreference(app)
+            }
+        }
     }
 
     companion object {
diff --git a/tests/spa_unit/src/com/android/settings/spa/app/appinfo/AppTimeSpentPreferenceTest.kt b/tests/spa_unit/src/com/android/settings/spa/app/appinfo/AppTimeSpentPreferenceTest.kt
index b2ff4f2..6cc3e3c 100644
--- a/tests/spa_unit/src/com/android/settings/spa/app/appinfo/AppTimeSpentPreferenceTest.kt
+++ b/tests/spa_unit/src/com/android/settings/spa/app/appinfo/AppTimeSpentPreferenceTest.kt
@@ -49,8 +49,7 @@
 
 @RunWith(AndroidJUnit4::class)
 class AppTimeSpentPreferenceTest {
-    @JvmField
-    @Rule
+    @get:Rule
     val mockito: MockitoRule = MockitoJUnit.rule()
 
     @get:Rule
diff --git a/tests/spa_unit/src/com/android/settings/spa/app/appinfo/DefaultAppShortcutPreferenceTest.kt b/tests/spa_unit/src/com/android/settings/spa/app/appinfo/DefaultAppShortcutPreferenceTest.kt
index d5f7241..5c24559 100644
--- a/tests/spa_unit/src/com/android/settings/spa/app/appinfo/DefaultAppShortcutPreferenceTest.kt
+++ b/tests/spa_unit/src/com/android/settings/spa/app/appinfo/DefaultAppShortcutPreferenceTest.kt
@@ -55,8 +55,7 @@
 
 @RunWith(AndroidJUnit4::class)
 class DefaultAppShortcutPreferenceTest {
-    @JvmField
-    @Rule
+    @get:Rule
     val mockito: MockitoRule = MockitoJUnit.rule()
 
     @get:Rule
diff --git a/tests/spa_unit/src/com/android/settings/spa/app/appinfo/HibernationSwitchPreferenceTest.kt b/tests/spa_unit/src/com/android/settings/spa/app/appinfo/HibernationSwitchPreferenceTest.kt
index 688ef86..6acdcf5 100644
--- a/tests/spa_unit/src/com/android/settings/spa/app/appinfo/HibernationSwitchPreferenceTest.kt
+++ b/tests/spa_unit/src/com/android/settings/spa/app/appinfo/HibernationSwitchPreferenceTest.kt
@@ -49,6 +49,7 @@
 import com.android.settings.Utils.PROPERTY_APP_HIBERNATION_ENABLED
 import com.android.settings.Utils.PROPERTY_HIBERNATION_TARGETS_PRE_S_APPS
 import com.android.settings.testutils.TestDeviceConfig
+import com.android.settings.testutils.mockAsUser
 import com.android.settingslib.spaprivileged.framework.common.appHibernationManager
 import com.android.settingslib.spaprivileged.framework.common.appOpsManager
 import com.android.settingslib.spaprivileged.framework.common.permissionControllerManager
@@ -75,8 +76,7 @@
 @RunWith(AndroidJUnit4::class)
 class HibernationSwitchPreferenceTest {
 
-    @JvmField
-    @Rule
+    @get:Rule
     val mockito: MockitoRule = MockitoJUnit.rule()
 
     @get:Rule
@@ -104,8 +104,7 @@
     fun setUp() {
         hibernationEnabledConfig.override(true)
         hibernationTargetsPreSConfig.override(false)
-        doReturn(context)
-            .`when`(context).createContextAsUser(UserHandle.getUserHandleForUid(UID), 0)
+        context.mockAsUser()
         whenever(context.permissionControllerManager).thenReturn(permissionControllerManager)
         whenever(context.appOpsManager).thenReturn(appOpsManager)
         whenever(context.appHibernationManager).thenReturn(appHibernationManager)
diff --git a/tests/spa_unit/src/com/android/settings/spa/app/appinfo/PackageInfoPresenterTest.kt b/tests/spa_unit/src/com/android/settings/spa/app/appinfo/PackageInfoPresenterTest.kt
new file mode 100644
index 0000000..3bfa90e
--- /dev/null
+++ b/tests/spa_unit/src/com/android/settings/spa/app/appinfo/PackageInfoPresenterTest.kt
@@ -0,0 +1,168 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.spa.app.appinfo
+
+import android.app.ActivityManager
+import android.app.settings.SettingsEnums
+import android.content.Context
+import android.content.Intent
+import android.content.pm.PackageManager
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.settings.testutils.FakeFeatureFactory
+import com.android.settings.testutils.mockAsUser
+import com.android.settingslib.spaprivileged.framework.common.activityManager
+import com.android.settingslib.spaprivileged.model.app.IPackageManagers
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.coroutineScope
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.ArgumentCaptor
+import org.mockito.Mock
+import org.mockito.Mockito.any
+import org.mockito.Mockito.doNothing
+import org.mockito.Mockito.verify
+import org.mockito.Spy
+import org.mockito.junit.MockitoJUnit
+import org.mockito.junit.MockitoRule
+import org.mockito.Mockito.`when` as whenever
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@RunWith(AndroidJUnit4::class)
+class PackageInfoPresenterTest {
+    @get:Rule
+    val mockito: MockitoRule = MockitoJUnit.rule()
+
+    @Spy
+    private val context: Context = ApplicationProvider.getApplicationContext()
+
+    @Mock
+    private lateinit var packageManager: PackageManager
+
+    @Mock
+    private lateinit var activityManager: ActivityManager
+
+    @Mock
+    private lateinit var packageManagers: IPackageManagers
+
+    private val fakeFeatureFactory = FakeFeatureFactory()
+    private val metricsFeatureProvider = fakeFeatureFactory.metricsFeatureProvider
+
+    @Before
+    fun setUp() {
+        context.mockAsUser()
+        whenever(context.packageManager).thenReturn(packageManager)
+        whenever(context.activityManager).thenReturn(activityManager)
+    }
+
+    @Test
+    fun enable() = runTest {
+        coroutineScope {
+            val packageInfoPresenter =
+                PackageInfoPresenter(context, PACKAGE_NAME, USER_ID, this, packageManagers)
+
+            packageInfoPresenter.enable()
+        }
+
+        verifyAction(SettingsEnums.ACTION_SETTINGS_ENABLE_APP)
+        verify(packageManager).setApplicationEnabledSetting(
+            PACKAGE_NAME, PackageManager.COMPONENT_ENABLED_STATE_DEFAULT, 0
+        )
+    }
+
+    @Test
+    fun disable() = runTest {
+        coroutineScope {
+            val packageInfoPresenter =
+                PackageInfoPresenter(context, PACKAGE_NAME, USER_ID, this, packageManagers)
+
+            packageInfoPresenter.disable()
+        }
+
+        verifyAction(SettingsEnums.ACTION_SETTINGS_DISABLE_APP)
+        verify(packageManager).setApplicationEnabledSetting(
+            PACKAGE_NAME, PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER, 0
+        )
+    }
+
+    @Test
+    fun startUninstallActivity() = runTest {
+        doNothing().`when`(context).startActivityAsUser(any(), any())
+        val packageInfoPresenter =
+            PackageInfoPresenter(context, PACKAGE_NAME, USER_ID, this, packageManagers)
+
+        packageInfoPresenter.startUninstallActivity()
+
+        verifyAction(SettingsEnums.ACTION_SETTINGS_UNINSTALL_APP)
+        val intentCaptor = ArgumentCaptor.forClass(Intent::class.java)
+        verify(context).startActivityAsUser(intentCaptor.capture(), any())
+        with(intentCaptor.value) {
+            assertThat(action).isEqualTo(Intent.ACTION_UNINSTALL_PACKAGE)
+            assertThat(data?.schemeSpecificPart).isEqualTo(PACKAGE_NAME)
+            assertThat(getBooleanExtra(Intent.EXTRA_UNINSTALL_ALL_USERS, true)).isEqualTo(false)
+        }
+    }
+
+    @Test
+    fun clearInstantApp() = runTest {
+        coroutineScope {
+            val packageInfoPresenter =
+                PackageInfoPresenter(context, PACKAGE_NAME, USER_ID, this, packageManagers)
+
+            packageInfoPresenter.clearInstantApp()
+        }
+
+        verifyAction(SettingsEnums.ACTION_SETTINGS_CLEAR_INSTANT_APP)
+        verify(packageManager).deletePackageAsUser(PACKAGE_NAME, null, 0, USER_ID)
+    }
+
+    @Test
+    fun forceStop() = runTest {
+        coroutineScope {
+            val packageInfoPresenter =
+                PackageInfoPresenter(context, PACKAGE_NAME, USER_ID, this, packageManagers)
+
+            packageInfoPresenter.forceStop()
+        }
+
+        verifyAction(SettingsEnums.ACTION_APP_FORCE_STOP)
+        verify(activityManager).forceStopPackageAsUser(PACKAGE_NAME, USER_ID)
+    }
+
+    @Test
+    fun logAction() = runTest {
+        val packageInfoPresenter =
+            PackageInfoPresenter(context, PACKAGE_NAME, USER_ID, this, packageManagers)
+
+        packageInfoPresenter.logAction(123)
+
+        verifyAction(123)
+    }
+
+    private fun verifyAction(category: Int) {
+        verify(metricsFeatureProvider).action(context, category, PACKAGE_NAME)
+    }
+
+    private companion object {
+        const val PACKAGE_NAME = "package.name"
+        const val USER_ID = 0
+    }
+}
diff --git a/tests/spa_unit/src/com/android/settings/testutils/ContextTestUtil.kt b/tests/spa_unit/src/com/android/settings/testutils/ContextTestUtil.kt
new file mode 100644
index 0000000..43b7a20
--- /dev/null
+++ b/tests/spa_unit/src/com/android/settings/testutils/ContextTestUtil.kt
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.testutils
+
+import android.content.Context
+import org.mockito.Mockito.any
+import org.mockito.Mockito.doReturn
+import org.mockito.Mockito.eq
+
+fun Context.mockAsUser() {
+    doReturn(this).`when`(this).createContextAsUser(any(), eq(0))
+}
diff --git a/tests/unit/src/com/android/settings/development/PhantomProcessPreferenceControllerTest.java b/tests/unit/src/com/android/settings/development/PhantomProcessPreferenceControllerTest.java
new file mode 100644
index 0000000..7ebde1b
--- /dev/null
+++ b/tests/unit/src/com/android/settings/development/PhantomProcessPreferenceControllerTest.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.development;
+
+import static android.util.FeatureFlagUtils.SETTINGS_ENABLE_MONITOR_PHANTOM_PROCS;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.content.Context;
+import android.os.Looper;
+import android.util.FeatureFlagUtils;
+
+import androidx.preference.PreferenceManager;
+import androidx.preference.PreferenceScreen;
+import androidx.preference.SwitchPreference;
+import androidx.test.core.app.ApplicationProvider;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class PhantomProcessPreferenceControllerTest {
+
+    private Context mContext;
+    private PhantomProcessPreferenceController mController;
+    private SwitchPreference mPreference;
+
+    @Before
+    public void setUp() {
+        mContext = ApplicationProvider.getApplicationContext();
+        mController = new PhantomProcessPreferenceController(mContext);
+        if (Looper.myLooper() == null) {
+            Looper.prepare();
+        }
+
+        final PreferenceManager preferenceManager = new PreferenceManager(mContext);
+        final PreferenceScreen screen = preferenceManager.createPreferenceScreen(mContext);
+        mPreference = new SwitchPreference(mContext);
+        mPreference.setKey(mController.getPreferenceKey());
+        screen.addPreference(mPreference);
+        mController.displayPreference(screen);
+    }
+
+    @Test
+    public void onPreferenceChanged_settingDisabled_shouldNotDisablePhantomProcessMonitor() {
+        mController.onPreferenceChange(mPreference, false /* new value */);
+
+        final boolean mode = !FeatureFlagUtils.isEnabled(mContext,
+                SETTINGS_ENABLE_MONITOR_PHANTOM_PROCS);
+
+        assertThat(mode).isFalse();
+    }
+
+    @Test
+    public void onPreferenceChanged_settingEnabled_shouldDisablePhantomProcessMonitor() {
+        mController.onPreferenceChange(mPreference, true /* new value */);
+
+        final boolean mode = !FeatureFlagUtils.isEnabled(mContext,
+                SETTINGS_ENABLE_MONITOR_PHANTOM_PROCS);
+
+        assertThat(mode).isTrue();
+    }
+
+    @Test
+    public void updateState_settingEnabled_preferenceShouldBeChecked() {
+        FeatureFlagUtils.setEnabled(mContext, SETTINGS_ENABLE_MONITOR_PHANTOM_PROCS, false);
+
+        mController.updateState(mPreference);
+        assertThat(mPreference.isChecked()).isTrue();
+    }
+
+    @Test
+    public void updateState_settingDisabled_preferenceShouldNotBeChecked() {
+        FeatureFlagUtils.setEnabled(mContext, SETTINGS_ENABLE_MONITOR_PHANTOM_PROCS, true);
+
+        mController.updateState(mPreference);
+        assertThat(mPreference.isChecked()).isFalse();
+    }
+
+    @Test
+    public void onDeveloperOptionsDisabled_shouldDisablePreference() {
+        mController.onDeveloperOptionsSwitchDisabled();
+        final boolean mode = !FeatureFlagUtils.isEnabled(mContext,
+                SETTINGS_ENABLE_MONITOR_PHANTOM_PROCS);
+
+        mController.updateState(mPreference);
+
+        assertThat(mode).isFalse();
+        assertThat(mPreference.isChecked()).isFalse();
+    }
+}