diff --git a/src/com/android/settings/applications/appinfo/AppBatteryPreferenceController.java b/src/com/android/settings/applications/appinfo/AppBatteryPreferenceController.java index 19187ba9930..5f1d9d2a52d 100644 --- a/src/com/android/settings/applications/appinfo/AppBatteryPreferenceController.java +++ b/src/com/android/settings/applications/appinfo/AppBatteryPreferenceController.java @@ -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); diff --git a/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetail.java b/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetail.java index 9edae9d361c..399a84d7fea 100644 --- a/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetail.java +++ b/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetail.java @@ -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); diff --git a/src/com/android/settings/fuelgauge/BatteryAppListPreferenceController.java b/src/com/android/settings/fuelgauge/BatteryAppListPreferenceController.java index cfa9e23a076..47b2a0af649 100644 --- a/src/com/android/settings/fuelgauge/BatteryAppListPreferenceController.java +++ b/src/com/android/settings/fuelgauge/BatteryAppListPreferenceController.java @@ -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 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 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 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 getCoalescedUsageList(final List sippers) { - final SparseArray uidList = new SparseArray<>(); + private List getCoalescedUsageList(boolean showAllApps) { + final SparseArray batteryEntryList = new SparseArray<>(); - final ArrayList 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 results = new ArrayList<>(); + final List 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 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 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 getFakeStats() { - ArrayList 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) { diff --git a/src/com/android/settings/fuelgauge/BatteryEntry.java b/src/com/android/settings/fuelgauge/BatteryEntry.java index f1b87aff810..9fafefd154b 100644 --- a/src/com/android/settings/fuelgauge/BatteryEntry.java +++ b/src/com/android/settings/fuelgauge/BatteryEntry.java @@ -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 sUidCache = new HashMap(); + static final HashMap sUidCache = new HashMap<>(); - static final ArrayList mRequestQueue = new ArrayList(); + static final ArrayList sRequestQueue = new ArrayList(); 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 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; } } diff --git a/src/com/android/settings/fuelgauge/BatteryUtils.java b/src/com/android/settings/fuelgauge/BatteryUtils.java index 0174cfa5a84..d3633b1b92e 100644 --- a/src/com/android/settings/fuelgauge/BatteryUtils.java +++ b/src/com/android/settings/fuelgauge/BatteryUtils.java @@ -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 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 usageList) { - Collections.sort(usageList, new Comparator() { - @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 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; } } - diff --git a/src/com/android/settings/fuelgauge/PowerUsageAdvanced.java b/src/com/android/settings/fuelgauge/PowerUsageAdvanced.java index 86e52d9555f..9279e5d3ad6 100644 --- a/src/com/android/settings/fuelgauge/PowerUsageAdvanced.java +++ b/src/com/android/settings/fuelgauge/PowerUsageAdvanced.java @@ -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) { diff --git a/src/com/android/settings/fuelgauge/PowerUsageFeatureProvider.java b/src/com/android/settings/fuelgauge/PowerUsageFeatureProvider.java index 4f292dddacc..6a22ed4691a 100644 --- a/src/com/android/settings/fuelgauge/PowerUsageFeatureProvider.java +++ b/src/com/android/settings/fuelgauge/PowerUsageFeatureProvider.java @@ -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 */ diff --git a/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImpl.java b/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImpl.java index ab71c97e141..cb83d80cee6 100644 --- a/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImpl.java +++ b/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImpl.java @@ -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; diff --git a/tests/robotests/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetailTest.java b/tests/robotests/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetailTest.java index 8296c8c2bbd..dd1a0e1adc8 100644 --- a/tests/robotests/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetailTest.java +++ b/tests/robotests/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetailTest.java @@ -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))); } diff --git a/tests/robotests/src/com/android/settings/fuelgauge/BatteryAppListPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/fuelgauge/BatteryAppListPreferenceControllerTest.java index 28655f32946..1faa75fb700 100644 --- a/tests/robotests/src/com/android/settings/fuelgauge/BatteryAppListPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/fuelgauge/BatteryAppListPreferenceControllerTest.java @@ -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(); diff --git a/tests/robotests/src/com/android/settings/fuelgauge/BatteryEntryTest.java b/tests/robotests/src/com/android/settings/fuelgauge/BatteryEntryTest.java index 8531b2871f0..6858579479b 100644 --- a/tests/robotests/src/com/android/settings/fuelgauge/BatteryEntryTest.java +++ b/tests/robotests/src/com/android/settings/fuelgauge/BatteryEntryTest.java @@ -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"); + } } diff --git a/tests/robotests/src/com/android/settings/fuelgauge/BatteryUtilsTest.java b/tests/robotests/src/com/android/settings/fuelgauge/BatteryUtilsTest.java index 17fee4aa2c3..2d22a12a7e8 100644 --- a/tests/robotests/src/com/android/settings/fuelgauge/BatteryUtilsTest.java +++ b/tests/robotests/src/com/android/settings/fuelgauge/BatteryUtilsTest.java @@ -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 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 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(); diff --git a/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageAdvancedTest.java b/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageAdvancedTest.java index 1ef288016b4..c9b1a00bbf5 100644 --- a/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageAdvancedTest.java +++ b/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageAdvancedTest.java @@ -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); }