0. 介绍
主要介绍UI位置和基本函数入口,其中耗电详情与power_profile.xml息息相关
1. UI 界面
2. 源码
2.1 设置界面入口
PowerUsageSummary->getPreferenceScreenResId()
package com.android.settings.fuelgauge;
/**
* Displays a list of apps and subsystems that consume power, ordered by how much power was
* consumed since the last time it was unplugged.
*/
public class PowerUsageSummary extends PowerUsageBase implements
AnomalyDialogListener, OnLongClickListener, OnClickListener {
@Override
protected int getPreferenceScreenResId() {
return R.xml.power_usage_summary;
}
2.2 UI 布局
R.xml.power_usage_summary
<string name="power_usage_list_summary" msgid="6775339745194635000">"充满电(<xliff:g id="TIME">^1</xliff:g>前)后的应用用电量"</string>
<PreferenceCategory
android:key="app_list"
android:title="@string/power_usage_list_summary"/>
上述即 key 为 app_list 为耗电详情列表
2.3 耗电详情 app_list
PowerUsageSummary.java
private static final String KEY_APP_LIST = "app_list";
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
...
mAppListGroup = (PreferenceGroup) findPreference(KEY_APP_LIST);
2.4 耗电数据填充
- PowerUsageSummary->refreshAppListGroup, 显示耗电详情
- PowerUsageSummary->addNotAvailableMessage, 显示没有电池使用数据
private void refreshAppListGroup() {
...
mAppListGroup.addPreference(notAvailable);
...
}
private void addNotAvailableMessage() {
final String NOT_AVAILABLE = "not_available";
Preference notAvailable = getCachedPreference(NOT_AVAILABLE);
if (notAvailable == null) {
notAvailable = new Preference(getPrefContext());
notAvailable.setKey(NOT_AVAILABLE);
// <string name="power_usage_not_available" msgid="3109326074656512387">"没有电池使用数据。"</string>
notAvailable.setTitle(R.string.power_usage_not_available);
mAppListGroup.addPreference(notAvailable);
}
}
2.5 refreshAppListGroup 数据处理
2.5.1 条件判断-功耗参考文件
PowerUsageSummary->refreshAppListGroup
// 是否使用假数据
private static final boolean USE_FAKE_DATA = false;
// 背光电流的最小值
private static final int MIN_AVERAGE_POWER_THRESHOLD_MILLI_AMP = 10;
private void refreshAppListGroup() {
// 获取背光亮度功率
final double averagePower = powerProfile.getAveragePower(PowerProfile.POWER_SCREEN_FULL);
if (averagePower >= MIN_AVERAGE_POWER_THRESHOLD_MILLI_AMP || USE_FAKE_DATA) {
// 这里要求平均电流需要大于 10, 要求我们需要配置 power_profile.xml 文件的电流数据
// frameworks\base\core\res\res\xml\power_profile.xml 厂商根据功耗电流进行配置,否则该项数据始终为无
final List<BatterySipper> usageList = getCoalescedUsageList(
USE_FAKE_DATA ? getFakeStats() : mStatsHelper.getUsageList());
}
小知识
文件路径在于:frameworks\base\core\java\com\android\internal\os\PowerProfile.java
文件路径:frameworks\base\core\res\res\xml\power_profile.xml
/**
* Power consumption at full backlight brightness. If the backlight is at
* 50% brightness, then this should be multiplied by 0.5
*/
public static final String POWER_SCREEN_FULL = "screen.full";
<item name="screen.full">0.1</item> <!-- ~300mA -->
2.5.2 功耗文件,获取假数据
PowerUsageSummary-> getFakeStats()
private static List<BatterySipper> getFakeStats() {
ArrayList<BatterySipper> stats = new ArrayList<>();
float use = 5;
for (DrainType type : DrainType.values()) {
if (type == DrainType.APP) {
continue;
}
stats.add(new BatterySipper(type, null, use));
use += 5;
}
for (int i = 0; i < 100; i++) {
stats.add(new BatterySipper(DrainType.APP,
new FakeUid(Process.FIRST_APPLICATION_UID + i), use));
}
stats.add(new BatterySipper(DrainType.APP,
new FakeUid(0), use));
// Simulate dex2oat process.
BatterySipper sipper = new BatterySipper(DrainType.APP,
new FakeUid(UserHandle.getSharedAppGid(Process.FIRST_APPLICATION_UID)), 10.0f);
sipper.packageWithHighestDrain = "dex2oat";
stats.add(sipper);
sipper = new BatterySipper(DrainType.APP,
new FakeUid(UserHandle.getSharedAppGid(Process.FIRST_APPLICATION_UID + 1)), 10.0f);
sipper.packageWithHighestDrain = "dex2oat";
stats.add(sipper);
sipper = new BatterySipper(DrainType.APP,
new FakeUid(UserHandle.getSharedAppGid(Process.LOG_UID)), 9.0f);
stats.add(sipper);
return stats;
}
2.5.3 功耗文件,获取功耗数据
frameworks/base/core/java/com/android/internal/os/BatteryStatsHelper.java
BatteryStatsHelper->getUsageList()
/**
* List of apps using power.
*/
private final List<BatterySipper> mUsageList = new ArrayList<>();
public List<BatterySipper> getUsageList() {
return mUsageList;
}
public void refreshStats(int statsType, SparseArray<UserHandle> asUsers, long rawRealtimeUs, long rawUptimeUs) {
...
mUsageList.add(index, bs);
...
}