Refactor battery usage page contollers interaction logic
(1) Move controllers interaction logic from BatteryChartPreferenceController to main page PowerUsageAdvanced. (2) Move query power anomaly logic to DataProcessManager async job. Bug: 284893240 Test: manual Change-Id: Ib23b338fe3946e68ff73a372342ec5d86494c566 Merged-In: Ib23b338fe3946e68ff73a372342ec5d86494c566
This commit is contained in:
@@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
@VisibleForTesting
|
// Show empty hourly chart view only if there is no valid battery usage data.
|
||||||
boolean refreshUi() {
|
void showEmptyChart() {
|
||||||
if (mDailyChartView == null || mHourlyChartView == null) {
|
setChartSummaryVisible(true);
|
||||||
// Chart views are not initialized.
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// When mDailyViewModel or mHourlyViewModels is null, there is no battery level data.
|
|
||||||
// This is mainly in 2 cases:
|
|
||||||
// 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);
|
|
||||||
mHourlyChartView.setVisibility(View.GONE);
|
|
||||||
mDailyChartView.setViewModel(null);
|
|
||||||
mHourlyChartView.setViewModel(null);
|
|
||||||
return false;
|
|
||||||
} 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);
|
mDailyChartView.setVisibility(View.GONE);
|
||||||
mHourlyChartView.setVisibility(View.VISIBLE);
|
mHourlyChartView.setVisibility(View.VISIBLE);
|
||||||
mHourlyChartView.setViewModel(null);
|
mHourlyChartView.setViewModel(null);
|
||||||
}
|
}
|
||||||
return true;
|
|
||||||
|
@VisibleForTesting
|
||||||
|
void refreshUi() {
|
||||||
|
if (mDailyChartView == null || mHourlyChartView == null) {
|
||||||
|
// Chart views are not initialized.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mDailyViewModel == null || mHourlyViewModels == null) {
|
||||||
|
setChartSummaryVisible(false);
|
||||||
|
mDailyChartView.setVisibility(View.GONE);
|
||||||
|
mHourlyChartView.setVisibility(View.GONE);
|
||||||
|
mDailyChartView.setViewModel(null);
|
||||||
|
mHourlyChartView.setViewModel(null);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
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) {
|
||||||
|
@@ -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);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@@ -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(
|
||||||
|
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user