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:
@@ -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
|
||||||
|
@@ -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) {
|
||||||
|
@@ -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
|
||||||
|
@@ -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(
|
||||||
|
80
src/com/android/settings/fuelgauge/BatteryInfoLoader.java
Normal file
80
src/com/android/settings/fuelgauge/BatteryInfoLoader.java
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
@@ -274,7 +274,7 @@ public class BatteryUtils {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private long convertUsToMs(long timeUs) {
|
public long convertUsToMs(long timeUs) {
|
||||||
return timeUs / 1000;
|
return timeUs / 1000;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -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);
|
||||||
|
@@ -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(
|
||||||
|
Reference in New Issue
Block a user