Impl highlight effect on BatteryChartView slots. am: 6750634259

Original change: https://googleplex-android-review.googlesource.com/c/platform/packages/apps/Settings/+/24498956

Change-Id: Iff96ebb33e50b2c2bddbe44eada5bf35f7118531
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
mxyyiyi
2023-09-13 07:57:45 +00:00
committed by Automerger Merge Worker
15 changed files with 538 additions and 110 deletions

View File

@@ -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"

View File

@@ -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>

View File

@@ -85,6 +85,10 @@ public class BatteryChartPreferenceController extends AbstractPreferenceControll
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 @@ public class BatteryChartPreferenceController extends AbstractPreferenceControll
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 @@ public class BatteryChartPreferenceController extends AbstractPreferenceControll
mDailyChartIndex = BatteryChartViewModel.SELECTED_INDEX_ALL;
}
mDailyViewModel.setSelectedIndex(mDailyChartIndex);
mDailyViewModel.setHighlightSlotIndex(mDailyHighlightSlotIndex);
mDailyChartView.setViewModel(mDailyViewModel);
}
@@ -334,6 +370,9 @@ public class BatteryChartPreferenceController extends AbstractPreferenceControll
mHourlyChartIndex = BatteryChartViewModel.SELECTED_INDEX_ALL;
}
hourlyViewModel.setSelectedIndex(mHourlyChartIndex);
hourlyViewModel.setHighlightSlotIndex((mDailyChartIndex == mDailyHighlightSlotIndex)
? mHourlyHighlightSlotIndex
: BatteryChartViewModel.SELECTED_INDEX_INVALID);
mHourlyChartView.setViewModel(hourlyViewModel);
}
}

View File

@@ -31,6 +31,7 @@ import android.graphics.CornerPathEffect;
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 @@ public class BatteryChartView extends AppCompatImageView implements View.OnClick
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 @@ public class BatteryChartView extends AppCompatImageView implements View.OnClick
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 @@ public class BatteryChartView extends AppCompatImageView implements View.OnClick
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 @@ public class BatteryChartView extends AppCompatImageView implements View.OnClick
}
drawVerticalDividers(canvas);
drawTrapezoids(canvas);
drawTransomLine(canvas);
}
@Override
@@ -340,6 +352,40 @@ public class BatteryChartView extends AppCompatImageView implements View.OnClick
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 @@ public class BatteryChartView extends AppCompatImageView implements View.OnClick
}
}
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) {

View File

@@ -55,6 +55,7 @@ class BatteryChartViewModel {
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 @@ class BatteryChartViewModel {
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);

View File

@@ -20,6 +20,7 @@ import static com.android.settingslib.fuelgauge.BatteryStatus.BATTERY_LEVEL_UNKN
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 @@ public final class BatteryLevelData {
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 @@ public final class BatteryLevelData {
}
}
/** 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;
}

View File

@@ -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.Preference;
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 @@ public class BatteryTipsCardPreference extends Preference implements View.OnClic
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 @@ public class BatteryTipsCardPreference extends Preference implements View.OnClic
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 @@ public class BatteryTipsCardPreference extends Preference implements View.OnClic
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;
}
/**
@@ -92,13 +96,6 @@ public class BatteryTipsCardPreference extends Preference implements View.OnClic
}
}
/**
* 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.
*/
@@ -119,50 +116,18 @@ public class BatteryTipsCardPreference extends Preference implements View.OnClic
}
}
/**
* 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();
}
}
}

View File

@@ -18,13 +18,16 @@ 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;
@@ -39,6 +42,21 @@ public class BatteryTipsController extends BasePreferenceController {
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 @@ public class BatteryTipsController extends BasePreferenceController {
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 @@ public class BatteryTipsController extends BasePreferenceController {
: 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 @@ public class BatteryTipsController extends BasePreferenceController {
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);
}
}

View File

@@ -27,6 +27,7 @@ import android.os.Handler;
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 @@ public class PowerUsageAdvanced extends PowerUsageBase {
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 @@ public class PowerUsageAdvanced extends PowerUsageBase {
}
};
@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 @@ public class PowerUsageAdvanced extends PowerUsageBase {
mIsChartDataLoaded = true;
mBatteryLevelData = null;
mBatteryUsageMap = null;
mPowerAnomalyEvent = null;
restartLoader(LoaderIndex.BATTERY_LEVEL_DATA_LOADER, bundle,
mBatteryLevelDataLoaderCallbacks);
}
@@ -254,12 +264,45 @@ public class PowerUsageAdvanced extends PowerUsageBase {
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 @@ public class PowerUsageAdvanced extends PowerUsageBase {
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 @@ public class PowerUsageAdvanced extends PowerUsageBase {
controllers.add(new BatteryUsageBreakdownController(
context, null /* lifecycle */, null /* activity */,
null /* fragment */));
controllers.add(new BatteryTipsController(context));
return controllers;
}
};

View File

@@ -60,4 +60,6 @@ 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;
}

View File

@@ -18,6 +18,10 @@ package com.android.settings.fuelgauge.batteryusage;
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 @@ public class BatteryLevelDataTest {
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));
}
}

View File

@@ -19,7 +19,9 @@ package com.android.settings.fuelgauge.batteryusage;
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.mockito.MockitoAnnotations;
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 @@ public final class BatteryTipsCardPreferenceTest {
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 @@ public final class BatteryTipsCardPreferenceTest {
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 @@ public final class BatteryTipsCardPreferenceTest {
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 @@ public final class BatteryTipsCardPreferenceTest {
@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");
}
}

View File

@@ -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;
@@ -73,6 +75,19 @@ public final class BatteryTipsControllerTest {
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();
@@ -80,7 +95,6 @@ public final class BatteryTipsControllerTest {
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 @@ public final class BatteryTipsControllerTest {
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 @@ public final class BatteryTipsControllerTest {
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 @@ public final class BatteryTipsControllerTest {
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 @@ public final class BatteryTipsControllerTest {
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 @@ public final class BatteryTipsControllerTest {
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");

View File

@@ -17,9 +17,15 @@ package com.android.settings.fuelgauge.batteryusage;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.isNull;
import static org.mockito.ArgumentMatchers.notNull;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import android.content.Context;
import android.util.Pair;
import com.android.settings.testutils.BatteryTestUtils;
import com.android.settings.testutils.shadow.ShadowDashboardFragment;
@@ -27,19 +33,47 @@ import com.android.settings.testutils.shadow.ShadowDashboardFragment;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
import java.util.Map;
import java.util.Optional;
import java.util.TimeZone;
@RunWith(RobolectricTestRunner.class)
@Config(shadows = ShadowDashboardFragment.class)
public final class PowerUsageAdvancedTest {
private Context mContext;
private PowerUsageAdvanced mPowerUsageAdvanced;
@Mock
private BatteryTipsController mBatteryTipsController;
@Mock
private BatteryChartPreferenceController mBatteryChartPreferenceController;
@Mock
private ScreenOnTimeController mScreenOnTimeController;
@Mock
private BatteryUsageBreakdownController mBatteryUsageBreakdownController;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
TimeZone.setDefault(TimeZone.getTimeZone("GMT+8"));
mContext = spy(RuntimeEnvironment.application);
mPowerUsageAdvanced = new PowerUsageAdvanced();
mPowerUsageAdvanced.mBatteryTipsController = mBatteryTipsController;
mPowerUsageAdvanced.mBatteryChartPreferenceController = mBatteryChartPreferenceController;
mPowerUsageAdvanced.mScreenOnTimeController = mScreenOnTimeController;
mPowerUsageAdvanced.mBatteryUsageBreakdownController = mBatteryUsageBreakdownController;
mPowerUsageAdvanced.mBatteryLevelData = Optional.of(new BatteryLevelData(Map.of(
1694354400000L, 1, // 2023-09-10 22:00:00
1694361600000L, 2, // 2023-09-11 00:00:00
1694368800000L, 3))); // 2023-09-11 02:00:00
}
@Test
@@ -87,6 +121,65 @@ public final class PowerUsageAdvancedTest {
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));
}
}

View File

@@ -283,6 +283,9 @@ public class BatteryTestUtils {
.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")