Transition BatteryInfo and BatteryUtils to BatteryUsageStats API

Bug: 173745486
Test: make RunSettingsRoboTests ROBOTEST_FILTER=com.android.settings.fuelgauge.BatteryHistoryPreferenceTest
Test: make RunSettingsRoboTests ROBOTEST_FILTER=com.android.settings.fuelgauge.BatteryInfoLoaderTest
Test: make RunSettingsRoboTests ROBOTEST_FILTER=com.android.settings.fuelgauge.BatteryInfoTest
Test: make RunSettingsRoboTests ROBOTEST_FILTER=com.android.settings.fuelgauge.BatteryUtilsTest
Test: make RunSettingsRoboTests ROBOTEST_FILTER=com.android.settings.fuelgauge.batterytip.detectors

Change-Id: I469ff8b88aa3307422c02f51943df4ef1759db56
This commit is contained in:
Dmitri Plotnikov
2021-02-19 14:34:01 -08:00
parent e604c56241
commit 820bee81d6
18 changed files with 296 additions and 180 deletions

View File

@@ -230,7 +230,7 @@ public class AppBatteryPreferenceController extends BasePreferenceController
@Override @Override
@NonNull @NonNull
public Loader<BatteryUsageStats> onCreateLoader(int id, Bundle args) { public Loader<BatteryUsageStats> onCreateLoader(int id, Bundle args) {
return new BatteryUsageStatsLoader(mContext); return new BatteryUsageStatsLoader(mContext, /* includeBatteryHistory */ false);
} }
@Override @Override

View File

@@ -17,15 +17,16 @@
package com.android.settings.fuelgauge; package com.android.settings.fuelgauge;
import android.content.Context; import android.content.Context;
import android.os.BatteryUsageStats;
import android.util.AttributeSet; import android.util.AttributeSet;
import android.view.View; import android.view.View;
import android.widget.TextView; import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.VisibleForTesting; import androidx.annotation.VisibleForTesting;
import androidx.preference.Preference; import androidx.preference.Preference;
import androidx.preference.PreferenceViewHolder; import androidx.preference.PreferenceViewHolder;
import com.android.internal.os.BatteryStatsHelper;
import com.android.settings.R; import com.android.settings.R;
import com.android.settings.widget.UsageView; import com.android.settings.widget.UsageView;
@@ -50,11 +51,11 @@ public class BatteryHistoryPreference extends Preference {
setSelectable(false); setSelectable(false);
} }
public void setStats(BatteryStatsHelper batteryStats) { void setBatteryUsageStats(@NonNull BatteryUsageStats batteryUsageStats) {
BatteryInfo.getBatteryInfo(getContext(), info -> { BatteryInfo.getBatteryInfo(getContext(), info -> {
mBatteryInfo = info; mBatteryInfo = info;
notifyChanged(); notifyChanged();
}, batteryStats, false); }, batteryUsageStats, false);
} }
public void setBottomSummary(CharSequence text) { public void setBottomSummary(CharSequence text) {

View File

@@ -20,16 +20,18 @@ import android.content.IntentFilter;
import android.content.res.Resources; import android.content.res.Resources;
import android.os.AsyncTask; import android.os.AsyncTask;
import android.os.BatteryManager; import android.os.BatteryManager;
import android.os.BatteryStats;
import android.os.BatteryStats.HistoryItem; import android.os.BatteryStats.HistoryItem;
import android.os.Bundle; import android.os.BatteryStatsManager;
import android.os.BatteryUsageStats;
import android.os.SystemClock; import android.os.SystemClock;
import android.text.format.Formatter; import android.text.format.Formatter;
import android.util.SparseIntArray; import android.util.SparseIntArray;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.WorkerThread; import androidx.annotation.WorkerThread;
import com.android.internal.os.BatteryStatsHelper; import com.android.internal.os.BatteryStatsHistoryIterator;
import com.android.settings.Utils; import com.android.settings.Utils;
import com.android.settings.overlay.FeatureFactory; import com.android.settings.overlay.FeatureFactory;
import com.android.settings.widget.UsageView; import com.android.settings.widget.UsageView;
@@ -52,7 +54,7 @@ public class BatteryInfo {
public String statusLabel; public String statusLabel;
public String suggestionLabel; public String suggestionLabel;
private boolean mCharging; private boolean mCharging;
private BatteryStats mStats; private BatteryUsageStats mBatteryUsageStats;
private static final String LOG_TAG = "BatteryInfo"; private static final String LOG_TAG = "BatteryInfo";
private long timePeriod; private long timePeriod;
@@ -126,7 +128,7 @@ public class BatteryInfo {
parserList[i] = parsers[i]; parserList[i] = parsers[i];
} }
parserList[parsers.length] = parser; parserList[parsers.length] = parser;
parse(mStats, parserList); parseBatteryHistory(parserList);
String timeString = context.getString(R.string.charge_length_format, String timeString = context.getString(R.string.charge_length_format,
Formatter.formatShortElapsedTime(context, timePeriod)); Formatter.formatShortElapsedTime(context, timePeriod));
String remaining = ""; String remaining = "";
@@ -137,22 +139,25 @@ public class BatteryInfo {
view.setBottomLabels(new CharSequence[]{timeString, remaining}); view.setBottomLabels(new CharSequence[]{timeString, remaining});
} }
public static void getBatteryInfo(final Context context, final Callback callback) {
BatteryInfo.getBatteryInfo(context, callback, null /* statsHelper */,
false /* shortString */);
}
public static void getBatteryInfo(final Context context, final Callback callback, public static void getBatteryInfo(final Context context, final Callback callback,
boolean shortString) { boolean shortString) {
BatteryInfo.getBatteryInfo(context, callback, null /* statsHelper */, shortString); BatteryInfo.getBatteryInfo(context, callback, /* batteryUsageStats */ null, shortString);
} }
public static void getBatteryInfo(final Context context, final Callback callback, public static void getBatteryInfo(final Context context, final Callback callback,
final BatteryStatsHelper statsHelper, boolean shortString) { @Nullable final BatteryUsageStats batteryUsageStats,
boolean shortString) {
new AsyncTask<Void, Void, BatteryInfo>() { new AsyncTask<Void, Void, BatteryInfo>() {
@Override @Override
protected BatteryInfo doInBackground(Void... params) { protected BatteryInfo doInBackground(Void... params) {
return getBatteryInfo(context, statsHelper, shortString); BatteryUsageStats stats;
if (batteryUsageStats != null) {
stats = batteryUsageStats;
} else {
stats = context.getSystemService(BatteryStatsManager.class)
.getBatteryUsageStats();
}
return getBatteryInfo(context, stats, shortString);
} }
@Override @Override
@@ -164,18 +169,13 @@ public class BatteryInfo {
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
} }
/**
* Creates a BatteryInfo based on BatteryUsageStats
*/
@WorkerThread
public static BatteryInfo getBatteryInfo(final Context context, public static BatteryInfo getBatteryInfo(final Context context,
final BatteryStatsHelper statsHelper, boolean shortString) { @NonNull final BatteryUsageStats batteryUsageStats, boolean shortString) {
final BatteryStats stats;
final long batteryStatsTime = System.currentTimeMillis(); final long batteryStatsTime = System.currentTimeMillis();
if (statsHelper == null) {
final BatteryStatsHelper localStatsHelper = new BatteryStatsHelper(context,
true);
localStatsHelper.create((Bundle) null);
stats = localStatsHelper.getStats();
} else {
stats = statsHelper.getStats();
}
BatteryUtils.logRuntime(LOG_TAG, "time for getStats", batteryStatsTime); BatteryUtils.logRuntime(LOG_TAG, "time for getStats", batteryStatsTime);
final long startTime = System.currentTimeMillis(); final long startTime = System.currentTimeMillis();
@@ -197,38 +197,38 @@ public class BatteryInfo {
Estimate.storeCachedEstimate(context, estimate); Estimate.storeCachedEstimate(context, estimate);
BatteryUtils BatteryUtils
.logRuntime(LOG_TAG, "time for enhanced BatteryInfo", startTime); .logRuntime(LOG_TAG, "time for enhanced BatteryInfo", startTime);
return BatteryInfo.getBatteryInfo(context, batteryBroadcast, stats, return BatteryInfo.getBatteryInfo(context, batteryBroadcast, batteryUsageStats,
estimate, elapsedRealtimeUs, shortString); estimate, elapsedRealtimeUs, shortString);
} }
} }
final long prediction = discharging final long prediction = discharging ? batteryUsageStats.getBatteryTimeRemainingMs() : 0;
? stats.computeBatteryTimeRemaining(elapsedRealtimeUs) : 0;
final Estimate estimate = new Estimate( final Estimate estimate = new Estimate(
PowerUtil.convertUsToMs(prediction), PowerUtil.convertUsToMs(prediction),
false, /* isBasedOnUsage */ false, /* isBasedOnUsage */
EstimateKt.AVERAGE_TIME_TO_DISCHARGE_UNKNOWN); EstimateKt.AVERAGE_TIME_TO_DISCHARGE_UNKNOWN);
BatteryUtils.logRuntime(LOG_TAG, "time for regular BatteryInfo", startTime); BatteryUtils.logRuntime(LOG_TAG, "time for regular BatteryInfo", startTime);
return BatteryInfo.getBatteryInfo(context, batteryBroadcast, stats, return BatteryInfo.getBatteryInfo(context, batteryBroadcast, batteryUsageStats,
estimate, elapsedRealtimeUs, shortString); estimate, elapsedRealtimeUs, shortString);
} }
@WorkerThread @WorkerThread
public static BatteryInfo getBatteryInfoOld(Context context, Intent batteryBroadcast, public static BatteryInfo getBatteryInfoOld(Context context, Intent batteryBroadcast,
BatteryStats stats, long elapsedRealtimeUs, boolean shortString) { BatteryUsageStats batteryUsageStats, long elapsedRealtimeUs, boolean shortString) {
Estimate estimate = new Estimate( Estimate estimate = new Estimate(
PowerUtil.convertUsToMs(stats.computeBatteryTimeRemaining(elapsedRealtimeUs)), batteryUsageStats.getBatteryTimeRemainingMs(),
false, false,
EstimateKt.AVERAGE_TIME_TO_DISCHARGE_UNKNOWN); EstimateKt.AVERAGE_TIME_TO_DISCHARGE_UNKNOWN);
return getBatteryInfo(context, batteryBroadcast, stats, estimate, elapsedRealtimeUs, return getBatteryInfo(context, batteryBroadcast, batteryUsageStats, estimate,
shortString); elapsedRealtimeUs, shortString);
} }
@WorkerThread @WorkerThread
public static BatteryInfo getBatteryInfo(Context context, Intent batteryBroadcast, public static BatteryInfo getBatteryInfo(Context context, Intent batteryBroadcast,
BatteryStats stats, Estimate estimate, long elapsedRealtimeUs, boolean shortString) { @NonNull BatteryUsageStats batteryUsageStats, Estimate estimate,
long elapsedRealtimeUs, boolean shortString) {
final long startTime = System.currentTimeMillis(); final long startTime = System.currentTimeMillis();
BatteryInfo info = new BatteryInfo(); BatteryInfo info = new BatteryInfo();
info.mStats = stats; info.mBatteryUsageStats = batteryUsageStats;
info.batteryLevel = Utils.getBatteryLevel(batteryBroadcast); info.batteryLevel = Utils.getBatteryLevel(batteryBroadcast);
info.batteryPercentString = Utils.formatPercentage(info.batteryLevel); info.batteryPercentString = Utils.formatPercentage(info.batteryLevel);
info.mCharging = batteryBroadcast.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0) != 0; info.mCharging = batteryBroadcast.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0) != 0;
@@ -241,16 +241,17 @@ public class BatteryInfo {
if (!info.mCharging) { if (!info.mCharging) {
updateBatteryInfoDischarging(context, shortString, estimate, info); updateBatteryInfoDischarging(context, shortString, estimate, info);
} else { } else {
updateBatteryInfoCharging(context, batteryBroadcast, stats, elapsedRealtimeUs, info); updateBatteryInfoCharging(context, batteryBroadcast, batteryUsageStats,
info);
} }
BatteryUtils.logRuntime(LOG_TAG, "time for getBatteryInfo", startTime); BatteryUtils.logRuntime(LOG_TAG, "time for getBatteryInfo", startTime);
return info; return info;
} }
private static void updateBatteryInfoCharging(Context context, Intent batteryBroadcast, private static void updateBatteryInfoCharging(Context context, Intent batteryBroadcast,
BatteryStats stats, long elapsedRealtimeUs, BatteryInfo info) { BatteryUsageStats stats, BatteryInfo info) {
final Resources resources = context.getResources(); final Resources resources = context.getResources();
final long chargeTime = stats.computeChargeTimeRemaining(elapsedRealtimeUs); final long chargeTimeMs = stats.getChargeTimeRemainingMs();
final int status = batteryBroadcast.getIntExtra(BatteryManager.EXTRA_STATUS, final int status = batteryBroadcast.getIntExtra(BatteryManager.EXTRA_STATUS,
BatteryManager.BATTERY_STATUS_UNKNOWN); BatteryManager.BATTERY_STATUS_UNKNOWN);
info.discharging = false; info.discharging = false;
@@ -260,8 +261,8 @@ public class BatteryInfo {
int chargingLimitedResId = R.string.power_charging_limited; int chargingLimitedResId = R.string.power_charging_limited;
info.chargeLabel = info.chargeLabel =
context.getString(chargingLimitedResId, info.batteryPercentString); context.getString(chargingLimitedResId, info.batteryPercentString);
} else if (chargeTime > 0 && status != BatteryManager.BATTERY_STATUS_FULL) { } else if (chargeTimeMs > 0 && status != BatteryManager.BATTERY_STATUS_FULL) {
info.remainingTimeUs = chargeTime; info.remainingTimeUs = PowerUtil.convertMsToUs(chargeTimeMs);
CharSequence timeString = StringUtil.formatElapsedTime(context, CharSequence timeString = StringUtil.formatElapsedTime(context,
PowerUtil.convertUsToMs(info.remainingTimeUs), false /* withSeconds */); PowerUtil.convertUsToMs(info.remainingTimeUs), false /* withSeconds */);
int resId = R.string.power_charging_duration; int resId = R.string.power_charging_duration;
@@ -313,7 +314,11 @@ public class BatteryInfo {
void onParsingDone(); void onParsingDone();
} }
public static void parse(BatteryStats stats, BatteryDataParser... parsers) { /**
* Iterates over battery history included in the BatteryUsageStats that this object
* was initialized with.
*/
public void parseBatteryHistory(BatteryDataParser... parsers) {
long startWalltime = 0; long startWalltime = 0;
long endWalltime = 0; long endWalltime = 0;
long historyStart = 0; long historyStart = 0;
@@ -324,41 +329,41 @@ public class BatteryInfo {
int lastInteresting = 0; int lastInteresting = 0;
int pos = 0; int pos = 0;
boolean first = true; boolean first = true;
if (stats.startIteratingHistoryLocked()) { final BatteryStatsHistoryIterator iterator1 =
final HistoryItem rec = new HistoryItem(); mBatteryUsageStats.iterateBatteryStatsHistory();
while (stats.getNextHistoryLocked(rec)) { final HistoryItem rec = new HistoryItem();
pos++; while (iterator1.next(rec)) {
if (first) { pos++;
first = false; if (first) {
historyStart = rec.time; first = false;
historyStart = rec.time;
}
if (rec.cmd == HistoryItem.CMD_CURRENT_TIME
|| rec.cmd == HistoryItem.CMD_RESET) {
// If there is a ridiculously large jump in time, then we won't be
// able to create a good chart with that data, so just ignore the
// times we got before and pretend like our data extends back from
// the time we have now.
// Also, if we are getting a time change and we are less than 5 minutes
// since the start of the history real time, then also use this new
// time to compute the base time, since whatever time we had before is
// pretty much just noise.
if (rec.currentTime > (lastWallTime + (180 * 24 * 60 * 60 * 1000L))
|| rec.time < (historyStart + (5 * 60 * 1000L))) {
startWalltime = 0;
} }
if (rec.cmd == HistoryItem.CMD_CURRENT_TIME lastWallTime = rec.currentTime;
|| rec.cmd == HistoryItem.CMD_RESET) { lastRealtime = rec.time;
// If there is a ridiculously large jump in time, then we won't be if (startWalltime == 0) {
// able to create a good chart with that data, so just ignore the startWalltime = lastWallTime - (lastRealtime - historyStart);
// times we got before and pretend like our data extends back from
// the time we have now.
// Also, if we are getting a time change and we are less than 5 minutes
// since the start of the history real time, then also use this new
// time to compute the base time, since whatever time we had before is
// pretty much just noise.
if (rec.currentTime > (lastWallTime + (180 * 24 * 60 * 60 * 1000L))
|| rec.time < (historyStart + (5 * 60 * 1000L))) {
startWalltime = 0;
}
lastWallTime = rec.currentTime;
lastRealtime = rec.time;
if (startWalltime == 0) {
startWalltime = lastWallTime - (lastRealtime - historyStart);
}
}
if (rec.isDeltaData()) {
lastInteresting = pos;
historyEnd = rec.time;
} }
} }
if (rec.isDeltaData()) {
lastInteresting = pos;
historyEnd = rec.time;
}
} }
stats.finishIteratingHistoryLocked();
endWalltime = lastWallTime + historyEnd - lastRealtime; endWalltime = lastWallTime + historyEnd - lastRealtime;
int i = 0; int i = 0;
@@ -367,9 +372,11 @@ public class BatteryInfo {
for (int j = 0; j < parsers.length; j++) { for (int j = 0; j < parsers.length; j++) {
parsers[j].onParsingStarted(startWalltime, endWalltime); parsers[j].onParsingStarted(startWalltime, endWalltime);
} }
if (endWalltime > startWalltime && stats.startIteratingHistoryLocked()) {
final HistoryItem rec = new HistoryItem(); if (endWalltime > startWalltime) {
while (stats.getNextHistoryLocked(rec) && i < N) { final BatteryStatsHistoryIterator iterator2 =
mBatteryUsageStats.iterateBatteryStatsHistory();
while (iterator2.next(rec) && i < N) {
if (rec.isDeltaData()) { if (rec.isDeltaData()) {
curWalltime += rec.time - lastRealtime; curWalltime += rec.time - lastRealtime;
lastRealtime = rec.time; lastRealtime = rec.time;
@@ -404,8 +411,6 @@ public class BatteryInfo {
} }
} }
stats.finishIteratingHistoryLocked();
for (int j = 0; j < parsers.length; j++) { for (int j = 0; j < parsers.length; j++) {
parsers[j].onParsingDone(); parsers[j].onParsingDone();
} }

View File

@@ -19,7 +19,6 @@ import android.content.Context;
import androidx.annotation.VisibleForTesting; import androidx.annotation.VisibleForTesting;
import com.android.internal.os.BatteryStatsHelper;
import com.android.settingslib.utils.AsyncLoaderCompat; import com.android.settingslib.utils.AsyncLoaderCompat;
/** /**
@@ -28,17 +27,14 @@ import com.android.settingslib.utils.AsyncLoaderCompat;
* when not available. * when not available.
*/ */
public class BatteryInfoLoader extends AsyncLoaderCompat<BatteryInfo>{ public class BatteryInfoLoader extends AsyncLoaderCompat<BatteryInfo>{
BatteryStatsHelper mStatsHelper;
private static final String LOG_TAG = "BatteryInfoLoader"; private static final String LOG_TAG = "BatteryInfoLoader";
@VisibleForTesting @VisibleForTesting
BatteryUtils batteryUtils; BatteryUtils mBatteryUtils;
public BatteryInfoLoader(Context context, BatteryStatsHelper batteryStatsHelper) { public BatteryInfoLoader(Context context) {
super(context); super(context);
mStatsHelper = batteryStatsHelper; mBatteryUtils = BatteryUtils.getInstance(context);
batteryUtils = BatteryUtils.getInstance(context);
} }
@Override @Override
@@ -48,6 +44,6 @@ public class BatteryInfoLoader extends AsyncLoaderCompat<BatteryInfo>{
@Override @Override
public BatteryInfo loadInBackground() { public BatteryInfo loadInBackground() {
return batteryUtils.getBatteryInfo(mStatsHelper, LOG_TAG); return mBatteryUtils.getBatteryInfo(LOG_TAG);
} }
} }

View File

@@ -19,6 +19,7 @@ package com.android.settings.fuelgauge;
import android.content.Context; import android.content.Context;
import android.os.BatteryStatsManager; import android.os.BatteryStatsManager;
import android.os.BatteryUsageStats; import android.os.BatteryUsageStats;
import android.os.BatteryUsageStatsQuery;
import com.android.settingslib.utils.AsyncLoaderCompat; import com.android.settingslib.utils.AsyncLoaderCompat;
@@ -27,15 +28,21 @@ import com.android.settingslib.utils.AsyncLoaderCompat;
*/ */
public class BatteryUsageStatsLoader extends AsyncLoaderCompat<BatteryUsageStats> { public class BatteryUsageStatsLoader extends AsyncLoaderCompat<BatteryUsageStats> {
private final BatteryStatsManager mBatteryStatsManager; private final BatteryStatsManager mBatteryStatsManager;
private final boolean mIncludeBatteryHistory;
public BatteryUsageStatsLoader(Context context) { public BatteryUsageStatsLoader(Context context, boolean includeBatteryHistory) {
super(context); super(context);
mBatteryStatsManager = context.getSystemService(BatteryStatsManager.class); mBatteryStatsManager = context.getSystemService(BatteryStatsManager.class);
mIncludeBatteryHistory = includeBatteryHistory;
} }
@Override @Override
public BatteryUsageStats loadInBackground() { public BatteryUsageStats loadInBackground() {
return mBatteryStatsManager.getBatteryUsageStats(); final BatteryUsageStatsQuery.Builder builder = new BatteryUsageStatsQuery.Builder();
if (mIncludeBatteryHistory) {
builder.includeBatteryHistory();
}
return mBatteryStatsManager.getBatteryUsageStats(builder.build());
} }
@Override @Override

View File

@@ -24,6 +24,9 @@ import android.content.pm.PackageInfo;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo; import android.content.pm.ResolveInfo;
import android.os.BatteryStats; import android.os.BatteryStats;
import android.os.BatteryStatsManager;
import android.os.BatteryUsageStats;
import android.os.BatteryUsageStatsQuery;
import android.os.Build; import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
import android.os.Process; import android.os.Process;
@@ -103,7 +106,7 @@ public class BatteryUtils {
} }
@VisibleForTesting @VisibleForTesting
BatteryUtils(Context context) { public BatteryUtils(Context context) {
mContext = context; mContext = context;
mPackageManager = context.getPackageManager(); mPackageManager = context.getPackageManager();
mAppOpsManager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE); mAppOpsManager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
@@ -472,29 +475,35 @@ public class BatteryUtils {
} }
@WorkerThread @WorkerThread
public BatteryInfo getBatteryInfo(final BatteryStatsHelper statsHelper, final String tag) { public BatteryInfo getBatteryInfo(final String tag) {
final BatteryStatsManager systemService = mContext.getSystemService(
BatteryStatsManager.class);
final BatteryUsageStats batteryUsageStats = systemService.getBatteryUsageStats(
new BatteryUsageStatsQuery.Builder().includeBatteryHistory().build());
final long startTime = System.currentTimeMillis(); final long startTime = System.currentTimeMillis();
// Stuff we always need to get BatteryInfo // Stuff we always need to get BatteryInfo
final Intent batteryBroadcast = mContext.registerReceiver(null, final Intent batteryBroadcast = mContext.registerReceiver(null,
new IntentFilter(Intent.ACTION_BATTERY_CHANGED)); new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
final long elapsedRealtimeUs = PowerUtil.convertMsToUs( final long elapsedRealtimeUs = PowerUtil.convertMsToUs(
SystemClock.elapsedRealtime()); SystemClock.elapsedRealtime());
final BatteryStats stats = statsHelper.getStats();
BatteryInfo batteryInfo; BatteryInfo batteryInfo;
Estimate estimate = getEnhancedEstimate(); Estimate estimate = getEnhancedEstimate();
// couldn't get estimate from cache or provider, use fallback // couldn't get estimate from cache or provider, use fallback
if (estimate == null) { if (estimate == null) {
estimate = new Estimate( estimate = new Estimate(
PowerUtil.convertUsToMs(stats.computeBatteryTimeRemaining(elapsedRealtimeUs)), PowerUtil.convertUsToMs(batteryUsageStats.getBatteryTimeRemainingMs()),
false /* isBasedOnUsage */, false /* isBasedOnUsage */,
EstimateKt.AVERAGE_TIME_TO_DISCHARGE_UNKNOWN); EstimateKt.AVERAGE_TIME_TO_DISCHARGE_UNKNOWN);
} }
BatteryUtils.logRuntime(tag, "BatteryInfoLoader post query", startTime); BatteryUtils.logRuntime(tag, "BatteryInfoLoader post query", startTime);
batteryInfo = BatteryInfo.getBatteryInfo(mContext, batteryBroadcast, stats, batteryInfo = BatteryInfo.getBatteryInfo(mContext, batteryBroadcast,
estimate, elapsedRealtimeUs, false /* shortString */); batteryUsageStats, estimate, elapsedRealtimeUs, false /* shortString */);
BatteryUtils.logRuntime(tag, "BatteryInfoLoader.loadInBackground", startTime); BatteryUtils.logRuntime(tag, "BatteryInfoLoader.loadInBackground", startTime);
return batteryInfo; return batteryInfo;

View File

@@ -19,6 +19,8 @@ import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.IntentFilter; import android.content.IntentFilter;
import android.os.BatteryStats; import android.os.BatteryStats;
import android.os.BatteryStatsManager;
import android.os.BatteryUsageStats;
import android.os.SystemClock; import android.os.SystemClock;
import com.android.internal.os.BatteryStatsHelper; import com.android.internal.os.BatteryStatsHelper;
@@ -56,15 +58,17 @@ public class DebugEstimatesLoader extends AsyncLoaderCompat<List<BatteryInfo>> {
Intent batteryBroadcast = getContext().registerReceiver(null, Intent batteryBroadcast = getContext().registerReceiver(null,
new IntentFilter(Intent.ACTION_BATTERY_CHANGED)); new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
BatteryStats stats = mStatsHelper.getStats(); BatteryStats stats = mStatsHelper.getStats();
BatteryUsageStats batteryUsageStats =
context.getSystemService(BatteryStatsManager.class).getBatteryUsageStats();
BatteryInfo oldinfo = BatteryInfo.getBatteryInfoOld(getContext(), batteryBroadcast, BatteryInfo oldinfo = BatteryInfo.getBatteryInfoOld(getContext(), batteryBroadcast,
stats, elapsedRealtimeUs, false); batteryUsageStats, elapsedRealtimeUs, false);
Estimate estimate = powerUsageFeatureProvider.getEnhancedBatteryPrediction(context); Estimate estimate = powerUsageFeatureProvider.getEnhancedBatteryPrediction(context);
if (estimate == null) { if (estimate == null) {
estimate = new Estimate(0, false, EstimateKt.AVERAGE_TIME_TO_DISCHARGE_UNKNOWN); estimate = new Estimate(0, false, EstimateKt.AVERAGE_TIME_TO_DISCHARGE_UNKNOWN);
} }
BatteryInfo newInfo = BatteryInfo.getBatteryInfo(getContext(), batteryBroadcast, stats, BatteryInfo newInfo = BatteryInfo.getBatteryInfo(getContext(), batteryBroadcast,
batteryUsageStats,
estimate, elapsedRealtimeUs, false); estimate, elapsedRealtimeUs, false);
List<BatteryInfo> infos = new ArrayList<>(); List<BatteryInfo> infos = new ArrayList<>();

View File

@@ -141,6 +141,11 @@ public class PowerUsageAdvanced extends PowerUsageBase {
return controllers; return controllers;
} }
@Override
protected boolean isBatteryHistoryNeeded() {
return true;
}
@Override @Override
protected void refreshUi(@BatteryUpdateType int refreshType) { protected void refreshUi(@BatteryUpdateType int refreshType) {
final Context context = getContext(); final Context context = getContext();

View File

@@ -19,10 +19,12 @@ import static com.android.settings.fuelgauge.BatteryBroadcastReceiver.BatteryUpd
import android.app.Activity; import android.app.Activity;
import android.content.Context; import android.content.Context;
import android.os.BatteryUsageStats;
import android.os.Bundle; import android.os.Bundle;
import android.os.UserManager; import android.os.UserManager;
import android.view.Menu; import android.view.Menu;
import androidx.annotation.NonNull;
import androidx.annotation.VisibleForTesting; import androidx.annotation.VisibleForTesting;
import androidx.loader.app.LoaderManager; import androidx.loader.app.LoaderManager;
import androidx.loader.content.Loader; import androidx.loader.content.Loader;
@@ -40,12 +42,29 @@ public abstract class PowerUsageBase extends DashboardFragment {
static final int MENU_STATS_REFRESH = Menu.FIRST + 1; static final int MENU_STATS_REFRESH = Menu.FIRST + 1;
private static final String TAG = "PowerUsageBase"; private static final String TAG = "PowerUsageBase";
private static final String KEY_REFRESH_TYPE = "refresh_type"; private static final String KEY_REFRESH_TYPE = "refresh_type";
private static final String KEY_INCLUDE_HISTORY = "include_history";
private static final int LOADER_BATTERY_STATS_HELPER = 0;
private static final int LOADER_BATTERY_USAGE_STATS = 1;
protected BatteryStatsHelper mStatsHelper; protected BatteryStatsHelper mStatsHelper;
@VisibleForTesting
BatteryUsageStats mBatteryUsageStats;
protected UserManager mUm; protected UserManager mUm;
private BatteryBroadcastReceiver mBatteryBroadcastReceiver; private BatteryBroadcastReceiver mBatteryBroadcastReceiver;
protected boolean mIsBatteryPresent = true; protected boolean mIsBatteryPresent = true;
// TODO(b/180630447): switch to BatteryUsageStatsLoader and remove all references to
// BatteryStatsHelper and BatterySipper
@VisibleForTesting
final BatteryStatsHelperLoaderCallbacks mBatteryStatsHelperLoaderCallbacks =
new BatteryStatsHelperLoaderCallbacks();
@VisibleForTesting
final BatteryUsageStatsLoaderCallbacks mBatteryUsageStatsLoaderCallbacks =
new BatteryUsageStatsLoaderCallbacks();
@Override @Override
public void onAttach(Activity activity) { public void onAttach(Activity activity) {
super.onAttach(activity); super.onAttach(activity);
@@ -83,42 +102,73 @@ public abstract class PowerUsageBase extends DashboardFragment {
protected void restartBatteryStatsLoader(int refreshType) { protected void restartBatteryStatsLoader(int refreshType) {
final Bundle bundle = new Bundle(); final Bundle bundle = new Bundle();
bundle.putInt(KEY_REFRESH_TYPE, refreshType); bundle.putInt(KEY_REFRESH_TYPE, refreshType);
bundle.putBoolean(KEY_INCLUDE_HISTORY, isBatteryHistoryNeeded());
getLoaderManager().restartLoader(LOADER_BATTERY_STATS_HELPER, bundle,
mBatteryStatsHelperLoaderCallbacks);
getLoaderManager().restartLoader(LOADER_BATTERY_USAGE_STATS, bundle,
mBatteryUsageStatsLoaderCallbacks);
}
getLoaderManager().restartLoader(0, bundle, new PowerLoaderCallback()); private void onLoadFinished(@BatteryUpdateType int refreshType) {
// Wait for both loaders to finish before proceeding.
if (mStatsHelper == null || mBatteryUsageStats == null) {
return;
}
refreshUi(refreshType);
} }
protected abstract void refreshUi(@BatteryUpdateType int refreshType); protected abstract void refreshUi(@BatteryUpdateType int refreshType);
protected abstract boolean isBatteryHistoryNeeded();
protected void updatePreference(BatteryHistoryPreference historyPref) { protected void updatePreference(BatteryHistoryPreference historyPref) {
final long startTime = System.currentTimeMillis(); final long startTime = System.currentTimeMillis();
historyPref.setStats(mStatsHelper); historyPref.setBatteryUsageStats(mBatteryUsageStats);
BatteryUtils.logRuntime(TAG, "updatePreference", startTime); BatteryUtils.logRuntime(TAG, "updatePreference", startTime);
} }
/** private class BatteryStatsHelperLoaderCallbacks
* {@link android.app.LoaderManager.LoaderCallbacks} for {@link PowerUsageBase} to load implements LoaderManager.LoaderCallbacks<BatteryStatsHelper> {
* the {@link BatteryStatsHelper}
*/
public class PowerLoaderCallback implements LoaderManager.LoaderCallbacks<BatteryStatsHelper> {
private int mRefreshType; private int mRefreshType;
@Override @Override
public Loader<BatteryStatsHelper> onCreateLoader(int id, public Loader<BatteryStatsHelper> onCreateLoader(int id, Bundle args) {
Bundle args) {
mRefreshType = args.getInt(KEY_REFRESH_TYPE); mRefreshType = args.getInt(KEY_REFRESH_TYPE);
return new BatteryStatsHelperLoader(getContext()); return new BatteryStatsHelperLoader(getContext());
} }
@Override @Override
public void onLoadFinished(Loader<BatteryStatsHelper> loader, public void onLoadFinished(Loader<BatteryStatsHelper> loader,
BatteryStatsHelper statsHelper) { BatteryStatsHelper batteryHelper) {
mStatsHelper = statsHelper; mStatsHelper = batteryHelper;
refreshUi(mRefreshType); PowerUsageBase.this.onLoadFinished(mRefreshType);
} }
@Override @Override
public void onLoaderReset(Loader<BatteryStatsHelper> loader) { public void onLoaderReset(Loader<BatteryStatsHelper> loader) {
}
}
private class BatteryUsageStatsLoaderCallbacks
implements LoaderManager.LoaderCallbacks<BatteryUsageStats> {
private int mRefreshType;
@Override
@NonNull
public Loader<BatteryUsageStats> onCreateLoader(int id, Bundle args) {
mRefreshType = args.getInt(KEY_REFRESH_TYPE);
return new BatteryUsageStatsLoader(getContext(), args.getBoolean(KEY_INCLUDE_HISTORY));
}
@Override
public void onLoadFinished(Loader<BatteryUsageStats> loader,
BatteryUsageStats batteryUsageStats) {
mBatteryUsageStats = batteryUsageStats;
PowerUsageBase.this.onLoadFinished(mRefreshType);
}
@Override
public void onLoaderReset(Loader<BatteryUsageStats> loader) {
} }
} }
} }

View File

@@ -88,7 +88,7 @@ public class PowerUsageSummary extends PowerUsageBase implements
@Override @Override
public Loader<BatteryInfo> onCreateLoader(int i, Bundle bundle) { public Loader<BatteryInfo> onCreateLoader(int i, Bundle bundle) {
return new BatteryInfoLoader(getContext(), mStatsHelper); return new BatteryInfoLoader(getContext());
} }
@Override @Override
@@ -190,6 +190,11 @@ public class PowerUsageSummary extends PowerUsageBase implements
return R.string.help_url_battery; return R.string.help_url_battery;
} }
@Override
protected boolean isBatteryHistoryNeeded() {
return false;
}
protected void refreshUi(@BatteryUpdateType int refreshType) { protected void refreshUi(@BatteryUpdateType int refreshType) {
final Context context = getContext(); final Context context = getContext();
if (context == null) { if (context == null) {

View File

@@ -65,12 +65,11 @@ public class BatteryTipLoader extends AsyncLoaderCompat<List<BatteryTip>> {
} }
final List<BatteryTip> tips = new ArrayList<>(); final List<BatteryTip> tips = new ArrayList<>();
final BatteryTipPolicy policy = new BatteryTipPolicy(getContext()); final BatteryTipPolicy policy = new BatteryTipPolicy(getContext());
final BatteryInfo batteryInfo = mBatteryUtils.getBatteryInfo(mBatteryStatsHelper, TAG); final BatteryInfo batteryInfo = mBatteryUtils.getBatteryInfo(TAG);
final Context context = getContext(); final Context context = getContext();
tips.add(new LowBatteryDetector(context, policy, batteryInfo).detect()); tips.add(new LowBatteryDetector(context, policy, batteryInfo).detect());
tips.add(new HighUsageDetector(context, policy, mBatteryStatsHelper, tips.add(new HighUsageDetector(context, policy, mBatteryStatsHelper, batteryInfo).detect());
batteryInfo.discharging).detect());
tips.add(new SmartBatteryDetector(policy, context.getContentResolver()).detect()); tips.add(new SmartBatteryDetector(policy, context.getContentResolver()).detect());
tips.add(new EarlyWarningDetector(policy, context).detect()); tips.add(new EarlyWarningDetector(policy, context).detect());
tips.add(new BatteryDefenderDetector(batteryInfo).detect()); tips.add(new BatteryDefenderDetector(batteryInfo).detect());

View File

@@ -45,6 +45,7 @@ import java.util.concurrent.TimeUnit;
public class HighUsageDetector implements BatteryTipDetector { public class HighUsageDetector implements BatteryTipDetector {
private BatteryTipPolicy mPolicy; private BatteryTipPolicy mPolicy;
private BatteryStatsHelper mBatteryStatsHelper; private BatteryStatsHelper mBatteryStatsHelper;
private final BatteryInfo mBatteryInfo;
private List<AppInfo> mHighUsageAppList; private List<AppInfo> mHighUsageAppList;
@VisibleForTesting @VisibleForTesting
HighUsageDataParser mDataParser; HighUsageDataParser mDataParser;
@@ -54,14 +55,15 @@ public class HighUsageDetector implements BatteryTipDetector {
boolean mDischarging; boolean mDischarging;
public HighUsageDetector(Context context, BatteryTipPolicy policy, public HighUsageDetector(Context context, BatteryTipPolicy policy,
BatteryStatsHelper batteryStatsHelper, boolean discharging) { BatteryStatsHelper batteryStatsHelper, BatteryInfo batteryInfo) {
mPolicy = policy; mPolicy = policy;
mBatteryStatsHelper = batteryStatsHelper; mBatteryStatsHelper = batteryStatsHelper;
mBatteryInfo = batteryInfo;
mHighUsageAppList = new ArrayList<>(); mHighUsageAppList = new ArrayList<>();
mBatteryUtils = BatteryUtils.getInstance(context); mBatteryUtils = BatteryUtils.getInstance(context);
mDataParser = new HighUsageDataParser(mPolicy.highUsagePeriodMs, mDataParser = new HighUsageDataParser(mPolicy.highUsagePeriodMs,
mPolicy.highUsageBatteryDraining); mPolicy.highUsageBatteryDraining);
mDischarging = discharging; mDischarging = batteryInfo.discharging;
} }
@Override @Override
@@ -115,6 +117,6 @@ public class HighUsageDetector implements BatteryTipDetector {
@VisibleForTesting @VisibleForTesting
void parseBatteryData() { void parseBatteryData() {
BatteryInfo.parse(mBatteryStatsHelper.getStats(), mDataParser); mBatteryInfo.parseBatteryHistory(mDataParser);
} }
} }

View File

@@ -19,23 +19,23 @@ package com.android.settings.fuelgauge;
import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.spy; import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.os.BatteryStats; import android.os.BatteryStatsManager;
import android.os.BatteryUsageStats;
import android.os.BatteryUsageStatsQuery;
import com.android.internal.os.BatteryStatsHelper;
import com.android.settings.testutils.BatteryTestUtils; import com.android.settings.testutils.BatteryTestUtils;
import com.android.settings.testutils.FakeFeatureFactory; import com.android.settings.testutils.FakeFeatureFactory;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.mockito.Answers;
import org.mockito.Mock; import org.mockito.Mock;
import org.mockito.MockitoAnnotations; import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner; import org.robolectric.RobolectricTestRunner;
@@ -46,10 +46,10 @@ public class BatteryInfoLoaderTest {
private static final long TEST_TIME_REMAINING = 1000L; private static final long TEST_TIME_REMAINING = 1000L;
@Mock (answer = Answers.RETURNS_DEEP_STUBS) @Mock
private BatteryStatsHelper mHelper; private BatteryStatsManager mBatteryStatsManager;
@Mock (answer = Answers.RETURNS_DEEP_STUBS) @Mock
private BatteryStats mStats; private BatteryUsageStats mBatteryUsageStats;
private Context mContext; private Context mContext;
@@ -60,8 +60,11 @@ public class BatteryInfoLoaderTest {
FakeFeatureFactory.setupForTest().getPowerUsageFeatureProvider(mContext); FakeFeatureFactory.setupForTest().getPowerUsageFeatureProvider(mContext);
doReturn(mContext).when(mContext).getApplicationContext(); doReturn(mContext).when(mContext).getApplicationContext();
when(mStats.computeBatteryTimeRemaining(anyLong())).thenReturn(TEST_TIME_REMAINING); when(mContext.getSystemService(eq(Context.BATTERY_STATS_SERVICE)))
doReturn(mStats).when(mHelper).getStats(); .thenReturn(mBatteryStatsManager);
when(mBatteryUsageStats.getBatteryTimeRemainingMs()).thenReturn(TEST_TIME_REMAINING);
when(mBatteryStatsManager.getBatteryUsageStats(any(BatteryUsageStatsQuery.class)))
.thenReturn(mBatteryUsageStats);
final Intent dischargingBatteryBroadcast = BatteryTestUtils.getDischargingIntent(); final Intent dischargingBatteryBroadcast = BatteryTestUtils.getDischargingIntent();
doReturn(dischargingBatteryBroadcast).when(mContext).registerReceiver(any(), any()); doReturn(dischargingBatteryBroadcast).when(mContext).registerReceiver(any(), any());
@@ -69,8 +72,8 @@ public class BatteryInfoLoaderTest {
@Test @Test
public void test_loadInBackground_dischargingOldEstimate_dischargingLabelNotNull() { public void test_loadInBackground_dischargingOldEstimate_dischargingLabelNotNull() {
BatteryInfoLoader loader = new BatteryInfoLoader(mContext, mHelper); BatteryInfoLoader loader = new BatteryInfoLoader(mContext);
loader.batteryUtils = new BatteryUtils(mContext); loader.mBatteryUtils = new BatteryUtils(mContext);
BatteryInfo info = loader.loadInBackground(); BatteryInfo info = loader.loadInBackground();

View File

@@ -34,9 +34,11 @@ import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.os.BatteryManager; import android.os.BatteryManager;
import android.os.BatteryStats; import android.os.BatteryStats;
import android.os.BatteryUsageStats;
import android.os.SystemClock; import android.os.SystemClock;
import android.util.SparseIntArray; import android.util.SparseIntArray;
import com.android.internal.os.BatteryStatsHistoryIterator;
import com.android.settings.testutils.BatteryTestUtils; import com.android.settings.testutils.BatteryTestUtils;
import com.android.settings.testutils.FakeFeatureFactory; import com.android.settings.testutils.FakeFeatureFactory;
import com.android.settings.widget.UsageView; import com.android.settings.widget.UsageView;
@@ -46,7 +48,6 @@ import com.android.settingslib.fuelgauge.Estimate;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.mockito.Answers;
import org.mockito.ArgumentCaptor; import org.mockito.ArgumentCaptor;
import org.mockito.Mock; import org.mockito.Mock;
import org.mockito.MockitoAnnotations; import org.mockito.MockitoAnnotations;
@@ -83,9 +84,8 @@ public class BatteryInfoTest {
private Intent mChargingBatteryBroadcast; private Intent mChargingBatteryBroadcast;
private Context mContext; private Context mContext;
private FakeFeatureFactory mFeatureFactory; private FakeFeatureFactory mFeatureFactory;
@Mock
@Mock(answer = Answers.RETURNS_DEEP_STUBS) private BatteryUsageStats mBatteryUsageStats;
private BatteryStats mBatteryStats;
@Before @Before
public void setUp() { public void setUp() {
@@ -100,9 +100,10 @@ public class BatteryInfoTest {
@Test @Test
public void testGetBatteryInfo_hasStatusLabel() { public void testGetBatteryInfo_hasStatusLabel() {
doReturn(REMAINING_TIME_NULL).when(mBatteryStats).computeBatteryTimeRemaining(anyLong()); doReturn(REMAINING_TIME_NULL).when(mBatteryUsageStats).getBatteryTimeRemainingMs();
BatteryInfo info = BatteryInfo.getBatteryInfoOld(mContext, BatteryInfo info = BatteryInfo.getBatteryInfoOld(mContext,
mDisChargingBatteryBroadcast, mBatteryStats, SystemClock.elapsedRealtime() * 1000, mDisChargingBatteryBroadcast, mBatteryUsageStats,
SystemClock.elapsedRealtime() * 1000,
true /* shortString */); true /* shortString */);
assertThat(info.statusLabel).isEqualTo(STATUS_NOT_CHARGING); assertThat(info.statusLabel).isEqualTo(STATUS_NOT_CHARGING);
@@ -110,28 +111,28 @@ public class BatteryInfoTest {
@Test @Test
public void testGetBatteryInfo_doNotShowChargingMethod_hasRemainingTime() { public void testGetBatteryInfo_doNotShowChargingMethod_hasRemainingTime() {
doReturn(REMAINING_TIME).when(mBatteryStats).computeChargeTimeRemaining(anyLong()); doReturn(REMAINING_TIME).when(mBatteryUsageStats).getChargeTimeRemainingMs();
BatteryInfo info = BatteryInfo.getBatteryInfoOld(mContext, mChargingBatteryBroadcast, BatteryInfo info = BatteryInfo.getBatteryInfoOld(mContext, mChargingBatteryBroadcast,
mBatteryStats, SystemClock.elapsedRealtime() * 1000, false /* shortString */); mBatteryUsageStats, SystemClock.elapsedRealtime() * 1000, false /* shortString */);
assertThat(info.chargeLabel.toString()).isEqualTo(STATUS_CHARGING_TIME); assertThat(info.chargeLabel.toString()).isEqualTo(STATUS_CHARGING_TIME);
} }
@Test @Test
public void testGetBatteryInfo_doNotShowChargingMethod_noRemainingTime() { public void testGetBatteryInfo_doNotShowChargingMethod_noRemainingTime() {
doReturn(REMAINING_TIME_NULL).when(mBatteryStats).computeChargeTimeRemaining(anyLong()); doReturn(REMAINING_TIME_NULL).when(mBatteryUsageStats).getChargeTimeRemainingMs();
BatteryInfo info = BatteryInfo.getBatteryInfoOld(mContext, mChargingBatteryBroadcast, BatteryInfo info = BatteryInfo.getBatteryInfoOld(mContext, mChargingBatteryBroadcast,
mBatteryStats, SystemClock.elapsedRealtime() * 1000, false /* shortString */); mBatteryUsageStats, SystemClock.elapsedRealtime() * 1000, false /* shortString */);
assertThat(info.chargeLabel.toString()).isEqualTo(STATUS_CHARGING_NO_TIME); assertThat(info.chargeLabel.toString()).isEqualTo(STATUS_CHARGING_NO_TIME);
} }
@Test @Test
public void testGetBatteryInfo_pluggedInUsingShortString_usesCorrectData() { public void testGetBatteryInfo_pluggedInUsingShortString_usesCorrectData() {
doReturn(TEST_CHARGE_TIME_REMAINING).when(mBatteryStats).computeChargeTimeRemaining( doReturn(TEST_CHARGE_TIME_REMAINING / 1000)
anyLong()); .when(mBatteryUsageStats).getChargeTimeRemainingMs();
BatteryInfo info = BatteryInfo.getBatteryInfoOld(mContext, mChargingBatteryBroadcast, BatteryInfo info = BatteryInfo.getBatteryInfoOld(mContext, mChargingBatteryBroadcast,
mBatteryStats, SystemClock.elapsedRealtime() * 1000, true /* shortString */); mBatteryUsageStats, SystemClock.elapsedRealtime() * 1000, true /* shortString */);
assertThat(info.discharging).isEqualTo(false); assertThat(info.discharging).isEqualTo(false);
assertThat(info.chargeLabel.toString()).isEqualTo("50% - 1 min until charged"); assertThat(info.chargeLabel.toString()).isEqualTo("50% - 1 min until charged");
@@ -143,10 +144,10 @@ public class BatteryInfoTest {
true /* isBasedOnUsage */, true /* isBasedOnUsage */,
1000 /* averageDischargeTime */); 1000 /* averageDischargeTime */);
BatteryInfo info = BatteryInfo.getBatteryInfo(mContext, mDisChargingBatteryBroadcast, BatteryInfo info = BatteryInfo.getBatteryInfo(mContext, mDisChargingBatteryBroadcast,
mBatteryStats, estimate, SystemClock.elapsedRealtime() * 1000, mBatteryUsageStats, estimate, SystemClock.elapsedRealtime() * 1000,
false /* shortString */); false /* shortString */);
BatteryInfo info2 = BatteryInfo.getBatteryInfo(mContext, mDisChargingBatteryBroadcast, BatteryInfo info2 = BatteryInfo.getBatteryInfo(mContext, mDisChargingBatteryBroadcast,
mBatteryStats, estimate, SystemClock.elapsedRealtime() * 1000, mBatteryUsageStats, estimate, SystemClock.elapsedRealtime() * 1000,
true /* shortString */); true /* shortString */);
// We only add special mention for the long string // We only add special mention for the long string
@@ -163,10 +164,10 @@ public class BatteryInfoTest {
true /* isBasedOnUsage */, true /* isBasedOnUsage */,
1000 /* averageDischargeTime */); 1000 /* averageDischargeTime */);
BatteryInfo info = BatteryInfo.getBatteryInfo(mContext, mDisChargingBatteryBroadcast, BatteryInfo info = BatteryInfo.getBatteryInfo(mContext, mDisChargingBatteryBroadcast,
mBatteryStats, estimate, SystemClock.elapsedRealtime() * 1000, mBatteryUsageStats, estimate, SystemClock.elapsedRealtime() * 1000,
false /* shortString */); false /* shortString */);
BatteryInfo info2 = BatteryInfo.getBatteryInfo(mContext, mDisChargingBatteryBroadcast, BatteryInfo info2 = BatteryInfo.getBatteryInfo(mContext, mDisChargingBatteryBroadcast,
mBatteryStats, estimate, SystemClock.elapsedRealtime() * 1000, mBatteryUsageStats, estimate, SystemClock.elapsedRealtime() * 1000,
true /* shortString */); true /* shortString */);
// These should be identical in either case // These should be identical in either case
@@ -183,7 +184,7 @@ public class BatteryInfoTest {
true /* isBasedOnUsage */, true /* isBasedOnUsage */,
1000 /* averageDischargeTime */); 1000 /* averageDischargeTime */);
BatteryInfo info = BatteryInfo.getBatteryInfo(mContext, mDisChargingBatteryBroadcast, BatteryInfo info = BatteryInfo.getBatteryInfo(mContext, mDisChargingBatteryBroadcast,
mBatteryStats, estimate, SystemClock.elapsedRealtime() * 1000, mBatteryUsageStats, estimate, SystemClock.elapsedRealtime() * 1000,
false /* shortString */); false /* shortString */);
assertThat(info.suggestionLabel).doesNotContain(BATTERY_RUN_OUT_PREFIX); assertThat(info.suggestionLabel).doesNotContain(BATTERY_RUN_OUT_PREFIX);
@@ -196,7 +197,7 @@ public class BatteryInfoTest {
true /* isBasedOnUsage */, true /* isBasedOnUsage */,
1000 /* averageDischargeTime */); 1000 /* averageDischargeTime */);
BatteryInfo info = BatteryInfo.getBatteryInfo(mContext, mDisChargingBatteryBroadcast, BatteryInfo info = BatteryInfo.getBatteryInfo(mContext, mDisChargingBatteryBroadcast,
mBatteryStats, estimate, SystemClock.elapsedRealtime() * 1000, mBatteryUsageStats, estimate, SystemClock.elapsedRealtime() * 1000,
false /* shortString */); false /* shortString */);
// Check that strings are showing less than 15 minutes remaining regardless of exact time. // Check that strings are showing less than 15 minutes remaining regardless of exact time.
@@ -211,10 +212,10 @@ public class BatteryInfoTest {
@Test @Test
public void testGetBatteryInfo_basedOnUsageFalse_usesDefaultString() { public void testGetBatteryInfo_basedOnUsageFalse_usesDefaultString() {
BatteryInfo info = BatteryInfo.getBatteryInfo(mContext, mDisChargingBatteryBroadcast, BatteryInfo info = BatteryInfo.getBatteryInfo(mContext, mDisChargingBatteryBroadcast,
mBatteryStats, MOCK_ESTIMATE, SystemClock.elapsedRealtime() * 1000, mBatteryUsageStats, MOCK_ESTIMATE, SystemClock.elapsedRealtime() * 1000,
false /* shortString */); false /* shortString */);
BatteryInfo info2 = BatteryInfo.getBatteryInfo(mContext, mDisChargingBatteryBroadcast, BatteryInfo info2 = BatteryInfo.getBatteryInfo(mContext, mDisChargingBatteryBroadcast,
mBatteryStats, MOCK_ESTIMATE, SystemClock.elapsedRealtime() * 1000, mBatteryUsageStats, MOCK_ESTIMATE, SystemClock.elapsedRealtime() * 1000,
true /* shortString */); true /* shortString */);
assertThat(info.remainingLabel.toString()).doesNotContain(ENHANCED_STRING_SUFFIX); assertThat(info.remainingLabel.toString()).doesNotContain(ENHANCED_STRING_SUFFIX);
@@ -223,12 +224,11 @@ public class BatteryInfoTest {
@Test @Test
public void testGetBatteryInfo_charging_usesChargeTime() { public void testGetBatteryInfo_charging_usesChargeTime() {
doReturn(TEST_CHARGE_TIME_REMAINING) doReturn(TEST_CHARGE_TIME_REMAINING / 1000)
.when(mBatteryStats) .when(mBatteryUsageStats).getChargeTimeRemainingMs();
.computeChargeTimeRemaining(anyLong());
BatteryInfo info = BatteryInfo.getBatteryInfo(mContext, mChargingBatteryBroadcast, BatteryInfo info = BatteryInfo.getBatteryInfo(mContext, mChargingBatteryBroadcast,
mBatteryStats, MOCK_ESTIMATE, SystemClock.elapsedRealtime() * 1000, mBatteryUsageStats, MOCK_ESTIMATE, SystemClock.elapsedRealtime() * 1000,
false /* shortString */); false /* shortString */);
assertThat(info.remainingTimeUs).isEqualTo(TEST_CHARGE_TIME_REMAINING); assertThat(info.remainingTimeUs).isEqualTo(TEST_CHARGE_TIME_REMAINING);
assertThat(info.remainingLabel.toString()) assertThat(info.remainingLabel.toString())
@@ -240,7 +240,7 @@ public class BatteryInfoTest {
mChargingBatteryBroadcast.putExtra(BatteryManager.EXTRA_LEVEL, 100); mChargingBatteryBroadcast.putExtra(BatteryManager.EXTRA_LEVEL, 100);
BatteryInfo info = BatteryInfo.getBatteryInfo(mContext, mChargingBatteryBroadcast, BatteryInfo info = BatteryInfo.getBatteryInfo(mContext, mChargingBatteryBroadcast,
mBatteryStats, MOCK_ESTIMATE, SystemClock.elapsedRealtime() * 1000, mBatteryUsageStats, MOCK_ESTIMATE, SystemClock.elapsedRealtime() * 1000,
false /* shortString */); false /* shortString */);
assertThat(info.chargeLabel).isEqualTo("100%"); assertThat(info.chargeLabel).isEqualTo("100%");
@@ -249,13 +249,13 @@ public class BatteryInfoTest {
@Test @Test
public void testGetBatteryInfo_chargingWithOverheated_updateChargeLabel() { public void testGetBatteryInfo_chargingWithOverheated_updateChargeLabel() {
doReturn(TEST_CHARGE_TIME_REMAINING) doReturn(TEST_CHARGE_TIME_REMAINING)
.when(mBatteryStats) .when(mBatteryUsageStats)
.computeChargeTimeRemaining(anyLong()); .getChargeTimeRemainingMs();
mChargingBatteryBroadcast mChargingBatteryBroadcast
.putExtra(BatteryManager.EXTRA_HEALTH, BatteryManager.BATTERY_HEALTH_OVERHEAT); .putExtra(BatteryManager.EXTRA_HEALTH, BatteryManager.BATTERY_HEALTH_OVERHEAT);
BatteryInfo info = BatteryInfo.getBatteryInfo(mContext, mChargingBatteryBroadcast, BatteryInfo info = BatteryInfo.getBatteryInfo(mContext, mChargingBatteryBroadcast,
mBatteryStats, MOCK_ESTIMATE, SystemClock.elapsedRealtime() * 1000, mBatteryUsageStats, MOCK_ESTIMATE, SystemClock.elapsedRealtime() * 1000,
false /* shortString */); false /* shortString */);
assertThat(info.isOverheated).isTrue(); assertThat(info.isOverheated).isTrue();
@@ -264,28 +264,29 @@ public class BatteryInfoTest {
// Make our battery stats return a sequence of battery events. // Make our battery stats return a sequence of battery events.
private void mockBatteryStatsHistory() { private void mockBatteryStatsHistory() {
// Mock out new data every time start...Locked is called. // Mock out new data every time iterateBatteryStatsHistory is called.
doAnswer(invocation -> { doAnswer(invocation -> {
doAnswer(new Answer() { BatteryStatsHistoryIterator iterator = mock(BatteryStatsHistoryIterator.class);
private int count = 0; doAnswer(new Answer<Boolean>() {
private long[] times = {1000, 1500, 2000}; private int mCount = 0;
private byte[] levels = {99, 98, 97}; private final long[] mTimes = {1000, 1500, 2000};
private final byte[] mLevels = {99, 98, 97};
@Override @Override
public Object answer(InvocationOnMock invocation) throws Throwable { public Boolean answer(InvocationOnMock invocation) throws Throwable {
if (count == times.length) { if (mCount == mTimes.length) {
return false; return false;
} }
BatteryStats.HistoryItem record = invocation.getArgument(0); BatteryStats.HistoryItem record = invocation.getArgument(0);
record.cmd = BatteryStats.HistoryItem.CMD_UPDATE; record.cmd = BatteryStats.HistoryItem.CMD_UPDATE;
record.time = times[count]; record.time = mTimes[mCount];
record.batteryLevel = levels[count]; record.batteryLevel = mLevels[mCount];
count++; mCount++;
return true; return true;
} }
}).when(mBatteryStats).getNextHistoryLocked(any(BatteryStats.HistoryItem.class)); }).when(iterator).next(any(BatteryStats.HistoryItem.class));
return true; return iterator;
}).when(mBatteryStats).startIteratingHistoryLocked(); }).when(mBatteryUsageStats).iterateBatteryStatsHistory();
} }
private void assertOnlyHistory(BatteryInfo info) { private void assertOnlyHistory(BatteryInfo info) {
@@ -337,9 +338,9 @@ public class BatteryInfoTest {
private BatteryInfo getBatteryInfo(boolean charging, boolean enhanced, boolean estimate) { private BatteryInfo getBatteryInfo(boolean charging, boolean enhanced, boolean estimate) {
if (charging && estimate) { if (charging && estimate) {
doReturn(1000L).when(mBatteryStats).computeChargeTimeRemaining(anyLong()); doReturn(1000L).when(mBatteryUsageStats).getChargeTimeRemainingMs();
} else { } else {
doReturn(0L).when(mBatteryStats).computeChargeTimeRemaining(anyLong()); doReturn(0L).when(mBatteryUsageStats).getChargeTimeRemainingMs();
} }
Estimate batteryEstimate = new Estimate( Estimate batteryEstimate = new Estimate(
estimate ? 1000 : 0, estimate ? 1000 : 0,
@@ -347,7 +348,7 @@ public class BatteryInfoTest {
1000 /* averageDischargeTime */); 1000 /* averageDischargeTime */);
BatteryInfo info = BatteryInfo.getBatteryInfo(mContext, BatteryInfo info = BatteryInfo.getBatteryInfo(mContext,
charging ? mChargingBatteryBroadcast : mDisChargingBatteryBroadcast, charging ? mChargingBatteryBroadcast : mDisChargingBatteryBroadcast,
mBatteryStats, batteryEstimate, SystemClock.elapsedRealtime() * 1000, false); mBatteryUsageStats, batteryEstimate, SystemClock.elapsedRealtime() * 1000, false);
doReturn(enhanced).when(mFeatureFactory.powerUsageFeatureProvider) doReturn(enhanced).when(mFeatureFactory.powerUsageFeatureProvider)
.isEnhancedBatteryPredictionEnabled(mContext); .isEnhancedBatteryPredictionEnabled(mContext);
return info; return info;

View File

@@ -48,6 +48,7 @@ import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo; import android.content.pm.ResolveInfo;
import android.os.BatteryStats; import android.os.BatteryStats;
import android.os.BatteryStatsManager;
import android.os.Build; import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
import android.os.Process; import android.os.Process;
@@ -157,6 +158,8 @@ public class BatteryUtilsTest {
private ApplicationInfo mApplicationInfo; private ApplicationInfo mApplicationInfo;
@Mock(answer = Answers.RETURNS_DEEP_STUBS) @Mock(answer = Answers.RETURNS_DEEP_STUBS)
private BatteryStatsHelper mBatteryStatsHelper; private BatteryStatsHelper mBatteryStatsHelper;
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
private BatteryStatsManager mBatteryStatsManager;
@Mock @Mock
private ApplicationInfo mHighApplicationInfo; private ApplicationInfo mHighApplicationInfo;
@Mock @Mock
@@ -228,6 +231,8 @@ public class BatteryUtilsTest {
mContext = spy(RuntimeEnvironment.application); mContext = spy(RuntimeEnvironment.application);
doReturn(mPackageManager).when(mContext).getPackageManager(); doReturn(mPackageManager).when(mContext).getPackageManager();
doReturn(mAppOpsManager).when(mContext).getSystemService(Context.APP_OPS_SERVICE); doReturn(mAppOpsManager).when(mContext).getSystemService(Context.APP_OPS_SERVICE);
doReturn(mBatteryStatsManager).when(mContext)
.getSystemService(Context.BATTERY_STATS_SERVICE);
mBatteryUtils = spy(new BatteryUtils(mContext)); mBatteryUtils = spy(new BatteryUtils(mContext));
mBatteryUtils.mPowerUsageFeatureProvider = mProvider; mBatteryUtils.mPowerUsageFeatureProvider = mProvider;
doReturn(0L).when(mBatteryUtils) doReturn(0L).when(mBatteryUtils)
@@ -741,7 +746,7 @@ public class BatteryUtilsTest {
any(IntentFilter.class))).thenReturn(new Intent()); any(IntentFilter.class))).thenReturn(new Intent());
//Should not crash //Should not crash
assertThat(mBatteryUtils.getBatteryInfo(mBatteryStatsHelper, TAG)).isNotNull(); assertThat(mBatteryUtils.getBatteryInfo(TAG)).isNotNull();
} }
@Test @Test

View File

@@ -74,6 +74,11 @@ public class PowerUsageBaseTest {
return 0; return 0;
} }
@Override
protected boolean isBatteryHistoryNeeded() {
return false;
}
@Override @Override
protected void refreshUi(int refreshType) { protected void refreshUi(int refreshType) {
// Do nothing // Do nothing

View File

@@ -77,7 +77,7 @@ public class BatteryTipLoaderTest {
doReturn(mContext).when(mContext).getApplicationContext(); doReturn(mContext).when(mContext).getApplicationContext();
doReturn(mPowerManager).when(mContext).getSystemService(Context.POWER_SERVICE); doReturn(mPowerManager).when(mContext).getSystemService(Context.POWER_SERVICE);
doReturn(mIntent).when(mContext).registerReceiver(any(), any()); doReturn(mIntent).when(mContext).registerReceiver(any(), any());
doReturn(mBatteryInfo).when(mBatteryUtils).getBatteryInfo(any(), any()); doReturn(mBatteryInfo).when(mBatteryUtils).getBatteryInfo(any());
mBatteryTipLoader = new BatteryTipLoader(mContext, mBatteryStatsHelper); mBatteryTipLoader = new BatteryTipLoader(mContext, mBatteryStatsHelper);
mBatteryTipLoader.mBatteryUtils = mBatteryUtils; mBatteryTipLoader.mBatteryUtils = mBatteryUtils;
} }

View File

@@ -18,7 +18,9 @@ package com.android.settings.fuelgauge.batterytip.detectors;
import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
@@ -26,8 +28,11 @@ import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
import android.content.Context; import android.content.Context;
import android.content.Intent;
import android.os.BatteryStats; import android.os.BatteryStats;
import android.text.format.DateUtils; import android.os.BatteryStatsManager;
import android.os.BatteryUsageStats;
import android.os.BatteryUsageStatsQuery;
import com.android.internal.os.BatterySipper; import com.android.internal.os.BatterySipper;
import com.android.internal.os.BatteryStatsHelper; import com.android.internal.os.BatteryStatsHelper;
@@ -53,6 +58,8 @@ import java.util.List;
@RunWith(RobolectricTestRunner.class) @RunWith(RobolectricTestRunner.class)
public class HighUsageDetectorTest { public class HighUsageDetectorTest {
private static final String TAG = "HighUsageDetectorTest";
private static final int UID_HIGH = 123; private static final int UID_HIGH = 123;
private static final int UID_LOW = 345; private static final int UID_LOW = 345;
private static final double POWER_HIGH = 20000; private static final double POWER_HIGH = 20000;
@@ -68,6 +75,10 @@ public class HighUsageDetectorTest {
private BatterySipper mSystemBatterySipper; private BatterySipper mSystemBatterySipper;
@Mock @Mock
private HighUsageDataParser mDataParser; private HighUsageDataParser mDataParser;
@Mock
private BatteryUsageStats mBatteryUsageStats;
@Mock
private BatteryStatsManager mBatteryStatsManager;
private AppInfo mHighAppInfo; private AppInfo mHighAppInfo;
private AppInfo mLowAppInfo; private AppInfo mLowAppInfo;
@@ -80,11 +91,19 @@ public class HighUsageDetectorTest {
public void setUp() { public void setUp() {
MockitoAnnotations.initMocks(this); MockitoAnnotations.initMocks(this);
mContext = RuntimeEnvironment.application; mContext = spy(RuntimeEnvironment.application);
mPolicy = spy(new BatteryTipPolicy(mContext)); mPolicy = spy(new BatteryTipPolicy(mContext));
mBatteryUtils = spy(BatteryUtils.getInstance(mContext)); mBatteryUtils = spy(new BatteryUtils(mContext));
when(mContext.getSystemService(eq(Context.BATTERY_STATS_SERVICE)))
.thenReturn(mBatteryStatsManager);
when(mBatteryStatsManager.getBatteryUsageStats(any(BatteryUsageStatsQuery.class)))
.thenReturn(mBatteryUsageStats);
mContext.sendStickyBroadcast(new Intent(Intent.ACTION_BATTERY_CHANGED));
mHighUsageDetector = spy(new HighUsageDetector(mContext, mPolicy, mBatteryStatsHelper, mHighUsageDetector = spy(new HighUsageDetector(mContext, mPolicy, mBatteryStatsHelper,
true /* mDischarging */)); mBatteryUtils.getBatteryInfo(TAG)));
mHighUsageDetector.mBatteryUtils = mBatteryUtils; mHighUsageDetector.mBatteryUtils = mBatteryUtils;
mHighUsageDetector.mDataParser = mDataParser; mHighUsageDetector.mDataParser = mDataParser;
doNothing().when(mHighUsageDetector).parseBatteryData(); doNothing().when(mHighUsageDetector).parseBatteryData();