Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 180051cf authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Refine the interpolation rule and clip the usage time data" into sc-dev

parents ac1b7661 4280a7f8
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -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(
+45 −17
Original line number Diff line number Diff line
@@ -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,
@@ -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();
                }
            }
+68 −6
Original line number Diff line number Diff line
@@ -140,6 +140,21 @@ public final class ConvertUtilsTest {
            .isEqualTo(ConvertUtils.FAKE_PACKAGE_NAME);
    }

    @Test
    public void testGetIndexedUsageMap_nullOrEmptyHistoryMap_returnEmptyCollection() {
        final int timeSlotSize = 2;
        final long[] batteryHistoryKeys = new long[] {101L, 102L, 103L, 104L, 105L};

        assertThat(ConvertUtils.getIndexedUsageMap(
                mContext, timeSlotSize, batteryHistoryKeys,
                /*batteryHistoryMap=*/ null, /*purgeLowPercentageAndFakeData=*/ true))
            .isEmpty();
        assertThat(ConvertUtils.getIndexedUsageMap(
                mContext, timeSlotSize, batteryHistoryKeys,
                new HashMap<Long, Map<String, BatteryHistEntry>>(),
                /*purgeLowPercentageAndFakeData=*/ true))
            .isEmpty();
    }
    @Test
    public void testGetIndexedUsageMap_returnsExpectedResult() {
        // Creates the fake testing data.
@@ -147,21 +162,25 @@ public final class ConvertUtilsTest {
        final long[] batteryHistoryKeys = new long[] {101L, 102L, 103L, 104L, 105L};
        final Map<Long, Map<String, BatteryHistEntry>> batteryHistoryMap =
            new HashMap<>();
        final BatteryHistEntry fakeEntry = createBatteryHistEntry(
            ConvertUtils.FAKE_PACKAGE_NAME, "fake_label", 0, 0L, 0L, 0L);
        // Adds the index = 0 data.
        Map<String, BatteryHistEntry> entryMap = new HashMap<>();
        BatteryHistEntry entry = createBatteryHistEntry(
            "package1", "label1", 5.0, 1L, 10L, 20L);
        entryMap.put(entry.getKey(), entry);
        entryMap.put(fakeEntry.getKey(), fakeEntry);
        batteryHistoryMap.put(Long.valueOf(batteryHistoryKeys[0]), entryMap);
        // Adds the index = 1 data.
        batteryHistoryMap.put(
            Long.valueOf(batteryHistoryKeys[1]),
            new HashMap<String, BatteryHistEntry>());
        entryMap = new HashMap<>();
        entryMap.put(fakeEntry.getKey(), fakeEntry);
        batteryHistoryMap.put(Long.valueOf(batteryHistoryKeys[1]), entryMap);
        // Adds the index = 2 data.
        entryMap = new HashMap<>();
        entry = createBatteryHistEntry(
            "package2", "label2", 10.0, 2L, 15L, 25L);
        entryMap.put(entry.getKey(), entry);
        entryMap.put(fakeEntry.getKey(), fakeEntry);
        batteryHistoryMap.put(Long.valueOf(batteryHistoryKeys[2]), entryMap);
        // Adds the index = 3 data.
        entryMap = new HashMap<>();
@@ -171,6 +190,7 @@ public final class ConvertUtilsTest {
        entry = createBatteryHistEntry(
            "package3", "label3", 5.0, 3L, 5L, 5L);
        entryMap.put(entry.getKey(), entry);
        entryMap.put(fakeEntry.getKey(), fakeEntry);
        batteryHistoryMap.put(Long.valueOf(batteryHistoryKeys[3]), entryMap);
        // Adds the index = 4 data.
        entryMap = new HashMap<>();
@@ -183,12 +203,13 @@ public final class ConvertUtilsTest {
        entry = createBatteryHistEntry(
            "package3", "label3", 5.0, 3L, 5L, 5L);
        entryMap.put(entry.getKey(), entry);
        entryMap.put(fakeEntry.getKey(), fakeEntry);
        batteryHistoryMap.put(Long.valueOf(batteryHistoryKeys[4]), entryMap);

        final Map<Integer, List<BatteryDiffEntry>> resultMap =
            ConvertUtils.getIndexedUsageMap(
                mContext, timeSlotSize, batteryHistoryKeys, batteryHistoryMap,
                /*purgeLowPercentageData=*/ false);
                /*purgeLowPercentageAndFakeData=*/ false);

        assertThat(resultMap).hasSize(3);
        // Verifies the first timestamp result.
@@ -213,7 +234,7 @@ public final class ConvertUtilsTest {
        final Map<Integer, List<BatteryDiffEntry>> purgedResultMap =
            ConvertUtils.getIndexedUsageMap(
                mContext, timeSlotSize, batteryHistoryKeys, batteryHistoryMap,
                 /*purgeLowPercentageData=*/ true);
                 /*purgeLowPercentageAndFakeData=*/ true);

        assertThat(purgedResultMap).hasSize(3);
        // Verifies the first timestamp result.
@@ -225,8 +246,49 @@ public final class ConvertUtilsTest {
        assertBatteryDiffEntry(entryList.get(0), 75, 40L, 50L);
        // Verifies the last 24 hours aggregate result.
        entryList = purgedResultMap.get(Integer.valueOf(-1));
        assertThat(entryList).hasSize(2);
        // Verifies the fake data is cleared out.
        assertThat(entryList.get(0).getPackageName())
            .isNotEqualTo(ConvertUtils.FAKE_PACKAGE_NAME);
        assertThat(entryList.get(1).getPackageName())
            .isNotEqualTo(ConvertUtils.FAKE_PACKAGE_NAME);
    }

    @Test
    public void testGetIndexedUsageMap_usageTimeExceed_returnsExpectedResult() {
        final int timeSlotSize = 1;
        final long[] batteryHistoryKeys = new long[] {101L, 102L, 103L};
        final Map<Long, Map<String, BatteryHistEntry>> batteryHistoryMap =
            new HashMap<>();
        final BatteryHistEntry fakeEntry = createBatteryHistEntry(
            ConvertUtils.FAKE_PACKAGE_NAME, "fake_label", 0, 0L, 0L, 0L);
        // Adds the index = 0 data.
        Map<String, BatteryHistEntry> entryMap = new HashMap<>();
        entryMap.put(fakeEntry.getKey(), fakeEntry);
        batteryHistoryMap.put(Long.valueOf(batteryHistoryKeys[0]), entryMap);
        // Adds the index = 1 data.
        entryMap = new HashMap<>();
        entryMap.put(fakeEntry.getKey(), fakeEntry);
        batteryHistoryMap.put(Long.valueOf(batteryHistoryKeys[1]), entryMap);
        // Adds the index = 2 data.
        entryMap = new HashMap<>();
        final BatteryHistEntry entry = createBatteryHistEntry(
            "package3", "label3", 500, 5L, 3600000L, 7200000L);
        entryMap.put(entry.getKey(), entry);
        batteryHistoryMap.put(Long.valueOf(batteryHistoryKeys[2]), entryMap);

        final Map<Integer, List<BatteryDiffEntry>> purgedResultMap =
            ConvertUtils.getIndexedUsageMap(
                mContext, timeSlotSize, batteryHistoryKeys, batteryHistoryMap,
                 /*purgeLowPercentageAndFakeData=*/ true);

        assertThat(purgedResultMap).hasSize(2);
        final List<BatteryDiffEntry> entryList = purgedResultMap.get(0);
        assertThat(entryList).hasSize(1);
        assertBatteryDiffEntry(entryList.get(0), 68, 40L, 50L);
        // Verifies the clipped usage time.
        final BatteryDiffEntry resultEntry = entryList.get(0);
        assertThat(resultEntry.mForegroundUsageTimeInMs).isEqualTo(2400000);
        assertThat(resultEntry.mBackgroundUsageTimeInMs).isEqualTo(4800000);
    }

    @Test