Merge "Fix that the padding top/bottom of the preview was wrong when display size is smallest."
diff --git a/res/values/strings.xml b/res/values/strings.xml
index fd186af..28055ab 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -11261,6 +11261,21 @@
     <!-- [CHAR_LIMIT=NONE] Label for when app is ignoring battery optimizations -->
     <string name="not_battery_optimizing">Not using battery optimization</string>
 
+    <!-- Preference title for battery optimization list page[CHAR_LIMIT=50]-->
+    <string name="app_battery_optimization_title">Manage battery usage</string>
+
+    <!-- Preference summary for battery optimization list page[CHAR_LIMIT=50]-->
+    <string name="app_battery_optimization_summary">Set battery usage for apps</string>
+
+    <!-- Filter title for battery unrestricted[CHAR_LIMIT=50]-->
+    <string name="filter_battery_unrestricted_title">Unrestricted</string>
+
+    <!-- Filter title for battery optimized[CHAR_LIMIT=50]-->
+    <string name="filter_battery_optimized_title">Optimized</string>
+
+    <!-- Filter title for battery restricted[CHAR_LIMIT=50]-->
+    <string name="filter_battery_restricted_title">Restricted</string>
+
     <!-- Text for the setting on whether you can type text into notifications without unlocking the device. -->
     <string name="lockscreen_remote_input">If device is locked, prevent typing replies or other text in notifications</string>
 
diff --git a/src/com/android/settings/Settings.java b/src/com/android/settings/Settings.java
index c3ab8e2..f7ba017 100644
--- a/src/com/android/settings/Settings.java
+++ b/src/com/android/settings/Settings.java
@@ -326,6 +326,8 @@
     public static class ChangeWifiStateActivity extends SettingsActivity { /* empty */ }
     public static class AppDrawOverlaySettingsActivity extends SettingsActivity { /* empty */ }
     public static class AppWriteSettingsActivity extends SettingsActivity { /* empty */ }
+    /** Activity to manage app battery optimization details. */
+    public static class AppBatteryOptimizationActivity extends SettingsActivity { /* empty */ }
 
     public static class ManageExternalSourcesActivity extends SettingsActivity {/* empty */ }
     public static class ManageAppExternalSourcesActivity extends SettingsActivity { /* empty */ }
diff --git a/src/com/android/settings/applications/AppStateBatteryOptimizationBridge.java b/src/com/android/settings/applications/AppStateBatteryOptimizationBridge.java
new file mode 100644
index 0000000..6301c85
--- /dev/null
+++ b/src/com/android/settings/applications/AppStateBatteryOptimizationBridge.java
@@ -0,0 +1,180 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.applications;
+
+import android.annotation.IntDef;
+import android.app.AppOpsManager;
+import android.content.Context;
+import android.os.Build;
+import android.util.Log;
+
+import com.android.settingslib.applications.ApplicationsState;
+import com.android.settingslib.applications.ApplicationsState.AppEntry;
+import com.android.settingslib.applications.ApplicationsState.AppFilter;
+import com.android.settingslib.fuelgauge.PowerAllowlistBackend;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Class for bridging the Battery optimization information to ApplicationState.
+ */
+public class AppStateBatteryOptimizationBridge extends AppStateBaseBridge {
+    private static final String TAG = AppStateBatteryOptimizationBridge.class.getSimpleName();
+    static final boolean DEBUG = Build.IS_DEBUGGABLE;
+
+    private final Context mContext;
+    private final AppOpsManager mAppOpsManager;
+    private final PowerAllowlistBackend mPowerAllowlistBackend;
+
+    private static final int MODE_UNKNOWN = 0;
+    private static final int MODE_UNRESTRICTED = 1;
+    private static final int MODE_OPTIMIZED = 2;
+    private static final int MODE_RESTRICTED = 3;
+
+    @IntDef(
+            prefix = {"MODE_"},
+            value = {
+                    MODE_UNKNOWN,
+                    MODE_RESTRICTED,
+                    MODE_UNRESTRICTED,
+                    MODE_OPTIMIZED,
+            })
+    @Retention(RetentionPolicy.SOURCE)
+    @interface OptimizationMode {
+    }
+
+    public AppStateBatteryOptimizationBridge(
+            Context context, ApplicationsState appState, Callback callback) {
+        super(appState, callback);
+        mContext = context;
+        mAppOpsManager = context.getSystemService(AppOpsManager.class);
+        mPowerAllowlistBackend = PowerAllowlistBackend.getInstance(mContext);
+    }
+
+    @Override
+    protected void updateExtraInfo(AppEntry app, String pkg, int uid) {
+        app.extraInfo = getAppBatteryOptimizationState(pkg, uid);
+    }
+
+    @Override
+    protected void loadAllExtraInfo() {
+        if (DEBUG) {
+            Log.d(TAG, "Start loadAllExtraInfo()");
+        }
+        mAppSession.getAllApps().stream().forEach(appEntry ->
+                updateExtraInfo(appEntry, appEntry.info.packageName, appEntry.info.uid));
+        if (DEBUG) {
+            Log.d(TAG, "End loadAllExtraInfo()");
+        }
+    }
+
+    protected Object getAppBatteryOptimizationState(String pkg, int uid) {
+        // Restricted = AppOpsManager.MODE_IGNORED + !allowListed
+        // Unrestricted = AppOpsManager.MODE_ALLOWED + allowListed
+        // Optimized = AppOpsManager.MODE_ALLOWED + !allowListed
+
+        boolean allowListed = mPowerAllowlistBackend.isAllowlisted(pkg);
+        int aomMode =
+                mAppOpsManager.checkOpNoThrow(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, uid, pkg);
+        @OptimizationMode int mode = MODE_UNKNOWN;
+        String modeName = "";
+        if (aomMode == AppOpsManager.MODE_IGNORED && !allowListed) {
+            mode = MODE_RESTRICTED;
+            if (DEBUG) {
+                modeName = "RESTRICTED";
+            }
+        } else if (aomMode == AppOpsManager.MODE_ALLOWED) {
+            mode = allowListed ? MODE_UNRESTRICTED : MODE_OPTIMIZED;
+            if (DEBUG) {
+                modeName = allowListed ? "UNRESTRICTED" : "OPTIMIZED";
+            }
+        }
+        if (DEBUG) {
+            Log.d(TAG, "Pkg: " + pkg + ", mode: " + modeName);
+        }
+        return new BatteryOptimizationDetails(mode);
+    }
+
+    @OptimizationMode
+    private static int getBatteryOptimizationDetailsMode(AppEntry entry) {
+        if (entry == null || entry.extraInfo == null) {
+            return MODE_UNKNOWN;
+        }
+
+        return entry.extraInfo instanceof BatteryOptimizationDetails
+                ? ((BatteryOptimizationDetails) entry.extraInfo).mMode
+                : MODE_UNKNOWN;
+    }
+
+    /**
+     * Used by {@link com.android.settings.applications.manageapplications.AppFilterRegistry} to
+     * determine which apps are unrestricted.
+     */
+    public static final AppFilter FILTER_BATTERY_UNRESTRICTED_APPS =
+            new AppFilter() {
+                @Override
+                public void init() {}
+
+                @Override
+                public boolean filterApp(AppEntry info) {
+                    return getBatteryOptimizationDetailsMode(info) == MODE_UNRESTRICTED;
+                }
+            };
+
+    /**
+     * Used by {@link com.android.settings.applications.manageapplications.AppFilterRegistry} to
+     * determine which apps are optimized.
+     */
+    public static final AppFilter FILTER_BATTERY_OPTIMIZED_APPS =
+            new AppFilter() {
+                @Override
+                public void init() {}
+
+                @Override
+                public boolean filterApp(AppEntry info) {
+                    return getBatteryOptimizationDetailsMode(info) == MODE_OPTIMIZED;
+                }
+            };
+
+    /**
+     * Used by {@link com.android.settings.applications.manageapplications.AppFilterRegistry} to
+     * determine which apps are restricted.
+     */
+    public static final AppFilter FILTER_BATTERY_RESTRICTED_APPS =
+            new AppFilter() {
+                @Override
+                public void init() {}
+
+                @Override
+                public boolean filterApp(AppEntry info) {
+                    return getBatteryOptimizationDetailsMode(info) == MODE_RESTRICTED;
+                }
+            };
+
+    /**
+     * Extra details for battery optimization app data.
+     */
+    static final class BatteryOptimizationDetails {
+        @OptimizationMode
+        int mMode;
+
+        BatteryOptimizationDetails(@OptimizationMode int mode) {
+            mMode = mode;
+        }
+    }
+}
diff --git a/src/com/android/settings/applications/manageapplications/AppFilterRegistry.java b/src/com/android/settings/applications/manageapplications/AppFilterRegistry.java
index 3c00b73..35de16e 100644
--- a/src/com/android/settings/applications/manageapplications/AppFilterRegistry.java
+++ b/src/com/android/settings/applications/manageapplications/AppFilterRegistry.java
@@ -20,6 +20,7 @@
 
 import com.android.settings.R;
 import com.android.settings.applications.AppStateAlarmsAndRemindersBridge;
+import com.android.settings.applications.AppStateBatteryOptimizationBridge;
 import com.android.settings.applications.AppStateInstallAppsBridge;
 import com.android.settings.applications.AppStateLocaleBridge;
 import com.android.settings.applications.AppStateManageExternalStorageBridge;
@@ -37,28 +38,31 @@
  */
 public class AppFilterRegistry {
 
-    @IntDef(value = {
-            FILTER_APPS_POWER_ALLOWLIST,
-            FILTER_APPS_POWER_ALLOWLIST_ALL,
-            FILTER_APPS_ALL,
-            FILTER_APPS_ENABLED,
-            FILTER_APPS_INSTANT,
-            FILTER_APPS_DISABLED,
-            FILTER_APPS_RECENT,
-            FILTER_APPS_FREQUENT,
-            FILTER_APPS_PERSONAL,
-            FILTER_APPS_WORK,
-            FILTER_APPS_USAGE_ACCESS,
-            FILTER_APPS_WITH_OVERLAY,
-            FILTER_APPS_WRITE_SETTINGS,
-            FILTER_APPS_INSTALL_SOURCES,
-            FILTER_APPS_BLOCKED,
-            FILTER_ALARMS_AND_REMINDERS,
-            FILTER_APPS_MEDIA_MANAGEMENT,
-            FILTER_APPS_LOCALE,
-    })
-    @interface FilterType {
-    }
+    @IntDef(
+            value = {
+                FILTER_APPS_POWER_ALLOWLIST,
+                FILTER_APPS_POWER_ALLOWLIST_ALL,
+                FILTER_APPS_ALL,
+                FILTER_APPS_ENABLED,
+                FILTER_APPS_INSTANT,
+                FILTER_APPS_DISABLED,
+                FILTER_APPS_RECENT,
+                FILTER_APPS_FREQUENT,
+                FILTER_APPS_PERSONAL,
+                FILTER_APPS_WORK,
+                FILTER_APPS_USAGE_ACCESS,
+                FILTER_APPS_WITH_OVERLAY,
+                FILTER_APPS_WRITE_SETTINGS,
+                FILTER_APPS_INSTALL_SOURCES,
+                FILTER_APPS_BLOCKED,
+                FILTER_ALARMS_AND_REMINDERS,
+                FILTER_APPS_MEDIA_MANAGEMENT,
+                FILTER_APPS_LOCALE,
+                FILTER_APPS_BATTERY_UNRESTRICTED,
+                FILTER_APPS_BATTERY_OPTIMIZED,
+                FILTER_APPS_BATTERY_RESTRICTED,
+            })
+    @interface FilterType {}
 
     // Filter options used for displayed list of applications
     // Filters will appear sorted based on their value defined here.
@@ -82,14 +86,18 @@
     public static final int FILTER_ALARMS_AND_REMINDERS = 18;
     public static final int FILTER_APPS_MEDIA_MANAGEMENT = 19;
     public static final int FILTER_APPS_LOCALE = 20;
-    // Next id: 21. If you add an entry here, length of mFilters should be updated
+    public static final int FILTER_APPS_BATTERY_UNRESTRICTED = 21;
+    public static final int FILTER_APPS_BATTERY_OPTIMIZED = 22;
+    public static final int FILTER_APPS_BATTERY_RESTRICTED = 23;
+    // Next id: 24. If you add an entry here, please change NUM_FILTER_ENTRIES.
+    private static final int NUM_FILTER_ENTRIES = 24;
 
     private static AppFilterRegistry sRegistry;
 
     private final AppFilterItem[] mFilters;
 
     private AppFilterRegistry() {
-        mFilters = new AppFilterItem[21];
+        mFilters = new AppFilterItem[NUM_FILTER_ENTRIES];
 
         // High power allowlist, on
         mFilters[FILTER_APPS_POWER_ALLOWLIST] = new AppFilterItem(
@@ -212,6 +220,28 @@
                 AppStateLocaleBridge.FILTER_APPS_LOCALE,
                 FILTER_APPS_LOCALE,
                 R.string.app_locale_picker_title);
+
+        // Battery optimization app states:
+        // Unrestricted
+        mFilters[FILTER_APPS_BATTERY_UNRESTRICTED] =
+                new AppFilterItem(
+                        AppStateBatteryOptimizationBridge.FILTER_BATTERY_UNRESTRICTED_APPS,
+                        FILTER_APPS_BATTERY_UNRESTRICTED,
+                        R.string.filter_battery_unrestricted_title);
+
+        // Optimized
+        mFilters[FILTER_APPS_BATTERY_OPTIMIZED] =
+                new AppFilterItem(
+                        AppStateBatteryOptimizationBridge.FILTER_BATTERY_OPTIMIZED_APPS,
+                        FILTER_APPS_BATTERY_OPTIMIZED,
+                        R.string.filter_battery_optimized_title);
+
+        // Unrestricted
+        mFilters[FILTER_APPS_BATTERY_RESTRICTED] =
+                new AppFilterItem(
+                        AppStateBatteryOptimizationBridge.FILTER_BATTERY_RESTRICTED_APPS,
+                        FILTER_APPS_BATTERY_RESTRICTED,
+                        R.string.filter_battery_restricted_title);
     }
 
 
@@ -248,6 +278,8 @@
                 return FILTER_APPS_MEDIA_MANAGEMENT;
             case ManageApplications.LIST_TYPE_APPS_LOCALE:
                 return FILTER_APPS_LOCALE;
+            case ManageApplications.LIST_TYPE_BATTERY_OPTIMIZATION:
+                return FILTER_APPS_BATTERY_OPTIMIZED;
             default:
                 return FILTER_APPS_ALL;
         }
diff --git a/src/com/android/settings/applications/manageapplications/ManageApplications.java b/src/com/android/settings/applications/manageapplications/ManageApplications.java
index 0b7d522..d020f33 100644
--- a/src/com/android/settings/applications/manageapplications/ManageApplications.java
+++ b/src/com/android/settings/applications/manageapplications/ManageApplications.java
@@ -21,6 +21,9 @@
 
 import static com.android.settings.ChangeIds.CHANGE_RESTRICT_SAW_INTENT;
 import static com.android.settings.applications.manageapplications.AppFilterRegistry.FILTER_APPS_ALL;
+import static com.android.settings.applications.manageapplications.AppFilterRegistry.FILTER_APPS_BATTERY_OPTIMIZED;
+import static com.android.settings.applications.manageapplications.AppFilterRegistry.FILTER_APPS_BATTERY_RESTRICTED;
+import static com.android.settings.applications.manageapplications.AppFilterRegistry.FILTER_APPS_BATTERY_UNRESTRICTED;
 import static com.android.settings.applications.manageapplications.AppFilterRegistry.FILTER_APPS_BLOCKED;
 import static com.android.settings.applications.manageapplications.AppFilterRegistry.FILTER_APPS_DISABLED;
 import static com.android.settings.applications.manageapplications.AppFilterRegistry.FILTER_APPS_ENABLED;
@@ -96,6 +99,7 @@
 import com.android.settings.applications.AppStateAlarmsAndRemindersBridge;
 import com.android.settings.applications.AppStateAppOpsBridge.PermissionState;
 import com.android.settings.applications.AppStateBaseBridge;
+import com.android.settings.applications.AppStateBatteryOptimizationBridge;
 import com.android.settings.applications.AppStateInstallAppsBridge;
 import com.android.settings.applications.AppStateLocaleBridge;
 import com.android.settings.applications.AppStateManageExternalStorageBridge;
@@ -120,6 +124,7 @@
 import com.android.settings.core.InstrumentedFragment;
 import com.android.settings.core.SubSettingLauncher;
 import com.android.settings.dashboard.profileselector.ProfileSelectFragment;
+import com.android.settings.fuelgauge.AdvancedPowerUsageDetail;
 import com.android.settings.fuelgauge.HighPowerDetail;
 import com.android.settings.localepicker.AppLocalePickerActivity;
 import com.android.settings.notification.ConfigureNotificationSettings;
@@ -229,6 +234,7 @@
     public static final int LIST_TYPE_ALARMS_AND_REMINDERS = 12;
     public static final int LIST_TYPE_MEDIA_MANAGEMENT_APPS = 13;
     public static final int LIST_TYPE_APPS_LOCALE = 14;
+    public static final int LIST_TYPE_BATTERY_OPTIMIZATION = 15;
 
     // List types that should show instant apps.
     public static final Set<Integer> LIST_TYPES_WITH_INSTANT = new ArraySet<>(Arrays.asList(
@@ -327,6 +333,8 @@
             }
         } else if (className.equals(AppLocaleDetails.class.getName())) {
             mListType = LIST_TYPE_APPS_LOCALE;
+        } else if (className.equals(Settings.AppBatteryOptimizationActivity.class.getName())) {
+            mListType = LIST_TYPE_BATTERY_OPTIMIZATION;
         } else {
             mListType = LIST_TYPE_MAIN;
         }
@@ -460,6 +468,12 @@
         if (mListType == LIST_TYPE_HIGH_POWER) {
             mFilterAdapter.enableFilter(FILTER_APPS_POWER_ALLOWLIST_ALL);
         }
+        if (mListType == LIST_TYPE_BATTERY_OPTIMIZATION) {
+            mFilterAdapter.enableFilter(FILTER_APPS_ALL);
+            mFilterAdapter.enableFilter(FILTER_APPS_BATTERY_UNRESTRICTED);
+            mFilterAdapter.enableFilter(FILTER_APPS_BATTERY_OPTIMIZED);
+            mFilterAdapter.enableFilter(FILTER_APPS_BATTERY_RESTRICTED);
+        }
 
         setCompositeFilter();
     }
@@ -511,6 +525,8 @@
                 return SettingsEnums.MEDIA_MANAGEMENT_APPS;
             case LIST_TYPE_APPS_LOCALE:
                 return SettingsEnums.APPS_LOCALE_LIST;
+            case LIST_TYPE_BATTERY_OPTIMIZATION:
+                return SettingsEnums.BATTERY_OPTIMIZED_APPS_LIST;
             default:
                 return SettingsEnums.PAGE_UNKNOWN;
         }
@@ -641,6 +657,10 @@
                 intent.putExtra(AppInfoBase.ARG_PACKAGE_UID, mCurrentUid);
                 startActivity(intent);
                 break;
+            case LIST_TYPE_BATTERY_OPTIMIZATION:
+                AdvancedPowerUsageDetail.startBatteryDetailPage(
+                        getActivity(), this, mCurrentPkgName);
+                break;
             // TODO: Figure out if there is a way where we can spin up the profile's settings
             // process ahead of time, to avoid a long load of data when user clicks on a managed
             // app. Maybe when they load the list of apps that contains managed profile apps.
@@ -923,6 +943,8 @@
             screenTitle = R.string.app_notifications_title;
         } else if (className.equals(AppLocaleDetails.class.getName())) {
             screenTitle = R.string.app_locales_picker_menu_title;
+        } else if (className.equals(Settings.AppBatteryOptimizationActivity.class.getName())) {
+            screenTitle = R.string.app_battery_optimization_title;
         } else {
             if (screenTitle == -1) {
                 screenTitle = R.string.all_apps;
@@ -1115,6 +1137,8 @@
                 mExtraInfoBridge = new AppStateMediaManagementAppsBridge(mContext, mState, this);
             } else if (mManageApplications.mListType == LIST_TYPE_APPS_LOCALE) {
                 mExtraInfoBridge = new AppStateLocaleBridge(mContext, mState, this);
+            } else if (mManageApplications.mListType == LIST_TYPE_BATTERY_OPTIMIZATION) {
+                mExtraInfoBridge = new AppStateBatteryOptimizationBridge(mContext, mState, this);
             } else {
                 mExtraInfoBridge = null;
             }
@@ -1146,18 +1170,21 @@
 
         public void setFilter(AppFilterItem appFilter) {
             mAppFilter = appFilter;
+            final int filterType = appFilter.getFilterType();
 
             // Notification filters require resorting the list
             if (mManageApplications.mListType == LIST_TYPE_NOTIFICATION) {
-                if (FILTER_APPS_FREQUENT == appFilter.getFilterType()) {
+                if (FILTER_APPS_FREQUENT == filterType) {
                     rebuild(R.id.sort_order_frequent_notification, false);
-                } else if (FILTER_APPS_RECENT == appFilter.getFilterType()) {
+                } else if (FILTER_APPS_RECENT == filterType) {
                     rebuild(R.id.sort_order_recent_notification, false);
-                } else if (FILTER_APPS_BLOCKED == appFilter.getFilterType()) {
+                } else if (FILTER_APPS_BLOCKED == filterType) {
                     rebuild(R.id.sort_order_alpha, true);
                 } else {
                     rebuild(R.id.sort_order_alpha, true);
                 }
+            } else if (mManageApplications.mListType == LIST_TYPE_BATTERY_OPTIMIZATION) {
+                logBatteryOptimization(filterType);
             } else {
                 rebuild();
             }
@@ -1294,6 +1321,26 @@
             });
         }
 
+        private void logBatteryOptimization(int filterType) {
+            switch(filterType) {
+                case FILTER_APPS_BATTERY_UNRESTRICTED:
+                    logAction(SettingsEnums.ACTION_BATTERY_OPTIMIZED_APPS_FILTER_UNRESTRICTED);
+                    break;
+                case FILTER_APPS_BATTERY_OPTIMIZED:
+                    logAction(SettingsEnums.ACTION_BATTERY_OPTIMIZED_APPS_FILTER_OPTIMIZED);
+                    break;
+                case FILTER_APPS_BATTERY_RESTRICTED:
+                    logAction(SettingsEnums.ACTION_BATTERY_OPTIMIZED_APPS_FILTER_RESTRICTED);
+                    break;
+                default:
+                    logAction(SettingsEnums.ACTION_BATTERY_OPTIMIZED_APPS_FILTER_ALL_APPS);
+            }
+        }
+
+        private void logAction(int action) {
+            mManageApplications.mMetricsFeatureProvider.action(mContext, action);
+        }
+
         @VisibleForTesting
         void filterSearch(String query) {
             if (mSearchFilter == null) {
diff --git a/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetail.java b/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetail.java
index cf58c3c..c813a57 100644
--- a/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetail.java
+++ b/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetail.java
@@ -41,15 +41,16 @@
 import com.android.settings.core.InstrumentedPreferenceFragment;
 import com.android.settings.core.SubSettingLauncher;
 import com.android.settings.dashboard.DashboardFragment;
-import com.android.settings.overlay.FeatureFactory;
 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;
 import com.android.settingslib.applications.AppUtils;
 import com.android.settingslib.applications.ApplicationsState;
 import com.android.settingslib.core.AbstractPreferenceController;
+import com.android.settingslib.core.instrumentation.Instrumentable;
 import com.android.settingslib.utils.StringUtil;
 import com.android.settingslib.widget.FooterPreference;
 import com.android.settingslib.widget.LayoutPreference;
@@ -209,8 +210,11 @@
         return UserHandle.getUserId(batteryEntry.getUid());
     }
 
-    public static void startBatteryDetailPage(Activity caller,
-            InstrumentedPreferenceFragment fragment, String packageName) {
+    /**
+     * Start packageName's battery detail page.
+     */
+    public static void startBatteryDetailPage(
+            Activity caller, Instrumentable instrumentable, String packageName) {
         final Bundle args = new Bundle(3);
         final PackageManager packageManager = caller.getPackageManager();
         args.putString(EXTRA_PACKAGE_NAME, packageName);
@@ -225,7 +229,7 @@
                 .setDestination(AdvancedPowerUsageDetail.class.getName())
                 .setTitleRes(R.string.battery_details_title)
                 .setArguments(args)
-                .setSourceMetricsCategory(fragment.getMetricsCategory())
+                .setSourceMetricsCategory(instrumentable.getMetricsCategory())
                 .launch();
     }
 
diff --git a/src/com/android/settings/fuelgauge/batteryusage/BatteryChartPreferenceControllerV2.java b/src/com/android/settings/fuelgauge/batteryusage/BatteryChartPreferenceControllerV2.java
index 2932984..45d145a 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/BatteryChartPreferenceControllerV2.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/BatteryChartPreferenceControllerV2.java
@@ -79,7 +79,7 @@
     private static int sUiMode = Configuration.UI_MODE_NIGHT_UNDEFINED;
 
     @VisibleForTesting
-    Map<Integer, List<BatteryDiffEntry>> mBatteryIndexedMap;
+    Map<Integer, Map<Integer, BatteryDiffData>> mBatteryUsageMap;
 
     @VisibleForTesting
     Context mPrefContext;
@@ -112,7 +112,6 @@
     private final String mPreferenceKey;
     private final SettingsActivity mActivity;
     private final InstrumentedPreferenceFragment mFragment;
-    private final CharSequence[] mNotAllowShowEntryPackages;
     private final CharSequence[] mNotAllowShowSummaryPackages;
     private final MetricsFeatureProvider mMetricsFeatureProvider;
     private final Handler mHandler = new Handler(Looper.getMainLooper());
@@ -120,8 +119,6 @@
     // Preference cache to avoid create new instance each time.
     @VisibleForTesting
     final Map<String, Preference> mPreferenceCache = new HashMap<>();
-    @VisibleForTesting
-    final List<BatteryDiffEntry> mSystemEntries = new ArrayList<>();
 
     public BatteryChartPreferenceControllerV2(
             Context context, String preferenceKey,
@@ -134,10 +131,6 @@
         mIs24HourFormat = DateFormat.is24HourFormat(context);
         mMetricsFeatureProvider =
                 FeatureFactory.getFactory(mContext).getMetricsFeatureProvider();
-        mNotAllowShowEntryPackages =
-                FeatureFactory.getFactory(context)
-                        .getPowerUsageFeatureProvider(context)
-                        .getHideApplicationEntries(context);
         mNotAllowShowSummaryPackages =
                 FeatureFactory.getFactory(context)
                         .getPowerUsageFeatureProvider(context)
@@ -266,9 +259,12 @@
             final Map<Long, Map<String, BatteryHistEntry>> batteryHistoryMap) {
         Log.d(TAG, "setBatteryHistoryMap() " + (batteryHistoryMap == null ? "null"
                 : ("size=" + batteryHistoryMap.size())));
-        // TODO: implement the callback function.
         final BatteryLevelData batteryLevelData =
-                DataProcessor.getBatteryLevelData(mContext, mHandler, batteryHistoryMap, null);
+                DataProcessor.getBatteryLevelData(mContext, mHandler, batteryHistoryMap,
+                        batteryUsageMap -> {
+                            mBatteryUsageMap = batteryUsageMap;
+                            refreshUi();
+                        });
         Log.d(TAG, "getBatteryLevelData: " + batteryLevelData);
         if (batteryLevelData == null) {
             mDailyViewModel = null;
@@ -293,7 +289,6 @@
                     BatteryChartViewModel.AxisLabelPosition.BETWEEN_TRAPEZOIDS));
         }
         refreshUi();
-        // TODO: Loads item icon and label and build mBatteryIndexedMap.
     }
 
     void setBatteryChartView(@NonNull final BatteryChartViewV2 dailyChartView,
@@ -335,7 +330,7 @@
 
     @VisibleForTesting
     boolean refreshUi() {
-        if (mBatteryIndexedMap == null || mDailyChartView == null || mHourlyChartView == null) {
+        if (mBatteryUsageMap == null || mDailyChartView == null || mHourlyChartView == null) {
             return false;
         }
 
@@ -378,45 +373,22 @@
     }
 
     private void addAllPreferences() {
-        // TODO: Get the right diff entry according to daily and hourly chart selection.
-        final int index = mDailyChartIndex;
-        final List<BatteryDiffEntry> entries =
-                mBatteryIndexedMap.get(Integer.valueOf(index));
-        addFooterPreferenceIfNeeded(entries != null && !entries.isEmpty());
-        if (entries == null) {
-            Log.w(TAG, "cannot find BatteryDiffEntry for:" + index);
+        final BatteryDiffData batteryDiffData =
+                mBatteryUsageMap.get(mDailyChartIndex).get(mHourlyChartIndex);
+        addFooterPreferenceIfNeeded(batteryDiffData != null
+                && (!batteryDiffData.getAppDiffEntryList().isEmpty()
+                || !batteryDiffData.getSystemDiffEntryList().isEmpty()));
+        if (batteryDiffData == null) {
+            Log.w(TAG, "cannot find BatteryDiffEntry for daily_index: " + mDailyChartIndex
+                    + " hourly_index: " + mHourlyChartIndex);
             return;
         }
-        // Separates data into two groups and sort them individually.
-        final List<BatteryDiffEntry> appEntries = new ArrayList<>();
-        mSystemEntries.clear();
-        entries.forEach(entry -> {
-            final String packageName = entry.getPackageName();
-            if (!isValidToShowEntry(packageName)) {
-                Log.w(TAG, "ignore showing item:" + packageName);
-                return;
-            }
-            if (entry.isSystemEntry()) {
-                mSystemEntries.add(entry);
-            } else {
-                appEntries.add(entry);
-            }
-            // Validates the usage time if users click a specific slot.
-            if (index >= 0) {
-                validateUsageTime(entry);
-            }
-        });
-        Collections.sort(appEntries, BatteryDiffEntry.COMPARATOR);
-        Collections.sort(mSystemEntries, BatteryDiffEntry.COMPARATOR);
-        Log.d(TAG, String.format("addAllPreferences() app=%d system=%d",
-                appEntries.size(), mSystemEntries.size()));
-
         // Adds app entries to the list if it is not empty.
-        if (!appEntries.isEmpty()) {
-            addPreferenceToScreen(appEntries);
+        if (!batteryDiffData.getAppDiffEntryList().isEmpty()) {
+            addPreferenceToScreen(batteryDiffData.getAppDiffEntryList());
         }
         // Adds the expabable divider if we have system entries data.
-        if (!mSystemEntries.isEmpty()) {
+        if (!batteryDiffData.getSystemDiffEntryList().isEmpty()) {
             if (mExpandDividerPreference == null) {
                 mExpandDividerPreference = new ExpandDividerPreference(mPrefContext);
                 mExpandDividerPreference.setOnExpandListener(this);
@@ -490,11 +462,13 @@
     }
 
     private void refreshExpandUi() {
+        final List<BatteryDiffEntry> systemEntries = mBatteryUsageMap.get(mDailyChartIndex).get(
+                mHourlyChartIndex).getSystemDiffEntryList();
         if (mIsExpanded) {
-            addPreferenceToScreen(mSystemEntries);
+            addPreferenceToScreen(systemEntries);
         } else {
             // Removes and recycles all system entries to hide all of them.
-            for (BatteryDiffEntry entry : mSystemEntries) {
+            for (BatteryDiffEntry entry : systemEntries) {
                 final String prefKey = entry.mBatteryHistEntry.getKey();
                 final Preference pref = mAppListPrefGroup.findPreference(prefKey);
                 if (pref != null) {
@@ -592,11 +566,6 @@
         return !contains(packageName, mNotAllowShowSummaryPackages);
     }
 
-    @VisibleForTesting
-    boolean isValidToShowEntry(String packageName) {
-        return !contains(packageName, mNotAllowShowEntryPackages);
-    }
-
     private void addFooterPreferenceIfNeeded(boolean containAppItems) {
         if (mIsFooterPrefAdded || mFooterPreference == null) {
             return;
@@ -643,20 +612,6 @@
         return false;
     }
 
-    @VisibleForTesting
-    static boolean validateUsageTime(BatteryDiffEntry entry) {
-        final long foregroundUsageTimeInMs = entry.mForegroundUsageTimeInMs;
-        final long backgroundUsageTimeInMs = entry.mBackgroundUsageTimeInMs;
-        final long totalUsageTimeInMs = foregroundUsageTimeInMs + backgroundUsageTimeInMs;
-        if (foregroundUsageTimeInMs > VALID_USAGE_TIME_DURATION
-                || backgroundUsageTimeInMs > VALID_USAGE_TIME_DURATION
-                || totalUsageTimeInMs > VALID_USAGE_TIME_DURATION) {
-            Log.e(TAG, "validateUsageTime() fail for\n" + entry);
-            return false;
-        }
-        return true;
-    }
-
     // TODO: Change this method to fromLastFullCharged.
 
     /** Used for {@link AppBatteryPreferenceController}. */
diff --git a/src/com/android/settings/fuelgauge/batteryusage/DataProcessor.java b/src/com/android/settings/fuelgauge/batteryusage/DataProcessor.java
index a004a51..a51fbec 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/DataProcessor.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/DataProcessor.java
@@ -218,7 +218,7 @@
      *
      * The valid result should be composed of 3 parts:
      * 1) start timestamp
-     * 2) every 0am timestamp (default timezone) between the start and end
+     * 2) every 00:00 timestamp (default timezone) between the start and end
      * 3) end timestamp
      * Otherwise, returns an empty list.
      */
@@ -277,18 +277,27 @@
     }
 
     /**
-     * @return Returns the timestamp for 0am 1 day after the given timestamp based on local
+     * @return Returns the timestamp for 00:00 1 day after the given timestamp based on local
      * timezone.
      */
     @VisibleForTesting
     static long getTimestampOfNextDay(long timestamp) {
-        final Calendar nextDayCalendar = Calendar.getInstance();
-        nextDayCalendar.setTimeInMillis(timestamp);
-        nextDayCalendar.add(Calendar.DAY_OF_YEAR, 1);
-        nextDayCalendar.set(Calendar.HOUR_OF_DAY, 0);
-        nextDayCalendar.set(Calendar.MINUTE, 0);
-        nextDayCalendar.set(Calendar.SECOND, 0);
-        return nextDayCalendar.getTimeInMillis();
+        return getTimestampWithDayDiff(timestamp, /*dayDiff=*/ 1);
+    }
+
+    /**
+     *  Returns whether currentSlot will be used in daily chart.
+     */
+    @VisibleForTesting
+    static boolean isForDailyChart(final boolean isStartOrEnd, final long currentSlot) {
+        // The start and end timestamps will always be used in daily chart.
+        if (isStartOrEnd) {
+            return true;
+        }
+
+        // The timestamps for 00:00 will be used in daily chart.
+        final long startOfTheDay = getTimestampWithDayDiff(currentSlot, /*dayDiff=*/ 0);
+        return currentSlot == startOfTheDay;
     }
 
     /**
@@ -350,10 +359,13 @@
             startIndex = 1;
             resultMap.put(expectedStartTimestamp, batteryHistoryMap.get(rawStartTimestamp));
         }
-        for (int index = startIndex; index < expectedTimestampSlots.size(); index++) {
+        final int expectedTimestampSlotsSize = expectedTimestampSlots.size();
+        for (int index = startIndex; index < expectedTimestampSlotsSize; index++) {
             final long currentSlot = expectedTimestampSlots.get(index);
+            final boolean isStartOrEnd = index == 0 || index == expectedTimestampSlotsSize - 1;
             interpolateHistoryForSlot(
-                    context, currentSlot, rawTimestampList, batteryHistoryMap, resultMap);
+                    context, currentSlot, rawTimestampList, batteryHistoryMap, resultMap,
+                    isStartOrEnd);
         }
     }
 
@@ -362,7 +374,8 @@
             final long currentSlot,
             final List<Long> rawTimestampList,
             final Map<Long, Map<String, BatteryHistEntry>> batteryHistoryMap,
-            final Map<Long, Map<String, BatteryHistEntry>> resultMap) {
+            final Map<Long, Map<String, BatteryHistEntry>> resultMap,
+            final boolean isStartOrEnd) {
         final long[] nearestTimestamps = findNearestTimestamp(rawTimestampList, currentSlot);
         final long lowerTimestamp = nearestTimestamps[0];
         final long upperTimestamp = nearestTimestamps[1];
@@ -385,7 +398,8 @@
             return;
         }
         interpolateHistoryForSlot(context,
-                currentSlot, lowerTimestamp, upperTimestamp, batteryHistoryMap, resultMap);
+                currentSlot, lowerTimestamp, upperTimestamp, batteryHistoryMap, resultMap,
+                isStartOrEnd);
     }
 
     private static void interpolateHistoryForSlot(
@@ -394,7 +408,8 @@
             final long lowerTimestamp,
             final long upperTimestamp,
             final Map<Long, Map<String, BatteryHistEntry>> batteryHistoryMap,
-            final Map<Long, Map<String, BatteryHistEntry>> resultMap) {
+            final Map<Long, Map<String, BatteryHistEntry>> resultMap,
+            final boolean isStartOrEnd) {
         final Map<String, BatteryHistEntry> lowerEntryDataMap =
                 batteryHistoryMap.get(lowerTimestamp);
         final Map<String, BatteryHistEntry> upperEntryDataMap =
@@ -405,7 +420,10 @@
         final long upperEntryDataBootTimestamp =
                 upperEntryDataFirstEntry.mTimestamp - upperEntryDataFirstEntry.mBootTimestamp;
         // Lower data is captured before upper data corresponding device is booting.
-        if (lowerTimestamp < upperEntryDataBootTimestamp) {
+        // Skips the booting-specific logics and always does interpolation for daily chart level
+        // data.
+        if (lowerTimestamp < upperEntryDataBootTimestamp
+                && !isForDailyChart(isStartOrEnd, currentSlot)) {
             // Provides an opportunity to force align the slot directly.
             if ((upperTimestamp - currentSlot) < 10 * DateUtils.MINUTE_IN_MILLIS) {
                 log(context, "force align into the nearest slot", currentSlot, null);
@@ -877,6 +895,16 @@
         return true;
     }
 
+    private static long getTimestampWithDayDiff(final long timestamp, final int dayDiff) {
+        final Calendar calendar = Calendar.getInstance();
+        calendar.setTimeInMillis(timestamp);
+        calendar.add(Calendar.DAY_OF_YEAR, dayDiff);
+        calendar.set(Calendar.HOUR_OF_DAY, 0);
+        calendar.set(Calendar.MINUTE, 0);
+        calendar.set(Calendar.SECOND, 0);
+        return calendar.getTimeInMillis();
+    }
+
     private static boolean contains(String target, Set<CharSequence> packageNames) {
         if (target != null && packageNames != null) {
             for (CharSequence packageName : packageNames) {
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryChartPreferenceControllerV2Test.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryChartPreferenceControllerV2Test.java
index a5f193b..16e0459 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryChartPreferenceControllerV2Test.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryChartPreferenceControllerV2Test.java
@@ -19,6 +19,7 @@
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.atLeastOnce;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.reset;
@@ -168,13 +169,10 @@
 
     @Test
     public void setBatteryChartViewModel_6Hours() {
-        // TODO: Removes the following line after loading mBatteryIndexedMap is supported.
-        mBatteryChartPreferenceController.mBatteryIndexedMap = new HashMap<>();
-
         mBatteryChartPreferenceController.setBatteryHistoryMap(createBatteryHistoryMap(6));
 
-        verify(mDailyChartView).setVisibility(View.GONE);
-        verify(mHourlyChartView).setVisibility(View.VISIBLE);
+        verify(mDailyChartView, atLeastOnce()).setVisibility(View.GONE);
+        verify(mHourlyChartView, atLeastOnce()).setVisibility(View.VISIBLE);
         verify(mHourlyChartView).setViewModel(new BatteryChartViewModel(
                 List.of(100, 97, 95),
                 List.of("8 am", "10 am", "12 pm"),
@@ -184,13 +182,10 @@
 
     @Test
     public void setBatteryChartViewModel_60Hours() {
-        // TODO: Removes the following line after loading mBatteryIndexedMap is supported.
-        mBatteryChartPreferenceController.mBatteryIndexedMap = new HashMap<>();
-
         mBatteryChartPreferenceController.setBatteryHistoryMap(createBatteryHistoryMap(60));
 
-        verify(mDailyChartView).setVisibility(View.VISIBLE);
-        verify(mHourlyChartView).setVisibility(View.GONE);
+        verify(mDailyChartView, atLeastOnce()).setVisibility(View.VISIBLE);
+        verify(mHourlyChartView, atLeastOnce()).setVisibility(View.GONE);
         verify(mDailyChartView).setViewModel(new BatteryChartViewModel(
                 List.of(100, 83, 59, 41),
                 List.of("SAT", "SUN", "MON", "MON"),
@@ -256,6 +251,12 @@
     }
 
     @Test
+    public void refreshUi_normalCase_returnTrue() {
+        mBatteryChartPreferenceController.setBatteryHistoryMap(createBatteryHistoryMap(6));
+        assertThat(mBatteryChartPreferenceController.refreshUi()).isTrue();
+    }
+
+    @Test
     public void refreshUi_batteryIndexedMapIsNull_ignoreRefresh() {
         mBatteryChartPreferenceController.setBatteryHistoryMap(null);
         assertThat(mBatteryChartPreferenceController.refreshUi()).isFalse();
@@ -275,7 +276,8 @@
 
     @Test
     public void removeAndCacheAllPrefs_emptyContent_ignoreRemoveAll() {
-        mBatteryChartPreferenceController.mHourlyChartIndex = 1;
+        mBatteryChartPreferenceController.setBatteryHistoryMap(createBatteryHistoryMap(6));
+        mBatteryChartPreferenceController.mBatteryUsageMap = createBatteryUsageMap();
         doReturn(0).when(mAppListGroup).getPreferenceCount();
 
         mBatteryChartPreferenceController.refreshUi();
@@ -283,6 +285,25 @@
     }
 
     @Test
+    public void removeAndCacheAllPrefs_buildCacheAndRemoveAllPreference() {
+        mBatteryChartPreferenceController.setBatteryHistoryMap(createBatteryHistoryMap(6));
+        mBatteryChartPreferenceController.mBatteryUsageMap = createBatteryUsageMap();
+        doReturn(1).when(mAppListGroup).getPreferenceCount();
+        doReturn(mPowerGaugePreference).when(mAppListGroup).getPreference(0);
+        doReturn(PREF_KEY).when(mBatteryHistEntry).getKey();
+        doReturn(PREF_KEY).when(mPowerGaugePreference).getKey();
+        doReturn(mPowerGaugePreference).when(mAppListGroup).findPreference(PREF_KEY);
+        // Ensures the testing data is correct.
+        assertThat(mBatteryChartPreferenceController.mPreferenceCache).isEmpty();
+
+        mBatteryChartPreferenceController.refreshUi();
+
+        assertThat(mBatteryChartPreferenceController.mPreferenceCache.get(PREF_KEY))
+                .isEqualTo(mPowerGaugePreference);
+        verify(mAppListGroup).removeAll();
+    }
+
+    @Test
     public void addPreferenceToScreen_emptyContent_ignoreAddPreference() {
         mBatteryChartPreferenceController.addPreferenceToScreen(
                 new ArrayList<BatteryDiffEntry>());
@@ -454,36 +475,9 @@
     }
 
     @Test
-    public void validateUsageTime_returnTrueIfBatteryDiffEntryIsValid() {
-        assertThat(BatteryChartPreferenceControllerV2.validateUsageTime(
-                createBatteryDiffEntry(
-                        /*foregroundUsageTimeInMs=*/ DateUtils.MINUTE_IN_MILLIS,
-                        /*backgroundUsageTimeInMs=*/ DateUtils.MINUTE_IN_MILLIS)))
-                .isTrue();
-    }
-
-    @Test
-    public void validateUsageTime_foregroundTimeExceedThreshold_returnFalse() {
-        assertThat(BatteryChartPreferenceControllerV2.validateUsageTime(
-                createBatteryDiffEntry(
-                        /*foregroundUsageTimeInMs=*/ DateUtils.HOUR_IN_MILLIS * 3,
-                        /*backgroundUsageTimeInMs=*/ 0)))
-                .isFalse();
-    }
-
-    @Test
-    public void validateUsageTime_backgroundTimeExceedThreshold_returnFalse() {
-        assertThat(BatteryChartPreferenceControllerV2.validateUsageTime(
-                createBatteryDiffEntry(
-                        /*foregroundUsageTimeInMs=*/ 0,
-                        /*backgroundUsageTimeInMs=*/ DateUtils.HOUR_IN_MILLIS * 3)))
-                .isFalse();
-    }
-
-    @Test
     public void onExpand_expandedIsTrue_addSystemEntriesToPreferenceGroup() {
         doReturn(1).when(mAppListGroup).getPreferenceCount();
-        mBatteryChartPreferenceController.mSystemEntries.add(mBatteryDiffEntry);
+        mBatteryChartPreferenceController.mBatteryUsageMap = createBatteryUsageMap();
         doReturn("label").when(mBatteryDiffEntry).getAppLabel();
         doReturn(mDrawable).when(mBatteryDiffEntry).getAppIcon();
         doReturn(PREF_KEY).when(mBatteryHistEntry).getKey();
@@ -505,7 +499,7 @@
     public void onExpand_expandedIsFalse_removeSystemEntriesFromPreferenceGroup() {
         doReturn(PREF_KEY).when(mBatteryHistEntry).getKey();
         doReturn(mPowerGaugePreference).when(mAppListGroup).findPreference(PREF_KEY);
-        mBatteryChartPreferenceController.mSystemEntries.add(mBatteryDiffEntry);
+        mBatteryChartPreferenceController.mBatteryUsageMap = createBatteryUsageMap();
         // Verifies the cache is empty first.
         assertThat(mBatteryChartPreferenceController.mPreferenceCache).isEmpty();
 
@@ -580,18 +574,6 @@
                 .isFalse();
     }
 
-    @Test
-    public void isValidToShowEntry_returnExpectedResult() {
-        assertThat(mBatteryChartPreferenceController
-                .isValidToShowEntry("com.google.android.apps.scone"))
-                .isTrue();
-
-        // Verifies the items which are defined in the array list.
-        assertThat(mBatteryChartPreferenceController
-                .isValidToShowEntry("com.android.gms.persistent"))
-                .isFalse();
-    }
-
     private static Long generateTimestamp(int index) {
         // "2021-04-23 07:00:00 UTC" + index hours
         return 1619247600000L + index * DateUtils.HOUR_IN_MILLIS;
@@ -603,6 +585,7 @@
         for (int index = 0; index < numOfHours; index++) {
             final ContentValues values = new ContentValues();
             values.put("batteryLevel", Integer.valueOf(100 - index));
+            values.put("consumePower", Integer.valueOf(100 - index));
             final BatteryHistEntry entry = new BatteryHistEntry(values);
             final Map<String, BatteryHistEntry> entryMap = new HashMap<>();
             entryMap.put("fake_entry_key" + index, entry);
@@ -611,6 +594,22 @@
         return batteryHistoryMap;
     }
 
+    private Map<Integer, Map<Integer, BatteryDiffData>> createBatteryUsageMap() {
+        final int selectedAll = BatteryChartViewModel.SELECTED_INDEX_ALL;
+        return Map.of(
+                selectedAll, Map.of(
+                        selectedAll, new BatteryDiffData(
+                                Arrays.asList(mBatteryDiffEntry),
+                                Arrays.asList(mBatteryDiffEntry))),
+                0, Map.of(
+                        selectedAll, new BatteryDiffData(
+                                Arrays.asList(mBatteryDiffEntry),
+                                Arrays.asList(mBatteryDiffEntry)),
+                        0, new BatteryDiffData(
+                                Arrays.asList(mBatteryDiffEntry),
+                                Arrays.asList(mBatteryDiffEntry))));
+    }
+
     private BatteryDiffEntry createBatteryDiffEntry(
             long foregroundUsageTimeInMs, long backgroundUsageTimeInMs) {
         return new BatteryDiffEntry(
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 1b1e469..af1030c 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/DataProcessorTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/DataProcessorTest.java
@@ -402,6 +402,17 @@
     }
 
     @Test
+    public void isForDailyChart_returnExpectedResult() {
+        assertThat(DataProcessor.isForDailyChart(/*isStartOrEnd=*/ true, 0L)).isTrue();
+        // 2022-01-01 00:00:00
+        assertThat(DataProcessor.isForDailyChart(/*isStartOrEnd=*/ false, 1640966400000L))
+                .isTrue();
+        // 2022-01-01 01:00:05
+        assertThat(DataProcessor.isForDailyChart(/*isStartOrEnd=*/ false, 1640970005000L))
+                .isFalse();
+    }
+
+    @Test
     public void getBatteryUsageMap_emptyHistoryMap_returnNull() {
         final List<BatteryLevelData.PeriodBatteryLevelData> hourlyBatteryLevelsPerDay =
                 new ArrayList<>();
diff --git a/tests/unit/src/com/android/settings/applications/manageapplications/AppFilterRegistryTest.java b/tests/unit/src/com/android/settings/applications/manageapplications/AppFilterRegistryTest.java
index 4c271c6..13bc3db 100644
--- a/tests/unit/src/com/android/settings/applications/manageapplications/AppFilterRegistryTest.java
+++ b/tests/unit/src/com/android/settings/applications/manageapplications/AppFilterRegistryTest.java
@@ -18,6 +18,7 @@
 
 import static com.android.settings.applications.manageapplications.AppFilterRegistry.FILTER_ALARMS_AND_REMINDERS;
 import static com.android.settings.applications.manageapplications.AppFilterRegistry.FILTER_APPS_ALL;
+import static com.android.settings.applications.manageapplications.AppFilterRegistry.FILTER_APPS_BATTERY_OPTIMIZED;
 import static com.android.settings.applications.manageapplications.AppFilterRegistry.FILTER_APPS_INSTALL_SOURCES;
 import static com.android.settings.applications.manageapplications.AppFilterRegistry.FILTER_APPS_MEDIA_MANAGEMENT;
 import static com.android.settings.applications.manageapplications.AppFilterRegistry.FILTER_APPS_POWER_ALLOWLIST;
@@ -26,6 +27,7 @@
 import static com.android.settings.applications.manageapplications.AppFilterRegistry.FILTER_APPS_WITH_OVERLAY;
 import static com.android.settings.applications.manageapplications.AppFilterRegistry.FILTER_APPS_WRITE_SETTINGS;
 import static com.android.settings.applications.manageapplications.ManageApplications.LIST_TYPE_ALARMS_AND_REMINDERS;
+import static com.android.settings.applications.manageapplications.ManageApplications.LIST_TYPE_BATTERY_OPTIMIZATION;
 import static com.android.settings.applications.manageapplications.ManageApplications.LIST_TYPE_GAMES;
 import static com.android.settings.applications.manageapplications.ManageApplications.LIST_TYPE_HIGH_POWER;
 import static com.android.settings.applications.manageapplications.ManageApplications.LIST_TYPE_MAIN;
@@ -66,6 +68,8 @@
 
         assertThat(registry.getDefaultFilterType(LIST_TYPE_MEDIA_MANAGEMENT_APPS))
                 .isEqualTo(FILTER_APPS_MEDIA_MANAGEMENT);
+        assertThat(registry.getDefaultFilterType(LIST_TYPE_BATTERY_OPTIMIZATION))
+                .isEqualTo(FILTER_APPS_BATTERY_OPTIMIZED);
 
         assertThat(registry.getDefaultFilterType(LIST_TYPE_MAIN)).isEqualTo(FILTER_APPS_ALL);
         assertThat(registry.getDefaultFilterType(LIST_TYPE_NOTIFICATION))