Impl highlight effect on BatteryChartView slots.
Screenshot: https://screenshot.googleplex.com/F5VrGjj5kdNHMV6
Bug: 284893240
Bug: 291689623
Test: manual
Change-Id: I846d95d31e8bb839481b86a94d5191ff205f8328
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/src/com/android/settings/fuelgauge/batteryusage/BatteryChartPreferenceController.java b/src/com/android/settings/fuelgauge/batteryusage/BatteryChartPreferenceController.java
index d04ab0b..1893096 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/BatteryChartPreferenceController.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/BatteryChartPreferenceController.java
@@ -85,6 +85,10 @@
int mDailyChartIndex = BatteryChartViewModel.SELECTED_INDEX_ALL;
@VisibleForTesting
int mHourlyChartIndex = BatteryChartViewModel.SELECTED_INDEX_ALL;
+ @VisibleForTesting
+ int mDailyHighlightSlotIndex = BatteryChartViewModel.SELECTED_INDEX_INVALID;
+ @VisibleForTesting
+ int mHourlyHighlightSlotIndex = BatteryChartViewModel.SELECTED_INDEX_INVALID;
private boolean mIs24HourFormat;
private View mBatteryChartViewGroup;
@@ -217,6 +221,37 @@
refreshUi();
}
+ 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();
@@ -320,6 +355,7 @@
mDailyChartIndex = BatteryChartViewModel.SELECTED_INDEX_ALL;
}
mDailyViewModel.setSelectedIndex(mDailyChartIndex);
+ mDailyViewModel.setHighlightSlotIndex(mDailyHighlightSlotIndex);
mDailyChartView.setViewModel(mDailyViewModel);
}
@@ -334,6 +370,9 @@
mHourlyChartIndex = BatteryChartViewModel.SELECTED_INDEX_ALL;
}
hourlyViewModel.setSelectedIndex(mHourlyChartIndex);
+ hourlyViewModel.setHighlightSlotIndex((mDailyChartIndex == mDailyHighlightSlotIndex)
+ ? mHourlyHighlightSlotIndex
+ : BatteryChartViewModel.SELECTED_INDEX_INVALID);
mHourlyChartView.setViewModel(hourlyViewModel);
}
}
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 763a0f8..e98077c 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/BatteryTipsCardPreference.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/BatteryTipsCardPreference.java
@@ -16,9 +16,7 @@
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;
@@ -31,8 +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.overlay.FeatureFactory;
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
@@ -45,10 +41,17 @@
private static final String TAG = "BatteryTipsCardPreference";
- 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;
@@ -56,12 +59,6 @@
CharSequence mMainButtonLabel;
@VisibleForTesting
CharSequence mDismissButtonLabel;
- @VisibleForTesting
- String mDestinationComponentName;
- @VisibleForTesting
- String mPreferenceHighlightKey;
- @VisibleForTesting
- Integer mSourceMetricsCategory;
public BatteryTipsCardPreference(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -69,7 +66,14 @@
setSelectable(false);
final FeatureFactory featureFactory = FeatureFactory.getFactory(context);
mMetricsFeatureProvider = featureFactory.getMetricsFeatureProvider();
- mPowerAnomalyKey = null;
+ }
+
+ public void setOnConfirmListener(OnConfirmListener listener) {
+ mOnConfirmListener = listener;
+ }
+
+ public void setOnRejectListener(OnRejectListener listener) {
+ mOnRejectListener = listener;
}
/**
@@ -93,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) {
@@ -119,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();
}
}
}
diff --git a/src/com/android/settings/fuelgauge/batteryusage/BatteryTipsController.java b/src/com/android/settings/fuelgauge/batteryusage/BatteryTipsController.java
index fd81e9b..400e70a 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/BatteryTipsController.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/BatteryTipsController.java
@@ -18,13 +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.core.SubSettingLauncher;
import com.android.settings.overlay.FeatureFactory;
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
@@ -39,6 +42,21 @@
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;
@@ -59,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) {
@@ -95,6 +121,21 @@
: 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) {
mCardPreference.setVisible(false);
@@ -109,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/PowerUsageAdvanced.java b/src/com/android/settings/fuelgauge/batteryusage/PowerUsageAdvanced.java
index ccfc1e2..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;
@@ -67,11 +68,6 @@
private boolean mIsChartDataLoaded = false;
private long mResumeTimestamp;
- private BatteryTipsController mBatteryTipsController;
- private BatteryChartPreferenceController mBatteryChartPreferenceController;
- private ScreenOnTimeController mScreenOnTimeController;
- private BatteryUsageBreakdownController mBatteryUsageBreakdownController;
- private Optional<BatteryLevelData> mBatteryLevelData;
private Map<Integer, Map<Integer, BatteryDiffData>> mBatteryUsageMap;
private final ExecutorService mExecutor = Executors.newSingleThreadExecutor();
@@ -87,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);
@@ -179,6 +188,7 @@
mIsChartDataLoaded = true;
mBatteryLevelData = null;
mBatteryUsageMap = null;
+ mPowerAnomalyEvent = null;
restartLoader(LoaderIndex.BATTERY_LEVEL_DATA_LOADER, bundle,
mBatteryLevelDataLoaderCallbacks);
}
@@ -254,12 +264,45 @@
Log.d(TAG, "anomalyEventList = " + anomalyEventList);
final PowerAnomalyEvent displayEvent =
getHighestScoreAnomalyEvent(getContext(), anomalyEventList);
- if (displayEvent == null) {
+ onDisplayAnomalyEventUpdated(displayEvent);
+ }
+
+ @VisibleForTesting
+ void onDisplayAnomalyEventUpdated(PowerAnomalyEvent event) {
+ mPowerAnomalyEvent = event;
+ if (mBatteryTipsController == null
+ || mBatteryChartPreferenceController == null
+ || mBatteryUsageBreakdownController == null) {
return;
}
- if (mBatteryTipsController != null) {
- mBatteryTipsController.handleBatteryTipsCardUpdated(displayEvent);
+
+ // 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() {
@@ -307,8 +350,8 @@
final PowerAnomalyEvent highestScoreEvent = anomalyEventList.getPowerAnomalyEventsList()
.stream()
- .filter(event -> event.hasKey()
- && !dismissedPowerAnomalyKeys.contains(event.getKey().name()))
+ .filter(event -> !dismissedPowerAnomalyKeys.contains(
+ BatteryTipsController.getDismissRecordKey(event)))
.max(Comparator.comparing(PowerAnomalyEvent::getScore))
.orElse(null);
Log.d(TAG, "highestScoreAnomalyEvent = " + highestScoreEvent);
@@ -342,6 +385,7 @@
controllers.add(new BatteryUsageBreakdownController(
context, null /* lifecycle */, null /* activity */,
null /* fragment */));
+ controllers.add(new BatteryTipsController(context));
return controllers;
}
};
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/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
index ee2a8b2..953c2d4 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/PowerUsageAdvancedTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/PowerUsageAdvancedTest.java
@@ -17,9 +17,15 @@
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;
@@ -27,19 +33,47 @@
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
@@ -87,6 +121,65 @@
final PowerAnomalyEvent highestScoreEvent =
PowerUsageAdvanced.getHighestScoreAnomalyEvent(mContext, powerAnomalyEventList);
- assertThat(highestScoreEvent).isEqualTo(null);
+ 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/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")