Make the list in advanced battery page sorted by usage.

1. Make the preference dynamically generated in code
2. Make PowerUsageData comparable and add title resource id.

Bug: 34385770
Test: RunSettingsRoboTests
Change-Id: I1b90b4c6cc7107bc146e3554db04cec7641e1cde
This commit is contained in:
jackqdyulei
2017-02-09 09:38:01 -08:00
parent d72b6cc1e9
commit 22dbc106e7
4 changed files with 93 additions and 111 deletions

View File

@@ -25,40 +25,6 @@
<PreferenceCategory
android:key="battery_usage_list"
android:title="@string/battery_detail_since_full_charge">
<com.android.settings.fuelgauge.PowerGaugePreference
android:key="battery_apps"
android:title="@string/power_apps"/>
<com.android.settings.fuelgauge.PowerGaugePreference
android:key="battery_wifi"
android:title="@string/power_wifi"/>
<com.android.settings.fuelgauge.PowerGaugePreference
android:key="battery_cell"
android:title="@string/power_cell"/>
<com.android.settings.fuelgauge.PowerGaugePreference
android:key="battery_service"
android:title="@string/power_service"/>
<com.android.settings.fuelgauge.PowerGaugePreference
android:key="battery_system"
android:title="@string/power_system"/>
<com.android.settings.fuelgauge.PowerGaugePreference
android:key="battery_bluetooth"
android:title="@string/power_bluetooth"/>
<com.android.settings.fuelgauge.PowerGaugePreference
android:key="battery_idle"
android:title="@string/power_idle"/>
<com.android.settings.fuelgauge.PowerGaugePreference
android:key="battery_user"
android:title="@string/power_user"/>
</PreferenceCategory>
android:title="@string/battery_detail_since_full_charge"/>
</PreferenceScreen>

View File

@@ -49,13 +49,8 @@ public class PowerGaugePreference extends TintablePreference {
mIconSize = context.getResources().getDimensionPixelSize(R.dimen.app_icon_size);
}
public PowerGaugePreference(Context context, AttributeSet attrs) {
super(context, attrs);
final Drawable icon = context.getDrawable(R.drawable.ic_battery_circle);
setIcon(icon);
setWidgetLayoutResource(R.layout.preference_widget_summary);
mIconSize = icon.getIntrinsicWidth();
public PowerGaugePreference(Context context) {
this(context, null, null, null);
}
public void setContentDescription(String name) {

View File

@@ -19,8 +19,10 @@ import android.os.Process;
import android.provider.SearchIndexableResource;
import android.support.annotation.ColorInt;
import android.support.annotation.IntDef;
import android.support.annotation.NonNull;
import android.support.annotation.StringRes;
import android.support.annotation.VisibleForTesting;
import android.util.SparseArray;
import android.support.v7.preference.PreferenceGroup;
import com.android.internal.logging.nano.MetricsProto;
import com.android.internal.os.BatterySipper;
import com.android.internal.os.BatterySipper.DrainType;
@@ -35,32 +37,37 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
public class PowerUsageAdvanced extends PowerUsageBase {
private static final String TAG = "AdvancedBatteryUsage";
private static final String KEY_BATTERY_GRAPH = "battery_graph";
private static final String KEY_BATTERY_APPS = "battery_apps";
private static final String KEY_BATTERY_WIFI = "battery_wifi";
private static final String KEY_BATTERY_CELL = "battery_cell";
private static final String KEY_BATTERY_BLUETOOTH = "battery_bluetooth";
private static final String KEY_BATTERY_IDLE = "battery_idle";
private static final String KEY_BATTERY_SERVICE = "battery_service";
private static final String KEY_BATTERY_SYSTEM = "battery_system";
private static final String KEY_BATTERY_USER = "battery_user";
private static final String KEY_BATTERY_USAGE_LIST = "battery_usage_list";
private BatteryHistoryPreference mHistPref;
@VisibleForTesting
SparseArray<String> mUsageTypeMap;
final int[] mUsageTypes = {
UsageType.WIFI,
UsageType.CELL,
UsageType.SERVICE,
UsageType.SYSTEM,
UsageType.BLUETOOTH,
UsageType.USER,
UsageType.IDLE,
UsageType.APP};
private BatteryHistoryPreference mHistPref;
private PreferenceGroup mUsageListGroup;
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
mHistPref = (BatteryHistoryPreference) findPreference(KEY_BATTERY_GRAPH);
init();
mUsageListGroup = (PreferenceGroup) findPreference(KEY_BATTERY_USAGE_LIST);
}
@Override
@@ -96,12 +103,15 @@ public class PowerUsageAdvanced extends PowerUsageBase {
updatePreference(mHistPref);
List<PowerUsageData> dataList = parsePowerUsageData(mStatsHelper);
mUsageListGroup.removeAll();
for (int i = 0, size = dataList.size(); i < size; i++) {
final PowerUsageData data = dataList.get(i);
final String key = mUsageTypeMap.get(data.usageType);
if (key != null) {
bindData(key, data);
}
final PowerUsageData batteryData = dataList.get(i);
final PowerGaugePreference pref = new PowerGaugePreference(getContext());
pref.setTitle(batteryData.titleResId);
pref.setSummary(batteryData.summary);
pref.setPercent(batteryData.percentage);
mUsageListGroup.addPreference(pref);
}
}
@@ -128,28 +138,13 @@ public class PowerUsageAdvanced extends PowerUsageBase {
}
}
@VisibleForTesting
void init() {
// Store projection from UsageType to preference key
mUsageTypeMap = new SparseArray<>();
mUsageTypeMap.put(UsageType.APP, KEY_BATTERY_APPS);
mUsageTypeMap.put(UsageType.WIFI, KEY_BATTERY_WIFI);
mUsageTypeMap.put(UsageType.CELL, KEY_BATTERY_CELL);
mUsageTypeMap.put(UsageType.BLUETOOTH, KEY_BATTERY_BLUETOOTH);
mUsageTypeMap.put(UsageType.IDLE, KEY_BATTERY_IDLE);
mUsageTypeMap.put(UsageType.SERVICE, KEY_BATTERY_SERVICE);
mUsageTypeMap.put(UsageType.USER, KEY_BATTERY_USER);
mUsageTypeMap.put(UsageType.SYSTEM, KEY_BATTERY_SYSTEM);
}
@VisibleForTesting
List<PowerUsageData> parsePowerUsageData(BatteryStatsHelper statusHelper) {
final List<BatterySipper> batterySippers = statusHelper.getUsageList();
final Map<Integer, PowerUsageData> batteryDataMap = new HashMap<>();
for (int i = 0, size = mUsageTypeMap.size(); i < size; i++) {
@UsageType final int type = mUsageTypeMap.keyAt(i);
batteryDataMap.put(type, PowerUsageData.createBatteryUsageData(type));
for (final @UsageType Integer type : mUsageTypes) {
batteryDataMap.put(type, new PowerUsageData(type));
}
// Accumulate power usage based on usage type
@@ -165,21 +160,17 @@ public class PowerUsageAdvanced extends PowerUsageBase {
usageData.percentage = (usageData.totalPowerMah / totalPower) * 100;
}
Collections.sort(batteryDataList);
return batteryDataList;
}
private void bindData(String key, PowerUsageData batteryData) {
final PowerGaugePreference pref = (PowerGaugePreference) findPreference(key);
pref.setSummary(batteryData.summary);
pref.setPercent(batteryData.percentage);
}
/**
* Class that contains data used in {@link PowerGaugePreference}.
*/
@VisibleForTesting
static class PowerUsageData {
static class PowerUsageData implements Comparable<PowerUsageData> {
@Retention(RetentionPolicy.SOURCE)
@IntDef({UsageType.APP,
UsageType.WIFI,
@@ -200,6 +191,8 @@ public class PowerUsageAdvanced extends PowerUsageBase {
int IDLE = 7;
}
@StringRes
public int titleResId;
public String summary;
public double percentage;
public double totalPowerMah;
@@ -208,14 +201,43 @@ public class PowerUsageAdvanced extends PowerUsageBase {
@UsageType
public int usageType;
private PowerUsageData(@UsageType int usageType) {
this.usageType = usageType;
totalPowerMah = 0;
public PowerUsageData(@UsageType int usageType) {
this(usageType, 0);
}
public static PowerUsageData createBatteryUsageData(@UsageType int usageType) {
// TODO(b/34385770): add color logic in this part
return new PowerUsageData(usageType);
public PowerUsageData(@UsageType int usageType, double totalPower) {
this.usageType = usageType;
totalPowerMah = 0;
titleResId = getTitleResId(usageType);
totalPowerMah = totalPower;
}
private int getTitleResId(@UsageType int usageType) {
switch (usageType) {
case UsageType.WIFI:
return R.string.power_wifi;
case UsageType.CELL:
return R.string.power_cell;
case UsageType.SERVICE:
return R.string.power_service;
case UsageType.SYSTEM:
return R.string.power_system;
case UsageType.BLUETOOTH:
return R.string.power_bluetooth;
case UsageType.USER:
return R.string.power_user;
case UsageType.IDLE:
return R.string.power_idle;
case UsageType.APP:
default:
return R.string.power_apps;
}
}
@Override
public int compareTo(@NonNull PowerUsageData powerUsageData) {
final int diff = Double.compare(powerUsageData.totalPowerMah, totalPowerMah);
return diff != 0 ? diff : usageType - powerUsageData.usageType;
}
}

View File

@@ -1,7 +1,6 @@
package com.android.settings.fuelgauge;
import android.os.Process;
import android.util.SparseArray;
import com.android.internal.os.BatterySipper;
import com.android.internal.os.BatterySipper.DrainType;
import com.android.internal.os.BatteryStatsHelper;
@@ -17,7 +16,9 @@ import org.mockito.MockitoAnnotations;
import org.robolectric.annotation.Config;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.when;
@@ -33,7 +34,6 @@ public class PowerUsageAdvancedTest {
private static final double TOTAL_USAGE = TYPE_APP_USAGE * 2 + TYPE_BLUETOOTH_USAGE
+ TYPE_WIFI_USAGE;
private static final double PRECISION = 0.001;
private static final String STRING_NOT_FOUND = "not_found";
@Mock
private BatterySipper mBatterySipper;
@Mock
@@ -92,7 +92,6 @@ public class PowerUsageAdvancedTest {
final double percentWifi = TYPE_WIFI_USAGE / TOTAL_USAGE * 100;
final double percentBluetooth = TYPE_BLUETOOTH_USAGE / TOTAL_USAGE * 100;
mPowerUsageAdvanced.init();
List<PowerUsageData> batteryData =
mPowerUsageAdvanced.parsePowerUsageData(mBatteryStatsHelper);
for (PowerUsageData data : batteryData) {
@@ -114,24 +113,24 @@ public class PowerUsageAdvancedTest {
@Test
public void testInit_ContainsAllUsageType() {
mPowerUsageAdvanced.init();
final SparseArray<String> array = mPowerUsageAdvanced.mUsageTypeMap;
final int[] usageTypeSet = mPowerUsageAdvanced.mUsageTypes;
assertThat(array.get(UsageType.APP, STRING_NOT_FOUND))
.isNotEqualTo(STRING_NOT_FOUND);
assertThat(array.get(UsageType.WIFI, STRING_NOT_FOUND))
.isNotEqualTo(STRING_NOT_FOUND);
assertThat(array.get(UsageType.CELL, STRING_NOT_FOUND))
.isNotEqualTo(STRING_NOT_FOUND);
assertThat(array.get(UsageType.BLUETOOTH, STRING_NOT_FOUND))
.isNotEqualTo(STRING_NOT_FOUND);
assertThat(array.get(UsageType.IDLE, STRING_NOT_FOUND))
.isNotEqualTo(STRING_NOT_FOUND);
assertThat(array.get(UsageType.SERVICE, STRING_NOT_FOUND))
.isNotEqualTo(STRING_NOT_FOUND);
assertThat(array.get(UsageType.USER, STRING_NOT_FOUND))
.isNotEqualTo(STRING_NOT_FOUND);
assertThat(array.get(UsageType.SYSTEM, STRING_NOT_FOUND))
.isNotEqualTo(STRING_NOT_FOUND);
assertThat(usageTypeSet).asList().containsExactly(UsageType.APP, UsageType.WIFI,
UsageType.CELL, UsageType.BLUETOOTH, UsageType.IDLE, UsageType.SERVICE,
UsageType.USER, UsageType.SYSTEM);
}
@Test
public void testPowerUsageData_SortedByUsage() {
List<PowerUsageData> dataList = new ArrayList<>();
dataList.add(new PowerUsageData(UsageType.WIFI, TYPE_WIFI_USAGE));
dataList.add(new PowerUsageData(UsageType.BLUETOOTH, TYPE_BLUETOOTH_USAGE));
dataList.add(new PowerUsageData(UsageType.APP, TYPE_APP_USAGE));
Collections.sort(dataList);
for (int i = 1, size = dataList.size(); i < size; i++) {
assertThat(dataList.get(i - 1).totalPowerMah).isAtLeast(dataList.get(i).totalPowerMah);
}
}
}