Make manage apps UI multi-user aware.
The details screens still need some work. Change-Id: I850cc9ba9a8db7787fae629ae3cb6c6772c726f5
This commit is contained in:
@@ -56,6 +56,9 @@
|
|||||||
<uses-permission android:name="android.permission.MANAGE_USB" />
|
<uses-permission android:name="android.permission.MANAGE_USB" />
|
||||||
<uses-permission android:name="android.permission.SET_POINTER_SPEED" />
|
<uses-permission android:name="android.permission.SET_POINTER_SPEED" />
|
||||||
<uses-permission android:name="android.permission.SET_KEYBOARD_LAYOUT" />
|
<uses-permission android:name="android.permission.SET_KEYBOARD_LAYOUT" />
|
||||||
|
<uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" />
|
||||||
|
<uses-permission android:name="android.permission.COPY_PROTECTED_DATA" />
|
||||||
|
<uses-permission android:name="android.permission.MANAGE_USERS" />
|
||||||
|
|
||||||
<application android:label="@string/settings_label"
|
<application android:label="@string/settings_label"
|
||||||
android:icon="@mipmap/ic_launcher_settings"
|
android:icon="@mipmap/ic_launcher_settings"
|
||||||
|
@@ -2626,6 +2626,8 @@
|
|||||||
<string name="memory">RAM</string>
|
<string name="memory">RAM</string>
|
||||||
<!-- Text to label a process entry with the process name. -->
|
<!-- Text to label a process entry with the process name. -->
|
||||||
<string name="service_process_name"><xliff:g id="process">%1$s</xliff:g></string>
|
<string name="service_process_name"><xliff:g id="process">%1$s</xliff:g></string>
|
||||||
|
<!-- [CHAR LIMIT=NONE] Label of a running process that represents another user -->
|
||||||
|
<string name="running_process_item_user_label">User: <xliff:g id="user_name">%1$s</xliff:g></string>
|
||||||
<!-- Descriptive text of a running process: singular process, singular service. -->
|
<!-- Descriptive text of a running process: singular process, singular service. -->
|
||||||
<string name="running_processes_item_description_s_s"><xliff:g id="numprocess">%1$d</xliff:g>
|
<string name="running_processes_item_description_s_s"><xliff:g id="numprocess">%1$d</xliff:g>
|
||||||
process and <xliff:g id="numservices">%2$d</xliff:g> service</string>
|
process and <xliff:g id="numservices">%2$d</xliff:g> service</string>
|
||||||
|
@@ -102,6 +102,7 @@ public class Settings extends PreferenceActivity
|
|||||||
R.id.device_section,
|
R.id.device_section,
|
||||||
R.id.sound_settings,
|
R.id.sound_settings,
|
||||||
R.id.display_settings,
|
R.id.display_settings,
|
||||||
|
R.id.application_settings,
|
||||||
R.id.personal_section,
|
R.id.personal_section,
|
||||||
R.id.security_settings,
|
R.id.security_settings,
|
||||||
R.id.account_settings,
|
R.id.account_settings,
|
||||||
|
@@ -26,6 +26,7 @@ import android.content.Context;
|
|||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.SystemClock;
|
import android.os.SystemClock;
|
||||||
|
import android.os.UserHandle;
|
||||||
import android.preference.PreferenceActivity;
|
import android.preference.PreferenceActivity;
|
||||||
import android.text.format.DateUtils;
|
import android.text.format.DateUtils;
|
||||||
import android.text.format.Formatter;
|
import android.text.format.Formatter;
|
||||||
@@ -42,6 +43,7 @@ import android.widget.TextView;
|
|||||||
import android.widget.AbsListView.RecyclerListener;
|
import android.widget.AbsListView.RecyclerListener;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
|
|
||||||
@@ -49,6 +51,8 @@ public class RunningProcessesView extends FrameLayout
|
|||||||
implements AdapterView.OnItemClickListener, RecyclerListener,
|
implements AdapterView.OnItemClickListener, RecyclerListener,
|
||||||
RunningState.OnRefreshUiListener {
|
RunningState.OnRefreshUiListener {
|
||||||
|
|
||||||
|
final int mMyUserId;
|
||||||
|
|
||||||
long SECONDARY_SERVER_MEM;
|
long SECONDARY_SERVER_MEM;
|
||||||
|
|
||||||
final HashMap<View, ActiveItem> mActiveItems = new HashMap<View, ActiveItem>();
|
final HashMap<View, ActiveItem> mActiveItems = new HashMap<View, ActiveItem>();
|
||||||
@@ -167,10 +171,13 @@ public class RunningProcessesView extends FrameLayout
|
|||||||
if (item.mPackageInfo == null && item instanceof RunningState.MergedItem) {
|
if (item.mPackageInfo == null && item instanceof RunningState.MergedItem) {
|
||||||
// Items for background processes don't normally load
|
// Items for background processes don't normally load
|
||||||
// their labels for performance reasons. Do it now.
|
// their labels for performance reasons. Do it now.
|
||||||
|
RunningState.MergedItem mergedItem = (RunningState.MergedItem)item;
|
||||||
|
if (mergedItem.mProcess != null) {
|
||||||
((RunningState.MergedItem)item).mProcess.ensureLabel(pm);
|
((RunningState.MergedItem)item).mProcess.ensureLabel(pm);
|
||||||
item.mPackageInfo = ((RunningState.MergedItem)item).mProcess.mPackageInfo;
|
item.mPackageInfo = ((RunningState.MergedItem)item).mProcess.mPackageInfo;
|
||||||
item.mDisplayLabel = ((RunningState.MergedItem)item).mProcess.mDisplayLabel;
|
item.mDisplayLabel = ((RunningState.MergedItem)item).mProcess.mDisplayLabel;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
name.setText(item.mDisplayLabel);
|
name.setText(item.mDisplayLabel);
|
||||||
ActiveItem ai = new ActiveItem();
|
ActiveItem ai = new ActiveItem();
|
||||||
ai.mRootView = rootView;
|
ai.mRootView = rootView;
|
||||||
@@ -183,9 +190,7 @@ public class RunningProcessesView extends FrameLayout
|
|||||||
description.setText(item.mDescription);
|
description.setText(item.mDescription);
|
||||||
}
|
}
|
||||||
item.mCurSizeStr = null;
|
item.mCurSizeStr = null;
|
||||||
if (item.mPackageInfo != null) {
|
icon.setImageDrawable(item.loadIcon(rootView.getContext(), state));
|
||||||
icon.setImageDrawable(item.mPackageInfo.loadIcon(pm));
|
|
||||||
}
|
|
||||||
icon.setVisibility(View.VISIBLE);
|
icon.setVisibility(View.VISIBLE);
|
||||||
ai.updateTime(rootView.getContext(), builder);
|
ai.updateTime(rootView.getContext(), builder);
|
||||||
return ai;
|
return ai;
|
||||||
@@ -203,7 +208,9 @@ public class RunningProcessesView extends FrameLayout
|
|||||||
final RunningState mState;
|
final RunningState mState;
|
||||||
final LayoutInflater mInflater;
|
final LayoutInflater mInflater;
|
||||||
boolean mShowBackground;
|
boolean mShowBackground;
|
||||||
ArrayList<RunningState.MergedItem> mItems;
|
ArrayList<RunningState.MergedItem> mOrigItems;
|
||||||
|
final ArrayList<RunningState.MergedItem> mItems
|
||||||
|
= new ArrayList<RunningState.MergedItem>();
|
||||||
|
|
||||||
ServiceListAdapter(RunningState state) {
|
ServiceListAdapter(RunningState state) {
|
||||||
mState = state;
|
mState = state;
|
||||||
@@ -230,11 +237,17 @@ public class RunningProcessesView extends FrameLayout
|
|||||||
ArrayList<RunningState.MergedItem> newItems =
|
ArrayList<RunningState.MergedItem> newItems =
|
||||||
mShowBackground ? mState.getCurrentBackgroundItems()
|
mShowBackground ? mState.getCurrentBackgroundItems()
|
||||||
: mState.getCurrentMergedItems();
|
: mState.getCurrentMergedItems();
|
||||||
if (mItems != newItems) {
|
if (mOrigItems != newItems) {
|
||||||
mItems = newItems;
|
mOrigItems = newItems;
|
||||||
|
if (newItems == null) {
|
||||||
|
mItems.clear();
|
||||||
|
} else {
|
||||||
|
mItems.clear();
|
||||||
|
mItems.addAll(newItems);
|
||||||
|
if (mShowBackground) {
|
||||||
|
Collections.sort(mItems, mState.mBackgroundComparator);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (mItems == null) {
|
|
||||||
mItems = new ArrayList<RunningState.MergedItem>();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -374,8 +387,11 @@ public class RunningProcessesView extends FrameLayout
|
|||||||
if (mOwner != null) {
|
if (mOwner != null) {
|
||||||
// start new fragment to display extended information
|
// start new fragment to display extended information
|
||||||
Bundle args = new Bundle();
|
Bundle args = new Bundle();
|
||||||
|
if (mi.mProcess != null) {
|
||||||
args.putInt(RunningServiceDetails.KEY_UID, mi.mProcess.mUid);
|
args.putInt(RunningServiceDetails.KEY_UID, mi.mProcess.mUid);
|
||||||
args.putString(RunningServiceDetails.KEY_PROCESS, mi.mProcess.mProcessName);
|
args.putString(RunningServiceDetails.KEY_PROCESS, mi.mProcess.mProcessName);
|
||||||
|
}
|
||||||
|
args.putInt(RunningServiceDetails.KEY_USER_ID, mi.mUserId);
|
||||||
args.putBoolean(RunningServiceDetails.KEY_BACKGROUND, mAdapter.mShowBackground);
|
args.putBoolean(RunningServiceDetails.KEY_BACKGROUND, mAdapter.mShowBackground);
|
||||||
|
|
||||||
PreferenceActivity pa = (PreferenceActivity)mOwner.getActivity();
|
PreferenceActivity pa = (PreferenceActivity)mOwner.getActivity();
|
||||||
@@ -390,6 +406,7 @@ public class RunningProcessesView extends FrameLayout
|
|||||||
|
|
||||||
public RunningProcessesView(Context context, AttributeSet attrs) {
|
public RunningProcessesView(Context context, AttributeSet attrs) {
|
||||||
super(context, attrs);
|
super(context, attrs);
|
||||||
|
mMyUserId = UserHandle.myUserId();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void doCreate(Bundle savedInstanceState) {
|
public void doCreate(Bundle savedInstanceState) {
|
||||||
|
@@ -26,6 +26,7 @@ import android.os.Bundle;
|
|||||||
import android.os.Debug;
|
import android.os.Debug;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.os.SystemClock;
|
import android.os.SystemClock;
|
||||||
|
import android.os.UserHandle;
|
||||||
import android.provider.Settings;
|
import android.provider.Settings;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
@@ -39,12 +40,14 @@ import java.io.FileInputStream;
|
|||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
|
||||||
public class RunningServiceDetails extends Fragment
|
public class RunningServiceDetails extends Fragment
|
||||||
implements RunningState.OnRefreshUiListener {
|
implements RunningState.OnRefreshUiListener {
|
||||||
static final String TAG = "RunningServicesDetails";
|
static final String TAG = "RunningServicesDetails";
|
||||||
|
|
||||||
static final String KEY_UID = "uid";
|
static final String KEY_UID = "uid";
|
||||||
|
static final String KEY_USER_ID = "user_id";
|
||||||
static final String KEY_PROCESS = "process";
|
static final String KEY_PROCESS = "process";
|
||||||
static final String KEY_BACKGROUND = "background";
|
static final String KEY_BACKGROUND = "background";
|
||||||
|
|
||||||
@@ -57,6 +60,7 @@ public class RunningServiceDetails extends Fragment
|
|||||||
boolean mHaveData;
|
boolean mHaveData;
|
||||||
|
|
||||||
int mUid;
|
int mUid;
|
||||||
|
int mUserId;
|
||||||
String mProcessName;
|
String mProcessName;
|
||||||
boolean mShowBackground;
|
boolean mShowBackground;
|
||||||
|
|
||||||
@@ -195,8 +199,14 @@ public class RunningServiceDetails extends Fragment
|
|||||||
if (newItems != null) {
|
if (newItems != null) {
|
||||||
for (int i=0; i<newItems.size(); i++) {
|
for (int i=0; i<newItems.size(); i++) {
|
||||||
RunningState.MergedItem mi = newItems.get(i);
|
RunningState.MergedItem mi = newItems.get(i);
|
||||||
if (mi.mProcess.mUid == mUid
|
if (mi.mUserId != mUserId) {
|
||||||
&& mi.mProcess.mProcessName.equals(mProcessName)) {
|
continue;
|
||||||
|
}
|
||||||
|
if (mUid >= 0 && mi.mProcess != null && mi.mProcess.mUid != mUid) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (mProcessName == null || (mi.mProcess != null
|
||||||
|
&& mProcessName.equals(mi.mProcess.mProcessName))) {
|
||||||
item = mi;
|
item = mi;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -210,7 +220,7 @@ public class RunningServiceDetails extends Fragment
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void addServiceDetailsView(RunningState.ServiceItem si, RunningState.MergedItem mi) {
|
void addServicesHeader() {
|
||||||
if (mNumServices == 0) {
|
if (mNumServices == 0) {
|
||||||
mServicesHeader = (TextView)mInflater.inflate(R.layout.separator_label,
|
mServicesHeader = (TextView)mInflater.inflate(R.layout.separator_label,
|
||||||
mAllDetails, false);
|
mAllDetails, false);
|
||||||
@@ -218,6 +228,29 @@ public class RunningServiceDetails extends Fragment
|
|||||||
mAllDetails.addView(mServicesHeader);
|
mAllDetails.addView(mServicesHeader);
|
||||||
}
|
}
|
||||||
mNumServices++;
|
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;
|
RunningState.BaseItem bi = si != null ? si : mi;
|
||||||
|
|
||||||
@@ -230,12 +263,26 @@ public class RunningServiceDetails extends Fragment
|
|||||||
detail.mViewHolder = new RunningProcessesView.ViewHolder(root);
|
detail.mViewHolder = new RunningProcessesView.ViewHolder(root);
|
||||||
detail.mActiveItem = detail.mViewHolder.bind(mState, bi, mBuilder);
|
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) {
|
if (si != null && si.mRunningService.clientLabel != 0) {
|
||||||
detail.mManageIntent = mAm.getRunningServiceControlPanel(
|
detail.mManageIntent = mAm.getRunningServiceControlPanel(
|
||||||
si.mRunningService.service);
|
si.mRunningService.service);
|
||||||
}
|
}
|
||||||
|
|
||||||
TextView description = (TextView)root.findViewById(R.id.comp_description);
|
TextView description = (TextView)root.findViewById(R.id.comp_description);
|
||||||
|
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 (si != null && si.mServiceInfo.descriptionRes != 0) {
|
if (si != null && si.mServiceInfo.descriptionRes != 0) {
|
||||||
description.setText(getActivity().getPackageManager().getText(
|
description.setText(getActivity().getPackageManager().getText(
|
||||||
si.mServiceInfo.packageName, si.mServiceInfo.descriptionRes,
|
si.mServiceInfo.packageName, si.mServiceInfo.descriptionRes,
|
||||||
@@ -259,12 +306,9 @@ public class RunningServiceDetails extends Fragment
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
detail.mStopButton = (Button)root.findViewById(R.id.left_button);
|
|
||||||
detail.mStopButton.setOnClickListener(detail);
|
detail.mStopButton.setOnClickListener(detail);
|
||||||
detail.mStopButton.setText(getActivity().getText(detail.mManageIntent != null
|
detail.mStopButton.setText(getActivity().getText(detail.mManageIntent != null
|
||||||
? R.string.service_manage : R.string.service_stop));
|
? R.string.service_manage : R.string.service_stop));
|
||||||
|
|
||||||
detail.mReportButton = (Button)root.findViewById(R.id.right_button);
|
|
||||||
detail.mReportButton.setOnClickListener(detail);
|
detail.mReportButton.setOnClickListener(detail);
|
||||||
detail.mReportButton.setText(com.android.internal.R.string.report);
|
detail.mReportButton.setText(com.android.internal.R.string.report);
|
||||||
// check if error reporting is enabled in secure settings
|
// check if error reporting is enabled in secure settings
|
||||||
@@ -278,18 +322,13 @@ public class RunningServiceDetails extends Fragment
|
|||||||
} else {
|
} else {
|
||||||
detail.mReportButton.setEnabled(false);
|
detail.mReportButton.setEnabled(false);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
mActiveDetails.add(detail);
|
mActiveDetails.add(detail);
|
||||||
}
|
}
|
||||||
|
|
||||||
void addProcessDetailsView(RunningState.ProcessItem pi, boolean isMain) {
|
void addProcessDetailsView(RunningState.ProcessItem pi, boolean isMain) {
|
||||||
if (mNumProcesses == 0) {
|
addProcessesHeader();
|
||||||
mProcessesHeader = (TextView)mInflater.inflate(R.layout.separator_label,
|
|
||||||
mAllDetails, false);
|
|
||||||
mProcessesHeader.setText(R.string.runningservicedetails_processes_title);
|
|
||||||
mAllDetails.addView(mProcessesHeader);
|
|
||||||
}
|
|
||||||
mNumProcesses++;
|
|
||||||
|
|
||||||
ActiveDetail detail = new ActiveDetail();
|
ActiveDetail detail = new ActiveDetail();
|
||||||
View root = mInflater.inflate(R.layout.running_service_details_process,
|
View root = mInflater.inflate(R.layout.running_service_details_process,
|
||||||
@@ -300,7 +339,11 @@ public class RunningServiceDetails extends Fragment
|
|||||||
detail.mActiveItem = detail.mViewHolder.bind(mState, pi, mBuilder);
|
detail.mActiveItem = detail.mViewHolder.bind(mState, pi, mBuilder);
|
||||||
|
|
||||||
TextView description = (TextView)root.findViewById(R.id.comp_description);
|
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);
|
description.setText(R.string.main_running_process_description);
|
||||||
} else {
|
} else {
|
||||||
int textid = 0;
|
int textid = 0;
|
||||||
@@ -343,6 +386,38 @@ public class RunningServiceDetails extends Fragment
|
|||||||
mActiveDetails.add(detail);
|
mActiveDetails.add(detail);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void addDetailsViews(RunningState.MergedItem item, boolean inclServices,
|
||||||
|
boolean inclProcesses) {
|
||||||
|
if (item != null) {
|
||||||
|
if (inclServices) {
|
||||||
|
for (int i=0; i<item.mServices.size(); i++) {
|
||||||
|
addServiceDetailsView(item.mServices.get(i), item, true, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (inclProcesses) {
|
||||||
|
if (item.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, item, false, item.mUserId != UserHandle.myUserId());
|
||||||
|
} else {
|
||||||
|
// This screen is actually showing services, so also show
|
||||||
|
// the process details.
|
||||||
|
for (int i=-1; i<item.mOtherProcesses.size(); i++) {
|
||||||
|
RunningState.ProcessItem pi = i < 0 ? item.mProcess
|
||||||
|
: item.mOtherProcesses.get(i);
|
||||||
|
if (pi != null && pi.mPid <= 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
addProcessDetailsView(pi, i < 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void addDetailViews() {
|
void addDetailViews() {
|
||||||
for (int i=mActiveDetails.size()-1; i>=0; i--) {
|
for (int i=mActiveDetails.size()-1; i>=0; i--) {
|
||||||
mAllDetails.removeView(mActiveDetails.get(i).mRootView);
|
mAllDetails.removeView(mActiveDetails.get(i).mRootView);
|
||||||
@@ -361,27 +436,22 @@ public class RunningServiceDetails extends Fragment
|
|||||||
|
|
||||||
mNumServices = mNumProcesses = 0;
|
mNumServices = mNumProcesses = 0;
|
||||||
|
|
||||||
if (mMergedItem != null) {
|
if (mMergedItem.mUser != null) {
|
||||||
for (int i=0; i<mMergedItem.mServices.size(); i++) {
|
ArrayList<RunningState.MergedItem> items;
|
||||||
addServiceDetailsView(mMergedItem.mServices.get(i), mMergedItem);
|
if (mShowBackground) {
|
||||||
|
items = new ArrayList<RunningState.MergedItem>(mMergedItem.mChildren);
|
||||||
|
Collections.sort(items, mState.mBackgroundComparator);
|
||||||
|
} else {
|
||||||
|
items = mMergedItem.mChildren;
|
||||||
}
|
}
|
||||||
|
for (int i=0; i<items.size(); i++) {
|
||||||
if (mMergedItem.mServices.size() <= 0) {
|
addDetailsViews(items.get(i), true, false);
|
||||||
// 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<items.size(); i++) {
|
||||||
for (int i=-1; i<mMergedItem.mOtherProcesses.size(); i++) {
|
addDetailsViews(items.get(i), false, true);
|
||||||
RunningState.ProcessItem pi = i < 0 ? mMergedItem.mProcess
|
|
||||||
: mMergedItem.mOtherProcesses.get(i);
|
|
||||||
if (pi.mPid <= 0) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
addProcessDetailsView(pi, i < 0);
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
addDetailsViews(mMergedItem, true, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -423,8 +493,9 @@ public class RunningServiceDetails extends Fragment
|
|||||||
public void onCreate(Bundle savedInstanceState) {
|
public void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
|
|
||||||
mUid = getArguments().getInt(KEY_UID, 0);
|
mUid = getArguments().getInt(KEY_UID, -1);
|
||||||
mProcessName = getArguments().getString(KEY_PROCESS);
|
mUserId = getArguments().getInt(KEY_USER_ID, 0);
|
||||||
|
mProcessName = getArguments().getString(KEY_PROCESS, null);
|
||||||
mShowBackground = getArguments().getBoolean(KEY_BACKGROUND, false);
|
mShowBackground = getArguments().getBoolean(KEY_BACKGROUND, false);
|
||||||
|
|
||||||
mAm = (ActivityManager)getActivity().getSystemService(Context.ACTIVITY_SERVICE);
|
mAm = (ActivityManager)getActivity().getSystemService(Context.ACTIVITY_SERVICE);
|
||||||
|
@@ -27,12 +27,16 @@ 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.ServiceInfo;
|
import android.content.pm.ServiceInfo;
|
||||||
|
import android.content.pm.UserInfo;
|
||||||
import android.content.res.Resources;
|
import android.content.res.Resources;
|
||||||
|
import android.graphics.drawable.Drawable;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.os.HandlerThread;
|
import android.os.HandlerThread;
|
||||||
import android.os.Looper;
|
import android.os.Looper;
|
||||||
import android.os.Message;
|
import android.os.Message;
|
||||||
import android.os.RemoteException;
|
import android.os.RemoteException;
|
||||||
|
import android.os.UserHandle;
|
||||||
|
import android.os.UserManager;
|
||||||
import android.text.format.Formatter;
|
import android.text.format.Formatter;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.util.SparseArray;
|
import android.util.SparseArray;
|
||||||
@@ -49,6 +53,9 @@ import java.util.List;
|
|||||||
* applications/processes/services.
|
* applications/processes/services.
|
||||||
*/
|
*/
|
||||||
public class RunningState {
|
public class RunningState {
|
||||||
|
static final String TAG = "RunningState";
|
||||||
|
static final boolean DEBUG_COMPARE = false;
|
||||||
|
|
||||||
static Object sGlobalLock = new Object();
|
static Object sGlobalLock = new Object();
|
||||||
static RunningState sInstance;
|
static RunningState sInstance;
|
||||||
|
|
||||||
@@ -65,6 +72,8 @@ public class RunningState {
|
|||||||
final Context mApplicationContext;
|
final Context mApplicationContext;
|
||||||
final ActivityManager mAm;
|
final ActivityManager mAm;
|
||||||
final PackageManager mPm;
|
final PackageManager mPm;
|
||||||
|
final UserManager mUm;
|
||||||
|
final int mMyUserId;
|
||||||
|
|
||||||
OnRefreshUiListener mRefreshUiListener;
|
OnRefreshUiListener mRefreshUiListener;
|
||||||
|
|
||||||
@@ -100,6 +109,17 @@ public class RunningState {
|
|||||||
// All processes, used for retrieving memory information.
|
// All processes, used for retrieving memory information.
|
||||||
final ArrayList<ProcessItem> mAllProcessItems = new ArrayList<ProcessItem>();
|
final ArrayList<ProcessItem> mAllProcessItems = new ArrayList<ProcessItem>();
|
||||||
|
|
||||||
|
// 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<MergedItem> mOtherUserMergedItems = new SparseArray<MergedItem>();
|
||||||
|
|
||||||
|
// 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<MergedItem> mOtherUserBackgroundItems = new SparseArray<MergedItem>();
|
||||||
|
|
||||||
|
// Tracking of information about users.
|
||||||
|
final SparseArray<UserState> mUsers = new SparseArray<UserState>();
|
||||||
|
|
||||||
static class AppProcessInfo {
|
static class AppProcessInfo {
|
||||||
final ActivityManager.RunningAppProcessInfo info;
|
final ActivityManager.RunningAppProcessInfo info;
|
||||||
boolean hasServices;
|
boolean hasServices;
|
||||||
@@ -115,6 +135,63 @@ public class RunningState {
|
|||||||
|
|
||||||
int mSequence = 0;
|
int mSequence = 0;
|
||||||
|
|
||||||
|
final Comparator<RunningState.MergedItem> mBackgroundComparator
|
||||||
|
= new Comparator<RunningState.MergedItem>() {
|
||||||
|
@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 -----
|
// ----- following protected by mLock -----
|
||||||
|
|
||||||
// Lock for protecting the state that will be shared between the
|
// Lock for protecting the state that will be shared between the
|
||||||
@@ -128,6 +205,7 @@ public class RunningState {
|
|||||||
ArrayList<BaseItem> mItems = new ArrayList<BaseItem>();
|
ArrayList<BaseItem> mItems = new ArrayList<BaseItem>();
|
||||||
ArrayList<MergedItem> mMergedItems = new ArrayList<MergedItem>();
|
ArrayList<MergedItem> mMergedItems = new ArrayList<MergedItem>();
|
||||||
ArrayList<MergedItem> mBackgroundItems = new ArrayList<MergedItem>();
|
ArrayList<MergedItem> mBackgroundItems = new ArrayList<MergedItem>();
|
||||||
|
ArrayList<MergedItem> mUserBackgroundItems = new ArrayList<MergedItem>();
|
||||||
|
|
||||||
int mNumBackgroundProcesses;
|
int mNumBackgroundProcesses;
|
||||||
long mBackgroundProcessMemory;
|
long mBackgroundProcessMemory;
|
||||||
@@ -211,8 +289,15 @@ public class RunningState {
|
|||||||
public void onRefreshUi(int what);
|
public void onRefreshUi(int what);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static class UserState {
|
||||||
|
UserInfo mInfo;
|
||||||
|
String mLabel;
|
||||||
|
Drawable mIcon;
|
||||||
|
}
|
||||||
|
|
||||||
static class BaseItem {
|
static class BaseItem {
|
||||||
final boolean mIsProcess;
|
final boolean mIsProcess;
|
||||||
|
final int mUserId;
|
||||||
|
|
||||||
PackageItemInfo mPackageInfo;
|
PackageItemInfo mPackageInfo;
|
||||||
CharSequence mDisplayLabel;
|
CharSequence mDisplayLabel;
|
||||||
@@ -228,8 +313,16 @@ public class RunningState {
|
|||||||
boolean mNeedDivider;
|
boolean mNeedDivider;
|
||||||
boolean mBackground;
|
boolean mBackground;
|
||||||
|
|
||||||
public BaseItem(boolean isProcess) {
|
public BaseItem(boolean isProcess, int userId) {
|
||||||
mIsProcess = isProcess;
|
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;
|
MergedItem mMergedItem;
|
||||||
|
|
||||||
public ServiceItem() {
|
public ServiceItem(int userId) {
|
||||||
super(false);
|
super(false, userId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -271,7 +364,7 @@ public class RunningState {
|
|||||||
long mActiveSince;
|
long mActiveSince;
|
||||||
|
|
||||||
public ProcessItem(Context context, int uid, String processName) {
|
public ProcessItem(Context context, int uid, String processName) {
|
||||||
super(true);
|
super(true, UserHandle.getUserId(uid));
|
||||||
mDescription = context.getResources().getString(
|
mDescription = context.getResources().getString(
|
||||||
R.string.service_process_name, processName);
|
R.string.service_process_name, processName);
|
||||||
mUid = uid;
|
mUid = uid;
|
||||||
@@ -332,8 +425,9 @@ public class RunningState {
|
|||||||
// If still don't have anything to display, just use the
|
// If still don't have anything to display, just use the
|
||||||
// service info.
|
// service info.
|
||||||
if (mServices.size() > 0) {
|
if (mServices.size() > 0) {
|
||||||
mPackageInfo = mServices.values().iterator().next()
|
ApplicationInfo ai = mServices.values().iterator().next()
|
||||||
.mServiceInfo.applicationInfo;
|
.mServiceInfo.applicationInfo;
|
||||||
|
mPackageInfo = ai;
|
||||||
mDisplayLabel = mPackageInfo.loadLabel(pm);
|
mDisplayLabel = mPackageInfo.loadLabel(pm);
|
||||||
mLabel = mDisplayLabel.toString();
|
mLabel = mDisplayLabel.toString();
|
||||||
return;
|
return;
|
||||||
@@ -358,7 +452,7 @@ public class RunningState {
|
|||||||
ServiceItem si = mServices.get(service.service);
|
ServiceItem si = mServices.get(service.service);
|
||||||
if (si == null) {
|
if (si == null) {
|
||||||
changed = true;
|
changed = true;
|
||||||
si = new ServiceItem();
|
si = new ServiceItem(mUserId);
|
||||||
si.mRunningService = service;
|
si.mRunningService = service;
|
||||||
try {
|
try {
|
||||||
si.mServiceInfo = pm.getServiceInfo(service.service, 0);
|
si.mServiceInfo = pm.getServiceInfo(service.service, 0);
|
||||||
@@ -456,24 +550,18 @@ public class RunningState {
|
|||||||
|
|
||||||
static class MergedItem extends BaseItem {
|
static class MergedItem extends BaseItem {
|
||||||
ProcessItem mProcess;
|
ProcessItem mProcess;
|
||||||
|
UserState mUser;
|
||||||
final ArrayList<ProcessItem> mOtherProcesses = new ArrayList<ProcessItem>();
|
final ArrayList<ProcessItem> mOtherProcesses = new ArrayList<ProcessItem>();
|
||||||
final ArrayList<ServiceItem> mServices = new ArrayList<ServiceItem>();
|
final ArrayList<ServiceItem> mServices = new ArrayList<ServiceItem>();
|
||||||
|
final ArrayList<MergedItem> mChildren = new ArrayList<MergedItem>();
|
||||||
|
|
||||||
private int mLastNumProcesses = -1, mLastNumServices = -1;
|
private int mLastNumProcesses = -1, mLastNumServices = -1;
|
||||||
|
|
||||||
MergedItem() {
|
MergedItem(int userId) {
|
||||||
super(false);
|
super(false, userId);
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean update(Context context, boolean background) {
|
private void setDescription(Context context, int numProcesses, int numServices) {
|
||||||
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) {
|
if (mLastNumProcesses != numProcesses || mLastNumServices != numServices) {
|
||||||
mLastNumProcesses = numProcesses;
|
mLastNumProcesses = numProcesses;
|
||||||
mLastNumServices = numServices;
|
mLastNumServices = numServices;
|
||||||
@@ -490,6 +578,43 @@ public class RunningState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boolean update(Context context, boolean background) {
|
||||||
|
mBackground = background;
|
||||||
|
|
||||||
|
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<mChildren.size(); i++) {
|
||||||
|
MergedItem child = mChildren.get(i);
|
||||||
|
numProcesses += child.mLastNumProcesses;
|
||||||
|
numServices += child.mLastNumServices;
|
||||||
|
if (child.mActiveSince >= 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;
|
mActiveSince = -1;
|
||||||
for (int i=0; i<mServices.size(); i++) {
|
for (int i=0; i<mServices.size(); i++) {
|
||||||
ServiceItem si = mServices.get(i);
|
ServiceItem si = mServices.get(i);
|
||||||
@@ -497,15 +622,25 @@ public class RunningState {
|
|||||||
mActiveSince = si.mActiveSince;
|
mActiveSince = si.mActiveSince;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean updateSize(Context context) {
|
boolean updateSize(Context context) {
|
||||||
|
if (mUser != null) {
|
||||||
|
mSize = 0;
|
||||||
|
for (int i=0; i<mChildren.size(); i++) {
|
||||||
|
MergedItem child = mChildren.get(i);
|
||||||
|
child.updateSize(context);
|
||||||
|
mSize += child.mSize;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
mSize = mProcess.mSize;
|
mSize = mProcess.mSize;
|
||||||
for (int i=0; i<mOtherProcesses.size(); i++) {
|
for (int i=0; i<mOtherProcesses.size(); i++) {
|
||||||
mSize += mOtherProcesses.get(i).mSize;
|
mSize += mOtherProcesses.get(i).mSize;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
String sizeStr = Formatter.formatShortFileSize(
|
String sizeStr = Formatter.formatShortFileSize(
|
||||||
context, mSize);
|
context, mSize);
|
||||||
@@ -518,10 +653,26 @@ public class RunningState {
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Drawable loadIcon(Context context, RunningState state) {
|
||||||
|
if (mUser == null) {
|
||||||
|
return super.loadIcon(context, state);
|
||||||
|
}
|
||||||
|
if (mUser.mIcon != null) {
|
||||||
|
return mUser.mIcon.getConstantState().newDrawable();
|
||||||
|
}
|
||||||
|
return context.getResources().getDrawable(
|
||||||
|
com.android.internal.R.drawable.ic_menu_cc);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static class ServiceProcessComparator implements Comparator<ProcessItem> {
|
class ServiceProcessComparator implements Comparator<ProcessItem> {
|
||||||
public int compare(ProcessItem object1, ProcessItem object2) {
|
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) {
|
if (object1.mIsStarted != object2.mIsStarted) {
|
||||||
// Non-started processes go last.
|
// Non-started processes go last.
|
||||||
return object1.mIsStarted ? -1 : 1;
|
return object1.mIsStarted ? -1 : 1;
|
||||||
@@ -570,6 +721,8 @@ public class RunningState {
|
|||||||
mApplicationContext = context.getApplicationContext();
|
mApplicationContext = context.getApplicationContext();
|
||||||
mAm = (ActivityManager)mApplicationContext.getSystemService(Context.ACTIVITY_SERVICE);
|
mAm = (ActivityManager)mApplicationContext.getSystemService(Context.ACTIVITY_SERVICE);
|
||||||
mPm = mApplicationContext.getPackageManager();
|
mPm = mApplicationContext.getPackageManager();
|
||||||
|
mUm = (UserManager)mApplicationContext.getSystemService(Context.USER_SERVICE);
|
||||||
|
mMyUserId = UserHandle.myUserId();
|
||||||
mResumed = false;
|
mResumed = false;
|
||||||
mBackgroundThread = new HandlerThread("RunningState:Background");
|
mBackgroundThread = new HandlerThread("RunningState:Background");
|
||||||
mBackgroundThread.start();
|
mBackgroundThread.start();
|
||||||
@@ -646,6 +799,42 @@ public class RunningState {
|
|||||||
mRunningProcesses.clear();
|
mRunningProcesses.clear();
|
||||||
mProcessItems.clear();
|
mProcessItems.clear();
|
||||||
mAllProcessItems.clear();
|
mAllProcessItems.clear();
|
||||||
|
mUsers.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addOtherUserItem(Context context, ArrayList<MergedItem> newMergedItems,
|
||||||
|
SparseArray<MergedItem> 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) {
|
private boolean update(Context context, ActivityManager am) {
|
||||||
@@ -940,6 +1129,7 @@ public class RunningState {
|
|||||||
|
|
||||||
ArrayList<BaseItem> newItems = new ArrayList<BaseItem>();
|
ArrayList<BaseItem> newItems = new ArrayList<BaseItem>();
|
||||||
ArrayList<MergedItem> newMergedItems = new ArrayList<MergedItem>();
|
ArrayList<MergedItem> newMergedItems = new ArrayList<MergedItem>();
|
||||||
|
SparseArray<MergedItem> otherUsers = null;
|
||||||
mProcessItems.clear();
|
mProcessItems.clear();
|
||||||
for (int i=0; i<sortedProcesses.size(); i++) {
|
for (int i=0; i<sortedProcesses.size(); i++) {
|
||||||
ProcessItem pi = sortedProcesses.get(i);
|
ProcessItem pi = sortedProcesses.get(i);
|
||||||
@@ -975,7 +1165,7 @@ public class RunningState {
|
|||||||
if (!haveAllMerged || mergedItem == null
|
if (!haveAllMerged || mergedItem == null
|
||||||
|| mergedItem.mServices.size() != pi.mServices.size()) {
|
|| mergedItem.mServices.size() != pi.mServices.size()) {
|
||||||
// Whoops, we need to build a new MergedItem!
|
// Whoops, we need to build a new MergedItem!
|
||||||
mergedItem = new MergedItem();
|
mergedItem = new MergedItem(pi.mUserId);
|
||||||
for (ServiceItem si : pi.mServices.values()) {
|
for (ServiceItem si : pi.mServices.values()) {
|
||||||
mergedItem.mServices.add(si);
|
mergedItem.mServices.add(si);
|
||||||
si.mMergedItem = mergedItem;
|
si.mMergedItem = mergedItem;
|
||||||
@@ -988,8 +1178,12 @@ public class RunningState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
mergedItem.update(context, false);
|
mergedItem.update(context, false);
|
||||||
|
if (mergedItem.mUserId != mMyUserId) {
|
||||||
|
addOtherUserItem(context, newMergedItems, mOtherUserMergedItems, mergedItem);
|
||||||
|
} else {
|
||||||
newMergedItems.add(mergedItem);
|
newMergedItems.add(mergedItem);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Finally, interesting processes need to be shown and will
|
// Finally, interesting processes need to be shown and will
|
||||||
// go at the top.
|
// go at the top.
|
||||||
@@ -998,15 +1192,30 @@ public class RunningState {
|
|||||||
ProcessItem proc = mInterestingProcesses.get(i);
|
ProcessItem proc = mInterestingProcesses.get(i);
|
||||||
if (proc.mClient == null && proc.mServices.size() <= 0) {
|
if (proc.mClient == null && proc.mServices.size() <= 0) {
|
||||||
if (proc.mMergedItem == null) {
|
if (proc.mMergedItem == null) {
|
||||||
proc.mMergedItem = new MergedItem();
|
proc.mMergedItem = new MergedItem(proc.mUserId);
|
||||||
proc.mMergedItem.mProcess = proc;
|
proc.mMergedItem.mProcess = proc;
|
||||||
}
|
}
|
||||||
proc.mMergedItem.update(context, false);
|
proc.mMergedItem.update(context, false);
|
||||||
|
if (proc.mMergedItem.mUserId != mMyUserId) {
|
||||||
|
addOtherUserItem(context, newMergedItems, mOtherUserMergedItems,
|
||||||
|
proc.mMergedItem);
|
||||||
|
} else {
|
||||||
newMergedItems.add(0, proc.mMergedItem);
|
newMergedItems.add(0, proc.mMergedItem);
|
||||||
|
}
|
||||||
mProcessItems.add(proc);
|
mProcessItems.add(proc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Finally finally, user aggregated merged items need to be
|
||||||
|
// updated now that they have all of their children.
|
||||||
|
final int NU = mOtherUserMergedItems.size();
|
||||||
|
for (int i=0; i<NU; i++) {
|
||||||
|
MergedItem user = mOtherUserMergedItems.valueAt(i);
|
||||||
|
if (user.mCurSeq == mSequence) {
|
||||||
|
user.update(context, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
synchronized (mLock) {
|
synchronized (mLock) {
|
||||||
mItems = newItems;
|
mItems = newItems;
|
||||||
mMergedItems = newMergedItems;
|
mMergedItems = newMergedItems;
|
||||||
@@ -1047,6 +1256,8 @@ public class RunningState {
|
|||||||
long foregroundProcessMemory = 0;
|
long foregroundProcessMemory = 0;
|
||||||
long serviceProcessMemory = 0;
|
long serviceProcessMemory = 0;
|
||||||
ArrayList<MergedItem> newBackgroundItems = null;
|
ArrayList<MergedItem> newBackgroundItems = null;
|
||||||
|
ArrayList<MergedItem> newUserBackgroundItems = null;
|
||||||
|
boolean diffUsers = false;
|
||||||
try {
|
try {
|
||||||
final int numProc = mAllProcessItems.size();
|
final int numProc = mAllProcessItems.size();
|
||||||
int[] pids = new int[numProc];
|
int[] pids = new int[numProc];
|
||||||
@@ -1066,18 +1277,22 @@ public class RunningState {
|
|||||||
backgroundProcessMemory += proc.mSize;
|
backgroundProcessMemory += proc.mSize;
|
||||||
MergedItem mergedItem;
|
MergedItem mergedItem;
|
||||||
if (newBackgroundItems != null) {
|
if (newBackgroundItems != null) {
|
||||||
mergedItem = proc.mMergedItem = new MergedItem();
|
mergedItem = proc.mMergedItem = new MergedItem(proc.mUserId);
|
||||||
proc.mMergedItem.mProcess = proc;
|
proc.mMergedItem.mProcess = proc;
|
||||||
|
diffUsers |= mergedItem.mUserId != mMyUserId;
|
||||||
newBackgroundItems.add(mergedItem);
|
newBackgroundItems.add(mergedItem);
|
||||||
} else {
|
} else {
|
||||||
if (bgIndex >= mBackgroundItems.size()
|
if (bgIndex >= mBackgroundItems.size()
|
||||||
|| mBackgroundItems.get(bgIndex).mProcess != proc) {
|
|| mBackgroundItems.get(bgIndex).mProcess != proc) {
|
||||||
newBackgroundItems = new ArrayList<MergedItem>(numBackgroundProcesses);
|
newBackgroundItems = new ArrayList<MergedItem>(numBackgroundProcesses);
|
||||||
for (int bgi=0; bgi<bgIndex; bgi++) {
|
for (int bgi=0; bgi<bgIndex; bgi++) {
|
||||||
newBackgroundItems.add(mBackgroundItems.get(bgi));
|
mergedItem = mBackgroundItems.get(bgi);
|
||||||
|
diffUsers |= mergedItem.mUserId != mMyUserId;
|
||||||
|
newBackgroundItems.add(mergedItem);
|
||||||
}
|
}
|
||||||
mergedItem = proc.mMergedItem = new MergedItem();
|
mergedItem = proc.mMergedItem = new MergedItem(proc.mUserId);
|
||||||
proc.mMergedItem.mProcess = proc;
|
proc.mMergedItem.mProcess = proc;
|
||||||
|
diffUsers |= mergedItem.mUserId != mMyUserId;
|
||||||
newBackgroundItems.add(mergedItem);
|
newBackgroundItems.add(mergedItem);
|
||||||
} else {
|
} else {
|
||||||
mergedItem = mBackgroundItems.get(bgIndex);
|
mergedItem = mBackgroundItems.get(bgIndex);
|
||||||
@@ -1099,7 +1314,42 @@ public class RunningState {
|
|||||||
if (mBackgroundItems.size() > numBackgroundProcesses) {
|
if (mBackgroundItems.size() > numBackgroundProcesses) {
|
||||||
newBackgroundItems = new ArrayList<MergedItem>(numBackgroundProcesses);
|
newBackgroundItems = new ArrayList<MergedItem>(numBackgroundProcesses);
|
||||||
for (int bgi=0; bgi<numBackgroundProcesses; bgi++) {
|
for (int bgi=0; bgi<numBackgroundProcesses; bgi++) {
|
||||||
newBackgroundItems.add(mBackgroundItems.get(bgi));
|
MergedItem mergedItem = mBackgroundItems.get(bgi);
|
||||||
|
diffUsers |= mergedItem.mUserId != mMyUserId;
|
||||||
|
newBackgroundItems.add(mergedItem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (newBackgroundItems != null) {
|
||||||
|
// The background items have changed; we need to re-build the
|
||||||
|
// per-user items.
|
||||||
|
if (!diffUsers) {
|
||||||
|
// Easy: there are no other users, we can just use the same array.
|
||||||
|
newUserBackgroundItems = newBackgroundItems;
|
||||||
|
} else {
|
||||||
|
// We now need to re-build the per-user list so that background
|
||||||
|
// items for users are collapsed together.
|
||||||
|
newUserBackgroundItems = new ArrayList<MergedItem>();
|
||||||
|
final int NB = newBackgroundItems.size();
|
||||||
|
for (int i=0; i<NB; i++) {
|
||||||
|
MergedItem mergedItem = newBackgroundItems.get(i);
|
||||||
|
if (mergedItem.mUserId != mMyUserId) {
|
||||||
|
addOtherUserItem(context, newUserBackgroundItems,
|
||||||
|
mOtherUserBackgroundItems, mergedItem);
|
||||||
|
} else {
|
||||||
|
newUserBackgroundItems.add(mergedItem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// And user aggregated merged items need to be
|
||||||
|
// updated now that they have all of their children.
|
||||||
|
final int NU = mOtherUserBackgroundItems.size();
|
||||||
|
for (int i=0; i<NU; i++) {
|
||||||
|
MergedItem user = mOtherUserBackgroundItems.valueAt(i);
|
||||||
|
if (user.mCurSeq == mSequence) {
|
||||||
|
user.update(context, true);
|
||||||
|
user.updateSize(context);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1117,6 +1367,7 @@ public class RunningState {
|
|||||||
mServiceProcessMemory = serviceProcessMemory;
|
mServiceProcessMemory = serviceProcessMemory;
|
||||||
if (newBackgroundItems != null) {
|
if (newBackgroundItems != null) {
|
||||||
mBackgroundItems = newBackgroundItems;
|
mBackgroundItems = newBackgroundItems;
|
||||||
|
mUserBackgroundItems = newUserBackgroundItems;
|
||||||
if (mWatchingBackgroundItems) {
|
if (mWatchingBackgroundItems) {
|
||||||
changed = true;
|
changed = true;
|
||||||
}
|
}
|
||||||
@@ -1150,7 +1401,7 @@ public class RunningState {
|
|||||||
|
|
||||||
ArrayList<MergedItem> getCurrentBackgroundItems() {
|
ArrayList<MergedItem> getCurrentBackgroundItems() {
|
||||||
synchronized (mLock) {
|
synchronized (mLock) {
|
||||||
return mBackgroundItems;
|
return mUserBackgroundItems;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user