Merge "update navigation mode settings string" into udc-qpr-dev
diff --git a/res/layout/battery_chart_graph.xml b/res/layout/battery_chart_graph.xml
index f116c8e..9e816ed 100644
--- a/res/layout/battery_chart_graph.xml
+++ b/res/layout/battery_chart_graph.xml
@@ -27,6 +27,7 @@
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:layout_marginVertical="16dp"
+        android:textAlignment="viewStart"
         android:textAppearance="?android:attr/textAppearanceSmall"
         android:textColor="?android:attr/textColorSecondary"
         android:text="@string/battery_usage_chart_graph_hint_last_full_charge" />
@@ -40,7 +41,7 @@
         <com.android.settings.fuelgauge.batteryusage.BatteryChartView
             android:id="@+id/daily_battery_chart"
             android:layout_width="match_parent"
-            android:layout_height="170dp"
+            android:layout_height="@dimen/chartview_layout_height"
             android:layout_marginBottom="16dp"
             android:visibility="gone"
             android:contentDescription="@string/daily_battery_usage_chart"
@@ -50,7 +51,7 @@
         <com.android.settings.fuelgauge.batteryusage.BatteryChartView
             android:id="@+id/hourly_battery_chart"
             android:layout_width="match_parent"
-            android:layout_height="170dp"
+            android:layout_height="@dimen/chartview_layout_height"
             android:layout_marginBottom="16dp"
             android:visibility="visible"
             android:contentDescription="@string/hourly_battery_usage_chart"
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index fd582de..4ae140e 100755
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -369,6 +369,12 @@
     <dimen name="chartview_text_padding">6dp</dimen>
     <dimen name="chartview_divider_width">1dp</dimen>
     <dimen name="chartview_divider_height">4dp</dimen>
+    <dimen name="chartview_transom_width">4dp</dimen>
+    <dimen name="chartview_transom_radius">4dp</dimen>
+    <dimen name="chartview_transom_icon_size">12dp</dimen>
+    <dimen name="chartview_transom_padding_top">2dp</dimen>
+    <dimen name="chartview_transom_layout_height">12dp</dimen>
+    <dimen name="chartview_layout_height">182dp</dimen>
     <dimen name="chartview_trapezoid_radius">5dp</dimen>
     <dimen name="chartview_trapezoid_margin_start">1dp</dimen>
     <dimen name="chartview_trapezoid_margin_bottom">2dp</dimen>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 545e784..aef86a6 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -12144,11 +12144,13 @@
     <!-- [CHAR LIMIT=60] Aspect ratio title setting to choose app aspect ratio -->
     <string name="aspect_ratio_title">Aspect ratio</string>
     <!-- [CHAR LIMIT=NONE] Aspect ratio setting summary to choose aspect ratio for apps unoptimized for device -->
-    <string name="aspect_ratio_summary">Choose an aspect ratio to view this app if it hasn\'t been designed to fit your <xliff:g id="device_name">%1$s</xliff:g></string>
+    <string name="aspect_ratio_summary">Try a new aspect ratio to view this app if it hasn\'t been designed to fit your <xliff:g id="device_name">%1$s</xliff:g></string>
+    <!-- [CHAR LIMIT=NONE] Aspect ratio setting main summary on page to choose aspect ratio for apps unoptimized for device -->
+    <string name="aspect_ratio_main_summary">Try a new aspect ratio to view this app if it hasn\'t been designed to fit your <xliff:g id="device_name">%1$s</xliff:g>. Some apps may not be optimized for certain aspect ratios.</string>
     <!-- [CHAR LIMIT=NONE] Aspect ratio suggested apps filter label -->
     <string name="user_aspect_ratio_suggested_apps_label">Suggested apps</string>
-    <!-- [CHAR LIMIT=NONE] Filter label for apps that have user aspect ratio override applied -->
-    <string name="user_aspect_ratio_overridden_apps_label">Apps you have overridden</string>
+    <!-- [CHAR LIMIT=14] Filter label for apps that have user aspect ratio changed -->
+    <string name="user_aspect_ratio_changed_apps_label">Changed apps</string>
     <!-- [CHAR LIMIT=NONE] App default aspect ratio entry -->
     <string name="user_aspect_ratio_app_default">App default</string>
     <!-- [CHAR LIMIT=NONE] Fullscreen aspect ratio entry -->
@@ -12164,7 +12166,7 @@
     <!-- [CHAR LIMIT=NONE] 4:3 aspect ratio entry -->
     <string name="user_aspect_ratio_4_3">4:3</string>
     <!-- [CHAR LIMIT=NONE] Warning description for app info aspect ratio page -->
-    <string name="app_aspect_ratio_footer">The app will restart when you change aspect ratio. You may lose unsaved changes.</string>
+    <string name="app_aspect_ratio_footer">The app will restart when you change aspect ratio. You may lose unsaved changes. Some apps may not be optimized for certain aspect ratios.</string>
 
 
     <!-- Accessibility label for fingerprint sensor [CHAR LIMIT=NONE] -->
diff --git a/res/xml/apps.xml b/res/xml/apps.xml
index 651ed9b..db46a1a 100644
--- a/res/xml/apps.xml
+++ b/res/xml/apps.xml
@@ -80,18 +80,6 @@
         android:order="10"/>
 
     <Preference
-        android:key="aspect_ratio_apps"
-        android:title="@string/aspect_ratio_title"
-        android:summary="@string/summary_placeholder"
-        android:order="14"
-        settings:controller="com.android.settings.applications.appcompat.UserAspectRatioAppsPreferenceController"
-        android:fragment="com.android.settings.applications.manageapplications.ManageApplications">
-        <extra android:name="classname"
-               android:value="com.android.settings.Settings$UserAspectRatioAppListActivity"/>
-        <intent android:action="android.settings.MANAGE_USER_ASPECT_RATIO_SETTINGS"/>
-    </Preference>
-
-    <Preference
         android:key="hibernated_apps"
         android:title="@string/unused_apps"
         android:summary="@string/summary_placeholder"
@@ -119,4 +107,23 @@
         android:title="@string/special_access"
         android:order="20"/>
 
+    <PreferenceCategory
+        android:key="advanced_category"
+        android:title="@string/advanced_apps"
+        android:order="21"
+        android:visibility="gone"
+        settings:searchable="false"/>
+
+    <Preference
+        android:key="aspect_ratio_apps"
+        android:title="@string/aspect_ratio_title"
+        android:summary="@string/summary_placeholder"
+        android:order="22"
+        settings:controller="com.android.settings.applications.appcompat.UserAspectRatioAppsPreferenceController"
+        android:fragment="com.android.settings.applications.manageapplications.ManageApplications">
+        <extra android:name="classname"
+               android:value="com.android.settings.Settings$UserAspectRatioAppListActivity"/>
+        <intent android:action="android.settings.MANAGE_USER_ASPECT_RATIO_SETTINGS"/>
+    </Preference>
+
 </PreferenceScreen>
diff --git a/res/xml/reset_dashboard_fragment.xml b/res/xml/reset_dashboard_fragment.xml
index 3bd7a13..08852c9 100644
--- a/res/xml/reset_dashboard_fragment.xml
+++ b/res/xml/reset_dashboard_fragment.xml
@@ -57,5 +57,13 @@
         settings:keywords="@string/keywords_factory_data_reset"
         settings:userRestriction="no_factory_reset"
         settings:useAdminDisabledSummary="true"
+        settings:controller="com.android.settings.system.FactoryResetPreferenceController"
+        android:fragment="com.android.settings.MainClear" />
+
+    <Preference
+        android:key="factory_reset_demo_user"
+        android:title="@string/main_clear_title"
+        settings:keywords="@string/keywords_factory_data_reset"
+        settings:controller="com.android.settings.system.FactoryResetDemoUserPreferenceController"
         android:fragment="com.android.settings.MainClear" />
 </PreferenceScreen>
diff --git a/src/com/android/settings/MainClear.java b/src/com/android/settings/MainClear.java
index f706c78..8a441e2 100644
--- a/src/com/android/settings/MainClear.java
+++ b/src/com/android/settings/MainClear.java
@@ -569,7 +569,7 @@
                         UserHandle.myUserId());
         if (disallow && !Utils.isDemoUser(context)) {
             return inflater.inflate(R.layout.main_clear_disallowed_screen, null);
-        } else if (admin != null) {
+        } else if (admin != null && !Utils.isDemoUser(context)) {
             new ActionDisabledByAdminDialogHelper(getActivity())
                     .prepareDialogBuilder(UserManager.DISALLOW_FACTORY_RESET, admin)
                     .setOnDismissListener(__ -> getActivity().finish())
diff --git a/src/com/android/settings/fuelgauge/PowerUsageFeatureProvider.java b/src/com/android/settings/fuelgauge/PowerUsageFeatureProvider.java
index 30eabfa..4253ca6 100644
--- a/src/com/android/settings/fuelgauge/PowerUsageFeatureProvider.java
+++ b/src/com/android/settings/fuelgauge/PowerUsageFeatureProvider.java
@@ -44,11 +44,6 @@
     boolean isBatteryTipsEnabled();
 
     /**
-     * Check whether the feedback card is enabled in the battery tips card
-     */
-    boolean isBatteryTipsFeedbackEnabled();
-
-    /**
      * Returns a threshold (in milliseconds) for the minimal screen on time in battery usage list
      */
     double getBatteryUsageListScreenOnTimeThresholdInMs();
diff --git a/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImpl.java b/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImpl.java
index 127178a..5931e206 100644
--- a/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImpl.java
+++ b/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImpl.java
@@ -81,11 +81,6 @@
     }
 
     @Override
-    public boolean isBatteryTipsFeedbackEnabled() {
-        return false;
-    }
-
-    @Override
     public double getBatteryUsageListScreenOnTimeThresholdInMs() {
         return 0;
     }
diff --git a/src/com/android/settings/fuelgauge/batteryusage/BatteryChartPreferenceController.java b/src/com/android/settings/fuelgauge/batteryusage/BatteryChartPreferenceController.java
index 1720f0d..1893096 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/BatteryChartPreferenceController.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/BatteryChartPreferenceController.java
@@ -36,7 +36,6 @@
 import com.android.settings.R;
 import com.android.settings.SettingsActivity;
 import com.android.settings.core.PreferenceControllerMixin;
-import com.android.settings.fuelgauge.PowerUsageFeatureProvider;
 import com.android.settings.overlay.FeatureFactory;
 import com.android.settingslib.core.AbstractPreferenceController;
 import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
@@ -44,7 +43,6 @@
 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;
 
@@ -52,17 +50,12 @@
 
 import java.util.ArrayList;
 import java.util.Calendar;
-import java.util.Comparator;
 import java.util.List;
 import java.util.Map;
-import java.util.Set;
-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, OnPause,
+        implements PreferenceControllerMixin, LifecycleObserver, OnCreate, OnDestroy,
         OnSaveInstanceState, OnResume {
     private static final String TAG = "BatteryChartPreferenceController";
     private static final String PREFERENCE_KEY = "battery_chart";
@@ -74,53 +67,17 @@
     private static final String KEY_DAILY_CHART_INDEX = "daily_chart_index";
     private static final String KEY_HOURLY_CHART_INDEX = "hourly_chart_index";
 
-    /**
-     * A callback listener for battery usage is updated.
-     * This happens when battery usage data is ready or the selected index is changed.
-     */
-    public interface OnBatteryUsageUpdatedListener {
-        /**
-         * The callback function for battery usage is updated.
-         * @param slotUsageData The battery usage diff data for the selected slot. This is used in
-         *                      the app list.
-         * @param slotTimestamp The selected slot timestamp information. This is used in the battery
-         *                      usage breakdown category.
-         * @param isAllUsageDataEmpty Whether all the battery usage data is null or empty. This is
-         *                            used when showing the footer.
-         */
-        void onBatteryUsageUpdated(
-                BatteryDiffData slotUsageData, String slotTimestamp, boolean isAllUsageDataEmpty);
+    /** A callback listener for the selected index is updated. */
+    interface OnSelectedIndexUpdatedListener {
+        /** The callback function for the selected index is updated. */
+        void onSelectedIndexUpdated();
     }
 
-    /**
-     * A callback listener for the device screen on time is updated.
-     * This happens when screen on time data is ready or the selected index is changed.
-     */
-    public interface OnScreenOnTimeUpdatedListener {
-        /**
-         * The callback function for the device screen on time is updated.
-         * @param screenOnTime The selected slot device screen on time.
-         * @param slotTimestamp The selected slot timestamp information.
-         */
-        void onScreenOnTimeUpdated(Long screenOnTime, String slotTimestamp);
-    }
-
-    /**
-     * A callback listener for the battery tips card is updated.
-     * This happens when battery tips card is ready.
-     */
-    public interface OnBatteryTipsUpdatedListener {
-        /**
-         * The callback function for the battery tips card is updated.
-         * @param powerAnomalyEvent the power anomaly event with highest score
-         */
-        void onBatteryTipsUpdated(PowerAnomalyEvent powerAnomalyEvent);
-    }
-
-
     @VisibleForTesting
     Context mPrefContext;
     @VisibleForTesting
+    TextView mChartSummaryTextView;
+    @VisibleForTesting
     BatteryChartView mDailyChartView;
     @VisibleForTesting
     BatteryChartView mHourlyChartView;
@@ -129,27 +86,23 @@
     @VisibleForTesting
     int mHourlyChartIndex = BatteryChartViewModel.SELECTED_INDEX_ALL;
     @VisibleForTesting
-    Map<Integer, Map<Integer, BatteryDiffData>> mBatteryUsageMap;
+    int mDailyHighlightSlotIndex = BatteryChartViewModel.SELECTED_INDEX_INVALID;
+    @VisibleForTesting
+    int mHourlyHighlightSlotIndex = BatteryChartViewModel.SELECTED_INDEX_INVALID;
 
     private boolean mIs24HourFormat;
     private View mBatteryChartViewGroup;
-    private TextView mChartSummaryTextView;
     private BatteryChartViewModel mDailyViewModel;
     private List<BatteryChartViewModel> mHourlyViewModels;
-    private OnBatteryUsageUpdatedListener mOnBatteryUsageUpdatedListener;
-    private OnScreenOnTimeUpdatedListener mOnScreenOnTimeUpdatedListener;
-    private OnBatteryTipsUpdatedListener mOnBatteryTipsUpdatedListener;
-    private AtomicBoolean mIsAppResume = new AtomicBoolean(false);
+    private OnSelectedIndexUpdatedListener mOnSelectedIndexUpdatedListener;
 
     private final SettingsActivity mActivity;
     private final MetricsFeatureProvider mMetricsFeatureProvider;
-    private final PowerUsageFeatureProvider mPowerUsageFeatureProvider;
     private final Handler mHandler = new Handler(Looper.getMainLooper());
     private final AnimatorListenerAdapter mHourlyChartFadeInAdapter =
             createHourlyChartAnimatorListenerAdapter(/*visible=*/ true);
     private final AnimatorListenerAdapter mHourlyChartFadeOutAdapter =
             createHourlyChartAnimatorListenerAdapter(/*visible=*/ false);
-    private final ExecutorService mExecutor = Executors.newSingleThreadExecutor();
 
     @VisibleForTesting
     final DailyChartLabelTextGenerator mDailyChartLabelTextGenerator =
@@ -165,8 +118,6 @@
         mIs24HourFormat = DateFormat.is24HourFormat(context);
         mMetricsFeatureProvider =
                 FeatureFactory.getFactory(mContext).getMetricsFeatureProvider();
-        mPowerUsageFeatureProvider =
-                FeatureFactory.getFactory(mContext).getPowerUsageFeatureProvider(context);
         if (lifecycle != null) {
             lifecycle.addObserver(this);
         }
@@ -184,15 +135,9 @@
         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);
     }
@@ -232,16 +177,16 @@
         return PREFERENCE_KEY;
     }
 
-    void setOnBatteryUsageUpdatedListener(OnBatteryUsageUpdatedListener listener) {
-        mOnBatteryUsageUpdatedListener = listener;
+    int getDailyChartIndex() {
+        return mDailyChartIndex;
     }
 
-    void setOnScreenOnTimeUpdatedListener(OnScreenOnTimeUpdatedListener listener) {
-        mOnScreenOnTimeUpdatedListener = listener;
+    int getHourlyChartIndex() {
+        return mHourlyChartIndex;
     }
 
-    void setOnBatteryTipsUpdatedListener(OnBatteryTipsUpdatedListener listener) {
-        mOnBatteryTipsUpdatedListener = listener;
+    void setOnSelectedIndexUpdatedListener(OnSelectedIndexUpdatedListener listener) {
+        mOnSelectedIndexUpdatedListener = listener;
     }
 
     void onBatteryLevelDataUpdate(final BatteryLevelData batteryLevelData) {
@@ -276,13 +221,37 @@
         refreshUi();
     }
 
-    void onBatteryUsageMapUpdate(Map<Integer, Map<Integer, BatteryDiffData>> batteryUsageMap) {
-        Log.d(TAG, "onBatteryUsageMapUpdate: " + batteryUsageMap);
-        mBatteryUsageMap = batteryUsageMap;
-        logScreenUsageTime();
+    void onHighlightSlotIndexUpdate(int dailyHighlightSlotIndex, int hourlyHighlightSlotIndex) {
+        if (mDailyHighlightSlotIndex == dailyHighlightSlotIndex
+                && mHourlyHighlightSlotIndex == hourlyHighlightSlotIndex) {
+            return;
+        }
+        mDailyHighlightSlotIndex = dailyHighlightSlotIndex;
+        mHourlyHighlightSlotIndex = hourlyHighlightSlotIndex;
         refreshUi();
     }
 
+    void selectHighlightSlotIndex() {
+        if (mDailyHighlightSlotIndex == BatteryChartViewModel.SELECTED_INDEX_INVALID
+                || mHourlyHighlightSlotIndex == BatteryChartViewModel.SELECTED_INDEX_INVALID) {
+            return;
+        }
+        if (mDailyHighlightSlotIndex == mDailyChartIndex
+                && mHourlyHighlightSlotIndex == mHourlyChartIndex) {
+            return;
+        }
+        mDailyChartIndex = mDailyHighlightSlotIndex;
+        mHourlyChartIndex = mHourlyHighlightSlotIndex;
+        Log.d(TAG, String.format("onDailyChartSelect:%d, onHourlyChartSelect:%d",
+                mDailyChartIndex, mHourlyChartIndex));
+        refreshUi();
+        mHandler.post(() -> mDailyChartView.announceForAccessibility(
+                getAccessibilityAnnounceMessage()));
+        if (mOnSelectedIndexUpdatedListener != null) {
+            mOnSelectedIndexUpdatedListener.onSelectedIndexUpdated();
+        }
+    }
+
     void setBatteryChartView(@NonNull final BatteryChartView dailyChartView,
             @NonNull final BatteryChartView hourlyChartView) {
         final View parentView = (View) dailyChartView.getParent();
@@ -319,6 +288,9 @@
                             ? SettingsEnums.ACTION_BATTERY_USAGE_DAILY_SHOW_ALL
                             : SettingsEnums.ACTION_BATTERY_USAGE_DAILY_TIME_SLOT,
                     mDailyChartIndex);
+            if (mOnSelectedIndexUpdatedListener != null) {
+                mOnSelectedIndexUpdatedListener.onSelectedIndexUpdated();
+            }
         });
         mHourlyChartView = hourlyChartView;
         mHourlyChartView.setOnSelectListener(trapezoidIndex -> {
@@ -340,105 +312,37 @@
                             ? SettingsEnums.ACTION_BATTERY_USAGE_SHOW_ALL
                             : SettingsEnums.ACTION_BATTERY_USAGE_TIME_SLOT,
                     mHourlyChartIndex);
+            if (mOnSelectedIndexUpdatedListener != null) {
+                mOnSelectedIndexUpdatedListener.onSelectedIndexUpdated();
+            }
         });
         refreshUi();
     }
 
+    // Show empty hourly chart view only if there is no valid battery usage data.
+    void showEmptyChart() {
+        setChartSummaryVisible(true);
+        mDailyChartView.setVisibility(View.GONE);
+        mHourlyChartView.setVisibility(View.VISIBLE);
+        mHourlyChartView.setViewModel(null);
+    }
+
     @VisibleForTesting
-    boolean refreshUi() {
+    void refreshUi() {
         if (mDailyChartView == null || mHourlyChartView == null) {
             // Chart views are not initialized.
-            return false;
+            return;
         }
 
-        // When mDailyViewModel or mHourlyViewModels is null, there is no battery level data.
-        // This is mainly in 2 cases:
-        // 1) battery data is within 2 hours
-        // 2) no battery data in the latest 7 days (power off >= 7 days)
-        final boolean refreshUiResult = mDailyViewModel == null || mHourlyViewModels == null
-                ? refreshUiWithNoLevelDataCase()
-                : refreshUiWithLevelDataCase();
-
-        if (!refreshUiResult) {
-            return false;
-        }
-
-        if (mOnBatteryUsageUpdatedListener != null && mBatteryUsageMap != null
-                && mBatteryUsageMap.get(mDailyChartIndex) != null) {
-            final BatteryDiffData slotUsageData =
-                    mBatteryUsageMap.get(mDailyChartIndex).get(mHourlyChartIndex);
-            if (slotUsageData != null) {
-                mOnScreenOnTimeUpdatedListener.onScreenOnTimeUpdated(
-                        slotUsageData.getScreenOnTime(),
-                        getSlotInformation());
-            }
-            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(() -> {
-                                if (mIsAppResume.get()) {
-                                    mOnBatteryTipsUpdatedListener
-                                            .onBatteryTipsUpdated(displayEvent);
-                                }
-                            }
-                    );
-                });
-            }
-        }
-        return true;
-    }
-
-    @VisibleForTesting
-    PowerAnomalyEvent getHighestScoreAnomalyEvent(PowerAnomalyEventList anomalyEventList) {
-        if (anomalyEventList == null || anomalyEventList.getPowerAnomalyEventsCount() == 0) {
-            return null;
-        }
-        final Set<String> dismissedPowerAnomalyKeys =
-                DatabaseUtils.getDismissedPowerAnomalyKeys(mContext);
-        Log.d(TAG, "dismissedPowerAnomalyKeys = " + dismissedPowerAnomalyKeys);
-
-        final PowerAnomalyEvent highestScoreEvent = anomalyEventList.getPowerAnomalyEventsList()
-                .stream()
-                .filter(event -> event.hasKey()
-                        && !dismissedPowerAnomalyKeys.contains(event.getKey().name()))
-                .max(Comparator.comparing(PowerAnomalyEvent::getScore))
-                .orElse(null);
-        Log.d(TAG, "highestScoreAnomalyEvent = " + highestScoreEvent);
-        return highestScoreEvent;
-    }
-
-    private boolean refreshUiWithNoLevelDataCase() {
-        setChartSummaryVisible(false);
-        if (mBatteryUsageMap == null) {
-            // There is no battery level data and battery usage data is not ready, wait for data
-            // ready to refresh UI. Show nothing temporarily.
+        if (mDailyViewModel == null || mHourlyViewModels == null) {
+            setChartSummaryVisible(false);
             mDailyChartView.setVisibility(View.GONE);
             mHourlyChartView.setVisibility(View.GONE);
             mDailyChartView.setViewModel(null);
             mHourlyChartView.setViewModel(null);
-            return false;
-        } else if (mBatteryUsageMap
-                .get(BatteryChartViewModel.SELECTED_INDEX_ALL)
-                .get(BatteryChartViewModel.SELECTED_INDEX_ALL) == null) {
-            // There is no battery level data and battery usage data, show an empty hourly chart
-            // view.
-            mDailyChartView.setVisibility(View.GONE);
-            mHourlyChartView.setVisibility(View.VISIBLE);
-            mHourlyChartView.setViewModel(null);
+            return;
         }
-        return true;
-    }
 
-    private boolean refreshUiWithLevelDataCase() {
         setChartSummaryVisible(true);
         // Gets valid battery level data.
         if (isBatteryLevelDataInOneDay()) {
@@ -451,6 +355,7 @@
                 mDailyChartIndex = BatteryChartViewModel.SELECTED_INDEX_ALL;
             }
             mDailyViewModel.setSelectedIndex(mDailyChartIndex);
+            mDailyViewModel.setHighlightSlotIndex(mDailyHighlightSlotIndex);
             mDailyChartView.setViewModel(mDailyViewModel);
         }
 
@@ -465,17 +370,13 @@
                 mHourlyChartIndex = BatteryChartViewModel.SELECTED_INDEX_ALL;
             }
             hourlyViewModel.setSelectedIndex(mHourlyChartIndex);
+            hourlyViewModel.setHighlightSlotIndex((mDailyChartIndex == mDailyHighlightSlotIndex)
+                    ? mHourlyHighlightSlotIndex
+                    : BatteryChartViewModel.SELECTED_INDEX_INVALID);
             mHourlyChartView.setViewModel(hourlyViewModel);
         }
-
-        if (mBatteryUsageMap == null) {
-            // Battery usage data is not ready, wait for data ready to refresh UI.
-            return false;
-        }
-        return true;
     }
 
-    @VisibleForTesting
     String getSlotInformation() {
         if (mDailyViewModel == null || mHourlyViewModels == null) {
             // No data
@@ -566,44 +467,6 @@
         };
     }
 
-    private void logScreenUsageTime() {
-        if (mBatteryUsageMap == null) {
-            return;
-        }
-        final BatteryDiffData allBatteryDiffData = mBatteryUsageMap.get(
-                BatteryChartViewModel.SELECTED_INDEX_ALL).get(
-                BatteryChartViewModel.SELECTED_INDEX_ALL);
-        if (allBatteryDiffData == null) {
-            return;
-        }
-        mMetricsFeatureProvider.action(
-                mPrefContext,
-                SettingsEnums.ACTION_BATTERY_USAGE_SCREEN_ON_TIME,
-                (int) allBatteryDiffData.getScreenOnTime());
-        mMetricsFeatureProvider.action(
-                mPrefContext,
-                SettingsEnums.ACTION_BATTERY_USAGE_FOREGROUND_USAGE_TIME,
-                (int) getTotalForegroundUsageTime());
-    }
-
-    private long getTotalForegroundUsageTime() {
-        if (mBatteryUsageMap == null) {
-            return 0;
-        }
-        final BatteryDiffData totalBatteryUsageDiffData =
-                mBatteryUsageMap
-                        .get(BatteryChartViewModel.SELECTED_INDEX_ALL)
-                        .get(BatteryChartViewModel.SELECTED_INDEX_ALL);
-        if (totalBatteryUsageDiffData == null) {
-            return 0;
-        }
-        long totalValue = 0;
-        for (final BatteryDiffEntry entry : totalBatteryUsageDiffData.getAppDiffEntryList()) {
-            totalValue += entry.mForegroundUsageTimeInMs;
-        }
-        return totalValue;
-    }
-
     private boolean isBatteryLevelDataInOneDay() {
         return mHourlyViewModels != null && mHourlyViewModels.size() == 1;
     }
@@ -614,19 +477,6 @@
                 && mHourlyChartIndex == BatteryChartViewModel.SELECTED_INDEX_ALL;
     }
 
-    private boolean isBatteryUsageMapNullOrEmpty() {
-        if (mBatteryUsageMap == null) {
-            return true;
-        }
-        BatteryDiffData allBatteryDiffData = mBatteryUsageMap
-                .get(BatteryChartViewModel.SELECTED_INDEX_ALL)
-                .get(BatteryChartViewModel.SELECTED_INDEX_ALL);
-        // If all data is null or empty, each slot must be null or empty.
-        return allBatteryDiffData == null
-                || (allBatteryDiffData.getAppDiffEntryList().isEmpty()
-                && allBatteryDiffData.getSystemDiffEntryList().isEmpty());
-    }
-
     @VisibleForTesting
     static int getTotalHours(final BatteryLevelData batteryLevelData) {
         if (batteryLevelData == null) {
diff --git a/src/com/android/settings/fuelgauge/batteryusage/BatteryChartView.java b/src/com/android/settings/fuelgauge/batteryusage/BatteryChartView.java
index 086f56c..bb468fe 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/BatteryChartView.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/BatteryChartView.java
@@ -31,6 +31,7 @@
 import android.graphics.Paint;
 import android.graphics.Path;
 import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
 import android.os.Bundle;
 import android.util.ArraySet;
 import android.util.AttributeSet;
@@ -90,6 +91,15 @@
     private int mTrapezoidHoverColor;
     private int mDefaultTextColor;
     private int mTextPadding;
+    private int mTransomIconSize;
+    private int mTransomTop;
+    private int mTransomViewHeight;
+    private int mTransomLineDefaultColor;
+    private int mTransomLineSelectedColor;
+    private float mTransomPadding;
+    private Drawable mTransomIcon;
+    private Paint mTransomLinePaint;
+    private Paint mTransomSelectedSlotPaint;
     private Paint mDividerPaint;
     private Paint mTrapezoidPaint;
     private Paint mTextPaint;
@@ -123,8 +133,9 @@
             return;
         }
 
-        Log.d(TAG, String.format("setViewModel(): size: %d, selectedIndex: %d.",
-                viewModel.size(), viewModel.selectedIndex()));
+        Log.d(TAG, String.format(
+                "setViewModel(): size: %d, selectedIndex: %d, getHighlightSlotIndex: %d",
+                viewModel.size(), viewModel.selectedIndex(), viewModel.getHighlightSlotIndex()));
         mViewModel = viewModel;
         initializeAxisLabelsBounds();
         initializeTrapezoidSlots(viewModel.size() - 1);
@@ -162,7 +173,7 @@
                         mPercentageBounds[index]);
             }
             // Updates the indent configurations.
-            mIndent.top = mPercentageBounds[0].height();
+            mIndent.top = mPercentageBounds[0].height() + mTransomViewHeight;
             final int textWidth = mPercentageBounds[0].width() + mTextPadding;
             if (isRTL()) {
                 mIndent.left = textWidth;
@@ -196,6 +207,7 @@
         }
         drawVerticalDividers(canvas);
         drawTrapezoids(canvas);
+        drawTransomLine(canvas);
     }
 
     @Override
@@ -340,6 +352,40 @@
                         resources.getDimensionPixelSize(R.dimen.chartview_trapezoid_radius)));
         // Initializes for drawing text information.
         mTextPadding = resources.getDimensionPixelSize(R.dimen.chartview_text_padding);
+        // Initializes the padding top for drawing text information.
+        mTransomViewHeight = resources.getDimensionPixelSize(
+                R.dimen.chartview_transom_layout_height);
+    }
+
+    private void initializeTransomPaint() {
+        if (mTransomLinePaint != null && mTransomSelectedSlotPaint != null
+                && mTransomIcon != null) {
+            return;
+        }
+        // Initializes the transom line paint.
+        final Resources resources = getContext().getResources();
+        final int transomLineWidth = resources.getDimensionPixelSize(
+                R.dimen.chartview_transom_width);
+        final int transomRadius = resources.getDimensionPixelSize(R.dimen.chartview_transom_radius);
+        mTransomPadding = transomRadius * .5f;
+        mTransomTop = resources.getDimensionPixelSize(R.dimen.chartview_transom_padding_top);
+        mTransomLineDefaultColor = Utils.getDisabled(mContext, DIVIDER_COLOR);
+        mTransomLineSelectedColor = resources.getColor(
+                R.color.color_battery_anomaly_yellow_selector);
+        final int slotHighlightColor = Utils.getDisabled(mContext, mTransomLineSelectedColor);
+        mTransomIconSize = resources.getDimensionPixelSize(R.dimen.chartview_transom_icon_size);
+        mTransomLinePaint = new Paint();
+        mTransomLinePaint.setAntiAlias(true);
+        mTransomLinePaint.setStyle(Paint.Style.STROKE);
+        mTransomLinePaint.setStrokeWidth(transomLineWidth);
+        mTransomLinePaint.setStrokeCap(Paint.Cap.ROUND);
+        mTransomLinePaint.setPathEffect(new CornerPathEffect(transomRadius));
+        mTransomSelectedSlotPaint = new Paint();
+        mTransomSelectedSlotPaint.setAntiAlias(true);
+        mTransomSelectedSlotPaint.setColor(slotHighlightColor);
+        mTransomSelectedSlotPaint.setStyle(Paint.Style.FILL);
+        // Get the companion icon beside transom line
+        mTransomIcon = getResources().getDrawable(R.drawable.ic_battery_tips_warning_icon);
     }
 
     private void drawHorizontalDividers(Canvas canvas) {
@@ -592,6 +638,50 @@
         }
     }
 
+    private boolean isHighlightSlotValid() {
+        return mViewModel != null && mViewModel.getHighlightSlotIndex()
+                != BatteryChartViewModel.SELECTED_INDEX_INVALID;
+    }
+
+    private void drawTransomLine(Canvas canvas) {
+        if (!isHighlightSlotValid()) {
+            return;
+        }
+        initializeTransomPaint();
+        // Draw the whole transom line and a warning icon
+        mTransomLinePaint.setColor(mTransomLineDefaultColor);
+        final int width = getWidth() - abs(mIndent.width());
+        final float transomOffset = mTrapezoidHOffset + mDividerWidth * .5f + mTransomPadding;
+        final float trapezoidBottom = getHeight() - mIndent.bottom - mDividerHeight - mDividerWidth
+                - mTrapezoidVOffset;
+        canvas.drawLine(mIndent.left + transomOffset, mTransomTop,
+                mIndent.left + width - transomOffset, mTransomTop,
+                mTransomLinePaint);
+        drawTransomIcon(canvas);
+        // Draw selected segment of transom line and a highlight slot
+        mTransomLinePaint.setColor(mTransomLineSelectedColor);
+        final int index = mViewModel.getHighlightSlotIndex();
+        final float startX = mTrapezoidSlots[index].mLeft;
+        final float endX = mTrapezoidSlots[index].mRight;
+        canvas.drawLine(startX + mTransomPadding, mTransomTop,
+                endX - mTransomPadding, mTransomTop,
+                mTransomLinePaint);
+        canvas.drawRect(startX, mTransomTop, endX, trapezoidBottom,
+                mTransomSelectedSlotPaint);
+    }
+
+    private void drawTransomIcon(Canvas canvas) {
+        if (mTransomIcon == null) {
+            return;
+        }
+        final int left = isRTL()
+                ? mIndent.left - mTextPadding - mTransomIconSize
+                : getWidth() - abs(mIndent.width()) + mTextPadding;
+        mTransomIcon.setBounds(left, mTransomTop - mTransomIconSize / 2,
+                left + mTransomIconSize, mTransomTop + mTransomIconSize / 2);
+        mTransomIcon.draw(canvas);
+    }
+
     // Searches the corresponding trapezoid index from x location.
     private int getTrapezoidIndex(float x) {
         if (mTrapezoidSlots == null) {
diff --git a/src/com/android/settings/fuelgauge/batteryusage/BatteryChartViewModel.java b/src/com/android/settings/fuelgauge/batteryusage/BatteryChartViewModel.java
index f58d241..bf8a771 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/BatteryChartViewModel.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/BatteryChartViewModel.java
@@ -55,6 +55,7 @@
     private final String[] mFullTexts;
 
     private int mSelectedIndex = SELECTED_INDEX_ALL;
+    private int mHighlightSlotIndex = SELECTED_INDEX_INVALID;
 
     BatteryChartViewModel(@NonNull List<Integer> levels, @NonNull List<Long> timestamps,
             @NonNull AxisLabelPosition axisLabelPosition,
@@ -106,6 +107,14 @@
         mSelectedIndex = index;
     }
 
+    public int getHighlightSlotIndex() {
+        return mHighlightSlotIndex;
+    }
+
+    public void setHighlightSlotIndex(int index) {
+        mHighlightSlotIndex = index;
+    }
+
     @Override
     public int hashCode() {
         return Objects.hash(mLevels, mTimestamps, mSelectedIndex, mAxisLabelPosition);
diff --git a/src/com/android/settings/fuelgauge/batteryusage/BatteryLevelData.java b/src/com/android/settings/fuelgauge/batteryusage/BatteryLevelData.java
index 53ebbd9..09d66c7 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/BatteryLevelData.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/BatteryLevelData.java
@@ -20,6 +20,7 @@
 
 import android.text.format.DateUtils;
 import android.util.ArrayMap;
+import android.util.Pair;
 
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
@@ -69,6 +70,16 @@
             return String.format(Locale.ENGLISH, "timestamps: %s; levels: %s",
                     Objects.toString(mTimestamps), Objects.toString(mLevels));
         }
+
+        private int getIndexByTimestamps(long startTimestamp, long endTimestamp) {
+            for (int index = 0; index < mTimestamps.size() - 1; index++) {
+                if (mTimestamps.get(index) <= startTimestamp
+                        && endTimestamp <= mTimestamps.get(index + 1)) {
+                    return index;
+                }
+            }
+            return BatteryChartViewModel.SELECTED_INDEX_INVALID;
+        }
     }
 
     /**
@@ -100,6 +111,18 @@
         }
     }
 
+    /** Gets daily and hourly index between start and end timestamps. */
+    public Pair<Integer, Integer> getIndexByTimestamps(long startTimestamp, long endTimestamp) {
+        final int dailyHighlightIndex =
+                mDailyBatteryLevels.getIndexByTimestamps(startTimestamp, endTimestamp);
+        final int hourlyHighlightIndex =
+                (dailyHighlightIndex == BatteryChartViewModel.SELECTED_INDEX_INVALID)
+                        ? BatteryChartViewModel.SELECTED_INDEX_INVALID
+                        : mHourlyBatteryLevelsPerDay.get(dailyHighlightIndex)
+                        .getIndexByTimestamps(startTimestamp, endTimestamp);
+        return Pair.create(dailyHighlightIndex, hourlyHighlightIndex);
+    }
+
     public PeriodBatteryLevelData getDailyBatteryLevels() {
         return mDailyBatteryLevels;
     }
diff --git a/src/com/android/settings/fuelgauge/batteryusage/BatteryTipsCardPreference.java b/src/com/android/settings/fuelgauge/batteryusage/BatteryTipsCardPreference.java
index ea5534d..e98077c 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/BatteryTipsCardPreference.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/BatteryTipsCardPreference.java
@@ -16,13 +16,10 @@
 
 package com.android.settings.fuelgauge.batteryusage;
 
-import android.app.settings.SettingsEnums;
 import android.content.Context;
-import android.os.Bundle;
 import android.text.TextUtils;
 import android.util.AttributeSet;
 import android.view.View;
-import android.widget.ImageButton;
 import android.widget.ImageView;
 import android.widget.LinearLayout;
 import android.widget.TextView;
@@ -32,9 +29,6 @@
 import androidx.preference.PreferenceViewHolder;
 
 import com.android.settings.R;
-import com.android.settings.SettingsActivity;
-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;
 
@@ -47,11 +41,17 @@
 
     private static final String TAG = "BatteryTipsCardPreference";
 
-    private final PowerUsageFeatureProvider mPowerUsageFeatureProvider;
-    private final MetricsFeatureProvider mMetricsFeatureProvider;
+    interface OnConfirmListener {
+        void onConfirm();
+    }
 
-    private String mAnomalyEventId;
-    private PowerAnomalyKey mPowerAnomalyKey;
+    interface OnRejectListener {
+        void onReject();
+    }
+
+    private final MetricsFeatureProvider mMetricsFeatureProvider;
+    private OnConfirmListener mOnConfirmListener;
+    private OnRejectListener mOnRejectListener;
     private int mIconResourceId = 0;
     private int mMainButtonStrokeColorResourceId = 0;
 
@@ -59,21 +59,21 @@
     CharSequence mMainButtonLabel;
     @VisibleForTesting
     CharSequence mDismissButtonLabel;
-    @VisibleForTesting
-    String mDestinationComponentName;
-    @VisibleForTesting
-    String mPreferenceHighlightKey;
-    @VisibleForTesting
-    Integer mSourceMetricsCategory;
 
     public BatteryTipsCardPreference(Context context, AttributeSet attrs) {
         super(context, attrs);
         setLayoutResource(R.layout.battery_tips_card);
         setSelectable(false);
         final FeatureFactory featureFactory = FeatureFactory.getFactory(context);
-        mPowerUsageFeatureProvider =  featureFactory.getPowerUsageFeatureProvider(context);
         mMetricsFeatureProvider = featureFactory.getMetricsFeatureProvider();
-        mPowerAnomalyKey = null;
+    }
+
+    public void setOnConfirmListener(OnConfirmListener listener) {
+        mOnConfirmListener = listener;
+    }
+
+    public void setOnRejectListener(OnRejectListener listener) {
+        mOnRejectListener = listener;
     }
 
     /**
@@ -97,13 +97,6 @@
     }
 
     /**
-     * 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) {
@@ -123,50 +116,18 @@
         }
     }
 
-    /**
-     * Sets the power anomaly key of battery tips card.
-     */
-    public void setPowerAnomalyKey(final PowerAnomalyKey powerAnomalyKey) {
-        mPowerAnomalyKey = powerAnomalyKey;
-    }
-
-    /**
-     * Sets the info of target fragment launched by main button.
-     */
-    public void setMainButtonLauncherInfo(final String destinationClassName,
-            final Integer sourceMetricsCategory, final String highlightKey) {
-        mDestinationComponentName = destinationClassName;
-        mSourceMetricsCategory = sourceMetricsCategory;
-        mPreferenceHighlightKey = highlightKey;
-    }
-
     @Override
     public void onClick(View view) {
         final int viewId = view.getId();
         if (viewId == R.id.main_button || viewId == R.id.tips_card) {
-            if (TextUtils.isEmpty(mDestinationComponentName)) {
-                return;
-            }
-            Bundle arguments = Bundle.EMPTY;
-            if (!TextUtils.isEmpty(mPreferenceHighlightKey)) {
-                arguments = new Bundle(1);
-                arguments.putString(SettingsActivity.EXTRA_FRAGMENT_ARG_KEY,
-                        mPreferenceHighlightKey);
-            }
-            new SubSettingLauncher(getContext())
-                    .setDestination(mDestinationComponentName)
-                    .setSourceMetricsCategory(mSourceMetricsCategory)
-                    .setArguments(arguments)
-                    .launch();
             setVisible(false);
-            mMetricsFeatureProvider.action(
-                    getContext(), SettingsEnums.ACTION_BATTERY_TIPS_CARD_ACCEPT, mAnomalyEventId);
+            if (mOnConfirmListener != null) {
+                mOnConfirmListener.onConfirm();
+            }
         } else if (viewId == R.id.dismiss_button) {
             setVisible(false);
-            mMetricsFeatureProvider.action(
-                    getContext(), SettingsEnums.ACTION_BATTERY_TIPS_CARD_DISMISS, mAnomalyEventId);
-            if (mPowerAnomalyKey != null) {
-                DatabaseUtils.setDismissedPowerAnomalyKeys(getContext(), mPowerAnomalyKey.name());
+            if (mOnRejectListener != null) {
+                mOnRejectListener.onReject();
             }
         }
     }
@@ -191,17 +152,5 @@
         if (mIconResourceId != 0) {
             ((ImageView) view.findViewById(R.id.icon)).setImageResource(mIconResourceId);
         }
-
-        if (!mPowerUsageFeatureProvider.isBatteryTipsFeedbackEnabled()) {
-            return;
-        }
-        view.findViewById(R.id.tips_card)
-                .setBackgroundResource(R.drawable.battery_tips_half_rounded_top_bg);
-        view.findViewById(R.id.feedback_card).setVisibility(View.VISIBLE);
-
-        ImageButton thumbUpButton = (ImageButton) view.findViewById(R.id.thumb_up);
-        thumbUpButton.setOnClickListener(this);
-        ImageButton thumbDownButton = (ImageButton) view.findViewById(R.id.thumb_down);
-        thumbDownButton.setOnClickListener(this);
     }
 }
diff --git a/src/com/android/settings/fuelgauge/batteryusage/BatteryTipsController.java b/src/com/android/settings/fuelgauge/batteryusage/BatteryTipsController.java
index 80b2695..400e70a 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/BatteryTipsController.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/BatteryTipsController.java
@@ -18,14 +18,16 @@
 
 import android.app.settings.SettingsEnums;
 import android.content.Context;
+import android.os.Bundle;
 import android.text.TextUtils;
 
 import androidx.preference.PreferenceScreen;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.settings.R;
+import com.android.settings.SettingsActivity;
 import com.android.settings.core.BasePreferenceController;
-import com.android.settings.fuelgauge.PowerUsageFeatureProvider;
+import com.android.settings.core.SubSettingLauncher;
 import com.android.settings.overlay.FeatureFactory;
 import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
 
@@ -38,23 +40,32 @@
     private static final String ROOT_PREFERENCE_KEY = "battery_tips_category";
     private static final String CARD_PREFERENCE_KEY = "battery_tips_card";
 
-    private final PowerUsageFeatureProvider mPowerUsageFeatureProvider;
     private final MetricsFeatureProvider mMetricsFeatureProvider;
 
+    /** A callback listener for the battery tips is confirmed. */
+    interface OnAnomalyConfirmListener {
+        /** The callback function for the battery tips is confirmed. */
+        void onAnomalyConfirm();
+    }
+
+    /** A callback listener for the battery tips is rejected. */
+    interface OnAnomalyRejectListener {
+        /** The callback function for the battery tips is rejected. */
+        void onAnomalyReject();
+    }
+
+    private OnAnomalyConfirmListener mOnAnomalyConfirmListener;
+    private OnAnomalyRejectListener mOnAnomalyRejectListener;
+
     @VisibleForTesting
     BatteryTipsCardPreference mCardPreference;
 
     public BatteryTipsController(Context context) {
         super(context, ROOT_PREFERENCE_KEY);
         final FeatureFactory featureFactory = FeatureFactory.getFactory(context);
-        mPowerUsageFeatureProvider =  featureFactory.getPowerUsageFeatureProvider(context);
         mMetricsFeatureProvider = featureFactory.getMetricsFeatureProvider();
     }
 
-    private boolean isTipsCardVisible() {
-        return mPowerUsageFeatureProvider.isBatteryTipsEnabled();
-    }
-
     @Override
     public int getAvailabilityStatus() {
         return AVAILABLE;
@@ -66,6 +77,14 @@
         mCardPreference = screen.findPreference(CARD_PREFERENCE_KEY);
     }
 
+    void setOnAnomalyConfirmListener(OnAnomalyConfirmListener listener) {
+        mOnAnomalyConfirmListener = listener;
+    }
+
+    void setOnAnomalyRejectListener(OnAnomalyRejectListener listener) {
+        mOnAnomalyRejectListener = listener;
+    }
+
     private <T> T getInfo(PowerAnomalyEvent powerAnomalyEvent,
                           Function<WarningBannerInfo, T> warningBannerInfoSupplier,
                           Function<WarningItemInfo, T> warningItemInfoSupplier) {
@@ -102,12 +121,22 @@
                 : getStringFromResource(resourceId, resourceIndex);
     }
 
-    @VisibleForTesting
-    void handleBatteryTipsCardUpdated(PowerAnomalyEvent powerAnomalyEvent) {
-        if (!isTipsCardVisible()) {
-            mCardPreference.setVisible(false);
-            return;
+    /** Generate a key string of current anomaly to record as dismissed in sharedPreferences. */
+    public static String getDismissRecordKey(PowerAnomalyEvent event) {
+        if (!event.hasKey()) {
+            return null;
         }
+        switch (event.getKey()){
+            case KEY_APP:
+                return event.hasWarningItemInfo()
+                        && event.getWarningItemInfo().hasDismissRecordKey()
+                        ? event.getWarningItemInfo().getDismissRecordKey() : null;
+            default:
+                return event.getKey().name();
+        }
+    }
+
+    void handleBatteryTipsCardUpdated(PowerAnomalyEvent powerAnomalyEvent) {
         if (powerAnomalyEvent == null) {
             mCardPreference.setVisible(false);
             return;
@@ -121,44 +150,76 @@
                 R.array.battery_tips_card_colors, cardStyleId, "color");
 
         // Get card preference strings and navigate fragment info
+        final String eventId = powerAnomalyEvent.hasEventId()
+                ? powerAnomalyEvent.getEventId() : null;
         final PowerAnomalyKey powerAnomalyKey = powerAnomalyEvent.hasKey()
                 ? powerAnomalyEvent.getKey() : null;
         final int resourceIndex = powerAnomalyKey != null ? powerAnomalyKey.getNumber() : -1;
 
-        String titleString = getString(powerAnomalyEvent, WarningBannerInfo::getTitleString,
+        final String titleString = getString(powerAnomalyEvent, WarningBannerInfo::getTitleString,
                 WarningItemInfo::getTitleString, R.array.power_anomaly_titles, resourceIndex);
         if (titleString.isEmpty()) {
             mCardPreference.setVisible(false);
             return;
         }
 
-        String mainBtnString = getString(powerAnomalyEvent,
+        final String mainBtnString = getString(powerAnomalyEvent,
                 WarningBannerInfo::getMainButtonString, WarningItemInfo::getMainButtonString,
                 R.array.power_anomaly_main_btn_strings, resourceIndex);
-        String dismissBtnString = getString(powerAnomalyEvent,
+        final String dismissBtnString = getString(powerAnomalyEvent,
                 WarningBannerInfo::getCancelButtonString, WarningItemInfo::getCancelButtonString,
                 R.array.power_anomaly_dismiss_btn_strings, resourceIndex);
 
-        String destinationClassName = getInfo(powerAnomalyEvent,
+        final String destinationClassName = getInfo(powerAnomalyEvent,
                 WarningBannerInfo::getMainButtonDestination, null);
-        Integer sourceMetricsCategory = getInfo(powerAnomalyEvent,
+        final Integer sourceMetricsCategory = getInfo(powerAnomalyEvent,
                 WarningBannerInfo::getMainButtonSourceMetricsCategory, null);
-        String preferenceHighlightKey = getInfo(powerAnomalyEvent,
+        final String preferenceHighlightKey = getInfo(powerAnomalyEvent,
                 WarningBannerInfo::getMainButtonSourceHighlightKey, null);
 
         // Update card preference and main button fragment launcher
-        mCardPreference.setAnomalyEventId(powerAnomalyEvent.getEventId());
-        mCardPreference.setPowerAnomalyKey(powerAnomalyKey);
         mCardPreference.setTitle(titleString);
         mCardPreference.setIconResourceId(iconResId);
         mCardPreference.setMainButtonStrokeColorResourceId(colorResId);
         mCardPreference.setMainButtonLabel(mainBtnString);
         mCardPreference.setDismissButtonLabel(dismissBtnString);
-        mCardPreference.setMainButtonLauncherInfo(
-                destinationClassName, sourceMetricsCategory, preferenceHighlightKey);
-        mCardPreference.setVisible(true);
 
-        mMetricsFeatureProvider.action(mContext,
-                SettingsEnums.ACTION_BATTERY_TIPS_CARD_SHOW, powerAnomalyEvent.getEventId());
+        // Set battery tips card listener
+        mCardPreference.setOnConfirmListener(() -> {
+            if (mOnAnomalyConfirmListener != null) {
+                mOnAnomalyConfirmListener.onAnomalyConfirm();
+            } else if (!TextUtils.isEmpty(destinationClassName)) {
+                // Navigate to sub setting page
+                Bundle arguments = Bundle.EMPTY;
+                if (!TextUtils.isEmpty(preferenceHighlightKey)) {
+                    arguments = new Bundle(1);
+                    arguments.putString(SettingsActivity.EXTRA_FRAGMENT_ARG_KEY,
+                            preferenceHighlightKey);
+                }
+                new SubSettingLauncher(mContext)
+                        .setDestination(destinationClassName)
+                        .setSourceMetricsCategory(sourceMetricsCategory)
+                        .setArguments(arguments)
+                        .launch();
+            }
+            mMetricsFeatureProvider.action(
+                    mContext, SettingsEnums.ACTION_BATTERY_TIPS_CARD_ACCEPT, eventId);
+        });
+        mCardPreference.setOnRejectListener(() -> {
+            if (mOnAnomalyRejectListener != null) {
+                mOnAnomalyRejectListener.onAnomalyReject();
+            }
+            // For anomaly events with same record key, dismissed until next time full charged.
+            final String dismissRecordKey = getDismissRecordKey(powerAnomalyEvent);
+            if (!TextUtils.isEmpty(dismissRecordKey)) {
+                DatabaseUtils.setDismissedPowerAnomalyKeys(mContext, dismissRecordKey);
+            }
+            mMetricsFeatureProvider.action(
+                    mContext, SettingsEnums.ACTION_BATTERY_TIPS_CARD_DISMISS, eventId);
+        });
+
+        mCardPreference.setVisible(true);
+        mMetricsFeatureProvider.action(
+                mContext, SettingsEnums.ACTION_BATTERY_TIPS_CARD_SHOW, eventId);
     }
 }
diff --git a/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBroadcastReceiver.java b/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBroadcastReceiver.java
index ed5f182..952b83f 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBroadcastReceiver.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBroadcastReceiver.java
@@ -120,6 +120,7 @@
 
         mFetchBatteryUsageData = true;
         BatteryUsageDataLoader.enqueueWork(context, /*isFullChargeStart=*/ true);
+        BootBroadcastReceiver.invokeJobRecheck(context);
     }
 
     private void sendBatteryEventData(Context context, BatteryEventType batteryEventType) {
diff --git a/src/com/android/settings/fuelgauge/batteryusage/ConvertUtils.java b/src/com/android/settings/fuelgauge/batteryusage/ConvertUtils.java
index ec0d01a..a1987c9 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/ConvertUtils.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/ConvertUtils.java
@@ -473,6 +473,9 @@
                 .setConsumePower(batteryDiffEntry.mConsumePower)
                 .setForegroundUsageConsumePower(batteryDiffEntry.mForegroundUsageConsumePower)
                 .setBackgroundUsageConsumePower(batteryDiffEntry.mBackgroundUsageConsumePower)
+                .setForegroundServiceUsageConsumePower(
+                        batteryDiffEntry.mForegroundServiceUsageConsumePower)
+                .setCachedUsageConsumePower(batteryDiffEntry.mCachedUsageConsumePower)
                 .setForegroundUsageTime(batteryDiffEntry.mForegroundUsageTimeInMs)
                 .setBackgroundUsageTime(batteryDiffEntry.mBackgroundUsageTimeInMs)
                 .setScreenOnTime(batteryDiffEntry.mScreenOnTimeInMs);
@@ -525,9 +528,9 @@
                 batteryUsageDiff.getScreenOnTime(),
                 batteryUsageDiff.getConsumePower(),
                 batteryUsageDiff.getForegroundUsageConsumePower(),
-                /*foregroundServiceUsageConsumePower=*/ 0,
+                batteryUsageDiff.getForegroundServiceUsageConsumePower(),
                 batteryUsageDiff.getBackgroundUsageConsumePower(),
-                /*cachedUsageConsumePower=*/ 0);
+                batteryUsageDiff.getCachedUsageConsumePower());
     }
 
     static BatteryDiffData convertToBatteryDiffData(
diff --git a/src/com/android/settings/fuelgauge/batteryusage/PeriodicJobManager.java b/src/com/android/settings/fuelgauge/batteryusage/PeriodicJobManager.java
index 8c0e66c..43cd69d 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/PeriodicJobManager.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/PeriodicJobManager.java
@@ -68,6 +68,8 @@
     /** Schedules the next alarm job if it is available. */
     public void refreshJob(final boolean fromBoot) {
         if (mAlarmManager == null) {
+            BatteryUsageLogUtils.writeLog(mContext, Action.SCHEDULE_JOB,
+                    "cannot schedule next alarm job due to AlarmManager is null");
             Log.e(TAG, "cannot schedule next alarm job");
             return;
         }
@@ -80,8 +82,8 @@
                 AlarmManager.RTC_WAKEUP, triggerAtMillis, pendingIntent);
 
         final String utcToLocalTime = ConvertUtils.utcToLocalTimeForLogging(triggerAtMillis);
-        BatteryUsageLogUtils.writeLog(
-                mContext, Action.SCHEDULE_JOB, "triggerTime=" + utcToLocalTime);
+        BatteryUsageLogUtils.writeLog(mContext, Action.SCHEDULE_JOB,
+                String.format("triggerTime=%s, fromBoot=%b", utcToLocalTime, fromBoot));
         Log.d(TAG, "schedule next alarm job at " + utcToLocalTime);
     }
 
diff --git a/src/com/android/settings/fuelgauge/batteryusage/PeriodicJobReceiver.java b/src/com/android/settings/fuelgauge/batteryusage/PeriodicJobReceiver.java
index 2371a19..dccca43 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/PeriodicJobReceiver.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/PeriodicJobReceiver.java
@@ -33,12 +33,23 @@
 
     @Override
     public void onReceive(Context context, Intent intent) {
+        try {
+            loadDataAndRefreshJob(context, intent);
+        } catch (Exception e) {
+            BatteryUsageLogUtils.writeLog(context, Action.SCHEDULE_JOB,
+                    String.format("loadDataAndRefreshJob() failed: %s", e));
+        }
+    }
+
+    private static void loadDataAndRefreshJob(Context context, Intent intent) {
         final String action = intent == null ? "" : intent.getAction();
         if (!ACTION_PERIODIC_JOB_UPDATE.equals(action)) {
             Log.w(TAG, "receive unexpected action=" + action);
             return;
         }
         if (DatabaseUtils.isWorkProfile(context)) {
+            BatteryUsageLogUtils.writeLog(context, Action.SCHEDULE_JOB,
+                    "do not refresh job for work profile");
             Log.w(TAG, "do not refresh job for work profile action=" + action);
             return;
         }
diff --git a/src/com/android/settings/fuelgauge/batteryusage/PowerUsageAdvanced.java b/src/com/android/settings/fuelgauge/batteryusage/PowerUsageAdvanced.java
index e4f8b39..4e8e396 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/PowerUsageAdvanced.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/PowerUsageAdvanced.java
@@ -27,6 +27,7 @@
 import android.os.Looper;
 import android.provider.SearchIndexableResource;
 import android.util.Log;
+import android.util.Pair;
 
 import androidx.annotation.VisibleForTesting;
 import androidx.loader.app.LoaderManager;
@@ -44,9 +45,13 @@
 
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Comparator;
 import java.util.List;
 import java.util.Map;
 import java.util.Optional;
+import java.util.Set;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
 
 /** Advanced power usage. */
 @SearchIndexable(forTarget = SearchIndexable.ALL & ~SearchIndexable.ARC)
@@ -63,9 +68,9 @@
 
     private boolean mIsChartDataLoaded = false;
     private long mResumeTimestamp;
-    private BatteryChartPreferenceController mBatteryChartPreferenceController;
-    private Optional<BatteryLevelData> mBatteryLevelData;
+    private Map<Integer, Map<Integer, BatteryDiffData>> mBatteryUsageMap;
 
+    private final ExecutorService mExecutor = Executors.newSingleThreadExecutor();
     private final Handler mHandler = new Handler(Looper.getMainLooper());
     private final ContentObserver mBatteryObserver =
             new ContentObserver(mHandler) {
@@ -78,6 +83,19 @@
                 }
             };
 
+    @VisibleForTesting
+    BatteryTipsController mBatteryTipsController;
+    @VisibleForTesting
+    BatteryChartPreferenceController mBatteryChartPreferenceController;
+    @VisibleForTesting
+    ScreenOnTimeController mScreenOnTimeController;
+    @VisibleForTesting
+    BatteryUsageBreakdownController mBatteryUsageBreakdownController;
+    @VisibleForTesting
+    PowerAnomalyEvent mPowerAnomalyEvent;
+    @VisibleForTesting
+    Optional<BatteryLevelData> mBatteryLevelData;
+
     @Override
     public void onCreate(Bundle icicle) {
         super.onCreate(icicle);
@@ -92,6 +110,7 @@
         if (getActivity().isChangingConfigurations()) {
             BatteryEntry.clearUidCache();
         }
+        mExecutor.shutdown();
     }
 
     @Override
@@ -114,7 +133,6 @@
         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);
@@ -135,33 +153,25 @@
     @Override
     protected List<AbstractPreferenceController> createPreferenceControllers(Context context) {
         final List<AbstractPreferenceController> controllers = new ArrayList<>();
+        mBatteryTipsController = new BatteryTipsController(context);
         mBatteryChartPreferenceController =
                 new BatteryChartPreferenceController(
                         context, getSettingsLifecycle(), (SettingsActivity) getActivity());
-        ScreenOnTimeController screenOnTimeController = new ScreenOnTimeController(context);
-        BatteryUsageBreakdownController batteryUsageBreakdownController =
+        mScreenOnTimeController = new ScreenOnTimeController(context);
+        mBatteryUsageBreakdownController =
                 new BatteryUsageBreakdownController(
                         context, getSettingsLifecycle(), (SettingsActivity) getActivity(), this);
 
-        mBatteryChartPreferenceController.setOnScreenOnTimeUpdatedListener(
-                screenOnTimeController::handleSceenOnTimeUpdated);
-        mBatteryChartPreferenceController.setOnBatteryUsageUpdatedListener(
-                batteryUsageBreakdownController::handleBatteryUsageUpdated);
-
+        controllers.add(mBatteryTipsController);
         controllers.add(mBatteryChartPreferenceController);
-        controllers.add(screenOnTimeController);
-        controllers.add(batteryUsageBreakdownController);
+        controllers.add(mScreenOnTimeController);
+        controllers.add(mBatteryUsageBreakdownController);
         setBatteryChartPreferenceController();
+        mBatteryChartPreferenceController.setOnSelectedIndexUpdatedListener(
+                this::onSelectedSlotDataUpdated);
 
-        final PowerUsageFeatureProvider powerUsageFeatureProvider =
-                FeatureFactory.getFactory(context).getPowerUsageFeatureProvider(context);
-        if (powerUsageFeatureProvider.isBatteryTipsEnabled()) {
-            BatteryTipsController batteryTipsController = new BatteryTipsController(context);
-            mBatteryChartPreferenceController.setOnBatteryTipsUpdatedListener(
-                    batteryTipsController::handleBatteryTipsCardUpdated);
-            controllers.add(batteryTipsController);
-        }
-
+        // Force UI refresh if battery usage data was loaded before UI initialization.
+        onSelectedSlotDataUpdated();
         return controllers;
     }
 
@@ -176,12 +186,18 @@
         bundle.putInt(KEY_REFRESH_TYPE, refreshType);
         if (!mIsChartDataLoaded) {
             mIsChartDataLoaded = true;
+            mBatteryLevelData = null;
+            mBatteryUsageMap = null;
+            mPowerAnomalyEvent = null;
             restartLoader(LoaderIndex.BATTERY_LEVEL_DATA_LOADER, bundle,
                     mBatteryLevelDataLoaderCallbacks);
         }
     }
 
     private void onBatteryLevelDataUpdate(BatteryLevelData batteryLevelData) {
+        if (!isResumed()) {
+            return;
+        }
         mBatteryLevelData = Optional.ofNullable(batteryLevelData);
         if (mBatteryChartPreferenceController != null) {
             mBatteryChartPreferenceController.onBatteryLevelDataUpdate(batteryLevelData);
@@ -191,23 +207,164 @@
     }
 
     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);
+        if (!isResumed() || mBatteryLevelData == null) {
+            return;
         }
+        mBatteryUsageMap = DataProcessor.generateBatteryUsageMap(
+                getContext(), batteryDiffDataMap, mBatteryLevelData.orElse(null));
+        Log.d(TAG, "onBatteryDiffDataMapUpdate: " + mBatteryUsageMap);
+        DataProcessor.loadLabelAndIcon(mBatteryUsageMap);
+        onSelectedSlotDataUpdated();
+        detectAnomaly();
+        logScreenUsageTime();
+        if (mBatteryChartPreferenceController != null
+                && mBatteryLevelData.isEmpty() && isBatteryUsageMapNullOrEmpty()) {
+            // No available battery usage and battery level data.
+            mBatteryChartPreferenceController.showEmptyChart();
+        }
+    }
+
+    private void onSelectedSlotDataUpdated() {
+        if (mBatteryChartPreferenceController == null
+                || mScreenOnTimeController == null
+                || mBatteryUsageBreakdownController == null
+                || mBatteryUsageMap == null) {
+            return;
+        }
+        final int dailyIndex = mBatteryChartPreferenceController.getDailyChartIndex();
+        final int hourlyIndex = mBatteryChartPreferenceController.getHourlyChartIndex();
+        final String slotInformation = mBatteryChartPreferenceController.getSlotInformation();
+        final BatteryDiffData slotUsageData = mBatteryUsageMap.get(dailyIndex).get(hourlyIndex);
+        if (slotUsageData != null) {
+            mScreenOnTimeController.handleSceenOnTimeUpdated(
+                    slotUsageData.getScreenOnTime(), slotInformation);
+        }
+        mBatteryUsageBreakdownController.handleBatteryUsageUpdated(
+                slotUsageData, slotInformation, isBatteryUsageMapNullOrEmpty());
         Log.d(TAG, String.format("Battery usage list shows in %d millis",
                 System.currentTimeMillis() - mResumeTimestamp));
     }
 
+    private void detectAnomaly() {
+        mExecutor.execute(() -> {
+            final PowerUsageFeatureProvider powerUsageFeatureProvider =
+                    FeatureFactory.getFactory(getContext())
+                            .getPowerUsageFeatureProvider(getContext());
+            final PowerAnomalyEventList anomalyEventList =
+                    powerUsageFeatureProvider.detectSettingsAnomaly(
+                            getContext(), /* displayDrain= */ 0);
+            mHandler.post(() -> onAnomalyDetected(anomalyEventList));
+        });
+    }
+
+    private void onAnomalyDetected(PowerAnomalyEventList anomalyEventList) {
+        if (!isResumed() || anomalyEventList == null) {
+            return;
+        }
+        Log.d(TAG, "anomalyEventList = " + anomalyEventList);
+        final PowerAnomalyEvent displayEvent =
+                getHighestScoreAnomalyEvent(getContext(), anomalyEventList);
+        onDisplayAnomalyEventUpdated(displayEvent);
+    }
+
+    @VisibleForTesting
+    void onDisplayAnomalyEventUpdated(PowerAnomalyEvent event) {
+        mPowerAnomalyEvent = event;
+        if (mBatteryTipsController == null
+                || mBatteryChartPreferenceController == null
+                || mBatteryUsageBreakdownController == null) {
+            return;
+        }
+
+        // Update battery tips card preference & behaviour
+        mBatteryTipsController.setOnAnomalyConfirmListener(null);
+        mBatteryTipsController.setOnAnomalyRejectListener(null);
+        mBatteryTipsController.handleBatteryTipsCardUpdated(mPowerAnomalyEvent);
+
+        // Update highlight slot effect in battery chart view
+        Pair<Integer, Integer> highlightSlotIndexPair = Pair.create(
+                BatteryChartViewModel.SELECTED_INDEX_INVALID,
+                BatteryChartViewModel.SELECTED_INDEX_INVALID);
+        if (mPowerAnomalyEvent != null && mPowerAnomalyEvent.hasWarningItemInfo()) {
+            final WarningItemInfo warningItemInfo = mPowerAnomalyEvent.getWarningItemInfo();
+            final Long startTimestamp = warningItemInfo.hasStartTimestamp()
+                    ? warningItemInfo.getStartTimestamp() : null;
+            final Long endTimestamp = warningItemInfo.hasEndTimestamp()
+                    ? warningItemInfo.getEndTimestamp() : null;
+            if (startTimestamp != null && endTimestamp != null) {
+                highlightSlotIndexPair = mBatteryLevelData.map(levelData ->
+                                levelData.getIndexByTimestamps(startTimestamp, endTimestamp))
+                        .orElse(highlightSlotIndexPair);
+                mBatteryTipsController.setOnAnomalyConfirmListener(
+                        mBatteryChartPreferenceController::selectHighlightSlotIndex);
+                mBatteryTipsController.setOnAnomalyRejectListener(
+                        () -> onDisplayAnomalyEventUpdated(null));
+            }
+        }
+        mBatteryChartPreferenceController.onHighlightSlotIndexUpdate(
+                highlightSlotIndexPair.first, highlightSlotIndexPair.second);
+    }
+
     private void setBatteryChartPreferenceController() {
         if (mHistPref != null && mBatteryChartPreferenceController != null) {
             mHistPref.setChartPreferenceController(mBatteryChartPreferenceController);
         }
     }
 
+    private boolean isBatteryUsageMapNullOrEmpty() {
+        final BatteryDiffData allBatteryDiffData = getAllBatteryDiffData(mBatteryUsageMap);
+        // If all data is null or empty, each slot must be null or empty.
+        return allBatteryDiffData == null
+                || (allBatteryDiffData.getAppDiffEntryList().isEmpty()
+                && allBatteryDiffData.getSystemDiffEntryList().isEmpty());
+    }
+
+    private void logScreenUsageTime() {
+        final BatteryDiffData allBatteryDiffData = getAllBatteryDiffData(mBatteryUsageMap);
+        if (allBatteryDiffData == null) {
+            return;
+        }
+        long totalForegroundUsageTime = 0;
+        for (final BatteryDiffEntry entry : allBatteryDiffData.getAppDiffEntryList()) {
+            totalForegroundUsageTime += entry.mForegroundUsageTimeInMs;
+        }
+        mMetricsFeatureProvider.action(
+                getContext(),
+                SettingsEnums.ACTION_BATTERY_USAGE_SCREEN_ON_TIME,
+                (int) allBatteryDiffData.getScreenOnTime());
+        mMetricsFeatureProvider.action(
+                getContext(),
+                SettingsEnums.ACTION_BATTERY_USAGE_FOREGROUND_USAGE_TIME,
+                (int) totalForegroundUsageTime);
+    }
+
+    @VisibleForTesting
+    static PowerAnomalyEvent getHighestScoreAnomalyEvent(
+            Context context, PowerAnomalyEventList anomalyEventList) {
+        if (anomalyEventList == null || anomalyEventList.getPowerAnomalyEventsCount() == 0) {
+            return null;
+        }
+        final Set<String> dismissedPowerAnomalyKeys =
+                DatabaseUtils.getDismissedPowerAnomalyKeys(context);
+        Log.d(TAG, "dismissedPowerAnomalyKeys = " + dismissedPowerAnomalyKeys);
+
+        final PowerAnomalyEvent highestScoreEvent = anomalyEventList.getPowerAnomalyEventsList()
+                .stream()
+                .filter(event -> !dismissedPowerAnomalyKeys.contains(
+                        BatteryTipsController.getDismissRecordKey(event)))
+                .max(Comparator.comparing(PowerAnomalyEvent::getScore))
+                .orElse(null);
+        Log.d(TAG, "highestScoreAnomalyEvent = " + highestScoreEvent);
+        return highestScoreEvent;
+    }
+
+    private static BatteryDiffData getAllBatteryDiffData(
+            Map<Integer, Map<Integer, BatteryDiffData>> batteryUsageMap) {
+        return batteryUsageMap == null ? null : batteryUsageMap
+                .get(BatteryChartViewModel.SELECTED_INDEX_ALL)
+                .get(BatteryChartViewModel.SELECTED_INDEX_ALL);
+    }
+
     public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
             new BaseSearchIndexProvider() {
                 @Override
@@ -228,6 +385,7 @@
                     controllers.add(new BatteryUsageBreakdownController(
                             context, null /* lifecycle */, null /* activity */,
                             null /* fragment */));
+                    controllers.add(new BatteryTipsController(context));
                     return controllers;
                 }
             };
@@ -244,7 +402,7 @@
                 public BatteryLevelData loadInBackground() {
                     return DataProcessManager.getBatteryLevelData(
                             getContext(), mHandler, /*isFromPeriodJob=*/ false,
-                            map -> PowerUsageAdvanced.this.onBatteryDiffDataMapUpdate(map));
+                            PowerUsageAdvanced.this::onBatteryDiffDataMapUpdate);
                 }
             };
         }
diff --git a/src/com/android/settings/fuelgauge/protos/battery_usage_slot.proto b/src/com/android/settings/fuelgauge/protos/battery_usage_slot.proto
index e3b604b..5bc1a3e 100644
--- a/src/com/android/settings/fuelgauge/protos/battery_usage_slot.proto
+++ b/src/com/android/settings/fuelgauge/protos/battery_usage_slot.proto
@@ -26,7 +26,9 @@
   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;
+  optional double foreground_service_usage_consume_power = 12;
+  optional double cached_usage_consume_power = 13;
+  optional int64 foreground_usage_time = 14;
+  optional int64 background_usage_time = 15;
+  optional int64 screen_on_time = 16;
 }
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 644ab9e..99df215 100644
--- a/src/com/android/settings/fuelgauge/protos/power_anomaly_event.proto
+++ b/src/com/android/settings/fuelgauge/protos/power_anomaly_event.proto
@@ -60,4 +60,6 @@
   optional string description_string = 5;
   optional string main_button_string = 6;
   optional string cancel_button_string = 7;
+  optional string dismiss_record_key = 8;
+  optional string item_key = 9;
 }
diff --git a/src/com/android/settings/spa/app/appcompat/UserAspectRatioAppsPageProvider.kt b/src/com/android/settings/spa/app/appcompat/UserAspectRatioAppsPageProvider.kt
index 35e99a7..1884599 100644
--- a/src/com/android/settings/spa/app/appcompat/UserAspectRatioAppsPageProvider.kt
+++ b/src/com/android/settings/spa/app/appcompat/UserAspectRatioAppsPageProvider.kt
@@ -110,7 +110,7 @@
         appList = appList,
         header = {
             Box(Modifier.padding(SettingsDimension.itemPadding)) {
-                SettingsBody(UserAspectRatioAppsPageProvider.getSummary())
+                SettingsBody(stringResource(R.string.aspect_ratio_main_summary, Build.MODEL))
             }
             Illustration(object : IllustrationModel {
                 override val resId = R.raw.user_aspect_ratio_education
@@ -217,5 +217,5 @@
 private enum class SpinnerItem(val stringResId: Int) {
     Suggested(R.string.user_aspect_ratio_suggested_apps_label),
     All(R.string.filter_all_apps),
-    Overridden(R.string.user_aspect_ratio_overridden_apps_label)
+    Overridden(R.string.user_aspect_ratio_changed_apps_label)
 }
\ No newline at end of file
diff --git a/src/com/android/settings/system/FactoryResetDemoUserPreferenceController.java b/src/com/android/settings/system/FactoryResetDemoUserPreferenceController.java
new file mode 100644
index 0000000..f6a9b31
--- /dev/null
+++ b/src/com/android/settings/system/FactoryResetDemoUserPreferenceController.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+package com.android.settings.system;
+
+import android.content.Context;
+import com.android.settings.Utils;
+
+public class FactoryResetDemoUserPreferenceController extends FactoryResetPreferenceController {
+
+    public FactoryResetDemoUserPreferenceController(Context context, String preferenceKey) {
+        super(context, preferenceKey);
+    }
+
+    /** Hide demo user specific "Factory reset" settings for non demo users. */
+    @Override
+    public int getAvailabilityStatus() {
+        return Utils.isDemoUser(mContext) ? AVAILABLE : DISABLED_FOR_USER;
+    }
+}
diff --git a/src/com/android/settings/system/FactoryResetPreferenceController.java b/src/com/android/settings/system/FactoryResetPreferenceController.java
index a307171..6e010c1 100644
--- a/src/com/android/settings/system/FactoryResetPreferenceController.java
+++ b/src/com/android/settings/system/FactoryResetPreferenceController.java
@@ -24,35 +24,26 @@
 import com.android.settings.R;
 import com.android.settings.Settings;
 import com.android.settings.Utils;
-import com.android.settings.core.PreferenceControllerMixin;
-import com.android.settingslib.core.AbstractPreferenceController;
+import com.android.settings.core.BasePreferenceController;
 
-public class FactoryResetPreferenceController extends AbstractPreferenceController
-        implements PreferenceControllerMixin {
-    /** Key of the "Factory reset" preference in {@link R.xml.reset_dashboard_fragment}. */
-    private static final String KEY_FACTORY_RESET = "factory_reset";
+public class FactoryResetPreferenceController extends BasePreferenceController {
 
     private final UserManager mUm;
 
-    public FactoryResetPreferenceController(Context context) {
-        super(context);
+    public FactoryResetPreferenceController(Context context, String preferenceKey) {
+        super(context, preferenceKey);
         mUm = (UserManager) context.getSystemService(Context.USER_SERVICE);
     }
 
-    /** Hide "Factory reset" settings for secondary users, except demo users. */
+    /** Hide "Factory reset" settings for secondary users. */
     @Override
-    public boolean isAvailable() {
-        return mUm.isAdminUser() || Utils.isDemoUser(mContext);
-    }
-
-    @Override
-    public String getPreferenceKey() {
-        return KEY_FACTORY_RESET;
+    public int getAvailabilityStatus() {
+        return mUm.isAdminUser() ? AVAILABLE : DISABLED_FOR_USER;
     }
 
     @Override
     public boolean handlePreferenceTreeClick(Preference preference) {
-        if (KEY_FACTORY_RESET.equals(preference.getKey())) {
+        if (mPreferenceKey.equals(preference.getKey())) {
             final Intent intent = new Intent(mContext, Settings.FactoryResetActivity.class);
             mContext.startActivity(intent);
             return true;
diff --git a/src/com/android/settings/system/ResetDashboardFragment.java b/src/com/android/settings/system/ResetDashboardFragment.java
index aea92aa..662edc5 100644
--- a/src/com/android/settings/system/ResetDashboardFragment.java
+++ b/src/com/android/settings/system/ResetDashboardFragment.java
@@ -78,7 +78,6 @@
         if (SubscriptionUtil.isSimHardwareVisible(context)) {
             controllers.add(new NetworkResetPreferenceController(context));
         }
-        controllers.add(new FactoryResetPreferenceController(context));
         controllers.add(new ResetAppPrefPreferenceController(context, lifecycle));
         return controllers;
     }
diff --git a/src/com/android/settings/system/ResetPreferenceController.java b/src/com/android/settings/system/ResetPreferenceController.java
index 0740ac9..35f1ff7 100644
--- a/src/com/android/settings/system/ResetPreferenceController.java
+++ b/src/com/android/settings/system/ResetPreferenceController.java
@@ -26,13 +26,11 @@
 
     private final UserManager mUm;
     private final NetworkResetPreferenceController mNetworkReset;
-    private final FactoryResetPreferenceController mFactpruReset;
 
     public ResetPreferenceController(Context context, String preferenceKey) {
         super(context, preferenceKey);
         mUm = (UserManager) context.getSystemService(Context.USER_SERVICE);
         mNetworkReset = new NetworkResetPreferenceController(context);
-        mFactpruReset = new FactoryResetPreferenceController(context);
     }
 
     @Override
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImplTest.java b/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImplTest.java
index bf4e893..a0b449a 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImplTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImplTest.java
@@ -73,10 +73,6 @@
     }
 
     @Test
-    public void testIsBatteryTipsFeedbackEnabled_returnFalse() {
-        assertThat(mPowerFeatureProvider.isBatteryTipsFeedbackEnabled()).isFalse();
-    }
-    @Test
     public void testGetBatteryUsageListConsumePowerThreshold_return0() {
         assertThat(mPowerFeatureProvider.getBatteryUsageListConsumePowerThreshold()).isEqualTo(0.0);
     }
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 786a529..cd4e599 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryChartPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryChartPreferenceControllerTest.java
@@ -28,6 +28,7 @@
 import static org.mockito.Mockito.atLeast;
 import static org.mockito.Mockito.atLeastOnce;
 import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.reset;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.verify;
@@ -44,9 +45,9 @@
 import android.view.View;
 import android.view.ViewPropertyAnimator;
 import android.widget.LinearLayout;
+import android.widget.TextView;
 
 import com.android.settings.SettingsActivity;
-import com.android.settings.testutils.BatteryTestUtils;
 import com.android.settings.testutils.FakeFeatureFactory;
 
 import org.junit.Before;
@@ -72,6 +73,8 @@
     @Mock
     private SettingsActivity mSettingsActivity;
     @Mock
+    private TextView mChartSummaryTextView;
+    @Mock
     private BatteryChartView mDailyChartView;
     @Mock
     private BatteryChartView mHourlyChartView;
@@ -112,6 +115,7 @@
         setupHourlyChartViewAnimationMock();
         mBatteryChartPreferenceController = createController();
         mBatteryChartPreferenceController.mPrefContext = mContext;
+        mBatteryChartPreferenceController.mChartSummaryTextView = mChartSummaryTextView;
         mBatteryChartPreferenceController.mDailyChartView = mDailyChartView;
         mBatteryChartPreferenceController.mHourlyChartView = mHourlyChartView;
         BatteryDiffEntry.clearCache();
@@ -180,7 +184,6 @@
                 mBatteryChartPreferenceController.mDailyChartLabelTextGenerator);
 
         mBatteryChartPreferenceController.onBatteryLevelDataUpdate(createBatteryLevelData(60));
-        mBatteryChartPreferenceController.onBatteryUsageMapUpdate(getEmptyBatteryUsageMap());
 
         verify(mDailyChartView, atLeastOnce()).setVisibility(View.VISIBLE);
         verify(mViewPropertyAnimator, atLeastOnce()).alpha(0f);
@@ -275,29 +278,78 @@
     }
 
     @Test
-    public void refreshUi_normalCase_returnTrue() {
+    public void onBatteryLevelDataUpdate_oneDay_showHourlyChartOnly() {
+        doReturn(View.GONE).when(mHourlyChartView).getVisibility();
+
         mBatteryChartPreferenceController.onBatteryLevelDataUpdate(createBatteryLevelData(6));
-        mBatteryChartPreferenceController.onBatteryUsageMapUpdate(getEmptyBatteryUsageMap());
-        assertThat(mBatteryChartPreferenceController.refreshUi()).isTrue();
+
+        verify(mChartSummaryTextView).setVisibility(View.VISIBLE);
+        verify(mDailyChartView).setVisibility(View.GONE);
+        verify(mHourlyChartView).setVisibility(View.VISIBLE);
     }
 
     @Test
-    public void refreshUi_batteryIndexedMapIsNull_returnTrue() {
+    public void onBatteryLevelDataUpdate_selectAllForMultipleDays_showDailyChartOnly() {
+        doReturn(View.GONE).when(mHourlyChartView).getVisibility();
+
+        mBatteryChartPreferenceController.mDailyChartIndex = SELECTED_INDEX_ALL;
+        mBatteryChartPreferenceController.onBatteryLevelDataUpdate(createBatteryLevelData(60));
+
+        verify(mChartSummaryTextView).setVisibility(View.VISIBLE);
+        verify(mDailyChartView).setVisibility(View.VISIBLE);
+        verify(mHourlyChartView, never()).setVisibility(View.VISIBLE);
+    }
+
+    @Test
+    public void onBatteryLevelDataUpdate_selectOneDayForMultipleDays_showBothCharts() {
+        doReturn(View.GONE).when(mHourlyChartView).getVisibility();
+
+        mBatteryChartPreferenceController.mDailyChartIndex = 0;
+        mBatteryChartPreferenceController.onBatteryLevelDataUpdate(createBatteryLevelData(60));
+
+        verify(mChartSummaryTextView).setVisibility(View.VISIBLE);
+        verify(mDailyChartView).setVisibility(View.VISIBLE);
+        verify(mHourlyChartView).setVisibility(View.VISIBLE);
+    }
+
+    @Test
+    public void onBatteryLevelDataUpdate_batteryLevelDataIsNull_showNoChart() {
+        doReturn(View.GONE).when(mHourlyChartView).getVisibility();
+
         mBatteryChartPreferenceController.onBatteryLevelDataUpdate(null);
-        mBatteryChartPreferenceController.onBatteryUsageMapUpdate(getEmptyBatteryUsageMap());
-        assertThat(mBatteryChartPreferenceController.refreshUi()).isTrue();
+
+        verify(mChartSummaryTextView).setVisibility(View.GONE);
+        verify(mDailyChartView).setVisibility(View.GONE);
+        verify(mHourlyChartView).setVisibility(View.GONE);
+    }
+
+    @Test
+    public void showEmptyChart_normalCase_showEmptyChart() {
+        doReturn(View.GONE).when(mHourlyChartView).getVisibility();
+
+        mBatteryChartPreferenceController.showEmptyChart();
+
+        verify(mChartSummaryTextView).setVisibility(View.VISIBLE);
+        verify(mDailyChartView).setVisibility(View.GONE);
+        verify(mHourlyChartView).setVisibility(View.VISIBLE);
     }
 
     @Test
     public void refreshUi_dailyChartViewIsNull_ignoreRefresh() {
         mBatteryChartPreferenceController.mDailyChartView = null;
-        assertThat(mBatteryChartPreferenceController.refreshUi()).isFalse();
+
+        mBatteryChartPreferenceController.refreshUi();
+
+        verify(mChartSummaryTextView, never()).setVisibility(anyInt());
     }
 
     @Test
     public void refreshUi_hourlyChartViewIsNull_ignoreRefresh() {
         mBatteryChartPreferenceController.mHourlyChartView = null;
-        assertThat(mBatteryChartPreferenceController.refreshUi()).isFalse();
+
+        mBatteryChartPreferenceController.refreshUi();
+
+        verify(mChartSummaryTextView, never()).setVisibility(anyInt());
     }
 
     @Test
@@ -408,57 +460,6 @@
         assertThat(totalHour).isEqualTo(59);
     }
 
-    @Test
-    public void getHighestScoreAnomalyEvent_withEmptyOrNullList_getNull() {
-        assertThat(mBatteryChartPreferenceController.getHighestScoreAnomalyEvent(null))
-                .isEqualTo(null);
-        assertThat(mBatteryChartPreferenceController.getHighestScoreAnomalyEvent(
-                BatteryTestUtils.createEmptyPowerAnomalyEventList()))
-                .isEqualTo(null);
-    }
-
-    @Test
-    public void getHighestScoreAnomalyEvent_withoutDismissed_getHighestScoreEvent() {
-        final PowerAnomalyEventList eventList =
-                BatteryTestUtils.createNonEmptyPowerAnomalyEventList();
-
-        final PowerAnomalyEvent highestScoreEvent =
-                mBatteryChartPreferenceController.getHighestScoreAnomalyEvent(eventList);
-
-        assertThat(highestScoreEvent)
-                .isEqualTo(BatteryTestUtils.createAdaptiveBrightnessAnomalyEvent());
-    }
-
-    @Test
-    public void getHighestScoreAnomalyEvent_withBrightnessDismissed_getScreenTimeout() {
-        final PowerAnomalyEventList eventList =
-                BatteryTestUtils.createNonEmptyPowerAnomalyEventList();
-        DatabaseUtils.removeDismissedPowerAnomalyKeys(mContext);
-        DatabaseUtils.setDismissedPowerAnomalyKeys(mContext, PowerAnomalyKey.KEY_BRIGHTNESS.name());
-
-        final PowerAnomalyEvent highestScoreEvent =
-                mBatteryChartPreferenceController.getHighestScoreAnomalyEvent(eventList);
-
-        assertThat(highestScoreEvent)
-                .isEqualTo(BatteryTestUtils.createScreenTimeoutAnomalyEvent());
-    }
-
-    @Test
-    public void getHighestScoreAnomalyEvent_withAllDismissed_getNull() {
-        final PowerAnomalyEventList eventList =
-                BatteryTestUtils.createNonEmptyPowerAnomalyEventList();
-        DatabaseUtils.removeDismissedPowerAnomalyKeys(mContext);
-        for (PowerAnomalyKey key : PowerAnomalyKey.values()) {
-            DatabaseUtils.setDismissedPowerAnomalyKeys(mContext, key.name());
-        }
-
-        final PowerAnomalyEvent highestScoreEvent =
-                mBatteryChartPreferenceController.getHighestScoreAnomalyEvent(eventList);
-
-        assertThat(highestScoreEvent).isEqualTo(null);
-    }
-
-
     private static Long generateTimestamp(int index) {
         // "2021-04-23 07:00:00 UTC" + index hours
         return 1619247600000L + index * DateUtils.HOUR_IN_MILLIS;
@@ -481,11 +482,6 @@
         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() {
         final BatteryChartPreferenceController controller =
                 new BatteryChartPreferenceController(
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryLevelDataTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryLevelDataTest.java
index 13d60bb..7dc4eab 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryLevelDataTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryLevelDataTest.java
@@ -18,6 +18,10 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import android.util.Pair;
+
+import com.android.settings.testutils.BatteryTestUtils;
+
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -211,4 +215,29 @@
         assertThat(result.getHourlyBatteryLevelsPerDay().get(0).getLevels())
                 .isEqualTo(List.of(100, 98));
     }
+
+    @Test
+    public void getIndexByTimestamps_returnExpectedResult() {
+        final BatteryLevelData batteryLevelData =
+                new BatteryLevelData(Map.of(
+                        1694354400000L, 1,      // 2023-09-10 22:00:00
+                        1694361600000L, 2,      // 2023-09-11 00:00:00
+                        1694368800000L, 3));    // 2023-09-11 02:00:00
+        final PowerAnomalyEvent event = BatteryTestUtils.createAppAnomalyEvent();
+
+        assertThat(batteryLevelData.getIndexByTimestamps(0L, 0L))
+                .isEqualTo(Pair.create(BatteryChartViewModel.SELECTED_INDEX_INVALID,
+                        BatteryChartViewModel.SELECTED_INDEX_INVALID));
+        assertThat(batteryLevelData.getIndexByTimestamps(1694361600000L + 1L, 1694368800000L + 1L))
+                .isEqualTo(Pair.create(BatteryChartViewModel.SELECTED_INDEX_INVALID,
+                        BatteryChartViewModel.SELECTED_INDEX_INVALID));
+        assertThat(batteryLevelData.getIndexByTimestamps(1694361600000L, 1694368800000L))
+                .isEqualTo(Pair.create(1, 0));
+        assertThat(batteryLevelData.getIndexByTimestamps(1694361600000L + 1L, 1694368800000L - 1L))
+                .isEqualTo(Pair.create(1, 0));
+        assertThat(batteryLevelData.getIndexByTimestamps(
+                event.getWarningItemInfo().getStartTimestamp(),
+                event.getWarningItemInfo().getEndTimestamp()))
+                .isEqualTo(Pair.create(1, 0));
+    }
 }
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 ac67dfd..630ff45 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryTipsCardPreferenceTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryTipsCardPreferenceTest.java
@@ -19,7 +19,9 @@
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
@@ -45,16 +47,24 @@
 import org.robolectric.RobolectricTestRunner;
 import org.robolectric.RuntimeEnvironment;
 
+import java.util.Map;
+import java.util.Optional;
+
 @RunWith(RobolectricTestRunner.class)
 public final class BatteryTipsCardPreferenceTest {
 
     private Context mContext;
     private FakeFeatureFactory mFeatureFactory;
     private BatteryTipsCardPreference mBatteryTipsCardPreference;
+    private PowerUsageAdvanced mPowerUsageAdvanced;
     private BatteryTipsController mBatteryTipsController;
 
     @Mock
     private View mFakeView;
+    @Mock
+    private BatteryChartPreferenceController mBatteryChartPreferenceController;
+    @Mock
+    private BatteryUsageBreakdownController mBatteryUsageBreakdownController;
 
     @Before
     public void setUp() {
@@ -64,6 +74,14 @@
         mBatteryTipsCardPreference = new BatteryTipsCardPreference(mContext, /*attrs=*/ null);
         mBatteryTipsController = new BatteryTipsController(mContext);
         mBatteryTipsController.mCardPreference = mBatteryTipsCardPreference;
+        mPowerUsageAdvanced = new PowerUsageAdvanced();
+        mPowerUsageAdvanced.mBatteryTipsController = mBatteryTipsController;
+        mPowerUsageAdvanced.mBatteryChartPreferenceController = mBatteryChartPreferenceController;
+        mPowerUsageAdvanced.mBatteryUsageBreakdownController = mBatteryUsageBreakdownController;
+        mPowerUsageAdvanced.mBatteryLevelData = Optional.of(new BatteryLevelData(Map.of(
+                1694354400000L, 1,      // 2023-09-10 22:00:00
+                1694361600000L, 2,      // 2023-09-11 00:00:00
+                1694368800000L, 3)));    // 2023-09-11 02:00:00
     }
 
     @Test
@@ -71,8 +89,9 @@
         assertThat(mBatteryTipsCardPreference.getLayoutResource()).isEqualTo(
                 R.layout.battery_tips_card);
     }
+
     @Test
-    public void onClick_mainBtn_getAdaptiveBrightnessLauncher() {
+    public void onClick_mainBtnOfSettingsAnomaly_getAdaptiveBrightnessLauncher() {
         final ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class);
         PowerAnomalyEvent adaptiveBrightnessAnomaly =
                 BatteryTestUtils.createAdaptiveBrightnessAnomalyEvent();
@@ -80,10 +99,10 @@
         when(mFakeView.getId()).thenReturn(R.id.main_button);
         doNothing().when(mContext).startActivity(captor.capture());
 
-        mBatteryTipsController.handleBatteryTipsCardUpdated(adaptiveBrightnessAnomaly);
+        mPowerUsageAdvanced.onDisplayAnomalyEventUpdated(adaptiveBrightnessAnomaly);
         mBatteryTipsCardPreference.onClick(mFakeView);
 
-        assertThat(mBatteryTipsCardPreference.isVisible()).isEqualTo(false);
+        assertThat(mBatteryTipsCardPreference.isVisible()).isFalse();
         verify(mContext).startActivity(any(Intent.class));
         final Intent intent = captor.getValue();
         assertThat(intent.getStringExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT))
@@ -96,21 +115,53 @@
 
     @Test
     public void onClick_dismissBtn_cardDismissAndLogged() {
-        PowerAnomalyEvent screenTimeoutAnomaly =
+        final PowerAnomalyEvent screenTimeoutAnomaly =
                 BatteryTestUtils.createScreenTimeoutAnomalyEvent();
         DatabaseUtils.removeDismissedPowerAnomalyKeys(mContext);
         when(mFeatureFactory.powerUsageFeatureProvider.isBatteryTipsEnabled()).thenReturn(true);
         when(mFakeView.getId()).thenReturn(R.id.dismiss_button);
 
-        mBatteryTipsController.handleBatteryTipsCardUpdated(screenTimeoutAnomaly);
+        mPowerUsageAdvanced.onDisplayAnomalyEventUpdated(screenTimeoutAnomaly);
         mBatteryTipsCardPreference.onClick(mFakeView);
 
-        assertThat(mBatteryTipsCardPreference.isVisible()).isEqualTo(false);
-        assertThat(DatabaseUtils.getDismissedPowerAnomalyKeys(mContext).size())
-                .isEqualTo(1);
+        assertThat(mBatteryTipsCardPreference.isVisible()).isFalse();
+        assertThat(DatabaseUtils.getDismissedPowerAnomalyKeys(mContext)).hasSize(1);
         assertThat(DatabaseUtils.getDismissedPowerAnomalyKeys(mContext))
                 .contains(PowerAnomalyKey.KEY_SCREEN_TIMEOUT.name());
         verify(mFeatureFactory.metricsFeatureProvider).action(
                 mContext, SettingsEnums.ACTION_BATTERY_TIPS_CARD_DISMISS, "ScreenTimeoutAnomaly");
     }
+
+    @Test
+    public void onClick_mainBtnOfAppsAnomaly_selectHighlightSlot() {
+        final PowerAnomalyEvent appsAnomaly = BatteryTestUtils.createAppAnomalyEvent();
+        when(mFeatureFactory.powerUsageFeatureProvider.isBatteryTipsEnabled()).thenReturn(true);
+        when(mFakeView.getId()).thenReturn(R.id.main_button);
+
+        mPowerUsageAdvanced.onDisplayAnomalyEventUpdated(appsAnomaly);
+        mBatteryTipsCardPreference.onClick(mFakeView);
+
+        assertThat(mBatteryTipsCardPreference.isVisible()).isFalse();
+        verify(mContext, never()).startActivity(any(Intent.class));
+        verify(mBatteryChartPreferenceController).selectHighlightSlotIndex();
+        verify(mFeatureFactory.metricsFeatureProvider).action(
+                mContext, SettingsEnums.ACTION_BATTERY_TIPS_CARD_ACCEPT, "AppAnomaly");
+    }
+
+    @Test
+    public void onClick_dismissBtnOfAppsAnomaly_removeHighlightSlotIndex() {
+        final PowerAnomalyEvent appsAnomaly = BatteryTestUtils.createAppAnomalyEvent();
+        when(mFeatureFactory.powerUsageFeatureProvider.isBatteryTipsEnabled()).thenReturn(true);
+        when(mFakeView.getId()).thenReturn(R.id.dismiss_button);
+
+        mPowerUsageAdvanced.onDisplayAnomalyEventUpdated(appsAnomaly);
+        mBatteryTipsCardPreference.onClick(mFakeView);
+
+        assertThat(mBatteryTipsCardPreference.isVisible()).isFalse();
+        verify(mBatteryChartPreferenceController).onHighlightSlotIndexUpdate(
+                eq(BatteryChartViewModel.SELECTED_INDEX_INVALID),
+                eq(BatteryChartViewModel.SELECTED_INDEX_INVALID));
+        verify(mFeatureFactory.metricsFeatureProvider).action(
+                mContext, SettingsEnums.ACTION_BATTERY_TIPS_CARD_DISMISS, "AppAnomaly");
+    }
 }
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 ac9de1f..913c00a 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryTipsControllerTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryTipsControllerTest.java
@@ -16,6 +16,8 @@
 
 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;
@@ -74,13 +76,25 @@
     }
 
     @Test
+    public void getDismissRecordKey_returnExpectedResult() {
+        assertThat(BatteryTipsController.getDismissRecordKey(
+                BatteryTestUtils.createAdaptiveBrightnessAnomalyEvent()))
+                .isEqualTo("KEY_BRIGHTNESS");
+        assertThat(BatteryTipsController.getDismissRecordKey(
+                BatteryTestUtils.createScreenTimeoutAnomalyEvent()))
+                .isEqualTo("KEY_SCREEN_TIMEOUT");
+        assertThat(BatteryTipsController.getDismissRecordKey(
+                BatteryTestUtils.createAppAnomalyEvent()))
+                .isEqualTo("KEY_APP_1");
+    }
+
+    @Test
     public void handleBatteryTipsCardUpdated_adaptiveBrightnessAnomaly_showAnomaly() {
         PowerAnomalyEvent event = BatteryTestUtils.createAdaptiveBrightnessAnomalyEvent();
         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");
@@ -90,9 +104,6 @@
         verify(mBatteryTipsCardPreference).setMainButtonLabel("View Settings");
         verify(mBatteryTipsCardPreference).setDismissButtonLabel("Got it");
         // Check proto info
-        verify(mBatteryTipsCardPreference).setMainButtonLauncherInfo(
-                "com.android.settings.DisplaySettings",
-                46, "auto_brightness_entry");
         verify(mBatteryTipsCardPreference).setVisible(true);
         verify(mFeatureFactory.metricsFeatureProvider).action(
                 mContext, SettingsEnums.ACTION_BATTERY_TIPS_CARD_SHOW, "BrightnessAnomaly");
@@ -105,16 +116,12 @@
 
         mBatteryTipsController.handleBatteryTipsCardUpdated(event);
 
-        verify(mBatteryTipsCardPreference).setAnomalyEventId("ScreenTimeoutAnomaly");
         verify(mBatteryTipsCardPreference).setTitle("Reduce screen timeout to extend battery life");
         verify(mBatteryTipsCardPreference).setIconResourceId(R.drawable.ic_battery_tips_lightbulb);
         verify(mBatteryTipsCardPreference).setMainButtonStrokeColorResourceId(
                 R.color.color_accent_selector);
         verify(mBatteryTipsCardPreference).setMainButtonLabel("View Settings");
         verify(mBatteryTipsCardPreference).setDismissButtonLabel("Got it");
-        verify(mBatteryTipsCardPreference).setMainButtonLauncherInfo(
-                "com.android.settings.display.ScreenTimeoutSettings",
-                1852, "60000");
         verify(mBatteryTipsCardPreference).setVisible(true);
         verify(mFeatureFactory.metricsFeatureProvider).action(
                 mContext, SettingsEnums.ACTION_BATTERY_TIPS_CARD_SHOW, "ScreenTimeoutAnomaly");
@@ -134,16 +141,12 @@
 
         mBatteryTipsController.handleBatteryTipsCardUpdated(event);
 
-        verify(mBatteryTipsCardPreference).setAnomalyEventId("ScreenTimeoutAnomaly");
         verify(mBatteryTipsCardPreference).setTitle(testTitle);
         verify(mBatteryTipsCardPreference).setIconResourceId(R.drawable.ic_battery_tips_lightbulb);
         verify(mBatteryTipsCardPreference).setMainButtonStrokeColorResourceId(
                 R.color.color_accent_selector);
         verify(mBatteryTipsCardPreference).setMainButtonLabel("View Settings");
         verify(mBatteryTipsCardPreference).setDismissButtonLabel("Got it");
-        verify(mBatteryTipsCardPreference).setMainButtonLauncherInfo(
-                "com.android.settings.display.ScreenTimeoutSettings",
-                1852, "60000");
         verify(mBatteryTipsCardPreference).setVisible(true);
         verify(mFeatureFactory.metricsFeatureProvider).action(
                 mContext, SettingsEnums.ACTION_BATTERY_TIPS_CARD_SHOW, "ScreenTimeoutAnomaly");
@@ -156,7 +159,6 @@
 
         mBatteryTipsController.handleBatteryTipsCardUpdated(event);
 
-        verify(mBatteryTipsCardPreference).setAnomalyEventId("AppAnomaly");
         verify(mBatteryTipsCardPreference).setTitle(
                 "Chrome used more battery than usual in foreground");
         verify(mBatteryTipsCardPreference).setIconResourceId(
@@ -165,8 +167,6 @@
                 R.color.color_battery_anomaly_yellow_selector);
         verify(mBatteryTipsCardPreference).setMainButtonLabel("Check");
         verify(mBatteryTipsCardPreference).setDismissButtonLabel("Got it");
-        verify(mBatteryTipsCardPreference).setMainButtonLauncherInfo(
-                null, null, null);
         verify(mBatteryTipsCardPreference).setVisible(true);
         verify(mFeatureFactory.metricsFeatureProvider).action(
                 mContext, SettingsEnums.ACTION_BATTERY_TIPS_CARD_SHOW, "AppAnomaly");
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/PowerUsageAdvancedTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/PowerUsageAdvancedTest.java
new file mode 100644
index 0000000..953c2d4
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/PowerUsageAdvancedTest.java
@@ -0,0 +1,185 @@
+/*
+ * 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 com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.isNull;
+import static org.mockito.ArgumentMatchers.notNull;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import android.content.Context;
+import android.util.Pair;
+
+import com.android.settings.testutils.BatteryTestUtils;
+import com.android.settings.testutils.shadow.ShadowDashboardFragment;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
+
+import java.util.Map;
+import java.util.Optional;
+import java.util.TimeZone;
+
+@RunWith(RobolectricTestRunner.class)
+@Config(shadows = ShadowDashboardFragment.class)
+public final class PowerUsageAdvancedTest {
+
+    private Context mContext;
+    private PowerUsageAdvanced mPowerUsageAdvanced;
+
+    @Mock
+    private BatteryTipsController mBatteryTipsController;
+    @Mock
+    private BatteryChartPreferenceController mBatteryChartPreferenceController;
+    @Mock
+    private ScreenOnTimeController mScreenOnTimeController;
+    @Mock
+    private BatteryUsageBreakdownController mBatteryUsageBreakdownController;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        TimeZone.setDefault(TimeZone.getTimeZone("GMT+8"));
+        mContext = spy(RuntimeEnvironment.application);
+
+        mPowerUsageAdvanced = new PowerUsageAdvanced();
+        mPowerUsageAdvanced.mBatteryTipsController = mBatteryTipsController;
+        mPowerUsageAdvanced.mBatteryChartPreferenceController = mBatteryChartPreferenceController;
+        mPowerUsageAdvanced.mScreenOnTimeController = mScreenOnTimeController;
+        mPowerUsageAdvanced.mBatteryUsageBreakdownController = mBatteryUsageBreakdownController;
+        mPowerUsageAdvanced.mBatteryLevelData = Optional.of(new BatteryLevelData(Map.of(
+                1694354400000L, 1,      // 2023-09-10 22:00:00
+                1694361600000L, 2,      // 2023-09-11 00:00:00
+                1694368800000L, 3)));    // 2023-09-11 02:00:00
+    }
+
+    @Test
+    public void getHighestScoreAnomalyEvent_withEmptyOrNullList_getNull() {
+        assertThat(PowerUsageAdvanced.getHighestScoreAnomalyEvent(mContext, null)).isNull();
+        assertThat(PowerUsageAdvanced.getHighestScoreAnomalyEvent(
+                mContext, BatteryTestUtils.createEmptyPowerAnomalyEventList())).isNull();
+    }
+
+    @Test
+    public void getHighestScoreAnomalyEvent_withoutDismissed_getHighestScoreEvent() {
+        final PowerAnomalyEventList powerAnomalyEventList =
+                BatteryTestUtils.createNonEmptyPowerAnomalyEventList();
+
+        final PowerAnomalyEvent highestScoreEvent =
+                PowerUsageAdvanced.getHighestScoreAnomalyEvent(mContext, powerAnomalyEventList);
+
+        assertThat(highestScoreEvent)
+                .isEqualTo(BatteryTestUtils.createAdaptiveBrightnessAnomalyEvent());
+    }
+
+    @Test
+    public void getHighestScoreAnomalyEvent_withBrightnessDismissed_getScreenTimeout() {
+        final PowerAnomalyEventList powerAnomalyEventList =
+                BatteryTestUtils.createNonEmptyPowerAnomalyEventList();
+        DatabaseUtils.removeDismissedPowerAnomalyKeys(mContext);
+        DatabaseUtils.setDismissedPowerAnomalyKeys(mContext, PowerAnomalyKey.KEY_BRIGHTNESS.name());
+
+        final PowerAnomalyEvent highestScoreEvent =
+                PowerUsageAdvanced.getHighestScoreAnomalyEvent(mContext, powerAnomalyEventList);
+
+        assertThat(highestScoreEvent)
+                .isEqualTo(BatteryTestUtils.createScreenTimeoutAnomalyEvent());
+    }
+
+    @Test
+    public void getHighestScoreAnomalyEvent_withAllDismissed_getNull() {
+        final PowerAnomalyEventList powerAnomalyEventList =
+                BatteryTestUtils.createNonEmptyPowerAnomalyEventList();
+        DatabaseUtils.removeDismissedPowerAnomalyKeys(mContext);
+        for (PowerAnomalyKey key : PowerAnomalyKey.values()) {
+            DatabaseUtils.setDismissedPowerAnomalyKeys(mContext, key.name());
+        }
+
+        final PowerAnomalyEvent highestScoreEvent =
+                PowerUsageAdvanced.getHighestScoreAnomalyEvent(mContext, powerAnomalyEventList);
+
+        assertThat(highestScoreEvent).isNull();
+    }
+
+    @Test
+    public void onDisplayAnomalyEventUpdated_withSettingsAnomalyEvent_skipHighlightSlotEffect() {
+        final PowerAnomalyEvent event = BatteryTestUtils.createAdaptiveBrightnessAnomalyEvent();
+
+        mPowerUsageAdvanced.onDisplayAnomalyEventUpdated(event);
+
+        assertThat(mPowerUsageAdvanced.mPowerAnomalyEvent).isEqualTo(event);
+        verify(mBatteryTipsController).handleBatteryTipsCardUpdated(eq(event));
+        verify(mPowerUsageAdvanced.mBatteryTipsController).setOnAnomalyConfirmListener(isNull());
+        verify(mPowerUsageAdvanced.mBatteryTipsController).setOnAnomalyRejectListener(isNull());
+        verify(mPowerUsageAdvanced.mBatteryChartPreferenceController).onHighlightSlotIndexUpdate(
+                eq(BatteryChartViewModel.SELECTED_INDEX_INVALID),
+                eq(BatteryChartViewModel.SELECTED_INDEX_INVALID));
+    }
+
+    @Test
+    public void onDisplayAnomalyEventUpdated_withAppAnomalyEvent_setHighlightSlotEffect() {
+        final PowerAnomalyEvent event = BatteryTestUtils.createAppAnomalyEvent();
+
+        mPowerUsageAdvanced.onDisplayAnomalyEventUpdated(event);
+
+        assertThat(mPowerUsageAdvanced.mPowerAnomalyEvent).isEqualTo(event);
+        verify(mBatteryTipsController).handleBatteryTipsCardUpdated(eq(event));
+        verify(mBatteryTipsController).setOnAnomalyConfirmListener(isNull());
+        verify(mBatteryTipsController).setOnAnomalyRejectListener(isNull());
+
+        assertThat(event.getWarningItemInfo().hasStartTimestamp()).isTrue();
+        assertThat(event.getWarningItemInfo().hasEndTimestamp()).isTrue();
+        assertThat(mPowerUsageAdvanced.mBatteryLevelData.get().getIndexByTimestamps(
+                event.getWarningItemInfo().getStartTimestamp(),
+                event.getWarningItemInfo().getEndTimestamp()
+        )).isEqualTo(Pair.create(1, 0));
+        verify(mBatteryChartPreferenceController).onHighlightSlotIndexUpdate(eq(1), eq(0));
+        verify(mBatteryTipsController).setOnAnomalyConfirmListener(notNull());
+        verify(mBatteryTipsController).setOnAnomalyRejectListener(notNull());
+    }
+
+    @Test
+    public void onDisplayAnomalyEventUpdated_withNull_removeHighlightSlotEffect() {
+        final PowerAnomalyEvent event = BatteryTestUtils.createAppAnomalyEvent();
+
+        mPowerUsageAdvanced.onDisplayAnomalyEventUpdated(event);
+        mPowerUsageAdvanced.onDisplayAnomalyEventUpdated(null);
+
+        assertThat(mPowerUsageAdvanced.mPowerAnomalyEvent).isNull();
+        verify(mBatteryTipsController, times(2))
+                .setOnAnomalyConfirmListener(isNull());
+        verify(mBatteryTipsController, times(2))
+                .setOnAnomalyRejectListener(isNull());
+        verify(mBatteryTipsController).setOnAnomalyConfirmListener(notNull());
+        verify(mBatteryTipsController).setOnAnomalyRejectListener(notNull());
+
+        verify(mBatteryChartPreferenceController)
+                .onHighlightSlotIndexUpdate(eq(1), eq(0));
+        verify(mBatteryChartPreferenceController).onHighlightSlotIndexUpdate(
+                eq(BatteryChartViewModel.SELECTED_INDEX_INVALID),
+                eq(BatteryChartViewModel.SELECTED_INDEX_INVALID));
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/system/FactoryResetDemoUserPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/system/FactoryResetDemoUserPreferenceControllerTest.java
new file mode 100644
index 0000000..0c92b05
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/system/FactoryResetDemoUserPreferenceControllerTest.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+package com.android.settings.system;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.content.Context;
+import android.content.pm.UserInfo;
+import android.os.UserHandle;
+import android.provider.Settings;
+
+import com.android.settings.testutils.shadow.ShadowUserManager;
+import com.android.settings.testutils.shadow.ShadowUtils;
+
+import org.junit.After;
+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 = ShadowUserManager.class)
+public class FactoryResetDemoUserPreferenceControllerTest {
+
+    private static final String FACTORY_RESET_DEMO_USER_KEY = "factory_reset_demo_user";
+
+    private ShadowUserManager mShadowUserManager;
+
+    private Context mContext;
+    private FactoryResetDemoUserPreferenceController mController;
+
+    @Before
+    public void setUp() {
+        mContext = RuntimeEnvironment.application;
+        mShadowUserManager = ShadowUserManager.getShadow();
+
+        mController = new FactoryResetDemoUserPreferenceController(
+            mContext, FACTORY_RESET_DEMO_USER_KEY);
+    }
+
+    @After
+    public void tearDown() {
+        ShadowUtils.reset();
+        mShadowUserManager.setIsAdminUser(false);
+        mShadowUserManager.setIsDemoUser(false);
+        Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.DEVICE_DEMO_MODE, 0);
+    }
+
+    @Test
+    public void isAvailable_systemUser() {
+        mShadowUserManager.setIsAdminUser(true);
+
+        assertThat(mController.isAvailable()).isFalse();
+    }
+
+    @Test
+    public void isAvailable_nonSystemUser() {
+        mShadowUserManager.setIsAdminUser(false);
+        mShadowUserManager.setIsDemoUser(false);
+
+        assertThat(mController.isAvailable()).isFalse();
+    }
+
+    @Test
+    public void isAvailable_demoUser() {
+        mShadowUserManager.setIsAdminUser(false);
+
+        // Place the device in demo mode.
+        Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.DEVICE_DEMO_MODE, 1);
+
+        // Indicate the user is a demo user.
+        mShadowUserManager.addUser(UserHandle.myUserId(), "test", UserInfo.FLAG_DEMO);
+
+        assertThat(mController.isAvailable()).isTrue();
+    }
+
+    @Test
+    public void getPreferenceKey() {
+        assertThat(mController.getPreferenceKey()).isEqualTo(FACTORY_RESET_DEMO_USER_KEY);
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/system/FactoryResetPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/system/FactoryResetPreferenceControllerTest.java
index f2a932e..6e6fad8 100644
--- a/tests/robotests/src/com/android/settings/system/FactoryResetPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/system/FactoryResetPreferenceControllerTest.java
@@ -49,7 +49,7 @@
         mContext = RuntimeEnvironment.application;
         mShadowUserManager = ShadowUserManager.getShadow();
 
-        mController = new FactoryResetPreferenceController(mContext);
+        mController = new FactoryResetPreferenceController(mContext, FACTORY_RESET_KEY);
     }
 
     @After
@@ -85,7 +85,7 @@
         // Indicate the user is a demo user.
         mShadowUserManager.addUser(UserHandle.myUserId(), "test", UserInfo.FLAG_DEMO);
 
-        assertThat(mController.isAvailable()).isTrue();
+        assertThat(mController.isAvailable()).isFalse();
     }
 
     @Test
diff --git a/tests/robotests/src/com/android/settings/testutils/BatteryTestUtils.java b/tests/robotests/src/com/android/settings/testutils/BatteryTestUtils.java
index 3297d1e..1035560 100644
--- a/tests/robotests/src/com/android/settings/testutils/BatteryTestUtils.java
+++ b/tests/robotests/src/com/android/settings/testutils/BatteryTestUtils.java
@@ -283,6 +283,9 @@
                 .setKey(PowerAnomalyKey.KEY_APP)
                 .setScore(2.0f)
                 .setWarningItemInfo(WarningItemInfo.newBuilder()
+                        .setDismissRecordKey("KEY_APP_1")
+                        .setStartTimestamp(1694361600000L)  // 2023-09-11 00:00:00
+                        .setEndTimestamp(1694368800000L)    // 2023-09-11 02:00:00
                         .setTitleString("Chrome used more battery than usual in foreground")
                         .setMainButtonString("Check")
                         .setCancelButtonString("Got it")
diff --git a/tests/spa_unit/src/com/android/settings/spa/app/appcompat/UserAspectRatioAppsPageProviderTest.kt b/tests/spa_unit/src/com/android/settings/spa/app/appcompat/UserAspectRatioAppsPageProviderTest.kt
index c314655..044968d 100644
--- a/tests/spa_unit/src/com/android/settings/spa/app/appcompat/UserAspectRatioAppsPageProviderTest.kt
+++ b/tests/spa_unit/src/com/android/settings/spa/app/appcompat/UserAspectRatioAppsPageProviderTest.kt
@@ -67,7 +67,8 @@
     @Test
     fun injectEntry_summary() {
         setInjectEntry()
-        composeTestRule.onNodeWithText(context.getString(R.string.aspect_ratio_summary, Build.MODEL))
+        composeTestRule
+            .onNodeWithText(context.getString(R.string.aspect_ratio_summary, Build.MODEL))
             .assertIsDisplayed()
     }