Loading src/com/android/settings/fuelgauge/BatteryChartPreferenceController.java +43 −1 Original line number Diff line number Diff line Loading @@ -55,6 +55,8 @@ public class BatteryChartPreferenceController extends AbstractPreferenceControll private static final String TAG = "BatteryChartPreferenceController"; private static final int CHART_KEY_ARRAY_SIZE = 25; private static final int CHART_LEVEL_ARRAY_SIZE = 13; private static final long VALID_USAGE_TIME_DURATION = DateUtils.HOUR_IN_MILLIS * 2; private static final long VALID_DIFF_DURATION = DateUtils.MINUTE_IN_MILLIS * 3; @VisibleForTesting Map<Integer, List<BatteryDiffEntry>> mBatteryIndexedMap; Loading Loading @@ -179,6 +181,7 @@ public class BatteryChartPreferenceController extends AbstractPreferenceControll final List<Long> batteryHistoryKeyList = new ArrayList<Long>(batteryHistoryMap.keySet()); Collections.sort(batteryHistoryKeyList); validateSlotTimestamp(batteryHistoryKeyList); mBatteryHistoryKeys = new long[CHART_KEY_ARRAY_SIZE]; final int elementSize = Math.min(batteryHistoryKeyList.size(), CHART_KEY_ARRAY_SIZE); final int offset = CHART_KEY_ARRAY_SIZE - elementSize; Loading Loading @@ -270,6 +273,10 @@ public class BatteryChartPreferenceController extends AbstractPreferenceControll } else { appEntries.add(entry); } // Validates the usage time if users click a specific slot. if (mTrapezoidIndex >= 0) { validateUsageTime(entry); } }); Collections.sort(appEntries, BatteryDiffEntry.COMPARATOR); Collections.sort(systemEntries, BatteryDiffEntry.COMPARATOR); Loading @@ -289,7 +296,7 @@ public class BatteryChartPreferenceController extends AbstractPreferenceControll final String appLabel = entry.getAppLabel(); final Drawable appIcon = entry.getAppIcon(); if (TextUtils.isEmpty(appLabel) || appIcon == null) { Log.w(TAG, "cannot find app resource:" + entry.mBatteryHistEntry); Log.w(TAG, "cannot find app resource for\n" + entry); continue; } final String prefKey = entry.mBatteryHistEntry.getKey(); Loading Loading @@ -389,4 +396,39 @@ public class BatteryChartPreferenceController extends AbstractPreferenceControll } return builder.toString(); } @VisibleForTesting static boolean validateUsageTime(BatteryDiffEntry entry) { final long foregroundUsageTimeInMs = entry.mForegroundUsageTimeInMs; final long backgroundUsageTimeInMs = entry.mBackgroundUsageTimeInMs; final long totalUsageTimeInMs = foregroundUsageTimeInMs + backgroundUsageTimeInMs; if (foregroundUsageTimeInMs > VALID_USAGE_TIME_DURATION || backgroundUsageTimeInMs > VALID_USAGE_TIME_DURATION || totalUsageTimeInMs > VALID_USAGE_TIME_DURATION) { Log.e(TAG, "validateUsageTime() fail for\n" + entry); return false; } return true; } @VisibleForTesting static boolean validateSlotTimestamp(List<Long> batteryHistoryKeys) { // Whether the nearest two slot time diff is valid or not? final int size = batteryHistoryKeys.size(); for (int index = 0; index < size - 1; index++) { final long currentTime = batteryHistoryKeys.get(index); final long nextTime = batteryHistoryKeys.get(index + 1); final long diffTime = Math.abs( DateUtils.HOUR_IN_MILLIS - Math.abs(currentTime - nextTime)); if (currentTime == 0) { continue; } else if (diffTime > VALID_DIFF_DURATION) { Log.e(TAG, String.format("validateSlotTimestamp() %s > %s", ConvertUtils.utcToLocalTime(currentTime), ConvertUtils.utcToLocalTime(nextTime))); return false; } } return true; } } src/com/android/settings/fuelgauge/BatteryDiffEntry.java +11 −6 Original line number Diff line number Diff line Loading @@ -27,6 +27,8 @@ import android.util.Log; import androidx.annotation.VisibleForTesting; import com.android.settingslib.utils.StringUtil; import java.time.Duration; import java.util.Comparator; import java.util.HashMap; Loading Loading @@ -254,14 +256,17 @@ public class BatteryDiffEntry { public String toString() { final StringBuilder builder = new StringBuilder() .append("BatteryDiffEntry{") .append("\n\tname=" + mBatteryHistEntry.mAppLabel) .append("\n\tname=" + getAppLabel()) .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)); .append(String.format("\n\tforeground:%s background:%s", StringUtil.formatElapsedTime(mContext, mForegroundUsageTimeInMs, /*withSeconds=*/ true, /*collapseTimeUnit=*/ false), StringUtil.formatElapsedTime(mContext, mBackgroundUsageTimeInMs, /*withSeconds=*/ true, /*collapseTimeUnit=*/ false))) .append(String.format("\n\tpackage:%s|%s uid:%d userId:%d", mBatteryHistEntry.mPackageName, getPackageName(), mBatteryHistEntry.mUid, mBatteryHistEntry.mUserId)); return builder.toString(); } Loading src/com/android/settings/fuelgauge/BatteryHistEntry.java +5 −0 Original line number Diff line number Diff line Loading @@ -123,6 +123,11 @@ public class BatteryHistEntry { return mConsumerType == ConvertUtils.CONSUMER_TYPE_UID_BATTERY; } /** Whether this {@link BatteryHistEntry} is system consumer or not. */ public boolean isSystemEntry() { return mConsumerType == ConvertUtils.CONSUMER_TYPE_SYSTEM_BATTERY; } /** Gets an identifier to represent this {@link BatteryHistEntry}. */ public String getKey() { if (mKey == null) { Loading src/com/android/settings/fuelgauge/PowerUsageAdvanced.java +7 −0 Original line number Diff line number Diff line Loading @@ -99,6 +99,13 @@ public class PowerUsageAdvanced extends PowerUsageBase { return R.xml.power_usage_advanced; } @Override public void onPause() { super.onPause(); // Resets the flag to reload usage data in onResume() callback. mIsChartDataLoaded = false; } @Override protected List<AbstractPreferenceController> createPreferenceControllers(Context context) { refreshFeatureFlag(context); Loading tests/robotests/src/com/android/settings/fuelgauge/BatteryChartPreferenceControllerTest.java +52 −0 Original line number Diff line number Diff line Loading @@ -381,6 +381,58 @@ public final class BatteryChartPreferenceControllerTest { assertThat(pref.getSummary()).isNull(); } @Test public void testValidateUsageTime_returnTrueIfBatteryDiffEntryIsValid() { assertThat(BatteryChartPreferenceController.validateUsageTime( createBatteryDiffEntry( /*foregroundUsageTimeInMs=*/ DateUtils.MINUTE_IN_MILLIS, /*backgroundUsageTimeInMs=*/ DateUtils.MINUTE_IN_MILLIS))) .isTrue(); } @Test public void testValidateUsageTime_foregroundTimeExceedThreshold_returnFalse() { assertThat(BatteryChartPreferenceController.validateUsageTime( createBatteryDiffEntry( /*foregroundUsageTimeInMs=*/ DateUtils.HOUR_IN_MILLIS * 3, /*backgroundUsageTimeInMs=*/ 0))) .isFalse(); } @Test public void testValidateUsageTime_backgroundTimeExceedThreshold_returnFalse() { assertThat(BatteryChartPreferenceController.validateUsageTime( createBatteryDiffEntry( /*foregroundUsageTimeInMs=*/ 0, /*backgroundUsageTimeInMs=*/ DateUtils.HOUR_IN_MILLIS * 3))) .isFalse(); } @Test public void testValidateSlotTimestamp_emptyContent_returnTrue() { assertThat(BatteryChartPreferenceController.validateSlotTimestamp( new ArrayList<Long>())).isTrue(); } @Test public void testValidateSlotTimestamp_returnExpectedResult() { final List<Long> slotTimestampList = Arrays.asList( Long.valueOf(0), Long.valueOf(DateUtils.HOUR_IN_MILLIS), Long.valueOf(DateUtils.HOUR_IN_MILLIS * 2 + DateUtils.MINUTE_IN_MILLIS), Long.valueOf(DateUtils.HOUR_IN_MILLIS * 3 + DateUtils.MINUTE_IN_MILLIS * 2)); // Verifies the testing data is correct before we added invalid data into it. assertThat(BatteryChartPreferenceController.validateSlotTimestamp(slotTimestampList)) .isTrue(); // Insert invalid timestamp into the list. slotTimestampList.add( Long.valueOf(DateUtils.HOUR_IN_MILLIS * 4 + DateUtils.MINUTE_IN_MILLIS * 3)); assertThat(BatteryChartPreferenceController.validateSlotTimestamp(slotTimestampList)) .isFalse(); } private static Map<Long, List<BatteryHistEntry>> createBatteryHistoryMap(int size) { final Map<Long, List<BatteryHistEntry>> batteryHistoryMap = new HashMap<>(); for (int index = 0; index < size; index++) { Loading Loading
src/com/android/settings/fuelgauge/BatteryChartPreferenceController.java +43 −1 Original line number Diff line number Diff line Loading @@ -55,6 +55,8 @@ public class BatteryChartPreferenceController extends AbstractPreferenceControll private static final String TAG = "BatteryChartPreferenceController"; private static final int CHART_KEY_ARRAY_SIZE = 25; private static final int CHART_LEVEL_ARRAY_SIZE = 13; private static final long VALID_USAGE_TIME_DURATION = DateUtils.HOUR_IN_MILLIS * 2; private static final long VALID_DIFF_DURATION = DateUtils.MINUTE_IN_MILLIS * 3; @VisibleForTesting Map<Integer, List<BatteryDiffEntry>> mBatteryIndexedMap; Loading Loading @@ -179,6 +181,7 @@ public class BatteryChartPreferenceController extends AbstractPreferenceControll final List<Long> batteryHistoryKeyList = new ArrayList<Long>(batteryHistoryMap.keySet()); Collections.sort(batteryHistoryKeyList); validateSlotTimestamp(batteryHistoryKeyList); mBatteryHistoryKeys = new long[CHART_KEY_ARRAY_SIZE]; final int elementSize = Math.min(batteryHistoryKeyList.size(), CHART_KEY_ARRAY_SIZE); final int offset = CHART_KEY_ARRAY_SIZE - elementSize; Loading Loading @@ -270,6 +273,10 @@ public class BatteryChartPreferenceController extends AbstractPreferenceControll } else { appEntries.add(entry); } // Validates the usage time if users click a specific slot. if (mTrapezoidIndex >= 0) { validateUsageTime(entry); } }); Collections.sort(appEntries, BatteryDiffEntry.COMPARATOR); Collections.sort(systemEntries, BatteryDiffEntry.COMPARATOR); Loading @@ -289,7 +296,7 @@ public class BatteryChartPreferenceController extends AbstractPreferenceControll final String appLabel = entry.getAppLabel(); final Drawable appIcon = entry.getAppIcon(); if (TextUtils.isEmpty(appLabel) || appIcon == null) { Log.w(TAG, "cannot find app resource:" + entry.mBatteryHistEntry); Log.w(TAG, "cannot find app resource for\n" + entry); continue; } final String prefKey = entry.mBatteryHistEntry.getKey(); Loading Loading @@ -389,4 +396,39 @@ public class BatteryChartPreferenceController extends AbstractPreferenceControll } return builder.toString(); } @VisibleForTesting static boolean validateUsageTime(BatteryDiffEntry entry) { final long foregroundUsageTimeInMs = entry.mForegroundUsageTimeInMs; final long backgroundUsageTimeInMs = entry.mBackgroundUsageTimeInMs; final long totalUsageTimeInMs = foregroundUsageTimeInMs + backgroundUsageTimeInMs; if (foregroundUsageTimeInMs > VALID_USAGE_TIME_DURATION || backgroundUsageTimeInMs > VALID_USAGE_TIME_DURATION || totalUsageTimeInMs > VALID_USAGE_TIME_DURATION) { Log.e(TAG, "validateUsageTime() fail for\n" + entry); return false; } return true; } @VisibleForTesting static boolean validateSlotTimestamp(List<Long> batteryHistoryKeys) { // Whether the nearest two slot time diff is valid or not? final int size = batteryHistoryKeys.size(); for (int index = 0; index < size - 1; index++) { final long currentTime = batteryHistoryKeys.get(index); final long nextTime = batteryHistoryKeys.get(index + 1); final long diffTime = Math.abs( DateUtils.HOUR_IN_MILLIS - Math.abs(currentTime - nextTime)); if (currentTime == 0) { continue; } else if (diffTime > VALID_DIFF_DURATION) { Log.e(TAG, String.format("validateSlotTimestamp() %s > %s", ConvertUtils.utcToLocalTime(currentTime), ConvertUtils.utcToLocalTime(nextTime))); return false; } } return true; } }
src/com/android/settings/fuelgauge/BatteryDiffEntry.java +11 −6 Original line number Diff line number Diff line Loading @@ -27,6 +27,8 @@ import android.util.Log; import androidx.annotation.VisibleForTesting; import com.android.settingslib.utils.StringUtil; import java.time.Duration; import java.util.Comparator; import java.util.HashMap; Loading Loading @@ -254,14 +256,17 @@ public class BatteryDiffEntry { public String toString() { final StringBuilder builder = new StringBuilder() .append("BatteryDiffEntry{") .append("\n\tname=" + mBatteryHistEntry.mAppLabel) .append("\n\tname=" + getAppLabel()) .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)); .append(String.format("\n\tforeground:%s background:%s", StringUtil.formatElapsedTime(mContext, mForegroundUsageTimeInMs, /*withSeconds=*/ true, /*collapseTimeUnit=*/ false), StringUtil.formatElapsedTime(mContext, mBackgroundUsageTimeInMs, /*withSeconds=*/ true, /*collapseTimeUnit=*/ false))) .append(String.format("\n\tpackage:%s|%s uid:%d userId:%d", mBatteryHistEntry.mPackageName, getPackageName(), mBatteryHistEntry.mUid, mBatteryHistEntry.mUserId)); return builder.toString(); } Loading
src/com/android/settings/fuelgauge/BatteryHistEntry.java +5 −0 Original line number Diff line number Diff line Loading @@ -123,6 +123,11 @@ public class BatteryHistEntry { return mConsumerType == ConvertUtils.CONSUMER_TYPE_UID_BATTERY; } /** Whether this {@link BatteryHistEntry} is system consumer or not. */ public boolean isSystemEntry() { return mConsumerType == ConvertUtils.CONSUMER_TYPE_SYSTEM_BATTERY; } /** Gets an identifier to represent this {@link BatteryHistEntry}. */ public String getKey() { if (mKey == null) { Loading
src/com/android/settings/fuelgauge/PowerUsageAdvanced.java +7 −0 Original line number Diff line number Diff line Loading @@ -99,6 +99,13 @@ public class PowerUsageAdvanced extends PowerUsageBase { return R.xml.power_usage_advanced; } @Override public void onPause() { super.onPause(); // Resets the flag to reload usage data in onResume() callback. mIsChartDataLoaded = false; } @Override protected List<AbstractPreferenceController> createPreferenceControllers(Context context) { refreshFeatureFlag(context); Loading
tests/robotests/src/com/android/settings/fuelgauge/BatteryChartPreferenceControllerTest.java +52 −0 Original line number Diff line number Diff line Loading @@ -381,6 +381,58 @@ public final class BatteryChartPreferenceControllerTest { assertThat(pref.getSummary()).isNull(); } @Test public void testValidateUsageTime_returnTrueIfBatteryDiffEntryIsValid() { assertThat(BatteryChartPreferenceController.validateUsageTime( createBatteryDiffEntry( /*foregroundUsageTimeInMs=*/ DateUtils.MINUTE_IN_MILLIS, /*backgroundUsageTimeInMs=*/ DateUtils.MINUTE_IN_MILLIS))) .isTrue(); } @Test public void testValidateUsageTime_foregroundTimeExceedThreshold_returnFalse() { assertThat(BatteryChartPreferenceController.validateUsageTime( createBatteryDiffEntry( /*foregroundUsageTimeInMs=*/ DateUtils.HOUR_IN_MILLIS * 3, /*backgroundUsageTimeInMs=*/ 0))) .isFalse(); } @Test public void testValidateUsageTime_backgroundTimeExceedThreshold_returnFalse() { assertThat(BatteryChartPreferenceController.validateUsageTime( createBatteryDiffEntry( /*foregroundUsageTimeInMs=*/ 0, /*backgroundUsageTimeInMs=*/ DateUtils.HOUR_IN_MILLIS * 3))) .isFalse(); } @Test public void testValidateSlotTimestamp_emptyContent_returnTrue() { assertThat(BatteryChartPreferenceController.validateSlotTimestamp( new ArrayList<Long>())).isTrue(); } @Test public void testValidateSlotTimestamp_returnExpectedResult() { final List<Long> slotTimestampList = Arrays.asList( Long.valueOf(0), Long.valueOf(DateUtils.HOUR_IN_MILLIS), Long.valueOf(DateUtils.HOUR_IN_MILLIS * 2 + DateUtils.MINUTE_IN_MILLIS), Long.valueOf(DateUtils.HOUR_IN_MILLIS * 3 + DateUtils.MINUTE_IN_MILLIS * 2)); // Verifies the testing data is correct before we added invalid data into it. assertThat(BatteryChartPreferenceController.validateSlotTimestamp(slotTimestampList)) .isTrue(); // Insert invalid timestamp into the list. slotTimestampList.add( Long.valueOf(DateUtils.HOUR_IN_MILLIS * 4 + DateUtils.MINUTE_IN_MILLIS * 3)); assertThat(BatteryChartPreferenceController.validateSlotTimestamp(slotTimestampList)) .isFalse(); } private static Map<Long, List<BatteryHistEntry>> createBatteryHistoryMap(int size) { final Map<Long, List<BatteryHistEntry>> batteryHistoryMap = new HashMap<>(); for (int index = 0; index < size; index++) { Loading