Transition BatteryAppListPreferences to BatteryUsageStats API
Bug: 173745486 Test: make RunSettingsRoboTests Test: male RunSettingsGoogleRoboTests Change-Id: I7af8cbcd27433b89cb2184750c6854aa74761d0d
This commit is contained in:
@@ -18,7 +18,6 @@ package com.android.settings.applications.appinfo;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.os.BatteryStats;
|
||||
import android.os.BatteryUsageStats;
|
||||
import android.os.Bundle;
|
||||
import android.os.UidBatteryConsumer;
|
||||
@@ -112,10 +111,10 @@ public class AppBatteryPreferenceController extends BasePreferenceController
|
||||
if (isBatteryStatsAvailable()) {
|
||||
final UserManager userManager =
|
||||
(UserManager) mContext.getSystemService(Context.USER_SERVICE);
|
||||
final BatteryEntry entry = new BatteryEntry(mContext, null, userManager, mSipper,
|
||||
mUidBatteryConsumer, mPackageName);
|
||||
final BatteryEntry entry = new BatteryEntry(mContext, /* handler */null, userManager,
|
||||
mUidBatteryConsumer, /* isHidden */ false, /* packages */ null, mPackageName);
|
||||
AdvancedPowerUsageDetail.startBatteryDetailPage(mParent.getActivity(), mParent,
|
||||
mBatteryHelper, BatteryStats.STATS_SINCE_CHARGED, entry, mBatteryPercent);
|
||||
entry, mBatteryPercent);
|
||||
} else {
|
||||
AdvancedPowerUsageDetail.startBatteryDetailPage(mParent.getActivity(), mParent,
|
||||
mPackageName);
|
||||
|
@@ -32,7 +32,6 @@ import android.view.View;
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
import androidx.preference.Preference;
|
||||
|
||||
import com.android.internal.os.BatteryStatsHelper;
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.SettingsActivity;
|
||||
import com.android.settings.Utils;
|
||||
@@ -98,16 +97,14 @@ public class AdvancedPowerUsageDetail extends DashboardFragment implements
|
||||
|
||||
private String mPackageName;
|
||||
|
||||
@VisibleForTesting
|
||||
static void startBatteryDetailPage(Activity caller, BatteryUtils batteryUtils,
|
||||
InstrumentedPreferenceFragment fragment, BatteryStatsHelper helper, int which,
|
||||
BatteryEntry entry, String usagePercent) {
|
||||
// Initialize mStats if necessary.
|
||||
helper.getStats();
|
||||
|
||||
/**
|
||||
* Launches battery details page for an individual battery consumer.
|
||||
*/
|
||||
public static void startBatteryDetailPage(Activity caller,
|
||||
InstrumentedPreferenceFragment fragment, BatteryEntry entry, String usagePercent) {
|
||||
final Bundle args = new Bundle();
|
||||
final long foregroundTimeMs = entry.getTimeInForegroundMs(batteryUtils);
|
||||
final long backgroundTimeMs = entry.getTimeInBackgroundMs(batteryUtils);
|
||||
final long foregroundTimeMs = entry.getTimeInForegroundMs();
|
||||
final long backgroundTimeMs = entry.getTimeInBackgroundMs();
|
||||
final String packageName = entry.getDefaultPackageName();
|
||||
if (packageName == null) {
|
||||
// populate data for system app
|
||||
@@ -142,13 +139,6 @@ public class AdvancedPowerUsageDetail extends DashboardFragment implements
|
||||
return UserHandle.getUserId(batteryEntry.getUid());
|
||||
}
|
||||
|
||||
public static void startBatteryDetailPage(Activity caller,
|
||||
InstrumentedPreferenceFragment fragment, BatteryStatsHelper helper, int which,
|
||||
BatteryEntry entry, String usagePercent) {
|
||||
startBatteryDetailPage(caller, BatteryUtils.getInstance(caller), fragment, helper, which,
|
||||
entry, usagePercent);
|
||||
}
|
||||
|
||||
public static void startBatteryDetailPage(Activity caller,
|
||||
InstrumentedPreferenceFragment fragment, String packageName) {
|
||||
final Bundle args = new Bundle(3);
|
||||
|
@@ -19,18 +19,22 @@ package com.android.settings.fuelgauge;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.BatteryStats;
|
||||
import android.os.BatteryConsumer;
|
||||
import android.os.BatteryUsageStats;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.os.Message;
|
||||
import android.os.Process;
|
||||
import android.os.SystemBatteryConsumer;
|
||||
import android.os.UidBatteryConsumer;
|
||||
import android.os.UserBatteryConsumer;
|
||||
import android.os.UserHandle;
|
||||
import android.os.UserManager;
|
||||
import android.text.TextUtils;
|
||||
import android.text.format.DateUtils;
|
||||
import android.util.ArrayMap;
|
||||
import android.util.Log;
|
||||
import android.util.SparseArray;
|
||||
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
@@ -38,9 +42,6 @@ import androidx.preference.Preference;
|
||||
import androidx.preference.PreferenceGroup;
|
||||
import androidx.preference.PreferenceScreen;
|
||||
|
||||
import com.android.internal.os.BatterySipper;
|
||||
import com.android.internal.os.BatterySipper.DrainType;
|
||||
import com.android.internal.os.BatteryStatsHelper;
|
||||
import com.android.internal.os.PowerProfile;
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.SettingsActivity;
|
||||
@@ -65,32 +66,53 @@ public class BatteryAppListPreferenceController extends AbstractPreferenceContro
|
||||
static final boolean USE_FAKE_DATA = false;
|
||||
private static final int MAX_ITEMS_TO_LIST = USE_FAKE_DATA ? 30 : 20;
|
||||
private static final int MIN_AVERAGE_POWER_THRESHOLD_MILLI_AMP = 10;
|
||||
private static final int STATS_TYPE = BatteryStats.STATS_SINCE_CHARGED;
|
||||
|
||||
private final String mPreferenceKey;
|
||||
@VisibleForTesting
|
||||
PreferenceGroup mAppListGroup;
|
||||
private BatteryStatsHelper mBatteryStatsHelper;
|
||||
private BatteryUsageStats mBatteryUsageStats;
|
||||
private ArrayMap<String, Preference> mPreferenceCache;
|
||||
@VisibleForTesting
|
||||
BatteryUtils mBatteryUtils;
|
||||
private UserManager mUserManager;
|
||||
private SettingsActivity mActivity;
|
||||
private InstrumentedPreferenceFragment mFragment;
|
||||
private final UserManager mUserManager;
|
||||
private final PackageManager mPackageManager;
|
||||
private final SettingsActivity mActivity;
|
||||
private final InstrumentedPreferenceFragment mFragment;
|
||||
private Context mPrefContext;
|
||||
|
||||
private Handler mHandler = new Handler(Looper.getMainLooper()) {
|
||||
/**
|
||||
* Battery attribution list configuration.
|
||||
*/
|
||||
public interface Config {
|
||||
/**
|
||||
* Returns true if the attribution list should be shown.
|
||||
*/
|
||||
boolean shouldShowBatteryAttributionList(Context context);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
static Config sConfig = new Config() {
|
||||
@Override
|
||||
public boolean shouldShowBatteryAttributionList(Context context) {
|
||||
if (USE_FAKE_DATA) {
|
||||
return true;
|
||||
}
|
||||
|
||||
PowerProfile powerProfile = new PowerProfile(context);
|
||||
return powerProfile.getAveragePower(PowerProfile.POWER_SCREEN_FULL)
|
||||
>= MIN_AVERAGE_POWER_THRESHOLD_MILLI_AMP;
|
||||
}
|
||||
};
|
||||
|
||||
private final Handler mHandler = new Handler(Looper.getMainLooper()) {
|
||||
@Override
|
||||
public void handleMessage(Message msg) {
|
||||
switch (msg.what) {
|
||||
case BatteryEntry.MSG_UPDATE_NAME_ICON:
|
||||
BatteryEntry entry = (BatteryEntry) msg.obj;
|
||||
int uid = entry.getUid();
|
||||
PowerGaugePreference pgp =
|
||||
(PowerGaugePreference) mAppListGroup.findPreference(
|
||||
Integer.toString(uid));
|
||||
PowerGaugePreference pgp = mAppListGroup.findPreference(entry.getKey());
|
||||
if (pgp != null) {
|
||||
final int userId = UserHandle.getUserId(uid);
|
||||
final int userId = UserHandle.getUserId(entry.getUid());
|
||||
final UserHandle userHandle = new UserHandle(userId);
|
||||
pgp.setIcon(mUserManager.getBadgedIconForUser(entry.getIcon(), userHandle));
|
||||
pgp.setTitle(entry.name);
|
||||
@@ -122,6 +144,7 @@ public class BatteryAppListPreferenceController extends AbstractPreferenceContro
|
||||
mPreferenceKey = preferenceKey;
|
||||
mBatteryUtils = BatteryUtils.getInstance(context);
|
||||
mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
|
||||
mPackageManager = context.getPackageManager();
|
||||
mActivity = activity;
|
||||
mFragment = fragment;
|
||||
}
|
||||
@@ -161,79 +184,63 @@ public class BatteryAppListPreferenceController extends AbstractPreferenceContro
|
||||
if (preference instanceof PowerGaugePreference) {
|
||||
PowerGaugePreference pgp = (PowerGaugePreference) preference;
|
||||
BatteryEntry entry = pgp.getInfo();
|
||||
AdvancedPowerUsageDetail.startBatteryDetailPage(mActivity, mBatteryUtils,
|
||||
mFragment, mBatteryStatsHelper, STATS_TYPE, entry, pgp.getPercent());
|
||||
AdvancedPowerUsageDetail.startBatteryDetailPage(mActivity,
|
||||
mFragment, entry, pgp.getPercent());
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void refreshAppListGroup(BatteryStatsHelper statsHelper, boolean showAllApps) {
|
||||
/**
|
||||
* Refreshes the list of battery consumers using the supplied BatteryUsageStats.
|
||||
*/
|
||||
public void refreshAppListGroup(BatteryUsageStats batteryUsageStats, boolean showAllApps) {
|
||||
if (!isAvailable()) {
|
||||
return;
|
||||
}
|
||||
|
||||
mBatteryStatsHelper = statsHelper;
|
||||
mBatteryUsageStats = USE_FAKE_DATA ? getFakeStats() : batteryUsageStats;
|
||||
mAppListGroup.setTitle(R.string.power_usage_list_summary);
|
||||
|
||||
final PowerProfile powerProfile = statsHelper.getPowerProfile();
|
||||
final BatteryStats stats = statsHelper.getStats();
|
||||
final double averagePower = powerProfile.getAveragePower(PowerProfile.POWER_SCREEN_FULL);
|
||||
boolean addedSome = false;
|
||||
final int dischargeAmount = USE_FAKE_DATA ? 5000
|
||||
: stats != null ? stats.getDischargeAmount(STATS_TYPE) : 0;
|
||||
|
||||
cacheRemoveAllPrefs(mAppListGroup);
|
||||
mAppListGroup.setOrderingAsAdded(false);
|
||||
|
||||
if (averagePower >= MIN_AVERAGE_POWER_THRESHOLD_MILLI_AMP || USE_FAKE_DATA) {
|
||||
final List<BatterySipper> usageList = getCoalescedUsageList(
|
||||
USE_FAKE_DATA ? getFakeStats() : statsHelper.getUsageList());
|
||||
if (!showAllApps) {
|
||||
mBatteryUtils.removeHiddenBatterySippers(usageList);
|
||||
}
|
||||
mBatteryUtils.sortUsageList(usageList);
|
||||
|
||||
if (sConfig.shouldShowBatteryAttributionList(mContext)) {
|
||||
final int dischargePercentage = getDischargePercentage(batteryUsageStats);
|
||||
final List<BatteryEntry> usageList = getCoalescedUsageList(showAllApps);
|
||||
final double totalPower = batteryUsageStats.getConsumedPower();
|
||||
final int numSippers = usageList.size();
|
||||
for (int i = 0; i < numSippers; i++) {
|
||||
final BatterySipper sipper = usageList.get(i);
|
||||
double totalPower = USE_FAKE_DATA ? 4000 : statsHelper.getTotalPower();
|
||||
final BatteryEntry entry = usageList.get(i);
|
||||
|
||||
final double percentOfTotal = mBatteryUtils.calculateBatteryPercent(
|
||||
sipper.totalPowerMah, totalPower, dischargeAmount);
|
||||
entry.getConsumedPower(), totalPower, dischargePercentage);
|
||||
|
||||
if (((int) (percentOfTotal + .5)) < 1) {
|
||||
continue;
|
||||
}
|
||||
if (shouldHideSipper(sipper)) {
|
||||
continue;
|
||||
}
|
||||
final UserHandle userHandle = new UserHandle(UserHandle.getUserId(sipper.getUid()));
|
||||
final BatteryEntry entry = new BatteryEntry(mActivity, mHandler, mUserManager,
|
||||
sipper, null, null);
|
||||
|
||||
final UserHandle userHandle = new UserHandle(UserHandle.getUserId(entry.getUid()));
|
||||
final Drawable badgedIcon = mUserManager.getBadgedIconForUser(entry.getIcon(),
|
||||
userHandle);
|
||||
final CharSequence contentDescription = mUserManager.getBadgedLabelForUser(
|
||||
entry.getLabel(),
|
||||
userHandle);
|
||||
entry.getLabel(), userHandle);
|
||||
|
||||
final String key = extractKeyFromSipper(sipper);
|
||||
final String key = entry.getKey();
|
||||
PowerGaugePreference pref = (PowerGaugePreference) getCachedPreference(key);
|
||||
if (pref == null) {
|
||||
pref = new PowerGaugePreference(mPrefContext, badgedIcon,
|
||||
contentDescription, entry);
|
||||
pref.setKey(key);
|
||||
}
|
||||
sipper.percent = percentOfTotal;
|
||||
entry.percent = percentOfTotal;
|
||||
pref.setTitle(entry.getLabel());
|
||||
pref.setOrder(i + 1);
|
||||
pref.setPercent(percentOfTotal);
|
||||
pref.shouldShowAnomalyIcon(false);
|
||||
if (sipper.usageTimeMs == 0 && sipper.drainType == DrainType.APP) {
|
||||
sipper.usageTimeMs = mBatteryUtils.getProcessTimeMs(
|
||||
BatteryUtils.StatusType.FOREGROUND, sipper.uidObj, STATS_TYPE);
|
||||
}
|
||||
setUsageSummary(pref, sipper);
|
||||
setUsageSummary(pref, entry);
|
||||
addedSome = true;
|
||||
mAppListGroup.addPreference(pref);
|
||||
if (mAppListGroup.getPreferenceCount() - getCachedCount()
|
||||
@@ -250,6 +257,14 @@ public class BatteryAppListPreferenceController extends AbstractPreferenceContro
|
||||
BatteryEntry.startRequestQueue();
|
||||
}
|
||||
|
||||
private int getDischargePercentage(BatteryUsageStats batteryUsageStats) {
|
||||
int dischargePercentage = batteryUsageStats.getDischargePercentage();
|
||||
if (dischargePercentage < 0) {
|
||||
dischargePercentage = 0;
|
||||
}
|
||||
return dischargePercentage;
|
||||
}
|
||||
|
||||
/**
|
||||
* We want to coalesce some UIDs. For example, dex2oat runs under a shared gid that
|
||||
* exists for all users of the same app. We detect this case and merge the power use
|
||||
@@ -257,129 +272,102 @@ public class BatteryAppListPreferenceController extends AbstractPreferenceContro
|
||||
*
|
||||
* @return A sorted list of apps using power.
|
||||
*/
|
||||
private List<BatterySipper> getCoalescedUsageList(final List<BatterySipper> sippers) {
|
||||
final SparseArray<BatterySipper> uidList = new SparseArray<>();
|
||||
private List<BatteryEntry> getCoalescedUsageList(boolean showAllApps) {
|
||||
final SparseArray<BatteryEntry> batteryEntryList = new SparseArray<>();
|
||||
|
||||
final ArrayList<BatterySipper> results = new ArrayList<>();
|
||||
final int numSippers = sippers.size();
|
||||
for (int i = 0; i < numSippers; i++) {
|
||||
BatterySipper sipper = sippers.get(i);
|
||||
if (sipper.getUid() > 0) {
|
||||
int realUid = sipper.getUid();
|
||||
final ArrayList<BatteryEntry> results = new ArrayList<>();
|
||||
final List<UidBatteryConsumer> uidBatteryConsumers =
|
||||
mBatteryUsageStats.getUidBatteryConsumers();
|
||||
for (int i = 0, size = uidBatteryConsumers.size(); i < size; i++) {
|
||||
final UidBatteryConsumer consumer = uidBatteryConsumers.get(i);
|
||||
int realUid = consumer.getUid();
|
||||
|
||||
// Check if this UID is a shared GID. If so, we combine it with the OWNER's
|
||||
// actual app UID.
|
||||
if (isSharedGid(sipper.getUid())) {
|
||||
realUid = UserHandle.getUid(UserHandle.USER_SYSTEM,
|
||||
UserHandle.getAppIdFromSharedAppGid(sipper.getUid()));
|
||||
}
|
||||
// Check if this UID is a shared GID. If so, we combine it with the OWNER's
|
||||
// actual app UID.
|
||||
if (isSharedGid(consumer.getUid())) {
|
||||
realUid = UserHandle.getUid(UserHandle.USER_SYSTEM,
|
||||
UserHandle.getAppIdFromSharedAppGid(consumer.getUid()));
|
||||
}
|
||||
|
||||
// Check if this UID is a system UID (mediaserver, logd, nfc, drm, etc).
|
||||
if (isSystemUid(realUid)
|
||||
&& !"mediaserver".equals(sipper.packageWithHighestDrain)) {
|
||||
// Use the system UID for all UIDs running in their own sandbox that
|
||||
// are not apps. We exclude mediaserver because we already are expected to
|
||||
// report that as a separate item.
|
||||
realUid = Process.SYSTEM_UID;
|
||||
}
|
||||
// Check if this UID is a system UID (mediaserver, logd, nfc, drm, etc).
|
||||
if (isSystemUid(realUid)
|
||||
&& !"mediaserver".equals(consumer.getPackageWithHighestDrain())) {
|
||||
// Use the system UID for all UIDs running in their own sandbox that
|
||||
// are not apps. We exclude mediaserver because we already are expected to
|
||||
// report that as a separate item.
|
||||
realUid = Process.SYSTEM_UID;
|
||||
}
|
||||
|
||||
if (realUid != sipper.getUid()) {
|
||||
// Replace the BatterySipper with a new one with the real UID set.
|
||||
BatterySipper newSipper = new BatterySipper(sipper.drainType,
|
||||
new FakeUid(realUid), 0.0);
|
||||
newSipper.add(sipper);
|
||||
newSipper.packageWithHighestDrain = sipper.packageWithHighestDrain;
|
||||
newSipper.mPackages = sipper.mPackages;
|
||||
sipper = newSipper;
|
||||
}
|
||||
final String[] packages = mPackageManager.getPackagesForUid(consumer.getUid());
|
||||
if (mBatteryUtils.shouldHideUidBatteryConsumerUnconditionally(consumer, packages)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
int index = uidList.indexOfKey(realUid);
|
||||
if (index < 0) {
|
||||
// New entry.
|
||||
uidList.put(realUid, sipper);
|
||||
} else {
|
||||
// Combine BatterySippers if we already have one with this UID.
|
||||
final BatterySipper existingSipper = uidList.valueAt(index);
|
||||
existingSipper.add(sipper);
|
||||
if (existingSipper.packageWithHighestDrain == null
|
||||
&& sipper.packageWithHighestDrain != null) {
|
||||
existingSipper.packageWithHighestDrain = sipper.packageWithHighestDrain;
|
||||
}
|
||||
final boolean isHidden = mBatteryUtils.shouldHideUidBatteryConsumer(consumer, packages);
|
||||
if (isHidden && !showAllApps) {
|
||||
continue;
|
||||
}
|
||||
|
||||
final int existingPackageLen = existingSipper.mPackages != null ?
|
||||
existingSipper.mPackages.length : 0;
|
||||
final int newPackageLen = sipper.mPackages != null ?
|
||||
sipper.mPackages.length : 0;
|
||||
if (newPackageLen > 0) {
|
||||
String[] newPackages = new String[existingPackageLen + newPackageLen];
|
||||
if (existingPackageLen > 0) {
|
||||
System.arraycopy(existingSipper.mPackages, 0, newPackages, 0,
|
||||
existingPackageLen);
|
||||
}
|
||||
System.arraycopy(sipper.mPackages, 0, newPackages, existingPackageLen,
|
||||
newPackageLen);
|
||||
existingSipper.mPackages = newPackages;
|
||||
}
|
||||
}
|
||||
final int index = batteryEntryList.indexOfKey(realUid);
|
||||
if (index < 0) {
|
||||
// New entry.
|
||||
batteryEntryList.put(realUid, new BatteryEntry(mActivity, mHandler, mUserManager,
|
||||
consumer, isHidden, packages, null));
|
||||
} else {
|
||||
results.add(sipper);
|
||||
// Combine BatterySippers if we already have one with this UID.
|
||||
final BatteryEntry existingSipper = batteryEntryList.valueAt(index);
|
||||
existingSipper.add(consumer);
|
||||
}
|
||||
}
|
||||
|
||||
final int numUidSippers = uidList.size();
|
||||
final List<SystemBatteryConsumer> systemBatteryConsumers =
|
||||
mBatteryUsageStats.getSystemBatteryConsumers();
|
||||
for (int i = 0, size = systemBatteryConsumers.size(); i < size; i++) {
|
||||
final SystemBatteryConsumer consumer = systemBatteryConsumers.get(i);
|
||||
if (!showAllApps && mBatteryUtils.shouldHideSystemBatteryConsumer(consumer)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
results.add(new BatteryEntry(mActivity, mHandler, mUserManager,
|
||||
consumer, /* isHidden */ true, null, null));
|
||||
}
|
||||
|
||||
if (showAllApps) {
|
||||
final List<UserBatteryConsumer> userBatteryConsumers =
|
||||
mBatteryUsageStats.getUserBatteryConsumers();
|
||||
for (int i = 0, size = userBatteryConsumers.size(); i < size; i++) {
|
||||
final UserBatteryConsumer consumer = userBatteryConsumers.get(i);
|
||||
results.add(new BatteryEntry(mActivity, mHandler, mUserManager,
|
||||
consumer, /* isHidden */ true, null, null));
|
||||
}
|
||||
}
|
||||
|
||||
final int numUidSippers = batteryEntryList.size();
|
||||
|
||||
for (int i = 0; i < numUidSippers; i++) {
|
||||
results.add(uidList.valueAt(i));
|
||||
results.add(batteryEntryList.valueAt(i));
|
||||
}
|
||||
|
||||
// The sort order must have changed, so re-sort based on total power use.
|
||||
mBatteryUtils.sortUsageList(results);
|
||||
results.sort(BatteryEntry.COMPARATOR);
|
||||
return results;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
void setUsageSummary(Preference preference, BatterySipper sipper) {
|
||||
void setUsageSummary(Preference preference, BatteryEntry entry) {
|
||||
// Only show summary when usage time is longer than one minute
|
||||
final long usageTimeMs = sipper.usageTimeMs;
|
||||
if (shouldShowSummary(sipper) && usageTimeMs >= DateUtils.MINUTE_IN_MILLIS) {
|
||||
final long usageTimeMs = entry.getTimeInForegroundMs();
|
||||
if (shouldShowSummary(entry) && usageTimeMs >= DateUtils.MINUTE_IN_MILLIS) {
|
||||
final CharSequence timeSequence =
|
||||
StringUtil.formatElapsedTime(mContext, usageTimeMs, false);
|
||||
preference.setSummary(
|
||||
(sipper.drainType != DrainType.APP || mBatteryUtils.shouldHideSipper(sipper))
|
||||
entry.isHidden()
|
||||
? timeSequence
|
||||
: TextUtils.expandTemplate(mContext.getText(R.string.battery_used_for),
|
||||
timeSequence));
|
||||
}
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
boolean shouldHideSipper(BatterySipper sipper) {
|
||||
// Don't show over-counted, unaccounted and hidden system module in any condition
|
||||
return sipper.drainType == BatterySipper.DrainType.OVERCOUNTED
|
||||
|| sipper.drainType == BatterySipper.DrainType.UNACCOUNTED
|
||||
|| mBatteryUtils.isHiddenSystemModule(sipper) || sipper.getUid() < 0;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
String extractKeyFromSipper(BatterySipper sipper) {
|
||||
if (sipper.uidObj != null) {
|
||||
return extractKeyFromUid(sipper.getUid());
|
||||
} else if (sipper.drainType == DrainType.USER) {
|
||||
return sipper.drainType.toString() + sipper.userId;
|
||||
} else if (sipper.drainType != DrainType.APP) {
|
||||
return sipper.drainType.toString();
|
||||
} else if (sipper.getPackages() != null) {
|
||||
return TextUtils.concat(sipper.getPackages()).toString();
|
||||
} else {
|
||||
Log.w(TAG, "Inappropriate BatterySipper without uid and package names: " + sipper);
|
||||
return "-1";
|
||||
}
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
String extractKeyFromUid(int uid) {
|
||||
return Integer.toString(uid);
|
||||
}
|
||||
|
||||
private void cacheRemoveAllPrefs(PreferenceGroup group) {
|
||||
mPreferenceCache = new ArrayMap<>();
|
||||
final int N = group.getPreferenceCount();
|
||||
@@ -392,12 +380,12 @@ public class BatteryAppListPreferenceController extends AbstractPreferenceContro
|
||||
}
|
||||
}
|
||||
|
||||
private boolean shouldShowSummary(BatterySipper sipper) {
|
||||
private boolean shouldShowSummary(BatteryEntry entry) {
|
||||
final CharSequence[] allowlistPackages = mContext.getResources()
|
||||
.getTextArray(R.array.allowlist_hide_summary_in_battery_usage);
|
||||
final String target = sipper.packageWithHighestDrain;
|
||||
final String target = entry.getDefaultPackageName();
|
||||
|
||||
for (CharSequence packageName: allowlistPackages) {
|
||||
for (CharSequence packageName : allowlistPackages) {
|
||||
if (TextUtils.equals(target, packageName)) {
|
||||
return false;
|
||||
}
|
||||
@@ -414,39 +402,54 @@ public class BatteryAppListPreferenceController extends AbstractPreferenceContro
|
||||
return appUid >= Process.SYSTEM_UID && appUid < Process.FIRST_APPLICATION_UID;
|
||||
}
|
||||
|
||||
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));
|
||||
private BatteryUsageStats getFakeStats() {
|
||||
BatteryUsageStats.Builder builder = new BatteryUsageStats.Builder(0, 0)
|
||||
.setDischargePercentage(100);
|
||||
|
||||
float use = 500;
|
||||
for (@SystemBatteryConsumer.DrainType int drainType : new int[]{
|
||||
SystemBatteryConsumer.DRAIN_TYPE_AMBIENT_DISPLAY,
|
||||
SystemBatteryConsumer.DRAIN_TYPE_BLUETOOTH,
|
||||
SystemBatteryConsumer.DRAIN_TYPE_CAMERA,
|
||||
SystemBatteryConsumer.DRAIN_TYPE_FLASHLIGHT,
|
||||
SystemBatteryConsumer.DRAIN_TYPE_IDLE,
|
||||
SystemBatteryConsumer.DRAIN_TYPE_MEMORY,
|
||||
SystemBatteryConsumer.DRAIN_TYPE_MOBILE_RADIO,
|
||||
SystemBatteryConsumer.DRAIN_TYPE_PHONE,
|
||||
SystemBatteryConsumer.DRAIN_TYPE_SCREEN,
|
||||
SystemBatteryConsumer.DRAIN_TYPE_WIFI,
|
||||
}) {
|
||||
builder.getOrCreateSystemBatteryConsumerBuilder(drainType)
|
||||
.setConsumedPower(BatteryConsumer.POWER_COMPONENT_USAGE, use);
|
||||
use += 5;
|
||||
}
|
||||
|
||||
use = 450;
|
||||
for (int i = 0; i < 100; i++) {
|
||||
stats.add(new BatterySipper(DrainType.APP,
|
||||
new FakeUid(Process.FIRST_APPLICATION_UID + i), use));
|
||||
builder.getOrCreateUidBatteryConsumerBuilder(
|
||||
new FakeUid(Process.FIRST_APPLICATION_UID + i))
|
||||
.setTimeInStateMs(BatteryConsumer.TIME_COMPONENT_USAGE, 10000 + i * 1000)
|
||||
.setConsumedPower(BatteryConsumer.POWER_COMPONENT_USAGE, use);
|
||||
use += 1;
|
||||
}
|
||||
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);
|
||||
builder.getOrCreateUidBatteryConsumerBuilder(new FakeUid(Process.FIRST_APPLICATION_UID))
|
||||
.setTimeInStateMs(BatteryConsumer.TIME_COMPONENT_USAGE, 100000)
|
||||
.setConsumedPower(BatteryConsumer.POWER_COMPONENT_USAGE, 1000.0)
|
||||
.setPackageWithHighestDrain("dex2oat");
|
||||
|
||||
sipper = new BatterySipper(DrainType.APP,
|
||||
new FakeUid(UserHandle.getSharedAppGid(Process.FIRST_APPLICATION_UID + 1)), 10.0f);
|
||||
sipper.packageWithHighestDrain = "dex2oat";
|
||||
stats.add(sipper);
|
||||
builder.getOrCreateUidBatteryConsumerBuilder(new FakeUid(Process.FIRST_APPLICATION_UID + 1))
|
||||
.setTimeInStateMs(BatteryConsumer.TIME_COMPONENT_USAGE, 100000)
|
||||
.setConsumedPower(BatteryConsumer.POWER_COMPONENT_USAGE, 1000.0)
|
||||
.setPackageWithHighestDrain("dex2oat");
|
||||
|
||||
sipper = new BatterySipper(DrainType.APP,
|
||||
new FakeUid(UserHandle.getSharedAppGid(Process.LOG_UID)), 9.0f);
|
||||
stats.add(sipper);
|
||||
builder.getOrCreateUidBatteryConsumerBuilder(
|
||||
new FakeUid(UserHandle.getSharedAppGid(Process.LOG_UID)))
|
||||
.setTimeInStateMs(BatteryConsumer.TIME_COMPONENT_USAGE, 100000)
|
||||
.setConsumedPower(BatteryConsumer.POWER_COMPONENT_USAGE, 900.0);
|
||||
|
||||
return stats;
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
private Preference getCachedPreference(String key) {
|
||||
|
@@ -26,22 +26,23 @@ import android.content.pm.PackageManager.NameNotFoundException;
|
||||
import android.content.pm.UserInfo;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.BatteryConsumer;
|
||||
import android.os.BatteryStats;
|
||||
import android.os.Handler;
|
||||
import android.os.Process;
|
||||
import android.os.RemoteException;
|
||||
import android.os.SystemBatteryConsumer;
|
||||
import android.os.UidBatteryConsumer;
|
||||
import android.os.UserBatteryConsumer;
|
||||
import android.os.UserHandle;
|
||||
import android.os.UserManager;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.internal.os.BatterySipper;
|
||||
import com.android.internal.util.ArrayUtils;
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settingslib.Utils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.Locale;
|
||||
|
||||
@@ -56,9 +57,9 @@ public class BatteryEntry {
|
||||
private static final String TAG = "BatteryEntry";
|
||||
private static final String PACKAGE_SYSTEM = "android";
|
||||
|
||||
static final HashMap<String,UidToDetail> sUidCache = new HashMap<String,UidToDetail>();
|
||||
static final HashMap<String, UidToDetail> sUidCache = new HashMap<>();
|
||||
|
||||
static final ArrayList<BatteryEntry> mRequestQueue = new ArrayList<BatteryEntry>();
|
||||
static final ArrayList<BatteryEntry> sRequestQueue = new ArrayList<BatteryEntry>();
|
||||
static Handler sHandler;
|
||||
|
||||
static Locale sCurrentLocale = null;
|
||||
@@ -78,15 +79,14 @@ public class BatteryEntry {
|
||||
public void run() {
|
||||
while (true) {
|
||||
BatteryEntry be;
|
||||
synchronized (mRequestQueue) {
|
||||
if (mRequestQueue.isEmpty() || mAbort) {
|
||||
synchronized (sRequestQueue) {
|
||||
if (sRequestQueue.isEmpty() || mAbort) {
|
||||
if (sHandler != null) {
|
||||
sHandler.sendEmptyMessage(MSG_REPORT_FULLY_DRAWN);
|
||||
}
|
||||
mRequestQueue.clear();
|
||||
return;
|
||||
}
|
||||
be = mRequestQueue.remove(0);
|
||||
be = sRequestQueue.remove(0);
|
||||
}
|
||||
be.loadNameAndIcon();
|
||||
}
|
||||
@@ -97,25 +97,26 @@ public class BatteryEntry {
|
||||
|
||||
public static void startRequestQueue() {
|
||||
if (sHandler != null) {
|
||||
synchronized (mRequestQueue) {
|
||||
if (!mRequestQueue.isEmpty()) {
|
||||
synchronized (sRequestQueue) {
|
||||
if (!sRequestQueue.isEmpty()) {
|
||||
if (mRequestThread != null) {
|
||||
mRequestThread.abort();
|
||||
}
|
||||
mRequestThread = new NameAndIconLoader();
|
||||
mRequestThread.setPriority(Thread.MIN_PRIORITY);
|
||||
mRequestThread.start();
|
||||
mRequestQueue.notify();
|
||||
sRequestQueue.notify();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void stopRequestQueue() {
|
||||
synchronized (mRequestQueue) {
|
||||
synchronized (sRequestQueue) {
|
||||
if (mRequestThread != null) {
|
||||
mRequestThread.abort();
|
||||
mRequestThread = null;
|
||||
sRequestQueue.clear();
|
||||
sHandler = null;
|
||||
}
|
||||
}
|
||||
@@ -125,14 +126,19 @@ public class BatteryEntry {
|
||||
sUidCache.clear();
|
||||
}
|
||||
|
||||
public final Context context;
|
||||
private final BatterySipper mSipper;
|
||||
public static final Comparator<BatteryEntry> COMPARATOR =
|
||||
(a, b) -> Double.compare(b.getConsumedPower(), a.getConsumedPower());
|
||||
|
||||
private final Context mContext;
|
||||
private final BatteryConsumer mBatteryConsumer;
|
||||
private final boolean mIsHidden;
|
||||
|
||||
public String name;
|
||||
public Drawable icon;
|
||||
public int iconId; // For passing to the detail screen.
|
||||
public double percent;
|
||||
private String mDefaultPackageName;
|
||||
private double mConsumedPower;
|
||||
|
||||
static class UidToDetail {
|
||||
String name;
|
||||
@@ -140,20 +146,20 @@ public class BatteryEntry {
|
||||
Drawable icon;
|
||||
}
|
||||
|
||||
public BatteryEntry(Context context, Handler handler, UserManager um, BatterySipper sipper,
|
||||
BatteryConsumer batteryConsumer, String packageName) {
|
||||
public BatteryEntry(Context context, Handler handler, UserManager um,
|
||||
@NonNull BatteryConsumer batteryConsumer, boolean isHidden, String[] packages,
|
||||
String packageName) {
|
||||
sHandler = handler;
|
||||
this.context = context;
|
||||
this.mSipper = sipper;
|
||||
this.mBatteryConsumer = batteryConsumer;
|
||||
this.mDefaultPackageName = packageName;
|
||||
mContext = context;
|
||||
mBatteryConsumer = batteryConsumer;
|
||||
mIsHidden = isHidden;
|
||||
mDefaultPackageName = packageName;
|
||||
mConsumedPower = batteryConsumer.getConsumedPower();
|
||||
|
||||
if (batteryConsumer instanceof UidBatteryConsumer) {
|
||||
UidBatteryConsumer uidBatteryConsumer = (UidBatteryConsumer) batteryConsumer;
|
||||
int uid = uidBatteryConsumer.getUid();
|
||||
PackageManager pm = context.getPackageManager();
|
||||
if (mDefaultPackageName == null) {
|
||||
String[] packages = pm.getPackagesForUid(uid);
|
||||
// Apps should only have one package
|
||||
if (packages != null && packages.length == 1) {
|
||||
mDefaultPackageName = packages[0];
|
||||
@@ -162,6 +168,7 @@ public class BatteryEntry {
|
||||
}
|
||||
}
|
||||
if (mDefaultPackageName != null) {
|
||||
PackageManager pm = context.getPackageManager();
|
||||
try {
|
||||
ApplicationInfo appInfo =
|
||||
pm.getApplicationInfo(mDefaultPackageName, 0 /* no flags */);
|
||||
@@ -172,92 +179,67 @@ public class BatteryEntry {
|
||||
name = mDefaultPackageName;
|
||||
}
|
||||
}
|
||||
getQuickNameIconForUid(uid);
|
||||
getQuickNameIconForUid(uid, packages);
|
||||
return;
|
||||
} else if (batteryConsumer instanceof SystemBatteryConsumer) {
|
||||
switch(((SystemBatteryConsumer) batteryConsumer).getDrainType()) {
|
||||
case SystemBatteryConsumer.DRAIN_TYPE_AMBIENT_DISPLAY:
|
||||
name = context.getResources().getString(R.string.ambient_display_screen_title);
|
||||
iconId = R.drawable.ic_settings_aod;
|
||||
break;
|
||||
case SystemBatteryConsumer.DRAIN_TYPE_BLUETOOTH:
|
||||
name = context.getResources().getString(R.string.power_bluetooth);
|
||||
iconId = com.android.internal.R.drawable.ic_settings_bluetooth;
|
||||
break;
|
||||
case SystemBatteryConsumer.DRAIN_TYPE_CAMERA:
|
||||
name = context.getResources().getString(R.string.power_camera);
|
||||
iconId = R.drawable.ic_settings_camera;
|
||||
break;
|
||||
case SystemBatteryConsumer.DRAIN_TYPE_MOBILE_RADIO:
|
||||
name = context.getResources().getString(R.string.power_cell);
|
||||
iconId = R.drawable.ic_cellular_1_bar;
|
||||
break;
|
||||
case SystemBatteryConsumer.DRAIN_TYPE_FLASHLIGHT:
|
||||
name = context.getResources().getString(R.string.power_flashlight);
|
||||
iconId = R.drawable.ic_settings_display;
|
||||
break;
|
||||
case SystemBatteryConsumer.DRAIN_TYPE_PHONE:
|
||||
name = context.getResources().getString(R.string.power_phone);
|
||||
iconId = R.drawable.ic_settings_voice_calls;
|
||||
break;
|
||||
case SystemBatteryConsumer.DRAIN_TYPE_SCREEN:
|
||||
name = context.getResources().getString(R.string.power_screen);
|
||||
iconId = R.drawable.ic_settings_display;
|
||||
break;
|
||||
case SystemBatteryConsumer.DRAIN_TYPE_WIFI:
|
||||
name = context.getResources().getString(R.string.power_wifi);
|
||||
iconId = R.drawable.ic_settings_wireless;
|
||||
break;
|
||||
case SystemBatteryConsumer.DRAIN_TYPE_IDLE:
|
||||
case SystemBatteryConsumer.DRAIN_TYPE_MEMORY:
|
||||
name = context.getResources().getString(R.string.power_idle);
|
||||
iconId = R.drawable.ic_settings_phone_idle;
|
||||
break;
|
||||
case SystemBatteryConsumer.DRAIN_TYPE_CUSTOM:
|
||||
name = null;
|
||||
iconId = R.drawable.ic_power_system;
|
||||
break;
|
||||
}
|
||||
} else if (batteryConsumer instanceof UserBatteryConsumer) {
|
||||
UserInfo info = um.getUserInfo(((UserBatteryConsumer) batteryConsumer).getUserId());
|
||||
if (info != null) {
|
||||
icon = Utils.getUserIcon(context, um, info);
|
||||
name = Utils.getUserLabel(context, info);
|
||||
} else {
|
||||
icon = null;
|
||||
name = context.getResources().getString(
|
||||
R.string.running_process_item_removed_user_label);
|
||||
}
|
||||
}
|
||||
|
||||
switch (sipper.drainType) {
|
||||
case IDLE:
|
||||
name = context.getResources().getString(R.string.power_idle);
|
||||
iconId = R.drawable.ic_settings_phone_idle;
|
||||
break;
|
||||
case CELL:
|
||||
name = context.getResources().getString(R.string.power_cell);
|
||||
iconId = R.drawable.ic_cellular_1_bar;
|
||||
break;
|
||||
case PHONE:
|
||||
name = context.getResources().getString(R.string.power_phone);
|
||||
iconId = R.drawable.ic_settings_voice_calls;
|
||||
break;
|
||||
case WIFI:
|
||||
name = context.getResources().getString(R.string.power_wifi);
|
||||
iconId = R.drawable.ic_settings_wireless;
|
||||
break;
|
||||
case BLUETOOTH:
|
||||
name = context.getResources().getString(R.string.power_bluetooth);
|
||||
iconId = com.android.internal.R.drawable.ic_settings_bluetooth;
|
||||
break;
|
||||
case SCREEN:
|
||||
name = context.getResources().getString(R.string.power_screen);
|
||||
iconId = R.drawable.ic_settings_display;
|
||||
break;
|
||||
case FLASHLIGHT:
|
||||
name = context.getResources().getString(R.string.power_flashlight);
|
||||
iconId = R.drawable.ic_settings_display;
|
||||
break;
|
||||
case APP:
|
||||
PackageManager pm = context.getPackageManager();
|
||||
sipper.mPackages = pm.getPackagesForUid(sipper.uidObj.getUid());
|
||||
// Apps should only have one package
|
||||
if (sipper.mPackages == null || sipper.mPackages.length != 1) {
|
||||
name = sipper.packageWithHighestDrain;
|
||||
} else {
|
||||
mDefaultPackageName = pm.getPackagesForUid(sipper.uidObj.getUid())[0];
|
||||
try {
|
||||
ApplicationInfo appInfo =
|
||||
pm.getApplicationInfo(mDefaultPackageName, 0 /* no flags */);
|
||||
name = pm.getApplicationLabel(appInfo).toString();
|
||||
} catch (NameNotFoundException e) {
|
||||
Log.d(TAG, "PackageManager failed to retrieve ApplicationInfo for: "
|
||||
+ mDefaultPackageName);
|
||||
name = mDefaultPackageName;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case USER: {
|
||||
UserInfo info = um.getUserInfo(sipper.userId);
|
||||
if (info != null) {
|
||||
icon = Utils.getUserIcon(context, um, info);
|
||||
name = Utils.getUserLabel(context, info);
|
||||
} else {
|
||||
icon = null;
|
||||
name = context.getResources().getString(
|
||||
R.string.running_process_item_removed_user_label);
|
||||
}
|
||||
} break;
|
||||
case UNACCOUNTED:
|
||||
name = context.getResources().getString(R.string.power_unaccounted);
|
||||
iconId = R.drawable.ic_android;
|
||||
break;
|
||||
case OVERCOUNTED:
|
||||
name = context.getResources().getString(R.string.power_overcounted);
|
||||
iconId = R.drawable.ic_android;
|
||||
break;
|
||||
case CAMERA:
|
||||
name = context.getResources().getString(R.string.power_camera);
|
||||
iconId = R.drawable.ic_settings_camera;
|
||||
break;
|
||||
case AMBIENT_DISPLAY:
|
||||
name = context.getResources().getString(R.string.ambient_display_screen_title);
|
||||
iconId = R.drawable.ic_settings_aod;
|
||||
break;
|
||||
}
|
||||
if (iconId > 0) {
|
||||
if (iconId != 0) {
|
||||
icon = context.getDrawable(iconId);
|
||||
}
|
||||
if ((name == null || iconId == 0) && sipper.uidObj != null) {
|
||||
getQuickNameIconForUid(sipper.uidObj.getUid());
|
||||
}
|
||||
}
|
||||
|
||||
public Drawable getIcon() {
|
||||
@@ -271,7 +253,7 @@ public class BatteryEntry {
|
||||
return name;
|
||||
}
|
||||
|
||||
void getQuickNameIconForUid(final int uid) {
|
||||
void getQuickNameIconForUid(final int uid, final String[] packages) {
|
||||
// Locale sync to system config in Settings
|
||||
final Locale locale = Locale.getDefault();
|
||||
if (sCurrentLocale != locale) {
|
||||
@@ -287,23 +269,24 @@ public class BatteryEntry {
|
||||
icon = utd.icon;
|
||||
return;
|
||||
}
|
||||
PackageManager pm = context.getPackageManager();
|
||||
icon = pm.getDefaultActivityIcon();
|
||||
if (pm.getPackagesForUid(uid) == null) {
|
||||
|
||||
if (packages == null || packages.length == 0) {
|
||||
if (uid == 0) {
|
||||
name = context.getResources().getString(R.string.process_kernel_label);
|
||||
name = mContext.getResources().getString(R.string.process_kernel_label);
|
||||
} else if ("mediaserver".equals(name)) {
|
||||
name = context.getResources().getString(R.string.process_mediaserver_label);
|
||||
name = mContext.getResources().getString(R.string.process_mediaserver_label);
|
||||
} else if ("dex2oat".equals(name)) {
|
||||
name = context.getResources().getString(R.string.process_dex2oat_label);
|
||||
name = mContext.getResources().getString(R.string.process_dex2oat_label);
|
||||
}
|
||||
iconId = R.drawable.ic_power_system;
|
||||
icon = context.getDrawable(iconId);
|
||||
icon = mContext.getDrawable(iconId);
|
||||
} else {
|
||||
icon = mContext.getPackageManager().getDefaultActivityIcon();
|
||||
}
|
||||
|
||||
if (sHandler != null) {
|
||||
synchronized (mRequestQueue) {
|
||||
mRequestQueue.add(this);
|
||||
synchronized (sRequestQueue) {
|
||||
sRequestQueue.add(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -313,17 +296,19 @@ public class BatteryEntry {
|
||||
*/
|
||||
public void loadNameAndIcon() {
|
||||
// Bail out if the current sipper is not an App sipper.
|
||||
if (mSipper.uidObj == null) {
|
||||
final int uid = getUid();
|
||||
if (uid == 0 || uid == Process.INVALID_UID) {
|
||||
return;
|
||||
}
|
||||
|
||||
PackageManager pm = context.getPackageManager();
|
||||
final int uid = mSipper.uidObj.getUid();
|
||||
if (mSipper.mPackages == null) {
|
||||
mSipper.mPackages = pm.getPackagesForUid(uid);
|
||||
final PackageManager pm = mContext.getPackageManager();
|
||||
final String[] packages;
|
||||
if (uid == Process.SYSTEM_UID) {
|
||||
packages = new String[]{PACKAGE_SYSTEM};
|
||||
} else {
|
||||
packages = pm.getPackagesForUid(uid);
|
||||
}
|
||||
|
||||
final String[] packages = extractPackagesFromSipper(mSipper);
|
||||
if (packages != null) {
|
||||
String[] packageLabels = new String[packages.length];
|
||||
System.arraycopy(packages, 0, packageLabels, 0, packages.length);
|
||||
@@ -400,28 +385,41 @@ public class BatteryEntry {
|
||||
utd.name = name;
|
||||
utd.icon = icon;
|
||||
utd.packageName = mDefaultPackageName;
|
||||
|
||||
sUidCache.put(uidString, utd);
|
||||
if (sHandler != null) {
|
||||
sHandler.sendMessage(sHandler.obtainMessage(MSG_UPDATE_NAME_ICON, this));
|
||||
}
|
||||
}
|
||||
|
||||
static String[] extractPackagesFromSipper(BatterySipper sipper) {
|
||||
// Only use system package if uid is system uid, so it could find a consistent name and icon
|
||||
return sipper.getUid() == Process.SYSTEM_UID
|
||||
? new String[]{PACKAGE_SYSTEM}
|
||||
: sipper.mPackages;
|
||||
/**
|
||||
* Returns a string that uniquely identifies this battery consumer.
|
||||
*/
|
||||
public String getKey() {
|
||||
if (mBatteryConsumer instanceof UidBatteryConsumer) {
|
||||
return Integer.toString(((UidBatteryConsumer) mBatteryConsumer).getUid());
|
||||
} else if (mBatteryConsumer instanceof SystemBatteryConsumer) {
|
||||
return "S|" + ((SystemBatteryConsumer) mBatteryConsumer).getDrainType();
|
||||
} else if (mBatteryConsumer instanceof UserBatteryConsumer) {
|
||||
return "U|" + ((UserBatteryConsumer) mBatteryConsumer).getUserId();
|
||||
} else {
|
||||
Log.w(TAG, "Unsupported BatteryConsumer: " + mBatteryConsumer);
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the entry is hidden from the battery usage summary list.
|
||||
*/
|
||||
public boolean isHidden() {
|
||||
return mIsHidden;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this entry describes an app (UID)
|
||||
*/
|
||||
public boolean isAppEntry() {
|
||||
if (mBatteryConsumer instanceof UidBatteryConsumer) {
|
||||
return true;
|
||||
} else {
|
||||
return mSipper.drainType == BatterySipper.DrainType.APP;
|
||||
}
|
||||
return mBatteryConsumer instanceof UidBatteryConsumer;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -430,9 +428,8 @@ public class BatteryEntry {
|
||||
public boolean isUserEntry() {
|
||||
if (mBatteryConsumer instanceof UserBatteryConsumer) {
|
||||
return true;
|
||||
} else {
|
||||
return mSipper.drainType == BatterySipper.DrainType.USER;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -440,14 +437,7 @@ public class BatteryEntry {
|
||||
* by this entry.
|
||||
*/
|
||||
public String getDefaultPackageName() {
|
||||
if (mDefaultPackageName != null) {
|
||||
return mDefaultPackageName;
|
||||
}
|
||||
if (ArrayUtils.isEmpty(mSipper.mPackages)) {
|
||||
return null;
|
||||
} else {
|
||||
return mSipper.mPackages[0];
|
||||
}
|
||||
return mDefaultPackageName;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -456,44 +446,30 @@ public class BatteryEntry {
|
||||
public int getUid() {
|
||||
if (mBatteryConsumer instanceof UidBatteryConsumer) {
|
||||
return ((UidBatteryConsumer) mBatteryConsumer).getUid();
|
||||
} else if (mBatteryConsumer != null) {
|
||||
return Process.INVALID_UID;
|
||||
} else {
|
||||
return mSipper.getUid();
|
||||
return Process.INVALID_UID;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns foreground foreground time (in milliseconds) that is attributed to this entry.
|
||||
*/
|
||||
public long getTimeInForegroundMs(BatteryUtils batteryUtils) {
|
||||
public long getTimeInForegroundMs() {
|
||||
if (mBatteryConsumer instanceof UidBatteryConsumer) {
|
||||
return ((UidBatteryConsumer) mBatteryConsumer).getTimeInStateMs(
|
||||
UidBatteryConsumer.STATE_FOREGROUND);
|
||||
} else if (mBatteryConsumer != null) {
|
||||
return mBatteryConsumer.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_USAGE);
|
||||
} else if (mSipper.drainType == BatterySipper.DrainType.APP) {
|
||||
return batteryUtils.getProcessTimeMs(
|
||||
BatteryUtils.StatusType.FOREGROUND, mSipper.uidObj,
|
||||
BatteryStats.STATS_SINCE_CHARGED);
|
||||
} else {
|
||||
return mSipper.usageTimeMs;
|
||||
return mBatteryConsumer.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_USAGE);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns background activity time (in milliseconds) that is attributed to this entry.
|
||||
*/
|
||||
public long getTimeInBackgroundMs(BatteryUtils batteryUtils) {
|
||||
public long getTimeInBackgroundMs() {
|
||||
if (mBatteryConsumer instanceof UidBatteryConsumer) {
|
||||
return ((UidBatteryConsumer) mBatteryConsumer).getTimeInStateMs(
|
||||
UidBatteryConsumer.STATE_BACKGROUND);
|
||||
} else if (mBatteryConsumer != null) {
|
||||
return 0;
|
||||
} else if (mSipper.drainType == BatterySipper.DrainType.APP) {
|
||||
return batteryUtils.getProcessTimeMs(
|
||||
BatteryUtils.StatusType.BACKGROUND, mSipper.uidObj,
|
||||
BatteryStats.STATS_SINCE_CHARGED);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
@@ -503,9 +479,18 @@ public class BatteryEntry {
|
||||
* Returns total amount of power (in milli-amp-hours) that is attributed to this entry.
|
||||
*/
|
||||
public double getConsumedPower() {
|
||||
if (mBatteryConsumer != null) {
|
||||
return mBatteryConsumer.getConsumedPower();
|
||||
return mConsumedPower;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the consumed power of the supplied BatteryConsumer to this entry. Also
|
||||
* uses its package with highest drain, if necessary.
|
||||
*/
|
||||
public void add(BatteryConsumer batteryConsumer) {
|
||||
mConsumedPower += batteryConsumer.getConsumedPower();
|
||||
if (mDefaultPackageName == null && batteryConsumer instanceof UidBatteryConsumer) {
|
||||
mDefaultPackageName =
|
||||
((UidBatteryConsumer) batteryConsumer).getPackageWithHighestDrain();
|
||||
}
|
||||
return (int) mSipper.totalPowerMah;
|
||||
}
|
||||
}
|
||||
|
@@ -30,7 +30,9 @@ import android.os.BatteryUsageStatsQuery;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.Process;
|
||||
import android.os.SystemBatteryConsumer;
|
||||
import android.os.SystemClock;
|
||||
import android.os.UidBatteryConsumer;
|
||||
import android.os.UserHandle;
|
||||
import android.os.UserManager;
|
||||
import android.util.Log;
|
||||
@@ -59,8 +61,6 @@ import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@@ -86,6 +86,7 @@ public class BatteryUtils {
|
||||
private static final String TAG = "BatteryUtils";
|
||||
|
||||
private static final int MIN_POWER_THRESHOLD_MILLI_AMP = 5;
|
||||
private static final double MIN_POWER_THRESHOLD_MILLI_AMP_HOURS = 0.002;
|
||||
|
||||
private static final int SECONDS_IN_HOUR = 60 * 60;
|
||||
private static BatteryUtils sInstance;
|
||||
@@ -171,21 +172,6 @@ public class BatteryUtils {
|
||||
+ PowerUtil.convertUsToMs(getForegroundServiceTotalTimeUs(uid, rawRealTimeUs));
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the {@link BatterySipper} that we should hide.
|
||||
*
|
||||
* @param sippers sipper list that need to check and remove
|
||||
* for proportional smearing
|
||||
*/
|
||||
public void removeHiddenBatterySippers(List<BatterySipper> sippers) {
|
||||
for (int i = sippers.size() - 1; i >= 0; i--) {
|
||||
final BatterySipper sipper = sippers.get(i);
|
||||
if (shouldHideSipper(sipper)) {
|
||||
sippers.remove(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether we should hide the battery sipper.
|
||||
*/
|
||||
@@ -205,6 +191,42 @@ public class BatteryUtils {
|
||||
|| isHiddenSystemModule(sipper);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the specified battery consumer should be excluded from the summary
|
||||
* battery consumption list.
|
||||
*/
|
||||
public boolean shouldHideUidBatteryConsumer(UidBatteryConsumer consumer, String[] packages) {
|
||||
return consumer.getConsumedPower() < MIN_POWER_THRESHOLD_MILLI_AMP_HOURS
|
||||
|| mPowerUsageFeatureProvider.isTypeSystem(consumer.getUid(), packages)
|
||||
|| shouldHideUidBatteryConsumerUnconditionally(consumer, packages);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the specified battery consumer should be excluded from
|
||||
* battery consumption lists, either short or full.
|
||||
*/
|
||||
boolean shouldHideUidBatteryConsumerUnconditionally(UidBatteryConsumer consumer,
|
||||
String[] packages) {
|
||||
return consumer.getUid() < 0 || isHiddenSystemModule(packages);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the specified battery consumer should be excluded from the summary
|
||||
* battery consumption list.
|
||||
*/
|
||||
public boolean shouldHideSystemBatteryConsumer(SystemBatteryConsumer consumer) {
|
||||
switch (consumer.getDrainType()) {
|
||||
case SystemBatteryConsumer.DRAIN_TYPE_IDLE:
|
||||
case SystemBatteryConsumer.DRAIN_TYPE_MOBILE_RADIO:
|
||||
case SystemBatteryConsumer.DRAIN_TYPE_SCREEN:
|
||||
case SystemBatteryConsumer.DRAIN_TYPE_BLUETOOTH:
|
||||
case SystemBatteryConsumer.DRAIN_TYPE_WIFI:
|
||||
return true;
|
||||
default:
|
||||
return consumer.getConsumedPower() < MIN_POWER_THRESHOLD_MILLI_AMP_HOURS;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return {@code true} if one of packages in {@code sipper} is hidden system modules
|
||||
*/
|
||||
@@ -213,14 +235,20 @@ public class BatteryUtils {
|
||||
return false;
|
||||
}
|
||||
sipper.mPackages = mPackageManager.getPackagesForUid(sipper.getUid());
|
||||
if (sipper.mPackages != null) {
|
||||
for (int i = 0, length = sipper.mPackages.length; i < length; i++) {
|
||||
if (AppUtils.isHiddenSystemModule(mContext, sipper.mPackages[i])) {
|
||||
return isHiddenSystemModule(sipper.mPackages);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if one the specified packages belongs to a hidden system module.
|
||||
*/
|
||||
public boolean isHiddenSystemModule(String[] packages) {
|
||||
if (packages != null) {
|
||||
for (int i = 0, length = packages.length; i < length; i++) {
|
||||
if (AppUtils.isHiddenSystemModule(mContext, packages[i])) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -305,18 +333,6 @@ public class BatteryUtils {
|
||||
return mode == AppOpsManager.MODE_IGNORED || mode == AppOpsManager.MODE_ERRORED;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sort the {@code usageList} based on {@link BatterySipper#totalPowerMah}
|
||||
*/
|
||||
public void sortUsageList(List<BatterySipper> usageList) {
|
||||
Collections.sort(usageList, new Comparator<BatterySipper>() {
|
||||
@Override
|
||||
public int compare(BatterySipper a, BatterySipper b) {
|
||||
return Double.compare(b.totalPowerMah, a.totalPowerMah);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the time since last full charge, including the device off time
|
||||
*
|
||||
@@ -330,18 +346,6 @@ public class BatteryUtils {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the screen usage time since last full charge.
|
||||
*
|
||||
* @param batteryStatsHelper utility class that contains the screen usage data
|
||||
* @return time in millis
|
||||
*/
|
||||
public long calculateScreenUsageTime(BatteryStatsHelper batteryStatsHelper) {
|
||||
final BatterySipper sipper = findBatterySipperByType(
|
||||
batteryStatsHelper.getUsageList(), BatterySipper.DrainType.SCREEN);
|
||||
return sipper != null ? sipper.usageTimeMs : 0;
|
||||
}
|
||||
|
||||
public static void logRuntime(String tag, String message, long startTime) {
|
||||
Log.d(tag, message + ": " + (System.currentTimeMillis() - startTime) + "ms");
|
||||
}
|
||||
@@ -466,20 +470,6 @@ public class BatteryUtils {
|
||||
return estimate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the {@link BatterySipper} with the corresponding {@link BatterySipper.DrainType}
|
||||
*/
|
||||
public BatterySipper findBatterySipperByType(List<BatterySipper> usageList,
|
||||
BatterySipper.DrainType type) {
|
||||
for (int i = 0, size = usageList.size(); i < size; i++) {
|
||||
final BatterySipper sipper = usageList.get(i);
|
||||
if (sipper.drainType == type) {
|
||||
return sipper;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private boolean isDataCorrupted() {
|
||||
return mPackageManager == null || mAppOpsManager == null;
|
||||
}
|
||||
@@ -614,4 +604,3 @@ public class BatteryUtils {
|
||||
return -1L;
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -50,7 +50,6 @@ public class PowerUsageAdvanced extends PowerUsageBase {
|
||||
|
||||
@VisibleForTesting
|
||||
BatteryHistoryPreference mHistPref;
|
||||
private BatteryUtils mBatteryUtils;
|
||||
private PowerUsageFeatureProvider mPowerUsageFeatureProvider;
|
||||
private BatteryAppListPreferenceController mBatteryAppListPreferenceController;
|
||||
@VisibleForTesting
|
||||
@@ -64,7 +63,6 @@ public class PowerUsageAdvanced extends PowerUsageBase {
|
||||
mHistPref = (BatteryHistoryPreference) findPreference(KEY_BATTERY_GRAPH);
|
||||
mPowerUsageFeatureProvider = FeatureFactory.getFactory(context)
|
||||
.getPowerUsageFeatureProvider(context);
|
||||
mBatteryUtils = BatteryUtils.getInstance(context);
|
||||
|
||||
// init the summary so other preferences won't have unnecessary move
|
||||
updateHistPrefSummary(context);
|
||||
@@ -155,7 +153,7 @@ public class PowerUsageAdvanced extends PowerUsageBase {
|
||||
updatePreference(mHistPref);
|
||||
updateHistPrefSummary(context);
|
||||
|
||||
mBatteryAppListPreferenceController.refreshAppListGroup(mStatsHelper, mShowAllApps);
|
||||
mBatteryAppListPreferenceController.refreshAppListGroup(mBatteryUsageStats, mShowAllApps);
|
||||
}
|
||||
|
||||
private void updateHistPrefSummary(Context context) {
|
||||
|
@@ -58,6 +58,11 @@ public interface PowerUsageFeatureProvider {
|
||||
*/
|
||||
boolean isTypeSystem(BatterySipper sipper);
|
||||
|
||||
/**
|
||||
* Check whether it is type system
|
||||
*/
|
||||
boolean isTypeSystem(int uid, String[] packages);
|
||||
|
||||
/**
|
||||
* Check whether the toggle for power accounting is enabled
|
||||
*/
|
||||
|
@@ -65,6 +65,21 @@ public class PowerUsageFeatureProviderImpl implements PowerUsageFeatureProvider
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTypeSystem(int uid, String[] packages) {
|
||||
// Classify all the sippers to type system if the range of uid is 0...FIRST_APPLICATION_UID
|
||||
if (uid >= Process.ROOT_UID && uid < Process.FIRST_APPLICATION_UID) {
|
||||
return true;
|
||||
} else if (packages != null) {
|
||||
for (final String packageName : packages) {
|
||||
if (ArrayUtils.contains(PACKAGES_SYSTEM, packageName)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLocationSettingEnabled(String[] packages) {
|
||||
return false;
|
||||
|
@@ -166,10 +166,8 @@ public class AdvancedPowerUsageDetailTest {
|
||||
|
||||
when(mBatteryEntry.getUid()).thenReturn(UID);
|
||||
when(mBatteryEntry.getLabel()).thenReturn(APP_LABEL);
|
||||
when(mBatteryEntry.getTimeInBackgroundMs(any(BatteryUtils.class)))
|
||||
.thenReturn(BACKGROUND_TIME_MS);
|
||||
when(mBatteryEntry.getTimeInForegroundMs(any(BatteryUtils.class)))
|
||||
.thenReturn(FOREGROUND_TIME_MS);
|
||||
when(mBatteryEntry.getTimeInBackgroundMs()).thenReturn(BACKGROUND_TIME_MS);
|
||||
when(mBatteryEntry.getTimeInForegroundMs()).thenReturn(FOREGROUND_TIME_MS);
|
||||
mBatteryEntry.iconId = ICON_ID;
|
||||
|
||||
mFragment.mHeaderPreference = mHeaderPreference;
|
||||
@@ -253,8 +251,8 @@ public class AdvancedPowerUsageDetailTest {
|
||||
|
||||
@Test
|
||||
public void testStartBatteryDetailPage_hasBasicData() {
|
||||
AdvancedPowerUsageDetail.startBatteryDetailPage(mActivity, mBatteryUtils, mFragment,
|
||||
mBatteryStatsHelper, 0, mBatteryEntry, USAGE_PERCENT);
|
||||
AdvancedPowerUsageDetail.startBatteryDetailPage(mActivity, mFragment,
|
||||
mBatteryEntry, USAGE_PERCENT);
|
||||
|
||||
assertThat(mBundle.getInt(AdvancedPowerUsageDetail.EXTRA_UID)).isEqualTo(UID);
|
||||
assertThat(mBundle.getLong(AdvancedPowerUsageDetail.EXTRA_BACKGROUND_TIME))
|
||||
@@ -269,8 +267,8 @@ public class AdvancedPowerUsageDetailTest {
|
||||
public void testStartBatteryDetailPage_NormalApp() {
|
||||
when(mBatteryEntry.getDefaultPackageName()).thenReturn(PACKAGE_NAME[0]);
|
||||
|
||||
AdvancedPowerUsageDetail.startBatteryDetailPage(mActivity, mBatteryUtils, mFragment,
|
||||
mBatteryStatsHelper, 0, mBatteryEntry, USAGE_PERCENT);
|
||||
AdvancedPowerUsageDetail.startBatteryDetailPage(mActivity, mFragment,
|
||||
mBatteryEntry, USAGE_PERCENT);
|
||||
|
||||
assertThat(mBundle.getString(AdvancedPowerUsageDetail.EXTRA_PACKAGE_NAME)).isEqualTo(
|
||||
PACKAGE_NAME[0]);
|
||||
@@ -280,8 +278,8 @@ public class AdvancedPowerUsageDetailTest {
|
||||
public void testStartBatteryDetailPage_SystemApp() {
|
||||
when(mBatteryEntry.getDefaultPackageName()).thenReturn(null);
|
||||
|
||||
AdvancedPowerUsageDetail.startBatteryDetailPage(mActivity, mBatteryUtils, mFragment,
|
||||
mBatteryStatsHelper, 0, mBatteryEntry, USAGE_PERCENT);
|
||||
AdvancedPowerUsageDetail.startBatteryDetailPage(mActivity, mFragment,
|
||||
mBatteryEntry, USAGE_PERCENT);
|
||||
|
||||
assertThat(mBundle.getString(AdvancedPowerUsageDetail.EXTRA_LABEL)).isEqualTo(APP_LABEL);
|
||||
assertThat(mBundle.getInt(AdvancedPowerUsageDetail.EXTRA_ICON_ID)).isEqualTo(ICON_ID);
|
||||
@@ -293,8 +291,8 @@ public class AdvancedPowerUsageDetailTest {
|
||||
final int appUid = 1010019;
|
||||
doReturn(appUid).when(mBatteryEntry).getUid();
|
||||
|
||||
AdvancedPowerUsageDetail.startBatteryDetailPage(mActivity, mBatteryUtils, mFragment,
|
||||
mBatteryStatsHelper, 0, mBatteryEntry, USAGE_PERCENT);
|
||||
AdvancedPowerUsageDetail.startBatteryDetailPage(mActivity, mFragment,
|
||||
mBatteryEntry, USAGE_PERCENT);
|
||||
|
||||
verify(mActivity).startActivityAsUser(any(Intent.class), eq(new UserHandle(10)));
|
||||
}
|
||||
@@ -305,8 +303,8 @@ public class AdvancedPowerUsageDetailTest {
|
||||
|
||||
final int currentUser = 20;
|
||||
ShadowActivityManager.setCurrentUser(currentUser);
|
||||
AdvancedPowerUsageDetail.startBatteryDetailPage(mActivity, mBatteryUtils, mFragment,
|
||||
mBatteryStatsHelper, 0, mBatteryEntry, USAGE_PERCENT);
|
||||
AdvancedPowerUsageDetail.startBatteryDetailPage(mActivity, mFragment,
|
||||
mBatteryEntry, USAGE_PERCENT);
|
||||
|
||||
verify(mActivity).startActivityAsUser(any(Intent.class), eq(new UserHandle(currentUser)));
|
||||
}
|
||||
|
@@ -20,21 +20,16 @@ import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.Matchers.anyInt;
|
||||
import static org.mockito.Mockito.doReturn;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.os.BatteryStats;
|
||||
import android.os.UserManager;
|
||||
import android.text.TextUtils;
|
||||
import android.text.format.DateUtils;
|
||||
|
||||
import androidx.preference.PreferenceGroup;
|
||||
|
||||
import com.android.internal.os.BatterySipper;
|
||||
import com.android.internal.os.BatteryStatsImpl;
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.SettingsActivity;
|
||||
import com.android.settings.core.InstrumentedPreferenceFragment;
|
||||
@@ -51,12 +46,8 @@ import org.robolectric.RuntimeEnvironment;
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
public class BatteryAppListPreferenceControllerTest {
|
||||
|
||||
private static final String[] PACKAGE_NAMES = {"com.app1", "com.app2"};
|
||||
private static final String KEY_APP_LIST = "app_list";
|
||||
private static final int UID = 123;
|
||||
|
||||
@Mock
|
||||
private BatterySipper mNormalBatterySipper;
|
||||
@Mock
|
||||
private SettingsActivity mSettingsActivity;
|
||||
@Mock
|
||||
@@ -69,6 +60,8 @@ public class BatteryAppListPreferenceControllerTest {
|
||||
private PackageManager mPackageManager;
|
||||
@Mock
|
||||
private UserManager mUserManager;
|
||||
@Mock
|
||||
private BatteryEntry mBatteryEntry;
|
||||
|
||||
private Context mContext;
|
||||
private PowerGaugePreference mPreference;
|
||||
@@ -87,137 +80,67 @@ public class BatteryAppListPreferenceControllerTest {
|
||||
FakeFeatureFactory.setupForTest();
|
||||
|
||||
mPreference = new PowerGaugePreference(mContext);
|
||||
when(mNormalBatterySipper.getPackages()).thenReturn(PACKAGE_NAMES);
|
||||
when(mNormalBatterySipper.getUid()).thenReturn(UID);
|
||||
mNormalBatterySipper.drainType = BatterySipper.DrainType.APP;
|
||||
mNormalBatterySipper.uidObj = mock(BatteryStats.Uid.class);
|
||||
|
||||
mPreferenceController = new BatteryAppListPreferenceController(mContext, KEY_APP_LIST, null,
|
||||
mSettingsActivity, mFragment);
|
||||
mPreferenceController.mBatteryUtils = mBatteryUtils;
|
||||
mPreferenceController.mAppListGroup = mAppListGroup;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExtractKeyFromSipper_typeAPPUidObjectNull_returnPackageNames() {
|
||||
mNormalBatterySipper.uidObj = null;
|
||||
mNormalBatterySipper.drainType = BatterySipper.DrainType.APP;
|
||||
|
||||
final String key = mPreferenceController.extractKeyFromSipper(mNormalBatterySipper);
|
||||
assertThat(key).isEqualTo(TextUtils.concat(mNormalBatterySipper.getPackages()).toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExtractKeyFromSipper_typeOther_returnDrainType() {
|
||||
mNormalBatterySipper.uidObj = null;
|
||||
mNormalBatterySipper.drainType = BatterySipper.DrainType.BLUETOOTH;
|
||||
|
||||
final String key = mPreferenceController.extractKeyFromSipper(mNormalBatterySipper);
|
||||
assertThat(key).isEqualTo(mNormalBatterySipper.drainType.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExtractKeyFromSipper_typeUser_returnDrainTypeWithUserId() {
|
||||
mNormalBatterySipper.uidObj = null;
|
||||
mNormalBatterySipper.drainType = BatterySipper.DrainType.USER;
|
||||
mNormalBatterySipper.userId = 2;
|
||||
|
||||
final String key = mPreferenceController.extractKeyFromSipper(mNormalBatterySipper);
|
||||
assertThat(key).isEqualTo("USER2");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExtractKeyFromSipper_typeAPPUidObjectNotNull_returnUid() {
|
||||
mNormalBatterySipper.uidObj = new BatteryStatsImpl.Uid(new BatteryStatsImpl(), UID);
|
||||
mNormalBatterySipper.drainType = BatterySipper.DrainType.APP;
|
||||
|
||||
final String key = mPreferenceController.extractKeyFromSipper(mNormalBatterySipper);
|
||||
assertThat(key).isEqualTo(Integer.toString(mNormalBatterySipper.getUid()));
|
||||
BatteryAppListPreferenceController.sConfig =
|
||||
new BatteryAppListPreferenceController.Config() {
|
||||
@Override
|
||||
public boolean shouldShowBatteryAttributionList(Context context) {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetUsageSummary_timeLessThanOneMinute_DoNotSetSummary() {
|
||||
mNormalBatterySipper.usageTimeMs = 59 * DateUtils.SECOND_IN_MILLIS;
|
||||
when(mBatteryEntry.getTimeInForegroundMs()).thenReturn(59 * DateUtils.SECOND_IN_MILLIS);
|
||||
|
||||
mPreferenceController.setUsageSummary(mPreference, mNormalBatterySipper);
|
||||
mPreferenceController.setUsageSummary(mPreference, mBatteryEntry);
|
||||
assertThat(mPreference.getSummary()).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetUsageSummary_timeMoreThanOneMinute_normalApp_setScreenSummary() {
|
||||
mNormalBatterySipper.usageTimeMs = 2 * DateUtils.MINUTE_IN_MILLIS;
|
||||
when(mBatteryEntry.getTimeInForegroundMs()).thenReturn(2 * DateUtils.MINUTE_IN_MILLIS);
|
||||
doReturn(mContext.getText(R.string.battery_used_for)).when(mFragment).getText(
|
||||
R.string.battery_used_for);
|
||||
doReturn(mContext).when(mFragment).getContext();
|
||||
|
||||
mPreferenceController.setUsageSummary(mPreference, mNormalBatterySipper);
|
||||
mPreferenceController.setUsageSummary(mPreference, mBatteryEntry);
|
||||
|
||||
assertThat(mPreference.getSummary().toString()).isEqualTo("Used for 2 min");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetUsageSummary_timeMoreThanOneMinute_GoogleApp_shouldNotSetScreenSummary() {
|
||||
mNormalBatterySipper.usageTimeMs = 2 * DateUtils.MINUTE_IN_MILLIS;
|
||||
mNormalBatterySipper.packageWithHighestDrain = "com.google.android.googlequicksearchbox";
|
||||
when(mBatteryEntry.getTimeInForegroundMs()).thenReturn(2 * DateUtils.MINUTE_IN_MILLIS);
|
||||
when(mBatteryEntry.getDefaultPackageName())
|
||||
.thenReturn("com.google.android.googlequicksearchbox");
|
||||
doReturn(mContext.getText(R.string.battery_used_for)).when(mFragment).getText(
|
||||
R.string.battery_used_for);
|
||||
doReturn(mContext).when(mFragment).getContext();
|
||||
|
||||
mPreferenceController.setUsageSummary(mPreference, mNormalBatterySipper);
|
||||
mPreferenceController.setUsageSummary(mPreference, mBatteryEntry);
|
||||
|
||||
assertThat(mPreference.getSummary()).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetUsageSummary_timeMoreThanOneMinute_hiddenApp_setUsedSummary() {
|
||||
mNormalBatterySipper.usageTimeMs = 2 * DateUtils.MINUTE_IN_MILLIS;
|
||||
doReturn(true).when(mBatteryUtils).shouldHideSipper(mNormalBatterySipper);
|
||||
when(mBatteryEntry.getTimeInForegroundMs()).thenReturn(2 * DateUtils.MINUTE_IN_MILLIS);
|
||||
when(mBatteryEntry.isHidden()).thenReturn(true);
|
||||
|
||||
doReturn(mContext).when(mFragment).getContext();
|
||||
|
||||
mPreferenceController.setUsageSummary(mPreference, mNormalBatterySipper);
|
||||
mPreferenceController.setUsageSummary(mPreference, mBatteryEntry);
|
||||
|
||||
assertThat(mPreference.getSummary().toString()).isEqualTo("2 min");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetUsageSummary_timeMoreThanOneMinute_notApp_setUsedSummary() {
|
||||
mNormalBatterySipper.usageTimeMs = 2 * DateUtils.MINUTE_IN_MILLIS;
|
||||
mNormalBatterySipper.drainType = BatterySipper.DrainType.PHONE;
|
||||
doReturn(mContext).when(mFragment).getContext();
|
||||
|
||||
mPreferenceController.setUsageSummary(mPreference, mNormalBatterySipper);
|
||||
|
||||
assertThat(mPreference.getSummary().toString()).isEqualTo("2 min");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testShouldHideSipper_typeOvercounted_returnTrue() {
|
||||
mNormalBatterySipper.drainType = BatterySipper.DrainType.OVERCOUNTED;
|
||||
|
||||
assertThat(mPreferenceController.shouldHideSipper(mNormalBatterySipper)).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testShouldHideSipper_typeUnaccounted_returnTrue() {
|
||||
mNormalBatterySipper.drainType = BatterySipper.DrainType.UNACCOUNTED;
|
||||
|
||||
assertThat(mPreferenceController.shouldHideSipper(mNormalBatterySipper)).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testShouldHideSipper_typeNormal_returnFalse() {
|
||||
mNormalBatterySipper.drainType = BatterySipper.DrainType.APP;
|
||||
|
||||
assertThat(mPreferenceController.shouldHideSipper(mNormalBatterySipper)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testShouldHideSipper_hiddenSystemModule_returnTrue() {
|
||||
when(mBatteryUtils.isHiddenSystemModule(mNormalBatterySipper)).thenReturn(true);
|
||||
|
||||
assertThat(mPreferenceController.shouldHideSipper(mNormalBatterySipper)).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNeverUseFakeData() {
|
||||
assertThat(BatteryAppListPreferenceController.USE_FAKE_DATA).isFalse();
|
||||
|
@@ -18,6 +18,7 @@ package com.android.settings.fuelgauge;
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyString;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
@@ -27,21 +28,20 @@ import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.PackageManager.NameNotFoundException;
|
||||
import android.os.BatteryConsumer;
|
||||
import android.os.BatteryStats;
|
||||
import android.os.Handler;
|
||||
import android.os.Process;
|
||||
import android.os.SystemBatteryConsumer;
|
||||
import android.os.UidBatteryConsumer;
|
||||
import android.os.UserBatteryConsumer;
|
||||
import android.os.UserManager;
|
||||
|
||||
import com.android.internal.os.BatterySipper;
|
||||
import com.android.internal.os.BatterySipper.DrainType;
|
||||
import com.android.settings.R;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Answers;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.MockitoJUnit;
|
||||
import org.mockito.junit.MockitoRule;
|
||||
@@ -56,188 +56,153 @@ public class BatteryEntryTest {
|
||||
private static final int APP_UID = 123;
|
||||
private static final int SYSTEM_UID = Process.SYSTEM_UID;
|
||||
private static final String APP_DEFAULT_PACKAGE_NAME = "com.android.test";
|
||||
private static final String APP_LABEL = "Test App Name";
|
||||
private static final String LABEL_PREFIX = "Label for ";
|
||||
private static final String HIGH_DRAIN_PACKAGE = "com.android.test.screen";
|
||||
private static final String ANDROID_PACKAGE = "android";
|
||||
private static final String[] SYSTEM_PACKAGES = {HIGH_DRAIN_PACKAGE, ANDROID_PACKAGE};
|
||||
|
||||
@Rule public MockitoRule mocks = MockitoJUnit.rule();
|
||||
|
||||
@Mock private Context mockContext;
|
||||
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
|
||||
private Context mMockContext;
|
||||
@Mock private Handler mockHandler;
|
||||
@Mock private PackageManager mockPackageManager;
|
||||
@Mock private UserManager mockUserManager;
|
||||
@Mock private UidBatteryConsumer mUidBatteryConsumer;
|
||||
@Mock private SystemBatteryConsumer mSystemBatteryConsumer;
|
||||
@Mock BatteryUtils mBatteryUtils;
|
||||
|
||||
@Before
|
||||
public void stubContextToReturnMockPackageManager() {
|
||||
when(mockContext.getPackageManager()).thenReturn(mockPackageManager);
|
||||
when(mMockContext.getPackageManager()).thenReturn(mockPackageManager);
|
||||
}
|
||||
|
||||
@Before
|
||||
public void stubPackageManagerToReturnAppPackageAndName() throws NameNotFoundException {
|
||||
when(mockPackageManager.getPackagesForUid(APP_UID))
|
||||
.thenReturn(new String[] {APP_DEFAULT_PACKAGE_NAME});
|
||||
|
||||
ApplicationInfo appInfo = mock(ApplicationInfo.class);
|
||||
when(mockPackageManager.getApplicationInfo(APP_DEFAULT_PACKAGE_NAME, 0 /* no flags */))
|
||||
.thenReturn(appInfo);
|
||||
when(mockPackageManager.getApplicationLabel(appInfo)).thenReturn(APP_LABEL);
|
||||
when(mockPackageManager.getApplicationInfo(anyString(), eq(0) /* no flags */))
|
||||
.thenAnswer(invocation -> {
|
||||
ApplicationInfo info = new ApplicationInfo();
|
||||
info.packageName = invocation.getArgument(0);
|
||||
return info;
|
||||
});
|
||||
when(mockPackageManager.getApplicationLabel(any(ApplicationInfo.class)))
|
||||
.thenAnswer(invocation -> LABEL_PREFIX
|
||||
+ ((ApplicationInfo) invocation.getArgument(0)).packageName);
|
||||
}
|
||||
|
||||
private BatteryEntry createBatteryEntryForApp() {
|
||||
return new BatteryEntry(mockContext, mockHandler, mockUserManager, createSipperForApp(),
|
||||
null, null);
|
||||
private BatteryEntry createBatteryEntryForApp(String[] packages, String packageName,
|
||||
String highDrainPackage) {
|
||||
UidBatteryConsumer consumer = mock(UidBatteryConsumer.class);
|
||||
when(consumer.getUid()).thenReturn(APP_UID);
|
||||
when(consumer.getPackageWithHighestDrain()).thenReturn(highDrainPackage);
|
||||
return new BatteryEntry(mMockContext, mockHandler, mockUserManager,
|
||||
consumer, false, packages, packageName);
|
||||
}
|
||||
|
||||
private BatterySipper createSipperForApp() {
|
||||
BatterySipper sipper =
|
||||
new BatterySipper(DrainType.APP, new FakeUid(APP_UID), 0 /* power use */);
|
||||
sipper.packageWithHighestDrain = HIGH_DRAIN_PACKAGE;
|
||||
return sipper;
|
||||
private BatteryEntry createSystemBatteryEntry(int drainType) {
|
||||
SystemBatteryConsumer consumer = mock(SystemBatteryConsumer.class);
|
||||
when(consumer.getDrainType()).thenReturn(drainType);
|
||||
return new BatteryEntry(mMockContext, mockHandler, mockUserManager,
|
||||
consumer, false, null, null);
|
||||
}
|
||||
|
||||
private BatterySipper createSipperForSystem() {
|
||||
BatterySipper sipper =
|
||||
new BatterySipper(DrainType.APP, new FakeUid(SYSTEM_UID), 0 /* power use */);
|
||||
sipper.packageWithHighestDrain = HIGH_DRAIN_PACKAGE;
|
||||
sipper.mPackages = SYSTEM_PACKAGES;
|
||||
return sipper;
|
||||
}
|
||||
|
||||
private BatterySipper createNonAppSipper() {
|
||||
return new BatterySipper(DrainType.IDLE, null, 0 /* power use */);
|
||||
private BatteryEntry createUserBatteryConsumer(int userId) {
|
||||
UserBatteryConsumer consumer = mock(UserBatteryConsumer.class);
|
||||
when(consumer.getUserId()).thenReturn(userId);
|
||||
return new BatteryEntry(mMockContext, mockHandler, mockUserManager,
|
||||
consumer, false, null, null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void batteryEntryForApp_shouldSetDefaultPackageNameAndLabel() throws Exception {
|
||||
BatteryEntry entry = createBatteryEntryForApp();
|
||||
BatteryEntry entry = createBatteryEntryForApp(null, APP_DEFAULT_PACKAGE_NAME,
|
||||
HIGH_DRAIN_PACKAGE);
|
||||
|
||||
assertThat(entry.getDefaultPackageName()).isEqualTo(APP_DEFAULT_PACKAGE_NAME);
|
||||
assertThat(entry.getLabel()).isEqualTo(APP_LABEL);
|
||||
assertThat(entry.getLabel()).isEqualTo(LABEL_PREFIX + APP_DEFAULT_PACKAGE_NAME);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void batteryEntryForApp_shouldSetLabelAsPackageName_whenPackageCannotBeFound()
|
||||
throws Exception {
|
||||
when(mockPackageManager.getApplicationInfo(APP_DEFAULT_PACKAGE_NAME, 0 /* no flags */))
|
||||
.thenThrow(new NameNotFoundException());
|
||||
throws Exception {
|
||||
when(mockPackageManager.getApplicationInfo(APP_DEFAULT_PACKAGE_NAME, 0 /* no flags */))
|
||||
.thenThrow(new NameNotFoundException());
|
||||
|
||||
BatteryEntry entry = createBatteryEntryForApp();
|
||||
BatteryEntry entry = createBatteryEntryForApp(null, APP_DEFAULT_PACKAGE_NAME, null);
|
||||
|
||||
assertThat(entry.getLabel()).isEqualTo(APP_DEFAULT_PACKAGE_NAME);
|
||||
assertThat(entry.getLabel()).isEqualTo(APP_DEFAULT_PACKAGE_NAME);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void batteryEntryForApp_shouldSetHighestDrainPackage_whenPackagesCannotBeFoundForUid() {
|
||||
when(mockPackageManager.getPackagesForUid(APP_UID)).thenReturn(null);
|
||||
|
||||
BatteryEntry entry = createBatteryEntryForApp();
|
||||
BatteryEntry entry = createBatteryEntryForApp(null, null, HIGH_DRAIN_PACKAGE);
|
||||
|
||||
assertThat(entry.getLabel()).isEqualTo(HIGH_DRAIN_PACKAGE);
|
||||
assertThat(entry.getLabel()).isEqualTo(LABEL_PREFIX + HIGH_DRAIN_PACKAGE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void batteryEntryForApp_shouldSetHighestDrainPackage_whenMultiplePackagesFoundForUid() {
|
||||
when(mockPackageManager.getPackagesForUid(APP_UID))
|
||||
.thenReturn(new String[] {APP_DEFAULT_PACKAGE_NAME, "package2", "package3"});
|
||||
BatteryEntry entry = createBatteryEntryForApp(
|
||||
new String[] {APP_DEFAULT_PACKAGE_NAME, "package2", "package3"}, null,
|
||||
HIGH_DRAIN_PACKAGE);
|
||||
|
||||
BatteryEntry entry = createBatteryEntryForApp();
|
||||
|
||||
assertThat(entry.getLabel()).isEqualTo(HIGH_DRAIN_PACKAGE);
|
||||
assertThat(entry.getLabel()).isEqualTo(LABEL_PREFIX + HIGH_DRAIN_PACKAGE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void batteryEntryForAOD_containCorrectInfo() {
|
||||
final BatterySipper batterySipper = mock(BatterySipper.class);
|
||||
batterySipper.drainType = DrainType.AMBIENT_DISPLAY;
|
||||
final SystemBatteryConsumer systemBatteryConsumer = mock(SystemBatteryConsumer.class);
|
||||
when(systemBatteryConsumer.getDrainType())
|
||||
.thenReturn(SystemBatteryConsumer.DRAIN_TYPE_AMBIENT_DISPLAY);
|
||||
final BatteryEntry entry = new BatteryEntry(RuntimeEnvironment.application, mockHandler,
|
||||
mockUserManager, batterySipper, null, null);
|
||||
mockUserManager, systemBatteryConsumer, false, null, null);
|
||||
|
||||
assertThat(entry.iconId).isEqualTo(R.drawable.ic_settings_aod);
|
||||
assertThat(entry.name).isEqualTo("Ambient display");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void extractPackageFromSipper_systemSipper_returnSystemPackage() {
|
||||
assertThat(BatteryEntry.extractPackagesFromSipper(createSipperForSystem()))
|
||||
.isEqualTo(new String[] {ANDROID_PACKAGE});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void extractPackageFromSipper_normalSipper_returnDefaultPackage() {
|
||||
BatterySipper sipper = createSipperForApp();
|
||||
assertThat(BatteryEntry.extractPackagesFromSipper(sipper)).isEqualTo(sipper.mPackages);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getTimeInForegroundMs_app() {
|
||||
final BatteryEntry entry = new BatteryEntry(RuntimeEnvironment.application, mockHandler,
|
||||
mockUserManager, null, mUidBatteryConsumer, null);
|
||||
mockUserManager, mUidBatteryConsumer, false, null, null);
|
||||
|
||||
when(mUidBatteryConsumer.getTimeInStateMs(UidBatteryConsumer.STATE_FOREGROUND))
|
||||
.thenReturn(100L);
|
||||
|
||||
assertThat(entry.getTimeInForegroundMs(mBatteryUtils)).isEqualTo(100L);
|
||||
assertThat(entry.getTimeInForegroundMs()).isEqualTo(100L);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getTimeInForegroundMs_systemConsumer() {
|
||||
final BatteryEntry entry = new BatteryEntry(RuntimeEnvironment.application, mockHandler,
|
||||
mockUserManager, createNonAppSipper(), mSystemBatteryConsumer, null);
|
||||
mockUserManager, mSystemBatteryConsumer, false, null, null);
|
||||
|
||||
when(mSystemBatteryConsumer.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_USAGE))
|
||||
.thenReturn(100L);
|
||||
|
||||
assertThat(entry.getTimeInForegroundMs(mBatteryUtils)).isEqualTo(100L);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getTimeInForegroundMs_useSipper() {
|
||||
final BatterySipper batterySipper = createSipperForApp();
|
||||
final BatteryEntry entry = new BatteryEntry(RuntimeEnvironment.application, mockHandler,
|
||||
mockUserManager, batterySipper, null, null);
|
||||
|
||||
when(mBatteryUtils.getProcessTimeMs(eq(BatteryUtils.StatusType.FOREGROUND),
|
||||
any(BatteryStats.Uid.class), eq(BatteryStats.STATS_SINCE_CHARGED)))
|
||||
.thenReturn(100L);
|
||||
assertThat(entry.getTimeInForegroundMs(mBatteryUtils)).isEqualTo(100L);
|
||||
assertThat(entry.getTimeInForegroundMs()).isEqualTo(100L);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getTimeInBackgroundMs_app() {
|
||||
final BatteryEntry entry = new BatteryEntry(RuntimeEnvironment.application, mockHandler,
|
||||
mockUserManager, null, mUidBatteryConsumer, null);
|
||||
mockUserManager, mUidBatteryConsumer, false, null, null);
|
||||
|
||||
when(mUidBatteryConsumer.getTimeInStateMs(UidBatteryConsumer.STATE_BACKGROUND))
|
||||
.thenReturn(100L);
|
||||
|
||||
assertThat(entry.getTimeInBackgroundMs(mBatteryUtils)).isEqualTo(100L);
|
||||
assertThat(entry.getTimeInBackgroundMs()).isEqualTo(100L);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getTimeInBackgroundMs_systemConsumer() {
|
||||
final BatteryEntry entry = new BatteryEntry(RuntimeEnvironment.application, mockHandler,
|
||||
mockUserManager, createNonAppSipper(), mSystemBatteryConsumer, null);
|
||||
mockUserManager, mSystemBatteryConsumer, false, null, null);
|
||||
|
||||
when(mSystemBatteryConsumer.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_USAGE))
|
||||
.thenReturn(100L);
|
||||
|
||||
assertThat(entry.getTimeInBackgroundMs(mBatteryUtils)).isEqualTo(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getTimeInBackgroundMs_useSipper() {
|
||||
final BatterySipper batterySipper = createSipperForApp();
|
||||
final BatteryEntry entry = new BatteryEntry(RuntimeEnvironment.application, mockHandler,
|
||||
mockUserManager, batterySipper, null, null);
|
||||
|
||||
when(mBatteryUtils.getProcessTimeMs(eq(BatteryUtils.StatusType.BACKGROUND),
|
||||
any(BatteryStats.Uid.class), eq(BatteryStats.STATS_SINCE_CHARGED)))
|
||||
.thenReturn(100L);
|
||||
assertThat(entry.getTimeInBackgroundMs(mBatteryUtils)).isEqualTo(100L);
|
||||
assertThat(entry.getTimeInBackgroundMs()).isEqualTo(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -249,7 +214,29 @@ public class BatteryEntryTest {
|
||||
assertThat(BatteryEntry.sUidCache).isNotEmpty();
|
||||
|
||||
Locale.setDefault(new Locale("zh_TW"));
|
||||
createBatteryEntryForApp();
|
||||
createBatteryEntryForApp(null, null, HIGH_DRAIN_PACKAGE);
|
||||
assertThat(BatteryEntry.sUidCache).isEmpty(); // check if cache is clear
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getKey_UidBatteryConsumer() {
|
||||
final BatteryEntry entry = createBatteryEntryForApp(null, null, null);
|
||||
final String key = entry.getKey();
|
||||
assertThat(key).isEqualTo("123");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getKey_SystemBatteryConsumer_returnDrainType() {
|
||||
final BatteryEntry entry =
|
||||
createSystemBatteryEntry(SystemBatteryConsumer.DRAIN_TYPE_BLUETOOTH);
|
||||
final String key = entry.getKey();
|
||||
assertThat(key).isEqualTo("S|2");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getKey_UserBatteryConsumer_returnUserId() {
|
||||
final BatteryEntry entry = createUserBatteryConsumer(2);
|
||||
final String key = entry.getKey();
|
||||
assertThat(key).isEqualTo("U|2");
|
||||
}
|
||||
}
|
||||
|
@@ -49,6 +49,7 @@ import android.os.BatteryStatsManager;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.Process;
|
||||
import android.os.SystemBatteryConsumer;
|
||||
import android.os.SystemClock;
|
||||
import android.os.UserManager;
|
||||
|
||||
@@ -119,6 +120,8 @@ public class BatteryUtilsTest {
|
||||
@Mock
|
||||
private BatteryStats.Timer mTimer;
|
||||
@Mock
|
||||
private SystemBatteryConsumer mSystemBatteryConsumer;
|
||||
@Mock
|
||||
private BatterySipper mNormalBatterySipper;
|
||||
@Mock
|
||||
private BatterySipper mWifiBatterySipper;
|
||||
@@ -283,21 +286,54 @@ public class BatteryUtilsTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRemoveHiddenBatterySippers_ContainsHiddenSippers_RemoveAndReturnValue() {
|
||||
final List<BatterySipper> sippers = new ArrayList<>();
|
||||
sippers.add(mNormalBatterySipper);
|
||||
sippers.add(mScreenBatterySipper);
|
||||
sippers.add(mSystemBatterySipper);
|
||||
sippers.add(mOvercountedBatterySipper);
|
||||
sippers.add(mUnaccountedBatterySipper);
|
||||
sippers.add(mWifiBatterySipper);
|
||||
sippers.add(mBluetoothBatterySipper);
|
||||
sippers.add(mIdleBatterySipper);
|
||||
when(mProvider.isTypeSystem(mSystemBatterySipper)).thenReturn(true);
|
||||
public void testShouldHideSystemConsumer_TypeIdle_ReturnTrue() {
|
||||
when(mSystemBatteryConsumer.getDrainType())
|
||||
.thenReturn(SystemBatteryConsumer.DRAIN_TYPE_IDLE);
|
||||
assertThat(mBatteryUtils.shouldHideSystemBatteryConsumer(mSystemBatteryConsumer)).isTrue();
|
||||
}
|
||||
|
||||
mBatteryUtils.removeHiddenBatterySippers(sippers);
|
||||
@Test
|
||||
public void testShouldHideSystemConsumer_TypeMobileRadio_ReturnTrue() {
|
||||
when(mSystemBatteryConsumer.getDrainType())
|
||||
.thenReturn(SystemBatteryConsumer.DRAIN_TYPE_MOBILE_RADIO);
|
||||
assertThat(mBatteryUtils.shouldHideSystemBatteryConsumer(mSystemBatteryConsumer)).isTrue();
|
||||
}
|
||||
|
||||
assertThat(sippers).containsExactly(mNormalBatterySipper);
|
||||
@Test
|
||||
public void testShouldHideSystemConsumer_TypeScreen_ReturnTrue() {
|
||||
when(mSystemBatteryConsumer.getDrainType())
|
||||
.thenReturn(SystemBatteryConsumer.DRAIN_TYPE_SCREEN);
|
||||
assertThat(mBatteryUtils.shouldHideSystemBatteryConsumer(mSystemBatteryConsumer)).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testShouldHideSystemConsumer_TypeBluetooth_ReturnTrue() {
|
||||
when(mSystemBatteryConsumer.getDrainType())
|
||||
.thenReturn(SystemBatteryConsumer.DRAIN_TYPE_BLUETOOTH);
|
||||
assertThat(mBatteryUtils.shouldHideSystemBatteryConsumer(mSystemBatteryConsumer)).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testShouldHideSystemConsumer_TypeWifi_ReturnTrue() {
|
||||
when(mSystemBatteryConsumer.getDrainType())
|
||||
.thenReturn(SystemBatteryConsumer.DRAIN_TYPE_WIFI);
|
||||
assertThat(mBatteryUtils.shouldHideSystemBatteryConsumer(mSystemBatteryConsumer)).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testShouldHideSystemConsumer_LowPower_ReturnTrue() {
|
||||
when(mSystemBatteryConsumer.getDrainType())
|
||||
.thenReturn(SystemBatteryConsumer.DRAIN_TYPE_FLASHLIGHT);
|
||||
when(mSystemBatteryConsumer.getConsumedPower()).thenReturn(0.0005);
|
||||
assertThat(mBatteryUtils.shouldHideSystemBatteryConsumer(mSystemBatteryConsumer)).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testShouldHideSystemConsumer_HighPower_ReturnFalse() {
|
||||
when(mSystemBatteryConsumer.getDrainType())
|
||||
.thenReturn(SystemBatteryConsumer.DRAIN_TYPE_FLASHLIGHT);
|
||||
when(mSystemBatteryConsumer.getConsumedPower()).thenReturn(0.5);
|
||||
assertThat(mBatteryUtils.shouldHideSystemBatteryConsumer(mSystemBatteryConsumer)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -388,19 +424,6 @@ public class BatteryUtilsTest {
|
||||
BatteryStats.STATS_SINCE_CHARGED)).isEqualTo(TIME_SINCE_LAST_FULL_CHARGE_MS);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSortUsageList() {
|
||||
final List<BatterySipper> sippers = new ArrayList<>();
|
||||
sippers.add(mNormalBatterySipper);
|
||||
sippers.add(mScreenBatterySipper);
|
||||
sippers.add(mSystemBatterySipper);
|
||||
|
||||
mBatteryUtils.sortUsageList(sippers);
|
||||
|
||||
assertThat(sippers).containsExactly(mNormalBatterySipper, mSystemBatterySipper,
|
||||
mScreenBatterySipper);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCalculateLastFullChargeTime() {
|
||||
final long currentTimeMs = System.currentTimeMillis();
|
||||
@@ -469,30 +492,6 @@ public class BatteryUtilsTest {
|
||||
mUserManager.getUserProfiles());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFindBatterySipperByType_findTypeScreen() {
|
||||
BatterySipper sipper = mBatteryUtils.findBatterySipperByType(mUsageList,
|
||||
BatterySipper.DrainType.SCREEN);
|
||||
|
||||
assertThat(sipper).isSameInstanceAs(mScreenBatterySipper);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFindBatterySipperByType_findTypeApp() {
|
||||
BatterySipper sipper = mBatteryUtils.findBatterySipperByType(mUsageList,
|
||||
BatterySipper.DrainType.APP);
|
||||
|
||||
assertThat(sipper).isSameInstanceAs(mNormalBatterySipper);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCalculateScreenUsageTime_returnCorrectTime() {
|
||||
mScreenBatterySipper.usageTimeMs = TIME_EXPECTED_FOREGROUND;
|
||||
|
||||
assertThat(mBatteryUtils.calculateScreenUsageTime(mBatteryStatsHelper)).isEqualTo(
|
||||
TIME_EXPECTED_FOREGROUND);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsPreOApp_SdkLowerThanO_ReturnTrue() {
|
||||
assertThat(mBatteryUtils.isPreOApp(LOW_SDK_PACKAGE)).isTrue();
|
||||
|
@@ -69,6 +69,14 @@ public class PowerUsageAdvancedTest {
|
||||
mFeatureFactory = FakeFeatureFactory.setupForTest();
|
||||
when(mToggleAppsMenu.getItemId()).thenReturn(PowerUsageAdvanced.MENU_TOGGLE_APPS);
|
||||
|
||||
BatteryAppListPreferenceController.sConfig =
|
||||
new BatteryAppListPreferenceController.Config() {
|
||||
@Override
|
||||
public boolean shouldShowBatteryAttributionList(Context context) {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
mFragment = spy(new PowerUsageAdvanced());
|
||||
mFragment.onAttach(mContext);
|
||||
}
|
||||
|
Reference in New Issue
Block a user