From 9db43b8f76a8f56f239a5feeca6bc43a1b3bab9c Mon Sep 17 00:00:00 2001 From: ykhung Date: Wed, 5 May 2021 14:03:02 +0800 Subject: [PATCH] Add new constructor to create BatteryHistEntry from interpolation https://matthew-brett.github.io/teaching/linear_interpolation.html Bug: 184807417 Test: make SettingsRoboTests Change-Id: I6dbdb3db8243e40bc54bde3aab7157fda2719de9 --- .../settings/fuelgauge/BatteryHistEntry.java | 75 ++++++ .../fuelgauge/BatteryHistEntryTest.java | 217 ++++++++++++++---- 2 files changed, 241 insertions(+), 51 deletions(-) diff --git a/src/com/android/settings/fuelgauge/BatteryHistEntry.java b/src/com/android/settings/fuelgauge/BatteryHistEntry.java index 211d4b6b83e..6130fffc4a0 100644 --- a/src/com/android/settings/fuelgauge/BatteryHistEntry.java +++ b/src/com/android/settings/fuelgauge/BatteryHistEntry.java @@ -114,6 +114,35 @@ public class BatteryHistEntry { mBatteryHealth = getInteger(cursor, KEY_BATTERY_HEALTH); } + private BatteryHistEntry( + BatteryHistEntry fromEntry, + long bootTimestamp, + long timestamp, + double totalPower, + double consumePower, + long foregroundUsageTimeInMs, + long backgroundUsageTimeInMs, + int batteryLevel) { + mUid = fromEntry.mUid; + mUserId = fromEntry.mUserId; + mAppLabel = fromEntry.mAppLabel; + mPackageName = fromEntry.mPackageName; + mIsHidden = fromEntry.mIsHidden; + mBootTimestamp = bootTimestamp; + mTimestamp = timestamp; + mZoneId = fromEntry.mZoneId; + mTotalPower = totalPower; + mConsumePower = consumePower; + mPercentOfTotal = fromEntry.mPercentOfTotal; + mForegroundUsageTimeInMs = foregroundUsageTimeInMs; + mBackgroundUsageTimeInMs = backgroundUsageTimeInMs; + mDrainType = fromEntry.mDrainType; + mConsumerType = fromEntry.mConsumerType; + mBatteryLevel = batteryLevel; + mBatteryStatus = fromEntry.mBatteryStatus; + mBatteryHealth = fromEntry.mBatteryHealth; + } + /** Whether this {@link BatteryHistEntry} is valid or not? */ public boolean isValidEntry() { return mIsValidEntry; @@ -257,4 +286,50 @@ public class BatteryHistEntry { mIsValidEntry = false; return false; } + + /** Creates new {@link BatteryHistEntry} from interpolation. */ + public static BatteryHistEntry interpolate( + long slotTimestamp, + long upperTimestamp, + double ratio, + BatteryHistEntry lowerHistEntry, + BatteryHistEntry upperHistEntry) { + final double totalPower = interpolate( + lowerHistEntry == null ? 0 : lowerHistEntry.mTotalPower, + upperHistEntry.mTotalPower, + ratio); + final double consumePower = interpolate( + lowerHistEntry == null ? 0 : lowerHistEntry.mConsumePower, + upperHistEntry.mConsumePower, + ratio); + final double foregroundUsageTimeInMs = interpolate( + lowerHistEntry == null ? 0 : lowerHistEntry.mForegroundUsageTimeInMs, + upperHistEntry.mForegroundUsageTimeInMs, + ratio); + final double backgroundUsageTimeInMs = interpolate( + lowerHistEntry == null ? 0 : lowerHistEntry.mBackgroundUsageTimeInMs, + upperHistEntry.mBackgroundUsageTimeInMs, + ratio); + final double batteryLevel = + lowerHistEntry == null + ? upperHistEntry.mBatteryLevel + : interpolate( + lowerHistEntry.mBatteryLevel, + upperHistEntry.mBatteryLevel, + ratio); + return new BatteryHistEntry( + upperHistEntry, + /*bootTimestamp=*/ upperHistEntry.mBootTimestamp + - (upperTimestamp - slotTimestamp), + /*timestamp=*/ slotTimestamp, + totalPower, + consumePower, + Math.round(foregroundUsageTimeInMs), + Math.round(backgroundUsageTimeInMs), + (int) Math.round(batteryLevel)); + } + + private static double interpolate(double v1, double v2, double ratio) { + return v1 + ratio * (v2 - v1); + } } diff --git a/tests/robotests/src/com/android/settings/fuelgauge/BatteryHistEntryTest.java b/tests/robotests/src/com/android/settings/fuelgauge/BatteryHistEntryTest.java index b127cca6638..ca3109c4757 100644 --- a/tests/robotests/src/com/android/settings/fuelgauge/BatteryHistEntryTest.java +++ b/tests/robotests/src/com/android/settings/fuelgauge/BatteryHistEntryTest.java @@ -87,50 +87,15 @@ public final class BatteryHistEntryTest { @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_BOOT_TIMESTAMP, - 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(101l), - 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), + createBatteryHistEntry( + /*bootTimestamp=*/ 101L, + /*timestamp=*/ 10001L, + /*totalPower=*/ 5.1, + /*consumePower=*/ 1.1, + /*foregroundUsageTimeInMs=*/ 1234L, + /*backgroundUsageTimeInMs=*/ 5689L, + /*batteryLevel=*/ 12), /*drainType=*/ 3, /*percentOfTotal=*/ 0.3); } @@ -195,6 +160,82 @@ public final class BatteryHistEntryTest { .isFalse(); } + @Test + public void testInterpolate_returnExpectedResult() { + final long slotTimestamp = 200L; + final long upperTimestamp = 300L; + final long lowerTimestamp = 100L; + final double ratio = 0.5; + final BatteryHistEntry lowerHistEntry = createBatteryHistEntry( + /*bootTimestamp=*/ 1000L, + lowerTimestamp, + /*totalPower=*/ 50, + /*consumePower=*/ 10, + /*foregroundUsageTimeInMs=*/ 100, + /*backgroundUsageTimeInMs=*/ 200, + /*batteryLevel=*/ 90); + final BatteryHistEntry upperHistEntry = createBatteryHistEntry( + /*bootTimestamp=*/ 1200L, + upperTimestamp, + /*totalPower=*/ 80, + /*consumePower=*/ 20, + /*foregroundUsageTimeInMs=*/ 200, + /*backgroundUsageTimeInMs=*/ 300, + /*batteryLevel=*/ 80); + + final BatteryHistEntry newEntry = + BatteryHistEntry.interpolate( + slotTimestamp, + upperTimestamp, + ratio, + lowerHistEntry, + upperHistEntry); + + assertBatteryHistEntry( + newEntry, 3, upperHistEntry.mPercentOfTotal, + /*bootTimestamp=*/ 1200 - 100, + /*timestamp=*/ slotTimestamp, + /*totalPower=*/ 50 + 0.5 * (80 - 50), + /*consumePower=*/ 10 + 0.5 * (20 - 10), + /*foregroundUsageTimeInMs=*/ Math.round(100 + 0.5 * (200 - 100)), + /*backgroundUsageTimeInMs=*/ Math.round(200 + 0.5 * (300 - 200)), + /*batteryLevel=*/ (int) Math.round(90 + 0.5 * (80 - 90))); + } + + @Test + public void testInterpolate_withoutLowerEntryData_returnExpectedResult() { + final long slotTimestamp = 200L; + final long upperTimestamp = 300L; + final long lowerTimestamp = 100L; + final double ratio = 0.5; + final BatteryHistEntry upperHistEntry = createBatteryHistEntry( + /*bootTimestamp=*/ 1200L, + upperTimestamp, + /*totalPower=*/ 80, + /*consumePower=*/ 20, + /*foregroundUsageTimeInMs=*/ 200, + /*backgroundUsageTimeInMs=*/ 300, + /*batteryLevel=*/ 80); + + final BatteryHistEntry newEntry = + BatteryHistEntry.interpolate( + slotTimestamp, + upperTimestamp, + ratio, + /*lowerHistEntry=*/ null, + upperHistEntry); + + assertBatteryHistEntry( + newEntry, 3, upperHistEntry.mPercentOfTotal, + /*bootTimestamp=*/ 1200 - 100, + /*timestamp=*/ slotTimestamp, + /*totalPower=*/ 0.5 * 80, + /*consumePower=*/ 0.5 * 20, + /*foregroundUsageTimeInMs=*/ Math.round(0.5 * 200), + /*backgroundUsageTimeInMs=*/ Math.round(0.5 * 300), + /*batteryLevel=*/ upperHistEntry.mBatteryLevel); + } + private static BatteryHistEntry createEntry(int consumerType) { return new BatteryHistEntry(getContentValuesWithType(consumerType)); } @@ -207,7 +248,29 @@ public final class BatteryHistEntryTest { } private void assertBatteryHistEntry( - BatteryHistEntry entry, int drainType, double percentOfTotal) { + BatteryHistEntry entry, int drainType, double percentOfTotal) { + assertBatteryHistEntry( + entry, drainType, percentOfTotal, + /*bootTimestamp=*/ 101L, + /*timestamp=*/ 10001L, + /*totalPower=*/ 5.1, + /*consumePower=*/ 1.1, + /*foregroundUsageTimeInMs=*/ 1234L, + /*backgroundUsageTimeInMs=*/ 5689L, + /*batteryLevel=*/ 12); + } + + private void assertBatteryHistEntry( + BatteryHistEntry entry, + int drainType, + double percentOfTotal, + long bootTimestamp, + long timestamp, + double totalPower, + double consumePower, + long foregroundUsageTimeInMs, + long backgroundUsageTimeInMs, + int batteryLevel) { assertThat(entry.isValidEntry()).isTrue(); assertThat(entry.mUid).isEqualTo(1001); assertThat(entry.mUserId).isEqualTo(UserHandle.getUserId(1001)); @@ -215,21 +278,73 @@ public final class BatteryHistEntryTest { assertThat(entry.mPackageName) .isEqualTo("com.google.android.settings.battery"); assertThat(entry.mIsHidden).isTrue(); - assertThat(entry.mBootTimestamp).isEqualTo(101L); - assertThat(entry.mTimestamp).isEqualTo(10001L); + assertThat(entry.mBootTimestamp).isEqualTo(bootTimestamp); + assertThat(entry.mTimestamp).isEqualTo(timestamp); assertThat(entry.mZoneId).isEqualTo(TimeZone.getDefault().getID()); - assertThat(entry.mTotalPower).isEqualTo(5.1); - assertThat(entry.mConsumePower).isEqualTo(1.1); + assertThat(entry.mTotalPower).isEqualTo(totalPower); + assertThat(entry.mConsumePower).isEqualTo(consumePower); assertThat(entry.mPercentOfTotal).isEqualTo(percentOfTotal); - assertThat(entry.mForegroundUsageTimeInMs).isEqualTo(1234L); - assertThat(entry.mBackgroundUsageTimeInMs).isEqualTo(5689L); + assertThat(entry.mForegroundUsageTimeInMs).isEqualTo(foregroundUsageTimeInMs); + assertThat(entry.mBackgroundUsageTimeInMs).isEqualTo(backgroundUsageTimeInMs); assertThat(entry.mDrainType).isEqualTo(drainType); assertThat(entry.mConsumerType) .isEqualTo(ConvertUtils.CONSUMER_TYPE_SYSTEM_BATTERY); - assertThat(entry.mBatteryLevel).isEqualTo(12); + assertThat(entry.mBatteryLevel).isEqualTo(batteryLevel); assertThat(entry.mBatteryStatus) .isEqualTo(BatteryManager.BATTERY_STATUS_FULL); assertThat(entry.mBatteryHealth) .isEqualTo(BatteryManager.BATTERY_HEALTH_COLD); } + + private BatteryHistEntry createBatteryHistEntry( + long bootTimestamp, + long timestamp, + double totalPower, + double consumePower, + long foregroundUsageTimeInMs, + long backgroundUsageTimeInMs, + int batteryLevel) { + 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_BOOT_TIMESTAMP, + 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(bootTimestamp), + Long.valueOf(timestamp), + TimeZone.getDefault().getID(), + Double.valueOf(totalPower), + Double.valueOf(consumePower), + Double.valueOf(0.3), + Long.valueOf(foregroundUsageTimeInMs), + Long.valueOf(backgroundUsageTimeInMs), + Integer.valueOf(3), + Integer.valueOf(ConvertUtils.CONSUMER_TYPE_SYSTEM_BATTERY), + Integer.valueOf(batteryLevel), + Integer.valueOf(BatteryManager.BATTERY_STATUS_FULL), + Integer.valueOf(BatteryManager.BATTERY_HEALTH_COLD)}); + cursor.moveToFirst(); + return new BatteryHistEntry(cursor); + } }