Merge "[ToA] Terms of Address UI, string and locale list" into main
diff --git a/Android.bp b/Android.bp
index 44f83f3..c6a62a7 100644
--- a/Android.bp
+++ b/Android.bp
@@ -85,6 +85,7 @@
         "net-utils-framework-common",
         "app-usage-event-protos-lite",
         "battery-event-protos-lite",
+        "battery-usage-slot-protos-lite",
         "power-anomaly-event-protos-lite",
         "settings-contextual-card-protos-lite",
         "settings-log-bridge-protos-lite",
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index c3bd4df..b147fff 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -2567,7 +2567,8 @@
             </intent-filter>
         </activity>
 
-        <activity android:name=".biometrics.fingerprint2.enrollment.ui.activity.FingerprintEnrollmentV2Activity"
+
+        <activity android:name=".biometrics.fingerprint2.ui.enrollment.activity.FingerprintEnrollmentV2Activity"
             android:exported="true"
             android:permission="android.permission.MANAGE_FINGERPRINT"
             android:theme="@style/GlifTheme.Light">
@@ -4942,7 +4943,7 @@
                 <category android:name="android.intent.category.DEFAULT" />
             </intent-filter>
             <meta-data android:name="com.android.settings.FRAGMENT_CLASS"
-                android:value="com.android.settings.biometrics.fingerprint2.ui.fragment.FingerprintSettingsV2Fragment" />
+                android:value="com.android.settings.biometrics.fingerprint2.ui.settings.fragment.FingerprintSettingsV2Fragment" />
             <meta-data android:name="com.android.settings.HIGHLIGHT_MENU_KEY"
                 android:value="@string/menu_key_security"/>
         </activity>
diff --git a/res/layout/battery_tips_card.xml b/res/layout/battery_tips_card.xml
index 2fa5bf2..dde559d 100644
--- a/res/layout/battery_tips_card.xml
+++ b/res/layout/battery_tips_card.xml
@@ -28,7 +28,6 @@
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
             android:layout_marginTop="8dp"
-            android:maxLines="2"
             android:textAlignment="viewStart"
             android:textAppearance="?android:attr/textAppearanceLarge"
             android:textColor="?android:attr/textColorPrimary" />
@@ -45,7 +44,7 @@
                 style="@style/Widget.Material3.Button.TextButton"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
-                android:layout_gravity="end"
+                android:layout_gravity="end|center_vertical"
                 android:paddingHorizontal="16dp"
                 android:layout_marginEnd="8dp"
                 android:text="@string/battery_tips_card_dismiss_button"
@@ -59,7 +58,7 @@
                 android:paddingHorizontal="16dp"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
-                android:layout_gravity="end"
+                android:layout_gravity="end|center_vertical"
                 android:text="@string/battery_tips_card_action_button"
                 android:textAppearance="?android:attr/textAppearanceSmall"
                 android:textColor="?android:attr/textColorPrimary"
diff --git a/res/layout/remove_account_button.xml b/res/layout/remove_account_button.xml
index 070ecc5..2d308ae 100644
--- a/res/layout/remove_account_button.xml
+++ b/res/layout/remove_account_button.xml
@@ -19,7 +19,7 @@
     android:layout_height="wrap_content"
     android:orientation="vertical">
 
-    <Button
+    <com.android.settings.widget.RestrictedButton
         android:id="@+id/button"
         android:text="@string/remove_account_label"
         android:layout_width="wrap_content"
diff --git a/res/values/arrays.xml b/res/values/arrays.xml
index 0dd63de..81c87f7 100644
--- a/res/values/arrays.xml
+++ b/res/values/arrays.xml
@@ -1409,12 +1409,7 @@
     <integer-array name="network_mode_3g_deprecated_carrier_id" translatable="false">
     </integer-array>
 
-    <!-- The following 4 arrays are for power anomaly tips card. Please keep them the same size. -->
-    <string-array name="power_anomaly_keys" translatable="false">
-        <item>adaptive_brightness</item>
-        <item>screen_timeout</item>
-    </string-array>
-
+    <!-- The following 3 arrays are for power anomaly tips card. Please keep them the same size. -->
     <string-array name="power_anomaly_titles">
         <item>Turn on adaptive brightness to extend battery life</item>
         <item>Reduce screen timeout to extend battery life</item>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 26f700a..1ef051e 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -2181,6 +2181,13 @@
     <!-- The footer message for Wi-Fi hotspot security settings [CHAR LIMIT=NONE] -->
     <string name="wifi_hotspot_security_footer">Security settings may change if you change the hotspot’s frequency</string>
 
+    <!-- Title for the instant hotspot state [CHAR LIMIT=NONE]-->
+    <string name="wifi_hotspot_instant_title">Instant hotspot</string>
+    <!-- Summary text when instant hotspot is turned on -->
+    <string name="wifi_hotspot_instant_summary_on">On</string>
+    <!-- Summary text when instant hotspot is turned off -->
+    <string name="wifi_hotspot_instant_summary_off">Off</string>
+
     <!-- Summary text when turning hotspot on -->
     <string name="wifi_tether_starting">Turning hotspot on\u2026</string>
     <!-- Summary text when turning hotspot off -->
diff --git a/res/xml/wifi_tether_settings.xml b/res/xml/wifi_tether_settings.xml
index a85d9ea..b8b810f 100644
--- a/res/xml/wifi_tether_settings.xml
+++ b/res/xml/wifi_tether_settings.xml
@@ -59,4 +59,10 @@
         android:summary="@string/summary_placeholder"
         android:fragment="com.android.settings.wifi.tether.WifiHotspotSpeedSettings"
         settings:isPreferenceVisible="@bool/config_show_wifi_hotspot_speed"/>
+
+    <Preference
+        android:key="wifi_hotspot_instant"
+        android:title="@string/wifi_hotspot_instant_title"
+        android:summary="@string/summary_placeholder"
+        settings:isPreferenceVisible="false"/>
 </PreferenceScreen>
diff --git a/src/com/android/settings/Utils.java b/src/com/android/settings/Utils.java
index dda5b24..c20529b 100644
--- a/src/com/android/settings/Utils.java
+++ b/src/com/android/settings/Utils.java
@@ -16,9 +16,6 @@
 
 package com.android.settings;
 
-import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROFILE_CONFIRM_PASSWORD;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROFILE_CONFIRM_PATTERN;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROFILE_CONFIRM_PIN;
 import static android.content.Intent.EXTRA_USER;
 import static android.content.Intent.EXTRA_USER_ID;
 import static android.text.format.DateUtils.FORMAT_ABBREV_MONTH;
@@ -791,36 +788,15 @@
     @Nullable public static String getConfirmCredentialStringForUser(@NonNull Context context,
              int userId, @LockPatternUtils.CredentialType int credentialType) {
         final int effectiveUserId = UserManager.get(context).getCredentialOwnerProfile(userId);
-        final boolean isEffectiveUserManagedProfile = UserManager.get(context)
-                .isManagedProfile(effectiveUserId);
-        final DevicePolicyManager devicePolicyManager = context
-                .getSystemService(DevicePolicyManager.class);
+        if (UserManager.get(context).isManagedProfile(effectiveUserId)) {
+            return null;
+        }
         switch (credentialType) {
             case LockPatternUtils.CREDENTIAL_TYPE_PIN:
-                if (isEffectiveUserManagedProfile) {
-                    return devicePolicyManager.getResources().getString(WORK_PROFILE_CONFIRM_PIN,
-                            () -> context.getString(
-                                    R.string.lockpassword_confirm_your_pin_generic_profile));
-                }
-
                 return context.getString(R.string.lockpassword_confirm_your_pin_generic);
             case LockPatternUtils.CREDENTIAL_TYPE_PATTERN:
-                if (isEffectiveUserManagedProfile) {
-                    return devicePolicyManager.getResources().getString(
-                            WORK_PROFILE_CONFIRM_PATTERN,
-                            () -> context.getString(
-                                    R.string.lockpassword_confirm_your_pattern_generic_profile));
-                }
-
                 return context.getString(R.string.lockpassword_confirm_your_pattern_generic);
             case LockPatternUtils.CREDENTIAL_TYPE_PASSWORD:
-                if (isEffectiveUserManagedProfile) {
-                    return devicePolicyManager.getResources().getString(
-                            WORK_PROFILE_CONFIRM_PASSWORD,
-                            () -> context.getString(
-                                    R.string.lockpassword_confirm_your_password_generic_profile));
-                }
-
                 return context.getString(R.string.lockpassword_confirm_your_password_generic);
         }
         return null;
diff --git a/src/com/android/settings/accessibility/FlashNotificationsPreviewPreferenceController.java b/src/com/android/settings/accessibility/FlashNotificationsPreviewPreferenceController.java
index f137584..ae1adfa 100644
--- a/src/com/android/settings/accessibility/FlashNotificationsPreviewPreferenceController.java
+++ b/src/com/android/settings/accessibility/FlashNotificationsPreviewPreferenceController.java
@@ -28,6 +28,7 @@
 import android.net.Uri;
 import android.os.Handler;
 import android.os.Looper;
+import android.os.UserHandle;
 import android.provider.Settings;
 
 import androidx.annotation.NonNull;
@@ -81,7 +82,7 @@
         if (getPreferenceKey().equals(preference.getKey())) {
             Intent intent = new Intent(ACTION_FLASH_NOTIFICATION_START_PREVIEW);
             intent.putExtra(EXTRA_FLASH_NOTIFICATION_PREVIEW_TYPE, TYPE_SHORT_PREVIEW);
-            mContext.sendBroadcast(intent);
+            mContext.sendBroadcastAsUser(intent, UserHandle.SYSTEM);
             return true;
         }
 
diff --git a/src/com/android/settings/accessibility/HearingAidCompatibilityPreferenceController.java b/src/com/android/settings/accessibility/HearingAidCompatibilityPreferenceController.java
index 71e4a21..cd2f6f0 100644
--- a/src/com/android/settings/accessibility/HearingAidCompatibilityPreferenceController.java
+++ b/src/com/android/settings/accessibility/HearingAidCompatibilityPreferenceController.java
@@ -73,6 +73,6 @@
     }
 
     private void setAudioParameterHacEnabled(boolean enabled) {
-        mAudioManager.setParameters(HAC_KEY + "=" + (enabled ? HAC_VAL_ON : HAC_VAL_OFF));
+        mAudioManager.setParameters(HAC_KEY + "=" + (enabled ? HAC_VAL_ON : HAC_VAL_OFF) + ";");
     }
 }
diff --git a/src/com/android/settings/accessibility/ScreenFlashNotificationColorDialogFragment.java b/src/com/android/settings/accessibility/ScreenFlashNotificationColorDialogFragment.java
index 9683966..ca77f16 100644
--- a/src/com/android/settings/accessibility/ScreenFlashNotificationColorDialogFragment.java
+++ b/src/com/android/settings/accessibility/ScreenFlashNotificationColorDialogFragment.java
@@ -27,6 +27,7 @@
 import android.content.Intent;
 import android.graphics.Color;
 import android.os.Bundle;
+import android.os.UserHandle;
 import android.view.View;
 
 import androidx.annotation.ColorInt;
@@ -41,6 +42,7 @@
 import java.util.TimerTask;
 import java.util.function.Consumer;
 
+
 /**
  * DialogFragment for Screen flash notification color picker.
  */
@@ -166,14 +168,14 @@
         Intent intent = new Intent(ACTION_FLASH_NOTIFICATION_START_PREVIEW);
         intent.putExtra(EXTRA_FLASH_NOTIFICATION_PREVIEW_TYPE, TYPE_LONG_PREVIEW);
         intent.putExtra(EXTRA_FLASH_NOTIFICATION_PREVIEW_COLOR, mCurrentColor);
-        getContext().sendBroadcast(intent);
+        getContext().sendBroadcastAsUser(intent, UserHandle.SYSTEM);
     }
 
     private void stopPreviewLocked() {
         if (getContext() == null) return;
 
         Intent stopIntent = new Intent(ACTION_FLASH_NOTIFICATION_STOP_PREVIEW);
-        getContext().sendBroadcast(stopIntent);
+        getContext().sendBroadcastAsUser(stopIntent, UserHandle.SYSTEM);
         mIsPreview = false;
     }
 
diff --git a/src/com/android/settings/accounts/AccountHeaderPreferenceController.java b/src/com/android/settings/accounts/AccountHeaderPreferenceController.java
index 11fcaff..b466d2b 100644
--- a/src/com/android/settings/accounts/AccountHeaderPreferenceController.java
+++ b/src/com/android/settings/accounts/AccountHeaderPreferenceController.java
@@ -95,6 +95,6 @@
                 .newInstance(mActivity, mHost, mHeaderPreference.findViewById(R.id.entity_header))
                 .setLabel(mAccount.name)
                 .setIcon(helper.getDrawableForType(mContext, mAccount.type))
-                .done(mActivity, true /* rebindButtons */);
+                .done(true /* rebindButtons */);
     }
 }
diff --git a/src/com/android/settings/accounts/AccountSyncSettings.java b/src/com/android/settings/accounts/AccountSyncSettings.java
index 83f89d8..80056a8 100644
--- a/src/com/android/settings/accounts/AccountSyncSettings.java
+++ b/src/com/android/settings/accounts/AccountSyncSettings.java
@@ -140,11 +140,10 @@
         final Activity activity = getActivity();
         final Preference pref = EntityHeaderController
                 .newInstance(activity, this, null /* header */)
-                .setRecyclerView(getListView(), getSettingsLifecycle())
                 .setIcon(getDrawableForType(mAccount.type))
                 .setLabel(mAccount.name)
                 .setSummary(getLabelForType(mAccount.type))
-                .done(activity, getPrefContext());
+                .done(getPrefContext());
         pref.setOrder(0);
         getPreferenceScreen().addPreference(pref);
         if (savedInstanceState != null && savedInstanceState.containsKey(UID_REQUEST_KEY)) {
diff --git a/src/com/android/settings/accounts/RemoveAccountPreferenceController.java b/src/com/android/settings/accounts/RemoveAccountPreferenceController.java
index b8ebf61..cdb35b4 100644
--- a/src/com/android/settings/accounts/RemoveAccountPreferenceController.java
+++ b/src/com/android/settings/accounts/RemoveAccountPreferenceController.java
@@ -34,19 +34,17 @@
 import android.util.Log;
 import android.view.View;
 import android.view.View.OnClickListener;
-import android.widget.Button;
 
 import androidx.appcompat.app.AlertDialog;
 import androidx.fragment.app.Fragment;
+import androidx.preference.Preference;
 import androidx.preference.PreferenceScreen;
 
 import com.android.settings.R;
 import com.android.settings.core.PreferenceControllerMixin;
 import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
 import com.android.settings.overlay.FeatureFactory;
-import com.android.settingslib.RestrictedLockUtils;
-import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
-import com.android.settingslib.RestrictedLockUtilsInternal;
+import com.android.settings.widget.RestrictedButton;
 import com.android.settingslib.core.AbstractPreferenceController;
 import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
 import com.android.settingslib.widget.LayoutPreference;
@@ -64,6 +62,7 @@
     private Fragment mParentFragment;
     private UserHandle mUserHandle;
     private LayoutPreference mRemoveAccountPreference;
+    private RestrictedButton mRemoveAccountButton;
 
     public RemoveAccountPreferenceController(Context context, Fragment parent) {
         super(context);
@@ -75,8 +74,14 @@
     public void displayPreference(PreferenceScreen screen) {
         super.displayPreference(screen);
         mRemoveAccountPreference = screen.findPreference(KEY_REMOVE_ACCOUNT);
-        final Button removeAccountButton = mRemoveAccountPreference.findViewById(R.id.button);
-        removeAccountButton.setOnClickListener(this);
+        mRemoveAccountButton = mRemoveAccountPreference.findViewById(R.id.button);
+        mRemoveAccountButton.setOnClickListener(this);
+    }
+
+    @Override
+    public void updateState(Preference preference) {
+        super.updateState(preference);
+        mRemoveAccountButton.updateState();
     }
 
     @Override
@@ -93,21 +98,13 @@
     public void onClick(View v) {
         mMetricsFeatureProvider.logClickedPreference(mRemoveAccountPreference,
                 mMetricsFeatureProvider.getMetricsCategory(mParentFragment));
-        if (mUserHandle != null) {
-            final EnforcedAdmin admin = RestrictedLockUtilsInternal.checkIfRestrictionEnforced(
-                    mContext, UserManager.DISALLOW_MODIFY_ACCOUNTS, mUserHandle.getIdentifier());
-            if (admin != null) {
-                RestrictedLockUtils.sendShowAdminSupportDetailsIntent(mContext, admin);
-                return;
-            }
-        }
-
         ConfirmRemoveAccountDialog.show(mParentFragment, mAccount, mUserHandle);
     }
 
     public void init(Account account, UserHandle userHandle) {
         mAccount = account;
         mUserHandle = userHandle;
+        mRemoveAccountButton.init(mUserHandle, UserManager.DISALLOW_MODIFY_ACCOUNTS);
     }
 
     /**
diff --git a/src/com/android/settings/applications/AppInfoWithHeader.java b/src/com/android/settings/applications/AppInfoWithHeader.java
index 7bf9f64..8645628 100644
--- a/src/com/android/settings/applications/AppInfoWithHeader.java
+++ b/src/com/android/settings/applications/AppInfoWithHeader.java
@@ -46,7 +46,6 @@
         final Activity activity = getActivity();
         final Preference pref = EntityHeaderController
                 .newInstance(activity, this, null /* header */)
-                .setRecyclerView(getListView(), getSettingsLifecycle())
                 .setIcon(Utils.getBadgedIcon(getContext(), mPackageInfo.applicationInfo))
                 .setLabel(mPackageInfo.applicationInfo.loadLabel(mPm))
                 .setSummary(mPackageInfo)
@@ -55,7 +54,7 @@
                 .setUid(mPackageInfo.applicationInfo.uid)
                 .setHasAppInfoLink(true)
                 .setButtonActions(ActionType.ACTION_NONE, ActionType.ACTION_NONE)
-                .done(activity, getPrefContext());
+                .done(getPrefContext());
         getPreferenceScreen().addPreference(pref);
     }
 }
diff --git a/src/com/android/settings/applications/ProcessStatsDetail.java b/src/com/android/settings/applications/ProcessStatsDetail.java
index 266c195..de21a46 100644
--- a/src/com/android/settings/applications/ProcessStatsDetail.java
+++ b/src/com/android/settings/applications/ProcessStatsDetail.java
@@ -129,7 +129,6 @@
         final Activity activity = getActivity();
         final Preference pref = EntityHeaderController
                 .newInstance(activity, this, null /* appHeader */)
-                .setRecyclerView(getListView(), getSettingsLifecycle())
                 .setIcon(mApp.mUiTargetApp != null
                         ? IconDrawableFactory.newInstance(activity).getBadgedIcon(mApp.mUiTargetApp)
                         : new ColorDrawable(0))
@@ -140,7 +139,7 @@
                         : UserHandle.USER_NULL)
                 .setHasAppInfoLink(true)
                 .setButtonActions(ActionType.ACTION_NONE, ActionType.ACTION_NONE)
-                .done(activity, getPrefContext());
+                .done(getPrefContext());
         getPreferenceScreen().addPreference(pref);
     }
 
diff --git a/src/com/android/settings/applications/appinfo/AppHeaderViewPreferenceController.java b/src/com/android/settings/applications/appinfo/AppHeaderViewPreferenceController.java
index 285493a..5542087 100644
--- a/src/com/android/settings/applications/appinfo/AppHeaderViewPreferenceController.java
+++ b/src/com/android/settings/applications/appinfo/AppHeaderViewPreferenceController.java
@@ -66,7 +66,6 @@
         final Activity activity = mParent.getActivity();
         mEntityHeaderController = EntityHeaderController
                 .newInstance(activity, mParent, mHeader.findViewById(R.id.entity_header))
-                .setRecyclerView(mParent.getListView(), mLifecycle)
                 .setPackageName(mPackageName)
                 .setButtonActions(EntityHeaderController.ActionType.ACTION_NONE,
                         EntityHeaderController.ActionType.ACTION_NONE)
@@ -86,6 +85,6 @@
                 .setLabel(appEntry)
                 .setIcon(appEntry)
                 .setIsInstantApp(isInstantApp)
-                .done(activity, false /* rebindActions */);
+                .done(false /* rebindActions */);
     }
 }
diff --git a/src/com/android/settings/applications/appinfo/AppLocaleDetails.java b/src/com/android/settings/applications/appinfo/AppLocaleDetails.java
index 6144a73..1e7ca1e 100644
--- a/src/com/android/settings/applications/appinfo/AppLocaleDetails.java
+++ b/src/com/android/settings/applications/appinfo/AppLocaleDetails.java
@@ -137,7 +137,6 @@
         final Activity activity = getActivity();
         final Preference pref = EntityHeaderController
                 .newInstance(activity, this, null /* header */)
-                .setRecyclerView(getListView(), getSettingsLifecycle())
                 .setIcon(Utils.getBadgedIcon(getContext(), mApplicationInfo))
                 .setLabel(mApplicationInfo.loadLabel(getContext().getPackageManager()))
                 .setIsInstantApp(AppUtils.isInstant(mApplicationInfo))
@@ -146,7 +145,7 @@
                 .setHasAppInfoLink(true)
                 .setButtonActions(ActionType.ACTION_NONE, ActionType.ACTION_NONE)
                 .setOrder(10)
-                .done(activity, getPrefContext());
+                .done(getPrefContext());
         getPreferenceScreen().addPreference(pref);
     }
 
diff --git a/src/com/android/settings/applications/intentpicker/AppLaunchSettings.java b/src/com/android/settings/applications/intentpicker/AppLaunchSettings.java
index cc662aa..cebb4f7 100644
--- a/src/com/android/settings/applications/intentpicker/AppLaunchSettings.java
+++ b/src/com/android/settings/applications/intentpicker/AppLaunchSettings.java
@@ -200,7 +200,6 @@
         final String summary = activity.getString(R.string.app_launch_top_intro_message);
         final Preference pref = EntityHeaderController
                 .newInstance(activity, this, null /* header */)
-                .setRecyclerView(getListView(), getSettingsLifecycle())
                 .setIcon(Utils.getBadgedIcon(mContext, mPackageInfo.applicationInfo))
                 .setLabel(mPackageInfo.applicationInfo.loadLabel(mPm))
                 .setSummary(summary)  // add intro text
@@ -210,7 +209,7 @@
                 .setHasAppInfoLink(true)
                 .setButtonActions(EntityHeaderController.ActionType.ACTION_NONE,
                         EntityHeaderController.ActionType.ACTION_NONE)
-                .done(activity, getPrefContext());
+                .done(getPrefContext());
         getPreferenceScreen().addPreference(pref);
     }
 
diff --git a/src/com/android/settings/applications/specialaccess/notificationaccess/HeaderPreferenceController.java b/src/com/android/settings/applications/specialaccess/notificationaccess/HeaderPreferenceController.java
index 8ccf7ed..b636264 100644
--- a/src/com/android/settings/applications/specialaccess/notificationaccess/HeaderPreferenceController.java
+++ b/src/com/android/settings/applications/specialaccess/notificationaccess/HeaderPreferenceController.java
@@ -109,7 +109,6 @@
         mHeaderController = EntityHeaderController.newInstance(
                 mFragment.getActivity(), mFragment, pref.findViewById(R.id.entity_header));
         pref = mHeaderController
-                .setRecyclerView(mFragment.getListView(), mFragment.getSettingsLifecycle())
                 .setIcon(IconDrawableFactory.newInstance(mFragment.getActivity())
                         .getBadgedIcon(mPackageInfo.applicationInfo))
                 .setLabel(mPackageInfo.applicationInfo.loadLabel(mPm))
@@ -122,7 +121,7 @@
                 .setHasAppInfoLink(true)
                 .setButtonActions(EntityHeaderController.ActionType.ACTION_NONE,
                         EntityHeaderController.ActionType.ACTION_NONE)
-                .done(mFragment.getActivity(), mContext);
+                .done(mContext);
         pref.findViewById(R.id.entity_header).setVisibility(View.VISIBLE);
     }
 }
diff --git a/src/com/android/settings/biometrics/face/FaceSettingsRemoveButtonPreferenceController.java b/src/com/android/settings/biometrics/face/FaceSettingsRemoveButtonPreferenceController.java
index 739de6b..797364b 100644
--- a/src/com/android/settings/biometrics/face/FaceSettingsRemoveButtonPreferenceController.java
+++ b/src/com/android/settings/biometrics/face/FaceSettingsRemoveButtonPreferenceController.java
@@ -30,6 +30,7 @@
 import android.widget.Button;
 import android.widget.Toast;
 
+import androidx.annotation.VisibleForTesting;
 import androidx.preference.Preference;
 
 import com.android.settings.R;
@@ -57,10 +58,18 @@
     static final String KEY = "security_settings_face_delete_faces_container";
 
     public static class ConfirmRemoveDialog extends InstrumentedDialogFragment {
-
-        private boolean mIsConvenience;
+        private static final String KEY_IS_CONVENIENCE = "is_convenience";
         private DialogInterface.OnClickListener mOnClickListener;
 
+        /** Returns the new instance of the class */
+        public static ConfirmRemoveDialog newInstance(boolean isConvenience) {
+            final ConfirmRemoveDialog dialog = new ConfirmRemoveDialog();
+            final Bundle args = new Bundle();
+            args.putBoolean(KEY_IS_CONVENIENCE, isConvenience);
+            dialog.setArguments(args);
+            return dialog;
+        }
+
         @Override
         public int getMetricsCategory() {
             return SettingsEnums.DIALOG_FACE_REMOVE;
@@ -68,6 +77,8 @@
 
         @Override
         public Dialog onCreateDialog(Bundle savedInstanceState) {
+            boolean isConvenience = getArguments().getBoolean(KEY_IS_CONVENIENCE);
+
             AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
 
             final PackageManager pm = getContext().getPackageManager();
@@ -75,11 +86,11 @@
             final int dialogMessageRes;
 
             if (hasFingerprint) {
-                dialogMessageRes = mIsConvenience
+                dialogMessageRes = isConvenience
                         ? R.string.security_settings_face_remove_dialog_details_fingerprint_conv
                         : R.string.security_settings_face_remove_dialog_details_fingerprint;
             } else {
-                dialogMessageRes = mIsConvenience
+                dialogMessageRes = isConvenience
                         ? R.string.security_settings_face_settings_remove_dialog_details_convenience
                         : R.string.security_settings_face_settings_remove_dialog_details;
             }
@@ -93,10 +104,6 @@
             return dialog;
         }
 
-        public void setIsConvenience(boolean isConvenience) {
-            mIsConvenience = isConvenience;
-        }
-
         public void setOnClickListener(DialogInterface.OnClickListener listener) {
             mOnClickListener = listener;
         }
@@ -111,7 +118,8 @@
     private Listener mListener;
     private SettingsActivity mActivity;
     private int mUserId;
-    private boolean mRemoving;
+    @VisibleForTesting
+    boolean mRemoving;
 
     private final MetricsFeatureProvider mMetricsFeatureProvider;
     private final Context mContext;
@@ -142,7 +150,7 @@
         }
     };
 
-    private final DialogInterface.OnClickListener mOnClickListener
+    private final DialogInterface.OnClickListener mOnConfirmDialogClickListener
             = new DialogInterface.OnClickListener() {
         @Override
         public void onClick(DialogInterface dialog, int which) {
@@ -196,6 +204,16 @@
 
         mButton.setOnClickListener(this);
 
+        // If there is already a ConfirmRemoveDialog showing, reset the listener since the
+        // controller has been recreated.
+        ConfirmRemoveDialog removeDialog =
+                (ConfirmRemoveDialog) mActivity.getSupportFragmentManager()
+                        .findFragmentByTag(ConfirmRemoveDialog.class.getName());
+        if (removeDialog != null) {
+            mRemoving = true;
+            removeDialog.setOnClickListener(mOnConfirmDialogClickListener);
+        }
+
         if (!FaceSettings.isFaceHardwareDetected(mContext)) {
             mButton.setEnabled(false);
         } else {
@@ -218,10 +236,11 @@
         if (v == mButton) {
             mMetricsFeatureProvider.logClickedPreference(mPreference, getMetricsCategory());
             mRemoving = true;
-            ConfirmRemoveDialog dialog = new ConfirmRemoveDialog();
-            dialog.setOnClickListener(mOnClickListener);
-            dialog.setIsConvenience(BiometricUtils.isConvenience(mFaceManager));
-            dialog.show(mActivity.getSupportFragmentManager(), ConfirmRemoveDialog.class.getName());
+            ConfirmRemoveDialog confirmRemoveDialog =
+                    ConfirmRemoveDialog.newInstance(BiometricUtils.isConvenience(mFaceManager));
+            confirmRemoveDialog.setOnClickListener(mOnConfirmDialogClickListener);
+            confirmRemoveDialog.show(mActivity.getSupportFragmentManager(),
+                            ConfirmRemoveDialog.class.getName());
         }
     }
 
diff --git a/src/com/android/settings/biometrics/fingerprint2/OWNERS b/src/com/android/settings/biometrics/fingerprint2/OWNERS
new file mode 100644
index 0000000..c58a06d
--- /dev/null
+++ b/src/com/android/settings/biometrics/fingerprint2/OWNERS
@@ -0,0 +1,3 @@
+# Owners for Biometric Fingerprint
+joshmccloskey@google.com
+jbolinger@google.com
\ No newline at end of file
diff --git a/src/com/android/settings/biometrics/fingerprint2/README.md b/src/com/android/settings/biometrics/fingerprint2/README.md
new file mode 100644
index 0000000..4a99a2b
--- /dev/null
+++ b/src/com/android/settings/biometrics/fingerprint2/README.md
@@ -0,0 +1,10 @@
+### Fingerprint Settings Enrollment
+
+#### Flows
+
+* FingerprintSettings (ui.settings.fragment.FingerprintSettingsV2Fragment)
+* FingerprintEnrollment (ui.enrollment.activity.FingerprintEnrollmentV2Activity)
+
+#### Style
+
+* Please use [kfmt](https://plugins.jetbrains.com/plugin/14912-ktfmt)
\ No newline at end of file
diff --git a/src/com/android/settings/biometrics/fingerprint2/domain/interactor/FingerprintManagerInteractor.kt b/src/com/android/settings/biometrics/fingerprint2/domain/interactor/FingerprintManagerInteractor.kt
index 2fbdedf..e7c458d 100644
--- a/src/com/android/settings/biometrics/fingerprint2/domain/interactor/FingerprintManagerInteractor.kt
+++ b/src/com/android/settings/biometrics/fingerprint2/domain/interactor/FingerprintManagerInteractor.kt
@@ -25,8 +25,8 @@
 import android.os.CancellationSignal
 import android.util.Log
 import com.android.settings.biometrics.GatekeeperPasswordProvider
-import com.android.settings.biometrics.fingerprint2.ui.viewmodel.FingerprintAuthAttemptViewModel
-import com.android.settings.biometrics.fingerprint2.ui.viewmodel.FingerprintViewModel
+import com.android.settings.biometrics.fingerprint2.shared.model.FingerprintAuthAttemptViewModel
+import com.android.settings.biometrics.fingerprint2.shared.model.FingerprintViewModel
 import com.android.settings.password.ChooseLockSettingsHelper
 import kotlin.coroutines.resume
 import kotlin.coroutines.suspendCoroutine
diff --git a/src/com/android/settings/biometrics/fingerprint2/ui/viewmodel/FingerprintViewModel.kt b/src/com/android/settings/biometrics/fingerprint2/shared/model/FingerprintViewModel.kt
similarity index 86%
rename from src/com/android/settings/biometrics/fingerprint2/ui/viewmodel/FingerprintViewModel.kt
rename to src/com/android/settings/biometrics/fingerprint2/shared/model/FingerprintViewModel.kt
index 1df0e34..36bdf8d 100644
--- a/src/com/android/settings/biometrics/fingerprint2/ui/viewmodel/FingerprintViewModel.kt
+++ b/src/com/android/settings/biometrics/fingerprint2/shared/model/FingerprintViewModel.kt
@@ -14,7 +14,9 @@
  * limitations under the License.
  */
 
-package com.android.settings.biometrics.fingerprint2.ui.viewmodel
+package com.android.settings.biometrics.fingerprint2.shared.model
+
+import android.hardware.fingerprint.FingerprintSensorPropertiesInternal
 
 /** Represents the fingerprint data nad the relevant state. */
 data class FingerprintStateViewModel(
@@ -23,6 +25,7 @@
   val maxFingerprints: Int,
   val hasSideFps: Boolean,
   val pressToAuth: Boolean,
+  val sensorProps: FingerprintSensorPropertiesInternal,
 )
 
 data class FingerprintViewModel(
diff --git a/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/README.md b/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/README.md
new file mode 100644
index 0000000..8469f59
--- /dev/null
+++ b/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/README.md
@@ -0,0 +1,23 @@
+### Fingerprint Settings Enrollment
+
+#### Entry Points (To FingerprintEnrollment)
+
+* FingerprintSettings (which launches the below intent)
+* Intent -> ".biometrics.fingerprint2.ui.enrollment.activity.FingerprintEnrollmentV2Activity")
+
+#### General Architecture
+
+The code should follow the MVVM architecture.
+
+**In addition, one activity (FingerprintEnrollmentV2Activity) should**
+
+* Control a list of fragments which correspond to enrollment steps
+* Be responsible for navigation events between fragments
+* Be responsible for navigation events to other activities if need be (
+  ConfirmDeviceCredentialActivity)
+* Be the controller of the viewmodels
+
+#### Style
+
+* Please use [kfmt](https://plugins.jetbrains.com/plugin/14912-ktfmt)
+
diff --git a/src/com/android/settings/biometrics/fingerprint2/enrollment/ui/activity/FingerprintEnrollmentV2Activity.kt b/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/activity/FingerprintEnrollmentV2Activity.kt
similarity index 85%
rename from src/com/android/settings/biometrics/fingerprint2/enrollment/ui/activity/FingerprintEnrollmentV2Activity.kt
rename to src/com/android/settings/biometrics/fingerprint2/ui/enrollment/activity/FingerprintEnrollmentV2Activity.kt
index 7bea4b4..d497d46 100644
--- a/src/com/android/settings/biometrics/fingerprint2/enrollment/ui/activity/FingerprintEnrollmentV2Activity.kt
+++ b/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/activity/FingerprintEnrollmentV2Activity.kt
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.settings.biometrics.fingerprint2.enrollment.ui.activity
+package com.android.settings.biometrics.fingerprint2.ui.enrollment.activity
 
 import android.annotation.ColorInt
 import android.app.Activity
@@ -40,21 +40,21 @@
 import com.android.settings.biometrics.BiometricEnrollBase.RESULT_FINISHED
 import com.android.settings.biometrics.GatekeeperPasswordProvider
 import com.android.settings.biometrics.fingerprint2.domain.interactor.FingerprintManagerInteractorImpl
-import com.android.settings.biometrics.fingerprint2.enrollment.ui.fragment.FingerprintEnrollConfirmationV2Fragment
-import com.android.settings.biometrics.fingerprint2.enrollment.ui.fragment.FingerprintEnrollEnrollingV2Fragment
-import com.android.settings.biometrics.fingerprint2.enrollment.ui.fragment.FingerprintEnrollFindSensorV2Fragment
-import com.android.settings.biometrics.fingerprint2.enrollment.ui.fragment.FingerprintEnrollmentIntroV2Fragment
-import com.android.settings.biometrics.fingerprint2.enrollment.ui.viewmodel.Confirmation
-import com.android.settings.biometrics.fingerprint2.enrollment.ui.viewmodel.Education
-import com.android.settings.biometrics.fingerprint2.enrollment.ui.viewmodel.Enrollment
-import com.android.settings.biometrics.fingerprint2.enrollment.ui.viewmodel.FingerprintEnrollmentNavigationViewModel
-import com.android.settings.biometrics.fingerprint2.enrollment.ui.viewmodel.FingerprintGatekeeperViewModel
-import com.android.settings.biometrics.fingerprint2.enrollment.ui.viewmodel.FingerprintScrollViewModel
-import com.android.settings.biometrics.fingerprint2.enrollment.ui.viewmodel.FingerprintViewModel
-import com.android.settings.biometrics.fingerprint2.enrollment.ui.viewmodel.Finish
-import com.android.settings.biometrics.fingerprint2.enrollment.ui.viewmodel.GatekeeperInfo
-import com.android.settings.biometrics.fingerprint2.enrollment.ui.viewmodel.Intro
-import com.android.settings.biometrics.fingerprint2.enrollment.ui.viewmodel.LaunchConfirmDeviceCredential
+import com.android.settings.biometrics.fingerprint2.ui.enrollment.fragment.FingerprintEnrollConfirmationV2Fragment
+import com.android.settings.biometrics.fingerprint2.ui.enrollment.fragment.FingerprintEnrollEnrollingV2Fragment
+import com.android.settings.biometrics.fingerprint2.ui.enrollment.fragment.FingerprintEnrollFindSensorV2Fragment
+import com.android.settings.biometrics.fingerprint2.ui.enrollment.fragment.FingerprintEnrollmentIntroV2Fragment
+import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.Confirmation
+import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.Education
+import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.Enrollment
+import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintEnrollmentNavigationViewModel
+import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintGatekeeperViewModel
+import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintScrollViewModel
+import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintViewModel
+import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.Finish
+import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.GatekeeperInfo
+import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.Intro
+import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.LaunchConfirmDeviceCredential
 import com.android.settings.password.ChooseLockGeneric
 import com.android.settings.password.ChooseLockSettingsHelper
 import com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_GK_PW_HANDLE
diff --git a/src/com/android/settings/biometrics/fingerprint2/enrollment/ui/fragment/FingerprintEnrollConfirmationV2Fragment.kt b/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/fragment/FingerprintEnrollConfirmationV2Fragment.kt
similarity index 86%
rename from src/com/android/settings/biometrics/fingerprint2/enrollment/ui/fragment/FingerprintEnrollConfirmationV2Fragment.kt
rename to src/com/android/settings/biometrics/fingerprint2/ui/enrollment/fragment/FingerprintEnrollConfirmationV2Fragment.kt
index 84a5658..df4cf72 100644
--- a/src/com/android/settings/biometrics/fingerprint2/enrollment/ui/fragment/FingerprintEnrollConfirmationV2Fragment.kt
+++ b/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/fragment/FingerprintEnrollConfirmationV2Fragment.kt
@@ -14,12 +14,12 @@
  * limitations under the License.
  */
 
-package com.android.settings.biometrics.fingerprint2.enrollment.ui.fragment
+package com.android.settings.biometrics.fingerprint2.ui.enrollment.fragment
 
 import android.os.Bundle
 import androidx.fragment.app.Fragment
 import androidx.lifecycle.ViewModelProvider
-import com.android.settings.biometrics.fingerprint2.enrollment.ui.viewmodel.FingerprintEnrollmentNavigationViewModel
+import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintEnrollmentNavigationViewModel
 
 /**
  * A fragment to indicate that fingerprint enrollment has been completed.
diff --git a/src/com/android/settings/biometrics/fingerprint2/enrollment/ui/fragment/FingerprintEnrollEnrollingV2Fragment.kt b/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/fragment/FingerprintEnrollEnrollingV2Fragment.kt
similarity index 85%
rename from src/com/android/settings/biometrics/fingerprint2/enrollment/ui/fragment/FingerprintEnrollEnrollingV2Fragment.kt
rename to src/com/android/settings/biometrics/fingerprint2/ui/enrollment/fragment/FingerprintEnrollEnrollingV2Fragment.kt
index 846bad7..915aa1f 100644
--- a/src/com/android/settings/biometrics/fingerprint2/enrollment/ui/fragment/FingerprintEnrollEnrollingV2Fragment.kt
+++ b/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/fragment/FingerprintEnrollEnrollingV2Fragment.kt
@@ -14,12 +14,12 @@
  * limitations under the License.
  */
 
-package com.android.settings.biometrics.fingerprint2.enrollment.ui.fragment
+package com.android.settings.biometrics.fingerprint2.ui.enrollment.fragment
 
 import android.os.Bundle
 import androidx.fragment.app.Fragment
 import androidx.lifecycle.ViewModelProvider
-import com.android.settings.biometrics.fingerprint2.enrollment.ui.viewmodel.FingerprintEnrollmentNavigationViewModel
+import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintEnrollmentNavigationViewModel
 
 /** A fragment that is responsible for enrolling a users fingerprint. */
 class FingerprintEnrollEnrollingV2Fragment : Fragment() {
diff --git a/src/com/android/settings/biometrics/fingerprint2/enrollment/ui/fragment/FingerprintEnrollFindSensorV2Fragment.kt b/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/fragment/FingerprintEnrollFindSensorV2Fragment.kt
similarity index 88%
rename from src/com/android/settings/biometrics/fingerprint2/enrollment/ui/fragment/FingerprintEnrollFindSensorV2Fragment.kt
rename to src/com/android/settings/biometrics/fingerprint2/ui/enrollment/fragment/FingerprintEnrollFindSensorV2Fragment.kt
index 6b07467..e9e1db2 100644
--- a/src/com/android/settings/biometrics/fingerprint2/enrollment/ui/fragment/FingerprintEnrollFindSensorV2Fragment.kt
+++ b/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/fragment/FingerprintEnrollFindSensorV2Fragment.kt
@@ -14,13 +14,13 @@
  * limitations under the License.
  */
 
-package com.android.settings.biometrics.fingerprint2.enrollment.ui.fragment
+package com.android.settings.biometrics.fingerprint2.ui.enrollment.fragment
 
 import android.os.Bundle
 import androidx.fragment.app.Fragment
 import androidx.lifecycle.ViewModelProvider
 import com.android.settings.R
-import com.android.settings.biometrics.fingerprint2.enrollment.ui.viewmodel.FingerprintEnrollmentNavigationViewModel
+import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintEnrollmentNavigationViewModel
 
 /**
  * A fragment that is used to educate the user about the fingerprint sensor on this device.
diff --git a/src/com/android/settings/biometrics/fingerprint2/enrollment/ui/fragment/FingerprintEnrollmentIntroV2Fragment.kt b/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/fragment/FingerprintEnrollmentIntroV2Fragment.kt
similarity index 95%
rename from src/com/android/settings/biometrics/fingerprint2/enrollment/ui/fragment/FingerprintEnrollmentIntroV2Fragment.kt
rename to src/com/android/settings/biometrics/fingerprint2/ui/enrollment/fragment/FingerprintEnrollmentIntroV2Fragment.kt
index 14229ee..88f8391 100644
--- a/src/com/android/settings/biometrics/fingerprint2/enrollment/ui/fragment/FingerprintEnrollmentIntroV2Fragment.kt
+++ b/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/fragment/FingerprintEnrollmentIntroV2Fragment.kt
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.settings.biometrics.fingerprint2.enrollment.ui.fragment
+package com.android.settings.biometrics.fingerprint2.ui.enrollment.fragment
 
 import android.annotation.NonNull
 import android.annotation.StringRes
@@ -34,11 +34,11 @@
 import androidx.lifecycle.ViewModelProvider
 import androidx.lifecycle.lifecycleScope
 import com.android.settings.R
-import com.android.settings.biometrics.fingerprint2.enrollment.ui.viewmodel.FingerprintEnrollmentNavigationViewModel
-import com.android.settings.biometrics.fingerprint2.enrollment.ui.viewmodel.FingerprintGatekeeperViewModel
-import com.android.settings.biometrics.fingerprint2.enrollment.ui.viewmodel.FingerprintScrollViewModel
-import com.android.settings.biometrics.fingerprint2.enrollment.ui.viewmodel.FingerprintViewModel
-import com.android.settings.biometrics.fingerprint2.enrollment.ui.viewmodel.Unicorn
+import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintEnrollmentNavigationViewModel
+import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintGatekeeperViewModel
+import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintScrollViewModel
+import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintViewModel
+import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.Unicorn
 import com.google.android.setupcompat.template.FooterBarMixin
 import com.google.android.setupcompat.template.FooterButton
 import com.google.android.setupdesign.GlifLayout
diff --git a/src/com/android/settings/biometrics/fingerprint2/enrollment/ui/viewmodel/FingerprintEnrolllmentNavigationViewModel.kt b/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/viewmodel/FingerprintEnrolllmentNavigationViewModel.kt
similarity index 98%
rename from src/com/android/settings/biometrics/fingerprint2/enrollment/ui/viewmodel/FingerprintEnrolllmentNavigationViewModel.kt
rename to src/com/android/settings/biometrics/fingerprint2/ui/enrollment/viewmodel/FingerprintEnrolllmentNavigationViewModel.kt
index d074fdd..6a8a8c4 100644
--- a/src/com/android/settings/biometrics/fingerprint2/enrollment/ui/viewmodel/FingerprintEnrolllmentNavigationViewModel.kt
+++ b/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/viewmodel/FingerprintEnrolllmentNavigationViewModel.kt
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.settings.biometrics.fingerprint2.enrollment.ui.viewmodel
+package com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel
 
 import android.util.Log
 import androidx.lifecycle.ViewModel
diff --git a/src/com/android/settings/biometrics/fingerprint2/enrollment/ui/viewmodel/FingerprintGatekeeperViewModel.kt b/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/viewmodel/FingerprintGatekeeperViewModel.kt
similarity index 98%
rename from src/com/android/settings/biometrics/fingerprint2/enrollment/ui/viewmodel/FingerprintGatekeeperViewModel.kt
rename to src/com/android/settings/biometrics/fingerprint2/ui/enrollment/viewmodel/FingerprintGatekeeperViewModel.kt
index 8079f7a..5486e7a 100644
--- a/src/com/android/settings/biometrics/fingerprint2/enrollment/ui/viewmodel/FingerprintGatekeeperViewModel.kt
+++ b/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/viewmodel/FingerprintGatekeeperViewModel.kt
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.settings.biometrics.fingerprint2.enrollment.ui.viewmodel
+package com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel
 
 import android.os.CountDownTimer
 import android.util.Log
diff --git a/src/com/android/settings/biometrics/fingerprint2/enrollment/ui/viewmodel/FingerprintScrollViewModel.kt b/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/viewmodel/FingerprintScrollViewModel.kt
similarity index 95%
rename from src/com/android/settings/biometrics/fingerprint2/enrollment/ui/viewmodel/FingerprintScrollViewModel.kt
rename to src/com/android/settings/biometrics/fingerprint2/ui/enrollment/viewmodel/FingerprintScrollViewModel.kt
index ad90fc7..d79d9c0 100644
--- a/src/com/android/settings/biometrics/fingerprint2/enrollment/ui/viewmodel/FingerprintScrollViewModel.kt
+++ b/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/viewmodel/FingerprintScrollViewModel.kt
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.settings.biometrics.fingerprint2.enrollment.ui.viewmodel
+package com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel
 
 import androidx.lifecycle.ViewModel
 import androidx.lifecycle.ViewModelProvider
diff --git a/src/com/android/settings/biometrics/fingerprint2/enrollment/ui/viewmodel/FingerprintStateViewModel.kt b/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/viewmodel/FingerprintStateViewModel.kt
similarity index 78%
rename from src/com/android/settings/biometrics/fingerprint2/enrollment/ui/viewmodel/FingerprintStateViewModel.kt
rename to src/com/android/settings/biometrics/fingerprint2/ui/enrollment/viewmodel/FingerprintStateViewModel.kt
index 1acd15a..20e3a0a 100644
--- a/src/com/android/settings/biometrics/fingerprint2/enrollment/ui/viewmodel/FingerprintStateViewModel.kt
+++ b/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/viewmodel/FingerprintStateViewModel.kt
@@ -14,13 +14,13 @@
  * limitations under the License.
  */
 
-package com.android.settings.biometrics.fingerprint2.enrollment.ui.viewmodel
+package com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel
 
-import android.hardware.fingerprint.FingerprintSensorPropertiesInternal
 import androidx.lifecycle.ViewModel
 import androidx.lifecycle.ViewModelProvider
 import androidx.lifecycle.viewModelScope
 import com.android.settings.biometrics.fingerprint2.domain.interactor.FingerprintManagerInteractor
+import com.android.settings.biometrics.fingerprint2.shared.model.FingerprintStateViewModel
 import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.MutableStateFlow
 import kotlinx.coroutines.flow.asStateFlow
@@ -28,21 +28,6 @@
 import kotlinx.coroutines.flow.update
 import kotlinx.coroutines.launch
 
-/** Represents the fingerprint data nad the relevant state. */
-data class FingerprintStateViewModel(
-  val fingerprintViewModels: List<FingerEnrollmentViewModel>,
-  val canEnroll: Boolean,
-  val maxFingerprints: Int,
-  val sensorProps: FingerprintSensorPropertiesInternal,
-)
-
-/** Represents a fingerprint enrollment. */
-data class FingerEnrollmentViewModel(
-  val name: String,
-  val fingerId: Int,
-  val deviceId: Long,
-)
-
 /** Represents all of the fingerprint information needed for fingerprint enrollment. */
 class FingerprintViewModel(fingerprintManagerInteractor: FingerprintManagerInteractor) :
   ViewModel() {
@@ -61,7 +46,11 @@
     viewModelScope.launch {
       val enrolledFingerprints =
         fingerprintManagerInteractor.enrolledFingerprints.last().map {
-          FingerEnrollmentViewModel(it.name, it.fingerId, it.deviceId)
+          com.android.settings.biometrics.fingerprint2.shared.model.FingerprintViewModel(
+            it.name,
+            it.fingerId,
+            it.deviceId
+          )
         }
       val sensorProps = fingerprintManagerInteractor.sensorPropertiesInternal().first()
       val maxFingerprints = 5
@@ -70,6 +59,8 @@
           enrolledFingerprints,
           enrolledFingerprints.size < maxFingerprints,
           maxFingerprints,
+          sensorProps.isAnySidefpsType,
+          false,
           sensorProps,
         )
       }
diff --git a/src/com/android/settings/biometrics/fingerprint2/enrollment/ui/viewmodel/NextStepViewModel.kt b/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/viewmodel/NextStepViewModel.kt
similarity index 97%
rename from src/com/android/settings/biometrics/fingerprint2/enrollment/ui/viewmodel/NextStepViewModel.kt
rename to src/com/android/settings/biometrics/fingerprint2/ui/enrollment/viewmodel/NextStepViewModel.kt
index a8a8077..e99b8f9 100644
--- a/src/com/android/settings/biometrics/fingerprint2/enrollment/ui/viewmodel/NextStepViewModel.kt
+++ b/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/viewmodel/NextStepViewModel.kt
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.settings.biometrics.fingerprint2.enrollment.ui.viewmodel
+package com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel
 
 /**
  * A class that represents an action that the consumer should transition between lastStep and
diff --git a/src/com/android/settings/biometrics/fingerprint2/ui/settings/README.md b/src/com/android/settings/biometrics/fingerprint2/ui/settings/README.md
new file mode 100644
index 0000000..461ffc2
--- /dev/null
+++ b/src/com/android/settings/biometrics/fingerprint2/ui/settings/README.md
@@ -0,0 +1,17 @@
+### Fingerprint Settings Enrollment
+
+#### Entry Point (For Fingerprint Settings)
+
+* [SecuritySettings] (https://cs.android.com/android/platform/superproject/+/master:packages/apps/Settings/src/com/android/settings/security/SecuritySettings.java;l=40?q=SecuritySettings)
+
+#### General Architecture
+
+The code should follow the MVVM architecture.
+
+The FingerprintSettingsV2Fragment is responsible for most of the heavy lifting. It should coordinate
+navigation events, maintain the viewmodels, and launch new activities if need be.
+
+#### Style
+
+* Please use [kfmt](https://plugins.jetbrains.com/plugin/14912-ktfmt)
+
diff --git a/src/com/android/settings/biometrics/fingerprint2/ui/binder/FingerprintSettingsViewBinder.kt b/src/com/android/settings/biometrics/fingerprint2/ui/settings/binder/FingerprintSettingsViewBinder.kt
similarity index 81%
rename from src/com/android/settings/biometrics/fingerprint2/ui/binder/FingerprintSettingsViewBinder.kt
rename to src/com/android/settings/biometrics/fingerprint2/ui/settings/binder/FingerprintSettingsViewBinder.kt
index d9f3e43..6a44630 100644
--- a/src/com/android/settings/biometrics/fingerprint2/ui/binder/FingerprintSettingsViewBinder.kt
+++ b/src/com/android/settings/biometrics/fingerprint2/ui/settings/binder/FingerprintSettingsViewBinder.kt
@@ -14,25 +14,25 @@
  * limitations under the License.
  */
 
-package com.android.settings.biometrics.fingerprint2.ui.binder
+package com.android.settings.biometrics.fingerprint2.ui.settings.binder
 
 import android.hardware.fingerprint.FingerprintManager
 import android.util.Log
 import androidx.lifecycle.LifecycleCoroutineScope
-import com.android.settings.biometrics.fingerprint2.ui.binder.FingerprintSettingsViewBinder.FingerprintView
-import com.android.settings.biometrics.fingerprint2.ui.viewmodel.EnrollAdditionalFingerprint
-import com.android.settings.biometrics.fingerprint2.ui.viewmodel.EnrollFirstFingerprint
-import com.android.settings.biometrics.fingerprint2.ui.viewmodel.FingerprintAuthAttemptViewModel
-import com.android.settings.biometrics.fingerprint2.ui.viewmodel.FingerprintSettingsNavigationViewModel
-import com.android.settings.biometrics.fingerprint2.ui.viewmodel.FingerprintSettingsViewModel
-import com.android.settings.biometrics.fingerprint2.ui.viewmodel.FingerprintStateViewModel
-import com.android.settings.biometrics.fingerprint2.ui.viewmodel.FingerprintViewModel
-import com.android.settings.biometrics.fingerprint2.ui.viewmodel.FinishSettings
-import com.android.settings.biometrics.fingerprint2.ui.viewmodel.FinishSettingsWithResult
-import com.android.settings.biometrics.fingerprint2.ui.viewmodel.LaunchConfirmDeviceCredential
-import com.android.settings.biometrics.fingerprint2.ui.viewmodel.LaunchedActivity
-import com.android.settings.biometrics.fingerprint2.ui.viewmodel.PreferenceViewModel
-import com.android.settings.biometrics.fingerprint2.ui.viewmodel.ShowSettings
+import com.android.settings.biometrics.fingerprint2.shared.model.FingerprintAuthAttemptViewModel
+import com.android.settings.biometrics.fingerprint2.shared.model.FingerprintStateViewModel
+import com.android.settings.biometrics.fingerprint2.shared.model.FingerprintViewModel
+import com.android.settings.biometrics.fingerprint2.ui.settings.binder.FingerprintSettingsViewBinder.FingerprintView
+import com.android.settings.biometrics.fingerprint2.ui.settings.viewmodel.EnrollAdditionalFingerprint
+import com.android.settings.biometrics.fingerprint2.ui.settings.viewmodel.EnrollFirstFingerprint
+import com.android.settings.biometrics.fingerprint2.ui.settings.viewmodel.FingerprintSettingsNavigationViewModel
+import com.android.settings.biometrics.fingerprint2.ui.settings.viewmodel.FingerprintSettingsViewModel
+import com.android.settings.biometrics.fingerprint2.ui.settings.viewmodel.FinishSettings
+import com.android.settings.biometrics.fingerprint2.ui.settings.viewmodel.FinishSettingsWithResult
+import com.android.settings.biometrics.fingerprint2.ui.settings.viewmodel.LaunchConfirmDeviceCredential
+import com.android.settings.biometrics.fingerprint2.ui.settings.viewmodel.LaunchedActivity
+import com.android.settings.biometrics.fingerprint2.ui.settings.viewmodel.PreferenceViewModel
+import com.android.settings.biometrics.fingerprint2.ui.settings.viewmodel.ShowSettings
 import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.Job
 import kotlinx.coroutines.flow.collectLatest
diff --git a/src/com/android/settings/biometrics/fingerprint2/ui/fragment/FingerprintDeletionDialog.kt b/src/com/android/settings/biometrics/fingerprint2/ui/settings/fragment/FingerprintDeletionDialog.kt
similarity index 96%
rename from src/com/android/settings/biometrics/fingerprint2/ui/fragment/FingerprintDeletionDialog.kt
rename to src/com/android/settings/biometrics/fingerprint2/ui/settings/fragment/FingerprintDeletionDialog.kt
index 42e2047..32b50c5 100644
--- a/src/com/android/settings/biometrics/fingerprint2/ui/fragment/FingerprintDeletionDialog.kt
+++ b/src/com/android/settings/biometrics/fingerprint2/ui/settings/fragment/FingerprintDeletionDialog.kt
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.settings.biometrics.fingerprint2.ui.fragment
+package com.android.settings.biometrics.fingerprint2.ui.settings.fragment
 
 import android.app.Dialog
 import android.app.admin.DevicePolicyManager
@@ -26,7 +26,7 @@
 import android.os.UserManager
 import androidx.appcompat.app.AlertDialog
 import com.android.settings.R
-import com.android.settings.biometrics.fingerprint2.ui.viewmodel.FingerprintViewModel
+import com.android.settings.biometrics.fingerprint2.shared.model.FingerprintViewModel
 import com.android.settings.core.instrumentation.InstrumentedDialogFragment
 import kotlin.coroutines.resume
 import kotlinx.coroutines.suspendCancellableCoroutine
diff --git a/src/com/android/settings/biometrics/fingerprint2/ui/fragment/FingerprintSettingsPreference.kt b/src/com/android/settings/biometrics/fingerprint2/ui/settings/fragment/FingerprintSettingsPreference.kt
similarity index 95%
rename from src/com/android/settings/biometrics/fingerprint2/ui/fragment/FingerprintSettingsPreference.kt
rename to src/com/android/settings/biometrics/fingerprint2/ui/settings/fragment/FingerprintSettingsPreference.kt
index e12785d..b1e5097 100644
--- a/src/com/android/settings/biometrics/fingerprint2/ui/fragment/FingerprintSettingsPreference.kt
+++ b/src/com/android/settings/biometrics/fingerprint2/ui/settings/fragment/FingerprintSettingsPreference.kt
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.settings.biometrics.fingerprint2.ui.fragment
+package com.android.settings.biometrics.fingerprint2.ui.settings.fragment
 
 import android.content.Context
 import android.util.Log
@@ -22,7 +22,7 @@
 import androidx.lifecycle.lifecycleScope
 import androidx.preference.PreferenceViewHolder
 import com.android.settings.R
-import com.android.settings.biometrics.fingerprint2.ui.viewmodel.FingerprintViewModel
+import com.android.settings.biometrics.fingerprint2.shared.model.FingerprintViewModel
 import com.android.settingslib.widget.TwoTargetPreference
 import kotlinx.coroutines.delay
 import kotlinx.coroutines.launch
diff --git a/src/com/android/settings/biometrics/fingerprint2/ui/fragment/FingerprintSettingsRenameDialog.kt b/src/com/android/settings/biometrics/fingerprint2/ui/settings/fragment/FingerprintSettingsRenameDialog.kt
similarity index 94%
rename from src/com/android/settings/biometrics/fingerprint2/ui/fragment/FingerprintSettingsRenameDialog.kt
rename to src/com/android/settings/biometrics/fingerprint2/ui/settings/fragment/FingerprintSettingsRenameDialog.kt
index 9542ed8..0ebc561 100644
--- a/src/com/android/settings/biometrics/fingerprint2/ui/fragment/FingerprintSettingsRenameDialog.kt
+++ b/src/com/android/settings/biometrics/fingerprint2/ui/settings/fragment/FingerprintSettingsRenameDialog.kt
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.settings.biometrics.fingerprint2.ui.fragment
+package com.android.settings.biometrics.fingerprint2.ui.settings.fragment
 
 import android.app.Dialog
 import android.app.settings.SettingsEnums
@@ -27,7 +27,7 @@
 import android.widget.ImeAwareEditText
 import androidx.appcompat.app.AlertDialog
 import com.android.settings.R
-import com.android.settings.biometrics.fingerprint2.ui.viewmodel.FingerprintViewModel
+import com.android.settings.biometrics.fingerprint2.shared.model.FingerprintViewModel
 import com.android.settings.core.instrumentation.InstrumentedDialogFragment
 import kotlin.coroutines.resume
 import kotlinx.coroutines.suspendCancellableCoroutine
@@ -106,8 +106,8 @@
         val dialog = FingerprintSettingsRenameDialog()
         val onClick =
           DialogInterface.OnClickListener { _, _ ->
-            val dialogTextField = dialog.requireDialog()
-                .requireViewById(R.id.fingerprint_rename_field) as ImeAwareEditText
+            val dialogTextField =
+              dialog.requireDialog().findViewById(R.id.fingerprint_rename_field) as ImeAwareEditText
             val newName = dialogTextField.text.toString()
             if (!TextUtils.equals(newName, fp.name)) {
               Log.d(TAG, "rename $fp.name to $newName for $dialog")
diff --git a/src/com/android/settings/biometrics/fingerprint2/ui/fragment/FingerprintSettingsV2Fragment.kt b/src/com/android/settings/biometrics/fingerprint2/ui/settings/fragment/FingerprintSettingsV2Fragment.kt
similarity index 96%
rename from src/com/android/settings/biometrics/fingerprint2/ui/fragment/FingerprintSettingsV2Fragment.kt
rename to src/com/android/settings/biometrics/fingerprint2/ui/settings/fragment/FingerprintSettingsV2Fragment.kt
index b82f7c1..7dcf46a 100644
--- a/src/com/android/settings/biometrics/fingerprint2/ui/fragment/FingerprintSettingsV2Fragment.kt
+++ b/src/com/android/settings/biometrics/fingerprint2/ui/settings/fragment/FingerprintSettingsV2Fragment.kt
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.settings.biometrics.fingerprint2.ui.fragment
+package com.android.settings.biometrics.fingerprint2.ui.settings.fragment
 
 import android.app.Activity
 import android.app.admin.DevicePolicyManager
@@ -26,7 +26,6 @@
 import android.os.Bundle
 import android.provider.Settings.Secure
 import android.text.TextUtils
-import android.util.FeatureFlagUtils
 import android.util.Log
 import android.view.View
 import android.widget.Toast
@@ -47,12 +46,12 @@
 import com.android.settings.biometrics.fingerprint.FingerprintEnrollEnrolling
 import com.android.settings.biometrics.fingerprint.FingerprintEnrollIntroductionInternal
 import com.android.settings.biometrics.fingerprint2.domain.interactor.FingerprintManagerInteractorImpl
-import com.android.settings.biometrics.fingerprint2.ui.binder.FingerprintSettingsViewBinder
-import com.android.settings.biometrics.fingerprint2.ui.viewmodel.FingerprintAuthAttemptViewModel
-import com.android.settings.biometrics.fingerprint2.ui.viewmodel.FingerprintSettingsNavigationViewModel
-import com.android.settings.biometrics.fingerprint2.ui.viewmodel.FingerprintSettingsViewModel
-import com.android.settings.biometrics.fingerprint2.ui.viewmodel.FingerprintStateViewModel
-import com.android.settings.biometrics.fingerprint2.ui.viewmodel.FingerprintViewModel
+import com.android.settings.biometrics.fingerprint2.shared.model.FingerprintAuthAttemptViewModel
+import com.android.settings.biometrics.fingerprint2.shared.model.FingerprintStateViewModel
+import com.android.settings.biometrics.fingerprint2.shared.model.FingerprintViewModel
+import com.android.settings.biometrics.fingerprint2.ui.settings.binder.FingerprintSettingsViewBinder
+import com.android.settings.biometrics.fingerprint2.ui.settings.viewmodel.FingerprintSettingsNavigationViewModel
+import com.android.settings.biometrics.fingerprint2.ui.settings.viewmodel.FingerprintSettingsViewModel
 import com.android.settings.core.SettingsBaseActivity
 import com.android.settings.core.instrumentation.InstrumentedDialogFragment
 import com.android.settings.dashboard.DashboardFragment
@@ -164,6 +163,7 @@
       Log.d(TAG, "onCreate()")
     }
 
+    /*
     if (
       !FeatureFlagUtils.isEnabled(
         context,
@@ -175,6 +175,8 @@
       return
     }
 
+     */
+
     val context = requireContext()
     val userId = context.userId
 
diff --git a/src/com/android/settings/biometrics/fingerprint2/ui/viewmodel/FingerprintSettingsNavigationViewModel.kt b/src/com/android/settings/biometrics/fingerprint2/ui/settings/viewmodel/FingerprintSettingsNavigationViewModel.kt
similarity index 98%
rename from src/com/android/settings/biometrics/fingerprint2/ui/viewmodel/FingerprintSettingsNavigationViewModel.kt
rename to src/com/android/settings/biometrics/fingerprint2/ui/settings/viewmodel/FingerprintSettingsNavigationViewModel.kt
index a638806..538bb6d 100644
--- a/src/com/android/settings/biometrics/fingerprint2/ui/viewmodel/FingerprintSettingsNavigationViewModel.kt
+++ b/src/com/android/settings/biometrics/fingerprint2/ui/settings/viewmodel/FingerprintSettingsNavigationViewModel.kt
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.settings.biometrics.fingerprint2.ui.viewmodel
+package com.android.settings.biometrics.fingerprint2.ui.settings.viewmodel
 
 import android.hardware.fingerprint.FingerprintManager
 import androidx.lifecycle.ViewModel
diff --git a/src/com/android/settings/biometrics/fingerprint2/ui/viewmodel/FingerprintSettingsViewModel.kt b/src/com/android/settings/biometrics/fingerprint2/ui/settings/viewmodel/FingerprintSettingsViewModel.kt
similarity index 95%
rename from src/com/android/settings/biometrics/fingerprint2/ui/viewmodel/FingerprintSettingsViewModel.kt
rename to src/com/android/settings/biometrics/fingerprint2/ui/settings/viewmodel/FingerprintSettingsViewModel.kt
index 0bae075..fbd0f1d 100644
--- a/src/com/android/settings/biometrics/fingerprint2/ui/viewmodel/FingerprintSettingsViewModel.kt
+++ b/src/com/android/settings/biometrics/fingerprint2/ui/settings/viewmodel/FingerprintSettingsViewModel.kt
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.settings.biometrics.fingerprint2.ui.viewmodel
+package com.android.settings.biometrics.fingerprint2.ui.settings.viewmodel
 
 import android.hardware.fingerprint.FingerprintManager
 import android.hardware.fingerprint.FingerprintSensorProperties
@@ -24,6 +24,9 @@
 import androidx.lifecycle.ViewModelProvider
 import androidx.lifecycle.viewModelScope
 import com.android.settings.biometrics.fingerprint2.domain.interactor.FingerprintManagerInteractor
+import com.android.settings.biometrics.fingerprint2.shared.model.FingerprintAuthAttemptViewModel
+import com.android.settings.biometrics.fingerprint2.shared.model.FingerprintStateViewModel
+import com.android.settings.biometrics.fingerprint2.shared.model.FingerprintViewModel
 import kotlinx.coroutines.CoroutineDispatcher
 import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.MutableSharedFlow
@@ -270,7 +273,8 @@
         canEnrollFingerprint,
         maxFingerprints,
         hasSideFps,
-        pressToAuthEnabled
+        pressToAuthEnabled,
+        fingerprintManagerInteractor.sensorPropertiesInternal().first(),
       )
     }
   }
diff --git a/src/com/android/settings/biometrics/fingerprint2/ui/viewmodel/NextStepViewModel.kt b/src/com/android/settings/biometrics/fingerprint2/ui/settings/viewmodel/NextStepViewModel.kt
similarity index 94%
rename from src/com/android/settings/biometrics/fingerprint2/ui/viewmodel/NextStepViewModel.kt
rename to src/com/android/settings/biometrics/fingerprint2/ui/settings/viewmodel/NextStepViewModel.kt
index f9dbbff..d9155b6 100644
--- a/src/com/android/settings/biometrics/fingerprint2/ui/viewmodel/NextStepViewModel.kt
+++ b/src/com/android/settings/biometrics/fingerprint2/ui/settings/viewmodel/NextStepViewModel.kt
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.settings.biometrics.fingerprint2.ui.viewmodel
+package com.android.settings.biometrics.fingerprint2.ui.settings.viewmodel
 
 /**
  * A class to represent a high level step for FingerprintSettings. This is typically to perform an
diff --git a/src/com/android/settings/biometrics/fingerprint2/ui/viewmodel/PreferenceViewModel.kt b/src/com/android/settings/biometrics/fingerprint2/ui/settings/viewmodel/PreferenceViewModel.kt
similarity index 84%
rename from src/com/android/settings/biometrics/fingerprint2/ui/viewmodel/PreferenceViewModel.kt
rename to src/com/android/settings/biometrics/fingerprint2/ui/settings/viewmodel/PreferenceViewModel.kt
index 05764a2..4c33f7f 100644
--- a/src/com/android/settings/biometrics/fingerprint2/ui/viewmodel/PreferenceViewModel.kt
+++ b/src/com/android/settings/biometrics/fingerprint2/ui/settings/viewmodel/PreferenceViewModel.kt
@@ -14,7 +14,9 @@
  * limitations under the License.
  */
 
-package com.android.settings.biometrics.fingerprint2.ui.viewmodel
+package com.android.settings.biometrics.fingerprint2.ui.settings.viewmodel
+
+import com.android.settings.biometrics.fingerprint2.shared.model.FingerprintViewModel
 
 /** Classed use to represent a Dialogs state. */
 sealed class PreferenceViewModel {
diff --git a/src/com/android/settings/bluetooth/BluetoothDetailsHeaderController.java b/src/com/android/settings/bluetooth/BluetoothDetailsHeaderController.java
index 8f90b28..5ffa8cf 100644
--- a/src/com/android/settings/bluetooth/BluetoothDetailsHeaderController.java
+++ b/src/com/android/settings/bluetooth/BluetoothDetailsHeaderController.java
@@ -29,8 +29,6 @@
 import com.android.settings.widget.EntityHeaderController;
 import com.android.settingslib.bluetooth.BluetoothUtils;
 import com.android.settingslib.bluetooth.CachedBluetoothDevice;
-import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager;
-import com.android.settingslib.bluetooth.LocalBluetoothManager;
 import com.android.settingslib.core.lifecycle.Lifecycle;
 import com.android.settingslib.widget.LayoutPreference;
 
@@ -41,15 +39,10 @@
     private static final String KEY_DEVICE_HEADER = "bluetooth_device_header";
 
     private EntityHeaderController mHeaderController;
-    private LocalBluetoothManager mLocalManager;
-    private CachedBluetoothDeviceManager mDeviceManager;
 
     public BluetoothDetailsHeaderController(Context context, PreferenceFragmentCompat fragment,
-            CachedBluetoothDevice device, Lifecycle lifecycle,
-            LocalBluetoothManager bluetoothManager) {
+            CachedBluetoothDevice device, Lifecycle lifecycle) {
         super(context, fragment, device, lifecycle);
-        mLocalManager = bluetoothManager;
-        mDeviceManager = mLocalManager.getCachedDeviceManager();
     }
 
     @Override
@@ -87,7 +80,7 @@
     protected void refresh() {
         if (isAvailable()) {
             setHeaderProperties();
-            mHeaderController.done(mFragment.getActivity(), true /* rebindActions */);
+            mHeaderController.done(true /* rebindActions */);
         }
     }
 
diff --git a/src/com/android/settings/bluetooth/BluetoothDetailsSpatialAudioController.java b/src/com/android/settings/bluetooth/BluetoothDetailsSpatialAudioController.java
index a1e133e..bec6b03 100644
--- a/src/com/android/settings/bluetooth/BluetoothDetailsSpatialAudioController.java
+++ b/src/com/android/settings/bluetooth/BluetoothDetailsSpatialAudioController.java
@@ -16,6 +16,8 @@
 
 package com.android.settings.bluetooth;
 
+import static android.media.Spatializer.SPATIALIZER_IMMERSIVE_LEVEL_NONE;
+
 import android.content.Context;
 import android.media.AudioDeviceAttributes;
 import android.media.AudioDeviceInfo;
@@ -106,6 +108,10 @@
 
     @Override
     protected void refresh() {
+        if (mAudioDevice == null) {
+            return;
+        }
+
         SwitchPreference spatialAudioPref = mProfilesContainer.findPreference(KEY_SPATIAL_AUDIO);
         if (spatialAudioPref == null) {
             spatialAudioPref = createSpatialAudioPreference(mProfilesContainer.getContext());
@@ -152,6 +158,14 @@
     }
 
     private void getAvailableDevice() {
+        if (mSpatializer.getImmersiveAudioLevel() == SPATIALIZER_IMMERSIVE_LEVEL_NONE) {
+            mIsAvailable = false;
+            mAudioDevice = null;
+            Log.d(TAG, "getAvailableDevice() ignored: spatializer not supported");
+
+            return;
+        }
+
         AudioDeviceAttributes a2dpDevice = new AudioDeviceAttributes(
                 AudioDeviceAttributes.ROLE_OUTPUT,
                 AudioDeviceInfo.TYPE_BLUETOOTH_A2DP,
diff --git a/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragment.java b/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragment.java
index f9afa5b..bf8ed77 100644
--- a/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragment.java
+++ b/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragment.java
@@ -295,7 +295,7 @@
         if (mCachedDevice != null) {
             Lifecycle lifecycle = getSettingsLifecycle();
             controllers.add(new BluetoothDetailsHeaderController(context, this, mCachedDevice,
-                    lifecycle, mManager));
+                    lifecycle));
             controllers.add(new BluetoothDetailsButtonsController(context, this, mCachedDevice,
                     lifecycle));
             controllers.add(new BluetoothDetailsCompanionAppsController(context, this,
diff --git a/src/com/android/settings/connecteddevice/stylus/UsbStylusBroadcastReceiver.java b/src/com/android/settings/connecteddevice/stylus/UsbStylusBroadcastReceiver.java
index 8c8b4fd..10b875f 100644
--- a/src/com/android/settings/connecteddevice/stylus/UsbStylusBroadcastReceiver.java
+++ b/src/com/android/settings/connecteddevice/stylus/UsbStylusBroadcastReceiver.java
@@ -41,6 +41,7 @@
             final IntentFilter intentFilter = new IntentFilter();
             intentFilter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED);
             intentFilter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED);
+            intentFilter.addAction(UsbManager.ACTION_USB_STATE);
             final Intent intent = mContext.registerReceiver(this, intentFilter);
             if (intent != null) {
                 onReceive(mContext, intent);
diff --git a/src/com/android/settings/connecteddevice/usb/UsbDetailsHeaderController.java b/src/com/android/settings/connecteddevice/usb/UsbDetailsHeaderController.java
index e151258..39d7c75 100644
--- a/src/com/android/settings/connecteddevice/usb/UsbDetailsHeaderController.java
+++ b/src/com/android/settings/connecteddevice/usb/UsbDetailsHeaderController.java
@@ -50,7 +50,7 @@
     protected void refresh(boolean connected, long functions, int powerRole, int dataRole) {
         mHeaderController.setLabel(mContext.getString(R.string.usb_pref));
         mHeaderController.setIcon(mContext.getDrawable(R.drawable.ic_usb));
-        mHeaderController.done(mFragment.getActivity(), true /* rebindActions */);
+        mHeaderController.done(true /* rebindActions */);
     }
 
     @Override
diff --git a/src/com/android/settings/core/gateway/SettingsGateway.java b/src/com/android/settings/core/gateway/SettingsGateway.java
index a06af8e..f269ed1 100644
--- a/src/com/android/settings/core/gateway/SettingsGateway.java
+++ b/src/com/android/settings/core/gateway/SettingsGateway.java
@@ -72,7 +72,7 @@
 import com.android.settings.biometrics.combination.CombinedBiometricSettings;
 import com.android.settings.biometrics.face.FaceSettings;
 import com.android.settings.biometrics.fingerprint.FingerprintSettings;
-import com.android.settings.biometrics.fingerprint2.ui.fragment.FingerprintSettingsV2Fragment;
+import com.android.settings.biometrics.fingerprint2.ui.settings.fragment.FingerprintSettingsV2Fragment;
 import com.android.settings.bluetooth.BluetoothBroadcastDialog;
 import com.android.settings.bluetooth.BluetoothDeviceDetailsFragment;
 import com.android.settings.bluetooth.BluetoothFindBroadcastsFragment;
diff --git a/src/com/android/settings/datausage/AppDataUsage.java b/src/com/android/settings/datausage/AppDataUsage.java
index e15cead..c14c01b 100644
--- a/src/com/android/settings/datausage/AppDataUsage.java
+++ b/src/com/android/settings/datausage/AppDataUsage.java
@@ -417,7 +417,6 @@
         final Activity activity = getActivity();
         final Preference pref = EntityHeaderController
                 .newInstance(activity, this, null /* header */)
-                .setRecyclerView(getListView(), getSettingsLifecycle())
                 .setUid(uid)
                 .setHasAppInfoLink(showInfoButton)
                 .setButtonActions(EntityHeaderController.ActionType.ACTION_NONE,
@@ -425,7 +424,7 @@
                 .setIcon(mIcon)
                 .setLabel(mLabel)
                 .setPackageName(pkg)
-                .done(activity, getPrefContext());
+                .done(getPrefContext());
         getPreferenceScreen().addPreference(pref);
     }
 
diff --git a/src/com/android/settings/datausage/DataUsageInfoController.java b/src/com/android/settings/datausage/DataUsageInfoController.java
index a471c39..380322b 100644
--- a/src/com/android/settings/datausage/DataUsageInfoController.java
+++ b/src/com/android/settings/datausage/DataUsageInfoController.java
@@ -14,8 +14,6 @@
 
 package com.android.settings.datausage;
 
-import android.net.NetworkPolicy;
-
 import com.android.settingslib.net.DataUsageController.DataUsageInfo;
 
 /**
@@ -23,21 +21,6 @@
  */
 public class DataUsageInfoController {
     /**
-     * Take the cached data usage values in the NetworkPolicy to update DataUsageInfo.
-     */
-    public void updateDataLimit(DataUsageInfo info, NetworkPolicy policy) {
-        if (info == null || policy == null) {
-            return;
-        }
-        if (policy.warningBytes >= 0) {
-            info.warningLevel = policy.warningBytes;
-        }
-        if (policy.limitBytes >= 0) {
-            info.limitLevel = policy.limitBytes;
-        }
-    }
-
-    /**
      * @returns the most appropriate limit for the data usage summary. Use the total usage when it
      * is higher than the limit and warning level. Use the limit when it is set and less than usage.
      * Otherwise use warning level.
diff --git a/src/com/android/settings/datausage/DataUsageSummary.java b/src/com/android/settings/datausage/DataUsageSummary.java
index 25fc49b..68473b5 100644
--- a/src/com/android/settings/datausage/DataUsageSummary.java
+++ b/src/com/android/settings/datausage/DataUsageSummary.java
@@ -61,13 +61,6 @@
 
     // Mobile data keys
     public static final String KEY_MOBILE_USAGE_TITLE = "mobile_category";
-    public static final String KEY_MOBILE_DATA_USAGE_TOGGLE = "data_usage_enable";
-    public static final String KEY_MOBILE_DATA_USAGE = "cellular_data_usage";
-    public static final String KEY_MOBILE_BILLING_CYCLE = "billing_preference";
-
-    // Wifi keys
-    public static final String KEY_WIFI_USAGE_TITLE = "wifi_category";
-    public static final String KEY_WIFI_DATA_USAGE = "wifi_data_usage";
 
     private DataUsageSummaryPreference mSummaryPreference;
     private DataUsageSummaryPreferenceController mSummaryController;
@@ -161,7 +154,7 @@
             return controllers;
         }
         mSummaryController =
-                new DataUsageSummaryPreferenceController(activity, getSettingsLifecycle(), this,
+                new DataUsageSummaryPreferenceController(activity, this,
                         DataUsageUtils.getDefaultSubscriptionId(activity));
         controllers.add(mSummaryController);
         getSettingsLifecycle().addObserver(mSummaryController);
diff --git a/src/com/android/settings/datausage/DataUsageSummaryPreference.java b/src/com/android/settings/datausage/DataUsageSummaryPreference.java
index 86e01ed..a14fce3 100644
--- a/src/com/android/settings/datausage/DataUsageSummaryPreference.java
+++ b/src/com/android/settings/datausage/DataUsageSummaryPreference.java
@@ -67,15 +67,9 @@
     private CharSequence mStartLabel;
     private CharSequence mEndLabel;
 
-    /** large vs small size is 36/16 ~ 2.25 */
-    private static final float LARGER_FONT_RATIO = 2.25f;
-    private static final float SMALLER_FONT_RATIO = 1.0f;
-
-    private boolean mDefaultTextColorSet;
-    private int mDefaultTextColor;
     private int mNumPlans;
     /** The specified un-initialized value for cycle time */
-    private final long CYCLE_TIME_UNINITIAL_VALUE = 0;
+    private static final long CYCLE_TIME_UNINITIAL_VALUE = 0;
     /** The ending time of the billing cycle in milliseconds since epoch. */
     private long mCycleEndTimeMs;
     /** The time of the last update in standard milliseconds since the epoch */
diff --git a/src/com/android/settings/datausage/DataUsageSummaryPreferenceController.java b/src/com/android/settings/datausage/DataUsageSummaryPreferenceController.java
index fe20a01..4eb2a71 100644
--- a/src/com/android/settings/datausage/DataUsageSummaryPreferenceController.java
+++ b/src/com/android/settings/datausage/DataUsageSummaryPreferenceController.java
@@ -21,7 +21,6 @@
 import android.content.Intent;
 import android.content.pm.PackageManager;
 import android.net.INetworkPolicyManager;
-import android.net.NetworkPolicyManager;
 import android.net.NetworkTemplate;
 import android.os.ServiceManager;
 import android.telephony.SubscriptionInfo;
@@ -34,7 +33,6 @@
 import androidx.annotation.VisibleForTesting;
 import androidx.preference.Preference;
 import androidx.preference.PreferenceFragmentCompat;
-import androidx.recyclerview.widget.RecyclerView;
 
 import com.android.internal.util.CollectionUtils;
 import com.android.settings.R;
@@ -43,8 +41,6 @@
 import com.android.settings.network.ProxySubscriptionManager;
 import com.android.settings.network.telephony.TelephonyBasePreferenceController;
 import com.android.settings.widget.EntityHeaderController;
-import com.android.settingslib.NetworkPolicyEditor;
-import com.android.settingslib.core.lifecycle.Lifecycle;
 import com.android.settingslib.core.lifecycle.LifecycleObserver;
 import com.android.settingslib.core.lifecycle.events.OnStart;
 import com.android.settingslib.net.DataUsageController;
@@ -64,17 +60,12 @@
     private static final String TAG = "DataUsageController";
     private static final String KEY = "status_header";
     private static final long PETA = 1000000000000000L;
-    private static final float RELATIVE_SIZE_LARGE = 1.25f * 1.25f;  // (1/0.8)^2
-    private static final float RELATIVE_SIZE_SMALL = 1.0f / RELATIVE_SIZE_LARGE;  // 0.8^2
 
     private EntityHeaderController mEntityHeaderController;
-    private final Lifecycle mLifecycle;
     private final PreferenceFragmentCompat mFragment;
     protected DataUsageController mDataUsageController;
     protected DataUsageInfoController mDataInfoController;
     private NetworkTemplate mDefaultTemplate;
-    protected NetworkPolicyEditor mPolicyEditor;
-    private int mDataUsageTemplate;
     private boolean mHasMobileData;
 
     /** Name of the carrier, or null if not available */
@@ -95,8 +86,6 @@
     private long mDataBarSize;
     /** The number of bytes used since the start of the cycle. */
     private long mDataplanUse;
-    /** The starting time of the billing cycle in ms since the epoch */
-    private long mCycleStart;
     /** The ending time of the billing cycle in ms since the epoch */
     private long mCycleEnd;
 
@@ -104,11 +93,10 @@
 
     private Future<Long> mHistoricalUsageLevel;
 
-    public DataUsageSummaryPreferenceController(Activity activity,
-            Lifecycle lifecycle, PreferenceFragmentCompat fragment, int subscriptionId) {
+    public DataUsageSummaryPreferenceController(
+            Activity activity, PreferenceFragmentCompat fragment, int subscriptionId) {
         super(activity, KEY);
 
-        mLifecycle = lifecycle;
         mFragment = fragment;
         init(subscriptionId);
     }
@@ -125,22 +113,15 @@
 
     protected void updateConfiguration(Context context,
             int subscriptionId, SubscriptionInfo subInfo) {
-        final NetworkPolicyManager policyManager =
-                context.getSystemService(NetworkPolicyManager.class);
-        mPolicyEditor = new NetworkPolicyEditor(policyManager);
-
         mDataUsageController = createDataUsageController(context);
         mDataUsageController.setSubscriptionId(subscriptionId);
         mDataInfoController = new DataUsageInfoController();
 
         if (subInfo != null) {
-            mDataUsageTemplate = R.string.cell_data_template;
             mDefaultTemplate = DataUsageLib.getMobileTemplate(context, subscriptionId);
         } else if (DataUsageUtils.hasWifiRadio(context)) {
-            mDataUsageTemplate = R.string.wifi_data_template;
             mDefaultTemplate = new NetworkTemplate.Builder(NetworkTemplate.MATCH_WIFI).build();
         } else {
-            mDataUsageTemplate = R.string.ethernet_data_template;
             mDefaultTemplate = DataUsageUtils.getDefaultTemplate(context, subscriptionId);
         }
     }
@@ -155,10 +136,7 @@
             DataUsageController dataUsageController,
             DataUsageInfoController dataInfoController,
             NetworkTemplate defaultTemplate,
-            NetworkPolicyEditor policyEditor,
-            int dataUsageTemplate,
             Activity activity,
-            Lifecycle lifecycle,
             EntityHeaderController entityHeaderController,
             PreferenceFragmentCompat fragment,
             int subscriptionId) {
@@ -166,10 +144,7 @@
         mDataUsageController = dataUsageController;
         mDataInfoController = dataInfoController;
         mDefaultTemplate = defaultTemplate;
-        mPolicyEditor = policyEditor;
-        mDataUsageTemplate = dataUsageTemplate;
         mHasMobileData = true;
-        mLifecycle = lifecycle;
         mEntityHeaderController = entityHeaderController;
         mFragment = fragment;
         mSubId = subscriptionId;
@@ -181,8 +156,6 @@
             mEntityHeaderController =
                     EntityHeaderController.newInstance((Activity) mContext, mFragment, null);
         }
-        RecyclerView view = mFragment.getListView();
-        mEntityHeaderController.setRecyclerView(view, mLifecycle);
     }
 
     @VisibleForTesting
@@ -223,7 +196,6 @@
         long usageLevel = info.usageLevel;
 
         if (subInfo != null) {
-            mDataInfoController.updateDataLimit(info, mPolicyEditor.getPolicy(mDefaultTemplate));
             summaryPreference.setWifiMode(/* isWifiMode */ false,
                     /* usagePeriod */ null, /* isSingleWifi */ false);
         } else {
@@ -302,7 +274,6 @@
         mDataplanSize = -1L;
         mDataBarSize = mDataInfoController.getSummaryLimit(info);
         mDataplanUse = info.usageLevel;
-        mCycleStart = info.cycleStart;
         mCycleEnd = info.cycleEnd;
         mSnapshotTime = -1L;
 
@@ -322,7 +293,6 @@
 
                 RecurrenceRule rule = primaryPlan.getCycleRule();
                 if (rule != null && rule.start != null && rule.end != null) {
-                    mCycleStart = rule.start.toEpochSecond() * 1000L;
                     mCycleEnd = rule.end.toEpochSecond() * 1000L;
                 }
                 mSnapshotTime = primaryPlan.getDataUsageTime();
diff --git a/src/com/android/settings/datausage/WifiDataUsageSummaryPreferenceController.java b/src/com/android/settings/datausage/WifiDataUsageSummaryPreferenceController.java
index 4d2dd00..26a9667 100644
--- a/src/com/android/settings/datausage/WifiDataUsageSummaryPreferenceController.java
+++ b/src/com/android/settings/datausage/WifiDataUsageSummaryPreferenceController.java
@@ -23,7 +23,6 @@
 import androidx.preference.Preference;
 import androidx.preference.PreferenceFragmentCompat;
 
-import com.android.settingslib.core.lifecycle.Lifecycle;
 import com.android.settingslib.net.DataUsageController;
 
 import java.util.HashSet;
@@ -35,9 +34,9 @@
 public class WifiDataUsageSummaryPreferenceController extends DataUsageSummaryPreferenceController {
     final Set<String> mAllNetworkKeys;
 
-    public WifiDataUsageSummaryPreferenceController(Activity activity, Lifecycle lifecycle,
-            PreferenceFragmentCompat fragment, Set<String> allNetworkKeys) {
-        super(activity, lifecycle, fragment, SubscriptionManager.INVALID_SUBSCRIPTION_ID);
+    public WifiDataUsageSummaryPreferenceController(
+            Activity activity, PreferenceFragmentCompat fragment, Set<String> allNetworkKeys) {
+        super(activity, fragment, SubscriptionManager.INVALID_SUBSCRIPTION_ID);
         mAllNetworkKeys = new HashSet<>(allNetworkKeys);
     }
 
@@ -55,7 +54,6 @@
         }
         final DataUsageController.DataUsageInfo info = mDataUsageController.getDataUsageInfo(
                 template);
-        mDataInfoController.updateDataLimit(info, mPolicyEditor.getPolicy(template));
 
         mPreference.setWifiMode(/* isWifiMode */ true, /* usagePeriod */
                 info.period, /* isSingleWifi */ true);
diff --git a/src/com/android/settings/development/AdbDeviceDetailsHeaderController.java b/src/com/android/settings/development/AdbDeviceDetailsHeaderController.java
index 7830bb9..1bb4f3c 100644
--- a/src/com/android/settings/development/AdbDeviceDetailsHeaderController.java
+++ b/src/com/android/settings/development/AdbDeviceDetailsHeaderController.java
@@ -82,7 +82,7 @@
         mEntityHeaderController
                 .setIcon(mContext.getDrawable(com.android.internal.R.drawable.ic_bt_laptop))
                 .setLabel(mPairedDevice.name)
-                .done(mFragment.getActivity(), true);
+                .done(true);
     }
 }
 
diff --git a/src/com/android/settings/deviceinfo/aboutphone/MyDeviceInfoFragment.java b/src/com/android/settings/deviceinfo/aboutphone/MyDeviceInfoFragment.java
index 5e5e2ab..50b6097 100644
--- a/src/com/android/settings/deviceinfo/aboutphone/MyDeviceInfoFragment.java
+++ b/src/com/android/settings/deviceinfo/aboutphone/MyDeviceInfoFragment.java
@@ -183,7 +183,6 @@
         final Bundle bundle = getArguments();
         final EntityHeaderController controller = EntityHeaderController
                 .newInstance(context, this, headerView)
-                .setRecyclerView(getListView(), getSettingsLifecycle())
                 .setButtonActions(EntityHeaderController.ActionType.ACTION_NONE,
                         EntityHeaderController.ActionType.ACTION_NONE);
 
@@ -199,7 +198,7 @@
                     com.android.settingslib.Utils.getUserIcon(getActivity(), userManager, info));
         }
 
-        controller.done(context, true /* rebindActions */);
+        controller.done(true /* rebindActions */);
     }
 
     @Override
diff --git a/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetail.java b/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetail.java
index b443773..994ad07 100644
--- a/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetail.java
+++ b/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetail.java
@@ -16,6 +16,8 @@
 
 package com.android.settings.fuelgauge;
 
+import static com.android.settings.fuelgauge.batteryusage.ConvertUtils.isUserConsumer;
+
 import android.app.Activity;
 import android.app.ActivityManager;
 import android.app.backup.BackupManager;
@@ -41,7 +43,6 @@
 import com.android.settings.fuelgauge.BatteryOptimizeHistoricalLogEntry.Action;
 import com.android.settings.fuelgauge.batteryusage.BatteryDiffEntry;
 import com.android.settings.fuelgauge.batteryusage.BatteryEntry;
-import com.android.settings.fuelgauge.batteryusage.BatteryHistEntry;
 import com.android.settings.overlay.FeatureFactory;
 import com.android.settings.widget.EntityHeaderController;
 import com.android.settingslib.HelpUtils;
@@ -149,14 +150,13 @@
             Context context, int sourceMetricsCategory,
             BatteryDiffEntry diffEntry, String usagePercent, String slotInformation,
             boolean showTimeInformation) {
-        final BatteryHistEntry histEntry = diffEntry.mBatteryHistEntry;
         final LaunchBatteryDetailPageArgs launchArgs = new LaunchBatteryDetailPageArgs();
         // configure the launch argument.
         launchArgs.mUsagePercent = usagePercent;
         launchArgs.mPackageName = diffEntry.getPackageName();
         launchArgs.mAppLabel = diffEntry.getAppLabel();
         launchArgs.mSlotInformation = slotInformation;
-        launchArgs.mUid = (int) histEntry.mUid;
+        launchArgs.mUid = (int) diffEntry.mUid;
         launchArgs.mIconId = diffEntry.getAppIconId();
         launchArgs.mConsumedPower = (int) diffEntry.mConsumePower;
         if (showTimeInformation) {
@@ -164,7 +164,7 @@
             launchArgs.mBackgroundTimeMs = diffEntry.mBackgroundUsageTimeInMs;
             launchArgs.mScreenOnTimeMs = diffEntry.mScreenOnTimeInMs;
         }
-        launchArgs.mIsUserEntry = histEntry.isUserEntry();
+        launchArgs.mIsUserEntry = isUserConsumer(diffEntry.mConsumerType);
         startBatteryDetailPage(context, sourceMetricsCategory, launchArgs);
     }
 
@@ -316,7 +316,6 @@
         final Bundle bundle = getArguments();
         EntityHeaderController controller = EntityHeaderController
                 .newInstance(context, this, appSnippet)
-                .setRecyclerView(getListView(), getSettingsLifecycle())
                 .setButtonActions(EntityHeaderController.ActionType.ACTION_NONE,
                         EntityHeaderController.ActionType.ACTION_NONE);
 
@@ -337,7 +336,7 @@
         }
 
         controller.setSummary(getHeaderSummary(bundle));
-        controller.done(context, true /* rebindActions */);
+        controller.done(true /* rebindActions */);
     }
 
     @VisibleForTesting
diff --git a/src/com/android/settings/fuelgauge/BatteryHeaderPreferenceController.java b/src/com/android/settings/fuelgauge/BatteryHeaderPreferenceController.java
index d7f1f68..790ebc3 100644
--- a/src/com/android/settings/fuelgauge/BatteryHeaderPreferenceController.java
+++ b/src/com/android/settings/fuelgauge/BatteryHeaderPreferenceController.java
@@ -35,7 +35,6 @@
 import com.android.settings.overlay.FeatureFactory;
 import com.android.settings.widget.EntityHeaderController;
 import com.android.settingslib.Utils;
-import com.android.settingslib.core.lifecycle.Lifecycle;
 import com.android.settingslib.core.lifecycle.LifecycleObserver;
 import com.android.settingslib.core.lifecycle.events.OnStart;
 import com.android.settingslib.widget.UsageProgressBarPreference;
@@ -59,7 +58,6 @@
 
     private Activity mActivity;
     private PreferenceFragmentCompat mHost;
-    private Lifecycle mLifecycle;
     private BatteryTip mBatteryTip;
     private final PowerManager mPowerManager;
 
@@ -78,10 +76,6 @@
         mHost = fragment;
     }
 
-    public void setLifecycle(Lifecycle lifecycle) {
-        mLifecycle = lifecycle;
-    }
-
     @Override
     public void displayPreference(PreferenceScreen screen) {
         super.displayPreference(screen);
@@ -104,8 +98,7 @@
 
     @Override
     public void onStart() {
-        EntityHeaderController.newInstance(mActivity, mHost, null /* header view */)
-                .setRecyclerView(mHost.getListView(), mLifecycle);
+        EntityHeaderController.newInstance(mActivity, mHost, null /* header view */);
     }
 
     private CharSequence generateLabel(BatteryInfo info) {
diff --git a/src/com/android/settings/fuelgauge/batteryusage/AppUsageDataLoader.java b/src/com/android/settings/fuelgauge/batteryusage/AppUsageDataLoader.java
deleted file mode 100644
index c336fcd..0000000
--- a/src/com/android/settings/fuelgauge/batteryusage/AppUsageDataLoader.java
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * 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.batteryusage;
-
-import android.app.usage.UsageEvents;
-import android.content.Context;
-import android.os.AsyncTask;
-import android.util.Log;
-
-import androidx.annotation.VisibleForTesting;
-
-import java.util.List;
-import java.util.Map;
-import java.util.function.Supplier;
-
-/** Load app usage events data in the background. */
-public final class AppUsageDataLoader {
-    private static final String TAG = "AppUsageDataLoader";
-
-    // For testing only.
-    @VisibleForTesting
-    static Supplier<Map<Long, UsageEvents>> sFakeAppUsageEventsSupplier;
-    @VisibleForTesting
-    static Supplier<List<AppUsageEvent>> sFakeUsageEventsListSupplier;
-
-    private AppUsageDataLoader() {}
-
-    static void enqueueWork(final Context context) {
-        AsyncTask.execute(() -> {
-            Log.d(TAG, "loadAppUsageDataSafely() in the AsyncTask");
-            loadAppUsageDataSafely(context.getApplicationContext());
-        });
-    }
-
-    @VisibleForTesting
-    static void loadAppUsageData(final Context context) {
-        final long start = System.currentTimeMillis();
-        final Map<Long, UsageEvents> appUsageEvents =
-                sFakeAppUsageEventsSupplier != null
-                        ? sFakeAppUsageEventsSupplier.get()
-                        : DataProcessor.getAppUsageEvents(context);
-        if (appUsageEvents == null) {
-            Log.w(TAG, "loadAppUsageData() returns null");
-            return;
-        }
-        final List<AppUsageEvent> appUsageEventList =
-                sFakeUsageEventsListSupplier != null
-                        ? sFakeUsageEventsListSupplier.get()
-                        : DataProcessor.generateAppUsageEventListFromUsageEvents(
-                                context, appUsageEvents);
-        if (appUsageEventList == null || appUsageEventList.isEmpty()) {
-            Log.w(TAG, "loadAppUsageData() returns null or empty content");
-            return;
-        }
-        final long elapsedTime = System.currentTimeMillis() - start;
-        Log.d(TAG, String.format("loadAppUsageData() size=%d in %d/ms", appUsageEventList.size(),
-                elapsedTime));
-        // Uploads the AppUsageEvent data into database.
-        DatabaseUtils.sendAppUsageEventData(context, appUsageEventList);
-    }
-
-    private static void loadAppUsageDataSafely(final Context context) {
-        try {
-            loadAppUsageData(context);
-        } catch (RuntimeException e) {
-            Log.e(TAG, "loadAppUsageData:" + e);
-        }
-    }
-}
diff --git a/src/com/android/settings/fuelgauge/batteryusage/BatteryChartPreferenceController.java b/src/com/android/settings/fuelgauge/batteryusage/BatteryChartPreferenceController.java
index d2ca306..ea56c09 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/BatteryChartPreferenceController.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/BatteryChartPreferenceController.java
@@ -44,6 +44,7 @@
 import com.android.settingslib.core.lifecycle.LifecycleObserver;
 import com.android.settingslib.core.lifecycle.events.OnCreate;
 import com.android.settingslib.core.lifecycle.events.OnDestroy;
+import com.android.settingslib.core.lifecycle.events.OnPause;
 import com.android.settingslib.core.lifecycle.events.OnResume;
 import com.android.settingslib.core.lifecycle.events.OnSaveInstanceState;
 
@@ -51,14 +52,17 @@
 
 import java.util.ArrayList;
 import java.util.Calendar;
+import java.util.Collections;
+import java.util.Comparator;
 import java.util.List;
 import java.util.Map;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
+import java.util.concurrent.atomic.AtomicBoolean;
 
 /** Controls the update for chart graph and the list items. */
 public class BatteryChartPreferenceController extends AbstractPreferenceController
-        implements PreferenceControllerMixin, LifecycleObserver, OnCreate, OnDestroy,
+        implements PreferenceControllerMixin, LifecycleObserver, OnCreate, OnDestroy, OnPause,
         OnSaveInstanceState, OnResume {
     private static final String TAG = "BatteryChartPreferenceController";
     private static final String PREFERENCE_KEY = "battery_chart";
@@ -128,7 +132,6 @@
     Map<Integer, Map<Integer, BatteryDiffData>> mBatteryUsageMap;
 
     private boolean mIs24HourFormat;
-    private boolean mHourlyChartVisible = true;
     private View mBatteryChartViewGroup;
     private TextView mChartSummaryTextView;
     private BatteryChartViewModel mDailyViewModel;
@@ -136,6 +139,7 @@
     private OnBatteryUsageUpdatedListener mOnBatteryUsageUpdatedListener;
     private OnScreenOnTimeUpdatedListener mOnScreenOnTimeUpdatedListener;
     private OnBatteryTipsUpdatedListener mOnBatteryTipsUpdatedListener;
+    private AtomicBoolean mIsAppResume = new AtomicBoolean(false);
 
     private final SettingsActivity mActivity;
     private final MetricsFeatureProvider mMetricsFeatureProvider;
@@ -180,9 +184,15 @@
         Log.d(TAG, String.format("onCreate() dailyIndex=%d hourlyIndex=%d",
                 mDailyChartIndex, mHourlyChartIndex));
     }
+    @Override
+    public void onPause() {
+        mIsAppResume.compareAndSet(/* expect= */ true, /* update= */ false);
+    }
+
 
     @Override
     public void onResume() {
+        mIsAppResume.compareAndSet(/* expect= */ false, /* update= */ true);
         mIs24HourFormat = DateFormat.is24HourFormat(mContext);
         mMetricsFeatureProvider.action(mPrefContext, SettingsEnums.OPEN_BATTERY_USAGE);
     }
@@ -234,20 +244,8 @@
         mOnBatteryTipsUpdatedListener = listener;
     }
 
-    void setBatteryHistoryMap(
-            final Map<Long, Map<String, BatteryHistEntry>> batteryHistoryMap) {
-        Log.d(TAG, "setBatteryHistoryMap() " + (batteryHistoryMap == null ? "null"
-                : ("size=" + batteryHistoryMap.size())));
-        // Ensure the battery chart group is visible for users.
-        animateBatteryChartViewGroup();
-        final BatteryLevelData batteryLevelData =
-                DataProcessManager.getBatteryLevelData(mContext, mHandler, batteryHistoryMap,
-                        batteryUsageMap -> {
-                            mBatteryUsageMap = batteryUsageMap;
-                            logScreenUsageTime();
-                            refreshUi();
-                        });
-        Log.d(TAG, "getBatteryLevelData: " + batteryLevelData);
+    void onBatteryLevelDataUpdate(final BatteryLevelData batteryLevelData) {
+        Log.d(TAG, "onBatteryLevelDataUpdate: " + batteryLevelData);
         mMetricsFeatureProvider.action(
                 mPrefContext,
                 SettingsEnums.ACTION_BATTERY_HISTORY_LOADED,
@@ -278,6 +276,13 @@
         refreshUi();
     }
 
+    void onBatteryUsageMapUpdate(Map<Integer, Map<Integer, BatteryDiffData>> batteryUsageMap) {
+        Log.d(TAG, "onBatteryUsageMapUpdate: " + batteryUsageMap);
+        mBatteryUsageMap = batteryUsageMap;
+        logScreenUsageTime();
+        refreshUi();
+    }
+
     void setBatteryChartView(@NonNull final BatteryChartView dailyChartView,
             @NonNull final BatteryChartView hourlyChartView) {
         final View parentView = (View) dailyChartView.getParent();
@@ -370,14 +375,22 @@
             mOnBatteryUsageUpdatedListener.onBatteryUsageUpdated(
                     slotUsageData, getSlotInformation(), isBatteryUsageMapNullOrEmpty());
 
+            Log.d(TAG, "isBatteryTipsEnabled = "
+                    + mPowerUsageFeatureProvider.isBatteryTipsEnabled());
             if (mOnBatteryTipsUpdatedListener != null) {
                 mExecutor.execute(() -> {
                     final PowerAnomalyEventList anomalyEventList = mPowerUsageFeatureProvider
                             .detectSettingsAnomaly(mContext, /* displayDrain= */ 0);
+                    Log.d(TAG, "anomalyEventList = " + anomalyEventList);
                     final PowerAnomalyEvent displayEvent =
                             getHighestScoreAnomalyEvent(anomalyEventList);
-                    mHandler.post(()
-                            -> mOnBatteryTipsUpdatedListener.onBatteryTipsUpdated(displayEvent));
+                    mHandler.post(() -> {
+                                if (mIsAppResume.get()) {
+                                    mOnBatteryTipsUpdatedListener
+                                            .onBatteryTipsUpdated(displayEvent);
+                                }
+                            }
+                    );
                 });
             }
         }
@@ -388,13 +401,8 @@
         if (anomalyEventList == null || anomalyEventList.getPowerAnomalyEventsCount() == 0) {
             return null;
         }
-        PowerAnomalyEvent highestScoreEvent = null;
-        for (PowerAnomalyEvent event : anomalyEventList.getPowerAnomalyEventsList()) {
-            if (highestScoreEvent == null || event.getScore() > highestScoreEvent.getScore()) {
-                highestScoreEvent = event;
-            }
-        }
-        return highestScoreEvent;
+        return Collections.max(anomalyEventList.getPowerAnomalyEventsList(),
+                Comparator.comparing(PowerAnomalyEvent::getScore));
     }
 
     private boolean refreshUiWithNoLevelDataCase() {
@@ -498,10 +506,10 @@
     }
 
     private void animateBatteryHourlyChartView(final boolean visible) {
-        if (mHourlyChartView == null || mHourlyChartVisible == visible) {
+        if (mHourlyChartView == null
+                || (mHourlyChartView.getVisibility() == View.VISIBLE) == visible) {
             return;
         }
-        mHourlyChartVisible = visible;
 
         if (visible) {
             mHourlyChartView.setVisibility(View.VISIBLE);
@@ -658,10 +666,8 @@
             return null;
         }
         for (BatteryDiffEntry entry : entries) {
-            final BatteryHistEntry batteryHistEntry = entry.mBatteryHistEntry;
-            if (batteryHistEntry != null
-                    && batteryHistEntry.mConsumerType == ConvertUtils.CONSUMER_TYPE_UID_BATTERY
-                    && batteryHistEntry.mUserId == userId
+            if (!entry.isSystemEntry()
+                    && entry.mUserId == userId
                     && packageName.equals(entry.getPackageName())) {
                 return entry;
             }
diff --git a/src/com/android/settings/fuelgauge/batteryusage/BatteryChartView.java b/src/com/android/settings/fuelgauge/batteryusage/BatteryChartView.java
index 891e5e0..086f56c 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/BatteryChartView.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/BatteryChartView.java
@@ -17,6 +17,7 @@
 
 import static com.android.settings.Utils.formatPercentage;
 import static com.android.settings.fuelgauge.batteryusage.BatteryChartViewModel.AxisLabelPosition.BETWEEN_TRAPEZOIDS;
+import static com.android.settingslib.fuelgauge.BatteryStatus.BATTERY_LEVEL_UNKNOWN;
 
 import static java.lang.Math.abs;
 import static java.lang.Math.round;
@@ -615,8 +616,8 @@
 
     private static boolean isTrapezoidValid(
             @NonNull BatteryChartViewModel viewModel, int trapezoidIndex) {
-        return viewModel.getLevel(trapezoidIndex) != null
-                && viewModel.getLevel(trapezoidIndex + 1) != null;
+        return viewModel.getLevel(trapezoidIndex) != BATTERY_LEVEL_UNKNOWN
+                && viewModel.getLevel(trapezoidIndex + 1) != BATTERY_LEVEL_UNKNOWN;
     }
 
     private static boolean isTrapezoidIndexValid(
diff --git a/src/com/android/settings/fuelgauge/batteryusage/BatteryDiffData.java b/src/com/android/settings/fuelgauge/batteryusage/BatteryDiffData.java
index 90a5f19..f25e16f 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/BatteryDiffData.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/BatteryDiffData.java
@@ -16,6 +16,8 @@
 
 package com.android.settings.fuelgauge.batteryusage;
 
+import static com.android.settings.fuelgauge.batteryusage.ConvertUtils.utcToLocalTimeForLogging;
+
 import android.content.Context;
 import android.os.BatteryConsumer;
 
@@ -34,6 +36,10 @@
 public class BatteryDiffData {
     static final double SMALL_PERCENTAGE_THRESHOLD = 1f;
 
+    private final long mStartTimestamp;
+    private final long mEndTimestamp;
+    private final int mStartBatteryLevel;
+    private final int mEndBatteryLevel;
     private final long mScreenOnTime;
     private final List<BatteryDiffEntry> mAppEntries;
     private final List<BatteryDiffEntry> mSystemEntries;
@@ -41,12 +47,20 @@
     /** Constructor for the diff entries. */
     public BatteryDiffData(
             final Context context,
+            final long startTimestamp,
+            final long endTimestamp,
+            final int startBatteryLevel,
+            final int endBatteryLevel,
             final long screenOnTime,
             final @NonNull List<BatteryDiffEntry> appDiffEntries,
             final @NonNull List<BatteryDiffEntry> systemDiffEntries,
             final @NonNull Set<String> systemAppsPackageNames,
             final @NonNull Set<Integer> systemAppsUids,
             final boolean isAccumulated) {
+        mStartTimestamp = startTimestamp;
+        mEndTimestamp = endTimestamp;
+        mStartBatteryLevel = startBatteryLevel;
+        mEndBatteryLevel = endBatteryLevel;
         mScreenOnTime = screenOnTime;
         mAppEntries = appDiffEntries;
         mSystemEntries = systemDiffEntries;
@@ -63,18 +77,48 @@
         processAndSortEntries(mSystemEntries);
     }
 
-    public long getScreenOnTime() {
+    long getStartTimestamp() {
+        return mStartTimestamp;
+    }
+
+    long getEndTimestamp() {
+        return mEndTimestamp;
+    }
+
+    int getStartBatteryLevel() {
+        return mStartBatteryLevel;
+    }
+
+    int getEndBatteryLevel() {
+        return mEndBatteryLevel;
+    }
+
+    long getScreenOnTime() {
         return mScreenOnTime;
     }
 
-    public List<BatteryDiffEntry> getAppDiffEntryList() {
+    List<BatteryDiffEntry> getAppDiffEntryList() {
         return mAppEntries;
     }
 
-    public List<BatteryDiffEntry> getSystemDiffEntryList() {
+    List<BatteryDiffEntry> getSystemDiffEntryList() {
         return mSystemEntries;
     }
 
+    @Override
+    public String toString() {
+        return new StringBuilder("BatteryDiffData{")
+                .append("startTimestamp:" + utcToLocalTimeForLogging(mStartTimestamp))
+                .append("|endTimestamp:" + utcToLocalTimeForLogging(mEndTimestamp))
+                .append("|startLevel:" + mStartBatteryLevel)
+                .append("|endLevel:" + mEndBatteryLevel)
+                .append("|screenOnTime:" + mScreenOnTime)
+                .append("|appEntries.size:" + mAppEntries.size())
+                .append("|systemEntries.size:" + mSystemEntries.size())
+                .append("}")
+                .toString();
+    }
+
     /** Removes fake usage data and hidden packages. */
     private void purgeBatteryDiffData(final PowerUsageFeatureProvider featureProvider) {
         purgeBatteryDiffData(featureProvider, mAppEntries);
@@ -109,7 +153,7 @@
             final long screenOnTimeInMs = entry.mScreenOnTimeInMs;
             final double comsumePower = entry.mConsumePower;
             final String packageName = entry.getPackageName();
-            final Integer componentId = entry.mBatteryHistEntry.mDrainType;
+            final Integer componentId = entry.mComponentId;
             if ((screenOnTimeInMs < screenOnTimeThresholdInMs
                     && comsumePower < consumePowerThreshold)
                     || ConvertUtils.FAKE_PACKAGE_NAME.equals(packageName)
@@ -130,14 +174,16 @@
             final @NonNull Set<Integer> systemAppsUids,
             final @NonNull List<BatteryDiffEntry> appEntries) {
         final List<String> systemAppsAllowlist = featureProvider.getSystemAppsAllowlist();
-        BatteryDiffEntry.SystemAppsBatteryDiffEntry systemAppsDiffEntry = null;
+        BatteryDiffEntry systemAppsDiffEntry = null;
         final Iterator<BatteryDiffEntry> appListIterator = appEntries.iterator();
         while (appListIterator.hasNext()) {
             final BatteryDiffEntry batteryDiffEntry = appListIterator.next();
             if (needsCombineInSystemApp(batteryDiffEntry, systemAppsAllowlist,
                     systemAppsPackageNames, systemAppsUids)) {
                 if (systemAppsDiffEntry == null) {
-                    systemAppsDiffEntry = new BatteryDiffEntry.SystemAppsBatteryDiffEntry(context);
+                    systemAppsDiffEntry = new BatteryDiffEntry(context,
+                            BatteryDiffEntry.SYSTEM_APPS_KEY, BatteryDiffEntry.SYSTEM_APPS_KEY,
+                            ConvertUtils.CONSUMER_TYPE_UID_BATTERY);
                 }
                 systemAppsDiffEntry.mConsumePower += batteryDiffEntry.mConsumePower;
                 systemAppsDiffEntry.mForegroundUsageTimeInMs +=
@@ -159,17 +205,18 @@
         final Set<Integer> othersSystemComponentSet = featureProvider.getOthersSystemComponentSet();
         final Set<String> othersCustomComponentNameSet =
                 featureProvider.getOthersCustomComponentNameSet();
-        BatteryDiffEntry.OthersBatteryDiffEntry othersDiffEntry = null;
+        BatteryDiffEntry othersDiffEntry = null;
         final Iterator<BatteryDiffEntry> systemListIterator = systemEntries.iterator();
         while (systemListIterator.hasNext()) {
             final BatteryDiffEntry batteryDiffEntry = systemListIterator.next();
-            final int componentId = batteryDiffEntry.mBatteryHistEntry.mDrainType;
+            final int componentId = batteryDiffEntry.mComponentId;
             if (othersSystemComponentSet.contains(componentId) || (
                     componentId >= BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID
                             && othersCustomComponentNameSet.contains(
                                     batteryDiffEntry.getAppLabel()))) {
                 if (othersDiffEntry == null) {
-                    othersDiffEntry = new BatteryDiffEntry.OthersBatteryDiffEntry(context);
+                    othersDiffEntry = new BatteryDiffEntry(context, BatteryDiffEntry.OTHERS_KEY,
+                            BatteryDiffEntry.OTHERS_KEY, ConvertUtils.CONSUMER_TYPE_SYSTEM_BATTERY);
                 }
                 othersDiffEntry.mConsumePower += batteryDiffEntry.mConsumePower;
                 othersDiffEntry.setTotalConsumePower(
@@ -188,7 +235,7 @@
             final @NonNull List<String> systemAppsAllowlist,
             final @NonNull Set<String> systemAppsPackageNames,
             final @NonNull Set<Integer> systemAppsUids) {
-        if (batteryDiffEntry.mBatteryHistEntry.mIsHidden) {
+        if (batteryDiffEntry.mIsHidden) {
             return true;
         }
 
@@ -201,7 +248,7 @@
             return true;
         }
 
-        int uid = (int) batteryDiffEntry.mBatteryHistEntry.mUid;
+        int uid = (int) batteryDiffEntry.mUid;
         return systemAppsPackageNames.contains(packageName) || systemAppsUids.contains(uid);
     }
 
diff --git a/src/com/android/settings/fuelgauge/batteryusage/BatteryDiffEntry.java b/src/com/android/settings/fuelgauge/batteryusage/BatteryDiffEntry.java
index 2ed9196..b284ea5 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/BatteryDiffEntry.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/BatteryDiffEntry.java
@@ -15,7 +15,6 @@
  */
 package com.android.settings.fuelgauge.batteryusage;
 
-import android.content.ContentValues;
 import android.content.Context;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
@@ -24,6 +23,7 @@
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.util.Log;
+import android.util.Pair;
 
 import androidx.annotation.VisibleForTesting;
 
@@ -45,12 +45,29 @@
     static final Map<String, BatteryEntry.NameAndIcon> sResourceCache = new HashMap<>();
     // Whether a specific item is valid to launch restriction page?
     @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)
-    public static final Map<String, Boolean> sValidForRestriction = new HashMap<>();
-
+    static final Map<String, Boolean> sValidForRestriction = new HashMap<>();
     /** A comparator for {@link BatteryDiffEntry} based on the sorting key. */
-    public static final Comparator<BatteryDiffEntry> COMPARATOR =
+    static final Comparator<BatteryDiffEntry> COMPARATOR =
             (a, b) -> Double.compare(b.getSortingKey(), a.getSortingKey());
+    static final String SYSTEM_APPS_KEY = "A|SystemApps";
+    static final String OTHERS_KEY = "S|Others";
 
+    // key -> (label_id, icon_id)
+    private static final Map<String, Pair<Integer, Integer>> SPECIAL_ENTRY_MAP = Map.of(
+            SYSTEM_APPS_KEY,
+            Pair.create(R.string.battery_usage_system_apps, R.drawable.ic_power_system),
+            OTHERS_KEY,
+            Pair.create(R.string.battery_usage_others,
+                    R.drawable.ic_settings_battery_usage_others));
+
+    public long mUid;
+    public long mUserId;
+    public String mKey;
+    public boolean mIsHidden;
+    public int mComponentId;
+    public String mLegacyPackageName;
+    public String mLegacyLabel;
+    public int mConsumerType;
     public long mForegroundUsageTimeInMs;
     public long mBackgroundUsageTimeInMs;
     public long mScreenOnTimeInMs;
@@ -59,8 +76,6 @@
     public double mForegroundServiceUsageConsumePower;
     public double mBackgroundUsageConsumePower;
     public double mCachedUsageConsumePower;
-    // A BatteryHistEntry corresponding to this diff usage data.
-    public final BatteryHistEntry mBatteryHistEntry;
 
     protected Context mContext;
 
@@ -83,6 +98,14 @@
 
     public BatteryDiffEntry(
             Context context,
+            long uid,
+            long userId,
+            String key,
+            boolean isHidden,
+            int componentId,
+            String legacyPackageName,
+            String legacyLabel,
+            int consumerType,
             long foregroundUsageTimeInMs,
             long backgroundUsageTimeInMs,
             long screenOnTimeInMs,
@@ -90,21 +113,36 @@
             double foregroundUsageConsumePower,
             double foregroundServiceUsageConsumePower,
             double backgroundUsageConsumePower,
-            double cachedUsageConsumePower,
-            BatteryHistEntry batteryHistEntry) {
+            double cachedUsageConsumePower) {
         mContext = context;
+        mUid = uid;
+        mUserId = userId;
+        mKey = key;
+        mIsHidden = isHidden;
+        mComponentId = componentId;
+        mLegacyPackageName = legacyPackageName;
+        mLegacyLabel = legacyLabel;
+        mConsumerType = consumerType;
+        mForegroundUsageTimeInMs = foregroundUsageTimeInMs;
+        mBackgroundUsageTimeInMs = backgroundUsageTimeInMs;
+        mScreenOnTimeInMs = screenOnTimeInMs;
         mConsumePower = consumePower;
         mForegroundUsageConsumePower = foregroundUsageConsumePower;
         mForegroundServiceUsageConsumePower = foregroundServiceUsageConsumePower;
         mBackgroundUsageConsumePower = backgroundUsageConsumePower;
         mCachedUsageConsumePower = cachedUsageConsumePower;
-        mForegroundUsageTimeInMs = foregroundUsageTimeInMs;
-        mBackgroundUsageTimeInMs = backgroundUsageTimeInMs;
-        mScreenOnTimeInMs = screenOnTimeInMs;
-        mBatteryHistEntry = batteryHistEntry;
         mUserManager = context.getSystemService(UserManager.class);
     }
 
+    public BatteryDiffEntry(Context context, String key, String legacyLabel, int consumerType) {
+        this(context, /*uid=*/ 0, /*userId=*/ 0, key, /*isHidden=*/ false, /*componentId=*/ -1,
+                /*legacyPackageName=*/ null, legacyLabel, consumerType,
+                /*foregroundUsageTimeInMs=*/ 0, /*backgroundUsageTimeInMs=*/ 0,
+                /*screenOnTimeInMs=*/ 0, /*consumePower=*/ 0, /*foregroundUsageConsumePower=*/ 0,
+                /*foregroundServiceUsageConsumePower=*/ 0, /*backgroundUsageConsumePower=*/ 0,
+                /*cachedUsageConsumePower=*/ 0);
+    }
+
     /** Sets the total consumed power in a specific time slot. */
     public void setTotalConsumePower(double totalConsumePower) {
         mTotalConsumePower = totalConsumePower;
@@ -135,13 +173,22 @@
 
     /** Gets the key for sorting */
     public double getSortingKey() {
-        return getPercentage() + getAdjustPercentageOffset();
+        return getKey() != null && SPECIAL_ENTRY_MAP.containsKey(getKey())
+                ? -1 : getPercentage() + getAdjustPercentageOffset();
     }
 
     /** Clones a new instance. */
     public BatteryDiffEntry clone() {
         return new BatteryDiffEntry(
                 this.mContext,
+                this.mUid,
+                this.mUserId,
+                this.mKey,
+                this.mIsHidden,
+                this.mComponentId,
+                this.mLegacyPackageName,
+                this.mLegacyLabel,
+                this.mConsumerType,
                 this.mForegroundUsageTimeInMs,
                 this.mBackgroundUsageTimeInMs,
                 this.mScreenOnTimeInMs,
@@ -149,17 +196,14 @@
                 this.mForegroundUsageConsumePower,
                 this.mForegroundServiceUsageConsumePower,
                 this.mBackgroundUsageConsumePower,
-                this.mCachedUsageConsumePower,
-                this.mBatteryHistEntry /*same instance*/);
+                this.mCachedUsageConsumePower);
     }
 
     /** Gets the app label name for this entry. */
     public String getAppLabel() {
         loadLabelAndIcon();
-        // Returns default applicationn label if we cannot find it.
-        return mAppLabel == null || mAppLabel.length() == 0
-                ? mBatteryHistEntry.mAppLabel
-                : mAppLabel;
+        // Returns default application label if we cannot find it.
+        return mAppLabel == null || mAppLabel.length() == 0 ? mLegacyLabel : mAppLabel;
     }
 
     /** Gets the app icon {@link Drawable} for this entry. */
@@ -179,7 +223,7 @@
     /** Gets the searching package name for UID battery type. */
     public String getPackageName() {
         final String packageName = mDefaultPackageName != null
-                ? mDefaultPackageName : mBatteryHistEntry.mPackageName;
+                ? mDefaultPackageName : mLegacyPackageName;
         if (packageName == null) {
             return packageName;
         }
@@ -198,10 +242,10 @@
 
     /** Whether the current BatteryDiffEntry is system component or not. */
     public boolean isSystemEntry() {
-        if (mBatteryHistEntry.mIsHidden) {
+        if (mIsHidden) {
             return false;
         }
-        switch (mBatteryHistEntry.mConsumerType) {
+        switch (mConsumerType) {
             case ConvertUtils.CONSUMER_TYPE_USER_BATTERY:
             case ConvertUtils.CONSUMER_TYPE_SYSTEM_BATTERY:
                 return true;
@@ -236,12 +280,22 @@
         updateRestrictionFlagState();
         sValidForRestriction.put(getKey(), Boolean.valueOf(mValidForRestriction));
 
+        if (getKey() != null && SPECIAL_ENTRY_MAP.containsKey(getKey())) {
+            Pair<Integer, Integer> pair = SPECIAL_ENTRY_MAP.get(getKey());
+            mAppLabel = mContext.getString(pair.first);
+            mAppIconId = pair.second;
+            mAppIcon = mContext.getDrawable(mAppIconId);
+            sResourceCache.put(
+                    getKey(),
+                    new BatteryEntry.NameAndIcon(mAppLabel, mAppIcon, mAppIconId));
+            return;
+        }
+
         // Loads application icon and label based on consumer type.
-        switch (mBatteryHistEntry.mConsumerType) {
+        switch (mConsumerType) {
             case ConvertUtils.CONSUMER_TYPE_USER_BATTERY:
                 final BatteryEntry.NameAndIcon nameAndIconForUser =
-                        BatteryEntry.getNameAndIconFromUserId(
-                                mContext, (int) mBatteryHistEntry.mUserId);
+                        BatteryEntry.getNameAndIconFromUserId(mContext, (int) mUserId);
                 if (nameAndIconForUser != null) {
                     mAppIcon = nameAndIconForUser.mIcon;
                     mAppLabel = nameAndIconForUser.mName;
@@ -252,8 +306,7 @@
                 break;
             case ConvertUtils.CONSUMER_TYPE_SYSTEM_BATTERY:
                 final BatteryEntry.NameAndIcon nameAndIconForSystem =
-                        BatteryEntry.getNameAndIconFromPowerComponent(
-                                mContext, mBatteryHistEntry.mDrainType);
+                        BatteryEntry.getNameAndIconFromPowerComponent(mContext, mComponentId);
                 if (nameAndIconForSystem != null) {
                     mAppLabel = nameAndIconForSystem.mName;
                     if (nameAndIconForSystem.mIconId != 0) {
@@ -283,12 +336,12 @@
     }
 
     String getKey() {
-        return mBatteryHistEntry.getKey();
+        return mKey;
     }
 
     @VisibleForTesting
     void updateRestrictionFlagState() {
-        if (!mBatteryHistEntry.isAppEntry()) {
+        if (isSystemEntry()) {
             mValidForRestriction = false;
             return;
         }
@@ -348,7 +401,7 @@
             return;
         }
 
-        final int uid = (int) mBatteryHistEntry.mUid;
+        final int uid = (int) mUid;
         final String[] packages = packageManager.getPackagesForUid(uid);
         // Loads special defined application label and icon if available.
         if (packages == null || packages.length == 0) {
@@ -394,8 +447,7 @@
                         StringUtil.formatElapsedTime(mContext, (double) mScreenOnTimeInMs,
                                 /*withSeconds=*/ true, /*collapseTimeUnit=*/ false)))
                 .append(String.format("\n\tpackage:%s|%s uid:%d userId:%d",
-                        mBatteryHistEntry.mPackageName, getPackageName(),
-                        mBatteryHistEntry.mUid, mBatteryHistEntry.mUserId));
+                        mLegacyPackageName, getPackageName(), mUid, mUserId));
         return builder.toString();
     }
 
@@ -406,130 +458,8 @@
     }
 
     private Drawable getBadgeIconForUser(Drawable icon) {
-        final int userId = UserHandle.getUserId((int) mBatteryHistEntry.mUid);
+        final int userId = UserHandle.getUserId((int) mUid);
         return userId == UserHandle.USER_OWNER ? icon :
                 mUserManager.getBadgedIconForUser(icon, new UserHandle(userId));
     }
-
-    /** Specific battery diff entry for system apps. */
-    static class SystemAppsBatteryDiffEntry extends BatteryDiffEntry {
-        SystemAppsBatteryDiffEntry(Context context) {
-            super(context,
-                    /*foregroundUsageTimeInMs=*/ 0,
-                    /*backgroundUsageTimeInMs=*/ 0,
-                    /*screenOnTimeInMs=*/ 0,
-                    /*consumePower=*/ 0,
-                    /*foregroundUsageConsumePower=*/ 0,
-                    /*foregroundServiceUsageConsumePower=*/ 0,
-                    /*backgroundUsageConsumePower=*/ 0,
-                    /*cachedUsageConsumePower=*/ 0,
-                    new BatteryHistEntry(new ContentValues()));
-        }
-
-        @Override
-        public String getKey() {
-            return "A|SystemApps";
-        }
-
-        @Override
-        public String getAppLabel() {
-            return mContext.getString(R.string.battery_usage_system_apps);
-        }
-
-        @Override
-        public Drawable getAppIcon() {
-            return mContext.getDrawable(R.drawable.ic_power_system);
-        }
-
-        @Override
-        public boolean validForRestriction() {
-            return false;
-        }
-
-        @Override
-        public boolean isSystemEntry() {
-            return false;
-        }
-
-        @Override
-        public double getSortingKey() {
-            // Always on the bottom of the app list.
-            return -1;
-        }
-
-        @Override
-        public BatteryDiffEntry clone() {
-            SystemAppsBatteryDiffEntry newEntry = new SystemAppsBatteryDiffEntry(this.mContext);
-            newEntry.mForegroundUsageTimeInMs = this.mForegroundUsageTimeInMs;
-            newEntry.mBackgroundUsageTimeInMs = this.mBackgroundUsageTimeInMs;
-            newEntry.mScreenOnTimeInMs = this.mScreenOnTimeInMs;
-            newEntry.mConsumePower = this.mConsumePower;
-            newEntry.mForegroundUsageConsumePower = this.mForegroundUsageConsumePower;
-            newEntry.mForegroundServiceUsageConsumePower = this.mForegroundServiceUsageConsumePower;
-            newEntry.mBackgroundUsageConsumePower = this.mBackgroundUsageConsumePower;
-            newEntry.mCachedUsageConsumePower = this.mCachedUsageConsumePower;
-            return newEntry;
-        }
-    }
-
-    /** Specific battery diff entry for others. */
-    static class OthersBatteryDiffEntry extends BatteryDiffEntry {
-        OthersBatteryDiffEntry(Context context) {
-            super(context,
-                    /*foregroundUsageTimeInMs=*/ 0,
-                    /*backgroundUsageTimeInMs=*/ 0,
-                    /*screenOnTimeInMs=*/ 0,
-                    /*consumePower=*/ 0,
-                    /*foregroundUsageConsumePower=*/ 0,
-                    /*foregroundServiceUsageConsumePower=*/ 0,
-                    /*backgroundUsageConsumePower=*/ 0,
-                    /*cachedUsageConsumePower=*/ 0,
-                    new BatteryHistEntry(new ContentValues()));
-        }
-
-        @Override
-        public String getKey() {
-            return "S|Others";
-        }
-
-        @Override
-        public String getAppLabel() {
-            return mContext.getString(R.string.battery_usage_others);
-        }
-
-        @Override
-        public Drawable getAppIcon() {
-            return mContext.getDrawable(R.drawable.ic_settings_battery_usage_others);
-        }
-
-        @Override
-        public boolean validForRestriction() {
-            return false;
-        }
-
-        @Override
-        public boolean isSystemEntry() {
-            return true;
-        }
-
-        @Override
-        public double getSortingKey() {
-            // Always on the bottom of the system list.
-            return -1;
-        }
-
-        @Override
-        public BatteryDiffEntry clone() {
-            OthersBatteryDiffEntry newEntry = new OthersBatteryDiffEntry(this.mContext);
-            newEntry.mForegroundUsageTimeInMs = this.mForegroundUsageTimeInMs;
-            newEntry.mBackgroundUsageTimeInMs = this.mBackgroundUsageTimeInMs;
-            newEntry.mScreenOnTimeInMs = this.mScreenOnTimeInMs;
-            newEntry.mConsumePower = this.mConsumePower;
-            newEntry.mForegroundUsageConsumePower = this.mForegroundUsageConsumePower;
-            newEntry.mForegroundServiceUsageConsumePower = this.mForegroundServiceUsageConsumePower;
-            newEntry.mBackgroundUsageConsumePower = this.mBackgroundUsageConsumePower;
-            newEntry.mCachedUsageConsumePower = this.mCachedUsageConsumePower;
-            return newEntry;
-        }
-    }
 }
diff --git a/src/com/android/settings/fuelgauge/batteryusage/BatteryHistEntry.java b/src/com/android/settings/fuelgauge/batteryusage/BatteryHistEntry.java
index 827f0fc..6f78566 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/BatteryHistEntry.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/BatteryHistEntry.java
@@ -169,21 +169,6 @@
         return mIsValidEntry;
     }
 
-    /** Whether this {@link BatteryHistEntry} is user consumer or not. */
-    public boolean isUserEntry() {
-        return mConsumerType == ConvertUtils.CONSUMER_TYPE_USER_BATTERY;
-    }
-
-    /** Whether this {@link BatteryHistEntry} is app consumer or not. */
-    public boolean isAppEntry() {
-        return mConsumerType == ConvertUtils.CONSUMER_TYPE_UID_BATTERY;
-    }
-
-    /** Whether this {@link BatteryHistEntry} is system consumer or not. */
-    public boolean isSystemEntry() {
-        return mConsumerType == ConvertUtils.CONSUMER_TYPE_SYSTEM_BATTERY;
-    }
-
     /** Gets an identifier to represent this {@link BatteryHistEntry}. */
     public String getKey() {
         if (mKey == null) {
diff --git a/src/com/android/settings/fuelgauge/batteryusage/BatteryHistoryLoader.java b/src/com/android/settings/fuelgauge/batteryusage/BatteryHistoryLoader.java
deleted file mode 100644
index 9a0e410..0000000
--- a/src/com/android/settings/fuelgauge/batteryusage/BatteryHistoryLoader.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * 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.batteryusage;
-
-import android.content.Context;
-
-import com.android.settingslib.utils.AsyncLoaderCompat;
-
-import java.util.Calendar;
-import java.util.Map;
-
-/** Loader that can be used to load battery history information. */
-public class BatteryHistoryLoader
-        extends AsyncLoaderCompat<Map<Long, Map<String, BatteryHistEntry>>> {
-    private static final String TAG = "BatteryHistoryLoader";
-
-    private final Context mContext;
-
-    public BatteryHistoryLoader(Context context) {
-        super(context);
-        mContext = context;
-    }
-
-    @Override
-    protected void onDiscardResult(Map<Long, Map<String, BatteryHistEntry>> result) {
-    }
-
-    @Override
-    public Map<Long, Map<String, BatteryHistEntry>> loadInBackground() {
-        return DatabaseUtils.getHistoryMapSinceLastFullCharge(mContext, Calendar.getInstance());
-    }
-}
diff --git a/src/com/android/settings/fuelgauge/batteryusage/BatteryHistoryPreference.java b/src/com/android/settings/fuelgauge/batteryusage/BatteryHistoryPreference.java
index c78b3c7..d64bf34 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/BatteryHistoryPreference.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/BatteryHistoryPreference.java
@@ -17,17 +17,13 @@
 package com.android.settings.fuelgauge.batteryusage;
 
 import android.content.Context;
-import android.os.BatteryUsageStats;
 import android.util.AttributeSet;
 import android.widget.TextView;
 
-import androidx.annotation.NonNull;
-import androidx.annotation.VisibleForTesting;
 import androidx.preference.Preference;
 import androidx.preference.PreferenceViewHolder;
 
 import com.android.settings.R;
-import com.android.settings.fuelgauge.BatteryInfo;
 import com.android.settings.fuelgauge.BatteryUtils;
 
 /**
@@ -36,9 +32,6 @@
 public class BatteryHistoryPreference extends Preference {
     private static final String TAG = "BatteryHistoryPreference";
 
-    @VisibleForTesting
-    BatteryInfo mBatteryInfo;
-
     private BatteryChartView mDailyChartView;
     private BatteryChartView mHourlyChartView;
     private BatteryChartPreferenceController mChartPreferenceController;
@@ -49,13 +42,6 @@
         setSelectable(false);
     }
 
-    void setBatteryUsageStats(@NonNull BatteryUsageStats batteryUsageStats) {
-        BatteryInfo.getBatteryInfo(getContext(), info -> {
-            mBatteryInfo = info;
-            notifyChanged();
-        }, batteryUsageStats, false);
-    }
-
     void setChartPreferenceController(BatteryChartPreferenceController controller) {
         mChartPreferenceController = controller;
         if (mDailyChartView != null && mHourlyChartView != null) {
@@ -67,9 +53,6 @@
     public void onBindViewHolder(PreferenceViewHolder view) {
         super.onBindViewHolder(view);
         final long startTime = System.currentTimeMillis();
-        if (mBatteryInfo == null) {
-            return;
-        }
         final TextView companionTextView = (TextView) view.findViewById(R.id.companion_text);
         mDailyChartView = (BatteryChartView) view.findViewById(R.id.daily_battery_chart);
         mDailyChartView.setCompanionTextView(companionTextView);
diff --git a/src/com/android/settings/fuelgauge/batteryusage/BatteryLevelData.java b/src/com/android/settings/fuelgauge/batteryusage/BatteryLevelData.java
index 4ff9eeb..53ebbd9 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/BatteryLevelData.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/BatteryLevelData.java
@@ -16,15 +16,28 @@
 
 package com.android.settings.fuelgauge.batteryusage;
 
+import static com.android.settingslib.fuelgauge.BatteryStatus.BATTERY_LEVEL_UNKNOWN;
+
+import android.text.format.DateUtils;
+import android.util.ArrayMap;
+
 import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.annotation.VisibleForTesting;
 import androidx.core.util.Preconditions;
 
+import java.util.ArrayList;
+import java.util.Collections;
 import java.util.List;
 import java.util.Locale;
+import java.util.Map;
 import java.util.Objects;
 
 /** Wraps the battery timestamp and level data used for battery usage chart. */
 public final class BatteryLevelData {
+    private static final long MIN_SIZE = 2;
+    private static final long TIME_SLOT = DateUtils.HOUR_IN_MILLIS * 2;
+
     /** A container for the battery timestamp and level data. */
     public static final class PeriodBatteryLevelData {
         // The length of mTimestamps and mLevels must be the same. mLevels[index] might be null when
@@ -33,12 +46,14 @@
         private final List<Integer> mLevels;
 
         public PeriodBatteryLevelData(
-                @NonNull List<Long> timestamps, @NonNull List<Integer> levels) {
-            Preconditions.checkArgument(timestamps.size() == levels.size(),
-                    /* errorMessage= */ "Timestamp: " + timestamps.size() + ", Level: "
-                            + levels.size());
+                @NonNull Map<Long, Integer> batteryLevelMap,
+                @NonNull List<Long> timestamps) {
             mTimestamps = timestamps;
-            mLevels = levels;
+            mLevels = new ArrayList<>(timestamps.size());
+            for (Long timestamp : timestamps) {
+                mLevels.add(batteryLevelMap.containsKey(timestamp)
+                        ? batteryLevelMap.get(timestamp) : BATTERY_LEVEL_UNKNOWN);
+            }
         }
 
         public List<Long> getTimestamps() {
@@ -68,15 +83,21 @@
     // The size of hourly data must be the size of daily data - 1.
     private final List<PeriodBatteryLevelData> mHourlyBatteryLevelsPerDay;
 
-    public BatteryLevelData(
-            @NonNull PeriodBatteryLevelData dailyBatteryLevels,
-            @NonNull List<PeriodBatteryLevelData> hourlyBatteryLevelsPerDay) {
-        final long dailySize = dailyBatteryLevels.getTimestamps().size();
-        final long hourlySize = hourlyBatteryLevelsPerDay.size();
-        Preconditions.checkArgument(hourlySize == dailySize - 1,
-                /* errorMessage= */ "DailySize: " + dailySize + ", HourlySize: " + hourlySize);
-        mDailyBatteryLevels = dailyBatteryLevels;
-        mHourlyBatteryLevelsPerDay = hourlyBatteryLevelsPerDay;
+    public BatteryLevelData(@NonNull Map<Long, Integer> batteryLevelMap) {
+        final int mapSize = batteryLevelMap.size();
+        Preconditions.checkArgument(mapSize >= MIN_SIZE, "batteryLevelMap size:" + mapSize);
+
+        final List<Long> timestampList = new ArrayList<>(batteryLevelMap.keySet());
+        Collections.sort(timestampList);
+        final List<Long> dailyTimestamps = getDailyTimestamps(timestampList);
+        final List<List<Long>> hourlyTimestamps = getHourlyTimestamps(dailyTimestamps);
+
+        mDailyBatteryLevels = new PeriodBatteryLevelData(batteryLevelMap, dailyTimestamps);
+        mHourlyBatteryLevelsPerDay = new ArrayList<>(hourlyTimestamps.size());
+        for (List<Long> hourlyTimestampsPerDay : hourlyTimestamps) {
+            mHourlyBatteryLevelsPerDay.add(
+                    new PeriodBatteryLevelData(batteryLevelMap, hourlyTimestampsPerDay));
+        }
     }
 
     public PeriodBatteryLevelData getDailyBatteryLevels() {
@@ -94,5 +115,69 @@
                 Objects.toString(mDailyBatteryLevels),
                 Objects.toString(mHourlyBatteryLevelsPerDay));
     }
+
+    @Nullable
+    static BatteryLevelData combine(@Nullable BatteryLevelData existingBatteryLevelData,
+            List<BatteryEvent> batteryLevelRecordEvents) {
+        final Map<Long, Integer> batteryLevelMap = new ArrayMap<>(batteryLevelRecordEvents.size());
+        for (BatteryEvent event : batteryLevelRecordEvents) {
+            batteryLevelMap.put(event.getTimestamp(), event.getBatteryLevel());
+        }
+        if (existingBatteryLevelData != null) {
+            List<PeriodBatteryLevelData> multiDaysData =
+                    existingBatteryLevelData.getHourlyBatteryLevelsPerDay();
+            for (int dayIndex = 0; dayIndex < multiDaysData.size(); dayIndex++) {
+                PeriodBatteryLevelData oneDayData = multiDaysData.get(dayIndex);
+                for (int hourIndex = 0; hourIndex < oneDayData.getLevels().size(); hourIndex++) {
+                    batteryLevelMap.put(oneDayData.getTimestamps().get(hourIndex),
+                            oneDayData.getLevels().get(hourIndex));
+                }
+            }
+        }
+        return batteryLevelMap.size() < MIN_SIZE ? null : new BatteryLevelData(batteryLevelMap);
+    }
+
+    /**
+     * Computes expected daily timestamp slots.
+     *
+     * The valid result should be composed of 3 parts:
+     * 1) start timestamp
+     * 2) every 00:00 timestamp (default timezone) between the start and end
+     * 3) end timestamp
+     * Otherwise, returns an empty list.
+     */
+    @VisibleForTesting
+    static List<Long> getDailyTimestamps(final List<Long> timestampList) {
+        Preconditions.checkArgument(
+                timestampList.size() >= MIN_SIZE, "timestampList size:" + timestampList.size());
+        final List<Long> dailyTimestampList = new ArrayList<>();
+        final long startTimestamp = timestampList.get(0);
+        final long endTimestamp = timestampList.get(timestampList.size() - 1);
+        for (long timestamp = startTimestamp; timestamp < endTimestamp;
+                timestamp = TimestampUtils.getNextDayTimestamp(timestamp)) {
+            dailyTimestampList.add(timestamp);
+        }
+        dailyTimestampList.add(endTimestamp);
+        return dailyTimestampList;
+    }
+
+    private static List<List<Long>> getHourlyTimestamps(final List<Long> dailyTimestamps) {
+        final List<List<Long>> hourlyTimestamps = new ArrayList<>();
+        for (int dailyIndex = 0; dailyIndex < dailyTimestamps.size() - 1; dailyIndex++) {
+            final List<Long> hourlyTimestampsPerDay = new ArrayList<>();
+            final long startTime = dailyTimestamps.get(dailyIndex);
+            final long endTime = dailyTimestamps.get(dailyIndex + 1);
+
+            hourlyTimestampsPerDay.add(startTime);
+            for (long timestamp = TimestampUtils.getNextEvenHourTimestamp(startTime);
+                    timestamp < endTime; timestamp += TIME_SLOT) {
+                hourlyTimestampsPerDay.add(timestamp);
+            }
+            hourlyTimestampsPerDay.add(endTime);
+
+            hourlyTimestamps.add(hourlyTimestampsPerDay);
+        }
+        return hourlyTimestamps;
+    }
 }
 
diff --git a/src/com/android/settings/fuelgauge/batteryusage/BatteryTipsCardPreference.java b/src/com/android/settings/fuelgauge/batteryusage/BatteryTipsCardPreference.java
index 976897f..1bd1f22 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/BatteryTipsCardPreference.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/BatteryTipsCardPreference.java
@@ -16,6 +16,7 @@
 
 package com.android.settings.fuelgauge.batteryusage;
 
+import android.app.settings.SettingsEnums;
 import android.content.Context;
 import android.text.TextUtils;
 import android.util.AttributeSet;
@@ -32,6 +33,7 @@
 import com.android.settings.core.SubSettingLauncher;
 import com.android.settings.fuelgauge.PowerUsageFeatureProvider;
 import com.android.settings.overlay.FeatureFactory;
+import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
 
 import com.google.android.material.button.MaterialButton;
 
@@ -43,6 +45,9 @@
     private static final String TAG = "BatteryTipsCardPreference";
 
     private final PowerUsageFeatureProvider mPowerUsageFeatureProvider;
+    private final MetricsFeatureProvider mMetricsFeatureProvider;
+
+    private String mAnomalyEventId;
 
     @VisibleForTesting
     CharSequence mMainButtonLabel;
@@ -51,18 +56,26 @@
     @VisibleForTesting
     String mDestinationComponentName;
     @VisibleForTesting
-    int mSourceMetricsCategory;
+    Integer mSourceMetricsCategory;
 
     public BatteryTipsCardPreference(Context context, AttributeSet attrs) {
         super(context, attrs);
         setLayoutResource(R.layout.battery_tips_card);
         setSelectable(false);
-        mPowerUsageFeatureProvider = FeatureFactory.getFeatureFactory()
-            .getPowerUsageFeatureProvider();
+        final FeatureFactory featureFactory = FeatureFactory.getFeatureFactory();
+        mPowerUsageFeatureProvider =  featureFactory.getPowerUsageFeatureProvider();
+        mMetricsFeatureProvider = featureFactory.getMetricsFeatureProvider();
     }
 
     /**
-     * Update the label of main button in tips card.
+     * Sets the anomaly event id which is used in metrics.
+     */
+    public void setAnomalyEventId(final String anomalyEventId) {
+        mAnomalyEventId = anomalyEventId;
+    }
+
+    /**
+     * Sets the label of main button in tips card.
      */
     public void setMainButtonLabel(CharSequence label) {
         if (!TextUtils.equals(mMainButtonLabel, label)) {
@@ -72,7 +85,7 @@
     }
 
     /**
-     * Update the label of dismiss button in tips card.
+     * Sets the label of dismiss button in tips card.
      */
     public void setDismissButtonLabel(CharSequence label) {
         if (!TextUtils.equals(mDismissButtonLabel, label)) {
@@ -82,7 +95,7 @@
     }
 
     /**
-     * Update the info of target fragment launched by main button.
+     * Sets the info of target fragment launched by main button.
      */
     public void setMainButtonLauncherInfo(final String destinationClassName,
             final Integer sourceMetricsCategory) {
@@ -101,8 +114,13 @@
                     .setDestination(mDestinationComponentName)
                     .setSourceMetricsCategory(mSourceMetricsCategory)
                     .launch();
+            setVisible(false);
+            mMetricsFeatureProvider.action(
+                    getContext(), SettingsEnums.ACTION_BATTERY_TIPS_CARD_ACCEPT, mAnomalyEventId);
         } else if (viewId == R.id.dismiss_button) {
             setVisible(false);
+            mMetricsFeatureProvider.action(
+                    getContext(), SettingsEnums.ACTION_BATTERY_TIPS_CARD_DISMISS, mAnomalyEventId);
         }
     }
 
diff --git a/src/com/android/settings/fuelgauge/batteryusage/BatteryTipsController.java b/src/com/android/settings/fuelgauge/batteryusage/BatteryTipsController.java
index 91fe59c..5338d7d 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/BatteryTipsController.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/BatteryTipsController.java
@@ -16,6 +16,7 @@
 
 package com.android.settings.fuelgauge.batteryusage;
 
+import android.app.settings.SettingsEnums;
 import android.content.Context;
 import android.text.TextUtils;
 
@@ -26,6 +27,7 @@
 import com.android.settings.core.BasePreferenceController;
 import com.android.settings.fuelgauge.PowerUsageFeatureProvider;
 import com.android.settings.overlay.FeatureFactory;
+import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
 
 import java.util.function.Function;
 
@@ -36,22 +38,20 @@
     private static final String ROOT_PREFERENCE_KEY = "battery_tips_category";
     private static final String CARD_PREFERENCE_KEY = "battery_tips_card";
 
-    private final String[] mPowerAnomalyKeys;
+    private final PowerUsageFeatureProvider mPowerUsageFeatureProvider;
+    private final MetricsFeatureProvider mMetricsFeatureProvider;
 
     @VisibleForTesting
     BatteryTipsCardPreference mCardPreference;
-    @VisibleForTesting
-    PowerUsageFeatureProvider mPowerUsageFeatureProvider;
 
     public BatteryTipsController(Context context) {
         super(context, ROOT_PREFERENCE_KEY);
-        mPowerUsageFeatureProvider = FeatureFactory.getFeatureFactory()
-            .getPowerUsageFeatureProvider();
-        mPowerAnomalyKeys = context.getResources().getStringArray(R.array.power_anomaly_keys);
+        final FeatureFactory featureFactory = FeatureFactory.getFeatureFactory();
+        mPowerUsageFeatureProvider =  featureFactory.getPowerUsageFeatureProvider();
+        mMetricsFeatureProvider = featureFactory.getMetricsFeatureProvider();
     }
 
     private boolean isTipsCardVisible() {
-        // TODO: compared with the timestamp of last user dismiss action in sharedPreference.
         return mPowerUsageFeatureProvider.isBatteryTipsEnabled();
     }
 
@@ -66,16 +66,6 @@
         mCardPreference = screen.findPreference(CARD_PREFERENCE_KEY);
     }
 
-    @VisibleForTesting
-    int getPowerAnomalyEventIndex(String powerAnomalyKey) {
-        for (int index = 0; index < mPowerAnomalyKeys.length; index++) {
-            if (mPowerAnomalyKeys[index].equals(powerAnomalyKey)) {
-                return index;
-            }
-        }
-        return -1;
-    }
-
     private <T> T getInfo(PowerAnomalyEvent powerAnomalyEvent,
                           Function<WarningBannerInfo, T> warningBannerInfoSupplier,
                           Function<WarningItemInfo, T> warningItemInfoSupplier) {
@@ -98,8 +88,9 @@
             return string;
         }
 
-        if (resourceIndex >= 0) {
-            string = mContext.getResources().getStringArray(resourceId)[resourceIndex];
+        String[] stringArray = mContext.getResources().getStringArray(resourceId);
+        if (resourceIndex >= 0 && resourceIndex < stringArray.length) {
+            string = stringArray[resourceIndex];
         }
 
         return string;
@@ -117,10 +108,11 @@
         }
 
         // Get card preference strings and navigate fragment info
-        final int index = getPowerAnomalyEventIndex(powerAnomalyEvent.getKey());
+        final int resourceIndex = powerAnomalyEvent.hasKey()
+                ? powerAnomalyEvent.getKey().getNumber() : -1;
 
         String titleString = getString(powerAnomalyEvent, WarningBannerInfo::getTitleString,
-                WarningItemInfo::getTitleString, R.array.power_anomaly_titles, index);
+                WarningItemInfo::getTitleString, R.array.power_anomaly_titles, resourceIndex);
         if (titleString.isEmpty()) {
             mCardPreference.setVisible(false);
             return;
@@ -128,10 +120,10 @@
 
         String mainBtnString = getString(powerAnomalyEvent,
                 WarningBannerInfo::getMainButtonString, WarningItemInfo::getMainButtonString,
-                R.array.power_anomaly_main_btn_strings, index);
+                R.array.power_anomaly_main_btn_strings, resourceIndex);
         String dismissBtnString = getString(powerAnomalyEvent,
                 WarningBannerInfo::getCancelButtonString, WarningItemInfo::getCancelButtonString,
-                R.array.power_anomaly_dismiss_btn_strings, index);
+                R.array.power_anomaly_dismiss_btn_strings, resourceIndex);
 
         String destinationClassName = getString(powerAnomalyEvent,
                 WarningBannerInfo::getMainButtonDestination,
@@ -142,10 +134,14 @@
                 WarningItemInfo::getMainButtonSourceMetricsCategory);
 
         // Updated card preference and main button fragment launcher
+        mCardPreference.setAnomalyEventId(powerAnomalyEvent.getEventId());
         mCardPreference.setTitle(titleString);
         mCardPreference.setMainButtonLabel(mainBtnString);
         mCardPreference.setDismissButtonLabel(dismissBtnString);
         mCardPreference.setMainButtonLauncherInfo(destinationClassName, sourceMetricsCategory);
         mCardPreference.setVisible(true);
+
+        mMetricsFeatureProvider.action(mContext,
+                SettingsEnums.ACTION_BATTERY_TIPS_CARD_SHOW, powerAnomalyEvent.getEventId());
     }
 }
diff --git a/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBreakdownController.java b/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBreakdownController.java
index a3b73df..d51485a 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBreakdownController.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBreakdownController.java
@@ -144,19 +144,17 @@
         }
         final PowerGaugePreference powerPref = (PowerGaugePreference) preference;
         final BatteryDiffEntry diffEntry = powerPref.getBatteryDiffEntry();
-        final BatteryHistEntry histEntry = diffEntry.mBatteryHistEntry;
-        final String packageName = histEntry.mPackageName;
-        final boolean isAppEntry = histEntry.isAppEntry();
+        final String packageName = diffEntry.getPackageName();
         mMetricsFeatureProvider.action(
                 /* attribution */ SettingsEnums.OPEN_BATTERY_USAGE,
-                /* action */ isAppEntry
-                        ? SettingsEnums.ACTION_BATTERY_USAGE_APP_ITEM
-                        : SettingsEnums.ACTION_BATTERY_USAGE_SYSTEM_ITEM,
+                /* action */ diffEntry.isSystemEntry()
+                        ? SettingsEnums.ACTION_BATTERY_USAGE_SYSTEM_ITEM
+                        : SettingsEnums.ACTION_BATTERY_USAGE_APP_ITEM,
                 /* pageId */ SettingsEnums.OPEN_BATTERY_USAGE,
                 TextUtils.isEmpty(packageName) ? PACKAGE_NAME_NONE : packageName,
                 (int) Math.round(diffEntry.getPercentage()));
         Log.d(TAG, String.format("handleClick() label=%s key=%s package=%s",
-                diffEntry.getAppLabel(), histEntry.getKey(), histEntry.mPackageName));
+                diffEntry.getAppLabel(), diffEntry.getKey(), packageName));
         AdvancedPowerUsageDetail.startBatteryDetailPage(
                 mActivity, mFragment, diffEntry, powerPref.getPercentage(), mSlotTimestamp);
         return true;
diff --git a/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageContentProvider.java b/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageContentProvider.java
index 1b2d4cd..edba7c4 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageContentProvider.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageContentProvider.java
@@ -21,7 +21,6 @@
 import android.content.UriMatcher;
 import android.database.Cursor;
 import android.net.Uri;
-import android.os.AsyncTask;
 import android.text.TextUtils;
 import android.util.Log;
 
@@ -36,12 +35,14 @@
 import com.android.settings.fuelgauge.batteryusage.db.BatteryState;
 import com.android.settings.fuelgauge.batteryusage.db.BatteryStateDao;
 import com.android.settings.fuelgauge.batteryusage.db.BatteryStateDatabase;
+import com.android.settings.fuelgauge.batteryusage.db.BatteryUsageSlotDao;
+import com.android.settings.fuelgauge.batteryusage.db.BatteryUsageSlotEntity;
 
 import java.time.Clock;
 import java.time.Duration;
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
-import java.util.stream.Collectors;
 
 /** {@link ContentProvider} class to fetch battery usage data. */
 public class BatteryUsageContentProvider extends ContentProvider {
@@ -55,7 +56,12 @@
     private static final int APP_USAGE_LATEST_TIMESTAMP_CODE = 2;
     private static final int APP_USAGE_EVENT_CODE = 3;
     private static final int BATTERY_EVENT_CODE = 4;
+    private static final int LAST_FULL_CHARGE_TIMESTAMP_CODE = 5;
+    private static final int BATTERY_STATE_LATEST_TIMESTAMP_CODE = 6;
+    private static final int BATTERY_USAGE_SLOT_CODE = 7;
 
+    private static final List<Integer> ALL_BATTERY_EVENT_TYPES =
+            Arrays.stream(BatteryEventType.values()).map(type -> type.getNumber()).toList();
     private static final UriMatcher sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
 
     static {
@@ -75,12 +81,25 @@
                 DatabaseUtils.AUTHORITY,
                 /*path=*/ DatabaseUtils.BATTERY_EVENT_TABLE,
                 /*code=*/ BATTERY_EVENT_CODE);
+        sUriMatcher.addURI(
+                DatabaseUtils.AUTHORITY,
+                /*path=*/ DatabaseUtils.LAST_FULL_CHARGE_TIMESTAMP_PATH,
+                /*code=*/ LAST_FULL_CHARGE_TIMESTAMP_CODE);
+        sUriMatcher.addURI(
+                DatabaseUtils.AUTHORITY,
+                /*path=*/ DatabaseUtils.BATTERY_STATE_LATEST_TIMESTAMP_PATH,
+                /*code=*/ BATTERY_STATE_LATEST_TIMESTAMP_CODE);
+        sUriMatcher.addURI(
+                DatabaseUtils.AUTHORITY,
+                /*path=*/ DatabaseUtils.BATTERY_USAGE_SLOT_TABLE,
+                /*code=*/ BATTERY_USAGE_SLOT_CODE);
     }
 
     private Clock mClock;
     private BatteryStateDao mBatteryStateDao;
     private AppUsageEventDao mAppUsageEventDao;
     private BatteryEventDao mBatteryEventDao;
+    private BatteryUsageSlotDao mBatteryUsageSlotDao;
 
     @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
     public void setClock(Clock clock) {
@@ -94,9 +113,11 @@
             return false;
         }
         mClock = Clock.systemUTC();
-        mBatteryStateDao = BatteryStateDatabase.getInstance(getContext()).batteryStateDao();
-        mAppUsageEventDao = BatteryStateDatabase.getInstance(getContext()).appUsageEventDao();
-        mBatteryEventDao = BatteryStateDatabase.getInstance(getContext()).batteryEventDao();
+        final BatteryStateDatabase database = BatteryStateDatabase.getInstance(getContext());
+        mBatteryStateDao = database.batteryStateDao();
+        mAppUsageEventDao = database.appUsageEventDao();
+        mBatteryEventDao = database.batteryEventDao();
+        mBatteryUsageSlotDao = database.batteryUsageSlotDao();
         Log.w(TAG, "create content provider from " + getCallingPackage());
         return true;
     }
@@ -118,6 +139,12 @@
                 return getAppUsageLatestTimestamp(uri);
             case BATTERY_EVENT_CODE:
                 return getBatteryEvents(uri);
+            case LAST_FULL_CHARGE_TIMESTAMP_CODE:
+                return getLastFullChargeTimestamp(uri);
+            case BATTERY_STATE_LATEST_TIMESTAMP_CODE:
+                return getBatteryStateLatestTimestamp(uri);
+            case BATTERY_USAGE_SLOT_CODE:
+                return getBatteryUsageSlots(uri);
             default:
                 throw new IllegalArgumentException("unknown URI: " + uri);
         }
@@ -132,34 +159,31 @@
     @Nullable
     @Override
     public Uri insert(@NonNull Uri uri, @Nullable ContentValues contentValues) {
-        switch (sUriMatcher.match(uri)) {
-            case BATTERY_STATE_CODE:
-                try {
+        try {
+            switch (sUriMatcher.match(uri)) {
+                case BATTERY_STATE_CODE:
                     mBatteryStateDao.insert(BatteryState.create(contentValues));
-                    return uri;
-                } catch (RuntimeException e) {
-                    Log.e(TAG, "insert() from:" + uri + " error:" + e);
-                    return null;
-                }
-            case APP_USAGE_EVENT_CODE:
-                try {
+                    break;
+                case APP_USAGE_EVENT_CODE:
                     mAppUsageEventDao.insert(AppUsageEventEntity.create(contentValues));
-                    return uri;
-                } catch (RuntimeException e) {
-                    Log.e(TAG, "insert() from:" + uri + " error:" + e);
-                    return null;
-                }
-            case BATTERY_EVENT_CODE:
-                try {
+                    break;
+                case BATTERY_EVENT_CODE:
                     mBatteryEventDao.insert(BatteryEventEntity.create(contentValues));
-                    return uri;
-                } catch (RuntimeException e) {
-                    Log.e(TAG, "insert() from:" + uri + " error:" + e);
-                    return null;
-                }
-            default:
-                throw new IllegalArgumentException("unknown URI: " + uri);
+                    break;
+                case BATTERY_USAGE_SLOT_CODE:
+                    mBatteryUsageSlotDao.insert(BatteryUsageSlotEntity.create(contentValues));
+                    break;
+                default:
+                    throw new IllegalArgumentException("unknown URI: " + uri);
+            }
+        } catch (RuntimeException e) {
+            if (e instanceof  IllegalArgumentException) {
+                throw e;
+            }
+            Log.e(TAG, "insert() from:" + uri + " error:", e);
+            return null;
         }
+        return uri;
     }
 
     @Override
@@ -176,21 +200,44 @@
         throw new UnsupportedOperationException("unsupported!");
     }
 
-    private Cursor getBatteryStates(Uri uri) {
-        final long queryTimestamp = getQueryTimestamp(uri);
-        return getBatteryStates(uri, queryTimestamp);
-    }
-
-    private Cursor getBatteryStates(Uri uri, long firstTimestamp) {
+    private Cursor getLastFullChargeTimestamp(Uri uri) {
         final long timestamp = mClock.millis();
         Cursor cursor = null;
         try {
-            cursor = mBatteryStateDao.getCursorSinceLastFullCharge(firstTimestamp);
+            cursor = mBatteryEventDao.getLastFullChargeTimestamp();
         } catch (RuntimeException e) {
-            Log.e(TAG, "query() from:" + uri + " error:" + e);
+            Log.e(TAG, "query() from:" + uri + " error:", e);
         }
-        AsyncTask.execute(() -> BootBroadcastReceiver.invokeJobRecheck(getContext()));
-        Log.d(TAG, "query battery states in " + (mClock.millis() - timestamp) + "/ms");
+        Log.d(TAG, String.format("getLastFullChargeTimestamp() in %d/ms",
+                mClock.millis() - timestamp));
+        return cursor;
+    }
+
+    private Cursor getBatteryStateLatestTimestamp(Uri uri) {
+        final long queryTimestamp = getQueryTimestamp(uri);
+        final long timestamp = mClock.millis();
+        Cursor cursor = null;
+        try {
+            cursor = mBatteryStateDao.getLatestTimestampBefore(queryTimestamp);
+        } catch (RuntimeException e) {
+            Log.e(TAG, "query() from:" + uri + " error:", e);
+        }
+        Log.d(TAG, String.format("getBatteryStateLatestTimestamp() no later than %d in %d/ms",
+                queryTimestamp, mClock.millis() - timestamp));
+        return cursor;
+    }
+
+    private Cursor getBatteryStates(Uri uri) {
+        final long queryTimestamp = getQueryTimestamp(uri);
+        final long timestamp = mClock.millis();
+        Cursor cursor = null;
+        try {
+            cursor = mBatteryStateDao.getBatteryStatesAfter(queryTimestamp);
+        } catch (RuntimeException e) {
+            Log.e(TAG, "query() from:" + uri + " error:", e);
+        }
+        Log.d(TAG, String.format("getBatteryStates() after %d in %d/ms",
+                queryTimestamp, mClock.millis() - timestamp));
         return cursor;
     }
 
@@ -205,9 +252,9 @@
         try {
             cursor = mAppUsageEventDao.getAllForUsersAfter(queryUserIds, queryTimestamp);
         } catch (RuntimeException e) {
-            Log.e(TAG, "query() from:" + uri + " error:" + e);
+            Log.e(TAG, "query() from:" + uri + " error:", e);
         }
-        Log.w(TAG, "query app usage events in " + (mClock.millis() - timestamp) + "/ms");
+        Log.w(TAG, "getAppUsageEvents() in " + (mClock.millis() - timestamp) + "/ms");
         return cursor;
     }
 
@@ -221,42 +268,78 @@
         try {
             cursor = mAppUsageEventDao.getLatestTimestampOfUser(queryUserId);
         } catch (RuntimeException e) {
-            Log.e(TAG, "query() from:" + uri + " error:" + e);
+            Log.e(TAG, "query() from:" + uri + " error:", e);
         }
-        Log.d(TAG, String.format("query app usage latest timestamp %d for user %d in %d/ms",
-                timestamp, queryUserId, (mClock.millis() - timestamp)));
+        Log.d(TAG, String.format("getAppUsageLatestTimestamp() for user %d in %d/ms",
+                queryUserId, (mClock.millis() - timestamp)));
         return cursor;
     }
 
     private Cursor getBatteryEvents(Uri uri) {
+        List<Integer> queryBatteryEventTypes = getQueryBatteryEventTypes(uri);
+        if (queryBatteryEventTypes == null || queryBatteryEventTypes.isEmpty()) {
+            queryBatteryEventTypes = ALL_BATTERY_EVENT_TYPES;
+        }
         final long queryTimestamp = getQueryTimestamp(uri);
         final long timestamp = mClock.millis();
         Cursor cursor = null;
         try {
-            cursor = mBatteryEventDao.getAllAfter(queryTimestamp);
+            cursor = mBatteryEventDao.getAllAfter(queryTimestamp, queryBatteryEventTypes);
         } catch (RuntimeException e) {
-            Log.e(TAG, "query() from:" + uri + " error:" + e);
+            Log.e(TAG, "query() from:" + uri + " error:", e);
         }
-        Log.w(TAG, "query app usage events in " + (mClock.millis() - timestamp) + "/ms");
+        Log.w(TAG, "getBatteryEvents() in " + (mClock.millis() - timestamp) + "/ms");
         return cursor;
     }
 
+    private Cursor getBatteryUsageSlots(Uri uri) {
+        final long queryTimestamp = getQueryTimestamp(uri);
+        final long timestamp = mClock.millis();
+        Cursor cursor = null;
+        try {
+            cursor = mBatteryUsageSlotDao.getAllAfter(queryTimestamp);
+        } catch (RuntimeException e) {
+            Log.e(TAG, "query() from:" + uri + " error:", e);
+        }
+        Log.w(TAG, "getBatteryUsageSlots() in " + (mClock.millis() - timestamp) + "/ms");
+        return cursor;
+    }
+
+    private List<Integer> getQueryBatteryEventTypes(Uri uri) {
+        Log.d(TAG, "getQueryBatteryEventTypes from uri: " + uri);
+        final String batteryEventTypesParameter =
+                uri.getQueryParameter(DatabaseUtils.QUERY_BATTERY_EVENT_TYPE);
+        if (TextUtils.isEmpty(batteryEventTypesParameter)) {
+            return null;
+        }
+        try {
+            List<Integer> batteryEventTypes = new ArrayList<>();
+            for (String typeString : batteryEventTypesParameter.split(",")) {
+                batteryEventTypes.add(Integer.parseInt(typeString.trim()));
+            }
+            return batteryEventTypes;
+        } catch (NumberFormatException e) {
+            Log.e(TAG, "invalid query value: " + batteryEventTypesParameter, e);
+            return null;
+        }
+    }
+
     // If URI contains query parameter QUERY_KEY_USERID, use the value directly.
     // Otherwise, return null.
     private List<Long> getQueryUserIds(Uri uri) {
         Log.d(TAG, "getQueryUserIds from uri: " + uri);
-        final String value = uri.getQueryParameter(DatabaseUtils.QUERY_KEY_USERID);
-        if (TextUtils.isEmpty(value)) {
-            Log.w(TAG, "empty query value");
+        final String userIdsParameter = uri.getQueryParameter(DatabaseUtils.QUERY_KEY_USERID);
+        if (TextUtils.isEmpty(userIdsParameter)) {
             return null;
         }
         try {
-            return Arrays.asList(value.split(","))
-                    .stream()
-                    .map(s -> Long.parseLong(s.trim()))
-                    .collect(Collectors.toList());
+            List<Long> userIds = new ArrayList<>();
+            for (String idString : userIdsParameter.split(",")) {
+                userIds.add(Long.parseLong(idString.trim()));
+            }
+            return userIds;
         } catch (NumberFormatException e) {
-            Log.e(TAG, "invalid query value: " + value, e);
+            Log.e(TAG, "invalid query value: " + userIdsParameter, e);
             return null;
         }
     }
diff --git a/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageDataLoader.java b/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageDataLoader.java
index ae86095..48a39f4 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageDataLoader.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageDataLoader.java
@@ -16,9 +16,12 @@
 
 package com.android.settings.fuelgauge.batteryusage;
 
+import android.app.usage.UsageEvents;
 import android.content.Context;
 import android.os.AsyncTask;
 import android.os.BatteryUsageStats;
+import android.os.Handler;
+import android.os.Looper;
 import android.util.Log;
 
 import androidx.annotation.VisibleForTesting;
@@ -27,6 +30,7 @@
 import com.android.settings.fuelgauge.batteryusage.bugreport.BatteryUsageLogUtils;
 
 import java.util.List;
+import java.util.Map;
 import java.util.function.Supplier;
 
 /** Load battery usage data in the background. */
@@ -36,6 +40,10 @@
     // For testing only.
     @VisibleForTesting
     static Supplier<List<BatteryEntry>> sFakeBatteryEntryListSupplier;
+    @VisibleForTesting
+    static Supplier<Map<Long, UsageEvents>> sFakeAppUsageEventsSupplier;
+    @VisibleForTesting
+    static Supplier<List<AppUsageEvent>> sFakeUsageEventsListSupplier;
 
     private BatteryUsageDataLoader() {
     }
@@ -48,9 +56,9 @@
     }
 
     @VisibleForTesting
-    static void loadUsageData(final Context context, final boolean isFullChargeStart) {
+    static void loadBatteryStatsData(final Context context, final boolean isFullChargeStart) {
         BatteryUsageLogUtils.writeLog(context, Action.FETCH_USAGE_DATA, "");
-        final long start = System.currentTimeMillis();
+        final long currentTime = System.currentTimeMillis();
         final BatteryUsageStats batteryUsageStats = DataProcessor.getBatteryUsageStats(context);
         final List<BatteryEntry> batteryEntryList =
                 sFakeBatteryEntryListSupplier != null ? sFakeBatteryEntryListSupplier.get()
@@ -59,25 +67,81 @@
         if (batteryEntryList == null || batteryEntryList.isEmpty()) {
             Log.w(TAG, "getBatteryEntryList() returns null or empty content");
         }
-        final long elapsedTime = System.currentTimeMillis() - start;
+        final long elapsedTime = System.currentTimeMillis() - currentTime;
         Log.d(TAG, String.format("getBatteryUsageStats() in %d/ms", elapsedTime));
         if (isFullChargeStart) {
             DatabaseUtils.recordDateTime(
                     context, DatabaseUtils.KEY_LAST_LOAD_FULL_CHARGE_TIME);
+            DatabaseUtils.sendBatteryEventData(context, ConvertUtils.convertToBatteryEvent(
+                    currentTime, BatteryEventType.FULL_CHARGED, 100));
         }
 
         // Uploads the BatteryEntry data into database.
         DatabaseUtils.sendBatteryEntryData(
-                context, batteryEntryList, batteryUsageStats, isFullChargeStart);
+                context, currentTime, batteryEntryList, batteryUsageStats, isFullChargeStart);
         DataProcessor.closeBatteryUsageStats(batteryUsageStats);
     }
 
+    @VisibleForTesting
+    static void loadAppUsageData(final Context context) {
+        final long start = System.currentTimeMillis();
+        final Map<Long, UsageEvents> appUsageEvents =
+                sFakeAppUsageEventsSupplier != null
+                        ? sFakeAppUsageEventsSupplier.get()
+                        : DataProcessor.getAppUsageEvents(context);
+        if (appUsageEvents == null) {
+            Log.w(TAG, "loadAppUsageData() returns null");
+            return;
+        }
+        final List<AppUsageEvent> appUsageEventList =
+                sFakeUsageEventsListSupplier != null
+                        ? sFakeUsageEventsListSupplier.get()
+                        : DataProcessor.generateAppUsageEventListFromUsageEvents(
+                                context, appUsageEvents);
+        if (appUsageEventList == null || appUsageEventList.isEmpty()) {
+            Log.w(TAG, "loadAppUsageData() returns null or empty content");
+            return;
+        }
+        final long elapsedTime = System.currentTimeMillis() - start;
+        Log.d(TAG, String.format("loadAppUsageData() size=%d in %d/ms", appUsageEventList.size(),
+                elapsedTime));
+        // Uploads the AppUsageEvent data into database.
+        DatabaseUtils.sendAppUsageEventData(context, appUsageEventList);
+    }
+
+    private static void preprocessBatteryUsageSlots(final Context context) {
+        final long start = System.currentTimeMillis();
+        final Handler handler = new Handler(Looper.getMainLooper());
+        final BatteryLevelData batteryLevelData = DataProcessManager.getBatteryLevelData(
+                context, handler, /*isFromPeriodJob=*/ true,
+                batteryDiffDataMap -> DatabaseUtils.sendBatteryUsageSlotData(context,
+                        ConvertUtils.convertToBatteryUsageSlotList(batteryDiffDataMap)));
+        if (batteryLevelData == null) {
+            Log.d(TAG, "preprocessBatteryUsageSlots() no new battery usage data.");
+            return;
+        }
+
+        DatabaseUtils.sendBatteryEventData(
+                context, ConvertUtils.convertToBatteryEventList(batteryLevelData));
+        Log.d(TAG, String.format(
+                "preprocessBatteryUsageSlots() batteryLevelData=%s in %d/ms",
+                batteryLevelData, System.currentTimeMillis() - start));
+    }
+
     private static void loadUsageDataSafely(
             final Context context, final boolean isFullChargeStart) {
         try {
-            loadUsageData(context, isFullChargeStart);
+            final long start = System.currentTimeMillis();
+            loadBatteryStatsData(context, isFullChargeStart);
+            if (!isFullChargeStart) {
+                // No app usage data or battery diff data at this time.
+                loadAppUsageData(context);
+                preprocessBatteryUsageSlots(context);
+            }
+            Log.d(TAG, String.format(
+                    "loadUsageDataSafely() in %d/ms", System.currentTimeMillis() - start));
         } catch (RuntimeException e) {
-            Log.e(TAG, "loadUsageData:" + e);
+            Log.e(TAG, "loadUsageData:", e);
         }
     }
 }
diff --git a/src/com/android/settings/fuelgauge/batteryusage/ConvertUtils.java b/src/com/android/settings/fuelgauge/batteryusage/ConvertUtils.java
index 5fc4ad5..ec0d01a 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/ConvertUtils.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/ConvertUtils.java
@@ -33,15 +33,21 @@
 import android.util.Base64;
 import android.util.Log;
 
+import androidx.annotation.NonNull;
 import androidx.annotation.VisibleForTesting;
 
 import com.android.settings.fuelgauge.BatteryUtils;
 import com.android.settings.fuelgauge.batteryusage.db.AppUsageEventEntity;
 import com.android.settings.fuelgauge.batteryusage.db.BatteryEventEntity;
+import com.android.settings.fuelgauge.batteryusage.db.BatteryUsageSlotEntity;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
+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. */
@@ -75,7 +81,22 @@
     private ConvertUtils() {
     }
 
-    /** Converts {@link BatteryEntry} to content values */
+    /** Whether {@code consumerType} is app consumer or not. */
+    public static boolean isUidConsumer(final int consumerType) {
+        return consumerType == CONSUMER_TYPE_UID_BATTERY;
+    }
+
+    /** Whether {@code consumerType} is user consumer or not. */
+    public static boolean isUserConsumer(final int consumerType) {
+        return consumerType == CONSUMER_TYPE_USER_BATTERY;
+    }
+
+    /** Whether {@code consumerType} is system consumer or not. */
+    public static boolean isSystemConsumer(final int consumerType) {
+        return consumerType == CONSUMER_TYPE_SYSTEM_BATTERY;
+    }
+
+    /** Converts {@link BatteryEntry} to {@link ContentValues} */
     public static ContentValues convertBatteryEntryToContentValues(
             final BatteryEntry entry,
             final BatteryUsageStats batteryUsageStats,
@@ -118,7 +139,7 @@
         return values;
     }
 
-    /** Converts {@link AppUsageEvent} to content values */
+    /** Converts {@link AppUsageEvent} to {@link ContentValues} */
     public static ContentValues convertAppUsageEventToContentValues(final AppUsageEvent event) {
         final ContentValues values = new ContentValues();
         values.put(AppUsageEventEntity.KEY_UID, event.getUid());
@@ -131,7 +152,7 @@
         return values;
     }
 
-    /** Converts {@link BatteryEvent} to content values */
+    /** Converts {@link BatteryEvent} to {@link ContentValues} */
     public static ContentValues convertBatteryEventToContentValues(final BatteryEvent event) {
         final ContentValues values = new ContentValues();
         values.put(BatteryEventEntity.KEY_TIMESTAMP, event.getTimestamp());
@@ -140,6 +161,16 @@
         return values;
     }
 
+    /** Converts {@link BatteryUsageSlot} to {@link ContentValues} */
+    public static ContentValues convertBatteryUsageSlotToContentValues(
+            final BatteryUsageSlot batteryUsageSlot) {
+        final ContentValues values = new ContentValues(2);
+        values.put(BatteryUsageSlotEntity.KEY_TIMESTAMP, batteryUsageSlot.getStartTimestamp());
+        values.put(BatteryUsageSlotEntity.KEY_BATTERY_USAGE_SLOT,
+                Base64.encodeToString(batteryUsageSlot.toByteArray(), Base64.DEFAULT));
+        return values;
+    }
+
     /** Gets the encoded string from {@link BatteryInformation} instance. */
     public static String convertBatteryInformationToString(
             final BatteryInformation batteryInformation) {
@@ -183,7 +214,7 @@
                         /*isFullChargeStart=*/ false));
     }
 
-    /** Converts to {@link AppUsageEvent} from {@link Event} */
+    /** Converts from {@link Event} to {@link AppUsageEvent} */
     @Nullable
     public static AppUsageEvent convertToAppUsageEvent(
             Context context, IUsageStatsManager usageStatsManager, final Event event,
@@ -234,8 +265,8 @@
         return appUsageEventBuilder.build();
     }
 
-    /** Converts to {@link AppUsageEvent} from {@link Cursor} */
-    public static AppUsageEvent convertToAppUsageEventFromCursor(final Cursor cursor) {
+    /** Converts from {@link Cursor} to {@link AppUsageEvent} */
+    public static AppUsageEvent convertToAppUsageEvent(final Cursor cursor) {
         final AppUsageEvent.Builder eventBuilder = AppUsageEvent.newBuilder();
         eventBuilder.setTimestamp(getLongFromCursor(cursor, AppUsageEventEntity.KEY_TIMESTAMP));
         eventBuilder.setType(
@@ -253,7 +284,7 @@
         return eventBuilder.build();
     }
 
-    /** Converts to {@link BatteryEvent} from {@link BatteryEventType} */
+    /** Converts from {@link BatteryEventType} to {@link BatteryEvent} */
     public static BatteryEvent convertToBatteryEvent(
             long timestamp, BatteryEventType type, int batteryLevel) {
         final BatteryEvent.Builder eventBuilder = BatteryEvent.newBuilder();
@@ -263,8 +294,8 @@
         return eventBuilder.build();
     }
 
-    /** Converts to {@link BatteryEvent} from {@link Cursor} */
-    public static BatteryEvent convertToBatteryEventFromCursor(final Cursor cursor) {
+    /** Converts from {@link Cursor} to {@link BatteryEvent} */
+    public static BatteryEvent convertToBatteryEvent(final Cursor cursor) {
         final BatteryEvent.Builder eventBuilder = BatteryEvent.newBuilder();
         eventBuilder.setTimestamp(getLongFromCursor(cursor, BatteryEventEntity.KEY_TIMESTAMP));
         eventBuilder.setType(
@@ -276,6 +307,42 @@
         return eventBuilder.build();
     }
 
+    /** Converts from {@link BatteryLevelData} to {@link List<BatteryEvent>} */
+    public static List<BatteryEvent> convertToBatteryEventList(
+            final BatteryLevelData batteryLevelData) {
+        final List<BatteryEvent> batteryEventList = new ArrayList<>();
+        final List<BatteryLevelData.PeriodBatteryLevelData> levelDataList =
+                batteryLevelData.getHourlyBatteryLevelsPerDay();
+        for (BatteryLevelData.PeriodBatteryLevelData oneDayData : levelDataList) {
+            for (int hourIndex = 0; hourIndex < oneDayData.getLevels().size() - 1; hourIndex++) {
+                batteryEventList.add(convertToBatteryEvent(
+                        oneDayData.getTimestamps().get(hourIndex),
+                        BatteryEventType.EVEN_HOUR,
+                        oneDayData.getLevels().get(hourIndex)));
+            }
+        }
+        return batteryEventList;
+    }
+
+    /** Converts from {@link Cursor} to {@link BatteryUsageSlot} */
+    public static BatteryUsageSlot convertToBatteryUsageSlot(final Cursor cursor) {
+        final BatteryUsageSlot defaultInstance = BatteryUsageSlot.getDefaultInstance();
+        final int columnIndex =
+                cursor.getColumnIndex(BatteryUsageSlotEntity.KEY_BATTERY_USAGE_SLOT);
+        return columnIndex < 0 ? defaultInstance : BatteryUtils.parseProtoFromString(
+                cursor.getString(columnIndex), defaultInstance);
+    }
+
+    /** Converts from {@link Map<Long, BatteryDiffData>} to {@link List<BatteryUsageSlot>} */
+    public static List<BatteryUsageSlot> convertToBatteryUsageSlotList(
+            final Map<Long, BatteryDiffData> batteryDiffDataMap) {
+        List<BatteryUsageSlot> batteryUsageSlotList = new ArrayList<>();
+        for (BatteryDiffData batteryDiffData : batteryDiffDataMap.values()) {
+            batteryUsageSlotList.add(convertToBatteryUsageSlot(batteryDiffData));
+        }
+        return batteryUsageSlotList;
+    }
+
     /** Converts UTC timestamp to local time string for logging only, so use the US locale for
      *  better readability in debugging. */
     public static String utcToLocalTimeForLogging(long timestamp) {
@@ -396,6 +463,100 @@
         }
     }
 
+    private static BatteryUsageDiff convertToBatteryUsageDiff(BatteryDiffEntry batteryDiffEntry) {
+        BatteryUsageDiff.Builder builder = BatteryUsageDiff.newBuilder()
+                .setUid(batteryDiffEntry.mUid)
+                .setUserId(batteryDiffEntry.mUserId)
+                .setIsHidden(batteryDiffEntry.mIsHidden)
+                .setComponentId(batteryDiffEntry.mComponentId)
+                .setConsumerType(batteryDiffEntry.mConsumerType)
+                .setConsumePower(batteryDiffEntry.mConsumePower)
+                .setForegroundUsageConsumePower(batteryDiffEntry.mForegroundUsageConsumePower)
+                .setBackgroundUsageConsumePower(batteryDiffEntry.mBackgroundUsageConsumePower)
+                .setForegroundUsageTime(batteryDiffEntry.mForegroundUsageTimeInMs)
+                .setBackgroundUsageTime(batteryDiffEntry.mBackgroundUsageTimeInMs)
+                .setScreenOnTime(batteryDiffEntry.mScreenOnTimeInMs);
+        if (batteryDiffEntry.mKey != null) {
+            builder.setKey(batteryDiffEntry.mKey);
+        }
+        if (batteryDiffEntry.mLegacyPackageName != null) {
+            builder.setPackageName(batteryDiffEntry.mLegacyPackageName);
+        }
+        if (batteryDiffEntry.mLegacyLabel != null) {
+            builder.setLabel(batteryDiffEntry.mLegacyLabel);
+        }
+        return builder.build();
+    }
+
+    private static BatteryUsageSlot convertToBatteryUsageSlot(
+            final BatteryDiffData batteryDiffData) {
+        if (batteryDiffData == null) {
+            return BatteryUsageSlot.getDefaultInstance();
+        }
+        final BatteryUsageSlot.Builder builder = BatteryUsageSlot.newBuilder()
+                .setStartTimestamp(batteryDiffData.getStartTimestamp())
+                .setEndTimestamp(batteryDiffData.getEndTimestamp())
+                .setStartBatteryLevel(batteryDiffData.getStartBatteryLevel())
+                .setEndBatteryLevel(batteryDiffData.getEndBatteryLevel())
+                .setScreenOnTime(batteryDiffData.getScreenOnTime());
+        for (BatteryDiffEntry batteryDiffEntry : batteryDiffData.getAppDiffEntryList()) {
+            builder.addAppUsage(convertToBatteryUsageDiff(batteryDiffEntry));
+        }
+        for (BatteryDiffEntry batteryDiffEntry : batteryDiffData.getSystemDiffEntryList()) {
+            builder.addSystemUsage(convertToBatteryUsageDiff(batteryDiffEntry));
+        }
+        return builder.build();
+    }
+
+    private static BatteryDiffEntry convertToBatteryDiffEntry(
+            Context context, final BatteryUsageDiff batteryUsageDiff) {
+        return new BatteryDiffEntry(
+                context,
+                batteryUsageDiff.getUid(),
+                batteryUsageDiff.getUserId(),
+                batteryUsageDiff.getKey(),
+                batteryUsageDiff.getIsHidden(),
+                batteryUsageDiff.getComponentId(),
+                batteryUsageDiff.getPackageName(),
+                batteryUsageDiff.getLabel(),
+                batteryUsageDiff.getConsumerType(),
+                batteryUsageDiff.getForegroundUsageTime(),
+                batteryUsageDiff.getBackgroundUsageTime(),
+                batteryUsageDiff.getScreenOnTime(),
+                batteryUsageDiff.getConsumePower(),
+                batteryUsageDiff.getForegroundUsageConsumePower(),
+                /*foregroundServiceUsageConsumePower=*/ 0,
+                batteryUsageDiff.getBackgroundUsageConsumePower(),
+                /*cachedUsageConsumePower=*/ 0);
+    }
+
+    static BatteryDiffData convertToBatteryDiffData(
+            Context context,
+            final BatteryUsageSlot batteryUsageSlot,
+            @NonNull final Set<String> systemAppsPackageNames,
+            @NonNull final Set<Integer> systemAppsUids) {
+        final List<BatteryDiffEntry> appDiffEntries = new ArrayList<>();
+        final List<BatteryDiffEntry> systemDiffEntries = new ArrayList<>();
+        for (BatteryUsageDiff batteryUsageDiff : batteryUsageSlot.getAppUsageList()) {
+            appDiffEntries.add(convertToBatteryDiffEntry(context, batteryUsageDiff));
+        }
+        for (BatteryUsageDiff batteryUsageDiff : batteryUsageSlot.getSystemUsageList()) {
+            systemDiffEntries.add(convertToBatteryDiffEntry(context, batteryUsageDiff));
+        }
+        return new BatteryDiffData(
+                context,
+                batteryUsageSlot.getStartTimestamp(),
+                batteryUsageSlot.getEndTimestamp(),
+                batteryUsageSlot.getStartBatteryLevel(),
+                batteryUsageSlot.getEndBatteryLevel(),
+                batteryUsageSlot.getScreenOnTime(),
+                appDiffEntries,
+                systemDiffEntries,
+                systemAppsPackageNames,
+                systemAppsUids,
+                /*isAccumulated=*/ false);
+    }
+
     private static BatteryInformation constructBatteryInformation(
             final BatteryEntry entry,
             final BatteryUsageStats batteryUsageStats,
diff --git a/src/com/android/settings/fuelgauge/batteryusage/DataProcessManager.java b/src/com/android/settings/fuelgauge/batteryusage/DataProcessManager.java
index 1c851fd..1a226fd 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/DataProcessManager.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/DataProcessManager.java
@@ -23,6 +23,7 @@
 import android.os.Looper;
 import android.os.UserHandle;
 import android.os.UserManager;
+import android.util.ArrayMap;
 import android.util.Log;
 
 import androidx.annotation.NonNull;
@@ -33,10 +34,10 @@
 
 import java.util.ArrayList;
 import java.util.Calendar;
-import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 
 /**
  * Manages the async tasks to process battery and app usage data.
@@ -69,28 +70,37 @@
  */
 public class DataProcessManager {
     private static final String TAG = "DataProcessManager";
+    private static final List<BatteryEventType> POWER_CONNECTION_EVENTS =
+            List.of(BatteryEventType.POWER_CONNECTED, BatteryEventType.POWER_DISCONNECTED);
+    private static final List<BatteryEventType> BATTERY_LEVEL_RECORD_EVENTS =
+            List.of(BatteryEventType.FULL_CHARGED, BatteryEventType.EVEN_HOUR);
 
-    private final Handler mHandler;
-    private final DataProcessor.UsageMapAsyncResponse mCallbackFunction;
-    private final List<AppUsageEvent> mAppUsageEventList = new ArrayList<>();
-    private final List<BatteryEvent> mBatteryEventList = new ArrayList<>();
-
-    private Context mContext;
-    private UserManager mUserManager;
-    private List<BatteryLevelData.PeriodBatteryLevelData> mHourlyBatteryLevelsPerDay;
-    private Map<Long, Map<String, BatteryHistEntry>> mBatteryHistoryMap;
+    // For testing only.
+    @VisibleForTesting
+    static Map<Long, Map<String, BatteryHistEntry>> sFakeBatteryHistoryMap;
 
     // Raw start timestamp with round to the nearest hour.
-    private long mRawStartTimestamp;
+    private final long mRawStartTimestamp;
+    private final long mLastFullChargeTimestamp;
+    private final Context mContext;
+    private final Handler mHandler;
+    private final UserManager mUserManager;
+    private final OnBatteryDiffDataMapLoadedListener mCallbackFunction;
+    private final List<AppUsageEvent> mAppUsageEventList = new ArrayList<>();
+    private final List<BatteryEvent> mBatteryEventList = new ArrayList<>();
+    private final List<BatteryUsageSlot> mBatteryUsageSlotList = new ArrayList<>();
+    private final List<BatteryLevelData.PeriodBatteryLevelData> mHourlyBatteryLevelsPerDay;
+    private final Map<Long, Map<String, BatteryHistEntry>> mBatteryHistoryMap;
 
     private boolean mIsCurrentBatteryHistoryLoaded = false;
     private boolean mIsCurrentAppUsageLoaded = false;
     private boolean mIsDatabaseAppUsageLoaded = false;
     private boolean mIsBatteryEventLoaded = false;
+    private boolean mIsBatteryUsageSlotLoaded = false;
     // Used to identify whether screen-on time data should be shown in the UI.
     private boolean mShowScreenOnTime = true;
-    // Used to identify whether battery level data should be shown in the UI.
-    private boolean mShowBatteryLevel = true;
+    private Set<String> mSystemAppsPackageNames = null;
+    private Set<Integer> mSystemAppsUids = null;
 
     /**
      * The indexed {@link AppUsagePeriod} list data for each corresponding time slot.
@@ -101,22 +111,33 @@
             mAppUsagePeriodMap;
 
     /**
+     *  A callback listener when all the data is processed.
+     *  This happens when all the async tasks complete and generate the final callback.
+     */
+    public interface OnBatteryDiffDataMapLoadedListener {
+        /** The callback function when all the data is processed. */
+        void onBatteryDiffDataMapLoaded(Map<Long, BatteryDiffData> batteryDiffDataMap);
+    }
+
+    /**
      * Constructor when there exists battery level data.
      */
     DataProcessManager(
             Context context,
             Handler handler,
             final long rawStartTimestamp,
-            @NonNull final DataProcessor.UsageMapAsyncResponse callbackFunction,
+            final long lastFullChargeTimestamp,
+            @NonNull final OnBatteryDiffDataMapLoadedListener callbackFunction,
             @NonNull final List<BatteryLevelData.PeriodBatteryLevelData> hourlyBatteryLevelsPerDay,
             @NonNull final Map<Long, Map<String, BatteryHistEntry>> batteryHistoryMap) {
         mContext = context.getApplicationContext();
         mHandler = handler;
         mUserManager = mContext.getSystemService(UserManager.class);
+        mRawStartTimestamp = rawStartTimestamp;
+        mLastFullChargeTimestamp = lastFullChargeTimestamp;
         mCallbackFunction = callbackFunction;
         mHourlyBatteryLevelsPerDay = hourlyBatteryLevelsPerDay;
         mBatteryHistoryMap = batteryHistoryMap;
-        mRawStartTimestamp = rawStartTimestamp;
     }
 
     /**
@@ -125,31 +146,49 @@
     DataProcessManager(
             Context context,
             Handler handler,
-            @NonNull final DataProcessor.UsageMapAsyncResponse callbackFunction) {
+            @NonNull final OnBatteryDiffDataMapLoadedListener callbackFunction) {
         mContext = context.getApplicationContext();
         mHandler = handler;
         mUserManager = mContext.getSystemService(UserManager.class);
         mCallbackFunction = callbackFunction;
+        mRawStartTimestamp = 0L;
+        mLastFullChargeTimestamp = 0L;
+        mHourlyBatteryLevelsPerDay = null;
+        mBatteryHistoryMap = null;
         // When there is no battery level data, don't show screen-on time and battery level chart on
         // the UI.
         mShowScreenOnTime = false;
-        mShowBatteryLevel = false;
     }
 
     /**
      * Starts the async tasks to load battery history data and app usage data.
      */
     public void start() {
+        start(/*isFromPeriodJob=*/ false);
+    }
+
+    /**
+     * Starts the async tasks to load battery history data and app usage data.
+     */
+    public void start(boolean isFromPeriodJob) {
         // If we have battery level data, load the battery history map and app usage simultaneously.
-        if (mShowBatteryLevel) {
-            // Loads the latest battery history data from the service.
-            loadCurrentBatteryHistoryMap();
+        if (mHourlyBatteryLevelsPerDay != null) {
+            if (isFromPeriodJob) {
+                mIsCurrentBatteryHistoryLoaded = true;
+                mIsCurrentAppUsageLoaded = true;
+                mIsBatteryUsageSlotLoaded = true;
+            } else {
+                // Loads the latest battery history data from the service.
+                loadCurrentBatteryHistoryMap();
+                // Loads the latest app usage list from the service.
+                loadCurrentAppUsageList();
+                // Loads existing battery usage slots from database.
+                loadBatteryUsageSlotList();
+            }
             // Loads app usage list from database.
             loadDatabaseAppUsageList();
-            // Loads the latest app usage list from the service.
-            loadCurrentAppUsageList();
             // Loads the battery event list from database.
-            loadBatteryEventList();
+            loadPowerConnectionBatteryEventList();
         } else {
             // If there is no battery level data, only load the battery history data from service
             // and show it as the app list directly.
@@ -193,11 +232,6 @@
         return mShowScreenOnTime;
     }
 
-    @VisibleForTesting
-    boolean getShowBatteryLevel() {
-        return mShowBatteryLevel;
-    }
-
     private void loadCurrentBatteryHistoryMap() {
         new AsyncTask<Void, Void, Map<String, BatteryHistEntry>>() {
             @Override
@@ -323,7 +357,7 @@
         }.execute();
     }
 
-    private void loadBatteryEventList() {
+    private void loadPowerConnectionBatteryEventList() {
         new AsyncTask<Void, Void, List<BatteryEvent>>() {
             @Override
             protected List<BatteryEvent> doInBackground(Void... voids) {
@@ -331,8 +365,10 @@
                 // Loads the battery event data from the database.
                 final List<BatteryEvent> batteryEventList =
                         DatabaseUtils.getBatteryEvents(
-                                mContext, Calendar.getInstance(), mRawStartTimestamp);
-                Log.d(TAG, String.format("execute loadBatteryEventList size=%d in %d/ms",
+                                mContext, Calendar.getInstance(), mRawStartTimestamp,
+                                POWER_CONNECTION_EVENTS);
+                Log.d(TAG, String.format(
+                        "execute loadPowerConnectionBatteryEventList size=%d in %d/ms",
                         batteryEventList.size(), (System.currentTimeMillis() - startTime)));
                 return batteryEventList;
             }
@@ -352,29 +388,55 @@
         }.execute();
     }
 
-    private void loadAndApplyBatteryMapFromServiceOnly() {
-        new AsyncTask<Void, Void, Map<Integer, Map<Integer, BatteryDiffData>>>() {
+    private void loadBatteryUsageSlotList() {
+        new AsyncTask<Void, Void, List<BatteryUsageSlot>>() {
             @Override
-            protected Map<Integer, Map<Integer, BatteryDiffData>> doInBackground(Void... voids) {
+            protected List<BatteryUsageSlot> doInBackground(Void... voids) {
                 final long startTime = System.currentTimeMillis();
-                final Map<Integer, Map<Integer, BatteryDiffData>> batteryUsageMap =
-                        DataProcessor.getBatteryUsageMapFromStatsService(mContext);
-                DataProcessor.loadLabelAndIcon(batteryUsageMap);
-                Log.d(TAG, String.format(
-                        "execute loadAndApplyBatteryMapFromServiceOnly size=%d in %d/ms",
-                        batteryUsageMap.size(), (System.currentTimeMillis() - startTime)));
-                return batteryUsageMap;
+                // Loads the battery usage slot data from the database.
+                final List<BatteryUsageSlot> batteryUsageSlotList =
+                        DatabaseUtils.getBatteryUsageSlots(
+                                mContext, Calendar.getInstance(), mLastFullChargeTimestamp);
+                Log.d(TAG, String.format("execute loadBatteryUsageSlotList size=%d in %d/ms",
+                        batteryUsageSlotList.size(), (System.currentTimeMillis() - startTime)));
+                return batteryUsageSlotList;
             }
 
             @Override
-            protected void onPostExecute(
-                    final Map<Integer, Map<Integer, BatteryDiffData>> batteryUsageMap) {
-                // Set the unused variables to null.
-                mContext = null;
+            protected void onPostExecute(final List<BatteryUsageSlot> batteryUsageSlotList) {
+                if (batteryUsageSlotList == null || batteryUsageSlotList.isEmpty()) {
+                    Log.d(TAG, "batteryUsageSlotList is null or empty");
+                } else {
+                    mBatteryUsageSlotList.clear();
+                    mBatteryUsageSlotList.addAll(batteryUsageSlotList);
+                }
+                mIsBatteryUsageSlotLoaded = true;
+                tryToGenerateFinalDataAndApplyCallback();
+            }
+        }.execute();
+    }
+
+    private void loadAndApplyBatteryMapFromServiceOnly() {
+        new AsyncTask<Void, Void, Map<Long, BatteryDiffData>>() {
+            @Override
+            protected Map<Long, BatteryDiffData> doInBackground(Void... voids) {
+                final long startTime = System.currentTimeMillis();
+                final Map<Long, BatteryDiffData> batteryDiffDataMap =
+                        DataProcessor.getBatteryDiffDataMapFromStatsService(
+                                mContext, mRawStartTimestamp, getSystemAppsPackageNames(),
+                                getSystemAppsUids());
+                Log.d(TAG, String.format(
+                        "execute loadAndApplyBatteryMapFromServiceOnly size=%d in %d/ms",
+                        batteryDiffDataMap.size(), (System.currentTimeMillis() - startTime)));
+                return batteryDiffDataMap;
+            }
+
+            @Override
+            protected void onPostExecute(final Map<Long, BatteryDiffData> batteryDiffDataMap) {
                 // Post results back to main thread to refresh UI.
                 if (mHandler != null && mCallbackFunction != null) {
                     mHandler.post(() -> {
-                        mCallbackFunction.onBatteryCallbackDataLoaded(batteryUsageMap);
+                        mCallbackFunction.onBatteryDiffDataMapLoaded(batteryDiffDataMap);
                     });
                 }
             }
@@ -406,38 +468,41 @@
         if (!mIsCurrentBatteryHistoryLoaded
                 || !mIsCurrentAppUsageLoaded
                 || !mIsDatabaseAppUsageLoaded
-                || !mIsBatteryEventLoaded) {
+                || !mIsBatteryEventLoaded
+                || !mIsBatteryUsageSlotLoaded) {
             return;
         }
         generateFinalDataAndApplyCallback();
     }
 
-    private void generateFinalDataAndApplyCallback() {
-        new AsyncTask<Void, Void, Map<Integer, Map<Integer, BatteryDiffData>>>() {
+    private synchronized void generateFinalDataAndApplyCallback() {
+        new AsyncTask<Void, Void, Map<Long, BatteryDiffData>>() {
             @Override
-            protected Map<Integer, Map<Integer, BatteryDiffData>> doInBackground(Void... voids) {
+            protected Map<Long, BatteryDiffData> doInBackground(Void... voids) {
                 final long startTime = System.currentTimeMillis();
-                final Map<Integer, Map<Integer, BatteryDiffData>> batteryUsageMap =
-                        DataProcessor.getBatteryUsageMap(
-                                mContext, mHourlyBatteryLevelsPerDay, mBatteryHistoryMap,
-                                mAppUsagePeriodMap);
-                DataProcessor.loadLabelAndIcon(batteryUsageMap);
-                Log.d(TAG, String.format("execute generateFinalDataAndApplyCallback in %d/ms",
-                        (System.currentTimeMillis() - startTime)));
-                return batteryUsageMap;
+                final Map<Long, BatteryDiffData> batteryDiffDataMap = new ArrayMap<>();
+                for (BatteryUsageSlot batteryUsageSlot : mBatteryUsageSlotList) {
+                    batteryDiffDataMap.put(batteryUsageSlot.getStartTimestamp(),
+                            ConvertUtils.convertToBatteryDiffData(
+                                    mContext, batteryUsageSlot, getSystemAppsPackageNames(),
+                                    getSystemAppsUids()));
+                }
+                batteryDiffDataMap.putAll(DataProcessor.getBatteryDiffDataMap(mContext,
+                        mHourlyBatteryLevelsPerDay, mBatteryHistoryMap, mAppUsagePeriodMap,
+                        getSystemAppsPackageNames(), getSystemAppsUids()));
+
+                Log.d(TAG, String.format(
+                        "execute generateFinalDataAndApplyCallback size=%d in %d/ms",
+                        batteryDiffDataMap.size(), System.currentTimeMillis() - startTime));
+                return batteryDiffDataMap;
             }
 
             @Override
-            protected void onPostExecute(
-                    final Map<Integer, Map<Integer, BatteryDiffData>> batteryUsageMap) {
-                // Set the unused variables to null.
-                mContext = null;
-                mHourlyBatteryLevelsPerDay = null;
-                mBatteryHistoryMap = null;
+            protected void onPostExecute(final Map<Long, BatteryDiffData> batteryDiffDataMap) {
                 // Post results back to main thread to refresh UI.
                 if (mHandler != null && mCallbackFunction != null) {
                     mHandler.post(() -> {
-                        mCallbackFunction.onBatteryCallbackDataLoaded(batteryUsageMap);
+                        mCallbackFunction.onBatteryDiffDataMapLoaded(batteryDiffDataMap);
                     });
                 }
             }
@@ -445,7 +510,7 @@
     }
 
     // Whether we should load app usage data from service or database.
-    private boolean shouldLoadAppUsageData() {
+    private synchronized boolean shouldLoadAppUsageData() {
         if (!mShowScreenOnTime) {
             return false;
         }
@@ -480,6 +545,20 @@
         return userHandle != null ? userHandle.getIdentifier() : Integer.MIN_VALUE;
     }
 
+    private synchronized Set<String> getSystemAppsPackageNames() {
+        if (mSystemAppsPackageNames == null) {
+            mSystemAppsPackageNames = DataProcessor.getSystemAppsPackageNames(mContext);
+        }
+        return mSystemAppsPackageNames;
+    }
+
+    private synchronized Set<Integer> getSystemAppsUids() {
+        if (mSystemAppsUids == null) {
+            mSystemAppsUids = DataProcessor.getSystemAppsUids(mContext);
+        }
+        return mSystemAppsUids;
+    }
+
     /**
      * @return Returns battery level data and start async task to compute battery diff usage data
      * and load app labels + icons.
@@ -489,14 +568,55 @@
     public static BatteryLevelData getBatteryLevelData(
             Context context,
             @Nullable Handler handler,
-            @Nullable final Map<Long, Map<String, BatteryHistEntry>> batteryHistoryMap,
-            final DataProcessor.UsageMapAsyncResponse asyncResponseDelegate) {
-        if (batteryHistoryMap == null || batteryHistoryMap.isEmpty()) {
-            Log.d(TAG, "batteryHistoryMap is null in getBatteryLevelData()");
-            new DataProcessManager(context, handler, asyncResponseDelegate).start();
+            final boolean isFromPeriodJob,
+            final OnBatteryDiffDataMapLoadedListener onBatteryUsageMapLoadedListener) {
+        final long start = System.currentTimeMillis();
+        final long lastFullChargeTime = DatabaseUtils.getLastFullChargeTime(context);
+        final List<BatteryEvent> batteryLevelRecordEvents =
+                DatabaseUtils.getBatteryEvents(
+                        context, Calendar.getInstance(), lastFullChargeTime,
+                        BATTERY_LEVEL_RECORD_EVENTS);
+        final long startTimestamp = batteryLevelRecordEvents.isEmpty()
+                ? lastFullChargeTime : batteryLevelRecordEvents.get(0).getTimestamp();
+        final BatteryLevelData batteryLevelData = getPeriodBatteryLevelData(context, handler,
+                startTimestamp, lastFullChargeTime, isFromPeriodJob,
+                onBatteryUsageMapLoadedListener);
+        Log.d(TAG, String.format("execute getBatteryLevelData in %d/ms,"
+                        + " batteryLevelRecordEvents.size=%d",
+                (System.currentTimeMillis() - start), batteryLevelRecordEvents.size()));
+
+        return isFromPeriodJob
+                ? batteryLevelData
+                : BatteryLevelData.combine(batteryLevelData, batteryLevelRecordEvents);
+    }
+
+    private static BatteryLevelData getPeriodBatteryLevelData(
+            Context context,
+            @Nullable Handler handler,
+            final long startTimestamp,
+            final long lastFullChargeTime,
+            final boolean isFromPeriodJob,
+            final OnBatteryDiffDataMapLoadedListener onBatteryDiffDataMapLoadedListener) {
+        final long currentTime = System.currentTimeMillis();
+        Log.d(TAG, String.format("getPeriodBatteryLevelData() startTimestamp=%s",
+                ConvertUtils.utcToLocalTimeForLogging(startTimestamp)));
+        if (isFromPeriodJob
+                && startTimestamp >= TimestampUtils.getLastEvenHourTimestamp(currentTime)) {
+            // Nothing needs to be loaded for period job.
             return null;
         }
+
         handler = handler != null ? handler : new Handler(Looper.getMainLooper());
+        final Map<Long, Map<String, BatteryHistEntry>> batteryHistoryMap =
+                sFakeBatteryHistoryMap != null ? sFakeBatteryHistoryMap
+                        : DatabaseUtils.getHistoryMapSinceLatestRecordBeforeQueryTimestamp(context,
+                                Calendar.getInstance(), startTimestamp, lastFullChargeTime);
+        if (batteryHistoryMap == null || batteryHistoryMap.isEmpty()) {
+            Log.d(TAG, "batteryHistoryMap is null in getPeriodBatteryLevelData()");
+            new DataProcessManager(context, handler, onBatteryDiffDataMapLoadedListener).start();
+            return null;
+        }
+
         // Process raw history map data into hourly timestamps.
         final Map<Long, Map<String, BatteryHistEntry>> processedBatteryHistoryMap =
                 DataProcessor.getHistoryMapWithExpectedTimestamps(context, batteryHistoryMap);
@@ -505,20 +625,20 @@
                 DataProcessor.getLevelDataThroughProcessedHistoryMap(
                         context, processedBatteryHistoryMap);
         if (batteryLevelData == null) {
-            new DataProcessManager(context, handler, asyncResponseDelegate).start();
+            new DataProcessManager(context, handler, onBatteryDiffDataMapLoadedListener).start();
             Log.d(TAG, "getBatteryLevelData() returns null");
             return null;
         }
 
-        final long rawStartTimestamp = Collections.min(batteryHistoryMap.keySet());
         // Start the async task to compute diff usage data and load labels and icons.
         new DataProcessManager(
                 context,
                 handler,
-                rawStartTimestamp,
-                asyncResponseDelegate,
+                startTimestamp,
+                lastFullChargeTime,
+                onBatteryDiffDataMapLoadedListener,
                 batteryLevelData.getHourlyBatteryLevelsPerDay(),
-                processedBatteryHistoryMap).start();
+                processedBatteryHistoryMap).start(isFromPeriodJob);
 
         return batteryLevelData;
     }
diff --git a/src/com/android/settings/fuelgauge/batteryusage/DataProcessor.java b/src/com/android/settings/fuelgauge/batteryusage/DataProcessor.java
index 71ed46f..32cd1b9 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/DataProcessor.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/DataProcessor.java
@@ -17,6 +17,9 @@
 package com.android.settings.fuelgauge.batteryusage;
 
 import static com.android.settings.fuelgauge.batteryusage.ConvertUtils.getEffectivePackageName;
+import static com.android.settings.fuelgauge.batteryusage.ConvertUtils.isSystemConsumer;
+import static com.android.settings.fuelgauge.batteryusage.ConvertUtils.isUidConsumer;
+import static com.android.settingslib.fuelgauge.BatteryStatus.BATTERY_LEVEL_UNKNOWN;
 
 import android.app.usage.IUsageStatsManager;
 import android.app.usage.UsageEvents;
@@ -44,6 +47,7 @@
 import android.util.Log;
 import android.util.SparseArray;
 
+import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 
 import com.android.internal.annotations.VisibleForTesting;
@@ -54,6 +58,8 @@
 import com.android.settingslib.fuelgauge.BatteryStatus;
 import com.android.settingslib.spaprivileged.model.app.AppListRepositoryUtil;
 
+import com.google.common.base.Preconditions;
+
 import java.time.Duration;
 import java.util.ArrayList;
 import java.util.Calendar;
@@ -76,9 +82,7 @@
     private static final int POWER_COMPONENT_WAKELOCK = 12;
     private static final int MIN_AVERAGE_POWER_THRESHOLD_MILLI_AMP = 10;
     private static final int MIN_DAILY_DATA_SIZE = 2;
-    private static final int MIN_TIMESTAMP_DATA_SIZE = 2;
     private static final int MAX_DIFF_SECONDS_OF_UPPER_TIMESTAMP = 5;
-    private static final long MIN_TIME_SLOT = DateUtils.HOUR_IN_MILLIS * 2;
     private static final String MEDIASERVER_PACKAGE_NAME = "mediaserver";
     private static final String ANDROID_CORE_APPS_SHARED_USER_ID = "android.uid.shared";
     private static final Map<String, BatteryHistEntry> EMPTY_BATTERY_MAP = new ArrayMap<>();
@@ -157,11 +161,14 @@
         }
         return batteryLevelData == null
                 ? null
-                : getBatteryUsageMap(
-                        context,
-                        batteryLevelData.getHourlyBatteryLevelsPerDay(),
-                        processedBatteryHistoryMap,
-                        /*appUsagePeriodMap=*/ null);
+                : generateBatteryUsageMap(context,
+                        getBatteryDiffDataMap(context,
+                                batteryLevelData.getHourlyBatteryLevelsPerDay(),
+                                processedBatteryHistoryMap,
+                                /*appUsagePeriodMap=*/ null,
+                                getSystemAppsPackageNames(context),
+                                getSystemAppsUids(context)),
+                        batteryLevelData);
     }
 
     /**
@@ -261,7 +268,7 @@
      * </ul>
      *
      * <p>The structure is consistent with the battery usage map returned by
-     * {@code getBatteryUsageMap}.</p>
+     * {@code generateBatteryUsageMap}.</p>
      *
      * <p>{@code Long} stands for the userId.</p>
      * <p>{@code String} stands for the packageName.</p>
@@ -403,8 +410,8 @@
 
     /**
      * @return Returns the processed history map which has interpolated to every hour data.
-     * The start and end timestamp must be the even hours.
-     * The keys of processed history map should contain every hour between the start and end
+     * The start timestamp is the first timestamp in batteryHistoryMap. The end timestamp is current
+     * time. The keys of processed history map should contain every hour between the start and end
      * timestamp. If there's no data in some key, the value will be the empty map.
      */
     static Map<Long, Map<String, BatteryHistEntry>> getHistoryMapWithExpectedTimestamps(
@@ -431,28 +438,23 @@
     static BatteryLevelData getLevelDataThroughProcessedHistoryMap(
             Context context,
             final Map<Long, Map<String, BatteryHistEntry>> processedBatteryHistoryMap) {
-        final List<Long> timestampList = new ArrayList<>(processedBatteryHistoryMap.keySet());
-        Collections.sort(timestampList);
-        final List<Long> dailyTimestamps = getDailyTimestamps(timestampList);
         // There should be at least the start and end timestamps. Otherwise, return null to not show
         // data in usage chart.
-        if (dailyTimestamps.size() < MIN_DAILY_DATA_SIZE) {
+        if (processedBatteryHistoryMap.size() < MIN_DAILY_DATA_SIZE) {
             return null;
         }
-
-        final List<List<Long>> hourlyTimestamps = getHourlyTimestamps(dailyTimestamps);
-        final BatteryLevelData.PeriodBatteryLevelData dailyLevelData =
-                getPeriodBatteryLevelData(context, processedBatteryHistoryMap, dailyTimestamps);
-        final List<BatteryLevelData.PeriodBatteryLevelData> hourlyLevelData =
-                getHourlyPeriodBatteryLevelData(
-                        context, processedBatteryHistoryMap, hourlyTimestamps);
-        return new BatteryLevelData(dailyLevelData, hourlyLevelData);
+        Map<Long, Integer> batteryLevelMap = new ArrayMap<>();
+        for (Long timestamp : processedBatteryHistoryMap.keySet()) {
+            batteryLevelMap.put(
+                    timestamp, getLevel(context, processedBatteryHistoryMap, timestamp));
+        }
+        return new BatteryLevelData(batteryLevelMap);
     }
 
     /**
-     * Computes expected timestamp slots. The start timestamp is the last full charge time.
-     * The end timestamp is current time. The middle timestamps are the sharp hour timestamps
-     * between the start and end timestamps.
+     * Computes expected timestamp slots. The start timestamp is the first timestamp in
+     * rawTimestampList. The end timestamp is current time. The middle timestamps are the sharp hour
+     * timestamps between the start and end timestamps.
      */
     @VisibleForTesting
     static List<Long> getTimestampSlots(final List<Long> rawTimestampList, final long currentTime) {
@@ -475,56 +477,6 @@
         return timestampSlots;
     }
 
-    /**
-     * Computes expected daily timestamp slots.
-     *
-     * The valid result should be composed of 3 parts:
-     * 1) start timestamp
-     * 2) every 00:00 timestamp (default timezone) between the start and end
-     * 3) end timestamp
-     * Otherwise, returns an empty list.
-     */
-    @VisibleForTesting
-    static List<Long> getDailyTimestamps(final List<Long> timestampList) {
-        final List<Long> dailyTimestampList = new ArrayList<>();
-        // If timestamp number is smaller than 2, the following computation is not necessary.
-        if (timestampList.size() < MIN_TIMESTAMP_DATA_SIZE) {
-            return dailyTimestampList;
-        }
-        final long startTime = timestampList.get(0);
-        final long endTime = timestampList.get(timestampList.size() - 1);
-        for (long timestamp = startTime; timestamp < endTime;
-                timestamp = TimestampUtils.getNextDayTimestamp(timestamp)) {
-            dailyTimestampList.add(timestamp);
-        }
-        dailyTimestampList.add(endTime);
-        return dailyTimestampList;
-    }
-
-    @VisibleForTesting
-    static List<List<Long>> getHourlyTimestamps(final List<Long> dailyTimestamps) {
-        final List<List<Long>> hourlyTimestamps = new ArrayList<>();
-        if (dailyTimestamps.size() < MIN_DAILY_DATA_SIZE) {
-            return hourlyTimestamps;
-        }
-
-        for (int dailyIndex = 0; dailyIndex < dailyTimestamps.size() - 1; dailyIndex++) {
-            final List<Long> hourlyTimestampsPerDay = new ArrayList<>();
-            final long startTime = dailyTimestamps.get(dailyIndex);
-            final long endTime = dailyTimestamps.get(dailyIndex + 1);
-
-            hourlyTimestampsPerDay.add(startTime);
-            for (long timestamp = TimestampUtils.getNextEvenHourTimestamp(startTime);
-                    timestamp < endTime; timestamp += MIN_TIME_SLOT) {
-                hourlyTimestampsPerDay.add(timestamp);
-            }
-            hourlyTimestampsPerDay.add(endTime);
-
-            hourlyTimestamps.add(hourlyTimestampsPerDay);
-        }
-        return hourlyTimestamps;
-    }
-
     @VisibleForTesting
     static boolean isFromFullCharge(@Nullable final Map<String, BatteryHistEntry> entryList) {
         if (entryList == null) {
@@ -560,34 +512,102 @@
         return results;
     }
 
+    static Map<Long, BatteryDiffData> getBatteryDiffDataMap(
+            Context context,
+            final List<BatteryLevelData.PeriodBatteryLevelData> hourlyBatteryLevelsPerDay,
+            final Map<Long, Map<String, BatteryHistEntry>> batteryHistoryMap,
+            final Map<Integer, Map<Integer, Map<Long, Map<String, List<AppUsagePeriod>>>>>
+                    appUsagePeriodMap,
+            final @NonNull Set<String> systemAppsPackageNames,
+            final @NonNull Set<Integer> systemAppsUids) {
+        final Map<Long, BatteryDiffData> batteryDiffDataMap = new ArrayMap<>();
+        final int currentUserId = context.getUserId();
+        final UserHandle userHandle =
+                Utils.getManagedProfile(context.getSystemService(UserManager.class));
+        final int workProfileUserId =
+                userHandle != null ? userHandle.getIdentifier() : Integer.MIN_VALUE;
+        // Each time slot usage diff data =
+        //     sum(Math.abs(timestamp[i+1] data - timestamp[i] data));
+        // since we want to aggregate every hour usage diff data into a single time slot.
+        for (int dailyIndex = 0; dailyIndex < hourlyBatteryLevelsPerDay.size(); dailyIndex++) {
+            if (hourlyBatteryLevelsPerDay.get(dailyIndex) == null) {
+                continue;
+            }
+            final List<Long> hourlyTimestamps =
+                    hourlyBatteryLevelsPerDay.get(dailyIndex).getTimestamps();
+            for (int hourlyIndex = 0; hourlyIndex < hourlyTimestamps.size() - 1; hourlyIndex++) {
+                final Long startTimestamp = hourlyTimestamps.get(hourlyIndex);
+                final Long endTimestamp = hourlyTimestamps.get(hourlyIndex + 1);
+                final int startBatteryLevel =
+                        hourlyBatteryLevelsPerDay.get(dailyIndex).getLevels().get(hourlyIndex);
+                final int endBatteryLevel =
+                        hourlyBatteryLevelsPerDay.get(dailyIndex).getLevels().get(hourlyIndex + 1);
+                final long slotDuration = endTimestamp - startTimestamp;
+                List<Map<String, BatteryHistEntry>> slotBatteryHistoryList = new ArrayList<>();
+                slotBatteryHistoryList.add(
+                        batteryHistoryMap.getOrDefault(startTimestamp, EMPTY_BATTERY_MAP));
+                for (Long timestamp = TimestampUtils.getNextHourTimestamp(startTimestamp);
+                        timestamp < endTimestamp; timestamp += DateUtils.HOUR_IN_MILLIS) {
+                    slotBatteryHistoryList.add(
+                            batteryHistoryMap.getOrDefault(timestamp, EMPTY_BATTERY_MAP));
+                }
+                slotBatteryHistoryList.add(
+                        batteryHistoryMap.getOrDefault(endTimestamp, EMPTY_BATTERY_MAP));
+
+                final BatteryDiffData hourlyBatteryDiffData =
+                        insertHourlyUsageDiffDataPerSlot(
+                                context,
+                                startTimestamp,
+                                endTimestamp,
+                                startBatteryLevel,
+                                endBatteryLevel,
+                                currentUserId,
+                                workProfileUserId,
+                                slotDuration,
+                                systemAppsPackageNames,
+                                systemAppsUids,
+                                appUsagePeriodMap == null
+                                        || appUsagePeriodMap.get(dailyIndex) == null
+                                        ? null
+                                        : appUsagePeriodMap.get(dailyIndex).get(hourlyIndex),
+                                slotBatteryHistoryList);
+                batteryDiffDataMap.put(startTimestamp, hourlyBatteryDiffData);
+            }
+        }
+        return batteryDiffDataMap;
+    }
+
     /**
      * @return Returns the indexed battery usage data for each corresponding time slot.
      *
      * <p>There could be 2 cases of the returned value:</p>
      * <ul>
-     * <li>null: empty or invalid data.</li>
-     * <li>non-null: must be a 2d map and composed by 3 parts:</li>
+     * <li> null: empty or invalid data.</li>
+     * <li> 1 part: if batteryLevelData is null.</li>
+     * <p>  [SELECTED_INDEX_ALL][SELECTED_INDEX_ALL]</p>
+     * <li> 3 parts: if batteryLevelData is not null.</li>
      * <p>  1 - [SELECTED_INDEX_ALL][SELECTED_INDEX_ALL]</p>
      * <p>  2 - [0][SELECTED_INDEX_ALL] ~ [maxDailyIndex][SELECTED_INDEX_ALL]</p>
      * <p>  3 - [0][0] ~ [maxDailyIndex][maxHourlyIndex]</p>
      * </ul>
      */
-    @Nullable
-    static Map<Integer, Map<Integer, BatteryDiffData>> getBatteryUsageMap(
+    static Map<Integer, Map<Integer, BatteryDiffData>> generateBatteryUsageMap(
             final Context context,
-            final List<BatteryLevelData.PeriodBatteryLevelData> hourlyBatteryLevelsPerDay,
-            final Map<Long, Map<String, BatteryHistEntry>> batteryHistoryMap,
-            final Map<Integer, Map<Integer, Map<Long, Map<String, List<AppUsagePeriod>>>>>
-                    appUsagePeriodMap) {
-        if (batteryHistoryMap.isEmpty()) {
-            return null;
-        }
+            final Map<Long, BatteryDiffData> batteryDiffDataMap,
+            final @Nullable BatteryLevelData batteryLevelData) {
         final Map<Integer, Map<Integer, BatteryDiffData>> resultMap = new ArrayMap<>();
-        final Set<String> systemAppsPackageNames = getSystemAppsPackageNames(context);
-        final Set<Integer> systemAppsUids = getSystemAppsUids(context);
+        if (batteryLevelData == null) {
+            Preconditions.checkArgument(batteryDiffDataMap.size() == 1);
+            BatteryDiffData batteryDiffData = batteryDiffDataMap.values().stream().toList().get(0);
+            final Map<Integer, BatteryDiffData> allUsageMap = new ArrayMap<>();
+            allUsageMap.put(SELECTED_INDEX_ALL, batteryDiffData);
+            resultMap.put(SELECTED_INDEX_ALL, allUsageMap);
+            return resultMap;
+        }
+        List<BatteryLevelData.PeriodBatteryLevelData> hourlyBatteryLevelsPerDay =
+                batteryLevelData.getHourlyBatteryLevelsPerDay();
         // Insert diff data from [0][0] to [maxDailyIndex][maxHourlyIndex].
-        insertHourlyUsageDiffData(context, systemAppsPackageNames, systemAppsUids,
-                hourlyBatteryLevelsPerDay, batteryHistoryMap, appUsagePeriodMap, resultMap);
+        insertHourlyUsageDiffData(hourlyBatteryLevelsPerDay, batteryDiffDataMap, resultMap);
         // Insert diff data from [0][SELECTED_INDEX_ALL] to [maxDailyIndex][SELECTED_INDEX_ALL].
         insertDailyUsageDiffData(context, hourlyBatteryLevelsPerDay, resultMap);
         // Insert diff data [SELECTED_INDEX_ALL][SELECTED_INDEX_ALL].
@@ -602,7 +622,10 @@
     @Nullable
     static BatteryDiffData generateBatteryDiffData(
             final Context context,
-            final List<BatteryHistEntry> batteryHistEntryList) {
+            final long startTimestamp,
+            final List<BatteryHistEntry> batteryHistEntryList,
+            final @NonNull Set<String> systemAppsPackageNames,
+            final @NonNull Set<Integer> systemAppsUids) {
         if (batteryHistEntryList == null || batteryHistEntryList.isEmpty()) {
             Log.w(TAG, "batteryHistEntryList is null or empty in generateBatteryDiffData()");
             return null;
@@ -624,6 +647,14 @@
             } else {
                 final BatteryDiffEntry currentBatteryDiffEntry = new BatteryDiffEntry(
                         context,
+                        entry.mUid,
+                        entry.mUserId,
+                        entry.getKey(),
+                        entry.mIsHidden,
+                        entry.mDrainType,
+                        entry.mPackageName,
+                        entry.mAppLabel,
+                        entry.mConsumerType,
                         entry.mForegroundUsageTimeInMs,
                         entry.mBackgroundUsageTimeInMs,
                         /*screenOnTimeInMs=*/ 0,
@@ -631,8 +662,7 @@
                         entry.mForegroundUsageConsumePower,
                         entry.mForegroundServiceUsageConsumePower,
                         entry.mBackgroundUsageConsumePower,
-                        entry.mCachedUsageConsumePower,
-                        entry);
+                        entry.mCachedUsageConsumePower);
                 if (currentBatteryDiffEntry.isSystemEntry()) {
                     systemEntries.add(currentBatteryDiffEntry);
                 } else {
@@ -645,11 +675,10 @@
         if (appEntries.isEmpty() && systemEntries.isEmpty()) {
             return null;
         }
-
-        final Set<String> systemAppsPackageNames = getSystemAppsPackageNames(context);
-        final Set<Integer> systemAppsUids = getSystemAppsUids(context);
-        return new BatteryDiffData(context, /* screenOnTime= */ 0L, appEntries, systemEntries,
-                systemAppsPackageNames, systemAppsUids, /* isAccumulated= */ false);
+        return new BatteryDiffData(context, startTimestamp, getCurrentTimeMillis(),
+                /* startBatteryLevel =*/ 100, getCurrentLevel(context), /* screenOnTime= */ 0L,
+                appEntries, systemEntries, systemAppsPackageNames, systemAppsUids,
+                /* isAccumulated= */ false);
     }
 
     /**
@@ -845,21 +874,15 @@
         return getScreenOnTime(appUsageMap.get(userId).get(packageName));
     }
 
-    /**
-     * @return Returns the overall battery usage data from battery stats service directly.
-     *
-     * The returned value should be always a 2d map and composed by only 1 part:
-     * - [SELECTED_INDEX_ALL][SELECTED_INDEX_ALL]
-     */
-    static Map<Integer, Map<Integer, BatteryDiffData>> getBatteryUsageMapFromStatsService(
-            final Context context) {
-        final Map<Integer, Map<Integer, BatteryDiffData>> resultMap = new ArrayMap<>();
-        final Map<Integer, BatteryDiffData> allUsageMap = new ArrayMap<>();
-        // Always construct the map whether the value is null or not.
-        allUsageMap.put(SELECTED_INDEX_ALL,
-                generateBatteryDiffData(context, getBatteryHistListFromFromStatsService(context)));
-        resultMap.put(SELECTED_INDEX_ALL, allUsageMap);
-        return resultMap;
+    static Map<Long, BatteryDiffData> getBatteryDiffDataMapFromStatsService(
+            final Context context, final long startTimestamp,
+            @NonNull final Set<String> systemAppsPackageNames,
+            @NonNull final Set<Integer> systemAppsUids) {
+        Map<Long, BatteryDiffData> batteryDiffDataMap = new ArrayMap<>(1);
+        batteryDiffDataMap.put(startTimestamp, generateBatteryDiffData(
+                context, startTimestamp, getBatteryHistListFromFromStatsService(context),
+                systemAppsPackageNames, systemAppsUids));
+        return batteryDiffDataMap;
     }
 
     static void loadLabelAndIcon(
@@ -878,6 +901,22 @@
         }
     }
 
+    static Set<String> getSystemAppsPackageNames(Context context) {
+        return sTestSystemAppsPackageNames != null ? sTestSystemAppsPackageNames
+                : AppListRepositoryUtil.getSystemPackageNames(context, context.getUserId());
+    }
+
+    static Set<Integer> getSystemAppsUids(Context context) {
+        Set<Integer> result = new ArraySet<>(1);
+        try {
+            result.add(context.getPackageManager().getUidForSharedUser(
+                    ANDROID_CORE_APPS_SHARED_USER_ID));
+        } catch (PackageManager.NameNotFoundException e) {
+            // No Android Core Apps
+        }
+        return result;
+    }
+
     /**
      * Generates the list of {@link AppUsageEvent} within the specific time range.
      * The buffer is added to make sure the app usage calculation near the boundaries is correct.
@@ -1158,28 +1197,6 @@
         resultMap.put(currentSlot, newHistEntryMap);
     }
 
-    private static List<BatteryLevelData.PeriodBatteryLevelData> getHourlyPeriodBatteryLevelData(
-            Context context,
-            final Map<Long, Map<String, BatteryHistEntry>> processedBatteryHistoryMap,
-            final List<List<Long>> timestamps) {
-        final List<BatteryLevelData.PeriodBatteryLevelData> levelData = new ArrayList<>();
-        timestamps.forEach(
-                timestampList -> levelData.add(
-                        getPeriodBatteryLevelData(
-                                context, processedBatteryHistoryMap, timestampList)));
-        return levelData;
-    }
-
-    private static BatteryLevelData.PeriodBatteryLevelData getPeriodBatteryLevelData(
-            Context context,
-            final Map<Long, Map<String, BatteryHistEntry>> processedBatteryHistoryMap,
-            final List<Long> timestamps) {
-        final List<Integer> levels = new ArrayList<>();
-        timestamps.forEach(
-                timestamp -> levels.add(getLevel(context, processedBatteryHistoryMap, timestamp)));
-        return new BatteryLevelData.PeriodBatteryLevelData(timestamps, levels);
-    }
-
     private static Integer getLevel(
             Context context,
             final Map<Long, Map<String, BatteryHistEntry>> processedBatteryHistoryMap,
@@ -1188,13 +1205,12 @@
         if (entryMap == null || entryMap.isEmpty()) {
             Log.e(TAG, "abnormal entry list in the timestamp:"
                     + ConvertUtils.utcToLocalTimeForLogging(timestamp));
-            return null;
+            return BATTERY_LEVEL_UNKNOWN;
         }
         // The current time battery history hasn't been loaded yet, returns the current battery
         // level.
         if (entryMap.containsKey(CURRENT_TIME_BATTERY_HISTORY_PLACEHOLDER)) {
-            final Intent intent = BatteryUtils.getBatteryIntent(context);
-            return BatteryStatus.getBatteryLevel(intent);
+            return getCurrentLevel(context);
         }
         // Averages the battery level in each time slot to avoid corner conditions.
         float batteryLevelCounter = 0;
@@ -1204,20 +1220,15 @@
         return Math.round(batteryLevelCounter / entryMap.size());
     }
 
+    private static int getCurrentLevel(Context context) {
+        final Intent intent = BatteryUtils.getBatteryIntent(context);
+        return BatteryStatus.getBatteryLevel(intent);
+    }
+
     private static void insertHourlyUsageDiffData(
-            Context context,
-            final Set<String> systemAppsPackageNames,
-            final Set<Integer> systemAppsUids,
             final List<BatteryLevelData.PeriodBatteryLevelData> hourlyBatteryLevelsPerDay,
-            final Map<Long, Map<String, BatteryHistEntry>> batteryHistoryMap,
-            final Map<Integer, Map<Integer, Map<Long, Map<String, List<AppUsagePeriod>>>>>
-                    appUsagePeriodMap,
+            final Map<Long, BatteryDiffData> batteryDiffDataMap,
             final Map<Integer, Map<Integer, BatteryDiffData>> resultMap) {
-        final int currentUserId = context.getUserId();
-        final UserHandle userHandle =
-                Utils.getManagedProfile(context.getSystemService(UserManager.class));
-        final int workProfileUserId =
-                userHandle != null ? userHandle.getIdentifier() : Integer.MIN_VALUE;
         // Each time slot usage diff data =
         //     sum(Math.abs(timestamp[i+1] data - timestamp[i] data));
         // since we want to aggregate every hour usage diff data into a single time slot.
@@ -1231,33 +1242,7 @@
                     hourlyBatteryLevelsPerDay.get(dailyIndex).getTimestamps();
             for (int hourlyIndex = 0; hourlyIndex < hourlyTimestamps.size() - 1; hourlyIndex++) {
                 final Long startTimestamp = hourlyTimestamps.get(hourlyIndex);
-                final Long endTimestamp = hourlyTimestamps.get(hourlyIndex + 1);
-                final long slotDuration = endTimestamp - startTimestamp;
-                List<Map<String, BatteryHistEntry>> slotBatteryHistoryList = new ArrayList<>();
-                slotBatteryHistoryList.add(
-                        batteryHistoryMap.getOrDefault(startTimestamp, EMPTY_BATTERY_MAP));
-                for (Long timestamp = TimestampUtils.getNextHourTimestamp(startTimestamp);
-                        timestamp < endTimestamp; timestamp += DateUtils.HOUR_IN_MILLIS) {
-                    slotBatteryHistoryList.add(
-                            batteryHistoryMap.getOrDefault(timestamp, EMPTY_BATTERY_MAP));
-                }
-                slotBatteryHistoryList.add(
-                        batteryHistoryMap.getOrDefault(endTimestamp, EMPTY_BATTERY_MAP));
-
-                final BatteryDiffData hourlyBatteryDiffData =
-                        insertHourlyUsageDiffDataPerSlot(
-                                context,
-                                currentUserId,
-                                workProfileUserId,
-                                slotDuration,
-                                systemAppsPackageNames,
-                                systemAppsUids,
-                                appUsagePeriodMap == null
-                                        || appUsagePeriodMap.get(dailyIndex) == null
-                                        ? null
-                                        : appUsagePeriodMap.get(dailyIndex).get(hourlyIndex),
-                                slotBatteryHistoryList);
-                dailyDiffMap.put(hourlyIndex, hourlyBatteryDiffData);
+                dailyDiffMap.put(hourlyIndex, batteryDiffDataMap.get(startTimestamp));
             }
         }
     }
@@ -1292,6 +1277,10 @@
     @Nullable
     private static BatteryDiffData insertHourlyUsageDiffDataPerSlot(
             final Context context,
+            final long startTimestamp,
+            final long endTimestamp,
+            final int startBatteryLevel,
+            final int endBatteryLevel,
             final int currentUserId,
             final int workProfileUserId,
             final long slotDuration,
@@ -1401,7 +1390,7 @@
                                 currentEntry.mCachedUsageConsumePower,
                                 nextEntry.mCachedUsageConsumePower);
             }
-            if (selectedBatteryEntry.isSystemEntry()
+            if (isSystemConsumer(selectedBatteryEntry.mConsumerType)
                     && selectedBatteryEntry.mDrainType == BatteryConsumer.POWER_COMPONENT_SCREEN) {
                 // Replace Screen system component time with screen on time.
                 foregroundUsageTimeInMs = slotScreenOnTime;
@@ -1447,6 +1436,14 @@
                     backgroundUsageTimeInMs, (long) slotDuration - screenOnTime);
             final BatteryDiffEntry currentBatteryDiffEntry = new BatteryDiffEntry(
                     context,
+                    selectedBatteryEntry.mUid,
+                    selectedBatteryEntry.mUserId,
+                    selectedBatteryEntry.getKey(),
+                    selectedBatteryEntry.mIsHidden,
+                    selectedBatteryEntry.mDrainType,
+                    selectedBatteryEntry.mPackageName,
+                    selectedBatteryEntry.mAppLabel,
+                    selectedBatteryEntry.mConsumerType,
                     foregroundUsageTimeInMs,
                     backgroundUsageTimeInMs,
                     screenOnTime,
@@ -1454,8 +1451,7 @@
                     foregroundUsageConsumePower,
                     foregroundServiceUsageConsumePower,
                     backgroundUsageConsumePower,
-                    cachedUsageConsumePower,
-                    selectedBatteryEntry);
+                    cachedUsageConsumePower);
             if (currentBatteryDiffEntry.isSystemEntry()) {
                 systemEntries.add(currentBatteryDiffEntry);
             } else {
@@ -1468,7 +1464,8 @@
             return null;
         }
 
-        return new BatteryDiffData(context, slotScreenOnTime, appEntries, systemEntries,
+        return new BatteryDiffData(context, startTimestamp, endTimestamp, startBatteryLevel,
+                endBatteryLevel, slotScreenOnTime, appEntries, systemEntries,
                 systemAppsPackageNames, systemAppsUids, /* isAccumulated= */ false);
     }
 
@@ -1519,7 +1516,7 @@
             final int currentUserId,
             final int workProfileUserId,
             final BatteryHistEntry batteryHistEntry) {
-        return batteryHistEntry.mConsumerType == ConvertUtils.CONSUMER_TYPE_UID_BATTERY
+        return isUidConsumer(batteryHistEntry.mConsumerType)
                 && batteryHistEntry.mUserId != currentUserId
                 && batteryHistEntry.mUserId != workProfileUserId;
     }
@@ -1531,11 +1528,23 @@
         final List<BatteryDiffEntry> appEntries = new ArrayList<>();
         final List<BatteryDiffEntry> systemEntries = new ArrayList<>();
 
+        long startTimestamp = Long.MAX_VALUE;
+        long endTimestamp = 0;
+        int startBatteryLevel = BATTERY_LEVEL_UNKNOWN;
+        int endBatteryLevel = BATTERY_LEVEL_UNKNOWN;
         long totalScreenOnTime = 0;
         for (BatteryDiffData batteryDiffData : batteryDiffDataList) {
             if (batteryDiffData == null) {
                 continue;
             }
+            if (startTimestamp > batteryDiffData.getStartTimestamp()) {
+                startTimestamp = batteryDiffData.getStartTimestamp();
+                startBatteryLevel = batteryDiffData.getStartBatteryLevel();
+            }
+            if (endTimestamp > batteryDiffData.getEndTimestamp()) {
+                endTimestamp = batteryDiffData.getEndTimestamp();
+                endBatteryLevel = batteryDiffData.getEndBatteryLevel();
+            }
             totalScreenOnTime += batteryDiffData.getScreenOnTime();
             for (BatteryDiffEntry entry : batteryDiffData.getAppDiffEntryList()) {
                 computeUsageDiffDataPerEntry(entry, diffEntryMap);
@@ -1554,8 +1563,9 @@
             }
         }
 
-        return diffEntryList.isEmpty() ? null : new BatteryDiffData(context, totalScreenOnTime,
-                appEntries, systemEntries, /* systemAppsPackageNames= */ new ArraySet<>(),
+        return diffEntryList.isEmpty() ? null : new BatteryDiffData(context, startTimestamp,
+                endTimestamp, startBatteryLevel, endBatteryLevel, totalScreenOnTime, appEntries,
+                systemEntries, /* systemAppsPackageNames= */ new ArraySet<>(),
                 /* systemAppsUids= */ new ArraySet<>(), /* isAccumulated= */ true);
     }
 
@@ -1751,22 +1761,6 @@
         return v2 > v1 ? v2 - v1 : 0;
     }
 
-    private static Set<String> getSystemAppsPackageNames(Context context) {
-        return sTestSystemAppsPackageNames != null ? sTestSystemAppsPackageNames
-                : AppListRepositoryUtil.getSystemPackageNames(context, context.getUserId());
-    }
-
-    private static Set<Integer> getSystemAppsUids(Context context) {
-        Set<Integer> result = new ArraySet<>();
-        try {
-            result.add(context.getPackageManager().getUidForSharedUser(
-                    ANDROID_CORE_APPS_SHARED_USER_ID));
-        } catch (PackageManager.NameNotFoundException e) {
-            // No Android Core Apps
-        }
-        return result;
-    }
-
     private static long getCurrentTimeMillis() {
         return sTestCurrentTimeMillis > 0 ? sTestCurrentTimeMillis : System.currentTimeMillis();
     }
diff --git a/src/com/android/settings/fuelgauge/batteryusage/DatabaseUtils.java b/src/com/android/settings/fuelgauge/batteryusage/DatabaseUtils.java
index b54563b..465afbe 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/DatabaseUtils.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/DatabaseUtils.java
@@ -15,6 +15,8 @@
  */
 
 package com.android.settings.fuelgauge.batteryusage;
+import static com.android.settings.fuelgauge.batteryusage.ConvertUtils.utcToLocalTimeForLogging;
+
 import android.app.usage.IUsageStatsManager;
 import android.app.usage.UsageStatsManager;
 import android.content.ContentResolver;
@@ -76,12 +78,20 @@
     public static final String BATTERY_EVENT_TABLE = "BatteryEvent";
     /** A table name for battery usage history. */
     public static final String BATTERY_STATE_TABLE = "BatteryState";
+    /** A table name for battery usage slot. */
+    public static final String BATTERY_USAGE_SLOT_TABLE = "BatteryUsageSlot";
+    /** A path name for last full charge time query. */
+    public static final String LAST_FULL_CHARGE_TIMESTAMP_PATH = "lastFullChargeTimestamp";
+    /** A path name for querying the latest record timestamp in battery state table. */
+    public static final String BATTERY_STATE_LATEST_TIMESTAMP_PATH = "batteryStateLatestTimestamp";
     /** A path name for app usage latest timestamp query. */
     public static final String APP_USAGE_LATEST_TIMESTAMP_PATH = "appUsageLatestTimestamp";
     /** Key for query parameter timestamp used in BATTERY_CONTENT_URI **/
     public static final String QUERY_KEY_TIMESTAMP = "timestamp";
     /** Key for query parameter userid used in APP_USAGE_EVENT_URI **/
     public static final String QUERY_KEY_USERID = "userid";
+    /** Key for query parameter battery event type used in BATTERY_EVENT_URI **/
+    public static final String QUERY_BATTERY_EVENT_TYPE = "batteryEventType";
 
     public static final long INVALID_USER_ID = Integer.MIN_VALUE;
     /**
@@ -111,6 +121,13 @@
                     .authority(AUTHORITY)
                     .appendPath(BATTERY_STATE_TABLE)
                     .build();
+    /** A content URI to access battery usage slots data. */
+    public static final Uri BATTERY_USAGE_SLOT_URI =
+            new Uri.Builder()
+                    .scheme(ContentResolver.SCHEME_CONTENT)
+                    .authority(AUTHORITY)
+                    .appendPath(BATTERY_USAGE_SLOT_TABLE)
+                    .build();
 
     // For testing only.
     @VisibleForTesting
@@ -140,7 +157,7 @@
                         .build();
         final long latestTimestamp =
                 loadAppUsageLatestTimestampFromContentProvider(context, appUsageLatestTimestampUri);
-        final String latestTimestampString = ConvertUtils.utcToLocalTimeForLogging(latestTimestamp);
+        final String latestTimestampString = utcToLocalTimeForLogging(latestTimestamp);
         Log.d(TAG, String.format(
                 "getAppUsageStartTimestampOfUser() userId=%d latestTimestamp=%s in %d/ms",
                 userId, latestTimestampString, (System.currentTimeMillis() - startTime)));
@@ -161,8 +178,7 @@
         // sure the app usage calculation near the boundaries is correct.
         final long queryTimestamp =
                 Math.max(rawStartTimestamp, sixDaysAgoTimestamp) - USAGE_QUERY_BUFFER_HOURS;
-        Log.d(TAG, "sixDayAgoTimestamp: " + ConvertUtils.utcToLocalTimeForLogging(
-                sixDaysAgoTimestamp));
+        Log.d(TAG, "sixDaysAgoTimestamp: " + utcToLocalTimeForLogging(sixDaysAgoTimestamp));
         final String queryUserIdString = userIds.stream()
                 .map(userId -> String.valueOf(userId))
                 .collect(Collectors.joining(","));
@@ -189,11 +205,15 @@
     public static List<BatteryEvent> getBatteryEvents(
             Context context,
             final Calendar calendar,
-            final long rawStartTimestamp) {
+            final long rawStartTimestamp,
+            final List<BatteryEventType> queryBatteryEventTypes) {
         final long startTime = System.currentTimeMillis();
         final long sixDaysAgoTimestamp = getTimestampSixDaysAgo(calendar);
         final long queryTimestamp = Math.max(rawStartTimestamp, sixDaysAgoTimestamp);
         Log.d(TAG, "getBatteryEvents for timestamp: " + queryTimestamp);
+        final String queryBatteryEventTypesString = queryBatteryEventTypes.stream()
+                .map(type -> String.valueOf(type.getNumber()))
+                .collect(Collectors.joining(","));
         // Builds the content uri everytime to avoid cache.
         final Uri batteryEventUri =
                 new Uri.Builder()
@@ -202,6 +222,8 @@
                         .appendPath(BATTERY_EVENT_TABLE)
                         .appendQueryParameter(
                                 QUERY_KEY_TIMESTAMP, Long.toString(queryTimestamp))
+                        .appendQueryParameter(
+                                QUERY_BATTERY_EVENT_TYPE, queryBatteryEventTypesString)
                         .build();
 
         final List<BatteryEvent> batteryEventList =
@@ -211,13 +233,82 @@
         return batteryEventList;
     }
 
-    /** Long: for timestamp and String: for BatteryHistEntry.getKey() */
-    public static Map<Long, Map<String, BatteryHistEntry>> getHistoryMapSinceLastFullCharge(
-            Context context, Calendar calendar) {
+    /**
+     * Returns the battery usage slot data after {@code rawStartTimestamp} in battery event table.
+     */
+    public static List<BatteryUsageSlot> getBatteryUsageSlots(
+            Context context,
+            final Calendar calendar,
+            final long rawStartTimestamp) {
         final long startTime = System.currentTimeMillis();
         final long sixDaysAgoTimestamp = getTimestampSixDaysAgo(calendar);
-        Log.d(TAG, "sixDayAgoTimestamp: " + ConvertUtils.utcToLocalTimeForLogging(
-                sixDaysAgoTimestamp));
+        final long queryTimestamp = Math.max(rawStartTimestamp, sixDaysAgoTimestamp);
+        Log.d(TAG, "getBatteryUsageSlots for timestamp: " + queryTimestamp);
+        // Builds the content uri everytime to avoid cache.
+        final Uri batteryUsageSlotUri =
+                new Uri.Builder()
+                        .scheme(ContentResolver.SCHEME_CONTENT)
+                        .authority(AUTHORITY)
+                        .appendPath(BATTERY_USAGE_SLOT_TABLE)
+                        .appendQueryParameter(
+                                QUERY_KEY_TIMESTAMP, Long.toString(queryTimestamp))
+                        .build();
+
+        final List<BatteryUsageSlot> batteryUsageSlotList =
+                loadBatteryUsageSlotsFromContentProvider(context, batteryUsageSlotUri);
+        Log.d(TAG, String.format("getBatteryUsageSlots size=%d in %d/ms",
+                batteryUsageSlotList.size(), (System.currentTimeMillis() - startTime)));
+        return batteryUsageSlotList;
+    }
+
+    /** Returns the last full charge time. */
+    public static long getLastFullChargeTime(Context context) {
+        final long startTime = System.currentTimeMillis();
+        // Builds the content uri everytime to avoid cache.
+        final Uri lastFullChargeTimeUri =
+                new Uri.Builder()
+                        .scheme(ContentResolver.SCHEME_CONTENT)
+                        .authority(AUTHORITY)
+                        .appendPath(LAST_FULL_CHARGE_TIMESTAMP_PATH)
+                        .build();
+        final long lastFullChargeTime = loadLastFullChargeTimeFromContentProvider(
+                context, lastFullChargeTimeUri);
+        final String lastFullChargeTimeString = utcToLocalTimeForLogging(lastFullChargeTime);
+        Log.d(TAG, String.format(
+                "getLastFullChargeTime() lastFullChargeTime=%s in %d/ms",
+                lastFullChargeTimeString, (System.currentTimeMillis() - startTime)));
+        return lastFullChargeTime;
+    }
+
+    /** Returns the first battery state timestamp no later than the {@code queryTimestamp}. */
+    @VisibleForTesting
+    static long getBatteryStateLatestTimestampBeforeQueryTimestamp(
+            Context context, final long queryTimestamp) {
+        final long startTime = System.currentTimeMillis();
+        // Builds the content uri everytime to avoid cache.
+        final Uri batteryStateLatestTimestampUri =
+                new Uri.Builder()
+                        .scheme(ContentResolver.SCHEME_CONTENT)
+                        .authority(AUTHORITY)
+                        .appendPath(BATTERY_STATE_LATEST_TIMESTAMP_PATH)
+                        .appendQueryParameter(
+                                QUERY_KEY_TIMESTAMP, Long.toString(queryTimestamp))
+                        .build();
+        final long batteryStateLatestTimestamp = loadBatteryStateLatestTimestampFromContentProvider(
+                context, batteryStateLatestTimestampUri);
+        final String batteryStateLatestTimestampString =
+                utcToLocalTimeForLogging(batteryStateLatestTimestamp);
+        Log.d(TAG, String.format(
+                "getBatteryStateLatestTimestamp() batteryStateLatestTimestamp=%s in %d/ms",
+                batteryStateLatestTimestampString, (System.currentTimeMillis() - startTime)));
+        return batteryStateLatestTimestamp;
+    }
+
+    /** Returns the battery history map after the given timestamp. */
+    @VisibleForTesting
+    static Map<Long, Map<String, BatteryHistEntry>> getHistoryMapSinceQueryTimestamp(
+            Context context, final long queryTimestamp) {
+        final long startTime = System.currentTimeMillis();
         // Builds the content uri everytime to avoid cache.
         final Uri batteryStateUri =
                 new Uri.Builder()
@@ -225,20 +316,46 @@
                         .authority(AUTHORITY)
                         .appendPath(BATTERY_STATE_TABLE)
                         .appendQueryParameter(
-                                QUERY_KEY_TIMESTAMP, Long.toString(sixDaysAgoTimestamp))
+                                QUERY_KEY_TIMESTAMP, Long.toString(queryTimestamp))
                         .build();
 
         final Map<Long, Map<String, BatteryHistEntry>> resultMap =
                 loadHistoryMapFromContentProvider(context, batteryStateUri);
         if (resultMap == null || resultMap.isEmpty()) {
-            Log.d(TAG, "getHistoryMapSinceLastFullCharge() returns empty or null");
+            Log.d(TAG, "getBatteryHistoryMap() returns empty or null");
         } else {
-            Log.d(TAG, String.format("getHistoryMapSinceLastFullCharge() size=%d in %d/ms",
+            Log.d(TAG, String.format("getBatteryHistoryMap() size=%d in %d/ms",
                     resultMap.size(), (System.currentTimeMillis() - startTime)));
         }
         return resultMap;
     }
 
+    /**
+     * Returns the battery history map since the latest record no later than the given timestamp.
+     * If there is no record before the given timestamp or the given timestamp is before last full
+     * charge time, returns the history map since last full charge time.
+     */
+    public static Map<Long, Map<String, BatteryHistEntry>>
+            getHistoryMapSinceLatestRecordBeforeQueryTimestamp(Context context, Calendar calendar,
+                    final long queryTimestamp, final long lastFullChargeTime) {
+        final long sixDaysAgoTimestamp = getTimestampSixDaysAgo(calendar);
+        Log.d(TAG, "sixDaysAgoTimestamp: " + utcToLocalTimeForLogging(sixDaysAgoTimestamp));
+        final long batteryStateLatestTimestamp =
+                queryTimestamp == 0L ? 0L : getBatteryStateLatestTimestampBeforeQueryTimestamp(
+                        context, queryTimestamp);
+        final long maxTimestamp = Math.max(Math.max(
+                sixDaysAgoTimestamp, lastFullChargeTime), batteryStateLatestTimestamp);
+        return getHistoryMapSinceQueryTimestamp(context, maxTimestamp);
+    }
+
+    /** Returns the history map since last full charge time. */
+    public static Map<Long, Map<String, BatteryHistEntry>> getHistoryMapSinceLastFullCharge(
+            Context context, Calendar calendar) {
+        final long lastFullChargeTime = getLastFullChargeTime(context);
+        return getHistoryMapSinceLatestRecordBeforeQueryTimestamp(
+                context, calendar, 0, lastFullChargeTime);
+    }
+
     /** Clears all data in the battery usage database. */
     public static void clearAll(Context context) {
         AsyncTask.execute(() -> {
@@ -248,6 +365,7 @@
                 database.appUsageEventDao().clearAll();
                 database.batteryEventDao().clearAll();
                 database.batteryStateDao().clearAll();
+                database.batteryUsageSlotDao().clearAll();
             } catch (RuntimeException e) {
                 Log.e(TAG, "clearAll() failed", e);
             }
@@ -265,6 +383,7 @@
                 database.appUsageEventDao().clearAllBefore(earliestTimestamp);
                 database.batteryEventDao().clearAllBefore(earliestTimestamp);
                 database.batteryStateDao().clearAllBefore(earliestTimestamp);
+                database.batteryUsageSlotDao().clearAllBefore(earliestTimestamp);
             } catch (RuntimeException e) {
                 Log.e(TAG, "clearAllBefore() failed", e);
             }
@@ -293,7 +412,7 @@
                         /*user=*/ context.getSystemService(UserManager.class)
                                 .getProfileParent(context.getUser()));
             } catch (PackageManager.NameNotFoundException e) {
-                Log.e(TAG, "context.createPackageContextAsUser() fail:" + e);
+                Log.e(TAG, "context.createPackageContextAsUser() fail:", e);
                 return null;
             }
         }
@@ -320,7 +439,7 @@
                 resolver.notifyChange(APP_USAGE_EVENT_URI, /*observer=*/ null);
                 Log.d(TAG, "insert() app usage events data into database");
             } catch (Exception e) {
-                Log.e(TAG, "bulkInsert() app usage data into database error:\n" + e);
+                Log.e(TAG, "bulkInsert() app usage data into database error:", e);
             }
         }
         Log.d(TAG, String.format("sendAppUsageEventData() size=%d in %d/ms",
@@ -346,8 +465,65 @@
         return contentValues;
     }
 
+    static List<ContentValues> sendBatteryEventData(
+            final Context context, final List<BatteryEvent> batteryEventList) {
+        final long startTime = System.currentTimeMillis();
+        // Creates the ContentValues list to insert them into provider.
+        final List<ContentValues> valuesList = new ArrayList<>();
+        batteryEventList.stream()
+                .forEach(batteryEvent -> valuesList.add(
+                        ConvertUtils.convertBatteryEventToContentValues(batteryEvent)));
+        int size = 0;
+        final ContentResolver resolver = context.getContentResolver();
+        // Inserts all ContentValues into battery provider.
+        if (!valuesList.isEmpty()) {
+            final ContentValues[] valuesArray = new ContentValues[valuesList.size()];
+            valuesList.toArray(valuesArray);
+            try {
+                size = resolver.bulkInsert(BATTERY_EVENT_URI, valuesArray);
+                resolver.notifyChange(BATTERY_EVENT_URI, /*observer=*/ null);
+                Log.d(TAG, "insert() battery event data into database");
+            } catch (Exception e) {
+                Log.e(TAG, "bulkInsert() battery event data into database error:", e);
+            }
+        }
+        Log.d(TAG, String.format("sendBatteryEventData() size=%d in %d/ms",
+                size, (System.currentTimeMillis() - startTime)));
+        clearMemory();
+        return valuesList;
+    }
+
+    static List<ContentValues> sendBatteryUsageSlotData(
+            final Context context, final List<BatteryUsageSlot> batteryUsageSlotList) {
+        final long startTime = System.currentTimeMillis();
+        // Creates the ContentValues list to insert them into provider.
+        final List<ContentValues> valuesList = new ArrayList<>();
+        batteryUsageSlotList.stream()
+                .forEach(batteryUsageSlot -> valuesList.add(
+                        ConvertUtils.convertBatteryUsageSlotToContentValues(batteryUsageSlot)));
+        int size = 0;
+        final ContentResolver resolver = context.getContentResolver();
+        // Inserts all ContentValues into battery provider.
+        if (!valuesList.isEmpty()) {
+            final ContentValues[] valuesArray = new ContentValues[valuesList.size()];
+            valuesList.toArray(valuesArray);
+            try {
+                size = resolver.bulkInsert(BATTERY_USAGE_SLOT_URI, valuesArray);
+                resolver.notifyChange(BATTERY_USAGE_SLOT_URI, /*observer=*/ null);
+                Log.d(TAG, "insert() battery usage slots data into database");
+            } catch (Exception e) {
+                Log.e(TAG, "bulkInsert() battery usage slots data into database error:", e);
+            }
+        }
+        Log.d(TAG, String.format("sendBatteryUsageSlotData() size=%d in %d/ms",
+                size, (System.currentTimeMillis() - startTime)));
+        clearMemory();
+        return valuesList;
+    }
+
     static List<ContentValues> sendBatteryEntryData(
             final Context context,
+            final long snapshotTimestamp,
             final List<BatteryEntry> batteryEntryList,
             final BatteryUsageStats batteryUsageStats,
             final boolean isFullChargeStart) {
@@ -364,7 +540,6 @@
         final int batteryHealth = intent.getIntExtra(
                 BatteryManager.EXTRA_HEALTH, BatteryManager.BATTERY_HEALTH_UNKNOWN);
         // We should use the same timestamp for each data snapshot.
-        final long snapshotTimestamp = Clock.systemUTC().millis();
         final long snapshotBootTimestamp = SystemClock.elapsedRealtime();
 
         // Creates the ContentValues list to insert them into provider.
@@ -409,8 +584,7 @@
                 Log.d(TAG, "insert() battery states data into database with isFullChargeStart:"
                         + isFullChargeStart);
             } catch (Exception e) {
-                errorMessage = e.toString();
-                Log.e(TAG, "bulkInsert() data into database error:\n" + errorMessage);
+                Log.e(TAG, "bulkInsert() data into database error:", e);
             }
         } else {
             // Inserts one fake data into battery provider.
@@ -430,8 +604,7 @@
                         + isFullChargeStart);
 
             } catch (Exception e) {
-                errorMessage = e.toString();
-                Log.e(TAG, "insert() data into database error:\n" + errorMessage);
+                Log.e(TAG, "insert() data into database error:", e);
             }
             valuesList.add(contentValues);
         }
@@ -504,8 +677,7 @@
     static void recordDateTime(Context context, String preferenceKey) {
         final SharedPreferences sharedPreferences = getSharedPreferences(context);
         if (sharedPreferences != null) {
-            final String currentTime = ConvertUtils.utcToLocalTimeForLogging(
-                    System.currentTimeMillis());
+            final String currentTime = utcToLocalTimeForLogging(System.currentTimeMillis());
             sharedPreferences.edit().putString(preferenceKey, currentTime).apply();
         }
     }
@@ -533,11 +705,6 @@
             cursor.moveToFirst();
             // There is only one column returned so use the index 0 directly.
             final long latestTimestamp = cursor.getLong(/*columnIndex=*/ 0);
-            try {
-                cursor.close();
-            } catch (Exception e) {
-                Log.e(TAG, "cursor.close() failed", e);
-            }
             // If there is no data for this user, 0 will be returned from the database.
             return latestTimestamp == 0 ? INVALID_USER_ID : latestTimestamp;
         }
@@ -556,14 +723,9 @@
             if (cursor == null || cursor.getCount() == 0) {
                 return appUsageEventList;
             }
-            // Loads and recovers all AppUsageEvent data from cursor.
+            // Loads and converts all AppUsageEvent data from cursor.
             while (cursor.moveToNext()) {
-                appUsageEventList.add(ConvertUtils.convertToAppUsageEventFromCursor(cursor));
-            }
-            try {
-                cursor.close();
-            } catch (Exception e) {
-                Log.e(TAG, "cursor.close() failed", e);
+                appUsageEventList.add(ConvertUtils.convertToAppUsageEvent(cursor));
             }
         }
         return appUsageEventList;
@@ -582,19 +744,71 @@
             if (cursor == null || cursor.getCount() == 0) {
                 return batteryEventList;
             }
-            // Loads and recovers all AppUsageEvent data from cursor.
+            // Loads and converts all AppUsageEvent data from cursor.
             while (cursor.moveToNext()) {
-                batteryEventList.add(ConvertUtils.convertToBatteryEventFromCursor(cursor));
-            }
-            try {
-                cursor.close();
-            } catch (Exception e) {
-                Log.e(TAG, "cursor.close() failed", e);
+                batteryEventList.add(ConvertUtils.convertToBatteryEvent(cursor));
             }
         }
         return batteryEventList;
     }
 
+    private static List<BatteryUsageSlot> loadBatteryUsageSlotsFromContentProvider(
+            Context context, Uri batteryUsageSlotUri) {
+        final List<BatteryUsageSlot> batteryUsageSlotList = new ArrayList<>();
+        context = getParentContext(context);
+        if (context == null) {
+            return batteryUsageSlotList;
+        }
+        try (Cursor cursor = sFakeSupplier != null
+                ? sFakeSupplier.get()
+                : context.getContentResolver().query(batteryUsageSlotUri, null, null, null)) {
+            if (cursor == null || cursor.getCount() == 0) {
+                return batteryUsageSlotList;
+            }
+            // Loads and converts all AppUsageEvent data from cursor.
+            while (cursor.moveToNext()) {
+                batteryUsageSlotList.add(ConvertUtils.convertToBatteryUsageSlot(cursor));
+            }
+        }
+        return batteryUsageSlotList;
+    }
+
+    private static long loadLastFullChargeTimeFromContentProvider(
+            Context context, final Uri lastFullChargeTimeUri) {
+        // We have already make sure the context here is with profile parent's user identity. Don't
+        // need to check whether current user is work profile.
+        try (Cursor cursor = sFakeSupplier != null
+                ? sFakeSupplier.get()
+                : context.getContentResolver().query(
+                        lastFullChargeTimeUri, null, null, null)) {
+            if (cursor == null || cursor.getCount() == 0) {
+                return 0L;
+            }
+            cursor.moveToFirst();
+            // There is only one column returned so use the index 0 directly.
+            final long lastFullChargeTime = cursor.getLong(/*columnIndex=*/ 0);
+            return lastFullChargeTime;
+        }
+    }
+
+    private static long loadBatteryStateLatestTimestampFromContentProvider(
+            Context context, final Uri batteryStateLatestTimestampUri) {
+        // We have already make sure the context here is with profile parent's user identity. Don't
+        // need to check whether current user is work profile.
+        try (Cursor cursor = sFakeSupplier != null
+                ? sFakeSupplier.get()
+                : context.getContentResolver().query(
+                        batteryStateLatestTimestampUri, null, null, null)) {
+            if (cursor == null || cursor.getCount() == 0) {
+                return 0L;
+            }
+            cursor.moveToFirst();
+            // There is only one column returned so use the index 0 directly.
+            final long batteryStateLatestTimestamp = cursor.getLong(/*columnIndex=*/ 0);
+            return batteryStateLatestTimestamp;
+        }
+    }
+
     private static Map<Long, Map<String, BatteryHistEntry>> loadHistoryMapFromContentProvider(
             Context context, Uri batteryStateUri) {
         context = getParentContext(context);
@@ -607,7 +821,7 @@
             if (cursor == null || cursor.getCount() == 0) {
                 return resultMap;
             }
-            // Loads and recovers all BatteryHistEntry data from cursor.
+            // Loads and converts all BatteryHistEntry data from cursor.
             while (cursor.moveToNext()) {
                 final BatteryHistEntry entry = new BatteryHistEntry(cursor);
                 final long timestamp = entry.mTimestamp;
@@ -620,11 +834,6 @@
                 }
                 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/fuelgauge/batteryusage/PeriodicJobReceiver.java b/src/com/android/settings/fuelgauge/batteryusage/PeriodicJobReceiver.java
index 2bd0466..2371a19 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/PeriodicJobReceiver.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/PeriodicJobReceiver.java
@@ -44,7 +44,6 @@
         }
         BatteryUsageLogUtils.writeLog(context, Action.EXECUTE_JOB, "");
         BatteryUsageDataLoader.enqueueWork(context, /*isFullChargeStart=*/ false);
-        AppUsageDataLoader.enqueueWork(context);
         Log.d(TAG, "refresh periodic job from action=" + action);
         PeriodicJobManager.getInstance(context).refreshJob(/*fromBoot=*/ false);
         DatabaseUtils.clearExpiredDataIfNeeded(context);
diff --git a/src/com/android/settings/fuelgauge/batteryusage/PowerUsageAdvanced.java b/src/com/android/settings/fuelgauge/batteryusage/PowerUsageAdvanced.java
index 5a96fb4..f13f34c 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/PowerUsageAdvanced.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/PowerUsageAdvanced.java
@@ -21,12 +21,13 @@
 import android.content.Context;
 import android.database.ContentObserver;
 import android.net.Uri;
+import android.os.AsyncTask;
 import android.os.Bundle;
 import android.os.Handler;
+import android.os.Looper;
 import android.provider.SearchIndexableResource;
 import android.util.Log;
 
-import androidx.annotation.NonNull;
 import androidx.annotation.VisibleForTesting;
 import androidx.loader.app.LoaderManager;
 import androidx.loader.content.Loader;
@@ -39,11 +40,13 @@
 import com.android.settings.search.BaseSearchIndexProvider;
 import com.android.settingslib.core.AbstractPreferenceController;
 import com.android.settingslib.search.SearchIndexable;
+import com.android.settingslib.utils.AsyncLoaderCompat;
 
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
 import java.util.Map;
+import java.util.Optional;
 
 /** Advanced power usage. */
 @SearchIndexable(forTarget = SearchIndexable.ALL & ~SearchIndexable.ARC)
@@ -55,16 +58,17 @@
     @VisibleForTesting
     BatteryHistoryPreference mHistPref;
     @VisibleForTesting
-    Map<Long, Map<String, BatteryHistEntry>> mBatteryHistoryMap;
-    @VisibleForTesting
-    final BatteryHistoryLoaderCallbacks mBatteryHistoryLoaderCallbacks =
-            new BatteryHistoryLoaderCallbacks();
+    final BatteryLevelDataLoaderCallbacks mBatteryLevelDataLoaderCallbacks =
+            new BatteryLevelDataLoaderCallbacks();
 
     private boolean mIsChartDataLoaded = false;
+    private long mResumeTimestamp;
     private BatteryChartPreferenceController mBatteryChartPreferenceController;
+    private Optional<BatteryLevelData> mBatteryLevelData;
 
+    private final Handler mHandler = new Handler(Looper.getMainLooper());
     private final ContentObserver mBatteryObserver =
-            new ContentObserver(new Handler()) {
+            new ContentObserver(mHandler) {
                 @Override
                 public void onChange(boolean selfChange) {
                     Log.d(TAG, "onBatteryContentChange: " + selfChange);
@@ -79,6 +83,7 @@
         super.onCreate(icicle);
         mHistPref = findPreference(KEY_BATTERY_CHART);
         setBatteryChartPreferenceController();
+        AsyncTask.execute(() -> BootBroadcastReceiver.invokeJobRecheck(getContext()));
     }
 
     @Override
@@ -109,6 +114,7 @@
         super.onPause();
         // Resets the flag to reload usage data in onResume() callback.
         mIsChartDataLoaded = false;
+        mBatteryLevelData = null;
         final Uri uri = DatabaseUtils.BATTERY_CONTENT_URI;
         if (uri != null) {
             getContext().getContentResolver().unregisterContentObserver(mBatteryObserver);
@@ -118,6 +124,7 @@
     @Override
     public void onResume() {
         super.onResume();
+        mResumeTimestamp = System.currentTimeMillis();
         final Uri uri = DatabaseUtils.BATTERY_CONTENT_URI;
         if (uri != null) {
             getContext().getContentResolver().registerContentObserver(
@@ -159,20 +166,8 @@
     }
 
     @Override
-    protected boolean isBatteryHistoryNeeded() {
-        return true;
-    }
-
-    @Override
     protected void refreshUi(@BatteryUpdateType int refreshType) {
-        final Context context = getContext();
-        if (context == null) {
-            return;
-        }
-        updatePreference(mHistPref);
-        if (mBatteryChartPreferenceController != null && mBatteryHistoryMap != null) {
-            mBatteryChartPreferenceController.setBatteryHistoryMap(mBatteryHistoryMap);
-        }
+        // Do nothing
     }
 
     @Override
@@ -181,11 +176,32 @@
         bundle.putInt(KEY_REFRESH_TYPE, refreshType);
         if (!mIsChartDataLoaded) {
             mIsChartDataLoaded = true;
-            restartLoader(LoaderIndex.BATTERY_HISTORY_LOADER, bundle,
-                    mBatteryHistoryLoaderCallbacks);
+            restartLoader(LoaderIndex.BATTERY_LEVEL_DATA_LOADER, bundle,
+                    mBatteryLevelDataLoaderCallbacks);
         }
     }
 
+    private void onBatteryLevelDataUpdate(BatteryLevelData batteryLevelData) {
+        mBatteryLevelData = Optional.ofNullable(batteryLevelData);
+        if (mBatteryChartPreferenceController != null) {
+            mBatteryChartPreferenceController.onBatteryLevelDataUpdate(batteryLevelData);
+            Log.d(TAG, String.format("Battery chart shows in %d millis",
+                    System.currentTimeMillis() - mResumeTimestamp));
+        }
+    }
+
+    private void onBatteryDiffDataMapUpdate(Map<Long, BatteryDiffData> batteryDiffDataMap) {
+        if (mBatteryLevelData != null && mBatteryChartPreferenceController != null) {
+            Map<Integer, Map<Integer, BatteryDiffData>> batteryUsageMap =
+                    DataProcessor.generateBatteryUsageMap(
+                            getContext(), batteryDiffDataMap, mBatteryLevelData.orElse(null));
+            DataProcessor.loadLabelAndIcon(batteryUsageMap);
+            mBatteryChartPreferenceController.onBatteryUsageMapUpdate(batteryUsageMap);
+        }
+        Log.d(TAG, String.format("Battery usage list shows in %d millis",
+                System.currentTimeMillis() - mResumeTimestamp));
+    }
+
     private void setBatteryChartPreferenceController() {
         if (mHistPref != null && mBatteryChartPreferenceController != null) {
             mHistPref.setChartPreferenceController(mBatteryChartPreferenceController);
@@ -216,28 +232,31 @@
                 }
             };
 
-    private class BatteryHistoryLoaderCallbacks
-            implements LoaderManager.LoaderCallbacks<Map<Long, Map<String, BatteryHistEntry>>> {
-        private int mRefreshType;
-
+    private class BatteryLevelDataLoaderCallbacks
+            implements LoaderManager.LoaderCallbacks<BatteryLevelData> {
         @Override
-        @NonNull
-        public Loader<Map<Long, Map<String, BatteryHistEntry>>> onCreateLoader(
-                int id, Bundle bundle) {
-            mRefreshType = bundle.getInt(KEY_REFRESH_TYPE);
-            return new BatteryHistoryLoader(getContext());
+        public Loader<BatteryLevelData> onCreateLoader(int id, Bundle bundle) {
+            return new AsyncLoaderCompat<BatteryLevelData>(getContext().getApplicationContext()) {
+                @Override
+                protected void onDiscardResult(BatteryLevelData result) {}
+
+                @Override
+                public BatteryLevelData loadInBackground() {
+                    return DataProcessManager.getBatteryLevelData(
+                            getContext(), mHandler, /*isFromPeriodJob=*/ false,
+                            map -> PowerUsageAdvanced.this.onBatteryDiffDataMapUpdate(map));
+                }
+            };
         }
 
         @Override
-        public void onLoadFinished(Loader<Map<Long, Map<String, BatteryHistEntry>>> loader,
-                Map<Long, Map<String, BatteryHistEntry>> batteryHistoryMap) {
-            mBatteryHistoryMap = batteryHistoryMap;
-            PowerUsageAdvanced.this.onLoadFinished(mRefreshType);
+        public void onLoadFinished(Loader<BatteryLevelData> loader,
+                BatteryLevelData batteryLevelData) {
+            PowerUsageAdvanced.this.onBatteryLevelDataUpdate(batteryLevelData);
         }
 
         @Override
-        public void onLoaderReset(Loader<Map<Long, Map<String, BatteryHistEntry>>> loader) {
+        public void onLoaderReset(Loader<BatteryLevelData> loader) {
         }
     }
-
 }
diff --git a/src/com/android/settings/fuelgauge/batteryusage/PowerUsageBase.java b/src/com/android/settings/fuelgauge/batteryusage/PowerUsageBase.java
index ed3a921..22856b6 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/PowerUsageBase.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/PowerUsageBase.java
@@ -32,7 +32,6 @@
 
 import com.android.settings.dashboard.DashboardFragment;
 import com.android.settings.fuelgauge.BatteryBroadcastReceiver;
-import com.android.settings.fuelgauge.BatteryUtils;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -63,14 +62,14 @@
             LoaderIndex.BATTERY_USAGE_STATS_LOADER,
             LoaderIndex.BATTERY_INFO_LOADER,
             LoaderIndex.BATTERY_TIP_LOADER,
-            LoaderIndex.BATTERY_HISTORY_LOADER
+            LoaderIndex.BATTERY_LEVEL_DATA_LOADER
 
     })
     public @interface LoaderIndex {
         int BATTERY_USAGE_STATS_LOADER = 0;
         int BATTERY_INFO_LOADER = 1;
         int BATTERY_TIP_LOADER = 2;
-        int BATTERY_HISTORY_LOADER = 3;
+        int BATTERY_LEVEL_DATA_LOADER = 3;
     }
 
     @Override
@@ -108,7 +107,7 @@
     protected void restartBatteryStatsLoader(int refreshType) {
         final Bundle bundle = new Bundle();
         bundle.putInt(KEY_REFRESH_TYPE, refreshType);
-        bundle.putBoolean(KEY_INCLUDE_HISTORY, isBatteryHistoryNeeded());
+        bundle.putBoolean(KEY_INCLUDE_HISTORY, false);
         restartLoader(LoaderIndex.BATTERY_USAGE_STATS_LOADER, bundle,
                 mBatteryUsageStatsLoaderCallbacks);
     }
@@ -137,14 +136,6 @@
 
     protected abstract void refreshUi(@BatteryUpdateType int refreshType);
 
-    protected abstract boolean isBatteryHistoryNeeded();
-
-    protected void updatePreference(BatteryHistoryPreference historyPref) {
-        final long startTime = System.currentTimeMillis();
-        historyPref.setBatteryUsageStats(mBatteryUsageStats);
-        BatteryUtils.logRuntime(TAG, "updatePreference", startTime);
-    }
-
     private class BatteryUsageStatsLoaderCallbacks
             implements LoaderManager.LoaderCallbacks<BatteryUsageStats> {
         private int mRefreshType;
diff --git a/src/com/android/settings/fuelgauge/batteryusage/PowerUsageSummary.java b/src/com/android/settings/fuelgauge/batteryusage/PowerUsageSummary.java
index a0c5843..3b9a1c9 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/PowerUsageSummary.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/PowerUsageSummary.java
@@ -45,7 +45,6 @@
 import com.android.settings.overlay.FeatureFactory;
 import com.android.settings.search.BaseSearchIndexProvider;
 import com.android.settingslib.search.SearchIndexable;
-import com.android.settingslib.widget.LayoutPreference;
 
 import java.util.List;
 
@@ -69,8 +68,6 @@
     @VisibleForTesting
     BatteryUtils mBatteryUtils;
     @VisibleForTesting
-    LayoutPreference mBatteryLayoutPref;
-    @VisibleForTesting
     BatteryInfo mBatteryInfo;
 
     @VisibleForTesting
@@ -145,7 +142,6 @@
         mBatteryHeaderPreferenceController = use(BatteryHeaderPreferenceController.class);
         mBatteryHeaderPreferenceController.setActivity(activity);
         mBatteryHeaderPreferenceController.setFragment(this);
-        mBatteryHeaderPreferenceController.setLifecycle(getSettingsLifecycle());
 
         mBatteryTipPreferenceController = use(BatteryTipPreferenceController.class);
         mBatteryTipPreferenceController.setActivity(activity);
@@ -208,11 +204,6 @@
         return R.string.help_url_battery;
     }
 
-    @Override
-    protected boolean isBatteryHistoryNeeded() {
-        return false;
-    }
-
     protected void refreshUi(@BatteryUpdateType int refreshType) {
         final Context context = getContext();
         if (context == null) {
@@ -240,11 +231,6 @@
     }
 
     @VisibleForTesting
-    void setBatteryLayoutPreference(LayoutPreference layoutPreference) {
-        mBatteryLayoutPref = layoutPreference;
-    }
-
-    @VisibleForTesting
     void initFeatureProvider() {
         mPowerFeatureProvider = FeatureFactory.getFeatureFactory().getPowerUsageFeatureProvider();
     }
diff --git a/src/com/android/settings/fuelgauge/batteryusage/db/BatteryEventDao.java b/src/com/android/settings/fuelgauge/batteryusage/db/BatteryEventDao.java
index a638d09..0a6de71 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/db/BatteryEventDao.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/db/BatteryEventDao.java
@@ -36,9 +36,16 @@
     @Query("SELECT * FROM BatteryEventEntity ORDER BY timestamp DESC")
     List<BatteryEventEntity> getAll();
 
+    /** Gets the {@link Cursor} of the last full charge time . */
+    @Query("SELECT MAX(timestamp) FROM BatteryEventEntity"
+            + " WHERE batteryEventType = 3")  // BatteryEventType.FULL_CHARGED = 3
+    Cursor getLastFullChargeTimestamp();
+
     /** Gets the {@link Cursor} of all recorded data after a specific timestamp. */
-    @Query("SELECT * FROM BatteryEventEntity WHERE timestamp > :timestamp ORDER BY timestamp DESC")
-    Cursor getAllAfter(long timestamp);
+    @Query("SELECT * FROM BatteryEventEntity"
+            + " WHERE timestamp > :timestamp AND batteryEventType IN (:batteryEventTypes)"
+            + " ORDER BY timestamp DESC")
+    Cursor getAllAfter(long timestamp, List<Integer> batteryEventTypes);
 
     /** Deletes all recorded data before a specific timestamp. */
     @Query("DELETE FROM BatteryEventEntity WHERE timestamp <= :timestamp")
diff --git a/src/com/android/settings/fuelgauge/batteryusage/db/BatteryStateDao.java b/src/com/android/settings/fuelgauge/batteryusage/db/BatteryStateDao.java
index 6d2ab8d..520c6be 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/db/BatteryStateDao.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/db/BatteryStateDao.java
@@ -37,16 +37,18 @@
     @Insert(onConflict = OnConflictStrategy.REPLACE)
     void insertAll(List<BatteryState> states);
 
+    /** Gets the {@link Cursor} of the latest record timestamp no later than the given timestamp. */
+    @Query("SELECT MAX(timestamp) FROM BatteryState WHERE timestamp <= :timestamp")
+    Cursor getLatestTimestampBefore(long timestamp);
+
+    /** Lists all recorded battery states after a specific timestamp. */
+    @Query("SELECT * FROM BatteryState WHERE timestamp >= :timestamp ORDER BY timestamp ASC")
+    Cursor getBatteryStatesAfter(long timestamp);
+
     /** Lists all recorded data after a specific timestamp. */
     @Query("SELECT * FROM BatteryState WHERE timestamp > :timestamp ORDER BY timestamp DESC")
     List<BatteryState> getAllAfter(long timestamp);
 
-    /** Gets the {@link Cursor} of all recorded data since last full charge within 7 days. */
-    @Query("SELECT * FROM BatteryState WHERE timestamp >= :timestampSixDaysAgo AND timestamp >= "
-            + "(SELECT IFNULL((SELECT MAX(timestamp) FROM BatteryState "
-            + "WHERE isFullChargeCycleStart = 1), 0)) ORDER BY timestamp ASC")
-    Cursor getCursorSinceLastFullCharge(long timestampSixDaysAgo);
-
     /** Get the count of distinct timestamp after a specific timestamp. */
     @Query("SELECT COUNT(DISTINCT timestamp) FROM BatteryState WHERE timestamp > :timestamp")
     int getDistinctTimestampCount(long timestamp);
diff --git a/src/com/android/settings/fuelgauge/batteryusage/db/BatteryStateDatabase.java b/src/com/android/settings/fuelgauge/batteryusage/db/BatteryStateDatabase.java
index 466a7ca..28a0012 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/db/BatteryStateDatabase.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/db/BatteryStateDatabase.java
@@ -25,7 +25,8 @@
 
 /** A {@link RoomDatabase} for battery usage states history. */
 @Database(
-        entities = {AppUsageEventEntity.class, BatteryEventEntity.class, BatteryState.class},
+        entities = {AppUsageEventEntity.class, BatteryEventEntity.class, BatteryState.class,
+                BatteryUsageSlotEntity.class},
         version = 1)
 public abstract class BatteryStateDatabase extends RoomDatabase {
     private static final String TAG = "BatteryStateDatabase";
@@ -38,13 +39,15 @@
     public abstract BatteryEventDao batteryEventDao();
     /** Provides DAO for battery state table. */
     public abstract BatteryStateDao batteryStateDao();
+    /** Provides DAO for battery usage slot table. */
+    public abstract BatteryUsageSlotDao batteryUsageSlotDao();
 
     /** Gets or creates an instance of {@link RoomDatabase}. */
     public static BatteryStateDatabase getInstance(Context context) {
         if (sBatteryStateDatabase == null) {
             sBatteryStateDatabase =
                     Room.databaseBuilder(
-                                    context, BatteryStateDatabase.class, "battery-usage-db-v8")
+                                    context, BatteryStateDatabase.class, "battery-usage-db-v9")
                             // Allows accessing data in the main thread for dumping bugreport.
                             .allowMainThreadQueries()
                             .fallbackToDestructiveMigration()
diff --git a/src/com/android/settings/fuelgauge/batteryusage/db/BatteryUsageSlotDao.java b/src/com/android/settings/fuelgauge/batteryusage/db/BatteryUsageSlotDao.java
new file mode 100644
index 0000000..a695f6a
--- /dev/null
+++ b/src/com/android/settings/fuelgauge/batteryusage/db/BatteryUsageSlotDao.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2023 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.batteryusage.db;
+
+import android.database.Cursor;
+
+import androidx.room.Dao;
+import androidx.room.Insert;
+import androidx.room.OnConflictStrategy;
+import androidx.room.Query;
+
+import java.util.List;
+
+/** Data access object for accessing {@link BatteryUsageSlotEntity} in the database. */
+@Dao
+public interface BatteryUsageSlotDao {
+    /** Inserts a {@link BatteryUsageSlotEntity} data into the database. */
+    @Insert(onConflict = OnConflictStrategy.REPLACE)
+    void insert(BatteryUsageSlotEntity event);
+
+    /** Gets all recorded data. */
+    @Query("SELECT * FROM BatteryUsageSlotEntity ORDER BY timestamp ASC")
+    List<BatteryUsageSlotEntity> getAll();
+
+    /** Gets the {@link Cursor} of all recorded data after a specific timestamp. */
+    @Query("SELECT * FROM BatteryUsageSlotEntity WHERE timestamp >= :timestamp"
+            + " ORDER BY timestamp ASC")
+    Cursor getAllAfter(long timestamp);
+
+    /** Deletes all recorded data before a specific timestamp. */
+    @Query("DELETE FROM BatteryUsageSlotEntity WHERE timestamp <= :timestamp")
+    void clearAllBefore(long timestamp);
+
+    /** Clears all recorded data in the database. */
+    @Query("DELETE FROM BatteryUsageSlotEntity")
+    void clearAll();
+}
diff --git a/src/com/android/settings/fuelgauge/batteryusage/db/BatteryUsageSlotEntity.java b/src/com/android/settings/fuelgauge/batteryusage/db/BatteryUsageSlotEntity.java
new file mode 100644
index 0000000..c2d5631
--- /dev/null
+++ b/src/com/android/settings/fuelgauge/batteryusage/db/BatteryUsageSlotEntity.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2023 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.batteryusage.db;
+
+import android.content.ContentValues;
+
+import androidx.room.Entity;
+import androidx.room.PrimaryKey;
+
+import com.android.settings.fuelgauge.batteryusage.ConvertUtils;
+
+import com.google.errorprone.annotations.CanIgnoreReturnValue;
+
+import java.util.Locale;
+
+/** A {@link Entity} class to save battery usage slot into database. */
+@Entity
+public class BatteryUsageSlotEntity {
+    /** Keys for accessing {@link ContentValues}. */
+    public static final String KEY_TIMESTAMP = "timestamp";
+    public static final String KEY_BATTERY_USAGE_SLOT = "batteryUsageSlot";
+
+    @PrimaryKey(autoGenerate = true)
+    private long mId;
+
+    public final long timestamp;
+    public final String batteryUsageSlot;
+
+    public BatteryUsageSlotEntity(final long timestamp, final String batteryUsageSlot) {
+        this.timestamp = timestamp;
+        this.batteryUsageSlot = batteryUsageSlot;
+    }
+
+    /** Sets the auto-generated content ID. */
+    public void setId(long id) {
+        this.mId = id;
+    }
+
+    /** Gets the auto-generated content ID. */
+    public long getId() {
+        return mId;
+    }
+
+    @Override
+    public String toString() {
+        final String recordAtDateTime = ConvertUtils.utcToLocalTimeForLogging(timestamp);
+        final StringBuilder builder = new StringBuilder()
+                .append("\nBatteryUsageSlot{")
+                .append(String.format(Locale.US, "\n\ttimestamp=%s|batteryUsageSlot=%s",
+                        recordAtDateTime, batteryUsageSlot))
+                .append("\n}");
+        return builder.toString();
+    }
+
+    /** Creates new {@link BatteryUsageSlotEntity} from {@link ContentValues}. */
+    public static BatteryUsageSlotEntity create(ContentValues contentValues) {
+        Builder builder = BatteryUsageSlotEntity.newBuilder();
+        if (contentValues.containsKey(KEY_TIMESTAMP)) {
+            builder.setTimestamp(contentValues.getAsLong(KEY_TIMESTAMP));
+        }
+        if (contentValues.containsKey(KEY_BATTERY_USAGE_SLOT)) {
+            builder.setBatteryUsageSlot(contentValues.getAsString(KEY_BATTERY_USAGE_SLOT));
+        }
+        return builder.build();
+    }
+
+    /** Creates a new {@link Builder} instance. */
+    public static Builder newBuilder() {
+        return new Builder();
+    }
+
+    /** A convenience builder class to improve readability. */
+    public static class Builder {
+        private long mTimestamp;
+        private String mBatteryUsageSlot;
+
+        /** Sets the timestamp. */
+        @CanIgnoreReturnValue
+        public Builder setTimestamp(final long timestamp) {
+            mTimestamp = timestamp;
+            return this;
+        }
+
+        /** Sets the battery usage slot. */
+        @CanIgnoreReturnValue
+        public Builder setBatteryUsageSlot(final String batteryUsageSlot) {
+            mBatteryUsageSlot = batteryUsageSlot;
+            return this;
+        }
+
+        /** Builds the {@link BatteryUsageSlotEntity}. */
+        public BatteryUsageSlotEntity build() {
+            return new BatteryUsageSlotEntity(mTimestamp, mBatteryUsageSlot);
+        }
+
+        private Builder() {}
+    }
+}
diff --git a/src/com/android/settings/fuelgauge/protos/Android.bp b/src/com/android/settings/fuelgauge/protos/Android.bp
index 1f3cdd9..531bdc32 100644
--- a/src/com/android/settings/fuelgauge/protos/Android.bp
+++ b/src/com/android/settings/fuelgauge/protos/Android.bp
@@ -24,6 +24,14 @@
 }
 
 java_library {
+    name: "battery-usage-slot-protos-lite",
+    proto: {
+        type: "lite",
+    },
+    srcs: ["battery_usage_slot.proto"],
+}
+
+java_library {
     name: "fuelgauge-usage-state-protos-lite",
     proto: {
         type: "lite",
diff --git a/src/com/android/settings/fuelgauge/protos/battery_event.proto b/src/com/android/settings/fuelgauge/protos/battery_event.proto
index 80ccb3b..58ab3be 100644
--- a/src/com/android/settings/fuelgauge/protos/battery_event.proto
+++ b/src/com/android/settings/fuelgauge/protos/battery_event.proto
@@ -8,6 +8,8 @@
   UNKNOWN_EVENT = 0;
   POWER_CONNECTED = 1;
   POWER_DISCONNECTED = 2;
+  FULL_CHARGED = 3;
+  EVEN_HOUR = 4;
 }
 
 message BatteryEvent {
diff --git a/src/com/android/settings/fuelgauge/protos/battery_usage_slot.proto b/src/com/android/settings/fuelgauge/protos/battery_usage_slot.proto
new file mode 100644
index 0000000..e3b604b
--- /dev/null
+++ b/src/com/android/settings/fuelgauge/protos/battery_usage_slot.proto
@@ -0,0 +1,32 @@
+syntax = "proto2";
+
+option java_multiple_files = true;
+option java_package = "com.android.settings.fuelgauge.batteryusage";
+option java_outer_classname = "BatteryUsageSlotProto";
+
+message BatteryUsageSlot {
+  optional int64 start_timestamp = 1;
+  optional int64 end_timestamp = 2;
+  optional int32 start_battery_level = 3;
+  optional int32 end_battery_level = 4;
+  optional int64 screen_on_time = 5;
+  repeated BatteryUsageDiff app_usage = 6;
+  repeated BatteryUsageDiff system_usage = 7;
+}
+
+message BatteryUsageDiff {
+  optional int64 uid = 1;
+  optional int64 user_id = 2;
+  optional string package_name = 3;
+  optional string label = 4;
+  optional string key = 5;
+  optional bool is_hidden = 6;
+  optional int32 component_id = 7;
+  optional int32 consumer_type = 8;
+  optional double consume_power = 9;
+  optional double foreground_usage_consume_power = 10;
+  optional double background_usage_consume_power = 11;
+  optional int64 foreground_usage_time = 12;
+  optional int64 background_usage_time = 13;
+  optional int64 screen_on_time = 14;
+}
diff --git a/src/com/android/settings/fuelgauge/protos/power_anomaly_event.proto b/src/com/android/settings/fuelgauge/protos/power_anomaly_event.proto
index 380c786..c799d7a 100644
--- a/src/com/android/settings/fuelgauge/protos/power_anomaly_event.proto
+++ b/src/com/android/settings/fuelgauge/protos/power_anomaly_event.proto
@@ -11,8 +11,8 @@
 message PowerAnomalyEvent {
   optional string event_id = 1;
   optional int64 timestamp = 2;
-  optional string type = 3;  // e.g. settings, apps
-  optional string key = 4;  // e.g. brightness, significant_increase
+  optional PowerAnomalyType type = 3;
+  optional PowerAnomalyKey key = 4;
   optional float score = 5;
   oneof info {
     WarningBannerInfo warning_banner_info = 6;
@@ -20,6 +20,25 @@
   }
 }
 
+// NOTE: Please DO NOT delete enum items or change enum values. Use [deprecated = true] instead.
+// The enum value will be used to decide the tips card style like icons and colors.
+//
+// Next id: 2
+enum PowerAnomalyType{
+  TYPE_SETTINGS_BANNER = 0;
+  TYPE_APPS_ITEM = 1;
+}
+
+// NOTE: Please DO NOT delete enum items or change enum values. Use [deprecated = true] instead.
+// The enum value will be used to decide pre-defined title and button labels.
+//
+// Next id: 3
+enum PowerAnomalyKey{
+  KEY_BRIGHTNESS = 0;
+  KEY_SCREEN_TIMEOUT = 1;
+  KEY_APP = 2;
+}
+
 message WarningBannerInfo {
   optional string title_string = 1;
   optional string description_string = 2;
diff --git a/src/com/android/settings/localepicker/LocaleDialogFragment.java b/src/com/android/settings/localepicker/LocaleDialogFragment.java
index 52ee63d..53846ba 100644
--- a/src/com/android/settings/localepicker/LocaleDialogFragment.java
+++ b/src/com/android/settings/localepicker/LocaleDialogFragment.java
@@ -204,8 +204,6 @@
                 bundle.putInt(ARG_DIALOG_TYPE, DIALOG_CONFIRM_SYSTEM_DEFAULT);
                 intent.putExtras(bundle);
                 mParent.onActivityResult(DIALOG_CONFIRM_SYSTEM_DEFAULT, result, intent);
-                mMetricsFeatureProvider.action(mContext, SettingsEnums.ACTION_CHANGE_LANGUAGE,
-                        changed);
             }
             mShouldKeepDialog = false;
         }
diff --git a/src/com/android/settings/localepicker/LocaleDragAndDropAdapter.java b/src/com/android/settings/localepicker/LocaleDragAndDropAdapter.java
index af9ad85..bfe0749 100644
--- a/src/com/android/settings/localepicker/LocaleDragAndDropAdapter.java
+++ b/src/com/android/settings/localepicker/LocaleDragAndDropAdapter.java
@@ -16,7 +16,6 @@
 
 package com.android.settings.localepicker;
 
-import android.app.settings.SettingsEnums;
 import android.content.Context;
 import android.graphics.Canvas;
 import android.os.Bundle;
@@ -39,7 +38,6 @@
 import com.android.internal.app.LocalePicker;
 import com.android.internal.app.LocaleStore;
 import com.android.settings.R;
-import com.android.settings.overlay.FeatureFactory;
 import com.android.settings.shortcut.ShortcutsUpdateTask;
 
 import java.text.NumberFormat;
@@ -53,7 +51,6 @@
     private static final String TAG = "LocaleDragAndDropAdapter";
     private static final String CFGKEY_SELECTED_LOCALES = "selectedLocales";
     private static final String CFGKEY_DRAG_LOCALE = "dragLocales";
-    private static final String CFGKEY_DRAG_LOCALES_TO_POSITION = "dragLocales_end";
 
     private final Context mContext;
     private final ItemTouchHelper mItemTouchHelper;
@@ -61,7 +58,6 @@
     private List<LocaleStore.LocaleInfo> mFeedItemList;
     private List<LocaleStore.LocaleInfo> mCacheItemList;
     private RecyclerView mParentView = null;
-    private LocaleListEditor mParent;
     private boolean mRemoveMode = false;
     private boolean mDragEnabled = true;
     private NumberFormat mNumberFormatter = NumberFormat.getNumberInstance();
@@ -94,7 +90,6 @@
 
     LocaleDragAndDropAdapter(LocaleListEditor parent, List<LocaleStore.LocaleInfo> feedItemList) {
         mFeedItemList = feedItemList;
-        mParent = parent;
         mCacheItemList = new ArrayList<>(feedItemList);
         mContext = parent.getContext();
 
@@ -230,12 +225,6 @@
                     "Negative position in onItemMove %d -> %d", fromPosition, toPosition));
         }
 
-        if (fromPosition != toPosition) {
-            FeatureFactory.getFeatureFactory().getMetricsFeatureProvider()
-                    .action(mContext, SettingsEnums.ACTION_REORDER_LANGUAGE,
-                            mDragLocale.getLocale().toLanguageTag() + " move to " + toPosition);
-        }
-
         notifyItemChanged(fromPosition); // to update the numbers
         notifyItemChanged(toPosition);
         notifyItemMoved(fromPosition, toPosition);
@@ -274,9 +263,6 @@
         for (int i = itemCount - 1; i >= 0; i--) {
             localeInfo = mFeedItemList.get(i);
             if (localeInfo.getChecked()) {
-                FeatureFactory.getFeatureFactory().getMetricsFeatureProvider()
-                        .action(mContext, SettingsEnums.ACTION_REMOVE_LANGUAGE,
-                                localeInfo.getLocale().toLanguageTag());
                 mFeedItemList.remove(i);
             }
         }
diff --git a/src/com/android/settings/localepicker/LocaleListEditor.java b/src/com/android/settings/localepicker/LocaleListEditor.java
index d9109c3..d8dd736 100644
--- a/src/com/android/settings/localepicker/LocaleListEditor.java
+++ b/src/com/android/settings/localepicker/LocaleListEditor.java
@@ -216,8 +216,6 @@
             localeInfo = mayAppendUnicodeTags(localeInfo, preferencesTags);
             mAdapter.addLocale(localeInfo);
             updateVisibilityOfRemoveMenu();
-            mMetricsFeatureProvider.action(getContext(), SettingsEnums.ACTION_ADD_LANGUAGE,
-                    localeInfo.getLocale().toLanguageTag());
         } else if (requestCode == DIALOG_CONFIRM_SYSTEM_DEFAULT) {
             localeInfo = mAdapter.getFeedItemList().get(0);
             if (resultCode == Activity.RESULT_OK) {
diff --git a/src/com/android/settings/network/telephony/MobileNetworkSettings.java b/src/com/android/settings/network/telephony/MobileNetworkSettings.java
index 1d862f3..400ddff 100644
--- a/src/com/android/settings/network/telephony/MobileNetworkSettings.java
+++ b/src/com/android/settings/network/telephony/MobileNetworkSettings.java
@@ -167,8 +167,7 @@
         });
 
         return Arrays.asList(
-                new DataUsageSummaryPreferenceController(getActivity(), getSettingsLifecycle(),
-                        this, mSubId),
+                new DataUsageSummaryPreferenceController(getActivity(), this, mSubId),
                 new RoamingPreferenceController(context, KEY_ROAMING_PREF, getSettingsLifecycle(),
                         this, mSubId),
                 new CallsDefaultSubscriptionController(context, KEY_CALLS_PREF,
diff --git a/src/com/android/settings/notification/app/ConversationHeaderPreferenceController.java b/src/com/android/settings/notification/app/ConversationHeaderPreferenceController.java
index 43b50c8..2b2184e 100644
--- a/src/com/android/settings/notification/app/ConversationHeaderPreferenceController.java
+++ b/src/com/android/settings/notification/app/ConversationHeaderPreferenceController.java
@@ -89,8 +89,7 @@
                     .setButtonActions(EntityHeaderController.ActionType.ACTION_NOTIF_PREFERENCE,
                             EntityHeaderController.ActionType.ACTION_NONE)
                     .setHasAppInfoLink(true)
-                    .setRecyclerView(mFragment.getListView(), mFragment.getSettingsLifecycle())
-                    .done(activity, mContext);
+                    .done(mContext);
 
             pref.findViewById(R.id.entity_header).setVisibility(View.VISIBLE);
             pref.findViewById(R.id.entity_header).setBackground(null);
diff --git a/src/com/android/settings/notification/app/HeaderPreferenceController.java b/src/com/android/settings/notification/app/HeaderPreferenceController.java
index 7379d55..220e7b5 100644
--- a/src/com/android/settings/notification/app/HeaderPreferenceController.java
+++ b/src/com/android/settings/notification/app/HeaderPreferenceController.java
@@ -25,7 +25,6 @@
 import android.text.TextUtils;
 import android.view.View;
 
-import androidx.annotation.VisibleForTesting;
 import androidx.lifecycle.LifecycleObserver;
 import androidx.lifecycle.OnLifecycleEvent;
 import androidx.preference.Preference;
@@ -90,8 +89,7 @@
                     .setButtonActions(EntityHeaderController.ActionType.ACTION_NOTIF_PREFERENCE,
                             EntityHeaderController.ActionType.ACTION_NONE)
                     .setHasAppInfoLink(true)
-                    .setRecyclerView(mFragment.getListView(), mFragment.getSettingsLifecycle())
-                    .done(activity, mContext);
+                    .done(mContext);
             pref.findViewById(R.id.entity_header).setVisibility(View.VISIBLE);
             pref.findViewById(R.id.entity_header).setBackground(null);
         }
diff --git a/src/com/android/settings/notification/history/NotificationHistoryActivity.java b/src/com/android/settings/notification/history/NotificationHistoryActivity.java
index b71d295..4808773 100644
--- a/src/com/android/settings/notification/history/NotificationHistoryActivity.java
+++ b/src/com/android/settings/notification/history/NotificationHistoryActivity.java
@@ -50,6 +50,7 @@
 import android.widget.ImageView;
 import android.widget.TextView;
 
+import androidx.core.graphics.ColorUtils;
 import androidx.recyclerview.widget.LinearLayoutManager;
 import androidx.recyclerview.widget.RecyclerView;
 
@@ -176,7 +177,8 @@
                     com.android.internal.R.id.expand_button);
             int textColor = obtainThemeColor(android.R.attr.textColorPrimary);
             int backgroundColor = obtainThemeColor(android.R.attr.colorBackgroundFloating);
-            expand.setDefaultPillColor(backgroundColor);
+            int pillColor = ColorUtils.blendARGB(textColor, backgroundColor, 0.9f);
+            expand.setDefaultPillColor(pillColor);
             expand.setDefaultTextColor(textColor);
             expand.setExpanded(false);
             header.setStateDescription(container.getVisibility() == View.VISIBLE
diff --git a/src/com/android/settings/notification/zen/ZenAutomaticRuleHeaderPreferenceController.java b/src/com/android/settings/notification/zen/ZenAutomaticRuleHeaderPreferenceController.java
index a0c33df..95823fe 100644
--- a/src/com/android/settings/notification/zen/ZenAutomaticRuleHeaderPreferenceController.java
+++ b/src/com/android/settings/notification/zen/ZenAutomaticRuleHeaderPreferenceController.java
@@ -76,7 +76,7 @@
 
         mController.setIcon(getIcon())
                 .setLabel(mRule.getName())
-                .done(mFragment.getActivity(), false /* rebindActions */);
+                .done(false /* rebindActions */);
     }
 
     private Drawable getIcon() {
diff --git a/src/com/android/settings/password/BiometricFragment.java b/src/com/android/settings/password/BiometricFragment.java
index 4ad04a1..379ce80 100644
--- a/src/com/android/settings/password/BiometricFragment.java
+++ b/src/com/android/settings/password/BiometricFragment.java
@@ -126,10 +126,9 @@
         final Bundle bundle = getArguments();
         final PromptInfo promptInfo = bundle.getParcelable(KEY_PROMPT_INFO);
 
-        mBiometricPrompt = new BiometricPrompt.Builder(getContext())
+        BiometricPrompt.Builder promptBuilder = new BiometricPrompt.Builder(getContext())
                 .setTitle(promptInfo.getTitle())
                 .setUseDefaultTitle() // use default title if title is null/empty
-                .setUseDefaultSubtitle() // use default subtitle if subtitle is null/empty
                 .setDeviceCredentialAllowed(true)
                 .setSubtitle(promptInfo.getSubtitle())
                 .setDescription(promptInfo.getDescription())
@@ -140,9 +139,15 @@
                 .setConfirmationRequired(promptInfo.isConfirmationRequested())
                 .setDisallowBiometricsIfPolicyExists(
                         promptInfo.isDisallowBiometricsIfPolicyExists())
+                .setShowEmergencyCallButton(promptInfo.isShowEmergencyCallButton())
                 .setReceiveSystemEvents(true)
-                .setAllowBackgroundAuthentication(true)
-                .build();
+                .setAllowBackgroundAuthentication(true);
+
+        // Check if the default subtitle should be used if subtitle is null/empty
+        if (promptInfo.isUseDefaultSubtitle()) {
+            promptBuilder.setUseDefaultSubtitle();
+        }
+        mBiometricPrompt = promptBuilder.build();
     }
 
     @Override
diff --git a/src/com/android/settings/password/ChooseLockPassword.java b/src/com/android/settings/password/ChooseLockPassword.java
index c126a88..737d1df 100644
--- a/src/com/android/settings/password/ChooseLockPassword.java
+++ b/src/com/android/settings/password/ChooseLockPassword.java
@@ -524,7 +524,6 @@
             setupPasswordRequirementsView(headerLayout);
 
             mPasswordRestrictionView.setLayoutManager(new LinearLayoutManager(getActivity()));
-            mPasswordRestrictionView.setAccessibilityLiveRegion(ACCESSIBILITY_LIVE_REGION_POLITE);
             mPasswordEntry = view.findViewById(R.id.password_entry);
             mPasswordEntry.setOnEditorActionListener(this);
             mPasswordEntry.addTextChangedListener(this);
diff --git a/src/com/android/settings/password/ConfirmDeviceCredentialActivity.java b/src/com/android/settings/password/ConfirmDeviceCredentialActivity.java
index e4ebad7..70d4d7d 100644
--- a/src/com/android/settings/password/ConfirmDeviceCredentialActivity.java
+++ b/src/com/android/settings/password/ConfirmDeviceCredentialActivity.java
@@ -26,6 +26,7 @@
 import android.app.KeyguardManager;
 import android.app.RemoteLockscreenValidationSession;
 import android.app.admin.DevicePolicyManager;
+import android.app.admin.ManagedSubscriptionsPolicy;
 import android.app.trust.TrustManager;
 import android.content.ComponentName;
 import android.content.Context;
@@ -200,6 +201,13 @@
         promptInfo.setDescription(mDetails);
         promptInfo.setDisallowBiometricsIfPolicyExists(mCheckDevicePolicyManager);
 
+        final int policyType = mDevicePolicyManager.getManagedSubscriptionsPolicy().getPolicyType();
+
+        if (isEffectiveUserManagedProfile
+                && (policyType == ManagedSubscriptionsPolicy.TYPE_ALL_MANAGED_SUBSCRIPTIONS)) {
+            promptInfo.setShowEmergencyCallButton(true);
+        }
+
         final @LockPatternUtils.CredentialType int credentialType = Utils.getCredentialType(
                 mContext, effectiveUserId);
         if (mTitle == null) {
diff --git a/src/com/android/settings/password/PasswordRequirementAdapter.java b/src/com/android/settings/password/PasswordRequirementAdapter.java
index a4d349e..0d8f02e 100644
--- a/src/com/android/settings/password/PasswordRequirementAdapter.java
+++ b/src/com/android/settings/password/PasswordRequirementAdapter.java
@@ -16,6 +16,7 @@
 
 package com.android.settings.password;
 
+import android.annotation.NonNull;
 import android.content.Context;
 import android.view.LayoutInflater;
 import android.view.View;
@@ -64,6 +65,11 @@
     }
 
     @Override
+    public void onViewAttachedToWindow(@NonNull PasswordRequirementViewHolder holder) {
+        holder.mDescriptionText.announceForAccessibility(holder.mDescriptionText.getText());
+    }
+
+    @Override
     public void onBindViewHolder(PasswordRequirementViewHolder holder, int position) {
         final int fontSize = mContext.getResources().getDimensionPixelSize(
                 R.dimen.password_requirement_font_size);
diff --git a/src/com/android/settings/sim/SimListDialogFragment.java b/src/com/android/settings/sim/SimListDialogFragment.java
index 5b84d7b..2763211 100644
--- a/src/com/android/settings/sim/SimListDialogFragment.java
+++ b/src/com/android/settings/sim/SimListDialogFragment.java
@@ -56,7 +56,8 @@
 
     protected SelectSubscriptionAdapter mAdapter;
     @VisibleForTesting
-    List<SubscriptionInfo> mSubscriptions;
+    @NonNull
+    List<SubscriptionInfo> mSubscriptions = new ArrayList<>();
 
     public static SimListDialogFragment newInstance(int dialogType, int titleResId,
             boolean includeAskEveryTime, boolean isCancelItemShowed) {
@@ -71,8 +72,6 @@
     @NonNull
     @Override
     public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
-        mSubscriptions = new ArrayList<>();
-
         final AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
         View titleView = LayoutInflater.from(getContext()).inflate(
                 R.layout.sim_confirm_dialog_title_multiple_enabled_profiles_supported, null);
diff --git a/src/com/android/settings/widget/EntityHeaderController.java b/src/com/android/settings/widget/EntityHeaderController.java
index bcd3f4b..376bd22 100644
--- a/src/com/android/settings/widget/EntityHeaderController.java
+++ b/src/com/android/settings/widget/EntityHeaderController.java
@@ -38,13 +38,11 @@
 import androidx.annotation.IntDef;
 import androidx.annotation.VisibleForTesting;
 import androidx.fragment.app.Fragment;
-import androidx.recyclerview.widget.RecyclerView;
 
 import com.android.settings.R;
 import com.android.settings.Utils;
 import com.android.settings.overlay.FeatureFactory;
 import com.android.settingslib.applications.ApplicationsState;
-import com.android.settingslib.core.lifecycle.Lifecycle;
 import com.android.settingslib.widget.LayoutPreference;
 
 import java.lang.annotation.Retention;
@@ -67,12 +65,9 @@
     private static final String TAG = "AppDetailFeature";
 
     private final Context mAppContext;
-    private final Activity mActivity;
     private final Fragment mFragment;
     private final int mMetricsCategory;
     private final View mHeader;
-    private Lifecycle mLifecycle;
-    private RecyclerView mRecyclerView;
     private Drawable mIcon;
     private int mPrefOrder = -1000;
     private String mIconContentDescription;
@@ -107,7 +102,6 @@
     }
 
     private EntityHeaderController(Activity activity, Fragment fragment, View header) {
-        mActivity = activity;
         mAppContext = activity.getApplicationContext();
         mFragment = fragment;
         mMetricsCategory = FeatureFactory.getFeatureFactory().getMetricsFeatureProvider()
@@ -121,12 +115,6 @@
         }
     }
 
-    public EntityHeaderController setRecyclerView(RecyclerView recyclerView, Lifecycle lifecycle) {
-        mRecyclerView = recyclerView;
-        mLifecycle = lifecycle;
-        return this;
-    }
-
     /**
      * Set the icon in the header. Callers should also consider calling setIconContentDescription
      * to provide a description of this icon for accessibility purposes.
@@ -181,13 +169,6 @@
         return this;
     }
 
-    public EntityHeaderController setSecondSummary(PackageInfo packageInfo) {
-        if (packageInfo != null) {
-            mSummary = packageInfo.versionName;
-        }
-        return this;
-    }
-
     public EntityHeaderController setHasAppInfoLink(boolean hasAppInfoLink) {
         mHasAppInfoLink = hasAppInfoLink;
         return this;
@@ -234,8 +215,8 @@
     /**
      * Done mutating entity header, rebinds everything and return a new {@link LayoutPreference}.
      */
-    public LayoutPreference done(Activity activity, Context uiContext) {
-        final LayoutPreference pref = new LayoutPreference(uiContext, done(activity));
+    public LayoutPreference done(Context uiContext) {
+        final LayoutPreference pref = new LayoutPreference(uiContext, done());
         // Makes sure it's the first preference onscreen.
         pref.setOrder(mPrefOrder);
         pref.setSelectable(false);
@@ -247,7 +228,7 @@
     /**
      * Done mutating entity header, rebinds everything (optionally skip rebinding buttons).
      */
-    public View done(Activity activity, boolean rebindActions) {
+    public View done(boolean rebindActions) {
         ImageView iconView = mHeader.findViewById(R.id.entity_header_icon);
         if (iconView != null) {
             iconView.setImageDrawable(mIcon);
@@ -303,8 +284,8 @@
      * Done mutating entity header, rebinds everything.
      */
     @VisibleForTesting
-    View done(Activity activity) {
-        return done(activity, true /* rebindActions */);
+    View done() {
+        return done(true /* rebindActions */);
     }
 
     private void bindButton(ImageButton button, @ActionType int action) {
diff --git a/src/com/android/settings/widget/RadioButtonPickerFragment.java b/src/com/android/settings/widget/RadioButtonPickerFragment.java
index 0b59714..9450bb9 100644
--- a/src/com/android/settings/widget/RadioButtonPickerFragment.java
+++ b/src/com/android/settings/widget/RadioButtonPickerFragment.java
@@ -33,8 +33,8 @@
 import androidx.preference.PreferenceScreen;
 
 import com.android.settings.R;
+import com.android.settings.SettingsPreferenceFragment;
 import com.android.settings.Utils;
-import com.android.settings.core.InstrumentedPreferenceFragment;
 import com.android.settings.core.PreferenceXmlParserUtils;
 import com.android.settings.core.PreferenceXmlParserUtils.MetadataFlag;
 import com.android.settingslib.widget.CandidateInfo;
@@ -46,7 +46,10 @@
 import java.util.List;
 import java.util.Map;
 
-public abstract class RadioButtonPickerFragment extends InstrumentedPreferenceFragment implements
+/**
+ * A fragment to handle general radio button picker
+ */
+public abstract class RadioButtonPickerFragment extends SettingsPreferenceFragment implements
         SelectorWithWidgetPreference.OnClickListener {
 
     @VisibleForTesting
diff --git a/src/com/android/settings/widget/RestrictedButton.java b/src/com/android/settings/widget/RestrictedButton.java
new file mode 100644
index 0000000..778ea34
--- /dev/null
+++ b/src/com/android/settings/widget/RestrictedButton.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2023 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.widget;
+
+import android.content.Context;
+import android.os.UserHandle;
+import android.util.AttributeSet;
+import android.widget.Button;
+
+import com.android.settingslib.RestrictedLockUtils;
+import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
+import com.android.settingslib.RestrictedLockUtilsInternal;
+
+/**
+ * A preference with a plus button on the side representing an "add" action. The plus button will
+ * only be visible when a non-null click listener is registered.
+ */
+public class RestrictedButton extends Button {
+
+    private UserHandle mUserHandle;
+    private String mUserRestriction;
+
+    public RestrictedButton(Context context) {
+        super(context);
+    }
+
+    public RestrictedButton(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    public RestrictedButton(Context context, AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+    }
+
+    public RestrictedButton(Context context, AttributeSet attrs, int defStyleAttr,
+            int defStyleRes) {
+        super(context, attrs, defStyleAttr, defStyleRes);
+    }
+
+    @Override
+    public boolean performClick() {
+        EnforcedAdmin admin = getEnforcedAdmin();
+        if (admin != null) {
+            RestrictedLockUtils.sendShowAdminSupportDetailsIntent(mContext, admin);
+            return false;
+        }
+        return super.performClick();
+    }
+
+    /** Initialize the button with {@link UserHandle} and a restriction */
+    public void init(UserHandle userHandle, String restriction) {
+        setAllowClickWhenDisabled(true);
+        mUserHandle = userHandle;
+        mUserRestriction = restriction;
+    }
+
+    /** Update the restriction state */
+    public void updateState() {
+        setEnabled(getEnforcedAdmin() == null);
+    }
+
+    private EnforcedAdmin getEnforcedAdmin() {
+        if (mUserHandle != null) {
+            EnforcedAdmin admin = RestrictedLockUtilsInternal.checkIfRestrictionEnforced(
+                    mContext, mUserRestriction, mUserHandle.getIdentifier());
+            if (admin != null) {
+                return admin;
+            }
+        }
+        return null;
+    }
+}
diff --git a/src/com/android/settings/wifi/details2/WifiDetailPreferenceController2.java b/src/com/android/settings/wifi/details2/WifiDetailPreferenceController2.java
index 2e1bc31..d54c0d0 100644
--- a/src/com/android/settings/wifi/details2/WifiDetailPreferenceController2.java
+++ b/src/com/android/settings/wifi/details2/WifiDetailPreferenceController2.java
@@ -434,8 +434,7 @@
             mDataUsageSummaryPref.setVisible(true);
             mSummaryHeaderController =
                     new WifiDataUsageSummaryPreferenceController(mFragment.getActivity(),
-                            mLifecycle, (PreferenceFragmentCompat) mFragment,
-                            mWifiEntry.getWifiConfiguration().getAllNetworkKeys());
+                            mFragment, mWifiEntry.getWifiConfiguration().getAllNetworkKeys());
             return;
         }
 
@@ -489,8 +488,7 @@
             mEntityHeaderController
                     .setSummary(mWifiEntry.getSummary())
                     .setSecondSummary(getExpiryTimeSummary())
-                    .setRecyclerView(mFragment.getListView(), mLifecycle)
-                    .done(mFragment.getActivity(), true /* rebind */);
+                    .done(true /* rebind */);
         }
     }
 
@@ -583,9 +581,7 @@
         Drawable wifiIcon = mIconInjector.getIcon(mShowX, mRssiSignalLevel);
 
         if (mEntityHeaderController != null) {
-            mEntityHeaderController
-                    .setIcon(redrawIconForHeader(wifiIcon)).done(mFragment.getActivity(),
-                            true /* rebind */);
+            mEntityHeaderController.setIcon(redrawIconForHeader(wifiIcon)).done(true /* rebind */);
         }
 
         Drawable wifiIconDark = wifiIcon.getConstantState().newDrawable().mutate();
diff --git a/src/com/android/settings/wifi/dpp/WifiDppUtils.java b/src/com/android/settings/wifi/dpp/WifiDppUtils.java
index c336c62..83a1571 100644
--- a/src/com/android/settings/wifi/dpp/WifiDppUtils.java
+++ b/src/com/android/settings/wifi/dpp/WifiDppUtils.java
@@ -396,8 +396,7 @@
             final int userId = UserHandle.myUserId();
 
             final BiometricPrompt.Builder builder = new BiometricPrompt.Builder(context)
-                    .setTitle(context.getText(R.string.wifi_dpp_lockscreen_title))
-                    .setUseDefaultSubtitle();
+                    .setTitle(context.getText(R.string.wifi_dpp_lockscreen_title));
 
             if (keyguardManager.isDeviceSecure()) {
                 builder.setDeviceCredentialAllowed(true);
diff --git a/src/com/android/settings/wifi/factory/WifiFeatureProvider.java b/src/com/android/settings/wifi/factory/WifiFeatureProvider.java
index c61cf51..3f0d62f 100644
--- a/src/com/android/settings/wifi/factory/WifiFeatureProvider.java
+++ b/src/com/android/settings/wifi/factory/WifiFeatureProvider.java
@@ -26,6 +26,7 @@
 import androidx.lifecycle.ViewModelProvider;
 import androidx.lifecycle.ViewModelStoreOwner;
 
+import com.android.settings.wifi.repository.SharedConnectivityRepository;
 import com.android.settings.wifi.repository.WifiHotspotRepository;
 import com.android.settings.wifi.tether.WifiHotspotSecurityViewModel;
 import com.android.settings.wifi.tether.WifiHotspotSpeedViewModel;
@@ -44,6 +45,7 @@
     private TetheringManager mTetheringManager;
     private WifiVerboseLogging mWifiVerboseLogging;
     private WifiHotspotRepository mWifiHotspotRepository;
+    private SharedConnectivityRepository mSharedConnectivityRepository;
 
     public WifiFeatureProvider(@NonNull Context appContext) {
         mAppContext = appContext;
@@ -93,6 +95,17 @@
     }
 
     /**
+     * Gets SharedConnectivityRepository
+     */
+    public SharedConnectivityRepository getSharedConnectivityRepository() {
+        if (mSharedConnectivityRepository == null) {
+            mSharedConnectivityRepository = new SharedConnectivityRepository(mAppContext);
+            verboseLog(TAG, "getSharedConnectivityRepository():" + mSharedConnectivityRepository);
+        }
+        return mSharedConnectivityRepository;
+    }
+
+    /**
      * Gets WifiTetherViewModel
      */
     public WifiTetherViewModel getWifiTetherViewModel(@NotNull ViewModelStoreOwner owner) {
diff --git a/src/com/android/settings/wifi/repository/SharedConnectivityRepository.java b/src/com/android/settings/wifi/repository/SharedConnectivityRepository.java
new file mode 100644
index 0000000..fa34b00
--- /dev/null
+++ b/src/com/android/settings/wifi/repository/SharedConnectivityRepository.java
@@ -0,0 +1,184 @@
+/*
+ * Copyright (C) 2023 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.wifi.repository;
+
+import android.app.PendingIntent;
+import android.content.Context;
+import android.net.wifi.sharedconnectivity.app.HotspotNetwork;
+import android.net.wifi.sharedconnectivity.app.HotspotNetworkConnectionStatus;
+import android.net.wifi.sharedconnectivity.app.KnownNetwork;
+import android.net.wifi.sharedconnectivity.app.KnownNetworkConnectionStatus;
+import android.net.wifi.sharedconnectivity.app.SharedConnectivityClientCallback;
+import android.net.wifi.sharedconnectivity.app.SharedConnectivityManager;
+import android.net.wifi.sharedconnectivity.app.SharedConnectivitySettingsState;
+import android.os.HandlerThread;
+import android.provider.DeviceConfig;
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.VisibleForTesting;
+import androidx.annotation.WorkerThread;
+import androidx.lifecycle.LiveData;
+import androidx.lifecycle.MutableLiveData;
+
+import com.android.settings.overlay.FeatureFactory;
+
+import java.util.List;
+import java.util.concurrent.Executor;
+
+/**
+ * Shared Connectivity Repository for {@link SharedConnectivityManager}
+ */
+public class SharedConnectivityRepository {
+    private static final String TAG = "SharedConnectivityRepository";
+    private static final String DEVICE_CONFIG_NAMESPACE = "wifi";
+    private static final String DEVICE_CONFIG_KEY = "shared_connectivity_enabled";
+
+    private Context mAppContext;
+    private SharedConnectivityManager mManager;
+    private ClientCallback mClientCallback = new ClientCallback();
+    private HandlerThread mWorkerThread = new HandlerThread(TAG);
+    private Executor mWorkerExecutor = cmd -> mWorkerThread.getThreadHandler().post(cmd);
+    private Runnable mLaunchSettingsRunnable = () -> handleLaunchSettings();
+    @VisibleForTesting
+    MutableLiveData<SharedConnectivitySettingsState> mSettingsState = new MutableLiveData<>();
+
+    public SharedConnectivityRepository(@NonNull Context appContext) {
+        this(appContext,
+                DeviceConfig.getBoolean(DEVICE_CONFIG_NAMESPACE, DEVICE_CONFIG_KEY, false));
+    }
+
+    @VisibleForTesting
+    SharedConnectivityRepository(@NonNull Context appContext, boolean isConfigEnabled) {
+        mAppContext = appContext;
+        if (!isConfigEnabled) {
+            return;
+        }
+        mManager = mAppContext.getSystemService(SharedConnectivityManager.class);
+        if (mManager == null) {
+            Log.w(TAG, "Failed to get SharedConnectivityManager");
+            return;
+        }
+        mWorkerThread.start();
+        mManager.registerCallback(mWorkerExecutor, mClientCallback);
+    }
+
+    /**
+     * Return whether Wi-Fi Shared Connectivity service is available or not.
+     *
+     * @return {@code true} if Wi-Fi Shared Connectivity service is available
+     */
+    public boolean isServiceAvailable() {
+        return mManager != null;
+    }
+
+    /**
+     * Gets SharedConnectivitySettingsState LiveData
+     */
+    public LiveData<SharedConnectivitySettingsState> getSettingsState() {
+        return mSettingsState;
+    }
+
+    /**
+     * Launch Instant Hotspot Settings
+     */
+    public void launchSettings() {
+        mWorkerExecutor.execute(mLaunchSettingsRunnable);
+    }
+
+    @WorkerThread
+    @VisibleForTesting
+    void handleLaunchSettings() {
+        if (mManager == null) {
+            return;
+        }
+        SharedConnectivitySettingsState state = mManager.getSettingsState();
+        log("handleLaunchSettings(), state:" + state);
+        if (state == null) {
+            Log.e(TAG, "No SettingsState to launch Instant Hotspot settings");
+            return;
+        }
+        PendingIntent intent = state.getInstantTetherSettingsPendingIntent();
+        if (intent == null) {
+            Log.e(TAG, "No PendingIntent to launch Instant Hotspot settings");
+            return;
+        }
+        sendSettingsIntent(intent);
+    }
+
+    @WorkerThread
+    @VisibleForTesting
+    void sendSettingsIntent(@NonNull PendingIntent intent) {
+        try {
+            log("sendSettingsIntent(), sent intent:" + intent);
+            intent.send();
+        } catch (PendingIntent.CanceledException e) {
+            Log.e(TAG, "Failed to launch Instant Hotspot settings", e);
+        }
+    }
+
+    @WorkerThread
+    class ClientCallback implements SharedConnectivityClientCallback {
+
+        @Override
+        public void onHotspotNetworkConnectionStatusChanged(HotspotNetworkConnectionStatus status) {
+            log("onHotspotNetworkConnectionStatusChanged(), status:" + status);
+        }
+
+        @Override
+        public void onHotspotNetworksUpdated(List<HotspotNetwork> networks) {
+            log("onHotspotNetworksUpdated(), networks:" + networks);
+        }
+
+        @Override
+        public void onKnownNetworkConnectionStatusChanged(KnownNetworkConnectionStatus status) {
+            log("onKnownNetworkConnectionStatusChanged(), status:" + status);
+        }
+
+        @Override
+        public void onKnownNetworksUpdated(List<KnownNetwork> networks) {
+            log("onKnownNetworksUpdated(), networks:" + networks);
+        }
+
+        @Override
+        public void onRegisterCallbackFailed(Exception e) {
+            Log.e(TAG, "onRegisterCallbackFailed(), e:" + e);
+        }
+
+        @Override
+        public void onServiceConnected() {
+            SharedConnectivitySettingsState state = mManager.getSettingsState();
+            Log.d(TAG, "onServiceConnected(), Manager#getSettingsState:" + state);
+            mSettingsState.postValue(state);
+        }
+
+        @Override
+        public void onServiceDisconnected() {
+            log("onServiceDisconnected()");
+        }
+
+        @Override
+        public void onSharedConnectivitySettingsChanged(SharedConnectivitySettingsState state) {
+            Log.d(TAG, "onSharedConnectivitySettingsChanged(), state:" + state);
+            mSettingsState.postValue(state);
+        }
+    }
+
+    private void log(String msg) {
+        FeatureFactory.getFeatureFactory().getWifiFeatureProvider().verboseLog(TAG, msg);
+    }
+}
diff --git a/src/com/android/settings/wifi/tether/WifiTetherSettings.java b/src/com/android/settings/wifi/tether/WifiTetherSettings.java
index 85812a5..df31f49 100644
--- a/src/com/android/settings/wifi/tether/WifiTetherSettings.java
+++ b/src/com/android/settings/wifi/tether/WifiTetherSettings.java
@@ -76,6 +76,8 @@
     static final String KEY_WIFI_HOTSPOT_SECURITY = "wifi_hotspot_security";
     @VisibleForTesting
     static final String KEY_WIFI_HOTSPOT_SPEED = "wifi_hotspot_speed";
+    @VisibleForTesting
+    static final String KEY_INSTANT_HOTSPOT = "wifi_hotspot_instant";
 
     @VisibleForTesting
     SettingsMainSwitchBar mMainSwitchBar;
@@ -103,6 +105,8 @@
     Preference mWifiHotspotSecurity;
     @VisibleForTesting
     Preference mWifiHotspotSpeed;
+    @VisibleForTesting
+    Preference mInstantHotspot;
 
     static {
         TETHER_STATE_CHANGE_FILTER = new IntentFilter(WIFI_AP_STATE_CHANGED_ACTION);
@@ -148,6 +152,7 @@
                 .getWifiTetherViewModel(this);
         if (mWifiTetherViewModel != null) {
             setupSpeedFeature(mWifiTetherViewModel.isSpeedFeatureAvailable());
+            setupInstantHotspot(mWifiTetherViewModel.isInstantHotspotFeatureAvailable());
             mWifiTetherViewModel.getRestarting().observe(this, this::onRestartingChanged);
         }
     }
@@ -167,6 +172,24 @@
         }
     }
 
+    @VisibleForTesting
+    void setupInstantHotspot(boolean isFeatureAvailable) {
+        if (!isFeatureAvailable) {
+            return;
+        }
+        mInstantHotspot = findPreference(KEY_INSTANT_HOTSPOT);
+        if (mInstantHotspot == null) {
+            Log.e(TAG, "Failed to find Instant Hotspot preference:" + KEY_INSTANT_HOTSPOT);
+            return;
+        }
+        mWifiTetherViewModel.getInstantHotspotSummary()
+                .observe(this, this::onInstantHotspotChanged);
+        mInstantHotspot.setOnPreferenceClickListener(p -> {
+            mWifiTetherViewModel.launchInstantHotspotSettings();
+            return true;
+        });
+    }
+
     @Override
     public void onAttach(Context context) {
         super.onAttach(context);
@@ -280,6 +303,16 @@
     }
 
     @VisibleForTesting
+    void onInstantHotspotChanged(String summary) {
+        if (summary == null) {
+            mInstantHotspot.setVisible(false);
+            return;
+        }
+        mInstantHotspot.setVisible(true);
+        mInstantHotspot.setSummary(summary);
+    }
+
+    @VisibleForTesting
     SoftApConfiguration buildNewConfig() {
         SoftApConfiguration currentConfig = mWifiTetherViewModel.getSoftApConfiguration();
         SoftApConfiguration.Builder configBuilder = new SoftApConfiguration.Builder(currentConfig);
diff --git a/src/com/android/settings/wifi/tether/WifiTetherViewModel.java b/src/com/android/settings/wifi/tether/WifiTetherViewModel.java
index 4cde1be..ea09482 100644
--- a/src/com/android/settings/wifi/tether/WifiTetherViewModel.java
+++ b/src/com/android/settings/wifi/tether/WifiTetherViewModel.java
@@ -28,7 +28,9 @@
 
 import android.app.Application;
 import android.net.wifi.SoftApConfiguration;
+import android.net.wifi.sharedconnectivity.app.SharedConnectivitySettingsState;
 
+import androidx.annotation.VisibleForTesting;
 import androidx.lifecycle.AndroidViewModel;
 import androidx.lifecycle.LiveData;
 import androidx.lifecycle.MutableLiveData;
@@ -36,6 +38,8 @@
 
 import com.android.settings.R;
 import com.android.settings.overlay.FeatureFactory;
+import com.android.settings.wifi.factory.WifiFeatureProvider;
+import com.android.settings.wifi.repository.SharedConnectivityRepository;
 import com.android.settings.wifi.repository.WifiHotspotRepository;
 
 import org.jetbrains.annotations.NotNull;
@@ -48,6 +52,8 @@
  */
 public class WifiTetherViewModel extends AndroidViewModel {
     private static final String TAG = "WifiTetherViewModel";
+    static final int RES_INSTANT_HOTSPOT_SUMMARY_ON = R.string.wifi_hotspot_instant_summary_on;
+    static final int RES_INSTANT_HOTSPOT_SUMMARY_OFF = R.string.wifi_hotspot_instant_summary_off;
 
     static Map<Integer, Integer> sSecuritySummaryResMap = new HashMap<>();
 
@@ -78,10 +84,23 @@
     protected final Observer<Integer> mSecurityTypeObserver = st -> onSecurityTypeChanged(st);
     protected final Observer<Integer> mSpeedTypeObserver = st -> onSpeedTypeChanged(st);
 
+    private SharedConnectivityRepository mSharedConnectivityRepository;
+    @VisibleForTesting
+    MutableLiveData<String> mInstantHotspotSummary = new MutableLiveData<>();
+    @VisibleForTesting
+    Observer<SharedConnectivitySettingsState> mInstantHotspotStateObserver =
+            state -> onInstantHotspotStateChanged(state);
+
     public WifiTetherViewModel(@NotNull Application application) {
         super(application);
-        mWifiHotspotRepository = FeatureFactory.getFeatureFactory().getWifiFeatureProvider()
-                .getWifiHotspotRepository();
+        WifiFeatureProvider featureProvider = FeatureFactory.getFeatureFactory()
+                .getWifiFeatureProvider();
+        mWifiHotspotRepository = featureProvider.getWifiHotspotRepository();
+        mSharedConnectivityRepository = featureProvider.getSharedConnectivityRepository();
+        if (mSharedConnectivityRepository.isServiceAvailable()) {
+            mSharedConnectivityRepository.getSettingsState()
+                    .observeForever(mInstantHotspotStateObserver);
+        }
     }
 
     @Override
@@ -92,6 +111,10 @@
         if (mSpeedSummary != null) {
             mWifiHotspotRepository.getSpeedType().removeObserver(mSpeedTypeObserver);
         }
+        if (mSharedConnectivityRepository.isServiceAvailable()) {
+            mSharedConnectivityRepository.getSettingsState()
+                    .removeObserver(mInstantHotspotStateObserver);
+        }
     }
 
     /**
@@ -172,4 +195,46 @@
     public LiveData<Boolean> getRestarting() {
         return mWifiHotspotRepository.getRestarting();
     }
+
+    /**
+     * Return whether Wi-Fi Instant Hotspot feature is available or not.
+     *
+     * @return {@code true} if Wi-Fi Instant Hotspot feature is available
+     */
+    public boolean isInstantHotspotFeatureAvailable() {
+        return mSharedConnectivityRepository.isServiceAvailable();
+    }
+
+    /**
+     * Gets InstantHotspotSummary
+     */
+    public LiveData<String> getInstantHotspotSummary() {
+        return mInstantHotspotSummary;
+    }
+
+    @VisibleForTesting
+    void onInstantHotspotStateChanged(SharedConnectivitySettingsState state) {
+        log("onInstantHotspotStateChanged(), state:" + state);
+        if (state == null) {
+            mInstantHotspotSummary.setValue(null);
+            return;
+        }
+        mInstantHotspotSummary.setValue(getInstantHotspotSummary(state.isInstantTetherEnabled()));
+    }
+
+    private String getInstantHotspotSummary(boolean enabled) {
+        return getApplication().getString(
+                enabled ? RES_INSTANT_HOTSPOT_SUMMARY_ON : RES_INSTANT_HOTSPOT_SUMMARY_OFF);
+    }
+
+    /**
+     * Launch Instant Hotspot Settings
+     */
+    public void launchInstantHotspotSettings() {
+        mSharedConnectivityRepository.launchSettings();
+    }
+
+    private void log(String msg) {
+        FeatureFactory.getFeatureFactory().getWifiFeatureProvider().verboseLog(TAG, msg);
+    }
 }
diff --git a/tests/robotests/Android.bp b/tests/robotests/Android.bp
index 83ab128..f620348 100644
--- a/tests/robotests/Android.bp
+++ b/tests/robotests/Android.bp
@@ -24,6 +24,7 @@
         "Settings-core",
         "androidx.fragment_fragment-testing",
         "frameworks-base-testutils",
+        "androidx.fragment_fragment",
     ],
 
     aaptflags: ["--extra-packages com.android.settings"],
@@ -48,6 +49,8 @@
     ],
 
     static_libs: [
+        "Robolectric_shadows_androidx_fragment_upstream",
+        "Settings_robolectric_meta_service_file",
         "SettingsLib-robo-testutils",
         "Settings-robo-testutils",
         "androidx.test.core",
@@ -75,15 +78,16 @@
         "SettingsLib",
         "SettingsLib-search",
     ],
+
+    upstream: true,
 }
 
 java_library {
     name: "Settings-robo-testutils",
     srcs: ["testutils/**/*.java"],
-
     libs: [
+        "Robolectric_all-target_upstream",
         "Settings-core",
-        "Robolectric_all-target",
         "mockito-robolectric-prebuilt",
         "truth-prebuilt",
     ],
diff --git a/tests/robotests/config/robolectric.properties b/tests/robotests/config/robolectric.properties
index ee805c4..3c8b258 100644
--- a/tests/robotests/config/robolectric.properties
+++ b/tests/robotests/config/robolectric.properties
@@ -2,3 +2,4 @@
 shadows=\
    com.android.settings.testutils.shadow.ShadowThreadUtils \
    com.android.settings.network.ShadowServiceManagerExtend
+instrumentedPackages=androidx.preference
\ No newline at end of file
diff --git a/tests/robotests/src/com/android/settings/MainClearConfirmTest.java b/tests/robotests/src/com/android/settings/MainClearConfirmTest.java
index 41aec0b..43fe9ca 100644
--- a/tests/robotests/src/com/android/settings/MainClearConfirmTest.java
+++ b/tests/robotests/src/com/android/settings/MainClearConfirmTest.java
@@ -40,10 +40,14 @@
 import org.mockito.MockitoAnnotations;
 import org.robolectric.Robolectric;
 import org.robolectric.RobolectricTestRunner;
+import org.robolectric.annotation.Config;
 
 import java.util.ArrayList;
 
 @RunWith(RobolectricTestRunner.class)
+@Config(shadows = {
+        com.android.settings.testutils.shadow.ShadowFragment.class,
+})
 public class MainClearConfirmTest {
 
     private FragmentActivity mActivity;
diff --git a/tests/robotests/src/com/android/settings/MainClearTest.java b/tests/robotests/src/com/android/settings/MainClearTest.java
index d1e9408..d782e6d 100644
--- a/tests/robotests/src/com/android/settings/MainClearTest.java
+++ b/tests/robotests/src/com/android/settings/MainClearTest.java
@@ -50,6 +50,7 @@
 
 import androidx.fragment.app.FragmentActivity;
 
+import com.android.settings.testutils.shadow.ShadowUserManager;
 import com.android.settings.testutils.shadow.ShadowUtils;
 import com.android.settings.utils.ActivityControllerWrapper;
 import com.android.settingslib.development.DevelopmentSettingsEnabler;
@@ -66,11 +67,15 @@
 import org.robolectric.RobolectricTestRunner;
 import org.robolectric.Shadows;
 import org.robolectric.annotation.Config;
+import org.robolectric.shadow.api.Shadow;
 import org.robolectric.shadows.ShadowActivity;
-import org.robolectric.shadows.ShadowUserManager;
 
 @RunWith(RobolectricTestRunner.class)
-@Config(shadows = ShadowUtils.class)
+@Config(shadows = {
+        ShadowUtils.class,
+        ShadowUserManager.class,
+        com.android.settings.testutils.shadow.ShadowFragment.class,
+})
 public class MainClearTest {
 
     private static final String TEST_ACCOUNT_TYPE = "android.test.account.type";
@@ -112,7 +117,7 @@
                 Robolectric.buildActivity(FragmentActivity.class)).get());
         mShadowActivity = Shadows.shadowOf(mActivity);
         UserManager userManager = mActivity.getSystemService(UserManager.class);
-        mShadowUserManager = Shadows.shadowOf(userManager);
+        mShadowUserManager = Shadow.extract(userManager);
         mShadowUserManager.setIsAdminUser(true);
         mContentView = LayoutInflater.from(mActivity).inflate(R.layout.main_clear, null);
 
diff --git a/tests/robotests/src/com/android/settings/ResetNetworkConfirmTest.java b/tests/robotests/src/com/android/settings/ResetNetworkConfirmTest.java
index 3b51ca8..34012d3 100644
--- a/tests/robotests/src/com/android/settings/ResetNetworkConfirmTest.java
+++ b/tests/robotests/src/com/android/settings/ResetNetworkConfirmTest.java
@@ -38,8 +38,10 @@
 import org.robolectric.Robolectric;
 import org.robolectric.RobolectricTestRunner;
 import org.robolectric.annotation.Config;
+import org.robolectric.annotation.LooperMode;
 
 @RunWith(RobolectricTestRunner.class)
+@LooperMode(LooperMode.Mode.LEGACY)
 @Config(shadows = {ShadowRecoverySystem.class, ShadowBluetoothAdapter.class})
 public class ResetNetworkConfirmTest {
 
diff --git a/tests/robotests/src/com/android/settings/SettingsPreferenceFragmentTest.java b/tests/robotests/src/com/android/settings/SettingsPreferenceFragmentTest.java
index 6489311..627d52f 100644
--- a/tests/robotests/src/com/android/settings/SettingsPreferenceFragmentTest.java
+++ b/tests/robotests/src/com/android/settings/SettingsPreferenceFragmentTest.java
@@ -40,7 +40,6 @@
 import androidx.preference.PreferenceScreen;
 
 import com.android.settings.testutils.FakeFeatureFactory;
-import com.android.settings.testutils.shadow.ShadowFragment;
 import com.android.settings.widget.WorkOnlyCategory;
 
 import org.junit.After;
@@ -55,6 +54,9 @@
 import org.robolectric.util.ReflectionHelpers;
 
 @RunWith(RobolectricTestRunner.class)
+@Config(shadows = {
+        com.android.settings.testutils.shadow.ShadowFragment.class,
+})
 public class SettingsPreferenceFragmentTest {
 
     private static final int ITEM_COUNT = 5;
@@ -166,7 +168,6 @@
     }
 
     @Test
-    @Config(shadows = ShadowFragment.class)
     public void onCreate_hasExtraFragmentKey_shouldExpandPreferences() {
         doReturn(mContext.getTheme()).when(mActivity).getTheme();
         doReturn(mContext.getResources()).when(mFragment).getResources();
@@ -181,7 +182,6 @@
     }
 
     @Test
-    @Config(shadows = ShadowFragment.class)
     public void onCreate_noPreferenceScreen_shouldNotCrash() {
         doReturn(mContext.getTheme()).when(mActivity).getTheme();
         doReturn(mContext.getResources()).when(mFragment).getResources();
diff --git a/tests/robotests/src/com/android/settings/UtilsTest.java b/tests/robotests/src/com/android/settings/UtilsTest.java
index 733a5e6..0c555da 100644
--- a/tests/robotests/src/com/android/settings/UtilsTest.java
+++ b/tests/robotests/src/com/android/settings/UtilsTest.java
@@ -16,15 +16,10 @@
 
 package com.android.settings;
 
-import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROFILE_CONFIRM_PASSWORD;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROFILE_CONFIRM_PATTERN;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROFILE_CONFIRM_PIN;
-
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertThrows;
-import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.ArgumentMatchers.eq;
@@ -399,45 +394,33 @@
     }
 
     @Test
-    public void getConfirmCredentialStringForUser_workPin_shouldReturnCorrectString() {
+    public void getConfirmCredentialStringForUser_workPin_shouldReturnNull() {
         setUpForConfirmCredentialString(true /* isEffectiveUserManagedProfile */);
 
-        when(mDevicePolicyResourcesManager
-                .getString(eq(WORK_PROFILE_CONFIRM_PIN), any()))
-                .thenReturn("WORK PIN");
-
         String confirmCredentialString = Utils.getConfirmCredentialStringForUser(mContext,
                 USER_ID, LockPatternUtils.CREDENTIAL_TYPE_PIN);
 
-        assertThat(confirmCredentialString).isEqualTo("WORK PIN");
+        assertNull(confirmCredentialString);
     }
 
     @Test
-    public void getConfirmCredentialStringForUser_workPattern_shouldReturnCorrectString() {
+    public void getConfirmCredentialStringForUser_workPattern_shouldReturnNull() {
         setUpForConfirmCredentialString(true /* isEffectiveUserManagedProfile */);
 
-        when(mDevicePolicyResourcesManager
-                .getString(eq(WORK_PROFILE_CONFIRM_PATTERN), any()))
-                .thenReturn("WORK PATTERN");
-
         String confirmCredentialString = Utils.getConfirmCredentialStringForUser(mContext,
                 USER_ID, LockPatternUtils.CREDENTIAL_TYPE_PATTERN);
 
-        assertThat(confirmCredentialString).isEqualTo("WORK PATTERN");
+        assertNull(confirmCredentialString);
     }
 
     @Test
-    public void getConfirmCredentialStringForUser_workPassword_shouldReturnCorrectString() {
+    public void getConfirmCredentialStringForUser_workPassword_shouldReturnNull() {
         setUpForConfirmCredentialString(true /* isEffectiveUserManagedProfile */);
 
-        when(mDevicePolicyResourcesManager
-                .getString(eq(WORK_PROFILE_CONFIRM_PASSWORD), any()))
-                .thenReturn("WORK PASSWORD");
-
         String confirmCredentialString = Utils.getConfirmCredentialStringForUser(mContext,
                 USER_ID, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD);
 
-        assertThat(confirmCredentialString).isEqualTo("WORK PASSWORD");
+        assertNull(confirmCredentialString);
     }
 
     @Test
@@ -454,7 +437,5 @@
         when(mContext.getSystemService(Context.USER_SERVICE)).thenReturn(mMockUserManager);
         when(mMockUserManager.getCredentialOwnerProfile(USER_ID)).thenReturn(USER_ID);
         when(mMockUserManager.isManagedProfile(USER_ID)).thenReturn(isEffectiveUserManagedProfile);
-        when(mContext.getSystemService(DevicePolicyManager.class)).thenReturn(mDevicePolicyManager);
-        when(mDevicePolicyManager.getResources()).thenReturn(mDevicePolicyResourcesManager);
     }
 }
diff --git a/tests/robotests/src/com/android/settings/accessibility/AccessibilityDetailsSettingsFragmentTest.java b/tests/robotests/src/com/android/settings/accessibility/AccessibilityDetailsSettingsFragmentTest.java
index 2f6ab9f..de8ae60 100644
--- a/tests/robotests/src/com/android/settings/accessibility/AccessibilityDetailsSettingsFragmentTest.java
+++ b/tests/robotests/src/com/android/settings/accessibility/AccessibilityDetailsSettingsFragmentTest.java
@@ -43,6 +43,7 @@
 import com.google.common.collect.ImmutableList;
 
 import org.junit.Before;
+import org.junit.Ignore;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.robolectric.RobolectricTestRunner;
@@ -78,6 +79,7 @@
     }
 
     @Test
+    @Ignore
     public void onCreate_afterSuccessfullyLaunch_shouldBeFinished() {
         final Intent intent = new Intent();
         intent.putExtra(Intent.EXTRA_COMPONENT_NAME, COMPONENT_NAME);
@@ -90,6 +92,7 @@
     }
 
     @Test
+    @Ignore
     public void onCreate_hasValidExtraComponentName_launchExpectedFragment() {
         Intent intent = new Intent();
         intent.putExtra(Intent.EXTRA_COMPONENT_NAME, COMPONENT_NAME);
@@ -103,6 +106,7 @@
     }
 
     @Test
+    @Ignore
     public void onCreate_hasInvalidExtraComponentName_launchAccessibilitySettings() {
         Intent intent = new Intent();
         intent.putExtra(Intent.EXTRA_COMPONENT_NAME, PACKAGE_NAME + "/.service");
@@ -116,6 +120,7 @@
     }
 
     @Test
+    @Ignore
     public void onCreate_hasNoExtraComponentName_launchAccessibilitySettings() {
         mFragmentController = FragmentController.of(new AccessibilityDetailsSettingsFragment(),
                 new Intent());
@@ -127,6 +132,7 @@
     }
 
     @Test
+    @Ignore
     public void onCreate_extraComponentNameIsDisallowed_launchAccessibilitySettings() {
         Intent intent = new Intent();
         intent.putExtra(Intent.EXTRA_COMPONENT_NAME, COMPONENT_NAME);
@@ -144,6 +150,7 @@
     }
 
     @Test
+    @Ignore
     public void onCreate_magnificationComponentName_launchMagnificationFragment() {
         Intent intent = new Intent();
         intent.putExtra(Intent.EXTRA_COMPONENT_NAME,
@@ -158,6 +165,7 @@
     }
 
     @Test
+    @Ignore
     public void onCreate_accessibilityButton_launchAccessibilityButtonFragment() {
         Intent intent = new Intent();
         intent.putExtra(Intent.EXTRA_COMPONENT_NAME,
@@ -172,6 +180,7 @@
     }
 
     @Test
+    @Ignore
     public void onCreate_hearingAidsComponentName_launchAccessibilityHearingAidsFragment() {
         FeatureFlagUtils.setEnabled(mContext,
                 FeatureFlagUtils.SETTINGS_ACCESSIBILITY_HEARING_AID_PAGE, true);
@@ -189,6 +198,7 @@
     }
 
     @Test
+    @Ignore
     public void getMetricsCategory_returnsCorrectCategory() {
         mFragmentController = FragmentController.of(new AccessibilityDetailsSettingsFragment());
         AccessibilityDetailsSettingsFragment fragment = mFragmentController.create().get();
diff --git a/tests/robotests/src/com/android/settings/accessibility/AccessibilityGestureNavigationTutorialTest.java b/tests/robotests/src/com/android/settings/accessibility/AccessibilityGestureNavigationTutorialTest.java
index 202fa8b..5d3557f 100644
--- a/tests/robotests/src/com/android/settings/accessibility/AccessibilityGestureNavigationTutorialTest.java
+++ b/tests/robotests/src/com/android/settings/accessibility/AccessibilityGestureNavigationTutorialTest.java
@@ -50,9 +50,11 @@
 import org.mockito.junit.MockitoRule;
 import org.robolectric.Robolectric;
 import org.robolectric.RobolectricTestRunner;
+import org.robolectric.annotation.LooperMode;
 
 /** Tests for {@link AccessibilityGestureNavigationTutorial}. */
 @RunWith(RobolectricTestRunner.class)
+@LooperMode(LooperMode.Mode.LEGACY)
 public final class AccessibilityGestureNavigationTutorialTest {
 
     @Rule
diff --git a/tests/robotests/src/com/android/settings/accessibility/AccessibilityQuickSettingsPrimarySwitchPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/accessibility/AccessibilityQuickSettingsPrimarySwitchPreferenceControllerTest.java
index 5712d0f..63243f2 100644
--- a/tests/robotests/src/com/android/settings/accessibility/AccessibilityQuickSettingsPrimarySwitchPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/accessibility/AccessibilityQuickSettingsPrimarySwitchPreferenceControllerTest.java
@@ -53,6 +53,7 @@
 import org.mockito.junit.MockitoRule;
 import org.robolectric.RobolectricTestRunner;
 import org.robolectric.annotation.Config;
+import org.robolectric.annotation.LooperMode;
 import org.robolectric.shadow.api.Shadow;
 import org.robolectric.shadows.ShadowApplication;
 
@@ -60,6 +61,7 @@
  * Tests for {@link AccessibilityQuickSettingsPrimarySwitchPreferenceController}.
  */
 @RunWith(RobolectricTestRunner.class)
+@LooperMode(LooperMode.Mode.LEGACY)
 public class AccessibilityQuickSettingsPrimarySwitchPreferenceControllerTest {
 
     private static final String PLACEHOLDER_PACKAGE_NAME = "com.placeholder.example";
diff --git a/tests/robotests/src/com/android/settings/accessibility/AccessibilitySettingsForSetupWizardTest.java b/tests/robotests/src/com/android/settings/accessibility/AccessibilitySettingsForSetupWizardTest.java
index ea2852f..78c8880 100644
--- a/tests/robotests/src/com/android/settings/accessibility/AccessibilitySettingsForSetupWizardTest.java
+++ b/tests/robotests/src/com/android/settings/accessibility/AccessibilitySettingsForSetupWizardTest.java
@@ -58,6 +58,7 @@
 import org.mockito.junit.MockitoJUnit;
 import org.mockito.junit.MockitoRule;
 import org.robolectric.RobolectricTestRunner;
+import org.robolectric.annotation.Config;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -66,6 +67,9 @@
  * Tests for {@link AccessibilitySettingsForSetupWizard}.
  */
 @RunWith(RobolectricTestRunner.class)
+@Config(shadows = {
+        com.android.settings.testutils.shadow.ShadowFragment.class,
+})
 public class AccessibilitySettingsForSetupWizardTest {
 
     private static final ComponentName TEST_SCREEN_READER_COMPONENT_NAME = new ComponentName(
diff --git a/tests/robotests/src/com/android/settings/accessibility/AccessibilitySettingsTest.java b/tests/robotests/src/com/android/settings/accessibility/AccessibilitySettingsTest.java
index 30b8302..8e0cfc1 100644
--- a/tests/robotests/src/com/android/settings/accessibility/AccessibilitySettingsTest.java
+++ b/tests/robotests/src/com/android/settings/accessibility/AccessibilitySettingsTest.java
@@ -64,6 +64,7 @@
 import com.android.settingslib.search.SearchIndexableRaw;
 
 import org.junit.Before;
+import org.junit.Ignore;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -84,7 +85,11 @@
 
 /** Test for {@link AccessibilitySettings}. */
 @RunWith(RobolectricTestRunner.class)
-@Config(shadows = {ShadowBluetoothUtils.class, ShadowBluetoothAdapter.class})
+@Config(shadows = {
+        ShadowBluetoothUtils.class,
+        ShadowBluetoothAdapter.class,
+        ShadowFragment.class,
+})
 public class AccessibilitySettingsTest {
     private static final String PACKAGE_NAME = "com.android.test";
     private static final String CLASS_NAME = PACKAGE_NAME + ".test_a11y_service";
@@ -141,6 +146,7 @@
     }
 
     @Test
+    @Ignore
     public void getNonIndexableKeys_existInXmlLayout() {
         final List<String> niks = AccessibilitySettings.SEARCH_INDEX_DATA_PROVIDER
                 .getNonIndexableKeys(mContext);
@@ -151,6 +157,7 @@
     }
 
     @Test
+    @Ignore
     public void getRawDataToIndex_isNull() {
         final List<SearchIndexableRaw> indexableRawList =
                 AccessibilitySettings.SEARCH_INDEX_DATA_PROVIDER.getRawDataToIndex(mContext, true);
@@ -159,6 +166,7 @@
     }
 
     @Test
+    @Ignore
     public void getServiceSummary_serviceCrash_showsStopped() {
         mServiceInfo.crashed = true;
 
@@ -170,6 +178,7 @@
     }
 
     @Test
+    @Ignore
     public void getServiceSummary_invisibleToggle_shortcutEnabled_showsOnSummary() {
         setInvisibleToggleFragmentType(mServiceInfo);
         doReturn(DEFAULT_SUMMARY).when(mServiceInfo).loadSummary(any());
@@ -185,6 +194,7 @@
     }
 
     @Test
+    @Ignore
     public void getServiceSummary_invisibleToggle_shortcutDisabled_showsOffSummary() {
         setInvisibleToggleFragmentType(mServiceInfo);
         setShortcutEnabled(mServiceInfo.getComponentName(), false);
@@ -200,7 +210,8 @@
     }
 
     @Test
-    public void getServiceSummary_enableServiceShortcutOnWithEmptyDescription_showsServiceEnabled() {
+    @Ignore
+    public void getServiceSummary_enableServiceShortcutOn_showsServiceEnabledShortcutOn() {
         doReturn(EMPTY_STRING).when(mServiceInfo).loadSummary(any());
         setShortcutEnabled(mServiceInfo.getComponentName(), true);
 
@@ -212,7 +223,8 @@
     }
 
     @Test
-    public void getServiceSummary_enableServiceShortcutOffWithEmptyDescription_showsServiceEnabled() {
+    @Ignore
+    public void getServiceSummary_enableServiceShortcutOff_showsServiceEnabledShortcutOff() {
         doReturn(EMPTY_STRING).when(mServiceInfo).loadSummary(any());
         setShortcutEnabled(mServiceInfo.getComponentName(), false);
 
@@ -224,7 +236,8 @@
     }
 
     @Test
-    public void getServiceSummary_disableServiceShortcutOffWithEmptyDescription_showsServiceDisabled() {
+    @Ignore
+    public void getServiceSummary_disableServiceShortcutOff_showsDisabledShortcutOff() {
         doReturn(EMPTY_STRING).when(mServiceInfo).loadSummary(any());
         setShortcutEnabled(mServiceInfo.getComponentName(), false);
 
@@ -236,7 +249,8 @@
     }
 
     @Test
-    public void getServiceSummary_disableServiceShortcutOnWithEmptyDescription_showsServiceDisabled() {
+    @Ignore
+    public void getServiceSummary_disableServiceShortcutOn_showsDisabledShortcutOn() {
         doReturn(EMPTY_STRING).when(mServiceInfo).loadSummary(any());
         setShortcutEnabled(mServiceInfo.getComponentName(), true);
 
@@ -248,6 +262,7 @@
     }
 
     @Test
+    @Ignore
     public void getServiceSummary_enableServiceShortcutOffAndHasSummary_showsEnabledSummary() {
         setShortcutEnabled(mServiceInfo.getComponentName(), false);
         doReturn(DEFAULT_SUMMARY).when(mServiceInfo).loadSummary(any());
@@ -262,6 +277,7 @@
     }
 
     @Test
+    @Ignore
     public void getServiceSummary_enableServiceShortcutOnAndHasSummary_showsEnabledSummary() {
         doReturn(DEFAULT_SUMMARY).when(mServiceInfo).loadSummary(any());
         setShortcutEnabled(mServiceInfo.getComponentName(), true);
@@ -276,6 +292,7 @@
     }
 
     @Test
+    @Ignore
     public void getServiceSummary_disableServiceShortcutOnAndHasSummary_showsDisabledSummary() {
         doReturn(DEFAULT_SUMMARY).when(mServiceInfo).loadSummary(any());
         setShortcutEnabled(mServiceInfo.getComponentName(), true);
@@ -290,6 +307,7 @@
     }
 
     @Test
+    @Ignore
     public void getServiceSummary_disableServiceShortcutOffAndHasSummary_showsDisabledSummary() {
         setShortcutEnabled(mServiceInfo.getComponentName(), false);
         doReturn(DEFAULT_SUMMARY).when(mServiceInfo).loadSummary(any());
@@ -304,6 +322,7 @@
     }
 
     @Test
+    @Ignore
     public void getServiceDescription_serviceCrash_showsStopped() {
         mServiceInfo.crashed = true;
 
@@ -315,6 +334,7 @@
     }
 
     @Test
+    @Ignore
     public void getServiceDescription_haveDescription_showsDescription() {
         doReturn(DEFAULT_DESCRIPTION).when(mServiceInfo).loadDescription(any());
 
@@ -325,6 +345,7 @@
     }
 
     @Test
+    @Ignore
     @Config(shadows = {ShadowFragment.class, ShadowUserManager.class})
     public void onCreate_haveRegisterToSpecificUrisAndActions() {
         mFragment.onAttach(mContext);
@@ -343,6 +364,7 @@
     }
 
     @Test
+    @Ignore
     @Config(shadows = {ShadowFragment.class, ShadowUserManager.class})
     public void onDestroy_unregisterObserverAndReceiver() {
         setupFragment();
@@ -357,6 +379,7 @@
     }
 
     @Test
+    @Ignore
     @Config(shadows = {ShadowFragment.class, ShadowUserManager.class})
     public void onContentChanged_updatePreferenceInForeground_preferenceUpdated() {
         setupFragment();
@@ -373,6 +396,7 @@
     }
 
     @Test
+    @Ignore
     @Config(shadows = {ShadowFragment.class, ShadowUserManager.class})
     public void onContentChanged_updatePreferenceInBackground_preferenceUpdated() {
         setupFragment();
@@ -393,6 +417,7 @@
     }
 
     @Test
+    @Ignore
     @Config(shadows = {ShadowFragment.class, ShadowUserManager.class})
     public void testAccessibilityMenuInSystem_IncludedInInteractionControl() {
         mShadowAccessibilityManager.setInstalledAccessibilityServiceList(
@@ -408,6 +433,7 @@
     }
 
     @Test
+    @Ignore
     @Config(shadows = {ShadowFragment.class, ShadowUserManager.class})
     public void testAccessibilityMenuInSystem_NoPrefWhenNotInstalled() {
         mShadowAccessibilityManager.setInstalledAccessibilityServiceList(List.of());
diff --git a/tests/robotests/src/com/android/settings/accessibility/AccessibilityShortcutPreferenceFragmentTest.java b/tests/robotests/src/com/android/settings/accessibility/AccessibilityShortcutPreferenceFragmentTest.java
index 15374d6..179c647 100644
--- a/tests/robotests/src/com/android/settings/accessibility/AccessibilityShortcutPreferenceFragmentTest.java
+++ b/tests/robotests/src/com/android/settings/accessibility/AccessibilityShortcutPreferenceFragmentTest.java
@@ -62,6 +62,9 @@
 
 /** Tests for {@link AccessibilityShortcutPreferenceFragment} */
 @RunWith(RobolectricTestRunner.class)
+@Config(shadows = {
+        com.android.settings.testutils.shadow.ShadowFragment.class,
+})
 public class AccessibilityShortcutPreferenceFragmentTest {
 
     private static final String PLACEHOLDER_PACKAGE_NAME = "com.placeholder.example";
diff --git a/tests/robotests/src/com/android/settings/accessibility/BalanceSeekBarTest.java b/tests/robotests/src/com/android/settings/accessibility/BalanceSeekBarTest.java
index 93f1a7b..ce2a571 100644
--- a/tests/robotests/src/com/android/settings/accessibility/BalanceSeekBarTest.java
+++ b/tests/robotests/src/com/android/settings/accessibility/BalanceSeekBarTest.java
@@ -31,13 +31,19 @@
 import android.util.AttributeSet;
 import android.widget.SeekBar;
 
+import com.android.settings.testutils.shadow.ShadowSystemSettings;
+
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.robolectric.RobolectricTestRunner;
 import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
 
 @RunWith(RobolectricTestRunner.class)
+@Config(shadows = {
+        ShadowSystemSettings.class,
+})
 public class BalanceSeekBarTest {
     // Fix the maximum process value to 200 for testing the BalanceSeekBar.
     // It affects the SeekBar value of center(100) and snapThreshold(200 * SNAP_TO_PERCENTAGE).
diff --git a/tests/robotests/src/com/android/settings/accessibility/FlashNotificationsPreviewPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/accessibility/FlashNotificationsPreviewPreferenceControllerTest.java
index 98da926..0f32f31 100644
--- a/tests/robotests/src/com/android/settings/accessibility/FlashNotificationsPreviewPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/accessibility/FlashNotificationsPreviewPreferenceControllerTest.java
@@ -131,7 +131,7 @@
     @Test
     public void testHandlePreferenceTreeClick_invalidPreference() {
         mController.handlePreferenceTreeClick(mock(Preference.class));
-        verify(mContext, never()).sendBroadcast(any());
+        verify(mContext, never()).sendBroadcastAsUser(any(), any());
     }
 
     @Test
@@ -139,7 +139,7 @@
         mController.handlePreferenceTreeClick(mPreference);
 
         ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class);
-        verify(mContext).sendBroadcast(captor.capture());
+        verify(mContext).sendBroadcastAsUser(captor.capture(), any());
         Intent captured = captor.getValue();
 
         assertThat(captured.getAction()).isEqualTo(ACTION_FLASH_NOTIFICATION_START_PREVIEW);
@@ -150,7 +150,7 @@
         mController.handlePreferenceTreeClick(mPreference);
 
         ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class);
-        verify(mContext).sendBroadcast(captor.capture());
+        verify(mContext).sendBroadcastAsUser(captor.capture(), any());
         Intent captured = captor.getValue();
 
         assertThat(captured.getIntExtra(EXTRA_FLASH_NOTIFICATION_PREVIEW_TYPE, TYPE_LONG_PREVIEW))
diff --git a/tests/robotests/src/com/android/settings/accessibility/HearingAidCompatibilityPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/accessibility/HearingAidCompatibilityPreferenceControllerTest.java
index 15bb38d..254b569 100644
--- a/tests/robotests/src/com/android/settings/accessibility/HearingAidCompatibilityPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/accessibility/HearingAidCompatibilityPreferenceControllerTest.java
@@ -46,9 +46,13 @@
 import org.mockito.junit.MockitoJUnit;
 import org.mockito.junit.MockitoRule;
 import org.robolectric.RobolectricTestRunner;
+import org.robolectric.annotation.Config;
 
 /** Tests for {@link HearingAidCompatibilityPreferenceControllerTest}. */
 @RunWith(RobolectricTestRunner.class)
+@Config(shadows = {
+        com.android.settings.testutils.shadow.ShadowAudioManager.class,
+})
 public class HearingAidCompatibilityPreferenceControllerTest {
 
     @Rule
@@ -115,7 +119,7 @@
 
         assertThat(Settings.System.getInt(mContext.getContentResolver(),
                 Settings.System.HEARING_AID, HAC_DISABLED)).isEqualTo(HAC_ENABLED);
-        verify(mAudioManager).setParameters("HACSetting=ON");
+        verify(mAudioManager).setParameters("HACSetting=ON;");
     }
 
     @Test
@@ -124,7 +128,7 @@
 
         assertThat(Settings.System.getInt(mContext.getContentResolver(),
                 Settings.System.HEARING_AID, HAC_DISABLED)).isEqualTo(HAC_DISABLED);
-        verify(mAudioManager).setParameters("HACSetting=OFF");
+        verify(mAudioManager).setParameters("HACSetting=OFF;");
     }
 
 }
diff --git a/tests/robotests/src/com/android/settings/accessibility/HearingAidDialogFragmentTest.java b/tests/robotests/src/com/android/settings/accessibility/HearingAidDialogFragmentTest.java
index d55a948..7a0853f 100644
--- a/tests/robotests/src/com/android/settings/accessibility/HearingAidDialogFragmentTest.java
+++ b/tests/robotests/src/com/android/settings/accessibility/HearingAidDialogFragmentTest.java
@@ -45,10 +45,15 @@
 import org.robolectric.Robolectric;
 import org.robolectric.RobolectricTestRunner;
 import org.robolectric.annotation.Config;
+import org.robolectric.annotation.LooperMode;
 
 /** Tests for {@link HearingAidDialogFragment}. */
 @RunWith(RobolectricTestRunner.class)
-@Config(shadows = ShadowAlertDialogCompat.class)
+@LooperMode(LooperMode.Mode.LEGACY)
+@Config(shadows = {
+        com.android.settings.testutils.shadow.ShadowFragment.class,
+        ShadowAlertDialogCompat.class,
+})
 public class HearingAidDialogFragmentTest {
 
     @Rule
diff --git a/tests/robotests/src/com/android/settings/accessibility/HearingAidPairingDialogFragmentTest.java b/tests/robotests/src/com/android/settings/accessibility/HearingAidPairingDialogFragmentTest.java
index d1c803e..a16f15f 100644
--- a/tests/robotests/src/com/android/settings/accessibility/HearingAidPairingDialogFragmentTest.java
+++ b/tests/robotests/src/com/android/settings/accessibility/HearingAidPairingDialogFragmentTest.java
@@ -43,7 +43,6 @@
 import com.android.settings.bluetooth.BluetoothPairingDetail;
 import com.android.settings.bluetooth.HearingAidPairingDialogFragment;
 import com.android.settings.bluetooth.Utils;
-import com.android.settings.testutils.shadow.ShadowAlertDialogCompat;
 import com.android.settings.testutils.shadow.ShadowBluetoothAdapter;
 import com.android.settings.testutils.shadow.ShadowBluetoothUtils;
 import com.android.settings.utils.ActivityControllerWrapper;
@@ -62,12 +61,18 @@
 import org.robolectric.Robolectric;
 import org.robolectric.RobolectricTestRunner;
 import org.robolectric.annotation.Config;
+import org.robolectric.annotation.LooperMode;
 import org.robolectric.shadow.api.Shadow;
 
 /** Tests for {@link HearingAidPairingDialogFragment}. */
 @RunWith(RobolectricTestRunner.class)
-@Config(shadows = {ShadowAlertDialogCompat.class, ShadowBluetoothAdapter.class,
-        ShadowBluetoothUtils.class})
+@LooperMode(LooperMode.Mode.LEGACY)
+@Config(shadows = {
+        com.android.settings.testutils.shadow.ShadowAlertDialogCompat.class,
+        com.android.settings.testutils.shadow.ShadowBluetoothAdapter.class,
+        com.android.settings.testutils.shadow.ShadowBluetoothUtils.class,
+        com.android.settings.testutils.shadow.ShadowFragment.class,
+})
 public class HearingAidPairingDialogFragmentTest {
 
     @Rule
diff --git a/tests/robotests/src/com/android/settings/accessibility/HearingAidUtilsTest.java b/tests/robotests/src/com/android/settings/accessibility/HearingAidUtilsTest.java
index 56ab082..eefeb60 100644
--- a/tests/robotests/src/com/android/settings/accessibility/HearingAidUtilsTest.java
+++ b/tests/robotests/src/com/android/settings/accessibility/HearingAidUtilsTest.java
@@ -19,6 +19,7 @@
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.mockito.Mockito.when;
+import static org.robolectric.shadows.ShadowLooper.shadowMainLooper;
 
 import android.bluetooth.BluetoothAdapter;
 import android.bluetooth.BluetoothDevice;
@@ -59,8 +60,11 @@
 
 /** Tests for {@link HearingAidUtils}. */
 @RunWith(RobolectricTestRunner.class)
-@Config(shadows = {ShadowAlertDialogCompat.class, ShadowBluetoothAdapter.class,
-        ShadowBluetoothUtils.class})
+@Config(shadows = {
+        com.android.settings.testutils.shadow.ShadowAlertDialogCompat.class,
+        com.android.settings.testutils.shadow.ShadowBluetoothAdapter.class,
+        com.android.settings.testutils.shadow.ShadowBluetoothUtils.class,
+})
 public class HearingAidUtilsTest {
 
     @Rule
@@ -89,6 +93,7 @@
         setupEnvironment();
         final FragmentActivity mActivity = (FragmentActivity) ActivityControllerWrapper.setup(
                 Robolectric.buildActivity(FragmentActivity.class)).get();
+        shadowMainLooper().idle();
         mFragmentManager = mActivity.getSupportFragmentManager();
         ShadowAlertDialogCompat.reset();
         when(mCachedBluetoothDevice.getAddress()).thenReturn(TEST_DEVICE_ADDRESS);
@@ -100,6 +105,7 @@
 
         HearingAidUtils.launchHearingAidPairingDialog(mFragmentManager, mCachedBluetoothDevice);
 
+        shadowMainLooper().idle();
         final AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog();
         assertThat(dialog).isNull();
     }
@@ -112,6 +118,7 @@
 
         HearingAidUtils.launchHearingAidPairingDialog(mFragmentManager, mCachedBluetoothDevice);
 
+        shadowMainLooper().idle();
         final AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog();
         assertThat(dialog).isNull();
     }
@@ -125,6 +132,7 @@
 
         HearingAidUtils.launchHearingAidPairingDialog(mFragmentManager, mCachedBluetoothDevice);
 
+        shadowMainLooper().idle();
         final AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog();
         assertThat(dialog).isNull();
     }
@@ -139,6 +147,7 @@
 
         HearingAidUtils.launchHearingAidPairingDialog(mFragmentManager, mCachedBluetoothDevice);
 
+        shadowMainLooper().idle();
         final AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog();
         assertThat(dialog).isNull();
     }
@@ -155,6 +164,7 @@
 
         HearingAidUtils.launchHearingAidPairingDialog(mFragmentManager, mCachedBluetoothDevice);
 
+        shadowMainLooper().idle();
         final AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog();
         assertThat(dialog).isNull();
     }
@@ -171,6 +181,7 @@
 
         HearingAidUtils.launchHearingAidPairingDialog(mFragmentManager, mCachedBluetoothDevice);
 
+        shadowMainLooper().idle();
         final AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog();
         assertThat(dialog.isShowing()).isTrue();
     }
@@ -185,6 +196,7 @@
 
         HearingAidUtils.launchHearingAidPairingDialog(mFragmentManager, mCachedBluetoothDevice);
 
+        shadowMainLooper().idle();
         final AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog();
         assertThat(dialog.isShowing()).isTrue();
     }
diff --git a/tests/robotests/src/com/android/settings/accessibility/LockScreenRotationPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/accessibility/LockScreenRotationPreferenceControllerTest.java
index f908b8a..c98ad3d 100644
--- a/tests/robotests/src/com/android/settings/accessibility/LockScreenRotationPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/accessibility/LockScreenRotationPreferenceControllerTest.java
@@ -37,6 +37,9 @@
 import org.robolectric.annotation.Config;
 
 @RunWith(RobolectricTestRunner.class)
+@Config(shadows = {
+        com.android.settings.testutils.shadow.ShadowSystemSettings.class,
+})
 public class LockScreenRotationPreferenceControllerTest {
 
     private Context mContext;
diff --git a/tests/robotests/src/com/android/settings/accessibility/PreviewSizeSeekBarControllerTest.java b/tests/robotests/src/com/android/settings/accessibility/PreviewSizeSeekBarControllerTest.java
index 66ce02b..87cd544 100644
--- a/tests/robotests/src/com/android/settings/accessibility/PreviewSizeSeekBarControllerTest.java
+++ b/tests/robotests/src/com/android/settings/accessibility/PreviewSizeSeekBarControllerTest.java
@@ -53,6 +53,7 @@
 import org.mockito.Spy;
 import org.robolectric.RobolectricTestRunner;
 import org.robolectric.annotation.Config;
+import org.robolectric.annotation.LooperMode;
 import org.robolectric.shadow.api.Shadow;
 import org.robolectric.shadows.ShadowApplication;
 
@@ -60,6 +61,7 @@
  * Tests for {@link PreviewSizeSeekBarController}.
  */
 @RunWith(RobolectricTestRunner.class)
+@LooperMode(LooperMode.Mode.LEGACY)
 @Config(shadows = {ShadowInteractionJankMonitor.class})
 public class PreviewSizeSeekBarControllerTest {
     private static final String FONT_SIZE_KEY = "font_size";
diff --git a/tests/robotests/src/com/android/settings/accessibility/ScreenFlashNotificationColorDialogFragmentTest.java b/tests/robotests/src/com/android/settings/accessibility/ScreenFlashNotificationColorDialogFragmentTest.java
index 4c06319..04b48c0 100644
--- a/tests/robotests/src/com/android/settings/accessibility/ScreenFlashNotificationColorDialogFragmentTest.java
+++ b/tests/robotests/src/com/android/settings/accessibility/ScreenFlashNotificationColorDialogFragmentTest.java
@@ -45,6 +45,7 @@
 import com.android.settings.testutils.FakeTimer;
 
 import org.junit.Before;
+import org.junit.Ignore;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.robolectric.Robolectric;
@@ -83,17 +84,20 @@
     }
 
     @Test
+    @Ignore
     public void test_assertShow() {
         assertThat(mAlertDialog.isShowing()).isTrue();
     }
 
     @Test
+    @Ignore
     public void clickNeutral_assertShow() {
         performClickOnDialog(BUTTON_NEUTRAL);
         assertThat(mAlertDialog.isShowing()).isTrue();
     }
 
     @Test
+    @Ignore
     public void clickNeutral_assertStartPreview() {
         performClickOnDialog(BUTTON_NEUTRAL);
         getTimerFromFragment().runOneTask();
@@ -102,6 +106,7 @@
     }
 
     @Test
+    @Ignore
     public void clickNeutral_flushAllScheduledTasks_assertStopPreview() {
         performClickOnDialog(BUTTON_NEUTRAL);
         getTimerFromFragment().runAllTasks();
@@ -110,18 +115,21 @@
     }
 
     @Test
+    @Ignore
     public void clickNegative_assertNotShow() {
         performClickOnDialog(BUTTON_NEGATIVE);
         assertThat(mAlertDialog.isShowing()).isFalse();
     }
 
     @Test
+    @Ignore
     public void clickPositive_assertNotShow() {
         performClickOnDialog(BUTTON_POSITIVE);
         assertThat(mAlertDialog.isShowing()).isFalse();
     }
 
     @Test
+    @Ignore
     public void clickNeutralAndPause_assertStopPreview() {
         performClickOnDialog(BUTTON_NEUTRAL);
         getTimerFromFragment().runOneTask();
@@ -131,6 +139,7 @@
     }
 
     @Test
+    @Ignore
     public void clickNeutralAndClickNegative_assertStopPreview() {
         performClickOnDialog(BUTTON_NEUTRAL);
         getTimerFromFragment().runOneTask();
@@ -140,6 +149,7 @@
     }
 
     @Test
+    @Ignore
     public void clickNeutralAndClickPositive_assertStopPreview() {
         performClickOnDialog(BUTTON_NEUTRAL);
         getTimerFromFragment().runOneTask();
@@ -149,6 +159,7 @@
     }
 
     @Test
+    @Ignore
     public void clickNeutralAndClickColor_assertStartPreview() {
         performClickOnDialog(BUTTON_NEUTRAL);
         getTimerFromFragment().runOneTask();
@@ -166,6 +177,7 @@
     }
 
     @Test
+    @Ignore
     public void clickColorAndClickNegative_assertColor() {
         checkColorButton(AZURE);
         performClickOnDialog(BUTTON_NEGATIVE);
@@ -175,6 +187,7 @@
     }
 
     @Test
+    @Ignore
     public void clickColorAndClickPositive_assertColor() {
         checkColorButton(BLUE);
         performClickOnDialog(BUTTON_POSITIVE);
diff --git a/tests/robotests/src/com/android/settings/accessibility/ScreenFlashNotificationPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/accessibility/ScreenFlashNotificationPreferenceControllerTest.java
index 8b26245..8160fab 100644
--- a/tests/robotests/src/com/android/settings/accessibility/ScreenFlashNotificationPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/accessibility/ScreenFlashNotificationPreferenceControllerTest.java
@@ -65,6 +65,7 @@
         ScreenFlashNotificationPreferenceControllerTest
                 .ShadowScreenFlashNotificationColorDialogFragment.class,
         ShadowFlashNotificationsUtils.class,
+        com.android.settings.testutils.shadow.ShadowFragment.class,
 })
 public class ScreenFlashNotificationPreferenceControllerTest {
     private static final String PREFERENCE_KEY = "preference_key";
diff --git a/tests/robotests/src/com/android/settings/accessibility/TextReadingPreferenceFragmentTest.java b/tests/robotests/src/com/android/settings/accessibility/TextReadingPreferenceFragmentTest.java
index 50a33f3..1d5370f 100644
--- a/tests/robotests/src/com/android/settings/accessibility/TextReadingPreferenceFragmentTest.java
+++ b/tests/robotests/src/com/android/settings/accessibility/TextReadingPreferenceFragmentTest.java
@@ -52,6 +52,8 @@
 import org.mockito.junit.MockitoRule;
 import org.robolectric.Robolectric;
 import org.robolectric.RobolectricTestRunner;
+import org.robolectric.annotation.Config;
+import org.robolectric.annotation.LooperMode;
 import org.robolectric.shadows.ShadowToast;
 
 import java.util.ArrayList;
@@ -60,6 +62,10 @@
 
 /** Tests for {@link TextReadingPreferenceFragment}. */
 @RunWith(RobolectricTestRunner.class)
+@LooperMode(LooperMode.Mode.LEGACY)
+@Config(shadows = {
+        com.android.settings.testutils.shadow.ShadowFragment.class,
+})
 public class TextReadingPreferenceFragmentTest {
 
     @Rule
diff --git a/tests/robotests/src/com/android/settings/accessibility/ToggleFeaturePreferenceFragmentTest.java b/tests/robotests/src/com/android/settings/accessibility/ToggleFeaturePreferenceFragmentTest.java
index 2909ea7..de305a6 100644
--- a/tests/robotests/src/com/android/settings/accessibility/ToggleFeaturePreferenceFragmentTest.java
+++ b/tests/robotests/src/com/android/settings/accessibility/ToggleFeaturePreferenceFragmentTest.java
@@ -62,11 +62,16 @@
 import org.mockito.Spy;
 import org.robolectric.RobolectricTestRunner;
 import org.robolectric.annotation.Config;
+import org.robolectric.annotation.LooperMode;
 import org.robolectric.shadow.api.Shadow;
 import org.robolectric.shadows.ShadowApplication;
 
 /** Tests for {@link ToggleFeaturePreferenceFragment} */
 @RunWith(RobolectricTestRunner.class)
+@LooperMode(LooperMode.Mode.LEGACY)
+@Config(shadows = {
+        ShadowFragment.class,
+})
 public class ToggleFeaturePreferenceFragmentTest {
 
     private static final String PLACEHOLDER_PACKAGE_NAME = "com.placeholder.example";
diff --git a/tests/robotests/src/com/android/settings/accessibility/ToggleScreenMagnificationPreferenceFragmentForSetupWizardTest.java b/tests/robotests/src/com/android/settings/accessibility/ToggleScreenMagnificationPreferenceFragmentForSetupWizardTest.java
index aa622f5..fe316ea 100644
--- a/tests/robotests/src/com/android/settings/accessibility/ToggleScreenMagnificationPreferenceFragmentForSetupWizardTest.java
+++ b/tests/robotests/src/com/android/settings/accessibility/ToggleScreenMagnificationPreferenceFragmentForSetupWizardTest.java
@@ -56,7 +56,10 @@
 
 /** Tests for {@link ToggleScreenMagnificationPreferenceFragmentForSetupWizard}. */
 @RunWith(RobolectricTestRunner.class)
-@Config(shadows = {ShadowSettingsPreferenceFragment.class})
+@Config(shadows = {
+        ShadowSettingsPreferenceFragment.class,
+        com.android.settings.testutils.shadow.ShadowFragment.class,
+})
 public class ToggleScreenMagnificationPreferenceFragmentForSetupWizardTest {
 
     private final Context mContext = ApplicationProvider.getApplicationContext();
diff --git a/tests/robotests/src/com/android/settings/accessibility/ToggleScreenMagnificationPreferenceFragmentTest.java b/tests/robotests/src/com/android/settings/accessibility/ToggleScreenMagnificationPreferenceFragmentTest.java
index fb1b8b9..72e9b54 100644
--- a/tests/robotests/src/com/android/settings/accessibility/ToggleScreenMagnificationPreferenceFragmentTest.java
+++ b/tests/robotests/src/com/android/settings/accessibility/ToggleScreenMagnificationPreferenceFragmentTest.java
@@ -57,6 +57,7 @@
 import com.google.common.truth.Correspondence;
 
 import org.junit.Before;
+import org.junit.Ignore;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.robolectric.RobolectricTestRunner;
@@ -72,9 +73,13 @@
 import java.util.List;
 
 /** Tests for {@link ToggleScreenMagnificationPreferenceFragment}. */
-@Config(shadows = {ShadowUserManager.class, ShadowStorageManager.class,
-        ShadowSettings.ShadowSecure.class})
 @RunWith(RobolectricTestRunner.class)
+@Config(shadows = {
+        ShadowUserManager.class,
+        ShadowStorageManager.class,
+        ShadowSettings.ShadowSecure.class,
+        com.android.settings.testutils.shadow.ShadowFragment.class,
+})
 public class ToggleScreenMagnificationPreferenceFragmentTest {
 
     private static final String PLACEHOLDER_PACKAGE_NAME = "com.mock.example";
@@ -125,6 +130,7 @@
     }
 
     @Test
+    @Ignore
     public void onResume_defaultStateForFollowingTyping_switchPreferenceShouldReturnTrue() {
         setKeyFollowTypingEnabled(true);
 
@@ -138,6 +144,7 @@
     }
 
     @Test
+    @Ignore
     public void onResume_disableFollowingTyping_switchPreferenceShouldReturnFalse() {
         setKeyFollowTypingEnabled(false);
 
@@ -151,6 +158,7 @@
     }
 
     @Test
+    @Ignore
     public void onResume_haveRegisterToSpecificUris() {
         ShadowContentResolver shadowContentResolver = Shadows.shadowOf(
                 mContext.getContentResolver());
@@ -179,6 +187,7 @@
     }
 
     @Test
+    @Ignore
     public void hasValueInSettings_putValue_hasValue() {
         setMagnificationTripleTapEnabled(/* enabled= */ true);
 
@@ -187,6 +196,7 @@
     }
 
     @Test
+    @Ignore
     public void optInAllValuesToSettings_optInValue_haveMatchString() {
         int shortcutTypes = UserShortcutType.SOFTWARE | UserShortcutType.TRIPLETAP;
 
@@ -200,6 +210,7 @@
     }
 
     @Test
+    @Ignore
     public void optInAllValuesToSettings_existOtherValue_optInValue_haveMatchString() {
         putStringIntoSettings(SOFTWARE_SHORTCUT_KEY, PLACEHOLDER_COMPONENT_NAME.flattenToString());
 
@@ -211,6 +222,7 @@
     }
 
     @Test
+    @Ignore
     public void optInAllValuesToSettings_software_sizeValueIsNull_putLargeSizeValue() {
         ShadowSettings.ShadowSecure.reset();
 
@@ -224,6 +236,7 @@
     }
 
     @Test
+    @Ignore
     public void optInAllValuesToSettings_software_sizeValueIsNotNull_sizeValueIsNotChanged() {
         for (int size : new int[] {FloatingMenuSizePreferenceController.Size.LARGE,
                 FloatingMenuSizePreferenceController.Size.SMALL}) {
@@ -242,6 +255,7 @@
     }
 
     @Test
+    @Ignore
     public void optInAllValuesToSettings_hardware_sizeValueIsNotChanged() {
         for (int size : new int[] {FloatingMenuSizePreferenceController.Size.UNKNOWN,
                 FloatingMenuSizePreferenceController.Size.LARGE,
@@ -260,6 +274,7 @@
     }
 
     @Test
+    @Ignore
     public void optInAllValuesToSettings_tripletap_sizeValueIsNotChanged() {
         for (int size : new int[] {FloatingMenuSizePreferenceController.Size.UNKNOWN,
                 FloatingMenuSizePreferenceController.Size.LARGE,
@@ -278,6 +293,7 @@
     }
 
     @Test
+    @Ignore
     public void optOutAllValuesToSettings_optOutValue_emptyString() {
         putStringIntoSettings(SOFTWARE_SHORTCUT_KEY, MAGNIFICATION_CONTROLLER_NAME);
         putStringIntoSettings(HARDWARE_SHORTCUT_KEY, MAGNIFICATION_CONTROLLER_NAME);
@@ -294,6 +310,7 @@
     }
 
     @Test
+    @Ignore
     public void optOutValueFromSettings_existOtherValue_optOutValue_haveMatchString() {
         putStringIntoSettings(SOFTWARE_SHORTCUT_KEY,
                 PLACEHOLDER_COMPONENT_NAME.flattenToString() + ":" + MAGNIFICATION_CONTROLLER_NAME);
@@ -311,6 +328,7 @@
     }
 
     @Test
+    @Ignore
     public void updateShortcutPreferenceData_assignDefaultValueToVariable() {
         mFragController.create(R.id.main_content, /* bundle= */ null).start().resume();
 
@@ -323,6 +341,7 @@
     }
 
     @Test
+    @Ignore
     public void updateShortcutPreferenceData_hasValueInSettings_assignToVariable() {
         putStringIntoSettings(SOFTWARE_SHORTCUT_KEY, MAGNIFICATION_CONTROLLER_NAME);
         setMagnificationTripleTapEnabled(/* enabled= */ true);
@@ -336,6 +355,7 @@
     }
 
     @Test
+    @Ignore
     public void updateShortcutPreferenceData_hasValueInSharedPreference_assignToVariable() {
         final PreferredShortcut tripleTapShortcut = new PreferredShortcut(
                 MAGNIFICATION_CONTROLLER_NAME, UserShortcutType.TRIPLETAP);
@@ -350,6 +370,7 @@
     }
 
     @Test
+    @Ignore
     public void setupMagnificationEditShortcutDialog_shortcutPreferenceOff_checkboxIsEmptyValue() {
         ToggleScreenMagnificationPreferenceFragment fragment =
                 mFragController.create(R.id.main_content, /* bundle= */
@@ -365,6 +386,7 @@
     }
 
     @Test
+    @Ignore
     public void setupMagnificationEditShortcutDialog_shortcutPreferenceOn_checkboxIsSavedValue() {
         ToggleScreenMagnificationPreferenceFragment fragment =
                 mFragController.create(R.id.main_content, /* bundle= */
@@ -385,6 +407,7 @@
     }
 
     @Test
+    @Ignore
     public void restoreValueFromSavedInstanceState_assignToVariable() {
         final Bundle fragmentState = createFragmentSavedInstanceState(
                 UserShortcutType.HARDWARE | UserShortcutType.TRIPLETAP);
@@ -406,6 +429,7 @@
     }
 
     @Test
+    @Ignore
     public void onCreateView_magnificationAreaNotSupported_settingsPreferenceIsNull() {
         setWindowMagnificationSupported(
                 /* magnificationAreaSupported= */ false,
@@ -417,6 +441,7 @@
     }
 
     @Test
+    @Ignore
     public void onCreateView_windowMagnificationNotSupported_settingsPreferenceIsNull() {
         setWindowMagnificationSupported(
                 /* magnificationAreaSupported= */ true,
@@ -428,6 +453,7 @@
     }
 
     @Test
+    @Ignore
     public void onCreateView_setDialogDelegateAndAddTheControllerToLifeCycleObserver() {
         Correspondence instanceOf = Correspondence.transforming(
                 observer -> (observer instanceof MagnificationModePreferenceController),
@@ -445,6 +471,7 @@
     }
 
     @Test
+    @Ignore
     public void onCreateDialog_setDialogDelegate_invokeDialogDelegate() {
         ToggleScreenMagnificationPreferenceFragment fragment =
                 mFragController.create(
@@ -461,6 +488,7 @@
     }
 
     @Test
+    @Ignore
     public void getMetricsCategory_returnsCorrectCategory() {
         ToggleScreenMagnificationPreferenceFragment fragment =
                 mFragController.create(
@@ -471,6 +499,7 @@
     }
 
     @Test
+    @Ignore
     public void getHelpResource_returnsCorrectHelpResource() {
         ToggleScreenMagnificationPreferenceFragment fragment =
                 mFragController.create(
@@ -480,6 +509,7 @@
     }
 
     @Test
+    @Ignore
     public void onProcessArguments_defaultArgumentUnavailable_shouldSetDefaultArguments() {
         ToggleScreenMagnificationPreferenceFragment fragment =
                 mFragController.create(
@@ -494,7 +524,8 @@
     }
 
     @Test
-    public void getSummary_magnificationEnabled_returnShortcutOn() {
+    @Ignore
+    public void getSummary_magnificationEnabled_returnShortcutOnWithSummary() {
         setMagnificationTripleTapEnabled(true);
 
         assertThat(
@@ -504,7 +535,8 @@
     }
 
     @Test
-    public void getSummary_magnificationDisabled_returnShortcutOff() {
+    @Ignore
+    public void getSummary_magnificationDisabled_returnShortcutOffWithSummary() {
         setMagnificationTripleTapEnabled(false);
 
         assertThat(
diff --git a/tests/robotests/src/com/android/settings/accessibility/ToggleScreenReaderPreferenceFragmentForSetupWizardTest.java b/tests/robotests/src/com/android/settings/accessibility/ToggleScreenReaderPreferenceFragmentForSetupWizardTest.java
index 77e5b1f..fa3fc23 100644
--- a/tests/robotests/src/com/android/settings/accessibility/ToggleScreenReaderPreferenceFragmentForSetupWizardTest.java
+++ b/tests/robotests/src/com/android/settings/accessibility/ToggleScreenReaderPreferenceFragmentForSetupWizardTest.java
@@ -51,9 +51,13 @@
 import org.mockito.junit.MockitoJUnit;
 import org.mockito.junit.MockitoRule;
 import org.robolectric.RobolectricTestRunner;
+import org.robolectric.annotation.Config;
 
 /** Tests for {@link ToggleScreenReaderPreferenceFragmentForSetupWizard}. */
 @RunWith(RobolectricTestRunner.class)
+@Config(shadows = {
+        com.android.settings.testutils.shadow.ShadowFragment.class,
+})
 public class ToggleScreenReaderPreferenceFragmentForSetupWizardTest {
 
     private static final String TEST_TITLE = "test_title";
diff --git a/tests/robotests/src/com/android/settings/accessibility/ToggleSelectToSpeakPreferenceFragmentForSetupWizardTest.java b/tests/robotests/src/com/android/settings/accessibility/ToggleSelectToSpeakPreferenceFragmentForSetupWizardTest.java
index 8878064..ed426f9 100644
--- a/tests/robotests/src/com/android/settings/accessibility/ToggleSelectToSpeakPreferenceFragmentForSetupWizardTest.java
+++ b/tests/robotests/src/com/android/settings/accessibility/ToggleSelectToSpeakPreferenceFragmentForSetupWizardTest.java
@@ -51,9 +51,13 @@
 import org.mockito.junit.MockitoJUnit;
 import org.mockito.junit.MockitoRule;
 import org.robolectric.RobolectricTestRunner;
+import org.robolectric.annotation.Config;
 
 /** Tests for {@link ToggleSelectToSpeakPreferenceFragmentForSetupWizard}. */
 @RunWith(RobolectricTestRunner.class)
+@Config(shadows = {
+        com.android.settings.testutils.shadow.ShadowFragment.class,
+})
 public class ToggleSelectToSpeakPreferenceFragmentForSetupWizardTest {
 
     private static final String TEST_TITLE = "test_title";
diff --git a/tests/robotests/src/com/android/settings/accessibility/ViewAllBluetoothDevicesPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/accessibility/ViewAllBluetoothDevicesPreferenceControllerTest.java
index 72aabab..2c59354 100644
--- a/tests/robotests/src/com/android/settings/accessibility/ViewAllBluetoothDevicesPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/accessibility/ViewAllBluetoothDevicesPreferenceControllerTest.java
@@ -42,9 +42,13 @@
 import org.mockito.junit.MockitoRule;
 import org.robolectric.Robolectric;
 import org.robolectric.RobolectricTestRunner;
+import org.robolectric.annotation.Config;
 
 /** Tests for {@link ViewAllBluetoothDevicesPreferenceController}. */
 @RunWith(RobolectricTestRunner.class)
+@Config(shadows = {
+        com.android.settings.testutils.shadow.ShadowFragment.class,
+})
 public class ViewAllBluetoothDevicesPreferenceControllerTest {
 
     @Rule
diff --git a/tests/robotests/src/com/android/settings/accounts/AccountDetailDashboardFragmentTest.java b/tests/robotests/src/com/android/settings/accounts/AccountDetailDashboardFragmentTest.java
index cccca9c..d696ebb 100644
--- a/tests/robotests/src/com/android/settings/accounts/AccountDetailDashboardFragmentTest.java
+++ b/tests/robotests/src/com/android/settings/accounts/AccountDetailDashboardFragmentTest.java
@@ -63,7 +63,12 @@
 import org.robolectric.util.ReflectionHelpers;
 
 @RunWith(RobolectricTestRunner.class)
-@Config(shadows = {ShadowAccountManager.class, ShadowUserManager.class})
+@Config(shadows = {
+        ShadowAccountManager.class,
+        ShadowUserManager.class,
+        com.android.settings.testutils.shadow.ShadowDashboardFragment.class,
+        com.android.settings.testutils.shadow.ShadowFragment.class,
+})
 public class AccountDetailDashboardFragmentTest {
 
     private static final String METADATA_CATEGORY = "com.android.settings.category";
diff --git a/tests/robotests/src/com/android/settings/accounts/AccountSyncSettingsTest.java b/tests/robotests/src/com/android/settings/accounts/AccountSyncSettingsTest.java
index bdf1290..3bdfec2 100644
--- a/tests/robotests/src/com/android/settings/accounts/AccountSyncSettingsTest.java
+++ b/tests/robotests/src/com/android/settings/accounts/AccountSyncSettingsTest.java
@@ -41,7 +41,10 @@
 import org.robolectric.util.ReflectionHelpers;
 
 @RunWith(RobolectricTestRunner.class)
-@Config(shadows = {ShadowContentResolver.class})
+@Config(shadows = {
+        ShadowContentResolver.class,
+        com.android.settings.testutils.shadow.ShadowFragment.class,
+})
 public class AccountSyncSettingsTest {
     private Context mContext;
     private AccountSyncSettings mAccountSyncSettings;
diff --git a/tests/robotests/src/com/android/settings/accounts/AccountTypePreferenceLoaderTest.java b/tests/robotests/src/com/android/settings/accounts/AccountTypePreferenceLoaderTest.java
index 405f6b3..f5c588f 100644
--- a/tests/robotests/src/com/android/settings/accounts/AccountTypePreferenceLoaderTest.java
+++ b/tests/robotests/src/com/android/settings/accounts/AccountTypePreferenceLoaderTest.java
@@ -52,6 +52,9 @@
 import org.robolectric.shadows.ShadowApplication;
 
 @RunWith(RobolectricTestRunner.class)
+@Config(shadows = {
+        com.android.settings.testutils.shadow.ShadowFragment.class,
+})
 public class AccountTypePreferenceLoaderTest {
 
     @Mock(answer = RETURNS_DEEP_STUBS)
diff --git a/tests/robotests/src/com/android/settings/accounts/CrossProfileCalendarPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/accounts/CrossProfileCalendarPreferenceControllerTest.java
index b50fa5e..ca4fc59 100644
--- a/tests/robotests/src/com/android/settings/accounts/CrossProfileCalendarPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/accounts/CrossProfileCalendarPreferenceControllerTest.java
@@ -26,34 +26,31 @@
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
-import static org.robolectric.RuntimeEnvironment.application;
 
-import android.app.admin.DevicePolicyManager;
 import android.content.ComponentName;
 import android.content.Context;
 import android.os.UserHandle;
 import android.provider.Settings;
-import android.util.ArraySet;
 
+import com.android.settings.testutils.shadow.ShadowDevicePolicyManager;
 import com.android.settingslib.RestrictedSwitchPreference;
 
 import org.junit.Before;
-import org.junit.Ignore;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 import org.robolectric.RobolectricTestRunner;
 import org.robolectric.RuntimeEnvironment;
-import org.robolectric.Shadows;
-import org.robolectric.shadows.ShadowDevicePolicyManager;
+import org.robolectric.annotation.Config;
 
-import java.util.Arrays;
 import java.util.Collections;
 
 @RunWith(RobolectricTestRunner.class)
+@Config(shadows = {
+        ShadowDevicePolicyManager.class,
+})
 public class CrossProfileCalendarPreferenceControllerTest {
 
     private static final String PREF_KEY = "cross_profile_calendar";
@@ -76,7 +73,7 @@
         mController = new CrossProfileCalendarPreferenceController(mContext, PREF_KEY);
         mController.setManagedUser(mManagedUser);
         mPreference = spy(new RestrictedSwitchPreference(mContext));
-        dpm = Shadows.shadowOf(application.getSystemService(DevicePolicyManager.class));
+        dpm = ShadowDevicePolicyManager.getShadow();
 
         when(mManagedUser.getIdentifier()).thenReturn(MANAGED_USER_ID);
         doReturn(mContext).when(mContext).createPackageContextAsUser(
diff --git a/tests/robotests/src/com/android/settings/accounts/ManagedProfileQuietModeEnablerTest.java b/tests/robotests/src/com/android/settings/accounts/ManagedProfileQuietModeEnablerTest.java
index 2698efa..81c44df 100644
--- a/tests/robotests/src/com/android/settings/accounts/ManagedProfileQuietModeEnablerTest.java
+++ b/tests/robotests/src/com/android/settings/accounts/ManagedProfileQuietModeEnablerTest.java
@@ -43,11 +43,13 @@
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 import org.robolectric.RobolectricTestRunner;
+import org.robolectric.annotation.LooperMode;
 
 import java.util.Collections;
 
 
 @RunWith(RobolectricTestRunner.class)
+@LooperMode(LooperMode.Mode.LEGACY)
 public class ManagedProfileQuietModeEnablerTest {
     private static final int MANAGED_USER_ID = 10;
     private Context mContext;
diff --git a/tests/robotests/src/com/android/settings/accounts/RemoveAccountPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/accounts/RemoveAccountPreferenceControllerTest.java
index 6eb5abb..8d8f0c1 100644
--- a/tests/robotests/src/com/android/settings/accounts/RemoveAccountPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/accounts/RemoveAccountPreferenceControllerTest.java
@@ -35,13 +35,10 @@
 import android.accounts.AuthenticatorException;
 import android.accounts.OperationCanceledException;
 import android.app.Activity;
-import android.content.ComponentName;
 import android.content.Context;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.UserHandle;
-import android.os.UserManager;
-import android.widget.Button;
 
 import androidx.fragment.app.FragmentActivity;
 import androidx.fragment.app.FragmentManager;
@@ -57,11 +54,11 @@
 import com.android.settings.testutils.shadow.ShadowFragment;
 import com.android.settings.testutils.shadow.ShadowUserManager;
 import com.android.settings.utils.ActivityControllerWrapper;
+import com.android.settings.widget.RestrictedButton;
 import com.android.settingslib.widget.LayoutPreference;
 
 import org.junit.After;
 import org.junit.Before;
-import org.junit.Ignore;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.ArgumentCaptor;
@@ -74,13 +71,12 @@
 import org.robolectric.shadows.ShadowApplication;
 
 import java.io.IOException;
-import java.util.ArrayList;
-import java.util.List;
 
 @RunWith(RobolectricTestRunner.class)
 @Config(shadows = {
         ShadowUserManager.class,
-        ShadowDevicePolicyManager.class
+        ShadowDevicePolicyManager.class,
+        ShadowFragment.class,
 })
 public class RemoveAccountPreferenceControllerTest {
 
@@ -129,7 +125,7 @@
     @Test
     public void displayPreference_shouldAddClickListener() {
         when(mScreen.findPreference(KEY_REMOVE_ACCOUNT)).thenReturn(mPreference);
-        final Button button = mock(Button.class);
+        final RestrictedButton button = mock(RestrictedButton.class);
         when(mPreference.findViewById(R.id.button)).thenReturn(button);
 
         mController.displayPreference(mScreen);
@@ -147,32 +143,6 @@
                 eq(TAG_REMOVE_ACCOUNT_DIALOG));
     }
 
-    @Ignore
-    @Test
-    public void onClick_modifyAccountsIsDisallowed_shouldNotStartConfirmDialog() {
-        when(mFragment.isAdded()).thenReturn(true);
-
-        final int userId = UserHandle.myUserId();
-        mController.init(new Account("test", "test"), UserHandle.of(userId));
-
-        List<UserManager.EnforcingUser> enforcingUsers = new ArrayList<>();
-        enforcingUsers.add(new UserManager.EnforcingUser(userId,
-                UserManager.RESTRICTION_SOURCE_DEVICE_OWNER));
-        ComponentName componentName = new ComponentName("test", "test");
-        // Ensure that RestrictedLockUtils.checkIfRestrictionEnforced doesn't return null.
-        ShadowUserManager.getShadow().setUserRestrictionSources(
-                UserManager.DISALLOW_MODIFY_ACCOUNTS,
-                UserHandle.of(userId),
-                enforcingUsers);
-        ShadowDevicePolicyManager.getShadow().setDeviceOwnerComponentOnAnyUser(componentName);
-
-        mController.onClick(null);
-
-        verify(mFragmentTransaction, never()).add(
-                any(RemoveAccountPreferenceController.ConfirmRemoveAccountDialog.class),
-                eq(TAG_REMOVE_ACCOUNT_DIALOG));
-    }
-
     @Test
     @Config(shadows = {ShadowAccountManager.class, ShadowContentResolver.class,
             ShadowFragment.class})
diff --git a/tests/robotests/src/com/android/settings/applications/AppWithAdminGrantedPermissionsCounterTest.java b/tests/robotests/src/com/android/settings/applications/AppWithAdminGrantedPermissionsCounterTest.java
index 71c532c..8740662 100644
--- a/tests/robotests/src/com/android/settings/applications/AppWithAdminGrantedPermissionsCounterTest.java
+++ b/tests/robotests/src/com/android/settings/applications/AppWithAdminGrantedPermissionsCounterTest.java
@@ -45,12 +45,14 @@
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 import org.robolectric.RobolectricTestRunner;
+import org.robolectric.annotation.LooperMode;
 import org.robolectric.shadows.ShadowApplication;
 
 import java.util.Arrays;
 import java.util.Collections;
 
 @RunWith(RobolectricTestRunner.class)
+@LooperMode(LooperMode.Mode.LEGACY)
 public final class AppWithAdminGrantedPermissionsCounterTest {
 
     private final String APP_1 = "app1";
diff --git a/tests/robotests/src/com/android/settings/applications/AppWithAdminGrantedPermissionsListerTest.java b/tests/robotests/src/com/android/settings/applications/AppWithAdminGrantedPermissionsListerTest.java
index 9a4978b..f08a9db 100644
--- a/tests/robotests/src/com/android/settings/applications/AppWithAdminGrantedPermissionsListerTest.java
+++ b/tests/robotests/src/com/android/settings/applications/AppWithAdminGrantedPermissionsListerTest.java
@@ -42,6 +42,7 @@
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 import org.robolectric.RobolectricTestRunner;
+import org.robolectric.annotation.LooperMode;
 import org.robolectric.shadows.ShadowApplication;
 
 import java.util.Arrays;
@@ -49,6 +50,7 @@
 import java.util.List;
 
 @RunWith(RobolectricTestRunner.class)
+@LooperMode(LooperMode.Mode.LEGACY)
 public final class AppWithAdminGrantedPermissionsListerTest {
 
     private final String APP_1 = "app1";
diff --git a/tests/robotests/src/com/android/settings/applications/ApplicationFeatureProviderImplTest.java b/tests/robotests/src/com/android/settings/applications/ApplicationFeatureProviderImplTest.java
index 7044389..4eb623d 100644
--- a/tests/robotests/src/com/android/settings/applications/ApplicationFeatureProviderImplTest.java
+++ b/tests/robotests/src/com/android/settings/applications/ApplicationFeatureProviderImplTest.java
@@ -50,6 +50,7 @@
 import org.robolectric.RobolectricTestRunner;
 import org.robolectric.RuntimeEnvironment;
 import org.robolectric.annotation.Config;
+import org.robolectric.annotation.LooperMode;
 import org.robolectric.shadows.ShadowApplication;
 import org.robolectric.util.ReflectionHelpers;
 
@@ -62,6 +63,7 @@
  * Tests for {@link ApplicationFeatureProviderImpl}.
  */
 @RunWith(RobolectricTestRunner.class)
+@LooperMode(LooperMode.Mode.LEGACY)
 public final class ApplicationFeatureProviderImplTest {
 
     private final int MAIN_USER_ID = 0;
diff --git a/tests/robotests/src/com/android/settings/applications/InstalledAppCounterTest.java b/tests/robotests/src/com/android/settings/applications/InstalledAppCounterTest.java
index 2c1fab8..cd9cdd6 100644
--- a/tests/robotests/src/com/android/settings/applications/InstalledAppCounterTest.java
+++ b/tests/robotests/src/com/android/settings/applications/InstalledAppCounterTest.java
@@ -45,6 +45,7 @@
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 import org.robolectric.RobolectricTestRunner;
+import org.robolectric.annotation.LooperMode;
 import org.robolectric.shadows.ShadowApplication;
 
 import java.util.ArrayList;
@@ -53,6 +54,7 @@
 import java.util.Set;
 
 @RunWith(RobolectricTestRunner.class)
+@LooperMode(LooperMode.Mode.LEGACY)
 public final class InstalledAppCounterTest {
 
     private final String APP_1 = "app1";
diff --git a/tests/robotests/src/com/android/settings/applications/InstalledAppListerTest.java b/tests/robotests/src/com/android/settings/applications/InstalledAppListerTest.java
index 602d678..1287d13 100644
--- a/tests/robotests/src/com/android/settings/applications/InstalledAppListerTest.java
+++ b/tests/robotests/src/com/android/settings/applications/InstalledAppListerTest.java
@@ -43,6 +43,7 @@
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 import org.robolectric.RobolectricTestRunner;
+import org.robolectric.annotation.LooperMode;
 import org.robolectric.shadows.ShadowApplication;
 
 import java.util.Arrays;
@@ -52,6 +53,7 @@
 import java.util.Set;
 
 @RunWith(RobolectricTestRunner.class)
+@LooperMode(LooperMode.Mode.LEGACY)
 public final class InstalledAppListerTest {
 
     private final String APP_1 = "app1";
diff --git a/tests/robotests/src/com/android/settings/applications/OpenSupportedLinksTest.java b/tests/robotests/src/com/android/settings/applications/OpenSupportedLinksTest.java
index 7712ae8..355b5db 100644
--- a/tests/robotests/src/com/android/settings/applications/OpenSupportedLinksTest.java
+++ b/tests/robotests/src/com/android/settings/applications/OpenSupportedLinksTest.java
@@ -49,9 +49,14 @@
 import org.robolectric.RobolectricTestRunner;
 import org.robolectric.RuntimeEnvironment;
 import org.robolectric.annotation.Config;
+import org.robolectric.annotation.LooperMode;
 
 @RunWith(RobolectricTestRunner.class)
-@Config(shadows = ShadowUtils.class)
+@LooperMode(LooperMode.Mode.LEGACY)
+@Config(shadows = {
+        ShadowUtils.class,
+        com.android.settings.testutils.shadow.ShadowFragment.class,
+})
 public class OpenSupportedLinksTest {
     private static final String TEST_FOOTER_TITLE = "FooterTitle";
     private static final String TEST_DOMAIN_LINK = "aaa.bbb.ccc";
diff --git a/tests/robotests/src/com/android/settings/applications/appinfo/AppBatteryPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/applications/appinfo/AppBatteryPreferenceControllerTest.java
index 6f0aec9..5ca7415 100644
--- a/tests/robotests/src/com/android/settings/applications/appinfo/AppBatteryPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/applications/appinfo/AppBatteryPreferenceControllerTest.java
@@ -56,6 +56,9 @@
 import java.util.List;
 
 @RunWith(RobolectricTestRunner.class)
+@Config(shadows = {
+        com.android.settings.testutils.shadow.ShadowFragment.class,
+})
 public class AppBatteryPreferenceControllerTest {
 
     private static final int TARGET_UID = 111;
diff --git a/tests/robotests/src/com/android/settings/applications/appinfo/AppHeaderViewPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/applications/appinfo/AppHeaderViewPreferenceControllerTest.java
index b12c8db..46eac83 100644
--- a/tests/robotests/src/com/android/settings/applications/appinfo/AppHeaderViewPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/applications/appinfo/AppHeaderViewPreferenceControllerTest.java
@@ -51,7 +51,10 @@
 import org.robolectric.annotation.Config;
 
 @RunWith(RobolectricTestRunner.class)
-@Config(shadows = ShadowSettingsLibUtils.class)
+@Config(shadows = {
+        ShadowSettingsLibUtils.class,
+        com.android.settings.testutils.shadow.ShadowFragment.class,
+})
 public class AppHeaderViewPreferenceControllerTest {
 
     @Mock
diff --git a/tests/robotests/src/com/android/settings/applications/appinfo/AppInfoDashboardFragmentTest.java b/tests/robotests/src/com/android/settings/applications/appinfo/AppInfoDashboardFragmentTest.java
index ecf98a7..87e4a8f 100644
--- a/tests/robotests/src/com/android/settings/applications/appinfo/AppInfoDashboardFragmentTest.java
+++ b/tests/robotests/src/com/android/settings/applications/appinfo/AppInfoDashboardFragmentTest.java
@@ -76,6 +76,9 @@
 import java.util.Set;
 
 @RunWith(RobolectricTestRunner.class)
+@Config(shadows = {
+        com.android.settings.testutils.shadow.ShadowFragment.class,
+})
 public final class AppInfoDashboardFragmentTest {
 
     private static final String PACKAGE_NAME = "test_package_name";
diff --git a/tests/robotests/src/com/android/settings/applications/appinfo/AppInfoPreferenceControllerBaseTest.java b/tests/robotests/src/com/android/settings/applications/appinfo/AppInfoPreferenceControllerBaseTest.java
index 71ba753..c14bcb5 100644
--- a/tests/robotests/src/com/android/settings/applications/appinfo/AppInfoPreferenceControllerBaseTest.java
+++ b/tests/robotests/src/com/android/settings/applications/appinfo/AppInfoPreferenceControllerBaseTest.java
@@ -46,8 +46,12 @@
 import org.mockito.MockitoAnnotations;
 import org.robolectric.RobolectricTestRunner;
 import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
 
 @RunWith(RobolectricTestRunner.class)
+@Config(shadows = {
+        com.android.settings.testutils.shadow.ShadowFragment.class,
+})
 public class AppInfoPreferenceControllerBaseTest {
 
     @Mock
diff --git a/tests/robotests/src/com/android/settings/applications/appinfo/AppMemoryPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/applications/appinfo/AppMemoryPreferenceControllerTest.java
index e433dd3..e948b7e 100644
--- a/tests/robotests/src/com/android/settings/applications/appinfo/AppMemoryPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/applications/appinfo/AppMemoryPreferenceControllerTest.java
@@ -49,7 +49,10 @@
 import org.robolectric.util.ReflectionHelpers;
 
 @RunWith(RobolectricTestRunner.class)
-@Config(shadows = {ShadowUserManager.class})
+@Config(shadows = {
+        ShadowUserManager.class,
+        com.android.settings.testutils.shadow.ShadowFragment.class,
+})
 public class AppMemoryPreferenceControllerTest {
 
     @Mock
diff --git a/tests/robotests/src/com/android/settings/applications/appinfo/AppNotificationPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/applications/appinfo/AppNotificationPreferenceControllerTest.java
index 3b366ca..f6ee7ce 100644
--- a/tests/robotests/src/com/android/settings/applications/appinfo/AppNotificationPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/applications/appinfo/AppNotificationPreferenceControllerTest.java
@@ -35,8 +35,8 @@
 import androidx.preference.Preference;
 import androidx.preference.PreferenceScreen;
 
-import com.android.settings.notification.app.AppNotificationSettings;
 import com.android.settings.notification.NotificationBackend;
+import com.android.settings.notification.app.AppNotificationSettings;
 import com.android.settingslib.applications.ApplicationsState;
 
 import org.junit.Before;
@@ -46,9 +46,13 @@
 import org.mockito.MockitoAnnotations;
 import org.robolectric.RobolectricTestRunner;
 import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
 import org.robolectric.util.ReflectionHelpers;
 
 @RunWith(RobolectricTestRunner.class)
+@Config(shadows = {
+        com.android.settings.testutils.shadow.ShadowFragment.class,
+})
 public class AppNotificationPreferenceControllerTest {
 
     @Mock
diff --git a/tests/robotests/src/com/android/settings/applications/appinfo/AppPermissionPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/applications/appinfo/AppPermissionPreferenceControllerTest.java
index 41ff9ed..b610d8c 100644
--- a/tests/robotests/src/com/android/settings/applications/appinfo/AppPermissionPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/applications/appinfo/AppPermissionPreferenceControllerTest.java
@@ -44,11 +44,15 @@
 import org.mockito.MockitoAnnotations;
 import org.robolectric.RobolectricTestRunner;
 import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
 import org.robolectric.util.ReflectionHelpers;
 
 import java.util.ArrayList;
 
 @RunWith(RobolectricTestRunner.class)
+@Config(shadows = {
+        com.android.settings.testutils.shadow.ShadowFragment.class,
+})
 public class AppPermissionPreferenceControllerTest {
 
     @Mock
diff --git a/tests/robotests/src/com/android/settings/applications/appinfo/InstantAppButtonDialogFragmentTest.java b/tests/robotests/src/com/android/settings/applications/appinfo/InstantAppButtonDialogFragmentTest.java
index 805cdd2..d035a64 100644
--- a/tests/robotests/src/com/android/settings/applications/appinfo/InstantAppButtonDialogFragmentTest.java
+++ b/tests/robotests/src/com/android/settings/applications/appinfo/InstantAppButtonDialogFragmentTest.java
@@ -44,8 +44,10 @@
 import org.robolectric.RobolectricTestRunner;
 import org.robolectric.RuntimeEnvironment;
 import org.robolectric.annotation.Config;
+import org.robolectric.annotation.LooperMode;
 
 @RunWith(RobolectricTestRunner.class)
+@LooperMode(LooperMode.Mode.LEGACY)
 @Config(shadows = ShadowAlertDialogCompat.class)
 public class InstantAppButtonDialogFragmentTest {
 
diff --git a/tests/robotests/src/com/android/settings/applications/appinfo/InstantAppButtonsPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/applications/appinfo/InstantAppButtonsPreferenceControllerTest.java
index a4277dd..9d6332e 100644
--- a/tests/robotests/src/com/android/settings/applications/appinfo/InstantAppButtonsPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/applications/appinfo/InstantAppButtonsPreferenceControllerTest.java
@@ -61,9 +61,13 @@
 import org.mockito.MockitoAnnotations;
 import org.robolectric.RobolectricTestRunner;
 import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
 import org.robolectric.util.ReflectionHelpers;
 
 @RunWith(RobolectricTestRunner.class)
+@Config(shadows = {
+        com.android.settings.testutils.shadow.ShadowFragment.class,
+})
 public class InstantAppButtonsPreferenceControllerTest {
 
     private static final String TEST_INSTALLER_PACKAGE_NAME = "com.installer";
diff --git a/tests/robotests/src/com/android/settings/applications/defaultapps/DefaultAppPickerFragmentTest.java b/tests/robotests/src/com/android/settings/applications/defaultapps/DefaultAppPickerFragmentTest.java
index 2a63f53..fdf7c0d 100644
--- a/tests/robotests/src/com/android/settings/applications/defaultapps/DefaultAppPickerFragmentTest.java
+++ b/tests/robotests/src/com/android/settings/applications/defaultapps/DefaultAppPickerFragmentTest.java
@@ -42,11 +42,15 @@
 import org.robolectric.Robolectric;
 import org.robolectric.RobolectricTestRunner;
 import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
 
 import java.util.ArrayList;
 import java.util.List;
 
 @RunWith(RobolectricTestRunner.class)
+@Config(shadows = {
+        com.android.settings.testutils.shadow.ShadowFragment.class,
+})
 public class DefaultAppPickerFragmentTest {
 
     @Mock
diff --git a/tests/robotests/src/com/android/settings/applications/defaultapps/DefaultAutofillPickerTest.java b/tests/robotests/src/com/android/settings/applications/defaultapps/DefaultAutofillPickerTest.java
index 8fcdaa2..259163e 100644
--- a/tests/robotests/src/com/android/settings/applications/defaultapps/DefaultAutofillPickerTest.java
+++ b/tests/robotests/src/com/android/settings/applications/defaultapps/DefaultAutofillPickerTest.java
@@ -58,7 +58,10 @@
 import java.util.Arrays;
 
 @RunWith(RobolectricTestRunner.class)
-@Config(shadows = ShadowSecureSettings.class)
+@Config(shadows = {
+        ShadowSecureSettings.class,
+        ShadowFragment.class,
+})
 public class DefaultAutofillPickerTest {
 
     private static final String MAIN_APP_KEY = "main.foo.bar/foo.bar.Baz";
diff --git a/tests/robotests/src/com/android/settings/applications/manageapplications/ManageApplicationsTest.java b/tests/robotests/src/com/android/settings/applications/manageapplications/ManageApplicationsTest.java
index 0622948..d3ae4e3 100644
--- a/tests/robotests/src/com/android/settings/applications/manageapplications/ManageApplicationsTest.java
+++ b/tests/robotests/src/com/android/settings/applications/manageapplications/ManageApplicationsTest.java
@@ -76,8 +76,12 @@
 import java.util.ArrayList;
 
 @RunWith(RobolectricTestRunner.class)
-@Config(shadows = {ShadowUserManager.class, ShadowAppUtils.class,
-        ShadowInteractionJankMonitor.class})
+@Config(shadows = {
+        ShadowUserManager.class,
+        ShadowAppUtils.class,
+        ShadowInteractionJankMonitor.class,
+        com.android.settings.testutils.shadow.ShadowFragment.class,
+})
 public class ManageApplicationsTest {
 
     @Mock
diff --git a/tests/robotests/src/com/android/settings/applications/specialaccess/interactacrossprofiles/InteractAcrossProfilesControllerTest.java b/tests/robotests/src/com/android/settings/applications/specialaccess/interactacrossprofiles/InteractAcrossProfilesControllerTest.java
index 730a3cc..eef7f7c 100644
--- a/tests/robotests/src/com/android/settings/applications/specialaccess/interactacrossprofiles/InteractAcrossProfilesControllerTest.java
+++ b/tests/robotests/src/com/android/settings/applications/specialaccess/interactacrossprofiles/InteractAcrossProfilesControllerTest.java
@@ -31,8 +31,12 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.robolectric.RobolectricTestRunner;
+import org.robolectric.annotation.Config;
 
 @RunWith(RobolectricTestRunner.class)
+@Config(shadows = {
+        com.android.settings.testutils.shadow.ShadowUserManager.class,
+})
 public class InteractAcrossProfilesControllerTest {
     private static final int PERSONAL_PROFILE_ID = 0;
     private static final int WORK_PROFILE_ID = 10;
diff --git a/tests/robotests/src/com/android/settings/applications/specialaccess/interactacrossprofiles/InteractAcrossProfilesDetailsTest.java b/tests/robotests/src/com/android/settings/applications/specialaccess/interactacrossprofiles/InteractAcrossProfilesDetailsTest.java
index edd85e4..61230b8 100644
--- a/tests/robotests/src/com/android/settings/applications/specialaccess/interactacrossprofiles/InteractAcrossProfilesDetailsTest.java
+++ b/tests/robotests/src/com/android/settings/applications/specialaccess/interactacrossprofiles/InteractAcrossProfilesDetailsTest.java
@@ -23,22 +23,32 @@
 import android.content.Context;
 import android.content.PermissionChecker;
 import android.content.pm.CrossProfileApps;
-import android.content.pm.PackageManager;
 import android.content.pm.UserInfo;
 import android.os.UserManager;
 
 import androidx.test.core.app.ApplicationProvider;
 
 import com.android.settings.R;
+import com.android.settings.testutils.shadow.ShadowApplicationPackageManager;
+import com.android.settings.testutils.shadow.ShadowCrossProfileApps;
+import com.android.settings.testutils.shadow.ShadowUserManager;
+import com.android.settingslib.testutils.shadow.ShadowPermissionChecker;
 
 import com.google.common.collect.ImmutableList;
 
+import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.robolectric.RobolectricTestRunner;
-import org.robolectric.shadows.ShadowPermissionChecker;
+import org.robolectric.annotation.Config;
 
 @RunWith(RobolectricTestRunner.class)
+@Config(shadows = {
+        ShadowApplicationPackageManager.class,
+        ShadowCrossProfileApps.class,
+        ShadowUserManager.class,
+        ShadowPermissionChecker.class,
+})
 public class InteractAcrossProfilesDetailsTest {
 
     private static final int PERSONAL_PROFILE_ID = 0;
@@ -48,23 +58,34 @@
             "android.permission.INTERACT_ACROSS_PROFILES";
 
     private final Context mContext = ApplicationProvider.getApplicationContext();
-    private final PackageManager mPackageManager = mContext.getPackageManager();
-    private final UserManager mUserManager = mContext.getSystemService(UserManager.class);
-    private final CrossProfileApps mCrossProfileApps = mContext.getSystemService(
-            CrossProfileApps.class);
+    private ShadowUserManager mShadowUserManager;
+    private ShadowCrossProfileApps mShadowCrossProfileApps;
+    private ShadowApplicationPackageManager mShadowPackageManager;
+
+    @Before
+    public void setUp() {
+        mShadowUserManager = (ShadowUserManager) shadowOf(
+                mContext.getSystemService(UserManager.class)
+        );
+        mShadowCrossProfileApps = (ShadowCrossProfileApps) shadowOf(
+                mContext.getSystemService(CrossProfileApps.class)
+        );
+        mShadowPackageManager =
+                (ShadowApplicationPackageManager) shadowOf(mContext.getPackageManager());
+    }
 
     @Test
     public void getPreferenceSummary_appOpAllowed_returnsAllowed() {
-        shadowOf(mUserManager).addUser(
+        mShadowUserManager.addUser(
                 PERSONAL_PROFILE_ID, "personal-profile"/* name */, 0/* flags */);
-        shadowOf(mUserManager).addProfile(
+        mShadowUserManager.addProfile(
                 PERSONAL_PROFILE_ID, WORK_PROFILE_ID,
                 "work-profile"/* profileName */, UserInfo.FLAG_MANAGED_PROFILE);
-        shadowOf(mPackageManager).setInstalledPackagesForUserId(
+        mShadowPackageManager.setInstalledPackagesForUserId(
                 PERSONAL_PROFILE_ID, ImmutableList.of(CROSS_PROFILE_PACKAGE_NAME));
-        shadowOf(mPackageManager).setInstalledPackagesForUserId(
+        mShadowPackageManager.setInstalledPackagesForUserId(
                 WORK_PROFILE_ID, ImmutableList.of(CROSS_PROFILE_PACKAGE_NAME));
-        shadowOf(mCrossProfileApps).addCrossProfilePackage(
+        mShadowCrossProfileApps.addCrossProfilePackage(
                 CROSS_PROFILE_PACKAGE_NAME);
         ShadowPermissionChecker.setResult(
                 CROSS_PROFILE_PACKAGE_NAME,
@@ -78,16 +99,16 @@
 
     @Test
     public void getPreferenceSummary_appOpNotAllowed_returnsNotAllowed() {
-        shadowOf(mUserManager).addUser(
+        mShadowUserManager.addUser(
                 PERSONAL_PROFILE_ID, "personal-profile"/* name */, 0/* flags */);
-        shadowOf(mUserManager).addProfile(
+        mShadowUserManager.addProfile(
                 PERSONAL_PROFILE_ID, WORK_PROFILE_ID,
                 "work-profile"/* profileName */, UserInfo.FLAG_MANAGED_PROFILE);
-        shadowOf(mPackageManager).setInstalledPackagesForUserId(
+        mShadowPackageManager.setInstalledPackagesForUserId(
                 PERSONAL_PROFILE_ID, ImmutableList.of(CROSS_PROFILE_PACKAGE_NAME));
-        shadowOf(mPackageManager).setInstalledPackagesForUserId(
+        mShadowPackageManager.setInstalledPackagesForUserId(
                 WORK_PROFILE_ID, ImmutableList.of(CROSS_PROFILE_PACKAGE_NAME));
-        shadowOf(mCrossProfileApps).addCrossProfilePackage(
+        mShadowCrossProfileApps.addCrossProfilePackage(
                 CROSS_PROFILE_PACKAGE_NAME);
         ShadowPermissionChecker.setResult(
                 CROSS_PROFILE_PACKAGE_NAME,
@@ -101,9 +122,9 @@
 
     @Test
     public void getPreferenceSummary_noWorkProfile_returnsNotAllowed() {
-        shadowOf(mUserManager).addUser(
+        mShadowUserManager.addUser(
                 PERSONAL_PROFILE_ID, "personal-profile"/* name */, 0/* flags */);
-        shadowOf(mPackageManager).setInstalledPackagesForUserId(
+        mShadowPackageManager.setInstalledPackagesForUserId(
                 PERSONAL_PROFILE_ID, ImmutableList.of(CROSS_PROFILE_PACKAGE_NAME));
 
         assertThat(InteractAcrossProfilesDetails.getPreferenceSummary(
diff --git a/tests/robotests/src/com/android/settings/applications/specialaccess/interactacrossprofiles/InteractAcrossProfilesPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/applications/specialaccess/interactacrossprofiles/InteractAcrossProfilesPreferenceControllerTest.java
index 8479035..5c55c76 100644
--- a/tests/robotests/src/com/android/settings/applications/specialaccess/interactacrossprofiles/InteractAcrossProfilesPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/applications/specialaccess/interactacrossprofiles/InteractAcrossProfilesPreferenceControllerTest.java
@@ -21,20 +21,28 @@
 import static org.robolectric.Shadows.shadowOf;
 
 import android.content.Context;
+import android.content.pm.CrossProfileApps;
 import android.content.pm.PackageInfo;
-import android.content.pm.PackageManager;
 
 import androidx.test.core.app.ApplicationProvider;
 
 import com.android.settings.core.BasePreferenceController;
+import com.android.settings.testutils.shadow.ShadowApplicationPackageManager;
+import com.android.settings.testutils.shadow.ShadowCrossProfileApps;
 
 import com.google.common.collect.ImmutableList;
 
+import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.robolectric.RobolectricTestRunner;
+import org.robolectric.annotation.Config;
 
 @RunWith(RobolectricTestRunner.class)
+@Config(shadows = {
+        ShadowApplicationPackageManager.class,
+        ShadowCrossProfileApps.class,
+})
 public class InteractAcrossProfilesPreferenceControllerTest {
 
     private static final String CROSS_PROFILE_PACKAGE_NAME = "crossProfilePackage";
@@ -44,16 +52,27 @@
     private static final int PROFILE_ID = 0;
 
     private final Context mContext = ApplicationProvider.getApplicationContext();
-    private final PackageManager mPackageManager = mContext.getPackageManager();
+    private ShadowApplicationPackageManager mShadowPackageManager;
     private final InteractAcrossProfilesDetailsPreferenceController mController =
             new InteractAcrossProfilesDetailsPreferenceController(mContext, "test_key");
 
+    @Before
+    public void setUp() {
+        mShadowPackageManager = (ShadowApplicationPackageManager) shadowOf(
+                mContext.getPackageManager()
+        );
+    }
+
     @Test
     public void getAvailabilityStatus_requestedCrossProfilePermission_returnsAvailable() {
         mController.setPackageName(CROSS_PROFILE_PACKAGE_NAME);
-        shadowOf(mPackageManager).setInstalledPackagesForUserId(
+        mShadowPackageManager.setInstalledPackagesForUserId(
                 PROFILE_ID, ImmutableList.of(CROSS_PROFILE_PACKAGE_NAME));
-        PackageInfo packageInfo = shadowOf(mPackageManager).getInternalMutablePackageInfo(
+        ShadowCrossProfileApps shadowCrossProfileApps = (ShadowCrossProfileApps) shadowOf(
+                mContext.getSystemService(CrossProfileApps.class)
+        );
+        shadowCrossProfileApps.addCrossProfilePackage(CROSS_PROFILE_PACKAGE_NAME);
+        PackageInfo packageInfo = mShadowPackageManager.getInternalMutablePackageInfo(
                 CROSS_PROFILE_PACKAGE_NAME);
         packageInfo.requestedPermissions = new String[]{
                 INTERACT_ACROSS_PROFILES_PERMISSION};
@@ -65,8 +84,12 @@
     @Test
     public void getAvailabilityStatus_notRequestedCrossProfilePermission_returnsDisabled() {
         mController.setPackageName(NOT_CROSS_PROFILE_PACKAGE_NAME);
-        shadowOf(mPackageManager).setInstalledPackagesForUserId(
+        mShadowPackageManager.setInstalledPackagesForUserId(
                 PROFILE_ID, ImmutableList.of(NOT_CROSS_PROFILE_PACKAGE_NAME));
+        ShadowCrossProfileApps shadowCrossProfileApps = (ShadowCrossProfileApps) shadowOf(
+                mContext.getSystemService(CrossProfileApps.class)
+        );
+        shadowCrossProfileApps.addCrossProfilePackage(NOT_CROSS_PROFILE_PACKAGE_NAME);
 
         assertThat(mController.getAvailabilityStatus())
                 .isEqualTo(BasePreferenceController.DISABLED_FOR_USER);
diff --git a/tests/robotests/src/com/android/settings/applications/specialaccess/interactacrossprofiles/InteractAcrossProfilesSettingsTest.java b/tests/robotests/src/com/android/settings/applications/specialaccess/interactacrossprofiles/InteractAcrossProfilesSettingsTest.java
index 029fb28..436ed92 100644
--- a/tests/robotests/src/com/android/settings/applications/specialaccess/interactacrossprofiles/InteractAcrossProfilesSettingsTest.java
+++ b/tests/robotests/src/com/android/settings/applications/specialaccess/interactacrossprofiles/InteractAcrossProfilesSettingsTest.java
@@ -34,17 +34,28 @@
 
 import androidx.test.core.app.ApplicationProvider;
 
+import com.android.settings.testutils.shadow.ShadowApplicationPackageManager;
+import com.android.settings.testutils.shadow.ShadowCrossProfileApps;
+import com.android.settings.testutils.shadow.ShadowUserManager;
+import com.android.settingslib.testutils.shadow.ShadowPermissionChecker;
+
 import com.google.common.collect.ImmutableList;
 
+import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.robolectric.RobolectricTestRunner;
-import org.robolectric.shadows.ShadowPermissionChecker;
+import org.robolectric.annotation.Config;
 import org.robolectric.shadows.ShadowProcess;
 
 import java.util.List;
 
 @RunWith(RobolectricTestRunner.class)
+@Config(shadows = {
+        ShadowUserManager.class,
+        ShadowApplicationPackageManager.class,
+        ShadowCrossProfileApps.class,
+})
 public class InteractAcrossProfilesSettingsTest {
 
     private static final int PERSONAL_PROFILE_ID = 0;
@@ -70,16 +81,33 @@
     private final CrossProfileApps mCrossProfileApps =
             mContext.getSystemService(CrossProfileApps.class);
 
+    private ShadowApplicationPackageManager mShadowPackageManager;
+    private ShadowUserManager mShadowUserManager;
+    private ShadowCrossProfileApps mShadowCrossProfileApps;
+
+    @Before
+    public void setUp() {
+        mShadowUserManager = (ShadowUserManager) shadowOf(
+                mContext.getSystemService(UserManager.class)
+        );
+        mShadowCrossProfileApps = (ShadowCrossProfileApps) shadowOf(
+                mContext.getSystemService(CrossProfileApps.class)
+        );
+        mShadowPackageManager = (ShadowApplicationPackageManager) shadowOf(
+                mContext.getPackageManager()
+        );
+    }
+
     @Test
     public void collectConfigurableApps_fromPersonal_returnsCombinedPackages() {
-        shadowOf(mUserManager).addUser(
+        mShadowUserManager.addUser(
                 PERSONAL_PROFILE_ID, "personal-profile"/* name */, 0/* flags */);
-        shadowOf(mUserManager).addProfile(
+        mShadowUserManager.addProfile(
                 PERSONAL_PROFILE_ID, WORK_PROFILE_ID,
                 "work-profile"/* profileName */, UserInfo.FLAG_MANAGED_PROFILE);
-        shadowOf(mPackageManager).setInstalledPackagesForUserId(
+        mShadowPackageManager.setInstalledPackagesForUserId(
                 PERSONAL_PROFILE_ID, PERSONAL_PROFILE_INSTALLED_PACKAGES);
-        shadowOf(mPackageManager).setInstalledPackagesForUserId(
+        mShadowPackageManager.setInstalledPackagesForUserId(
                 WORK_PROFILE_ID, WORK_PROFILE_INSTALLED_PACKAGES);
         installCrossProfilePackage(PERSONAL_CROSS_PROFILE_PACKAGE);
         installCrossProfilePackage(WORK_CROSS_PROFILE_PACKAGE);
@@ -97,15 +125,15 @@
 
     @Test
     public void collectConfigurableApps_fromWork_returnsCombinedPackages() {
-        shadowOf(mUserManager).addUser(
+        mShadowUserManager.addUser(
                 PERSONAL_PROFILE_ID, "personal-profile"/* name */, 0/* flags */);
-        shadowOf(mUserManager).addProfile(
+        mShadowUserManager.addProfile(
                 PERSONAL_PROFILE_ID, WORK_PROFILE_ID,
                 "work-profile"/* profileName */, UserInfo.FLAG_MANAGED_PROFILE);
         ShadowProcess.setUid(WORK_UID);
-        shadowOf(mPackageManager).setInstalledPackagesForUserId(
+        mShadowPackageManager.setInstalledPackagesForUserId(
                 PERSONAL_PROFILE_ID, PERSONAL_PROFILE_INSTALLED_PACKAGES);
-        shadowOf(mPackageManager).setInstalledPackagesForUserId(
+        mShadowPackageManager.setInstalledPackagesForUserId(
                 WORK_PROFILE_ID, WORK_PROFILE_INSTALLED_PACKAGES);
         installCrossProfilePackage(PERSONAL_CROSS_PROFILE_PACKAGE);
         installCrossProfilePackage(WORK_CROSS_PROFILE_PACKAGE);
@@ -123,9 +151,9 @@
 
     @Test
     public void collectConfigurableApps_onlyOneProfile_returnsEmpty() {
-        shadowOf(mUserManager).addUser(
+        mShadowUserManager.addUser(
                 PERSONAL_PROFILE_ID, "personal-profile"/* name */, 0/* flags */);
-        shadowOf(mPackageManager).setInstalledPackagesForUserId(
+        mShadowPackageManager.setInstalledPackagesForUserId(
                 PERSONAL_PROFILE_ID, PERSONAL_PROFILE_INSTALLED_PACKAGES);
         installCrossProfilePackage(PERSONAL_CROSS_PROFILE_PACKAGE);
 
@@ -138,18 +166,18 @@
 
     @Test
     public void getNumberOfEnabledApps_returnsNumberOfEnabledApps() {
-        shadowOf(mUserManager).addUser(
+        mShadowUserManager.addUser(
                 PERSONAL_PROFILE_ID, "personal-profile"/* name */, 0/* flags */);
-        shadowOf(mUserManager).addProfile(
+        mShadowUserManager.addProfile(
                 PERSONAL_PROFILE_ID, WORK_PROFILE_ID,
                 "work-profile"/* profileName */, UserInfo.FLAG_MANAGED_PROFILE);
-        shadowOf(mPackageManager).setInstalledPackagesForUserId(
+        mShadowPackageManager.setInstalledPackagesForUserId(
                 PERSONAL_PROFILE_ID, PERSONAL_PROFILE_INSTALLED_PACKAGES);
-        shadowOf(mPackageManager).setInstalledPackagesForUserId(
+        mShadowPackageManager.setInstalledPackagesForUserId(
                 WORK_PROFILE_ID, WORK_PROFILE_INSTALLED_PACKAGES);
         installCrossProfilePackage(PERSONAL_CROSS_PROFILE_PACKAGE);
         installCrossProfilePackage(WORK_CROSS_PROFILE_PACKAGE);
-        shadowOf(mCrossProfileApps).addCrossProfilePackage(PERSONAL_CROSS_PROFILE_PACKAGE);
+        mShadowCrossProfileApps.addCrossProfilePackage(PERSONAL_CROSS_PROFILE_PACKAGE);
         ShadowPermissionChecker.setResult(
                 PERSONAL_CROSS_PROFILE_PACKAGE,
                 INTERACT_ACROSS_PROFILES_PERMISSION,
@@ -166,7 +194,7 @@
     }
 
     private void installCrossProfilePackage(String packageName) {
-        PackageInfo personalPackageInfo = shadowOf(mPackageManager).getInternalMutablePackageInfo(
+        PackageInfo personalPackageInfo = mShadowPackageManager.getInternalMutablePackageInfo(
                 packageName);
         personalPackageInfo.requestedPermissions = new String[]{
                 INTERACT_ACROSS_PROFILES_PERMISSION};
diff --git a/tests/robotests/src/com/android/settings/applications/specialaccess/vrlistener/EnabledVrListenersControllerTest.java b/tests/robotests/src/com/android/settings/applications/specialaccess/vrlistener/EnabledVrListenersControllerTest.java
index 91a78da..8c4df32 100644
--- a/tests/robotests/src/com/android/settings/applications/specialaccess/vrlistener/EnabledVrListenersControllerTest.java
+++ b/tests/robotests/src/com/android/settings/applications/specialaccess/vrlistener/EnabledVrListenersControllerTest.java
@@ -34,6 +34,9 @@
 import org.robolectric.shadows.ShadowActivityManager;
 
 @RunWith(RobolectricTestRunner.class)
+@Config(shadows = {
+        ShadowActivityManager.class,
+})
 public class EnabledVrListenersControllerTest {
 
     private Context mContext;
diff --git a/tests/robotests/src/com/android/settings/applications/specialaccess/vrlistener/VrListenerScreenPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/applications/specialaccess/vrlistener/VrListenerScreenPreferenceControllerTest.java
index a312823..cf4e334 100644
--- a/tests/robotests/src/com/android/settings/applications/specialaccess/vrlistener/VrListenerScreenPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/applications/specialaccess/vrlistener/VrListenerScreenPreferenceControllerTest.java
@@ -23,6 +23,8 @@
 
 import android.content.Context;
 
+import com.android.settings.testutils.shadow.ShadowActivityManager;
+
 import org.junit.Before;
 import org.junit.Ignore;
 import org.junit.Test;
@@ -31,9 +33,11 @@
 import org.robolectric.RuntimeEnvironment;
 import org.robolectric.annotation.Config;
 import org.robolectric.shadow.api.Shadow;
-import org.robolectric.shadows.ShadowActivityManager;
 
 @RunWith(RobolectricTestRunner.class)
+@Config(shadows = {
+        ShadowActivityManager.class,
+})
 public class VrListenerScreenPreferenceControllerTest {
 
     private Context mContext;
diff --git a/tests/robotests/src/com/android/settings/applications/specialaccess/zenaccess/ZenAccessControllerTest.java b/tests/robotests/src/com/android/settings/applications/specialaccess/zenaccess/ZenAccessControllerTest.java
index 8febbc6..bf112a6 100644
--- a/tests/robotests/src/com/android/settings/applications/specialaccess/zenaccess/ZenAccessControllerTest.java
+++ b/tests/robotests/src/com/android/settings/applications/specialaccess/zenaccess/ZenAccessControllerTest.java
@@ -27,6 +27,7 @@
 
 import com.android.internal.logging.nano.MetricsProto;
 import com.android.settings.testutils.FakeFeatureFactory;
+import com.android.settings.testutils.shadow.ShadowActivityManager;
 import com.android.settings.testutils.shadow.ShadowNotificationManager;
 
 import org.junit.Before;
@@ -36,9 +37,11 @@
 import org.robolectric.RuntimeEnvironment;
 import org.robolectric.annotation.Config;
 import org.robolectric.shadow.api.Shadow;
-import org.robolectric.shadows.ShadowActivityManager;
 
 @RunWith(RobolectricTestRunner.class)
+@Config(shadows = {
+        ShadowActivityManager.class,
+})
 public class ZenAccessControllerTest {
 
     private static final String TEST_PKG = "com.test.package";
diff --git a/tests/robotests/src/com/android/settings/applications/specialaccess/zenaccess/ZenAccessSettingObserverMixinTest.java b/tests/robotests/src/com/android/settings/applications/specialaccess/zenaccess/ZenAccessSettingObserverMixinTest.java
index afda8d5..bdbd863 100644
--- a/tests/robotests/src/com/android/settings/applications/specialaccess/zenaccess/ZenAccessSettingObserverMixinTest.java
+++ b/tests/robotests/src/com/android/settings/applications/specialaccess/zenaccess/ZenAccessSettingObserverMixinTest.java
@@ -29,6 +29,7 @@
 
 import androidx.lifecycle.LifecycleOwner;
 
+import com.android.settings.testutils.shadow.ShadowActivityManager;
 import com.android.settingslib.core.lifecycle.Lifecycle;
 
 import org.junit.Before;
@@ -38,10 +39,15 @@
 import org.mockito.MockitoAnnotations;
 import org.robolectric.RobolectricTestRunner;
 import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
+import org.robolectric.annotation.LooperMode;
 import org.robolectric.shadow.api.Shadow;
-import org.robolectric.shadows.ShadowActivityManager;
 
 @RunWith(RobolectricTestRunner.class)
+@LooperMode(LooperMode.Mode.LEGACY)
+@Config(shadows = {
+        ShadowActivityManager.class,
+})
 public class ZenAccessSettingObserverMixinTest {
 
     @Mock
diff --git a/tests/robotests/src/com/android/settings/biometrics/face/FaceSettingsRemoveButtonPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/biometrics/face/FaceSettingsRemoveButtonPreferenceControllerTest.java
new file mode 100644
index 0000000..5f56fa7
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/biometrics/face/FaceSettingsRemoveButtonPreferenceControllerTest.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.biometrics.face;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.hardware.face.FaceManager;
+
+import com.android.settings.R;
+import com.android.settings.SettingsActivity;
+import com.android.settings.biometrics.face.FaceSettingsRemoveButtonPreferenceController.ConfirmRemoveDialog;
+import com.android.settings.testutils.shadow.ShadowUserManager;
+import com.android.settingslib.widget.LayoutPreference;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+import org.robolectric.Robolectric;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
+import org.robolectric.shadows.ShadowApplication;
+
+@RunWith(RobolectricTestRunner.class)
+@Config(shadows = {ShadowUserManager.class})
+public class FaceSettingsRemoveButtonPreferenceControllerTest {
+    @Rule
+    public final MockitoRule mMockitoRule = MockitoJUnit.rule();
+
+    private static final String TEST_PREF_KEY = "baz";
+
+    @Mock
+    private FaceManager mFaceManager;
+    @Mock
+    private PackageManager mPackageManager;
+    private SettingsActivity mActivity;
+    private Context mContext;
+    private FaceSettingsRemoveButtonPreferenceController mController;
+    private LayoutPreference mPreference;
+
+    @Before
+    public void setUp() {
+        mContext = spy(RuntimeEnvironment.application);
+        when(mContext.getPackageManager()).thenReturn(mPackageManager);
+        when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_FACE)).thenReturn(true);
+        ShadowApplication.getInstance().setSystemService(Context.FACE_SERVICE, mFaceManager);
+
+        mPreference = new LayoutPreference(mContext, R.layout.face_remove_button);
+        mController = new FaceSettingsRemoveButtonPreferenceController(mContext, TEST_PREF_KEY);
+
+        mActivity = spy(Robolectric.buildActivity(SettingsActivity.class).create().get());
+        mController.setActivity(mActivity);
+    }
+
+    @Test
+    public void testRotationConfirmRemoveDialog() {
+        // mController calls onClick(), the dialog is created.
+        mController.updateState(mPreference);
+        assertThat(mController.mRemoving).isFalse();
+
+        mController.onClick(
+                mPreference.findViewById(R.id.security_settings_face_settings_remove_button));
+
+        ConfirmRemoveDialog removeDialog =
+                (ConfirmRemoveDialog) mActivity.getSupportFragmentManager()
+                        .findFragmentByTag(ConfirmRemoveDialog.class.getName());
+        assertThat(removeDialog).isNotNull();
+        assertThat(mController.mRemoving).isTrue();
+
+
+        // Simulate rotation, a new controller mController2 is created and updateState() is called.
+        // Since the dialog hasn't been dismissed, so mController2.mRemoving should be true
+        FaceSettingsRemoveButtonPreferenceController controller2 =
+                new FaceSettingsRemoveButtonPreferenceController(mContext, TEST_PREF_KEY);
+        controller2.setActivity(mActivity);
+        assertThat(controller2.mRemoving).isFalse();
+        controller2.updateState(mPreference);
+        assertThat(controller2.mRemoving).isTrue();
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrollingTest.java b/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrollingTest.java
index 006c699..fa0cd2b 100644
--- a/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrollingTest.java
+++ b/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrollingTest.java
@@ -78,6 +78,7 @@
 import org.robolectric.RobolectricTestRunner;
 import org.robolectric.RuntimeEnvironment;
 import org.robolectric.android.controller.ActivityController;
+import org.robolectric.annotation.LooperMode;
 import org.robolectric.util.ReflectionHelpers;
 
 import java.util.ArrayList;
@@ -85,6 +86,7 @@
 import java.util.concurrent.atomic.AtomicReference;
 
 @RunWith(RobolectricTestRunner.class)
+@LooperMode(LooperMode.Mode.LEGACY)
 public class FingerprintEnrollEnrollingTest {
     private static final String ENROLL_PROGRESS_COLOR_LIGHT = "#699FF3";
     private static final String ENROLL_PROGRESS_COLOR_DARK = "#7DA7F1";
@@ -610,9 +612,10 @@
         mContext = spy(RuntimeEnvironment.application);
         mActivity = spy(FingerprintEnrollEnrolling.class);
 
-        when(mContext.getDisplay()).thenReturn(mMockDisplay);
+        doReturn(mMockDisplay).when(mContext).getDisplay();
         when(mMockDisplay.getRotation()).thenReturn(Surface.ROTATION_0);
 
+        doReturn(mMockDisplay).when(mActivity).getDisplay();
         doReturn(true).when(mActivity).shouldShowLottie();
         doReturn(mFingerprintManager).when(mActivity).getSystemService(FingerprintManager.class);
         doReturn(mVibrator).when(mActivity).getSystemService(Vibrator.class);
@@ -642,6 +645,7 @@
     }
 
     private void createActivity() {
+        System.setProperty("robolectric.createActivityContexts", "true");
         final Bundle savedInstanceState = new Bundle();
         savedInstanceState.putInt(KEY_STATE_PREVIOUS_ROTATION, Surface.ROTATION_90);
 
diff --git a/tests/robotests/src/com/android/settings/biometrics/fingerprint/SetupFingerprintEnrollFindSensorTest.java b/tests/robotests/src/com/android/settings/biometrics/fingerprint/SetupFingerprintEnrollFindSensorTest.java
index f6b6b2b..d5500ad 100644
--- a/tests/robotests/src/com/android/settings/biometrics/fingerprint/SetupFingerprintEnrollFindSensorTest.java
+++ b/tests/robotests/src/com/android/settings/biometrics/fingerprint/SetupFingerprintEnrollFindSensorTest.java
@@ -45,8 +45,10 @@
 import org.robolectric.Robolectric;
 import org.robolectric.RobolectricTestRunner;
 import org.robolectric.annotation.Config;
+import org.robolectric.annotation.LooperMode;
 
 @RunWith(RobolectricTestRunner.class)
+@LooperMode(LooperMode.Mode.LEGACY)
 @Config(shadows = {ShadowUtils.class, ShadowAlertDialogCompat.class})
 public class SetupFingerprintEnrollFindSensorTest {
 
diff --git a/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsControllerTestBase.java b/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsControllerTestBase.java
index 12ea9b2..8ba0b44 100644
--- a/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsControllerTestBase.java
+++ b/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsControllerTestBase.java
@@ -38,8 +38,12 @@
 import org.mockito.MockitoAnnotations;
 import org.robolectric.RobolectricTestRunner;
 import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
 
 @RunWith(RobolectricTestRunner.class)
+@Config(shadows = {
+        com.android.settings.testutils.shadow.ShadowFragment.class,
+})
 public abstract class BluetoothDetailsControllerTestBase {
 
     protected Context mContext;
diff --git a/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsHeaderControllerTest.java b/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsHeaderControllerTest.java
index 8be8b18..fcfe84b 100644
--- a/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsHeaderControllerTest.java
+++ b/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsHeaderControllerTest.java
@@ -70,8 +70,7 @@
         when(mBluetoothManager.getCachedDeviceManager()).thenReturn(mCachedDeviceManager);
         when(mCachedDeviceManager.getSubDeviceSummary(mCachedDevice)).thenReturn("abc");
         mController =
-            new BluetoothDetailsHeaderController(mContext, mFragment, mCachedDevice, mLifecycle,
-                mBluetoothManager);
+            new BluetoothDetailsHeaderController(mContext, mFragment, mCachedDevice, mLifecycle);
         mPreference = new LayoutPreference(
                 mContext, com.android.settingslib.widget.R.layout.settings_entity_header);
         mPreference.setKey(mController.getPreferenceKey());
@@ -104,7 +103,7 @@
         verify(mHeaderController).setIconContentDescription(any(String.class));
         verify(mHeaderController).setSummary(any(String.class));
         verify(mHeaderController).setSecondSummary(any(String.class));
-        verify(mHeaderController).done(mActivity, true);
+        verify(mHeaderController).done(true);
     }
 
     @Test
diff --git a/tests/robotests/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragmentTest.java b/tests/robotests/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragmentTest.java
index 939bd10..89e682c 100644
--- a/tests/robotests/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragmentTest.java
+++ b/tests/robotests/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragmentTest.java
@@ -62,10 +62,12 @@
 import org.robolectric.RuntimeEnvironment;
 import org.robolectric.annotation.Config;
 import org.robolectric.fakes.RoboMenu;
-import org.robolectric.shadows.ShadowUserManager;
 
 @RunWith(RobolectricTestRunner.class)
-@Config(shadows = ShadowUserManager.class)
+@Config(shadows = {
+        com.android.settings.testutils.shadow.ShadowUserManager.class,
+        com.android.settings.testutils.shadow.ShadowFragment.class,
+})
 public class BluetoothDeviceDetailsFragmentTest {
 
     private static final String TEST_ADDRESS = "55:66:77:88:99:AA";
diff --git a/tests/robotests/src/com/android/settings/bluetooth/BluetoothDevicePairingDetailBaseTest.java b/tests/robotests/src/com/android/settings/bluetooth/BluetoothDevicePairingDetailBaseTest.java
index 7c598e0..40f7895 100644
--- a/tests/robotests/src/com/android/settings/bluetooth/BluetoothDevicePairingDetailBaseTest.java
+++ b/tests/robotests/src/com/android/settings/bluetooth/BluetoothDevicePairingDetailBaseTest.java
@@ -54,7 +54,10 @@
 
 /** Tests for {@link BluetoothDevicePairingDetailBase}. */
 @RunWith(RobolectricTestRunner.class)
-@Config(shadows = {ShadowBluetoothAdapter.class})
+@Config(shadows = {
+        ShadowBluetoothAdapter.class,
+        com.android.settings.testutils.shadow.ShadowFragment.class,
+})
 public class BluetoothDevicePairingDetailBaseTest {
 
     @Rule
diff --git a/tests/robotests/src/com/android/settings/bluetooth/BluetoothDeviceRenamePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/bluetooth/BluetoothDeviceRenamePreferenceControllerTest.java
index f93c61e..6fd1d98 100644
--- a/tests/robotests/src/com/android/settings/bluetooth/BluetoothDeviceRenamePreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/bluetooth/BluetoothDeviceRenamePreferenceControllerTest.java
@@ -47,7 +47,10 @@
 import org.robolectric.shadow.api.Shadow;
 
 @RunWith(RobolectricTestRunner.class)
-@Config(shadows = {ShadowBluetoothAdapter.class})
+@Config(shadows = {
+        ShadowBluetoothAdapter.class,
+        com.android.settings.testutils.shadow.ShadowFragment.class,
+})
 public class BluetoothDeviceRenamePreferenceControllerTest {
 
     private static final String DEVICE_NAME = "Nightshade";
diff --git a/tests/robotests/src/com/android/settings/bluetooth/BluetoothFindBroadcastsFragmentTest.java b/tests/robotests/src/com/android/settings/bluetooth/BluetoothFindBroadcastsFragmentTest.java
index b029f92..046a90c 100644
--- a/tests/robotests/src/com/android/settings/bluetooth/BluetoothFindBroadcastsFragmentTest.java
+++ b/tests/robotests/src/com/android/settings/bluetooth/BluetoothFindBroadcastsFragmentTest.java
@@ -50,8 +50,12 @@
 import org.robolectric.Robolectric;
 import org.robolectric.RobolectricTestRunner;
 import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
 
 @RunWith(RobolectricTestRunner.class)
+@Config(shadows = {
+        com.android.settings.testutils.shadow.ShadowFragment.class,
+})
 public class BluetoothFindBroadcastsFragmentTest {
 
     private static final String TEST_ADDRESS = "55:66:77:88:99:AA";
diff --git a/tests/robotests/src/com/android/settings/bluetooth/DeviceListPreferenceFragmentTest.kt b/tests/robotests/src/com/android/settings/bluetooth/DeviceListPreferenceFragmentTest.kt
index 5a21aff..0f1ad4b 100644
--- a/tests/robotests/src/com/android/settings/bluetooth/DeviceListPreferenceFragmentTest.kt
+++ b/tests/robotests/src/com/android/settings/bluetooth/DeviceListPreferenceFragmentTest.kt
@@ -56,7 +56,10 @@
 import org.mockito.Mockito.`when` as whenever
 
 @RunWith(RobolectricTestRunner::class)
-@Config(shadows = [ShadowBluetoothAdapter::class])
+@Config(shadows = [
+    ShadowBluetoothAdapter::class,
+    com.android.settings.testutils.shadow.ShadowFragment::class,
+])
 class DeviceListPreferenceFragmentTest {
     @get:Rule
     val mockito: MockitoRule = MockitoJUnit.rule()
diff --git a/tests/robotests/src/com/android/settings/bugreporthandler/BugReportHandlerPickerTest.java b/tests/robotests/src/com/android/settings/bugreporthandler/BugReportHandlerPickerTest.java
index a3fdee6..48318df 100644
--- a/tests/robotests/src/com/android/settings/bugreporthandler/BugReportHandlerPickerTest.java
+++ b/tests/robotests/src/com/android/settings/bugreporthandler/BugReportHandlerPickerTest.java
@@ -50,12 +50,16 @@
 import org.robolectric.RobolectricTestRunner;
 import org.robolectric.RuntimeEnvironment;
 import org.robolectric.Shadows;
+import org.robolectric.annotation.Config;
 import org.robolectric.shadows.ShadowPackageManager;
 import org.robolectric.util.ReflectionHelpers;
 
 import java.util.Collections;
 
 @RunWith(RobolectricTestRunner.class)
+@Config(shadows = {
+        com.android.settings.testutils.shadow.ShadowFragment.class,
+})
 public class BugReportHandlerPickerTest {
     private static final String PACKAGE_NAME = "com.example.test";
     private static final int USER_ID = 0;
diff --git a/tests/robotests/src/com/android/settings/connecteddevice/AvailableMediaDeviceGroupControllerTest.java b/tests/robotests/src/com/android/settings/connecteddevice/AvailableMediaDeviceGroupControllerTest.java
index 0c3443e..17ab557 100644
--- a/tests/robotests/src/com/android/settings/connecteddevice/AvailableMediaDeviceGroupControllerTest.java
+++ b/tests/robotests/src/com/android/settings/connecteddevice/AvailableMediaDeviceGroupControllerTest.java
@@ -26,6 +26,7 @@
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
+import static org.robolectric.shadows.ShadowLooper.shadowMainLooper;
 
 import android.bluetooth.BluetoothDevice;
 import android.bluetooth.BluetoothProfile;
@@ -69,8 +70,12 @@
 
 /** Tests for {@link AvailableMediaDeviceGroupController}. */
 @RunWith(RobolectricTestRunner.class)
-@Config(shadows = {ShadowAudioManager.class, ShadowBluetoothAdapter.class,
-        ShadowBluetoothUtils.class})
+@Config(shadows = {
+        ShadowAudioManager.class,
+        ShadowBluetoothAdapter.class,
+        ShadowBluetoothUtils.class,
+        com.android.settings.testutils.shadow.ShadowFragment.class,
+})
 public class AvailableMediaDeviceGroupControllerTest {
 
     private static final String TEST_DEVICE_ADDRESS = "00:A1:A1:A1:A1:A1";
@@ -257,7 +262,7 @@
 
         mAvailableMediaDeviceGroupController.onActiveDeviceChanged(mCachedBluetoothDevice,
                 BluetoothProfile.HEARING_AID);
-
+        shadowMainLooper().idle();
         final AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog();
         assertThat(dialog.isShowing()).isTrue();
     }
diff --git a/tests/robotests/src/com/android/settings/connecteddevice/stylus/UsbStylusBroadcastReceiverTest.java b/tests/robotests/src/com/android/settings/connecteddevice/stylus/UsbStylusBroadcastReceiverTest.java
index ccaefb2..03279ee 100644
--- a/tests/robotests/src/com/android/settings/connecteddevice/stylus/UsbStylusBroadcastReceiverTest.java
+++ b/tests/robotests/src/com/android/settings/connecteddevice/stylus/UsbStylusBroadcastReceiverTest.java
@@ -95,4 +95,32 @@
 
         verifyNoMoreInteractions(mListener);
     }
+
+    @Test
+    public void onReceive_usbDeviceStateStylus_invokeCallback() {
+        when(mFeatureFactory.mStylusFeatureProvider.isUsbFirmwareUpdateEnabled(any()))
+                .thenReturn(true);
+        final UsbDevice usbDevice = mock(UsbDevice.class);
+        final Intent intent = new Intent();
+        intent.setAction(UsbManager.ACTION_USB_STATE);
+        intent.putExtra(UsbManager.EXTRA_DEVICE, usbDevice);
+
+        mReceiver.onReceive(mContext, intent);
+
+        verify(mListener).onUsbStylusConnectionChanged(usbDevice, false);
+    }
+
+    @Test
+    public void onReceive_usbDeviceStateNotStylus_doesNotInvokeCallback() {
+        when(mFeatureFactory.mStylusFeatureProvider.isUsbFirmwareUpdateEnabled(any()))
+                .thenReturn(false);
+        final UsbDevice usbDevice = mock(UsbDevice.class);
+        final Intent intent = new Intent();
+        intent.setAction(UsbManager.ACTION_USB_STATE);
+        intent.putExtra(UsbManager.EXTRA_DEVICE, usbDevice);
+
+        mReceiver.onReceive(mContext, intent);
+
+        verifyNoMoreInteractions(mListener);
+    }
 }
diff --git a/tests/robotests/src/com/android/settings/connecteddevice/usb/UsbDetailsDataRoleControllerTest.java b/tests/robotests/src/com/android/settings/connecteddevice/usb/UsbDetailsDataRoleControllerTest.java
index 8c8431d..9e24387 100644
--- a/tests/robotests/src/com/android/settings/connecteddevice/usb/UsbDetailsDataRoleControllerTest.java
+++ b/tests/robotests/src/com/android/settings/connecteddevice/usb/UsbDetailsDataRoleControllerTest.java
@@ -49,8 +49,12 @@
 import org.mockito.MockitoAnnotations;
 import org.robolectric.RobolectricTestRunner;
 import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
 
 @RunWith(RobolectricTestRunner.class)
+@Config(shadows = {
+        com.android.settings.testutils.shadow.ShadowFragment.class,
+})
 public class UsbDetailsDataRoleControllerTest {
 
     private UsbDetailsDataRoleController mDetailsDataRoleController;
diff --git a/tests/robotests/src/com/android/settings/connecteddevice/usb/UsbDetailsFunctionsControllerTest.java b/tests/robotests/src/com/android/settings/connecteddevice/usb/UsbDetailsFunctionsControllerTest.java
index 37efbd6..42c994a 100644
--- a/tests/robotests/src/com/android/settings/connecteddevice/usb/UsbDetailsFunctionsControllerTest.java
+++ b/tests/robotests/src/com/android/settings/connecteddevice/usb/UsbDetailsFunctionsControllerTest.java
@@ -58,6 +58,9 @@
 import java.util.List;
 
 @RunWith(RobolectricTestRunner.class)
+@Config(shadows = {
+        com.android.settings.testutils.shadow.ShadowFragment.class,
+})
 public class UsbDetailsFunctionsControllerTest {
 
     private UsbDetailsFunctionsController mDetailsFunctionsController;
diff --git a/tests/robotests/src/com/android/settings/connecteddevice/usb/UsbDetailsHeaderControllerTest.java b/tests/robotests/src/com/android/settings/connecteddevice/usb/UsbDetailsHeaderControllerTest.java
index 2b0ac7f..43bf657 100644
--- a/tests/robotests/src/com/android/settings/connecteddevice/usb/UsbDetailsHeaderControllerTest.java
+++ b/tests/robotests/src/com/android/settings/connecteddevice/usb/UsbDetailsHeaderControllerTest.java
@@ -52,7 +52,10 @@
 import org.robolectric.annotation.Config;
 
 @RunWith(RobolectricTestRunner.class)
-@Config(shadows = ShadowEntityHeaderController.class)
+@Config(shadows = {
+        ShadowEntityHeaderController.class,
+        com.android.settings.testutils.shadow.ShadowFragment.class,
+})
 public class UsbDetailsHeaderControllerTest {
 
     private UsbDetailsHeaderController mDetailsHeaderController;
@@ -111,6 +114,6 @@
             DrawableTestHelper.assertDrawableResId(t, R.drawable.ic_usb);
             return true;
         }));
-        verify(mHeaderController).done(mActivity, true);
+        verify(mHeaderController).done(true);
     }
 }
diff --git a/tests/robotests/src/com/android/settings/connecteddevice/usb/UsbDetailsPowerRoleControllerTest.java b/tests/robotests/src/com/android/settings/connecteddevice/usb/UsbDetailsPowerRoleControllerTest.java
index aa62741..e793336 100644
--- a/tests/robotests/src/com/android/settings/connecteddevice/usb/UsbDetailsPowerRoleControllerTest.java
+++ b/tests/robotests/src/com/android/settings/connecteddevice/usb/UsbDetailsPowerRoleControllerTest.java
@@ -52,8 +52,12 @@
 import org.mockito.MockitoAnnotations;
 import org.robolectric.RobolectricTestRunner;
 import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
 
 @RunWith(RobolectricTestRunner.class)
+@Config(shadows = {
+        com.android.settings.testutils.shadow.ShadowFragment.class,
+})
 public class UsbDetailsPowerRoleControllerTest {
 
     private UsbDetailsPowerRoleController mDetailsPowerRoleController;
diff --git a/tests/robotests/src/com/android/settings/connecteddevice/usb/UsbDetailsTranscodeMtpControllerTest.java b/tests/robotests/src/com/android/settings/connecteddevice/usb/UsbDetailsTranscodeMtpControllerTest.java
index 477b592..7cf3ecc 100644
--- a/tests/robotests/src/com/android/settings/connecteddevice/usb/UsbDetailsTranscodeMtpControllerTest.java
+++ b/tests/robotests/src/com/android/settings/connecteddevice/usb/UsbDetailsTranscodeMtpControllerTest.java
@@ -45,6 +45,9 @@
 import org.robolectric.annotation.Config;
 
 @RunWith(RobolectricTestRunner.class)
+@Config(shadows = {
+        com.android.settings.testutils.shadow.ShadowFragment.class,
+})
 public class UsbDetailsTranscodeMtpControllerTest {
     private static final String TRANSCODE_MTP_SYS_PROP_KEY = "sys.fuse.transcode_mtp";
 
diff --git a/tests/robotests/src/com/android/settings/core/InstrumentedPreferenceFragmentTest.java b/tests/robotests/src/com/android/settings/core/InstrumentedPreferenceFragmentTest.java
index 763cf15..dc173e5 100644
--- a/tests/robotests/src/com/android/settings/core/InstrumentedPreferenceFragmentTest.java
+++ b/tests/robotests/src/com/android/settings/core/InstrumentedPreferenceFragmentTest.java
@@ -38,9 +38,13 @@
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 import org.robolectric.RobolectricTestRunner;
+import org.robolectric.annotation.Config;
 import org.robolectric.util.ReflectionHelpers;
 
 @RunWith(RobolectricTestRunner.class)
+@Config(shadows = {
+        com.android.settings.testutils.shadow.ShadowFragment.class,
+})
 public class InstrumentedPreferenceFragmentTest {
 
     @Mock
diff --git a/tests/robotests/src/com/android/settings/core/SubSettingLauncherTest.java b/tests/robotests/src/com/android/settings/core/SubSettingLauncherTest.java
index b68bcec..bfc8ea6 100644
--- a/tests/robotests/src/com/android/settings/core/SubSettingLauncherTest.java
+++ b/tests/robotests/src/com/android/settings/core/SubSettingLauncherTest.java
@@ -45,8 +45,12 @@
 import org.mockito.MockitoAnnotations;
 import org.robolectric.RobolectricTestRunner;
 import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
 
 @RunWith(RobolectricTestRunner.class)
+@Config(shadows = {
+        com.android.settings.testutils.shadow.ShadowFragment.class,
+})
 public class SubSettingLauncherTest {
 
     @Mock
diff --git a/tests/robotests/src/com/android/settings/dashboard/profileselector/ProfileSelectFragmentTest.java b/tests/robotests/src/com/android/settings/dashboard/profileselector/ProfileSelectFragmentTest.java
index 1e19325..b595d06 100644
--- a/tests/robotests/src/com/android/settings/dashboard/profileselector/ProfileSelectFragmentTest.java
+++ b/tests/robotests/src/com/android/settings/dashboard/profileselector/ProfileSelectFragmentTest.java
@@ -50,7 +50,10 @@
 import java.util.Set;
 
 @RunWith(RobolectricTestRunner.class)
-@Config(shadows = {ShadowUserManager.class})
+@Config(shadows = {
+        ShadowUserManager.class,
+        com.android.settings.testutils.shadow.ShadowFragment.class,
+})
 public class ProfileSelectFragmentTest {
 
     private Context mContext;
diff --git a/tests/robotests/src/com/android/settings/datausage/AppDataUsageTest.java b/tests/robotests/src/com/android/settings/datausage/AppDataUsageTest.java
index 9f95712..fa61a33 100644
--- a/tests/robotests/src/com/android/settings/datausage/AppDataUsageTest.java
+++ b/tests/robotests/src/com/android/settings/datausage/AppDataUsageTest.java
@@ -100,7 +100,6 @@
         MockitoAnnotations.initMocks(this);
 
         ShadowEntityHeaderController.setUseMock(mHeaderController);
-        when(mHeaderController.setRecyclerView(any(), any())).thenReturn(mHeaderController);
         when(mHeaderController.setUid(anyInt())).thenReturn(mHeaderController);
     }
 
diff --git a/tests/robotests/src/com/android/settings/datausage/BillingCycleSettingsTest.java b/tests/robotests/src/com/android/settings/datausage/BillingCycleSettingsTest.java
index cef5928..6067324 100644
--- a/tests/robotests/src/com/android/settings/datausage/BillingCycleSettingsTest.java
+++ b/tests/robotests/src/com/android/settings/datausage/BillingCycleSettingsTest.java
@@ -59,6 +59,9 @@
 import org.robolectric.annotation.Config;
 
 @RunWith(RobolectricTestRunner.class)
+@Config(shadows = {
+        com.android.settings.testutils.shadow.ShadowFragment.class,
+})
 public class BillingCycleSettingsTest {
 
     private static final int LIMIT_BYTES = 123;
diff --git a/tests/robotests/src/com/android/settings/datausage/DataUsageSummaryPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/datausage/DataUsageSummaryPreferenceControllerTest.java
index 71d5d7e..fa8c368 100644
--- a/tests/robotests/src/com/android/settings/datausage/DataUsageSummaryPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/datausage/DataUsageSummaryPreferenceControllerTest.java
@@ -40,16 +40,11 @@
 import android.util.RecurrenceRule;
 
 import androidx.fragment.app.FragmentActivity;
-import androidx.preference.PreferenceFragmentCompat;
-import androidx.recyclerview.widget.RecyclerView;
 
 import com.android.internal.logging.nano.MetricsProto;
-import com.android.settings.R;
 import com.android.settings.testutils.FakeFeatureFactory;
 import com.android.settings.testutils.shadow.ShadowEntityHeaderController;
 import com.android.settings.widget.EntityHeaderController;
-import com.android.settingslib.NetworkPolicyEditor;
-import com.android.settingslib.core.lifecycle.Lifecycle;
 import com.android.settingslib.net.DataUsageController;
 
 import org.junit.After;
@@ -88,20 +83,14 @@
     @Mock
     private DataUsageSummaryPreference mSummaryPreference;
     @Mock
-    private NetworkPolicyEditor mPolicyEditor;
-    @Mock
     private NetworkTemplate mNetworkTemplate;
     @Mock
     private SubscriptionInfo mSubscriptionInfo;
     @Mock
     private SubscriptionPlan mSubscriptionPlan;
-    @Mock
-    private Lifecycle mLifecycle;
     @Mock(answer = Answers.RETURNS_DEEP_STUBS)
     private EntityHeaderController mHeaderController;
     @Mock
-    private PreferenceFragmentCompat mPreferenceFragment;
-    @Mock
     private TelephonyManager mTelephonyManager;
     @Mock
     private PackageManager mPm;
@@ -146,9 +135,7 @@
                 mDataUsageController,
                 mDataInfoController,
                 mNetworkTemplate,
-                mPolicyEditor,
-                R.string.cell_data_template,
-                mActivity, null, null, null, mDefaultSubscriptionId));
+                mActivity, null, null, mDefaultSubscriptionId));
         doReturn(null).when(mController).getSubscriptionInfo(
                 SubscriptionManager.INVALID_SUBSCRIPTION_ID);
         doReturn(null).when(mController).getSubscriptionPlans(
@@ -366,27 +353,6 @@
         assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE);
     }
 
-    @Test
-    public void testMobileData_entityHeaderSet() {
-        final RecyclerView recyclerView = new RecyclerView(mActivity);
-
-        mController = spy(new DataUsageSummaryPreferenceController(
-                mDataUsageController,
-                mDataInfoController,
-                mNetworkTemplate,
-                mPolicyEditor,
-                R.string.cell_data_template,
-                mActivity, mLifecycle, mHeaderController, mPreferenceFragment,
-                mDefaultSubscriptionId));
-
-        when(mPreferenceFragment.getListView()).thenReturn(recyclerView);
-
-        mController.onStart();
-
-        verify(mHeaderController)
-                .setRecyclerView(any(RecyclerView.class), any(Lifecycle.class));
-    }
-
     private DataUsageController.DataUsageInfo createTestDataUsageInfo(long now) {
         DataUsageController.DataUsageInfo info = new DataUsageController.DataUsageInfo();
         info.carrier = CARRIER_NAME;
diff --git a/tests/robotests/src/com/android/settings/datausage/WifiDataUsageSummaryPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/datausage/WifiDataUsageSummaryPreferenceControllerTest.java
index 711f6d7..cb1b890 100644
--- a/tests/robotests/src/com/android/settings/datausage/WifiDataUsageSummaryPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/datausage/WifiDataUsageSummaryPreferenceControllerTest.java
@@ -24,13 +24,11 @@
 import static org.mockito.Mockito.spy;
 
 import android.content.Context;
-import android.net.NetworkPolicyManager;
 import android.telephony.TelephonyManager;
 
 import androidx.fragment.app.FragmentActivity;
 import androidx.test.core.app.ApplicationProvider;
 
-import com.android.settingslib.core.lifecycle.Lifecycle;
 import com.android.settingslib.net.DataUsageController;
 
 import org.junit.Before;
@@ -56,12 +54,8 @@
     @Mock
     FragmentActivity mActivity;
     @Mock
-    Lifecycle mLifecycle;
-    @Mock
     TelephonyManager mTelephonyManager;
     @Mock
-    NetworkPolicyManager mNetworkPolicyManager;
-    @Mock
     DataUsageSummaryPreference mSummaryPreference;
     @Mock
     DataUsageController mDataUsageController;
@@ -75,12 +69,10 @@
     public void setUp() {
         doReturn(mContext.getResources()).when(mActivity).getResources();
         doReturn(mTelephonyManager).when(mActivity).getSystemService(TelephonyManager.class);
-        doReturn(mNetworkPolicyManager).when(mActivity)
-                .getSystemService(NetworkPolicyManager.class);
         doNothing().when(mSummaryPreference).setWifiMode(anyBoolean(), anyString(), anyBoolean());
         doReturn(mDataUsageInfo).when(mDataUsageController).getDataUsageInfo(any());
 
-        mController = spy(new WifiDataUsageSummaryPreferenceController(mActivity, mLifecycle, null,
+        mController = spy(new WifiDataUsageSummaryPreferenceController(mActivity, null,
                 mAllNetworkKeys));
         doReturn(mDataUsageController).when(mController).createDataUsageController(any());
     }
diff --git a/tests/robotests/src/com/android/settings/datetime/DatePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/datetime/DatePreferenceControllerTest.java
index 76ab289..ce9c701 100644
--- a/tests/robotests/src/com/android/settings/datetime/DatePreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/datetime/DatePreferenceControllerTest.java
@@ -20,6 +20,7 @@
 
 import static org.junit.Assert.assertEquals;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
@@ -43,11 +44,15 @@
 import org.mockito.MockitoAnnotations;
 import org.robolectric.RobolectricTestRunner;
 import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
 
 import java.util.Calendar;
 import java.util.GregorianCalendar;
 
 @RunWith(RobolectricTestRunner.class)
+@Config(shadows = {
+        com.android.settings.testutils.shadow.ShadowFragment.class,
+})
 public class DatePreferenceControllerTest {
 
     @Mock
@@ -65,6 +70,7 @@
     @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
+        mContext = spy(RuntimeEnvironment.application);
         when(mContext.getSystemService(TimeDetector.class)).thenReturn(mTimeDetector);
         when(mContext.getSystemService(TimeManager.class)).thenReturn(mTimeManager);
         mPreference = new RestrictedPreference(RuntimeEnvironment.application);
diff --git a/tests/robotests/src/com/android/settings/datetime/LocationTimeZoneDetectionPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/datetime/LocationTimeZoneDetectionPreferenceControllerTest.java
index baef01c..cd89c0c 100644
--- a/tests/robotests/src/com/android/settings/datetime/LocationTimeZoneDetectionPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/datetime/LocationTimeZoneDetectionPreferenceControllerTest.java
@@ -55,8 +55,12 @@
 import org.mockito.MockitoAnnotations;
 import org.robolectric.RobolectricTestRunner;
 import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
 
 @RunWith(RobolectricTestRunner.class)
+@Config(shadows = {
+        com.android.settings.testutils.shadow.ShadowFragment.class,
+})
 public class LocationTimeZoneDetectionPreferenceControllerTest {
     @Mock
     private TimeManager mTimeManager;
diff --git a/tests/robotests/src/com/android/settings/datetime/TimeChangeListenerMixinTest.java b/tests/robotests/src/com/android/settings/datetime/TimeChangeListenerMixinTest.java
index 270b874..eb56fd1 100644
--- a/tests/robotests/src/com/android/settings/datetime/TimeChangeListenerMixinTest.java
+++ b/tests/robotests/src/com/android/settings/datetime/TimeChangeListenerMixinTest.java
@@ -36,8 +36,10 @@
 import org.mockito.MockitoAnnotations;
 import org.robolectric.RobolectricTestRunner;
 import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.LooperMode;
 
 @RunWith(RobolectricTestRunner.class)
+@LooperMode(LooperMode.Mode.LEGACY)
 public class TimeChangeListenerMixinTest {
 
     @Mock
diff --git a/tests/robotests/src/com/android/settings/development/DesktopModePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/development/DesktopModePreferenceControllerTest.java
index 26b529d..460f6f9 100644
--- a/tests/robotests/src/com/android/settings/development/DesktopModePreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/development/DesktopModePreferenceControllerTest.java
@@ -45,8 +45,12 @@
 import org.mockito.MockitoAnnotations;
 import org.robolectric.RobolectricTestRunner;
 import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
 
 @RunWith(RobolectricTestRunner.class)
+@Config(shadows = {
+        com.android.settings.testutils.shadow.ShadowFragment.class,
+})
 public class DesktopModePreferenceControllerTest {
 
     private static final String ENG_BUILD_TYPE = "eng";
diff --git a/tests/robotests/src/com/android/settings/development/DevelopmentSettingsDashboardFragmentTest.java b/tests/robotests/src/com/android/settings/development/DevelopmentSettingsDashboardFragmentTest.java
index 7db7141..fca338d 100644
--- a/tests/robotests/src/com/android/settings/development/DevelopmentSettingsDashboardFragmentTest.java
+++ b/tests/robotests/src/com/android/settings/development/DevelopmentSettingsDashboardFragmentTest.java
@@ -35,6 +35,7 @@
 import com.android.internal.logging.nano.MetricsProto;
 import com.android.settings.R;
 import com.android.settings.testutils.shadow.ShadowAlertDialogCompat;
+import com.android.settings.testutils.shadow.ShadowUserManager;
 import com.android.settings.widget.SettingsMainSwitchBar;
 import com.android.settingslib.development.AbstractEnableAdbPreferenceController;
 import com.android.settingslib.development.DevelopmentSettingsEnabler;
@@ -51,14 +52,17 @@
 import org.robolectric.annotation.Implementation;
 import org.robolectric.annotation.Implements;
 import org.robolectric.shadow.api.Shadow;
-import org.robolectric.shadows.ShadowUserManager;
 import org.robolectric.shadows.androidx.fragment.FragmentController;
 import org.robolectric.util.ReflectionHelpers;
 
 import java.util.List;
 
 @RunWith(RobolectricTestRunner.class)
-@Config(shadows = {ShadowUserManager.class, ShadowAlertDialogCompat.class})
+@Config(shadows = {
+        ShadowAlertDialogCompat.class,
+        ShadowUserManager.class,
+        ShadowUserManager.class,
+})
 public class DevelopmentSettingsDashboardFragmentTest {
 
     private Switch mSwitch;
diff --git a/tests/robotests/src/com/android/settings/development/EnableVerboseVendorLoggingPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/development/EnableVerboseVendorLoggingPreferenceControllerTest.java
index 8e62521..97acdf6 100644
--- a/tests/robotests/src/com/android/settings/development/EnableVerboseVendorLoggingPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/development/EnableVerboseVendorLoggingPreferenceControllerTest.java
@@ -36,10 +36,12 @@
 import org.mockito.MockitoAnnotations;
 import org.robolectric.RobolectricTestRunner;
 import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.LooperMode;
 
 import java.lang.reflect.Field;
 
 @RunWith(RobolectricTestRunner.class)
+@LooperMode(LooperMode.Mode.LEGACY)
 public final class EnableVerboseVendorLoggingPreferenceControllerTest {
     @Mock
     private SwitchPreference mPreference;
diff --git a/tests/robotests/src/com/android/settings/development/FreeformWindowsPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/development/FreeformWindowsPreferenceControllerTest.java
index 695a291..bd005b3 100644
--- a/tests/robotests/src/com/android/settings/development/FreeformWindowsPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/development/FreeformWindowsPreferenceControllerTest.java
@@ -44,8 +44,12 @@
 import org.mockito.MockitoAnnotations;
 import org.robolectric.RobolectricTestRunner;
 import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
 
 @RunWith(RobolectricTestRunner.class)
+@Config(shadows = {
+        com.android.settings.testutils.shadow.ShadowFragment.class,
+})
 public class FreeformWindowsPreferenceControllerTest {
 
     private static final String ENG_BUILD_TYPE = "eng";
diff --git a/tests/robotests/src/com/android/settings/development/OemUnlockPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/development/OemUnlockPreferenceControllerTest.java
index c762349..4f89f02 100644
--- a/tests/robotests/src/com/android/settings/development/OemUnlockPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/development/OemUnlockPreferenceControllerTest.java
@@ -49,8 +49,12 @@
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 import org.robolectric.RobolectricTestRunner;
+import org.robolectric.annotation.Config;
 
 @RunWith(RobolectricTestRunner.class)
+@Config(shadows = {
+        com.android.settings.testutils.shadow.ShadowFragment.class,
+})
 public class OemUnlockPreferenceControllerTest {
 
     private static final String OEM_UNLOCK_SUPPORTED_KEY = "ro.oem_unlock_supported";
diff --git a/tests/robotests/src/com/android/settings/development/OverlayCategoryPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/development/OverlayCategoryPreferenceControllerTest.java
index b2e8013..12f70a4 100644
--- a/tests/robotests/src/com/android/settings/development/OverlayCategoryPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/development/OverlayCategoryPreferenceControllerTest.java
@@ -31,6 +31,9 @@
 import android.content.pm.PackageManager;
 import android.os.RemoteException;
 
+import androidx.preference.ListPreference;
+import androidx.preference.PreferenceScreen;
+
 import com.android.settings.R;
 
 import org.junit.Before;
@@ -40,16 +43,15 @@
 import org.mockito.MockitoAnnotations;
 import org.robolectric.RobolectricTestRunner;
 import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.LooperMode;
 import org.robolectric.shadows.ShadowApplication;
 import org.robolectric.shadows.ShadowToast;
 
 import java.util.ArrayList;
 import java.util.Arrays;
 
-import androidx.preference.ListPreference;
-import androidx.preference.PreferenceScreen;
-
 @RunWith(RobolectricTestRunner.class)
+@LooperMode(LooperMode.Mode.LEGACY)
 public class OverlayCategoryPreferenceControllerTest {
 
     private static final OverlayInfo ONE_DISABLED = createFakeOverlay("overlay.one", false, 1);
diff --git a/tests/robotests/src/com/android/settings/development/graphicsdriver/GraphicsDriverEnableAngleAsSystemDriverControllerTest.java b/tests/robotests/src/com/android/settings/development/graphicsdriver/GraphicsDriverEnableAngleAsSystemDriverControllerTest.java
index 9210b87..a338de3 100644
--- a/tests/robotests/src/com/android/settings/development/graphicsdriver/GraphicsDriverEnableAngleAsSystemDriverControllerTest.java
+++ b/tests/robotests/src/com/android/settings/development/graphicsdriver/GraphicsDriverEnableAngleAsSystemDriverControllerTest.java
@@ -47,9 +47,13 @@
 import org.mockito.MockitoAnnotations;
 import org.robolectric.RobolectricTestRunner;
 import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
 import org.robolectric.shadows.ShadowSystemProperties;
 
 @RunWith(RobolectricTestRunner.class)
+@Config(shadows = {
+        com.android.settings.testutils.shadow.ShadowFragment.class,
+})
 public class GraphicsDriverEnableAngleAsSystemDriverControllerTest {
     private static final String TAG = "GraphicsDriverEnableAngleAsSystemDriverControllerTest";
     @Mock private PreferenceScreen mScreen;
diff --git a/tests/robotests/src/com/android/settings/development/qstile/DevelopmentTilesTest.java b/tests/robotests/src/com/android/settings/development/qstile/DevelopmentTilesTest.java
index 9ab67c2..c7df289 100644
--- a/tests/robotests/src/com/android/settings/development/qstile/DevelopmentTilesTest.java
+++ b/tests/robotests/src/com/android/settings/development/qstile/DevelopmentTilesTest.java
@@ -27,6 +27,7 @@
 import android.os.UserManager;
 import android.service.quicksettings.Tile;
 
+import com.android.settings.testutils.shadow.ShadowUserManager;
 import com.android.settingslib.development.DevelopmentSettingsEnabler;
 
 import org.junit.Before;
@@ -37,10 +38,13 @@
 import org.robolectric.Robolectric;
 import org.robolectric.RobolectricTestRunner;
 import org.robolectric.RuntimeEnvironment;
-import org.robolectric.Shadows;
-import org.robolectric.shadows.ShadowUserManager;
+import org.robolectric.annotation.Config;
+import org.robolectric.shadow.api.Shadow;
 
 @RunWith(RobolectricTestRunner.class)
+@Config(shadows = {
+        ShadowUserManager.class,
+})
 public class DevelopmentTilesTest {
 
     @Mock
@@ -54,7 +58,7 @@
     public void setUp() {
         MockitoAnnotations.initMocks(this);
         mService = spy(Robolectric.setupService(DevelopmentTiles.ShowLayout.class));
-        final ShadowUserManager um = Shadows.shadowOf(
+        final ShadowUserManager um = Shadow.extract(
                 RuntimeEnvironment.application.getSystemService(UserManager.class));
         um.setIsAdminUser(true);
         doReturn(mTile).when(mService).getQsTile();
diff --git a/tests/robotests/src/com/android/settings/deviceinfo/PrivateVolumeUnmountTest.java b/tests/robotests/src/com/android/settings/deviceinfo/PrivateVolumeUnmountTest.java
index 9cb1d56..4704475 100644
--- a/tests/robotests/src/com/android/settings/deviceinfo/PrivateVolumeUnmountTest.java
+++ b/tests/robotests/src/com/android/settings/deviceinfo/PrivateVolumeUnmountTest.java
@@ -31,9 +31,11 @@
 import org.junit.runner.RunWith;
 import org.robolectric.RobolectricTestRunner;
 import org.robolectric.annotation.Config;
+import org.robolectric.annotation.LooperMode;
 import org.robolectric.shadows.androidx.fragment.FragmentController;
 
 @RunWith(RobolectricTestRunner.class)
+@LooperMode(LooperMode.Mode.LEGACY)
 @Config(shadows = ShadowStorageManager.class)
 public class PrivateVolumeUnmountTest {
 
diff --git a/tests/robotests/src/com/android/settings/deviceinfo/firmwareversion/MainlineModuleVersionPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/deviceinfo/firmwareversion/MainlineModuleVersionPreferenceControllerTest.java
index 35e044c..9129906 100644
--- a/tests/robotests/src/com/android/settings/deviceinfo/firmwareversion/MainlineModuleVersionPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/deviceinfo/firmwareversion/MainlineModuleVersionPreferenceControllerTest.java
@@ -184,7 +184,7 @@
         final MainlineModuleVersionPreferenceController controller =
                 new MainlineModuleVersionPreferenceController(mContext, "key");
 
-        assertThat(controller.getSummary()).isEqualTo("May 01, 2019");
+        assertThat(controller.getSummary()).isEqualTo("May 1, 2019");
     }
 
     @Test
diff --git a/tests/robotests/src/com/android/settings/deviceinfo/imei/ImeiInfoPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/deviceinfo/imei/ImeiInfoPreferenceControllerTest.java
index 6699b34..96324fa 100644
--- a/tests/robotests/src/com/android/settings/deviceinfo/imei/ImeiInfoPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/deviceinfo/imei/ImeiInfoPreferenceControllerTest.java
@@ -54,8 +54,12 @@
 import org.mockito.MockitoAnnotations;
 import org.robolectric.RobolectricTestRunner;
 import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
 
 @RunWith(RobolectricTestRunner.class)
+@Config(shadows = {
+        com.android.settings.testutils.shadow.ShadowFragment.class,
+})
 public class ImeiInfoPreferenceControllerTest {
 
     @Mock
diff --git a/tests/robotests/src/com/android/settings/deviceinfo/storage/StorageItemPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/deviceinfo/storage/StorageItemPreferenceControllerTest.java
index e697786..5db0243 100644
--- a/tests/robotests/src/com/android/settings/deviceinfo/storage/StorageItemPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/deviceinfo/storage/StorageItemPreferenceControllerTest.java
@@ -67,6 +67,9 @@
 import org.robolectric.annotation.Config;
 
 @RunWith(RobolectricTestRunner.class)
+@Config(shadows = {
+        com.android.settings.testutils.shadow.ShadowFragment.class,
+})
 public class StorageItemPreferenceControllerTest {
 
     private Context mContext;
diff --git a/tests/robotests/src/com/android/settings/display/AutoRotatePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/display/AutoRotatePreferenceControllerTest.java
index 5611e93..2bcf060 100644
--- a/tests/robotests/src/com/android/settings/display/AutoRotatePreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/display/AutoRotatePreferenceControllerTest.java
@@ -50,6 +50,9 @@
 import org.robolectric.annotation.Config;
 
 @RunWith(RobolectricTestRunner.class)
+@Config(shadows = {
+        com.android.settings.testutils.shadow.ShadowSystemSettings.class,
+})
 public class AutoRotatePreferenceControllerTest {
 
     @Mock(answer = Answers.RETURNS_DEEP_STUBS)
diff --git a/tests/robotests/src/com/android/settings/display/BrightnessLevelPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/display/BrightnessLevelPreferenceControllerTest.java
index 673771d..1076d15 100644
--- a/tests/robotests/src/com/android/settings/display/BrightnessLevelPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/display/BrightnessLevelPreferenceControllerTest.java
@@ -21,6 +21,7 @@
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
@@ -85,7 +86,7 @@
         ShadowApplication.getInstance().setSystemService(POWER_SERVICE,
                 mPowerManager);
         when(mScreen.findPreference(anyString())).thenReturn(mPreference);
-        when(mContext.getDisplay()).thenReturn(mDisplay);
+        doReturn(mDisplay).when(mContext).getDisplay();
         mController = spy(new BrightnessLevelPreferenceController(mContext, null));
     }
 
diff --git a/tests/robotests/src/com/android/settings/display/ScreenTimeoutSettingsTest.java b/tests/robotests/src/com/android/settings/display/ScreenTimeoutSettingsTest.java
index 009ac53..c33bd21 100644
--- a/tests/robotests/src/com/android/settings/display/ScreenTimeoutSettingsTest.java
+++ b/tests/robotests/src/com/android/settings/display/ScreenTimeoutSettingsTest.java
@@ -57,10 +57,14 @@
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 import org.robolectric.RobolectricTestRunner;
+import org.robolectric.annotation.Config;
 
 import java.util.List;
 
 @RunWith(RobolectricTestRunner.class)
+@Config(shadows = {
+        com.android.settings.testutils.shadow.ShadowFragment.class,
+})
 public class ScreenTimeoutSettingsTest {
     private static final String[] TIMEOUT_ENTRIES = new String[]{"15 secs", "30 secs"};
     private static final String[] TIMEOUT_VALUES = new String[]{"15000", "30000"};
diff --git a/tests/robotests/src/com/android/settings/display/SmartAutoRotateControllerTest.java b/tests/robotests/src/com/android/settings/display/SmartAutoRotateControllerTest.java
index 4596364..63395d1 100644
--- a/tests/robotests/src/com/android/settings/display/SmartAutoRotateControllerTest.java
+++ b/tests/robotests/src/com/android/settings/display/SmartAutoRotateControllerTest.java
@@ -42,6 +42,7 @@
 import com.android.settings.testutils.shadow.ShadowDeviceStateRotationLockSettingsManager;
 import com.android.settings.testutils.shadow.ShadowRotationPolicy;
 import com.android.settings.testutils.shadow.ShadowSensorPrivacyManager;
+import com.android.settings.testutils.shadow.ShadowSystemSettings;
 import com.android.settingslib.devicestate.DeviceStateRotationLockSettingsManager;
 
 import org.junit.Before;
@@ -56,7 +57,7 @@
 import org.robolectric.shadow.api.Shadow;
 
 @RunWith(RobolectricTestRunner.class)
-@Config(shadows = ShadowSensorPrivacyManager.class)
+@Config(shadows = {ShadowSensorPrivacyManager.class, ShadowSystemSettings.class})
 public class SmartAutoRotateControllerTest {
 
     private static final String PACKAGE_NAME = "package_name";
diff --git a/tests/robotests/src/com/android/settings/display/SmartAutoRotatePreferenceFragmentTest.java b/tests/robotests/src/com/android/settings/display/SmartAutoRotatePreferenceFragmentTest.java
index 800dc5e..01bb338 100644
--- a/tests/robotests/src/com/android/settings/display/SmartAutoRotatePreferenceFragmentTest.java
+++ b/tests/robotests/src/com/android/settings/display/SmartAutoRotatePreferenceFragmentTest.java
@@ -63,6 +63,7 @@
 
 @RunWith(RobolectricTestRunner.class)
 @Config(shadows = {
+        com.android.settings.testutils.shadow.ShadowFragment.class,
         ShadowDeviceStateRotationLockSettingsManager.class,
         ShadowRotationPolicy.class
 })
diff --git a/tests/robotests/src/com/android/settings/display/darkmode/DarkModeActivationPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/display/darkmode/DarkModeActivationPreferenceControllerTest.java
index f41352b..56946c3 100644
--- a/tests/robotests/src/com/android/settings/display/darkmode/DarkModeActivationPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/display/darkmode/DarkModeActivationPreferenceControllerTest.java
@@ -45,10 +45,14 @@
 import org.mockito.MockitoAnnotations;
 import org.robolectric.RobolectricTestRunner;
 import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
 
 import java.util.Locale;
 
 @RunWith(RobolectricTestRunner.class)
+@Config(shadows = {
+        com.android.settings.testutils.shadow.ShadowDateFormat.class,
+})
 public class DarkModeActivationPreferenceControllerTest {
     private DarkModeActivationPreferenceController mController;
     private String mPreferenceKey = "key";
diff --git a/tests/robotests/src/com/android/settings/display/darkmode/DarkModeCustomPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/display/darkmode/DarkModeCustomPreferenceControllerTest.java
index 8ac6257..710e640 100644
--- a/tests/robotests/src/com/android/settings/display/darkmode/DarkModeCustomPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/display/darkmode/DarkModeCustomPreferenceControllerTest.java
@@ -40,8 +40,12 @@
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 import org.robolectric.RobolectricTestRunner;
+import org.robolectric.annotation.Config;
 
 @RunWith(RobolectricTestRunner.class)
+@Config(shadows = {
+        com.android.settings.testutils.shadow.ShadowDateFormat.class,
+})
 public class DarkModeCustomPreferenceControllerTest {
     private DarkModeCustomPreferenceController mController;
     @Mock
diff --git a/tests/robotests/src/com/android/settings/enterprise/EnterpriseSetDefaultAppsListPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/enterprise/EnterpriseSetDefaultAppsListPreferenceControllerTest.java
index b1e2c0c..1a16d04 100644
--- a/tests/robotests/src/com/android/settings/enterprise/EnterpriseSetDefaultAppsListPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/enterprise/EnterpriseSetDefaultAppsListPreferenceControllerTest.java
@@ -53,12 +53,14 @@
 import org.mockito.MockitoAnnotations;
 import org.robolectric.RobolectricTestRunner;
 import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.LooperMode;
 import org.robolectric.shadows.ShadowApplication;
 
 import java.util.Arrays;
 import java.util.Collections;
 
 @RunWith(RobolectricTestRunner.class)
+@LooperMode(LooperMode.Mode.LEGACY)
 public class EnterpriseSetDefaultAppsListPreferenceControllerTest {
 
     private static final int USER_ID = 0;
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetailTest.java b/tests/robotests/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetailTest.java
index 5e9fb73..5827498 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetailTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetailTest.java
@@ -30,6 +30,7 @@
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.verifyNoInteractions;
 import static org.mockito.Mockito.when;
+import static org.robolectric.shadows.ShadowLooper.shadowMainLooper;
 
 import android.app.AppOpsManager;
 import android.app.backup.BackupManager;
@@ -46,7 +47,6 @@
 
 import androidx.fragment.app.FragmentActivity;
 import androidx.loader.app.LoaderManager;
-import androidx.recyclerview.widget.RecyclerView;
 
 import com.android.settings.R;
 import com.android.settings.SettingsActivity;
@@ -59,7 +59,6 @@
 import com.android.settingslib.applications.ApplicationsState;
 import com.android.settingslib.applications.instantapps.InstantAppDataProvider;
 import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
-import com.android.settingslib.core.lifecycle.Lifecycle;
 import com.android.settingslib.widget.FooterPreference;
 import com.android.settingslib.widget.LayoutPreference;
 import com.android.settingslib.widget.SelectorWithWidgetPreference;
@@ -78,10 +77,12 @@
 import org.robolectric.annotation.Config;
 import org.robolectric.util.ReflectionHelpers;
 
-import java.util.concurrent.TimeUnit;
-
 @RunWith(RobolectricTestRunner.class)
-@Config(shadows = {ShadowEntityHeaderController.class, ShadowActivityManager.class})
+@Config(shadows = {
+        ShadowEntityHeaderController.class,
+        ShadowActivityManager.class,
+        com.android.settings.testutils.shadow.ShadowFragment.class,
+})
 public class AdvancedPowerUsageDetailTest {
     private static final String APP_LABEL = "app label";
     private static final String SUMMARY = "summary";
@@ -156,8 +157,6 @@
 
         ShadowEntityHeaderController.setUseMock(mEntityHeaderController);
         doReturn(mEntityHeaderController).when(mEntityHeaderController)
-                .setRecyclerView(nullable(RecyclerView.class), nullable(Lifecycle.class));
-        doReturn(mEntityHeaderController).when(mEntityHeaderController)
                 .setButtonActions(anyInt(), anyInt());
         doReturn(mEntityHeaderController).when(mEntityHeaderController)
                 .setIcon(nullable(Drawable.class));
@@ -768,7 +767,7 @@
         mFragment.onRadioButtonClicked(mOptimizePreference);
         mFragment.onPause();
 
-        TimeUnit.SECONDS.sleep(100);
+        shadowMainLooper().idle();
         verify(mMetricsFeatureProvider)
                 .action(
                         SettingsEnums.OPEN_APP_BATTERY_USAGE,
@@ -792,7 +791,7 @@
         mFragment.onRadioButtonClicked(mOptimizePreference);
         mFragment.onPause();
 
-        TimeUnit.SECONDS.sleep(100);
+        shadowMainLooper().idle();
         verifyNoInteractions(mMetricsFeatureProvider);
     }
 
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/BatteryHeaderPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/fuelgauge/BatteryHeaderPreferenceControllerTest.java
index 4b097bb..41bcb88 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/BatteryHeaderPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/BatteryHeaderPreferenceControllerTest.java
@@ -127,7 +127,6 @@
         mLifecycle.addObserver(mController);
         mController.setActivity(mActivity);
         mController.setFragment(mPreferenceFragment);
-        mController.setLifecycle(mLifecycle);
         mController.mBatteryUsageProgressBarPref = mBatteryUsageProgressBarPref;
         mController.mBatteryStatusFeatureProvider = mBatteryStatusFeatureProvider;
     }
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batterysaver/BatterySaverSettingsTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batterysaver/BatterySaverSettingsTest.java
index 7cb57a3..c858902 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batterysaver/BatterySaverSettingsTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batterysaver/BatterySaverSettingsTest.java
@@ -31,8 +31,12 @@
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 import org.robolectric.RobolectricTestRunner;
+import org.robolectric.annotation.Config;
 
 @RunWith(RobolectricTestRunner.class)
+@Config(shadows = {
+        com.android.settings.testutils.shadow.ShadowFragment.class,
+})
 public class BatterySaverSettingsTest {
     BatterySaverSettings mFragment;
     @Mock
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/AppUsageDataLoaderTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/AppUsageDataLoaderTest.java
deleted file mode 100644
index 4b250a3..0000000
--- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/AppUsageDataLoaderTest.java
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * 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.batteryusage;
-
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
-
-import android.content.ContentResolver;
-import android.content.Context;
-import android.content.Intent;
-import android.os.UserManager;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-import org.robolectric.RobolectricTestRunner;
-import org.robolectric.RuntimeEnvironment;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-
-@RunWith(RobolectricTestRunner.class)
-public final class AppUsageDataLoaderTest {
-    private Context mContext;
-    @Mock
-    private ContentResolver mMockContentResolver;
-    @Mock
-    private UserManager mUserManager;
-
-    @Before
-    public void setUp() {
-        MockitoAnnotations.initMocks(this);
-        mContext = spy(RuntimeEnvironment.application);
-        doReturn(mContext).when(mContext).getApplicationContext();
-        doReturn(mMockContentResolver).when(mContext).getContentResolver();
-        doReturn(mUserManager).when(mContext).getSystemService(UserManager.class);
-        doReturn(new Intent()).when(mContext).registerReceiver(any(), any());
-    }
-
-    @Test
-    public void loadAppUsageData_withData_insertFakeDataIntoProvider() {
-        final List<AppUsageEvent> AppUsageEventList = new ArrayList<>();
-        final AppUsageEvent appUsageEvent = AppUsageEvent.newBuilder().setUid(0).build();
-        AppUsageEventList.add(appUsageEvent);
-        AppUsageDataLoader.sFakeAppUsageEventsSupplier = () -> new HashMap<>();
-        AppUsageDataLoader.sFakeUsageEventsListSupplier = () -> AppUsageEventList;
-
-        AppUsageDataLoader.loadAppUsageData(mContext);
-
-        verify(mMockContentResolver).bulkInsert(any(), any());
-        verify(mMockContentResolver).notifyChange(any(), any());
-    }
-
-    @Test
-    public void loadAppUsageData_nullAppUsageEvents_notInsertDataIntoProvider() {
-        AppUsageDataLoader.sFakeAppUsageEventsSupplier = () -> null;
-
-        AppUsageDataLoader.loadAppUsageData(mContext);
-
-        verifyNoMoreInteractions(mMockContentResolver);
-    }
-
-    @Test
-    public void loadAppUsageData_nullUsageEventsList_notInsertDataIntoProvider() {
-        AppUsageDataLoader.sFakeAppUsageEventsSupplier = () -> new HashMap<>();
-        AppUsageDataLoader.sFakeUsageEventsListSupplier = () -> null;
-
-        AppUsageDataLoader.loadAppUsageData(mContext);
-
-        verifyNoMoreInteractions(mMockContentResolver);
-    }
-
-    @Test
-    public void loadAppUsageData_emptyUsageEventsList_notInsertDataIntoProvider() {
-        AppUsageDataLoader.sFakeAppUsageEventsSupplier = () -> new HashMap<>();
-        AppUsageDataLoader.sFakeUsageEventsListSupplier = () -> new ArrayList<>();
-
-        AppUsageDataLoader.loadAppUsageData(mContext);
-
-        verifyNoMoreInteractions(mMockContentResolver);
-    }
-}
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 e1c193c..a54d4c1 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryChartPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryChartPreferenceControllerTest.java
@@ -16,6 +16,8 @@
 
 package com.android.settings.fuelgauge.batteryusage;
 
+import static com.android.settings.fuelgauge.batteryusage.BatteryChartViewModel.SELECTED_INDEX_ALL;
+
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.mockito.ArgumentMatchers.anyFloat;
@@ -30,7 +32,6 @@
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.verify;
 
-import android.content.ContentValues;
 import android.content.Context;
 import android.content.Intent;
 import android.content.res.Resources;
@@ -39,6 +40,7 @@
 import android.os.LocaleList;
 import android.os.UserManager;
 import android.text.format.DateUtils;
+import android.util.ArrayMap;
 import android.view.View;
 import android.view.ViewPropertyAnimator;
 import android.widget.LinearLayout;
@@ -54,7 +56,6 @@
 import org.robolectric.RobolectricTestRunner;
 import org.robolectric.RuntimeEnvironment;
 
-import java.util.HashMap;
 import java.util.List;
 import java.util.Locale;
 import java.util.Map;
@@ -112,6 +113,7 @@
         mBatteryChartPreferenceController.mPrefContext = mContext;
         mBatteryChartPreferenceController.mDailyChartView = mDailyChartView;
         mBatteryChartPreferenceController.mHourlyChartView = mHourlyChartView;
+        BatteryDiffEntry.clearCache();
         // Adds fake testing data.
         BatteryDiffEntry.sResourceCache.put(
                 "fakeBatteryDiffEntryKey",
@@ -144,7 +146,7 @@
         reset(mHourlyChartView);
         setupHourlyChartViewAnimationMock();
 
-        mBatteryChartPreferenceController.setBatteryHistoryMap(createBatteryHistoryMap(6));
+        mBatteryChartPreferenceController.onBatteryLevelDataUpdate(createBatteryLevelData(6));
 
         verify(mDailyChartView, atLeastOnce()).setVisibility(View.GONE);
         // Ignore fast refresh ui from the data processor callback.
@@ -176,16 +178,18 @@
                 BatteryChartViewModel.AxisLabelPosition.CENTER_OF_TRAPEZOIDS,
                 mBatteryChartPreferenceController.mDailyChartLabelTextGenerator);
 
-        mBatteryChartPreferenceController.setBatteryHistoryMap(createBatteryHistoryMap(60));
+        mBatteryChartPreferenceController.onBatteryLevelDataUpdate(createBatteryLevelData(60));
+        mBatteryChartPreferenceController.onBatteryUsageMapUpdate(getEmptyBatteryUsageMap());
 
         verify(mDailyChartView, atLeastOnce()).setVisibility(View.VISIBLE);
         verify(mViewPropertyAnimator, atLeastOnce()).alpha(0f);
-        verify(mDailyChartView).setViewModel(expectedDailyViewModel);
+        verify(mDailyChartView, atLeastOnce()).setViewModel(expectedDailyViewModel);
 
         reset(mDailyChartView);
         reset(mHourlyChartView);
         setupHourlyChartViewAnimationMock();
         doReturn(mLayoutParams).when(mDailyChartView).getLayoutParams();
+        doReturn(View.GONE).when(mHourlyChartView).getVisibility();
         mBatteryChartPreferenceController.mDailyChartIndex = 0;
         mBatteryChartPreferenceController.refreshUi();
         verify(mDailyChartView).setVisibility(View.VISIBLE);
@@ -245,8 +249,7 @@
         setupHourlyChartViewAnimationMock();
         doReturn(mLayoutParams).when(mDailyChartView).getLayoutParams();
         mBatteryChartPreferenceController.mDailyChartIndex = 2;
-        mBatteryChartPreferenceController.mHourlyChartIndex =
-                BatteryChartViewModel.SELECTED_INDEX_ALL;
+        mBatteryChartPreferenceController.mHourlyChartIndex = SELECTED_INDEX_ALL;
         mBatteryChartPreferenceController.refreshUi();
         verify(mDailyChartView).setVisibility(View.VISIBLE);
         verify(mViewPropertyAnimator, atLeastOnce()).alpha(1f);
@@ -272,13 +275,15 @@
 
     @Test
     public void refreshUi_normalCase_returnTrue() {
-        mBatteryChartPreferenceController.setBatteryHistoryMap(createBatteryHistoryMap(6));
+        mBatteryChartPreferenceController.onBatteryLevelDataUpdate(createBatteryLevelData(6));
+        mBatteryChartPreferenceController.onBatteryUsageMapUpdate(getEmptyBatteryUsageMap());
         assertThat(mBatteryChartPreferenceController.refreshUi()).isTrue();
     }
 
     @Test
     public void refreshUi_batteryIndexedMapIsNull_returnTrue() {
-        mBatteryChartPreferenceController.setBatteryHistoryMap(null);
+        mBatteryChartPreferenceController.onBatteryLevelDataUpdate(null);
+        mBatteryChartPreferenceController.onBatteryUsageMapUpdate(getEmptyBatteryUsageMap());
         assertThat(mBatteryChartPreferenceController.refreshUi()).isTrue();
     }
 
@@ -296,38 +301,34 @@
 
     @Test
     public void selectedSlotText_selectAllDaysAllHours_returnNull() {
-        mBatteryChartPreferenceController.setBatteryHistoryMap(createBatteryHistoryMap(60));
-        mBatteryChartPreferenceController.mDailyChartIndex =
-                BatteryChartViewModel.SELECTED_INDEX_ALL;
-        mBatteryChartPreferenceController.mHourlyChartIndex =
-                BatteryChartViewModel.SELECTED_INDEX_ALL;
+        mBatteryChartPreferenceController.onBatteryLevelDataUpdate(createBatteryLevelData(60));
+        mBatteryChartPreferenceController.mDailyChartIndex = SELECTED_INDEX_ALL;
+        mBatteryChartPreferenceController.mHourlyChartIndex = SELECTED_INDEX_ALL;
 
         assertThat(mBatteryChartPreferenceController.getSlotInformation()).isEqualTo(null);
     }
 
     @Test
     public void selectedSlotText_onlyOneDayDataSelectAllHours_returnNull() {
-        mBatteryChartPreferenceController.setBatteryHistoryMap(createBatteryHistoryMap(6));
+        mBatteryChartPreferenceController.onBatteryLevelDataUpdate(createBatteryLevelData(6));
         mBatteryChartPreferenceController.mDailyChartIndex = 0;
-        mBatteryChartPreferenceController.mHourlyChartIndex =
-                BatteryChartViewModel.SELECTED_INDEX_ALL;
+        mBatteryChartPreferenceController.mHourlyChartIndex = SELECTED_INDEX_ALL;
 
         assertThat(mBatteryChartPreferenceController.getSlotInformation()).isEqualTo(null);
     }
 
     @Test
     public void selectedSlotText_selectADayAllHours_onlyDayText() {
-        mBatteryChartPreferenceController.setBatteryHistoryMap(createBatteryHistoryMap(60));
+        mBatteryChartPreferenceController.onBatteryLevelDataUpdate(createBatteryLevelData(60));
         mBatteryChartPreferenceController.mDailyChartIndex = 1;
-        mBatteryChartPreferenceController.mHourlyChartIndex =
-                BatteryChartViewModel.SELECTED_INDEX_ALL;
+        mBatteryChartPreferenceController.mHourlyChartIndex = SELECTED_INDEX_ALL;
 
         assertThat(mBatteryChartPreferenceController.getSlotInformation()).isEqualTo("Sunday");
     }
 
     @Test
     public void selectedSlotText_onlyOneDayDataSelectAnHour_onlyHourText() {
-        mBatteryChartPreferenceController.setBatteryHistoryMap(createBatteryHistoryMap(6));
+        mBatteryChartPreferenceController.onBatteryLevelDataUpdate(createBatteryLevelData(6));
         mBatteryChartPreferenceController.mDailyChartIndex = 0;
         mBatteryChartPreferenceController.mHourlyChartIndex = 2;
 
@@ -337,7 +338,7 @@
 
     @Test
     public void selectedSlotText_SelectADayAnHour_dayAndHourText() {
-        mBatteryChartPreferenceController.setBatteryHistoryMap(createBatteryHistoryMap(60));
+        mBatteryChartPreferenceController.onBatteryLevelDataUpdate(createBatteryLevelData(60));
         mBatteryChartPreferenceController.mDailyChartIndex = 1;
         mBatteryChartPreferenceController.mHourlyChartIndex = 8;
 
@@ -347,7 +348,7 @@
 
     @Test
     public void selectedSlotText_selectFirstSlot_withMinuteText() {
-        mBatteryChartPreferenceController.setBatteryHistoryMap(createBatteryHistoryMap(6));
+        mBatteryChartPreferenceController.onBatteryLevelDataUpdate(createBatteryLevelData(6));
         mBatteryChartPreferenceController.mDailyChartIndex = 0;
         mBatteryChartPreferenceController.mHourlyChartIndex = 0;
 
@@ -357,7 +358,7 @@
 
     @Test
     public void selectedSlotText_selectLastSlot_withNowText() {
-        mBatteryChartPreferenceController.setBatteryHistoryMap(createBatteryHistoryMap(6));
+        mBatteryChartPreferenceController.onBatteryLevelDataUpdate(createBatteryLevelData(6));
         mBatteryChartPreferenceController.mDailyChartIndex = 0;
         mBatteryChartPreferenceController.mHourlyChartIndex = 3;
 
@@ -367,7 +368,7 @@
 
     @Test
     public void selectedSlotText_selectOnlySlot_withMinuteAndNowText() {
-        mBatteryChartPreferenceController.setBatteryHistoryMap(createBatteryHistoryMap(1));
+        mBatteryChartPreferenceController.onBatteryLevelDataUpdate(createBatteryLevelData(1));
         mBatteryChartPreferenceController.mDailyChartIndex = 0;
         mBatteryChartPreferenceController.mHourlyChartIndex = 0;
 
@@ -388,7 +389,7 @@
         mBatteryChartPreferenceController.mHourlyChartIndex = -1;
 
         mBatteryChartPreferenceController.onCreate(bundle);
-        mBatteryChartPreferenceController.setBatteryHistoryMap(createBatteryHistoryMap(25));
+        mBatteryChartPreferenceController.onBatteryLevelDataUpdate(createBatteryLevelData(25));
 
         assertThat(mBatteryChartPreferenceController.mDailyChartIndex)
                 .isEqualTo(expectedDailyIndex);
@@ -398,9 +399,7 @@
 
     @Test
     public void getTotalHours_getExpectedResult() {
-        Map<Long, Map<String, BatteryHistEntry>> batteryHistoryMap = createBatteryHistoryMap(60);
-        BatteryLevelData batteryLevelData =
-                DataProcessManager.getBatteryLevelData(mContext, null, batteryHistoryMap, null);
+        BatteryLevelData batteryLevelData = createBatteryLevelData(60);
 
         final int totalHour = BatteryChartPreferenceController.getTotalHours(batteryLevelData);
 
@@ -413,37 +412,26 @@
         return 1619247600000L + index * DateUtils.HOUR_IN_MILLIS;
     }
 
-    private static Map<Long, Map<String, BatteryHistEntry>> createBatteryHistoryMap(
-            int numOfHours) {
-        final Map<Long, Map<String, BatteryHistEntry>> batteryHistoryMap = new HashMap<>();
-        for (int index = 0; index < numOfHours; index++) {
-            final ContentValues values = new ContentValues();
-            final DeviceBatteryState deviceBatteryState =
-                    DeviceBatteryState
-                            .newBuilder()
-                            .setBatteryLevel(100 - index)
-                            .build();
-            final BatteryInformation batteryInformation =
-                    BatteryInformation
-                            .newBuilder()
-                            .setDeviceBatteryState(deviceBatteryState)
-                            .setConsumePower(100 - index)
-                            .build();
-            values.put(BatteryHistEntry.KEY_BATTERY_INFORMATION,
-                    ConvertUtils.convertBatteryInformationToString(batteryInformation));
-            values.put(BatteryHistEntry.KEY_PACKAGE_NAME, "package" + index);
-            final BatteryHistEntry entry = new BatteryHistEntry(values);
-            final Map<String, BatteryHistEntry> entryMap = new HashMap<>();
-            entryMap.put("fake_entry_key" + index, entry);
-            long timestamp = generateTimestamp(index);
+    private static BatteryLevelData createBatteryLevelData(int numOfHours) {
+        Map<Long, Integer> batteryLevelMap = new ArrayMap<>();
+        for (int index = 0; index < numOfHours; index += 2) {
+            final Integer level = 100 - index;
+            Long timestamp = generateTimestamp(index);
             if (index == 0) {
                 timestamp += DateUtils.MINUTE_IN_MILLIS;
+                index--;
             }
-            batteryHistoryMap.put(timestamp, entryMap);
+            batteryLevelMap.put(timestamp, level);
         }
-        DataProcessor.sTestCurrentTimeMillis =
-                generateTimestamp(numOfHours - 1) + DateUtils.MINUTE_IN_MILLIS * 2;
-        return batteryHistoryMap;
+        long current = generateTimestamp(numOfHours - 1) + DateUtils.MINUTE_IN_MILLIS * 2;
+        batteryLevelMap.put(current, 66);
+        DataProcessor.sTestCurrentTimeMillis = current;
+        return new BatteryLevelData(batteryLevelMap);
+    }
+
+    private static Map<Integer, Map<Integer, BatteryDiffData>> getEmptyBatteryUsageMap() {
+        return Map.of(SELECTED_INDEX_ALL, Map.of(SELECTED_INDEX_ALL, new BatteryDiffData(
+                null, 0, 0, 0, 0, 0, List.of(), List.of(), Set.of(), Set.of(), false)));
     }
 
     private BatteryChartPreferenceController createController() {
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryDiffDataTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryDiffDataTest.java
index 27539a5..d4bae29 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryDiffDataTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryDiffDataTest.java
@@ -147,6 +147,14 @@
                 /*foregroundUsageTimeInMs=*/ 0L,  /*backgroundUsageTimeInMs=*/ 0L, isHidden);
         return new BatteryDiffEntry(
                 context,
+                batteryHistEntry.mUid,
+                batteryHistEntry.mUserId,
+                batteryHistEntry.getKey(),
+                batteryHistEntry.mIsHidden,
+                batteryHistEntry.mDrainType,
+                batteryHistEntry.mPackageName,
+                batteryHistEntry.mAppLabel,
+                batteryHistEntry.mConsumerType,
                 /*foregroundUsageTimeInMs=*/ 0,
                 /*backgroundUsageTimeInMs=*/ 0,
                 /*screenOnTimeInMs=*/ 0,
@@ -154,8 +162,7 @@
                 /*foregroundUsageConsumePower=*/ 0,
                 /*foregroundServiceUsageConsumePower=*/ 0,
                 /*backgroundUsageConsumePower=*/ 0,
-                /*cachedUsageConsumePower=*/ 0,
-                batteryHistEntry);
+                /*cachedUsageConsumePower=*/ 0);
     }
 
     private static BatteryHistEntry createBatteryHistEntry(
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 655f1e4..9bb4b73 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryDiffEntryTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryDiffEntryTest.java
@@ -95,6 +95,14 @@
         final BatteryDiffEntry entry =
                 new BatteryDiffEntry(
                         mContext,
+                        /*uid=*/ 0,
+                        /*userId=*/ 0,
+                        /*key=*/ "key",
+                        /*isHidden=*/ false,
+                        /*componentId=*/ -1,
+                        /*legacyPackageName=*/ null,
+                        /*legacyLabel=*/ null,
+                        /*consumerType*/ ConvertUtils.CONSUMER_TYPE_UID_BATTERY,
                         /*foregroundUsageTimeInMs=*/ 10001L,
                         /*backgroundUsageTimeInMs=*/ 20002L,
                         /*screenOnTimeInMs=*/ 30003L,
@@ -102,8 +110,7 @@
                         /*foregroundUsageConsumePower=*/ 10.0,
                         /*foregroundServiceUsageConsumePower=*/ 10.0,
                         /*backgroundUsageConsumePower=*/ 1.0,
-                        /*cachedUsageConsumePower=*/ 1.0,
-                        /*batteryHistEntry=*/ null);
+                        /*cachedUsageConsumePower=*/ 1.0);
         entry.setTotalConsumePower(100.0);
 
         assertThat(entry.getPercentage()).isEqualTo(22.0);
@@ -114,6 +121,14 @@
         final BatteryDiffEntry entry =
                 new BatteryDiffEntry(
                         mContext,
+                        /*uid=*/ 0,
+                        /*userId=*/ 0,
+                        /*key=*/ "key",
+                        /*isHidden=*/ false,
+                        /*componentId=*/ -1,
+                        /*legacyPackageName=*/ null,
+                        /*legacyLabel=*/ null,
+                        /*consumerType*/ ConvertUtils.CONSUMER_TYPE_UID_BATTERY,
                         /*foregroundUsageTimeInMs=*/ 10001L,
                         /*backgroundUsageTimeInMs=*/ 20002L,
                         /*screenOnTimeInMs=*/ 30003L,
@@ -121,8 +136,7 @@
                         /*foregroundUsageConsumePower=*/ 10.0,
                         /*foregroundServiceUsageConsumePower=*/ 10.0,
                         /*backgroundUsageConsumePower=*/ 1.0,
-                        /*cachedUsageConsumePower=*/ 1.0,
-                        /*batteryHistEntry=*/ null);
+                        /*cachedUsageConsumePower=*/ 1.0);
         entry.setTotalConsumePower(0);
 
         assertThat(entry.getPercentage()).isEqualTo(0);
@@ -133,7 +147,24 @@
         final List<BatteryDiffEntry> entryList = new ArrayList<>();
         // Generates fake testing data.
         BatteryDiffEntry systemAppsBatteryDiffEntry =
-                new BatteryDiffEntry.SystemAppsBatteryDiffEntry(mContext);
+                new BatteryDiffEntry(
+                        mContext,
+                        /*uid=*/ 0,
+                        /*userId=*/ 0,
+                        /*key=*/ BatteryDiffEntry.SYSTEM_APPS_KEY,
+                        /*isHidden=*/ false,
+                        /*componentId=*/ -1,
+                        /*legacyPackageName=*/ null,
+                        /*legacyLabel=*/ BatteryDiffEntry.SYSTEM_APPS_KEY,
+                        /*consumerType*/ ConvertUtils.CONSUMER_TYPE_UID_BATTERY,
+                        /*foregroundUsageTimeInMs=*/ 0,
+                        /*backgroundUsageTimeInMs=*/ 0,
+                        /*screenOnTimeInMs=*/ 0,
+                        /*consumePower=*/ 0,
+                        /*foregroundUsageConsumePower=*/ 0,
+                        /*foregroundServiceUsageConsumePower=*/ 0,
+                        /*backgroundUsageConsumePower=*/ 0,
+                        /*cachedUsageConsumePower=*/ 0);
         systemAppsBatteryDiffEntry.mConsumePower = 16;
         systemAppsBatteryDiffEntry.setTotalConsumePower(100);
         entryList.add(systemAppsBatteryDiffEntry);
@@ -448,17 +479,16 @@
 
     private BatteryDiffEntry createBatteryDiffEntry(
             int consumerType, long uid, boolean isHidden) {
-        final ContentValues values = getContentValuesWithType(consumerType);
-        final BatteryInformation batteryInformation =
-                BatteryInformation
-                        .newBuilder()
-                        .setIsHidden(isHidden)
-                        .build();
-        values.put(BatteryHistEntry.KEY_BATTERY_INFORMATION,
-                ConvertUtils.convertBatteryInformationToString(batteryInformation));
-        values.put(BatteryHistEntry.KEY_UID, uid);
         return new BatteryDiffEntry(
                 mContext,
+                /*uid=*/ uid,
+                /*userId=*/ 0,
+                /*key=*/ "key",
+                /*isHidden=*/ isHidden,
+                /*componentId=*/ -1,
+                /*legacyPackageName=*/ null,
+                /*legacyLabel=*/ null,
+                /*consumerType*/ consumerType,
                 /*foregroundUsageTimeInMs=*/ 0,
                 /*backgroundUsageTimeInMs=*/ 0,
                 /*screenOnTimeInMs=*/ 0,
@@ -466,14 +496,21 @@
                 /*foregroundUsageConsumePower=*/ 0,
                 /*foregroundServiceUsageConsumePower=*/ 0,
                 /*backgroundUsageConsumePower=*/ 0,
-                /*cachedUsageConsumePower=*/ 0,
-                new BatteryHistEntry(values));
+                /*cachedUsageConsumePower=*/ 0);
     }
 
     private BatteryDiffEntry createBatteryDiffEntry(
             double consumePower, BatteryHistEntry batteryHistEntry) {
         final BatteryDiffEntry entry = new BatteryDiffEntry(
                 mContext,
+                batteryHistEntry.mUid,
+                batteryHistEntry.mUserId,
+                batteryHistEntry.getKey(),
+                batteryHistEntry.mIsHidden,
+                batteryHistEntry.mDrainType,
+                batteryHistEntry.mPackageName,
+                batteryHistEntry.mAppLabel,
+                batteryHistEntry.mConsumerType,
                 /*foregroundUsageTimeInMs=*/ 0,
                 /*backgroundUsageTimeInMs=*/ 0,
                 /*screenOnTimeInMs=*/ 0,
@@ -481,8 +518,7 @@
                 /*foregroundUsageConsumePower=*/ 0,
                 /*foregroundServiceUsageConsumePower=*/ 0,
                 /*backgroundUsageConsumePower=*/ 0,
-                /*cachedUsageConsumePower=*/ 0,
-                batteryHistEntry);
+                /*cachedUsageConsumePower=*/ 0);
         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 9667760..609f2fc 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryHistEntryTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryHistEntryTest.java
@@ -15,6 +15,10 @@
  */
 package com.android.settings.fuelgauge.batteryusage;
 
+import static com.android.settings.fuelgauge.batteryusage.ConvertUtils.isSystemConsumer;
+import static com.android.settings.fuelgauge.batteryusage.ConvertUtils.isUidConsumer;
+import static com.android.settings.fuelgauge.batteryusage.ConvertUtils.isUserConsumer;
+
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.mockito.Mockito.when;
@@ -147,32 +151,32 @@
 
     @Test
     public void testIsAppEntry_returnExpectedResult() {
-        assertThat(createEntry(ConvertUtils.CONSUMER_TYPE_SYSTEM_BATTERY).isAppEntry())
-                .isFalse();
-        assertThat(createEntry(ConvertUtils.CONSUMER_TYPE_USER_BATTERY).isAppEntry())
-                .isFalse();
-        assertThat(createEntry(ConvertUtils.CONSUMER_TYPE_UID_BATTERY).isAppEntry())
-                .isTrue();
+        assertThat(isUidConsumer(
+                createEntry(ConvertUtils.CONSUMER_TYPE_SYSTEM_BATTERY).mConsumerType)).isFalse();
+        assertThat(isUidConsumer(
+                createEntry(ConvertUtils.CONSUMER_TYPE_USER_BATTERY).mConsumerType)).isFalse();
+        assertThat(isUidConsumer(
+                createEntry(ConvertUtils.CONSUMER_TYPE_UID_BATTERY).mConsumerType)).isTrue();
     }
 
     @Test
     public void testIsUserEntry_returnExpectedResult() {
-        assertThat(createEntry(ConvertUtils.CONSUMER_TYPE_SYSTEM_BATTERY).isUserEntry())
-                .isFalse();
-        assertThat(createEntry(ConvertUtils.CONSUMER_TYPE_USER_BATTERY).isUserEntry())
-                .isTrue();
-        assertThat(createEntry(ConvertUtils.CONSUMER_TYPE_UID_BATTERY).isUserEntry())
-                .isFalse();
+        assertThat(isUserConsumer(
+                createEntry(ConvertUtils.CONSUMER_TYPE_SYSTEM_BATTERY).mConsumerType)).isFalse();
+        assertThat(isUserConsumer(
+                createEntry(ConvertUtils.CONSUMER_TYPE_USER_BATTERY).mConsumerType)).isTrue();
+        assertThat(isUserConsumer(
+                createEntry(ConvertUtils.CONSUMER_TYPE_UID_BATTERY).mConsumerType)).isFalse();
     }
 
     @Test
     public void testIsSystemEntry_returnExpectedResult() {
-        assertThat(createEntry(ConvertUtils.CONSUMER_TYPE_SYSTEM_BATTERY).isSystemEntry())
-                .isTrue();
-        assertThat(createEntry(ConvertUtils.CONSUMER_TYPE_USER_BATTERY).isSystemEntry())
-                .isFalse();
-        assertThat(createEntry(ConvertUtils.CONSUMER_TYPE_UID_BATTERY).isSystemEntry())
-                .isFalse();
+        assertThat(isSystemConsumer(
+                createEntry(ConvertUtils.CONSUMER_TYPE_SYSTEM_BATTERY).mConsumerType)).isTrue();
+        assertThat(isSystemConsumer(
+                createEntry(ConvertUtils.CONSUMER_TYPE_USER_BATTERY).mConsumerType)).isFalse();
+        assertThat(isSystemConsumer(
+                createEntry(ConvertUtils.CONSUMER_TYPE_UID_BATTERY).mConsumerType)).isFalse();
     }
 
     @Test
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryHistoryPreferenceTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryHistoryPreferenceTest.java
index e14ead5..9155c66 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryHistoryPreferenceTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryHistoryPreferenceTest.java
@@ -27,7 +27,6 @@
 import androidx.preference.PreferenceViewHolder;
 
 import com.android.settings.R;
-import com.android.settings.fuelgauge.BatteryInfo;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -42,8 +41,6 @@
     @Mock
     private PreferenceViewHolder mViewHolder;
     @Mock
-    private BatteryInfo mBatteryInfo;
-    @Mock
     private TextView mTextView;
     @Mock
     private BatteryChartView mDailyChartView;
@@ -59,7 +56,6 @@
                 LayoutInflater.from(context).inflate(R.layout.battery_chart_graph, null);
 
         mBatteryHistoryPreference = new BatteryHistoryPreference(context, null);
-        mBatteryHistoryPreference.mBatteryInfo = mBatteryInfo;
         mViewHolder = spy(PreferenceViewHolder.createInstanceForTests(itemView));
         when(mViewHolder.findViewById(R.id.daily_battery_chart)).thenReturn(mDailyChartView);
         when(mViewHolder.findViewById(R.id.hourly_battery_chart)).thenReturn(mHourlyChartView);
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryLevelDataTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryLevelDataTest.java
new file mode 100644
index 0000000..13d60bb
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryLevelDataTest.java
@@ -0,0 +1,214 @@
+/*
+ * Copyright (C) 2023 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.batteryusage;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
+
+import java.util.List;
+import java.util.Map;
+import java.util.TimeZone;
+
+@RunWith(RobolectricTestRunner.class)
+public class BatteryLevelDataTest {
+
+    @Before
+    public void setUp() {
+        TimeZone.setDefault(TimeZone.getTimeZone("GMT+8"));
+    }
+
+    @Test
+    public void getDailyTimestamps_allDataInOneHour_returnExpectedList() {
+        // Timezone GMT+8
+        final List<Long> timestamps = List.of(
+                1640970006000L, // 2022-01-01 01:00:06
+                1640973608000L  // 2022-01-01 01:00:08
+        );
+
+        final List<Long> expectedTimestamps = List.of(
+                1640970006000L, // 2022-01-01 01:00:06
+                1640973608000L  // 2022-01-01 01:00:08
+        );
+        assertThat(BatteryLevelData.getDailyTimestamps(timestamps)).isEqualTo(expectedTimestamps);
+    }
+
+    @Test
+    public void getDailyTimestamps_OneHourDataPerDay_returnExpectedList() {
+        // Timezone GMT+8
+        final List<Long> timestamps = List.of(
+                1641049200000L, // 2022-01-01 23:00:00
+                1641052800000L, // 2022-01-02 00:00:00
+                1641056400000L  // 2022-01-02 01:00:00
+        );
+
+        final List<Long> expectedTimestamps = List.of(
+                1641049200000L, // 2022-01-01 23:00:00
+                1641052800000L, // 2022-01-02 00:00:00
+                1641056400000L  // 2022-01-02 01:00:00
+        );
+        assertThat(BatteryLevelData.getDailyTimestamps(timestamps)).isEqualTo(expectedTimestamps);
+    }
+
+    @Test
+    public void getDailyTimestamps_OneDayData_returnExpectedList() {
+        // Timezone GMT+8
+        final List<Long> timestamps = List.of(
+                1640966400000L, // 2022-01-01 00:00:00
+                1640970000000L, // 2022-01-01 01:00:00
+                1640973600000L, // 2022-01-01 02:00:00
+                1640977200000L, // 2022-01-01 03:00:00
+                1640980800000L  // 2022-01-01 04:00:00
+        );
+
+        final List<Long> expectedTimestamps = List.of(
+                1640966400000L, // 2022-01-01 00:00:00
+                1640980800000L  // 2022-01-01 04:00:00
+        );
+        assertThat(BatteryLevelData.getDailyTimestamps(timestamps)).isEqualTo(expectedTimestamps);
+    }
+
+    @Test
+    public void getDailyTimestamps_MultipleDaysData_returnExpectedList() {
+        // Timezone GMT+8
+        final List<Long> timestamps = List.of(
+                1641045600000L, // 2022-01-01 22:00:00
+                1641060000000L, // 2022-01-02 02:00:00
+                1641160800000L, // 2022-01-03 06:00:00
+                1641232800000L  // 2022-01-04 02:00:00
+        );
+
+        final List<Long> expectedTimestamps = List.of(
+                1641045600000L, // 2022-01-01 22:00:00
+                1641052800000L, // 2022-01-02 00:00:00
+                1641139200000L, // 2022-01-03 00:00:00
+                1641225600000L, // 2022-01-04 00:00:00
+                1641232800000L  // 2022-01-04 02:00:00
+        );
+        assertThat(BatteryLevelData.getDailyTimestamps(timestamps)).isEqualTo(expectedTimestamps);
+    }
+
+    @Test
+    public void getDailyTimestamps_FirstDayOneHourData_returnExpectedList() {
+        // Timezone GMT+8
+        final List<Long> timestamps = List.of(
+                1641049200000L, // 2022-01-01 23:00:00
+                1641060000000L, // 2022-01-02 02:00:00
+                1641160800000L, // 2022-01-03 06:00:00
+                1641254400000L  // 2022-01-04 08:00:00
+        );
+
+        final List<Long> expectedTimestamps = List.of(
+                1641049200000L, // 2022-01-01 23:00:00
+                1641052800000L, // 2022-01-02 00:00:00
+                1641139200000L, // 2022-01-03 00:00:00
+                1641225600000L, // 2022-01-04 00:00:00
+                1641254400000L  // 2022-01-04 08:00:00
+        );
+        assertThat(BatteryLevelData.getDailyTimestamps(timestamps)).isEqualTo(expectedTimestamps);
+    }
+
+    @Test
+    public void getDailyTimestamps_LastDayNoData_returnExpectedList() {
+        // Timezone GMT+8
+        final List<Long> timestamps = List.of(
+                1640988000000L, // 2022-01-01 06:00:00
+                1641060000000L, // 2022-01-02 02:00:00
+                1641160800000L, // 2022-01-03 06:00:00
+                1641225600000L  // 2022-01-04 00:00:00
+        );
+
+        final List<Long> expectedTimestamps = List.of(
+                1640988000000L, // 2022-01-01 06:00:00
+                1641052800000L, // 2022-01-02 00:00:00
+                1641139200000L, // 2022-01-03 00:00:00
+                1641225600000L  // 2022-01-04 00:00:00
+        );
+        assertThat(BatteryLevelData.getDailyTimestamps(timestamps)).isEqualTo(expectedTimestamps);
+    }
+
+    @Test
+    public void getDailyTimestamps_LastDayOneHourData_returnExpectedList() {
+        // Timezone GMT+8
+        final List<Long> timestamps = List.of(
+                1640988000000L, // 2022-01-01 06:00:00
+                1641060000000L, // 2022-01-02 02:00:00
+                1641160800000L, // 2022-01-03 06:00:00
+                1641229200000L  // 2022-01-04 01:00:00
+        );
+
+        final List<Long> expectedTimestamps = List.of(
+                1640988000000L, // 2022-01-01 06:00:00
+                1641052800000L, // 2022-01-02 00:00:00
+                1641139200000L, // 2022-01-03 00:00:00
+                1641225600000L, // 2022-01-04 00:00:00
+                1641229200000L  // 2022-01-04 01:00:00
+        );
+        assertThat(BatteryLevelData.getDailyTimestamps(timestamps)).isEqualTo(expectedTimestamps);
+    }
+
+    @Test
+    public void combine_normalFlow_returnExpectedResult() {
+        final BatteryLevelData batteryLevelData =
+                new BatteryLevelData(Map.of(1691596800000L, 90, 1691604000000L, 80));
+        final List<BatteryEvent> batteryLevelRecordEvents = List.of(
+                BatteryEvent.newBuilder().setTimestamp(1691586000166L).setBatteryLevel(100)
+                        .setType(BatteryEventType.FULL_CHARGED).build(),
+                BatteryEvent.newBuilder().setTimestamp(1691589600000L).setBatteryLevel(98)
+                        .setType(BatteryEventType.EVEN_HOUR).build());
+
+        BatteryLevelData result =
+                BatteryLevelData.combine(batteryLevelData, batteryLevelRecordEvents);
+
+        assertThat(result.getDailyBatteryLevels().getTimestamps())
+                .isEqualTo(List.of(1691586000166L, 1691596800000L, 1691604000000L));
+        assertThat(result.getDailyBatteryLevels().getLevels())
+                .isEqualTo(List.of(100, 90, 80));
+        assertThat(result.getHourlyBatteryLevelsPerDay())
+                .hasSize(2);
+        assertThat(result.getHourlyBatteryLevelsPerDay().get(0).getTimestamps())
+                .isEqualTo(List.of(1691586000166L, 1691589600000L, 1691596800000L));
+        assertThat(result.getHourlyBatteryLevelsPerDay().get(0).getLevels())
+                .isEqualTo(List.of(100, 98, 90));
+        assertThat(result.getHourlyBatteryLevelsPerDay().get(1).getTimestamps())
+                .isEqualTo(List.of(1691596800000L, 1691604000000L));
+        assertThat(result.getHourlyBatteryLevelsPerDay().get(1).getLevels())
+                .isEqualTo(List.of(90, 80));
+    }
+
+    @Test
+    public void combine_existingBatteryLevelDataIsNull_returnExpectedResult() {
+        final List<BatteryEvent> batteryLevelRecordEvents = List.of(
+                BatteryEvent.newBuilder().setTimestamp(1691586000166L).setBatteryLevel(100)
+                        .setType(BatteryEventType.FULL_CHARGED).build(),
+                BatteryEvent.newBuilder().setTimestamp(1691589600000L).setBatteryLevel(98)
+                        .setType(BatteryEventType.EVEN_HOUR).build());
+
+        BatteryLevelData result =
+                BatteryLevelData.combine(null, batteryLevelRecordEvents);
+
+        assertThat(result.getHourlyBatteryLevelsPerDay())
+                .hasSize(1);
+        assertThat(result.getHourlyBatteryLevelsPerDay().get(0).getTimestamps())
+                .isEqualTo(List.of(1691586000166L, 1691589600000L));
+        assertThat(result.getHourlyBatteryLevelsPerDay().get(0).getLevels())
+                .isEqualTo(List.of(100, 98));
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryTipsCardPreferenceTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryTipsCardPreferenceTest.java
index ed2b315..737717e 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryTipsCardPreferenceTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryTipsCardPreferenceTest.java
@@ -32,8 +32,8 @@
 import com.android.settings.R;
 import com.android.settings.SettingsActivity;
 import com.android.settings.display.AutoBrightnessSettings;
-import com.android.settings.fuelgauge.PowerUsageFeatureProvider;
 import com.android.settings.testutils.BatteryTestUtils;
+import com.android.settings.testutils.FakeFeatureFactory;
 import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
 
 import org.junit.Before;
@@ -49,21 +49,21 @@
 public final class BatteryTipsCardPreferenceTest {
 
     private Context mContext;
+    private FakeFeatureFactory mFeatureFactory;
     private BatteryTipsCardPreference mBatteryTipsCardPreference;
     private BatteryTipsController mBatteryTipsController;
+
     @Mock
     private View mFakeView;
-    @Mock
-    private PowerUsageFeatureProvider mPowerUsageFeatureProvider;
 
     @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
         mContext = spy(RuntimeEnvironment.application);
+        mFeatureFactory = FakeFeatureFactory.setupForTest();
         mBatteryTipsCardPreference = new BatteryTipsCardPreference(mContext, /*attrs=*/ null);
         mBatteryTipsController = new BatteryTipsController(mContext);
         mBatteryTipsController.mCardPreference = mBatteryTipsCardPreference;
-        mBatteryTipsController.mPowerUsageFeatureProvider = mPowerUsageFeatureProvider;
     }
 
     @Test
@@ -72,11 +72,11 @@
                 R.layout.battery_tips_card);
     }
     @Test
-    public void onClick_actionBtn_getAdaptiveBrightnessLauncher() {
+    public void onClick_mainBtn_getAdaptiveBrightnessLauncher() {
         final ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class);
         PowerAnomalyEvent adaptiveBrightnessAnomaly =
                 BatteryTestUtils.createAdaptiveBrightnessAnomalyEvent();
-        when(mPowerUsageFeatureProvider.isBatteryTipsEnabled()).thenReturn(true);
+        when(mFeatureFactory.powerUsageFeatureProvider.isBatteryTipsEnabled()).thenReturn(true);
         when(mFakeView.getId()).thenReturn(R.id.main_button);
         doNothing().when(mContext).startActivity(captor.capture());
 
@@ -89,5 +89,21 @@
                 .isEqualTo(AutoBrightnessSettings.class.getName());
         assertThat(intent.getIntExtra(MetricsFeatureProvider.EXTRA_SOURCE_METRICS_CATEGORY, -1))
                 .isEqualTo(SettingsEnums.SETTINGS_AUTO_BRIGHTNESS);
+        verify(mFeatureFactory.metricsFeatureProvider).action(
+                mContext, SettingsEnums.ACTION_BATTERY_TIPS_CARD_ACCEPT, "BrightnessAnomaly");
+    }
+
+    @Test
+    public void onClick_dismissBtn_metricsLogged() {
+        PowerAnomalyEvent screenTimeoutAnomaly =
+                BatteryTestUtils.createScreenTimeoutAnomalyEvent();
+        when(mFeatureFactory.powerUsageFeatureProvider.isBatteryTipsEnabled()).thenReturn(true);
+        when(mFakeView.getId()).thenReturn(R.id.dismiss_button);
+
+        mBatteryTipsController.handleBatteryTipsCardUpdated(screenTimeoutAnomaly);
+        mBatteryTipsCardPreference.onClick(mFakeView);
+
+        verify(mFeatureFactory.metricsFeatureProvider).action(
+                mContext, SettingsEnums.ACTION_BATTERY_TIPS_CARD_DISMISS, "ScreenTimeoutAnomaly");
     }
 }
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryTipsControllerTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryTipsControllerTest.java
index 0c9a0b0..015a295 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryTipsControllerTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryTipsControllerTest.java
@@ -16,19 +16,18 @@
 
 package com.android.settings.fuelgauge.batteryusage;
 
-import static com.google.common.truth.Truth.assertThat;
-
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
+import android.app.settings.SettingsEnums;
 import android.content.Context;
 import android.content.res.Resources;
 import android.os.LocaleList;
 
-import com.android.settings.fuelgauge.PowerUsageFeatureProvider;
 import com.android.settings.testutils.BatteryTestUtils;
+import com.android.settings.testutils.FakeFeatureFactory;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -45,14 +44,12 @@
 public final class BatteryTipsControllerTest {
 
     private Context mContext;
+    private FakeFeatureFactory mFeatureFactory;
     private BatteryTipsController mBatteryTipsController;
 
     @Mock
     private BatteryTipsCardPreference mBatteryTipsCardPreference;
 
-    @Mock
-    private PowerUsageFeatureProvider mPowerUsageFeatureProvider;
-
     @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
@@ -63,24 +60,9 @@
         final Resources resources = spy(mContext.getResources());
         resources.getConfiguration().setLocales(new LocaleList(new Locale("en_US")));
         doReturn(resources).when(mContext).getResources();
+        mFeatureFactory = FakeFeatureFactory.setupForTest();
         mBatteryTipsController = new BatteryTipsController(mContext);
         mBatteryTipsController.mCardPreference = mBatteryTipsCardPreference;
-        mBatteryTipsController.mPowerUsageFeatureProvider = mPowerUsageFeatureProvider;
-    }
-
-    @Test
-    public void parsePowerAnomalyKey_preDefinedKeys_returnTrue() {
-        final String[] keys = {"adaptive_brightness", "screen_timeout"};
-        for (int index = 0; index < keys.length; index++) {
-            assertThat(mBatteryTipsController.getPowerAnomalyEventIndex(keys[index]))
-                    .isEqualTo(index);
-        }
-    }
-
-    @Test
-    public void parsePowerAnomalyKey_unknownKey_returnTrue() {
-        final String key = "unknown_key_for_test";
-        assertThat(mBatteryTipsController.getPowerAnomalyEventIndex(key)).isEqualTo(-1);
     }
 
     @Test
@@ -93,10 +75,11 @@
     @Test
     public void handleBatteryTipsCardUpdated_adaptiveBrightnessAnomaly_showAnomaly() {
         PowerAnomalyEvent event = BatteryTestUtils.createAdaptiveBrightnessAnomalyEvent();
-        when(mPowerUsageFeatureProvider.isBatteryTipsEnabled()).thenReturn(true);
+        when(mFeatureFactory.powerUsageFeatureProvider.isBatteryTipsEnabled()).thenReturn(true);
 
         mBatteryTipsController.handleBatteryTipsCardUpdated(event);
 
+        verify(mBatteryTipsCardPreference).setAnomalyEventId("BrightnessAnomaly");
         // Check pre-defined string
         verify(mBatteryTipsCardPreference).setTitle(
                 "Turn on adaptive brightness to extend battery life");
@@ -107,15 +90,18 @@
                 "com.android.settings.display.AutoBrightnessSettings",
                 1381);
         verify(mBatteryTipsCardPreference).setVisible(true);
+        verify(mFeatureFactory.metricsFeatureProvider).action(
+                mContext, SettingsEnums.ACTION_BATTERY_TIPS_CARD_SHOW, "BrightnessAnomaly");
     }
 
     @Test
     public void handleBatteryTipsCardUpdated_screenTimeoutAnomaly_showAnomaly() {
         PowerAnomalyEvent event = BatteryTestUtils.createScreenTimeoutAnomalyEvent();
-        when(mPowerUsageFeatureProvider.isBatteryTipsEnabled()).thenReturn(true);
+        when(mFeatureFactory.powerUsageFeatureProvider.isBatteryTipsEnabled()).thenReturn(true);
 
         mBatteryTipsController.handleBatteryTipsCardUpdated(event);
 
+        verify(mBatteryTipsCardPreference).setAnomalyEventId("ScreenTimeoutAnomaly");
         verify(mBatteryTipsCardPreference).setTitle("Reduce screen timeout to extend battery life");
         verify(mBatteryTipsCardPreference).setMainButtonLabel("View Settings");
         verify(mBatteryTipsCardPreference).setDismissButtonLabel("Got it");
@@ -123,6 +109,8 @@
                 "com.android.settings.display.ScreenTimeoutSettings",
                 1852);
         verify(mBatteryTipsCardPreference).setVisible(true);
+        verify(mFeatureFactory.metricsFeatureProvider).action(
+                mContext, SettingsEnums.ACTION_BATTERY_TIPS_CARD_SHOW, "ScreenTimeoutAnomaly");
     }
     @Test
     public void handleBatteryTipsCardUpdated_screenTimeoutAnomalyHasTitle_showAnomaly() {
@@ -134,10 +122,11 @@
                                 .setTitleString(testTitle)
                                 .build())
                 .build();
-        when(mPowerUsageFeatureProvider.isBatteryTipsEnabled()).thenReturn(true);
+        when(mFeatureFactory.powerUsageFeatureProvider.isBatteryTipsEnabled()).thenReturn(true);
 
         mBatteryTipsController.handleBatteryTipsCardUpdated(event);
 
+        verify(mBatteryTipsCardPreference).setAnomalyEventId("ScreenTimeoutAnomaly");
         verify(mBatteryTipsCardPreference).setTitle(testTitle);
         verify(mBatteryTipsCardPreference).setMainButtonLabel("View Settings");
         verify(mBatteryTipsCardPreference).setDismissButtonLabel("Got it");
@@ -145,5 +134,7 @@
                 "com.android.settings.display.ScreenTimeoutSettings",
                 1852);
         verify(mBatteryTipsCardPreference).setVisible(true);
+        verify(mFeatureFactory.metricsFeatureProvider).action(
+                mContext, SettingsEnums.ACTION_BATTERY_TIPS_CARD_SHOW, "ScreenTimeoutAnomaly");
     }
 }
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBreakdownControllerTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBreakdownControllerTest.java
index 3a9ce2b..d89c06b 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBreakdownControllerTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBreakdownControllerTest.java
@@ -96,6 +96,14 @@
         mBatteryUsageBreakdownController.mAppListPreferenceGroup = mAppListPreferenceGroup;
         mBatteryDiffEntry = new BatteryDiffEntry(
                 mContext,
+                /*uid=*/ 0L,
+                /*userId=*/ 0L,
+                /*key=*/ "key",
+                /*isHidden=*/ false,
+                /*componentId=*/ -1,
+                /*legacyPackageName=*/ null,
+                /*legacyLabel=*/ null,
+                /*consumerType=*/ ConvertUtils.CONSUMER_TYPE_UID_BATTERY,
                 /*foregroundUsageTimeInMs=*/ 1,
                 /*backgroundUsageTimeInMs=*/ 2,
                 /*screenOnTimeInMs=*/ 0,
@@ -103,13 +111,14 @@
                 /*foregroundUsageConsumePower=*/ 0,
                 /*foregroundServiceUsageConsumePower=*/ 1,
                 /*backgroundUsageConsumePower=*/ 2,
-                /*cachedUsageConsumePower=*/ 0,
-                mBatteryHistEntry);
+                /*cachedUsageConsumePower=*/ 0);
         mBatteryDiffEntry = spy(mBatteryDiffEntry);
         mBatteryUsageBreakdownController.mBatteryDiffData =
-                new BatteryDiffData(mContext, /* screenOnTime= */ 0L,
-                        Arrays.asList(mBatteryDiffEntry), Arrays.asList(), Set.of(), Set.of(),
-                        /* isAccumulated= */ false);
+                new BatteryDiffData(mContext, /* startTimestamp= */ 0L, /* endTimestamp= */ 0L,
+                        /* startBatteryLevel= */ 0, /* endBatteryLevel= */ 0,
+                        /* screenOnTime= */ 0L, Arrays.asList(mBatteryDiffEntry), Arrays.asList(),
+                        Set.of(), Set.of(), /* isAccumulated= */ false);
+        BatteryDiffEntry.clearCache();
         // Adds fake testing data.
         BatteryDiffEntry.sResourceCache.put(
                 "fakeBatteryDiffEntryKey",
@@ -140,7 +149,7 @@
         doReturn(1).when(mAppListPreferenceGroup).getPreferenceCount();
         doReturn(mDrawable).when(mBatteryDiffEntry).getAppIcon();
         doReturn(appLabel).when(mBatteryDiffEntry).getAppLabel();
-        doReturn(PREF_KEY).when(mBatteryHistEntry).getKey();
+        doReturn(PREF_KEY).when(mBatteryDiffEntry).getKey();
         doReturn(null).when(mAppListPreferenceGroup).findPreference(PREF_KEY);
         doReturn(false).when(mBatteryDiffEntry).validForRestriction();
 
@@ -168,7 +177,7 @@
         doReturn(1).when(mAppListPreferenceGroup).getPreferenceCount();
         doReturn(mDrawable).when(mBatteryDiffEntry).getAppIcon();
         doReturn(appLabel).when(mBatteryDiffEntry).getAppLabel();
-        doReturn(PREF_KEY).when(mBatteryHistEntry).getKey();
+        doReturn(PREF_KEY).when(mBatteryDiffEntry).getKey();
         doReturn(mPowerGaugePreference).when(mAppListPreferenceGroup).findPreference(PREF_KEY);
 
         mBatteryUsageBreakdownController.addAllPreferences();
@@ -197,7 +206,7 @@
     public void removeAndCacheAllUnusedPreferences_keepPref_KeepAllPreference() {
         doReturn(1).when(mAppListPreferenceGroup).getPreferenceCount();
         doReturn(mPowerGaugePreference).when(mAppListPreferenceGroup).getPreference(0);
-        doReturn(PREF_KEY).when(mBatteryHistEntry).getKey();
+        doReturn(PREF_KEY).when(mBatteryDiffEntry).getKey();
         doReturn(PREF_KEY).when(mPowerGaugePreference).getKey();
         doReturn(mPowerGaugePreference).when(mAppListPreferenceGroup).findPreference(PREF_KEY);
         // Ensures the testing data is correct.
@@ -222,7 +231,7 @@
 
     @Test
     public void handlePreferenceTreeClick_forAppEntry_returnTrue() {
-        doReturn(false).when(mBatteryHistEntry).isAppEntry();
+        mBatteryDiffEntry.mConsumerType = ConvertUtils.CONSUMER_TYPE_SYSTEM_BATTERY;
         doReturn(mBatteryDiffEntry).when(mPowerGaugePreference).getBatteryDiffEntry();
 
         assertThat(mBatteryUsageBreakdownController.handlePreferenceTreeClick(
@@ -238,7 +247,7 @@
 
     @Test
     public void handlePreferenceTreeClick_forSystemEntry_returnTrue() {
-        doReturn(true).when(mBatteryHistEntry).isAppEntry();
+        mBatteryDiffEntry.mConsumerType = ConvertUtils.CONSUMER_TYPE_UID_BATTERY;
         doReturn(mBatteryDiffEntry).when(mPowerGaugePreference).getBatteryDiffEntry();
 
         assertThat(mBatteryUsageBreakdownController.handlePreferenceTreeClick(
@@ -394,10 +403,23 @@
         contentValues.put(BatteryHistEntry.KEY_USER_ID, Integer.valueOf(1001));
         final BatteryHistEntry batteryHistEntry = new BatteryHistEntry(contentValues);
         return new BatteryDiffEntry(
-                mContext, foregroundUsageTimeInMs, backgroundUsageTimeInMs, screenOnTimeInMs,
-                /*consumePower=*/ 0, /*foregroundUsageConsumePower=*/ 0,
-                /*foregroundServiceUsageConsumePower=*/ 0, /*backgroundUsageConsumePower=*/ 0,
-                /*cachedUsageConsumePower=*/ 0, batteryHistEntry);
+                mContext,
+                batteryHistEntry.mUid,
+                batteryHistEntry.mUserId,
+                batteryHistEntry.getKey(),
+                batteryHistEntry.mIsHidden,
+                batteryHistEntry.mDrainType,
+                batteryHistEntry.mPackageName,
+                batteryHistEntry.mAppLabel,
+                batteryHistEntry.mConsumerType,
+                foregroundUsageTimeInMs,
+                backgroundUsageTimeInMs,
+                screenOnTimeInMs,
+                /*consumePower=*/ 0,
+                /*foregroundUsageConsumePower=*/ 0,
+                /*foregroundServiceUsageConsumePower=*/ 0,
+                /*backgroundUsageConsumePower=*/ 0,
+                /*cachedUsageConsumePower=*/ 0);
     }
 
     private BatteryUsageBreakdownController createController() {
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 05a6f2b..999a921 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageContentProviderTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageContentProviderTest.java
@@ -20,11 +20,9 @@
 
 import static org.junit.Assert.assertThrows;
 
-import android.app.Application;
 import android.content.ContentResolver;
 import android.content.ContentValues;
 import android.content.Context;
-import android.content.Intent;
 import android.database.Cursor;
 import android.net.Uri;
 
@@ -34,6 +32,7 @@
 import com.android.settings.fuelgauge.batteryusage.db.BatteryEventEntity;
 import com.android.settings.fuelgauge.batteryusage.db.BatteryState;
 import com.android.settings.fuelgauge.batteryusage.db.BatteryStateDatabase;
+import com.android.settings.fuelgauge.batteryusage.db.BatteryUsageSlotEntity;
 import com.android.settings.testutils.BatteryTestUtils;
 import com.android.settings.testutils.FakeClock;
 
@@ -41,12 +40,10 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.robolectric.RobolectricTestRunner;
-import org.robolectric.Shadows;
 
 import java.time.Duration;
 import java.util.ArrayList;
 import java.util.List;
-import java.util.concurrent.TimeUnit;
 import java.util.stream.Collectors;
 
 /** Tests for {@link BatteryUsageContentProvider}. */
@@ -127,10 +124,28 @@
     }
 
     @Test
+    public void query_getLastFullChargeTimestamp_returnsExpectedResult() throws Exception {
+        mProvider.onCreate();
+        ContentValues values = new ContentValues();
+        values.put(BatteryEventEntity.KEY_TIMESTAMP, 10001L);
+        values.put(BatteryEventEntity.KEY_BATTERY_EVENT_TYPE,
+                BatteryEventType.FULL_CHARGED.getNumber());
+        values.put(BatteryEventEntity.KEY_BATTERY_LEVEL, 100);
+        mProvider.insert(DatabaseUtils.BATTERY_EVENT_URI, values);
+
+        final Cursor cursor = getCursorOfLastFullChargeTimestamp();
+
+        assertThat(cursor.getCount()).isEqualTo(1);
+        cursor.moveToFirst();
+        final long lastFullChargeTimestamp = cursor.getLong(0);
+        assertThat(lastFullChargeTimestamp).isEqualTo(10001L);
+    }
+
+    @Test
     public void query_batteryState_returnsExpectedResult() throws Exception {
         mProvider.onCreate();
         final Duration currentTime = Duration.ofHours(52);
-        final long expiredTimeCutoff = currentTime.toMillis() - 3;
+        final long expiredTimeCutoff = currentTime.toMillis() - 8;
 
         final Cursor cursor = insertBatteryState(currentTime, Long.toString(expiredTimeCutoff));
 
@@ -150,19 +165,13 @@
         final String actualPackageName3 = cursor.getString(packageNameIndex);
         assertThat(actualPackageName3).isEqualTo(PACKAGE_NAME3);
         cursor.close();
-        // Verifies the broadcast intent.
-        TimeUnit.SECONDS.sleep(1);
-        final List<Intent> intents = Shadows.shadowOf((Application) mContext).getBroadcastIntents();
-        assertThat(intents).hasSize(1);
-        assertThat(intents.get(0).getAction()).isEqualTo(
-                BootBroadcastReceiver.ACTION_PERIODIC_JOB_RECHECK);
     }
 
     @Test
     public void query_batteryStateTimestamp_returnsExpectedResult() throws Exception {
         mProvider.onCreate();
         final Duration currentTime = Duration.ofHours(52);
-        final long expiredTimeCutoff = currentTime.toMillis() - 1;
+        final long expiredTimeCutoff = currentTime.toMillis() - 2;
 
         final Cursor cursor = insertBatteryState(currentTime, Long.toString(expiredTimeCutoff));
 
@@ -178,12 +187,25 @@
         final String actualPackageName2 = cursor.getString(packageNameIndex);
         assertThat(actualPackageName2).isEqualTo(PACKAGE_NAME3);
         cursor.close();
-        // Verifies the broadcast intent.
-        TimeUnit.SECONDS.sleep(1);
-        final List<Intent> intents = Shadows.shadowOf((Application) mContext).getBroadcastIntents();
-        assertThat(intents).hasSize(1);
-        assertThat(intents.get(0).getAction()).isEqualTo(
-                BootBroadcastReceiver.ACTION_PERIODIC_JOB_RECHECK);
+    }
+
+    @Test
+    public void query_getBatteryStateLatestTimestamp_returnsExpectedResult() throws Exception {
+        mProvider.onCreate();
+        final Duration currentTime = Duration.ofHours(52);
+        insertBatteryState(currentTime, Long.toString(currentTime.toMillis()));
+
+        final Cursor cursor1 = getCursorOfBatteryStateLatestTimestamp(currentTime.toMillis() - 5);
+        assertThat(cursor1.getCount()).isEqualTo(1);
+        cursor1.moveToFirst();
+        final long latestTimestamp1 = cursor1.getLong(0);
+        assertThat(latestTimestamp1).isEqualTo(currentTime.toMillis() - 6);
+
+        final Cursor cursor2 = getCursorOfBatteryStateLatestTimestamp(currentTime.toMillis() - 2);
+        assertThat(cursor2.getCount()).isEqualTo(1);
+        cursor2.moveToFirst();
+        final long latestTimestamp2 = cursor2.getLong(0);
+        assertThat(latestTimestamp2).isEqualTo(currentTime.toMillis() - 2);
     }
 
     @Test
@@ -355,7 +377,7 @@
     }
 
     @Test
-    public void insert_batteryEvent_returnsExpectedResult() {
+    public void insertAndQuery_batteryEvent_returnsExpectedResult() {
         mProvider.onCreate();
         ContentValues values = new ContentValues();
         values.put(BatteryEventEntity.KEY_TIMESTAMP, 10001L);
@@ -366,7 +388,7 @@
         final Uri uri = mProvider.insert(DatabaseUtils.BATTERY_EVENT_URI, values);
 
         assertThat(uri).isEqualTo(DatabaseUtils.BATTERY_EVENT_URI);
-        // Verifies the AppUsageEventEntity content.
+        // Verifies the BatteryEventEntity content.
         final List<BatteryEventEntity> entities =
                 BatteryStateDatabase.getInstance(mContext).batteryEventDao().getAll();
         assertThat(entities).hasSize(1);
@@ -374,6 +396,50 @@
         assertThat(entities.get(0).batteryEventType).isEqualTo(
                 BatteryEventType.POWER_CONNECTED.getNumber());
         assertThat(entities.get(0).batteryLevel).isEqualTo(66);
+
+        final Cursor cursor1 = getCursorOfBatteryEvents(
+                0L, List.of(BatteryEventType.POWER_CONNECTED.getNumber()));
+        assertThat(cursor1.getCount()).isEqualTo(1);
+        cursor1.moveToFirst();
+        assertThat(cursor1.getLong(cursor1.getColumnIndex(BatteryEventEntity.KEY_TIMESTAMP)))
+                .isEqualTo(10001L);
+        assertThat(
+                cursor1.getInt(cursor1.getColumnIndex(BatteryEventEntity.KEY_BATTERY_EVENT_TYPE)))
+                .isEqualTo(BatteryEventType.POWER_CONNECTED.getNumber());
+        assertThat(cursor1.getInt(cursor1.getColumnIndex(BatteryEventEntity.KEY_BATTERY_LEVEL)))
+                .isEqualTo(66);
+
+        final Cursor cursor2 = getCursorOfBatteryEvents(
+                0L, List.of(BatteryEventType.POWER_DISCONNECTED.getNumber()));
+        assertThat(cursor2.getCount()).isEqualTo(0);
+    }
+
+    @Test
+    public void insertAndQuery_batteryUsageSlot_returnsExpectedResult() {
+        mProvider.onCreate();
+        ContentValues values = new ContentValues();
+        values.put(BatteryUsageSlotEntity.KEY_TIMESTAMP, 10001L);
+        values.put(BatteryUsageSlotEntity.KEY_BATTERY_USAGE_SLOT, "TEST_STRING");
+
+        final Uri uri = mProvider.insert(DatabaseUtils.BATTERY_USAGE_SLOT_URI, values);
+        // Verifies the BatteryUsageSlotEntity content.
+        assertThat(uri).isEqualTo(DatabaseUtils.BATTERY_USAGE_SLOT_URI);
+        final List<BatteryUsageSlotEntity> entities =
+                BatteryStateDatabase.getInstance(mContext).batteryUsageSlotDao().getAll();
+        assertThat(entities).hasSize(1);
+        assertThat(entities.get(0).timestamp).isEqualTo(10001L);
+        assertThat(entities.get(0).batteryUsageSlot).isEqualTo("TEST_STRING");
+
+        final Cursor cursor1 = getCursorOfBatteryUsageSlots(10001L);
+        assertThat(cursor1.getCount()).isEqualTo(1);
+        cursor1.moveToFirst();
+        assertThat(cursor1.getLong(cursor1.getColumnIndex(BatteryUsageSlotEntity.KEY_TIMESTAMP)))
+                .isEqualTo(10001L);
+        assertThat(cursor1.getString(cursor1.getColumnIndex(
+                BatteryUsageSlotEntity.KEY_BATTERY_USAGE_SLOT))).isEqualTo("TEST_STRING");
+
+        final Cursor cursor2 = getCursorOfBatteryUsageSlots(10002L);
+        assertThat(cursor2.getCount()).isEqualTo(0);
     }
 
     @Test
@@ -404,10 +470,10 @@
         final long currentTimestamp = currentTime.toMillis();
         // Inserts some valid testing data.
         BatteryTestUtils.insertDataToBatteryStateTable(
-                mContext, currentTimestamp - 2, PACKAGE_NAME1,
+                mContext, currentTimestamp - 6, PACKAGE_NAME1,
                 /*isFullChargeStart=*/ true);
         BatteryTestUtils.insertDataToBatteryStateTable(
-                mContext, currentTimestamp - 1, PACKAGE_NAME2);
+                mContext, currentTimestamp - 2, PACKAGE_NAME2);
         BatteryTestUtils.insertDataToBatteryStateTable(
                 mContext, currentTimestamp, PACKAGE_NAME3);
 
@@ -420,17 +486,35 @@
                                 DatabaseUtils.QUERY_KEY_TIMESTAMP, queryTimestamp)
                         .build();
 
-        final Cursor cursor =
-                mProvider.query(
-                        batteryStateQueryContentUri,
-                        /*strings=*/ null,
-                        /*s=*/ null,
-                        /*strings1=*/ null,
-                        /*s1=*/ null);
+        final Cursor cursor = query(batteryStateQueryContentUri);
 
         return cursor;
     }
 
+    private Cursor getCursorOfLastFullChargeTimestamp() {
+        final Uri lastFullChargeTimestampContentUri =
+                new Uri.Builder()
+                        .scheme(ContentResolver.SCHEME_CONTENT)
+                        .authority(DatabaseUtils.AUTHORITY)
+                        .appendPath(DatabaseUtils.LAST_FULL_CHARGE_TIMESTAMP_PATH)
+                        .build();
+
+        return query(lastFullChargeTimestampContentUri);
+    }
+
+    private Cursor getCursorOfBatteryStateLatestTimestamp(final long queryTimestamp) {
+        final Uri batteryStateLatestTimestampUri =
+                new Uri.Builder()
+                        .scheme(ContentResolver.SCHEME_CONTENT)
+                        .authority(DatabaseUtils.AUTHORITY)
+                        .appendPath(DatabaseUtils.BATTERY_STATE_LATEST_TIMESTAMP_PATH)
+                        .appendQueryParameter(
+                                DatabaseUtils.QUERY_KEY_TIMESTAMP, Long.toString(queryTimestamp))
+                        .build();
+
+        return query(batteryStateLatestTimestampUri);
+    }
+
     private void insertAppUsageEvent() {
         mProvider.onCreate();
         // Inserts some valid testing data.
@@ -452,12 +536,7 @@
                                 DatabaseUtils.QUERY_KEY_USERID, Long.toString(userId))
                         .build();
 
-        return mProvider.query(
-                appUsageLatestTimestampQueryContentUri,
-                /*strings=*/ null,
-                /*s=*/ null,
-                /*strings1=*/ null,
-                /*s1=*/ null);
+        return query(appUsageLatestTimestampQueryContentUri);
     }
 
     private Cursor getCursorOfAppUsage(final List<Long> userIds, final long queryTimestamp) {
@@ -474,7 +553,43 @@
                         .appendQueryParameter(DatabaseUtils.QUERY_KEY_USERID, queryUserIdString)
                         .build();
 
+        return query(appUsageEventUri);
+    }
+
+    private Cursor getCursorOfBatteryEvents(
+            final long queryTimestamp, final List<Integer> batteryEventTypes) {
+        final String batteryEventTypesString = batteryEventTypes.stream()
+                .map(type -> String.valueOf(type))
+                .collect(Collectors.joining(","));
+        final Uri batteryEventUri =
+                new Uri.Builder()
+                        .scheme(ContentResolver.SCHEME_CONTENT)
+                        .authority(DatabaseUtils.AUTHORITY)
+                        .appendPath(DatabaseUtils.BATTERY_EVENT_TABLE)
+                        .appendQueryParameter(
+                                DatabaseUtils.QUERY_KEY_TIMESTAMP, Long.toString(queryTimestamp))
+                        .appendQueryParameter(
+                                DatabaseUtils.QUERY_BATTERY_EVENT_TYPE, batteryEventTypesString)
+                        .build();
+
+        return query(batteryEventUri);
+    }
+
+    private Cursor getCursorOfBatteryUsageSlots(final long queryTimestamp) {
+        final Uri batteryUsageSlotUri =
+                new Uri.Builder()
+                        .scheme(ContentResolver.SCHEME_CONTENT)
+                        .authority(DatabaseUtils.AUTHORITY)
+                        .appendPath(DatabaseUtils.BATTERY_USAGE_SLOT_TABLE)
+                        .appendQueryParameter(
+                                DatabaseUtils.QUERY_KEY_TIMESTAMP, Long.toString(queryTimestamp))
+                        .build();
+
+        return query(batteryUsageSlotUri);
+    }
+
+    private Cursor query(Uri uri) {
         return mProvider.query(
-                appUsageEventUri, /*strings=*/ null, /*s=*/ null, /*strings1=*/ null, /*s1=*/ null);
+                uri, /*strings=*/ null, /*s=*/ null, /*strings1=*/ null, /*s1=*/ null);
     }
 }
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageDataLoaderTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageDataLoaderTest.java
index 9aeff79..f3965fd 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageDataLoaderTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageDataLoaderTest.java
@@ -22,6 +22,7 @@
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
 import static org.mockito.Mockito.when;
 
 import android.content.ContentResolver;
@@ -31,6 +32,7 @@
 import android.os.BatteryStatsManager;
 import android.os.BatteryUsageStats;
 import android.os.BatteryUsageStatsQuery;
+import android.os.UserManager;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -43,6 +45,7 @@
 import org.robolectric.RuntimeEnvironment;
 
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.List;
 
 @RunWith(RobolectricTestRunner.class)
@@ -56,6 +59,8 @@
     @Mock
     private PackageManager mPackageManager;
     @Mock
+    private UserManager mUserManager;
+    @Mock
     private BatteryUsageStats mBatteryUsageStats;
     @Mock
     private BatteryEntry mMockBatteryEntry;
@@ -70,6 +75,7 @@
         doReturn(mBatteryStatsManager).when(mContext).getSystemService(
                 Context.BATTERY_STATS_SERVICE);
         doReturn(mPackageManager).when(mContext).getPackageManager();
+        doReturn(mUserManager).when(mContext).getSystemService(UserManager.class);
         doReturn(mMockContentResolver).when(mContext).getContentResolver();
         doReturn(new Intent()).when(mContext).registerReceiver(any(), any());
     }
@@ -82,7 +88,7 @@
                 .thenReturn(mBatteryUsageStats);
         BatteryUsageDataLoader.sFakeBatteryEntryListSupplier = () -> batteryEntryList;
 
-        BatteryUsageDataLoader.loadUsageData(mContext, /*isFullChargeStart=*/ false);
+        BatteryUsageDataLoader.loadBatteryStatsData(mContext, /*isFullChargeStart=*/ false);
 
         final int queryFlags = mStatsQueryCaptor.getValue().getFlags();
         assertThat(queryFlags
@@ -97,7 +103,7 @@
                 .thenReturn(mBatteryUsageStats);
         BatteryUsageDataLoader.sFakeBatteryEntryListSupplier = () -> null;
 
-        BatteryUsageDataLoader.loadUsageData(mContext, /*isFullChargeStart=*/ false);
+        BatteryUsageDataLoader.loadBatteryStatsData(mContext, /*isFullChargeStart=*/ false);
 
         verify(mMockContentResolver).insert(any(), any());
     }
@@ -108,8 +114,51 @@
                 .thenReturn(mBatteryUsageStats);
         BatteryUsageDataLoader.sFakeBatteryEntryListSupplier = () -> new ArrayList<>();
 
-        BatteryUsageDataLoader.loadUsageData(mContext, /*isFullChargeStart=*/ false);
+        BatteryUsageDataLoader.loadBatteryStatsData(mContext, /*isFullChargeStart=*/ false);
 
         verify(mMockContentResolver).insert(any(), any());
     }
+
+    @Test
+    public void loadAppUsageData_withData_insertFakeDataIntoProvider() {
+        final List<AppUsageEvent> AppUsageEventList = new ArrayList<>();
+        final AppUsageEvent appUsageEvent = AppUsageEvent.newBuilder().setUid(0).build();
+        AppUsageEventList.add(appUsageEvent);
+        BatteryUsageDataLoader.sFakeAppUsageEventsSupplier = () -> new HashMap<>();
+        BatteryUsageDataLoader.sFakeUsageEventsListSupplier = () -> AppUsageEventList;
+
+        BatteryUsageDataLoader.loadAppUsageData(mContext);
+
+        verify(mMockContentResolver).bulkInsert(any(), any());
+        verify(mMockContentResolver).notifyChange(any(), any());
+    }
+
+    @Test
+    public void loadAppUsageData_nullAppUsageEvents_notInsertDataIntoProvider() {
+        BatteryUsageDataLoader.sFakeAppUsageEventsSupplier = () -> null;
+
+        BatteryUsageDataLoader.loadAppUsageData(mContext);
+
+        verifyNoMoreInteractions(mMockContentResolver);
+    }
+
+    @Test
+    public void loadAppUsageData_nullUsageEventsList_notInsertDataIntoProvider() {
+        BatteryUsageDataLoader.sFakeAppUsageEventsSupplier = () -> new HashMap<>();
+        BatteryUsageDataLoader.sFakeUsageEventsListSupplier = () -> null;
+
+        BatteryUsageDataLoader.loadAppUsageData(mContext);
+
+        verifyNoMoreInteractions(mMockContentResolver);
+    }
+
+    @Test
+    public void loadAppUsageData_emptyUsageEventsList_notInsertDataIntoProvider() {
+        BatteryUsageDataLoader.sFakeAppUsageEventsSupplier = () -> new HashMap<>();
+        BatteryUsageDataLoader.sFakeUsageEventsListSupplier = () -> new ArrayList<>();
+
+        BatteryUsageDataLoader.loadAppUsageData(mContext);
+
+        verifyNoMoreInteractions(mMockContentResolver);
+    }
 }
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 e9108bc..f06dc63 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/ConvertUtilsTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/ConvertUtilsTest.java
@@ -39,6 +39,7 @@
 
 import com.android.settings.fuelgauge.batteryusage.db.AppUsageEventEntity;
 import com.android.settings.fuelgauge.batteryusage.db.BatteryEventEntity;
+import com.android.settings.fuelgauge.batteryusage.db.BatteryUsageSlotEntity;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -48,7 +49,10 @@
 import org.robolectric.RobolectricTestRunner;
 import org.robolectric.RuntimeEnvironment;
 
+import java.util.List;
 import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
 import java.util.TimeZone;
 
 @RunWith(RobolectricTestRunner.class)
@@ -213,6 +217,22 @@
     }
 
     @Test
+    public void convertBatteryUsageSlotToContentValues_normalCase_returnsExpectedContentValues() {
+        final BatteryUsageSlot batteryUsageSlot =
+                BatteryUsageSlot.newBuilder()
+                        .setStartTimestamp(10001L)
+                        .setEndTimestamp(30003L)
+                        .setStartBatteryLevel(88)
+                        .setEndBatteryLevel(66)
+                        .setScreenOnTime(123L)
+                        .build();
+        final ContentValues values =
+                ConvertUtils.convertBatteryUsageSlotToContentValues(batteryUsageSlot);
+        assertThat(values.getAsLong(BatteryUsageSlotEntity.KEY_TIMESTAMP)).isEqualTo(10001L);
+        assertThat(BatteryUsageSlotEntity.KEY_BATTERY_USAGE_SLOT).isNotEmpty();
+    }
+
+    @Test
     public void convertToBatteryHistEntry_returnsExpectedResult() {
         final int expectedType = 3;
         when(mMockBatteryEntry.getUid()).thenReturn(1001);
@@ -363,7 +383,7 @@
     }
 
     @Test
-    public void convertToAppUsageEventFromCursor_returnExpectedResult() {
+    public void convertToAppUsageEvent_returnExpectedResult() {
         final MatrixCursor cursor = new MatrixCursor(
                 new String[]{
                         AppUsageEventEntity.KEY_UID,
@@ -384,7 +404,7 @@
                         100001L});
         cursor.moveToFirst();
 
-        final AppUsageEvent appUsageEvent = ConvertUtils.convertToAppUsageEventFromCursor(cursor);
+        final AppUsageEvent appUsageEvent = ConvertUtils.convertToAppUsageEvent(cursor);
 
         assertThat(appUsageEvent.getUid()).isEqualTo(101L);
         assertThat(appUsageEvent.getUserId()).isEqualTo(1001L);
@@ -396,7 +416,7 @@
     }
 
     @Test
-    public void convertToAppUsageEventFromCursor_emptyInstanceIdAndRootName_returnExpectedResult() {
+    public void convertToAppUsageEvent_emptyInstanceIdAndRootName_returnExpectedResult() {
         final MatrixCursor cursor = new MatrixCursor(
                 new String[]{
                         AppUsageEventEntity.KEY_UID,
@@ -413,7 +433,7 @@
                         AppUsageEventType.DEVICE_SHUTDOWN.getNumber()});
         cursor.moveToFirst();
 
-        final AppUsageEvent appUsageEvent = ConvertUtils.convertToAppUsageEventFromCursor(cursor);
+        final AppUsageEvent appUsageEvent = ConvertUtils.convertToAppUsageEvent(cursor);
 
         assertThat(appUsageEvent.getUid()).isEqualTo(101L);
         assertThat(appUsageEvent.getUserId()).isEqualTo(1001L);
@@ -434,6 +454,42 @@
     }
 
     @Test
+    public void convertToBatteryEventList_normalCase_returnsExpectedResult() {
+        final BatteryLevelData batteryLevelData = new BatteryLevelData(Map.of(
+                1691589600000L, 98, 1691596800000L, 90, 1691596812345L, 80));
+
+        final List<BatteryEvent> batteryEventList =
+                ConvertUtils.convertToBatteryEventList(batteryLevelData);
+
+        assertThat(batteryEventList).hasSize(2);
+        assertThat(batteryEventList.get(0).getTimestamp()).isEqualTo(1691589600000L);
+        assertThat(batteryEventList.get(0).getType()).isEqualTo(BatteryEventType.EVEN_HOUR);
+        assertThat(batteryEventList.get(0).getBatteryLevel()).isEqualTo(98);
+        assertThat(batteryEventList.get(1).getTimestamp()).isEqualTo(1691596800000L);
+        assertThat(batteryEventList.get(1).getType()).isEqualTo(BatteryEventType.EVEN_HOUR);
+        assertThat(batteryEventList.get(1).getBatteryLevel()).isEqualTo(90);
+    }
+
+    @Test
+    public void convertToBatteryUsageSlotList_normalCase_returnsExpectedResult() {
+        BatteryDiffData batteryDiffData1 = new BatteryDiffData(
+                mContext, 11L, 12L, 13, 14, 15, List.of(), List.of(), Set.of(), Set.of(), false);
+        BatteryDiffData batteryDiffData2 = new BatteryDiffData(
+                mContext, 21L, 22L, 23, 24, 25, List.of(), List.of(), Set.of(), Set.of(), false);
+        BatteryDiffData batteryDiffData3 = new BatteryDiffData(
+                mContext, 31L, 32L, 33, 34, 35, List.of(), List.of(), Set.of(), Set.of(), false);
+        final Map<Long, BatteryDiffData> batteryDiffDataMap = Map.of(
+                11L, batteryDiffData1, 21L, batteryDiffData2, 31L, batteryDiffData3);
+
+        final List<BatteryUsageSlot> batteryUsageSlotList =
+                ConvertUtils.convertToBatteryUsageSlotList(batteryDiffDataMap);
+
+        assertThat(batteryUsageSlotList).hasSize(3);
+        assertThat(batteryUsageSlotList.stream().map((s) -> s.getScreenOnTime()).sorted().toList())
+                .isEqualTo(List.of(15L, 25L, 35L));
+    }
+
+    @Test
     public void getLocale_nullContext_returnDefaultLocale() {
         assertThat(ConvertUtils.getLocale(/*context=*/ null))
                 .isEqualTo(Locale.getDefault());
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/DataProcessManagerTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/DataProcessManagerTest.java
index b610cfb..d5909b2 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/DataProcessManagerTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/DataProcessManagerTest.java
@@ -30,8 +30,12 @@
 import android.content.ContentValues;
 import android.content.Context;
 import android.content.Intent;
+import android.database.Cursor;
 import android.database.MatrixCursor;
 import android.os.BatteryManager;
+import android.os.BatteryStatsManager;
+import android.os.BatteryUsageStats;
+import android.os.BatteryUsageStatsQuery;
 import android.os.Parcel;
 import android.os.RemoteException;
 import android.os.UserManager;
@@ -39,19 +43,24 @@
 
 import com.android.settings.fuelgauge.batteryusage.db.AppUsageEventEntity;
 
+import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 import org.robolectric.RobolectricTestRunner;
 import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.LooperMode;
 
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.function.Supplier;
 
 @RunWith(RobolectricTestRunner.class)
 public final class DataProcessManagerTest {
@@ -65,7 +74,13 @@
     @Mock
     private UserManager mUserManager;
     @Mock
+    private BatteryStatsManager mBatteryStatsManager;
+    @Mock
+    private BatteryUsageStats mBatteryUsageStats;
+    @Mock
     private Intent mIntent;
+    @Captor
+    private ArgumentCaptor<BatteryUsageStatsQuery> mBatteryUsageStatsQueryCaptor;
 
     @Before
     public void setUp() {
@@ -77,25 +92,37 @@
         doReturn(mUserManager)
                 .when(mContext)
                 .getSystemService(UserManager.class);
+        doReturn(mBatteryStatsManager).when(mContext).getSystemService(
+                Context.BATTERY_STATS_SERVICE);
+        doReturn(mBatteryUsageStats).when(
+                mBatteryStatsManager).getBatteryUsageStats(mBatteryUsageStatsQueryCaptor.capture());
         doReturn(mIntent).when(mContext).registerReceiver(any(), any());
         doReturn(100).when(mIntent).getIntExtra(eq(BatteryManager.EXTRA_SCALE), anyInt());
         doReturn(66).when(mIntent).getIntExtra(eq(BatteryManager.EXTRA_LEVEL), anyInt());
 
         mDataProcessManager = new DataProcessManager(
                 mContext, /*handler=*/ null,  /*rawStartTimestamp=*/ 0L,
-                /*callbackFunction=*/ null, /*hourlyBatteryLevelsPerDay=*/ new ArrayList<>(),
+                /*lastFullChargeTimestamp=*/ 0L, /*callbackFunction=*/ null,
+                /*hourlyBatteryLevelsPerDay=*/ new ArrayList<>(),
                 /*batteryHistoryMap=*/ new HashMap<>());
     }
 
+    @After
+    public void cleanUp() {
+        DatabaseUtils.sFakeSupplier = null;
+        DataProcessManager.sFakeBatteryHistoryMap = null;
+    }
+
     @Test
+    @LooperMode(LooperMode.Mode.LEGACY)
     public void constructor_noLevelData() {
         final DataProcessManager dataProcessManager =
                 new DataProcessManager(mContext, /*handler=*/ null, /*callbackFunction=*/ null);
         assertThat(dataProcessManager.getShowScreenOnTime()).isFalse();
-        assertThat(dataProcessManager.getShowBatteryLevel()).isFalse();
     }
 
     @Test
+    @LooperMode(LooperMode.Mode.LEGACY)
     public void start_loadEmptyDatabaseAppUsageData() {
         final MatrixCursor cursor = new MatrixCursor(
                 new String[]{
@@ -116,22 +143,25 @@
     }
 
     @Test
+    @LooperMode(LooperMode.Mode.LEGACY)
     public void start_loadExpectedAppUsageData() throws RemoteException {
         final List<BatteryLevelData.PeriodBatteryLevelData> hourlyBatteryLevelsPerDay =
                 new ArrayList<>();
         final String packageName = "package";
         // Adds the day 1 data.
         final List<Long> timestamps1 = List.of(2L, 3L, 4L);
-        final List<Integer> levels1 = List.of(100, 100, 100);
+        final Map<Long, Integer> batteryLevelMap1 =
+                Map.of(timestamps1.get(0), 100, timestamps1.get(1), 100, timestamps1.get(2), 100);
         hourlyBatteryLevelsPerDay.add(
-                new BatteryLevelData.PeriodBatteryLevelData(timestamps1, levels1));
+                new BatteryLevelData.PeriodBatteryLevelData(batteryLevelMap1, timestamps1));
         // Adds the day 2 data.
         hourlyBatteryLevelsPerDay.add(null);
         // Adds the day 3 data.
         final List<Long> timestamps2 = List.of(5L, 6L);
-        final List<Integer> levels2 = List.of(100, 100);
+        final Map<Long, Integer> batteryLevelMap2 =
+                Map.of(timestamps2.get(0), 100, timestamps2.get(1), 100);
         hourlyBatteryLevelsPerDay.add(
-                new BatteryLevelData.PeriodBatteryLevelData(timestamps2, levels2));
+                new BatteryLevelData.PeriodBatteryLevelData(batteryLevelMap2, timestamps2));
         // Fake current usage data.
         final UsageEvents.Event event1 =
                 getUsageEvent(UsageEvents.Event.ACTIVITY_RESUMED, /*timestamp=*/ 1, packageName);
@@ -171,10 +201,18 @@
         cursor.addRow(new Object[] {
                 AppUsageEventType.ACTIVITY_STOPPED.getNumber(), /*timestamp=*/ 6, /*userId=*/ 1,
                 /*instanceId=*/ 2, packageName});
-        DatabaseUtils.sFakeSupplier = () -> cursor;
+        DatabaseUtils.sFakeSupplier = new Supplier<>() {
+            private int mTimes = 0;
+            @Override
+            public Cursor get() {
+                mTimes++;
+                return mTimes <= 2 ? null : cursor;
+            }
+        };
 
         final DataProcessManager dataProcessManager = new DataProcessManager(
-                mContext, /*handler=*/ null, /*rawStartTimestamp=*/ 2L,  /*callbackFunction=*/ null,
+                mContext, /*handler=*/ null, /*rawStartTimestamp=*/ 2L,
+                /*lastFullChargeTimestamp=*/ 1L, /*callbackFunction=*/ null,
                 hourlyBatteryLevelsPerDay, /*batteryHistoryMap=*/ new HashMap<>());
         dataProcessManager.start();
 
@@ -224,6 +262,7 @@
     }
 
     @Test
+    @LooperMode(LooperMode.Mode.LEGACY)
     public void start_currentUserLocked_emptyAppUsageList() throws RemoteException {
         final UsageEvents.Event event =
                 getUsageEvent(UsageEvents.Event.ACTIVITY_RESUMED, /*timestamp=*/ 1, "package");
@@ -250,16 +289,18 @@
     }
 
     @Test
+    @LooperMode(LooperMode.Mode.LEGACY)
     public void getBatteryLevelData_emptyHistoryMap_returnNull() {
         assertThat(DataProcessManager.getBatteryLevelData(
                 mContext,
                 /*handler=*/ null,
-                /*batteryHistoryMap=*/ null,
-                /*asyncResponseDelegate=*/ null))
-                .isNull();
+                /*isFromPeriodJob=*/ false,
+                /*asyncResponseDelegate=*/ null)).isNull();
         assertThat(DataProcessManager.getBatteryLevelData(
-                mContext, /*handler=*/ null, new HashMap<>(), /*asyncResponseDelegate=*/ null))
-                .isNull();
+                mContext,
+                /*handler=*/ null,
+                /*isFromPeriodJob=*/ true,
+                /*asyncResponseDelegate=*/ null)).isNull();
     }
 
     @Test
@@ -270,18 +311,16 @@
                 DateUtils.HOUR_IN_MILLIS * 2 - 200L,
                 DateUtils.HOUR_IN_MILLIS * 2 - 100L};
         final int[] levels = {100, 99, 98};
-        final Map<Long, Map<String, BatteryHistEntry>> batteryHistoryMap =
-                createHistoryMap(timestamps, levels);
+        DataProcessManager.sFakeBatteryHistoryMap = createHistoryMap(timestamps, levels);
         DataProcessor.sTestCurrentTimeMillis = timestamps[timestamps.length - 1];
 
         final BatteryLevelData resultData =
                 DataProcessManager.getBatteryLevelData(
                         mContext,
                         /*handler=*/ null,
-                        batteryHistoryMap,
+                        /*isFromPeriodJob=*/ false,
                         /*asyncResponseDelegate=*/ null);
 
-
         final List<Long> expectedDailyTimestamps = List.of(
                 DateUtils.HOUR_IN_MILLIS * 2 - 300L,
                 DateUtils.HOUR_IN_MILLIS * 2 - 100L);
@@ -301,15 +340,14 @@
         // Timezone GMT+8: 2022-01-01 00:00:00, 2022-01-01 01:00:00
         final long[] timestamps = {1640966400000L, 1640970000000L};
         final int[] levels = {100, 99};
-        final Map<Long, Map<String, BatteryHistEntry>> batteryHistoryMap =
-                createHistoryMap(timestamps, levels);
+        DataProcessManager.sFakeBatteryHistoryMap = createHistoryMap(timestamps, levels);
         DataProcessor.sTestCurrentTimeMillis = timestamps[timestamps.length - 1];
 
         final BatteryLevelData resultData =
                 DataProcessManager.getBatteryLevelData(
                         mContext,
                         /*handler=*/ null,
-                        batteryHistoryMap,
+                        /*isFromPeriodJob=*/ false,
                         /*asyncResponseDelegate=*/ null);
 
         final List<Long> expectedDailyTimestamps = List.of(
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 c9b635e..c4394f7 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/DataProcessorTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/DataProcessorTest.java
@@ -16,6 +16,9 @@
 
 package com.android.settings.fuelgauge.batteryusage;
 
+import static com.android.settings.fuelgauge.batteryusage.ConvertUtils.FAKE_PACKAGE_NAME;
+import static com.android.settingslib.fuelgauge.BatteryStatus.BATTERY_LEVEL_UNKNOWN;
+
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.mockito.Mockito.anyInt;
@@ -42,6 +45,7 @@
 import android.os.Parcel;
 import android.os.RemoteException;
 import android.os.UserManager;
+import android.util.ArrayMap;
 
 import com.android.settings.fuelgauge.PowerUsageFeatureProvider;
 import com.android.settings.testutils.FakeFeatureFactory;
@@ -188,16 +192,18 @@
         final String packageName = "com.android.settings";
         // Adds the day 1 data.
         final List<Long> timestamps1 = List.of(14400000L, 18000000L, 21600000L);
-        final List<Integer> levels1 = List.of(100, 100, 100);
+        final Map<Long, Integer> batteryLevelMap1 =
+                Map.of(timestamps1.get(0), 100, timestamps1.get(1), 100, timestamps1.get(2), 100);
         hourlyBatteryLevelsPerDay.add(
-                new BatteryLevelData.PeriodBatteryLevelData(timestamps1, levels1));
+                new BatteryLevelData.PeriodBatteryLevelData(batteryLevelMap1, timestamps1));
         // Adds the day 2 data.
         hourlyBatteryLevelsPerDay.add(null);
         // Adds the day 3 data.
         final List<Long> timestamps2 = List.of(45200000L, 48800000L);
-        final List<Integer> levels2 = List.of(100, 100);
+        final Map<Long, Integer> batteryLevelMap2 =
+                Map.of(timestamps2.get(0), 100, timestamps2.get(1), 100);
         hourlyBatteryLevelsPerDay.add(
-                new BatteryLevelData.PeriodBatteryLevelData(timestamps2, levels2));
+                new BatteryLevelData.PeriodBatteryLevelData(batteryLevelMap2, timestamps2));
         final List<AppUsageEvent> appUsageEventList = new ArrayList<>();
         // Adds some events before the start timestamp.
         appUsageEventList.add(buildAppUsageEvent(
@@ -285,7 +291,7 @@
         final List<BatteryLevelData.PeriodBatteryLevelData> hourlyBatteryLevelsPerDay =
                 new ArrayList<>();
         hourlyBatteryLevelsPerDay.add(
-                new BatteryLevelData.PeriodBatteryLevelData(new ArrayList<>(), new ArrayList<>()));
+                new BatteryLevelData.PeriodBatteryLevelData(new ArrayMap<>(), new ArrayList<>()));
         assertThat(DataProcessor.generateAppUsagePeriodMap(
                 mContext, hourlyBatteryLevelsPerDay, new ArrayList<>(), new ArrayList<>()))
                 .isNull();
@@ -371,19 +377,6 @@
     }
 
     @Test
-    public void getLevelDataThroughProcessedHistoryMap_notEnoughData_returnNull() {
-        final long[] timestamps = {100L};
-        final int[] levels = {100};
-        final Map<Long, Map<String, BatteryHistEntry>> batteryHistoryMap =
-                createHistoryMap(timestamps, levels);
-        DataProcessor.sTestCurrentTimeMillis = timestamps[timestamps.length - 1];
-
-        assertThat(
-                DataProcessor.getLevelDataThroughProcessedHistoryMap(mContext, batteryHistoryMap))
-                .isNull();
-    }
-
-    @Test
     public void getLevelDataThroughProcessedHistoryMap_OneDayData_returnExpectedResult() {
         // Timezone GMT+8
         final long[] timestamps = {
@@ -441,7 +434,7 @@
         );
         final List<Integer> expectedDailyLevels = new ArrayList<>();
         expectedDailyLevels.add(100);
-        expectedDailyLevels.add(null);
+        expectedDailyLevels.add(BATTERY_LEVEL_UNKNOWN);
         expectedDailyLevels.add(82);
         final List<List<Long>> expectedHourlyTimestamps = List.of(
                 List.of(
@@ -459,13 +452,13 @@
         );
         final List<Integer> expectedHourlyLevels1 = new ArrayList<>();
         expectedHourlyLevels1.add(100);
-        expectedHourlyLevels1.add(null);
-        expectedHourlyLevels1.add(null);
+        expectedHourlyLevels1.add(BATTERY_LEVEL_UNKNOWN);
+        expectedHourlyLevels1.add(BATTERY_LEVEL_UNKNOWN);
         final List<Integer> expectedHourlyLevels2 = new ArrayList<>();
-        expectedHourlyLevels2.add(null);
+        expectedHourlyLevels2.add(BATTERY_LEVEL_UNKNOWN);
         expectedHourlyLevels2.add(94);
         expectedHourlyLevels2.add(90);
-        expectedHourlyLevels2.add(null);
+        expectedHourlyLevels2.add(BATTERY_LEVEL_UNKNOWN);
         expectedHourlyLevels2.add(82);
         final List<List<Integer>> expectedHourlyLevels = List.of(
                 expectedHourlyLevels1,
@@ -503,8 +496,8 @@
         );
         final List<Integer> expectedDailyLevels = new ArrayList<>();
         expectedDailyLevels.add(100);
-        expectedDailyLevels.add(null);
-        expectedDailyLevels.add(null);
+        expectedDailyLevels.add(BATTERY_LEVEL_UNKNOWN);
+        expectedDailyLevels.add(BATTERY_LEVEL_UNKNOWN);
         expectedDailyLevels.add(88);
         final List<List<Long>> expectedHourlyTimestamps = List.of(
                 List.of(
@@ -542,32 +535,32 @@
         );
         final List<Integer> expectedHourlyLevels1 = new ArrayList<>();
         expectedHourlyLevels1.add(100);
-        expectedHourlyLevels1.add(null);
-        expectedHourlyLevels1.add(null);
-        expectedHourlyLevels1.add(null);
-        expectedHourlyLevels1.add(null);
-        expectedHourlyLevels1.add(null);
-        expectedHourlyLevels1.add(null);
-        expectedHourlyLevels1.add(null);
+        expectedHourlyLevels1.add(BATTERY_LEVEL_UNKNOWN);
+        expectedHourlyLevels1.add(BATTERY_LEVEL_UNKNOWN);
+        expectedHourlyLevels1.add(BATTERY_LEVEL_UNKNOWN);
+        expectedHourlyLevels1.add(BATTERY_LEVEL_UNKNOWN);
+        expectedHourlyLevels1.add(BATTERY_LEVEL_UNKNOWN);
+        expectedHourlyLevels1.add(BATTERY_LEVEL_UNKNOWN);
+        expectedHourlyLevels1.add(BATTERY_LEVEL_UNKNOWN);
         final List<Integer> expectedHourlyLevels2 = new ArrayList<>();
-        expectedHourlyLevels2.add(null);
-        expectedHourlyLevels2.add(null);
-        expectedHourlyLevels2.add(null);
-        expectedHourlyLevels2.add(null);
-        expectedHourlyLevels2.add(null);
-        expectedHourlyLevels2.add(null);
-        expectedHourlyLevels2.add(null);
-        expectedHourlyLevels2.add(null);
-        expectedHourlyLevels2.add(null);
-        expectedHourlyLevels2.add(null);
-        expectedHourlyLevels2.add(null);
-        expectedHourlyLevels2.add(null);
-        expectedHourlyLevels2.add(null);
-        expectedHourlyLevels2.add(null);
+        expectedHourlyLevels2.add(BATTERY_LEVEL_UNKNOWN);
+        expectedHourlyLevels2.add(BATTERY_LEVEL_UNKNOWN);
+        expectedHourlyLevels2.add(BATTERY_LEVEL_UNKNOWN);
+        expectedHourlyLevels2.add(BATTERY_LEVEL_UNKNOWN);
+        expectedHourlyLevels2.add(BATTERY_LEVEL_UNKNOWN);
+        expectedHourlyLevels2.add(BATTERY_LEVEL_UNKNOWN);
+        expectedHourlyLevels2.add(BATTERY_LEVEL_UNKNOWN);
+        expectedHourlyLevels2.add(BATTERY_LEVEL_UNKNOWN);
+        expectedHourlyLevels2.add(BATTERY_LEVEL_UNKNOWN);
+        expectedHourlyLevels2.add(BATTERY_LEVEL_UNKNOWN);
+        expectedHourlyLevels2.add(BATTERY_LEVEL_UNKNOWN);
+        expectedHourlyLevels2.add(BATTERY_LEVEL_UNKNOWN);
+        expectedHourlyLevels2.add(BATTERY_LEVEL_UNKNOWN);
+        expectedHourlyLevels2.add(BATTERY_LEVEL_UNKNOWN);
         final List<Integer> expectedHourlyLevels3 = new ArrayList<>();
-        expectedHourlyLevels3.add(null);
-        expectedHourlyLevels3.add(null);
-        expectedHourlyLevels3.add(null);
+        expectedHourlyLevels3.add(BATTERY_LEVEL_UNKNOWN);
+        expectedHourlyLevels3.add(BATTERY_LEVEL_UNKNOWN);
+        expectedHourlyLevels3.add(BATTERY_LEVEL_UNKNOWN);
         expectedHourlyLevels3.add(88);
         final List<List<Integer>> expectedHourlyLevels = List.of(
                 expectedHourlyLevels1,
@@ -606,8 +599,8 @@
         );
         final List<Integer> expectedDailyLevels = new ArrayList<>();
         expectedDailyLevels.add(100);
-        expectedDailyLevels.add(null);
-        expectedDailyLevels.add(null);
+        expectedDailyLevels.add(BATTERY_LEVEL_UNKNOWN);
+        expectedDailyLevels.add(BATTERY_LEVEL_UNKNOWN);
         expectedDailyLevels.add(88);
         final List<List<Long>> expectedHourlyTimestamps = List.of(
                 List.of(
@@ -638,25 +631,25 @@
         );
         final List<Integer> expectedHourlyLevels1 = new ArrayList<>();
         expectedHourlyLevels1.add(100);
-        expectedHourlyLevels1.add(null);
+        expectedHourlyLevels1.add(BATTERY_LEVEL_UNKNOWN);
         final List<Integer> expectedHourlyLevels2 = new ArrayList<>();
-        expectedHourlyLevels2.add(null);
-        expectedHourlyLevels2.add(null);
-        expectedHourlyLevels2.add(null);
-        expectedHourlyLevels2.add(null);
-        expectedHourlyLevels2.add(null);
-        expectedHourlyLevels2.add(null);
-        expectedHourlyLevels2.add(null);
-        expectedHourlyLevels2.add(null);
-        expectedHourlyLevels2.add(null);
-        expectedHourlyLevels2.add(null);
-        expectedHourlyLevels2.add(null);
-        expectedHourlyLevels2.add(null);
-        expectedHourlyLevels2.add(null);
+        expectedHourlyLevels2.add(BATTERY_LEVEL_UNKNOWN);
+        expectedHourlyLevels2.add(BATTERY_LEVEL_UNKNOWN);
+        expectedHourlyLevels2.add(BATTERY_LEVEL_UNKNOWN);
+        expectedHourlyLevels2.add(BATTERY_LEVEL_UNKNOWN);
+        expectedHourlyLevels2.add(BATTERY_LEVEL_UNKNOWN);
+        expectedHourlyLevels2.add(BATTERY_LEVEL_UNKNOWN);
+        expectedHourlyLevels2.add(BATTERY_LEVEL_UNKNOWN);
+        expectedHourlyLevels2.add(BATTERY_LEVEL_UNKNOWN);
+        expectedHourlyLevels2.add(BATTERY_LEVEL_UNKNOWN);
+        expectedHourlyLevels2.add(BATTERY_LEVEL_UNKNOWN);
+        expectedHourlyLevels2.add(BATTERY_LEVEL_UNKNOWN);
+        expectedHourlyLevels2.add(BATTERY_LEVEL_UNKNOWN);
+        expectedHourlyLevels2.add(BATTERY_LEVEL_UNKNOWN);
         final List<Integer> expectedHourlyLevels3 = new ArrayList<>();
-        expectedHourlyLevels3.add(null);
-        expectedHourlyLevels3.add(null);
-        expectedHourlyLevels3.add(null);
+        expectedHourlyLevels3.add(BATTERY_LEVEL_UNKNOWN);
+        expectedHourlyLevels3.add(BATTERY_LEVEL_UNKNOWN);
+        expectedHourlyLevels3.add(BATTERY_LEVEL_UNKNOWN);
         expectedHourlyLevels3.add(88);
         final List<List<Integer>> expectedHourlyLevels = List.of(
                 expectedHourlyLevels1,
@@ -735,141 +728,6 @@
     }
 
     @Test
-    public void getDailyTimestamps_notEnoughData_returnEmptyList() {
-        assertThat(DataProcessor.getDailyTimestamps(new ArrayList<>())).isEmpty();
-        assertThat(DataProcessor.getDailyTimestamps(List.of(100L))).isEmpty();
-    }
-
-    @Test
-    public void getDailyTimestamps_allDataInOneHour_returnExpectedList() {
-        // Timezone GMT+8
-        final List<Long> timestamps = List.of(
-                1640970006000L, // 2022-01-01 01:00:06
-                1640973608000L  // 2022-01-01 01:00:08
-        );
-
-        final List<Long> expectedTimestamps = List.of(
-                1640970006000L, // 2022-01-01 01:00:06
-                1640973608000L  // 2022-01-01 01:00:08
-        );
-        assertThat(DataProcessor.getDailyTimestamps(timestamps)).isEqualTo(expectedTimestamps);
-    }
-
-    @Test
-    public void getDailyTimestamps_OneHourDataPerDay_returnExpectedList() {
-        // Timezone GMT+8
-        final List<Long> timestamps = List.of(
-                1641049200000L, // 2022-01-01 23:00:00
-                1641052800000L, // 2022-01-02 00:00:00
-                1641056400000L  // 2022-01-02 01:00:00
-        );
-
-        final List<Long> expectedTimestamps = List.of(
-                1641049200000L, // 2022-01-01 23:00:00
-                1641052800000L, // 2022-01-02 00:00:00
-                1641056400000L  // 2022-01-02 01:00:00
-        );
-        assertThat(DataProcessor.getDailyTimestamps(timestamps)).isEqualTo(expectedTimestamps);
-    }
-
-    @Test
-    public void getDailyTimestamps_OneDayData_returnExpectedList() {
-        // Timezone GMT+8
-        final List<Long> timestamps = List.of(
-                1640966400000L, // 2022-01-01 00:00:00
-                1640970000000L, // 2022-01-01 01:00:00
-                1640973600000L, // 2022-01-01 02:00:00
-                1640977200000L, // 2022-01-01 03:00:00
-                1640980800000L  // 2022-01-01 04:00:00
-        );
-
-        final List<Long> expectedTimestamps = List.of(
-                1640966400000L, // 2022-01-01 00:00:00
-                1640980800000L  // 2022-01-01 04:00:00
-        );
-        assertThat(DataProcessor.getDailyTimestamps(timestamps)).isEqualTo(expectedTimestamps);
-    }
-
-    @Test
-    public void getDailyTimestamps_MultipleDaysData_returnExpectedList() {
-        // Timezone GMT+8
-        final List<Long> timestamps = List.of(
-                1641045600000L, // 2022-01-01 22:00:00
-                1641060000000L, // 2022-01-02 02:00:00
-                1641160800000L, // 2022-01-03 06:00:00
-                1641232800000L  // 2022-01-04 02:00:00
-        );
-
-        final List<Long> expectedTimestamps = List.of(
-                1641045600000L, // 2022-01-01 22:00:00
-                1641052800000L, // 2022-01-02 00:00:00
-                1641139200000L, // 2022-01-03 00:00:00
-                1641225600000L, // 2022-01-04 00:00:00
-                1641232800000L  // 2022-01-04 02:00:00
-        );
-        assertThat(DataProcessor.getDailyTimestamps(timestamps)).isEqualTo(expectedTimestamps);
-    }
-
-    @Test
-    public void getDailyTimestamps_FirstDayOneHourData_returnExpectedList() {
-        // Timezone GMT+8
-        final List<Long> timestamps = List.of(
-                1641049200000L, // 2022-01-01 23:00:00
-                1641060000000L, // 2022-01-02 02:00:00
-                1641160800000L, // 2022-01-03 06:00:00
-                1641254400000L  // 2022-01-04 08:00:00
-        );
-
-        final List<Long> expectedTimestamps = List.of(
-                1641049200000L, // 2022-01-01 23:00:00
-                1641052800000L, // 2022-01-02 00:00:00
-                1641139200000L, // 2022-01-03 00:00:00
-                1641225600000L, // 2022-01-04 00:00:00
-                1641254400000L  // 2022-01-04 08:00:00
-        );
-        assertThat(DataProcessor.getDailyTimestamps(timestamps)).isEqualTo(expectedTimestamps);
-    }
-
-    @Test
-    public void getDailyTimestamps_LastDayNoData_returnExpectedList() {
-        // Timezone GMT+8
-        final List<Long> timestamps = List.of(
-                1640988000000L, // 2022-01-01 06:00:00
-                1641060000000L, // 2022-01-02 02:00:00
-                1641160800000L, // 2022-01-03 06:00:00
-                1641225600000L  // 2022-01-04 00:00:00
-        );
-
-        final List<Long> expectedTimestamps = List.of(
-                1640988000000L, // 2022-01-01 06:00:00
-                1641052800000L, // 2022-01-02 00:00:00
-                1641139200000L, // 2022-01-03 00:00:00
-                1641225600000L  // 2022-01-04 00:00:00
-        );
-        assertThat(DataProcessor.getDailyTimestamps(timestamps)).isEqualTo(expectedTimestamps);
-    }
-
-    @Test
-    public void getDailyTimestamps_LastDayOneHourData_returnExpectedList() {
-        // Timezone GMT+8
-        final List<Long> timestamps = List.of(
-                1640988000000L, // 2022-01-01 06:00:00
-                1641060000000L, // 2022-01-02 02:00:00
-                1641160800000L, // 2022-01-03 06:00:00
-                1641229200000L  // 2022-01-04 01:00:00
-        );
-
-        final List<Long> expectedTimestamps = List.of(
-                1640988000000L, // 2022-01-01 06:00:00
-                1641052800000L, // 2022-01-02 00:00:00
-                1641139200000L, // 2022-01-03 00:00:00
-                1641225600000L, // 2022-01-04 00:00:00
-                1641229200000L  // 2022-01-04 01:00:00
-        );
-        assertThat(DataProcessor.getDailyTimestamps(timestamps)).isEqualTo(expectedTimestamps);
-    }
-
-    @Test
     public void isFromFullCharge_emptyData_returnFalse() {
         assertThat(DataProcessor.isFromFullCharge(null)).isFalse();
         assertThat(DataProcessor.isFromFullCharge(new HashMap<>())).isFalse();
@@ -916,20 +774,53 @@
     }
 
     @Test
-    public void getBatteryUsageMap_emptyHistoryMap_returnNull() {
+    public void getBatteryDiffDataMap_emptyHistoryMap_returnEmpty() {
         final List<BatteryLevelData.PeriodBatteryLevelData> hourlyBatteryLevelsPerDay =
                 new ArrayList<>();
 
         hourlyBatteryLevelsPerDay.add(
-                new BatteryLevelData.PeriodBatteryLevelData(new ArrayList<>(), new ArrayList<>()));
+                new BatteryLevelData.PeriodBatteryLevelData(new ArrayMap<>(), new ArrayList<>()));
 
-        assertThat(DataProcessor.getBatteryUsageMap(
-                mContext, hourlyBatteryLevelsPerDay, new HashMap<>(), /*appUsagePeriodMap=*/ null))
-                .isNull();
+        assertThat(DataProcessor.getBatteryDiffDataMap(mContext, hourlyBatteryLevelsPerDay,
+                new HashMap<>(), /*appUsagePeriodMap=*/ null, Set.of(), Set.of())).isEmpty();
     }
 
     @Test
-    public void getBatteryUsageMap_returnsExpectedResult() {
+    public void getBatteryDiffDataMap_normalFlow_returnExpectedResult() {
+        final int userId = mContext.getUserId();
+        final long[] batteryHistoryKeys = new long[]{
+                1641045600000L, // 2022-01-01 22:00:00
+                1641049200000L, // 2022-01-01 23:00:00
+                1641052800000L, // 2022-01-02 00:00:00
+        };
+        final Map<Long, Map<String, BatteryHistEntry>> batteryHistoryMap = Map.of(
+                batteryHistoryKeys[0], Map.of(FAKE_PACKAGE_NAME, createBatteryHistEntry(
+                        FAKE_PACKAGE_NAME, "fake_label", /*consumePower=*/ 0, 0, 0,
+                        0, 0, 0L, userId, ConvertUtils.CONSUMER_TYPE_UID_BATTERY, 0L, 0L, false)),
+                batteryHistoryKeys[1], Map.of(FAKE_PACKAGE_NAME, createBatteryHistEntry(
+                        FAKE_PACKAGE_NAME, "fake_label", /*consumePower=*/ 5, 0, 0,
+                        0, 0, 0L, userId, ConvertUtils.CONSUMER_TYPE_UID_BATTERY, 0L, 0L, false)),
+                batteryHistoryKeys[2], Map.of(FAKE_PACKAGE_NAME, createBatteryHistEntry(
+                        FAKE_PACKAGE_NAME, "fake_label", /*consumePower=*/ 16, 0, 0,
+                        0, 0, 0L, userId, ConvertUtils.CONSUMER_TYPE_UID_BATTERY, 0L, 0L, false)));
+        final BatteryLevelData batteryLevelData = generateBatteryLevelData(batteryHistoryKeys);
+        final Map<Integer, Map<Integer, Map<Long, Map<String, List<AppUsagePeriod>>>>>
+                appUsagePeriodMap = Map.of(0, Map.of(0, Map.of(Long.valueOf(userId), Map.of(
+                FAKE_PACKAGE_NAME, List.of(buildAppUsagePeriod(0, 6))))));
+
+        Map<Long, BatteryDiffData> batteryDiffDataMap = DataProcessor.getBatteryDiffDataMap(
+                mContext, batteryLevelData.getHourlyBatteryLevelsPerDay(), batteryHistoryMap,
+                appUsagePeriodMap, Set.of(), Set.of());
+
+        assertThat(batteryDiffDataMap).hasSize(1);
+        assertThat(batteryDiffDataMap).containsKey(batteryHistoryKeys[0]);
+        BatteryDiffData batteryDiffData = batteryDiffDataMap.get(batteryHistoryKeys[0]);
+        assertThat(batteryDiffData.getStartTimestamp()).isEqualTo(batteryHistoryKeys[0]);
+        assertThat(batteryDiffData.getEndTimestamp()).isEqualTo(batteryHistoryKeys[2]);
+    }
+
+    @Test
+    public void generateBatteryUsageMap_returnsExpectedResult() {
         final long[] batteryHistoryKeys = new long[]{
                 1641045600000L, // 2022-01-01 22:00:00
                 1641049200000L, // 2022-01-01 23:00:00
@@ -940,7 +831,7 @@
         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,
+                FAKE_PACKAGE_NAME, "fake_label", /*consumePower=*/ 0,
                 /*foregroundUsageConsumePower=*/ 0, /*foregroundServiceUsageConsumePower=*/ 0,
                 /*backgroundUsageConsumePower=*/ 0, /*cachedUsageConsumePower=*/ 0,
                 /*uid=*/ 0L, currentUserId, ConvertUtils.CONSUMER_TYPE_UID_BATTERY,
@@ -1030,19 +921,7 @@
         entryMap.put(entry.getKey(), entry);
         entryMap.put(fakeEntry.getKey(), fakeEntry);
         batteryHistoryMap.put(batteryHistoryKeys[4], entryMap);
-        final List<BatteryLevelData.PeriodBatteryLevelData> hourlyBatteryLevelsPerDay =
-                new ArrayList<>();
-        // Adds the day 1 data.
-        List<Long> timestamps =
-                List.of(batteryHistoryKeys[0], batteryHistoryKeys[2]);
-        final List<Integer> levels = List.of(100, 100);
-        hourlyBatteryLevelsPerDay.add(
-                new BatteryLevelData.PeriodBatteryLevelData(timestamps, levels));
-        // Adds the day 2 data.
-        timestamps = List.of(batteryHistoryKeys[2], batteryHistoryKeys[4]);
-        hourlyBatteryLevelsPerDay.add(
-                new BatteryLevelData.PeriodBatteryLevelData(timestamps, levels));
-
+        final BatteryLevelData batteryLevelData = generateBatteryLevelData(batteryHistoryKeys);
         // Adds app usage data to test screen on time.
         final Map<Integer, Map<Integer, Map<Long, Map<String, List<AppUsagePeriod>>>>>
                 appUsagePeriodMap = new HashMap<>();
@@ -1066,8 +945,12 @@
         appUsagePeriodMap.get(1).put(0, appUsageMap);
 
         final Map<Integer, Map<Integer, BatteryDiffData>> resultMap =
-                DataProcessor.getBatteryUsageMap(
-                        mContext, hourlyBatteryLevelsPerDay, batteryHistoryMap, appUsagePeriodMap);
+                DataProcessor.generateBatteryUsageMap(
+                        mContext,
+                        DataProcessor.getBatteryDiffDataMap(mContext,
+                                batteryLevelData.getHourlyBatteryLevelsPerDay(), batteryHistoryMap,
+                                appUsagePeriodMap, Set.of(), Set.of()),
+                        batteryLevelData);
 
         BatteryDiffData resultDiffData =
                 resultMap
@@ -1128,7 +1011,7 @@
     }
 
     @Test
-    public void getBatteryUsageMap_multipleUsers_returnsExpectedResult() {
+    public void generateBatteryUsageMap_multipleUsers_returnsExpectedResult() {
         final long[] batteryHistoryKeys = new long[]{
                 1641052800000L, // 2022-01-02 00:00:00
                 1641056400000L, // 2022-01-02 01:00:00
@@ -1217,17 +1100,15 @@
                 /*backgroundUsageTimeInMs=*/ 30L, /*isHidden=*/ false);
         entryMap.put(entry.getKey(), entry);
         batteryHistoryMap.put(batteryHistoryKeys[2], entryMap);
-        final List<BatteryLevelData.PeriodBatteryLevelData> hourlyBatteryLevelsPerDay =
-                new ArrayList<>();
-        List<Long> timestamps = List.of(batteryHistoryKeys[0], batteryHistoryKeys[2]);
-        final List<Integer> levels = List.of(100, 100);
-        hourlyBatteryLevelsPerDay.add(
-                new BatteryLevelData.PeriodBatteryLevelData(timestamps, levels));
+        final BatteryLevelData batteryLevelData = generateBatteryLevelData(batteryHistoryKeys);
 
         final Map<Integer, Map<Integer, BatteryDiffData>> resultMap =
-                DataProcessor.getBatteryUsageMap(
-                        mContext, hourlyBatteryLevelsPerDay, batteryHistoryMap,
-                        /*appUsagePeriodMap=*/ null);
+                DataProcessor.generateBatteryUsageMap(
+                        mContext,
+                        DataProcessor.getBatteryDiffDataMap(mContext,
+                                batteryLevelData.getHourlyBatteryLevelsPerDay(), batteryHistoryMap,
+                                /*appUsagePeriodMap=*/ null, Set.of(), Set.of()),
+                        batteryLevelData);
 
         final BatteryDiffData resultDiffData =
                 resultMap
@@ -1247,7 +1128,7 @@
     }
 
     @Test
-    public void getBatteryUsageMap_usageTimeExceed_returnsExpectedResult() {
+    public void generateBatteryUsageMap_usageTimeExceed_returnsExpectedResult() {
         final long[] batteryHistoryKeys = new long[]{
                 1641052800000L, // 2022-01-02 00:00:00
                 1641056400000L, // 2022-01-02 01:00:00
@@ -1288,12 +1169,7 @@
                 /*backgroundUsageTimeInMs=*/ 7200000L, /*isHidden=*/ false);
         entryMap.put(entry.getKey(), entry);
         batteryHistoryMap.put(batteryHistoryKeys[2], entryMap);
-        final List<BatteryLevelData.PeriodBatteryLevelData> hourlyBatteryLevelsPerDay =
-                new ArrayList<>();
-        List<Long> timestamps = List.of(batteryHistoryKeys[0], batteryHistoryKeys[2]);
-        final List<Integer> levels = List.of(100, 100);
-        hourlyBatteryLevelsPerDay.add(
-                new BatteryLevelData.PeriodBatteryLevelData(timestamps, levels));
+        final BatteryLevelData batteryLevelData = generateBatteryLevelData(batteryHistoryKeys);
 
         // Adds app usage data to test screen on time.
         final Map<Integer, Map<Integer, Map<Long, Map<String, List<AppUsagePeriod>>>>>
@@ -1307,8 +1183,12 @@
         appUsagePeriodMap.get(0).put(0, appUsageMap);
 
         final Map<Integer, Map<Integer, BatteryDiffData>> resultMap =
-                DataProcessor.getBatteryUsageMap(
-                        mContext, hourlyBatteryLevelsPerDay, batteryHistoryMap, appUsagePeriodMap);
+                DataProcessor.generateBatteryUsageMap(
+                        mContext,
+                        DataProcessor.getBatteryDiffDataMap(mContext,
+                                batteryLevelData.getHourlyBatteryLevelsPerDay(), batteryHistoryMap,
+                                appUsagePeriodMap, Set.of(), Set.of()),
+                        batteryLevelData);
 
         final BatteryDiffData resultDiffData =
                 resultMap
@@ -1338,7 +1218,7 @@
     }
 
     @Test
-    public void getBatteryUsageMap_hideApplicationEntries_returnsExpectedResult() {
+    public void generateBatteryUsageMap_hideApplicationEntries_returnsExpectedResult() {
         final long[] batteryHistoryKeys = new long[]{
                 1641052800000L, // 2022-01-02 00:00:00
                 1641056400000L, // 2022-01-02 01:00:00
@@ -1403,19 +1283,17 @@
                 /*backgroundUsageTimeInMs=*/ 20L, /*isHidden=*/ false);
         entryMap.put(entry.getKey(), entry);
         batteryHistoryMap.put(batteryHistoryKeys[2], entryMap);
-        final List<BatteryLevelData.PeriodBatteryLevelData> hourlyBatteryLevelsPerDay =
-                new ArrayList<>();
-        List<Long> timestamps = List.of(batteryHistoryKeys[0], batteryHistoryKeys[2]);
-        final List<Integer> levels = List.of(100, 100);
-        hourlyBatteryLevelsPerDay.add(
-                new BatteryLevelData.PeriodBatteryLevelData(timestamps, levels));
+        final BatteryLevelData batteryLevelData = generateBatteryLevelData(batteryHistoryKeys);
         when(mPowerUsageFeatureProvider.getHideApplicationSet())
                 .thenReturn(Set.of("package1"));
 
         final Map<Integer, Map<Integer, BatteryDiffData>> resultMap =
-                DataProcessor.getBatteryUsageMap(
-                        mContext, hourlyBatteryLevelsPerDay, batteryHistoryMap,
-                        /*appUsagePeriodMap=*/ null);
+                DataProcessor.generateBatteryUsageMap(
+                        mContext,
+                        DataProcessor.getBatteryDiffDataMap(mContext,
+                                batteryLevelData.getHourlyBatteryLevelsPerDay(), batteryHistoryMap,
+                                /*appUsagePeriodMap=*/ null, Set.of(), Set.of()),
+                        batteryLevelData);
 
         final BatteryDiffData resultDiffData =
                 resultMap
@@ -1431,7 +1309,7 @@
     }
 
     @Test
-    public void getBatteryUsageMap_hideBackgroundUsageTime_returnsExpectedResult() {
+    public void generateBatteryUsageMap_hideBackgroundUsageTime_returnsExpectedResult() {
         final long[] batteryHistoryKeys = new long[]{
                 1641052800000L, // 2022-01-02 00:00:00
                 1641056400000L, // 2022-01-02 01:00:00
@@ -1496,19 +1374,17 @@
                 /*backgroundUsageTimeInMs=*/ 20L, /*isHidden=*/ false);
         entryMap.put(entry.getKey(), entry);
         batteryHistoryMap.put(batteryHistoryKeys[2], entryMap);
-        final List<BatteryLevelData.PeriodBatteryLevelData> hourlyBatteryLevelsPerDay =
-                new ArrayList<>();
-        List<Long> timestamps = List.of(batteryHistoryKeys[0], batteryHistoryKeys[2]);
-        final List<Integer> levels = List.of(100, 100);
-        hourlyBatteryLevelsPerDay.add(
-                new BatteryLevelData.PeriodBatteryLevelData(timestamps, levels));
+        final BatteryLevelData batteryLevelData = generateBatteryLevelData(batteryHistoryKeys);
         when(mPowerUsageFeatureProvider.getHideBackgroundUsageTimeSet())
                 .thenReturn(new HashSet(Arrays.asList((CharSequence) "package2")));
 
         final Map<Integer, Map<Integer, BatteryDiffData>> resultMap =
-                DataProcessor.getBatteryUsageMap(
-                        mContext, hourlyBatteryLevelsPerDay, batteryHistoryMap,
-                        /*appUsagePeriodMap=*/ null);
+                DataProcessor.generateBatteryUsageMap(
+                        mContext,
+                        DataProcessor.getBatteryDiffDataMap(mContext,
+                                batteryLevelData.getHourlyBatteryLevelsPerDay(), batteryHistoryMap,
+                                /*appUsagePeriodMap=*/ null, Set.of(), Set.of()),
+                        batteryLevelData);
 
         final BatteryDiffData resultDiffData =
                 resultMap
@@ -1523,7 +1399,10 @@
     @Test
     public void generateBatteryDiffData_emptyBatteryEntryList_returnNull() {
         assertThat(DataProcessor.generateBatteryDiffData(mContext,
-                DataProcessor.convertToBatteryHistEntry(null, mBatteryUsageStats))).isNull();
+                System.currentTimeMillis(),
+                DataProcessor.convertToBatteryHistEntry(null, mBatteryUsageStats),
+                /* systemAppsPackageNames= */ Set.of(),
+                /* systemAppsUids= */ Set.of())).isNull();
     }
 
     @Test
@@ -1574,7 +1453,10 @@
                 .when(mMockBatteryEntry4).getPowerComponentId();
 
         final BatteryDiffData batteryDiffData = DataProcessor.generateBatteryDiffData(mContext,
-                DataProcessor.convertToBatteryHistEntry(batteryEntryList, mBatteryUsageStats));
+                System.currentTimeMillis(),
+                DataProcessor.convertToBatteryHistEntry(batteryEntryList, mBatteryUsageStats),
+                /* systemAppsPackageNames= */ Set.of(),
+                /* systemAppsUids= */ Set.of());
 
         assertBatteryDiffEntry(
                 batteryDiffData.getAppDiffEntryList().get(0), 0, /*uid=*/ 2L,
@@ -2041,9 +1923,9 @@
             final double backgroundUsageConsumePower, final double cachedUsageConsumePower,
             final long foregroundUsageTimeInMs, final long backgroundUsageTimeInMs,
             final long screenOnTimeInMs) {
-        assertThat(entry.mBatteryHistEntry.mUserId).isEqualTo(userId);
-        assertThat(entry.mBatteryHistEntry.mUid).isEqualTo(uid);
-        assertThat(entry.mBatteryHistEntry.mConsumerType).isEqualTo(consumerType);
+        assertThat(entry.mUserId).isEqualTo(userId);
+        assertThat(entry.mUid).isEqualTo(uid);
+        assertThat(entry.mConsumerType).isEqualTo(consumerType);
         assertThat(entry.getPercentage()).isEqualTo(consumePercentage);
         assertThat(entry.mForegroundUsageConsumePower).isEqualTo(foregroundUsageConsumePower);
         assertThat(entry.mForegroundServiceUsageConsumePower)
@@ -2054,4 +1936,12 @@
         assertThat(entry.mBackgroundUsageTimeInMs).isEqualTo(backgroundUsageTimeInMs);
         assertThat(entry.mScreenOnTimeInMs).isEqualTo(screenOnTimeInMs);
     }
+
+    private BatteryLevelData generateBatteryLevelData(long[] timestamps) {
+        Map<Long, Integer> batteryLevelMap = new ArrayMap<>();
+        for (long timestamp : timestamps) {
+            batteryLevelMap.put(timestamp, 100);
+        }
+        return new BatteryLevelData(batteryLevelMap);
+    }
 }
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/DatabaseUtilsTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/DatabaseUtilsTest.java
index 8a1ba13..f72b333 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/DatabaseUtilsTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/DatabaseUtilsTest.java
@@ -173,8 +173,8 @@
         doReturn(null).when(mContext).registerReceiver(any(), any());
         assertThat(
                 DatabaseUtils.sendBatteryEntryData(
-                        mContext, /*batteryEntryList=*/ null, mBatteryUsageStats,
-                        /*isFullChargeStart=*/ false))
+                        mContext, System.currentTimeMillis(), /*batteryEntryList=*/ null,
+                        mBatteryUsageStats, /*isFullChargeStart=*/ false))
                 .isNull();
     }
 
@@ -193,7 +193,10 @@
 
         final List<ContentValues> valuesList =
                 DatabaseUtils.sendBatteryEntryData(
-                        mContext, batteryEntryList, mBatteryUsageStats,
+                        mContext,
+                        System.currentTimeMillis(),
+                        batteryEntryList,
+                        mBatteryUsageStats,
                         /*isFullChargeStart=*/ false);
 
         assertThat(valuesList).hasSize(2);
@@ -216,6 +219,7 @@
         final List<ContentValues> valuesList =
                 DatabaseUtils.sendBatteryEntryData(
                         mContext,
+                        System.currentTimeMillis(),
                         new ArrayList<>(),
                         mBatteryUsageStats,
                         /*isFullChargeStart=*/ false);
@@ -235,6 +239,7 @@
         final List<ContentValues> valuesList =
                 DatabaseUtils.sendBatteryEntryData(
                         mContext,
+                        System.currentTimeMillis(),
                         /*batteryEntryList=*/ null,
                         mBatteryUsageStats,
                         /*isFullChargeStart=*/ false);
@@ -254,6 +259,7 @@
         final List<ContentValues> valuesList =
                 DatabaseUtils.sendBatteryEntryData(
                         mContext,
+                        System.currentTimeMillis(),
                         /*batteryEntryList=*/ null,
                         /*batteryUsageStats=*/ null,
                         /*isFullChargeStart=*/ false);
@@ -359,7 +365,7 @@
     }
 
     @Test
-    public void getHistoryMapSinceLastFullCharge_emptyCursorContent_returnEmptyMap() {
+    public void getHistoryMap_emptyCursorContent_returnEmptyMap() {
         final MatrixCursor cursor = new MatrixCursor(
                 new String[] {
                         BatteryHistEntry.KEY_UID,
@@ -367,36 +373,33 @@
                         BatteryHistEntry.KEY_TIMESTAMP});
         DatabaseUtils.sFakeSupplier = () -> cursor;
 
-        assertThat(DatabaseUtils.getHistoryMapSinceLastFullCharge(
-                mContext, /*calendar=*/ null)).isEmpty();
+        assertThat(DatabaseUtils.getHistoryMapSinceQueryTimestamp(mContext, 0)).isEmpty();
     }
 
     @Test
-    public void getHistoryMapSinceLastFullCharge_nullCursor_returnEmptyMap() {
+    public void getHistoryMap_nullCursor_returnEmptyMap() {
         DatabaseUtils.sFakeSupplier = () -> null;
-        assertThat(DatabaseUtils.getHistoryMapSinceLastFullCharge(
-                mContext, /*calendar=*/ null)).isEmpty();
+        assertThat(DatabaseUtils.getHistoryMapSinceQueryTimestamp(mContext, 0)).isEmpty();
     }
 
     @Test
-    public void getHistoryMapSinceLastFullCharge_returnExpectedMap() {
+    public void getHistoryMap_returnExpectedMap() {
         final Long timestamp1 = Long.valueOf(1001L);
         final Long timestamp2 = Long.valueOf(1002L);
         final MatrixCursor cursor = getMatrixCursor();
         // Adds fake data into the cursor.
         cursor.addRow(new Object[] {
-                "app name1", timestamp1, 1, ConvertUtils.CONSUMER_TYPE_UID_BATTERY});
+                "app name1", timestamp1, 1, ConvertUtils.CONSUMER_TYPE_UID_BATTERY, true});
         cursor.addRow(new Object[] {
-                "app name2", timestamp2, 2, ConvertUtils.CONSUMER_TYPE_UID_BATTERY});
+                "app name2", timestamp2, 2, ConvertUtils.CONSUMER_TYPE_UID_BATTERY, false});
         cursor.addRow(new Object[] {
-                "app name3", timestamp2, 3, ConvertUtils.CONSUMER_TYPE_UID_BATTERY});
+                "app name3", timestamp2, 3, ConvertUtils.CONSUMER_TYPE_UID_BATTERY, false});
         cursor.addRow(new Object[] {
-                "app name4", timestamp2, 4, ConvertUtils.CONSUMER_TYPE_UID_BATTERY});
+                "app name4", timestamp2, 4, ConvertUtils.CONSUMER_TYPE_UID_BATTERY, false});
         DatabaseUtils.sFakeSupplier = () -> cursor;
 
         final Map<Long, Map<String, BatteryHistEntry>> batteryHistMap =
-                DatabaseUtils.getHistoryMapSinceLastFullCharge(
-                        mContext, /*calendar=*/ null);
+                DatabaseUtils.getHistoryMapSinceQueryTimestamp(mContext, timestamp1);
 
         assertThat(batteryHistMap).hasSize(2);
         // Verifies the BatteryHistEntry data for timestamp1.
@@ -412,7 +415,7 @@
     }
 
     @Test
-    public void getHistoryMapSinceLastFullCharge_withWorkProfile_returnExpectedMap()
+    public void getHistoryMap_withWorkProfile_returnExpectedMap()
             throws PackageManager.NameNotFoundException {
         doReturn("com.fake.package").when(mContext).getPackageName();
         doReturn(mMockContext).when(mContext).createPackageContextAsUser(
@@ -425,8 +428,7 @@
         DatabaseUtils.sFakeSupplier = () -> getMatrixCursor();
 
         final Map<Long, Map<String, BatteryHistEntry>> batteryHistMap =
-                DatabaseUtils.getHistoryMapSinceLastFullCharge(
-                        mContext, /*calendar=*/ null);
+                DatabaseUtils.getHistoryMapSinceQueryTimestamp(mContext, 0);
 
         assertThat(batteryHistMap).isEmpty();
     }
@@ -571,6 +573,7 @@
                         BatteryHistEntry.KEY_PACKAGE_NAME,
                         BatteryHistEntry.KEY_TIMESTAMP,
                         BatteryHistEntry.KEY_UID,
-                        BatteryHistEntry.KEY_CONSUMER_TYPE});
+                        BatteryHistEntry.KEY_CONSUMER_TYPE,
+                        BatteryHistEntry.KEY_IS_FULL_CHARGE_CYCLE_START});
     }
 }
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/PowerUsageBaseTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/PowerUsageBaseTest.java
index 6ed10cd..68766e6 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/PowerUsageBaseTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/PowerUsageBaseTest.java
@@ -135,11 +135,6 @@
         }
 
         @Override
-        protected boolean isBatteryHistoryNeeded() {
-            return false;
-        }
-
-        @Override
         protected void refreshUi(int refreshType) {
             // Do nothing
         }
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/PowerUsageSummaryTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/PowerUsageSummaryTest.java
index e44d92c..579d4a9 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/PowerUsageSummaryTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/PowerUsageSummaryTest.java
@@ -70,6 +70,9 @@
 
 // TODO: Improve this test class so that it starts up the real activity and fragment.
 @RunWith(RobolectricTestRunner.class)
+@Config(shadows = {
+        com.android.settings.testutils.shadow.ShadowFragment.class,
+})
 public class PowerUsageSummaryTest {
     private static Intent sAdditionalBatteryInfoIntent;
 
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/db/BatteryEventDaoTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/db/BatteryEventDaoTest.java
index 941f444..8462867 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/db/BatteryEventDaoTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/db/BatteryEventDaoTest.java
@@ -16,6 +16,10 @@
 
 package com.android.settings.fuelgauge.batteryusage.db;
 
+import static com.android.settings.fuelgauge.batteryusage.db.BatteryEventEntity.KEY_BATTERY_EVENT_TYPE;
+import static com.android.settings.fuelgauge.batteryusage.db.BatteryEventEntity.KEY_BATTERY_LEVEL;
+import static com.android.settings.fuelgauge.batteryusage.db.BatteryEventEntity.KEY_TIMESTAMP;
+
 import static com.google.common.truth.Truth.assertThat;
 
 import android.content.Context;
@@ -31,9 +35,14 @@
 import org.junit.runner.RunWith;
 import org.robolectric.RobolectricTestRunner;
 
+import java.util.List;
+
 /** Tests for {@link BatteryEventDao}. */
 @RunWith(RobolectricTestRunner.class)
 public final class BatteryEventDaoTest {
+    private static final long TIMESTAMP1 = System.currentTimeMillis();
+    private static final long TIMESTAMP2 = TIMESTAMP1 + 2;
+
     private Context mContext;
     private BatteryStateDatabase mDatabase;
     private BatteryEventDao mBatteryEventDao;
@@ -51,8 +60,44 @@
         BatteryStateDatabase.setBatteryStateDatabase(/*database=*/ null);
     }
 
+
     @Test
-    public void getAllAfter_returnExpectedResult() {
+    public void getLastFullChargeTimestamp_normalFlow_expectedBehavior() throws Exception {
+        mBatteryEventDao.insert(BatteryEventEntity.newBuilder()
+                .setTimestamp(TIMESTAMP1)
+                .setBatteryEventType(3)
+                .setBatteryLevel(100)
+                .build());
+        mBatteryEventDao.insert(BatteryEventEntity.newBuilder()
+                .setTimestamp(TIMESTAMP2)
+                .setBatteryEventType(4)
+                .setBatteryLevel(96)
+                .build());
+
+        final Cursor cursor = mBatteryEventDao.getLastFullChargeTimestamp();
+        assertThat(cursor.getCount()).isEqualTo(1);
+        cursor.moveToFirst();
+        assertThat(cursor.getLong(0)).isEqualTo(TIMESTAMP1);
+    }
+
+    @Test
+    public void getLastFullChargeTimestamp_noLastFullChargeTime_returns0() throws Exception {
+        mBatteryEventDao.clearAll();
+        mBatteryEventDao.insert(BatteryEventEntity.newBuilder()
+                .setTimestamp(TIMESTAMP2)
+                .setBatteryEventType(4)
+                .setBatteryLevel(96)
+                .build());
+
+        final Cursor cursor = mBatteryEventDao.getLastFullChargeTimestamp();
+
+        assertThat(cursor.getCount()).isEqualTo(1);
+        cursor.moveToFirst();
+        assertThat(cursor.getLong(0)).isEqualTo(0L);
+    }
+
+    @Test
+    public void getAllAfter_normalFlow_returnExpectedResult() {
         mBatteryEventDao.insert(BatteryEventEntity.newBuilder()
                 .setTimestamp(100L)
                 .setBatteryEventType(1)
@@ -64,17 +109,44 @@
                 .setBatteryLevel(88)
                 .build());
 
-        final Cursor cursor = mBatteryEventDao.getAllAfter(160L);
+        final Cursor cursor = mBatteryEventDao.getAllAfter(160L, List.of(1, 2));
         assertThat(cursor.getCount()).isEqualTo(1);
         cursor.moveToFirst();
-        assertThat(cursor.getLong(cursor.getColumnIndex(BatteryEventEntity.KEY_TIMESTAMP)))
+        assertThat(cursor.getLong(cursor.getColumnIndex(KEY_TIMESTAMP)))
                 .isEqualTo(200L);
-        assertThat(cursor.getInt(cursor.getColumnIndex(BatteryEventEntity.KEY_BATTERY_EVENT_TYPE)))
+        assertThat(cursor.getInt(cursor.getColumnIndex(KEY_BATTERY_EVENT_TYPE)))
                 .isEqualTo(2);
-        assertThat(cursor.getInt(cursor.getColumnIndex(BatteryEventEntity.KEY_BATTERY_LEVEL)))
+        assertThat(cursor.getInt(cursor.getColumnIndex(KEY_BATTERY_LEVEL)))
                 .isEqualTo(88);
 
         mBatteryEventDao.clearAll();
         assertThat(mBatteryEventDao.getAll()).isEmpty();
     }
+
+    @Test
+    public void getAllAfter_filterBatteryTypes_returnExpectedResult() {
+        mBatteryEventDao.insert(BatteryEventEntity.newBuilder()
+                .setTimestamp(100L)
+                .setBatteryEventType(1)
+                .setBatteryLevel(66)
+                .build());
+        mBatteryEventDao.insert(BatteryEventEntity.newBuilder()
+                .setTimestamp(200L)
+                .setBatteryEventType(2)
+                .setBatteryLevel(88)
+                .build());
+
+        final Cursor cursor = mBatteryEventDao.getAllAfter(0L, List.of(1));
+        assertThat(cursor.getCount()).isEqualTo(1);
+        cursor.moveToFirst();
+        assertThat(cursor.getLong(cursor.getColumnIndex(KEY_TIMESTAMP)))
+                .isEqualTo(100L);
+        assertThat(cursor.getInt(cursor.getColumnIndex(KEY_BATTERY_EVENT_TYPE)))
+                .isEqualTo(1);
+        assertThat(cursor.getInt(cursor.getColumnIndex(KEY_BATTERY_LEVEL)))
+                .isEqualTo(66);
+
+        mBatteryEventDao.clearAll();
+        assertThat(mBatteryEventDao.getAll()).isEmpty();
+    }
 }
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/db/BatteryStateDaoTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/db/BatteryStateDaoTest.java
index 57cf648..b3dba4e 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/db/BatteryStateDaoTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/db/BatteryStateDaoTest.java
@@ -37,9 +37,10 @@
 @RunWith(RobolectricTestRunner.class)
 public final class BatteryStateDaoTest {
     private static final int CURSOR_COLUMN_SIZE = 9;
-    private static final long TIMESTAMP1 = System.currentTimeMillis();
-    private static final long TIMESTAMP2 = System.currentTimeMillis() + 2;
-    private static final long TIMESTAMP3 = System.currentTimeMillis() + 4;
+    private static final long CURRENT = System.currentTimeMillis();
+    private static final long TIMESTAMP1 = CURRENT;
+    private static final long TIMESTAMP2 = CURRENT + 2;
+    private static final long TIMESTAMP3 = CURRENT + 4;
     private static final String PACKAGE_NAME1 = "com.android.apps.settings";
     private static final String PACKAGE_NAME2 = "com.android.apps.calendar";
     private static final String PACKAGE_NAME3 = "com.android.apps.gmail";
@@ -67,7 +68,7 @@
     }
 
     @Test
-    public void batteryStateDao_insertAll() throws Exception {
+    public void insertAll_normalFlow_expectedBehavior() throws Exception {
         final List<BatteryState> states = mBatteryStateDao.getAllAfter(TIMESTAMP1);
         assertThat(states).hasSize(2);
         // Verifies the queried battery states.
@@ -76,8 +77,26 @@
     }
 
     @Test
-    public void batteryStateDao_getCursorSinceLastFullCharge() throws Exception {
-        final Cursor cursor1 = mBatteryStateDao.getCursorSinceLastFullCharge(TIMESTAMP1);
+    public void getLatestTimestamp_normalFlow_expectedBehavior() throws Exception {
+        final Cursor cursor1 = mBatteryStateDao.getLatestTimestampBefore(TIMESTAMP1 - 1);
+        assertThat(cursor1.getCount()).isEqualTo(1);
+        cursor1.moveToFirst();
+        assertThat(cursor1.getLong(0)).isEqualTo(0L);
+
+        final Cursor cursor2 = mBatteryStateDao.getLatestTimestampBefore(TIMESTAMP2);
+        assertThat(cursor2.getCount()).isEqualTo(1);
+        cursor2.moveToFirst();
+        assertThat(cursor2.getLong(0)).isEqualTo(TIMESTAMP2);
+
+        final Cursor cursor3 = mBatteryStateDao.getLatestTimestampBefore(TIMESTAMP3 + 1);
+        assertThat(cursor3.getCount()).isEqualTo(1);
+        cursor3.moveToFirst();
+        assertThat(cursor3.getLong(0)).isEqualTo(TIMESTAMP3);
+    }
+
+    @Test
+    public void getBatteryStatesAfter_normalFlow_expectedBehavior() throws Exception {
+        final Cursor cursor1 = mBatteryStateDao.getBatteryStatesAfter(TIMESTAMP1);
         assertThat(cursor1.getCount()).isEqualTo(3);
         assertThat(cursor1.getColumnCount()).isEqualTo(CURSOR_COLUMN_SIZE);
         // Verifies the queried first battery state.
@@ -90,7 +109,7 @@
         cursor1.moveToNext();
         assertThat(cursor1.getString(3 /*packageName*/)).isEqualTo(PACKAGE_NAME3);
 
-        final Cursor cursor2 = mBatteryStateDao.getCursorSinceLastFullCharge(TIMESTAMP3);
+        final Cursor cursor2 = mBatteryStateDao.getBatteryStatesAfter(TIMESTAMP3);
         assertThat(cursor2.getCount()).isEqualTo(1);
         assertThat(cursor2.getColumnCount()).isEqualTo(CURSOR_COLUMN_SIZE);
         // Verifies the queried first battery state.
@@ -99,25 +118,7 @@
     }
 
     @Test
-    public void batteryStateDao_getCursorSinceLastFullCharge_noFullChargeData_returnSevenDaysData()
-            throws Exception {
-        mBatteryStateDao.clearAll();
-        BatteryTestUtils.insertDataToBatteryStateTable(mContext, TIMESTAMP3, PACKAGE_NAME3);
-        BatteryTestUtils.insertDataToBatteryStateTable(mContext, TIMESTAMP2, PACKAGE_NAME2);
-        BatteryTestUtils.insertDataToBatteryStateTable(mContext, TIMESTAMP1, PACKAGE_NAME1);
-        final Cursor cursor = mBatteryStateDao.getCursorSinceLastFullCharge(TIMESTAMP2);
-        assertThat(cursor.getCount()).isEqualTo(2);
-        assertThat(cursor.getColumnCount()).isEqualTo(CURSOR_COLUMN_SIZE);
-        // Verifies the queried first battery state.
-        cursor.moveToFirst();
-        assertThat(cursor.getString(3 /*packageName*/)).isEqualTo(PACKAGE_NAME2);
-        // Verifies the queried third battery state.
-        cursor.moveToNext();
-        assertThat(cursor.getString(3 /*packageName*/)).isEqualTo(PACKAGE_NAME3);
-    }
-
-    @Test
-    public void batteryStateDao_clearAllBefore() throws Exception {
+    public void clearAllBefore_normalFlow_expectedBehavior() throws Exception {
         mBatteryStateDao.clearAllBefore(TIMESTAMP2);
 
         final List<BatteryState> states = mBatteryStateDao.getAllAfter(0);
@@ -127,20 +128,20 @@
     }
 
     @Test
-    public void batteryStateDao_clearAll() throws Exception {
+    public void clearAll_normalFlow_expectedBehavior() throws Exception {
         assertThat(mBatteryStateDao.getAllAfter(0)).hasSize(3);
         mBatteryStateDao.clearAll();
         assertThat(mBatteryStateDao.getAllAfter(0)).isEmpty();
     }
 
     @Test
-    public void getInstance_createNewInstance() throws Exception {
+    public void getInstance_createNewInstance_returnsExpectedResult() throws Exception {
         BatteryStateDatabase.setBatteryStateDatabase(/*database=*/ null);
         assertThat(BatteryStateDatabase.getInstance(mContext)).isNotNull();
     }
 
     @Test
-    public void getDistinctTimestampCount_returnsExpectedResult() {
+    public void getDistinctTimestampCount_normalFlow_returnsExpectedResult() {
         assertThat(mBatteryStateDao.getDistinctTimestampCount(/*timestamp=*/ 0))
                 .isEqualTo(3);
         assertThat(mBatteryStateDao.getDistinctTimestampCount(TIMESTAMP1))
@@ -148,7 +149,7 @@
     }
 
     @Test
-    public void getDistinctTimestamps_returnsExpectedResult() {
+    public void getDistinctTimestamps_normalFlow_returnsExpectedResult() {
         final List<Long> timestamps =
                 mBatteryStateDao.getDistinctTimestamps(/*timestamp=*/ 0);
 
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/db/BatteryUsageSlotDaoTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/db/BatteryUsageSlotDaoTest.java
new file mode 100644
index 0000000..6f73954
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/db/BatteryUsageSlotDaoTest.java
@@ -0,0 +1,110 @@
+/*
+ * 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.batteryusage.db;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.content.Context;
+import android.database.Cursor;
+
+import androidx.test.core.app.ApplicationProvider;
+
+import com.android.settings.testutils.BatteryTestUtils;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
+
+import java.util.List;
+
+/** Tests for {@link BatteryUsageSlotDao}. */
+@RunWith(RobolectricTestRunner.class)
+public final class BatteryUsageSlotDaoTest {
+    private static final int CURSOR_COLUMN_SIZE = 3;
+    private static final long CURRENT = System.currentTimeMillis();
+    private static final long TIMESTAMP1 = CURRENT;
+    private static final long TIMESTAMP2 = CURRENT + 2;
+    private static final String BATTERY_USAGE_SLOT_STRING1 = "BATTERY_USAGE_SLOT_STRING1";
+    private static final String BATTERY_USAGE_SLOT_STRING2 = "BATTERY_USAGE_SLOT_STRING2";
+
+    private Context mContext;
+    private BatteryStateDatabase mDatabase;
+    private BatteryUsageSlotDao mBatteryUsageSlotDao;
+
+    @Before
+    public void setUp() {
+        mContext = ApplicationProvider.getApplicationContext();
+        mDatabase = BatteryTestUtils.setUpBatteryStateDatabase(mContext);
+        mBatteryUsageSlotDao = mDatabase.batteryUsageSlotDao();
+        mBatteryUsageSlotDao.insert(
+                new BatteryUsageSlotEntity(TIMESTAMP1, BATTERY_USAGE_SLOT_STRING1));
+        mBatteryUsageSlotDao.insert(
+                new BatteryUsageSlotEntity(TIMESTAMP2, BATTERY_USAGE_SLOT_STRING2));
+    }
+
+    @After
+    public void closeDb() {
+        mDatabase.close();
+        BatteryStateDatabase.setBatteryStateDatabase(/*database=*/ null);
+    }
+
+    @Test
+    public void getAll_normalFlow_expectedBehavior() throws Exception {
+        final List<BatteryUsageSlotEntity> entities = mBatteryUsageSlotDao.getAll();
+        assertThat(entities).hasSize(2);
+        assertThat(entities.get(0).timestamp).isEqualTo(TIMESTAMP1);
+        assertThat(entities.get(0).batteryUsageSlot).isEqualTo(BATTERY_USAGE_SLOT_STRING1);
+        assertThat(entities.get(1).timestamp).isEqualTo(TIMESTAMP2);
+        assertThat(entities.get(1).batteryUsageSlot).isEqualTo(BATTERY_USAGE_SLOT_STRING2);
+    }
+
+    @Test
+    public void getAllAfter_normalFlow_expectedBehavior() throws Exception {
+        final Cursor cursor1 = mBatteryUsageSlotDao.getAllAfter(TIMESTAMP1);
+        assertThat(cursor1.getCount()).isEqualTo(2);
+        assertThat(cursor1.getColumnCount()).isEqualTo(CURSOR_COLUMN_SIZE);
+        cursor1.moveToFirst();
+        assertThat(cursor1.getLong(1 /*timestamp*/)).isEqualTo(TIMESTAMP1);
+        cursor1.moveToNext();
+        assertThat(cursor1.getLong(1 /*timestamp*/)).isEqualTo(TIMESTAMP2);
+
+        final Cursor cursor2 = mBatteryUsageSlotDao.getAllAfter(TIMESTAMP1 + 1);
+        assertThat(cursor2.getCount()).isEqualTo(1);
+        assertThat(cursor2.getColumnCount()).isEqualTo(CURSOR_COLUMN_SIZE);
+        cursor2.moveToFirst();
+        assertThat(cursor2.getLong(1 /*timestamp*/)).isEqualTo(TIMESTAMP2);
+    }
+
+    @Test
+    public void clearAllBefore_normalFlow_expectedBehavior() throws Exception {
+        mBatteryUsageSlotDao.clearAllBefore(TIMESTAMP1);
+
+        final List<BatteryUsageSlotEntity> entities = mBatteryUsageSlotDao.getAll();
+        assertThat(entities).hasSize(1);
+        assertThat(entities.get(0).timestamp).isEqualTo(TIMESTAMP2);
+        assertThat(entities.get(0).batteryUsageSlot).isEqualTo(BATTERY_USAGE_SLOT_STRING2);
+    }
+
+    @Test
+    public void clearAll_normalFlow_expectedBehavior() throws Exception {
+        mBatteryUsageSlotDao.clearAll();
+
+        assertThat(mBatteryUsageSlotDao.getAll()).isEmpty();
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/db/BatteryUsageSlotEntityTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/db/BatteryUsageSlotEntityTest.java
new file mode 100644
index 0000000..ef276eb
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/db/BatteryUsageSlotEntityTest.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2023 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.batteryusage.db;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
+
+/** Tests for {@link BatteryUsageSlotEntity}. */
+@RunWith(RobolectricTestRunner.class)
+public final class BatteryUsageSlotEntityTest {
+
+    @Test
+    public void testBuilder_returnsExpectedResult() {
+        final long timestamp = 10001L;
+        final String batteryUsageSlotString = "batteryUsageSlotString";
+
+        BatteryUsageSlotEntity entity = BatteryUsageSlotEntity
+                .newBuilder()
+                .setTimestamp(timestamp)
+                .setBatteryUsageSlot(batteryUsageSlotString)
+                .build();
+
+        // Verifies the app relative information.
+        assertThat(entity.timestamp).isEqualTo(timestamp);
+        assertThat(entity.batteryUsageSlot).isEqualTo(batteryUsageSlotString);
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/gestures/BackGestureIndicatorViewTest.java b/tests/robotests/src/com/android/settings/gestures/BackGestureIndicatorViewTest.java
index 8d43aaa..527ea44 100644
--- a/tests/robotests/src/com/android/settings/gestures/BackGestureIndicatorViewTest.java
+++ b/tests/robotests/src/com/android/settings/gestures/BackGestureIndicatorViewTest.java
@@ -29,8 +29,10 @@
 import org.mockito.MockitoAnnotations;
 import org.robolectric.RobolectricTestRunner;
 import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.LooperMode;
 
 @RunWith(RobolectricTestRunner.class)
+@LooperMode(LooperMode.Mode.LEGACY)
 public class BackGestureIndicatorViewTest {
 
     private Context mContext;
diff --git a/tests/robotests/src/com/android/settings/homepage/SettingsHomepageActivityTest.java b/tests/robotests/src/com/android/settings/homepage/SettingsHomepageActivityTest.java
index 2c16db5..6bb8cd6 100644
--- a/tests/robotests/src/com/android/settings/homepage/SettingsHomepageActivityTest.java
+++ b/tests/robotests/src/com/android/settings/homepage/SettingsHomepageActivityTest.java
@@ -48,6 +48,7 @@
 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.ShadowActivityManager;
 import com.android.settings.testutils.shadow.ShadowPasswordUtils;
 import com.android.settings.testutils.shadow.ShadowUserManager;
 import com.android.settingslib.core.lifecycle.HideNonSystemOverlayMixin;
@@ -67,12 +68,14 @@
 import org.robolectric.annotation.Implementation;
 import org.robolectric.annotation.Implements;
 import org.robolectric.shadow.api.Shadow;
-import org.robolectric.shadows.ShadowActivityManager;
 import org.robolectric.util.ReflectionHelpers;
 
 @RunWith(RobolectricTestRunner.class)
-@Config(shadows = {ShadowUserManager.class,
-        SettingsHomepageActivityTest.ShadowSuggestionFeatureProviderImpl.class})
+@Config(shadows = {
+        ShadowUserManager.class,
+        SettingsHomepageActivityTest.ShadowSuggestionFeatureProviderImpl.class,
+        ShadowActivityManager.class,
+})
 public class SettingsHomepageActivityTest {
 
     @Before
diff --git a/tests/robotests/src/com/android/settings/homepage/contextualcards/conditional/AbnormalRingerConditionControllerBaseTest.java b/tests/robotests/src/com/android/settings/homepage/contextualcards/conditional/AbnormalRingerConditionControllerBaseTest.java
index 5d5070b..b75240c 100644
--- a/tests/robotests/src/com/android/settings/homepage/contextualcards/conditional/AbnormalRingerConditionControllerBaseTest.java
+++ b/tests/robotests/src/com/android/settings/homepage/contextualcards/conditional/AbnormalRingerConditionControllerBaseTest.java
@@ -32,8 +32,10 @@
 import org.mockito.MockitoAnnotations;
 import org.robolectric.RobolectricTestRunner;
 import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.LooperMode;
 
 @RunWith(RobolectricTestRunner.class)
+@LooperMode(LooperMode.Mode.LEGACY)
 public class AbnormalRingerConditionControllerBaseTest {
 
     @Mock
diff --git a/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/DarkThemeSliceTest.java b/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/DarkThemeSliceTest.java
index 3be65dc..f5f3d59 100644
--- a/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/DarkThemeSliceTest.java
+++ b/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/DarkThemeSliceTest.java
@@ -48,8 +48,12 @@
 import org.mockito.MockitoAnnotations;
 import org.robolectric.RobolectricTestRunner;
 import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
 
 @RunWith(RobolectricTestRunner.class)
+@Config(shadows = {
+        com.android.settings.testutils.shadow.ShadowDrawable.class,
+})
 public class DarkThemeSliceTest {
     @Mock
     private BatteryManager mBatteryManager;
diff --git a/tests/robotests/src/com/android/settings/inputmethod/InputMethodAndSubtypeEnablerTest.java b/tests/robotests/src/com/android/settings/inputmethod/InputMethodAndSubtypeEnablerTest.java
index ee5451a..5d67955 100644
--- a/tests/robotests/src/com/android/settings/inputmethod/InputMethodAndSubtypeEnablerTest.java
+++ b/tests/robotests/src/com/android/settings/inputmethod/InputMethodAndSubtypeEnablerTest.java
@@ -35,8 +35,12 @@
 import org.mockito.MockitoAnnotations;
 import org.robolectric.Robolectric;
 import org.robolectric.RobolectricTestRunner;
+import org.robolectric.annotation.Config;
 
 @RunWith(RobolectricTestRunner.class)
+@Config(shadows = {
+        com.android.settings.testutils.shadow.ShadowFragment.class,
+})
 public class InputMethodAndSubtypeEnablerTest {
 
     private FragmentActivity mActivity;
diff --git a/tests/robotests/src/com/android/settings/inputmethod/KeyboardSettingsPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/inputmethod/KeyboardSettingsPreferenceControllerTest.java
index 1bf61a4..4806b8a 100644
--- a/tests/robotests/src/com/android/settings/inputmethod/KeyboardSettingsPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/inputmethod/KeyboardSettingsPreferenceControllerTest.java
@@ -44,12 +44,16 @@
 import org.mockito.junit.MockitoJUnit;
 import org.mockito.junit.MockitoRule;
 import org.robolectric.RobolectricTestRunner;
+import org.robolectric.annotation.Config;
 
 import java.util.ArrayList;
 import java.util.List;
 
 /** Tests for {@link KeyboardSettingsPreferenceController} */
 @RunWith(RobolectricTestRunner.class)
+@Config(shadows = {
+        com.android.settings.testutils.shadow.ShadowInputManager.class,
+})
 public class KeyboardSettingsPreferenceControllerTest {
 
     @Rule
diff --git a/tests/robotests/src/com/android/settings/inputmethod/TrackpadBottomPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/inputmethod/TrackpadBottomPreferenceControllerTest.java
index 3c51cf3..fa73768 100644
--- a/tests/robotests/src/com/android/settings/inputmethod/TrackpadBottomPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/inputmethod/TrackpadBottomPreferenceControllerTest.java
@@ -40,9 +40,13 @@
 import org.mockito.junit.MockitoJUnit;
 import org.mockito.junit.MockitoRule;
 import org.robolectric.RobolectricTestRunner;
+import org.robolectric.annotation.Config;
 
 /** Tests for {@link TrackpadBottomPreferenceController} */
 @RunWith(RobolectricTestRunner.class)
+@Config(shadows = {
+        com.android.settings.testutils.shadow.ShadowSystemSettings.class,
+})
 public class TrackpadBottomPreferenceControllerTest {
     @Rule
     public MockitoRule rule = MockitoJUnit.rule();
diff --git a/tests/robotests/src/com/android/settings/inputmethod/TrackpadPointerSpeedPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/inputmethod/TrackpadPointerSpeedPreferenceControllerTest.java
index 1cfda12..8449dba 100644
--- a/tests/robotests/src/com/android/settings/inputmethod/TrackpadPointerSpeedPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/inputmethod/TrackpadPointerSpeedPreferenceControllerTest.java
@@ -40,9 +40,13 @@
 import org.mockito.junit.MockitoJUnit;
 import org.mockito.junit.MockitoRule;
 import org.robolectric.RobolectricTestRunner;
+import org.robolectric.annotation.Config;
 
 /** Tests for {@link TrackpadPointerSpeedPreferenceController} */
 @RunWith(RobolectricTestRunner.class)
+@Config(shadows = {
+        com.android.settings.testutils.shadow.ShadowSystemSettings.class,
+})
 public class TrackpadPointerSpeedPreferenceControllerTest {
     @Rule
     public MockitoRule rule = MockitoJUnit.rule();
diff --git a/tests/robotests/src/com/android/settings/inputmethod/TrackpadReverseScrollingPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/inputmethod/TrackpadReverseScrollingPreferenceControllerTest.java
index e74261e..f545c38 100644
--- a/tests/robotests/src/com/android/settings/inputmethod/TrackpadReverseScrollingPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/inputmethod/TrackpadReverseScrollingPreferenceControllerTest.java
@@ -40,9 +40,13 @@
 import org.mockito.junit.MockitoJUnit;
 import org.mockito.junit.MockitoRule;
 import org.robolectric.RobolectricTestRunner;
+import org.robolectric.annotation.Config;
 
 /** Tests for {@link TrackpadReverseScrollingPreferenceController} */
 @RunWith(RobolectricTestRunner.class)
+@Config(shadows = {
+        com.android.settings.testutils.shadow.ShadowSystemSettings.class,
+})
 public class TrackpadReverseScrollingPreferenceControllerTest {
     @Rule
     public MockitoRule rule = MockitoJUnit.rule();
diff --git a/tests/robotests/src/com/android/settings/inputmethod/TrackpadTapToClickPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/inputmethod/TrackpadTapToClickPreferenceControllerTest.java
index 3784cc7..8e9d026 100644
--- a/tests/robotests/src/com/android/settings/inputmethod/TrackpadTapToClickPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/inputmethod/TrackpadTapToClickPreferenceControllerTest.java
@@ -40,9 +40,13 @@
 import org.mockito.junit.MockitoJUnit;
 import org.mockito.junit.MockitoRule;
 import org.robolectric.RobolectricTestRunner;
+import org.robolectric.annotation.Config;
 
 /** Tests for {@link TrackpadTapToClickPreferenceController} */
 @RunWith(RobolectricTestRunner.class)
+@Config(shadows = {
+        com.android.settings.testutils.shadow.ShadowSystemSettings.class,
+})
 public class TrackpadTapToClickPreferenceControllerTest {
     @Rule
     public MockitoRule rule = MockitoJUnit.rule();
diff --git a/tests/robotests/src/com/android/settings/localepicker/LocaleDialogFragmentTest.java b/tests/robotests/src/com/android/settings/localepicker/LocaleDialogFragmentTest.java
index 57f2b01..bb22012 100644
--- a/tests/robotests/src/com/android/settings/localepicker/LocaleDialogFragmentTest.java
+++ b/tests/robotests/src/com/android/settings/localepicker/LocaleDialogFragmentTest.java
@@ -37,7 +37,6 @@
 import com.android.internal.app.LocaleStore;
 import com.android.settings.testutils.shadow.ShadowAlertDialogCompat;
 import com.android.settings.utils.ActivityControllerWrapper;
-import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -46,13 +45,14 @@
 import org.mockito.MockitoAnnotations;
 import org.robolectric.Robolectric;
 import org.robolectric.RobolectricTestRunner;
-import org.robolectric.RuntimeEnvironment;
 import org.robolectric.annotation.Config;
+import org.robolectric.annotation.LooperMode;
 
 import java.util.Locale;
 
 @RunWith(RobolectricTestRunner.class)
 @Config(shadows = {ShadowAlertDialogCompat.class})
+@LooperMode(LooperMode.Mode.LEGACY)
 public class LocaleDialogFragmentTest {
 
     @Mock
diff --git a/tests/robotests/src/com/android/settings/localepicker/LocaleListEditorTest.java b/tests/robotests/src/com/android/settings/localepicker/LocaleListEditorTest.java
index fb7d41a..df7fa40 100644
--- a/tests/robotests/src/com/android/settings/localepicker/LocaleListEditorTest.java
+++ b/tests/robotests/src/com/android/settings/localepicker/LocaleListEditorTest.java
@@ -72,6 +72,7 @@
 import org.robolectric.RobolectricTestRunner;
 import org.robolectric.RuntimeEnvironment;
 import org.robolectric.annotation.Config;
+import org.robolectric.annotation.LooperMode;
 import org.robolectric.util.ReflectionHelpers;
 
 import java.util.ArrayList;
@@ -79,7 +80,12 @@
 import java.util.Locale;
 
 @RunWith(RobolectricTestRunner.class)
-@Config(shadows = {ShadowAlertDialogCompat.class, ShadowActivityManager.class})
+@Config(shadows = {
+        ShadowAlertDialogCompat.class,
+        ShadowActivityManager.class,
+        com.android.settings.testutils.shadow.ShadowFragment.class,
+})
+@LooperMode(LooperMode.Mode.LEGACY)
 public class LocaleListEditorTest {
 
     private static final String ARG_DIALOG_TYPE = "arg_dialog_type";
diff --git a/tests/robotests/src/com/android/settings/location/LocationSettingsTest.java b/tests/robotests/src/com/android/settings/location/LocationSettingsTest.java
index aae8cec..a8a59ff 100644
--- a/tests/robotests/src/com/android/settings/location/LocationSettingsTest.java
+++ b/tests/robotests/src/com/android/settings/location/LocationSettingsTest.java
@@ -34,8 +34,12 @@
 import org.mockito.MockitoAnnotations;
 import org.robolectric.RobolectricTestRunner;
 import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
 
 @RunWith(RobolectricTestRunner.class)
+@Config(shadows = {
+        com.android.settings.testutils.shadow.ShadowFragment.class,
+})
 public class LocationSettingsTest {
 
     @Mock
diff --git a/tests/robotests/src/com/android/settings/network/MobileDataEnabledListenerTest.java b/tests/robotests/src/com/android/settings/network/MobileDataEnabledListenerTest.java
index 0824680..b232009 100644
--- a/tests/robotests/src/com/android/settings/network/MobileDataEnabledListenerTest.java
+++ b/tests/robotests/src/com/android/settings/network/MobileDataEnabledListenerTest.java
@@ -18,6 +18,7 @@
 
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.verify;
+import static org.robolectric.shadows.ShadowLooper.shadowMainLooper;
 
 import android.content.Context;
 import android.net.Uri;
@@ -30,8 +31,10 @@
 import org.mockito.MockitoAnnotations;
 import org.robolectric.RobolectricTestRunner;
 import org.robolectric.RuntimeEnvironment;
+// import org.robolectric.annotation.LooperMode;
 
 @RunWith(RobolectricTestRunner.class)
+// @LooperMode(LooperMode.Mode.LEGACY)
 public class MobileDataEnabledListenerTest {
     private static final int SUB_ID_ONE = 111;
     private static final int SUB_ID_TWO = 222;
@@ -54,6 +57,7 @@
         mListener.start(SUB_ID_ONE);
         final Uri uri = Settings.Global.getUriFor(Settings.Global.MOBILE_DATA + SUB_ID_ONE);
         mContext.getContentResolver().notifyChange(uri, null);
+        shadowMainLooper().idle();
         verify(mClient).onMobileDataEnabledChange();
     }
 
@@ -63,6 +67,7 @@
         mListener.stop();
         final Uri uri = Settings.Global.getUriFor(Settings.Global.MOBILE_DATA + SUB_ID_ONE);
         mContext.getContentResolver().notifyChange(uri, null);
+        shadowMainLooper().idle();
         verify(mClient, never()).onMobileDataEnabledChange();
     }
 
@@ -73,6 +78,7 @@
         mListener.start(SUB_ID_TWO);
         final Uri uri = Settings.Global.getUriFor(Settings.Global.MOBILE_DATA + SUB_ID_TWO);
         mContext.getContentResolver().notifyChange(uri, null);
+        shadowMainLooper().idle();
         verify(mClient).onMobileDataEnabledChange();
     }
 }
diff --git a/tests/robotests/src/com/android/settings/network/NetworkProviderSettingsTest.java b/tests/robotests/src/com/android/settings/network/NetworkProviderSettingsTest.java
index ef2013c..8a99099 100644
--- a/tests/robotests/src/com/android/settings/network/NetworkProviderSettingsTest.java
+++ b/tests/robotests/src/com/android/settings/network/NetworkProviderSettingsTest.java
@@ -99,6 +99,9 @@
 import java.util.List;
 
 @RunWith(RobolectricTestRunner.class)
+@Config(shadows = {
+        com.android.settings.testutils.shadow.ShadowFragment.class,
+})
 public class NetworkProviderSettingsTest {
 
     private static final int XML_RES = R.xml.wifi_tether_settings;
diff --git a/tests/robotests/src/com/android/settings/network/SubscriptionsChangeListenerTest.java b/tests/robotests/src/com/android/settings/network/SubscriptionsChangeListenerTest.java
index d075655..d805ee6 100644
--- a/tests/robotests/src/com/android/settings/network/SubscriptionsChangeListenerTest.java
+++ b/tests/robotests/src/com/android/settings/network/SubscriptionsChangeListenerTest.java
@@ -20,12 +20,14 @@
 
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.Mockito.atLeastOnce;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
+import static org.robolectric.shadows.ShadowLooper.shadowMainLooper;
 
 import android.content.BroadcastReceiver;
 import android.content.ContentResolver;
@@ -81,6 +83,7 @@
         final ContentResolver contentResolver = mock(ContentResolver.class);
         when(mContext.getContentResolver()).thenReturn(contentResolver);
         initListener(false);
+        shadowMainLooper().idle();
         verify(contentResolver, never()).registerContentObserver(any(Uri.class), anyBoolean(),
                 any(ContentObserver.class));
         verify(mSubscriptionManager, never()).addOnSubscriptionsChangedListener(any(), any());
@@ -93,6 +96,7 @@
         final ArgumentCaptor<SubscriptionManager.OnSubscriptionsChangedListener> captor =
                 ArgumentCaptor.forClass(SubscriptionManager.OnSubscriptionsChangedListener.class);
         verify(mSubscriptionManager).addOnSubscriptionsChangedListener(any(), captor.capture());
+        shadowMainLooper().idle();
         captor.getValue().onSubscriptionsChanged();
         verify(mClient).onSubscriptionsChanged();
     }
@@ -104,9 +108,11 @@
         mContext.sendStickyBroadcast(intent);
 
         initListener(true);
+        shadowMainLooper().idle();
         verify(mClient, never()).onSubscriptionsChanged();
 
         mContext.sendStickyBroadcast(intent);
+        shadowMainLooper().idle();
         verify(mClient, times(1)).onSubscriptionsChanged();
     }
 
@@ -115,8 +121,10 @@
         initListener(true);
         final ArgumentCaptor<BroadcastReceiver> broadcastReceiverCaptor =
                 ArgumentCaptor.forClass(BroadcastReceiver.class);
+        shadowMainLooper().idle();
         verify(mContext).registerReceiver(broadcastReceiverCaptor.capture(), any());
         broadcastReceiverCaptor.getValue().onReceive(mContext, null);
+        shadowMainLooper().idle();
         verify(mClient).onSubscriptionsChanged();
     }
 
@@ -125,7 +133,8 @@
         initListener(true);
         Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.AIRPLANE_MODE_ON, 1);
         mListener.onChange(false, mAirplaneModeUri);
-        verify(mClient).onAirplaneModeChanged(true);
+        shadowMainLooper().idle();
+        verify(mClient, atLeastOnce()).onAirplaneModeChanged(true);
         assertThat(mListener.isAirplaneModeOn()).isTrue();
     }
 
@@ -134,7 +143,8 @@
         initListener(true);
         Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.AIRPLANE_MODE_ON, 0);
         mListener.onChange(false, mAirplaneModeUri);
-        verify(mClient).onAirplaneModeChanged(false);
+        shadowMainLooper().idle();
+        verify(mClient, atLeastOnce()).onAirplaneModeChanged(false);
         assertThat(mListener.isAirplaneModeOn()).isFalse();
     }
 
diff --git a/tests/robotests/src/com/android/settings/network/TetherPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/network/TetherPreferenceControllerTest.java
index 54d616d..99869d8 100644
--- a/tests/robotests/src/com/android/settings/network/TetherPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/network/TetherPreferenceControllerTest.java
@@ -24,6 +24,7 @@
 import static org.mockito.Mockito.verifyNoInteractions;
 import static org.mockito.Mockito.verifyNoMoreInteractions;
 import static org.mockito.Mockito.when;
+import static org.robolectric.shadows.ShadowLooper.shadowMainLooper;
 
 import android.bluetooth.BluetoothAdapter;
 import android.bluetooth.BluetoothPan;
@@ -205,6 +206,7 @@
 
         context.sendBroadcast(new Intent(TetheringManager.ACTION_TETHER_STATE_CHANGED));
 
+        shadowMainLooper().idle();
         verify(mController).updateSummary();
     }
 }
diff --git a/tests/robotests/src/com/android/settings/network/TopLevelNetworkEntryPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/network/TopLevelNetworkEntryPreferenceControllerTest.java
index 43b961c..8e0c863 100644
--- a/tests/robotests/src/com/android/settings/network/TopLevelNetworkEntryPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/network/TopLevelNetworkEntryPreferenceControllerTest.java
@@ -29,6 +29,7 @@
 
 import com.android.settings.R;
 import com.android.settings.testutils.shadow.ShadowRestrictedLockUtilsInternal;
+import com.android.settings.testutils.shadow.ShadowUserManager;
 import com.android.settings.testutils.shadow.ShadowUtils;
 
 import org.junit.After;
@@ -39,13 +40,16 @@
 import org.mockito.MockitoAnnotations;
 import org.robolectric.RobolectricTestRunner;
 import org.robolectric.RuntimeEnvironment;
-import org.robolectric.Shadows;
 import org.robolectric.annotation.Config;
-import org.robolectric.shadows.ShadowUserManager;
+import org.robolectric.shadow.api.Shadow;
 import org.robolectric.util.ReflectionHelpers;
 
 @RunWith(RobolectricTestRunner.class)
-@Config(shadows = {ShadowRestrictedLockUtilsInternal.class, ShadowUtils.class})
+@Config(shadows = {
+        ShadowRestrictedLockUtilsInternal.class,
+        ShadowUtils.class,
+        ShadowUserManager.class,
+})
 public class TopLevelNetworkEntryPreferenceControllerTest {
 
     @Mock
@@ -58,7 +62,7 @@
     public void setUp() {
         MockitoAnnotations.initMocks(this);
         mContext = RuntimeEnvironment.application;
-        final ShadowUserManager um = Shadows.shadowOf(
+        final ShadowUserManager um = Shadow.extract(
                 RuntimeEnvironment.application.getSystemService(UserManager.class));
         um.setIsAdminUser(true);
 
diff --git a/tests/robotests/src/com/android/settings/network/apn/ApnEditorTest.java b/tests/robotests/src/com/android/settings/network/apn/ApnEditorTest.java
index 1006c32..d8895d5 100644
--- a/tests/robotests/src/com/android/settings/network/apn/ApnEditorTest.java
+++ b/tests/robotests/src/com/android/settings/network/apn/ApnEditorTest.java
@@ -54,7 +54,6 @@
 import com.android.settings.R;
 import com.android.settings.network.ProxySubscriptionManager;
 import com.android.settings.network.apn.ApnEditor.ApnData;
-import com.android.settings.testutils.shadow.ShadowFragment;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -69,6 +68,9 @@
 import org.robolectric.annotation.Config;
 
 @RunWith(RobolectricTestRunner.class)
+@Config(shadows = {
+        com.android.settings.testutils.shadow.ShadowFragment.class,
+})
 public class ApnEditorTest {
 
     private static final Object[] APN_DATA = {
@@ -497,7 +499,6 @@
     }
 
     @Test
-    @Config(shadows = ShadowFragment.class)
     public void onCreate_notAdminUser_shouldFinish() {
         doReturn(false).when(mUserManager).isAdminUser();
 
@@ -507,7 +508,6 @@
     }
 
     @Test
-    @Config(shadows = ShadowFragment.class)
     public void onCreate_hasUserRestriction_shouldFinish() {
         doReturn(true).when(mUserManager)
                 .hasUserRestriction(UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS);
@@ -518,7 +518,6 @@
     }
 
     @Test
-    @Config(shadows = ShadowFragment.class)
     public void onCreate_noAction_shouldFinishAndNoCrash() {
         ProxySubscriptionManager proxySubscriptionMgr = mock(ProxySubscriptionManager.class);
         mApnEditorUT.mProxySubscriptionMgr = proxySubscriptionMgr;
diff --git a/tests/robotests/src/com/android/settings/network/telephony/MobileNetworkSettingsTest.java b/tests/robotests/src/com/android/settings/network/telephony/MobileNetworkSettingsTest.java
index 3e219a4..297815b 100644
--- a/tests/robotests/src/com/android/settings/network/telephony/MobileNetworkSettingsTest.java
+++ b/tests/robotests/src/com/android/settings/network/telephony/MobileNetworkSettingsTest.java
@@ -58,7 +58,10 @@
 import java.util.List;
 
 @RunWith(RobolectricTestRunner.class)
-@Config(shadows = ShadowEntityHeaderController.class)
+@Config(shadows = {
+        ShadowEntityHeaderController.class,
+        com.android.settings.testutils.shadow.ShadowFragment.class,
+})
 public class MobileNetworkSettingsTest {
     @Mock
     private TelephonyManager mTelephonyManager;
diff --git a/tests/robotests/src/com/android/settings/network/tether/TetherSettingsTest.java b/tests/robotests/src/com/android/settings/network/tether/TetherSettingsTest.java
index 7fe1187..9269754 100644
--- a/tests/robotests/src/com/android/settings/network/tether/TetherSettingsTest.java
+++ b/tests/robotests/src/com/android/settings/network/tether/TetherSettingsTest.java
@@ -76,6 +76,9 @@
 import java.util.List;
 
 @RunWith(RobolectricTestRunner.class)
+@Config(shadows = {
+        com.android.settings.testutils.shadow.ShadowFragment.class,
+})
 public class TetherSettingsTest {
 
     private Context mContext;
diff --git a/tests/robotests/src/com/android/settings/notification/BubbleNotificationPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/BubbleNotificationPreferenceControllerTest.java
index 3cb3abf..b346b01 100644
--- a/tests/robotests/src/com/android/settings/notification/BubbleNotificationPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/notification/BubbleNotificationPreferenceControllerTest.java
@@ -35,6 +35,7 @@
 
 import androidx.preference.PreferenceScreen;
 
+import com.android.settings.testutils.shadow.ShadowActivityManager;
 import com.android.settingslib.testutils.shadow.ShadowInteractionJankMonitor;
 import com.android.settingslib.widget.MainSwitchPreference;
 
@@ -48,10 +49,12 @@
 import org.robolectric.RuntimeEnvironment;
 import org.robolectric.annotation.Config;
 import org.robolectric.shadow.api.Shadow;
-import org.robolectric.shadows.ShadowActivityManager;
 
 @RunWith(RobolectricTestRunner.class)
-@Config(shadows = {ShadowInteractionJankMonitor.class})
+@Config(shadows = {
+        ShadowInteractionJankMonitor.class,
+        ShadowActivityManager.class,
+})
 public class BubbleNotificationPreferenceControllerTest {
 
     private Context mContext;
diff --git a/tests/robotests/src/com/android/settings/notification/BubbleSummaryNotificationPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/BubbleSummaryNotificationPreferenceControllerTest.java
index 3b4e90f..e80fbc8 100644
--- a/tests/robotests/src/com/android/settings/notification/BubbleSummaryNotificationPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/notification/BubbleSummaryNotificationPreferenceControllerTest.java
@@ -32,16 +32,20 @@
 import androidx.preference.Preference;
 
 import com.android.settings.R;
+import com.android.settings.testutils.shadow.ShadowActivityManager;
 
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.robolectric.RobolectricTestRunner;
 import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
 import org.robolectric.shadow.api.Shadow;
-import org.robolectric.shadows.ShadowActivityManager;
 
 @RunWith(RobolectricTestRunner.class)
+@Config(shadows = {
+        ShadowActivityManager.class,
+})
 public class BubbleSummaryNotificationPreferenceControllerTest {
 
     private Context mContext;
diff --git a/tests/robotests/src/com/android/settings/notification/ChargingSoundPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/ChargingSoundPreferenceControllerTest.java
index aac4a0b..1c864c9 100644
--- a/tests/robotests/src/com/android/settings/notification/ChargingSoundPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/notification/ChargingSoundPreferenceControllerTest.java
@@ -41,6 +41,9 @@
 import org.robolectric.annotation.Config;
 
 @RunWith(RobolectricTestRunner.class)
+@Config(shadows = {
+        com.android.settings.testutils.shadow.ShadowFragment.class,
+})
 public class ChargingSoundPreferenceControllerTest {
 
     @Mock
diff --git a/tests/robotests/src/com/android/settings/notification/DialPadTonePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/DialPadTonePreferenceControllerTest.java
index fa95e52..c6511ef 100644
--- a/tests/robotests/src/com/android/settings/notification/DialPadTonePreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/notification/DialPadTonePreferenceControllerTest.java
@@ -37,8 +37,12 @@
 import org.mockito.MockitoAnnotations;
 import org.robolectric.RobolectricTestRunner;
 import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
 
 @RunWith(RobolectricTestRunner.class)
+@Config(shadows = {
+        com.android.settings.testutils.shadow.ShadowFragment.class,
+})
 public class DialPadTonePreferenceControllerTest {
 
     @Mock
diff --git a/tests/robotests/src/com/android/settings/notification/DockAudioMediaPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/DockAudioMediaPreferenceControllerTest.java
index 5e4efd0..097aed7 100644
--- a/tests/robotests/src/com/android/settings/notification/DockAudioMediaPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/notification/DockAudioMediaPreferenceControllerTest.java
@@ -45,8 +45,12 @@
 import org.mockito.MockitoAnnotations;
 import org.robolectric.RobolectricTestRunner;
 import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
 
 @RunWith(RobolectricTestRunner.class)
+@Config(shadows = {
+        com.android.settings.testutils.shadow.ShadowFragment.class,
+})
 public class DockAudioMediaPreferenceControllerTest {
 
     @Mock
diff --git a/tests/robotests/src/com/android/settings/notification/DockingSoundPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/DockingSoundPreferenceControllerTest.java
index 0cfc6b7..7aeddfc 100644
--- a/tests/robotests/src/com/android/settings/notification/DockingSoundPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/notification/DockingSoundPreferenceControllerTest.java
@@ -39,8 +39,12 @@
 import org.mockito.MockitoAnnotations;
 import org.robolectric.RobolectricTestRunner;
 import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
 
 @RunWith(RobolectricTestRunner.class)
+@Config(shadows = {
+        com.android.settings.testutils.shadow.ShadowFragment.class,
+})
 public class DockingSoundPreferenceControllerTest {
 
     @Mock
diff --git a/tests/robotests/src/com/android/settings/notification/EmergencyTonePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/EmergencyTonePreferenceControllerTest.java
index 49776de..bae7c4c 100644
--- a/tests/robotests/src/com/android/settings/notification/EmergencyTonePreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/notification/EmergencyTonePreferenceControllerTest.java
@@ -37,8 +37,12 @@
 import org.mockito.MockitoAnnotations;
 import org.robolectric.RobolectricTestRunner;
 import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
 
 @RunWith(RobolectricTestRunner.class)
+@Config(shadows = {
+        com.android.settings.testutils.shadow.ShadowFragment.class,
+})
 public class EmergencyTonePreferenceControllerTest {
 
     @Mock
diff --git a/tests/robotests/src/com/android/settings/notification/NotificationAccessSettingsTest.java b/tests/robotests/src/com/android/settings/notification/NotificationAccessSettingsTest.java
index e644c29..d19f17d 100644
--- a/tests/robotests/src/com/android/settings/notification/NotificationAccessSettingsTest.java
+++ b/tests/robotests/src/com/android/settings/notification/NotificationAccessSettingsTest.java
@@ -53,11 +53,13 @@
 import org.robolectric.RobolectricTestRunner;
 import org.robolectric.RuntimeEnvironment;
 import org.robolectric.annotation.Config;
+import org.robolectric.annotation.LooperMode;
 import org.robolectric.shadows.ShadowApplication;
 
 import java.util.ArrayList;
 
 @RunWith(RobolectricTestRunner.class)
+@LooperMode(LooperMode.Mode.LEGACY)
 @Config(shadows = {ShadowBluetoothUtils.class})
 public class NotificationAccessSettingsTest {
 
diff --git a/tests/robotests/src/com/android/settings/notification/NotificationAssistantDialogFragmentTest.java b/tests/robotests/src/com/android/settings/notification/NotificationAssistantDialogFragmentTest.java
index eef3f04..c4b5e80 100644
--- a/tests/robotests/src/com/android/settings/notification/NotificationAssistantDialogFragmentTest.java
+++ b/tests/robotests/src/com/android/settings/notification/NotificationAssistantDialogFragmentTest.java
@@ -35,8 +35,12 @@
 import org.mockito.MockitoAnnotations;
 import org.robolectric.RobolectricTestRunner;
 import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
 
 @RunWith(RobolectricTestRunner.class)
+@Config(shadows = {
+        com.android.settings.testutils.shadow.ShadowFragment.class,
+})
 public class NotificationAssistantDialogFragmentTest {
 
     private Context mContext;
diff --git a/tests/robotests/src/com/android/settings/notification/NotificationAssistantPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/NotificationAssistantPreferenceControllerTest.java
index 1dac399..fc90372 100644
--- a/tests/robotests/src/com/android/settings/notification/NotificationAssistantPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/notification/NotificationAssistantPreferenceControllerTest.java
@@ -69,6 +69,9 @@
 
 
 @RunWith(RobolectricTestRunner.class)
+@Config(shadows = {
+        com.android.settings.testutils.shadow.ShadowFragment.class,
+})
 public class NotificationAssistantPreferenceControllerTest {
 
     private static final String KEY = "TEST_KEY";
diff --git a/tests/robotests/src/com/android/settings/notification/ScreenLockSoundPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/ScreenLockSoundPreferenceControllerTest.java
index 49742c8..e0b7e14 100644
--- a/tests/robotests/src/com/android/settings/notification/ScreenLockSoundPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/notification/ScreenLockSoundPreferenceControllerTest.java
@@ -41,6 +41,9 @@
 import org.robolectric.annotation.Config;
 
 @RunWith(RobolectricTestRunner.class)
+@Config(shadows = {
+        com.android.settings.testutils.shadow.ShadowFragment.class,
+})
 public class ScreenLockSoundPreferenceControllerTest {
 
     @Mock
diff --git a/tests/robotests/src/com/android/settings/notification/SettingPrefControllerTest.java b/tests/robotests/src/com/android/settings/notification/SettingPrefControllerTest.java
index 6dec2d9..fc247c4 100644
--- a/tests/robotests/src/com/android/settings/notification/SettingPrefControllerTest.java
+++ b/tests/robotests/src/com/android/settings/notification/SettingPrefControllerTest.java
@@ -42,11 +42,15 @@
 import org.mockito.MockitoAnnotations;
 import org.robolectric.RobolectricTestRunner;
 import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
 
 import java.util.ArrayList;
 import java.util.List;
 
 @RunWith(RobolectricTestRunner.class)
+@Config(shadows = {
+        com.android.settings.testutils.shadow.ShadowFragment.class,
+})
 public class SettingPrefControllerTest {
 
     @Mock
diff --git a/tests/robotests/src/com/android/settings/notification/SoundWorkSettingsTest.java b/tests/robotests/src/com/android/settings/notification/SoundWorkSettingsTest.java
index 6f8b784..c7a110a 100644
--- a/tests/robotests/src/com/android/settings/notification/SoundWorkSettingsTest.java
+++ b/tests/robotests/src/com/android/settings/notification/SoundWorkSettingsTest.java
@@ -38,9 +38,13 @@
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 import org.robolectric.RobolectricTestRunner;
+import org.robolectric.annotation.Config;
 import org.robolectric.util.ReflectionHelpers;
 
 @RunWith(RobolectricTestRunner.class)
+@Config(shadows = {
+        com.android.settings.testutils.shadow.ShadowFragment.class,
+})
 public class SoundWorkSettingsTest {
 
     @Mock
diff --git a/tests/robotests/src/com/android/settings/notification/TouchSoundPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/TouchSoundPreferenceControllerTest.java
index 50facdd..53359cb 100644
--- a/tests/robotests/src/com/android/settings/notification/TouchSoundPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/notification/TouchSoundPreferenceControllerTest.java
@@ -42,6 +42,9 @@
 import org.robolectric.annotation.Config;
 
 @RunWith(RobolectricTestRunner.class)
+@Config(shadows = {
+        com.android.settings.testutils.shadow.ShadowFragment.class,
+})
 public class TouchSoundPreferenceControllerTest {
 
     @Mock
diff --git a/tests/robotests/src/com/android/settings/notification/app/AppChannelsBypassingDndPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/app/AppChannelsBypassingDndPreferenceControllerTest.java
index bcb641d..13528b4 100644
--- a/tests/robotests/src/com/android/settings/notification/app/AppChannelsBypassingDndPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/notification/app/AppChannelsBypassingDndPreferenceControllerTest.java
@@ -41,12 +41,14 @@
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 import org.robolectric.RobolectricTestRunner;
+import org.robolectric.annotation.LooperMode;
 import org.robolectric.shadows.ShadowApplication;
 
 import java.util.ArrayList;
 import java.util.Collections;
 
 @RunWith(RobolectricTestRunner.class)
+@LooperMode(LooperMode.Mode.LEGACY)
 public class AppChannelsBypassingDndPreferenceControllerTest {
 
     @Mock
diff --git a/tests/robotests/src/com/android/settings/notification/app/AppConversationListPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/app/AppConversationListPreferenceControllerTest.java
index 198c80a..916452c 100644
--- a/tests/robotests/src/com/android/settings/notification/app/AppConversationListPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/notification/app/AppConversationListPreferenceControllerTest.java
@@ -42,12 +42,14 @@
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 import org.robolectric.RobolectricTestRunner;
+import org.robolectric.annotation.LooperMode;
 import org.robolectric.shadows.ShadowApplication;
 
 import java.util.ArrayList;
 import java.util.Arrays;
 
 @RunWith(RobolectricTestRunner.class)
+@LooperMode(LooperMode.Mode.LEGACY)
 public class AppConversationListPreferenceControllerTest {
 
     private Context mContext;
diff --git a/tests/robotests/src/com/android/settings/notification/app/BubblePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/app/BubblePreferenceControllerTest.java
index e567590..487ba76 100644
--- a/tests/robotests/src/com/android/settings/notification/app/BubblePreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/notification/app/BubblePreferenceControllerTest.java
@@ -57,6 +57,7 @@
 import androidx.preference.PreferenceScreen;
 
 import com.android.settings.notification.NotificationBackend;
+import com.android.settings.testutils.shadow.ShadowActivityManager;
 import com.android.settingslib.RestrictedLockUtils;
 import com.android.settingslib.RestrictedSwitchPreference;
 
@@ -70,14 +71,17 @@
 import org.mockito.MockitoAnnotations;
 import org.robolectric.RobolectricTestRunner;
 import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
 import org.robolectric.shadow.api.Shadow;
-import org.robolectric.shadows.ShadowActivityManager;
 import org.robolectric.shadows.ShadowApplication;
 
 import java.util.ArrayList;
 import java.util.List;
 
 @RunWith(RobolectricTestRunner.class)
+@Config(shadows = {
+        ShadowActivityManager.class,
+})
 public class BubblePreferenceControllerTest {
 
     private Context mContext;
diff --git a/tests/robotests/src/com/android/settings/notification/app/BubbleSummaryPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/app/BubbleSummaryPreferenceControllerTest.java
index a9a1b97..7db308e 100644
--- a/tests/robotests/src/com/android/settings/notification/app/BubbleSummaryPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/notification/app/BubbleSummaryPreferenceControllerTest.java
@@ -46,6 +46,7 @@
 
 import com.android.settings.R;
 import com.android.settings.notification.NotificationBackend;
+import com.android.settings.testutils.shadow.ShadowActivityManager;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -54,11 +55,14 @@
 import org.mockito.MockitoAnnotations;
 import org.robolectric.RobolectricTestRunner;
 import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
 import org.robolectric.shadow.api.Shadow;
-import org.robolectric.shadows.ShadowActivityManager;
 import org.robolectric.shadows.ShadowApplication;
 
 @RunWith(RobolectricTestRunner.class)
+@Config(shadows = {
+        ShadowActivityManager.class,
+})
 public class BubbleSummaryPreferenceControllerTest {
 
     private Context mContext;
diff --git a/tests/robotests/src/com/android/settings/notification/app/ConversationDemotePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/app/ConversationDemotePreferenceControllerTest.java
index 0591cf2..e5a156e 100644
--- a/tests/robotests/src/com/android/settings/notification/app/ConversationDemotePreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/notification/app/ConversationDemotePreferenceControllerTest.java
@@ -46,11 +46,15 @@
 import org.mockito.MockitoAnnotations;
 import org.robolectric.RobolectricTestRunner;
 import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
 import org.robolectric.shadows.ShadowApplication;
 
 import java.util.ArrayList;
 
 @RunWith(RobolectricTestRunner.class)
+@Config(shadows = {
+        com.android.settings.testutils.shadow.ShadowFragment.class,
+})
 public class ConversationDemotePreferenceControllerTest {
 
     private Context mContext;
diff --git a/tests/robotests/src/com/android/settings/notification/app/ConversationHeaderPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/app/ConversationHeaderPreferenceControllerTest.java
index 9a1a3ab..9e67891 100644
--- a/tests/robotests/src/com/android/settings/notification/app/ConversationHeaderPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/notification/app/ConversationHeaderPreferenceControllerTest.java
@@ -48,11 +48,15 @@
 import org.mockito.MockitoAnnotations;
 import org.robolectric.RobolectricTestRunner;
 import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
 import org.robolectric.shadows.ShadowApplication;
 
 import java.util.ArrayList;
 
 @RunWith(RobolectricTestRunner.class)
+@Config(shadows = {
+        com.android.settings.testutils.shadow.ShadowFragment.class,
+})
 public class ConversationHeaderPreferenceControllerTest {
 
     private Context mContext;
diff --git a/tests/robotests/src/com/android/settings/notification/app/ConversationPromotePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/app/ConversationPromotePreferenceControllerTest.java
index 1c049be..56df38b 100644
--- a/tests/robotests/src/com/android/settings/notification/app/ConversationPromotePreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/notification/app/ConversationPromotePreferenceControllerTest.java
@@ -48,12 +48,15 @@
 import org.mockito.MockitoAnnotations;
 import org.robolectric.RobolectricTestRunner;
 import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
 import org.robolectric.shadows.ShadowApplication;
 
-import java.sql.Array;
 import java.util.ArrayList;
 
 @RunWith(RobolectricTestRunner.class)
+@Config(shadows = {
+        com.android.settings.testutils.shadow.ShadowFragment.class,
+})
 public class ConversationPromotePreferenceControllerTest {
 
     private Context mContext;
diff --git a/tests/robotests/src/com/android/settings/notification/app/FullScreenIntentPermissionPreferenceControllerTest.kt b/tests/robotests/src/com/android/settings/notification/app/FullScreenIntentPermissionPreferenceControllerTest.kt
index e148f71..64bb849 100644
--- a/tests/robotests/src/com/android/settings/notification/app/FullScreenIntentPermissionPreferenceControllerTest.kt
+++ b/tests/robotests/src/com/android/settings/notification/app/FullScreenIntentPermissionPreferenceControllerTest.kt
@@ -43,6 +43,7 @@
 import com.android.settings.notification.app.FullScreenIntentPermissionPreferenceController.Companion.KEY_FSI_PERMISSION
 import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin
 import com.android.settingslib.RestrictedSwitchPreference
+import com.android.settingslib.testutils.shadow.ShadowPermissionChecker
 import org.junit.Assert.assertFalse
 import org.junit.Assert.assertTrue
 import org.junit.Before
@@ -58,11 +59,13 @@
 import org.robolectric.RobolectricTestRunner
 import org.robolectric.annotation.Config
 import org.robolectric.shadows.ShadowApplicationPackageManager
-import org.robolectric.shadows.ShadowPermissionChecker
 import org.mockito.Mockito.`when` as whenever
 
 @RunWith(RobolectricTestRunner::class)
-@Config(shadows = [ShadowApplicationPackageManager::class])
+@Config(shadows = [
+    ShadowApplicationPackageManager::class,
+    ShadowPermissionChecker::class,
+])
 class FullScreenIntentPermissionPreferenceControllerTest {
     @JvmField
     @Rule
diff --git a/tests/robotests/src/com/android/settings/notification/app/HeaderPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/app/HeaderPreferenceControllerTest.java
index 4ca4f8d..05a41a6 100644
--- a/tests/robotests/src/com/android/settings/notification/app/HeaderPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/notification/app/HeaderPreferenceControllerTest.java
@@ -46,11 +46,15 @@
 import org.mockito.MockitoAnnotations;
 import org.robolectric.RobolectricTestRunner;
 import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
 import org.robolectric.shadows.ShadowApplication;
 
 import java.util.ArrayList;
 
 @RunWith(RobolectricTestRunner.class)
+@Config(shadows = {
+        com.android.settings.testutils.shadow.ShadowFragment.class,
+})
 public class HeaderPreferenceControllerTest {
 
     private Context mContext;
diff --git a/tests/robotests/src/com/android/settings/notification/zen/ZenModeEventRuleSettingsTest.java b/tests/robotests/src/com/android/settings/notification/zen/ZenModeEventRuleSettingsTest.java
index eeb53cf..f6df04d 100644
--- a/tests/robotests/src/com/android/settings/notification/zen/ZenModeEventRuleSettingsTest.java
+++ b/tests/robotests/src/com/android/settings/notification/zen/ZenModeEventRuleSettingsTest.java
@@ -39,12 +39,16 @@
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 import org.robolectric.RobolectricTestRunner;
+import org.robolectric.annotation.Config;
 import org.robolectric.shadows.ShadowToast;
 
 import java.util.ArrayList;
 import java.util.List;
 
 @RunWith(RobolectricTestRunner.class)
+@Config(shadows = {
+        com.android.settings.testutils.shadow.ShadowFragment.class,
+})
 public class ZenModeEventRuleSettingsTest {
 
     @Mock
diff --git a/tests/robotests/src/com/android/settings/notification/zen/ZenModeScheduleRuleSettingsTest.java b/tests/robotests/src/com/android/settings/notification/zen/ZenModeScheduleRuleSettingsTest.java
index a8a551f..4361eb3 100644
--- a/tests/robotests/src/com/android/settings/notification/zen/ZenModeScheduleRuleSettingsTest.java
+++ b/tests/robotests/src/com/android/settings/notification/zen/ZenModeScheduleRuleSettingsTest.java
@@ -39,9 +39,13 @@
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 import org.robolectric.RobolectricTestRunner;
+import org.robolectric.annotation.Config;
 import org.robolectric.shadows.ShadowToast;
 
 @RunWith(RobolectricTestRunner.class)
+@Config(shadows = {
+        com.android.settings.testutils.shadow.ShadowFragment.class,
+})
 public class ZenModeScheduleRuleSettingsTest {
 
     @Mock
diff --git a/tests/robotests/src/com/android/settings/panel/PanelFragmentTest.java b/tests/robotests/src/com/android/settings/panel/PanelFragmentTest.java
index 7d0bf99..e1687a0 100644
--- a/tests/robotests/src/com/android/settings/panel/PanelFragmentTest.java
+++ b/tests/robotests/src/com/android/settings/panel/PanelFragmentTest.java
@@ -49,10 +49,16 @@
 import org.robolectric.RobolectricTestRunner;
 import org.robolectric.RuntimeEnvironment;
 import org.robolectric.android.controller.ActivityController;
+import org.robolectric.annotation.Config;
+import org.robolectric.annotation.LooperMode;
 
 import java.util.Objects;
 
 @RunWith(RobolectricTestRunner.class)
+@LooperMode(LooperMode.Mode.LEGACY)
+@Config(shadows = {
+        com.android.settings.testutils.shadow.ShadowFragment.class,
+})
 public class PanelFragmentTest {
 
     private static final String TITLE = "title";
diff --git a/tests/robotests/src/com/android/settings/panel/SettingsPanelActivityTest.java b/tests/robotests/src/com/android/settings/panel/SettingsPanelActivityTest.java
index ea55b90..46c61e4 100644
--- a/tests/robotests/src/com/android/settings/panel/SettingsPanelActivityTest.java
+++ b/tests/robotests/src/com/android/settings/panel/SettingsPanelActivityTest.java
@@ -55,9 +55,13 @@
 import org.robolectric.Robolectric;
 import org.robolectric.RobolectricTestRunner;
 import org.robolectric.android.controller.ActivityController;
+import org.robolectric.annotation.Config;
 import org.robolectric.util.ReflectionHelpers;
 
 @RunWith(RobolectricTestRunner.class)
+@Config(shadows = {
+        com.android.settings.testutils.shadow.ShadowFragment.class,
+})
 public class SettingsPanelActivityTest {
 
     private FakeFeatureFactory mFakeFeatureFactory;
diff --git a/tests/robotests/src/com/android/settings/password/ChooseLockGenericTest.java b/tests/robotests/src/com/android/settings/password/ChooseLockGenericTest.java
index 5db998a..e625827 100644
--- a/tests/robotests/src/com/android/settings/password/ChooseLockGenericTest.java
+++ b/tests/robotests/src/com/android/settings/password/ChooseLockGenericTest.java
@@ -66,6 +66,7 @@
 import com.android.settings.testutils.FakeFeatureFactory;
 import com.android.settings.testutils.shadow.ShadowInteractionJankMonitor;
 import com.android.settings.testutils.shadow.ShadowLockPatternUtils;
+import com.android.settings.testutils.shadow.ShadowPersistentDataBlockManager;
 import com.android.settings.testutils.shadow.ShadowStorageManager;
 import com.android.settings.testutils.shadow.ShadowUserManager;
 import com.android.settings.testutils.shadow.ShadowUtils;
@@ -85,7 +86,6 @@
 import org.robolectric.android.controller.ActivityController;
 import org.robolectric.annotation.Config;
 import org.robolectric.shadows.ShadowApplication;
-import org.robolectric.shadows.ShadowPersistentDataBlockManager;
 
 @RunWith(RobolectricTestRunner.class)
 @Config(
diff --git a/tests/robotests/src/com/android/settings/password/ChooseLockTypeDialogFragmentTest.java b/tests/robotests/src/com/android/settings/password/ChooseLockTypeDialogFragmentTest.java
index 9e8644f..a7c71ad 100644
--- a/tests/robotests/src/com/android/settings/password/ChooseLockTypeDialogFragmentTest.java
+++ b/tests/robotests/src/com/android/settings/password/ChooseLockTypeDialogFragmentTest.java
@@ -41,9 +41,11 @@
 import org.robolectric.RobolectricTestRunner;
 import org.robolectric.RuntimeEnvironment;
 import org.robolectric.annotation.Config;
+import org.robolectric.annotation.LooperMode;
 import org.robolectric.shadows.androidx.fragment.FragmentController;
 
 @RunWith(RobolectricTestRunner.class)
+@LooperMode(LooperMode.Mode.LEGACY)
 @Config(shadows = {ShadowAlertDialogCompat.class, ShadowLockPatternUtils.class})
 public class ChooseLockTypeDialogFragmentTest {
 
diff --git a/tests/robotests/src/com/android/settings/password/SetupChooseLockGenericTest.java b/tests/robotests/src/com/android/settings/password/SetupChooseLockGenericTest.java
index b04a718..0eb365b 100644
--- a/tests/robotests/src/com/android/settings/password/SetupChooseLockGenericTest.java
+++ b/tests/robotests/src/com/android/settings/password/SetupChooseLockGenericTest.java
@@ -58,9 +58,7 @@
 import org.mockito.junit.MockitoRule;
 import org.robolectric.Robolectric;
 import org.robolectric.RobolectricTestRunner;
-import org.robolectric.Shadows;
 import org.robolectric.annotation.Config;
-import org.robolectric.shadows.ShadowActivity;
 
 import java.util.List;
 
@@ -107,8 +105,7 @@
         SetupChooseLockGeneric activity =
                 Robolectric.buildActivity(SetupChooseLockGeneric.class, intent).create().get();
 
-        ShadowActivity shadowActivity = Shadows.shadowOf(activity);
-        assertThat(shadowActivity.isFinishing()).isTrue();
+        assertThat(activity.isFinishing()).isTrue();
     }
 
     @Test
@@ -122,8 +119,7 @@
         SetupChooseLockGeneric activity =
                 Robolectric.buildActivity(SetupChooseLockGeneric.class, intent).create().get();
 
-        ShadowActivity shadowActivity = Shadows.shadowOf(activity);
-        assertThat(shadowActivity.isFinishing()).isFalse();
+        assertThat(activity.isFinishing()).isFalse();
     }
 
     @Test
diff --git a/tests/robotests/src/com/android/settings/password/SetupChooseLockPasswordTest.java b/tests/robotests/src/com/android/settings/password/SetupChooseLockPasswordTest.java
index 3242a59..bff6991 100644
--- a/tests/robotests/src/com/android/settings/password/SetupChooseLockPasswordTest.java
+++ b/tests/robotests/src/com/android/settings/password/SetupChooseLockPasswordTest.java
@@ -57,6 +57,7 @@
 import org.robolectric.annotation.Config;
 import org.robolectric.annotation.Implementation;
 import org.robolectric.annotation.Implements;
+import org.robolectric.annotation.LooperMode;
 import org.robolectric.shadows.ShadowActivity;
 import org.robolectric.shadows.ShadowDialog;
 import org.robolectric.shadows.ShadowInputMethodManager;
@@ -65,6 +66,7 @@
 import java.util.List;
 
 @RunWith(RobolectricTestRunner.class)
+@LooperMode(LooperMode.Mode.LEGACY)
 @Config(
         shadows = {
                 SettingsShadowResources.class,
diff --git a/tests/robotests/src/com/android/settings/password/SetupChooseLockPatternTest.java b/tests/robotests/src/com/android/settings/password/SetupChooseLockPatternTest.java
index d6df6c4..d353a22 100644
--- a/tests/robotests/src/com/android/settings/password/SetupChooseLockPatternTest.java
+++ b/tests/robotests/src/com/android/settings/password/SetupChooseLockPatternTest.java
@@ -59,6 +59,7 @@
 import org.robolectric.RobolectricTestRunner;
 import org.robolectric.Shadows;
 import org.robolectric.annotation.Config;
+import org.robolectric.annotation.LooperMode;
 import org.robolectric.shadows.ShadowPackageManager;
 import org.robolectric.util.ReflectionHelpers;
 import org.robolectric.util.ReflectionHelpers.ClassParameter;
@@ -66,6 +67,7 @@
 import java.util.Arrays;
 
 @RunWith(RobolectricTestRunner.class)
+@LooperMode(LooperMode.Mode.LEGACY)
 @Config(shadows = {ShadowUtils.class, ShadowAlertDialogCompat.class, ShadowLockPatternUtils.class})
 public class SetupChooseLockPatternTest {
 
diff --git a/tests/robotests/src/com/android/settings/password/SetupSkipDialogTest.java b/tests/robotests/src/com/android/settings/password/SetupSkipDialogTest.java
index 813efe9..2cc256b 100644
--- a/tests/robotests/src/com/android/settings/password/SetupSkipDialogTest.java
+++ b/tests/robotests/src/com/android/settings/password/SetupSkipDialogTest.java
@@ -47,11 +47,13 @@
 import org.robolectric.Robolectric;
 import org.robolectric.RobolectricTestRunner;
 import org.robolectric.annotation.Config;
+import org.robolectric.annotation.LooperMode;
 import org.robolectric.shadow.api.Shadow;
 import org.robolectric.shadows.ShadowAlertDialog;
 import org.robolectric.shadows.ShadowApplication;
 
 @RunWith(RobolectricTestRunner.class)
+@LooperMode(LooperMode.Mode.LEGACY)
 @Config(shadows = {ShadowUtils.class, ShadowAlertDialog.class})
 public class SetupSkipDialogTest {
 
diff --git a/tests/robotests/src/com/android/settings/search/actionbar/SearchMenuControllerTest.java b/tests/robotests/src/com/android/settings/search/actionbar/SearchMenuControllerTest.java
index d898e64..4dbd9eb 100644
--- a/tests/robotests/src/com/android/settings/search/actionbar/SearchMenuControllerTest.java
+++ b/tests/robotests/src/com/android/settings/search/actionbar/SearchMenuControllerTest.java
@@ -48,7 +48,10 @@
 import org.robolectric.annotation.Config;
 
 @RunWith(RobolectricTestRunner.class)
-@Config(shadows = ShadowUtils.class)
+@Config(shadows = {
+        ShadowUtils.class,
+        com.android.settings.testutils.shadow.ShadowFragment.class,
+})
 public class SearchMenuControllerTest {
 
     @Mock
diff --git a/tests/robotests/src/com/android/settings/security/OwnerInfoPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/security/OwnerInfoPreferenceControllerTest.java
index bcf9858..81f4fce 100644
--- a/tests/robotests/src/com/android/settings/security/OwnerInfoPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/security/OwnerInfoPreferenceControllerTest.java
@@ -49,9 +49,13 @@
 import org.mockito.MockitoAnnotations;
 import org.robolectric.RobolectricTestRunner;
 import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
 import org.robolectric.util.ReflectionHelpers;
 
 @RunWith(RobolectricTestRunner.class)
+@Config(shadows = {
+        com.android.settings.testutils.shadow.ShadowFragment.class,
+})
 public class OwnerInfoPreferenceControllerTest {
 
     @Mock
diff --git a/tests/robotests/src/com/android/settings/shortcut/CreateShortcutPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/shortcut/CreateShortcutPreferenceControllerTest.java
index df1fec3..85cf299 100644
--- a/tests/robotests/src/com/android/settings/shortcut/CreateShortcutPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/shortcut/CreateShortcutPreferenceControllerTest.java
@@ -125,6 +125,7 @@
                 new Intent(CreateShortcutPreferenceController.SHORTCUT_PROBE),
                 Arrays.asList(ri1, ri2));
 
+        doReturn(false).when(mController).canShowWifiHotspot();
         final List<ResolveInfo> info = mController.queryShortcuts();
         assertThat(info).hasSize(1);
         assertThat(info.get(0).activityInfo).isEqualTo(ri2.activityInfo);
@@ -150,6 +151,7 @@
                 new Intent(CreateShortcutPreferenceController.SHORTCUT_PROBE),
                 Arrays.asList(ri1, ri2));
 
+        doReturn(false).when(mController).canShowWifiHotspot();
         final List<ResolveInfo> info = mController.queryShortcuts();
         assertThat(info).hasSize(2);
         assertThat(info.get(0).activityInfo).isEqualTo(ri2.activityInfo);
@@ -158,6 +160,7 @@
 
     @Test
     public void queryShortcuts_setSupportOneHandedMode_ShouldEnableShortcuts() {
+        doReturn(true).when(mController).canShowWifiHotspot();
         SystemProperties.set(SUPPORT_ONE_HANDED_MODE, "true");
         setupActivityInfo(Settings.OneHandedSettingsActivity.class.getSimpleName());
 
@@ -166,6 +169,7 @@
 
     @Test
     public void queryShortcuts_setUnsupportOneHandedMode_ShouldDisableShortcuts() {
+        doReturn(false).when(mController).canShowWifiHotspot();
         SystemProperties.set(SUPPORT_ONE_HANDED_MODE, "false");
         setupActivityInfo(Settings.OneHandedSettingsActivity.class.getSimpleName());
 
@@ -174,7 +178,7 @@
 
     @Test
     public void queryShortcuts_configShowWifiHotspot_ShouldEnableShortcuts() {
-        when(mController.canShowWifiHotspot()).thenReturn(true);
+        doReturn(true).when(mController).canShowWifiHotspot();
         setupActivityInfo(Settings.WifiTetherSettingsActivity.class.getSimpleName());
 
         assertThat(mController.queryShortcuts()).hasSize(1);
@@ -182,7 +186,7 @@
 
     @Test
     public void queryShortcuts_configNotShowWifiHotspot_ShouldDisableShortcuts() {
-        when(mController.canShowWifiHotspot()).thenReturn(false);
+        doReturn(false).when(mController).canShowWifiHotspot();
         setupActivityInfo(Settings.WifiTetherSettingsActivity.class.getSimpleName());
 
         assertThat(mController.queryShortcuts()).hasSize(0);
diff --git a/tests/robotests/src/com/android/settings/testutils/BatteryTestUtils.java b/tests/robotests/src/com/android/settings/testutils/BatteryTestUtils.java
index e99b17f..dca15d5 100644
--- a/tests/robotests/src/com/android/settings/testutils/BatteryTestUtils.java
+++ b/tests/robotests/src/com/android/settings/testutils/BatteryTestUtils.java
@@ -36,6 +36,8 @@
 import com.android.settings.fuelgauge.batteryusage.DeviceBatteryState;
 import com.android.settings.fuelgauge.batteryusage.PowerAnomalyEvent;
 import com.android.settings.fuelgauge.batteryusage.PowerAnomalyEventList;
+import com.android.settings.fuelgauge.batteryusage.PowerAnomalyKey;
+import com.android.settings.fuelgauge.batteryusage.PowerAnomalyType;
 import com.android.settings.fuelgauge.batteryusage.WarningBannerInfo;
 import com.android.settings.fuelgauge.batteryusage.db.AppUsageEventDao;
 import com.android.settings.fuelgauge.batteryusage.db.AppUsageEventEntity;
@@ -209,8 +211,9 @@
     /** Create a power anomaly event proto of adaptive brightness. */
     public static PowerAnomalyEvent createAdaptiveBrightnessAnomalyEvent() {
         return PowerAnomalyEvent.newBuilder()
-                .setType("settings banner")
-                .setKey("adaptive_brightness")
+                .setEventId("BrightnessAnomaly")
+                .setType(PowerAnomalyType.TYPE_SETTINGS_BANNER)
+                .setKey(PowerAnomalyKey.KEY_BRIGHTNESS)
                 .setWarningBannerInfo(WarningBannerInfo.newBuilder()
                         .setMainButtonDestination(AutoBrightnessSettings.class.getName())
                         .setMainButtonSourceMetricsCategory(SettingsEnums.SETTINGS_AUTO_BRIGHTNESS)
@@ -221,8 +224,9 @@
     /** Create a power anomaly event proto of screen timeout. */
     public static PowerAnomalyEvent createScreenTimeoutAnomalyEvent() {
         return PowerAnomalyEvent.newBuilder()
-                .setType("settings banner")
-                .setKey("screen_timeout")
+                .setEventId("ScreenTimeoutAnomaly")
+                .setType(PowerAnomalyType.TYPE_SETTINGS_BANNER)
+                .setKey(PowerAnomalyKey.KEY_SCREEN_TIMEOUT)
                 .setWarningBannerInfo(WarningBannerInfo.newBuilder()
                         .setMainButtonDestination(ScreenTimeoutSettings.class.getName())
                         .setMainButtonSourceMetricsCategory(SettingsEnums.SCREEN_TIMEOUT)
diff --git a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowActivityManager.java b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowActivityManager.java
index 76bdaef..dd82e25 100644
--- a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowActivityManager.java
+++ b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowActivityManager.java
@@ -23,7 +23,7 @@
 import org.robolectric.annotation.Implements;
 
 @Implements(ActivityManager.class)
-public class ShadowActivityManager {
+public class ShadowActivityManager extends org.robolectric.shadows.ShadowActivityManager {
     private static int sCurrentUserId = 0;
     private static IActivityManager sService = null;
 
diff --git a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowApplicationPackageManager.java b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowApplicationPackageManager.java
new file mode 100644
index 0000000..7ff2e5d
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowApplicationPackageManager.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2023 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.shadow;
+
+import android.app.ApplicationPackageManager;
+import android.content.pm.PackageInfo;
+
+import org.robolectric.annotation.Implements;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+@Implements(ApplicationPackageManager.class)
+public class ShadowApplicationPackageManager
+        extends org.robolectric.shadows.ShadowApplicationPackageManager {
+    static final Map<Integer, List<String>> packagesForUserId = new HashMap<>();
+
+    public void setInstalledPackagesForUserId(int userId, List<String> packages) {
+        packagesForUserId.put(userId, packages);
+        for (String packageName : packages) {
+            addPackage(packageName);
+        }
+    }
+
+    protected List<PackageInfo> getInstalledPackagesAsUser(int flags, int userId) {
+        List<PackageInfo> packages = new ArrayList<>();
+        for (String packageName : packagesForUserId.getOrDefault(userId, new ArrayList<>())) {
+            try {
+                packages.add(getPackageInfo(packageName, flags));
+            } catch (Exception e) {
+                // ignore
+            }
+        }
+        return packages;
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowAudioManager.java b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowAudioManager.java
index e651baf..9c06665 100644
--- a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowAudioManager.java
+++ b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowAudioManager.java
@@ -31,12 +31,12 @@
 import android.media.AudioManager;
 import android.os.Handler;
 
-import java.util.List;
 import org.robolectric.annotation.Implementation;
 import org.robolectric.annotation.Implements;
 import org.robolectric.shadow.api.Shadow;
 
 import java.util.ArrayList;
+import java.util.List;
 
 @Implements(value = AudioManager.class)
 public class ShadowAudioManager extends org.robolectric.shadows.ShadowAudioManager {
@@ -46,7 +46,7 @@
     private List<AudioDeviceCallback> mDeviceCallbacks = new ArrayList<>();
 
     @Implementation
-    private int getRingerModeInternal() {
+    protected int getRingerModeInternal() {
         return mRingerMode;
     }
 
diff --git a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowAuthenticationHelper.java b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowAuthenticationHelper.java
index cb7da56..d14a089 100644
--- a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowAuthenticationHelper.java
+++ b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowAuthenticationHelper.java
@@ -33,6 +33,7 @@
     static final String[] LABELS = {"LABEL1", "LABEL2", "LABEL3", "LABEL4"};
     private static String[] sEnabledAccount = TYPES;
 
+    @Implementation
     protected void __constructor__(Context context, UserHandle userHandle,
             AuthenticatorHelper.OnAccountsUpdateListener listener) {
     }
diff --git a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowCrossProfileApps.java b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowCrossProfileApps.java
new file mode 100644
index 0000000..38e8218
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowCrossProfileApps.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2023 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.shadow;
+
+import android.Manifest;
+import android.annotation.NonNull;
+import android.content.Context;
+import android.content.pm.CrossProfileApps;
+import android.content.pm.ICrossProfileApps;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+
+import org.robolectric.annotation.Implementation;
+import org.robolectric.annotation.Implements;
+
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Set;
+
+@Implements(CrossProfileApps.class)
+public class ShadowCrossProfileApps extends org.robolectric.shadows.ShadowCrossProfileApps {
+    private static final Set<String> configurableInteractAcrossProfilePackages = new HashSet<>();
+    private Context mContext;
+    private PackageManager mPackageManager;
+
+    @Implementation
+    protected void __constructor__(Context context, ICrossProfileApps service) {
+        super.__constructor__(context, service);
+        this.mContext = context;
+        this.mPackageManager = context.getPackageManager();
+    }
+    public void addCrossProfilePackage(String packageName) {
+        configurableInteractAcrossProfilePackages.add(packageName);
+    }
+
+    @Implementation
+    protected boolean canConfigureInteractAcrossProfiles(@NonNull String packageName) {
+        return configurableInteractAcrossProfilePackages.contains(packageName);
+    }
+
+    @Implementation
+    protected boolean canUserAttemptToConfigureInteractAcrossProfiles(@NonNull String packageName) {
+        PackageInfo packageInfo;
+        try {
+            packageInfo = mPackageManager.getPackageInfo(packageName, /* flags= */ 0);
+        } catch (PackageManager.NameNotFoundException e) {
+            return false;
+        }
+        if (packageInfo == null || packageInfo.requestedPermissions == null) {
+            return false;
+        }
+        return Arrays.asList(packageInfo.requestedPermissions).contains(
+                Manifest.permission.INTERACT_ACROSS_PROFILES);
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowDateFormat.java b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowDateFormat.java
new file mode 100644
index 0000000..74e6a81
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowDateFormat.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2016 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.shadow;
+
+import android.content.Context;
+import android.text.format.DateFormat;
+
+import org.robolectric.annotation.Implementation;
+import org.robolectric.annotation.Implements;
+
+import java.util.Locale;
+
+@Implements(DateFormat.class)
+public class ShadowDateFormat {
+
+    @Implementation
+    protected static java.text.DateFormat getDateFormat(Context context) {
+        return new java.text.SimpleDateFormat("MMM-dd-yyyy", Locale.ROOT);
+    }
+
+    @Implementation
+    protected static java.text.DateFormat getLongDateFormat(Context context) {
+        return new java.text.SimpleDateFormat("MMMM dd, yyyy", Locale.ROOT);
+    }
+
+    @Implementation
+    protected static java.text.DateFormat getTimeFormat(Context context) {
+        return new java.text.SimpleDateFormat("HH:mm:ss", Locale.ROOT);
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowDevicePolicyManager.java b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowDevicePolicyManager.java
index 76c675a..867a306 100644
--- a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowDevicePolicyManager.java
+++ b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowDevicePolicyManager.java
@@ -1,27 +1,50 @@
+/*
+ * Copyright (C) 2023 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.shadow;
 
 import static android.app.admin.DevicePolicyManager.DEVICE_OWNER_TYPE_DEFAULT;
 import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
+import static android.os.Build.VERSION_CODES.O;
+import static android.os.Build.VERSION_CODES.Q;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.UserIdInt;
 import android.app.admin.DevicePolicyManager;
 import android.app.admin.DevicePolicyManager.DeviceOwnerType;
+import android.app.admin.IDevicePolicyManager;
 import android.app.admin.ManagedSubscriptionsPolicy;
 import android.app.admin.PasswordMetrics;
 import android.app.admin.PasswordPolicy;
 import android.content.ComponentName;
+import android.content.Context;
 
-import org.robolectric.RuntimeEnvironment;
+import androidx.test.core.app.ApplicationProvider;
+
 import org.robolectric.annotation.Implementation;
 import org.robolectric.annotation.Implements;
 import org.robolectric.shadow.api.Shadow;
 
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
+import java.util.Set;
 
 @Implements(DevicePolicyManager.class)
 public class ShadowDevicePolicyManager extends org.robolectric.shadows.ShadowDevicePolicyManager {
@@ -30,15 +53,22 @@
     private final Map<String, Integer> mDeviceOwnerTypes = new HashMap<>();
     private Map<Integer, CharSequence> mSupportMessagesMap = new HashMap<>();
     private boolean mIsAdminActiveAsUser = false;
+    private ComponentName mProfileOwner;
     private ComponentName mDeviceOwnerComponentName;
     private ManagedSubscriptionsPolicy mManagedSubscriptionsPolicy;
     private int mDeviceOwnerUserId = -1;
     private int mPasswordMinQuality = PASSWORD_QUALITY_UNSPECIFIED;
     private int mPasswordMinLength = 0;
     private int mPasswordMinSymbols = 0;
+    private Set<String> mCrossProfileCalendarPackages = Collections.emptySet();
 
     private List<String> mPermittedAccessibilityServices = null;
 
+    @Implementation(minSdk = O)
+    protected void __constructor__(Context context, IDevicePolicyManager service) {
+        super.__constructor__(ApplicationProvider.getApplicationContext(), service);
+    }
+
     public void setShortSupportMessageForUser(ComponentName admin, int userHandle, String message) {
         mSupportMessagesMap.put(Objects.hash(admin, userHandle), message);
     }
@@ -137,6 +167,35 @@
 
     public static ShadowDevicePolicyManager getShadow() {
         return (ShadowDevicePolicyManager) Shadow.extract(
-                RuntimeEnvironment.application.getSystemService(DevicePolicyManager.class));
+                ApplicationProvider.getApplicationContext()
+                        .getSystemService(DevicePolicyManager.class));
+    }
+
+    // BEGIN-INTERNAL
+    @Implementation(minSdk = Q)
+    protected Set<String> getCrossProfileCalendarPackages() {
+        return mCrossProfileCalendarPackages;
+    }
+
+    @Implementation(minSdk = Q)
+    public void setCrossProfileCalendarPackages(ComponentName admin, Set<String> packageNames) {
+        enforceProfileOwner(admin);
+        mCrossProfileCalendarPackages = packageNames;
+    }
+
+    /**
+     * Sets the admin as active admin and profile owner.
+     *
+     * @see DevicePolicyManager#getProfileOwner()
+     */
+    public void setProfileOwner(ComponentName admin) {
+        setActiveAdmin(admin);
+        mProfileOwner = admin;
+    }
+
+    private void enforceProfileOwner(ComponentName admin) {
+        if (!admin.equals(mProfileOwner)) {
+            throw new SecurityException("[" + admin + "] is not a profile owner");
+        }
     }
 }
diff --git a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowDrawable.java b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowDrawable.java
new file mode 100644
index 0000000..8dac1f1
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowDrawable.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2016 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.shadow;
+
+import org.robolectric.annotation.Implementation;
+import org.robolectric.annotation.Implements;
+
+@Implements(ShadowDrawable.class)
+public class ShadowDrawable extends org.robolectric.shadows.ShadowDrawable {
+    private static int sDefaultIntrinsicWidth = -1;
+    private int mIntrinsicWidth = sDefaultIntrinsicWidth;
+
+    @Implementation
+    public int getIntrinsicWidth() {
+        return mIntrinsicWidth;
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowInputManager.java b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowInputManager.java
new file mode 100644
index 0000000..b116292
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowInputManager.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2016 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.shadow;
+
+import static org.robolectric.util.ReflectionHelpers.ClassParameter.from;
+
+import android.hardware.input.IInputManager;
+import android.hardware.input.InputManager;
+import android.os.Handler;
+
+import org.robolectric.annotation.Implementation;
+import org.robolectric.annotation.Implements;
+import org.robolectric.util.ReflectionHelpers;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Shadow for {@link InputManager} that has accessors for registered
+ * {@link InputManager.InputDeviceListener}s.
+ */
+@Implements(value = InputManager.class, callThroughByDefault = false)
+public class ShadowInputManager extends org.robolectric.shadows.ShadowInputManager {
+
+    private List<InputManager.InputDeviceListener> mInputDeviceListeners;
+
+    @Implementation
+    protected void __constructor__(IInputManager service) {
+        mInputDeviceListeners = new ArrayList<>();
+    }
+
+    @Implementation
+    protected static InputManager getInstance() {
+        return ReflectionHelpers.callConstructor(
+                InputManager.class,
+                from(IInputManager.class, null));
+    }
+
+    @Implementation
+    protected void registerInputDeviceListener(InputManager.InputDeviceListener listener,
+            Handler handler) {
+        // TODO: Use handler.
+        if (!mInputDeviceListeners.contains(listener)) {
+            mInputDeviceListeners.add(listener);
+        }
+    }
+
+    @Implementation
+    protected void unregisterInputDeviceListener(InputManager.InputDeviceListener listener) {
+        mInputDeviceListeners.remove(listener);
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowKeyStore.java b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowKeyStore.java
index 098dcfc..99eca0a 100644
--- a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowKeyStore.java
+++ b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowKeyStore.java
@@ -28,7 +28,7 @@
     private static boolean sIsHardwareBacked;
 
     @Resetter
-    public void reset() {
+    public static void reset() {
         sIsHardwareBacked = false;
     }
 
diff --git a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowPersistentDataBlockManager.java b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowPersistentDataBlockManager.java
new file mode 100644
index 0000000..30ed0d1
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowPersistentDataBlockManager.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2023 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.shadow;
+
+import android.service.persistentdata.PersistentDataBlockManager;
+
+import org.robolectric.annotation.Implementation;
+import org.robolectric.annotation.Implements;
+import org.robolectric.annotation.Resetter;
+
+@Implements(PersistentDataBlockManager.class)
+public class ShadowPersistentDataBlockManager {
+    private static int sDataBlockSize = 0;
+
+    @Resetter
+    public static void reset() {
+        sDataBlockSize = 0;
+    }
+
+    @Implementation
+    protected int getDataBlockSize() {
+        return sDataBlockSize;
+    }
+
+    public static void setDataBlockSize(int dataBlockSize) {
+        sDataBlockSize = dataBlockSize;
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowSystemSettings.java b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowSystemSettings.java
new file mode 100644
index 0000000..3bb046a
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowSystemSettings.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2023 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.shadow;
+
+import static android.os.Build.VERSION_CODES.JELLY_BEAN_MR1;
+
+import android.content.ContentResolver;
+import android.provider.Settings;
+
+import org.robolectric.annotation.Implementation;
+import org.robolectric.annotation.Implements;
+import org.robolectric.annotation.Resetter;
+import org.robolectric.shadows.ShadowSettings;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.WeakHashMap;
+
+@Implements(value = Settings.System.class)
+public class ShadowSystemSettings extends ShadowSettings.ShadowSystem {
+    private static final Map<ContentResolver, Map<String, String>> sDataMap = new WeakHashMap<>();
+
+    @Resetter
+    public static void reset() {
+        sDataMap.clear();
+    }
+
+    @Implementation(minSdk = JELLY_BEAN_MR1)
+    protected static boolean putStringForUser(ContentResolver cr, String name, String value,
+            int userHandle) {
+        return putString(cr, name, value);
+    }
+
+    @Implementation(minSdk = JELLY_BEAN_MR1)
+    protected static String getStringForUser(ContentResolver cr, String name, int userHandle) {
+        return getString(cr, name);
+    }
+
+    @Implementation
+    protected static boolean putString(ContentResolver cr, String name, String value) {
+        get(cr).put(name, value);
+        return true;
+    }
+
+    @Implementation
+    protected static String getString(ContentResolver cr, String name) {
+        return get(cr).get(name);
+    }
+
+    private static Map<String, String> get(ContentResolver cr) {
+        Map<String, String> map = sDataMap.get(cr);
+        if (map == null) {
+            map = new HashMap<>();
+            sDataMap.put(cr, map);
+        }
+        return map;
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/users/UserDetailsSettingsTest.java b/tests/robotests/src/com/android/settings/users/UserDetailsSettingsTest.java
index ca3521b..fbe4a05 100644
--- a/tests/robotests/src/com/android/settings/users/UserDetailsSettingsTest.java
+++ b/tests/robotests/src/com/android/settings/users/UserDetailsSettingsTest.java
@@ -81,7 +81,7 @@
 
 @RunWith(RobolectricTestRunner.class)
 @Config(shadows = {
-        ShadowUserManager.class,
+        // ShadowUserManager.class,
         ShadowDevicePolicyManager.class
 })
 public class UserDetailsSettingsTest {
diff --git a/tests/robotests/src/com/android/settings/users/UserSettingsTest.java b/tests/robotests/src/com/android/settings/users/UserSettingsTest.java
index 9d818aa..37af4b1 100644
--- a/tests/robotests/src/com/android/settings/users/UserSettingsTest.java
+++ b/tests/robotests/src/com/android/settings/users/UserSettingsTest.java
@@ -97,6 +97,7 @@
         ShadowUserManager.class,
         ShadowDevicePolicyManager.class,
         SettingsShadowResources.class,
+        com.android.settings.testutils.shadow.ShadowFragment.class,
 })
 public class UserSettingsTest {
 
diff --git a/tests/robotests/src/com/android/settings/webview/WebViewAppPickerTest.java b/tests/robotests/src/com/android/settings/webview/WebViewAppPickerTest.java
index 9d7fbae..bed88e7 100644
--- a/tests/robotests/src/com/android/settings/webview/WebViewAppPickerTest.java
+++ b/tests/robotests/src/com/android/settings/webview/WebViewAppPickerTest.java
@@ -41,6 +41,7 @@
 
 import androidx.fragment.app.FragmentActivity;
 
+import com.android.settings.testutils.shadow.ShadowUserManager;
 import com.android.settingslib.applications.DefaultAppInfo;
 import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
 import com.android.settingslib.widget.SelectorWithWidgetPreference;
@@ -54,15 +55,18 @@
 import org.robolectric.RobolectricTestRunner;
 import org.robolectric.RuntimeEnvironment;
 import org.robolectric.Shadows;
+import org.robolectric.annotation.Config;
 import org.robolectric.shadow.api.Shadow;
 import org.robolectric.shadows.ShadowPackageManager;
-import org.robolectric.shadows.ShadowUserManager;
 import org.robolectric.util.ReflectionHelpers;
 
 import java.util.Arrays;
 import java.util.Collections;
 
 @RunWith(RobolectricTestRunner.class)
+@Config(shadows = {
+        ShadowUserManager.class,
+})
 public class WebViewAppPickerTest {
 
     private final static String PACKAGE_NAME = "com.example.test";
diff --git a/tests/robotests/src/com/android/settings/widget/EntityHeaderControllerTest.java b/tests/robotests/src/com/android/settings/widget/EntityHeaderControllerTest.java
index ed0ff6d..bc816fa 100644
--- a/tests/robotests/src/com/android/settings/widget/EntityHeaderControllerTest.java
+++ b/tests/robotests/src/com/android/settings/widget/EntityHeaderControllerTest.java
@@ -84,7 +84,7 @@
     @Test
     public void testBuildView_constructedWithoutView_shouldCreateNewView() {
         mController = EntityHeaderController.newInstance(mActivity, mFragment, null);
-        View view = mController.done(mActivity);
+        View view = mController.done();
 
         assertThat(view).isNotNull();
     }
@@ -92,7 +92,7 @@
     @Test
     public void testBuildView_withContext_shouldBuildPreferenceAllowedBelowDivider() {
         mController = EntityHeaderController.newInstance(mActivity, mFragment, null);
-        Preference preference = mController.done(mActivity, mShadowContext);
+        Preference preference = mController.done(mShadowContext);
 
         assertThat(preference instanceof LayoutPreference).isTrue();
         assertThat(((LayoutPreference)preference).isAllowDividerBelow()).isTrue();
@@ -103,7 +103,7 @@
         View inputView = mLayoutInflater.inflate(
                 com.android.settingslib.widget.R.layout.settings_entity_header, null /* root */);
         mController = EntityHeaderController.newInstance(mActivity, mFragment, inputView);
-        View view = mController.done(mActivity);
+        View view = mController.done();
 
         assertThat(view).isSameInstanceAs(inputView);
     }
@@ -123,7 +123,7 @@
         mController.setSummary(testString);
         mController.setSecondSummary(testString);
         mController.setIcon(mShadowContext.getDrawable(R.drawable.ic_add_24dp));
-        mController.done(mActivity);
+        mController.done();
 
         assertThat(label).isNotNull();
         assertThat(label.getText()).isEqualTo(testString);
@@ -144,15 +144,11 @@
         when(mActivity.getApplicationContext()).thenReturn(mContext);
 
         mController = EntityHeaderController.newInstance(mActivity, mFragment, view);
-        mController.setEditListener(new View.OnClickListener() {
-            public void onClick(View v) {
-                // do nothing
-            }
-        });
+        mController.setEditListener(v -> {/* do nothing */});
         mController.setButtonActions(
                 EntityHeaderController.ActionType.ACTION_EDIT_PREFERENCE,
                 EntityHeaderController.ActionType.ACTION_NONE);
-        mController.done(mActivity);
+        mController.done();
 
         final ImageButton button1 = view.findViewById(android.R.id.button1);
         assertThat(button1).isNotNull();
@@ -175,7 +171,7 @@
         mController.setButtonActions(
                 EntityHeaderController.ActionType.ACTION_EDIT_PREFERENCE,
                 EntityHeaderController.ActionType.ACTION_NONE);
-        mController.done(mActivity);
+        mController.done();
 
         assertThat(view.findViewById(android.R.id.button1).getVisibility()).isEqualTo(View.GONE);
         assertThat(view.findViewById(android.R.id.button2).getVisibility()).isEqualTo(View.GONE);
@@ -195,7 +191,7 @@
                 .setButtonActions(
                         EntityHeaderController.ActionType.ACTION_NONE,
                         EntityHeaderController.ActionType.ACTION_NONE);
-        mController.done(mActivity);
+        mController.done();
 
         assertThat(appLinks.findViewById(android.R.id.button1).getVisibility())
                 .isEqualTo(View.GONE);
@@ -224,7 +220,7 @@
                 .setButtonActions(
                         EntityHeaderController.ActionType.ACTION_NOTIF_PREFERENCE,
                         EntityHeaderController.ActionType.ACTION_NONE);
-        mController.done(mActivity);
+        mController.done();
 
         appLinks.findViewById(com.android.settingslib.widget.R.id.entity_header_content)
                 .performClick();
@@ -241,7 +237,7 @@
         String description = "Fake Description";
         mController.setIcon(mShadowContext.getDrawable(R.drawable.ic_add_24dp));
         mController.setIconContentDescription(description);
-        mController.done(mActivity);
+        mController.done();
         assertThat(view.findViewById(R.id.entity_header_icon).getContentDescription().toString())
                 .isEqualTo(description);
     }
@@ -254,7 +250,7 @@
         mController = EntityHeaderController.newInstance(mActivity, mFragment, view);
         String description = "Fake Description";
         mController.setIconContentDescription(description);
-        mController.done(mActivity);
+        mController.done();
         assertThat(view.findViewById(R.id.entity_header_icon).getContentDescription().toString())
                 .isEqualTo(description);
     }
@@ -269,7 +265,7 @@
                 .setButtonActions(
                         EntityHeaderController.ActionType.ACTION_NOTIF_PREFERENCE,
                         EntityHeaderController.ActionType.ACTION_NONE);
-        mController.done(mActivity);
+        mController.done();
 
         assertThat(appLinks.findViewById(android.R.id.button1).getVisibility())
                 .isEqualTo(View.VISIBLE);
@@ -284,7 +280,7 @@
         final View header = mLayoutInflater.inflate(
                 com.android.settingslib.widget.R.layout.settings_entity_header, null /* root */);
         mController = EntityHeaderController.newInstance(mActivity, mFragment, header);
-        mController.done(mActivity);
+        mController.done();
 
         View installType = header.findViewById(com.android.settingslib.widget.R.id.install_type);
         assertThat(installType.getVisibility()).isEqualTo(View.GONE);
@@ -297,7 +293,7 @@
                 com.android.settingslib.widget.R.layout.settings_entity_header, null /* root */);
         mController = EntityHeaderController.newInstance(mActivity, mFragment, header);
         mController.setIsInstantApp(true);
-        mController.done(mActivity);
+        mController.done();
         TextView label = header.findViewById(com.android.settingslib.widget.R.id.install_type);
 
         assertThat(label.getVisibility()).isEqualTo(View.VISIBLE);
diff --git a/tests/robotests/src/com/android/settings/widget/RestrictedButtonTest.java b/tests/robotests/src/com/android/settings/widget/RestrictedButtonTest.java
new file mode 100644
index 0000000..4b05b91
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/widget/RestrictedButtonTest.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2023 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.widget;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.os.UserManager.EnforcingUser;
+import android.view.View.OnClickListener;
+
+import androidx.fragment.app.FragmentActivity;
+
+import com.android.settings.testutils.shadow.ShadowDevicePolicyManager;
+import com.android.settings.testutils.shadow.ShadowUserManager;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.Robolectric;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.annotation.Config;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@RunWith(RobolectricTestRunner.class)
+@Config(shadows = {ShadowUserManager.class, ShadowDevicePolicyManager.class})
+public class RestrictedButtonTest {
+
+    private RestrictedButton mButton;
+    private OnClickListener mOnClickListener;
+    private UserHandle mUser;
+
+    @Before
+    public void setUp() {
+        mButton = new RestrictedButton(Robolectric.setupActivity(FragmentActivity.class));
+        mOnClickListener = mock(OnClickListener.class);
+        mButton.setOnClickListener(mOnClickListener);
+
+        int userId = UserHandle.myUserId();
+        mUser = UserHandle.of(userId);
+        List<EnforcingUser> enforcingUsers = new ArrayList<>();
+        enforcingUsers.add(new EnforcingUser(userId, UserManager.RESTRICTION_SOURCE_DEVICE_OWNER));
+        // Ensure that RestrictedLockUtils.checkIfRestrictionEnforced doesn't return null.
+        ShadowUserManager.getShadow().setUserRestrictionSources(
+                UserManager.DISALLOW_MODIFY_ACCOUNTS,
+                mUser,
+                enforcingUsers);
+    }
+
+    @Test
+    public void performClick_buttonIsNotInited_shouldCallListener() {
+        mButton.performClick();
+
+        verify(mOnClickListener).onClick(eq(mButton));
+    }
+
+    @Test
+    public void performClick_noRestriction_shouldCallListener() {
+        mButton.init(mUser, UserManager.DISALLOW_ADJUST_VOLUME);
+
+        mButton.performClick();
+
+        verify(mOnClickListener).onClick(eq(mButton));
+    }
+
+    @Test
+    public void performClick_hasRestriction_shouldNotCallListener() {
+        mButton.init(mUser, UserManager.DISALLOW_MODIFY_ACCOUNTS);
+
+        mButton.performClick();
+
+        verify(mOnClickListener, never()).onClick(eq(mButton));
+    }
+
+    @Test
+    public void updateState_noRestriction_shouldEnableButton() {
+        mButton.init(mUser, UserManager.DISALLOW_ADJUST_VOLUME);
+
+        mButton.updateState();
+
+        assertThat(mButton.isEnabled()).isTrue();
+    }
+
+    @Test
+    public void updateState_noRestriction_shoulddisableButton() {
+        mButton.init(mUser, UserManager.DISALLOW_MODIFY_ACCOUNTS);
+
+        mButton.updateState();
+
+        assertThat(mButton.isEnabled()).isFalse();
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/wifi/details2/WifiDetailPreferenceController2Test.java b/tests/robotests/src/com/android/settings/wifi/details2/WifiDetailPreferenceController2Test.java
index dcd9b36..7c9f665 100644
--- a/tests/robotests/src/com/android/settings/wifi/details2/WifiDetailPreferenceController2Test.java
+++ b/tests/robotests/src/com/android/settings/wifi/details2/WifiDetailPreferenceController2Test.java
@@ -299,8 +299,6 @@
 
         ShadowEntityHeaderController.setUseMock(mMockHeaderController);
         // builder pattern
-        when(mMockHeaderController.setRecyclerView(mMockFragment.getListView(), mLifecycle))
-                .thenReturn(mMockHeaderController);
         when(mMockHeaderController.setSummary(nullable(String.class)))
                 .thenReturn(mMockHeaderController);
         when(mMockHeaderController.setSecondSummary(nullable(String.class)))
diff --git a/tests/robotests/src/com/android/settings/wifi/tether/WifiTetherSettingsTest.java b/tests/robotests/src/com/android/settings/wifi/tether/WifiTetherSettingsTest.java
index 9f56fcd..84a7b36 100644
--- a/tests/robotests/src/com/android/settings/wifi/tether/WifiTetherSettingsTest.java
+++ b/tests/robotests/src/com/android/settings/wifi/tether/WifiTetherSettingsTest.java
@@ -23,6 +23,7 @@
 
 import static com.android.settings.wifi.WifiUtils.setCanShowWifiHotspotCached;
 import static com.android.settings.wifi.repository.WifiHotspotRepository.BAND_2GHZ_5GHZ_6GHZ;
+import static com.android.settings.wifi.tether.WifiTetherSettings.KEY_INSTANT_HOTSPOT;
 import static com.android.settings.wifi.tether.WifiTetherSettings.KEY_WIFI_HOTSPOT_SECURITY;
 import static com.android.settings.wifi.tether.WifiTetherSettings.KEY_WIFI_HOTSPOT_SPEED;
 
@@ -90,6 +91,7 @@
     private static final String[] WIFI_REGEXS = {"wifi_regexs"};
     private static final String SSID = "ssid";
     private static final String PASSWORD = "password";
+    private static final String SUMMARY = "summary";
 
     @Rule
     public final MockitoRule mMockitoRule = MockitoJUnit.rule();
@@ -133,6 +135,10 @@
     private WifiTetherAutoOffPreferenceController mWifiTetherAutoOffPreferenceController;
     @Mock
     private WifiTetherMaximizeCompatibilityPreferenceController mMaxCompatibilityPrefController;
+    @Mock
+    private Preference mInstantHotspot;
+    @Mock
+    private LiveData<String> mInstantHotspotSummary;
 
     private WifiTetherSettings mSettings;
 
@@ -155,8 +161,10 @@
         when(provider.getWifiTetherViewModel(mock(ViewModelStoreOwner.class)))
                 .thenReturn(mWifiTetherViewModel);
         when(mWifiTetherViewModel.isSpeedFeatureAvailable()).thenReturn(false);
+        when(mWifiTetherViewModel.isInstantHotspotFeatureAvailable()).thenReturn(true);
         when(mWifiTetherViewModel.getSecuritySummary()).thenReturn(mSecuritySummary);
         when(mWifiTetherViewModel.getSpeedSummary()).thenReturn(mSpeedSummary);
+        when(mWifiTetherViewModel.getInstantHotspotSummary()).thenReturn(mInstantHotspotSummary);
 
         mSettings = spy(new WifiTetherSettings(mWifiRestriction));
         mSettings.mMainSwitchBar = mMainSwitchBar;
@@ -172,6 +180,8 @@
         mSettings.mWifiTetherViewModel = mWifiTetherViewModel;
         when(mSettings.findPreference(KEY_WIFI_HOTSPOT_SECURITY)).thenReturn(mWifiHotspotSecurity);
         when(mSettings.findPreference(KEY_WIFI_HOTSPOT_SPEED)).thenReturn(mWifiHotspotSpeed);
+        when(mSettings.findPreference(KEY_INSTANT_HOTSPOT)).thenReturn(mInstantHotspot);
+        mSettings.mInstantHotspot = mInstantHotspot;
     }
 
     @Test
@@ -373,6 +383,47 @@
     }
 
     @Test
+    public void setupInstantHotspot_featureNotAvailable_doNothing() {
+        mSettings.setupInstantHotspot(false /* isFeatureAvailable */);
+
+        verify(mSettings, never()).findPreference(KEY_INSTANT_HOTSPOT);
+        verify(mWifiTetherViewModel, never()).getInstantHotspotSummary();
+    }
+
+    @Test
+    public void setupInstantHotspot_featureAvailable_doSetup() {
+        when(mWifiTetherViewModel.isInstantHotspotFeatureAvailable()).thenReturn(true);
+
+        mSettings.setupInstantHotspot(true /* isFeatureAvailable */);
+
+        verify(mSettings).findPreference(KEY_INSTANT_HOTSPOT);
+        verify(mInstantHotspotSummary).observe(any(), any());
+        verify(mInstantHotspot).setOnPreferenceClickListener(any());
+    }
+
+    @Test
+    public void onInstantHotspotChanged_nullRecord_setVisibleFalse() {
+        mSettings.onInstantHotspotChanged(null);
+
+        verify(mInstantHotspot).setVisible(false);
+    }
+
+    @Test
+    public void onInstantHotspotChanged_summaryNull_setVisibleFalse() {
+        mSettings.onInstantHotspotChanged(null);
+
+        verify(mInstantHotspot).setVisible(false);
+    }
+
+    @Test
+    public void onInstantHotspotChanged_summaryNotNull_setVisibleAndSummary() {
+        mSettings.onInstantHotspotChanged(SUMMARY);
+
+        verify(mInstantHotspot).setVisible(true);
+        verify(mInstantHotspot).setSummary(SUMMARY);
+    }
+
+    @Test
     public void buildNewConfig_speedFeatureIsAvailableAndPasswordChanged_bandShouldNotBeLost() {
         String newPassword = "new" + PASSWORD;
         SoftApConfiguration currentConfig = new SoftApConfiguration.Builder()
diff --git a/tests/robotests/testutils/com/android/settings/testutils/shadow/ShadowUserManager.java b/tests/robotests/testutils/com/android/settings/testutils/shadow/ShadowUserManager.java
index 0b3d3f9..c8d2866 100644
--- a/tests/robotests/testutils/com/android/settings/testutils/shadow/ShadowUserManager.java
+++ b/tests/robotests/testutils/com/android/settings/testutils/shadow/ShadowUserManager.java
@@ -16,6 +16,8 @@
 
 package com.android.settings.testutils.shadow;
 
+import static android.os.Build.VERSION_CODES.LOLLIPOP;
+
 import android.annotation.UserIdInt;
 import android.content.pm.UserInfo;
 import android.os.Bundle;
@@ -24,6 +26,9 @@
 import android.os.UserManager.EnforcingUser;
 
 import com.google.android.collect.Maps;
+import com.google.common.collect.BiMap;
+import com.google.common.collect.HashBiMap;
+import com.google.common.collect.ImmutableList;
 
 import org.robolectric.RuntimeEnvironment;
 import org.robolectric.annotation.Implementation;
@@ -32,6 +37,7 @@
 import org.robolectric.shadow.api.Shadow;
 
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -43,6 +49,7 @@
 public class ShadowUserManager extends org.robolectric.shadows.ShadowUserManager {
 
     private static boolean sIsSupportsMultipleUsers;
+    private static boolean sIsMultipleAdminEnabled = false;
 
     private static final int PRIMARY_USER_ID = 0;
 
@@ -50,12 +57,16 @@
     private final Map<String, List<EnforcingUser>> mRestrictionSources = new HashMap<>();
     private final List<UserInfo> mUserProfileInfos = new ArrayList<>();
     private final Set<Integer> mManagedProfiles = new HashSet<>();
+    private final Map<Integer, Integer> mProfileToParent = new HashMap<>();
+    private final Map<Integer, UserInfo> mUserInfoMap = new HashMap<>();
     private final Set<String> mEnabledTypes = new HashSet<>();
+    private BiMap<UserHandle, Long> mUserProfiles = HashBiMap.create();
     private boolean mIsQuietModeEnabled = false;
     private int[] mProfileIdsForUser = new int[0];
     private boolean mUserSwitchEnabled;
     private Bundle mDefaultGuestUserRestriction = new Bundle();
     private boolean mIsGuestUser = false;
+    private long mNextUserSerial = 0;
 
     private @UserManager.UserSwitchabilityResult int mSwitchabilityStatus =
             UserManager.SWITCHABILITY_STATUS_OK;
@@ -70,11 +81,47 @@
         sIsSupportsMultipleUsers = false;
     }
 
+    /**
+     * Creates a user with the specified name, userId and flags.
+     *
+     * @param id the unique id of user
+     * @param name name of the user
+     * @param flags 16 bits for user type. See {@link UserInfo#flags}
+     */
+    @Override public UserHandle addUser(int id, String name, int flags) {
+        UserHandle userHandle = super.addUser(id, name, flags);
+        mUserInfoMap.put(id, new UserInfo(id, name, flags));
+        return userHandle;
+    }
+
+    /** Add a profile to be returned by {@link #getProfiles(int)}. */
+    public void addProfile(
+            int userHandle, int profileUserHandle, String profileName, int profileFlags) {
+        UserInfo profileUserInfo = new UserInfo(profileUserHandle, profileName, profileFlags);
+        mUserProfileInfos.add(profileUserInfo);
+        mUserInfoMap.put(profileUserHandle, profileUserInfo);
+        mProfileToParent.put(profileUserHandle, userHandle);
+        if (profileFlags == UserInfo.FLAG_MANAGED_PROFILE) {
+            setManagedProfiles(new HashSet<>(Arrays.asList(profileUserHandle)));
+        }
+    }
+
     @Implementation
     protected List<UserInfo> getProfiles(@UserIdInt int userHandle) {
         return mUserProfileInfos;
     }
 
+    /**
+     * If this profile has been added using {@link #addProfile}, return its parent.
+     */
+    @Implementation(minSdk = LOLLIPOP)
+    protected UserInfo getProfileParent(int userHandle) {
+        if (!mProfileToParent.containsKey(userHandle)) {
+            return null;
+        }
+        return mUserInfoMap.get(mProfileToParent.get(userHandle));
+    }
+
     @Implementation
     protected int[] getProfileIds(@UserIdInt int userHandle, boolean enabledOnly) {
         int[] ids = new int[mUserProfileInfos.size()];
@@ -272,6 +319,19 @@
         }
     }
 
+    /**
+     * Sets that the current user is an admin user; controls the return value of
+     * {@link UserManager#isAdminUser}.
+     */
+    public void setIsAdminUser(boolean isAdminUser) {
+        UserInfo userInfo = getUserInfo(UserHandle.myUserId());
+        if (isAdminUser) {
+            userInfo.flags |= UserInfo.FLAG_ADMIN;
+        } else {
+            userInfo.flags &= ~UserInfo.FLAG_ADMIN;
+        }
+    }
+
     @Implementation
     protected boolean isGuestUser() {
         return mIsGuestUser;
@@ -280,4 +340,27 @@
     public void setGuestUser(boolean isGuestUser) {
         mIsGuestUser = isGuestUser;
     }
+
+    public static void setIsMultipleAdminEnabled(boolean enableMultipleAdmin) {
+        sIsMultipleAdminEnabled = enableMultipleAdmin;
+    }
+
+    /**
+     * Adds a profile associated for the user that the calling process is running on.
+     *
+     * <p>The user is assigned an arbitrary unique serial number.
+     *
+     * @return the user's serial number
+     * @deprecated use either addUser() or addProfile()
+     */
+    @Deprecated
+    public long addUserProfile(UserHandle userHandle) {
+        long serialNumber = mNextUserSerial++;
+        mUserProfiles.put(userHandle, serialNumber);
+        return serialNumber;
+    }
+
+    protected List<UserHandle> getUserProfiles() {
+        return ImmutableList.copyOf(mUserProfiles.keySet());
+    }
 }
diff --git a/tests/spa_unit/src/com/android/settings/spa/app/backgroundinstall/BackgroundInstalledAppsPageProviderTest.kt b/tests/spa_unit/src/com/android/settings/spa/app/backgroundinstall/BackgroundInstalledAppsPageProviderTest.kt
index 68ad065..ccd385f 100644
--- a/tests/spa_unit/src/com/android/settings/spa/app/backgroundinstall/BackgroundInstalledAppsPageProviderTest.kt
+++ b/tests/spa_unit/src/com/android/settings/spa/app/backgroundinstall/BackgroundInstalledAppsPageProviderTest.kt
@@ -31,9 +31,8 @@
 import com.android.settings.R
 import com.android.settingslib.spa.framework.compose.stateOf
 import com.android.settingslib.spa.testutils.FakeNavControllerWrapper
-import com.android.settingslib.spa.testutils.any
 import com.android.settingslib.spaprivileged.template.app.AppListItemModel
-import com.google.common.truth.Truth
+import com.google.common.truth.Truth.assertThat
 import kotlinx.coroutines.flow.first
 import kotlinx.coroutines.flow.flowOf
 import kotlinx.coroutines.test.runTest
@@ -41,12 +40,13 @@
 import org.junit.Rule
 import org.junit.Test
 import org.junit.runner.RunWith
-import org.mockito.ArgumentCaptor
-import org.mockito.ArgumentMatchers.eq
 import org.mockito.Mock
-import org.mockito.Mockito
 import org.mockito.junit.MockitoJUnit
 import org.mockito.junit.MockitoRule
+import org.mockito.kotlin.any
+import org.mockito.kotlin.argumentCaptor
+import org.mockito.kotlin.eq
+import org.mockito.kotlin.whenever
 
 @RunWith(AndroidJUnit4::class)
 class BackgroundInstalledAppsPageProviderTest {
@@ -67,26 +67,25 @@
     @Mock
     private lateinit var mockBackgroundInstallControlService: IBackgroundInstallControlService
 
-    private var packageInfoFlagsCaptor =
-        ArgumentCaptor.forClass(PackageManager.PackageInfoFlags::class.java)
+    private var packageInfoFlagsCaptor = argumentCaptor<PackageManager.PackageInfoFlags>()
 
     private val fakeNavControllerWrapper = FakeNavControllerWrapper()
 
     @Before
     fun setup() {
-        Mockito.`when`(mockContext.packageManager).thenReturn(mockPackageManager)
+        whenever(mockContext.packageManager).thenReturn(mockPackageManager)
     }
     @Test
     fun allAppListPageProvider_name() {
-        Truth.assertThat(BackgroundInstalledAppsPageProvider.name)
+        assertThat(BackgroundInstalledAppsPageProvider.name)
             .isEqualTo(EXPECTED_PROVIDER_NAME)
     }
 
     @Test
     fun injectEntry_title() {
-        Mockito.`when`(mockBackgroundInstallControlService
-            .getBackgroundInstalledPackages(any(Long::class.java), any(Int::class.java)))
+        whenever(mockBackgroundInstallControlService.getBackgroundInstalledPackages(any(), any()))
             .thenReturn(ParceledListSlice(listOf()))
+
         setInjectEntry(false)
 
         composeTestRule.onNodeWithText(
@@ -103,9 +102,9 @@
 
     @Test
     fun injectEntry_summary() {
-        Mockito.`when`(mockBackgroundInstallControlService
-            .getBackgroundInstalledPackages(any(Long::class.java), any(Int::class.java)))
+        whenever(mockBackgroundInstallControlService.getBackgroundInstalledPackages(any(), any()))
             .thenReturn(ParceledListSlice(listOf()))
+
         setInjectEntry(false)
 
         composeTestRule.onNodeWithText("0 apps").assertIsDisplayed()
@@ -120,15 +119,14 @@
 
     @Test
     fun injectEntry_onClick_navigate() {
-        Mockito.`when`(mockBackgroundInstallControlService
-            .getBackgroundInstalledPackages(any(Long::class.java), any(Int::class.java)))
+        whenever(mockBackgroundInstallControlService.getBackgroundInstalledPackages(any(), any()))
             .thenReturn(ParceledListSlice(listOf()))
         setInjectEntry(false)
 
         composeTestRule.onNodeWithText(
             context.getString(R.string.background_install_title)).performClick()
 
-        Truth.assertThat(fakeNavControllerWrapper.navigateCalledWith)
+        assertThat(fakeNavControllerWrapper.navigateCalledWith)
             .isEqualTo(EXPECTED_PROVIDER_NAME)
     }
 
@@ -166,7 +164,7 @@
 
         composeTestRule.onNodeWithText(TEST_LABEL).performClick()
 
-        Truth.assertThat(fakeNavControllerWrapper.navigateCalledWith)
+        assertThat(fakeNavControllerWrapper.navigateCalledWith)
             .isEqualTo("AppInfoSettings/package.name/0")
     }
 
@@ -181,7 +179,7 @@
                     System.currentTimeMillis()
                 ))
 
-        Truth.assertThat(actualGroupTitle).isEqualTo("Apps installed in the last 6 months")
+        assertThat(actualGroupTitle).isEqualTo("Apps installed in the last 6 months")
     }
 
     @Test
@@ -195,13 +193,13 @@
                     0L
         ))
 
-        Truth.assertThat(actualGroupTitle).isEqualTo("Apps installed more than 6 months ago")
+        assertThat(actualGroupTitle).isEqualTo("Apps installed more than 6 months ago")
     }
 
     @Test
     fun backgroundInstalledAppsWithGroupingListModel_transform() = runTest {
         val listModel = BackgroundInstalledAppsWithGroupingListModel(mockContext)
-        Mockito.`when`(mockPackageManager.getPackageInfoAsUser(
+        whenever(mockPackageManager.getPackageInfoAsUser(
             eq(TEST_PACKAGE_NAME),
             packageInfoFlagsCaptor.capture(),
             eq(TEST_USER_ID))
@@ -211,16 +209,16 @@
 
         val recordList = recordListFlow.first()
 
-        Truth.assertThat(recordList).hasSize(1)
-        Truth.assertThat(recordList[0].app).isSameInstanceAs(APP)
-        Truth.assertThat(packageInfoFlagsCaptor.value.value).isEqualTo(EXPECTED_PACKAGE_INFO_FLAG)
+        assertThat(recordList).hasSize(1)
+        assertThat(recordList[0].app).isSameInstanceAs(APP)
+        assertThat(packageInfoFlagsCaptor.firstValue.value).isEqualTo(EXPECTED_PACKAGE_INFO_FLAG)
     }
 
     @Test
     fun backgroundInstalledAppsWithGroupingListModel_filter() = runTest {
         val listModel = BackgroundInstalledAppsWithGroupingListModel(mockContext)
         listModel.setBackgroundInstallControlService(mockBackgroundInstallControlService)
-        Mockito.`when`(mockBackgroundInstallControlService.getBackgroundInstalledPackages(
+        whenever(mockBackgroundInstallControlService.getBackgroundInstalledPackages(
             PackageManager.MATCH_ALL.toLong(),
             TEST_USER_ID
         )).thenReturn(ParceledListSlice(listOf(PACKAGE_INFO)))
@@ -231,10 +229,9 @@
             flowOf(listOf(APP_RECORD_WITH_PACKAGE_MATCH, APP_RECORD_WITHOUT_PACKAGE_MATCH))
         )
 
-
         val recordList = recordListFlow.first()
-        Truth.assertThat(recordList).hasSize(1)
-        Truth.assertThat(recordList[0]).isSameInstanceAs(APP_RECORD_WITH_PACKAGE_MATCH)
+        assertThat(recordList).hasSize(1)
+        assertThat(recordList[0]).isSameInstanceAs(APP_RECORD_WITH_PACKAGE_MATCH)
     }
 
     private fun setItemContent() {
diff --git a/tests/spa_unit/src/com/android/settings/spa/notification/AppNotificationRepositoryTest.kt b/tests/spa_unit/src/com/android/settings/spa/notification/AppNotificationRepositoryTest.kt
index 87ff9ba..5dcc671 100644
--- a/tests/spa_unit/src/com/android/settings/spa/notification/AppNotificationRepositoryTest.kt
+++ b/tests/spa_unit/src/com/android/settings/spa/notification/AppNotificationRepositoryTest.kt
@@ -30,7 +30,6 @@
 import androidx.test.core.app.ApplicationProvider
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import com.android.settings.R
-import com.android.settingslib.spa.testutils.any
 import com.android.settingslib.spaprivileged.model.app.IPackageManagers
 import com.android.settingslib.spaprivileged.model.app.userId
 import com.google.common.truth.Truth.assertThat
@@ -42,11 +41,12 @@
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.mockito.Mock
-import org.mockito.Mockito.eq
-import org.mockito.Mockito.verify
 import org.mockito.junit.MockitoJUnit
 import org.mockito.junit.MockitoRule
-import org.mockito.Mockito.`when` as whenever
+import org.mockito.kotlin.any
+import org.mockito.kotlin.eq
+import org.mockito.kotlin.verify
+import org.mockito.kotlin.whenever
 
 @RunWith(AndroidJUnit4::class)
 class AppNotificationRepositoryTest {
diff --git a/tests/unit/src/com/android/settings/datausage/DataUsageInfoControllerTest.java b/tests/unit/src/com/android/settings/datausage/DataUsageInfoControllerTest.java
index b80e9d2..cb5860a 100644
--- a/tests/unit/src/com/android/settings/datausage/DataUsageInfoControllerTest.java
+++ b/tests/unit/src/com/android/settings/datausage/DataUsageInfoControllerTest.java
@@ -18,9 +18,6 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
-import android.net.NetworkPolicy;
-import android.net.NetworkTemplate;
-
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 
 import com.android.settingslib.net.DataUsageController.DataUsageInfo;
@@ -32,7 +29,6 @@
 @RunWith(AndroidJUnit4.class)
 public class DataUsageInfoControllerTest {
 
-    private static final int NEGATIVE = -1;
     private static final int ZERO = 0;
     private static final int POSITIVE_SMALL = 1;
     private static final int POSITIVE_LARGE = 5;
@@ -99,80 +95,4 @@
 
         assertThat(mInfoController.getSummaryLimit(info)).isEqualTo(info.usageLevel);
     }
-
-    private NetworkPolicy getDefaultNetworkPolicy() {
-        NetworkTemplate template = new NetworkTemplate.Builder(NetworkTemplate.MATCH_WIFI).build();
-        int cycleDay  = -1;
-        String cycleTimezone = "UTC";
-        long warningBytes = -1;
-        long limitBytes = -1;
-        return new NetworkPolicy(template, cycleDay, cycleTimezone, warningBytes, limitBytes, true);
-    }
-
-    @Test
-    public void updateDataLimit_NullArguments_NoError() {
-        mInfoController.updateDataLimit(null, null);
-        mInfoController.updateDataLimit(info, null);
-        mInfoController.updateDataLimit(null, getDefaultNetworkPolicy());
-    }
-
-    @Test
-    public void updateDataLimit_NegativeWarning_UpdatedToZero() {
-        NetworkPolicy policy = getDefaultNetworkPolicy();
-        policy.warningBytes = NEGATIVE;
-
-        mInfoController.updateDataLimit(info, policy);
-
-        assertThat(info.warningLevel).isEqualTo(ZERO);
-    }
-
-    @Test
-    public void updateDataLimit_WarningZero_UpdatedToZero() {
-        NetworkPolicy policy = getDefaultNetworkPolicy();
-        policy.warningBytes = ZERO;
-
-        mInfoController.updateDataLimit(info, policy);
-
-        assertThat(info.warningLevel).isEqualTo(ZERO);
-    }
-
-    @Test
-    public void updateDataLimit_WarningPositive_UpdatedToWarning() {
-        NetworkPolicy policy = getDefaultNetworkPolicy();
-        policy.warningBytes = POSITIVE_SMALL;
-
-        mInfoController.updateDataLimit(info, policy);
-
-        assertThat(info.warningLevel).isEqualTo(policy.warningBytes);
-    }
-
-    @Test
-    public void updateDataLimit_LimitNegative_UpdatedToZero() {
-        NetworkPolicy policy = getDefaultNetworkPolicy();
-        policy.limitBytes = NEGATIVE;
-
-        mInfoController.updateDataLimit(info, policy);
-
-        assertThat(info.limitLevel).isEqualTo(ZERO);
-    }
-
-    @Test
-    public void updateDataLimit_LimitZero_UpdatedToZero() {
-        NetworkPolicy policy = getDefaultNetworkPolicy();
-        policy.limitBytes = ZERO;
-
-        mInfoController.updateDataLimit(info, policy);
-
-        assertThat(info.limitLevel).isEqualTo(ZERO);
-    }
-
-    @Test
-    public void updateDataLimit_LimitPositive_UpdatedToLimit() {
-        NetworkPolicy policy = getDefaultNetworkPolicy();
-        policy.limitBytes = POSITIVE_SMALL;
-
-        mInfoController.updateDataLimit(info, policy);
-        
-        assertThat(info.limitLevel).isEqualTo(policy.limitBytes);
-    }
 }
diff --git a/tests/unit/src/com/android/settings/fingerprint2/domain/interactor/FakeFingerprintManagerInteractor.kt b/tests/unit/src/com/android/settings/fingerprint2/domain/interactor/FakeFingerprintManagerInteractor.kt
index 1848c01..759306e 100644
--- a/tests/unit/src/com/android/settings/fingerprint2/domain/interactor/FakeFingerprintManagerInteractor.kt
+++ b/tests/unit/src/com/android/settings/fingerprint2/domain/interactor/FakeFingerprintManagerInteractor.kt
@@ -20,8 +20,8 @@
 import android.hardware.fingerprint.FingerprintSensorProperties.TYPE_POWER_BUTTON
 import android.hardware.fingerprint.FingerprintSensorPropertiesInternal
 import com.android.settings.biometrics.fingerprint2.domain.interactor.FingerprintManagerInteractor
-import com.android.settings.biometrics.fingerprint2.ui.viewmodel.FingerprintAuthAttemptViewModel
-import com.android.settings.biometrics.fingerprint2.ui.viewmodel.FingerprintViewModel
+import com.android.settings.biometrics.fingerprint2.shared.model.FingerprintAuthAttemptViewModel
+import com.android.settings.biometrics.fingerprint2.shared.model.FingerprintViewModel
 import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.flow
 
diff --git a/tests/unit/src/com/android/settings/fingerprint2/domain/interactor/FingerprintManagerInteractorTest.kt b/tests/unit/src/com/android/settings/fingerprint2/domain/interactor/FingerprintManagerInteractorTest.kt
index 7af740a..cc6f42a 100644
--- a/tests/unit/src/com/android/settings/fingerprint2/domain/interactor/FingerprintManagerInteractorTest.kt
+++ b/tests/unit/src/com/android/settings/fingerprint2/domain/interactor/FingerprintManagerInteractorTest.kt
@@ -29,8 +29,8 @@
 import com.android.settings.biometrics.GatekeeperPasswordProvider
 import com.android.settings.biometrics.fingerprint2.domain.interactor.FingerprintManagerInteractor
 import com.android.settings.biometrics.fingerprint2.domain.interactor.FingerprintManagerInteractorImpl
-import com.android.settings.biometrics.fingerprint2.ui.viewmodel.FingerprintAuthAttemptViewModel
-import com.android.settings.biometrics.fingerprint2.ui.viewmodel.FingerprintViewModel
+import com.android.settings.biometrics.fingerprint2.shared.model.FingerprintAuthAttemptViewModel
+import com.android.settings.biometrics.fingerprint2.shared.model.FingerprintViewModel
 import com.android.settings.password.ChooseLockSettingsHelper
 import com.google.common.truth.Truth.assertThat
 import kotlinx.coroutines.cancelAndJoin
diff --git a/tests/unit/src/com/android/settings/fingerprint2/viewmodel/FingerprintSettingsNavigationViewModelTest.kt b/tests/unit/src/com/android/settings/fingerprint2/settings/viewmodel/FingerprintSettingsNavigationViewModelTest.kt
similarity index 93%
rename from tests/unit/src/com/android/settings/fingerprint2/viewmodel/FingerprintSettingsNavigationViewModelTest.kt
rename to tests/unit/src/com/android/settings/fingerprint2/settings/viewmodel/FingerprintSettingsNavigationViewModelTest.kt
index 9206afb..6bb8a16 100644
--- a/tests/unit/src/com/android/settings/fingerprint2/viewmodel/FingerprintSettingsNavigationViewModelTest.kt
+++ b/tests/unit/src/com/android/settings/fingerprint2/settings/viewmodel/FingerprintSettingsNavigationViewModelTest.kt
@@ -14,18 +14,18 @@
  * limitations under the License.
  */
 
-package com.android.settings.fingerprint2.viewmodel
+package com.android.settings.fingerprint2.settings.viewmodel
 
 import androidx.arch.core.executor.testing.InstantTaskExecutorRule
 import com.android.settings.biometrics.BiometricEnrollBase
-import com.android.settings.biometrics.fingerprint2.ui.viewmodel.EnrollFirstFingerprint
-import com.android.settings.biometrics.fingerprint2.ui.viewmodel.FingerprintSettingsNavigationViewModel
-import com.android.settings.biometrics.fingerprint2.ui.viewmodel.FingerprintViewModel
-import com.android.settings.biometrics.fingerprint2.ui.viewmodel.FinishSettings
-import com.android.settings.biometrics.fingerprint2.ui.viewmodel.FinishSettingsWithResult
-import com.android.settings.biometrics.fingerprint2.ui.viewmodel.LaunchConfirmDeviceCredential
-import com.android.settings.biometrics.fingerprint2.ui.viewmodel.NextStepViewModel
-import com.android.settings.biometrics.fingerprint2.ui.viewmodel.ShowSettings
+import com.android.settings.biometrics.fingerprint2.shared.model.FingerprintViewModel
+import com.android.settings.biometrics.fingerprint2.ui.settings.viewmodel.EnrollFirstFingerprint
+import com.android.settings.biometrics.fingerprint2.ui.settings.viewmodel.FingerprintSettingsNavigationViewModel
+import com.android.settings.biometrics.fingerprint2.ui.settings.viewmodel.FinishSettings
+import com.android.settings.biometrics.fingerprint2.ui.settings.viewmodel.FinishSettingsWithResult
+import com.android.settings.biometrics.fingerprint2.ui.settings.viewmodel.LaunchConfirmDeviceCredential
+import com.android.settings.biometrics.fingerprint2.ui.settings.viewmodel.NextStepViewModel
+import com.android.settings.biometrics.fingerprint2.ui.settings.viewmodel.ShowSettings
 import com.android.settings.fingerprint2.domain.interactor.FakeFingerprintManagerInteractor
 import com.google.common.truth.Truth.assertThat
 import kotlinx.coroutines.Dispatchers
diff --git a/tests/unit/src/com/android/settings/fingerprint2/viewmodel/FingerprintSettingsViewModelTest.kt b/tests/unit/src/com/android/settings/fingerprint2/settings/viewmodel/FingerprintSettingsViewModelTest.kt
similarity index 96%
rename from tests/unit/src/com/android/settings/fingerprint2/viewmodel/FingerprintSettingsViewModelTest.kt
rename to tests/unit/src/com/android/settings/fingerprint2/settings/viewmodel/FingerprintSettingsViewModelTest.kt
index 8bd0b10..e8a4d55 100644
--- a/tests/unit/src/com/android/settings/fingerprint2/viewmodel/FingerprintSettingsViewModelTest.kt
+++ b/tests/unit/src/com/android/settings/fingerprint2/settings/viewmodel/FingerprintSettingsViewModelTest.kt
@@ -14,17 +14,17 @@
  * limitations under the License.
  */
 
-package com.android.settings.fingerprint2.viewmodel
+package com.android.settings.fingerprint2.settings.viewmodel
 
 import android.hardware.biometrics.SensorProperties
 import android.hardware.fingerprint.FingerprintSensorProperties
 import android.hardware.fingerprint.FingerprintSensorPropertiesInternal
 import androidx.arch.core.executor.testing.InstantTaskExecutorRule
-import com.android.settings.biometrics.fingerprint2.ui.viewmodel.FingerprintAuthAttemptViewModel
-import com.android.settings.biometrics.fingerprint2.ui.viewmodel.FingerprintSettingsNavigationViewModel
-import com.android.settings.biometrics.fingerprint2.ui.viewmodel.FingerprintSettingsViewModel
-import com.android.settings.biometrics.fingerprint2.ui.viewmodel.FingerprintViewModel
-import com.android.settings.biometrics.fingerprint2.ui.viewmodel.PreferenceViewModel
+import com.android.settings.biometrics.fingerprint2.shared.model.FingerprintAuthAttemptViewModel
+import com.android.settings.biometrics.fingerprint2.shared.model.FingerprintViewModel
+import com.android.settings.biometrics.fingerprint2.ui.settings.viewmodel.FingerprintSettingsNavigationViewModel
+import com.android.settings.biometrics.fingerprint2.ui.settings.viewmodel.FingerprintSettingsViewModel
+import com.android.settings.biometrics.fingerprint2.ui.settings.viewmodel.PreferenceViewModel
 import com.android.settings.fingerprint2.domain.interactor.FakeFingerprintManagerInteractor
 import com.google.common.truth.Truth.assertThat
 import kotlinx.coroutines.Dispatchers
diff --git a/tests/unit/src/com/android/settings/regionalpreferences/NumberingSystemItemControllerTest.java b/tests/unit/src/com/android/settings/regionalpreferences/NumberingSystemItemControllerTest.java
index 5c42ad9..0a67824 100644
--- a/tests/unit/src/com/android/settings/regionalpreferences/NumberingSystemItemControllerTest.java
+++ b/tests/unit/src/com/android/settings/regionalpreferences/NumberingSystemItemControllerTest.java
@@ -24,7 +24,6 @@
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.verify;
 
-import android.app.settings.SettingsEnums;
 import android.content.Context;
 import android.os.Bundle;
 import android.os.LocaleList;
@@ -52,7 +51,6 @@
     private NumberingPreferencesFragment mFragment;
     private PreferenceScreen mPreferenceScreen;
     private LocaleList mCacheLocale;
-    private FakeFeatureFactory mFeatureFactory;
 
     @Before
     @UiThreadTest
@@ -61,7 +59,6 @@
             Looper.prepare();
         }
         mApplicationContext = ApplicationProvider.getApplicationContext();
-        mFeatureFactory = FakeFeatureFactory.setupForTest();
         mFragment = spy(new NumberingPreferencesFragment());
         PreferenceManager preferenceManager = new PreferenceManager(mApplicationContext);
         mPreferenceScreen = preferenceManager.createPreferenceScreen(mApplicationContext);
@@ -97,10 +94,6 @@
         }
 
         assertTrue(isCallingStartActivity);
-        verify(mFeatureFactory.metricsFeatureProvider).action(
-                mApplicationContext,
-                SettingsEnums.ACTION_CHOOSE_LANGUAGE_FOR_NUMBERS_PREFERENCES,
-                "I_am_the_key");
     }
 
     @Test
@@ -121,9 +114,6 @@
         mController.handlePreferenceTreeClick(preference);
 
         verify(mFragment).setArguments(any());
-        verify(mFeatureFactory.metricsFeatureProvider).action(
-                mApplicationContext, SettingsEnums.ACTION_SET_NUMBERS_PREFERENCES,
-                "test_key");
     }
 
     @Test
diff --git a/tests/unit/src/com/android/settings/sim/SimDialogActivityTest.java b/tests/unit/src/com/android/settings/sim/SimDialogActivityTest.java
deleted file mode 100644
index a232034..0000000
--- a/tests/unit/src/com/android/settings/sim/SimDialogActivityTest.java
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * Copyright (C) 2023 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.sim;
-
-import static android.os.UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.mockito.Mockito.when;
-
-import android.content.Context;
-import android.os.UserManager;
-
-import androidx.test.annotation.UiThreadTest;
-import androidx.test.core.app.ApplicationProvider;
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.Spy;
-import org.mockito.junit.MockitoJUnit;
-import org.mockito.junit.MockitoRule;
-
-@RunWith(AndroidJUnit4.class)
-@UiThreadTest
-public class SimDialogActivityTest {
-    @Rule
-    public final MockitoRule mMockitoRule = MockitoJUnit.rule();
-    @Spy
-    private final Context mContext = ApplicationProvider.getApplicationContext();
-    @Mock
-    private UserManager mUserManager;
-
-    private MockSimDialogActivity mActivity;
-
-    @Before
-    public void setUp() {
-        when(mContext.getSystemService(UserManager.class)).thenReturn(mUserManager);
-        when(mUserManager.isGuestUser()).thenReturn(false);
-        when(mUserManager.hasUserRestriction(DISALLOW_CONFIG_MOBILE_NETWORKS)).thenReturn(false);
-
-        mActivity = new MockSimDialogActivity();
-    }
-
-    @Test
-    public void isUiRestricted_normally_returnFalse() {
-        assertThat(mActivity.isUiRestricted()).isFalse();
-    }
-
-    @Test
-    public void isUiRestricted_isGuestUser_returnTrue() {
-        when(mUserManager.isGuestUser()).thenReturn(true);
-
-        assertThat(mActivity.isUiRestricted()).isTrue();
-    }
-
-    @Test
-    public void isUiRestricted_hasUserRestriction_returnTrue() {
-        when(mUserManager.hasUserRestriction(DISALLOW_CONFIG_MOBILE_NETWORKS)).thenReturn(true);
-
-        assertThat(mActivity.isUiRestricted()).isTrue();
-    }
-
-    public class MockSimDialogActivity extends SimDialogActivity {
-        @Override
-        public Context getApplicationContext() {
-            return mContext;
-        }
-    }
-}
diff --git a/tests/unit/src/com/android/settings/sim/SimDialogActivityTest.kt b/tests/unit/src/com/android/settings/sim/SimDialogActivityTest.kt
new file mode 100644
index 0000000..9546d69
--- /dev/null
+++ b/tests/unit/src/com/android/settings/sim/SimDialogActivityTest.kt
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2023 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.sim
+
+import android.content.Context
+import android.os.UserManager
+import androidx.test.annotation.UiThreadTest
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.settingslib.spaprivileged.framework.common.userManager
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.Spy
+import org.mockito.junit.MockitoJUnit
+import org.mockito.junit.MockitoRule
+import org.mockito.Mockito.`when` as whenever
+
+@RunWith(AndroidJUnit4::class)
+@UiThreadTest
+class SimDialogActivityTest {
+    @get:Rule
+    val mockito: MockitoRule = MockitoJUnit.rule()
+
+    @Spy
+    private val context: Context = ApplicationProvider.getApplicationContext()
+
+    @Mock
+    private lateinit var userManager: UserManager
+
+    private var activity = MockSimDialogActivity()
+
+    @Before
+    fun setUp() {
+        whenever(context.userManager).thenReturn(userManager)
+        whenever(userManager.isGuestUser).thenReturn(false)
+        whenever(userManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS))
+            .thenReturn(false)
+    }
+
+    @Test
+    fun isUiRestricted_normally_returnFalse() {
+        assertThat(activity.isUiRestricted).isFalse()
+    }
+
+    @Test
+    fun isUiRestricted_isGuestUser_returnTrue() {
+        whenever(userManager.isGuestUser).thenReturn(true)
+
+        assertThat(activity.isUiRestricted).isTrue()
+    }
+
+    @Test
+    fun isUiRestricted_hasUserRestriction_returnTrue() {
+        whenever(userManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS))
+            .thenReturn(true)
+
+        assertThat(activity.isUiRestricted).isTrue()
+    }
+
+    inner class MockSimDialogActivity : SimDialogActivity() {
+        override fun getApplicationContext() = context
+    }
+}
diff --git a/tests/unit/src/com/android/settings/wifi/repository/SharedConnectivityRepositoryTest.java b/tests/unit/src/com/android/settings/wifi/repository/SharedConnectivityRepositoryTest.java
new file mode 100644
index 0000000..4aef552
--- /dev/null
+++ b/tests/unit/src/com/android/settings/wifi/repository/SharedConnectivityRepositoryTest.java
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) 2023 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.wifi.repository;
+
+import static android.app.PendingIntent.FLAG_IMMUTABLE;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.app.PendingIntent;
+import android.content.Context;
+import android.content.Intent;
+import android.net.wifi.sharedconnectivity.app.SharedConnectivityManager;
+import android.net.wifi.sharedconnectivity.app.SharedConnectivitySettingsState;
+
+import androidx.test.core.app.ApplicationProvider;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.Spy;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+
+public class SharedConnectivityRepositoryTest {
+
+    @Rule
+    public final MockitoRule mMockitoRule = MockitoJUnit.rule();
+    @Spy
+    private Context mContext = ApplicationProvider.getApplicationContext();
+    @Mock
+    private SharedConnectivityManager mManager;
+
+    private SharedConnectivityRepository mRepository;
+    private PendingIntent mIntent = PendingIntent
+            .getActivity(mContext, 0, new Intent("test"), FLAG_IMMUTABLE);
+    private SharedConnectivitySettingsState mState = new SharedConnectivitySettingsState.Builder()
+            .setInstantTetherSettingsPendingIntent(mIntent).build();
+
+    @Before
+    public void setUp() {
+        when(mContext.getSystemService(SharedConnectivityManager.class)).thenReturn(mManager);
+        when(mManager.getSettingsState()).thenReturn(mState);
+
+        mRepository = spy(new SharedConnectivityRepository(mContext, true /* isConfigEnabled */));
+    }
+
+    @Test
+    public void constructor_configEnabled_registerCallback() {
+        verify(mManager).registerCallback(any(), any());
+    }
+
+    @Test
+    public void constructor_configNotEnabled_doNotRegisterCallback() {
+        SharedConnectivityManager manager = mock(SharedConnectivityManager.class);
+        when(mContext.getSystemService(SharedConnectivityManager.class)).thenReturn(manager);
+
+        mRepository = new SharedConnectivityRepository(mContext, false /* isConfigEnabled */);
+
+        verify(manager, never()).registerCallback(any(), any());
+    }
+
+    @Test
+    public void isServiceAvailable_configEnabled_returnTrue() {
+        mRepository = new SharedConnectivityRepository(mContext, true /* isConfigEnabled */);
+
+        assertThat(mRepository.isServiceAvailable()).isTrue();
+    }
+
+    @Test
+    public void isServiceAvailable_configNotEnabled_returnFalse() {
+        mRepository = new SharedConnectivityRepository(mContext, false /* isConfigEnabled */);
+
+        assertThat(mRepository.isServiceAvailable()).isFalse();
+    }
+
+    @Test
+    public void getSettingsState_isNotNull() {
+        assertThat(mRepository.getSettingsState()).isNotNull();
+    }
+
+    @Test
+    public void handleLaunchSettings_managerNull_doNothing() {
+        when(mContext.getSystemService(SharedConnectivityManager.class)).thenReturn(null);
+        mRepository = spy(new SharedConnectivityRepository(mContext, true /* isConfigEnabled */));
+
+        mRepository.handleLaunchSettings();
+
+        verify(mRepository, never()).sendSettingsIntent(mIntent);
+    }
+
+    @Test
+    public void handleLaunchSettings_stageNull_doNothing() {
+        when(mManager.getSettingsState()).thenReturn(null);
+
+        mRepository.handleLaunchSettings();
+
+        verify(mRepository, never()).sendSettingsIntent(mIntent);
+    }
+
+    @Test
+    public void handleLaunchSettings_intentNull_doNothing() {
+        mState = new SharedConnectivitySettingsState.Builder()
+                .setInstantTetherSettingsPendingIntent(null).build();
+        when(mManager.getSettingsState()).thenReturn(mState);
+
+        mRepository.handleLaunchSettings();
+
+        verify(mRepository, never()).sendSettingsIntent(mIntent);
+    }
+
+    @Test
+    public void handleLaunchSettings_allReady_sendSettingsIntent() {
+        mRepository.handleLaunchSettings();
+
+        verify(mRepository).sendSettingsIntent(mIntent);
+    }
+}
diff --git a/tests/unit/src/com/android/settings/wifi/tether/WifiTetherViewModelTest.java b/tests/unit/src/com/android/settings/wifi/tether/WifiTetherViewModelTest.java
index af1f62b..1c1473f 100644
--- a/tests/unit/src/com/android/settings/wifi/tether/WifiTetherViewModelTest.java
+++ b/tests/unit/src/com/android/settings/wifi/tether/WifiTetherViewModelTest.java
@@ -16,6 +16,9 @@
 
 package com.android.settings.wifi.tether;
 
+import static com.android.settings.wifi.tether.WifiTetherViewModel.RES_INSTANT_HOTSPOT_SUMMARY_OFF;
+import static com.android.settings.wifi.tether.WifiTetherViewModel.RES_INSTANT_HOTSPOT_SUMMARY_ON;
+
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.mockito.Mockito.verify;
@@ -23,12 +26,15 @@
 
 import android.app.Application;
 import android.net.wifi.SoftApConfiguration;
+import android.net.wifi.sharedconnectivity.app.SharedConnectivitySettingsState;
 
 import androidx.lifecycle.MutableLiveData;
 import androidx.test.annotation.UiThreadTest;
+import androidx.test.core.app.ApplicationProvider;
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 
 import com.android.settings.testutils.FakeFeatureFactory;
+import com.android.settings.wifi.repository.SharedConnectivityRepository;
 import com.android.settings.wifi.repository.WifiHotspotRepository;
 
 import org.junit.Before;
@@ -36,6 +42,7 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
+import org.mockito.Spy;
 import org.mockito.junit.MockitoJUnit;
 import org.mockito.junit.MockitoRule;
 
@@ -45,8 +52,8 @@
 public class WifiTetherViewModelTest {
     @Rule
     public final MockitoRule mMockitoRule = MockitoJUnit.rule();
-    @Mock
-    Application mApplication;
+    @Spy
+    Application mApplication = ApplicationProvider.getApplicationContext();
     @Mock
     Executor mExecutor;
     @Mock
@@ -57,6 +64,12 @@
     MutableLiveData<Integer> mSpeedType;
     @Mock
     private MutableLiveData<Boolean> mRestarting;
+    @Mock
+    private SharedConnectivityRepository mSharedConnectivityRepository;
+    @Mock
+    private MutableLiveData<SharedConnectivitySettingsState> mSettingsState;
+    @Mock
+    private MutableLiveData<String> mInstantHotspotSummary;
 
     WifiTetherViewModel mViewModel;
 
@@ -70,8 +83,18 @@
         when(mWifiHotspotRepository.getSecurityType()).thenReturn(mSecurityType);
         when(mWifiHotspotRepository.getSpeedType()).thenReturn(mSpeedType);
         when(mWifiHotspotRepository.getRestarting()).thenReturn(mRestarting);
+        when(featureFactory.getWifiFeatureProvider().getSharedConnectivityRepository())
+                .thenReturn(mSharedConnectivityRepository);
+        when(mSharedConnectivityRepository.isServiceAvailable()).thenReturn(true);
+        when(mSharedConnectivityRepository.getSettingsState()).thenReturn(mSettingsState);
 
         mViewModel = new WifiTetherViewModel(mApplication);
+        mViewModel.mInstantHotspotSummary = mInstantHotspotSummary;
+    }
+
+    @Test
+    public void constructor_observeData() {
+        verify(mSettingsState).observeForever(mViewModel.mInstantHotspotStateObserver);
     }
 
     @Test
@@ -83,6 +106,7 @@
 
         verify(mSecurityType).removeObserver(mViewModel.mSecurityTypeObserver);
         verify(mSpeedType).removeObserver(mViewModel.mSpeedTypeObserver);
+        verify(mSettingsState).removeObserver(mViewModel.mInstantHotspotStateObserver);
     }
 
     @Test
@@ -141,4 +165,59 @@
     public void getRestarting_shouldNotReturnNull() {
         assertThat(mViewModel.getRestarting()).isNotNull();
     }
+
+    @Test
+    public void isInstantHotspotFeatureAvailable_serviceAvailable_returnTrue() {
+        when(mSharedConnectivityRepository.isServiceAvailable()).thenReturn(true);
+
+        assertThat(mViewModel.isInstantHotspotFeatureAvailable()).isTrue();
+    }
+
+    @Test
+    public void isInstantHotspotFeatureAvailable_serviceNotAvailable_returnFalse() {
+        when(mSharedConnectivityRepository.isServiceAvailable()).thenReturn(false);
+
+        assertThat(mViewModel.isInstantHotspotFeatureAvailable()).isFalse();
+    }
+
+    @Test
+    public void getInstantHotspotSummary_isNotNull() {
+        assertThat(mViewModel.getInstantHotspotSummary()).isNotNull();
+    }
+
+    @Test
+    public void onInstantHotspotStateChanged_stageNull_summarySetValueNull() {
+        mViewModel.onInstantHotspotStateChanged(null);
+
+        verify(mInstantHotspotSummary).setValue(null);
+    }
+
+    @Test
+    public void onInstantHotspotStateChanged_stateEnabled_summarySetValueOn() {
+        SharedConnectivitySettingsState state = new SharedConnectivitySettingsState.Builder()
+                .setInstantTetherEnabled(true).build();
+
+        mViewModel.onInstantHotspotStateChanged(state);
+
+        verify(mInstantHotspotSummary)
+                .setValue(mApplication.getString(RES_INSTANT_HOTSPOT_SUMMARY_ON));
+    }
+
+    @Test
+    public void onInstantHotspotStateChanged_stateNotEnabled_recordVisibleSummaryOff() {
+        SharedConnectivitySettingsState state = new SharedConnectivitySettingsState.Builder()
+                .setInstantTetherEnabled(false).build();
+
+        mViewModel.onInstantHotspotStateChanged(state);
+
+        verify(mInstantHotspotSummary)
+                .setValue(mApplication.getString(RES_INSTANT_HOTSPOT_SUMMARY_OFF));
+    }
+
+    @Test
+    public void launchInstantHotspotSettings_launchSettingsByRepository() {
+        mViewModel.launchInstantHotspotSettings();
+
+        verify(mSharedConnectivityRepository).launchSettings();
+    }
 }