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);