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

Commit 1871275f authored by YUKAI HUNG's avatar YUKAI HUNG Committed by Android (Google) Code Review
Browse files

Merge changes I7771a43b,If613c5cf into sc-dev

* changes:
  Inserts last 24 hour agrregate data into indexed usage map
  Add a method to calculate battery usage diff results from history
parents 6f0a0da4 0d54b75b
Loading
Loading
Loading
Loading
+77 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2021 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;

import java.time.Duration;

/** A container class to carry battery data in a specific time slot. */
public final class BatteryDiffEntry {
    private static final String TAG = "BatteryDiffEntry";

    public long mForegroundUsageTimeInMs;
    public long mBackgroundUsageTimeInMs;
    public double mConsumePower;
    // A BatteryHistEntry corresponding to this diff usage data.
    public final BatteryHistEntry mBatteryHistEntry;

    private double mTotalConsumePower;
    private double mPercentOfTotal;

    public BatteryDiffEntry(
            long foregroundUsageTimeInMs,
            long backgroundUsageTimeInMs,
            double consumePower,
            BatteryHistEntry batteryHistEntry) {
        mForegroundUsageTimeInMs = foregroundUsageTimeInMs;
        mBackgroundUsageTimeInMs = backgroundUsageTimeInMs;
        mConsumePower = consumePower;
        mBatteryHistEntry = batteryHistEntry;
    }

    /** Sets the total consumed power in a specific time slot. */
    public void setTotalConsumePower(double totalConsumePower) {
        mTotalConsumePower = totalConsumePower;
        mPercentOfTotal = totalConsumePower == 0
            ? 0 : (mConsumePower / mTotalConsumePower) * 100.0;
    }

    /** Gets the percentage of total consumed power. */
    public double getPercentOfTotal() {
        return mPercentOfTotal;
    }

    /** Clones a new instance. */
    public BatteryDiffEntry clone() {
        return new BatteryDiffEntry(
            this.mForegroundUsageTimeInMs,
            this.mBackgroundUsageTimeInMs,
            this.mConsumePower,
            this.mBatteryHistEntry /*same instance*/);
    }

    @Override
    public String toString() {
        final StringBuilder builder = new StringBuilder()
            .append("BatteryDiffEntry{")
            .append("\n\tname=" + mBatteryHistEntry.mAppLabel)
            .append(String.format("\n\tconsume=%.2f%% %f/%f",
                  mPercentOfTotal, mConsumePower, mTotalConsumePower))
            .append(String.format("\n\tforeground:%d background:%d",
                  Duration.ofMillis(mForegroundUsageTimeInMs).getSeconds(),
                  Duration.ofMillis(mBackgroundUsageTimeInMs).getSeconds()))
            .append(String.format("\n\tpackage:%s uid:%s",
                  mBatteryHistEntry.mPackageName, mBatteryHistEntry.mUid));
        return builder.toString();
    }
}
+9 −4
Original line number Diff line number Diff line
@@ -112,6 +112,11 @@ public final class BatteryHistEntry {
        return mIsValidEntry;
    }

    /** Gets an identifier to represent this {@link BatteryHistEntry}. */
    public String getKey() {
        return mPackageName + "-" + mUserId;
    }

    @Override
    public String toString() {
        final String recordAtDateTime = ConvertUtils.utcToLocalTime(mTimestamp);
@@ -135,7 +140,7 @@ public final class BatteryHistEntry {
            return values.getAsInteger(key);
        };
        mIsValidEntry = false;
        return -1;
        return 0;
    }

    private int getInteger(Cursor cursor, String key) {
@@ -144,7 +149,7 @@ public final class BatteryHistEntry {
            return cursor.getInt(columnIndex);
        }
        mIsValidEntry = false;
        return -1;
        return 0;
    }

    private long getLong(ContentValues values, String key) {
@@ -152,7 +157,7 @@ public final class BatteryHistEntry {
            return values.getAsLong(key);
        }
        mIsValidEntry = false;
        return -1L;
        return 0L;
    }

    private long getLong(Cursor cursor, String key) {
@@ -161,7 +166,7 @@ public final class BatteryHistEntry {
            return cursor.getLong(columnIndex);
        }
        mIsValidEntry = false;
        return -1L;
        return 0L;
    }

    private double getDouble(ContentValues values, String key) {
+175 −0
Original line number Diff line number Diff line
@@ -26,13 +26,22 @@ import android.util.Log;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.TimeZone;

/** A utility class to convert data into another types. */
public final class ConvertUtils {
    private static final String TAG = "ConvertUtils";
    private static final Map<String, BatteryHistEntry> EMPTY_BATTERY_MAP = new HashMap<>();
    private static final BatteryHistEntry EMPTY_BATTERY_HIST_ENTRY =
        new BatteryHistEntry(new ContentValues());

    /** Invalid system battery consumer drain type. */
    public static final int INVALID_DRAIN_TYPE = -1;
@@ -126,4 +135,170 @@ public final class ConvertUtils {
        }
        return sSimpleDateFormat.format(new Date(timestamp));
    }

    /** Gets indexed battery usage data for each corresponding time slot. */
    public static Map<Integer, List<BatteryDiffEntry>> getIndexedUsageMap(
            final int timeSlotSize,
            final long[] batteryHistoryKeys,
            final Map<Long, List<BatteryHistEntry>> batteryHistoryMap) {
        final Map<Integer, List<BatteryDiffEntry>> resultMap = new HashMap<>();
        // Generates a temporary map to calculate diff usage data, which converts the inputted
        // List<BatteryDiffEntry> into Map<String, BatteryHistEntry> with the key comes from
        // the BatteryHistEntry.getKey() method.
        final Map<Long, Map<String, BatteryHistEntry>> newBatteryHistoryMap = new HashMap<>();
        for (int index = 0; index < batteryHistoryKeys.length; index++) {
            final Long timestamp = Long.valueOf(batteryHistoryKeys[index]);
            final List<BatteryHistEntry> entries = batteryHistoryMap.get(timestamp);
            if (entries == null || entries.isEmpty()) {
                continue;
            }
            final Map<String, BatteryHistEntry> slotBatteryHistDataMap = new HashMap<>();
            for (BatteryHistEntry entry : entries) {
                // Excludes auto-generated fake BatteryHistEntry data,
                // which is used to record battery level and status purpose only.
                if (!FAKE_PACKAGE_NAME.equals(entry.mPackageName)) {
                    slotBatteryHistDataMap.put(entry.getKey(), entry);
                }
            }
            newBatteryHistoryMap.put(timestamp, slotBatteryHistDataMap);
        }

        // Each time slot usage diff data =
        //     Math.abs(timestamp[i+2] data - timestamp[i+1] data) +
        //     Math.abs(timestamp[i+1] data - timestamp[i] data);
        // since we want to aggregate every two hours data into a single time slot.
        final int timestampStride = 2;
        for (int index = 0; index < timeSlotSize; index++) {
            final Long currentTimestamp =
                Long.valueOf(batteryHistoryKeys[index * timestampStride]);
            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 =
                newBatteryHistoryMap.getOrDefault(currentTimestamp, EMPTY_BATTERY_MAP);
            final Map<String, BatteryHistEntry> nextBatteryHistMap =
                newBatteryHistoryMap.getOrDefault(nextTimestamp, EMPTY_BATTERY_MAP);
            final Map<String, BatteryHistEntry> nextTwoBatteryHistMap =
                newBatteryHistoryMap.getOrDefault(nextTwoTimestamp, EMPTY_BATTERY_MAP);

            // Collects all keys in these three time slot records as population.
            final Set<String> allBatteryHistEntryKeys = new HashSet<>();
            allBatteryHistEntryKeys.addAll(currentBatteryHistMap.keySet());
            allBatteryHistEntryKeys.addAll(nextBatteryHistMap.keySet());
            allBatteryHistEntryKeys.addAll(nextTwoBatteryHistMap.keySet());

            double totalConsumePower = 0.0;
            final List<BatteryDiffEntry> batteryDiffEntryList = new ArrayList<>();
            // Adds a specific time slot BatteryDiffEntry list into result map.
            resultMap.put(Integer.valueOf(index), batteryDiffEntryList);

            // Calculates all packages diff usage data in a specific time slot.
            for (String key : allBatteryHistEntryKeys) {
                final BatteryHistEntry currentEntry =
                    currentBatteryHistMap.getOrDefault(key, EMPTY_BATTERY_HIST_ENTRY);
                final BatteryHistEntry nextEntry =
                    nextBatteryHistMap.getOrDefault(key, EMPTY_BATTERY_HIST_ENTRY);
                final BatteryHistEntry nextTwoEntry =
                    nextTwoBatteryHistMap.getOrDefault(key, EMPTY_BATTERY_HIST_ENTRY);
                // Cumulative values is a specific time slot for a specific app.
                final long foregroundUsageTimeInMs =
                    getDiffValue(
                        currentEntry.mForegroundUsageTimeInMs,
                        nextEntry.mForegroundUsageTimeInMs,
                        nextTwoEntry.mForegroundUsageTimeInMs);
                final long backgroundUsageTimeInMs =
                    getDiffValue(
                        currentEntry.mBackgroundUsageTimeInMs,
                        nextEntry.mBackgroundUsageTimeInMs,
                        nextTwoEntry.mBackgroundUsageTimeInMs);
                final double consumePower =
                    getDiffValue(
                        currentEntry.mConsumePower,
                        nextEntry.mConsumePower,
                        nextTwoEntry.mConsumePower);
                totalConsumePower += consumePower;

                // Excludes entry since we don't have enough data to calculate.
                if (foregroundUsageTimeInMs == 0
                    && backgroundUsageTimeInMs == 0
                    && consumePower == 0) {
                    continue;
                }
                final BatteryHistEntry selectedBatteryEntry =
                    selectBatteryHistEntry(currentEntry, nextEntry, nextTwoEntry);
                if (selectedBatteryEntry == null) {
                    continue;
                }
                batteryDiffEntryList.add(
                    new BatteryDiffEntry(
                        foregroundUsageTimeInMs,
                        backgroundUsageTimeInMs,
                        consumePower,
                        selectedBatteryEntry));
            }
            // Sets total consume power data into all BatteryDiffEntry in the same slot.
            for (BatteryDiffEntry diffEntry : batteryDiffEntryList) {
                diffEntry.setTotalConsumePower(totalConsumePower);
            }
        }
        insert24HoursData(BatteryChartView.SELECTED_INDEX_ALL, resultMap);
        return resultMap;
    }

    private static void insert24HoursData(
            final int desiredIndex,
            final Map<Integer, List<BatteryDiffEntry>> indexedUsageMap) {
        final Map<String, BatteryDiffEntry> resultMap = new HashMap<>();
        double totalConsumePower = 0.0;
        // Loops for all BatteryDiffEntry and aggregate them together.
        for (List<BatteryDiffEntry> entryList : indexedUsageMap.values()) {
            for (BatteryDiffEntry entry : entryList) {
                final String key = entry.mBatteryHistEntry.getKey();
                final BatteryDiffEntry oldBatteryDiffEntry = resultMap.get(key);
                // Creates new BatteryDiffEntry if we don't have it.
                if (oldBatteryDiffEntry == null) {
                    resultMap.put(key, entry.clone());
                } else {
                    // Sums up some fields data into the existing one.
                    oldBatteryDiffEntry.mForegroundUsageTimeInMs +=
                        entry.mForegroundUsageTimeInMs;
                    oldBatteryDiffEntry.mBackgroundUsageTimeInMs +=
                        entry.mBackgroundUsageTimeInMs;
                    oldBatteryDiffEntry.mConsumePower += entry.mConsumePower;
                }
                totalConsumePower += entry.mConsumePower;
            }
        }
        final List<BatteryDiffEntry> resultList = new ArrayList<>(resultMap.values());
        // Sets total 24 hours consume power data into all BatteryDiffEntry.
        for (BatteryDiffEntry entry : resultList) {
            entry.setTotalConsumePower(totalConsumePower);
        }
        indexedUsageMap.put(Integer.valueOf(desiredIndex), resultList);
    }

    private static long getDiffValue(long v1, long v2, long v3) {
        return (v2 > v1 ? v2 - v1 : 0) + (v3 > v2 ? v3 - v2 : 0);
    }

    private static double getDiffValue(double v1, double v2, double v3) {
        return (v2 > v1 ? v2 - v1 : 0) + (v3 > v2 ? v3 - v2 : 0);
    }

    private static BatteryHistEntry selectBatteryHistEntry(
            BatteryHistEntry entry1,
            BatteryHistEntry entry2,
            BatteryHistEntry entry3) {
        if (entry1 != null && entry1 != EMPTY_BATTERY_HIST_ENTRY) {
            return entry1;
        } else if (entry2 != null && entry2 != EMPTY_BATTERY_HIST_ENTRY) {
            return entry2;
        } else {
            return entry3 != null && entry3 != EMPTY_BATTERY_HIST_ENTRY
                ? entry3 : null;
        }
    }
}
+52 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2021 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;

import static com.google.common.truth.Truth.assertThat;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;

@RunWith(RobolectricTestRunner.class)
public final class BatteryDiffEntryTest {

    @Test
    public void testSetTotalConsumePower_returnExpectedResult() {
        final BatteryDiffEntry entry =
            new BatteryDiffEntry(
                /*foregroundUsageTimeInMs=*/ 10001L,
                /*backgroundUsageTimeInMs=*/ 20002L,
                /*consumePower=*/ 22.0,
                /*batteryHistEntry=*/ null);
        entry.setTotalConsumePower(100.0);

        assertThat(entry.getPercentOfTotal()).isEqualTo(22.0);
    }

    @Test
    public void testSetTotalConsumePower_setZeroValue_returnsZeroValue() {
        final BatteryDiffEntry entry =
            new BatteryDiffEntry(
                /*foregroundUsageTimeInMs=*/ 10001L,
                /*backgroundUsageTimeInMs=*/ 20002L,
                /*consumePower=*/ 22.0,
                /*batteryHistEntry=*/ null);
        entry.setTotalConsumePower(0);

        assertThat(entry.getPercentOfTotal()).isEqualTo(0);
    }
}
+2 −0
Original line number Diff line number Diff line
@@ -161,5 +161,7 @@ public final class BatteryHistEntryTest {
            .isEqualTo(BatteryManager.BATTERY_STATUS_FULL);
        assertThat(entry.mBatteryHealth)
            .isEqualTo(BatteryManager.BATTERY_HEALTH_COLD);
        assertThat(entry.getKey())
            .isEqualTo("com.google.android.settings.battery-" + entry.mUserId);
    }
}
Loading