App anomaly tips on PowerUsage App list
Screenshots: [in bg - banner] https://screenshot.googleplex.com/MzLC6LfX93TkkYf [in bg - hints] https://screenshot.googleplex.com/9JLXNsRiVG8arAU [in fg - banner] https://screenshot.googleplex.com/9oYbwUkeeLbQX2t [in fg - hints] https://screenshot.googleplex.com/53DTTUCUnf8rsoE [apps anomaly highlight hint + settings anomaly banner] https://screenshot.googleplex.com/8NdS2VMrSzwv2DM Bug: 291689643 Bug: 291689623 Test: manual (cherry picked from https://googleplex-android-review.googlesource.com/q/commit:bfd0f5859b6e5ffef4727ee562009f2050de7a58) Change-Id: Ic02db49cb3794ef134759d9dcec5f5ef32454a95
This commit is contained in:
@@ -52,6 +52,7 @@ import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
/** Advanced power usage. */
|
||||
@SearchIndexable(forTarget = SearchIndexable.ALL & ~SearchIndexable.ARC)
|
||||
@@ -92,9 +93,9 @@ public class PowerUsageAdvanced extends PowerUsageBase {
|
||||
@VisibleForTesting
|
||||
BatteryUsageBreakdownController mBatteryUsageBreakdownController;
|
||||
@VisibleForTesting
|
||||
PowerAnomalyEvent mPowerAnomalyEvent;
|
||||
@VisibleForTesting
|
||||
Optional<BatteryLevelData> mBatteryLevelData;
|
||||
@VisibleForTesting
|
||||
Optional<AnomalyEventWrapper> mHighlightEventWrapper;
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle icicle) {
|
||||
@@ -188,7 +189,7 @@ public class PowerUsageAdvanced extends PowerUsageBase {
|
||||
mIsChartDataLoaded = true;
|
||||
mBatteryLevelData = null;
|
||||
mBatteryUsageMap = null;
|
||||
mPowerAnomalyEvent = null;
|
||||
mHighlightEventWrapper = null;
|
||||
restartLoader(LoaderIndex.BATTERY_LEVEL_DATA_LOADER, bundle,
|
||||
mBatteryLevelDataLoaderCallbacks);
|
||||
}
|
||||
@@ -239,8 +240,13 @@ public class PowerUsageAdvanced extends PowerUsageBase {
|
||||
mScreenOnTimeController.handleSceenOnTimeUpdated(
|
||||
slotUsageData.getScreenOnTime(), slotInformation);
|
||||
}
|
||||
// Hide card tips if the related highlight slot was clicked.
|
||||
if (isAppsAnomalyEventFocused()) {
|
||||
mBatteryTipsController.acceptTipsCard();
|
||||
}
|
||||
mBatteryUsageBreakdownController.handleBatteryUsageUpdated(
|
||||
slotUsageData, slotInformation, isBatteryUsageMapNullOrEmpty());
|
||||
slotUsageData, slotInformation, isBatteryUsageMapNullOrEmpty(),
|
||||
isAppsAnomalyEventFocused(), mHighlightEventWrapper);
|
||||
Log.d(TAG, String.format("Battery usage list shows in %d millis",
|
||||
System.currentTimeMillis() - mResumeTimestamp));
|
||||
}
|
||||
@@ -261,49 +267,95 @@ public class PowerUsageAdvanced extends PowerUsageBase {
|
||||
return;
|
||||
}
|
||||
Log.d(TAG, "anomalyEventList = " + anomalyEventList);
|
||||
final PowerAnomalyEvent displayEvent =
|
||||
getHighestScoreAnomalyEvent(getContext(), anomalyEventList);
|
||||
onDisplayAnomalyEventUpdated(displayEvent);
|
||||
|
||||
final Set<String> dismissedPowerAnomalyKeys =
|
||||
DatabaseUtils.getDismissedPowerAnomalyKeys(getContext());
|
||||
Log.d(TAG, "dismissedPowerAnomalyKeys = " + dismissedPowerAnomalyKeys);
|
||||
|
||||
// Choose an app anomaly event with highest score to show highlight slot
|
||||
final PowerAnomalyEvent highlightEvent =
|
||||
getAnomalyEvent(anomalyEventList, PowerAnomalyEvent::hasWarningItemInfo);
|
||||
// Choose an event never dismissed to show as card.
|
||||
// If the slot is already highlighted, the tips card should be the corresponding app
|
||||
// or settings anomaly event.
|
||||
final PowerAnomalyEvent tipsCardEvent =
|
||||
getAnomalyEvent(anomalyEventList,
|
||||
event -> !dismissedPowerAnomalyKeys.contains(event.getDismissRecordKey())
|
||||
&& (event.equals(highlightEvent) || !event.hasWarningItemInfo()));
|
||||
onDisplayAnomalyEventUpdated(tipsCardEvent, highlightEvent);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
void onDisplayAnomalyEventUpdated(PowerAnomalyEvent event) {
|
||||
mPowerAnomalyEvent = event;
|
||||
void onDisplayAnomalyEventUpdated(
|
||||
PowerAnomalyEvent tipsCardEvent, PowerAnomalyEvent highlightEvent) {
|
||||
if (mBatteryTipsController == null
|
||||
|| mBatteryChartPreferenceController == null
|
||||
|| mBatteryUsageBreakdownController == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final boolean isSameAnomalyEvent = (tipsCardEvent == highlightEvent);
|
||||
// Update battery tips card preference & behaviour
|
||||
mBatteryTipsController.setOnAnomalyConfirmListener(null);
|
||||
mBatteryTipsController.setOnAnomalyRejectListener(null);
|
||||
mBatteryTipsController.handleBatteryTipsCardUpdated(mPowerAnomalyEvent);
|
||||
final AnomalyEventWrapper tipsCardEventWrapper = (tipsCardEvent == null) ? null :
|
||||
new AnomalyEventWrapper(getContext(), tipsCardEvent);
|
||||
if (tipsCardEventWrapper != null) {
|
||||
tipsCardEventWrapper.setRelatedBatteryDiffEntry(
|
||||
findRelatedBatteryDiffEntry(tipsCardEventWrapper));
|
||||
}
|
||||
mBatteryTipsController.handleBatteryTipsCardUpdated(
|
||||
tipsCardEventWrapper, isSameAnomalyEvent);
|
||||
|
||||
// Update highlight slot effect in battery chart view
|
||||
Pair<Integer, Integer> highlightSlotIndexPair = Pair.create(
|
||||
BatteryChartViewModel.SELECTED_INDEX_INVALID,
|
||||
BatteryChartViewModel.SELECTED_INDEX_INVALID);
|
||||
if (mPowerAnomalyEvent != null && mPowerAnomalyEvent.hasWarningItemInfo()) {
|
||||
final WarningItemInfo warningItemInfo = mPowerAnomalyEvent.getWarningItemInfo();
|
||||
final Long startTimestamp = warningItemInfo.hasStartTimestamp()
|
||||
? warningItemInfo.getStartTimestamp() : null;
|
||||
final Long endTimestamp = warningItemInfo.hasEndTimestamp()
|
||||
? warningItemInfo.getEndTimestamp() : null;
|
||||
if (startTimestamp != null && endTimestamp != null) {
|
||||
highlightSlotIndexPair = mBatteryLevelData.map(levelData ->
|
||||
levelData.getIndexByTimestamps(startTimestamp, endTimestamp))
|
||||
.orElse(highlightSlotIndexPair);
|
||||
mBatteryTipsController.setOnAnomalyConfirmListener(
|
||||
mBatteryChartPreferenceController::selectHighlightSlotIndex);
|
||||
mBatteryTipsController.setOnAnomalyRejectListener(
|
||||
() -> onDisplayAnomalyEventUpdated(null));
|
||||
mHighlightEventWrapper = Optional.ofNullable(isSameAnomalyEvent ? tipsCardEventWrapper :
|
||||
((highlightEvent != null)
|
||||
? new AnomalyEventWrapper(getContext(), highlightEvent) : null));
|
||||
if (mBatteryLevelData != null && mBatteryLevelData.isPresent()
|
||||
&& mHighlightEventWrapper.isPresent()
|
||||
&& mHighlightEventWrapper.get().hasHighlightSlotPair(mBatteryLevelData.get())) {
|
||||
highlightSlotIndexPair = mHighlightEventWrapper.get()
|
||||
.getHighlightSlotPair(mBatteryLevelData.get());
|
||||
if (isSameAnomalyEvent) {
|
||||
// For main button, focus on highlight slot when clicked
|
||||
mBatteryTipsController.setOnAnomalyConfirmListener(() -> {
|
||||
mBatteryChartPreferenceController.selectHighlightSlotIndex();
|
||||
mBatteryTipsController.acceptTipsCard();
|
||||
});
|
||||
}
|
||||
}
|
||||
mBatteryChartPreferenceController.onHighlightSlotIndexUpdate(
|
||||
highlightSlotIndexPair.first, highlightSlotIndexPair.second);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
BatteryDiffEntry findRelatedBatteryDiffEntry(AnomalyEventWrapper eventWrapper) {
|
||||
if (eventWrapper == null
|
||||
|| mBatteryLevelData == null || mBatteryLevelData.isEmpty()
|
||||
|| !eventWrapper.hasHighlightSlotPair(mBatteryLevelData.get())
|
||||
|| !eventWrapper.hasAnomalyEntryKey()
|
||||
|| mBatteryUsageMap == null) {
|
||||
return null;
|
||||
}
|
||||
final Pair<Integer, Integer> highlightSlotIndexPair =
|
||||
eventWrapper.getHighlightSlotPair(mBatteryLevelData.get());
|
||||
final BatteryDiffData relatedDiffData = mBatteryUsageMap
|
||||
.get(highlightSlotIndexPair.first).get(highlightSlotIndexPair.second);
|
||||
final String anomalyEntryKey = eventWrapper.getAnomalyEntryKey();
|
||||
if (relatedDiffData == null || anomalyEntryKey == null) {
|
||||
return null;
|
||||
}
|
||||
for (BatteryDiffEntry entry : relatedDiffData.getAppDiffEntryList()) {
|
||||
if (anomalyEntryKey.equals(entry.getKey())) {
|
||||
return entry;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private void setBatteryChartPreferenceController() {
|
||||
if (mHistPref != null && mBatteryChartPreferenceController != null) {
|
||||
mHistPref.setChartPreferenceController(mBatteryChartPreferenceController);
|
||||
@@ -318,6 +370,11 @@ public class PowerUsageAdvanced extends PowerUsageBase {
|
||||
&& allBatteryDiffData.getSystemDiffEntryList().isEmpty());
|
||||
}
|
||||
|
||||
private boolean isAppsAnomalyEventFocused() {
|
||||
return mBatteryChartPreferenceController != null
|
||||
&& mBatteryChartPreferenceController.isHighlightSlotFocused();
|
||||
}
|
||||
|
||||
private void logScreenUsageTime() {
|
||||
final BatteryDiffData allBatteryDiffData = getAllBatteryDiffData(mBatteryUsageMap);
|
||||
if (allBatteryDiffData == null) {
|
||||
@@ -338,25 +395,22 @@ public class PowerUsageAdvanced extends PowerUsageBase {
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
static PowerAnomalyEvent getHighestScoreAnomalyEvent(
|
||||
Context context, PowerAnomalyEventList anomalyEventList) {
|
||||
static PowerAnomalyEvent getAnomalyEvent(
|
||||
PowerAnomalyEventList anomalyEventList, Predicate<PowerAnomalyEvent> predicate) {
|
||||
if (anomalyEventList == null || anomalyEventList.getPowerAnomalyEventsCount() == 0) {
|
||||
return null;
|
||||
}
|
||||
final Set<String> dismissedPowerAnomalyKeys =
|
||||
DatabaseUtils.getDismissedPowerAnomalyKeys(context);
|
||||
Log.d(TAG, "dismissedPowerAnomalyKeys = " + dismissedPowerAnomalyKeys);
|
||||
|
||||
final PowerAnomalyEvent highestScoreEvent = anomalyEventList.getPowerAnomalyEventsList()
|
||||
final PowerAnomalyEvent filterAnomalyEvent = anomalyEventList.getPowerAnomalyEventsList()
|
||||
.stream()
|
||||
.filter(event -> !dismissedPowerAnomalyKeys.contains(
|
||||
BatteryTipsController.getDismissRecordKey(event)))
|
||||
.filter(predicate)
|
||||
.max(Comparator.comparing(PowerAnomalyEvent::getScore))
|
||||
.orElse(null);
|
||||
Log.d(TAG, "highestScoreAnomalyEvent = " + highestScoreEvent);
|
||||
return highestScoreEvent;
|
||||
Log.d(TAG, "filterAnomalyEvent = " + filterAnomalyEvent);
|
||||
return filterAnomalyEvent;
|
||||
}
|
||||
|
||||
|
||||
private static BatteryDiffData getAllBatteryDiffData(
|
||||
Map<Integer, Map<Integer, BatteryDiffData>> batteryUsageMap) {
|
||||
return batteryUsageMap == null ? null : batteryUsageMap
|
||||
|
Reference in New Issue
Block a user