diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index c4900fd5b9b..24fc8b04c19 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -56,6 +56,9 @@
+
+
+
RAM
%1$s
+
+ User: %1$s
%1$d
process and %2$d service
diff --git a/src/com/android/settings/Settings.java b/src/com/android/settings/Settings.java
index 364f96a938a..f8c23d77ad8 100644
--- a/src/com/android/settings/Settings.java
+++ b/src/com/android/settings/Settings.java
@@ -102,6 +102,7 @@ public class Settings extends PreferenceActivity
R.id.device_section,
R.id.sound_settings,
R.id.display_settings,
+ R.id.application_settings,
R.id.personal_section,
R.id.security_settings,
R.id.account_settings,
diff --git a/src/com/android/settings/applications/RunningProcessesView.java b/src/com/android/settings/applications/RunningProcessesView.java
index 7c3ebb03429..67221aef3e2 100644
--- a/src/com/android/settings/applications/RunningProcessesView.java
+++ b/src/com/android/settings/applications/RunningProcessesView.java
@@ -26,6 +26,7 @@ import android.content.Context;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.os.SystemClock;
+import android.os.UserHandle;
import android.preference.PreferenceActivity;
import android.text.format.DateUtils;
import android.text.format.Formatter;
@@ -42,6 +43,7 @@ import android.widget.TextView;
import android.widget.AbsListView.RecyclerListener;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
@@ -49,10 +51,12 @@ public class RunningProcessesView extends FrameLayout
implements AdapterView.OnItemClickListener, RecyclerListener,
RunningState.OnRefreshUiListener {
+ final int mMyUserId;
+
long SECONDARY_SERVER_MEM;
final HashMap mActiveItems = new HashMap();
-
+
ActivityManager mAm;
RunningState mState;
@@ -167,9 +171,12 @@ public class RunningProcessesView extends FrameLayout
if (item.mPackageInfo == null && item instanceof RunningState.MergedItem) {
// Items for background processes don't normally load
// their labels for performance reasons. Do it now.
- ((RunningState.MergedItem)item).mProcess.ensureLabel(pm);
- item.mPackageInfo = ((RunningState.MergedItem)item).mProcess.mPackageInfo;
- item.mDisplayLabel = ((RunningState.MergedItem)item).mProcess.mDisplayLabel;
+ RunningState.MergedItem mergedItem = (RunningState.MergedItem)item;
+ if (mergedItem.mProcess != null) {
+ ((RunningState.MergedItem)item).mProcess.ensureLabel(pm);
+ item.mPackageInfo = ((RunningState.MergedItem)item).mProcess.mPackageInfo;
+ item.mDisplayLabel = ((RunningState.MergedItem)item).mProcess.mDisplayLabel;
+ }
}
name.setText(item.mDisplayLabel);
ActiveItem ai = new ActiveItem();
@@ -183,9 +190,7 @@ public class RunningProcessesView extends FrameLayout
description.setText(item.mDescription);
}
item.mCurSizeStr = null;
- if (item.mPackageInfo != null) {
- icon.setImageDrawable(item.mPackageInfo.loadIcon(pm));
- }
+ icon.setImageDrawable(item.loadIcon(rootView.getContext(), state));
icon.setVisibility(View.VISIBLE);
ai.updateTime(rootView.getContext(), builder);
return ai;
@@ -203,7 +208,9 @@ public class RunningProcessesView extends FrameLayout
final RunningState mState;
final LayoutInflater mInflater;
boolean mShowBackground;
- ArrayList mItems;
+ ArrayList mOrigItems;
+ final ArrayList mItems
+ = new ArrayList();
ServiceListAdapter(RunningState state) {
mState = state;
@@ -230,11 +237,17 @@ public class RunningProcessesView extends FrameLayout
ArrayList newItems =
mShowBackground ? mState.getCurrentBackgroundItems()
: mState.getCurrentMergedItems();
- if (mItems != newItems) {
- mItems = newItems;
- }
- if (mItems == null) {
- mItems = new ArrayList();
+ if (mOrigItems != newItems) {
+ mOrigItems = newItems;
+ if (newItems == null) {
+ mItems.clear();
+ } else {
+ mItems.clear();
+ mItems.addAll(newItems);
+ if (mShowBackground) {
+ Collections.sort(mItems, mState.mBackgroundComparator);
+ }
+ }
}
}
@@ -374,8 +387,11 @@ public class RunningProcessesView extends FrameLayout
if (mOwner != null) {
// start new fragment to display extended information
Bundle args = new Bundle();
- args.putInt(RunningServiceDetails.KEY_UID, mi.mProcess.mUid);
- args.putString(RunningServiceDetails.KEY_PROCESS, mi.mProcess.mProcessName);
+ if (mi.mProcess != null) {
+ args.putInt(RunningServiceDetails.KEY_UID, mi.mProcess.mUid);
+ args.putString(RunningServiceDetails.KEY_PROCESS, mi.mProcess.mProcessName);
+ }
+ args.putInt(RunningServiceDetails.KEY_USER_ID, mi.mUserId);
args.putBoolean(RunningServiceDetails.KEY_BACKGROUND, mAdapter.mShowBackground);
PreferenceActivity pa = (PreferenceActivity)mOwner.getActivity();
@@ -390,6 +406,7 @@ public class RunningProcessesView extends FrameLayout
public RunningProcessesView(Context context, AttributeSet attrs) {
super(context, attrs);
+ mMyUserId = UserHandle.myUserId();
}
public void doCreate(Bundle savedInstanceState) {
diff --git a/src/com/android/settings/applications/RunningServiceDetails.java b/src/com/android/settings/applications/RunningServiceDetails.java
index 2087f21397e..52ed4586134 100644
--- a/src/com/android/settings/applications/RunningServiceDetails.java
+++ b/src/com/android/settings/applications/RunningServiceDetails.java
@@ -26,6 +26,7 @@ import android.os.Bundle;
import android.os.Debug;
import android.os.Handler;
import android.os.SystemClock;
+import android.os.UserHandle;
import android.provider.Settings;
import android.util.Log;
import android.view.LayoutInflater;
@@ -39,35 +40,38 @@ import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
+import java.util.Collections;
public class RunningServiceDetails extends Fragment
implements RunningState.OnRefreshUiListener {
static final String TAG = "RunningServicesDetails";
-
+
static final String KEY_UID = "uid";
+ static final String KEY_USER_ID = "user_id";
static final String KEY_PROCESS = "process";
static final String KEY_BACKGROUND = "background";
-
+
static final int DIALOG_CONFIRM_STOP = 1;
-
+
ActivityManager mAm;
LayoutInflater mInflater;
-
+
RunningState mState;
boolean mHaveData;
-
+
int mUid;
+ int mUserId;
String mProcessName;
boolean mShowBackground;
-
+
RunningState.MergedItem mMergedItem;
-
+
View mRootView;
ViewGroup mAllDetails;
ViewGroup mSnippet;
RunningProcessesView.ActiveItem mSnippetActiveItem;
RunningProcessesView.ViewHolder mSnippetViewHolder;
-
+
int mNumServices, mNumProcesses;
TextView mServicesHeader;
@@ -195,8 +199,14 @@ public class RunningServiceDetails extends Fragment
if (newItems != null) {
for (int i=0; i= 0 && mi.mProcess != null && mi.mProcess.mUid != mUid) {
+ continue;
+ }
+ if (mProcessName == null || (mi.mProcess != null
+ && mProcessName.equals(mi.mProcess.mProcessName))) {
item = mi;
break;
}
@@ -209,8 +219,8 @@ public class RunningServiceDetails extends Fragment
}
return false;
}
-
- void addServiceDetailsView(RunningState.ServiceItem si, RunningState.MergedItem mi) {
+
+ void addServicesHeader() {
if (mNumServices == 0) {
mServicesHeader = (TextView)mInflater.inflate(R.layout.separator_label,
mAllDetails, false);
@@ -218,7 +228,30 @@ public class RunningServiceDetails extends Fragment
mAllDetails.addView(mServicesHeader);
}
mNumServices++;
-
+ }
+
+ void addProcessesHeader() {
+ if (mNumProcesses == 0) {
+ mProcessesHeader = (TextView)mInflater.inflate(R.layout.separator_label,
+ mAllDetails, false);
+ mProcessesHeader.setText(R.string.runningservicedetails_processes_title);
+ mAllDetails.addView(mProcessesHeader);
+ }
+ mNumProcesses++;
+ }
+
+ void addServiceDetailsView(RunningState.ServiceItem si, RunningState.MergedItem mi,
+ boolean isService, boolean inclDetails) {
+ if (isService) {
+ addServicesHeader();
+ } else if (mi.mUserId != UserHandle.myUserId()) {
+ // This is being called for another user, and is not a service...
+ // That is, it is a background processes, being added for the
+ // details of a user. In this case we want a header for processes,
+ // since the top subject line is for the user.
+ addProcessesHeader();
+ }
+
RunningState.BaseItem bi = si != null ? si : mi;
ActiveDetail detail = new ActiveDetail();
@@ -229,68 +262,74 @@ public class RunningServiceDetails extends Fragment
detail.mServiceItem = si;
detail.mViewHolder = new RunningProcessesView.ViewHolder(root);
detail.mActiveItem = detail.mViewHolder.bind(mState, bi, mBuilder);
-
+
+ if (!inclDetails) {
+ root.findViewById(R.id.service).setVisibility(View.GONE);
+ }
+
if (si != null && si.mRunningService.clientLabel != 0) {
detail.mManageIntent = mAm.getRunningServiceControlPanel(
si.mRunningService.service);
}
TextView description = (TextView)root.findViewById(R.id.comp_description);
- if (si != null && si.mServiceInfo.descriptionRes != 0) {
- description.setText(getActivity().getPackageManager().getText(
- si.mServiceInfo.packageName, si.mServiceInfo.descriptionRes,
- si.mServiceInfo.applicationInfo));
+ detail.mStopButton = (Button)root.findViewById(R.id.left_button);
+ detail.mReportButton = (Button)root.findViewById(R.id.right_button);
+
+ if (isService && mi.mUserId != UserHandle.myUserId()) {
+ // For services from other users, we don't show any description or
+ // controls, because the current user can not perform
+ // actions on them.
+ description.setVisibility(View.GONE);
+ root.findViewById(R.id.control_buttons_panel).setVisibility(View.GONE);
} else {
- if (mi.mBackground) {
- description.setText(R.string.background_process_stop_description);
- } else if (detail.mManageIntent != null) {
- try {
- Resources clientr = getActivity().getPackageManager().getResourcesForApplication(
- si.mRunningService.clientPackage);
- String label = clientr.getString(si.mRunningService.clientLabel);
- description.setText(getActivity().getString(R.string.service_manage_description,
- label));
- } catch (PackageManager.NameNotFoundException e) {
- }
+ if (si != null && si.mServiceInfo.descriptionRes != 0) {
+ description.setText(getActivity().getPackageManager().getText(
+ si.mServiceInfo.packageName, si.mServiceInfo.descriptionRes,
+ si.mServiceInfo.applicationInfo));
} else {
- description.setText(getActivity().getText(si != null
- ? R.string.service_stop_description
- : R.string.heavy_weight_stop_description));
+ if (mi.mBackground) {
+ description.setText(R.string.background_process_stop_description);
+ } else if (detail.mManageIntent != null) {
+ try {
+ Resources clientr = getActivity().getPackageManager().getResourcesForApplication(
+ si.mRunningService.clientPackage);
+ String label = clientr.getString(si.mRunningService.clientLabel);
+ description.setText(getActivity().getString(R.string.service_manage_description,
+ label));
+ } catch (PackageManager.NameNotFoundException e) {
+ }
+ } else {
+ description.setText(getActivity().getText(si != null
+ ? R.string.service_stop_description
+ : R.string.heavy_weight_stop_description));
+ }
+ }
+
+ detail.mStopButton.setOnClickListener(detail);
+ detail.mStopButton.setText(getActivity().getText(detail.mManageIntent != null
+ ? R.string.service_manage : R.string.service_stop));
+ detail.mReportButton.setOnClickListener(detail);
+ detail.mReportButton.setText(com.android.internal.R.string.report);
+ // check if error reporting is enabled in secure settings
+ int enabled = Settings.Secure.getInt(getActivity().getContentResolver(),
+ Settings.Secure.SEND_ACTION_APP_ERROR, 0);
+ if (enabled != 0 && si != null) {
+ detail.mInstaller = ApplicationErrorReport.getErrorReportReceiver(
+ getActivity(), si.mServiceInfo.packageName,
+ si.mServiceInfo.applicationInfo.flags);
+ detail.mReportButton.setEnabled(detail.mInstaller != null);
+ } else {
+ detail.mReportButton.setEnabled(false);
}
}
-
- detail.mStopButton = (Button)root.findViewById(R.id.left_button);
- detail.mStopButton.setOnClickListener(detail);
- detail.mStopButton.setText(getActivity().getText(detail.mManageIntent != null
- ? R.string.service_manage : R.string.service_stop));
- detail.mReportButton = (Button)root.findViewById(R.id.right_button);
- detail.mReportButton.setOnClickListener(detail);
- detail.mReportButton.setText(com.android.internal.R.string.report);
- // check if error reporting is enabled in secure settings
- int enabled = Settings.Secure.getInt(getActivity().getContentResolver(),
- Settings.Secure.SEND_ACTION_APP_ERROR, 0);
- if (enabled != 0 && si != null) {
- detail.mInstaller = ApplicationErrorReport.getErrorReportReceiver(
- getActivity(), si.mServiceInfo.packageName,
- si.mServiceInfo.applicationInfo.flags);
- detail.mReportButton.setEnabled(detail.mInstaller != null);
- } else {
- detail.mReportButton.setEnabled(false);
- }
-
mActiveDetails.add(detail);
}
-
+
void addProcessDetailsView(RunningState.ProcessItem pi, boolean isMain) {
- if (mNumProcesses == 0) {
- mProcessesHeader = (TextView)mInflater.inflate(R.layout.separator_label,
- mAllDetails, false);
- mProcessesHeader.setText(R.string.runningservicedetails_processes_title);
- mAllDetails.addView(mProcessesHeader);
- }
- mNumProcesses++;
-
+ addProcessesHeader();
+
ActiveDetail detail = new ActiveDetail();
View root = mInflater.inflate(R.layout.running_service_details_process,
mAllDetails, false);
@@ -300,7 +339,11 @@ public class RunningServiceDetails extends Fragment
detail.mActiveItem = detail.mViewHolder.bind(mState, pi, mBuilder);
TextView description = (TextView)root.findViewById(R.id.comp_description);
- if (isMain) {
+ if (pi.mUserId != UserHandle.myUserId()) {
+ // Processes for another user are all shown batched together; there is
+ // no reason to have a description.
+ description.setVisibility(View.GONE);
+ } else if (isMain) {
description.setText(R.string.main_running_process_description);
} else {
int textid = 0;
@@ -342,7 +385,39 @@ public class RunningServiceDetails extends Fragment
mActiveDetails.add(detail);
}
+
+ void addDetailsViews(RunningState.MergedItem item, boolean inclServices,
+ boolean inclProcesses) {
+ if (item != null) {
+ if (inclServices) {
+ for (int i=0; i=0; i--) {
mAllDetails.removeView(mActiveDetails.get(i).mRootView);
@@ -358,30 +433,25 @@ public class RunningServiceDetails extends Fragment
mAllDetails.removeView(mProcessesHeader);
mProcessesHeader = null;
}
-
+
mNumServices = mNumProcesses = 0;
-
- if (mMergedItem != null) {
- for (int i=0; i items;
+ if (mShowBackground) {
+ items = new ArrayList(mMergedItem.mChildren);
+ Collections.sort(items, mState.mBackgroundComparator);
+ } else {
+ items = mMergedItem.mChildren;
}
-
- if (mMergedItem.mServices.size() <= 0) {
- // This item does not have any services, so it must be
- // another interesting process... we will put a fake service
- // entry for it, to allow the user to "stop" it.
- addServiceDetailsView(null, mMergedItem);
+ for (int i=0; i mAllProcessItems = new ArrayList();
+ // If there are other users on the device, these are the merged items
+ // representing all items that would be put in mMergedItems for that user.
+ final SparseArray mOtherUserMergedItems = new SparseArray();
+
+ // If there are other users on the device, these are the merged items
+ // representing all items that would be put in mUserBackgroundItems for that user.
+ final SparseArray mOtherUserBackgroundItems = new SparseArray();
+
+ // Tracking of information about users.
+ final SparseArray mUsers = new SparseArray();
+
static class AppProcessInfo {
final ActivityManager.RunningAppProcessInfo info;
boolean hasServices;
@@ -114,7 +134,64 @@ public class RunningState {
final SparseArray mTmpAppProcesses = new SparseArray();
int mSequence = 0;
-
+
+ final Comparator mBackgroundComparator
+ = new Comparator() {
+ @Override
+ public int compare(MergedItem lhs, MergedItem rhs) {
+ if (DEBUG_COMPARE) {
+ Log.i(TAG, "Comparing " + lhs + " with " + rhs);
+ Log.i(TAG, " Proc " + lhs.mProcess + " with " + rhs.mProcess);
+ Log.i(TAG, " UserId " + lhs.mUserId + " with " + rhs.mUserId);
+ }
+ if (lhs.mUserId != rhs.mUserId) {
+ if (lhs.mUserId == mMyUserId) return -1;
+ if (rhs.mUserId == mMyUserId) return 1;
+ return lhs.mUserId < rhs.mUserId ? -1 : 1;
+ }
+ if (lhs.mProcess == rhs.mProcess) {
+ if (lhs.mLabel == rhs.mLabel) {
+ return 0;
+ }
+ return lhs.mLabel != null ? lhs.mLabel.compareTo(rhs.mLabel) : -1;
+ }
+ if (lhs.mProcess == null) return -1;
+ if (rhs.mProcess == null) return 1;
+ if (DEBUG_COMPARE) Log.i(TAG, " Label " + lhs.mProcess.mLabel
+ + " with " + rhs.mProcess.mLabel);
+ final ActivityManager.RunningAppProcessInfo lhsInfo
+ = lhs.mProcess.mRunningProcessInfo;
+ final ActivityManager.RunningAppProcessInfo rhsInfo
+ = rhs.mProcess.mRunningProcessInfo;
+ final boolean lhsBg = lhsInfo.importance
+ >= ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND;
+ final boolean rhsBg = rhsInfo.importance
+ >= ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND;
+ if (DEBUG_COMPARE) Log.i(TAG, " Bg " + lhsBg + " with " + rhsBg);
+ if (lhsBg != rhsBg) {
+ return lhsBg ? 1 : -1;
+ }
+ final boolean lhsA = (lhsInfo.flags
+ & ActivityManager.RunningAppProcessInfo.FLAG_HAS_ACTIVITIES) != 0;
+ final boolean rhsA = (rhsInfo.flags
+ & ActivityManager.RunningAppProcessInfo.FLAG_HAS_ACTIVITIES) != 0;
+ if (DEBUG_COMPARE) Log.i(TAG, " Act " + lhsA + " with " + rhsA);
+ if (lhsA != rhsA) {
+ return lhsA ? -1 : 1;
+ }
+ if (DEBUG_COMPARE) Log.i(TAG, " Lru " + lhsInfo.lru + " with " + rhsInfo.lru);
+ if (lhsInfo.lru != rhsInfo.lru) {
+ return lhsInfo.lru < rhsInfo.lru ? -1 : 1;
+ }
+ if (lhs.mProcess.mLabel == rhs.mProcess.mLabel) {
+ return 0;
+ }
+ if (lhs.mProcess.mLabel == null) return 1;
+ if (rhs.mProcess.mLabel == null) return -1;
+ return lhs.mProcess.mLabel.compareTo(rhs.mProcess.mLabel);
+ }
+ };
+
// ----- following protected by mLock -----
// Lock for protecting the state that will be shared between the
@@ -128,6 +205,7 @@ public class RunningState {
ArrayList mItems = new ArrayList();
ArrayList mMergedItems = new ArrayList();
ArrayList mBackgroundItems = new ArrayList();
+ ArrayList mUserBackgroundItems = new ArrayList();
int mNumBackgroundProcesses;
long mBackgroundProcessMemory;
@@ -211,25 +289,40 @@ public class RunningState {
public void onRefreshUi(int what);
}
+ static class UserState {
+ UserInfo mInfo;
+ String mLabel;
+ Drawable mIcon;
+ }
+
static class BaseItem {
final boolean mIsProcess;
-
+ final int mUserId;
+
PackageItemInfo mPackageInfo;
CharSequence mDisplayLabel;
String mLabel;
String mDescription;
-
+
int mCurSeq;
-
+
long mActiveSince;
long mSize;
String mSizeStr;
String mCurSizeStr;
boolean mNeedDivider;
boolean mBackground;
-
- public BaseItem(boolean isProcess) {
+
+ public BaseItem(boolean isProcess, int userId) {
mIsProcess = isProcess;
+ mUserId = userId;
+ }
+
+ public Drawable loadIcon(Context context, RunningState state) {
+ if (mPackageInfo != null) {
+ return mPackageInfo.loadIcon(state.mPm);
+ }
+ return null;
}
}
@@ -240,8 +333,8 @@ public class RunningState {
MergedItem mMergedItem;
- public ServiceItem() {
- super(false);
+ public ServiceItem(int userId) {
+ super(false, userId);
}
}
@@ -271,7 +364,7 @@ public class RunningState {
long mActiveSince;
public ProcessItem(Context context, int uid, String processName) {
- super(true);
+ super(true, UserHandle.getUserId(uid));
mDescription = context.getResources().getString(
R.string.service_process_name, processName);
mUid = uid;
@@ -332,8 +425,9 @@ public class RunningState {
// If still don't have anything to display, just use the
// service info.
if (mServices.size() > 0) {
- mPackageInfo = mServices.values().iterator().next()
+ ApplicationInfo ai = mServices.values().iterator().next()
.mServiceInfo.applicationInfo;
+ mPackageInfo = ai;
mDisplayLabel = mPackageInfo.loadLabel(pm);
mLabel = mDisplayLabel.toString();
return;
@@ -358,7 +452,7 @@ public class RunningState {
ServiceItem si = mServices.get(service.service);
if (si == null) {
changed = true;
- si = new ServiceItem();
+ si = new ServiceItem(mUserId);
si.mRunningService = service;
try {
si.mServiceInfo = pm.getServiceInfo(service.service, 0);
@@ -456,55 +550,96 @@ public class RunningState {
static class MergedItem extends BaseItem {
ProcessItem mProcess;
+ UserState mUser;
final ArrayList mOtherProcesses = new ArrayList();
final ArrayList mServices = new ArrayList();
+ final ArrayList mChildren = new ArrayList();
private int mLastNumProcesses = -1, mLastNumServices = -1;
- MergedItem() {
- super(false);
+ MergedItem(int userId) {
+ super(false, userId);
}
-
+
+ private void setDescription(Context context, int numProcesses, int numServices) {
+ if (mLastNumProcesses != numProcesses || mLastNumServices != numServices) {
+ mLastNumProcesses = numProcesses;
+ mLastNumServices = numServices;
+ int resid = R.string.running_processes_item_description_s_s;
+ if (numProcesses != 1) {
+ resid = numServices != 1
+ ? R.string.running_processes_item_description_p_p
+ : R.string.running_processes_item_description_p_s;
+ } else if (numServices != 1) {
+ resid = R.string.running_processes_item_description_s_p;
+ }
+ mDescription = context.getResources().getString(resid, numProcesses,
+ numServices);
+ }
+ }
+
boolean update(Context context, boolean background) {
- mPackageInfo = mProcess.mPackageInfo;
- mDisplayLabel = mProcess.mDisplayLabel;
- mLabel = mProcess.mLabel;
mBackground = background;
-
- if (!mBackground) {
- int numProcesses = (mProcess.mPid > 0 ? 1 : 0) + mOtherProcesses.size();
- int numServices = mServices.size();
- if (mLastNumProcesses != numProcesses || mLastNumServices != numServices) {
- mLastNumProcesses = numProcesses;
- mLastNumServices = numServices;
- int resid = R.string.running_processes_item_description_s_s;
- if (numProcesses != 1) {
- resid = numServices != 1
- ? R.string.running_processes_item_description_p_p
- : R.string.running_processes_item_description_p_s;
- } else if (numServices != 1) {
- resid = R.string.running_processes_item_description_s_p;
+
+ if (mUser != null) {
+ // This is a merged item that contains a child collection
+ // of items... that is, it is an entire user, containing
+ // everything associated with that user. So set it up as such.
+ // For concrete stuff we need about the process of this item,
+ // we will just use the info from the first child.
+ MergedItem child0 = mChildren.get(0);
+ mPackageInfo = child0.mProcess.mPackageInfo;
+ mLabel = mUser != null ? mUser.mLabel : null;
+ mDisplayLabel = mLabel;
+ int numProcesses = 0;
+ int numServices = 0;
+ mActiveSince = -1;
+ for (int i=0; i= 0 && mActiveSince < child.mActiveSince) {
+ mActiveSince = child.mActiveSince;
+ }
+ }
+ if (!mBackground) {
+ setDescription(context, numProcesses, numServices);
+ }
+ } else {
+ mPackageInfo = mProcess.mPackageInfo;
+ mDisplayLabel = mProcess.mDisplayLabel;
+ mLabel = mProcess.mLabel;
+
+ if (!mBackground) {
+ setDescription(context, (mProcess.mPid > 0 ? 1 : 0) + mOtherProcesses.size(),
+ mServices.size());
+ }
+
+ mActiveSince = -1;
+ for (int i=0; i= 0 && mActiveSince < si.mActiveSince) {
+ mActiveSince = si.mActiveSince;
}
- mDescription = context.getResources().getString(resid, numProcesses,
- numServices);
}
}
-
- mActiveSince = -1;
- for (int i=0; i= 0 && mActiveSince < si.mActiveSince) {
- mActiveSince = si.mActiveSince;
- }
- }
-
+
return false;
}
boolean updateSize(Context context) {
- mSize = mProcess.mSize;
- for (int i=0; i {
+
+ class ServiceProcessComparator implements Comparator {
public int compare(ProcessItem object1, ProcessItem object2) {
+ if (object1.mUserId != object2.mUserId) {
+ if (object1.mUserId == mMyUserId) return -1;
+ if (object2.mUserId == mMyUserId) return 1;
+ return object1.mUserId < object2.mUserId ? -1 : 1;
+ }
if (object1.mIsStarted != object2.mIsStarted) {
// Non-started processes go last.
return object1.mIsStarted ? -1 : 1;
@@ -570,6 +721,8 @@ public class RunningState {
mApplicationContext = context.getApplicationContext();
mAm = (ActivityManager)mApplicationContext.getSystemService(Context.ACTIVITY_SERVICE);
mPm = mApplicationContext.getPackageManager();
+ mUm = (UserManager)mApplicationContext.getSystemService(Context.USER_SERVICE);
+ mMyUserId = UserHandle.myUserId();
mResumed = false;
mBackgroundThread = new HandlerThread("RunningState:Background");
mBackgroundThread.start();
@@ -646,6 +799,42 @@ public class RunningState {
mRunningProcesses.clear();
mProcessItems.clear();
mAllProcessItems.clear();
+ mUsers.clear();
+ }
+
+ private void addOtherUserItem(Context context, ArrayList newMergedItems,
+ SparseArray userItems, MergedItem newItem) {
+ MergedItem userItem = userItems.get(newItem.mUserId);
+ boolean first = userItem == null || userItem.mCurSeq != mSequence;
+ if (first) {
+ if (userItem == null) {
+ userItem = new MergedItem(newItem.mUserId);
+ userItems.put(newItem.mUserId, userItem);
+ } else {
+ userItem.mChildren.clear();
+ }
+ userItem.mCurSeq = mSequence;
+ if ((userItem.mUser=mUsers.get(newItem.mUserId)) == null) {
+ userItem.mUser = new UserState();
+ UserInfo info = mUm.getUserInfo(newItem.mUserId);
+ userItem.mUser.mInfo = info;
+ if (info != null && info.iconPath != null) {
+ try {
+ userItem.mUser.mIcon = Drawable.createFromPath(info.iconPath);
+ } catch (Exception e) {
+ Log.w(TAG, "Failure loading user picture " + info.iconPath, e);
+ }
+ }
+ String name = info != null ? info.name : null;
+ if (name == null) {
+ name = Integer.toString(info.id);
+ }
+ userItem.mUser.mLabel = context.getResources().getString(
+ R.string.running_process_item_user_label, name);
+ }
+ newMergedItems.add(userItem);
+ }
+ userItem.mChildren.add(newItem);
}
private boolean update(Context context, ActivityManager am) {
@@ -940,6 +1129,7 @@ public class RunningState {
ArrayList newItems = new ArrayList();
ArrayList newMergedItems = new ArrayList();
+ SparseArray otherUsers = null;
mProcessItems.clear();
for (int i=0; i newBackgroundItems = null;
+ ArrayList newUserBackgroundItems = null;
+ boolean diffUsers = false;
try {
final int numProc = mAllProcessItems.size();
int[] pids = new int[numProc];
@@ -1066,18 +1277,22 @@ public class RunningState {
backgroundProcessMemory += proc.mSize;
MergedItem mergedItem;
if (newBackgroundItems != null) {
- mergedItem = proc.mMergedItem = new MergedItem();
+ mergedItem = proc.mMergedItem = new MergedItem(proc.mUserId);
proc.mMergedItem.mProcess = proc;
+ diffUsers |= mergedItem.mUserId != mMyUserId;
newBackgroundItems.add(mergedItem);
} else {
if (bgIndex >= mBackgroundItems.size()
|| mBackgroundItems.get(bgIndex).mProcess != proc) {
newBackgroundItems = new ArrayList(numBackgroundProcesses);
for (int bgi=0; bgi numBackgroundProcesses) {
newBackgroundItems = new ArrayList(numBackgroundProcesses);
for (int bgi=0; bgi();
+ final int NB = newBackgroundItems.size();
+ for (int i=0; i getCurrentBackgroundItems() {
synchronized (mLock) {
- return mBackgroundItems;
+ return mUserBackgroundItems;
}
}
}