Merge "Add page id enum for storage settings"
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 82d23aa..34289dd 100644
--- a/src/com/android/settings/accessibility/AccessibilityHearingAidPreferenceController.java
+++ b/src/com/android/settings/accessibility/AccessibilityHearingAidPreferenceController.java
@@ -44,6 +44,7 @@
 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;
@@ -170,10 +171,13 @@
         }
 
         final int side = device.getDeviceSide();
-        if (side == HearingAidProfile.DeviceSide.SIDE_LEFT) {
+        if (side == HearingAidInfo.DeviceSide.SIDE_LEFT_AND_RIGHT) {
+            return mContext.getString(
+                    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 == HearingAidProfile.DeviceSide.SIDE_RIGHT) {
+        } else if (side == HearingAidInfo.DeviceSide.SIDE_RIGHT) {
             return mContext.getString(
                     R.string.accessibility_hearingaid_right_side_device_summary, name);
         }
diff --git a/src/com/android/settings/accessibility/HearingAidUtils.java b/src/com/android/settings/accessibility/HearingAidUtils.java
index 85861ce..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 {
@@ -41,7 +41,7 @@
     public static void launchHearingAidPairingDialog(FragmentManager fragmentManager,
             @NonNull CachedBluetoothDevice device) {
         if (device.isConnectedAshaHearingAidDevice()
-                && device.getDeviceMode() == HearingAidProfile.DeviceMode.MODE_BINAURAL
+                && 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/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/BluetoothDetailsPairOtherController.java b/src/com/android/settings/bluetooth/BluetoothDetailsPairOtherController.java
index f1227fb..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,7 +103,7 @@
     }
 
     private boolean isBinauralMode(CachedBluetoothDevice cachedDevice) {
-        return cachedDevice.getDeviceMode() == HearingAidProfile.DeviceMode.MODE_BINAURAL;
+        return cachedDevice.getDeviceMode() == HearingAidInfo.DeviceMode.MODE_BINAURAL;
     }
 
     private boolean isOnlyOneSideConnected(CachedBluetoothDevice cachedDevice) {
diff --git a/src/com/android/settings/bluetooth/HearingAidPairingDialogFragment.java b/src/com/android/settings/bluetooth/HearingAidPairingDialogFragment.java
index 8bd926a..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;
 
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/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..cfa537b 100644
--- a/src/com/android/settings/fuelgauge/BatteryInfo.java
+++ b/src/com/android/settings/fuelgauge/BatteryInfo.java
@@ -42,6 +42,8 @@
 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/ConvertUtils.java b/src/com/android/settings/fuelgauge/batteryusage/ConvertUtils.java
index ec6e812..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";
 
@@ -198,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(
@@ -387,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 4b46801..fdcbb4a 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/DatabaseUtils.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/DatabaseUtils.java
@@ -36,6 +36,7 @@
 
 import com.android.settings.fuelgauge.BatteryUtils;
 import com.android.settings.fuelgauge.batteryusage.db.BatteryStateDatabase;
+import com.android.settingslib.fuelgauge.BatteryStatus;
 
 import java.time.Clock;
 import java.time.Duration;
@@ -149,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(
@@ -164,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(
@@ -263,6 +269,11 @@
                 }
                 batteryHistEntryMap.put(key, entry);
             }
+            try {
+                cursor.close();
+            } catch (Exception e) {
+                Log.e(TAG, "cursor.close() failed", e);
+            }
         }
         return resultMap;
     }
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/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 3331a69..90e5a6b 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 6de25fc..62d09e1 100644
--- a/tests/robotests/src/com/android/settings/accessibility/AccessibilityHearingAidPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/accessibility/AccessibilityHearingAidPreferenceControllerTest.java
@@ -46,6 +46,7 @@
 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;
@@ -124,7 +125,7 @@
     @Test
     public void getSummary_connectedAshaHearingAidRightSide_connectedRightSideSummary() {
         when(mCachedBluetoothDevice.getDeviceSide()).thenReturn(
-                HearingAidProfile.DeviceSide.SIDE_RIGHT);
+                HearingAidInfo.DeviceSide.SIDE_RIGHT);
         when(mHearingAidProfile.getConnectedDevices()).thenReturn(generateHearingAidDeviceList());
 
         mPreferenceController.onStart();
@@ -139,7 +140,7 @@
     @Test
     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());
@@ -154,9 +155,9 @@
     }
 
     @Test
-    public void getSummary_connectedLeAudioHearingAidOneSide_connectedOneSideSummary() {
+    public void getSummary_connectedLeAudioHearingAidLeftSide_connectedLeftSideSummary() {
         when(mCachedBluetoothDevice.getDeviceSide()).thenReturn(
-                HearingAidProfile.DeviceSide.SIDE_INVALID);
+                HearingAidInfo.DeviceSide.SIDE_LEFT);
         when(mCachedBluetoothDevice.getMemberDevice()).thenReturn(new HashSet<>());
         when(mHapClientProfile.getConnectedDevices()).thenReturn(generateHearingAidDeviceList());
 
@@ -166,7 +167,39 @@
         sendIntent(intent);
 
         assertThat(mHearingAidPreference.getSummary().toString().contentEquals(
-                "TEST_HEARING_AID_BT_DEVICE_NAME active")).isTrue();
+                "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
@@ -187,7 +220,7 @@
     @Test
     public void getSummary_connectedMultipleHearingAids_connectedMultipleDevicesSummary() {
         when(mCachedBluetoothDevice.getDeviceSide()).thenReturn(
-                HearingAidProfile.DeviceSide.SIDE_LEFT);
+                HearingAidInfo.DeviceSide.SIDE_LEFT);
         when(mHearingAidProfile.getConnectedDevices()).thenReturn(
                 generateMultipleHearingAidDeviceList());
 
@@ -282,9 +315,9 @@
         final FragmentActivity mActivity = Robolectric.setupActivity(FragmentActivity.class);
         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,
@@ -297,7 +330,7 @@
     @Test
     public void onServiceConnected_onHearingAidProfileConnected_updateSummary() {
         when(mCachedBluetoothDevice.getDeviceSide()).thenReturn(
-                HearingAidProfile.DeviceSide.SIDE_LEFT);
+                HearingAidInfo.DeviceSide.SIDE_LEFT);
         when(mHearingAidProfile.getConnectedDevices()).thenReturn(generateHearingAidDeviceList());
 
         mPreferenceController.onStart();
@@ -310,14 +343,14 @@
     @Test
     public void onServiceConnected_onHapClientProfileConnected_updateSummary() {
         when(mCachedBluetoothDevice.getDeviceSide()).thenReturn(
-                HearingAidProfile.DeviceSide.SIDE_INVALID);
+                HearingAidInfo.DeviceSide.SIDE_RIGHT);
         when(mHapClientProfile.getConnectedDevices()).thenReturn(generateHearingAidDeviceList());
 
         mPreferenceController.onStart();
         mPreferenceController.onServiceConnected();
 
         assertThat(mHearingAidPreference.getSummary().toString()).isEqualTo(
-                "TEST_HEARING_AID_BT_DEVICE_NAME active");
+                "TEST_HEARING_AID_BT_DEVICE_NAME, right only");
     }
 
     private void setupEnvironment() {
diff --git a/tests/robotests/src/com/android/settings/accessibility/HearingAidPairingDialogFragmentTest.java b/tests/robotests/src/com/android/settings/accessibility/HearingAidPairingDialogFragmentTest.java
index 1623d40..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();
 
diff --git a/tests/robotests/src/com/android/settings/accessibility/HearingAidUtilsTest.java b/tests/robotests/src/com/android/settings/accessibility/HearingAidUtilsTest.java
index efdda73..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;
@@ -99,7 +99,7 @@
     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);
 
@@ -111,7 +111,7 @@
     public void launchHearingAidPairingDialog_deviceHasSubDevice_noDialog() {
         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);
@@ -124,9 +124,9 @@
     public void launchHearingAidPairingDialog_deviceIsInvalidSide_noDialog() {
         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);
 
@@ -138,9 +138,9 @@
     public void launchHearingAidPairingDialog_dialogShown() {
         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/bluetooth/BluetoothDetailsPairOtherControllerTest.java b/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsPairOtherControllerTest.java
index 9ccdf99..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);
 
@@ -100,7 +100,7 @@
     @Test
     public void isAvailable_isConnectedAshaHearingAidDevice_isMonaural_notAvailable() {
         when(mCachedDevice.isConnectedAshaHearingAidDevice()).thenReturn(true);
-        when(mCachedDevice.getDeviceMode()).thenReturn(HearingAidProfile.DeviceMode.MODE_MONAURAL);
+        when(mCachedDevice.getDeviceMode()).thenReturn(HearingAidInfo.DeviceMode.MODE_MONAURAL);
 
         assertThat(mController.isAvailable()).isFalse();
     }
@@ -108,7 +108,7 @@
     @Test
     public void isAvailable_subDeviceIsConnectedAshaHearingAidDevice_notAvailable() {
         when(mCachedDevice.isConnectedAshaHearingAidDevice()).thenReturn(true);
-        when(mCachedDevice.getDeviceMode()).thenReturn(HearingAidProfile.DeviceMode.MODE_BINAURAL);
+        when(mCachedDevice.getDeviceMode()).thenReturn(HearingAidInfo.DeviceMode.MODE_BINAURAL);
         when(mSubCachedDevice.isConnectedAshaHearingAidDevice()).thenReturn(true);
         when(mCachedDevice.getSubDevice()).thenReturn(mSubCachedDevice);
 
@@ -118,7 +118,7 @@
     @Test
     public void isAvailable_subDeviceIsNotConnectedAshaHearingAidDevice_available() {
         when(mCachedDevice.isConnectedAshaHearingAidDevice()).thenReturn(true);
-        when(mCachedDevice.getDeviceMode()).thenReturn(HearingAidProfile.DeviceMode.MODE_BINAURAL);
+        when(mCachedDevice.getDeviceMode()).thenReturn(HearingAidInfo.DeviceMode.MODE_BINAURAL);
         when(mSubCachedDevice.isConnectedAshaHearingAidDevice()).thenReturn(false);
         when(mCachedDevice.getSubDevice()).thenReturn(mSubCachedDevice);
 
@@ -128,7 +128,7 @@
     @Test
     public void isAvailable_subDeviceNotExist_available() {
         when(mCachedDevice.isConnectedAshaHearingAidDevice()).thenReturn(true);
-        when(mCachedDevice.getDeviceMode()).thenReturn(HearingAidProfile.DeviceMode.MODE_BINAURAL);
+        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();
diff --git a/tests/robotests/src/com/android/settings/connecteddevice/AvailableMediaDeviceGroupControllerTest.java b/tests/robotests/src/com/android/settings/connecteddevice/AvailableMediaDeviceGroupControllerTest.java
index 93ebd3f..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;
@@ -246,9 +246,9 @@
     public void onActiveDeviceChanged_hearingAidProfile_launchHearingAidPairingDialog() {
         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 21dc79b..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())
@@ -94,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,
@@ -178,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(
@@ -186,7 +201,12 @@
                 upperTimestamp,
                 /*totalPower=*/ 80,
                 /*consumePower=*/ 20,
+                /*foregroundUsageConsumePower=*/ 4,
+                /*foregroundServiceUsageConsumePower=*/ 5,
+                /*backgroundUsageConsumePower=*/ 6,
+                /*cachedUsageConsumePower=*/ 5,
                 /*foregroundUsageTimeInMs=*/ 200,
+                /*foregroundServiceUsageTimeInMs=*/ 250,
                 /*backgroundUsageTimeInMs=*/ 300,
                 /*batteryLevel=*/ 80);
 
@@ -204,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)));
     }
@@ -213,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);
 
@@ -238,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);
     }
@@ -262,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);
     }
@@ -275,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();
@@ -290,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)
@@ -308,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(
@@ -336,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 4b596a6..d6e7737 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageContentProviderTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageContentProviderTest.java
@@ -196,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();
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 9ea8ced..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())
@@ -117,8 +106,13 @@
         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);
@@ -169,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())
@@ -196,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);
@@ -230,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());
@@ -434,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/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/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 ffb3197..485caef 100644
--- a/tests/robotests/src/com/android/settings/testutils/BatteryTestUtils.java
+++ b/tests/robotests/src/com/android/settings/testutils/BatteryTestUtils.java
@@ -134,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();
+    }
+}