diff --git a/src/com/android/settings/fuelgauge/BatteryHistEntry.java b/src/com/android/settings/fuelgauge/BatteryHistEntry.java index b2c8eec637b..0ee9cf78b0c 100644 --- a/src/com/android/settings/fuelgauge/BatteryHistEntry.java +++ b/src/com/android/settings/fuelgauge/BatteryHistEntry.java @@ -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 double getDouble(String key) { - if (mContentValues != null && mContentValues.containsKey(key)) { - return mContentValues.getAsDouble(key); + 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(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; + } + } diff --git a/src/com/android/settings/fuelgauge/PowerUsageFeatureProvider.java b/src/com/android/settings/fuelgauge/PowerUsageFeatureProvider.java index 8557bf76cb5..29487b912c3 100644 --- a/src/com/android/settings/fuelgauge/PowerUsageFeatureProvider.java +++ b/src/com/android/settings/fuelgauge/PowerUsageFeatureProvider.java @@ -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> getBatteryHistory(Context context); } diff --git a/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImpl.java b/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImpl.java index a3e9aecedd2..1bbbba4ed46 100644 --- a/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImpl.java +++ b/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImpl.java @@ -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> getBatteryHistory(Context context) { + return null; + } } diff --git a/tests/robotests/src/com/android/settings/fuelgauge/BatteryHistEntryTest.java b/tests/robotests/src/com/android/settings/fuelgauge/BatteryHistEntryTest.java index 234f6ce3e7b..b0fb3d14bd9 100644 --- a/tests/robotests/src/com/android/settings/fuelgauge/BatteryHistEntryTest.java +++ b/tests/robotests/src/com/android/settings/fuelgauge/BatteryHistEntryTest.java @@ -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(); - } }