Merge "Refactor battery usage page contollers interaction logic" into main

This commit is contained in:
Zaiyue Xue
2023-09-06 11:46:09 +00:00
committed by Android (Google) Code Review
4 changed files with 328 additions and 306 deletions

View File

@@ -36,7 +36,6 @@ import androidx.preference.PreferenceScreen;
import com.android.settings.R; import com.android.settings.R;
import com.android.settings.SettingsActivity; import com.android.settings.SettingsActivity;
import com.android.settings.core.PreferenceControllerMixin; import com.android.settings.core.PreferenceControllerMixin;
import com.android.settings.fuelgauge.PowerUsageFeatureProvider;
import com.android.settings.overlay.FeatureFactory; import com.android.settings.overlay.FeatureFactory;
import com.android.settingslib.core.AbstractPreferenceController; import com.android.settingslib.core.AbstractPreferenceController;
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
@@ -44,7 +43,6 @@ import com.android.settingslib.core.lifecycle.Lifecycle;
import com.android.settingslib.core.lifecycle.LifecycleObserver; import com.android.settingslib.core.lifecycle.LifecycleObserver;
import com.android.settingslib.core.lifecycle.events.OnCreate; import com.android.settingslib.core.lifecycle.events.OnCreate;
import com.android.settingslib.core.lifecycle.events.OnDestroy; import com.android.settingslib.core.lifecycle.events.OnDestroy;
import com.android.settingslib.core.lifecycle.events.OnPause;
import com.android.settingslib.core.lifecycle.events.OnResume; import com.android.settingslib.core.lifecycle.events.OnResume;
import com.android.settingslib.core.lifecycle.events.OnSaveInstanceState; import com.android.settingslib.core.lifecycle.events.OnSaveInstanceState;
@@ -52,17 +50,12 @@ import com.google.common.base.Objects;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Calendar; import java.util.Calendar;
import java.util.Comparator;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicBoolean;
/** Controls the update for chart graph and the list items. */ /** Controls the update for chart graph and the list items. */
public class BatteryChartPreferenceController extends AbstractPreferenceController public class BatteryChartPreferenceController extends AbstractPreferenceController
implements PreferenceControllerMixin, LifecycleObserver, OnCreate, OnDestroy, OnPause, implements PreferenceControllerMixin, LifecycleObserver, OnCreate, OnDestroy,
OnSaveInstanceState, OnResume { OnSaveInstanceState, OnResume {
private static final String TAG = "BatteryChartPreferenceController"; private static final String TAG = "BatteryChartPreferenceController";
private static final String PREFERENCE_KEY = "battery_chart"; private static final String PREFERENCE_KEY = "battery_chart";
@@ -74,53 +67,17 @@ public class BatteryChartPreferenceController extends AbstractPreferenceControll
private static final String KEY_DAILY_CHART_INDEX = "daily_chart_index"; private static final String KEY_DAILY_CHART_INDEX = "daily_chart_index";
private static final String KEY_HOURLY_CHART_INDEX = "hourly_chart_index"; private static final String KEY_HOURLY_CHART_INDEX = "hourly_chart_index";
/** /** A callback listener for the selected index is updated. */
* A callback listener for battery usage is updated. interface OnSelectedIndexUpdatedListener {
* This happens when battery usage data is ready or the selected index is changed. /** The callback function for the selected index is updated. */
*/ void onSelectedIndexUpdated();
public interface OnBatteryUsageUpdatedListener {
/**
* The callback function for battery usage is updated.
* @param slotUsageData The battery usage diff data for the selected slot. This is used in
* the app list.
* @param slotTimestamp The selected slot timestamp information. This is used in the battery
* usage breakdown category.
* @param isAllUsageDataEmpty Whether all the battery usage data is null or empty. This is
* used when showing the footer.
*/
void onBatteryUsageUpdated(
BatteryDiffData slotUsageData, String slotTimestamp, boolean isAllUsageDataEmpty);
} }
/**
* A callback listener for the device screen on time is updated.
* This happens when screen on time data is ready or the selected index is changed.
*/
public interface OnScreenOnTimeUpdatedListener {
/**
* The callback function for the device screen on time is updated.
* @param screenOnTime The selected slot device screen on time.
* @param slotTimestamp The selected slot timestamp information.
*/
void onScreenOnTimeUpdated(Long screenOnTime, String slotTimestamp);
}
/**
* A callback listener for the battery tips card is updated.
* This happens when battery tips card is ready.
*/
public interface OnBatteryTipsUpdatedListener {
/**
* The callback function for the battery tips card is updated.
* @param powerAnomalyEvent the power anomaly event with highest score
*/
void onBatteryTipsUpdated(PowerAnomalyEvent powerAnomalyEvent);
}
@VisibleForTesting @VisibleForTesting
Context mPrefContext; Context mPrefContext;
@VisibleForTesting @VisibleForTesting
TextView mChartSummaryTextView;
@VisibleForTesting
BatteryChartView mDailyChartView; BatteryChartView mDailyChartView;
@VisibleForTesting @VisibleForTesting
BatteryChartView mHourlyChartView; BatteryChartView mHourlyChartView;
@@ -128,28 +85,20 @@ public class BatteryChartPreferenceController extends AbstractPreferenceControll
int mDailyChartIndex = BatteryChartViewModel.SELECTED_INDEX_ALL; int mDailyChartIndex = BatteryChartViewModel.SELECTED_INDEX_ALL;
@VisibleForTesting @VisibleForTesting
int mHourlyChartIndex = BatteryChartViewModel.SELECTED_INDEX_ALL; int mHourlyChartIndex = BatteryChartViewModel.SELECTED_INDEX_ALL;
@VisibleForTesting
Map<Integer, Map<Integer, BatteryDiffData>> mBatteryUsageMap;
private boolean mIs24HourFormat; private boolean mIs24HourFormat;
private View mBatteryChartViewGroup; private View mBatteryChartViewGroup;
private TextView mChartSummaryTextView;
private BatteryChartViewModel mDailyViewModel; private BatteryChartViewModel mDailyViewModel;
private List<BatteryChartViewModel> mHourlyViewModels; private List<BatteryChartViewModel> mHourlyViewModels;
private OnBatteryUsageUpdatedListener mOnBatteryUsageUpdatedListener; private OnSelectedIndexUpdatedListener mOnSelectedIndexUpdatedListener;
private OnScreenOnTimeUpdatedListener mOnScreenOnTimeUpdatedListener;
private OnBatteryTipsUpdatedListener mOnBatteryTipsUpdatedListener;
private AtomicBoolean mIsAppResume = new AtomicBoolean(false);
private final SettingsActivity mActivity; private final SettingsActivity mActivity;
private final MetricsFeatureProvider mMetricsFeatureProvider; private final MetricsFeatureProvider mMetricsFeatureProvider;
private final PowerUsageFeatureProvider mPowerUsageFeatureProvider;
private final Handler mHandler = new Handler(Looper.getMainLooper()); private final Handler mHandler = new Handler(Looper.getMainLooper());
private final AnimatorListenerAdapter mHourlyChartFadeInAdapter = private final AnimatorListenerAdapter mHourlyChartFadeInAdapter =
createHourlyChartAnimatorListenerAdapter(/*visible=*/ true); createHourlyChartAnimatorListenerAdapter(/*visible=*/ true);
private final AnimatorListenerAdapter mHourlyChartFadeOutAdapter = private final AnimatorListenerAdapter mHourlyChartFadeOutAdapter =
createHourlyChartAnimatorListenerAdapter(/*visible=*/ false); createHourlyChartAnimatorListenerAdapter(/*visible=*/ false);
private final ExecutorService mExecutor = Executors.newSingleThreadExecutor();
@VisibleForTesting @VisibleForTesting
final DailyChartLabelTextGenerator mDailyChartLabelTextGenerator = final DailyChartLabelTextGenerator mDailyChartLabelTextGenerator =
@@ -165,8 +114,6 @@ public class BatteryChartPreferenceController extends AbstractPreferenceControll
mIs24HourFormat = DateFormat.is24HourFormat(context); mIs24HourFormat = DateFormat.is24HourFormat(context);
mMetricsFeatureProvider = mMetricsFeatureProvider =
FeatureFactory.getFeatureFactory().getMetricsFeatureProvider(); FeatureFactory.getFeatureFactory().getMetricsFeatureProvider();
mPowerUsageFeatureProvider =
FeatureFactory.getFeatureFactory().getPowerUsageFeatureProvider();
if (lifecycle != null) { if (lifecycle != null) {
lifecycle.addObserver(this); lifecycle.addObserver(this);
} }
@@ -184,15 +131,9 @@ public class BatteryChartPreferenceController extends AbstractPreferenceControll
Log.d(TAG, String.format("onCreate() dailyIndex=%d hourlyIndex=%d", Log.d(TAG, String.format("onCreate() dailyIndex=%d hourlyIndex=%d",
mDailyChartIndex, mHourlyChartIndex)); mDailyChartIndex, mHourlyChartIndex));
} }
@Override
public void onPause() {
mIsAppResume.compareAndSet(/* expect= */ true, /* update= */ false);
}
@Override @Override
public void onResume() { public void onResume() {
mIsAppResume.compareAndSet(/* expect= */ false, /* update= */ true);
mIs24HourFormat = DateFormat.is24HourFormat(mContext); mIs24HourFormat = DateFormat.is24HourFormat(mContext);
mMetricsFeatureProvider.action(mPrefContext, SettingsEnums.OPEN_BATTERY_USAGE); mMetricsFeatureProvider.action(mPrefContext, SettingsEnums.OPEN_BATTERY_USAGE);
} }
@@ -232,16 +173,16 @@ public class BatteryChartPreferenceController extends AbstractPreferenceControll
return PREFERENCE_KEY; return PREFERENCE_KEY;
} }
void setOnBatteryUsageUpdatedListener(OnBatteryUsageUpdatedListener listener) { int getDailyChartIndex() {
mOnBatteryUsageUpdatedListener = listener; return mDailyChartIndex;
} }
void setOnScreenOnTimeUpdatedListener(OnScreenOnTimeUpdatedListener listener) { int getHourlyChartIndex() {
mOnScreenOnTimeUpdatedListener = listener; return mHourlyChartIndex;
} }
void setOnBatteryTipsUpdatedListener(OnBatteryTipsUpdatedListener listener) { void setOnSelectedIndexUpdatedListener(OnSelectedIndexUpdatedListener listener) {
mOnBatteryTipsUpdatedListener = listener; mOnSelectedIndexUpdatedListener = listener;
} }
void onBatteryLevelDataUpdate(final BatteryLevelData batteryLevelData) { void onBatteryLevelDataUpdate(final BatteryLevelData batteryLevelData) {
@@ -276,13 +217,6 @@ public class BatteryChartPreferenceController extends AbstractPreferenceControll
refreshUi(); refreshUi();
} }
void onBatteryUsageMapUpdate(Map<Integer, Map<Integer, BatteryDiffData>> batteryUsageMap) {
Log.d(TAG, "onBatteryUsageMapUpdate: " + batteryUsageMap);
mBatteryUsageMap = batteryUsageMap;
logScreenUsageTime();
refreshUi();
}
void setBatteryChartView(@NonNull final BatteryChartView dailyChartView, void setBatteryChartView(@NonNull final BatteryChartView dailyChartView,
@NonNull final BatteryChartView hourlyChartView) { @NonNull final BatteryChartView hourlyChartView) {
final View parentView = (View) dailyChartView.getParent(); final View parentView = (View) dailyChartView.getParent();
@@ -319,6 +253,9 @@ public class BatteryChartPreferenceController extends AbstractPreferenceControll
? SettingsEnums.ACTION_BATTERY_USAGE_DAILY_SHOW_ALL ? SettingsEnums.ACTION_BATTERY_USAGE_DAILY_SHOW_ALL
: SettingsEnums.ACTION_BATTERY_USAGE_DAILY_TIME_SLOT, : SettingsEnums.ACTION_BATTERY_USAGE_DAILY_TIME_SLOT,
mDailyChartIndex); mDailyChartIndex);
if (mOnSelectedIndexUpdatedListener != null) {
mOnSelectedIndexUpdatedListener.onSelectedIndexUpdated();
}
}); });
mHourlyChartView = hourlyChartView; mHourlyChartView = hourlyChartView;
mHourlyChartView.setOnSelectListener(trapezoidIndex -> { mHourlyChartView.setOnSelectListener(trapezoidIndex -> {
@@ -340,102 +277,37 @@ public class BatteryChartPreferenceController extends AbstractPreferenceControll
? SettingsEnums.ACTION_BATTERY_USAGE_SHOW_ALL ? SettingsEnums.ACTION_BATTERY_USAGE_SHOW_ALL
: SettingsEnums.ACTION_BATTERY_USAGE_TIME_SLOT, : SettingsEnums.ACTION_BATTERY_USAGE_TIME_SLOT,
mHourlyChartIndex); mHourlyChartIndex);
if (mOnSelectedIndexUpdatedListener != null) {
mOnSelectedIndexUpdatedListener.onSelectedIndexUpdated();
}
}); });
refreshUi(); refreshUi();
} }
// Show empty hourly chart view only if there is no valid battery usage data.
void showEmptyChart() {
setChartSummaryVisible(true);
mDailyChartView.setVisibility(View.GONE);
mHourlyChartView.setVisibility(View.VISIBLE);
mHourlyChartView.setViewModel(null);
}
@VisibleForTesting @VisibleForTesting
boolean refreshUi() { void refreshUi() {
if (mDailyChartView == null || mHourlyChartView == null) { if (mDailyChartView == null || mHourlyChartView == null) {
// Chart views are not initialized. // Chart views are not initialized.
return false; return;
} }
// When mDailyViewModel or mHourlyViewModels is null, there is no battery level data. if (mDailyViewModel == null || mHourlyViewModels == null) {
// This is mainly in 2 cases: setChartSummaryVisible(false);
// 1) battery data is within 2 hours
// 2) no battery data in the latest 7 days (power off >= 7 days)
final boolean refreshUiResult = mDailyViewModel == null || mHourlyViewModels == null
? refreshUiWithNoLevelDataCase()
: refreshUiWithLevelDataCase();
if (!refreshUiResult) {
return false;
}
if (mOnBatteryUsageUpdatedListener != null && mBatteryUsageMap != null
&& mBatteryUsageMap.get(mDailyChartIndex) != null) {
final BatteryDiffData slotUsageData =
mBatteryUsageMap.get(mDailyChartIndex).get(mHourlyChartIndex);
if (slotUsageData != null) {
mOnScreenOnTimeUpdatedListener.onScreenOnTimeUpdated(
slotUsageData.getScreenOnTime(),
getSlotInformation());
}
mOnBatteryUsageUpdatedListener.onBatteryUsageUpdated(
slotUsageData, getSlotInformation(), isBatteryUsageMapNullOrEmpty());
if (mOnBatteryTipsUpdatedListener != null) {
mExecutor.execute(() -> {
final PowerAnomalyEventList anomalyEventList = mPowerUsageFeatureProvider
.detectSettingsAnomaly(mContext, /* displayDrain= */ 0);
Log.d(TAG, "anomalyEventList = " + anomalyEventList);
final PowerAnomalyEvent displayEvent =
getHighestScoreAnomalyEvent(anomalyEventList);
mHandler.post(() -> {
if (mIsAppResume.get()) {
mOnBatteryTipsUpdatedListener
.onBatteryTipsUpdated(displayEvent);
}
}
);
});
}
}
return true;
}
@VisibleForTesting
PowerAnomalyEvent getHighestScoreAnomalyEvent(PowerAnomalyEventList anomalyEventList) {
if (anomalyEventList == null || anomalyEventList.getPowerAnomalyEventsCount() == 0) {
return null;
}
final Set<String> dismissedPowerAnomalyKeys =
DatabaseUtils.getDismissedPowerAnomalyKeys(mContext);
Log.d(TAG, "dismissedPowerAnomalyKeys = " + dismissedPowerAnomalyKeys);
final PowerAnomalyEvent highestScoreEvent = anomalyEventList.getPowerAnomalyEventsList()
.stream()
.filter(event -> event.hasKey()
&& !dismissedPowerAnomalyKeys.contains(event.getKey().name()))
.max(Comparator.comparing(PowerAnomalyEvent::getScore))
.orElse(null);
Log.d(TAG, "highestScoreAnomalyEvent = " + highestScoreEvent);
return highestScoreEvent;
}
private boolean refreshUiWithNoLevelDataCase() {
setChartSummaryVisible(false);
if (mBatteryUsageMap == null) {
// There is no battery level data and battery usage data is not ready, wait for data
// ready to refresh UI. Show nothing temporarily.
mDailyChartView.setVisibility(View.GONE); mDailyChartView.setVisibility(View.GONE);
mHourlyChartView.setVisibility(View.GONE); mHourlyChartView.setVisibility(View.GONE);
mDailyChartView.setViewModel(null); mDailyChartView.setViewModel(null);
mHourlyChartView.setViewModel(null); mHourlyChartView.setViewModel(null);
return false; return;
} else if (mBatteryUsageMap
.get(BatteryChartViewModel.SELECTED_INDEX_ALL)
.get(BatteryChartViewModel.SELECTED_INDEX_ALL) == null) {
// There is no battery level data and battery usage data, show an empty hourly chart
// view.
mDailyChartView.setVisibility(View.GONE);
mHourlyChartView.setVisibility(View.VISIBLE);
mHourlyChartView.setViewModel(null);
} }
return true;
}
private boolean refreshUiWithLevelDataCase() {
setChartSummaryVisible(true); setChartSummaryVisible(true);
// Gets valid battery level data. // Gets valid battery level data.
if (isBatteryLevelDataInOneDay()) { if (isBatteryLevelDataInOneDay()) {
@@ -464,15 +336,8 @@ public class BatteryChartPreferenceController extends AbstractPreferenceControll
hourlyViewModel.setSelectedIndex(mHourlyChartIndex); hourlyViewModel.setSelectedIndex(mHourlyChartIndex);
mHourlyChartView.setViewModel(hourlyViewModel); mHourlyChartView.setViewModel(hourlyViewModel);
} }
if (mBatteryUsageMap == null) {
// Battery usage data is not ready, wait for data ready to refresh UI.
return false;
}
return true;
} }
@VisibleForTesting
String getSlotInformation() { String getSlotInformation() {
if (mDailyViewModel == null || mHourlyViewModels == null) { if (mDailyViewModel == null || mHourlyViewModels == null) {
// No data // No data
@@ -563,44 +428,6 @@ public class BatteryChartPreferenceController extends AbstractPreferenceControll
}; };
} }
private void logScreenUsageTime() {
if (mBatteryUsageMap == null) {
return;
}
final BatteryDiffData allBatteryDiffData = mBatteryUsageMap.get(
BatteryChartViewModel.SELECTED_INDEX_ALL).get(
BatteryChartViewModel.SELECTED_INDEX_ALL);
if (allBatteryDiffData == null) {
return;
}
mMetricsFeatureProvider.action(
mPrefContext,
SettingsEnums.ACTION_BATTERY_USAGE_SCREEN_ON_TIME,
(int) allBatteryDiffData.getScreenOnTime());
mMetricsFeatureProvider.action(
mPrefContext,
SettingsEnums.ACTION_BATTERY_USAGE_FOREGROUND_USAGE_TIME,
(int) getTotalForegroundUsageTime());
}
private long getTotalForegroundUsageTime() {
if (mBatteryUsageMap == null) {
return 0;
}
final BatteryDiffData totalBatteryUsageDiffData =
mBatteryUsageMap
.get(BatteryChartViewModel.SELECTED_INDEX_ALL)
.get(BatteryChartViewModel.SELECTED_INDEX_ALL);
if (totalBatteryUsageDiffData == null) {
return 0;
}
long totalValue = 0;
for (final BatteryDiffEntry entry : totalBatteryUsageDiffData.getAppDiffEntryList()) {
totalValue += entry.mForegroundUsageTimeInMs;
}
return totalValue;
}
private boolean isBatteryLevelDataInOneDay() { private boolean isBatteryLevelDataInOneDay() {
return mHourlyViewModels != null && mHourlyViewModels.size() == 1; return mHourlyViewModels != null && mHourlyViewModels.size() == 1;
} }
@@ -611,19 +438,6 @@ public class BatteryChartPreferenceController extends AbstractPreferenceControll
&& mHourlyChartIndex == BatteryChartViewModel.SELECTED_INDEX_ALL; && mHourlyChartIndex == BatteryChartViewModel.SELECTED_INDEX_ALL;
} }
private boolean isBatteryUsageMapNullOrEmpty() {
if (mBatteryUsageMap == null) {
return true;
}
BatteryDiffData allBatteryDiffData = mBatteryUsageMap
.get(BatteryChartViewModel.SELECTED_INDEX_ALL)
.get(BatteryChartViewModel.SELECTED_INDEX_ALL);
// If all data is null or empty, each slot must be null or empty.
return allBatteryDiffData == null
|| (allBatteryDiffData.getAppDiffEntryList().isEmpty()
&& allBatteryDiffData.getSystemDiffEntryList().isEmpty());
}
@VisibleForTesting @VisibleForTesting
static int getTotalHours(final BatteryLevelData batteryLevelData) { static int getTotalHours(final BatteryLevelData batteryLevelData) {
if (batteryLevelData == null) { if (batteryLevelData == null) {

View File

@@ -35,6 +35,8 @@ import androidx.loader.content.Loader;
import com.android.settings.R; import com.android.settings.R;
import com.android.settings.SettingsActivity; import com.android.settings.SettingsActivity;
import com.android.settings.fuelgauge.BatteryBroadcastReceiver; import com.android.settings.fuelgauge.BatteryBroadcastReceiver;
import com.android.settings.fuelgauge.PowerUsageFeatureProvider;
import com.android.settings.overlay.FeatureFactory;
import com.android.settings.search.BaseSearchIndexProvider; import com.android.settings.search.BaseSearchIndexProvider;
import com.android.settingslib.core.AbstractPreferenceController; import com.android.settingslib.core.AbstractPreferenceController;
import com.android.settingslib.search.SearchIndexable; import com.android.settingslib.search.SearchIndexable;
@@ -42,9 +44,13 @@ import com.android.settingslib.utils.AsyncLoaderCompat;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Comparator;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Optional; import java.util.Optional;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/** Advanced power usage. */ /** Advanced power usage. */
@SearchIndexable(forTarget = SearchIndexable.ALL & ~SearchIndexable.ARC) @SearchIndexable(forTarget = SearchIndexable.ALL & ~SearchIndexable.ARC)
@@ -61,9 +67,14 @@ public class PowerUsageAdvanced extends PowerUsageBase {
private boolean mIsChartDataLoaded = false; private boolean mIsChartDataLoaded = false;
private long mResumeTimestamp; private long mResumeTimestamp;
private BatteryTipsController mBatteryTipsController;
private BatteryChartPreferenceController mBatteryChartPreferenceController; private BatteryChartPreferenceController mBatteryChartPreferenceController;
private ScreenOnTimeController mScreenOnTimeController;
private BatteryUsageBreakdownController mBatteryUsageBreakdownController;
private Optional<BatteryLevelData> mBatteryLevelData; private Optional<BatteryLevelData> mBatteryLevelData;
private Map<Integer, Map<Integer, BatteryDiffData>> mBatteryUsageMap;
private final ExecutorService mExecutor = Executors.newSingleThreadExecutor();
private final Handler mHandler = new Handler(Looper.getMainLooper()); private final Handler mHandler = new Handler(Looper.getMainLooper());
private final ContentObserver mBatteryObserver = private final ContentObserver mBatteryObserver =
new ContentObserver(mHandler) { new ContentObserver(mHandler) {
@@ -90,6 +101,7 @@ public class PowerUsageAdvanced extends PowerUsageBase {
if (getActivity().isChangingConfigurations()) { if (getActivity().isChangingConfigurations()) {
BatteryEntry.clearUidCache(); BatteryEntry.clearUidCache();
} }
mExecutor.shutdown();
} }
@Override @Override
@@ -112,7 +124,6 @@ public class PowerUsageAdvanced extends PowerUsageBase {
super.onPause(); super.onPause();
// Resets the flag to reload usage data in onResume() callback. // Resets the flag to reload usage data in onResume() callback.
mIsChartDataLoaded = false; mIsChartDataLoaded = false;
mBatteryLevelData = null;
final Uri uri = DatabaseUtils.BATTERY_CONTENT_URI; final Uri uri = DatabaseUtils.BATTERY_CONTENT_URI;
if (uri != null) { if (uri != null) {
getContext().getContentResolver().unregisterContentObserver(mBatteryObserver); getContext().getContentResolver().unregisterContentObserver(mBatteryObserver);
@@ -133,28 +144,25 @@ public class PowerUsageAdvanced extends PowerUsageBase {
@Override @Override
protected List<AbstractPreferenceController> createPreferenceControllers(Context context) { protected List<AbstractPreferenceController> createPreferenceControllers(Context context) {
final List<AbstractPreferenceController> controllers = new ArrayList<>(); final List<AbstractPreferenceController> controllers = new ArrayList<>();
mBatteryTipsController = new BatteryTipsController(context);
mBatteryChartPreferenceController = mBatteryChartPreferenceController =
new BatteryChartPreferenceController( new BatteryChartPreferenceController(
context, getSettingsLifecycle(), (SettingsActivity) getActivity()); context, getSettingsLifecycle(), (SettingsActivity) getActivity());
final ScreenOnTimeController screenOnTimeController = new ScreenOnTimeController(context); mScreenOnTimeController = new ScreenOnTimeController(context);
final BatteryUsageBreakdownController batteryUsageBreakdownController = mBatteryUsageBreakdownController =
new BatteryUsageBreakdownController( new BatteryUsageBreakdownController(
context, getSettingsLifecycle(), (SettingsActivity) getActivity(), this); context, getSettingsLifecycle(), (SettingsActivity) getActivity(), this);
final BatteryTipsController batteryTipsController = new BatteryTipsController(context);
mBatteryChartPreferenceController.setOnScreenOnTimeUpdatedListener(
screenOnTimeController::handleSceenOnTimeUpdated);
mBatteryChartPreferenceController.setOnBatteryUsageUpdatedListener(
batteryUsageBreakdownController::handleBatteryUsageUpdated);
mBatteryChartPreferenceController.setOnBatteryTipsUpdatedListener(
batteryTipsController::handleBatteryTipsCardUpdated);
controllers.add(mBatteryTipsController);
controllers.add(mBatteryChartPreferenceController); controllers.add(mBatteryChartPreferenceController);
controllers.add(screenOnTimeController); controllers.add(mScreenOnTimeController);
controllers.add(batteryUsageBreakdownController); controllers.add(mBatteryUsageBreakdownController);
controllers.add(batteryTipsController);
setBatteryChartPreferenceController(); setBatteryChartPreferenceController();
mBatteryChartPreferenceController.setOnSelectedIndexUpdatedListener(
this::onSelectedSlotDataUpdated);
// Force UI refresh if battery usage data was loaded before UI initialization.
onSelectedSlotDataUpdated();
return controllers; return controllers;
} }
@@ -169,12 +177,17 @@ public class PowerUsageAdvanced extends PowerUsageBase {
bundle.putInt(KEY_REFRESH_TYPE, refreshType); bundle.putInt(KEY_REFRESH_TYPE, refreshType);
if (!mIsChartDataLoaded) { if (!mIsChartDataLoaded) {
mIsChartDataLoaded = true; mIsChartDataLoaded = true;
mBatteryLevelData = null;
mBatteryUsageMap = null;
restartLoader(LoaderIndex.BATTERY_LEVEL_DATA_LOADER, bundle, restartLoader(LoaderIndex.BATTERY_LEVEL_DATA_LOADER, bundle,
mBatteryLevelDataLoaderCallbacks); mBatteryLevelDataLoaderCallbacks);
} }
} }
private void onBatteryLevelDataUpdate(BatteryLevelData batteryLevelData) { private void onBatteryLevelDataUpdate(BatteryLevelData batteryLevelData) {
if (!isResumed()) {
return;
}
mBatteryLevelData = Optional.ofNullable(batteryLevelData); mBatteryLevelData = Optional.ofNullable(batteryLevelData);
if (mBatteryChartPreferenceController != null) { if (mBatteryChartPreferenceController != null) {
mBatteryChartPreferenceController.onBatteryLevelDataUpdate(batteryLevelData); mBatteryChartPreferenceController.onBatteryLevelDataUpdate(batteryLevelData);
@@ -184,23 +197,130 @@ public class PowerUsageAdvanced extends PowerUsageBase {
} }
private void onBatteryDiffDataMapUpdate(Map<Long, BatteryDiffData> batteryDiffDataMap) { private void onBatteryDiffDataMapUpdate(Map<Long, BatteryDiffData> batteryDiffDataMap) {
if (mBatteryLevelData != null && mBatteryChartPreferenceController != null) { if (!isResumed() || mBatteryLevelData == null) {
Map<Integer, Map<Integer, BatteryDiffData>> batteryUsageMap = return;
DataProcessor.generateBatteryUsageMap(
getContext(), batteryDiffDataMap, mBatteryLevelData.orElse(null));
DataProcessor.loadLabelAndIcon(batteryUsageMap);
mBatteryChartPreferenceController.onBatteryUsageMapUpdate(batteryUsageMap);
} }
mBatteryUsageMap = DataProcessor.generateBatteryUsageMap(
getContext(), batteryDiffDataMap, mBatteryLevelData.orElse(null));
Log.d(TAG, "onBatteryDiffDataMapUpdate: " + mBatteryUsageMap);
DataProcessor.loadLabelAndIcon(mBatteryUsageMap);
onSelectedSlotDataUpdated();
detectAnomaly();
logScreenUsageTime();
if (mBatteryChartPreferenceController != null
&& mBatteryLevelData.isEmpty() && isBatteryUsageMapNullOrEmpty()) {
// No available battery usage and battery level data.
mBatteryChartPreferenceController.showEmptyChart();
}
}
private void onSelectedSlotDataUpdated() {
if (mBatteryChartPreferenceController == null
|| mScreenOnTimeController == null
|| mBatteryUsageBreakdownController == null
|| mBatteryUsageMap == null) {
return;
}
final int dailyIndex = mBatteryChartPreferenceController.getDailyChartIndex();
final int hourlyIndex = mBatteryChartPreferenceController.getHourlyChartIndex();
final String slotInformation = mBatteryChartPreferenceController.getSlotInformation();
final BatteryDiffData slotUsageData = mBatteryUsageMap.get(dailyIndex).get(hourlyIndex);
if (slotUsageData != null) {
mScreenOnTimeController.handleSceenOnTimeUpdated(
slotUsageData.getScreenOnTime(), slotInformation);
}
mBatteryUsageBreakdownController.handleBatteryUsageUpdated(
slotUsageData, slotInformation, isBatteryUsageMapNullOrEmpty());
Log.d(TAG, String.format("Battery usage list shows in %d millis", Log.d(TAG, String.format("Battery usage list shows in %d millis",
System.currentTimeMillis() - mResumeTimestamp)); System.currentTimeMillis() - mResumeTimestamp));
} }
private void detectAnomaly() {
mExecutor.execute(() -> {
final PowerUsageFeatureProvider powerUsageFeatureProvider =
FeatureFactory.getFeatureFactory().getPowerUsageFeatureProvider();
final PowerAnomalyEventList anomalyEventList =
powerUsageFeatureProvider.detectSettingsAnomaly(
getContext(), /* displayDrain= */ 0);
mHandler.post(() -> onAnomalyDetected(anomalyEventList));
});
}
private void onAnomalyDetected(PowerAnomalyEventList anomalyEventList) {
if (!isResumed() || anomalyEventList == null) {
return;
}
Log.d(TAG, "anomalyEventList = " + anomalyEventList);
final PowerAnomalyEvent displayEvent =
getHighestScoreAnomalyEvent(getContext(), anomalyEventList);
if (displayEvent == null) {
return;
}
if (mBatteryTipsController != null) {
mBatteryTipsController.handleBatteryTipsCardUpdated(displayEvent);
}
}
private void setBatteryChartPreferenceController() { private void setBatteryChartPreferenceController() {
if (mHistPref != null && mBatteryChartPreferenceController != null) { if (mHistPref != null && mBatteryChartPreferenceController != null) {
mHistPref.setChartPreferenceController(mBatteryChartPreferenceController); mHistPref.setChartPreferenceController(mBatteryChartPreferenceController);
} }
} }
private boolean isBatteryUsageMapNullOrEmpty() {
final BatteryDiffData allBatteryDiffData = getAllBatteryDiffData(mBatteryUsageMap);
// If all data is null or empty, each slot must be null or empty.
return allBatteryDiffData == null
|| (allBatteryDiffData.getAppDiffEntryList().isEmpty()
&& allBatteryDiffData.getSystemDiffEntryList().isEmpty());
}
private void logScreenUsageTime() {
final BatteryDiffData allBatteryDiffData = getAllBatteryDiffData(mBatteryUsageMap);
if (allBatteryDiffData == null) {
return;
}
long totalForegroundUsageTime = 0;
for (final BatteryDiffEntry entry : allBatteryDiffData.getAppDiffEntryList()) {
totalForegroundUsageTime += entry.mForegroundUsageTimeInMs;
}
mMetricsFeatureProvider.action(
getContext(),
SettingsEnums.ACTION_BATTERY_USAGE_SCREEN_ON_TIME,
(int) allBatteryDiffData.getScreenOnTime());
mMetricsFeatureProvider.action(
getContext(),
SettingsEnums.ACTION_BATTERY_USAGE_FOREGROUND_USAGE_TIME,
(int) totalForegroundUsageTime);
}
@VisibleForTesting
static PowerAnomalyEvent getHighestScoreAnomalyEvent(
Context context, PowerAnomalyEventList anomalyEventList) {
if (anomalyEventList == null || anomalyEventList.getPowerAnomalyEventsCount() == 0) {
return null;
}
final Set<String> dismissedPowerAnomalyKeys =
DatabaseUtils.getDismissedPowerAnomalyKeys(context);
Log.d(TAG, "dismissedPowerAnomalyKeys = " + dismissedPowerAnomalyKeys);
final PowerAnomalyEvent highestScoreEvent = anomalyEventList.getPowerAnomalyEventsList()
.stream()
.filter(event -> event.hasKey()
&& !dismissedPowerAnomalyKeys.contains(event.getKey().name()))
.max(Comparator.comparing(PowerAnomalyEvent::getScore))
.orElse(null);
Log.d(TAG, "highestScoreAnomalyEvent = " + highestScoreEvent);
return highestScoreEvent;
}
private static BatteryDiffData getAllBatteryDiffData(
Map<Integer, Map<Integer, BatteryDiffData>> batteryUsageMap) {
return batteryUsageMap == null ? null : batteryUsageMap
.get(BatteryChartViewModel.SELECTED_INDEX_ALL)
.get(BatteryChartViewModel.SELECTED_INDEX_ALL);
}
public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER = public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
new BaseSearchIndexProvider() { new BaseSearchIndexProvider() {
@Override @Override
@@ -237,7 +357,7 @@ public class PowerUsageAdvanced extends PowerUsageBase {
public BatteryLevelData loadInBackground() { public BatteryLevelData loadInBackground() {
return DataProcessManager.getBatteryLevelData( return DataProcessManager.getBatteryLevelData(
getContext(), mHandler, /*isFromPeriodJob=*/ false, getContext(), mHandler, /*isFromPeriodJob=*/ false,
map -> PowerUsageAdvanced.this.onBatteryDiffDataMapUpdate(map)); PowerUsageAdvanced.this::onBatteryDiffDataMapUpdate);
} }
}; };
} }

View File

@@ -28,6 +28,7 @@ import static org.mockito.Mockito.any;
import static org.mockito.Mockito.atLeast; import static org.mockito.Mockito.atLeast;
import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset; import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.spy; import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
@@ -44,9 +45,9 @@ import android.util.ArrayMap;
import android.view.View; import android.view.View;
import android.view.ViewPropertyAnimator; import android.view.ViewPropertyAnimator;
import android.widget.LinearLayout; import android.widget.LinearLayout;
import android.widget.TextView;
import com.android.settings.SettingsActivity; import com.android.settings.SettingsActivity;
import com.android.settings.testutils.BatteryTestUtils;
import com.android.settings.testutils.FakeFeatureFactory; import com.android.settings.testutils.FakeFeatureFactory;
import org.junit.Before; import org.junit.Before;
@@ -72,6 +73,8 @@ public final class BatteryChartPreferenceControllerTest {
@Mock @Mock
private SettingsActivity mSettingsActivity; private SettingsActivity mSettingsActivity;
@Mock @Mock
private TextView mChartSummaryTextView;
@Mock
private BatteryChartView mDailyChartView; private BatteryChartView mDailyChartView;
@Mock @Mock
private BatteryChartView mHourlyChartView; private BatteryChartView mHourlyChartView;
@@ -112,6 +115,7 @@ public final class BatteryChartPreferenceControllerTest {
setupHourlyChartViewAnimationMock(); setupHourlyChartViewAnimationMock();
mBatteryChartPreferenceController = createController(); mBatteryChartPreferenceController = createController();
mBatteryChartPreferenceController.mPrefContext = mContext; mBatteryChartPreferenceController.mPrefContext = mContext;
mBatteryChartPreferenceController.mChartSummaryTextView = mChartSummaryTextView;
mBatteryChartPreferenceController.mDailyChartView = mDailyChartView; mBatteryChartPreferenceController.mDailyChartView = mDailyChartView;
mBatteryChartPreferenceController.mHourlyChartView = mHourlyChartView; mBatteryChartPreferenceController.mHourlyChartView = mHourlyChartView;
BatteryDiffEntry.clearCache(); BatteryDiffEntry.clearCache();
@@ -180,7 +184,6 @@ public final class BatteryChartPreferenceControllerTest {
mBatteryChartPreferenceController.mDailyChartLabelTextGenerator); mBatteryChartPreferenceController.mDailyChartLabelTextGenerator);
mBatteryChartPreferenceController.onBatteryLevelDataUpdate(createBatteryLevelData(60)); mBatteryChartPreferenceController.onBatteryLevelDataUpdate(createBatteryLevelData(60));
mBatteryChartPreferenceController.onBatteryUsageMapUpdate(getEmptyBatteryUsageMap());
verify(mDailyChartView, atLeastOnce()).setVisibility(View.VISIBLE); verify(mDailyChartView, atLeastOnce()).setVisibility(View.VISIBLE);
verify(mViewPropertyAnimator, atLeastOnce()).alpha(0f); verify(mViewPropertyAnimator, atLeastOnce()).alpha(0f);
@@ -275,29 +278,78 @@ public final class BatteryChartPreferenceControllerTest {
} }
@Test @Test
public void refreshUi_normalCase_returnTrue() { public void onBatteryLevelDataUpdate_oneDay_showHourlyChartOnly() {
doReturn(View.GONE).when(mHourlyChartView).getVisibility();
mBatteryChartPreferenceController.onBatteryLevelDataUpdate(createBatteryLevelData(6)); mBatteryChartPreferenceController.onBatteryLevelDataUpdate(createBatteryLevelData(6));
mBatteryChartPreferenceController.onBatteryUsageMapUpdate(getEmptyBatteryUsageMap());
assertThat(mBatteryChartPreferenceController.refreshUi()).isTrue(); verify(mChartSummaryTextView).setVisibility(View.VISIBLE);
verify(mDailyChartView).setVisibility(View.GONE);
verify(mHourlyChartView).setVisibility(View.VISIBLE);
} }
@Test @Test
public void refreshUi_batteryIndexedMapIsNull_returnTrue() { public void onBatteryLevelDataUpdate_selectAllForMultipleDays_showDailyChartOnly() {
doReturn(View.GONE).when(mHourlyChartView).getVisibility();
mBatteryChartPreferenceController.mDailyChartIndex = SELECTED_INDEX_ALL;
mBatteryChartPreferenceController.onBatteryLevelDataUpdate(createBatteryLevelData(60));
verify(mChartSummaryTextView).setVisibility(View.VISIBLE);
verify(mDailyChartView).setVisibility(View.VISIBLE);
verify(mHourlyChartView, never()).setVisibility(View.VISIBLE);
}
@Test
public void onBatteryLevelDataUpdate_selectOneDayForMultipleDays_showBothCharts() {
doReturn(View.GONE).when(mHourlyChartView).getVisibility();
mBatteryChartPreferenceController.mDailyChartIndex = 0;
mBatteryChartPreferenceController.onBatteryLevelDataUpdate(createBatteryLevelData(60));
verify(mChartSummaryTextView).setVisibility(View.VISIBLE);
verify(mDailyChartView).setVisibility(View.VISIBLE);
verify(mHourlyChartView).setVisibility(View.VISIBLE);
}
@Test
public void onBatteryLevelDataUpdate_batteryLevelDataIsNull_showNoChart() {
doReturn(View.GONE).when(mHourlyChartView).getVisibility();
mBatteryChartPreferenceController.onBatteryLevelDataUpdate(null); mBatteryChartPreferenceController.onBatteryLevelDataUpdate(null);
mBatteryChartPreferenceController.onBatteryUsageMapUpdate(getEmptyBatteryUsageMap());
assertThat(mBatteryChartPreferenceController.refreshUi()).isTrue(); verify(mChartSummaryTextView).setVisibility(View.GONE);
verify(mDailyChartView).setVisibility(View.GONE);
verify(mHourlyChartView).setVisibility(View.GONE);
}
@Test
public void showEmptyChart_normalCase_showEmptyChart() {
doReturn(View.GONE).when(mHourlyChartView).getVisibility();
mBatteryChartPreferenceController.showEmptyChart();
verify(mChartSummaryTextView).setVisibility(View.VISIBLE);
verify(mDailyChartView).setVisibility(View.GONE);
verify(mHourlyChartView).setVisibility(View.VISIBLE);
} }
@Test @Test
public void refreshUi_dailyChartViewIsNull_ignoreRefresh() { public void refreshUi_dailyChartViewIsNull_ignoreRefresh() {
mBatteryChartPreferenceController.mDailyChartView = null; mBatteryChartPreferenceController.mDailyChartView = null;
assertThat(mBatteryChartPreferenceController.refreshUi()).isFalse();
mBatteryChartPreferenceController.refreshUi();
verify(mChartSummaryTextView, never()).setVisibility(anyInt());
} }
@Test @Test
public void refreshUi_hourlyChartViewIsNull_ignoreRefresh() { public void refreshUi_hourlyChartViewIsNull_ignoreRefresh() {
mBatteryChartPreferenceController.mHourlyChartView = null; mBatteryChartPreferenceController.mHourlyChartView = null;
assertThat(mBatteryChartPreferenceController.refreshUi()).isFalse();
mBatteryChartPreferenceController.refreshUi();
verify(mChartSummaryTextView, never()).setVisibility(anyInt());
} }
@Test @Test
@@ -408,57 +460,6 @@ public final class BatteryChartPreferenceControllerTest {
assertThat(totalHour).isEqualTo(59); assertThat(totalHour).isEqualTo(59);
} }
@Test
public void getHighestScoreAnomalyEvent_withEmptyOrNullList_getNull() {
assertThat(mBatteryChartPreferenceController.getHighestScoreAnomalyEvent(null))
.isEqualTo(null);
assertThat(mBatteryChartPreferenceController.getHighestScoreAnomalyEvent(
BatteryTestUtils.createEmptyPowerAnomalyEventList()))
.isEqualTo(null);
}
@Test
public void getHighestScoreAnomalyEvent_withoutDismissed_getHighestScoreEvent() {
final PowerAnomalyEventList eventList =
BatteryTestUtils.createNonEmptyPowerAnomalyEventList();
final PowerAnomalyEvent highestScoreEvent =
mBatteryChartPreferenceController.getHighestScoreAnomalyEvent(eventList);
assertThat(highestScoreEvent)
.isEqualTo(BatteryTestUtils.createAdaptiveBrightnessAnomalyEvent());
}
@Test
public void getHighestScoreAnomalyEvent_withBrightnessDismissed_getScreenTimeout() {
final PowerAnomalyEventList eventList =
BatteryTestUtils.createNonEmptyPowerAnomalyEventList();
DatabaseUtils.removeDismissedPowerAnomalyKeys(mContext);
DatabaseUtils.setDismissedPowerAnomalyKeys(mContext, PowerAnomalyKey.KEY_BRIGHTNESS.name());
final PowerAnomalyEvent highestScoreEvent =
mBatteryChartPreferenceController.getHighestScoreAnomalyEvent(eventList);
assertThat(highestScoreEvent)
.isEqualTo(BatteryTestUtils.createScreenTimeoutAnomalyEvent());
}
@Test
public void getHighestScoreAnomalyEvent_withAllDismissed_getNull() {
final PowerAnomalyEventList eventList =
BatteryTestUtils.createNonEmptyPowerAnomalyEventList();
DatabaseUtils.removeDismissedPowerAnomalyKeys(mContext);
for (PowerAnomalyKey key : PowerAnomalyKey.values()) {
DatabaseUtils.setDismissedPowerAnomalyKeys(mContext, key.name());
}
final PowerAnomalyEvent highestScoreEvent =
mBatteryChartPreferenceController.getHighestScoreAnomalyEvent(eventList);
assertThat(highestScoreEvent).isEqualTo(null);
}
private static Long generateTimestamp(int index) { private static Long generateTimestamp(int index) {
// "2021-04-23 07:00:00 UTC" + index hours // "2021-04-23 07:00:00 UTC" + index hours
return 1619247600000L + index * DateUtils.HOUR_IN_MILLIS; return 1619247600000L + index * DateUtils.HOUR_IN_MILLIS;
@@ -481,11 +482,6 @@ public final class BatteryChartPreferenceControllerTest {
return new BatteryLevelData(batteryLevelMap); return new BatteryLevelData(batteryLevelMap);
} }
private static Map<Integer, Map<Integer, BatteryDiffData>> getEmptyBatteryUsageMap() {
return Map.of(SELECTED_INDEX_ALL, Map.of(SELECTED_INDEX_ALL, new BatteryDiffData(
null, 0, 0, 0, 0, 0, List.of(), List.of(), Set.of(), Set.of(), false)));
}
private BatteryChartPreferenceController createController() { private BatteryChartPreferenceController createController() {
final BatteryChartPreferenceController controller = final BatteryChartPreferenceController controller =
new BatteryChartPreferenceController( new BatteryChartPreferenceController(

View File

@@ -0,0 +1,92 @@
/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.fuelgauge.batteryusage;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.spy;
import android.content.Context;
import com.android.settings.testutils.BatteryTestUtils;
import com.android.settings.testutils.shadow.ShadowDashboardFragment;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
@RunWith(RobolectricTestRunner.class)
@Config(shadows = ShadowDashboardFragment.class)
public final class PowerUsageAdvancedTest {
private Context mContext;
@Before
public void setUp() {
mContext = spy(RuntimeEnvironment.application);
}
@Test
public void getHighestScoreAnomalyEvent_withEmptyOrNullList_getNull() {
assertThat(PowerUsageAdvanced.getHighestScoreAnomalyEvent(mContext, null)).isNull();
assertThat(PowerUsageAdvanced.getHighestScoreAnomalyEvent(
mContext, BatteryTestUtils.createEmptyPowerAnomalyEventList())).isNull();
}
@Test
public void getHighestScoreAnomalyEvent_withoutDismissed_getHighestScoreEvent() {
final PowerAnomalyEventList powerAnomalyEventList =
BatteryTestUtils.createNonEmptyPowerAnomalyEventList();
final PowerAnomalyEvent highestScoreEvent =
PowerUsageAdvanced.getHighestScoreAnomalyEvent(mContext, powerAnomalyEventList);
assertThat(highestScoreEvent)
.isEqualTo(BatteryTestUtils.createAdaptiveBrightnessAnomalyEvent());
}
@Test
public void getHighestScoreAnomalyEvent_withBrightnessDismissed_getScreenTimeout() {
final PowerAnomalyEventList powerAnomalyEventList =
BatteryTestUtils.createNonEmptyPowerAnomalyEventList();
DatabaseUtils.removeDismissedPowerAnomalyKeys(mContext);
DatabaseUtils.setDismissedPowerAnomalyKeys(mContext, PowerAnomalyKey.KEY_BRIGHTNESS.name());
final PowerAnomalyEvent highestScoreEvent =
PowerUsageAdvanced.getHighestScoreAnomalyEvent(mContext, powerAnomalyEventList);
assertThat(highestScoreEvent)
.isEqualTo(BatteryTestUtils.createScreenTimeoutAnomalyEvent());
}
@Test
public void getHighestScoreAnomalyEvent_withAllDismissed_getNull() {
final PowerAnomalyEventList powerAnomalyEventList =
BatteryTestUtils.createNonEmptyPowerAnomalyEventList();
DatabaseUtils.removeDismissedPowerAnomalyKeys(mContext);
for (PowerAnomalyKey key : PowerAnomalyKey.values()) {
DatabaseUtils.setDismissedPowerAnomalyKeys(mContext, key.name());
}
final PowerAnomalyEvent highestScoreEvent =
PowerUsageAdvanced.getHighestScoreAnomalyEvent(mContext, powerAnomalyEventList);
assertThat(highestScoreEvent).isEqualTo(null);
}
}