Refine the interpolation rule and clip the usage time data

Bug: 184807417
Test: make SettingsRoboTests
Change-Id: I6c115beed34abd393e5c615cc59d3c4c323dfa0b
This commit is contained in:
ykhung
2021-05-07 12:27:38 +08:00
parent 3b6e225a5c
commit 4280a7f897
3 changed files with 114 additions and 24 deletions

View File

@@ -223,7 +223,7 @@ public class BatteryChartPreferenceController extends AbstractPreferenceControll
ConvertUtils.getIndexedUsageMap(
mPrefContext, /*timeSlotSize=*/ CHART_LEVEL_ARRAY_SIZE - 1,
mBatteryHistoryKeys, batteryHistoryMap,
/*purgeLowPercentageData=*/ true);
/*purgeLowPercentageAndFakeData=*/ true);
forceRefreshUi();
Log.d(TAG, String.format(

View File

@@ -18,12 +18,15 @@ import android.content.ContentValues;
import android.content.Context;
import android.os.BatteryUsageStats;
import android.os.UserHandle;
import android.text.format.DateUtils;
import android.util.Log;
import androidx.annotation.VisibleForTesting;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.text.SimpleDateFormat;
import java.time.Duration;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
@@ -41,6 +44,8 @@ public final class ConvertUtils {
private static final Map<String, BatteryHistEntry> EMPTY_BATTERY_MAP = new HashMap<>();
private static final BatteryHistEntry EMPTY_BATTERY_HIST_ENTRY =
new BatteryHistEntry(new ContentValues());
// Maximum total time value for each slot cumulative data at most 2 hours.
private static final float TOTAL_TIME_THRESHOLD = DateUtils.HOUR_IN_MILLIS * 2;
@VisibleForTesting
static double PERCENTAGE_OF_TOTAL_THRESHOLD = 1f;
@@ -145,7 +150,10 @@ public final class ConvertUtils {
final int timeSlotSize,
final long[] batteryHistoryKeys,
final Map<Long, Map<String, BatteryHistEntry>> batteryHistoryMap,
final boolean purgeLowPercentageData) {
final boolean purgeLowPercentageAndFakeData) {
if (batteryHistoryMap == null || batteryHistoryMap.isEmpty()) {
return new HashMap<>();
}
final Map<Integer, List<BatteryDiffEntry>> resultMap = new HashMap<>();
// Each time slot usage diff data =
// Math.abs(timestamp[i+2] data - timestamp[i+1] data) +
@@ -155,16 +163,10 @@ public final class ConvertUtils {
for (int index = 0; index < timeSlotSize; index++) {
final Long currentTimestamp =
Long.valueOf(batteryHistoryKeys[index * timestampStride]);
// Uses empty list if the timestamp is default value.
if (currentTimestamp == 0) {
resultMap.put(Integer.valueOf(index), new ArrayList<BatteryDiffEntry>());
continue;
}
final Long nextTimestamp =
Long.valueOf(batteryHistoryKeys[index * timestampStride + 1]);
final Long nextTwoTimestamp =
Long.valueOf(batteryHistoryKeys[index * timestampStride + 2]);
// Fetches BatteryHistEntry data from corresponding time slot.
final Map<String, BatteryHistEntry> currentBatteryHistMap =
batteryHistoryMap.getOrDefault(currentTimestamp, EMPTY_BATTERY_MAP);
@@ -172,8 +174,17 @@ public final class ConvertUtils {
batteryHistoryMap.getOrDefault(nextTimestamp, EMPTY_BATTERY_MAP);
final Map<String, BatteryHistEntry> nextTwoBatteryHistMap =
batteryHistoryMap.getOrDefault(nextTwoTimestamp, EMPTY_BATTERY_MAP);
// We should not get the empty list since we have at least one fake data to record
// the battery level and status in each time slot, the empty list is used to
// represent there is no enough data to apply interpolation arithmetic.
if (currentBatteryHistMap.isEmpty()
|| nextBatteryHistMap.isEmpty()
|| nextTwoBatteryHistMap.isEmpty()) {
resultMap.put(Integer.valueOf(index), new ArrayList<BatteryDiffEntry>());
continue;
}
// Collects all keys in these three time slot records as population.
// Collects all keys in these three time slot records as all populations.
final Set<String> allBatteryHistEntryKeys = new HashSet<>();
allBatteryHistEntryKeys.addAll(currentBatteryHistMap.keySet());
allBatteryHistEntryKeys.addAll(nextBatteryHistMap.keySet());
@@ -193,12 +204,12 @@ public final class ConvertUtils {
final BatteryHistEntry nextTwoEntry =
nextTwoBatteryHistMap.getOrDefault(key, EMPTY_BATTERY_HIST_ENTRY);
// Cumulative values is a specific time slot for a specific app.
final long foregroundUsageTimeInMs =
long foregroundUsageTimeInMs =
getDiffValue(
currentEntry.mForegroundUsageTimeInMs,
nextEntry.mForegroundUsageTimeInMs,
nextTwoEntry.mForegroundUsageTimeInMs);
final long backgroundUsageTimeInMs =
long backgroundUsageTimeInMs =
getDiffValue(
currentEntry.mBackgroundUsageTimeInMs,
nextEntry.mBackgroundUsageTimeInMs,
@@ -212,8 +223,8 @@ public final class ConvertUtils {
// Excludes entry since we don't have enough data to calculate.
if (foregroundUsageTimeInMs == 0
&& backgroundUsageTimeInMs == 0
&& consumePower == 0) {
&& backgroundUsageTimeInMs == 0
&& consumePower == 0) {
continue;
}
final BatteryHistEntry selectedBatteryEntry =
@@ -221,6 +232,21 @@ public final class ConvertUtils {
if (selectedBatteryEntry == null) {
continue;
}
// Force refine the cumulative value since it may introduce deviation
// error since we will apply the interpolation arithmetic.
final float totalUsageTimeInMs =
foregroundUsageTimeInMs + backgroundUsageTimeInMs;
if (totalUsageTimeInMs > TOTAL_TIME_THRESHOLD) {
final float ratio = TOTAL_TIME_THRESHOLD / totalUsageTimeInMs;
Log.w(TAG, String.format("abnormal usage time %d|%d for:\n%s",
Duration.ofMillis(foregroundUsageTimeInMs).getSeconds(),
Duration.ofMillis(backgroundUsageTimeInMs).getSeconds(),
currentEntry));
foregroundUsageTimeInMs =
Math.round(foregroundUsageTimeInMs * ratio);
backgroundUsageTimeInMs =
Math.round(backgroundUsageTimeInMs * ratio);
}
batteryDiffEntryList.add(
new BatteryDiffEntry(
context,
@@ -234,10 +260,10 @@ public final class ConvertUtils {
diffEntry.setTotalConsumePower(totalConsumePower);
}
}
insert24HoursData(BatteryChartView.SELECTED_INDEX_ALL, resultMap);
if (purgeLowPercentageData) {
purgeLowPercentageData(resultMap);
if (purgeLowPercentageAndFakeData) {
purgeLowPercentageAndFakeData(resultMap);
}
insert24HoursData(BatteryChartView.SELECTED_INDEX_ALL, resultMap);
return resultMap;
}
@@ -273,13 +299,15 @@ public final class ConvertUtils {
indexedUsageMap.put(Integer.valueOf(desiredIndex), resultList);
}
private static void purgeLowPercentageData(
// Removes low percentage data and fake usage data, which will be zero value.
private static void purgeLowPercentageAndFakeData(
final Map<Integer, List<BatteryDiffEntry>> indexedUsageMap) {
for (List<BatteryDiffEntry> entries : indexedUsageMap.values()) {
final Iterator<BatteryDiffEntry> iterator = entries.iterator();
while (iterator.hasNext()) {
final BatteryDiffEntry entry = iterator.next();
if (entry.getPercentOfTotal() < PERCENTAGE_OF_TOTAL_THRESHOLD) {
if (entry.getPercentOfTotal() < PERCENTAGE_OF_TOTAL_THRESHOLD
|| FAKE_PACKAGE_NAME.equals(entry.getPackageName())) {
iterator.remove();
}
}