Some improvements to the manage apps code:

- Battery stats now aggregates bluetooth usage.
- Battery stats now uses new history iterator API.
- Battery stats chart is refectored to have the start of a
  common facility for building tick charts.
- Manage apps will now asynchronously wait for the apps list
  if it is taking >.25ms to build.

Change-Id: I568dd74beedf9a0a5a4c88ab567510cee9af8299
This commit is contained in:
Dianne Hackborn
2010-09-20 11:40:46 -07:00
parent cb818619c6
commit 19df79af26
5 changed files with 415 additions and 216 deletions

View File

@@ -42,6 +42,7 @@ public class ApplicationsState {
public static interface Callbacks {
public void onRunningStateChanged(boolean running);
public void onPackageListChanged();
public void onRebuildComplete(ArrayList<AppEntry> apps);
public void onPackageIconChanged();
public void onPackageSizeChanged(String packageName);
public void onAllSizesComputed();
@@ -154,6 +155,14 @@ public class ApplicationsState {
long mCurId = 1;
String mCurComputingSizePkg;
// Rebuilding of app list. Synchronized on mRebuildSync.
final Object mRebuildSync = new Object();
boolean mRebuildRequested;
boolean mRebuildAsync;
AppFilter mRebuildFilter;
Comparator<AppEntry> mRebuildComparator;
ArrayList<AppEntry> mRebuildResult;
/**
* Receives notifications when applications are added/removed.
*/
@@ -209,8 +218,9 @@ public class ApplicationsState {
}
class MainHandler extends Handler {
static final int MSG_PACKAGE_LIST_CHANGED = 1;
static final int MSG_PACKAGE_ICON_CHANGED = 2;
static final int MSG_REBUILD_COMPLETE = 1;
static final int MSG_PACKAGE_LIST_CHANGED = 2;
static final int MSG_PACKAGE_ICON_CHANGED = 3;
static final int MSG_PACKAGE_SIZE_CHANGED = 4;
static final int MSG_ALL_SIZES_COMPUTED = 5;
static final int MSG_RUNNING_STATE_CHANGED = 6;
@@ -218,6 +228,11 @@ public class ApplicationsState {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_REBUILD_COMPLETE: {
if (mCurCallbacks != null) {
mCurCallbacks.onRebuildComplete((ArrayList<AppEntry>)msg.obj);
}
} break;
case MSG_PACKAGE_LIST_CHANGED: {
if (mCurCallbacks != null) {
mCurCallbacks.onPackageListChanged();
@@ -305,20 +320,89 @@ public class ApplicationsState {
// Creates a new list of app entries with the given filter and comparator.
ArrayList<AppEntry> rebuild(AppFilter filter, Comparator<AppEntry> comparator) {
ArrayList<AppEntry> filteredApps = new ArrayList<AppEntry>();
synchronized (mRebuildSync) {
mRebuildRequested = true;
mRebuildAsync = false;
mRebuildFilter = filter;
mRebuildComparator = comparator;
mRebuildResult = null;
if (!mBackgroundHandler.hasMessages(BackgroundHandler.MSG_REBUILD_LIST)) {
mBackgroundHandler.sendEmptyMessage(BackgroundHandler.MSG_REBUILD_LIST);
}
// We will wait for .25s for the list to be built.
long waitend = SystemClock.uptimeMillis()+250;
while (mRebuildResult == null) {
long now = SystemClock.uptimeMillis();
if (now >= waitend) {
break;
}
try {
mRebuildSync.wait(waitend - now);
} catch (InterruptedException e) {
}
}
mRebuildAsync = true;
return mRebuildResult;
}
}
void handleRebuildList() {
AppFilter filter;
Comparator<AppEntry> comparator;
synchronized (mRebuildSync) {
if (!mRebuildRequested) {
return;
}
filter = mRebuildFilter;
comparator = mRebuildComparator;
mRebuildRequested = false;
mRebuildFilter = null;
mRebuildComparator = null;
}
Process.setThreadPriority(Process.THREAD_PRIORITY_FOREGROUND);
List<ApplicationInfo> apps;
synchronized (mEntriesMap) {
if (DEBUG) Log.i(TAG, "Rebuilding...");
for (int i=0; i<mApplications.size(); i++) {
ApplicationInfo info = mApplications.get(i);
if (filter == null || filter.filterApp(info)) {
apps = new ArrayList<ApplicationInfo>(mApplications);
}
ArrayList<AppEntry> filteredApps = new ArrayList<AppEntry>();
if (DEBUG) Log.i(TAG, "Rebuilding...");
for (int i=0; i<apps.size(); i++) {
ApplicationInfo info = apps.get(i);
if (filter == null || filter.filterApp(info)) {
synchronized (mEntriesMap) {
AppEntry entry = getEntryLocked(info);
if (DEBUG) Log.i(TAG, "Using " + info.packageName + ": " + entry);
filteredApps.add(entry);
}
}
}
Collections.sort(filteredApps, comparator);
return filteredApps;
synchronized (mRebuildSync) {
if (!mRebuildRequested) {
if (!mRebuildAsync) {
mRebuildResult = filteredApps;
mRebuildSync.notifyAll();
} else {
if (!mMainHandler.hasMessages(MainHandler.MSG_REBUILD_COMPLETE)) {
Message msg = mMainHandler.obtainMessage(
MainHandler.MSG_REBUILD_COMPLETE, filteredApps);
mMainHandler.sendMessage(msg);
}
}
}
}
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
}
AppEntry getEntry(String packageName) {
@@ -447,9 +531,10 @@ public class ApplicationsState {
final HandlerThread mThread;
final BackgroundHandler mBackgroundHandler;
class BackgroundHandler extends Handler {
static final int MSG_LOAD_ENTRIES = 1;
static final int MSG_LOAD_ICONS = 2;
static final int MSG_LOAD_SIZES = 3;
static final int MSG_REBUILD_LIST = 1;
static final int MSG_LOAD_ENTRIES = 2;
static final int MSG_LOAD_ICONS = 3;
static final int MSG_LOAD_SIZES = 4;
boolean mRunning;
@@ -498,7 +583,12 @@ public class ApplicationsState {
@Override
public void handleMessage(Message msg) {
// Always try rebuilding list first thing, if needed.
handleRebuildList();
switch (msg.what) {
case MSG_REBUILD_LIST: {
} break;
case MSG_LOAD_ENTRIES: {
int numDone = 0;
synchronized (mEntriesMap) {

View File

@@ -18,6 +18,7 @@ package com.android.settings.applications;
import com.android.internal.content.PackageHelper;
import com.android.settings.R;
import com.android.settings.applications.ApplicationsState.AppEntry;
import android.app.Activity;
import android.app.ActivityManager;
@@ -384,6 +385,10 @@ public class InstalledAppDetails extends Activity
refreshUi();
}
@Override
public void onRebuildComplete(ArrayList<AppEntry> apps) {
}
@Override
public void onPackageSizeChanged(String packageName) {
if (packageName.equals(mAppEntry.info.packageName)) {

View File

@@ -23,6 +23,7 @@ import android.app.TabActivity;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.net.Uri;
import android.os.Bundle;
import android.provider.Settings;
@@ -47,6 +48,7 @@ import android.widget.AdapterView.OnItemClickListener;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
/**
* Activity to pick an application that will be used to display installation information and
@@ -152,6 +154,7 @@ public class ManageApplications extends TabActivity implements
private ArrayList<ApplicationsState.AppEntry> mEntries;
private boolean mResumed;
private int mLastFilterMode=-1, mLastSortMode=-1;
private boolean mWaitingForData;
CharSequence mCurFilterPrefix;
private Filter mFilter = new Filter() {
@@ -184,7 +187,7 @@ public class ManageApplications extends TabActivity implements
mState.resume(this);
mLastFilterMode = filter;
mLastSortMode = sort;
rebuild();
rebuild(true);
} else {
rebuild(filter, sort);
}
@@ -203,10 +206,10 @@ public class ManageApplications extends TabActivity implements
}
mLastFilterMode = filter;
mLastSortMode = sort;
rebuild();
rebuild(true);
}
public void rebuild() {
public void rebuild(boolean eraseold) {
if (DEBUG) Log.i(TAG, "Rebuilding app list...");
ApplicationsState.AppFilter filterObj;
Comparator<AppEntry> comparatorObj;
@@ -229,9 +232,28 @@ public class ManageApplications extends TabActivity implements
comparatorObj = ApplicationsState.ALPHA_COMPARATOR;
break;
}
mBaseEntries = mState.rebuild(filterObj, comparatorObj);
mEntries = applyPrefixFilter(mCurFilterPrefix, mBaseEntries);
ArrayList<ApplicationsState.AppEntry> entries
= mState.rebuild(filterObj, comparatorObj);
if (entries == null && !eraseold) {
// Don't have new list yet, but can continue using the old one.
return;
}
mBaseEntries = entries;
if (mBaseEntries != null) {
mEntries = applyPrefixFilter(mCurFilterPrefix, mBaseEntries);
} else {
mEntries = null;
}
notifyDataSetChanged();
if (entries == null) {
mWaitingForData = true;
mListContainer.setVisibility(View.INVISIBLE);
mLoadingContainer.setVisibility(View.VISIBLE);
} else {
mListContainer.setVisibility(View.VISIBLE);
mLoadingContainer.setVisibility(View.GONE);
}
}
ArrayList<ApplicationsState.AppEntry> applyPrefixFilter(CharSequence prefix,
@@ -259,9 +281,19 @@ public class ManageApplications extends TabActivity implements
setProgressBarIndeterminateVisibility(running);
}
@Override
public void onRebuildComplete(ArrayList<AppEntry> apps) {
mListContainer.setVisibility(View.VISIBLE);
mLoadingContainer.setVisibility(View.GONE);
mWaitingForData = false;
mBaseEntries = apps;
mEntries = applyPrefixFilter(mCurFilterPrefix, mBaseEntries);
notifyDataSetChanged();
}
@Override
public void onPackageListChanged() {
rebuild();
rebuild(false);
}
@Override
@@ -284,7 +316,7 @@ public class ManageApplications extends TabActivity implements
// user viewed, and are sorting by size... they may
// have cleared data, so we immediately want to resort
// the list with the new size to reflect it to the user.
rebuild();
rebuild(false);
}
return;
}
@@ -294,7 +326,7 @@ public class ManageApplications extends TabActivity implements
@Override
public void onAllSizesComputed() {
if (mLastSortMode == SORT_ORDER_SIZE) {
rebuild();
rebuild(false);
}
}
@@ -566,6 +598,7 @@ public class ManageApplications extends TabActivity implements
if (mCurView != which) {
mRunningProcessesView.setVisibility(View.GONE);
mListContainer.setVisibility(View.VISIBLE);
mLoadingContainer.setVisibility(View.GONE);
}
if (mActivityResumed) {
mApplicationsAdapter.resume(mFilterApps, mSortOrder);

View File

@@ -35,6 +35,69 @@ import android.util.TypedValue;
import android.view.View;
public class BatteryHistoryChart extends View {
static final int CHART_DATA_X_MASK = 0x0000ffff;
static final int CHART_DATA_BIN_MASK = 0xffff0000;
static final int CHART_DATA_BIN_SHIFT = 16;
static class ChartData {
int[] mColors;
Paint[] mPaints;
int mNumTicks;
int[] mTicks;
int mLastBin;
void setColors(int[] colors) {
mColors = colors;
mPaints = new Paint[colors.length];
for (int i=0; i<colors.length; i++) {
mPaints[i] = new Paint();
mPaints[i].setColor(colors[i]);
mPaints[i].setStyle(Paint.Style.FILL);
}
}
void init(int width) {
if (width > 0) {
mTicks = new int[width+2];
} else {
mTicks = null;
}
mNumTicks = 0;
mLastBin = 0;
}
void addTick(int x, int bin) {
if (bin != mLastBin) {
mTicks[mNumTicks] = x | bin << CHART_DATA_BIN_SHIFT;
mNumTicks++;
mLastBin = bin;
}
}
void finish(int width) {
if (mLastBin != 0) {
addTick(width, 0);
}
}
void draw(Canvas canvas, int top, int height) {
int lastBin=0, lastX=0;
int bottom = top + height;
for (int i=0; i<mNumTicks; i++) {
int tick = mTicks[i];
int x = tick&CHART_DATA_X_MASK;
int bin = (tick&CHART_DATA_BIN_MASK) >> CHART_DATA_BIN_SHIFT;
if (lastBin != 0) {
canvas.drawRect(lastX, top, x, bottom, mPaints[lastBin]);
}
lastBin = bin;
lastX = x;
}
}
}
static final int SANS = 1;
static final int SERIF = 2;
static final int MONOSPACE = 3;
@@ -42,7 +105,7 @@ public class BatteryHistoryChart extends View {
static final int BATTERY_WARN = 29;
static final int BATTERY_CRITICAL = 14;
// First value if for phone off; sirst value is "scanning"; following values
// First value if for phone off; first value is "scanning"; following values
// are battery stats signal strength buckets.
static final int NUM_PHONE_SIGNALS = 7;
@@ -55,11 +118,7 @@ public class BatteryHistoryChart extends View {
final Paint mGpsOnPaint = new Paint();
final Paint mWifiRunningPaint = new Paint();
final Paint mWakeLockPaint = new Paint();
final Paint[] mPhoneSignalPaints = new Paint[NUM_PHONE_SIGNALS];
final int[] mPhoneSignalColors = new int[] {
0x00000000, 0xffa00000, 0xffa0a000, 0xff808020,
0xff808040, 0xff808060, 0xff008000
};
final ChartData mPhoneSignalChart = new ChartData();
final TextPaint mTextPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG);
final Path mBatLevelPath = new Path();
@@ -103,14 +162,11 @@ public class BatteryHistoryChart extends View {
int mLevelOffset;
int mLevelTop;
int mLevelBottom;
static final int PHONE_SIGNAL_X_MASK = 0x0000ffff;
static final int PHONE_SIGNAL_BIN_MASK = 0xffff0000;
static final int PHONE_SIGNAL_BIN_SHIFT = 16;
int mNumPhoneSignalTicks;
int[] mPhoneSignalTicks;
static final int PHONE_SIGNAL_X_MASK = CHART_DATA_X_MASK;
static final int PHONE_SIGNAL_BIN_MASK = CHART_DATA_BIN_MASK;
static final int PHONE_SIGNAL_BIN_SHIFT = CHART_DATA_BIN_SHIFT;
int mNumHist;
BatteryStats.HistoryItem mHistFirst;
long mHistStart;
long mHistEnd;
int mBatLow;
@@ -131,19 +187,14 @@ public class BatteryHistoryChart extends View {
mBatteryCriticalPaint.setStyle(Paint.Style.STROKE);
mChargingPaint.setARGB(255, 0, 128, 0);
mChargingPaint.setStyle(Paint.Style.STROKE);
mScreenOnPaint.setARGB(255, 0, 0, 255);
mScreenOnPaint.setStyle(Paint.Style.STROKE);
mGpsOnPaint.setARGB(255, 0, 0, 255);
mGpsOnPaint.setStyle(Paint.Style.STROKE);
mWifiRunningPaint.setARGB(255, 0, 0, 255);
mWifiRunningPaint.setStyle(Paint.Style.STROKE);
mWakeLockPaint.setARGB(255, 0, 0, 255);
mWakeLockPaint.setStyle(Paint.Style.STROKE);
for (int i=0; i<NUM_PHONE_SIGNALS; i++) {
mPhoneSignalPaints[i] = new Paint();
mPhoneSignalPaints[i].setColor(mPhoneSignalColors[i]);
mPhoneSignalPaints[i].setStyle(Paint.Style.FILL);
}
mPhoneSignalChart.setColors(new int[] {
0x00000000, 0xffa00000, 0xffa0a000, 0xff808020,
0xff808040, 0xff808060, 0xff008000
});
mTextPaint.density = getResources().getDisplayMetrics().density;
mTextPaint.setCompatibilityScaling(
@@ -296,29 +347,30 @@ public class BatteryHistoryChart extends View {
mWakeLockLabel = getContext().getString(R.string.battery_stats_wake_lock_label);
mPhoneSignalLabel = getContext().getString(R.string.battery_stats_phone_signal_label);
BatteryStats.HistoryItem rec = stats.getHistory();
mHistFirst = null;
int pos = 0;
int lastInteresting = 0;
byte lastLevel = -1;
mBatLow = 0;
mBatHigh = 100;
int aggrStates = 0;
while (rec != null) {
pos++;
if (rec.cmd == HistoryItem.CMD_UPDATE) {
if (mHistFirst == null) {
mHistFirst = rec;
mHistStart = rec.time;
boolean first = true;
if (stats.startIteratingHistoryLocked()) {
final HistoryItem rec = new HistoryItem();
while (stats.getNextHistoryLocked(rec)) {
pos++;
if (rec.cmd == HistoryItem.CMD_UPDATE) {
if (first) {
first = false;
mHistStart = rec.time;
}
if (rec.batteryLevel != lastLevel || pos == 1) {
lastLevel = rec.batteryLevel;
lastInteresting = pos;
mHistEnd = rec.time;
}
aggrStates |= rec.states;
}
if (rec.batteryLevel != lastLevel || pos == 1) {
lastLevel = rec.batteryLevel;
lastInteresting = pos;
mHistEnd = rec.time;
}
aggrStates |= rec.states;
}
rec = rec.next;
}
mNumHist = lastInteresting;
mHaveGps = (aggrStates&HistoryItem.STATE_GPS_ON_FLAG) != 0;
@@ -337,15 +389,9 @@ public class BatteryHistoryChart extends View {
mTextDescent = (int)mTextPaint.descent();
}
void addPhoneSignalTick(int x, int bin) {
mPhoneSignalTicks[mNumPhoneSignalTicks]
= x | bin << PHONE_SIGNAL_BIN_SHIFT;
mNumPhoneSignalTicks++;
}
void finishPaths(int w, int h, int levelh, int startX, int y, Path curLevelPath,
int lastX, boolean lastCharging, boolean lastScreenOn, boolean lastGpsOn,
boolean lastWifiRunning, boolean lastWakeLock, int lastPhoneSignal, Path lastPath) {
boolean lastWifiRunning, boolean lastWakeLock, Path lastPath) {
if (curLevelPath != null) {
if (lastX >= 0 && lastX < w) {
if (lastPath != null) {
@@ -373,9 +419,7 @@ public class BatteryHistoryChart extends View {
if (lastWakeLock) {
mWakeLockPath.lineTo(w, h-mWakeLockOffset);
}
if (lastPhoneSignal != 0) {
addPhoneSignalTick(w, 0);
}
mPhoneSignalChart.finish(w);
}
@Override
@@ -389,10 +433,18 @@ public class BatteryHistoryChart extends View {
mLargeMode = true;
mLineWidth = textHeight/2;
mLevelTop = textHeight + mLineWidth;
mScreenOnPaint.setARGB(255, 32, 64, 255);
mGpsOnPaint.setARGB(255, 32, 64, 255);
mWifiRunningPaint.setARGB(255, 32, 64, 255);
mWakeLockPaint.setARGB(255, 32, 64, 255);
} else {
mLargeMode = false;
mLineWidth = mThinLineWidth;
mLevelTop = 0;
mScreenOnPaint.setARGB(255, 0, 0, 255);
mGpsOnPaint.setARGB(255, 0, 0, 255);
mWifiRunningPaint.setARGB(255, 0, 0, 255);
mWakeLockPaint.setARGB(255, 0, 0, 255);
}
if (mLineWidth <= 0) mLineWidth = 1;
mTextPaint.setStrokeWidth(mThinLineWidth);
@@ -414,14 +466,14 @@ public class BatteryHistoryChart extends View {
mGpsOnOffset = mWifiRunningOffset + (mHaveWifi ? barOffset : 0);
mPhoneSignalOffset = mGpsOnOffset + (mHaveGps ? barOffset : 0);
mLevelOffset = mPhoneSignalOffset + barOffset + mLineWidth;
mPhoneSignalTicks = new int[w+2];
mPhoneSignalChart.init(w);
} else {
mScreenOnOffset = mGpsOnOffset = mWifiRunningOffset
= mWakeLockOffset = mLineWidth;
mChargingOffset = mLineWidth*2;
mPhoneSignalOffset = 0;
mLevelOffset = mLineWidth*3;
mPhoneSignalTicks = null;
mPhoneSignalChart.init(0);
}
mBatLevelPath.reset();
@@ -443,146 +495,142 @@ public class BatteryHistoryChart extends View {
final int levelh = h - mLevelOffset - mLevelTop;
mLevelBottom = mLevelTop + levelh;
BatteryStats.HistoryItem rec = mHistFirst;
int x = 0, y = 0, startX = 0, lastX = -1, lastY = -1;
int i = 0;
Path curLevelPath = null;
Path lastLinePath = null;
boolean lastCharging = false, lastScreenOn = false, lastGpsOn = false;
boolean lastWifiRunning = false, lastWakeLock = false;
int lastPhoneSignalBin = 0;
final int N = mNumHist;
while (rec != null && i < N) {
if (rec.cmd == BatteryStats.HistoryItem.CMD_UPDATE) {
x = (int)(((rec.time-timeStart)*w)/timeChange);
y = mLevelTop + levelh - ((rec.batteryLevel-batLow)*(levelh-1))/batChange;
if (lastX != x) {
// We have moved by at least a pixel.
if (lastY != y) {
// Don't plot changes within a pixel.
Path path;
byte value = rec.batteryLevel;
if (value <= BATTERY_CRITICAL) path = mBatCriticalPath;
else if (value <= BATTERY_WARN) path = mBatWarnPath;
else path = mBatGoodPath;
if (path != lastLinePath) {
if (lastLinePath != null) {
lastLinePath.lineTo(x, y);
if (mStats.startIteratingHistoryLocked()) {
final HistoryItem rec = new HistoryItem();
while (mStats.getNextHistoryLocked(rec) && i < N) {
if (rec.cmd == BatteryStats.HistoryItem.CMD_UPDATE) {
x = (int)(((rec.time-timeStart)*w)/timeChange);
y = mLevelTop + levelh - ((rec.batteryLevel-batLow)*(levelh-1))/batChange;
if (lastX != x) {
// We have moved by at least a pixel.
if (lastY != y) {
// Don't plot changes within a pixel.
Path path;
byte value = rec.batteryLevel;
if (value <= BATTERY_CRITICAL) path = mBatCriticalPath;
else if (value <= BATTERY_WARN) path = mBatWarnPath;
else path = mBatGoodPath;
if (path != lastLinePath) {
if (lastLinePath != null) {
lastLinePath.lineTo(x, y);
}
path.moveTo(x, y);
lastLinePath = path;
} else {
path.lineTo(x, y);
}
path.moveTo(x, y);
lastLinePath = path;
} else {
path.lineTo(x, y);
if (curLevelPath == null) {
curLevelPath = mBatLevelPath;
curLevelPath.moveTo(x, y);
startX = x;
} else {
curLevelPath.lineTo(x, y);
}
lastX = x;
lastY = y;
}
if (curLevelPath == null) {
curLevelPath = mBatLevelPath;
curLevelPath.moveTo(x, y);
startX = x;
} else {
curLevelPath.lineTo(x, y);
final boolean charging =
(rec.states&HistoryItem.STATE_BATTERY_PLUGGED_FLAG) != 0;
if (charging != lastCharging) {
if (charging) {
mChargingPath.moveTo(x, h-mChargingOffset);
} else {
mChargingPath.lineTo(x, h-mChargingOffset);
}
lastCharging = charging;
}
final boolean screenOn =
(rec.states&HistoryItem.STATE_SCREEN_ON_FLAG) != 0;
if (screenOn != lastScreenOn) {
if (screenOn) {
mScreenOnPath.moveTo(x, h-mScreenOnOffset);
} else {
mScreenOnPath.lineTo(x, h-mScreenOnOffset);
}
lastScreenOn = screenOn;
}
final boolean gpsOn =
(rec.states&HistoryItem.STATE_GPS_ON_FLAG) != 0;
if (gpsOn != lastGpsOn) {
if (gpsOn) {
mGpsOnPath.moveTo(x, h-mGpsOnOffset);
} else {
mGpsOnPath.lineTo(x, h-mGpsOnOffset);
}
lastGpsOn = gpsOn;
}
final boolean wifiRunning =
(rec.states&HistoryItem.STATE_WIFI_RUNNING_FLAG) != 0;
if (wifiRunning != lastWifiRunning) {
if (wifiRunning) {
mWifiRunningPath.moveTo(x, h-mWifiRunningOffset);
} else {
mWifiRunningPath.lineTo(x, h-mWifiRunningOffset);
}
lastWifiRunning = wifiRunning;
}
final boolean wakeLock =
(rec.states&HistoryItem.STATE_WAKE_LOCK_FLAG) != 0;
if (wakeLock != lastWakeLock) {
if (wakeLock) {
mWakeLockPath.moveTo(x, h-mWakeLockOffset);
} else {
mWakeLockPath.lineTo(x, h-mWakeLockOffset);
}
lastWakeLock = wakeLock;
}
if (mLargeMode) {
int bin;
if (((rec.states&HistoryItem.STATE_PHONE_STATE_MASK)
>> HistoryItem.STATE_PHONE_STATE_SHIFT)
== ServiceState.STATE_POWER_OFF) {
bin = 0;
} else if ((rec.states&HistoryItem.STATE_PHONE_SCANNING_FLAG) != 0) {
bin = 1;
} else {
bin = (rec.states&HistoryItem.STATE_SIGNAL_STRENGTH_MASK)
>> HistoryItem.STATE_SIGNAL_STRENGTH_SHIFT;
bin += 2;
}
mPhoneSignalChart.addTick(x, bin);
}
lastX = x;
lastY = y;
}
final boolean charging =
(rec.states&HistoryItem.STATE_BATTERY_PLUGGED_FLAG) != 0;
if (charging != lastCharging) {
if (charging) {
mChargingPath.moveTo(x, h-mChargingOffset);
} else {
mChargingPath.lineTo(x, h-mChargingOffset);
}
lastCharging = charging;
}
final boolean screenOn =
(rec.states&HistoryItem.STATE_SCREEN_ON_FLAG) != 0;
if (screenOn != lastScreenOn) {
if (screenOn) {
mScreenOnPath.moveTo(x, h-mScreenOnOffset);
} else {
mScreenOnPath.lineTo(x, h-mScreenOnOffset);
}
lastScreenOn = screenOn;
}
final boolean gpsOn =
(rec.states&HistoryItem.STATE_GPS_ON_FLAG) != 0;
if (gpsOn != lastGpsOn) {
if (gpsOn) {
mGpsOnPath.moveTo(x, h-mGpsOnOffset);
} else {
mGpsOnPath.lineTo(x, h-mGpsOnOffset);
}
lastGpsOn = gpsOn;
}
final boolean wifiRunning =
(rec.states&HistoryItem.STATE_WIFI_RUNNING_FLAG) != 0;
if (wifiRunning != lastWifiRunning) {
if (wifiRunning) {
mWifiRunningPath.moveTo(x, h-mWifiRunningOffset);
} else {
mWifiRunningPath.lineTo(x, h-mWifiRunningOffset);
}
lastWifiRunning = wifiRunning;
}
final boolean wakeLock =
(rec.states&HistoryItem.STATE_WAKE_LOCK_FLAG) != 0;
if (wakeLock != lastWakeLock) {
if (wakeLock) {
mWakeLockPath.moveTo(x, h-mWakeLockOffset);
} else {
mWakeLockPath.lineTo(x, h-mWakeLockOffset);
}
lastWakeLock = wakeLock;
}
if (mLargeMode) {
int bin;
if (((rec.states&HistoryItem.STATE_PHONE_STATE_MASK)
>> HistoryItem.STATE_PHONE_STATE_SHIFT)
== ServiceState.STATE_POWER_OFF) {
bin = 0;
} else if ((rec.states&HistoryItem.STATE_PHONE_SCANNING_FLAG) != 0) {
bin = 1;
} else {
bin = (rec.states&HistoryItem.STATE_SIGNAL_STRENGTH_MASK)
>> HistoryItem.STATE_SIGNAL_STRENGTH_SHIFT;
bin += 2;
}
if (bin != lastPhoneSignalBin) {
addPhoneSignalTick(x, bin);
lastPhoneSignalBin = bin;
}
} else if (rec.cmd != BatteryStats.HistoryItem.CMD_OVERFLOW) {
if (curLevelPath != null) {
finishPaths(x+1, h, levelh, startX, lastY, curLevelPath, lastX,
lastCharging, lastScreenOn, lastGpsOn, lastWifiRunning,
lastWakeLock, lastLinePath);
lastX = lastY = -1;
curLevelPath = null;
lastLinePath = null;
lastCharging = lastScreenOn = lastGpsOn = lastWakeLock = false;
}
}
} else if (rec.cmd != BatteryStats.HistoryItem.CMD_OVERFLOW) {
if (curLevelPath != null) {
finishPaths(x+1, h, levelh, startX, lastY, curLevelPath, lastX,
lastCharging, lastScreenOn, lastGpsOn, lastWifiRunning,
lastWakeLock, lastPhoneSignalBin, lastLinePath);
lastX = lastY = -1;
curLevelPath = null;
lastLinePath = null;
lastCharging = lastScreenOn = lastGpsOn = lastWakeLock = false;
lastPhoneSignalBin = 0;
}
i++;
}
rec = rec.next;
i++;
}
finishPaths(w, h, levelh, startX, lastY, curLevelPath, lastX,
lastCharging, lastScreenOn, lastGpsOn, lastWifiRunning,
lastWakeLock, lastPhoneSignalBin, lastLinePath);
lastWakeLock, lastLinePath);
}
@Override
@@ -611,19 +659,8 @@ public class BatteryHistoryChart extends View {
if (!mBatCriticalPath.isEmpty()) {
canvas.drawPath(mBatCriticalPath, mBatteryCriticalPaint);
}
int lastBin=0, lastX=0;
int top = height-mPhoneSignalOffset - (mLineWidth/2);
int bottom = top + mLineWidth;
for (int i=0; i<mNumPhoneSignalTicks; i++) {
int tick = mPhoneSignalTicks[i];
int x = tick&PHONE_SIGNAL_X_MASK;
int bin = (tick&PHONE_SIGNAL_BIN_MASK) >> PHONE_SIGNAL_BIN_SHIFT;
if (lastBin != 0) {
canvas.drawRect(lastX, top, x, bottom, mPhoneSignalPaints[lastBin]);
}
lastBin = bin;
lastX = x;
}
mPhoneSignalChart.draw(canvas, top, mLineWidth);
if (!mScreenOnPath.isEmpty()) {
canvas.drawPath(mScreenOnPath, mScreenOnPaint);
}

View File

@@ -18,7 +18,6 @@ package com.android.settings.fuelgauge;
import android.content.Context;
import android.content.Intent;
import android.graphics.drawable.Drawable;
import android.hardware.SensorManager;
import android.os.BatteryStats;
import android.os.Bundle;
@@ -70,6 +69,7 @@ public class PowerUsageSummary extends PreferenceActivity implements Runnable {
BatteryStatsImpl mStats;
private final List<BatterySipper> mUsageList = new ArrayList<BatterySipper>();
private final List<BatterySipper> mWifiSippers = new ArrayList<BatterySipper>();
private final List<BatterySipper> mBluetoothSippers = new ArrayList<BatterySipper>();
private PreferenceGroup mAppListGroup;
@@ -82,6 +82,7 @@ public class PowerUsageSummary extends PreferenceActivity implements Runnable {
private double mMaxPower = 1;
private double mTotalPower;
private double mWifiPower;
private double mBluetoothPower;
private PowerProfile mPowerProfile;
// How much the apps together have left WIFI running.
@@ -228,6 +229,25 @@ public class PowerUsageSummary extends PreferenceActivity implements Runnable {
sipper.tcpBytesReceived,
};
} break;
case BLUETOOTH:
{
types = new int[] {
R.string.usage_type_on_time,
R.string.usage_type_cpu,
R.string.usage_type_cpu_foreground,
R.string.usage_type_wake_lock,
R.string.usage_type_data_send,
R.string.usage_type_data_recv,
};
values = new double[] {
sipper.usageTime,
sipper.cpuTime,
sipper.cpuFgTime,
sipper.wakeLockTime,
sipper.tcpBytesSent,
sipper.tcpBytesReceived,
};
} break;
default:
{
types = new int[] {
@@ -295,11 +315,13 @@ public class PowerUsageSummary extends PreferenceActivity implements Runnable {
mMaxPower = 0;
mTotalPower = 0;
mWifiPower = 0;
mBluetoothPower = 0;
mAppWifiRunning = 0;
mAppListGroup.removeAll();
mUsageList.clear();
mWifiSippers.clear();
mBluetoothSippers.clear();
processAppUsage();
processMiscUsage();
@@ -400,11 +422,15 @@ public class PowerUsageSummary extends PreferenceActivity implements Runnable {
}
cpuTime += tmpCpuTime;
power += processPower;
if (highestDrain < processPower) {
if (packageWithHighestDrain == null
|| packageWithHighestDrain.startsWith("*")) {
highestDrain = processPower;
packageWithHighestDrain = ent.getKey();
} else if (highestDrain < processPower
&& !ent.getKey().startsWith("*")) {
highestDrain = processPower;
packageWithHighestDrain = ent.getKey();
}
}
if (DEBUG) Log.i(TAG, "Max drain of " + highestDrain
+ " by " + packageWithHighestDrain);
@@ -486,12 +512,16 @@ public class PowerUsageSummary extends PreferenceActivity implements Runnable {
app.tcpBytesSent = tcpBytesSent;
if (u.getUid() == Process.WIFI_UID) {
mWifiSippers.add(app);
} else if (u.getUid() == Process.BLUETOOTH_GID) {
mBluetoothSippers.add(app);
} else {
mUsageList.add(app);
}
}
if (u.getUid() == Process.WIFI_UID) {
mWifiPower += power;
} else if (u.getUid() == Process.BLUETOOTH_GID) {
mBluetoothPower += power;
} else {
if (power > mMaxPower) mMaxPower = power;
mTotalPower += power;
@@ -551,6 +581,20 @@ public class PowerUsageSummary extends PreferenceActivity implements Runnable {
}
}
private void aggregateSippers(BatterySipper bs, List<BatterySipper> from, String tag) {
for (int i=0; i<from.size(); i++) {
BatterySipper wbs = from.get(i);
if (DEBUG) Log.i(TAG, tag + " adding sipper " + wbs + ": cpu=" + wbs.cpuTime);
bs.cpuTime += wbs.cpuTime;
bs.gpsTime += wbs.gpsTime;
bs.wifiRunningTime += wbs.wifiRunningTime;
bs.cpuFgTime += wbs.cpuFgTime;
bs.wakeLockTime += wbs.wakeLockTime;
bs.tcpBytesReceived += wbs.tcpBytesReceived;
bs.tcpBytesSent += wbs.tcpBytesSent;
}
}
private void addWiFiUsage(long uSecNow) {
long onTimeMs = mStats.getWifiOnTime(uSecNow, mStatsType) / 1000;
long runningTimeMs = mStats.getGlobalWifiRunningTime(uSecNow, mStatsType) / 1000;
@@ -564,17 +608,7 @@ public class PowerUsageSummary extends PreferenceActivity implements Runnable {
if (DEBUG) Log.i(TAG, "WIFI power=" + wifiPower + " from procs=" + mWifiPower);
BatterySipper bs = addEntry(getString(R.string.power_wifi), DrainType.WIFI, runningTimeMs,
R.drawable.ic_settings_wifi, wifiPower + mWifiPower);
for (int i=0; i<mWifiSippers.size(); i++) {
BatterySipper wbs = mWifiSippers.get(i);
if (DEBUG) Log.i(TAG, "WIFI adding sipper " + wbs + ": cpu=" + wbs.cpuTime);
bs.cpuTime += wbs.cpuTime;
bs.gpsTime += wbs.gpsTime;
bs.wifiRunningTime += wbs.wifiRunningTime;
bs.cpuFgTime += wbs.cpuFgTime;
bs.wakeLockTime += wbs.wakeLockTime;
bs.tcpBytesReceived += wbs.tcpBytesReceived;
bs.tcpBytesSent += wbs.tcpBytesSent;
}
aggregateSippers(bs, mWifiSippers, "WIFI");
}
private void addIdleUsage(long uSecNow) {
@@ -592,9 +626,9 @@ public class PowerUsageSummary extends PreferenceActivity implements Runnable {
int btPingCount = mStats.getBluetoothPingCount();
btPower += (btPingCount
* mPowerProfile.getAveragePower(PowerProfile.POWER_BLUETOOTH_AT_CMD)) / 1000;
addEntry(getString(R.string.power_bluetooth), DrainType.BLUETOOTH, btOnTimeMs,
R.drawable.ic_settings_bluetooth, btPower);
BatterySipper bs = addEntry(getString(R.string.power_bluetooth), DrainType.BLUETOOTH,
btOnTimeMs, R.drawable.ic_settings_bluetooth, btPower + mBluetoothPower);
aggregateSippers(bs, mBluetoothSippers, "Bluetooth");
}
private double getAverageDataCost() {