Merge "Fix issue# 2544176: running services list update outside of ui thread." into froyo

This commit is contained in:
Dianne Hackborn
2010-03-30 18:25:10 -07:00
committed by Android (Google) Code Review

View File

@@ -64,6 +64,8 @@ import android.widget.TextView;
import java.io.FileInputStream; import java.io.FileInputStream;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap; import java.util.HashMap;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
@@ -189,6 +191,11 @@ public class RunningServices extends ListActivity
int mRunningSeq; int mRunningSeq;
ActivityManager.RunningAppProcessInfo mRunningProcessInfo; ActivityManager.RunningAppProcessInfo mRunningProcessInfo;
// Purely for sorting.
boolean mIsSystem;
boolean mIsStarted;
long mActiveSince;
public ProcessItem(Context context, int uid, String processName) { public ProcessItem(Context context, int uid, String processName) {
super(true); super(true);
mDescription = context.getResources().getString( mDescription = context.getResources().getString(
@@ -382,11 +389,32 @@ public class RunningServices extends ListActivity
} }
} }
static class ServiceProcessComparator implements Comparator<ProcessItem> {
public int compare(ProcessItem object1, ProcessItem object2) {
if (object1.mIsStarted != object2.mIsStarted) {
// Non-started processes go last.
return object1.mIsStarted ? -1 : 1;
}
if (object1.mIsSystem != object2.mIsSystem) {
// System processes go below non-system.
return object1.mIsSystem ? 1 : -1;
}
if (object1.mActiveSince != object2.mActiveSince) {
// Remaining ones are sorted with the longest running
// services last.
return (object1.mActiveSince > object2.mActiveSince) ? -1 : 1;
}
return 0;
}
}
static class State { static class State {
final SparseArray<HashMap<String, ProcessItem>> mProcesses final SparseArray<HashMap<String, ProcessItem>> mProcesses
= new SparseArray<HashMap<String, ProcessItem>>(); = new SparseArray<HashMap<String, ProcessItem>>();
final SparseArray<ProcessItem> mActiveProcesses final SparseArray<ProcessItem> mActiveProcesses
= new SparseArray<ProcessItem>(); = new SparseArray<ProcessItem>();
final ServiceProcessComparator mServiceProcessComparator
= new ServiceProcessComparator();
// Temporary for finding process dependencies. // Temporary for finding process dependencies.
final SparseArray<ProcessItem> mRunningProcesses final SparseArray<ProcessItem> mRunningProcesses
@@ -566,25 +594,51 @@ public class RunningServices extends ListActivity
} }
if (changed) { if (changed) {
ArrayList<BaseItem> newItems = new ArrayList<BaseItem>(); // First determine an order for the services.
mProcessItems.clear(); ArrayList<ProcessItem> sortedProcesses = new ArrayList<ProcessItem>();
for (int i=0; i<mProcesses.size(); i++) { for (int i=0; i<mProcesses.size(); i++) {
for (ProcessItem pi : mProcesses.valueAt(i).values()) { for (ProcessItem pi : mProcesses.valueAt(i).values()) {
pi.mNeedDivider = false; pi.mIsSystem = false;
// First add processes we are dependent on. pi.mIsStarted = true;
pi.addDependentProcesses(newItems, mProcessItems); pi.mActiveSince = Long.MAX_VALUE;
// And add the process itself.
newItems.add(pi);
if (pi.mPid > 0) {
mProcessItems.add(pi);
}
// And finally the services running in it.
boolean needDivider = false;
for (ServiceItem si : pi.mServices.values()) { for (ServiceItem si : pi.mServices.values()) {
si.mNeedDivider = needDivider; if (si.mServiceInfo != null
needDivider = true; && (si.mServiceInfo.applicationInfo.flags
newItems.add(si); & ApplicationInfo.FLAG_SYSTEM) != 0) {
pi.mIsSystem = true;
}
if (si.mRunningService != null
&& si.mRunningService.clientLabel != 0) {
pi.mIsStarted = false;
if (pi.mActiveSince > si.mRunningService.activeSince) {
pi.mActiveSince = si.mRunningService.activeSince;
}
}
} }
sortedProcesses.add(pi);
}
}
Collections.sort(sortedProcesses, mServiceProcessComparator);
ArrayList<BaseItem> newItems = new ArrayList<BaseItem>();
mProcessItems.clear();
for (int i=0; i<sortedProcesses.size(); i++) {
ProcessItem pi = sortedProcesses.get(i);
pi.mNeedDivider = false;
// First add processes we are dependent on.
pi.addDependentProcesses(newItems, mProcessItems);
// And add the process itself.
newItems.add(pi);
if (pi.mPid > 0) {
mProcessItems.add(pi);
}
// And finally the services running in it.
boolean needDivider = false;
for (ServiceItem si : pi.mServices.values()) {
si.mNeedDivider = needDivider;
needDivider = true;
newItems.add(si);
} }
} }
synchronized (mLock) { synchronized (mLock) {
@@ -660,6 +714,12 @@ public class RunningServices extends ListActivity
return changed; return changed;
} }
ArrayList<BaseItem> getCurrentItems() {
synchronized (mLock) {
return mItems;
}
}
} }
static class TimeTicker extends TextView { static class TimeTicker extends TextView {
@@ -679,11 +739,21 @@ public class RunningServices extends ListActivity
class ServiceListAdapter extends BaseAdapter { class ServiceListAdapter extends BaseAdapter {
final State mState; final State mState;
final LayoutInflater mInflater; final LayoutInflater mInflater;
ArrayList<BaseItem> mItems;
ServiceListAdapter(State state) { ServiceListAdapter(State state) {
synchronized (state.mLock) { mState = state;
mState = state; mInflater = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
mInflater = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE); refreshItems();
}
void refreshItems() {
ArrayList<BaseItem> newItems = mState.getCurrentItems();
if (mItems != newItems) {
mItems = newItems;
}
if (mItems == null) {
mItems = new ArrayList<BaseItem>();
} }
} }
@@ -692,19 +762,15 @@ public class RunningServices extends ListActivity
} }
public int getCount() { public int getCount() {
synchronized (mState.mLock) { return mItems.size();
return mState.mItems.size();
}
} }
public Object getItem(int position) { public Object getItem(int position) {
synchronized (mState.mLock) { return mItems.get(position);
return mState.mItems.get(position);
}
} }
public long getItemId(int position) { public long getItemId(int position) {
return position; return mItems.get(position).hashCode();
} }
public boolean areAllItemsEnabled() { public boolean areAllItemsEnabled() {
@@ -712,9 +778,7 @@ public class RunningServices extends ListActivity
} }
public boolean isEnabled(int position) { public boolean isEnabled(int position) {
synchronized (mState.mLock) { return !mItems.get(position).mIsProcess;
return !mState.mItems.get(position).mIsProcess;
}
} }
public View getView(int position, View convertView, ViewGroup parent) { public View getView(int position, View convertView, ViewGroup parent) {
@@ -743,13 +807,13 @@ public class RunningServices extends ListActivity
public void bindView(View view, int position) { public void bindView(View view, int position) {
synchronized (mState.mLock) { synchronized (mState.mLock) {
ViewHolder vh = (ViewHolder) view.getTag(); ViewHolder vh = (ViewHolder) view.getTag();
if (position >= mState.mItems.size()) { if (position >= mItems.size()) {
// List must have changed since we last reported its // List must have changed since we last reported its
// size... ignore here, we will be doing a data changed // size... ignore here, we will be doing a data changed
// to refresh the entire list. // to refresh the entire list.
return; return;
} }
BaseItem item = mState.mItems.get(position); BaseItem item = mItems.get(position);
vh.name.setText(item.mDisplayLabel); vh.name.setText(item.mDisplayLabel);
vh.separator.setVisibility(item.mNeedDivider vh.separator.setVisibility(item.mNeedDivider
? View.VISIBLE : View.INVISIBLE); ? View.VISIBLE : View.INVISIBLE);
@@ -967,7 +1031,9 @@ public class RunningServices extends ListActivity
void refreshUi(boolean dataChanged) { void refreshUi(boolean dataChanged) {
if (dataChanged) { if (dataChanged) {
((ServiceListAdapter)(getListView().getAdapter())).notifyDataSetChanged(); ServiceListAdapter adapter = (ServiceListAdapter)(getListView().getAdapter());
adapter.refreshItems();
adapter.notifyDataSetChanged();
} }
// This is the amount of available memory until we start killing // This is the amount of available memory until we start killing