Make BatterySettings Asynchronous and use enhanced estimate

this CL changes BatteryInfo methods to all use the async style
callback approach it had for one of the methods. Non-async methods
are now annotated to only be used in worker threads. BatteryInfo
can now be obtained via callback by calling one of the async
methods. Alternatively if there is a worker thread available
the synchronous methods similar to the old ones can be used.

The callback methods have all been changed so that they cascade to a
async method that takes all the required info as paremeters. This
will minimize the amount of churn in files that currently use
BatteryInfo.

A new loader was created that can be used to get BatteryInfo in
places that wish to get it. This loader is used in
PowerUsageSummary to get the BatteryInfo.

Test: Robotests
Bug: 38399275
Bug: 38398949
Bug: 38399654
Change-Id: Ic5a82d8ca4c85fad1b883226327ec083badf861d
This commit is contained in:
Salvador Martinez
2017-05-30 11:18:09 -07:00
parent 31d5b3de6f
commit 9cfa7720f4
9 changed files with 237 additions and 191 deletions

View File

@@ -506,81 +506,82 @@ public class BatteryHistoryChart extends View {
mMaxPercentLabelString = Utils.formatPercentage(100); mMaxPercentLabelString = Utils.formatPercentage(100);
mMinPercentLabelString = Utils.formatPercentage(0); mMinPercentLabelString = Utils.formatPercentage(0);
mInfo = BatteryInfo.getBatteryInfo(getContext(), mBatteryBroadcast, mStats, BatteryInfo.getBatteryInfo(getContext(), info -> {
elapsedRealtimeUs); mInfo = info;
mDrainString = ""; mDrainString = "";
mChargeDurationString = ""; mChargeDurationString = "";
setContentDescription(mInfo.chargeLabelString); setContentDescription(mInfo.chargeLabelString);
int pos = 0; int pos = 0;
int lastInteresting = 0; int lastInteresting = 0;
byte lastLevel = -1; byte lastLevel = -1;
mBatLow = 0; mBatLow = 0;
mBatHigh = 100; mBatHigh = 100;
mStartWallTime = 0; mStartWallTime = 0;
mEndDataWallTime = 0; mEndDataWallTime = 0;
mEndWallTime = 0; mEndWallTime = 0;
mHistStart = 0; mHistStart = 0;
mHistEnd = 0; mHistEnd = 0;
long lastWallTime = 0; long lastWallTime = 0;
long lastRealtime = 0; long lastRealtime = 0;
int aggrStates = 0; int aggrStates = 0;
int aggrStates2 = 0; int aggrStates2 = 0;
boolean first = true; boolean first = true;
if (stats.startIteratingHistoryLocked()) { if (stats.startIteratingHistoryLocked()) {
final HistoryItem rec = new HistoryItem(); final HistoryItem rec = new HistoryItem();
while (stats.getNextHistoryLocked(rec)) { while (stats.getNextHistoryLocked(rec)) {
pos++; pos++;
if (first) { if (first) {
first = false; first = false;
mHistStart = rec.time; mHistStart = 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 < (mHistStart+(5*60*1000L))) {
mStartWallTime = 0;
} }
lastWallTime = rec.currentTime; if (rec.cmd == HistoryItem.CMD_CURRENT_TIME
lastRealtime = rec.time; || rec.cmd == HistoryItem.CMD_RESET) {
if (mStartWallTime == 0) { // If there is a ridiculously large jump in time, then we won't be
mStartWallTime = lastWallTime - (lastRealtime-mHistStart); // 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 < (mHistStart+(5*60*1000L))) {
mStartWallTime = 0;
}
lastWallTime = rec.currentTime;
lastRealtime = rec.time;
if (mStartWallTime == 0) {
mStartWallTime = lastWallTime - (lastRealtime-mHistStart);
}
} }
} if (rec.isDeltaData()) {
if (rec.isDeltaData()) { if (rec.batteryLevel != lastLevel || pos == 1) {
if (rec.batteryLevel != lastLevel || pos == 1) { lastLevel = rec.batteryLevel;
lastLevel = rec.batteryLevel; }
lastInteresting = pos;
mHistDataEnd = rec.time;
aggrStates |= rec.states;
aggrStates2 |= rec.states2;
} }
lastInteresting = pos;
mHistDataEnd = rec.time;
aggrStates |= rec.states;
aggrStates2 |= rec.states2;
} }
} }
} mHistEnd = mHistDataEnd + (mInfo.remainingTimeUs/1000);
mHistEnd = mHistDataEnd + (mInfo.remainingTimeUs/1000); mEndDataWallTime = lastWallTime + mHistDataEnd - lastRealtime;
mEndDataWallTime = lastWallTime + mHistDataEnd - lastRealtime; mEndWallTime = mEndDataWallTime + (mInfo.remainingTimeUs/1000);
mEndWallTime = mEndDataWallTime + (mInfo.remainingTimeUs/1000); mNumHist = lastInteresting;
mNumHist = lastInteresting; mHaveGps = (aggrStates&HistoryItem.STATE_GPS_ON_FLAG) != 0;
mHaveGps = (aggrStates&HistoryItem.STATE_GPS_ON_FLAG) != 0; mHaveFlashlight = (aggrStates2&HistoryItem.STATE2_FLASHLIGHT_FLAG) != 0;
mHaveFlashlight = (aggrStates2&HistoryItem.STATE2_FLASHLIGHT_FLAG) != 0; mHaveCamera = (aggrStates2&HistoryItem.STATE2_CAMERA_FLAG) != 0;
mHaveCamera = (aggrStates2&HistoryItem.STATE2_CAMERA_FLAG) != 0; mHaveWifi = (aggrStates2&HistoryItem.STATE2_WIFI_RUNNING_FLAG) != 0
mHaveWifi = (aggrStates2&HistoryItem.STATE2_WIFI_RUNNING_FLAG) != 0 || (aggrStates&(HistoryItem.STATE_WIFI_FULL_LOCK_FLAG
|| (aggrStates&(HistoryItem.STATE_WIFI_FULL_LOCK_FLAG |HistoryItem.STATE_WIFI_MULTICAST_ON_FLAG
|HistoryItem.STATE_WIFI_MULTICAST_ON_FLAG |HistoryItem.STATE_WIFI_SCAN_FLAG)) != 0;
|HistoryItem.STATE_WIFI_SCAN_FLAG)) != 0; if (!com.android.settings.Utils.isWifiOnly(getContext())) {
if (!com.android.settings.Utils.isWifiOnly(getContext())) { mHavePhoneSignal = true;
mHavePhoneSignal = true; }
} if (mHistEnd <= mHistStart) mHistEnd = mHistStart+1;
if (mHistEnd <= mHistStart) mHistEnd = mHistStart+1; }, mStats, false /* shortString */);
} }
@Override @Override

View File

@@ -20,7 +20,6 @@ import android.content.Intent;
import android.os.BatteryStats; import android.os.BatteryStats;
import android.os.BatteryStats.HistoryItem; import android.os.BatteryStats.HistoryItem;
import android.os.Bundle; import android.os.Bundle;
import android.os.SystemClock;
import android.util.TypedValue; import android.util.TypedValue;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
@@ -91,24 +90,25 @@ public class BatteryHistoryDetail extends SettingsPreferenceFragment {
} }
private void updateEverything() { private void updateEverything() {
BatteryInfo info = BatteryInfo.getBatteryInfo(getContext(), mBatteryBroadcast, mStats, BatteryInfo.getBatteryInfo(getContext(), info -> {
SystemClock.elapsedRealtime() * 1000); final View view = getView();
final View view = getView(); info.bindHistory((UsageView) view.findViewById(R.id.battery_usage), mChargingParser,
info.bindHistory((UsageView) view.findViewById(R.id.battery_usage), mChargingParser, mScreenOn, mGpsParser, mFlashlightParser, mCameraParser, mWifiParser,
mScreenOn, mGpsParser, mFlashlightParser, mCameraParser, mWifiParser, mCpuParser, mCpuParser, mPhoneParser);
mPhoneParser); ((TextView) view.findViewById(R.id.charge)).setText(info.batteryPercentString);
((TextView) view.findViewById(R.id.charge)).setText(info.batteryPercentString); ((TextView) view.findViewById(R.id.estimation)).setText(info.remainingLabel);
((TextView) view.findViewById(R.id.estimation)).setText(info.remainingLabel);
bindData(mChargingParser, R.string.battery_stats_charging_label, R.id.charging_group); bindData(mChargingParser, R.string.battery_stats_charging_label, R.id.charging_group);
bindData(mScreenOn, R.string.battery_stats_screen_on_label, R.id.screen_on_group); bindData(mScreenOn, R.string.battery_stats_screen_on_label, R.id.screen_on_group);
bindData(mGpsParser, R.string.battery_stats_gps_on_label, R.id.gps_group); bindData(mGpsParser, R.string.battery_stats_gps_on_label, R.id.gps_group);
bindData(mFlashlightParser, R.string.battery_stats_flashlight_on_label, bindData(mFlashlightParser, R.string.battery_stats_flashlight_on_label,
R.id.flashlight_group); R.id.flashlight_group);
bindData(mCameraParser, R.string.battery_stats_camera_on_label, R.id.camera_group); bindData(mCameraParser, R.string.battery_stats_camera_on_label, R.id.camera_group);
bindData(mWifiParser, R.string.battery_stats_wifi_running_label, R.id.wifi_group); bindData(mWifiParser, R.string.battery_stats_wifi_running_label, R.id.wifi_group);
bindData(mCpuParser, R.string.battery_stats_wake_lock_label, R.id.cpu_group); bindData(mCpuParser, R.string.battery_stats_wake_lock_label, R.id.cpu_group);
bindData(mPhoneParser, R.string.battery_stats_phone_signal_label, R.id.cell_network_group); bindData(mPhoneParser, R.string.battery_stats_phone_signal_label,
R.id.cell_network_group);
}, mStats, false /* shortString */);
} }
private void bindData(BatteryActiveProvider provider, int label, int groupId) { private void bindData(BatteryActiveProvider provider, int label, int groupId) {

View File

@@ -17,7 +17,6 @@
package com.android.settings.fuelgauge; package com.android.settings.fuelgauge;
import android.content.Context; import android.content.Context;
import android.os.SystemClock;
import android.support.annotation.VisibleForTesting; import android.support.annotation.VisibleForTesting;
import android.support.v7.preference.Preference; import android.support.v7.preference.Preference;
import android.support.v7.preference.PreferenceViewHolder; import android.support.v7.preference.PreferenceViewHolder;
@@ -43,10 +42,10 @@ public class BatteryHistoryPreference extends Preference {
} }
public void setStats(BatteryStatsHelper batteryStats) { public void setStats(BatteryStatsHelper batteryStats) {
final long elapsedRealtimeUs = SystemClock.elapsedRealtime() * 1000; BatteryInfo.getBatteryInfo(getContext(), info -> {
mBatteryInfo = BatteryInfo.getBatteryInfo(getContext(), batteryStats.getBatteryBroadcast(), mBatteryInfo = info;
batteryStats.getStats(), elapsedRealtimeUs); notifyChanged();
notifyChanged(); }, batteryStats.getStats(), false);
} }
@Override @Override

View File

@@ -24,9 +24,12 @@ import android.os.BatteryStats;
import android.os.BatteryStats.HistoryItem; import android.os.BatteryStats.HistoryItem;
import android.os.Bundle; import android.os.Bundle;
import android.os.SystemClock; import android.os.SystemClock;
import android.support.annotation.WorkerThread;
import android.text.format.Formatter; import android.text.format.Formatter;
import android.util.SparseIntArray; import android.util.SparseIntArray;
import com.android.internal.os.BatteryStatsHelper; import com.android.internal.os.BatteryStatsHelper;
import android.support.annotation.VisibleForTesting;
import com.android.settings.overlay.FeatureFactory;
import com.android.settingslib.R; import com.android.settingslib.R;
import com.android.settingslib.Utils; import com.android.settingslib.Utils;
import com.android.settingslib.graph.UsageView; import com.android.settingslib.graph.UsageView;
@@ -103,38 +106,57 @@ public class BatteryInfo {
public static void getBatteryInfo(final Context context, final Callback callback, public static void getBatteryInfo(final Context context, final Callback callback,
boolean shortString) { boolean shortString) {
new AsyncTask<Void, Void, BatteryStats>() { BatteryStatsHelper statsHelper = new BatteryStatsHelper(context, true);
statsHelper.create((Bundle) null);
BatteryInfo.getBatteryInfo(context, callback, statsHelper, shortString);
}
public static void getBatteryInfo(final Context context, final Callback callback,
BatteryStatsHelper statsHelper, boolean shortString) {
getBatteryInfo(context, callback, statsHelper.getStats(), shortString);
}
public static void getBatteryInfo(final Context context, final Callback callback,
BatteryStats stats, boolean shortString) {
new AsyncTask<Void, Void, BatteryInfo>() {
@Override @Override
protected BatteryStats doInBackground(Void... params) { protected BatteryInfo doInBackground(Void... params) {
BatteryStatsHelper statsHelper = new BatteryStatsHelper(context, true); PowerUsageFeatureProvider provider =
statsHelper.create((Bundle) null); FeatureFactory.getFactory(context).getPowerUsageFeatureProvider(context);
return statsHelper.getStats(); final BatteryUtils batteryUtils = BatteryUtils.getInstance(context);
final long elapsedRealtimeUs =
batteryUtils.convertMsToUs(SystemClock.elapsedRealtime());
Intent batteryBroadcast = context.registerReceiver(null,
new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
BatteryUtils utils = BatteryUtils.getInstance(context);
if (provider != null && provider.isEnhancedBatteryPredictionEnabled(context)) {
return BatteryInfo.getBatteryInfo(context, batteryBroadcast, stats,
elapsedRealtimeUs, shortString,
utils.convertMsToUs(provider.getEnhancedBatteryPrediction(context)),
true);
} else {
return BatteryInfo.getBatteryInfo(context, batteryBroadcast, stats,
elapsedRealtimeUs, shortString,
stats.computeBatteryTimeRemaining(elapsedRealtimeUs), false);
}
} }
@Override @Override
protected void onPostExecute(BatteryStats batteryStats) { protected void onPostExecute(BatteryInfo batteryInfo) {
final long elapsedRealtimeUs = SystemClock.elapsedRealtime() * 1000;
Intent batteryBroadcast = context.registerReceiver(null,
new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
BatteryInfo batteryInfo = BatteryInfo.getBatteryInfo(context, batteryBroadcast,
batteryStats, elapsedRealtimeUs, shortString);
callback.onBatteryInfoLoaded(batteryInfo); callback.onBatteryInfoLoaded(batteryInfo);
} }
}.execute(); }.execute();
} }
public static BatteryInfo getBatteryInfo(Context context, Intent batteryBroadcast, @WorkerThread
BatteryStats stats, long elapsedRealtimeUs) { public static BatteryInfo getBatteryInfoOld(Context context, Intent batteryBroadcast,
return BatteryInfo.getBatteryInfo(context, batteryBroadcast, stats, elapsedRealtimeUs,
false /* shortString */);
}
public static BatteryInfo getBatteryInfo(Context context, Intent batteryBroadcast,
BatteryStats stats, long elapsedRealtimeUs, boolean shortString) { BatteryStats stats, long elapsedRealtimeUs, boolean shortString) {
return getBatteryInfo(context, batteryBroadcast, stats, elapsedRealtimeUs, shortString, return getBatteryInfo(context, batteryBroadcast, stats, elapsedRealtimeUs, shortString,
stats.computeBatteryTimeRemaining(elapsedRealtimeUs), false); stats.computeBatteryTimeRemaining(elapsedRealtimeUs), false);
} }
@WorkerThread
public static BatteryInfo getBatteryInfo(Context context, Intent batteryBroadcast, public static BatteryInfo getBatteryInfo(Context context, Intent batteryBroadcast,
BatteryStats stats, long elapsedRealtimeUs, boolean shortString, long drainTimeUs, BatteryStats stats, long elapsedRealtimeUs, boolean shortString, long drainTimeUs,
boolean basedOnUsage) { boolean basedOnUsage) {
@@ -144,13 +166,14 @@ public class BatteryInfo {
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;
final Resources resources = context.getResources(); final Resources resources = context.getResources();
final BatteryUtils batteryUtils = BatteryUtils.getInstance(context);
info.statusLabel = Utils.getBatteryStatus(resources, batteryBroadcast); info.statusLabel = Utils.getBatteryStatus(resources, batteryBroadcast);
if (!info.mCharging) { if (!info.mCharging) {
if (drainTimeUs > 0) { if (drainTimeUs > 0) {
info.remainingTimeUs = drainTimeUs; info.remainingTimeUs = drainTimeUs;
String timeString = Formatter.formatShortElapsedTime(context, String timeString = Formatter.formatShortElapsedTime(context,
drainTimeUs / 1000); batteryUtils.convertUsToMs(drainTimeUs));
info.remainingLabel = resources.getString( info.remainingLabel = resources.getString(
shortString ? shortString ?
(basedOnUsage ? (basedOnUsage ?
@@ -179,7 +202,7 @@ public class BatteryInfo {
if (chargeTime > 0 && status != BatteryManager.BATTERY_STATUS_FULL) { if (chargeTime > 0 && status != BatteryManager.BATTERY_STATUS_FULL) {
info.remainingTimeUs = chargeTime; info.remainingTimeUs = chargeTime;
String timeString = Formatter.formatShortElapsedTime(context, String timeString = Formatter.formatShortElapsedTime(context,
chargeTime / 1000); batteryUtils.convertUsToMs(chargeTime));
int resId = shortString ? R.string.power_charging_duration_short int resId = shortString ? R.string.power_charging_duration_short
: R.string.power_charging_duration; : R.string.power_charging_duration;
info.remainingLabel = resources.getString( info.remainingLabel = resources.getString(

View File

@@ -0,0 +1,80 @@
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.fuelgauge;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.database.Cursor;
import android.net.Uri;
import android.os.BatteryStats;
import android.os.SystemClock;
import com.android.internal.os.BatteryStatsHelper;
import com.android.settings.overlay.FeatureFactory;
import com.android.settings.utils.AsyncLoader;
/**
* Loader that can be used by classes to load BatteryInfo in a background thread. This loader will
* automatically grab enhanced battery estimates if available or fall back to the system estimate
* when not available.
*/
public class BatteryInfoLoader extends AsyncLoader<BatteryInfo>{
BatteryStatsHelper mStatsHelper;
public BatteryInfoLoader(Context context, BatteryStatsHelper batteryStatsHelper) {
super(context);
mStatsHelper = batteryStatsHelper;
}
@Override
protected void onDiscardResult(BatteryInfo result) {
}
@Override
public BatteryInfo loadInBackground() {
Context context = getContext();
PowerUsageFeatureProvider powerUsageFeatureProvider =
FeatureFactory.getFactory(context).getPowerUsageFeatureProvider(context);
// Stuff we always need to get BatteryInfo
BatteryUtils batteryUtils = BatteryUtils.getInstance(context);
Intent batteryBroadcast = getContext().registerReceiver(null,
new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
final long elapsedRealtimeUs = batteryUtils.convertMsToUs(SystemClock.elapsedRealtime());
BatteryInfo batteryInfo;
// Get enhanced prediction if available, otherwise use the old prediction code
Cursor cursor = null;
if (powerUsageFeatureProvider.isEnhancedBatteryPredictionEnabled(context)) {
final Uri queryUri = powerUsageFeatureProvider.getEnhancedBatteryPredictionUri();
cursor = context.getContentResolver().query(queryUri, null, null, null, null);
}
if (cursor != null && cursor.moveToFirst()) {
long enhancedEstimate = powerUsageFeatureProvider.getTimeRemainingEstimate(cursor);
batteryInfo = BatteryInfo.getBatteryInfo(context, batteryBroadcast,
mStatsHelper.getStats(), elapsedRealtimeUs, false /* shortString */,
batteryUtils.convertMsToUs(enhancedEstimate), true /* basedOnUsage */);
} else {
BatteryStats stats = mStatsHelper.getStats();
batteryInfo = BatteryInfo.getBatteryInfo(context, batteryBroadcast, stats,
elapsedRealtimeUs, false /* shortString */,
stats.computeBatteryTimeRemaining(elapsedRealtimeUs), false /* basedOnUsage */);
}
return batteryInfo;
}
}

View File

@@ -274,7 +274,7 @@ public class BatteryUtils {
} }
private long convertUsToMs(long timeUs) { public long convertUsToMs(long timeUs) {
return timeUs / 1000; return timeUs / 1000;
} }

View File

@@ -19,21 +19,15 @@ package com.android.settings.fuelgauge;
import android.app.Activity; import android.app.Activity;
import android.app.LoaderManager; import android.app.LoaderManager;
import android.content.Context; import android.content.Context;
import android.content.CursorLoader;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.Loader; import android.content.Loader;
import android.content.res.TypedArray; import android.content.res.TypedArray;
import android.database.Cursor;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.BatteryStats; import android.os.BatteryStats;
import android.os.Build; import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
import android.os.Handler; import android.os.Handler;
import android.os.Message; import android.os.Message;
import android.os.Process; import android.os.Process;
import android.os.SystemClock;
import android.os.UserHandle; import android.os.UserHandle;
import android.provider.SearchIndexableResource; import android.provider.SearchIndexableResource;
import android.support.annotation.VisibleForTesting; import android.support.annotation.VisibleForTesting;
@@ -101,7 +95,7 @@ public class PowerUsageSummary extends PowerUsageBase implements
@VisibleForTesting @VisibleForTesting
static final int ANOMALY_LOADER = 1; static final int ANOMALY_LOADER = 1;
@VisibleForTesting @VisibleForTesting
static final int BATTERY_ESTIMATE_LOADER = 2; static final int BATTERY_INFO_LOADER = 2;
private static final int MENU_STATS_TYPE = Menu.FIRST; private static final int MENU_STATS_TYPE = Menu.FIRST;
@VisibleForTesting @VisibleForTesting
static final int MENU_HIGH_POWER_APPS = Menu.FIRST + 3; static final int MENU_HIGH_POWER_APPS = Menu.FIRST + 3;
@@ -124,8 +118,6 @@ public class PowerUsageSummary extends PowerUsageBase implements
PowerUsageFeatureProvider mPowerFeatureProvider; PowerUsageFeatureProvider mPowerFeatureProvider;
@VisibleForTesting @VisibleForTesting
BatteryUtils mBatteryUtils; BatteryUtils mBatteryUtils;
@VisibleForTesting
long mEnhancedEstimate = -1;
/** /**
* SparseArray that maps uid to {@link Anomaly}, so we could find {@link Anomaly} by uid * SparseArray that maps uid to {@link Anomaly}, so we could find {@link Anomaly} by uid
@@ -163,35 +155,21 @@ public class PowerUsageSummary extends PowerUsageBase implements
}; };
@VisibleForTesting @VisibleForTesting
LoaderManager.LoaderCallbacks<Cursor> mBatteryPredictionLoaderCallbacks = LoaderManager.LoaderCallbacks<BatteryInfo> BatteryInfoLoaderCallbacks =
new LoaderManager.LoaderCallbacks<Cursor>() { new LoaderManager.LoaderCallbacks<BatteryInfo>() {
@Override @Override
public Loader<Cursor> onCreateLoader(int i, Bundle bundle) { public Loader<BatteryInfo> onCreateLoader(int i, Bundle bundle) {
final Uri queryUri = mPowerFeatureProvider.getEnhancedBatteryPredictionUri(); return new BatteryInfoLoader(getContext(), mStatsHelper);
return new CursorLoader(getContext(), queryUri, null, null, null, null);
} }
@Override @Override
public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) { public void onLoadFinished(Loader<BatteryInfo> loader, BatteryInfo batteryInfo) {
if (cursor == null) {
return;
}
if (cursor.moveToFirst()) {
mEnhancedEstimate =
mPowerFeatureProvider.getTimeRemainingEstimate(cursor);
}
final long elapsedRealtimeUs =
mBatteryUtils.convertMsToUs(SystemClock.elapsedRealtime());
Intent batteryBroadcast = getContext().registerReceiver(null,
new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
BatteryInfo batteryInfo = getBatteryInfo(elapsedRealtimeUs, batteryBroadcast);
mBatteryHeaderPreferenceController.updateHeaderPreference(batteryInfo); mBatteryHeaderPreferenceController.updateHeaderPreference(batteryInfo);
} }
@Override @Override
public void onLoaderReset(Loader<Cursor> loader) { public void onLoaderReset(Loader<BatteryInfo> loader) {
// do nothing // do nothing
} }
}; };
@@ -213,7 +191,7 @@ public class PowerUsageSummary extends PowerUsageBase implements
mAnomalySparseArray = new SparseArray<>(); mAnomalySparseArray = new SparseArray<>();
initFeatureProvider(); initFeatureProvider();
initializeBatteryEstimateLoader(); restartBatteryInfoLoader();
} }
@Override @Override
@@ -480,12 +458,8 @@ public class PowerUsageSummary extends PowerUsageBase implements
initAnomalyDetectionIfPossible(); initAnomalyDetectionIfPossible();
final long elapsedRealtimeUs = mBatteryUtils.convertMsToUs(SystemClock.elapsedRealtime()); // reload BatteryInfo and updateUI
Intent batteryBroadcast = context.registerReceiver(null, restartBatteryInfoLoader();
new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
BatteryInfo batteryInfo = getBatteryInfo(elapsedRealtimeUs, batteryBroadcast);
mBatteryHeaderPreferenceController.updateHeaderPreference(batteryInfo);
final long lastFullChargeTime = mBatteryUtils.calculateLastFullChargeTime(mStatsHelper, final long lastFullChargeTime = mBatteryUtils.calculateLastFullChargeTime(mStatsHelper,
System.currentTimeMillis()); System.currentTimeMillis());
updateScreenPreference(); updateScreenPreference();
@@ -701,28 +675,12 @@ public class PowerUsageSummary extends PowerUsageBase implements
} }
} }
private BatteryInfo getBatteryInfo(long elapsedRealtimeUs, Intent batteryBroadcast) {
BatteryInfo batteryInfo;
if (mEnhancedEstimate > 0 &&
mPowerFeatureProvider.isEnhancedBatteryPredictionEnabled(
getContext())) {
// Drain time is in micro-seconds so we have to multiply by 1000
batteryInfo = BatteryInfo.getBatteryInfo(getContext(), batteryBroadcast,
mStatsHelper.getStats(), elapsedRealtimeUs, false,
mBatteryUtils.convertMsToUs(mEnhancedEstimate), true);
} else {
batteryInfo = BatteryInfo.getBatteryInfo(getContext(), batteryBroadcast,
mStatsHelper.getStats(), elapsedRealtimeUs, false);
}
return batteryInfo;
}
@VisibleForTesting @VisibleForTesting
void initializeBatteryEstimateLoader() { void restartBatteryInfoLoader() {
if (mPowerFeatureProvider != null if (mPowerFeatureProvider != null
&& mPowerFeatureProvider.isEnhancedBatteryPredictionEnabled(getContext())) { && mPowerFeatureProvider.isEnhancedBatteryPredictionEnabled(getContext())) {
getLoaderManager().initLoader(BATTERY_ESTIMATE_LOADER, Bundle.EMPTY, getLoaderManager().restartLoader(BATTERY_INFO_LOADER, Bundle.EMPTY,
mBatteryPredictionLoaderCallbacks); BatteryInfoLoaderCallbacks);
} }
} }

View File

@@ -24,6 +24,7 @@ import android.os.BatteryStats;
import android.os.SystemClock; import android.os.SystemClock;
import com.android.settings.TestConfig; import com.android.settings.TestConfig;
import com.android.settings.testutils.FakeFeatureFactory;
import com.android.settingslib.R; import com.android.settingslib.R;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
@@ -69,6 +70,7 @@ public class BatteryInfoTest {
@Before @Before
public void setUp() { public void setUp() {
MockitoAnnotations.initMocks(this); MockitoAnnotations.initMocks(this);
FakeFeatureFactory.setupForTest(mContext);
mDisChargingBatteryBroadcast = new Intent(); mDisChargingBatteryBroadcast = new Intent();
mDisChargingBatteryBroadcast.putExtra(BatteryManager.EXTRA_PLUGGED, 0); mDisChargingBatteryBroadcast.putExtra(BatteryManager.EXTRA_PLUGGED, 0);
@@ -97,8 +99,9 @@ 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(mBatteryStats).computeBatteryTimeRemaining(anyLong());
BatteryInfo info = BatteryInfo.getBatteryInfo(mContext, mDisChargingBatteryBroadcast, BatteryInfo info = BatteryInfo.getBatteryInfoOld(mContext,
mBatteryStats, SystemClock.elapsedRealtime() * 1000, true /* shortString */); mDisChargingBatteryBroadcast, mBatteryStats, SystemClock.elapsedRealtime() * 1000,
true /* shortString */);
assertThat(info.statusLabel).isEqualTo(STATUS_FULL); assertThat(info.statusLabel).isEqualTo(STATUS_FULL);
} }
@@ -106,7 +109,7 @@ 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(mBatteryStats).computeChargeTimeRemaining(anyLong());
BatteryInfo info = BatteryInfo.getBatteryInfo(mContext, mChargingBatteryBroadcast, BatteryInfo info = BatteryInfo.getBatteryInfoOld(mContext, mChargingBatteryBroadcast,
mBatteryStats, SystemClock.elapsedRealtime() * 1000, false /* shortString */); mBatteryStats, SystemClock.elapsedRealtime() * 1000, false /* shortString */);
assertThat(info.chargeLabelString).isEqualTo(STATUS_CHARGING_TIME); assertThat(info.chargeLabelString).isEqualTo(STATUS_CHARGING_TIME);
@@ -115,7 +118,7 @@ public class BatteryInfoTest {
@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(mBatteryStats).computeChargeTimeRemaining(anyLong());
BatteryInfo info = BatteryInfo.getBatteryInfo(mContext, mChargingBatteryBroadcast, BatteryInfo info = BatteryInfo.getBatteryInfoOld(mContext, mChargingBatteryBroadcast,
mBatteryStats, SystemClock.elapsedRealtime() * 1000, false /* shortString */); mBatteryStats, SystemClock.elapsedRealtime() * 1000, false /* shortString */);
assertThat(info.chargeLabelString).isEqualTo(STATUS_CHARGING_NO_TIME); assertThat(info.chargeLabelString).isEqualTo(STATUS_CHARGING_NO_TIME);
@@ -123,7 +126,7 @@ public class BatteryInfoTest {
@Test @Test
public void testGetBatteryInfo_pluggedIn_dischargingFalse() { public void testGetBatteryInfo_pluggedIn_dischargingFalse() {
BatteryInfo info = BatteryInfo.getBatteryInfo(mContext, mChargingBatteryBroadcast, BatteryInfo info = BatteryInfo.getBatteryInfoOld(mContext, mChargingBatteryBroadcast,
mBatteryStats, SystemClock.elapsedRealtime() * 1000, true /* shortString */); mBatteryStats, SystemClock.elapsedRealtime() * 1000, true /* shortString */);
assertThat(info.discharging).isEqualTo(false); assertThat(info.discharging).isEqualTo(false);

View File

@@ -438,24 +438,6 @@ public class PowerUsageSummaryTest {
assertThat(mFragment.mAnomalySparseArray.get(UID_2)).containsExactly(anomaly3); assertThat(mFragment.mAnomalySparseArray.get(UID_2)).containsExactly(anomaly3);
} }
@Test
public void testBatteryPredictionLoaderCallbacks_DoesNotCrashOnNull() {
// Sanity test to check for crash
mFragment.mBatteryPredictionLoaderCallbacks.onLoadFinished(null, null);
}
@Test
public void testOnCreate_BatteryPredictionSkippedWhenDisabled() {
PowerUsageFeatureProvider provider = mFeatureFactory.getPowerUsageFeatureProvider(mContext);
when(provider.isEnhancedBatteryPredictionEnabled(any())).thenReturn(false);
mFragment.mPowerFeatureProvider = provider;
doReturn(mLoaderManager).when(mFragment).getLoaderManager();
mFragment.initializeBatteryEstimateLoader();
verify(mLoaderManager, never()).initLoader(eq(PowerUsageSummary.BATTERY_ESTIMATE_LOADER),
eq(Bundle.EMPTY), any());
}
@Test @Test
public void testInitAnomalyDetectionIfPossible_detectionEnabled_init() { public void testInitAnomalyDetectionIfPossible_detectionEnabled_init() {
when(mFeatureFactory.powerUsageFeatureProvider.isAnomalyDetectionEnabled()).thenReturn( when(mFeatureFactory.powerUsageFeatureProvider.isAnomalyDetectionEnabled()).thenReturn(