Merge change 24553 into eclair

* changes:
  Make running services show dependent processes.
This commit is contained in:
Android (Google) Code Review
2009-09-10 15:57:57 -04:00
4 changed files with 383 additions and 122 deletions

View File

@@ -15,16 +15,46 @@
* limitations under the License. * limitations under the License.
--> -->
<merge xmlns:android="http://schemas.android.com/apk/res/android"> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
<ListView android:id="@android:id/list" android:layout_width="fill_parent"
android:layout_width="fill_parent" android:layout_height="fill_parent"
android:layout_height="fill_parent" android:orientation="vertical">
android:drawSelectorOnTop="false" <FrameLayout
android:fastScrollEnabled="true" /> android:layout_width="fill_parent"
<TextView android:id="@android:id/empty" android:layout_height="0px"
android:layout_weight="1">
<ListView android:id="@android:id/list"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:drawSelectorOnTop="false"
android:fastScrollEnabled="true" />
<TextView android:id="@android:id/empty"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:gravity="center"
android:text="@string/no_running_services"
android:textAppearance="?android:attr/textAppearanceLarge" />
</FrameLayout>
<LinearLayout
android:layout_width="fill_parent" android:layout_width="fill_parent"
android:layout_height="fill_parent" android:layout_height="wrap_content"
android:gravity="center" android:orientation="horizontal"
android:text="@string/no_running_services" android:background="?android:attr/colorForeground"
android:textAppearance="?android:attr/textAppearanceLarge" /> android:padding="4dp">
</merge> <TextView android:id="@+id/backgroundText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:textAppearance="?android:attr/textAppearanceSmallInverse"
android:color="?android:attr/textColorPrimaryInverse"
android:singleLine="true" />
<TextView android:id="@+id/foregroundText"
android:layout_gravity="center_vertical|right"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="0"
android:textAppearance="?android:attr/textAppearanceSmallInverse"
android:color="?android:attr/textColorPrimaryInverse"
android:singleLine="true" />
</LinearLayout>
</LinearLayout>

View File

@@ -50,10 +50,10 @@
<!-- Display settings. The type of animations to show. --> <!-- Display settings. The type of animations to show. -->
<string-array name="animations_entries"> <string-array name="animations_entries">
<item>Off</item> <item>No animations</item>
<item>Some</item> <item>Some animations</item>
<item>All</item> <item>All animations</item>
<item>Slow</item> <item>Slower all animations</item>
</string-array> </string-array>
<!-- Display settings. Summary for each type of animation. --> <!-- Display settings. Summary for each type of animation. -->

View File

@@ -1422,9 +1422,13 @@ found in the list of installed applications.</string>
<!-- Running services, button to cancel stopping of a service --> <!-- Running services, button to cancel stopping of a service -->
<string name="confirm_stop_cancel">Cancel</string> <string name="confirm_stop_cancel">Cancel</string>
<!-- Running services, description for a service in the started state --> <!-- Running services, description for a service in the started state -->
<string name="service_started_by_app">Started by application</string> <string name="service_started_by_app">Started by application: select to stop</string>
<!-- Running services, description for a service in the started state --> <!-- Running services, description for a service in the started state -->
<string name="service_client_name"><xliff:g id="client_name">%1$s</xliff:g>: select to manage</string> <string name="service_client_name"><xliff:g id="client_name">%1$s</xliff:g>: select to manage</string>
<!-- Running services, summary of background processes -->
<string name="service_background_processes">Background procs: <xliff:g id="client_name">%1$d</xliff:g></string>
<!-- Running services, summary of foreground processes -->
<string name="service_foreground_processes">Foreground procs: <xliff:g id="client_name">%1$d</xliff:g></string>
<!-- Language Settings --> <skip /> <!-- Language Settings --> <skip />
<!-- Title of setting on main settings screen. This item will take the user to the screen to tweak settings realted to locale and text --> <!-- Title of setting on main settings screen. This item will take the user to the screen to tweak settings realted to locale and text -->

View File

@@ -23,28 +23,17 @@ import android.app.AlertDialog;
import android.app.Dialog; import android.app.Dialog;
import android.app.ListActivity; import android.app.ListActivity;
import android.app.PendingIntent; import android.app.PendingIntent;
import android.app.ProgressDialog; import android.content.ActivityNotFoundException;
import android.content.BroadcastReceiver;
import android.content.ComponentName; import android.content.ComponentName;
import android.content.Context; import android.content.Context;
import android.content.DialogInterface; import android.content.DialogInterface;
import android.content.Intent; import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.content.pm.ApplicationInfo; import android.content.pm.ApplicationInfo;
import android.content.pm.IPackageStatsObserver;
import android.content.pm.PackageInfo; import android.content.pm.PackageInfo;
import android.content.pm.PackageItemInfo; import android.content.pm.PackageItemInfo;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.content.pm.PackageStats;
import android.content.pm.ServiceInfo; import android.content.pm.ServiceInfo;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.Configuration;
import android.content.res.Resources; import android.content.res.Resources;
import android.content.res.TypedArray;
import android.database.Cursor;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Bundle; import android.os.Bundle;
import android.os.Debug; import android.os.Debug;
import android.os.Handler; import android.os.Handler;
@@ -54,24 +43,16 @@ import android.os.SystemClock;
import android.text.format.DateUtils; import android.text.format.DateUtils;
import android.text.format.Formatter; import android.text.format.Formatter;
import android.util.AttributeSet; import android.util.AttributeSet;
import android.util.Config;
import android.util.Log; import android.util.Log;
import android.util.SparseArray; import android.util.SparseArray;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.view.Window;
import android.widget.AbsListView; import android.widget.AbsListView;
import android.widget.AdapterView;
import android.widget.BaseAdapter; import android.widget.BaseAdapter;
import android.widget.Filter;
import android.widget.Filterable;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.ListView; import android.widget.ListView;
import android.widget.TextView; import android.widget.TextView;
import android.widget.AdapterView.OnItemClickListener;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
@@ -104,6 +85,12 @@ public class RunningServices extends ListActivity
int mProcessBgColor; int mProcessBgColor;
TextView mBackgroundProcessText;
TextView mForegroundProcessText;
int mLastNumBackgroundProcesses = -1;
int mLastNumForegroundProcesses = -1;
Dialog mCurDialog; Dialog mCurDialog;
class ActiveItem { class ActiveItem {
@@ -114,18 +101,27 @@ public class RunningServices extends ListActivity
long mFirstRunTime; long mFirstRunTime;
void updateTime(Context context) { void updateTime(Context context) {
if (mItem.mActiveSince >= 0) { if (mItem.mIsProcess) {
mHolder.size.setText(DateUtils.formatElapsedTime(mBuilder, String size = mItem.mSizeStr != null ? mItem.mSizeStr : "";
(SystemClock.uptimeMillis()-mFirstRunTime)/1000)); if (!size.equals(mItem.mCurSizeStr)) {
mItem.mCurSizeStr = size;
mHolder.size.setText(size);
}
} else { } else {
mHolder.size.setText(context.getResources().getText( if (mItem.mActiveSince >= 0) {
R.string.service_restarting)); mHolder.size.setText(DateUtils.formatElapsedTime(mBuilder,
(SystemClock.uptimeMillis()-mFirstRunTime)/1000));
} else {
mHolder.size.setText(context.getResources().getText(
R.string.service_restarting));
}
} }
} }
} }
static class BaseItem { static class BaseItem {
boolean mIsProcess; final boolean mIsProcess;
PackageItemInfo mPackageInfo; PackageItemInfo mPackageInfo;
CharSequence mDisplayLabel; CharSequence mDisplayLabel;
String mLabel; String mLabel;
@@ -136,21 +132,119 @@ public class RunningServices extends ListActivity
long mActiveSince; long mActiveSince;
long mSize; long mSize;
String mSizeStr; String mSizeStr;
String mCurSizeStr;
boolean mNeedDivider; boolean mNeedDivider;
public BaseItem(boolean isProcess) {
mIsProcess = isProcess;
}
} }
static class ServiceItem extends BaseItem { static class ServiceItem extends BaseItem {
ActivityManager.RunningServiceInfo mRunningService; ActivityManager.RunningServiceInfo mRunningService;
ServiceInfo mServiceInfo; ServiceInfo mServiceInfo;
boolean mShownAsStarted; boolean mShownAsStarted;
public ServiceItem() {
super(false);
}
} }
static class ProcessItem extends BaseItem { static class ProcessItem extends BaseItem {
final HashMap<ComponentName, ServiceItem> mServices final HashMap<ComponentName, ServiceItem> mServices
= new HashMap<ComponentName, ServiceItem>(); = new HashMap<ComponentName, ServiceItem>();
int mUid; final SparseArray<ProcessItem> mDependentProcesses
= new SparseArray<ProcessItem>();
final int mUid;
final String mProcessName;
int mPid; int mPid;
ProcessItem mClient;
int mLastNumDependentProcesses;
int mRunningSeq;
ActivityManager.RunningAppProcessInfo mRunningProcessInfo;
public ProcessItem(int uid, String processName) {
super(true);
mDescription = processName;
mUid = uid;
mProcessName = processName;
}
void ensureLabel(PackageManager pm) {
if (mLabel != null) {
return;
}
try {
ApplicationInfo ai = pm.getApplicationInfo(mProcessName, 0);
if (ai.uid == mUid) {
mDisplayLabel = ai.loadLabel(pm);
mLabel = mDisplayLabel.toString();
mPackageInfo = ai;
return;
}
} catch (PackageManager.NameNotFoundException e) {
}
// If we couldn't get information about the overall
// process, try to find something about the uid.
String[] pkgs = pm.getPackagesForUid(mUid);
// If there is one package with this uid, that is what we want.
if (pkgs.length == 1) {
try {
ApplicationInfo ai = pm.getApplicationInfo(pkgs[0], 0);
mDisplayLabel = ai.loadLabel(pm);
mLabel = mDisplayLabel.toString();
mPackageInfo = ai;
return;
} catch (PackageManager.NameNotFoundException e) {
}
}
// If there are multiple, see if one gives us the official name
// for this uid.
for (String name : pkgs) {
try {
PackageInfo pi = pm.getPackageInfo(name, 0);
if (pi.sharedUserLabel != 0) {
CharSequence nm = pm.getText(name,
pi.sharedUserLabel, pi.applicationInfo);
if (nm != null) {
mDisplayLabel = nm;
mLabel = nm.toString();
mPackageInfo = pi.applicationInfo;
return;
}
}
} catch (PackageManager.NameNotFoundException e) {
}
}
// If still don't have anything to display, just use the
// service info.
if (mServices.size() > 0) {
mPackageInfo = mServices.values().iterator().next()
.mServiceInfo.applicationInfo;
mDisplayLabel = mPackageInfo.loadLabel(pm);
mLabel = mDisplayLabel.toString();
return;
}
// Finally... whatever, just pick the first package's name.
try {
ApplicationInfo ai = pm.getApplicationInfo(pkgs[0], 0);
mDisplayLabel = ai.loadLabel(pm);
mLabel = mDisplayLabel.toString();
mPackageInfo = ai;
return;
} catch (PackageManager.NameNotFoundException e) {
}
}
boolean updateService(Context context, boolean updateService(Context context,
ActivityManager.RunningServiceInfo service) { ActivityManager.RunningServiceInfo service) {
final PackageManager pm = context.getPackageManager(); final PackageManager pm = context.getPackageManager();
@@ -211,16 +305,89 @@ public class RunningServices extends ListActivity
return changed; return changed;
} }
boolean updateSize(Context context) {
boolean changed = false;
if (mPid != 0 && mSize == 0) {
final int NP = mDependentProcesses.size();
for (int i=0; i<NP; i++) {
ProcessItem proc = mDependentProcesses.valueAt(i);
changed |= proc.updateSize(context);
}
Debug.MemoryInfo mi = new Debug.MemoryInfo();
// XXX This is a hack... I really don't want to be
// doing a synchronous call into the app, but can't
// figure out any other way to get the pss.
try {
ActivityManagerNative.getDefault().getProcessMemoryInfo(
mPid, mi);
mSize = (mi.dalvikPss + mi.nativePss
+ mi.otherPss) * 1024;
String sizeStr = Formatter.formatFileSize(
context, mSize);
if (!sizeStr.equals(mSizeStr)){
//changed = true;
mSizeStr = sizeStr;
}
} catch (RemoteException e) {
}
}
return changed;
}
boolean buildDependencyChain(Context context, PackageManager pm, int curSeq) {
final int NP = mDependentProcesses.size();
boolean changed = false;
for (int i=0; i<NP; i++) {
ProcessItem proc = mDependentProcesses.valueAt(i);
if (proc.mClient != this) {
changed = true;
proc.mClient = this;
}
proc.mCurSeq = curSeq;
proc.ensureLabel(pm);
changed |= proc.updateSize(context);
changed |= proc.buildDependencyChain(context, pm, curSeq);
}
if (mLastNumDependentProcesses != mDependentProcesses.size()) {
changed = true;
mLastNumDependentProcesses = mDependentProcesses.size();
}
return changed;
}
void addDependentProcesses(ArrayList<BaseItem> dest) {
final int NP = mDependentProcesses.size();
for (int i=0; i<NP; i++) {
ProcessItem proc = mDependentProcesses.valueAt(i);
proc.addDependentProcesses(dest);
dest.add(proc);
}
}
} }
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
= new SparseArray<ProcessItem>();
// Temporary for finding process dependencies.
final SparseArray<ProcessItem> mRunningProcesses
= new SparseArray<ProcessItem>();
final ArrayList<BaseItem> mItems = new ArrayList<BaseItem>(); final ArrayList<BaseItem> mItems = new ArrayList<BaseItem>();
int mSequence = 0; int mSequence = 0;
int mNumBackgroundProcesses;
int mNumForegroundProcesses;
boolean update(Context context, ActivityManager am) { boolean update(Context context, ActivityManager am) {
final PackageManager pm = context.getPackageManager(); final PackageManager pm = context.getPackageManager();
@@ -230,10 +397,7 @@ public class RunningServices extends ListActivity
List<ActivityManager.RunningServiceInfo> services List<ActivityManager.RunningServiceInfo> services
= am.getRunningServices(MAX_SERVICES); = am.getRunningServices(MAX_SERVICES);
if (services == null) { final int NS = services != null ? services.size() : 0;
return false;
}
final int NS = services.size();
for (int i=0; i<NS; i++) { for (int i=0; i<NS; i++) {
ActivityManager.RunningServiceInfo si = services.get(i); ActivityManager.RunningServiceInfo si = services.get(i);
// We are not interested in services that have not been started // We are not interested in services that have not been started
@@ -257,19 +421,7 @@ public class RunningServices extends ListActivity
ProcessItem proc = procs.get(si.process); ProcessItem proc = procs.get(si.process);
if (proc == null) { if (proc == null) {
changed = true; changed = true;
proc = new ProcessItem(); proc = new ProcessItem(si.uid, si.process);
proc.mIsProcess = true;
proc.mDescription = si.process;
proc.mUid = si.uid;
try {
ApplicationInfo ai = pm.getApplicationInfo(si.process, 0);
if (ai.uid == si.uid) {
proc.mDisplayLabel = ai.loadLabel(context.getPackageManager());
proc.mLabel = proc.mDisplayLabel.toString();
proc.mPackageInfo = ai;
}
} catch (PackageManager.NameNotFoundException e) {
}
procs.put(si.process, proc); procs.put(si.process, proc);
} }
@@ -277,76 +429,127 @@ public class RunningServices extends ListActivity
int pid = si.restarting == 0 ? si.pid : 0; int pid = si.restarting == 0 ? si.pid : 0;
if (pid != proc.mPid) { if (pid != proc.mPid) {
changed = true; changed = true;
proc.mPid = pid; if (proc.mPid != pid) {
} if (proc.mPid != 0) {
proc.mSize = 0; mActiveProcesses.remove(proc.mPid);
if (proc.mPid != 0) {
Debug.MemoryInfo mi = new Debug.MemoryInfo();
// XXX This is a hack... I really don't want to be
// doing a synchronous call into the app, but can't
// figure out any other way to get the pss.
try {
ActivityManagerNative.getDefault().getProcessMemoryInfo(
proc.mPid, mi);
proc.mSize = (mi.dalvikPss + mi.nativePss
+ mi.otherPss) * 1024;
String sizeStr = Formatter.formatFileSize(
context, proc.mSize);
if (!sizeStr.equals(proc.mSizeStr)){
changed = true;
proc.mSizeStr = sizeStr;
} }
} catch (RemoteException e) { if (pid != 0) {
mActiveProcesses.put(pid, proc);
}
proc.mPid = pid;
} }
} }
proc.mSize = 0;
proc.mDependentProcesses.clear();
proc.mCurSeq = mSequence; proc.mCurSeq = mSequence;
} }
changed |= proc.updateService(context, si); changed |= proc.updateService(context, si);
}
if (proc.mLabel == null) {
// If we couldn't get information about the overall // Now update the map of other processes that are running (but
// process, try to find something about the uid. // don't have services actively running inside them).
String[] pkgs = pm.getPackagesForUid(proc.mUid); List<ActivityManager.RunningAppProcessInfo> processes
for (String name : pkgs) { = am.getRunningAppProcesses();
try { final int NP = processes != null ? processes.size() : 0;
PackageInfo pi = pm.getPackageInfo(name, 0); for (int i=0; i<NP; i++) {
if (pi.sharedUserLabel != 0) { ActivityManager.RunningAppProcessInfo pi = processes.get(i);
CharSequence nm = pm.getText(name, ProcessItem proc = mActiveProcesses.get(pi.pid);
pi.sharedUserLabel, pi.applicationInfo); if (proc == null) {
if (nm != null) { // This process is not one that is a direct container
proc.mDisplayLabel = nm; // of a service, so look for it in the secondary
proc.mLabel = nm.toString(); // running list.
proc.mPackageInfo = pi.applicationInfo; proc = mRunningProcesses.get(pi.pid);
break; if (proc == null) {
} proc = new ProcessItem(pi.uid, pi.processName);
} proc.mPid = pi.pid;
} catch (PackageManager.NameNotFoundException e) { mRunningProcesses.put(pi.pid, proc);
}
} }
proc.mDependentProcesses.clear();
// If still don't have anything to display, just use the proc.mSize = 0;
// service info. }
if (proc.mLabel == null) { proc.mRunningSeq = mSequence;
proc.mPackageInfo = proc.mServices.get(si.service) proc.mRunningProcessInfo = pi;
.mServiceInfo.applicationInfo; }
proc.mDisplayLabel = proc.mPackageInfo.loadLabel(pm);
proc.mLabel = proc.mDisplayLabel.toString(); // Build the chains from client processes to the process they are
// dependent on; also remove any old running processes.
int NRP = mRunningProcesses.size();
for (int i=0; i<NRP; i++) {
ProcessItem proc = mRunningProcesses.valueAt(i);
if (proc.mRunningSeq == mSequence) {
int clientPid = proc.mRunningProcessInfo.importanceReasonPid;
if (clientPid != 0) {
ProcessItem client = mActiveProcesses.get(clientPid);
if (client == null) {
client = mRunningProcesses.get(clientPid);
}
if (client != null) {
client.mDependentProcesses.put(proc.mPid, proc);
}
} else {
// In this pass the process doesn't have a client.
// Clear to make sure if it later gets the same one
// that we will detect the change.
proc.mClient = null;
}
} else {
mRunningProcesses.remove(mRunningProcesses.keyAt(i));
}
}
// Follow the tree from all primary service processes to all
// processes they are dependent on, marking these processes as
// still being active and determining if anything has changed.
final int NAP = mActiveProcesses.size();
for (int i=0; i<NAP; i++) {
ProcessItem proc = mActiveProcesses.valueAt(i);
if (proc.mCurSeq == mSequence) {
changed |= proc.buildDependencyChain(context, pm, mSequence);
}
}
// Count number of interesting other (non-active) processes.
mNumBackgroundProcesses = 0;
mNumForegroundProcesses = 0;
NRP = mRunningProcesses.size();
for (int i=0; i<NRP; i++) {
ProcessItem proc = mRunningProcesses.valueAt(i);
if (proc.mCurSeq != mSequence) {
// We didn't hit this process as a dependency on one
// of our active ones, so add it up if needed.
if (proc.mRunningProcessInfo.importance >=
ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND) {
mNumBackgroundProcesses++;
} else if (proc.mRunningProcessInfo.importance <=
ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE) {
mNumForegroundProcesses++;
} }
} }
} }
// Look for anything that no longer exists... // Look for services and their primary processes that no longer exist...
for (int i=0; i<mProcesses.size(); i++) { for (int i=0; i<mProcesses.size(); i++) {
HashMap<String, ProcessItem> procs = mProcesses.valueAt(i); HashMap<String, ProcessItem> procs = mProcesses.valueAt(i);
Iterator<ProcessItem> pit = procs.values().iterator(); Iterator<ProcessItem> pit = procs.values().iterator();
while (pit.hasNext()) { while (pit.hasNext()) {
ProcessItem pi = pit.next(); ProcessItem pi = pit.next();
if (pi.mCurSeq != mSequence) { if (pi.mCurSeq == mSequence) {
pi.ensureLabel(pm);
changed |= pi.updateSize(context);
if (pi.mPid == 0) {
// Sanity: a non-process can't be dependent on
// anything.
pi.mDependentProcesses.clear();
}
} else {
changed = true; changed = true;
pit.remove(); pit.remove();
if (procs.size() == 0) { if (procs.size() == 0) {
mProcesses.remove(mProcesses.keyAt(i)); mProcesses.remove(mProcesses.keyAt(i));
} }
if (pi.mPid != 0) {
mActiveProcesses.remove(pi.mPid);
}
continue; continue;
} }
Iterator<ServiceItem> sit = pi.mServices.values().iterator(); Iterator<ServiceItem> sit = pi.mServices.values().iterator();
@@ -365,7 +568,11 @@ public class RunningServices extends ListActivity
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.mNeedDivider = false;
// First add processes we are dependent on.
pi.addDependentProcesses(mItems);
// And add the process itself.
mItems.add(pi); mItems.add(pi);
// And finally the services running in it.
boolean needDivider = false; boolean needDivider = false;
for (ServiceItem si : pi.mServices.values()) { for (ServiceItem si : pi.mServices.values()) {
si.mNeedDivider = needDivider; si.mNeedDivider = needDivider;
@@ -456,25 +663,25 @@ public class RunningServices extends ListActivity
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);
ActiveItem ai = new ActiveItem();
ai.mRootView = view;
ai.mItem = item;
ai.mHolder = vh;
ai.mFirstRunTime = item.mActiveSince;
vh.description.setText(item.mDescription);
if (item.mIsProcess) { if (item.mIsProcess) {
view.setBackgroundColor(mProcessBgColor); view.setBackgroundColor(mProcessBgColor);
vh.icon.setImageDrawable(item.mPackageInfo.loadIcon(getPackageManager())); vh.icon.setImageDrawable(item.mPackageInfo.loadIcon(getPackageManager()));
vh.description.setText(item.mDescription); vh.description.setText(item.mDescription);
vh.size.setText(item.mSizeStr); item.mCurSizeStr = null;
mActiveItems.remove(view);
} else { } else {
view.setBackgroundDrawable(null); view.setBackgroundDrawable(null);
vh.icon.setImageDrawable(null); vh.icon.setImageDrawable(null);
vh.description.setText("");
ActiveItem ai = new ActiveItem();
ai.mRootView = view;
ai.mItem = item;
ai.mHolder = vh;
ai.mFirstRunTime = item.mActiveSince;
vh.description.setText(item.mDescription); vh.description.setText(item.mDescription);
ai.updateTime(RunningServices.this); ai.mFirstRunTime = item.mActiveSince;
mActiveItems.put(view, ai);
} }
ai.updateTime(RunningServices.this);
mActiveItems.put(view, ai);
} }
} }
@@ -516,14 +723,27 @@ public class RunningServices extends ListActivity
mState = new State(); mState = new State();
} }
mProcessBgColor = 0xff505050; mProcessBgColor = 0xff505050;
setContentView(R.layout.running_services);
getListView().setDivider(null); getListView().setDivider(null);
getListView().setAdapter(new ServiceListAdapter(mState)); getListView().setAdapter(new ServiceListAdapter(mState));
mBackgroundProcessText = (TextView)findViewById(R.id.backgroundText);
mForegroundProcessText = (TextView)findViewById(R.id.foregroundText);
} }
void updateList() { void updateList() {
if (mState.update(this, mAm)) { if (mState.update(this, mAm)) {
((ServiceListAdapter)(getListView().getAdapter())).notifyDataSetChanged(); ((ServiceListAdapter)(getListView().getAdapter())).notifyDataSetChanged();
} }
if (mLastNumBackgroundProcesses != mState.mNumBackgroundProcesses) {
mLastNumBackgroundProcesses = mState.mNumBackgroundProcesses;
mBackgroundProcessText.setText(getResources().getString(
R.string.service_background_processes, mLastNumBackgroundProcesses));
}
if (mLastNumForegroundProcesses != mState.mNumForegroundProcesses) {
mLastNumForegroundProcesses = mState.mNumForegroundProcesses;
mForegroundProcessText.setText(getResources().getString(
R.string.service_foreground_processes, mLastNumForegroundProcesses));
}
} }
@Override @Override
@@ -537,9 +757,16 @@ public class RunningServices extends ListActivity
si.mRunningService.service); si.mRunningService.service);
if (pi != null) { if (pi != null) {
try { try {
pi.send(); this.startActivity(pi, null,
Intent.FLAG_ACTIVITY_NEW_TASK
| Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET,
Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
} catch (PendingIntent.CanceledException e) { } catch (PendingIntent.CanceledException e) {
// whatever. Log.w(TAG, e);
} catch (IllegalArgumentException e) {
Log.w(TAG, e);
} catch (ActivityNotFoundException e) {
Log.w(TAG, e);
} }
} }
} else { } else {