App anomaly tips on PowerUsage App list
Screenshots: [in bg - banner] https://screenshot.googleplex.com/MzLC6LfX93TkkYf [in bg - hints] https://screenshot.googleplex.com/9JLXNsRiVG8arAU [in fg - banner] https://screenshot.googleplex.com/9oYbwUkeeLbQX2t [in fg - hints] https://screenshot.googleplex.com/53DTTUCUnf8rsoE [apps anomaly highlight hint + settings anomaly banner] https://screenshot.googleplex.com/8NdS2VMrSzwv2DM Bug: 291689643 Bug: 291689623 Test: manual (cherry picked from https://googleplex-android-review.googlesource.com/q/commit:bfd0f5859b6e5ffef4727ee562009f2050de7a58) Change-Id: Ic02db49cb3794ef134759d9dcec5f5ef32454a95
This commit is contained in:
22
res/drawable/battery_hints_chip_bg.xml
Normal file
22
res/drawable/battery_hints_chip_bg.xml
Normal file
@@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (C) 2023 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle">
|
||||
<solid android:color="@color/settingslib_dialog_background" />
|
||||
<corners android:radius="@dimen/battery_hints_chip_corner_radius" />
|
||||
</shape>
|
21
res/drawable/battery_hints_chip_bg_ripple.xml
Normal file
21
res/drawable/battery_hints_chip_bg_ripple.xml
Normal file
@@ -0,0 +1,21 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (C) 2023 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:color="?android:attr/colorControlHighlight">
|
||||
<item android:drawable="@drawable/battery_hints_chip_bg"/>
|
||||
</ripple>
|
67
res/layout/anomaly_app_item_preference.xml
Normal file
67
res/layout/anomaly_app_item_preference.xml
Normal file
@@ -0,0 +1,67 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2023 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<include layout="@layout/preference_app"/>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/warning_chip"
|
||||
android:visibility="gone"
|
||||
android:clickable="false"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="horizontal"
|
||||
android:paddingStart="?android:attr/listPreferredItemPaddingStart"
|
||||
android:paddingEnd="?android:attr/listPreferredItemPaddingEnd">
|
||||
|
||||
<Space
|
||||
android:layout_width="@dimen/secondary_app_icon_size"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:padding="8dp"
|
||||
android:layout_marginStart="16dp"
|
||||
android:background="@drawable/battery_hints_chip_bg_ripple">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="16dp"
|
||||
android:layout_height="16dp"
|
||||
android:layout_gravity="center_vertical|start"
|
||||
android:contentDescription="@string/battery_hints_warning_icon_a11y"
|
||||
android:src="@drawable/ic_battery_tips_warning_icon" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/warning_info"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingHorizontal="8dp"
|
||||
android:layout_gravity="center_vertical|start"
|
||||
android:textAlignment="viewStart"
|
||||
android:textAppearance="?android:attr/textAppearanceSmall"
|
||||
android:textColor="?android:attr/textColorPrimary"/>
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
@@ -1420,20 +1420,49 @@
|
||||
<item>color_battery_anomaly_yellow_selector</item>
|
||||
</string-array>
|
||||
|
||||
<!-- The following 3 arrays are for power anomaly tips card. Please keep them the same size. -->
|
||||
<string-array name="power_anomaly_titles">
|
||||
<item>Turn on adaptive brightness to extend battery life</item>
|
||||
<item>Reduce screen timeout to extend battery life</item>
|
||||
<!-- The following 4 arrays are for power anomaly tips card. Please keep them the same size. -->
|
||||
<string-array name="power_anomaly_title_ids" translatable="false">
|
||||
<item>battery_tips_settings_summary_brightness</item>
|
||||
<item>battery_tips_settings_summary_screen_timeout</item>
|
||||
<item>battery_tips_apps_summary_always_high</item>
|
||||
<item>battery_tips_apps_summary_higher_than_usual</item>
|
||||
<item>battery_tips_apps_summary_always_high_in_background</item>
|
||||
<item>battery_tips_apps_summary_higher_than_usual_in_background</item>
|
||||
<item>battery_tips_apps_summary_always_high_in_foreground</item>
|
||||
<item>battery_tips_apps_summary_higher_than_usual_in_foreground</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="power_anomaly_main_btn_strings" translatable="false">
|
||||
<item>@string/battery_tips_card_action_button</item>
|
||||
<item>@string/battery_tips_card_action_button</item>
|
||||
<item>@string/battery_tips_card_action_button_check</item>
|
||||
<item>@string/battery_tips_card_action_button_check</item>
|
||||
<item>@string/battery_tips_card_action_button_check</item>
|
||||
<item>@string/battery_tips_card_action_button_check</item>
|
||||
<item>@string/battery_tips_card_action_button_check</item>
|
||||
<item>@string/battery_tips_card_action_button_check</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="power_anomaly_dismiss_btn_strings" translatable="false">
|
||||
<item>@string/battery_tips_card_dismiss_button</item>
|
||||
<item>@string/battery_tips_card_dismiss_button</item>
|
||||
<item>@string/battery_tips_card_dismiss_button</item>
|
||||
<item>@string/battery_tips_card_dismiss_button</item>
|
||||
<item>@string/battery_tips_card_dismiss_button</item>
|
||||
<item>@string/battery_tips_card_dismiss_button</item>
|
||||
<item>@string/battery_tips_card_dismiss_button</item>
|
||||
<item>@string/battery_tips_card_dismiss_button</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="power_anomaly_hint_messages" translatable="false">
|
||||
<item></item>
|
||||
<item></item>
|
||||
<item>@string/battery_app_item_hint</item>
|
||||
<item>@string/battery_app_item_hint</item>
|
||||
<item>@string/battery_app_item_hint_in_bg</item>
|
||||
<item>@string/battery_app_item_hint_in_bg</item>
|
||||
<item>@string/battery_app_item_hint_in_fg</item>
|
||||
<item>@string/battery_app_item_hint_in_fg</item>
|
||||
</string-array>
|
||||
|
||||
<!-- A list of not supporting Terms of Address. [DO NOT TRANSLATE] -->
|
||||
|
@@ -403,6 +403,7 @@
|
||||
<!-- Battery tips card view component -->
|
||||
<dimen name="battery_tips_card_corner_radius_small">4dp</dimen>
|
||||
<dimen name="battery_tips_card_corner_radius_normal">24dp</dimen>
|
||||
<dimen name="battery_hints_chip_corner_radius">8dp</dimen>
|
||||
|
||||
<!-- Dimensions for Dream settings cards -->
|
||||
<dimen name="dream_item_min_column_width">174dp</dimen>
|
||||
|
@@ -9821,12 +9821,51 @@
|
||||
<!-- Label of action button in battery tips card [CHAR LIMIT=50] -->
|
||||
<string name="battery_tips_card_action_button">View Settings</string>
|
||||
|
||||
<!-- Label of action button in battery tips card [CHAR LIMIT=50] -->
|
||||
<string name="battery_tips_card_action_button_check">Check</string>
|
||||
|
||||
<!-- Label of dismiss button in battery tips card [CHAR LIMIT=50] -->
|
||||
<string name="battery_tips_card_dismiss_button">Got it</string>
|
||||
|
||||
<!-- Feedback card message in battery tips card [CHAR LIMIT=NONE] -->
|
||||
<string name="battery_tips_card_feedback_info">Is this message helpful?</string>
|
||||
|
||||
<!-- Content description for battery hints warning icon of app anomaly [CHAR LIMIT=NONE] -->
|
||||
<string name="battery_hints_warning_icon_a11y">Battery tips warning icon</string>
|
||||
|
||||
<!-- Summary of settings anomaly for adaptive brightness [CHAR LIMIT=NONE] -->
|
||||
<string name="battery_tips_settings_summary_brightness">Turn on adaptive brightness to extend battery life</string>
|
||||
|
||||
<!-- Summary of settings anomaly for screen timeout [CHAR LIMIT=NONE] -->
|
||||
<string name="battery_tips_settings_summary_screen_timeout">Reduce screen timeout to extend battery life</string>
|
||||
|
||||
<!-- Summary of apps anomaly for always high [CHAR LIMIT=NONE] -->
|
||||
<string name="battery_tips_apps_summary_always_high"><xliff:g id="app_label" example="Pokemon Go">%1$s</xliff:g> used more battery</string>
|
||||
|
||||
<!-- Summary of apps anomaly for higher than usual [CHAR LIMIT=NONE] -->
|
||||
<string name="battery_tips_apps_summary_higher_than_usual"><xliff:g id="app_label" example="Pokemon Go">%1$s</xliff:g> used more battery than usual</string>
|
||||
|
||||
<!-- Summary of apps anomaly for always high in background [CHAR LIMIT=NONE] -->
|
||||
<string name="battery_tips_apps_summary_always_high_in_background"><xliff:g id="app_label" example="Pokemon Go">%1$s</xliff:g> used more battery while in the background</string>
|
||||
|
||||
<!-- Summary of apps anomaly for higher than usual in background [CHAR LIMIT=NONE] -->
|
||||
<string name="battery_tips_apps_summary_higher_than_usual_in_background"><xliff:g id="app_label" example="Pokemon Go">%1$s</xliff:g> used more battery than usual while in the background</string>
|
||||
|
||||
<!-- Summary of apps anomaly for always high in foreground [CHAR LIMIT=NONE] -->
|
||||
<string name="battery_tips_apps_summary_always_high_in_foreground"><xliff:g id="app_label" example="Pokemon Go">%1$s</xliff:g> used more battery while in the foreground</string>
|
||||
|
||||
<!-- Summary of apps anomaly for higher than usual in foreground [CHAR LIMIT=NONE] -->
|
||||
<string name="battery_tips_apps_summary_higher_than_usual_in_foreground"><xliff:g id="app_label" example="Pokemon Go">%1$s</xliff:g> used more battery than usual while in the foreground</string>
|
||||
|
||||
<!-- Label of hint for apps anomaly in battery usage [CHAR LIMIT=NONE] -->
|
||||
<string name="battery_app_item_hint">High battery usage</string>
|
||||
|
||||
<!-- Label of hint for apps background anomaly in battery usage [CHAR LIMIT=NONE] -->
|
||||
<string name="battery_app_item_hint_in_bg">High battery usage in the background</string>
|
||||
|
||||
<!-- Label of hint for apps foreground anomaly in battery usage [CHAR LIMIT=NONE] -->
|
||||
<string name="battery_app_item_hint_in_fg">High battery usage in the foreground</string>
|
||||
|
||||
<!-- Filter title for battery unrestricted[CHAR_LIMIT=50]-->
|
||||
<string name="filter_battery_unrestricted_title">Unrestricted</string>
|
||||
|
||||
|
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright (C) 2023 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.settings.fuelgauge.batteryusage;
|
||||
|
||||
import android.content.Context;
|
||||
import android.text.TextUtils;
|
||||
import android.view.View;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.preference.PreferenceViewHolder;
|
||||
|
||||
import com.android.settings.R;
|
||||
|
||||
class AnomalyAppItemPreference extends PowerGaugePreference {
|
||||
|
||||
private static final String TAG = "AnomalyAppItemPreference";
|
||||
|
||||
private CharSequence mAnomalyHintText;
|
||||
|
||||
AnomalyAppItemPreference(Context context) {
|
||||
super(context, /* attrs */ null);
|
||||
setLayoutResource(R.layout.anomaly_app_item_preference);
|
||||
}
|
||||
|
||||
void setAnomalyHint(CharSequence anomalyHintText) {
|
||||
if (!TextUtils.equals(mAnomalyHintText, anomalyHintText)) {
|
||||
mAnomalyHintText = anomalyHintText;
|
||||
notifyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(PreferenceViewHolder viewHolder) {
|
||||
super.onBindViewHolder(viewHolder);
|
||||
final LinearLayout warningChipView =
|
||||
(LinearLayout) viewHolder.findViewById(R.id.warning_chip);
|
||||
|
||||
if (!TextUtils.isEmpty(mAnomalyHintText)) {
|
||||
((TextView) warningChipView.findViewById(R.id.warning_info)).setText(mAnomalyHintText);
|
||||
warningChipView.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
warningChipView.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,231 @@
|
||||
/*
|
||||
* Copyright (C) 2023 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.settings.fuelgauge.batteryusage;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Pair;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.SettingsActivity;
|
||||
import com.android.settings.core.SubSettingLauncher;
|
||||
|
||||
import java.util.function.Function;
|
||||
|
||||
final class AnomalyEventWrapper {
|
||||
private static final String TAG = "AnomalyEventWrapper";
|
||||
|
||||
private final Context mContext;
|
||||
private final PowerAnomalyEvent mPowerAnomalyEvent;
|
||||
|
||||
private final int mCardStyleId;
|
||||
private final int mResourceIndex;
|
||||
|
||||
private SubSettingLauncher mSubSettingLauncher = null;
|
||||
private Pair<Integer, Integer> mHighlightSlotPair = null;
|
||||
private BatteryDiffEntry mRelatedBatteryDiffEntry = null;
|
||||
|
||||
AnomalyEventWrapper(Context context, PowerAnomalyEvent powerAnomalyEvent) {
|
||||
mContext = context;
|
||||
mPowerAnomalyEvent = powerAnomalyEvent;
|
||||
// Set basic battery tips card info
|
||||
mCardStyleId = mPowerAnomalyEvent.getType().getNumber();
|
||||
mResourceIndex = mPowerAnomalyEvent.getKey().getNumber();
|
||||
}
|
||||
|
||||
private <T> T getInfo(Function<WarningBannerInfo, T> warningBannerInfoSupplier,
|
||||
Function<WarningItemInfo, T> warningItemInfoSupplier) {
|
||||
if (warningBannerInfoSupplier != null && mPowerAnomalyEvent.hasWarningBannerInfo()) {
|
||||
return warningBannerInfoSupplier.apply(mPowerAnomalyEvent.getWarningBannerInfo());
|
||||
} else if (warningItemInfoSupplier != null && mPowerAnomalyEvent.hasWarningItemInfo()) {
|
||||
return warningItemInfoSupplier.apply(mPowerAnomalyEvent.getWarningItemInfo());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private int getResourceId(int resourceId, int resourceIndex, String defType) {
|
||||
final String key = getStringFromArrayResource(resourceId, resourceIndex);
|
||||
return TextUtils.isEmpty(key) ? 0
|
||||
: mContext.getResources().getIdentifier(key, defType, mContext.getPackageName());
|
||||
}
|
||||
|
||||
private String getString(Function<WarningBannerInfo, String> warningBannerInfoSupplier,
|
||||
Function<WarningItemInfo, String> warningItemInfoSupplier,
|
||||
int resourceId, int resourceIndex) {
|
||||
final String string = getInfo(warningBannerInfoSupplier, warningItemInfoSupplier);
|
||||
return (!TextUtils.isEmpty(string) || resourceId <= 0) ? string
|
||||
: getStringFromArrayResource(resourceId, resourceIndex);
|
||||
}
|
||||
|
||||
private String getStringFromArrayResource(int resourceId, int resourceIndex) {
|
||||
if (resourceId <= 0 || resourceIndex < 0) {
|
||||
return null;
|
||||
}
|
||||
final String[] stringArray = mContext.getResources().getStringArray(resourceId);
|
||||
return (resourceIndex >= 0 && resourceIndex < stringArray.length)
|
||||
? stringArray[resourceIndex] : null;
|
||||
}
|
||||
|
||||
void setRelatedBatteryDiffEntry(BatteryDiffEntry batteryDiffEntry) {
|
||||
mRelatedBatteryDiffEntry = batteryDiffEntry;
|
||||
}
|
||||
|
||||
String getEventId() {
|
||||
return mPowerAnomalyEvent.hasEventId() ? mPowerAnomalyEvent.getEventId() : null;
|
||||
}
|
||||
|
||||
int getIconResId() {
|
||||
return getResourceId(R.array.battery_tips_card_icons, mCardStyleId, "drawable");
|
||||
}
|
||||
|
||||
int getColorResId() {
|
||||
return getResourceId(R.array.battery_tips_card_colors, mCardStyleId, "color");
|
||||
}
|
||||
|
||||
String getTitleString() {
|
||||
final String protoTitleString = getInfo(WarningBannerInfo::getTitleString,
|
||||
WarningItemInfo::getTitleString);
|
||||
if (!TextUtils.isEmpty(protoTitleString)) {
|
||||
return protoTitleString;
|
||||
}
|
||||
final int titleFormatResId = getResourceId(R.array.power_anomaly_title_ids,
|
||||
mResourceIndex, "string");
|
||||
if (mPowerAnomalyEvent.hasWarningBannerInfo()) {
|
||||
return mContext.getString(titleFormatResId);
|
||||
} else if (mPowerAnomalyEvent.hasWarningItemInfo() && mRelatedBatteryDiffEntry != null) {
|
||||
final String appLabel = mRelatedBatteryDiffEntry.getAppLabel();
|
||||
return mContext.getString(titleFormatResId, appLabel);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
String getMainBtnString() {
|
||||
return getString(WarningBannerInfo::getMainButtonString,
|
||||
WarningItemInfo::getMainButtonString,
|
||||
R.array.power_anomaly_main_btn_strings, mResourceIndex);
|
||||
}
|
||||
|
||||
String getDismissBtnString() {
|
||||
return getString(WarningBannerInfo::getCancelButtonString,
|
||||
WarningItemInfo::getCancelButtonString,
|
||||
R.array.power_anomaly_dismiss_btn_strings, mResourceIndex);
|
||||
}
|
||||
|
||||
String getAnomalyHintString() {
|
||||
return getStringFromArrayResource(R.array.power_anomaly_hint_messages, mResourceIndex);
|
||||
}
|
||||
|
||||
String getDismissRecordKey() {
|
||||
return mPowerAnomalyEvent.getDismissRecordKey();
|
||||
}
|
||||
|
||||
boolean hasAnomalyEntryKey() {
|
||||
return getAnomalyEntryKey() != null;
|
||||
}
|
||||
|
||||
String getAnomalyEntryKey() {
|
||||
return mPowerAnomalyEvent.hasWarningItemInfo()
|
||||
&& mPowerAnomalyEvent.getWarningItemInfo().hasItemKey()
|
||||
? mPowerAnomalyEvent.getWarningItemInfo().getItemKey() : null;
|
||||
}
|
||||
|
||||
boolean hasSubSettingLauncher() {
|
||||
if (mSubSettingLauncher == null) {
|
||||
mSubSettingLauncher = getSubSettingLauncher();
|
||||
}
|
||||
return mSubSettingLauncher != null;
|
||||
}
|
||||
|
||||
SubSettingLauncher getSubSettingLauncher() {
|
||||
if (mSubSettingLauncher != null) {
|
||||
return mSubSettingLauncher;
|
||||
}
|
||||
final String destinationClassName = getInfo(
|
||||
WarningBannerInfo::getMainButtonDestination, null);
|
||||
if (!TextUtils.isEmpty(destinationClassName)) {
|
||||
final Integer sourceMetricsCategory = getInfo(
|
||||
WarningBannerInfo::getMainButtonSourceMetricsCategory, null);
|
||||
final String preferenceHighlightKey = getInfo(
|
||||
WarningBannerInfo::getMainButtonSourceHighlightKey, null);
|
||||
Bundle arguments = Bundle.EMPTY;
|
||||
if (!TextUtils.isEmpty(preferenceHighlightKey)) {
|
||||
arguments = new Bundle(1);
|
||||
arguments.putString(SettingsActivity.EXTRA_FRAGMENT_ARG_KEY,
|
||||
preferenceHighlightKey);
|
||||
}
|
||||
mSubSettingLauncher = new SubSettingLauncher(mContext)
|
||||
.setDestination(destinationClassName)
|
||||
.setSourceMetricsCategory(sourceMetricsCategory)
|
||||
.setArguments(arguments);
|
||||
}
|
||||
return mSubSettingLauncher;
|
||||
}
|
||||
|
||||
boolean hasHighlightSlotPair(BatteryLevelData batteryLevelData) {
|
||||
if (mHighlightSlotPair == null) {
|
||||
mHighlightSlotPair = getHighlightSlotPair(batteryLevelData);
|
||||
}
|
||||
return mHighlightSlotPair != null;
|
||||
}
|
||||
|
||||
Pair<Integer, Integer> getHighlightSlotPair(BatteryLevelData batteryLevelData) {
|
||||
if (mHighlightSlotPair != null) {
|
||||
return mHighlightSlotPair;
|
||||
}
|
||||
if (!mPowerAnomalyEvent.hasWarningItemInfo()) {
|
||||
return null;
|
||||
}
|
||||
final WarningItemInfo warningItemInfo = mPowerAnomalyEvent.getWarningItemInfo();
|
||||
final Long startTimestamp = warningItemInfo.hasStartTimestamp()
|
||||
? warningItemInfo.getStartTimestamp() : null;
|
||||
final Long endTimestamp = warningItemInfo.hasEndTimestamp()
|
||||
? warningItemInfo.getEndTimestamp() : null;
|
||||
if (startTimestamp != null && endTimestamp != null) {
|
||||
mHighlightSlotPair = batteryLevelData
|
||||
.getIndexByTimestamps(startTimestamp, endTimestamp);
|
||||
if (mHighlightSlotPair.first == BatteryChartViewModel.SELECTED_INDEX_INVALID
|
||||
|| mHighlightSlotPair.second == BatteryChartViewModel.SELECTED_INDEX_INVALID) {
|
||||
// Drop invalid mHighlightSlotPair index
|
||||
mHighlightSlotPair = null;
|
||||
}
|
||||
}
|
||||
return mHighlightSlotPair;
|
||||
}
|
||||
|
||||
boolean updateTipsCardPreference(BatteryTipsCardPreference preference) {
|
||||
final String titleString = getTitleString();
|
||||
if (TextUtils.isEmpty(titleString)) {
|
||||
return false;
|
||||
}
|
||||
preference.setTitle(titleString);
|
||||
preference.setIconResourceId(getIconResId());
|
||||
preference.setMainButtonStrokeColorResourceId(getColorResId());
|
||||
preference.setMainButtonLabel(getMainBtnString());
|
||||
preference.setDismissButtonLabel(getDismissBtnString());
|
||||
return true;
|
||||
}
|
||||
|
||||
boolean launchSubSetting() {
|
||||
if (!hasSubSettingLauncher()) {
|
||||
return false;
|
||||
}
|
||||
// Navigate to sub setting page
|
||||
mSubSettingLauncher.launch();
|
||||
return true;
|
||||
}
|
||||
}
|
@@ -221,14 +221,20 @@ public class BatteryChartPreferenceController extends AbstractPreferenceControll
|
||||
refreshUi();
|
||||
}
|
||||
|
||||
boolean isHighlightSlotFocused() {
|
||||
return (mDailyHighlightSlotIndex != BatteryChartViewModel.SELECTED_INDEX_INVALID
|
||||
&& mDailyHighlightSlotIndex == mDailyChartIndex
|
||||
&& mHourlyHighlightSlotIndex != BatteryChartViewModel.SELECTED_INDEX_INVALID
|
||||
&& mHourlyHighlightSlotIndex == mHourlyChartIndex);
|
||||
}
|
||||
|
||||
void onHighlightSlotIndexUpdate(int dailyHighlightSlotIndex, int hourlyHighlightSlotIndex) {
|
||||
if (mDailyHighlightSlotIndex == dailyHighlightSlotIndex
|
||||
&& mHourlyHighlightSlotIndex == hourlyHighlightSlotIndex) {
|
||||
return;
|
||||
}
|
||||
mDailyHighlightSlotIndex = dailyHighlightSlotIndex;
|
||||
mHourlyHighlightSlotIndex = hourlyHighlightSlotIndex;
|
||||
refreshUi();
|
||||
if (mOnSelectedIndexUpdatedListener != null) {
|
||||
mOnSelectedIndexUpdatedListener.onSelectedIndexUpdated();
|
||||
}
|
||||
}
|
||||
|
||||
void selectHighlightSlotIndex() {
|
||||
@@ -405,7 +411,7 @@ public class BatteryChartPreferenceController extends AbstractPreferenceControll
|
||||
final String slotInformation = getSlotInformation();
|
||||
return slotInformation == null
|
||||
? mPrefContext.getString(
|
||||
R.string.battery_usage_breakdown_title_since_last_full_charge)
|
||||
R.string.battery_usage_breakdown_title_since_last_full_charge)
|
||||
: mPrefContext.getString(
|
||||
R.string.battery_usage_breakdown_title_for_slot, slotInformation);
|
||||
}
|
||||
|
@@ -120,12 +120,10 @@ public class BatteryTipsCardPreference extends Preference implements View.OnClic
|
||||
public void onClick(View view) {
|
||||
final int viewId = view.getId();
|
||||
if (viewId == R.id.main_button || viewId == R.id.tips_card) {
|
||||
setVisible(false);
|
||||
if (mOnConfirmListener != null) {
|
||||
mOnConfirmListener.onConfirm();
|
||||
}
|
||||
} else if (viewId == R.id.dismiss_button) {
|
||||
setVisible(false);
|
||||
if (mOnRejectListener != null) {
|
||||
mOnRejectListener.onReject();
|
||||
}
|
||||
|
@@ -18,21 +18,15 @@ package com.android.settings.fuelgauge.batteryusage;
|
||||
|
||||
import android.app.settings.SettingsEnums;
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import androidx.preference.PreferenceScreen;
|
||||
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.SettingsActivity;
|
||||
import com.android.settings.core.BasePreferenceController;
|
||||
import com.android.settings.core.SubSettingLauncher;
|
||||
import com.android.settings.overlay.FeatureFactory;
|
||||
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
|
||||
|
||||
import java.util.function.Function;
|
||||
|
||||
/** Controls the update for battery tips card */
|
||||
public class BatteryTipsController extends BasePreferenceController {
|
||||
|
||||
@@ -59,6 +53,10 @@ public class BatteryTipsController extends BasePreferenceController {
|
||||
|
||||
@VisibleForTesting
|
||||
BatteryTipsCardPreference mCardPreference;
|
||||
@VisibleForTesting
|
||||
AnomalyEventWrapper mAnomalyEventWrapper = null;
|
||||
@VisibleForTesting
|
||||
Boolean mIsAcceptable = false;
|
||||
|
||||
public BatteryTipsController(Context context) {
|
||||
super(context, ROOT_PREFERENCE_KEY);
|
||||
@@ -85,132 +83,56 @@ public class BatteryTipsController extends BasePreferenceController {
|
||||
mOnAnomalyRejectListener = listener;
|
||||
}
|
||||
|
||||
private <T> T getInfo(PowerAnomalyEvent powerAnomalyEvent,
|
||||
Function<WarningBannerInfo, T> warningBannerInfoSupplier,
|
||||
Function<WarningItemInfo, T> warningItemInfoSupplier) {
|
||||
if (warningBannerInfoSupplier != null && powerAnomalyEvent.hasWarningBannerInfo()) {
|
||||
return warningBannerInfoSupplier.apply(powerAnomalyEvent.getWarningBannerInfo());
|
||||
} else if (warningItemInfoSupplier != null && powerAnomalyEvent.hasWarningItemInfo()) {
|
||||
return warningItemInfoSupplier.apply(powerAnomalyEvent.getWarningItemInfo());
|
||||
void acceptTipsCard() {
|
||||
if (mAnomalyEventWrapper == null || !mIsAcceptable) {
|
||||
return;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private String getStringFromResource(int resourceId, int resourceIndex) {
|
||||
if (resourceId < 0) {
|
||||
return null;
|
||||
// For anomaly events with same record key, dismissed until next time full charged.
|
||||
final String dismissRecordKey = mAnomalyEventWrapper.getDismissRecordKey();
|
||||
if (!TextUtils.isEmpty(dismissRecordKey)) {
|
||||
DatabaseUtils.setDismissedPowerAnomalyKeys(mContext, dismissRecordKey);
|
||||
}
|
||||
final String[] stringArray = mContext.getResources().getStringArray(resourceId);
|
||||
return (resourceIndex >= 0 && resourceIndex < stringArray.length)
|
||||
? stringArray[resourceIndex] : null;
|
||||
mCardPreference.setVisible(false);
|
||||
mMetricsFeatureProvider.action(
|
||||
mContext, SettingsEnums.ACTION_BATTERY_TIPS_CARD_ACCEPT,
|
||||
mAnomalyEventWrapper.getEventId());
|
||||
}
|
||||
|
||||
private int getResourceId(int resourceId, int resourceIndex, String defType) {
|
||||
final String key = getStringFromResource(resourceId, resourceIndex);
|
||||
return TextUtils.isEmpty(key) ? 0
|
||||
: mContext.getResources().getIdentifier(key, defType, mContext.getPackageName());
|
||||
}
|
||||
|
||||
private String getString(PowerAnomalyEvent powerAnomalyEvent,
|
||||
Function<WarningBannerInfo, String> warningBannerInfoSupplier,
|
||||
Function<WarningItemInfo, String> warningItemInfoSupplier,
|
||||
int resourceId, int resourceIndex) {
|
||||
String string =
|
||||
getInfo(powerAnomalyEvent, warningBannerInfoSupplier, warningItemInfoSupplier);
|
||||
return (!TextUtils.isEmpty(string) || resourceId < 0) ? string
|
||||
: getStringFromResource(resourceId, resourceIndex);
|
||||
}
|
||||
|
||||
/** Generate a key string of current anomaly to record as dismissed in sharedPreferences. */
|
||||
public static String getDismissRecordKey(PowerAnomalyEvent event) {
|
||||
if (!event.hasKey()) {
|
||||
return null;
|
||||
}
|
||||
switch (event.getKey()){
|
||||
case KEY_APP:
|
||||
return event.hasWarningItemInfo()
|
||||
&& event.getWarningItemInfo().hasDismissRecordKey()
|
||||
? event.getWarningItemInfo().getDismissRecordKey() : null;
|
||||
default:
|
||||
return event.getKey().name();
|
||||
}
|
||||
}
|
||||
|
||||
void handleBatteryTipsCardUpdated(PowerAnomalyEvent powerAnomalyEvent) {
|
||||
if (powerAnomalyEvent == null) {
|
||||
void handleBatteryTipsCardUpdated(
|
||||
AnomalyEventWrapper anomalyEventWrapper, boolean isAcceptable) {
|
||||
mAnomalyEventWrapper = anomalyEventWrapper;
|
||||
mIsAcceptable = isAcceptable;
|
||||
if (mAnomalyEventWrapper == null) {
|
||||
mCardPreference.setVisible(false);
|
||||
return;
|
||||
}
|
||||
|
||||
// Get card icon and color styles
|
||||
final int cardStyleId = powerAnomalyEvent.getType().getNumber();
|
||||
final int iconResId = getResourceId(
|
||||
R.array.battery_tips_card_icons, cardStyleId, "drawable");
|
||||
final int colorResId = getResourceId(
|
||||
R.array.battery_tips_card_colors, cardStyleId, "color");
|
||||
|
||||
// Get card preference strings and navigate fragment info
|
||||
final String eventId = powerAnomalyEvent.hasEventId()
|
||||
? powerAnomalyEvent.getEventId() : null;
|
||||
final PowerAnomalyKey powerAnomalyKey = powerAnomalyEvent.hasKey()
|
||||
? powerAnomalyEvent.getKey() : null;
|
||||
final int resourceIndex = powerAnomalyKey != null ? powerAnomalyKey.getNumber() : -1;
|
||||
final String eventId = mAnomalyEventWrapper.getEventId();
|
||||
|
||||
final String titleString = getString(powerAnomalyEvent, WarningBannerInfo::getTitleString,
|
||||
WarningItemInfo::getTitleString, R.array.power_anomaly_titles, resourceIndex);
|
||||
if (titleString.isEmpty()) {
|
||||
// Update card & buttons preference
|
||||
if (!mAnomalyEventWrapper.updateTipsCardPreference(mCardPreference)) {
|
||||
mCardPreference.setVisible(false);
|
||||
return;
|
||||
}
|
||||
|
||||
final String mainBtnString = getString(powerAnomalyEvent,
|
||||
WarningBannerInfo::getMainButtonString, WarningItemInfo::getMainButtonString,
|
||||
R.array.power_anomaly_main_btn_strings, resourceIndex);
|
||||
final String dismissBtnString = getString(powerAnomalyEvent,
|
||||
WarningBannerInfo::getCancelButtonString, WarningItemInfo::getCancelButtonString,
|
||||
R.array.power_anomaly_dismiss_btn_strings, resourceIndex);
|
||||
|
||||
final String destinationClassName = getInfo(powerAnomalyEvent,
|
||||
WarningBannerInfo::getMainButtonDestination, null);
|
||||
final Integer sourceMetricsCategory = getInfo(powerAnomalyEvent,
|
||||
WarningBannerInfo::getMainButtonSourceMetricsCategory, null);
|
||||
final String preferenceHighlightKey = getInfo(powerAnomalyEvent,
|
||||
WarningBannerInfo::getMainButtonSourceHighlightKey, null);
|
||||
|
||||
// Update card preference and main button fragment launcher
|
||||
mCardPreference.setTitle(titleString);
|
||||
mCardPreference.setIconResourceId(iconResId);
|
||||
mCardPreference.setMainButtonStrokeColorResourceId(colorResId);
|
||||
mCardPreference.setMainButtonLabel(mainBtnString);
|
||||
mCardPreference.setDismissButtonLabel(dismissBtnString);
|
||||
|
||||
// Set battery tips card listener
|
||||
mCardPreference.setOnConfirmListener(() -> {
|
||||
mCardPreference.setVisible(false);
|
||||
if (mOnAnomalyConfirmListener != null) {
|
||||
mOnAnomalyConfirmListener.onAnomalyConfirm();
|
||||
} else if (!TextUtils.isEmpty(destinationClassName)) {
|
||||
// Navigate to sub setting page
|
||||
Bundle arguments = Bundle.EMPTY;
|
||||
if (!TextUtils.isEmpty(preferenceHighlightKey)) {
|
||||
arguments = new Bundle(1);
|
||||
arguments.putString(SettingsActivity.EXTRA_FRAGMENT_ARG_KEY,
|
||||
preferenceHighlightKey);
|
||||
}
|
||||
new SubSettingLauncher(mContext)
|
||||
.setDestination(destinationClassName)
|
||||
.setSourceMetricsCategory(sourceMetricsCategory)
|
||||
.setArguments(arguments)
|
||||
.launch();
|
||||
} else if (mAnomalyEventWrapper.launchSubSetting()) {
|
||||
mMetricsFeatureProvider.action(
|
||||
mContext, SettingsEnums.ACTION_BATTERY_TIPS_CARD_ACCEPT, eventId);
|
||||
}
|
||||
mMetricsFeatureProvider.action(
|
||||
mContext, SettingsEnums.ACTION_BATTERY_TIPS_CARD_ACCEPT, eventId);
|
||||
});
|
||||
mCardPreference.setOnRejectListener(() -> {
|
||||
mCardPreference.setVisible(false);
|
||||
if (mOnAnomalyRejectListener != null) {
|
||||
mOnAnomalyRejectListener.onAnomalyReject();
|
||||
}
|
||||
// For anomaly events with same record key, dismissed until next time full charged.
|
||||
final String dismissRecordKey = getDismissRecordKey(powerAnomalyEvent);
|
||||
final String dismissRecordKey = mAnomalyEventWrapper.getDismissRecordKey();
|
||||
if (!TextUtils.isEmpty(dismissRecordKey)) {
|
||||
DatabaseUtils.setDismissedPowerAnomalyKeys(mContext, dismissRecordKey);
|
||||
}
|
||||
|
@@ -53,6 +53,7 @@ import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
|
||||
/** Controller for battery usage breakdown preference group. */
|
||||
@@ -93,6 +94,14 @@ public class BatteryUsageBreakdownController extends BasePreferenceController
|
||||
BatteryDiffData mBatteryDiffData;
|
||||
@VisibleForTesting
|
||||
String mPercentLessThanThresholdText;
|
||||
@VisibleForTesting
|
||||
boolean mIsHighlightSlot;
|
||||
@VisibleForTesting
|
||||
String mAnomalyEventId;
|
||||
@VisibleForTesting
|
||||
String mAnomalyEntryKey;
|
||||
@VisibleForTesting
|
||||
String mAnomalyHintString;
|
||||
|
||||
public BatteryUsageBreakdownController(
|
||||
Context context, Lifecycle lifecycle, SettingsActivity activity,
|
||||
@@ -137,6 +146,12 @@ public class BatteryUsageBreakdownController extends BasePreferenceController
|
||||
return false;
|
||||
}
|
||||
|
||||
private String getActionKey(String packageName) {
|
||||
final String actionKey = TextUtils.isEmpty(packageName)
|
||||
? PACKAGE_NAME_NONE : packageName;
|
||||
return mAnomalyEventId == null ? actionKey : actionKey + "|" + mAnomalyEventId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handlePreferenceTreeClick(Preference preference) {
|
||||
if (!(preference instanceof PowerGaugePreference)) {
|
||||
@@ -151,7 +166,7 @@ public class BatteryUsageBreakdownController extends BasePreferenceController
|
||||
? SettingsEnums.ACTION_BATTERY_USAGE_SYSTEM_ITEM
|
||||
: SettingsEnums.ACTION_BATTERY_USAGE_APP_ITEM,
|
||||
/* pageId */ SettingsEnums.OPEN_BATTERY_USAGE,
|
||||
TextUtils.isEmpty(packageName) ? PACKAGE_NAME_NONE : packageName,
|
||||
getActionKey(packageName),
|
||||
(int) Math.round(diffEntry.getPercentage()));
|
||||
Log.d(TAG, String.format("handleClick() label=%s key=%s package=%s",
|
||||
diffEntry.getAppLabel(), diffEntry.getKey(), packageName));
|
||||
@@ -211,9 +226,23 @@ public class BatteryUsageBreakdownController extends BasePreferenceController
|
||||
* used when showing the footer.
|
||||
*/
|
||||
void handleBatteryUsageUpdated(
|
||||
BatteryDiffData slotUsageData, String slotTimestamp, boolean isAllUsageDataEmpty) {
|
||||
BatteryDiffData slotUsageData, String slotTimestamp,
|
||||
boolean isAllUsageDataEmpty, boolean isHighlightSlot,
|
||||
Optional<AnomalyEventWrapper> optionalAnomalyEventWrapper) {
|
||||
mBatteryDiffData = slotUsageData;
|
||||
mSlotTimestamp = slotTimestamp;
|
||||
mIsHighlightSlot = isHighlightSlot;
|
||||
|
||||
if (optionalAnomalyEventWrapper != null) {
|
||||
final AnomalyEventWrapper anomalyEventWrapper =
|
||||
optionalAnomalyEventWrapper.orElse(null);
|
||||
mAnomalyEventId = anomalyEventWrapper != null
|
||||
? anomalyEventWrapper.getEventId() : null;
|
||||
mAnomalyEntryKey = anomalyEventWrapper != null
|
||||
? anomalyEventWrapper.getAnomalyEntryKey() : null;
|
||||
mAnomalyHintString = anomalyEventWrapper != null
|
||||
? anomalyEventWrapper.getAnomalyHintString() : null;
|
||||
}
|
||||
|
||||
showCategoryTitle(slotTimestamp);
|
||||
showSpinnerAndAppList();
|
||||
@@ -278,15 +307,15 @@ public class BatteryUsageBreakdownController extends BasePreferenceController
|
||||
continue;
|
||||
}
|
||||
final String prefKey = entry.getKey();
|
||||
PowerGaugePreference pref = mAppListPreferenceGroup.findPreference(prefKey);
|
||||
AnomalyAppItemPreference pref = mAppListPreferenceGroup.findPreference(prefKey);
|
||||
if (pref != null) {
|
||||
isAdded = true;
|
||||
} else {
|
||||
pref = (PowerGaugePreference) mPreferenceCache.get(prefKey);
|
||||
pref = (AnomalyAppItemPreference) mPreferenceCache.get(prefKey);
|
||||
}
|
||||
// Creates new innstance if cached preference is not found.
|
||||
// Creates new instance if cached preference is not found.
|
||||
if (pref == null) {
|
||||
pref = new PowerGaugePreference(mPrefContext);
|
||||
pref = new AnomalyAppItemPreference(mPrefContext);
|
||||
pref.setKey(prefKey);
|
||||
mPreferenceCache.put(prefKey, pref);
|
||||
}
|
||||
@@ -294,6 +323,10 @@ public class BatteryUsageBreakdownController extends BasePreferenceController
|
||||
pref.setTitle(appLabel);
|
||||
pref.setOrder(prefIndex);
|
||||
pref.setSingleLineTitle(true);
|
||||
// Updates App item preference style
|
||||
pref.setAnomalyHint(mIsHighlightSlot && mAnomalyEntryKey != null
|
||||
&& mAnomalyEntryKey.equals(entry.getKey())
|
||||
? mAnomalyHintString : null);
|
||||
// Sets the BatteryDiffEntry to preference for launching detailed page.
|
||||
pref.setBatteryDiffEntry(entry);
|
||||
pref.setSelectable(entry.validForRestriction());
|
||||
|
@@ -52,6 +52,7 @@ import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
/** Advanced power usage. */
|
||||
@SearchIndexable(forTarget = SearchIndexable.ALL & ~SearchIndexable.ARC)
|
||||
@@ -92,9 +93,9 @@ public class PowerUsageAdvanced extends PowerUsageBase {
|
||||
@VisibleForTesting
|
||||
BatteryUsageBreakdownController mBatteryUsageBreakdownController;
|
||||
@VisibleForTesting
|
||||
PowerAnomalyEvent mPowerAnomalyEvent;
|
||||
@VisibleForTesting
|
||||
Optional<BatteryLevelData> mBatteryLevelData;
|
||||
@VisibleForTesting
|
||||
Optional<AnomalyEventWrapper> mHighlightEventWrapper;
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle icicle) {
|
||||
@@ -188,7 +189,7 @@ public class PowerUsageAdvanced extends PowerUsageBase {
|
||||
mIsChartDataLoaded = true;
|
||||
mBatteryLevelData = null;
|
||||
mBatteryUsageMap = null;
|
||||
mPowerAnomalyEvent = null;
|
||||
mHighlightEventWrapper = null;
|
||||
restartLoader(LoaderIndex.BATTERY_LEVEL_DATA_LOADER, bundle,
|
||||
mBatteryLevelDataLoaderCallbacks);
|
||||
}
|
||||
@@ -239,8 +240,13 @@ public class PowerUsageAdvanced extends PowerUsageBase {
|
||||
mScreenOnTimeController.handleSceenOnTimeUpdated(
|
||||
slotUsageData.getScreenOnTime(), slotInformation);
|
||||
}
|
||||
// Hide card tips if the related highlight slot was clicked.
|
||||
if (isAppsAnomalyEventFocused()) {
|
||||
mBatteryTipsController.acceptTipsCard();
|
||||
}
|
||||
mBatteryUsageBreakdownController.handleBatteryUsageUpdated(
|
||||
slotUsageData, slotInformation, isBatteryUsageMapNullOrEmpty());
|
||||
slotUsageData, slotInformation, isBatteryUsageMapNullOrEmpty(),
|
||||
isAppsAnomalyEventFocused(), mHighlightEventWrapper);
|
||||
Log.d(TAG, String.format("Battery usage list shows in %d millis",
|
||||
System.currentTimeMillis() - mResumeTimestamp));
|
||||
}
|
||||
@@ -261,49 +267,95 @@ public class PowerUsageAdvanced extends PowerUsageBase {
|
||||
return;
|
||||
}
|
||||
Log.d(TAG, "anomalyEventList = " + anomalyEventList);
|
||||
final PowerAnomalyEvent displayEvent =
|
||||
getHighestScoreAnomalyEvent(getContext(), anomalyEventList);
|
||||
onDisplayAnomalyEventUpdated(displayEvent);
|
||||
|
||||
final Set<String> dismissedPowerAnomalyKeys =
|
||||
DatabaseUtils.getDismissedPowerAnomalyKeys(getContext());
|
||||
Log.d(TAG, "dismissedPowerAnomalyKeys = " + dismissedPowerAnomalyKeys);
|
||||
|
||||
// Choose an app anomaly event with highest score to show highlight slot
|
||||
final PowerAnomalyEvent highlightEvent =
|
||||
getAnomalyEvent(anomalyEventList, PowerAnomalyEvent::hasWarningItemInfo);
|
||||
// Choose an event never dismissed to show as card.
|
||||
// If the slot is already highlighted, the tips card should be the corresponding app
|
||||
// or settings anomaly event.
|
||||
final PowerAnomalyEvent tipsCardEvent =
|
||||
getAnomalyEvent(anomalyEventList,
|
||||
event -> !dismissedPowerAnomalyKeys.contains(event.getDismissRecordKey())
|
||||
&& (event.equals(highlightEvent) || !event.hasWarningItemInfo()));
|
||||
onDisplayAnomalyEventUpdated(tipsCardEvent, highlightEvent);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
void onDisplayAnomalyEventUpdated(PowerAnomalyEvent event) {
|
||||
mPowerAnomalyEvent = event;
|
||||
void onDisplayAnomalyEventUpdated(
|
||||
PowerAnomalyEvent tipsCardEvent, PowerAnomalyEvent highlightEvent) {
|
||||
if (mBatteryTipsController == null
|
||||
|| mBatteryChartPreferenceController == null
|
||||
|| mBatteryUsageBreakdownController == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final boolean isSameAnomalyEvent = (tipsCardEvent == highlightEvent);
|
||||
// Update battery tips card preference & behaviour
|
||||
mBatteryTipsController.setOnAnomalyConfirmListener(null);
|
||||
mBatteryTipsController.setOnAnomalyRejectListener(null);
|
||||
mBatteryTipsController.handleBatteryTipsCardUpdated(mPowerAnomalyEvent);
|
||||
final AnomalyEventWrapper tipsCardEventWrapper = (tipsCardEvent == null) ? null :
|
||||
new AnomalyEventWrapper(getContext(), tipsCardEvent);
|
||||
if (tipsCardEventWrapper != null) {
|
||||
tipsCardEventWrapper.setRelatedBatteryDiffEntry(
|
||||
findRelatedBatteryDiffEntry(tipsCardEventWrapper));
|
||||
}
|
||||
mBatteryTipsController.handleBatteryTipsCardUpdated(
|
||||
tipsCardEventWrapper, isSameAnomalyEvent);
|
||||
|
||||
// Update highlight slot effect in battery chart view
|
||||
Pair<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));
|
||||
mHighlightEventWrapper = Optional.ofNullable(isSameAnomalyEvent ? tipsCardEventWrapper :
|
||||
((highlightEvent != null)
|
||||
? new AnomalyEventWrapper(getContext(), highlightEvent) : null));
|
||||
if (mBatteryLevelData != null && mBatteryLevelData.isPresent()
|
||||
&& mHighlightEventWrapper.isPresent()
|
||||
&& mHighlightEventWrapper.get().hasHighlightSlotPair(mBatteryLevelData.get())) {
|
||||
highlightSlotIndexPair = mHighlightEventWrapper.get()
|
||||
.getHighlightSlotPair(mBatteryLevelData.get());
|
||||
if (isSameAnomalyEvent) {
|
||||
// For main button, focus on highlight slot when clicked
|
||||
mBatteryTipsController.setOnAnomalyConfirmListener(() -> {
|
||||
mBatteryChartPreferenceController.selectHighlightSlotIndex();
|
||||
mBatteryTipsController.acceptTipsCard();
|
||||
});
|
||||
}
|
||||
}
|
||||
mBatteryChartPreferenceController.onHighlightSlotIndexUpdate(
|
||||
highlightSlotIndexPair.first, highlightSlotIndexPair.second);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
BatteryDiffEntry findRelatedBatteryDiffEntry(AnomalyEventWrapper eventWrapper) {
|
||||
if (eventWrapper == null
|
||||
|| mBatteryLevelData == null || mBatteryLevelData.isEmpty()
|
||||
|| !eventWrapper.hasHighlightSlotPair(mBatteryLevelData.get())
|
||||
|| !eventWrapper.hasAnomalyEntryKey()
|
||||
|| mBatteryUsageMap == null) {
|
||||
return null;
|
||||
}
|
||||
final Pair<Integer, Integer> highlightSlotIndexPair =
|
||||
eventWrapper.getHighlightSlotPair(mBatteryLevelData.get());
|
||||
final BatteryDiffData relatedDiffData = mBatteryUsageMap
|
||||
.get(highlightSlotIndexPair.first).get(highlightSlotIndexPair.second);
|
||||
final String anomalyEntryKey = eventWrapper.getAnomalyEntryKey();
|
||||
if (relatedDiffData == null || anomalyEntryKey == null) {
|
||||
return null;
|
||||
}
|
||||
for (BatteryDiffEntry entry : relatedDiffData.getAppDiffEntryList()) {
|
||||
if (anomalyEntryKey.equals(entry.getKey())) {
|
||||
return entry;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private void setBatteryChartPreferenceController() {
|
||||
if (mHistPref != null && mBatteryChartPreferenceController != null) {
|
||||
mHistPref.setChartPreferenceController(mBatteryChartPreferenceController);
|
||||
@@ -318,6 +370,11 @@ public class PowerUsageAdvanced extends PowerUsageBase {
|
||||
&& allBatteryDiffData.getSystemDiffEntryList().isEmpty());
|
||||
}
|
||||
|
||||
private boolean isAppsAnomalyEventFocused() {
|
||||
return mBatteryChartPreferenceController != null
|
||||
&& mBatteryChartPreferenceController.isHighlightSlotFocused();
|
||||
}
|
||||
|
||||
private void logScreenUsageTime() {
|
||||
final BatteryDiffData allBatteryDiffData = getAllBatteryDiffData(mBatteryUsageMap);
|
||||
if (allBatteryDiffData == null) {
|
||||
@@ -338,25 +395,22 @@ public class PowerUsageAdvanced extends PowerUsageBase {
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
static PowerAnomalyEvent getHighestScoreAnomalyEvent(
|
||||
Context context, PowerAnomalyEventList anomalyEventList) {
|
||||
static PowerAnomalyEvent getAnomalyEvent(
|
||||
PowerAnomalyEventList anomalyEventList, Predicate<PowerAnomalyEvent> predicate) {
|
||||
if (anomalyEventList == null || anomalyEventList.getPowerAnomalyEventsCount() == 0) {
|
||||
return null;
|
||||
}
|
||||
final Set<String> dismissedPowerAnomalyKeys =
|
||||
DatabaseUtils.getDismissedPowerAnomalyKeys(context);
|
||||
Log.d(TAG, "dismissedPowerAnomalyKeys = " + dismissedPowerAnomalyKeys);
|
||||
|
||||
final PowerAnomalyEvent highestScoreEvent = anomalyEventList.getPowerAnomalyEventsList()
|
||||
final PowerAnomalyEvent filterAnomalyEvent = anomalyEventList.getPowerAnomalyEventsList()
|
||||
.stream()
|
||||
.filter(event -> !dismissedPowerAnomalyKeys.contains(
|
||||
BatteryTipsController.getDismissRecordKey(event)))
|
||||
.filter(predicate)
|
||||
.max(Comparator.comparing(PowerAnomalyEvent::getScore))
|
||||
.orElse(null);
|
||||
Log.d(TAG, "highestScoreAnomalyEvent = " + highestScoreEvent);
|
||||
return highestScoreEvent;
|
||||
Log.d(TAG, "filterAnomalyEvent = " + filterAnomalyEvent);
|
||||
return filterAnomalyEvent;
|
||||
}
|
||||
|
||||
|
||||
private static BatteryDiffData getAllBatteryDiffData(
|
||||
Map<Integer, Map<Integer, BatteryDiffData>> batteryUsageMap) {
|
||||
return batteryUsageMap == null ? null : batteryUsageMap
|
||||
|
@@ -18,6 +18,7 @@ message PowerAnomalyEvent {
|
||||
WarningBannerInfo warning_banner_info = 6;
|
||||
WarningItemInfo warning_item_info = 7;
|
||||
}
|
||||
optional string dismiss_record_key = 8;
|
||||
}
|
||||
|
||||
// NOTE: Please DO NOT delete enum items or change enum values. Use [deprecated = true] instead.
|
||||
@@ -32,11 +33,16 @@ enum PowerAnomalyType{
|
||||
// NOTE: Please DO NOT delete enum items or change enum values. Use [deprecated = true] instead.
|
||||
// The enum value will be used to decide pre-defined title and button labels.
|
||||
//
|
||||
// Next id: 3
|
||||
// Next id: 8
|
||||
enum PowerAnomalyKey{
|
||||
KEY_BRIGHTNESS = 0;
|
||||
KEY_SCREEN_TIMEOUT = 1;
|
||||
KEY_APP = 2;
|
||||
KEY_APP_TOTAL_ALWAYS_HIGH = 2;
|
||||
KEY_APP_TOTAL_HIGHER_THAN_USUAL = 3;
|
||||
KEY_APP_BACKGROUND_ALWAYS_HIGH = 4;
|
||||
KEY_APP_BACKGROUND_HIGHER_THAN_USUAL = 5;
|
||||
KEY_APP_FOREGROUND_ALWAYS_HIGH = 6;
|
||||
KEY_APP_FOREGROUND_HIGHER_THAN_USUAL = 7;
|
||||
}
|
||||
|
||||
message WarningBannerInfo {
|
||||
@@ -60,6 +66,5 @@ message WarningItemInfo {
|
||||
optional string description_string = 5;
|
||||
optional string main_button_string = 6;
|
||||
optional string cancel_button_string = 7;
|
||||
optional string dismiss_record_key = 8;
|
||||
optional string item_key = 9;
|
||||
optional string item_key = 8;
|
||||
}
|
||||
|
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright (C) 2023 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.settings.fuelgauge.batteryusage;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.Mockito.spy;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import com.android.settings.testutils.BatteryTestUtils;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.robolectric.RobolectricTestRunner;
|
||||
import org.robolectric.RuntimeEnvironment;
|
||||
|
||||
import java.util.TimeZone;
|
||||
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
public class AnomalyEventWrapperTest {
|
||||
private AnomalyEventWrapper mAnomalyEventWrapper;
|
||||
private Context mContext;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
TimeZone.setDefault(TimeZone.getTimeZone("GMT+8"));
|
||||
mContext = spy(RuntimeEnvironment.application);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getDismissRecordKey_returnExpectedResult() {
|
||||
mAnomalyEventWrapper = new AnomalyEventWrapper(mContext,
|
||||
BatteryTestUtils.createAdaptiveBrightnessAnomalyEvent());
|
||||
assertThat(mAnomalyEventWrapper.getDismissRecordKey())
|
||||
.isEqualTo("KEY_BRIGHTNESS");
|
||||
|
||||
mAnomalyEventWrapper = new AnomalyEventWrapper(mContext,
|
||||
BatteryTestUtils.createScreenTimeoutAnomalyEvent());
|
||||
assertThat(mAnomalyEventWrapper.getDismissRecordKey())
|
||||
.isEqualTo("KEY_SCREEN_TIMEOUT");
|
||||
|
||||
mAnomalyEventWrapper = new AnomalyEventWrapper(mContext,
|
||||
BatteryTestUtils.createAppAnomalyEvent());
|
||||
assertThat(mAnomalyEventWrapper.getDismissRecordKey())
|
||||
.isEqualTo("KEY_APP_1");
|
||||
}
|
||||
}
|
@@ -21,6 +21,7 @@ import static com.google.common.truth.Truth.assertThat;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.doNothing;
|
||||
import static org.mockito.Mockito.doReturn;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.verify;
|
||||
@@ -58,13 +59,14 @@ public final class BatteryTipsCardPreferenceTest {
|
||||
private BatteryTipsCardPreference mBatteryTipsCardPreference;
|
||||
private PowerUsageAdvanced mPowerUsageAdvanced;
|
||||
private BatteryTipsController mBatteryTipsController;
|
||||
private BatteryChartPreferenceController mBatteryChartPreferenceController;
|
||||
|
||||
@Mock
|
||||
private View mFakeView;
|
||||
@Mock
|
||||
private BatteryChartPreferenceController mBatteryChartPreferenceController;
|
||||
@Mock
|
||||
private BatteryUsageBreakdownController mBatteryUsageBreakdownController;
|
||||
@Mock
|
||||
private BatteryDiffEntry mFakeEntry;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
@@ -73,8 +75,13 @@ public final class BatteryTipsCardPreferenceTest {
|
||||
mFeatureFactory = FakeFeatureFactory.setupForTest();
|
||||
mBatteryTipsCardPreference = new BatteryTipsCardPreference(mContext, /*attrs=*/ null);
|
||||
mBatteryTipsController = new BatteryTipsController(mContext);
|
||||
mBatteryChartPreferenceController =
|
||||
spy(new BatteryChartPreferenceController(mContext, null, null));
|
||||
mBatteryChartPreferenceController.mPrefContext = mContext;
|
||||
mBatteryTipsController.mCardPreference = mBatteryTipsCardPreference;
|
||||
mPowerUsageAdvanced = new PowerUsageAdvanced();
|
||||
|
||||
mPowerUsageAdvanced = spy(new PowerUsageAdvanced());
|
||||
doReturn(mContext).when(mPowerUsageAdvanced).getContext();
|
||||
mPowerUsageAdvanced.mBatteryTipsController = mBatteryTipsController;
|
||||
mPowerUsageAdvanced.mBatteryChartPreferenceController = mBatteryChartPreferenceController;
|
||||
mPowerUsageAdvanced.mBatteryUsageBreakdownController = mBatteryUsageBreakdownController;
|
||||
@@ -82,6 +89,7 @@ public final class BatteryTipsCardPreferenceTest {
|
||||
1694354400000L, 1, // 2023-09-10 22:00:00
|
||||
1694361600000L, 2, // 2023-09-11 00:00:00
|
||||
1694368800000L, 3))); // 2023-09-11 02:00:00
|
||||
doReturn("TestEntriesKey").when(mFakeEntry).getKey();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -99,7 +107,8 @@ public final class BatteryTipsCardPreferenceTest {
|
||||
when(mFakeView.getId()).thenReturn(R.id.main_button);
|
||||
doNothing().when(mContext).startActivity(captor.capture());
|
||||
|
||||
mPowerUsageAdvanced.onDisplayAnomalyEventUpdated(adaptiveBrightnessAnomaly);
|
||||
mPowerUsageAdvanced.onDisplayAnomalyEventUpdated(
|
||||
adaptiveBrightnessAnomaly, adaptiveBrightnessAnomaly);
|
||||
mBatteryTipsCardPreference.onClick(mFakeView);
|
||||
|
||||
assertThat(mBatteryTipsCardPreference.isVisible()).isFalse();
|
||||
@@ -109,25 +118,30 @@ public final class BatteryTipsCardPreferenceTest {
|
||||
.isEqualTo(DisplaySettings.class.getName());
|
||||
assertThat(intent.getIntExtra(MetricsFeatureProvider.EXTRA_SOURCE_METRICS_CATEGORY, -1))
|
||||
.isEqualTo(SettingsEnums.DISPLAY);
|
||||
verify(mFeatureFactory.metricsFeatureProvider).action(
|
||||
mContext, SettingsEnums.ACTION_BATTERY_TIPS_CARD_SHOW, "BrightnessAnomaly");
|
||||
verify(mFeatureFactory.metricsFeatureProvider).action(
|
||||
mContext, SettingsEnums.ACTION_BATTERY_TIPS_CARD_ACCEPT, "BrightnessAnomaly");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onClick_dismissBtn_cardDismissAndLogged() {
|
||||
public void onClick_dismissBtnOfSettingsAnomaly_cardDismissAndLogged() {
|
||||
final PowerAnomalyEvent screenTimeoutAnomaly =
|
||||
BatteryTestUtils.createScreenTimeoutAnomalyEvent();
|
||||
DatabaseUtils.removeDismissedPowerAnomalyKeys(mContext);
|
||||
when(mFeatureFactory.powerUsageFeatureProvider.isBatteryTipsEnabled()).thenReturn(true);
|
||||
when(mFakeView.getId()).thenReturn(R.id.dismiss_button);
|
||||
|
||||
mPowerUsageAdvanced.onDisplayAnomalyEventUpdated(screenTimeoutAnomaly);
|
||||
mPowerUsageAdvanced.onDisplayAnomalyEventUpdated(
|
||||
screenTimeoutAnomaly, screenTimeoutAnomaly);
|
||||
mBatteryTipsCardPreference.onClick(mFakeView);
|
||||
|
||||
assertThat(mBatteryTipsCardPreference.isVisible()).isFalse();
|
||||
assertThat(DatabaseUtils.getDismissedPowerAnomalyKeys(mContext)).hasSize(1);
|
||||
assertThat(DatabaseUtils.getDismissedPowerAnomalyKeys(mContext))
|
||||
.contains(PowerAnomalyKey.KEY_SCREEN_TIMEOUT.name());
|
||||
verify(mFeatureFactory.metricsFeatureProvider).action(
|
||||
mContext, SettingsEnums.ACTION_BATTERY_TIPS_CARD_SHOW, "ScreenTimeoutAnomaly");
|
||||
verify(mFeatureFactory.metricsFeatureProvider).action(
|
||||
mContext, SettingsEnums.ACTION_BATTERY_TIPS_CARD_DISMISS, "ScreenTimeoutAnomaly");
|
||||
}
|
||||
@@ -137,30 +151,40 @@ public final class BatteryTipsCardPreferenceTest {
|
||||
final PowerAnomalyEvent appsAnomaly = BatteryTestUtils.createAppAnomalyEvent();
|
||||
when(mFeatureFactory.powerUsageFeatureProvider.isBatteryTipsEnabled()).thenReturn(true);
|
||||
when(mFakeView.getId()).thenReturn(R.id.main_button);
|
||||
doNothing().when(mBatteryChartPreferenceController).selectHighlightSlotIndex();
|
||||
when(mPowerUsageAdvanced.findRelatedBatteryDiffEntry(any())).thenReturn(mFakeEntry);
|
||||
|
||||
mPowerUsageAdvanced.onDisplayAnomalyEventUpdated(appsAnomaly);
|
||||
mPowerUsageAdvanced.onDisplayAnomalyEventUpdated(appsAnomaly, appsAnomaly);
|
||||
mBatteryTipsCardPreference.onClick(mFakeView);
|
||||
|
||||
assertThat(mBatteryTipsCardPreference.isVisible()).isFalse();
|
||||
verify(mContext, never()).startActivity(any(Intent.class));
|
||||
verify(mBatteryChartPreferenceController).onHighlightSlotIndexUpdate(
|
||||
eq(1), eq(0));
|
||||
verify(mBatteryChartPreferenceController).selectHighlightSlotIndex();
|
||||
verify(mFeatureFactory.metricsFeatureProvider).action(
|
||||
mContext, SettingsEnums.ACTION_BATTERY_TIPS_CARD_SHOW, "AppAnomaly");
|
||||
verify(mFeatureFactory.metricsFeatureProvider).action(
|
||||
mContext, SettingsEnums.ACTION_BATTERY_TIPS_CARD_ACCEPT, "AppAnomaly");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onClick_dismissBtnOfAppsAnomaly_removeHighlightSlotIndex() {
|
||||
public void onClick_dismissBtnOfAppsAnomaly_keepHighlightSlotIndex() {
|
||||
final PowerAnomalyEvent appsAnomaly = BatteryTestUtils.createAppAnomalyEvent();
|
||||
when(mFeatureFactory.powerUsageFeatureProvider.isBatteryTipsEnabled()).thenReturn(true);
|
||||
when(mFakeView.getId()).thenReturn(R.id.dismiss_button);
|
||||
when(mPowerUsageAdvanced.findRelatedBatteryDiffEntry(any())).thenReturn(mFakeEntry);
|
||||
|
||||
mPowerUsageAdvanced.onDisplayAnomalyEventUpdated(appsAnomaly);
|
||||
mPowerUsageAdvanced.onDisplayAnomalyEventUpdated(appsAnomaly, appsAnomaly);
|
||||
mBatteryTipsCardPreference.onClick(mFakeView);
|
||||
|
||||
assertThat(mBatteryTipsCardPreference.isVisible()).isFalse();
|
||||
verify(mContext, never()).startActivity(any(Intent.class));
|
||||
verify(mBatteryChartPreferenceController).onHighlightSlotIndexUpdate(
|
||||
eq(BatteryChartViewModel.SELECTED_INDEX_INVALID),
|
||||
eq(BatteryChartViewModel.SELECTED_INDEX_INVALID));
|
||||
eq(1), eq(0));
|
||||
verify(mBatteryChartPreferenceController, never()).selectHighlightSlotIndex();
|
||||
verify(mFeatureFactory.metricsFeatureProvider).action(
|
||||
mContext, SettingsEnums.ACTION_BATTERY_TIPS_CARD_SHOW, "AppAnomaly");
|
||||
verify(mFeatureFactory.metricsFeatureProvider).action(
|
||||
mContext, SettingsEnums.ACTION_BATTERY_TIPS_CARD_DISMISS, "AppAnomaly");
|
||||
}
|
||||
|
@@ -16,8 +16,6 @@
|
||||
|
||||
package com.android.settings.fuelgauge.batteryusage;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.Mockito.doReturn;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.verify;
|
||||
@@ -70,30 +68,18 @@ public final class BatteryTipsControllerTest {
|
||||
|
||||
@Test
|
||||
public void handleBatteryTipsCardUpdated_null_hidePreference() {
|
||||
mBatteryTipsController.handleBatteryTipsCardUpdated(/* powerAnomalyEvents= */ null);
|
||||
mBatteryTipsController.handleBatteryTipsCardUpdated(/* powerAnomalyEvents= */ null, false);
|
||||
|
||||
verify(mBatteryTipsCardPreference).setVisible(false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getDismissRecordKey_returnExpectedResult() {
|
||||
assertThat(BatteryTipsController.getDismissRecordKey(
|
||||
BatteryTestUtils.createAdaptiveBrightnessAnomalyEvent()))
|
||||
.isEqualTo("KEY_BRIGHTNESS");
|
||||
assertThat(BatteryTipsController.getDismissRecordKey(
|
||||
BatteryTestUtils.createScreenTimeoutAnomalyEvent()))
|
||||
.isEqualTo("KEY_SCREEN_TIMEOUT");
|
||||
assertThat(BatteryTipsController.getDismissRecordKey(
|
||||
BatteryTestUtils.createAppAnomalyEvent()))
|
||||
.isEqualTo("KEY_APP_1");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void handleBatteryTipsCardUpdated_adaptiveBrightnessAnomaly_showAnomaly() {
|
||||
PowerAnomalyEvent event = BatteryTestUtils.createAdaptiveBrightnessAnomalyEvent();
|
||||
when(mFeatureFactory.powerUsageFeatureProvider.isBatteryTipsEnabled()).thenReturn(true);
|
||||
|
||||
mBatteryTipsController.handleBatteryTipsCardUpdated(event);
|
||||
mBatteryTipsController.handleBatteryTipsCardUpdated(
|
||||
new AnomalyEventWrapper(mContext, event), false);
|
||||
|
||||
// Check pre-defined string
|
||||
verify(mBatteryTipsCardPreference).setTitle(
|
||||
@@ -114,7 +100,8 @@ public final class BatteryTipsControllerTest {
|
||||
PowerAnomalyEvent event = BatteryTestUtils.createScreenTimeoutAnomalyEvent();
|
||||
when(mFeatureFactory.powerUsageFeatureProvider.isBatteryTipsEnabled()).thenReturn(true);
|
||||
|
||||
mBatteryTipsController.handleBatteryTipsCardUpdated(event);
|
||||
mBatteryTipsController.handleBatteryTipsCardUpdated(
|
||||
new AnomalyEventWrapper(mContext, event), false);
|
||||
|
||||
verify(mBatteryTipsCardPreference).setTitle("Reduce screen timeout to extend battery life");
|
||||
verify(mBatteryTipsCardPreference).setIconResourceId(R.drawable.ic_battery_tips_lightbulb);
|
||||
@@ -139,7 +126,8 @@ public final class BatteryTipsControllerTest {
|
||||
.build();
|
||||
when(mFeatureFactory.powerUsageFeatureProvider.isBatteryTipsEnabled()).thenReturn(true);
|
||||
|
||||
mBatteryTipsController.handleBatteryTipsCardUpdated(event);
|
||||
mBatteryTipsController.handleBatteryTipsCardUpdated(
|
||||
new AnomalyEventWrapper(mContext, event), false);
|
||||
|
||||
verify(mBatteryTipsCardPreference).setTitle(testTitle);
|
||||
verify(mBatteryTipsCardPreference).setIconResourceId(R.drawable.ic_battery_tips_lightbulb);
|
||||
@@ -157,10 +145,13 @@ public final class BatteryTipsControllerTest {
|
||||
PowerAnomalyEvent event = BatteryTestUtils.createAppAnomalyEvent();
|
||||
when(mFeatureFactory.powerUsageFeatureProvider.isBatteryTipsEnabled()).thenReturn(true);
|
||||
|
||||
mBatteryTipsController.handleBatteryTipsCardUpdated(event);
|
||||
AnomalyEventWrapper eventWrapper = new AnomalyEventWrapper(mContext, event);
|
||||
eventWrapper.setRelatedBatteryDiffEntry(
|
||||
new BatteryDiffEntry(mContext, "", "Chrome", 0));
|
||||
mBatteryTipsController.handleBatteryTipsCardUpdated(eventWrapper, false);
|
||||
|
||||
verify(mBatteryTipsCardPreference).setTitle(
|
||||
"Chrome used more battery than usual in foreground");
|
||||
"Chrome used more battery than usual");
|
||||
verify(mBatteryTipsCardPreference).setIconResourceId(
|
||||
R.drawable.ic_battery_tips_warning_icon);
|
||||
verify(mBatteryTipsCardPreference).setMainButtonStrokeColorResourceId(
|
||||
|
@@ -69,7 +69,7 @@ public final class BatteryUsageBreakdownControllerTest {
|
||||
@Mock
|
||||
private BatteryHistEntry mBatteryHistEntry;
|
||||
@Mock
|
||||
private PowerGaugePreference mPowerGaugePreference;
|
||||
private AnomalyAppItemPreference mAnomalyAppItemPreference;
|
||||
|
||||
private Context mContext;
|
||||
private FakeFeatureFactory mFeatureFactory;
|
||||
@@ -123,13 +123,14 @@ public final class BatteryUsageBreakdownControllerTest {
|
||||
BatteryDiffEntry.sResourceCache.put(
|
||||
"fakeBatteryDiffEntryKey",
|
||||
new BatteryEntry.NameAndIcon("fakeName", /*icon=*/ null, /*iconId=*/ 1));
|
||||
doReturn(mAnomalyAppItemPreference).when(mAppListPreferenceGroup).findPreference(PREF_KEY);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onDestroy_clearPreferenceCacheAndPreferenceGroupRemoveAll() {
|
||||
// Ensures the testing environment is correct.
|
||||
mBatteryUsageBreakdownController.mPreferenceCache.put(
|
||||
PREF_KEY, mPowerGaugePreference);
|
||||
PREF_KEY, mAnomalyAppItemPreference);
|
||||
assertThat(mBatteryUsageBreakdownController.mPreferenceCache).hasSize(1);
|
||||
|
||||
mBatteryUsageBreakdownController.onDestroy();
|
||||
@@ -178,7 +179,6 @@ public final class BatteryUsageBreakdownControllerTest {
|
||||
doReturn(mDrawable).when(mBatteryDiffEntry).getAppIcon();
|
||||
doReturn(appLabel).when(mBatteryDiffEntry).getAppLabel();
|
||||
doReturn(PREF_KEY).when(mBatteryDiffEntry).getKey();
|
||||
doReturn(mPowerGaugePreference).when(mAppListPreferenceGroup).findPreference(PREF_KEY);
|
||||
|
||||
mBatteryUsageBreakdownController.addAllPreferences();
|
||||
|
||||
@@ -188,27 +188,25 @@ public final class BatteryUsageBreakdownControllerTest {
|
||||
@Test
|
||||
public void removeAndCacheAllUnusedPreferences_removePref_buildCacheAndRemoveAllPreference() {
|
||||
doReturn(1).when(mAppListPreferenceGroup).getPreferenceCount();
|
||||
doReturn(mPowerGaugePreference).when(mAppListPreferenceGroup).getPreference(0);
|
||||
doReturn(mAnomalyAppItemPreference).when(mAppListPreferenceGroup).getPreference(0);
|
||||
doReturn(PREF_KEY2).when(mBatteryHistEntry).getKey();
|
||||
doReturn(PREF_KEY).when(mPowerGaugePreference).getKey();
|
||||
doReturn(mPowerGaugePreference).when(mAppListPreferenceGroup).findPreference(PREF_KEY);
|
||||
doReturn(PREF_KEY).when(mAnomalyAppItemPreference).getKey();
|
||||
// Ensures the testing data is correct.
|
||||
assertThat(mBatteryUsageBreakdownController.mPreferenceCache).isEmpty();
|
||||
|
||||
mBatteryUsageBreakdownController.removeAndCacheAllUnusedPreferences();
|
||||
|
||||
assertThat(mBatteryUsageBreakdownController.mPreferenceCache.get(PREF_KEY))
|
||||
.isEqualTo(mPowerGaugePreference);
|
||||
verify(mAppListPreferenceGroup).removePreference(mPowerGaugePreference);
|
||||
.isEqualTo(mAnomalyAppItemPreference);
|
||||
verify(mAppListPreferenceGroup).removePreference(mAnomalyAppItemPreference);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void removeAndCacheAllUnusedPreferences_keepPref_KeepAllPreference() {
|
||||
doReturn(1).when(mAppListPreferenceGroup).getPreferenceCount();
|
||||
doReturn(mPowerGaugePreference).when(mAppListPreferenceGroup).getPreference(0);
|
||||
doReturn(mAnomalyAppItemPreference).when(mAppListPreferenceGroup).getPreference(0);
|
||||
doReturn(PREF_KEY).when(mBatteryDiffEntry).getKey();
|
||||
doReturn(PREF_KEY).when(mPowerGaugePreference).getKey();
|
||||
doReturn(mPowerGaugePreference).when(mAppListPreferenceGroup).findPreference(PREF_KEY);
|
||||
doReturn(PREF_KEY).when(mAnomalyAppItemPreference).getKey();
|
||||
// Ensures the testing data is correct.
|
||||
assertThat(mBatteryUsageBreakdownController.mPreferenceCache).isEmpty();
|
||||
|
||||
@@ -232,10 +230,10 @@ public final class BatteryUsageBreakdownControllerTest {
|
||||
@Test
|
||||
public void handlePreferenceTreeClick_forAppEntry_returnTrue() {
|
||||
mBatteryDiffEntry.mConsumerType = ConvertUtils.CONSUMER_TYPE_SYSTEM_BATTERY;
|
||||
doReturn(mBatteryDiffEntry).when(mPowerGaugePreference).getBatteryDiffEntry();
|
||||
doReturn(mBatteryDiffEntry).when(mAnomalyAppItemPreference).getBatteryDiffEntry();
|
||||
|
||||
assertThat(mBatteryUsageBreakdownController.handlePreferenceTreeClick(
|
||||
mPowerGaugePreference)).isTrue();
|
||||
mAnomalyAppItemPreference)).isTrue();
|
||||
verify(mMetricsFeatureProvider)
|
||||
.action(
|
||||
SettingsEnums.OPEN_BATTERY_USAGE,
|
||||
@@ -248,10 +246,10 @@ public final class BatteryUsageBreakdownControllerTest {
|
||||
@Test
|
||||
public void handlePreferenceTreeClick_forSystemEntry_returnTrue() {
|
||||
mBatteryDiffEntry.mConsumerType = ConvertUtils.CONSUMER_TYPE_UID_BATTERY;
|
||||
doReturn(mBatteryDiffEntry).when(mPowerGaugePreference).getBatteryDiffEntry();
|
||||
doReturn(mBatteryDiffEntry).when(mAnomalyAppItemPreference).getBatteryDiffEntry();
|
||||
|
||||
assertThat(mBatteryUsageBreakdownController.handlePreferenceTreeClick(
|
||||
mPowerGaugePreference)).isTrue();
|
||||
mAnomalyAppItemPreference)).isTrue();
|
||||
verify(mMetricsFeatureProvider)
|
||||
.action(
|
||||
SettingsEnums.OPEN_BATTERY_USAGE,
|
||||
|
@@ -72,6 +72,7 @@ public final class ConvertUtilsTest {
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
|
||||
mContext = spy(RuntimeEnvironment.application);
|
||||
ConvertUtils.sUsageSource = ConvertUtils.EMPTY_USAGE_SOURCE;
|
||||
when(mContext.getPackageManager()).thenReturn(mMockPackageManager);
|
||||
|
@@ -20,8 +20,8 @@ import static com.google.common.truth.Truth.assertThat;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.ArgumentMatchers.isNull;
|
||||
import static org.mockito.ArgumentMatchers.notNull;
|
||||
import static org.mockito.Mockito.doReturn;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
import android.content.Context;
|
||||
@@ -41,7 +41,9 @@ import org.robolectric.annotation.Config;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.TimeZone;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
@Config(shadows = ShadowDashboardFragment.class)
|
||||
@@ -50,6 +52,9 @@ public final class PowerUsageAdvancedTest {
|
||||
private Context mContext;
|
||||
private PowerUsageAdvanced mPowerUsageAdvanced;
|
||||
|
||||
private Predicate<PowerAnomalyEvent> mCardFilterPredicate;
|
||||
private Predicate<PowerAnomalyEvent> mSlotFilterPredicate;
|
||||
|
||||
@Mock
|
||||
private BatteryTipsController mBatteryTipsController;
|
||||
@Mock
|
||||
@@ -65,7 +70,7 @@ public final class PowerUsageAdvancedTest {
|
||||
TimeZone.setDefault(TimeZone.getTimeZone("GMT+8"));
|
||||
mContext = spy(RuntimeEnvironment.application);
|
||||
|
||||
mPowerUsageAdvanced = new PowerUsageAdvanced();
|
||||
mPowerUsageAdvanced = spy(new PowerUsageAdvanced());
|
||||
mPowerUsageAdvanced.mBatteryTipsController = mBatteryTipsController;
|
||||
mPowerUsageAdvanced.mBatteryChartPreferenceController = mBatteryChartPreferenceController;
|
||||
mPowerUsageAdvanced.mScreenOnTimeController = mScreenOnTimeController;
|
||||
@@ -74,43 +79,63 @@ public final class PowerUsageAdvancedTest {
|
||||
1694354400000L, 1, // 2023-09-10 22:00:00
|
||||
1694361600000L, 2, // 2023-09-11 00:00:00
|
||||
1694368800000L, 3))); // 2023-09-11 02:00:00
|
||||
doReturn(mContext).when(mPowerUsageAdvanced).getContext();
|
||||
mSlotFilterPredicate = PowerAnomalyEvent::hasWarningItemInfo;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getHighestScoreAnomalyEvent_withEmptyOrNullList_getNull() {
|
||||
assertThat(PowerUsageAdvanced.getHighestScoreAnomalyEvent(mContext, null)).isNull();
|
||||
assertThat(PowerUsageAdvanced.getHighestScoreAnomalyEvent(
|
||||
mContext, BatteryTestUtils.createEmptyPowerAnomalyEventList())).isNull();
|
||||
public void getFilterAnomalyEvent_withEmptyOrNullList_getNull() {
|
||||
prepareCardFilterPredicate(null);
|
||||
assertThat(PowerUsageAdvanced
|
||||
.getAnomalyEvent(null, mCardFilterPredicate)).isNull();
|
||||
assertThat(PowerUsageAdvanced
|
||||
.getAnomalyEvent(null, mSlotFilterPredicate)).isNull();
|
||||
assertThat(PowerUsageAdvanced.getAnomalyEvent(
|
||||
BatteryTestUtils.createEmptyPowerAnomalyEventList(), mCardFilterPredicate))
|
||||
.isNull();
|
||||
assertThat(PowerUsageAdvanced.getAnomalyEvent(
|
||||
BatteryTestUtils.createEmptyPowerAnomalyEventList(), mSlotFilterPredicate))
|
||||
.isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getHighestScoreAnomalyEvent_withoutDismissed_getHighestScoreEvent() {
|
||||
public void getFilterAnomalyEvent_withoutDismissed_getHighestScoreEvent() {
|
||||
final PowerAnomalyEventList powerAnomalyEventList =
|
||||
BatteryTestUtils.createNonEmptyPowerAnomalyEventList();
|
||||
|
||||
final PowerAnomalyEvent highestScoreEvent =
|
||||
PowerUsageAdvanced.getHighestScoreAnomalyEvent(mContext, powerAnomalyEventList);
|
||||
final PowerAnomalyEvent slotEvent =
|
||||
PowerUsageAdvanced.getAnomalyEvent(powerAnomalyEventList,
|
||||
mSlotFilterPredicate);
|
||||
prepareCardFilterPredicate(slotEvent);
|
||||
final PowerAnomalyEvent cardEvent =
|
||||
PowerUsageAdvanced.getAnomalyEvent(powerAnomalyEventList,
|
||||
mCardFilterPredicate);
|
||||
|
||||
assertThat(highestScoreEvent)
|
||||
.isEqualTo(BatteryTestUtils.createAdaptiveBrightnessAnomalyEvent());
|
||||
assertThat(cardEvent).isEqualTo(BatteryTestUtils.createAdaptiveBrightnessAnomalyEvent());
|
||||
assertThat(slotEvent).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getHighestScoreAnomalyEvent_withBrightnessDismissed_getScreenTimeout() {
|
||||
public void getFilterAnomalyEvent_withBrightnessDismissed_getScreenTimeout() {
|
||||
final PowerAnomalyEventList powerAnomalyEventList =
|
||||
BatteryTestUtils.createNonEmptyPowerAnomalyEventList();
|
||||
DatabaseUtils.removeDismissedPowerAnomalyKeys(mContext);
|
||||
DatabaseUtils.setDismissedPowerAnomalyKeys(mContext, PowerAnomalyKey.KEY_BRIGHTNESS.name());
|
||||
|
||||
final PowerAnomalyEvent highestScoreEvent =
|
||||
PowerUsageAdvanced.getHighestScoreAnomalyEvent(mContext, powerAnomalyEventList);
|
||||
final PowerAnomalyEvent slotEvent =
|
||||
PowerUsageAdvanced.getAnomalyEvent(powerAnomalyEventList,
|
||||
mSlotFilterPredicate);
|
||||
prepareCardFilterPredicate(slotEvent);
|
||||
final PowerAnomalyEvent cardEvent =
|
||||
PowerUsageAdvanced.getAnomalyEvent(powerAnomalyEventList,
|
||||
mCardFilterPredicate);
|
||||
|
||||
assertThat(highestScoreEvent)
|
||||
.isEqualTo(BatteryTestUtils.createScreenTimeoutAnomalyEvent());
|
||||
assertThat(cardEvent).isEqualTo(BatteryTestUtils.createScreenTimeoutAnomalyEvent());
|
||||
assertThat(slotEvent).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getHighestScoreAnomalyEvent_withAllDismissed_getNull() {
|
||||
public void getFilterAnomalyEvent_withAllDismissed_getNull() {
|
||||
final PowerAnomalyEventList powerAnomalyEventList =
|
||||
BatteryTestUtils.createNonEmptyPowerAnomalyEventList();
|
||||
DatabaseUtils.removeDismissedPowerAnomalyKeys(mContext);
|
||||
@@ -118,20 +143,26 @@ public final class PowerUsageAdvancedTest {
|
||||
DatabaseUtils.setDismissedPowerAnomalyKeys(mContext, key.name());
|
||||
}
|
||||
|
||||
final PowerAnomalyEvent highestScoreEvent =
|
||||
PowerUsageAdvanced.getHighestScoreAnomalyEvent(mContext, powerAnomalyEventList);
|
||||
final PowerAnomalyEvent slotEvent =
|
||||
PowerUsageAdvanced.getAnomalyEvent(powerAnomalyEventList,
|
||||
mSlotFilterPredicate);
|
||||
prepareCardFilterPredicate(slotEvent);
|
||||
final PowerAnomalyEvent cardEvent =
|
||||
PowerUsageAdvanced.getAnomalyEvent(powerAnomalyEventList,
|
||||
mCardFilterPredicate);
|
||||
|
||||
assertThat(highestScoreEvent).isNull();
|
||||
assertThat(cardEvent).isNull();
|
||||
assertThat(slotEvent).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onDisplayAnomalyEventUpdated_withSettingsAnomalyEvent_skipHighlightSlotEffect() {
|
||||
final PowerAnomalyEvent event = BatteryTestUtils.createAdaptiveBrightnessAnomalyEvent();
|
||||
|
||||
mPowerUsageAdvanced.onDisplayAnomalyEventUpdated(event);
|
||||
mPowerUsageAdvanced.onDisplayAnomalyEventUpdated(event, event);
|
||||
|
||||
assertThat(mPowerUsageAdvanced.mPowerAnomalyEvent).isEqualTo(event);
|
||||
verify(mBatteryTipsController).handleBatteryTipsCardUpdated(eq(event));
|
||||
assertThat(mPowerUsageAdvanced.mHighlightEventWrapper.get().getEventId())
|
||||
.isEqualTo(event.getEventId());
|
||||
verify(mPowerUsageAdvanced.mBatteryTipsController).setOnAnomalyConfirmListener(isNull());
|
||||
verify(mPowerUsageAdvanced.mBatteryTipsController).setOnAnomalyRejectListener(isNull());
|
||||
verify(mPowerUsageAdvanced.mBatteryChartPreferenceController).onHighlightSlotIndexUpdate(
|
||||
@@ -140,46 +171,44 @@ public final class PowerUsageAdvancedTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onDisplayAnomalyEventUpdated_withAppAnomalyEvent_setHighlightSlotEffect() {
|
||||
public void onDisplayAnomalyEventUpdated_onlyAppAnomalyEvent_setHighlightSlotEffect() {
|
||||
final PowerAnomalyEvent event = BatteryTestUtils.createAppAnomalyEvent();
|
||||
|
||||
mPowerUsageAdvanced.onDisplayAnomalyEventUpdated(event);
|
||||
mPowerUsageAdvanced.onDisplayAnomalyEventUpdated(event, event);
|
||||
|
||||
assertThat(mPowerUsageAdvanced.mPowerAnomalyEvent).isEqualTo(event);
|
||||
verify(mBatteryTipsController).handleBatteryTipsCardUpdated(eq(event));
|
||||
assertThat(mPowerUsageAdvanced.mHighlightEventWrapper.get().getEventId())
|
||||
.isEqualTo(event.getEventId());
|
||||
verify(mBatteryTipsController).setOnAnomalyConfirmListener(isNull());
|
||||
verify(mBatteryTipsController).setOnAnomalyRejectListener(isNull());
|
||||
|
||||
assertThat(event.getWarningItemInfo().hasStartTimestamp()).isTrue();
|
||||
assertThat(event.getWarningItemInfo().hasEndTimestamp()).isTrue();
|
||||
assertThat(mPowerUsageAdvanced.mBatteryLevelData.get().getIndexByTimestamps(
|
||||
event.getWarningItemInfo().getStartTimestamp(),
|
||||
event.getWarningItemInfo().getEndTimestamp()
|
||||
)).isEqualTo(Pair.create(1, 0));
|
||||
verify(mBatteryChartPreferenceController).onHighlightSlotIndexUpdate(eq(1), eq(0));
|
||||
verify(mBatteryTipsController).setOnAnomalyConfirmListener(notNull());
|
||||
verify(mBatteryTipsController).setOnAnomalyRejectListener(notNull());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onDisplayAnomalyEventUpdated_withNull_removeHighlightSlotEffect() {
|
||||
final PowerAnomalyEvent event = BatteryTestUtils.createAppAnomalyEvent();
|
||||
public void onDisplayAnomalyEventUpdated_withSettingsCardAndAppsSlotEvent_showExpected() {
|
||||
final PowerAnomalyEvent settingsEvent =
|
||||
BatteryTestUtils.createAdaptiveBrightnessAnomalyEvent();
|
||||
final PowerAnomalyEvent appsEvent =
|
||||
BatteryTestUtils.createAppAnomalyEvent();
|
||||
|
||||
mPowerUsageAdvanced.onDisplayAnomalyEventUpdated(event);
|
||||
mPowerUsageAdvanced.onDisplayAnomalyEventUpdated(null);
|
||||
mPowerUsageAdvanced.onDisplayAnomalyEventUpdated(settingsEvent, appsEvent);
|
||||
|
||||
assertThat(mPowerUsageAdvanced.mPowerAnomalyEvent).isNull();
|
||||
verify(mBatteryTipsController, times(2))
|
||||
.setOnAnomalyConfirmListener(isNull());
|
||||
verify(mBatteryTipsController, times(2))
|
||||
.setOnAnomalyRejectListener(isNull());
|
||||
verify(mBatteryTipsController).setOnAnomalyConfirmListener(notNull());
|
||||
verify(mBatteryTipsController).setOnAnomalyRejectListener(notNull());
|
||||
|
||||
verify(mBatteryChartPreferenceController)
|
||||
.onHighlightSlotIndexUpdate(eq(1), eq(0));
|
||||
verify(mBatteryChartPreferenceController).onHighlightSlotIndexUpdate(
|
||||
eq(BatteryChartViewModel.SELECTED_INDEX_INVALID),
|
||||
eq(BatteryChartViewModel.SELECTED_INDEX_INVALID));
|
||||
assertThat(mPowerUsageAdvanced.mHighlightEventWrapper.get().getEventId())
|
||||
.isEqualTo(appsEvent.getEventId());
|
||||
verify(mBatteryChartPreferenceController).onHighlightSlotIndexUpdate(eq(1), eq(0));
|
||||
verify(mBatteryTipsController).setOnAnomalyConfirmListener(isNull());
|
||||
verify(mBatteryTipsController).setOnAnomalyRejectListener(isNull());
|
||||
}
|
||||
}
|
||||
|
||||
private void prepareCardFilterPredicate(PowerAnomalyEvent slotEvent) {
|
||||
final Set<String> dismissedPowerAnomalyKeys =
|
||||
DatabaseUtils.getDismissedPowerAnomalyKeys(mContext);
|
||||
mCardFilterPredicate = event -> !dismissedPowerAnomalyKeys.contains(
|
||||
event.getDismissRecordKey())
|
||||
&& (event.equals(slotEvent) || !event.hasWarningItemInfo());
|
||||
}
|
||||
}
|
@@ -247,6 +247,7 @@ public class BatteryTestUtils {
|
||||
.setEventId("BrightnessAnomaly")
|
||||
.setType(PowerAnomalyType.TYPE_SETTINGS_BANNER)
|
||||
.setKey(PowerAnomalyKey.KEY_BRIGHTNESS)
|
||||
.setDismissRecordKey(PowerAnomalyKey.KEY_BRIGHTNESS.name())
|
||||
.setScore(1.2f)
|
||||
.setWarningBannerInfo(WarningBannerInfo.newBuilder()
|
||||
.setMainButtonDestination(DisplaySettings.class.getName())
|
||||
@@ -264,6 +265,7 @@ public class BatteryTestUtils {
|
||||
.setEventId("ScreenTimeoutAnomaly")
|
||||
.setType(PowerAnomalyType.TYPE_SETTINGS_BANNER)
|
||||
.setKey(PowerAnomalyKey.KEY_SCREEN_TIMEOUT)
|
||||
.setDismissRecordKey(PowerAnomalyKey.KEY_SCREEN_TIMEOUT.name())
|
||||
.setScore(1.1f)
|
||||
.setWarningBannerInfo(WarningBannerInfo.newBuilder()
|
||||
.setMainButtonDestination(ScreenTimeoutSettings.class.getName())
|
||||
@@ -280,15 +282,12 @@ public class BatteryTestUtils {
|
||||
return PowerAnomalyEvent.newBuilder()
|
||||
.setEventId("AppAnomaly")
|
||||
.setType(PowerAnomalyType.TYPE_APPS_ITEM)
|
||||
.setKey(PowerAnomalyKey.KEY_APP)
|
||||
.setKey(PowerAnomalyKey.KEY_APP_TOTAL_HIGHER_THAN_USUAL)
|
||||
.setDismissRecordKey("KEY_APP_1")
|
||||
.setScore(2.0f)
|
||||
.setWarningItemInfo(WarningItemInfo.newBuilder()
|
||||
.setDismissRecordKey("KEY_APP_1")
|
||||
.setStartTimestamp(1694361600000L) // 2023-09-11 00:00:00
|
||||
.setEndTimestamp(1694368800000L) // 2023-09-11 02:00:00
|
||||
.setTitleString("Chrome used more battery than usual in foreground")
|
||||
.setMainButtonString("Check")
|
||||
.setCancelButtonString("Got it")
|
||||
.build())
|
||||
.build();
|
||||
}
|
||||
|
Reference in New Issue
Block a user