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

Commit 318cc18f authored by ykhung's avatar ykhung Committed by YUKAI HUNG
Browse files

Add getBatteryHistory method to query data from SettingsIntelligence

Bug: 184807417
Test: make SettingsRoboTests
Test: make SettingsGoogleRoboTests
Change-Id: Idd640f8f8b07311fafc76f7b61c96c453ae7b604
parent b6e8a1ca
Loading
Loading
Loading
Loading
+147 −36
Original line number Diff line number Diff line
@@ -14,11 +14,38 @@
package com.android.settings.fuelgauge;

import android.content.ContentValues;
import android.database.Cursor;
import android.util.Log;

import java.text.SimpleDateFormat;
import java.time.Duration;
import java.util.Date;
import java.util.TimeZone;


/** A container class to carry data from {@link ContentValues}. */
public final class BatteryHistEntry {
    private static final String TAG = "BatteryHistEntry";

    /** Keys for accessing {@link ContentValues} or {@link Cursor}. */
    public static final String KEY_UID = "uid";
    public static final String KEY_USER_ID = "userId";
    public static final String KEY_APP_LABEL = "appLabel";
    public static final String KEY_PACKAGE_NAME = "packageName";
    public static final String KEY_IS_HIDDEN = "isHidden";
    public static final String KEY_TIMESTAMP = "timestamp";
    public static final String KEY_ZONE_ID = "zoneId";
    public static final String KEY_TOTAL_POWER = "totalPower";
    public static final String KEY_CONSUME_POWER = "consumePower";
    public static final String KEY_PERCENT_OF_TOTAL = "percentOfTotal";
    public static final String KEY_FOREGROUND_USAGE_TIME = "foregroundUsageTimeInMs";
    public static final String KEY_BACKGROUND_USAGE_TIME = "backgroundUsageTimeInMs";
    public static final String KEY_DRAIN_TYPE = "drainType";
    public static final String KEY_CONSUMER_TYPE = "consumerType";
    public static final String KEY_BATTERY_LEVEL = "batteryLevel";
    public static final String KEY_BATTERY_STATUS = "batteryStatus";
    public static final String KEY_BATTERY_HEALTH = "batteryHealth";

    public final long mUid;
    public final long mUserId;
    public final String mAppLabel;
@@ -42,27 +69,45 @@ public final class BatteryHistEntry {
    public final int mBatteryHealth;

    private boolean mIsValidEntry = true;
    private ContentValues mContentValues;

    public BatteryHistEntry(ContentValues contentValues) {
        mContentValues = contentValues;
        mUid = getLong("uid");
        mUserId = getLong("userId");
        mAppLabel = getString("appLabel");
        mPackageName = getString("packageName");
        mIsHidden = getBoolean("isHidden");
        mTimestamp = getLong("timestamp");
        mZoneId = getString("zoneId");
        mTotalPower = getDouble("totalPower");
        mConsumePower = getDouble("consumePower");
        mPercentOfTotal = getDouble("percentOfTotal");
        mForegroundUsageTimeInMs = getLong("foregroundUsageTimeInMs");
        mBackgroundUsageTimeInMs = getLong("backgroundUsageTimeInMs");
        mDrainType = getInteger("drainType");
        mConsumerType = getInteger("consumerType");
        mBatteryLevel = getInteger("batteryLevel");
        mBatteryStatus = getInteger("batteryStatus");
        mBatteryHealth = getInteger("batteryHealth");

    public BatteryHistEntry(ContentValues values) {
        mUid = getLong(values, KEY_UID);
        mUserId = getLong(values, KEY_USER_ID);
        mAppLabel = getString(values, KEY_APP_LABEL);
        mPackageName = getString(values, KEY_PACKAGE_NAME);
        mIsHidden = getBoolean(values, KEY_IS_HIDDEN);
        mTimestamp = getLong(values, KEY_TIMESTAMP);
        mZoneId = getString(values, KEY_ZONE_ID);
        mTotalPower = getDouble(values, KEY_TOTAL_POWER);
        mConsumePower = getDouble(values, KEY_CONSUME_POWER);
        mPercentOfTotal = getDouble(values, KEY_PERCENT_OF_TOTAL);
        mForegroundUsageTimeInMs = getLong(values, KEY_FOREGROUND_USAGE_TIME);
        mBackgroundUsageTimeInMs = getLong(values, KEY_BACKGROUND_USAGE_TIME);
        mDrainType = getInteger(values, KEY_DRAIN_TYPE);
        mConsumerType = getInteger(values, KEY_CONSUMER_TYPE);
        mBatteryLevel = getInteger(values, KEY_BATTERY_LEVEL);
        mBatteryStatus = getInteger(values, KEY_BATTERY_STATUS);
        mBatteryHealth = getInteger(values, KEY_BATTERY_HEALTH);
    }

    public BatteryHistEntry(Cursor cursor) {
        mUid = getLong(cursor, KEY_UID);
        mUserId = getLong(cursor, KEY_USER_ID);
        mAppLabel = getString(cursor, KEY_APP_LABEL);
        mPackageName = getString(cursor, KEY_PACKAGE_NAME);
        mIsHidden = getBoolean(cursor, KEY_IS_HIDDEN);
        mTimestamp = getLong(cursor, KEY_TIMESTAMP);
        mZoneId = getString(cursor, KEY_ZONE_ID);
        mTotalPower = getDouble(cursor, KEY_TOTAL_POWER);
        mConsumePower = getDouble(cursor, KEY_CONSUME_POWER);
        mPercentOfTotal = getDouble(cursor, KEY_PERCENT_OF_TOTAL);
        mForegroundUsageTimeInMs = getLong(cursor, KEY_FOREGROUND_USAGE_TIME);
        mBackgroundUsageTimeInMs = getLong(cursor, KEY_BACKGROUND_USAGE_TIME);
        mDrainType = getInteger(cursor, KEY_DRAIN_TYPE);
        mConsumerType = getInteger(cursor, KEY_CONSUMER_TYPE);
        mBatteryLevel = getInteger(cursor, KEY_BATTERY_LEVEL);
        mBatteryStatus = getInteger(cursor, KEY_BATTERY_STATUS);
        mBatteryHealth = getInteger(cursor, KEY_BATTERY_HEALTH);
    }

    /** Whether this {@link BatteryHistEntry} is valid or not? */
@@ -70,43 +115,109 @@ public final class BatteryHistEntry {
        return mIsValidEntry;
    }

    private int getInteger(String key) {
        if (mContentValues != null && mContentValues.containsKey(key)) {
            return mContentValues.getAsInteger(key);
    @Override
    public String toString() {
        final String recordAtDateTime =
            new SimpleDateFormat("MMM dd,yyyy HH:mm:ss").format(new Date(mTimestamp));
        final StringBuilder builder = new StringBuilder()
            .append("\nBatteryHistEntry{")
            .append(String.format("\n\tpackage=%s|label=%s|uid=%d|userId=%d|isHidden=%b",
                  mPackageName, mAppLabel, mUid, mUserId, mIsHidden))
            .append(String.format("\n\ttimestamp=%s|zoneId=%s", recordAtDateTime, mZoneId))
            .append(String.format("\n\tusage=%f|total=%f|consume=%f|elapsedTime=%d|%d",
                  mPercentOfTotal, mTotalPower, mConsumePower,
                  Duration.ofMillis(mForegroundUsageTimeInMs).getSeconds(),
                  Duration.ofMillis(mBackgroundUsageTimeInMs).getSeconds()))
            .append(String.format("\n\tdrain=%d|consumer=%d", mDrainType, mConsumerType))
            .append(String.format("\n\tbattery=%d|status=%d|health=%d\n}",
                  mBatteryLevel, mBatteryStatus, mBatteryHealth));
        return builder.toString();
    }

    private int getInteger(ContentValues values, String key) {
        if (values != null && values.containsKey(key)) {
            return values.getAsInteger(key);
        };
        mIsValidEntry = false;
        return -1;
    }

    private long getLong(String key) {
        if (mContentValues != null && mContentValues.containsKey(key)) {
            return mContentValues.getAsLong(key);
    private int getInteger(Cursor cursor, String key) {
        final int columnIndex = cursor.getColumnIndex(key);
        if (columnIndex >= 0) {
            return cursor.getInt(columnIndex);
        }
        mIsValidEntry = false;
        return -1;
    }

    private long getLong(ContentValues values, String key) {
        if (values != null && values.containsKey(key)) {
            return values.getAsLong(key);
        }
        mIsValidEntry = false;
        return -1L;
    }

    private long getLong(Cursor cursor, String key) {
        final int columnIndex = cursor.getColumnIndex(key);
        if (columnIndex >= 0) {
            return cursor.getLong(columnIndex);
        }
        mIsValidEntry = false;
        return -1L;
    }

    private double getDouble(String key) {
        if (mContentValues != null && mContentValues.containsKey(key)) {
            return mContentValues.getAsDouble(key);
    private double getDouble(ContentValues values, String key) {
        if (values != null && values.containsKey(key)) {
            return values.getAsDouble(key);
        }
        mIsValidEntry = false;
        return 0f;
    }

    private String getString(String key) {
        if (mContentValues != null && mContentValues.containsKey(key)) {
            return mContentValues.getAsString(key);
    private double getDouble(Cursor cursor, String key) {
        final int columnIndex = cursor.getColumnIndex(key);
        if (columnIndex >= 0) {
            return cursor.getDouble(columnIndex);
        }
        mIsValidEntry = false;
        return 0f;
    }

    private String getString(ContentValues values, String key) {
        if (values != null && values.containsKey(key)) {
            return values.getAsString(key);
        }
        mIsValidEntry = false;
        return null;
    }

    private boolean getBoolean(String key) {
        if (mContentValues != null && mContentValues.containsKey(key)) {
            return mContentValues.getAsBoolean(key);
    private String getString(Cursor cursor, String key) {
        final int columnIndex = cursor.getColumnIndex(key);
        if (columnIndex >= 0) {
            return cursor.getString(columnIndex);
        }
        mIsValidEntry = false;
        return null;
    }

    private boolean getBoolean(ContentValues values, String key) {
        if (values != null && values.containsKey(key)) {
            return values.getAsBoolean(key);
        }
        mIsValidEntry = false;
        return false;
    }

    private boolean getBoolean(Cursor cursor, String key) {
        final int columnIndex = cursor.getColumnIndex(key);
        if (columnIndex >= 0) {
            // Use value == 1 to represent boolean value in the database.
            return cursor.getInt(columnIndex) == 1;
        }
        mIsValidEntry = false;
        return false;
    }

}
+9 −1
Original line number Diff line number Diff line
@@ -23,6 +23,9 @@ import android.util.SparseIntArray;
import com.android.internal.os.BatterySipper;
import com.android.settingslib.fuelgauge.Estimate;

import java.util.List;
import java.util.Map;

/**
 * Feature Provider used in power usage
 */
@@ -126,7 +129,12 @@ public interface PowerUsageFeatureProvider {
    boolean isSmartBatterySupported();

    /**
     * Checks whether we should enable chart graph design or not
     * Checks whether we should enable chart graph design or not.
     */
    boolean isChartGraphEnabled(Context context);

    /**
     * Returns battery history data with corresponding timestamp key.
     */
    Map<Long, List<BatteryHistEntry>> getBatteryHistory(Context context);
}
+8 −0
Original line number Diff line number Diff line
@@ -26,6 +26,9 @@ import com.android.internal.os.BatterySipper;
import com.android.internal.util.ArrayUtils;
import com.android.settingslib.fuelgauge.Estimate;

import java.util.List;
import java.util.Map;

public class PowerUsageFeatureProviderImpl implements PowerUsageFeatureProvider {

    private static final String PACKAGE_CALENDAR_PROVIDER = "com.android.providers.calendar";
@@ -155,4 +158,9 @@ public class PowerUsageFeatureProviderImpl implements PowerUsageFeatureProvider
    public boolean isChartGraphEnabled(Context context) {
        return false;
    }

    @Override
    public Map<Long, List<BatteryHistEntry>> getBatteryHistory(Context context) {
        return null;
    }
}
+65 −10
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@ import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.when;

import android.database.MatrixCursor;
import android.content.ContentValues;
import android.os.BatteryConsumer;
import android.os.BatteryManager;
@@ -52,7 +53,7 @@ public final class BatteryHistEntryTest {
    }

    @Test
    public void testConstructor_returnsExpectedResult() {
    public void testConstructor_contentValues_returnsExpectedResult() {
        final int expectedType = 3;
        when(mockBatteryEntry.getUid()).thenReturn(1001);
        when(mockBatteryEntry.getLabel()).thenReturn("Settings");
@@ -76,8 +77,68 @@ public final class BatteryHistEntryTest {
                /*batteryHealth=*/ BatteryManager.BATTERY_HEALTH_COLD,
                /*timestamp=*/ 10001L);

        final BatteryHistEntry entry = new BatteryHistEntry(values);
        assertBatteryHistEntry(
            new BatteryHistEntry(values),
            /*drainType=*/ expectedType,
            /*percentOfTotal=*/ mockBatteryEntry.percent);
    }

    @Test
    public void testConstructor_invalidField_returnsInvalidEntry() {
        final BatteryHistEntry entry = new BatteryHistEntry(new ContentValues());
        assertThat(entry.isValidEntry()).isFalse();
    }

    @Test
    public void testConstructor_cursor_returnsExpectedResult() {
        final MatrixCursor cursor = new MatrixCursor(
            new String[] {
                BatteryHistEntry.KEY_UID,
                BatteryHistEntry.KEY_USER_ID,
                BatteryHistEntry.KEY_APP_LABEL,
                BatteryHistEntry.KEY_PACKAGE_NAME,
                BatteryHistEntry.KEY_IS_HIDDEN,
                BatteryHistEntry.KEY_TIMESTAMP,
                BatteryHistEntry.KEY_ZONE_ID,
                BatteryHistEntry.KEY_TOTAL_POWER,
                BatteryHistEntry.KEY_CONSUME_POWER,
                BatteryHistEntry.KEY_PERCENT_OF_TOTAL,
                BatteryHistEntry.KEY_FOREGROUND_USAGE_TIME,
                BatteryHistEntry.KEY_BACKGROUND_USAGE_TIME,
                BatteryHistEntry.KEY_DRAIN_TYPE,
                BatteryHistEntry.KEY_CONSUMER_TYPE,
                BatteryHistEntry.KEY_BATTERY_LEVEL,
                BatteryHistEntry.KEY_BATTERY_STATUS,
                BatteryHistEntry.KEY_BATTERY_HEALTH});
        cursor.addRow(
            new Object[] {
                Long.valueOf(1001),
                Long.valueOf(UserHandle.getUserId(1001)),
                "Settings",
                "com.google.android.settings.battery",
                Integer.valueOf(1),
                Long.valueOf(10001L),
                TimeZone.getDefault().getID(),
                Double.valueOf(5.1),
                Double.valueOf(1.1),
                Double.valueOf(0.3),
                Long.valueOf(1234L),
                Long.valueOf(5689L),
                Integer.valueOf(3),
                Integer.valueOf(ConvertUtils.CONSUMER_TYPE_SYSTEM_BATTERY),
                Integer.valueOf(12),
                Integer.valueOf(BatteryManager.BATTERY_STATUS_FULL),
                Integer.valueOf(BatteryManager.BATTERY_HEALTH_COLD)});
        cursor.moveToFirst();

        assertBatteryHistEntry(
            new BatteryHistEntry(cursor),
            /*drainType=*/ 3,
            /*percentOfTotal=*/ 0.3);
    }

    private void assertBatteryHistEntry(
        BatteryHistEntry entry, int drainType, double percentOfTotal) {
        assertThat(entry.isValidEntry()).isTrue();
        assertThat(entry.mUid).isEqualTo(1001);
        assertThat(entry.mUserId).isEqualTo(UserHandle.getUserId(1001));
@@ -89,10 +150,10 @@ public final class BatteryHistEntryTest {
        assertThat(entry.mZoneId).isEqualTo(TimeZone.getDefault().getID());
        assertThat(entry.mTotalPower).isEqualTo(5.1);
        assertThat(entry.mConsumePower).isEqualTo(1.1);
        assertThat(entry.mPercentOfTotal).isEqualTo(mockBatteryEntry.percent);
        assertThat(entry.mPercentOfTotal).isEqualTo(percentOfTotal);
        assertThat(entry.mForegroundUsageTimeInMs).isEqualTo(1234L);
        assertThat(entry.mBackgroundUsageTimeInMs).isEqualTo(5689L);
        assertThat(entry.mDrainType).isEqualTo(expectedType);
        assertThat(entry.mDrainType).isEqualTo(drainType);
        assertThat(entry.mConsumerType)
            .isEqualTo(ConvertUtils.CONSUMER_TYPE_SYSTEM_BATTERY);
        assertThat(entry.mBatteryLevel).isEqualTo(12);
@@ -101,10 +162,4 @@ public final class BatteryHistEntryTest {
        assertThat(entry.mBatteryHealth)
            .isEqualTo(BatteryManager.BATTERY_HEALTH_COLD);
    }

    @Test
    public void testConstructor_invalidField_returnsInvalidEntry() {
        final BatteryHistEntry entry = new BatteryHistEntry(new ContentValues());
        assertThat(entry.isValidEntry()).isFalse();
    }
}