diff --git a/res/drawable/battery_hints_chip_bg.xml b/res/drawable/battery_hints_chip_bg.xml
new file mode 100644
index 00000000000..e7d1d0fd178
--- /dev/null
+++ b/res/drawable/battery_hints_chip_bg.xml
@@ -0,0 +1,22 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/res/drawable/battery_hints_chip_bg_ripple.xml b/res/drawable/battery_hints_chip_bg_ripple.xml
new file mode 100644
index 00000000000..a8bd0b37042
--- /dev/null
+++ b/res/drawable/battery_hints_chip_bg_ripple.xml
@@ -0,0 +1,21 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/res/layout/anomaly_app_item_preference.xml b/res/layout/anomaly_app_item_preference.xml
new file mode 100644
index 00000000000..0a198496f1e
--- /dev/null
+++ b/res/layout/anomaly_app_item_preference.xml
@@ -0,0 +1,67 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/res/values/arrays.xml b/res/values/arrays.xml
index 78e7ca41d13..1ab98767200 100644
--- a/res/values/arrays.xml
+++ b/res/values/arrays.xml
@@ -1420,20 +1420,49 @@
- color_battery_anomaly_yellow_selector
-
-
- - Turn on adaptive brightness to extend battery life
- - Reduce screen timeout to extend battery life
+
+
+ - battery_tips_settings_summary_brightness
+ - battery_tips_settings_summary_screen_timeout
+ - battery_tips_apps_summary_always_high
+ - battery_tips_apps_summary_higher_than_usual
+ - battery_tips_apps_summary_always_high_in_background
+ - battery_tips_apps_summary_higher_than_usual_in_background
+ - battery_tips_apps_summary_always_high_in_foreground
+ - battery_tips_apps_summary_higher_than_usual_in_foreground
- @string/battery_tips_card_action_button
- @string/battery_tips_card_action_button
+ - @string/battery_tips_card_action_button_check
+ - @string/battery_tips_card_action_button_check
+ - @string/battery_tips_card_action_button_check
+ - @string/battery_tips_card_action_button_check
+ - @string/battery_tips_card_action_button_check
+ - @string/battery_tips_card_action_button_check
- @string/battery_tips_card_dismiss_button
- @string/battery_tips_card_dismiss_button
+ - @string/battery_tips_card_dismiss_button
+ - @string/battery_tips_card_dismiss_button
+ - @string/battery_tips_card_dismiss_button
+ - @string/battery_tips_card_dismiss_button
+ - @string/battery_tips_card_dismiss_button
+ - @string/battery_tips_card_dismiss_button
+
+
+
+
+
+ - @string/battery_app_item_hint
+ - @string/battery_app_item_hint
+ - @string/battery_app_item_hint_in_bg
+ - @string/battery_app_item_hint_in_bg
+ - @string/battery_app_item_hint_in_fg
+ - @string/battery_app_item_hint_in_fg
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 4ae140e6b70..970312457e0 100755
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -382,6 +382,7 @@
4dp
24dp
+ 8dp
174dp
diff --git a/res/values/strings.xml b/res/values/strings.xml
index ac172688a4d..f8b770f5b21 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -9692,12 +9692,51 @@
View Settings
+
+ Check
+
Got it
Is this message helpful?
+
+ Battery tips warning icon
+
+
+ Turn on adaptive brightness to extend battery life
+
+
+ Reduce screen timeout to extend battery life
+
+
+ %1$s used more battery
+
+
+ %1$s used more battery than usual
+
+
+ %1$s used more battery while in the background
+
+
+ %1$s used more battery than usual while in the background
+
+
+ %1$s used more battery while in the foreground
+
+
+ %1$s used more battery than usual while in the foreground
+
+
+ High battery usage
+
+
+ High battery usage in the background
+
+
+ High battery usage in the foreground
+
Unrestricted
diff --git a/src/com/android/settings/fuelgauge/batteryusage/AnomalyAppItemPreference.java b/src/com/android/settings/fuelgauge/batteryusage/AnomalyAppItemPreference.java
new file mode 100644
index 00000000000..2f139ecaabc
--- /dev/null
+++ b/src/com/android/settings/fuelgauge/batteryusage/AnomalyAppItemPreference.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.fuelgauge.batteryusage;
+
+import android.content.Context;
+import android.text.TextUtils;
+import android.view.View;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import androidx.preference.PreferenceViewHolder;
+
+import com.android.settings.R;
+
+class AnomalyAppItemPreference extends PowerGaugePreference {
+
+ private static final String TAG = "AnomalyAppItemPreference";
+
+ private CharSequence mAnomalyHintText;
+
+ AnomalyAppItemPreference(Context context) {
+ super(context, /* attrs */ null);
+ setLayoutResource(R.layout.anomaly_app_item_preference);
+ }
+
+ void setAnomalyHint(CharSequence anomalyHintText) {
+ if (!TextUtils.equals(mAnomalyHintText, anomalyHintText)) {
+ mAnomalyHintText = anomalyHintText;
+ notifyChanged();
+ }
+ }
+
+ @Override
+ public void onBindViewHolder(PreferenceViewHolder viewHolder) {
+ super.onBindViewHolder(viewHolder);
+ final LinearLayout warningChipView =
+ (LinearLayout) viewHolder.findViewById(R.id.warning_chip);
+
+ if (!TextUtils.isEmpty(mAnomalyHintText)) {
+ ((TextView) warningChipView.findViewById(R.id.warning_info)).setText(mAnomalyHintText);
+ warningChipView.setVisibility(View.VISIBLE);
+ } else {
+ warningChipView.setVisibility(View.GONE);
+ }
+ }
+}
diff --git a/src/com/android/settings/fuelgauge/batteryusage/AnomalyEventWrapper.java b/src/com/android/settings/fuelgauge/batteryusage/AnomalyEventWrapper.java
new file mode 100644
index 00000000000..d5354900b05
--- /dev/null
+++ b/src/com/android/settings/fuelgauge/batteryusage/AnomalyEventWrapper.java
@@ -0,0 +1,231 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.fuelgauge.batteryusage;
+
+import android.content.Context;
+import android.os.Bundle;
+import android.text.TextUtils;
+import android.util.Pair;
+
+import com.android.settings.R;
+import com.android.settings.SettingsActivity;
+import com.android.settings.core.SubSettingLauncher;
+
+import java.util.function.Function;
+
+final class AnomalyEventWrapper {
+ private static final String TAG = "AnomalyEventWrapper";
+
+ private final Context mContext;
+ private final PowerAnomalyEvent mPowerAnomalyEvent;
+
+ private final int mCardStyleId;
+ private final int mResourceIndex;
+
+ private SubSettingLauncher mSubSettingLauncher = null;
+ private Pair mHighlightSlotPair = null;
+ private BatteryDiffEntry mRelatedBatteryDiffEntry = null;
+
+ AnomalyEventWrapper(Context context, PowerAnomalyEvent powerAnomalyEvent) {
+ mContext = context;
+ mPowerAnomalyEvent = powerAnomalyEvent;
+ // Set basic battery tips card info
+ mCardStyleId = mPowerAnomalyEvent.getType().getNumber();
+ mResourceIndex = mPowerAnomalyEvent.getKey().getNumber();
+ }
+
+ private T getInfo(Function warningBannerInfoSupplier,
+ Function warningItemInfoSupplier) {
+ if (warningBannerInfoSupplier != null && mPowerAnomalyEvent.hasWarningBannerInfo()) {
+ return warningBannerInfoSupplier.apply(mPowerAnomalyEvent.getWarningBannerInfo());
+ } else if (warningItemInfoSupplier != null && mPowerAnomalyEvent.hasWarningItemInfo()) {
+ return warningItemInfoSupplier.apply(mPowerAnomalyEvent.getWarningItemInfo());
+ }
+ return null;
+ }
+
+ private int getResourceId(int resourceId, int resourceIndex, String defType) {
+ final String key = getStringFromArrayResource(resourceId, resourceIndex);
+ return TextUtils.isEmpty(key) ? 0
+ : mContext.getResources().getIdentifier(key, defType, mContext.getPackageName());
+ }
+
+ private String getString(Function warningBannerInfoSupplier,
+ Function warningItemInfoSupplier,
+ int resourceId, int resourceIndex) {
+ final String string = getInfo(warningBannerInfoSupplier, warningItemInfoSupplier);
+ return (!TextUtils.isEmpty(string) || resourceId <= 0) ? string
+ : getStringFromArrayResource(resourceId, resourceIndex);
+ }
+
+ private String getStringFromArrayResource(int resourceId, int resourceIndex) {
+ if (resourceId <= 0 || resourceIndex < 0) {
+ return null;
+ }
+ final String[] stringArray = mContext.getResources().getStringArray(resourceId);
+ return (resourceIndex >= 0 && resourceIndex < stringArray.length)
+ ? stringArray[resourceIndex] : null;
+ }
+
+ void setRelatedBatteryDiffEntry(BatteryDiffEntry batteryDiffEntry) {
+ mRelatedBatteryDiffEntry = batteryDiffEntry;
+ }
+
+ String getEventId() {
+ return mPowerAnomalyEvent.hasEventId() ? mPowerAnomalyEvent.getEventId() : null;
+ }
+
+ int getIconResId() {
+ return getResourceId(R.array.battery_tips_card_icons, mCardStyleId, "drawable");
+ }
+
+ int getColorResId() {
+ return getResourceId(R.array.battery_tips_card_colors, mCardStyleId, "color");
+ }
+
+ String getTitleString() {
+ final String protoTitleString = getInfo(WarningBannerInfo::getTitleString,
+ WarningItemInfo::getTitleString);
+ if (!TextUtils.isEmpty(protoTitleString)) {
+ return protoTitleString;
+ }
+ final int titleFormatResId = getResourceId(R.array.power_anomaly_title_ids,
+ mResourceIndex, "string");
+ if (mPowerAnomalyEvent.hasWarningBannerInfo()) {
+ return mContext.getString(titleFormatResId);
+ } else if (mPowerAnomalyEvent.hasWarningItemInfo() && mRelatedBatteryDiffEntry != null) {
+ final String appLabel = mRelatedBatteryDiffEntry.getAppLabel();
+ return mContext.getString(titleFormatResId, appLabel);
+ }
+ return null;
+ }
+
+ String getMainBtnString() {
+ return getString(WarningBannerInfo::getMainButtonString,
+ WarningItemInfo::getMainButtonString,
+ R.array.power_anomaly_main_btn_strings, mResourceIndex);
+ }
+
+ String getDismissBtnString() {
+ return getString(WarningBannerInfo::getCancelButtonString,
+ WarningItemInfo::getCancelButtonString,
+ R.array.power_anomaly_dismiss_btn_strings, mResourceIndex);
+ }
+
+ String getAnomalyHintString() {
+ return getStringFromArrayResource(R.array.power_anomaly_hint_messages, mResourceIndex);
+ }
+
+ String getDismissRecordKey() {
+ return mPowerAnomalyEvent.getDismissRecordKey();
+ }
+
+ boolean hasAnomalyEntryKey() {
+ return getAnomalyEntryKey() != null;
+ }
+
+ String getAnomalyEntryKey() {
+ return mPowerAnomalyEvent.hasWarningItemInfo()
+ && mPowerAnomalyEvent.getWarningItemInfo().hasItemKey()
+ ? mPowerAnomalyEvent.getWarningItemInfo().getItemKey() : null;
+ }
+
+ boolean hasSubSettingLauncher() {
+ if (mSubSettingLauncher == null) {
+ mSubSettingLauncher = getSubSettingLauncher();
+ }
+ return mSubSettingLauncher != null;
+ }
+
+ SubSettingLauncher getSubSettingLauncher() {
+ if (mSubSettingLauncher != null) {
+ return mSubSettingLauncher;
+ }
+ final String destinationClassName = getInfo(
+ WarningBannerInfo::getMainButtonDestination, null);
+ if (!TextUtils.isEmpty(destinationClassName)) {
+ final Integer sourceMetricsCategory = getInfo(
+ WarningBannerInfo::getMainButtonSourceMetricsCategory, null);
+ final String preferenceHighlightKey = getInfo(
+ WarningBannerInfo::getMainButtonSourceHighlightKey, null);
+ Bundle arguments = Bundle.EMPTY;
+ if (!TextUtils.isEmpty(preferenceHighlightKey)) {
+ arguments = new Bundle(1);
+ arguments.putString(SettingsActivity.EXTRA_FRAGMENT_ARG_KEY,
+ preferenceHighlightKey);
+ }
+ mSubSettingLauncher = new SubSettingLauncher(mContext)
+ .setDestination(destinationClassName)
+ .setSourceMetricsCategory(sourceMetricsCategory)
+ .setArguments(arguments);
+ }
+ return mSubSettingLauncher;
+ }
+
+ boolean hasHighlightSlotPair(BatteryLevelData batteryLevelData) {
+ if (mHighlightSlotPair == null) {
+ mHighlightSlotPair = getHighlightSlotPair(batteryLevelData);
+ }
+ return mHighlightSlotPair != null;
+ }
+
+ Pair getHighlightSlotPair(BatteryLevelData batteryLevelData) {
+ if (mHighlightSlotPair != null) {
+ return mHighlightSlotPair;
+ }
+ if (!mPowerAnomalyEvent.hasWarningItemInfo()) {
+ return null;
+ }
+ 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) {
+ mHighlightSlotPair = batteryLevelData
+ .getIndexByTimestamps(startTimestamp, endTimestamp);
+ if (mHighlightSlotPair.first == BatteryChartViewModel.SELECTED_INDEX_INVALID
+ || mHighlightSlotPair.second == BatteryChartViewModel.SELECTED_INDEX_INVALID) {
+ // Drop invalid mHighlightSlotPair index
+ mHighlightSlotPair = null;
+ }
+ }
+ return mHighlightSlotPair;
+ }
+
+ boolean updateTipsCardPreference(BatteryTipsCardPreference preference) {
+ final String titleString = getTitleString();
+ if (TextUtils.isEmpty(titleString)) {
+ return false;
+ }
+ preference.setTitle(titleString);
+ preference.setIconResourceId(getIconResId());
+ preference.setMainButtonStrokeColorResourceId(getColorResId());
+ preference.setMainButtonLabel(getMainBtnString());
+ preference.setDismissButtonLabel(getDismissBtnString());
+ return true;
+ }
+
+ boolean launchSubSetting() {
+ if (!hasSubSettingLauncher()) {
+ return false;
+ }
+ // Navigate to sub setting page
+ mSubSettingLauncher.launch();
+ return true;
+ }
+}
diff --git a/src/com/android/settings/fuelgauge/batteryusage/BatteryChartPreferenceController.java b/src/com/android/settings/fuelgauge/batteryusage/BatteryChartPreferenceController.java
index 1893096dbf4..844241e18e0 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/BatteryChartPreferenceController.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/BatteryChartPreferenceController.java
@@ -221,14 +221,20 @@ public class BatteryChartPreferenceController extends AbstractPreferenceControll
refreshUi();
}
+ boolean isHighlightSlotFocused() {
+ return (mDailyHighlightSlotIndex != BatteryChartViewModel.SELECTED_INDEX_INVALID
+ && mDailyHighlightSlotIndex == mDailyChartIndex
+ && mHourlyHighlightSlotIndex != BatteryChartViewModel.SELECTED_INDEX_INVALID
+ && mHourlyHighlightSlotIndex == mHourlyChartIndex);
+ }
+
void onHighlightSlotIndexUpdate(int dailyHighlightSlotIndex, int hourlyHighlightSlotIndex) {
- if (mDailyHighlightSlotIndex == dailyHighlightSlotIndex
- && mHourlyHighlightSlotIndex == hourlyHighlightSlotIndex) {
- return;
- }
mDailyHighlightSlotIndex = dailyHighlightSlotIndex;
mHourlyHighlightSlotIndex = hourlyHighlightSlotIndex;
refreshUi();
+ if (mOnSelectedIndexUpdatedListener != null) {
+ mOnSelectedIndexUpdatedListener.onSelectedIndexUpdated();
+ }
}
void selectHighlightSlotIndex() {
@@ -405,7 +411,7 @@ public class BatteryChartPreferenceController extends AbstractPreferenceControll
final String slotInformation = getSlotInformation();
return slotInformation == null
? mPrefContext.getString(
- R.string.battery_usage_breakdown_title_since_last_full_charge)
+ R.string.battery_usage_breakdown_title_since_last_full_charge)
: mPrefContext.getString(
R.string.battery_usage_breakdown_title_for_slot, slotInformation);
}
diff --git a/src/com/android/settings/fuelgauge/batteryusage/BatteryTipsCardPreference.java b/src/com/android/settings/fuelgauge/batteryusage/BatteryTipsCardPreference.java
index e98077c699c..47d2ac38f65 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/BatteryTipsCardPreference.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/BatteryTipsCardPreference.java
@@ -120,12 +120,10 @@ public class BatteryTipsCardPreference extends Preference implements View.OnClic
public void onClick(View view) {
final int viewId = view.getId();
if (viewId == R.id.main_button || viewId == R.id.tips_card) {
- setVisible(false);
if (mOnConfirmListener != null) {
mOnConfirmListener.onConfirm();
}
} else if (viewId == R.id.dismiss_button) {
- setVisible(false);
if (mOnRejectListener != null) {
mOnRejectListener.onReject();
}
diff --git a/src/com/android/settings/fuelgauge/batteryusage/BatteryTipsController.java b/src/com/android/settings/fuelgauge/batteryusage/BatteryTipsController.java
index 400e70ad5dd..39ed0dc077b 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/BatteryTipsController.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/BatteryTipsController.java
@@ -18,21 +18,15 @@ package com.android.settings.fuelgauge.batteryusage;
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.core.SubSettingLauncher;
import com.android.settings.overlay.FeatureFactory;
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
-import java.util.function.Function;
-
/** Controls the update for battery tips card */
public class BatteryTipsController extends BasePreferenceController {
@@ -59,6 +53,10 @@ public class BatteryTipsController extends BasePreferenceController {
@VisibleForTesting
BatteryTipsCardPreference mCardPreference;
+ @VisibleForTesting
+ AnomalyEventWrapper mAnomalyEventWrapper = null;
+ @VisibleForTesting
+ Boolean mIsAcceptable = false;
public BatteryTipsController(Context context) {
super(context, ROOT_PREFERENCE_KEY);
@@ -85,132 +83,56 @@ public class BatteryTipsController extends BasePreferenceController {
mOnAnomalyRejectListener = listener;
}
- private T getInfo(PowerAnomalyEvent powerAnomalyEvent,
- Function warningBannerInfoSupplier,
- Function warningItemInfoSupplier) {
- if (warningBannerInfoSupplier != null && powerAnomalyEvent.hasWarningBannerInfo()) {
- return warningBannerInfoSupplier.apply(powerAnomalyEvent.getWarningBannerInfo());
- } else if (warningItemInfoSupplier != null && powerAnomalyEvent.hasWarningItemInfo()) {
- return warningItemInfoSupplier.apply(powerAnomalyEvent.getWarningItemInfo());
+ void acceptTipsCard() {
+ if (mAnomalyEventWrapper == null || !mIsAcceptable) {
+ return;
}
- return null;
- }
-
- private String getStringFromResource(int resourceId, int resourceIndex) {
- if (resourceId < 0) {
- return null;
+ // For anomaly events with same record key, dismissed until next time full charged.
+ final String dismissRecordKey = mAnomalyEventWrapper.getDismissRecordKey();
+ if (!TextUtils.isEmpty(dismissRecordKey)) {
+ DatabaseUtils.setDismissedPowerAnomalyKeys(mContext, dismissRecordKey);
}
- final String[] stringArray = mContext.getResources().getStringArray(resourceId);
- return (resourceIndex >= 0 && resourceIndex < stringArray.length)
- ? stringArray[resourceIndex] : null;
+ mCardPreference.setVisible(false);
+ mMetricsFeatureProvider.action(
+ mContext, SettingsEnums.ACTION_BATTERY_TIPS_CARD_ACCEPT,
+ mAnomalyEventWrapper.getEventId());
}
- private int getResourceId(int resourceId, int resourceIndex, String defType) {
- final String key = getStringFromResource(resourceId, resourceIndex);
- return TextUtils.isEmpty(key) ? 0
- : mContext.getResources().getIdentifier(key, defType, mContext.getPackageName());
- }
-
- private String getString(PowerAnomalyEvent powerAnomalyEvent,
- Function warningBannerInfoSupplier,
- Function warningItemInfoSupplier,
- int resourceId, int resourceIndex) {
- String string =
- getInfo(powerAnomalyEvent, warningBannerInfoSupplier, warningItemInfoSupplier);
- return (!TextUtils.isEmpty(string) || resourceId < 0) ? string
- : getStringFromResource(resourceId, resourceIndex);
- }
-
- /** 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) {
+ void handleBatteryTipsCardUpdated(
+ AnomalyEventWrapper anomalyEventWrapper, boolean isAcceptable) {
+ mAnomalyEventWrapper = anomalyEventWrapper;
+ mIsAcceptable = isAcceptable;
+ if (mAnomalyEventWrapper == null) {
mCardPreference.setVisible(false);
return;
}
- // Get card icon and color styles
- final int cardStyleId = powerAnomalyEvent.getType().getNumber();
- final int iconResId = getResourceId(
- R.array.battery_tips_card_icons, cardStyleId, "drawable");
- final int colorResId = getResourceId(
- 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;
+ final String eventId = mAnomalyEventWrapper.getEventId();
- final String titleString = getString(powerAnomalyEvent, WarningBannerInfo::getTitleString,
- WarningItemInfo::getTitleString, R.array.power_anomaly_titles, resourceIndex);
- if (titleString.isEmpty()) {
+ // Update card & buttons preference
+ if (!mAnomalyEventWrapper.updateTipsCardPreference(mCardPreference)) {
mCardPreference.setVisible(false);
return;
}
- final String mainBtnString = getString(powerAnomalyEvent,
- WarningBannerInfo::getMainButtonString, WarningItemInfo::getMainButtonString,
- R.array.power_anomaly_main_btn_strings, resourceIndex);
- final String dismissBtnString = getString(powerAnomalyEvent,
- WarningBannerInfo::getCancelButtonString, WarningItemInfo::getCancelButtonString,
- R.array.power_anomaly_dismiss_btn_strings, resourceIndex);
-
- final String destinationClassName = getInfo(powerAnomalyEvent,
- WarningBannerInfo::getMainButtonDestination, null);
- final Integer sourceMetricsCategory = getInfo(powerAnomalyEvent,
- WarningBannerInfo::getMainButtonSourceMetricsCategory, null);
- final String preferenceHighlightKey = getInfo(powerAnomalyEvent,
- WarningBannerInfo::getMainButtonSourceHighlightKey, null);
-
- // Update card preference and main button fragment launcher
- mCardPreference.setTitle(titleString);
- mCardPreference.setIconResourceId(iconResId);
- mCardPreference.setMainButtonStrokeColorResourceId(colorResId);
- mCardPreference.setMainButtonLabel(mainBtnString);
- mCardPreference.setDismissButtonLabel(dismissBtnString);
-
// Set battery tips card listener
mCardPreference.setOnConfirmListener(() -> {
+ mCardPreference.setVisible(false);
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();
+ } else if (mAnomalyEventWrapper.launchSubSetting()) {
+ mMetricsFeatureProvider.action(
+ mContext, SettingsEnums.ACTION_BATTERY_TIPS_CARD_ACCEPT, eventId);
}
- mMetricsFeatureProvider.action(
- mContext, SettingsEnums.ACTION_BATTERY_TIPS_CARD_ACCEPT, eventId);
});
mCardPreference.setOnRejectListener(() -> {
+ mCardPreference.setVisible(false);
if (mOnAnomalyRejectListener != null) {
mOnAnomalyRejectListener.onAnomalyReject();
}
// For anomaly events with same record key, dismissed until next time full charged.
- final String dismissRecordKey = getDismissRecordKey(powerAnomalyEvent);
+ final String dismissRecordKey = mAnomalyEventWrapper.getDismissRecordKey();
if (!TextUtils.isEmpty(dismissRecordKey)) {
DatabaseUtils.setDismissedPowerAnomalyKeys(mContext, dismissRecordKey);
}
diff --git a/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBreakdownController.java b/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBreakdownController.java
index 8aa31e2e0a6..b237ef674f5 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBreakdownController.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBreakdownController.java
@@ -53,6 +53,7 @@ import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.Optional;
import java.util.Set;
/** Controller for battery usage breakdown preference group. */
@@ -93,6 +94,14 @@ public class BatteryUsageBreakdownController extends BasePreferenceController
BatteryDiffData mBatteryDiffData;
@VisibleForTesting
String mPercentLessThanThresholdText;
+ @VisibleForTesting
+ boolean mIsHighlightSlot;
+ @VisibleForTesting
+ String mAnomalyEventId;
+ @VisibleForTesting
+ String mAnomalyEntryKey;
+ @VisibleForTesting
+ String mAnomalyHintString;
public BatteryUsageBreakdownController(
Context context, Lifecycle lifecycle, SettingsActivity activity,
@@ -137,6 +146,12 @@ public class BatteryUsageBreakdownController extends BasePreferenceController
return false;
}
+ private String getActionKey(String packageName) {
+ final String actionKey = TextUtils.isEmpty(packageName)
+ ? PACKAGE_NAME_NONE : packageName;
+ return mAnomalyEventId == null ? actionKey : actionKey + "|" + mAnomalyEventId;
+ }
+
@Override
public boolean handlePreferenceTreeClick(Preference preference) {
if (!(preference instanceof PowerGaugePreference)) {
@@ -151,7 +166,7 @@ public class BatteryUsageBreakdownController extends BasePreferenceController
? SettingsEnums.ACTION_BATTERY_USAGE_SYSTEM_ITEM
: SettingsEnums.ACTION_BATTERY_USAGE_APP_ITEM,
/* pageId */ SettingsEnums.OPEN_BATTERY_USAGE,
- TextUtils.isEmpty(packageName) ? PACKAGE_NAME_NONE : packageName,
+ getActionKey(packageName),
(int) Math.round(diffEntry.getPercentage()));
Log.d(TAG, String.format("handleClick() label=%s key=%s package=%s",
diffEntry.getAppLabel(), diffEntry.getKey(), packageName));
@@ -211,9 +226,23 @@ public class BatteryUsageBreakdownController extends BasePreferenceController
* used when showing the footer.
*/
void handleBatteryUsageUpdated(
- BatteryDiffData slotUsageData, String slotTimestamp, boolean isAllUsageDataEmpty) {
+ BatteryDiffData slotUsageData, String slotTimestamp,
+ boolean isAllUsageDataEmpty, boolean isHighlightSlot,
+ Optional optionalAnomalyEventWrapper) {
mBatteryDiffData = slotUsageData;
mSlotTimestamp = slotTimestamp;
+ mIsHighlightSlot = isHighlightSlot;
+
+ if (optionalAnomalyEventWrapper != null) {
+ final AnomalyEventWrapper anomalyEventWrapper =
+ optionalAnomalyEventWrapper.orElse(null);
+ mAnomalyEventId = anomalyEventWrapper != null
+ ? anomalyEventWrapper.getEventId() : null;
+ mAnomalyEntryKey = anomalyEventWrapper != null
+ ? anomalyEventWrapper.getAnomalyEntryKey() : null;
+ mAnomalyHintString = anomalyEventWrapper != null
+ ? anomalyEventWrapper.getAnomalyHintString() : null;
+ }
showCategoryTitle(slotTimestamp);
showSpinnerAndAppList();
@@ -278,15 +307,15 @@ public class BatteryUsageBreakdownController extends BasePreferenceController
continue;
}
final String prefKey = entry.getKey();
- PowerGaugePreference pref = mAppListPreferenceGroup.findPreference(prefKey);
+ AnomalyAppItemPreference pref = mAppListPreferenceGroup.findPreference(prefKey);
if (pref != null) {
isAdded = true;
} else {
- pref = (PowerGaugePreference) mPreferenceCache.get(prefKey);
+ pref = (AnomalyAppItemPreference) mPreferenceCache.get(prefKey);
}
- // Creates new innstance if cached preference is not found.
+ // Creates new instance if cached preference is not found.
if (pref == null) {
- pref = new PowerGaugePreference(mPrefContext);
+ pref = new AnomalyAppItemPreference(mPrefContext);
pref.setKey(prefKey);
mPreferenceCache.put(prefKey, pref);
}
@@ -294,6 +323,10 @@ public class BatteryUsageBreakdownController extends BasePreferenceController
pref.setTitle(appLabel);
pref.setOrder(prefIndex);
pref.setSingleLineTitle(true);
+ // Updates App item preference style
+ pref.setAnomalyHint(mIsHighlightSlot && mAnomalyEntryKey != null
+ && mAnomalyEntryKey.equals(entry.getKey())
+ ? mAnomalyHintString : null);
// Sets the BatteryDiffEntry to preference for launching detailed page.
pref.setBatteryDiffEntry(entry);
pref.setSelectable(entry.validForRestriction());
diff --git a/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageDataLoader.java b/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageDataLoader.java
index ece996014c3..658f104668a 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageDataLoader.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageDataLoader.java
@@ -28,6 +28,7 @@ import androidx.annotation.VisibleForTesting;
import com.android.settings.fuelgauge.BatteryUsageHistoricalLogEntry.Action;
import com.android.settings.fuelgauge.batteryusage.bugreport.BatteryUsageLogUtils;
+import com.android.settings.overlay.FeatureFactory;
import java.util.List;
import java.util.Map;
@@ -138,6 +139,8 @@ public final class BatteryUsageDataLoader {
// No app usage data or battery diff data at this time.
loadAppUsageData(context);
preprocessBatteryUsageSlots(context);
+ FeatureFactory.getFactory(context).getPowerUsageFeatureProvider(context)
+ .detectSettingsAnomaly(context, /* displayDrain= */ 0);
}
Log.d(TAG, String.format(
"loadUsageDataSafely() in %d/ms", System.currentTimeMillis() - start));
diff --git a/src/com/android/settings/fuelgauge/batteryusage/PowerUsageAdvanced.java b/src/com/android/settings/fuelgauge/batteryusage/PowerUsageAdvanced.java
index 4e8e396528e..fb92a76f682 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/PowerUsageAdvanced.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/PowerUsageAdvanced.java
@@ -52,6 +52,7 @@ import java.util.Optional;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
+import java.util.function.Predicate;
/** Advanced power usage. */
@SearchIndexable(forTarget = SearchIndexable.ALL & ~SearchIndexable.ARC)
@@ -92,9 +93,9 @@ public class PowerUsageAdvanced extends PowerUsageBase {
@VisibleForTesting
BatteryUsageBreakdownController mBatteryUsageBreakdownController;
@VisibleForTesting
- PowerAnomalyEvent mPowerAnomalyEvent;
- @VisibleForTesting
Optional mBatteryLevelData;
+ @VisibleForTesting
+ Optional mHighlightEventWrapper;
@Override
public void onCreate(Bundle icicle) {
@@ -188,7 +189,7 @@ public class PowerUsageAdvanced extends PowerUsageBase {
mIsChartDataLoaded = true;
mBatteryLevelData = null;
mBatteryUsageMap = null;
- mPowerAnomalyEvent = null;
+ mHighlightEventWrapper = null;
restartLoader(LoaderIndex.BATTERY_LEVEL_DATA_LOADER, bundle,
mBatteryLevelDataLoaderCallbacks);
}
@@ -239,8 +240,13 @@ public class PowerUsageAdvanced extends PowerUsageBase {
mScreenOnTimeController.handleSceenOnTimeUpdated(
slotUsageData.getScreenOnTime(), slotInformation);
}
+ // Hide card tips if the related highlight slot was clicked.
+ if (isAppsAnomalyEventFocused()) {
+ mBatteryTipsController.acceptTipsCard();
+ }
mBatteryUsageBreakdownController.handleBatteryUsageUpdated(
- slotUsageData, slotInformation, isBatteryUsageMapNullOrEmpty());
+ slotUsageData, slotInformation, isBatteryUsageMapNullOrEmpty(),
+ isAppsAnomalyEventFocused(), mHighlightEventWrapper);
Log.d(TAG, String.format("Battery usage list shows in %d millis",
System.currentTimeMillis() - mResumeTimestamp));
}
@@ -262,49 +268,95 @@ public class PowerUsageAdvanced extends PowerUsageBase {
return;
}
Log.d(TAG, "anomalyEventList = " + anomalyEventList);
- final PowerAnomalyEvent displayEvent =
- getHighestScoreAnomalyEvent(getContext(), anomalyEventList);
- onDisplayAnomalyEventUpdated(displayEvent);
+
+ final Set dismissedPowerAnomalyKeys =
+ DatabaseUtils.getDismissedPowerAnomalyKeys(getContext());
+ Log.d(TAG, "dismissedPowerAnomalyKeys = " + dismissedPowerAnomalyKeys);
+
+ // Choose an app anomaly event with highest score to show highlight slot
+ final PowerAnomalyEvent highlightEvent =
+ getAnomalyEvent(anomalyEventList, PowerAnomalyEvent::hasWarningItemInfo);
+ // Choose an event never dismissed to show as card.
+ // If the slot is already highlighted, the tips card should be the corresponding app
+ // or settings anomaly event.
+ final PowerAnomalyEvent tipsCardEvent =
+ getAnomalyEvent(anomalyEventList,
+ event -> !dismissedPowerAnomalyKeys.contains(event.getDismissRecordKey())
+ && (event.equals(highlightEvent) || !event.hasWarningItemInfo()));
+ onDisplayAnomalyEventUpdated(tipsCardEvent, highlightEvent);
}
@VisibleForTesting
- void onDisplayAnomalyEventUpdated(PowerAnomalyEvent event) {
- mPowerAnomalyEvent = event;
+ void onDisplayAnomalyEventUpdated(
+ PowerAnomalyEvent tipsCardEvent, PowerAnomalyEvent highlightEvent) {
if (mBatteryTipsController == null
|| mBatteryChartPreferenceController == null
|| mBatteryUsageBreakdownController == null) {
return;
}
+ final boolean isSameAnomalyEvent = (tipsCardEvent == highlightEvent);
// Update battery tips card preference & behaviour
mBatteryTipsController.setOnAnomalyConfirmListener(null);
mBatteryTipsController.setOnAnomalyRejectListener(null);
- mBatteryTipsController.handleBatteryTipsCardUpdated(mPowerAnomalyEvent);
+ final AnomalyEventWrapper tipsCardEventWrapper = (tipsCardEvent == null) ? null :
+ new AnomalyEventWrapper(getContext(), tipsCardEvent);
+ if (tipsCardEventWrapper != null) {
+ tipsCardEventWrapper.setRelatedBatteryDiffEntry(
+ findRelatedBatteryDiffEntry(tipsCardEventWrapper));
+ }
+ mBatteryTipsController.handleBatteryTipsCardUpdated(
+ tipsCardEventWrapper, isSameAnomalyEvent);
// Update highlight slot effect in battery chart view
Pair 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));
+ mHighlightEventWrapper = Optional.ofNullable(isSameAnomalyEvent ? tipsCardEventWrapper :
+ ((highlightEvent != null)
+ ? new AnomalyEventWrapper(getContext(), highlightEvent) : null));
+ if (mBatteryLevelData != null && mBatteryLevelData.isPresent()
+ && mHighlightEventWrapper.isPresent()
+ && mHighlightEventWrapper.get().hasHighlightSlotPair(mBatteryLevelData.get())) {
+ highlightSlotIndexPair = mHighlightEventWrapper.get()
+ .getHighlightSlotPair(mBatteryLevelData.get());
+ if (isSameAnomalyEvent) {
+ // For main button, focus on highlight slot when clicked
+ mBatteryTipsController.setOnAnomalyConfirmListener(() -> {
+ mBatteryChartPreferenceController.selectHighlightSlotIndex();
+ mBatteryTipsController.acceptTipsCard();
+ });
}
}
mBatteryChartPreferenceController.onHighlightSlotIndexUpdate(
highlightSlotIndexPair.first, highlightSlotIndexPair.second);
}
+ @VisibleForTesting
+ BatteryDiffEntry findRelatedBatteryDiffEntry(AnomalyEventWrapper eventWrapper) {
+ if (eventWrapper == null
+ || mBatteryLevelData == null || mBatteryLevelData.isEmpty()
+ || !eventWrapper.hasHighlightSlotPair(mBatteryLevelData.get())
+ || !eventWrapper.hasAnomalyEntryKey()
+ || mBatteryUsageMap == null) {
+ return null;
+ }
+ final Pair highlightSlotIndexPair =
+ eventWrapper.getHighlightSlotPair(mBatteryLevelData.get());
+ final BatteryDiffData relatedDiffData = mBatteryUsageMap
+ .get(highlightSlotIndexPair.first).get(highlightSlotIndexPair.second);
+ final String anomalyEntryKey = eventWrapper.getAnomalyEntryKey();
+ if (relatedDiffData == null || anomalyEntryKey == null) {
+ return null;
+ }
+ for (BatteryDiffEntry entry : relatedDiffData.getAppDiffEntryList()) {
+ if (anomalyEntryKey.equals(entry.getKey())) {
+ return entry;
+ }
+ }
+ return null;
+ }
+
private void setBatteryChartPreferenceController() {
if (mHistPref != null && mBatteryChartPreferenceController != null) {
mHistPref.setChartPreferenceController(mBatteryChartPreferenceController);
@@ -319,6 +371,11 @@ public class PowerUsageAdvanced extends PowerUsageBase {
&& allBatteryDiffData.getSystemDiffEntryList().isEmpty());
}
+ private boolean isAppsAnomalyEventFocused() {
+ return mBatteryChartPreferenceController != null
+ && mBatteryChartPreferenceController.isHighlightSlotFocused();
+ }
+
private void logScreenUsageTime() {
final BatteryDiffData allBatteryDiffData = getAllBatteryDiffData(mBatteryUsageMap);
if (allBatteryDiffData == null) {
@@ -339,25 +396,22 @@ public class PowerUsageAdvanced extends PowerUsageBase {
}
@VisibleForTesting
- static PowerAnomalyEvent getHighestScoreAnomalyEvent(
- Context context, PowerAnomalyEventList anomalyEventList) {
+ static PowerAnomalyEvent getAnomalyEvent(
+ PowerAnomalyEventList anomalyEventList, Predicate predicate) {
if (anomalyEventList == null || anomalyEventList.getPowerAnomalyEventsCount() == 0) {
return null;
}
- final Set dismissedPowerAnomalyKeys =
- DatabaseUtils.getDismissedPowerAnomalyKeys(context);
- Log.d(TAG, "dismissedPowerAnomalyKeys = " + dismissedPowerAnomalyKeys);
- final PowerAnomalyEvent highestScoreEvent = anomalyEventList.getPowerAnomalyEventsList()
+ final PowerAnomalyEvent filterAnomalyEvent = anomalyEventList.getPowerAnomalyEventsList()
.stream()
- .filter(event -> !dismissedPowerAnomalyKeys.contains(
- BatteryTipsController.getDismissRecordKey(event)))
+ .filter(predicate)
.max(Comparator.comparing(PowerAnomalyEvent::getScore))
.orElse(null);
- Log.d(TAG, "highestScoreAnomalyEvent = " + highestScoreEvent);
- return highestScoreEvent;
+ Log.d(TAG, "filterAnomalyEvent = " + filterAnomalyEvent);
+ return filterAnomalyEvent;
}
+
private static BatteryDiffData getAllBatteryDiffData(
Map> batteryUsageMap) {
return batteryUsageMap == null ? null : batteryUsageMap
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 99df215f5aa..caa9c352cc3 100644
--- a/src/com/android/settings/fuelgauge/protos/power_anomaly_event.proto
+++ b/src/com/android/settings/fuelgauge/protos/power_anomaly_event.proto
@@ -18,6 +18,7 @@ message PowerAnomalyEvent {
WarningBannerInfo warning_banner_info = 6;
WarningItemInfo warning_item_info = 7;
}
+ optional string dismiss_record_key = 8;
}
// NOTE: Please DO NOT delete enum items or change enum values. Use [deprecated = true] instead.
@@ -32,11 +33,16 @@ enum PowerAnomalyType{
// NOTE: Please DO NOT delete enum items or change enum values. Use [deprecated = true] instead.
// The enum value will be used to decide pre-defined title and button labels.
//
-// Next id: 3
+// Next id: 8
enum PowerAnomalyKey{
KEY_BRIGHTNESS = 0;
KEY_SCREEN_TIMEOUT = 1;
- KEY_APP = 2;
+ KEY_APP_TOTAL_ALWAYS_HIGH = 2;
+ KEY_APP_TOTAL_HIGHER_THAN_USUAL = 3;
+ KEY_APP_BACKGROUND_ALWAYS_HIGH = 4;
+ KEY_APP_BACKGROUND_HIGHER_THAN_USUAL = 5;
+ KEY_APP_FOREGROUND_ALWAYS_HIGH = 6;
+ KEY_APP_FOREGROUND_HIGHER_THAN_USUAL = 7;
}
message WarningBannerInfo {
@@ -60,6 +66,5 @@ message WarningItemInfo {
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;
+ optional string item_key = 8;
}
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/AnomalyEventWrapperTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/AnomalyEventWrapperTest.java
new file mode 100644
index 00000000000..60e0af09309
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/AnomalyEventWrapperTest.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.fuelgauge.batteryusage;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.spy;
+
+import android.content.Context;
+
+import com.android.settings.testutils.BatteryTestUtils;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+
+import java.util.TimeZone;
+
+@RunWith(RobolectricTestRunner.class)
+public class AnomalyEventWrapperTest {
+ private AnomalyEventWrapper mAnomalyEventWrapper;
+ private Context mContext;
+
+ @Before
+ public void setUp() {
+ TimeZone.setDefault(TimeZone.getTimeZone("GMT+8"));
+ mContext = spy(RuntimeEnvironment.application);
+ }
+
+ @Test
+ public void getDismissRecordKey_returnExpectedResult() {
+ mAnomalyEventWrapper = new AnomalyEventWrapper(mContext,
+ BatteryTestUtils.createAdaptiveBrightnessAnomalyEvent());
+ assertThat(mAnomalyEventWrapper.getDismissRecordKey())
+ .isEqualTo("KEY_BRIGHTNESS");
+
+ mAnomalyEventWrapper = new AnomalyEventWrapper(mContext,
+ BatteryTestUtils.createScreenTimeoutAnomalyEvent());
+ assertThat(mAnomalyEventWrapper.getDismissRecordKey())
+ .isEqualTo("KEY_SCREEN_TIMEOUT");
+
+ mAnomalyEventWrapper = new AnomalyEventWrapper(mContext,
+ BatteryTestUtils.createAppAnomalyEvent());
+ assertThat(mAnomalyEventWrapper.getDismissRecordKey())
+ .isEqualTo("KEY_APP_1");
+ }
+}
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 630ff45bf2f..63cb1b3c94b 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryTipsCardPreferenceTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryTipsCardPreferenceTest.java
@@ -21,6 +21,7 @@ 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.doReturn;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
@@ -58,13 +59,14 @@ public final class BatteryTipsCardPreferenceTest {
private BatteryTipsCardPreference mBatteryTipsCardPreference;
private PowerUsageAdvanced mPowerUsageAdvanced;
private BatteryTipsController mBatteryTipsController;
+ private BatteryChartPreferenceController mBatteryChartPreferenceController;
@Mock
private View mFakeView;
@Mock
- private BatteryChartPreferenceController mBatteryChartPreferenceController;
- @Mock
private BatteryUsageBreakdownController mBatteryUsageBreakdownController;
+ @Mock
+ private BatteryDiffEntry mFakeEntry;
@Before
public void setUp() {
@@ -73,8 +75,13 @@ public final class BatteryTipsCardPreferenceTest {
mFeatureFactory = FakeFeatureFactory.setupForTest();
mBatteryTipsCardPreference = new BatteryTipsCardPreference(mContext, /*attrs=*/ null);
mBatteryTipsController = new BatteryTipsController(mContext);
+ mBatteryChartPreferenceController =
+ spy(new BatteryChartPreferenceController(mContext, null, null));
+ mBatteryChartPreferenceController.mPrefContext = mContext;
mBatteryTipsController.mCardPreference = mBatteryTipsCardPreference;
- mPowerUsageAdvanced = new PowerUsageAdvanced();
+
+ mPowerUsageAdvanced = spy(new PowerUsageAdvanced());
+ doReturn(mContext).when(mPowerUsageAdvanced).getContext();
mPowerUsageAdvanced.mBatteryTipsController = mBatteryTipsController;
mPowerUsageAdvanced.mBatteryChartPreferenceController = mBatteryChartPreferenceController;
mPowerUsageAdvanced.mBatteryUsageBreakdownController = mBatteryUsageBreakdownController;
@@ -82,6 +89,7 @@ public final class BatteryTipsCardPreferenceTest {
1694354400000L, 1, // 2023-09-10 22:00:00
1694361600000L, 2, // 2023-09-11 00:00:00
1694368800000L, 3))); // 2023-09-11 02:00:00
+ doReturn("TestEntriesKey").when(mFakeEntry).getKey();
}
@Test
@@ -99,7 +107,8 @@ public final class BatteryTipsCardPreferenceTest {
when(mFakeView.getId()).thenReturn(R.id.main_button);
doNothing().when(mContext).startActivity(captor.capture());
- mPowerUsageAdvanced.onDisplayAnomalyEventUpdated(adaptiveBrightnessAnomaly);
+ mPowerUsageAdvanced.onDisplayAnomalyEventUpdated(
+ adaptiveBrightnessAnomaly, adaptiveBrightnessAnomaly);
mBatteryTipsCardPreference.onClick(mFakeView);
assertThat(mBatteryTipsCardPreference.isVisible()).isFalse();
@@ -109,25 +118,30 @@ public final class BatteryTipsCardPreferenceTest {
.isEqualTo(DisplaySettings.class.getName());
assertThat(intent.getIntExtra(MetricsFeatureProvider.EXTRA_SOURCE_METRICS_CATEGORY, -1))
.isEqualTo(SettingsEnums.DISPLAY);
+ verify(mFeatureFactory.metricsFeatureProvider).action(
+ mContext, SettingsEnums.ACTION_BATTERY_TIPS_CARD_SHOW, "BrightnessAnomaly");
verify(mFeatureFactory.metricsFeatureProvider).action(
mContext, SettingsEnums.ACTION_BATTERY_TIPS_CARD_ACCEPT, "BrightnessAnomaly");
}
@Test
- public void onClick_dismissBtn_cardDismissAndLogged() {
+ public void onClick_dismissBtnOfSettingsAnomaly_cardDismissAndLogged() {
final PowerAnomalyEvent screenTimeoutAnomaly =
BatteryTestUtils.createScreenTimeoutAnomalyEvent();
DatabaseUtils.removeDismissedPowerAnomalyKeys(mContext);
when(mFeatureFactory.powerUsageFeatureProvider.isBatteryTipsEnabled()).thenReturn(true);
when(mFakeView.getId()).thenReturn(R.id.dismiss_button);
- mPowerUsageAdvanced.onDisplayAnomalyEventUpdated(screenTimeoutAnomaly);
+ mPowerUsageAdvanced.onDisplayAnomalyEventUpdated(
+ screenTimeoutAnomaly, screenTimeoutAnomaly);
mBatteryTipsCardPreference.onClick(mFakeView);
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_SHOW, "ScreenTimeoutAnomaly");
verify(mFeatureFactory.metricsFeatureProvider).action(
mContext, SettingsEnums.ACTION_BATTERY_TIPS_CARD_DISMISS, "ScreenTimeoutAnomaly");
}
@@ -137,30 +151,40 @@ public final class BatteryTipsCardPreferenceTest {
final PowerAnomalyEvent appsAnomaly = BatteryTestUtils.createAppAnomalyEvent();
when(mFeatureFactory.powerUsageFeatureProvider.isBatteryTipsEnabled()).thenReturn(true);
when(mFakeView.getId()).thenReturn(R.id.main_button);
+ doNothing().when(mBatteryChartPreferenceController).selectHighlightSlotIndex();
+ when(mPowerUsageAdvanced.findRelatedBatteryDiffEntry(any())).thenReturn(mFakeEntry);
- mPowerUsageAdvanced.onDisplayAnomalyEventUpdated(appsAnomaly);
+ mPowerUsageAdvanced.onDisplayAnomalyEventUpdated(appsAnomaly, appsAnomaly);
mBatteryTipsCardPreference.onClick(mFakeView);
assertThat(mBatteryTipsCardPreference.isVisible()).isFalse();
verify(mContext, never()).startActivity(any(Intent.class));
+ verify(mBatteryChartPreferenceController).onHighlightSlotIndexUpdate(
+ eq(1), eq(0));
verify(mBatteryChartPreferenceController).selectHighlightSlotIndex();
+ verify(mFeatureFactory.metricsFeatureProvider).action(
+ mContext, SettingsEnums.ACTION_BATTERY_TIPS_CARD_SHOW, "AppAnomaly");
verify(mFeatureFactory.metricsFeatureProvider).action(
mContext, SettingsEnums.ACTION_BATTERY_TIPS_CARD_ACCEPT, "AppAnomaly");
}
@Test
- public void onClick_dismissBtnOfAppsAnomaly_removeHighlightSlotIndex() {
+ public void onClick_dismissBtnOfAppsAnomaly_keepHighlightSlotIndex() {
final PowerAnomalyEvent appsAnomaly = BatteryTestUtils.createAppAnomalyEvent();
when(mFeatureFactory.powerUsageFeatureProvider.isBatteryTipsEnabled()).thenReturn(true);
when(mFakeView.getId()).thenReturn(R.id.dismiss_button);
+ when(mPowerUsageAdvanced.findRelatedBatteryDiffEntry(any())).thenReturn(mFakeEntry);
- mPowerUsageAdvanced.onDisplayAnomalyEventUpdated(appsAnomaly);
+ mPowerUsageAdvanced.onDisplayAnomalyEventUpdated(appsAnomaly, appsAnomaly);
mBatteryTipsCardPreference.onClick(mFakeView);
assertThat(mBatteryTipsCardPreference.isVisible()).isFalse();
+ verify(mContext, never()).startActivity(any(Intent.class));
verify(mBatteryChartPreferenceController).onHighlightSlotIndexUpdate(
- eq(BatteryChartViewModel.SELECTED_INDEX_INVALID),
- eq(BatteryChartViewModel.SELECTED_INDEX_INVALID));
+ eq(1), eq(0));
+ verify(mBatteryChartPreferenceController, never()).selectHighlightSlotIndex();
+ verify(mFeatureFactory.metricsFeatureProvider).action(
+ mContext, SettingsEnums.ACTION_BATTERY_TIPS_CARD_SHOW, "AppAnomaly");
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 913c00a1fb6..b8afe984950 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryTipsControllerTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryTipsControllerTest.java
@@ -16,8 +16,6 @@
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;
@@ -70,30 +68,18 @@ public final class BatteryTipsControllerTest {
@Test
public void handleBatteryTipsCardUpdated_null_hidePreference() {
- mBatteryTipsController.handleBatteryTipsCardUpdated(/* powerAnomalyEvents= */ null);
+ mBatteryTipsController.handleBatteryTipsCardUpdated(/* powerAnomalyEvents= */ null, false);
verify(mBatteryTipsCardPreference).setVisible(false);
}
- @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);
+ mBatteryTipsController.handleBatteryTipsCardUpdated(
+ new AnomalyEventWrapper(mContext, event), false);
// Check pre-defined string
verify(mBatteryTipsCardPreference).setTitle(
@@ -114,7 +100,8 @@ public final class BatteryTipsControllerTest {
PowerAnomalyEvent event = BatteryTestUtils.createScreenTimeoutAnomalyEvent();
when(mFeatureFactory.powerUsageFeatureProvider.isBatteryTipsEnabled()).thenReturn(true);
- mBatteryTipsController.handleBatteryTipsCardUpdated(event);
+ mBatteryTipsController.handleBatteryTipsCardUpdated(
+ new AnomalyEventWrapper(mContext, event), false);
verify(mBatteryTipsCardPreference).setTitle("Reduce screen timeout to extend battery life");
verify(mBatteryTipsCardPreference).setIconResourceId(R.drawable.ic_battery_tips_lightbulb);
@@ -139,7 +126,8 @@ public final class BatteryTipsControllerTest {
.build();
when(mFeatureFactory.powerUsageFeatureProvider.isBatteryTipsEnabled()).thenReturn(true);
- mBatteryTipsController.handleBatteryTipsCardUpdated(event);
+ mBatteryTipsController.handleBatteryTipsCardUpdated(
+ new AnomalyEventWrapper(mContext, event), false);
verify(mBatteryTipsCardPreference).setTitle(testTitle);
verify(mBatteryTipsCardPreference).setIconResourceId(R.drawable.ic_battery_tips_lightbulb);
@@ -157,10 +145,13 @@ public final class BatteryTipsControllerTest {
PowerAnomalyEvent event = BatteryTestUtils.createAppAnomalyEvent();
when(mFeatureFactory.powerUsageFeatureProvider.isBatteryTipsEnabled()).thenReturn(true);
- mBatteryTipsController.handleBatteryTipsCardUpdated(event);
+ AnomalyEventWrapper eventWrapper = new AnomalyEventWrapper(mContext, event);
+ eventWrapper.setRelatedBatteryDiffEntry(
+ new BatteryDiffEntry(mContext, "", "Chrome", 0));
+ mBatteryTipsController.handleBatteryTipsCardUpdated(eventWrapper, false);
verify(mBatteryTipsCardPreference).setTitle(
- "Chrome used more battery than usual in foreground");
+ "Chrome used more battery than usual");
verify(mBatteryTipsCardPreference).setIconResourceId(
R.drawable.ic_battery_tips_warning_icon);
verify(mBatteryTipsCardPreference).setMainButtonStrokeColorResourceId(
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBreakdownControllerTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBreakdownControllerTest.java
index d89c06b1150..a721ad47f15 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBreakdownControllerTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBreakdownControllerTest.java
@@ -69,7 +69,7 @@ public final class BatteryUsageBreakdownControllerTest {
@Mock
private BatteryHistEntry mBatteryHistEntry;
@Mock
- private PowerGaugePreference mPowerGaugePreference;
+ private AnomalyAppItemPreference mAnomalyAppItemPreference;
private Context mContext;
private FakeFeatureFactory mFeatureFactory;
@@ -123,13 +123,14 @@ public final class BatteryUsageBreakdownControllerTest {
BatteryDiffEntry.sResourceCache.put(
"fakeBatteryDiffEntryKey",
new BatteryEntry.NameAndIcon("fakeName", /*icon=*/ null, /*iconId=*/ 1));
+ doReturn(mAnomalyAppItemPreference).when(mAppListPreferenceGroup).findPreference(PREF_KEY);
}
@Test
public void onDestroy_clearPreferenceCacheAndPreferenceGroupRemoveAll() {
// Ensures the testing environment is correct.
mBatteryUsageBreakdownController.mPreferenceCache.put(
- PREF_KEY, mPowerGaugePreference);
+ PREF_KEY, mAnomalyAppItemPreference);
assertThat(mBatteryUsageBreakdownController.mPreferenceCache).hasSize(1);
mBatteryUsageBreakdownController.onDestroy();
@@ -178,7 +179,6 @@ public final class BatteryUsageBreakdownControllerTest {
doReturn(mDrawable).when(mBatteryDiffEntry).getAppIcon();
doReturn(appLabel).when(mBatteryDiffEntry).getAppLabel();
doReturn(PREF_KEY).when(mBatteryDiffEntry).getKey();
- doReturn(mPowerGaugePreference).when(mAppListPreferenceGroup).findPreference(PREF_KEY);
mBatteryUsageBreakdownController.addAllPreferences();
@@ -188,27 +188,25 @@ public final class BatteryUsageBreakdownControllerTest {
@Test
public void removeAndCacheAllUnusedPreferences_removePref_buildCacheAndRemoveAllPreference() {
doReturn(1).when(mAppListPreferenceGroup).getPreferenceCount();
- doReturn(mPowerGaugePreference).when(mAppListPreferenceGroup).getPreference(0);
+ doReturn(mAnomalyAppItemPreference).when(mAppListPreferenceGroup).getPreference(0);
doReturn(PREF_KEY2).when(mBatteryHistEntry).getKey();
- doReturn(PREF_KEY).when(mPowerGaugePreference).getKey();
- doReturn(mPowerGaugePreference).when(mAppListPreferenceGroup).findPreference(PREF_KEY);
+ doReturn(PREF_KEY).when(mAnomalyAppItemPreference).getKey();
// Ensures the testing data is correct.
assertThat(mBatteryUsageBreakdownController.mPreferenceCache).isEmpty();
mBatteryUsageBreakdownController.removeAndCacheAllUnusedPreferences();
assertThat(mBatteryUsageBreakdownController.mPreferenceCache.get(PREF_KEY))
- .isEqualTo(mPowerGaugePreference);
- verify(mAppListPreferenceGroup).removePreference(mPowerGaugePreference);
+ .isEqualTo(mAnomalyAppItemPreference);
+ verify(mAppListPreferenceGroup).removePreference(mAnomalyAppItemPreference);
}
@Test
public void removeAndCacheAllUnusedPreferences_keepPref_KeepAllPreference() {
doReturn(1).when(mAppListPreferenceGroup).getPreferenceCount();
- doReturn(mPowerGaugePreference).when(mAppListPreferenceGroup).getPreference(0);
+ doReturn(mAnomalyAppItemPreference).when(mAppListPreferenceGroup).getPreference(0);
doReturn(PREF_KEY).when(mBatteryDiffEntry).getKey();
- doReturn(PREF_KEY).when(mPowerGaugePreference).getKey();
- doReturn(mPowerGaugePreference).when(mAppListPreferenceGroup).findPreference(PREF_KEY);
+ doReturn(PREF_KEY).when(mAnomalyAppItemPreference).getKey();
// Ensures the testing data is correct.
assertThat(mBatteryUsageBreakdownController.mPreferenceCache).isEmpty();
@@ -232,10 +230,10 @@ public final class BatteryUsageBreakdownControllerTest {
@Test
public void handlePreferenceTreeClick_forAppEntry_returnTrue() {
mBatteryDiffEntry.mConsumerType = ConvertUtils.CONSUMER_TYPE_SYSTEM_BATTERY;
- doReturn(mBatteryDiffEntry).when(mPowerGaugePreference).getBatteryDiffEntry();
+ doReturn(mBatteryDiffEntry).when(mAnomalyAppItemPreference).getBatteryDiffEntry();
assertThat(mBatteryUsageBreakdownController.handlePreferenceTreeClick(
- mPowerGaugePreference)).isTrue();
+ mAnomalyAppItemPreference)).isTrue();
verify(mMetricsFeatureProvider)
.action(
SettingsEnums.OPEN_BATTERY_USAGE,
@@ -248,10 +246,10 @@ public final class BatteryUsageBreakdownControllerTest {
@Test
public void handlePreferenceTreeClick_forSystemEntry_returnTrue() {
mBatteryDiffEntry.mConsumerType = ConvertUtils.CONSUMER_TYPE_UID_BATTERY;
- doReturn(mBatteryDiffEntry).when(mPowerGaugePreference).getBatteryDiffEntry();
+ doReturn(mBatteryDiffEntry).when(mAnomalyAppItemPreference).getBatteryDiffEntry();
assertThat(mBatteryUsageBreakdownController.handlePreferenceTreeClick(
- mPowerGaugePreference)).isTrue();
+ mAnomalyAppItemPreference)).isTrue();
verify(mMetricsFeatureProvider)
.action(
SettingsEnums.OPEN_BATTERY_USAGE,
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/ConvertUtilsTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/ConvertUtilsTest.java
index f06dc634005..cd594d32eb4 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/ConvertUtilsTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/ConvertUtilsTest.java
@@ -72,6 +72,7 @@ public final class ConvertUtilsTest {
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
+ TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
mContext = spy(RuntimeEnvironment.application);
ConvertUtils.sUsageSource = ConvertUtils.EMPTY_USAGE_SOURCE;
when(mContext.getPackageManager()).thenReturn(mMockPackageManager);
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/PowerUsageAdvancedTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/PowerUsageAdvancedTest.java
index 953c2d4ef39..9753bd28e1c 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/PowerUsageAdvancedTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/PowerUsageAdvancedTest.java
@@ -20,8 +20,8 @@ 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.doReturn;
import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import android.content.Context;
@@ -41,7 +41,9 @@ import org.robolectric.annotation.Config;
import java.util.Map;
import java.util.Optional;
+import java.util.Set;
import java.util.TimeZone;
+import java.util.function.Predicate;
@RunWith(RobolectricTestRunner.class)
@Config(shadows = ShadowDashboardFragment.class)
@@ -50,6 +52,9 @@ public final class PowerUsageAdvancedTest {
private Context mContext;
private PowerUsageAdvanced mPowerUsageAdvanced;
+ private Predicate mCardFilterPredicate;
+ private Predicate mSlotFilterPredicate;
+
@Mock
private BatteryTipsController mBatteryTipsController;
@Mock
@@ -65,7 +70,7 @@ public final class PowerUsageAdvancedTest {
TimeZone.setDefault(TimeZone.getTimeZone("GMT+8"));
mContext = spy(RuntimeEnvironment.application);
- mPowerUsageAdvanced = new PowerUsageAdvanced();
+ mPowerUsageAdvanced = spy(new PowerUsageAdvanced());
mPowerUsageAdvanced.mBatteryTipsController = mBatteryTipsController;
mPowerUsageAdvanced.mBatteryChartPreferenceController = mBatteryChartPreferenceController;
mPowerUsageAdvanced.mScreenOnTimeController = mScreenOnTimeController;
@@ -74,43 +79,63 @@ public final class PowerUsageAdvancedTest {
1694354400000L, 1, // 2023-09-10 22:00:00
1694361600000L, 2, // 2023-09-11 00:00:00
1694368800000L, 3))); // 2023-09-11 02:00:00
+ doReturn(mContext).when(mPowerUsageAdvanced).getContext();
+ mSlotFilterPredicate = PowerAnomalyEvent::hasWarningItemInfo;
}
@Test
- public void getHighestScoreAnomalyEvent_withEmptyOrNullList_getNull() {
- assertThat(PowerUsageAdvanced.getHighestScoreAnomalyEvent(mContext, null)).isNull();
- assertThat(PowerUsageAdvanced.getHighestScoreAnomalyEvent(
- mContext, BatteryTestUtils.createEmptyPowerAnomalyEventList())).isNull();
+ public void getFilterAnomalyEvent_withEmptyOrNullList_getNull() {
+ prepareCardFilterPredicate(null);
+ assertThat(PowerUsageAdvanced
+ .getAnomalyEvent(null, mCardFilterPredicate)).isNull();
+ assertThat(PowerUsageAdvanced
+ .getAnomalyEvent(null, mSlotFilterPredicate)).isNull();
+ assertThat(PowerUsageAdvanced.getAnomalyEvent(
+ BatteryTestUtils.createEmptyPowerAnomalyEventList(), mCardFilterPredicate))
+ .isNull();
+ assertThat(PowerUsageAdvanced.getAnomalyEvent(
+ BatteryTestUtils.createEmptyPowerAnomalyEventList(), mSlotFilterPredicate))
+ .isNull();
}
@Test
- public void getHighestScoreAnomalyEvent_withoutDismissed_getHighestScoreEvent() {
+ public void getFilterAnomalyEvent_withoutDismissed_getHighestScoreEvent() {
final PowerAnomalyEventList powerAnomalyEventList =
BatteryTestUtils.createNonEmptyPowerAnomalyEventList();
- final PowerAnomalyEvent highestScoreEvent =
- PowerUsageAdvanced.getHighestScoreAnomalyEvent(mContext, powerAnomalyEventList);
+ final PowerAnomalyEvent slotEvent =
+ PowerUsageAdvanced.getAnomalyEvent(powerAnomalyEventList,
+ mSlotFilterPredicate);
+ prepareCardFilterPredicate(slotEvent);
+ final PowerAnomalyEvent cardEvent =
+ PowerUsageAdvanced.getAnomalyEvent(powerAnomalyEventList,
+ mCardFilterPredicate);
- assertThat(highestScoreEvent)
- .isEqualTo(BatteryTestUtils.createAdaptiveBrightnessAnomalyEvent());
+ assertThat(cardEvent).isEqualTo(BatteryTestUtils.createAdaptiveBrightnessAnomalyEvent());
+ assertThat(slotEvent).isNull();
}
@Test
- public void getHighestScoreAnomalyEvent_withBrightnessDismissed_getScreenTimeout() {
+ public void getFilterAnomalyEvent_withBrightnessDismissed_getScreenTimeout() {
final PowerAnomalyEventList powerAnomalyEventList =
BatteryTestUtils.createNonEmptyPowerAnomalyEventList();
DatabaseUtils.removeDismissedPowerAnomalyKeys(mContext);
DatabaseUtils.setDismissedPowerAnomalyKeys(mContext, PowerAnomalyKey.KEY_BRIGHTNESS.name());
- final PowerAnomalyEvent highestScoreEvent =
- PowerUsageAdvanced.getHighestScoreAnomalyEvent(mContext, powerAnomalyEventList);
+ final PowerAnomalyEvent slotEvent =
+ PowerUsageAdvanced.getAnomalyEvent(powerAnomalyEventList,
+ mSlotFilterPredicate);
+ prepareCardFilterPredicate(slotEvent);
+ final PowerAnomalyEvent cardEvent =
+ PowerUsageAdvanced.getAnomalyEvent(powerAnomalyEventList,
+ mCardFilterPredicate);
- assertThat(highestScoreEvent)
- .isEqualTo(BatteryTestUtils.createScreenTimeoutAnomalyEvent());
+ assertThat(cardEvent).isEqualTo(BatteryTestUtils.createScreenTimeoutAnomalyEvent());
+ assertThat(slotEvent).isNull();
}
@Test
- public void getHighestScoreAnomalyEvent_withAllDismissed_getNull() {
+ public void getFilterAnomalyEvent_withAllDismissed_getNull() {
final PowerAnomalyEventList powerAnomalyEventList =
BatteryTestUtils.createNonEmptyPowerAnomalyEventList();
DatabaseUtils.removeDismissedPowerAnomalyKeys(mContext);
@@ -118,20 +143,26 @@ public final class PowerUsageAdvancedTest {
DatabaseUtils.setDismissedPowerAnomalyKeys(mContext, key.name());
}
- final PowerAnomalyEvent highestScoreEvent =
- PowerUsageAdvanced.getHighestScoreAnomalyEvent(mContext, powerAnomalyEventList);
+ final PowerAnomalyEvent slotEvent =
+ PowerUsageAdvanced.getAnomalyEvent(powerAnomalyEventList,
+ mSlotFilterPredicate);
+ prepareCardFilterPredicate(slotEvent);
+ final PowerAnomalyEvent cardEvent =
+ PowerUsageAdvanced.getAnomalyEvent(powerAnomalyEventList,
+ mCardFilterPredicate);
- assertThat(highestScoreEvent).isNull();
+ assertThat(cardEvent).isNull();
+ assertThat(slotEvent).isNull();
}
@Test
public void onDisplayAnomalyEventUpdated_withSettingsAnomalyEvent_skipHighlightSlotEffect() {
final PowerAnomalyEvent event = BatteryTestUtils.createAdaptiveBrightnessAnomalyEvent();
- mPowerUsageAdvanced.onDisplayAnomalyEventUpdated(event);
+ mPowerUsageAdvanced.onDisplayAnomalyEventUpdated(event, event);
- assertThat(mPowerUsageAdvanced.mPowerAnomalyEvent).isEqualTo(event);
- verify(mBatteryTipsController).handleBatteryTipsCardUpdated(eq(event));
+ assertThat(mPowerUsageAdvanced.mHighlightEventWrapper.get().getEventId())
+ .isEqualTo(event.getEventId());
verify(mPowerUsageAdvanced.mBatteryTipsController).setOnAnomalyConfirmListener(isNull());
verify(mPowerUsageAdvanced.mBatteryTipsController).setOnAnomalyRejectListener(isNull());
verify(mPowerUsageAdvanced.mBatteryChartPreferenceController).onHighlightSlotIndexUpdate(
@@ -140,46 +171,44 @@ public final class PowerUsageAdvancedTest {
}
@Test
- public void onDisplayAnomalyEventUpdated_withAppAnomalyEvent_setHighlightSlotEffect() {
+ public void onDisplayAnomalyEventUpdated_onlyAppAnomalyEvent_setHighlightSlotEffect() {
final PowerAnomalyEvent event = BatteryTestUtils.createAppAnomalyEvent();
- mPowerUsageAdvanced.onDisplayAnomalyEventUpdated(event);
+ mPowerUsageAdvanced.onDisplayAnomalyEventUpdated(event, event);
- assertThat(mPowerUsageAdvanced.mPowerAnomalyEvent).isEqualTo(event);
- verify(mBatteryTipsController).handleBatteryTipsCardUpdated(eq(event));
+ assertThat(mPowerUsageAdvanced.mHighlightEventWrapper.get().getEventId())
+ .isEqualTo(event.getEventId());
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();
+ public void onDisplayAnomalyEventUpdated_withSettingsCardAndAppsSlotEvent_showExpected() {
+ final PowerAnomalyEvent settingsEvent =
+ BatteryTestUtils.createAdaptiveBrightnessAnomalyEvent();
+ final PowerAnomalyEvent appsEvent =
+ BatteryTestUtils.createAppAnomalyEvent();
- mPowerUsageAdvanced.onDisplayAnomalyEventUpdated(event);
- mPowerUsageAdvanced.onDisplayAnomalyEventUpdated(null);
+ mPowerUsageAdvanced.onDisplayAnomalyEventUpdated(settingsEvent, appsEvent);
- 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));
+ assertThat(mPowerUsageAdvanced.mHighlightEventWrapper.get().getEventId())
+ .isEqualTo(appsEvent.getEventId());
+ verify(mBatteryChartPreferenceController).onHighlightSlotIndexUpdate(eq(1), eq(0));
+ verify(mBatteryTipsController).setOnAnomalyConfirmListener(isNull());
+ verify(mBatteryTipsController).setOnAnomalyRejectListener(isNull());
}
-}
+
+ private void prepareCardFilterPredicate(PowerAnomalyEvent slotEvent) {
+ final Set dismissedPowerAnomalyKeys =
+ DatabaseUtils.getDismissedPowerAnomalyKeys(mContext);
+ mCardFilterPredicate = event -> !dismissedPowerAnomalyKeys.contains(
+ event.getDismissRecordKey())
+ && (event.equals(slotEvent) || !event.hasWarningItemInfo());
+ }
+}
\ No newline at end of file
diff --git a/tests/robotests/src/com/android/settings/testutils/BatteryTestUtils.java b/tests/robotests/src/com/android/settings/testutils/BatteryTestUtils.java
index 10355605747..e98ea1b0278 100644
--- a/tests/robotests/src/com/android/settings/testutils/BatteryTestUtils.java
+++ b/tests/robotests/src/com/android/settings/testutils/BatteryTestUtils.java
@@ -247,6 +247,7 @@ public class BatteryTestUtils {
.setEventId("BrightnessAnomaly")
.setType(PowerAnomalyType.TYPE_SETTINGS_BANNER)
.setKey(PowerAnomalyKey.KEY_BRIGHTNESS)
+ .setDismissRecordKey(PowerAnomalyKey.KEY_BRIGHTNESS.name())
.setScore(1.2f)
.setWarningBannerInfo(WarningBannerInfo.newBuilder()
.setMainButtonDestination(DisplaySettings.class.getName())
@@ -264,6 +265,7 @@ public class BatteryTestUtils {
.setEventId("ScreenTimeoutAnomaly")
.setType(PowerAnomalyType.TYPE_SETTINGS_BANNER)
.setKey(PowerAnomalyKey.KEY_SCREEN_TIMEOUT)
+ .setDismissRecordKey(PowerAnomalyKey.KEY_SCREEN_TIMEOUT.name())
.setScore(1.1f)
.setWarningBannerInfo(WarningBannerInfo.newBuilder()
.setMainButtonDestination(ScreenTimeoutSettings.class.getName())
@@ -280,15 +282,12 @@ public class BatteryTestUtils {
return PowerAnomalyEvent.newBuilder()
.setEventId("AppAnomaly")
.setType(PowerAnomalyType.TYPE_APPS_ITEM)
- .setKey(PowerAnomalyKey.KEY_APP)
+ .setKey(PowerAnomalyKey.KEY_APP_TOTAL_HIGHER_THAN_USUAL)
+ .setDismissRecordKey("KEY_APP_1")
.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")
.build())
.build();
}