Java tutorial
/******************************************************************************** * (C) Copyright 2000-2010. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. ********************************************************************************/ package org.uguess.android.sysinfo; import java.io.BufferedReader; import java.io.ByteArrayOutputStream; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.text.Collator; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.LinkedHashSet; import java.util.List; import java.util.StringTokenizer; import android.app.Activity; import android.app.ActivityManager; import android.app.ActivityManager.RunningAppProcessInfo; import android.app.AlertDialog; import android.content.Context; import android.content.DialogInterface; import android.content.DialogInterface.OnClickListener; import android.content.DialogInterface.OnMultiChoiceClickListener; import android.content.Intent; import android.content.SharedPreferences; import android.content.SharedPreferences.Editor; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.ResolveInfo; import android.graphics.Color; import android.graphics.drawable.Drawable; import android.os.Bundle; import android.os.Handler; import android.preference.CheckBoxPreference; import android.preference.Preference; import android.preference.PreferenceActivity; import android.preference.PreferenceCategory; import android.preference.PreferenceScreen; import android.support.v4.app.ListFragment; import android.text.Html; import android.text.format.Formatter; import android.util.Log; import android.view.ContextMenu; import android.view.ContextMenu.ContextMenuInfo; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.view.Window; import android.widget.AdapterView.AdapterContextMenuInfo; import android.widget.ArrayAdapter; import android.widget.ImageView; import android.widget.ListView; import android.widget.TextView; /** * ProcessManager */ public final class ProcessManager extends ListFragment implements Constants { private static final String PSTORE_PROCESSMANAGER = ProcessManager.class.getSimpleName(); private static final int MSG_REFRESH_PKG_LABEL = MSG_PRIVATE + 1; private static final int MSG_REFRESH_PKG_ICON = MSG_PRIVATE + 2; private static final String PREF_KEY_IGNORE_ACTION = "ignore_action"; //$NON-NLS-1$ private static final String PREF_KEY_IGNORE_LIST = "ignore_list"; //$NON-NLS-1$ private static final String PREF_KEY_SHOW_MEM = "show_mem"; //$NON-NLS-1$ private static final String PREF_KEY_SHOW_CPU = "show_cpu"; //$NON-NLS-1$ private static final String PREF_KEY_SHOW_SYS_PROC = "show_sys_proc"; //$NON-NLS-1$ private static final String PREF_KEY_SHOW_KILL_WARN = "show_kill_warn"; //$NON-NLS-1$ private static final int ORDER_TYPE_NAME = 0; private static final int ORDER_TYPE_IMPORTANCE = 1; private static final int ORDER_TYPE_MEM = 2; private static final int ORDER_TYPE_CPU = 3; private static final int ACTION_MENU = 0; private static final int ACTION_SWITCH = 1; private static final int ACTION_END = 2; private static final int ACTION_END_OTHERS = 3; private static final int ACTION_IGNORE = 4; private static final int ACTION_DETAILS = 5; private static final int IGNORE_ACTION_HIDDEN = 0; private static final int IGNORE_ACTION_PROTECTED = 1; View rootView; ProcessCache procCache; long totalLoad, totalDelta, totalWork, workDelta; LinkedHashSet<String> ignoreList; ResourceUpdaterThread resUpdater; private byte[] buf = new byte[512]; Handler handler = new Handler() { public void handleMessage(android.os.Message msg) { Activity ctx = getActivity(); switch (msg.what) { case MSG_INIT_OK: if (resUpdater != null) { resUpdater.aborted = true; } (resUpdater = new ResourceUpdaterThread(ctx, procCache, handler)).start(); ArrayAdapter<ProcessItem> adapter = (ArrayAdapter<ProcessItem>) getListView().getAdapter(); adapter.setNotifyOnChange(false); synchronized (procCache) { adapter.clear(); ArrayList<ProcessItem> localList = procCache.procList; for (int i = 0, size = localList.size(); i < size; i++) { adapter.add(localList.get(i)); } } adapter.notifyDataSetChanged(); refreshHeader(); int interval = Util.getIntOption(ctx, PSTORE_PROCESSMANAGER, PREF_KEY_REFRESH_INTERVAL, REFRESH_LOW); switch (interval) { case REFRESH_HIGH: handler.postDelayed(task, 1000); break; case REFRESH_NORMAL: handler.postDelayed(task, 2000); break; case REFRESH_LOW: handler.postDelayed(task, 4000); break; } break; case MSG_REFRESH_PKG_LABEL: adapter = (ArrayAdapter<ProcessItem>) (ArrayAdapter<ProcessItem>) getListView().getAdapter(); if (msg.arg1 == 1) { adapter.setNotifyOnChange(false); synchronized (procCache) { adapter.clear(); ArrayList<ProcessItem> localList = procCache.procList; for (int i = 0, size = localList.size(); i < size; i++) { adapter.add(localList.get(i)); } } } adapter.notifyDataSetChanged(); break; case MSG_REFRESH_PKG_ICON: ((ArrayAdapter<ProcessItem>) getListView().getAdapter()).notifyDataSetChanged(); break; } }; }; Runnable task = new Runnable() { public void run() { ActivityManager am = (ActivityManager) getActivity().getSystemService(Context.ACTIVITY_SERVICE); List<RunningAppProcessInfo> raps = am.getRunningAppProcesses(); updateProcess(raps); handler.sendEmptyMessage(MSG_INIT_OK); } }; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setHasOptionsMenu(true); procCache = new ProcessCache(); ignoreList = new LinkedHashSet<String>(); ArrayList<String> list = getIgnoreList( getActivity().getSharedPreferences(PSTORE_PROCESSMANAGER, Context.MODE_PRIVATE)); if (list != null) { ignoreList.addAll(list); } } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { rootView = inflater.inflate(R.layout.proc_lst_view, container, false); ListView listView = (ListView) rootView.findViewById(android.R.id.list); registerForContextMenu(listView); View listHeader = rootView.findViewById(R.id.list_head); listHeader.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { boolean showWarning = Util.getBooleanOption(getActivity(), PSTORE_PROCESSMANAGER, PREF_KEY_SHOW_KILL_WARN); if (showWarning) { OnClickListener listener = new OnClickListener() { public void onClick(DialogInterface dialog, int which) { endAllExcept(null); } }; new AlertDialog.Builder(getActivity()).setTitle(R.string.warning) .setMessage(R.string.end_all_prompt).setPositiveButton(android.R.string.ok, listener) .setNegativeButton(android.R.string.cancel, null).create().show(); } else { endAllExcept(null); } } }); ArrayAdapter<ProcessItem> adapter = new ArrayAdapter<ProcessItem>(getActivity(), R.layout.proc_item) { public android.view.View getView(int position, android.view.View convertView, android.view.ViewGroup parent) { Activity ctx = getActivity(); View view; TextView txt_name, txt_mem, txt_cpu; ImageView img_type; if (convertView == null) { view = ctx.getLayoutInflater().inflate(R.layout.proc_item, parent, false); } else { view = convertView; } if (position >= getCount()) { return view; } ProcessItem itm = getItem(position); img_type = (ImageView) view.findViewById(R.id.img_proc_icon); txt_name = (TextView) view.findViewById(R.id.txt_proc_name); txt_mem = (TextView) view.findViewById(R.id.txt_mem); txt_cpu = (TextView) view.findViewById(R.id.txt_cpu); boolean showMem = Util.getBooleanOption(ctx, PSTORE_PROCESSMANAGER, PREF_KEY_SHOW_MEM); boolean showCpu = Util.getBooleanOption(ctx, PSTORE_PROCESSMANAGER, PREF_KEY_SHOW_CPU); String lb = itm.label == null ? itm.procInfo.processName : itm.label; if (itm.sys) { lb += " *"; //$NON-NLS-1$ } else if (ignoreList.contains(itm.procInfo.processName)) { lb += " ~"; //$NON-NLS-1$ } txt_name.setText(lb); switch (itm.procInfo.importance) { case RunningAppProcessInfo.IMPORTANCE_FOREGROUND: txt_name.setTextColor(Color.CYAN); break; case RunningAppProcessInfo.IMPORTANCE_PERCEPTIBLE: case RunningAppProcessInfo.IMPORTANCE_VISIBLE: txt_name.setTextColor(Color.GREEN); break; case RunningAppProcessInfo.IMPORTANCE_SERVICE: txt_name.setTextColor(Color.GRAY); break; case RunningAppProcessInfo.IMPORTANCE_BACKGROUND: txt_name.setTextColor(Color.YELLOW); break; case RunningAppProcessInfo.IMPORTANCE_EMPTY: default: txt_name.setTextColor(Color.WHITE); break; } img_type.setImageDrawable(itm.icon); if (showMem) { txt_mem.setVisibility(View.VISIBLE); txt_mem.setText(itm.mem); } else { txt_mem.setVisibility(View.GONE); } if (showCpu) { txt_cpu.setVisibility(View.VISIBLE); long delta = itm.lastcputime == 0 ? 0 : (itm.cputime - itm.lastcputime); long cu = totalDelta == 0 ? 0 : (delta * 100 / totalDelta); if (cu < 0) { cu = 0; } if (cu > 100) { cu = 100; } txt_cpu.setText(String.valueOf(cu)); } else { txt_cpu.setVisibility(View.GONE); } return view; } }; setListAdapter(adapter); return rootView; } @Override public void onListItemClick(ListView l, View v, int position, long id) { final ProcessItem rap = (ProcessItem) l.getItemAtPosition(position); Activity ctx = getActivity(); boolean showWarning = Util.getBooleanOption(ctx, PSTORE_PROCESSMANAGER, PREF_KEY_SHOW_KILL_WARN); final int action = Util.getIntOption(ctx, PSTORE_PROCESSMANAGER, PREF_KEY_DEFAULT_TAP_ACTION, ACTION_MENU); if (action == ACTION_END || action == ACTION_IGNORE) { boolean protect = ignoreList.contains(rap.procInfo.processName) || rap.sys; if (protect) { return; } } if (showWarning && (action == ACTION_END || action == ACTION_END_OTHERS)) { OnClickListener listener = new OnClickListener() { public void onClick(DialogInterface dialog, int which) { handleAction(rap, action); } }; new AlertDialog.Builder(ctx).setTitle(R.string.warning) .setMessage(action == ACTION_END ? R.string.end_prompt : R.string.end_other_prompt) .setPositiveButton(android.R.string.ok, listener) .setNegativeButton(android.R.string.cancel, null).create().show(); } else { handleAction(rap, action); } } @Override public void onDestroyView() { ((ArrayAdapter<ProcessItem>) getListView().getAdapter()).clear(); rootView = null; super.onDestroyView(); } @Override public void onDestroy() { procCache.clear(); super.onDestroy(); } @Override public void onResume() { super.onResume(); handler.post(task); } @Override public void onPause() { handler.removeCallbacks(task); handler.removeMessages(MSG_INIT_OK); if (resUpdater != null) { resUpdater.aborted = true; resUpdater = null; } super.onPause(); } @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { Activity ctx = getActivity(); if (requestCode == 1 && data != null) { Util.updateIntOption(data, ctx, PSTORE_PROCESSMANAGER, PREF_KEY_REFRESH_INTERVAL, REFRESH_LOW); Util.updateIntOption(data, ctx, PSTORE_PROCESSMANAGER, PREF_KEY_SORT_ORDER_TYPE, ORDER_TYPE_NAME); Util.updateIntOption(data, ctx, PSTORE_PROCESSMANAGER, PREF_KEY_SORT_DIRECTION, ORDER_ASC); Util.updateIntOption(data, ctx, PSTORE_PROCESSMANAGER, PREF_KEY_IGNORE_ACTION, IGNORE_ACTION_HIDDEN); Util.updateIntOption(data, ctx, PSTORE_PROCESSMANAGER, PREF_KEY_DEFAULT_TAP_ACTION, ACTION_MENU); Util.updateBooleanOption(data, ctx, PSTORE_PROCESSMANAGER, PREF_KEY_SHOW_MEM); Util.updateBooleanOption(data, ctx, PSTORE_PROCESSMANAGER, PREF_KEY_SHOW_CPU); Util.updateBooleanOption(data, ctx, PSTORE_PROCESSMANAGER, PREF_KEY_SHOW_SYS_PROC); Util.updateBooleanOption(data, ctx, PSTORE_PROCESSMANAGER, PREF_KEY_SHOW_KILL_WARN); ArrayList<String> list = data.getStringArrayListExtra(PREF_KEY_IGNORE_LIST); setIgnoreList(list); ignoreList.clear(); if (list != null) { ignoreList.addAll(list); } } } @Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { MenuItem mi = menu.add(Menu.NONE, MI_PREFERENCE, Menu.NONE, R.string.preference); mi.setIcon(android.R.drawable.ic_menu_preferences); Util.setShowAsAction(mi, MenuItem.SHOW_AS_ACTION_NEVER); } @Override public boolean onOptionsItemSelected(MenuItem item) { Activity ctx = getActivity(); if (item.getItemId() == MI_PREFERENCE) { Intent it = new Intent(ctx, ProcessSettings.class); it.putExtra(PREF_KEY_REFRESH_INTERVAL, Util.getIntOption(ctx, PSTORE_PROCESSMANAGER, PREF_KEY_REFRESH_INTERVAL, REFRESH_LOW)); it.putExtra(PREF_KEY_SORT_ORDER_TYPE, Util.getIntOption(ctx, PSTORE_PROCESSMANAGER, PREF_KEY_SORT_ORDER_TYPE, ORDER_TYPE_NAME)); it.putExtra(PREF_KEY_SORT_DIRECTION, Util.getIntOption(ctx, PSTORE_PROCESSMANAGER, PREF_KEY_SORT_DIRECTION, ORDER_ASC)); it.putExtra(PREF_KEY_IGNORE_ACTION, Util.getIntOption(ctx, PSTORE_PROCESSMANAGER, PREF_KEY_IGNORE_ACTION, IGNORE_ACTION_HIDDEN)); it.putExtra(PREF_KEY_DEFAULT_TAP_ACTION, Util.getIntOption(ctx, PSTORE_PROCESSMANAGER, PREF_KEY_DEFAULT_TAP_ACTION, ACTION_MENU)); it.putStringArrayListExtra(PREF_KEY_IGNORE_LIST, getIgnoreList(ctx.getSharedPreferences(PSTORE_PROCESSMANAGER, Context.MODE_PRIVATE))); it.putExtra(PREF_KEY_SHOW_MEM, Util.getBooleanOption(ctx, PSTORE_PROCESSMANAGER, PREF_KEY_SHOW_MEM)); it.putExtra(PREF_KEY_SHOW_CPU, Util.getBooleanOption(ctx, PSTORE_PROCESSMANAGER, PREF_KEY_SHOW_CPU)); it.putExtra(PREF_KEY_SHOW_SYS_PROC, Util.getBooleanOption(ctx, PSTORE_PROCESSMANAGER, PREF_KEY_SHOW_SYS_PROC)); it.putExtra(PREF_KEY_SHOW_KILL_WARN, Util.getBooleanOption(ctx, PSTORE_PROCESSMANAGER, PREF_KEY_SHOW_KILL_WARN)); startActivityForResult(it, 1); return true; } return false; } @Override public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) { super.onCreateContextMenu(menu, v, menuInfo); int pos = ((AdapterContextMenuInfo) menuInfo).position; ProcessItem rap = (ProcessItem) getListView().getItemAtPosition(pos); menu.setHeaderTitle(R.string.actions); menu.add(Menu.NONE, MI_DISPLAY, Menu.NONE, R.string.switch_to); boolean protect = ignoreList.contains(rap.procInfo.processName) || rap.sys; if (protect) { menu.add(Menu.NONE, MI_ENDTASK, Menu.NONE, R.string.end_task).setEnabled(false); } else { menu.add(Menu.NONE, MI_ENDTASK, Menu.NONE, R.string.end_task); } menu.add(Menu.NONE, MI_END_OTHERS, Menu.NONE, R.string.end_others); if (protect) { menu.add(Menu.NONE, MI_IGNORE, Menu.NONE, R.string.ignore).setEnabled(false); } else { menu.add(Menu.NONE, MI_IGNORE, Menu.NONE, R.string.ignore); } menu.add(Menu.NONE, MI_DETAILS, Menu.NONE, R.string.details); } @Override public boolean onContextItemSelected(MenuItem item) { int pos = ((AdapterContextMenuInfo) item.getMenuInfo()).position; if (pos < getListView().getCount()) { ProcessItem rap = (ProcessItem) getListView().getItemAtPosition(pos); if (item.getItemId() == MI_DISPLAY) { handleAction(rap, ACTION_SWITCH); return true; } else if (item.getItemId() == MI_ENDTASK) { handleAction(rap, ACTION_END); return true; } else if (item.getItemId() == MI_END_OTHERS) { handleAction(rap, ACTION_END_OTHERS); return true; } else if (item.getItemId() == MI_IGNORE) { handleAction(rap, ACTION_IGNORE); return true; } else if (item.getItemId() == MI_DETAILS) { handleAction(rap, ACTION_DETAILS); return true; } } return super.onContextItemSelected(item); } static ArrayList<String> getIgnoreList(SharedPreferences sp) { if (sp == null) { return null; } String listVal = sp.getString(PREF_KEY_IGNORE_LIST, null); if (listVal == null || listVal.length() == 0) { return null; } StringTokenizer tokenizer = new StringTokenizer(listVal); ArrayList<String> list = new ArrayList<String>(); while (tokenizer.hasMoreTokens()) { list.add(tokenizer.nextToken()); } return list.size() == 0 ? null : list; } private void setIgnoreList(Collection<String> list) { SharedPreferences sp = getActivity().getSharedPreferences(PSTORE_PROCESSMANAGER, Context.MODE_PRIVATE); Editor et = sp.edit(); if (list == null || list.isEmpty()) { et.remove(PREF_KEY_IGNORE_LIST); } else { StringBuffer sb = new StringBuffer(); int i = 0; for (String s : list) { if (i > 0) { sb.append(' '); } sb.append(s); i++; } et.putString(PREF_KEY_IGNORE_LIST, sb.toString()); } et.commit(); } void handleAction(final ProcessItem rap, int action) { Activity ctx = getActivity(); switch (action) { case ACTION_END: if (!ignoreList.contains(rap.procInfo.processName) && !rap.sys) { ActivityManager am = (ActivityManager) ctx.getSystemService(Context.ACTIVITY_SERVICE); String self = ctx.getPackageName(); if (self.equals(rap.procInfo.processName)) { Util.killSelf(handler, ctx, am, self); } else { endProcess(am, rap.procInfo.pkgList, self); handler.removeCallbacks(task); handler.post(task); } } break; case ACTION_END_OTHERS: endAllExcept(rap.procInfo.processName); break; case ACTION_SWITCH: String pkgName = rap.procInfo.processName; if (!pkgName.equals(ctx.getPackageName())) { Intent it = new Intent("android.intent.action.MAIN"); //$NON-NLS-1$ it.addCategory(Intent.CATEGORY_LAUNCHER); List<ResolveInfo> acts = ctx.getPackageManager().queryIntentActivities(it, 0); if (acts != null) { boolean started = false; for (int i = 0, size = acts.size(); i < size; i++) { ResolveInfo ri = acts.get(i); if (pkgName.equals(ri.activityInfo.packageName)) { it.setClassName(ri.activityInfo.packageName, ri.activityInfo.name); it.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) .addFlags(Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY); try { startActivity(it); started = true; } catch (Exception e) { Log.e(ProcessManager.class.getName(), "Cannot start activity: " + pkgName, //$NON-NLS-1$ e); } break; } } if (!started) { Util.shortToast(ctx, R.string.error_switch_task); } } } break; case ACTION_IGNORE: if (!ignoreList.contains(rap.procInfo.processName) && !rap.sys) { ignoreList.add(rap.procInfo.processName); setIgnoreList(ignoreList); if (IGNORE_ACTION_HIDDEN == Util.getIntOption(ctx, PSTORE_PROCESSMANAGER, PREF_KEY_IGNORE_ACTION, IGNORE_ACTION_HIDDEN)) { handler.removeCallbacks(task); handler.post(task); } } break; case ACTION_DETAILS: String[] status = readProcStatus(rap.procInfo.pid); StringBuffer sb = new StringBuffer().append("<small>") //$NON-NLS-1$ .append(getString(R.string.proc_name)).append(": ") //$NON-NLS-1$ .append(rap.procInfo.processName).append("<br>") //$NON-NLS-1$ .append(getString(R.string.pid)).append(": ") //$NON-NLS-1$ .append(rap.procInfo.pid).append("<br>") //$NON-NLS-1$ .append(getString(R.string.uid)).append(": ") //$NON-NLS-1$ .append(status == null ? "" : status[1]) //$NON-NLS-1$ .append("<br>") //$NON-NLS-1$ .append(getString(R.string.gid)).append(": ") //$NON-NLS-1$ .append(status == null ? "" : status[2]) //$NON-NLS-1$ .append("<br>") //$NON-NLS-1$ .append(getString(R.string.state)).append(": ") //$NON-NLS-1$ .append(status == null ? "" : status[0]) //$NON-NLS-1$ .append("<br>") //$NON-NLS-1$ .append(getString(R.string.threads)).append(": ") //$NON-NLS-1$ .append(status == null ? "" : status[3]) //$NON-NLS-1$ .append("<br>") //$NON-NLS-1$ .append(getString(R.string.importance)).append(": ") //$NON-NLS-1$ .append(rap.procInfo.importance).append("<br>LRU: ") //$NON-NLS-1$ .append(rap.procInfo.lru).append("<br>") //$NON-NLS-1$ .append(getString(R.string.pkg_name)).append(": "); //$NON-NLS-1$ if (rap.procInfo.pkgList != null) { int i = 0; for (String pkg : rap.procInfo.pkgList) { if (pkg != null) { if (i > 0) { sb.append(", "); //$NON-NLS-1$ } sb.append(pkg); i++; } } } sb.append("</small>"); //$NON-NLS-1$ new AlertDialog.Builder(ctx).setTitle(rap.label == null ? rap.procInfo.processName : rap.label) .setNeutralButton(R.string.close, null).setMessage(Html.fromHtml(sb.toString())).create() .show(); break; case ACTION_MENU: final boolean protect = ignoreList.contains(rap.procInfo.processName) || rap.sys; OnClickListener listener = new OnClickListener() { public void onClick(DialogInterface dialog, int which) { dialog.dismiss(); // bypass the 'showMenu' action offset int action = which + 1; if (!protect || (action != ACTION_END && action != ACTION_IGNORE)) { handleAction(rap, action); } } }; new AlertDialog.Builder( ctx).setTitle(R.string.actions) .setItems( new CharSequence[] { getString(R.string.switch_to), protect ? Html.fromHtml("<font color=\"#848484\">" //$NON-NLS-1$ + getString(R.string.end_task) + "</font>") //$NON-NLS-1$ : getString(R.string.end_task), getString(R.string.end_others), protect ? Html.fromHtml("<font color=\"#848484\">" //$NON-NLS-1$ + getString(R.string.ignore) + "</font>") //$NON-NLS-1$ : getString(R.string.ignore), getString(R.string.details) }, listener) .create().show(); break; } } private void endProcess(ActivityManager am, String[] pkgs, String self) { if (pkgs != null) { for (String pkg : pkgs) { if (pkg != null) { int subKillType = Util.killable(pkg, self, ignoreList); if (subKillType == 0) { am.restartPackage(pkg); } } } } } void endAllExcept(String exception) { Activity ctx = getActivity(); ActivityManager am = (ActivityManager) ctx.getSystemService(Context.ACTIVITY_SERVICE); String self = ctx.getPackageName(); ListView lstProcs = getListView(); // skip the dummy info for (int i = 1, size = lstProcs.getCount(); i < size; i++) { ProcessItem rap = (ProcessItem) lstProcs.getItemAtPosition(i); String procName = rap.procInfo.processName; if (!ignoreList.contains(procName) && !self.equals(procName) && !rap.sys && !procName.equals(exception)) { endProcess(am, rap.procInfo.pkgList, self); } } if (!ignoreList.contains(self) && !self.equals(exception)) { Util.killSelf(handler, ctx, am, self); } else { handler.removeCallbacks(task); handler.post(task); } } void refreshHeader() { if (rootView == null) { return; } Activity ctx = getActivity(); TextView txt_head_mem = (TextView) rootView.findViewById(R.id.txt_head_mem); TextView txt_head_cpu = (TextView) rootView.findViewById(R.id.txt_head_cpu); boolean showMem = Util.getBooleanOption(ctx, PSTORE_PROCESSMANAGER, PREF_KEY_SHOW_MEM); boolean showCpu = Util.getBooleanOption(ctx, PSTORE_PROCESSMANAGER, PREF_KEY_SHOW_CPU); StringBuilder totalString = null; if (showMem) { txt_head_mem.setVisibility(View.VISIBLE); long[] mem = SiragonManager.getMemState(ctx); if (mem != null) { totalString = new StringBuilder(); totalString.append(getString(R.string.free)).append(": ") //$NON-NLS-1$ .append(Formatter.formatFileSize(ctx, mem[2])); } } else { txt_head_mem.setVisibility(View.GONE); } if (showCpu) { txt_head_cpu.setVisibility(View.VISIBLE); long cu = totalDelta == 0 ? 0 : (workDelta * 100 / totalDelta); if (cu < 0) { cu = 0; } if (cu > 100) { cu = 100; } if (totalString == null) { totalString = new StringBuilder(); totalString.append(getString(R.string.load)).append(": ") //$NON-NLS-1$ .append(cu).append('%'); } else { totalString.append(" ") //$NON-NLS-1$ .append(getString(R.string.load)).append(": ") //$NON-NLS-1$ .append(cu).append('%'); } } else { txt_head_cpu.setVisibility(View.GONE); } View header = rootView.findViewById(R.id.list_head); if (totalString == null) { header.setVisibility(View.GONE); } else { TextView txt_head_total = (TextView) rootView.findViewById(R.id.txt_head_total); txt_head_total.setText(totalString); header.setVisibility(View.VISIBLE); } } void updateProcess(List<RunningAppProcessInfo> list) { Activity ctx = getActivity(); boolean showCpu = Util.getBooleanOption(ctx, PSTORE_PROCESSMANAGER, PREF_KEY_SHOW_CPU); if (showCpu) { long[] loads = readCpuLoad(); long newload = loads == null ? 0 : (loads[0] + loads[1]); if (totalLoad != 0) { totalDelta = newload - totalLoad; } totalLoad = newload; long newWork = loads == null ? 0 : loads[0]; if (totalWork != 0) { workDelta = newWork - totalWork; } totalWork = newWork; } synchronized (procCache) { procCache.procList.clear(); if (list != null) { int ignoreAction = Util.getIntOption(ctx, PSTORE_PROCESSMANAGER, PREF_KEY_IGNORE_ACTION, IGNORE_ACTION_HIDDEN); boolean showMem = Util.getBooleanOption(ctx, PSTORE_PROCESSMANAGER, PREF_KEY_SHOW_MEM); boolean showSys = Util.getBooleanOption(ctx, PSTORE_PROCESSMANAGER, PREF_KEY_SHOW_SYS_PROC); String name; boolean isSys; for (int i = 0, size = list.size(); i < size; i++) { RunningAppProcessInfo rap = list.get(i); name = rap.processName; isSys = Util.isSysProcess(name); if (isSys && !showSys) { continue; } if (ignoreAction == IGNORE_ACTION_HIDDEN && ignoreList.contains(name)) { continue; } ProcessItem pi = procCache.resCache.get(name); if (pi == null) { pi = new ProcessItem(); pi.procInfo = rap; pi.sys = isSys; } else { pi.procInfo = rap; pi.sys = isSys; pi.lastcputime = pi.cputime; } if (rap.pid != 0 && (showMem || showCpu)) { readProcessStat(ctx, buf, pi, showMem, showCpu); } procCache.procList.add(pi); } procCache.reOrder( Util.getIntOption(ctx, PSTORE_PROCESSMANAGER, PREF_KEY_SORT_ORDER_TYPE, ORDER_TYPE_NAME), Util.getIntOption(ctx, PSTORE_PROCESSMANAGER, PREF_KEY_SORT_DIRECTION, ORDER_ASC)); } } } /** * @return [worktime, idletime] */ static long[] readCpuLoad() { BufferedReader reader = null; try { reader = new BufferedReader(new InputStreamReader(new FileInputStream("/proc/stat")), //$NON-NLS-1$ 256); String line = reader.readLine(); if (line != null && line.startsWith("cpu ")) //$NON-NLS-1$ { line = line.substring(3).trim(); StringTokenizer tokens = new StringTokenizer(line); long totaltime = 0, idletime = 0; int i = 0; String tk; while (tokens.hasMoreTokens() && i < 7) { tk = tokens.nextToken(); if (i == 3) { idletime = Long.parseLong(tk); } else { totaltime += Long.parseLong(tk); } i++; } return new long[] { totaltime, idletime }; } } catch (Exception e) { Log.e(ProcessManager.class.getName(), e.getLocalizedMessage(), e); } finally { if (reader != null) { try { reader.close(); } catch (IOException e) { Log.e(ProcessManager.class.getName(), e.getLocalizedMessage(), e); } } } return null; } private static void readProcessStat(Context ctx, byte[] buf, ProcessItem pi, boolean showMem, boolean showCpu) { InputStream is = null; try { is = new FileInputStream("/proc/" //$NON-NLS-1$ + pi.procInfo.pid + "/stat"); //$NON-NLS-1$ ByteArrayOutputStream output = new ByteArrayOutputStream(); int len; while ((len = is.read(buf)) != -1) { output.write(buf, 0, len); } output.close(); String line = output.toString(); if (line != null) { line = line.trim(); int idx = line.lastIndexOf(')'); if (idx != -1) { line = line.substring(idx + 1).trim(); StringTokenizer tokens = new StringTokenizer(line); String rss = null; String utime = null; String stime = null; long nrss; int i = 0; String tk; // [11,12,21] for [utime,stime,rss] while (tokens.hasMoreTokens()) { tk = tokens.nextToken(); if (i == 11) { utime = tk; } else if (i == 12) { stime = tk; } else if (i == 21) { rss = tk; } if (rss != null) { break; } i++; } if (showCpu) { if (utime != null) { pi.cputime = Long.parseLong(utime); } if (stime != null) { pi.cputime += Long.parseLong(stime); } } if (showMem && rss != null) { nrss = Long.parseLong(rss); if (pi.rss != nrss || pi.mem == null) { pi.rss = nrss; pi.mem = Formatter.formatFileSize(ctx, pi.rss * 4 * 1024); } } } } } catch (Exception e) { Log.e(ProcessManager.class.getName(), e.getLocalizedMessage(), e); } finally { if (is != null) { try { is.close(); } catch (IOException e) { Log.e(ProcessManager.class.getName(), e.getLocalizedMessage(), e); } } } } /** * @return [State, UID, GID, Threads] */ private static String[] readProcStatus(int pid) { BufferedReader reader = null; try { reader = new BufferedReader(new InputStreamReader(new FileInputStream("/proc/" //$NON-NLS-1$ + pid + "/status")), //$NON-NLS-1$ 1024); String line; String stateMsg = ""; //$NON-NLS-1$ String uidMsg = ""; //$NON-NLS-1$ String gidMsg = ""; //$NON-NLS-1$ String threadsMsg = ""; //$NON-NLS-1$ while ((line = reader.readLine()) != null) { if (line.startsWith("State:")) //$NON-NLS-1$ { if (line.length() > 6) { stateMsg = line.substring(6).trim(); } } else if (line.startsWith("Uid:")) //$NON-NLS-1$ { if (line.length() > 4) { uidMsg = line.substring(4).trim(); int idx = uidMsg.indexOf('\t'); if (idx != -1) { uidMsg = uidMsg.substring(0, idx); } else { idx = uidMsg.indexOf(' '); if (idx != -1) { uidMsg = uidMsg.substring(0, idx); } } } } else if (line.startsWith("Gid:")) //$NON-NLS-1$ { if (line.length() > 4) { gidMsg = line.substring(4).trim(); int idx = gidMsg.indexOf('\t'); if (idx != -1) { gidMsg = gidMsg.substring(0, idx); } else { idx = gidMsg.indexOf(' '); if (idx != -1) { gidMsg = gidMsg.substring(0, idx); } } } } else if (line.startsWith("Threads:")) //$NON-NLS-1$ { if (line.length() > 8) { threadsMsg = line.substring(8).trim(); } } } return new String[] { stateMsg, uidMsg, gidMsg, threadsMsg }; } catch (Exception e) { Log.e(ProcessManager.class.getName(), e.getLocalizedMessage(), e); } finally { if (reader != null) { try { reader.close(); } catch (IOException ie) { Log.e(ProcessManager.class.getName(), ie.getLocalizedMessage(), ie); } } } return null; } /** * ResourceUpdaterThread */ private static final class ResourceUpdaterThread extends Thread { private Activity ac; private ProcessCache procCache; private Handler handler; volatile boolean aborted; ResourceUpdaterThread(Activity ac, ProcessCache procCache, Handler handler) { super("ProcessResourceUpdater"); //$NON-NLS-1$ this.ac = ac; this.procCache = procCache; this.handler = handler; } public void run() { PackageManager pm = ac.getPackageManager(); boolean changed = false; ArrayList<ProcessItem> localList = procCache.generateLocalList(); for (int i = 0, size = localList.size(); i < size; i++) { if (aborted) { return; } ProcessItem proc = localList.get(i); String pname = proc.procInfo.processName; if (procCache.resCache.containsKey(pname)) { continue; } try { ApplicationInfo ai = pm.getApplicationInfo(pname, 0); if (ai != null) { CharSequence label = pm.getApplicationLabel(ai); if (label != null) { proc.label = label.toString(); changed = true; } } } catch (NameNotFoundException e) { int idx = pname.indexOf(':'); if (idx != -1) { String name = pname.substring(0, idx); try { ApplicationInfo ai = pm.getApplicationInfo(name, 0); if (ai != null) { CharSequence label = pm.getApplicationLabel(ai); if (label != null) { proc.label = label.toString() + pname.substring(idx); changed = true; } } } catch (NameNotFoundException e1) { // ignore this exception } } } procCache.resCache.put(pname, proc); } if (changed) { // reorder by new names if (Util.getIntOption(ac, PSTORE_PROCESSMANAGER, PREF_KEY_SORT_ORDER_TYPE, ORDER_TYPE_NAME) == ORDER_TYPE_NAME) { procCache.reOrder(ORDER_TYPE_NAME, Util.getIntOption(ac, PSTORE_PROCESSMANAGER, PREF_KEY_SORT_DIRECTION, ORDER_ASC)); handler.sendMessage(handler.obtainMessage(MSG_REFRESH_PKG_LABEL, 1, 0)); } else { handler.sendMessage(handler.obtainMessage(MSG_REFRESH_PKG_LABEL, 0, 0)); } } changed = false; for (int i = 0, size = localList.size(); i < size; i++) { if (aborted) { return; } ProcessItem proc = localList.get(i); String pname = proc.procInfo.processName; if (proc.icon != null) { continue; } try { ApplicationInfo ai = pm.getApplicationInfo(pname, 0); if (ai != null) { try { proc.icon = pm.getApplicationIcon(ai); changed = true; } catch (OutOfMemoryError oom) { Log.e(ProcessManager.class.getName(), "OOM when loading icon: " //$NON-NLS-1$ + ai.packageName, oom); } } } catch (NameNotFoundException e1) { // ignore this exception } } if (changed) { handler.sendEmptyMessage(MSG_REFRESH_PKG_ICON); } } } /** * ProcessSettings */ public static final class ProcessSettings extends PreferenceActivity { @Override protected void onCreate(Bundle savedInstanceState) { requestWindowFeature(Window.FEATURE_NO_TITLE); super.onCreate(savedInstanceState); setPreferenceScreen(getPreferenceManager().createPreferenceScreen(this)); PreferenceCategory pc = new PreferenceCategory(this); pc.setTitle(R.string.preference); getPreferenceScreen().addPreference(pc); Preference perfInterval = new Preference(this); perfInterval.setKey(PREF_KEY_REFRESH_INTERVAL); perfInterval.setTitle(R.string.update_speed); pc.addPreference(perfInterval); CheckBoxPreference perfShowMem = new CheckBoxPreference(this); perfShowMem.setKey(PREF_KEY_SHOW_MEM); perfShowMem.setTitle(R.string.show_memory_usage); perfShowMem.setSummary(R.string.show_memory_summary); pc.addPreference(perfShowMem); CheckBoxPreference perfShowCpu = new CheckBoxPreference(this); perfShowCpu.setKey(PREF_KEY_SHOW_CPU); perfShowCpu.setTitle(R.string.show_cpu_usage); perfShowCpu.setSummary(R.string.show_cpu_summary); pc.addPreference(perfShowCpu); CheckBoxPreference perfShowSys = new CheckBoxPreference(this); perfShowSys.setKey(PREF_KEY_SHOW_SYS_PROC); perfShowSys.setTitle(R.string.show_sys_process); perfShowSys.setSummary(R.string.show_sys_process_sum); pc.addPreference(perfShowSys); CheckBoxPreference perfKillWarn = new CheckBoxPreference(this); perfKillWarn.setKey(PREF_KEY_SHOW_KILL_WARN); perfKillWarn.setTitle(R.string.end_task_warning); perfKillWarn.setSummary(R.string.end_task_warning_sum); pc.addPreference(perfKillWarn); Preference perfDefaultAction = new Preference(this); perfDefaultAction.setKey(PREF_KEY_DEFAULT_TAP_ACTION); perfDefaultAction.setTitle(R.string.default_tap_action); pc.addPreference(perfDefaultAction); pc = new PreferenceCategory(this); pc.setTitle(R.string.sort); getPreferenceScreen().addPreference(pc); Preference perfSortType = new Preference(this); perfSortType.setKey(PREF_KEY_SORT_ORDER_TYPE); perfSortType.setTitle(R.string.sort_type); pc.addPreference(perfSortType); Preference perfSortDirection = new Preference(this); perfSortDirection.setKey(PREF_KEY_SORT_DIRECTION); perfSortDirection.setTitle(R.string.sort_direction); pc.addPreference(perfSortDirection); pc = new PreferenceCategory(this); pc.setTitle(R.string.ignore); getPreferenceScreen().addPreference(pc); Preference perfIgnoreAction = new Preference(this); perfIgnoreAction.setKey(PREF_KEY_IGNORE_ACTION); perfIgnoreAction.setTitle(R.string.ignored_as); pc.addPreference(perfIgnoreAction); Preference perfIgnoreList = new Preference(this); perfIgnoreList.setKey(PREF_KEY_IGNORE_LIST); perfIgnoreList.setTitle(R.string.ignored_list); pc.addPreference(perfIgnoreList); refreshInterval(); refreshBooleanOption(PREF_KEY_SHOW_MEM); refreshBooleanOption(PREF_KEY_SHOW_CPU); refreshBooleanOption(PREF_KEY_SHOW_SYS_PROC); refreshBooleanOption(PREF_KEY_SHOW_KILL_WARN); refreshDefaultAction(); refreshSortType(); refreshSortDirection(); refreshIgnoreAction(); refreshIgnoreList(); setResult(RESULT_OK, getIntent()); } void refreshInterval() { int interval = getIntent().getIntExtra(PREF_KEY_REFRESH_INTERVAL, REFRESH_NORMAL); CharSequence label = getString(R.string.normal); switch (interval) { case REFRESH_HIGH: label = getString(R.string.high); break; case REFRESH_LOW: label = getString(R.string.low); break; case REFRESH_PAUSED: label = getString(R.string.paused); break; } findPreference(PREF_KEY_REFRESH_INTERVAL).setSummary(label); } void refreshBooleanOption(String key) { boolean val = getIntent().getBooleanExtra(key, true); ((CheckBoxPreference) findPreference(key)).setChecked(val); } void refreshDefaultAction() { int type = getIntent().getIntExtra(PREF_KEY_DEFAULT_TAP_ACTION, ACTION_MENU); String label = null; switch (type) { case ACTION_END: label = getString(R.string.end_task); break; case ACTION_END_OTHERS: label = getString(R.string.end_others); break; case ACTION_SWITCH: label = getString(R.string.switch_to); break; case ACTION_IGNORE: label = getString(R.string.ignore); break; case ACTION_DETAILS: label = getString(R.string.details); break; case ACTION_MENU: label = getString(R.string.show_menu); break; } findPreference(PREF_KEY_DEFAULT_TAP_ACTION).setSummary(label); } void refreshSortType() { int type = getIntent().getIntExtra(PREF_KEY_SORT_ORDER_TYPE, ORDER_TYPE_NAME); String label = null; switch (type) { case ORDER_TYPE_NAME: label = getString(R.string.name); break; case ORDER_TYPE_IMPORTANCE: label = getString(R.string.importance); break; case ORDER_TYPE_MEM: label = getString(R.string.memory_usage); break; case ORDER_TYPE_CPU: label = getString(R.string.cpu_usage); break; } findPreference(PREF_KEY_SORT_ORDER_TYPE).setSummary(label); } void refreshSortDirection() { int type = getIntent().getIntExtra(PREF_KEY_SORT_DIRECTION, ORDER_ASC); String label = type == ORDER_ASC ? getString(R.string.ascending) : getString(R.string.descending); findPreference(PREF_KEY_SORT_DIRECTION).setSummary(label); } void refreshIgnoreAction() { int action = getIntent().getIntExtra(PREF_KEY_IGNORE_ACTION, IGNORE_ACTION_HIDDEN); findPreference(PREF_KEY_IGNORE_ACTION) .setSummary(action == IGNORE_ACTION_HIDDEN ? R.string.hidden : R.string.protect); } void refreshIgnoreList() { ArrayList<String> list = getIntent().getStringArrayListExtra(PREF_KEY_IGNORE_LIST); Preference pref = findPreference(PREF_KEY_IGNORE_LIST); if (list == null || list.size() == 0) { pref.setSummary(getString(R.string.single_ignored, 0)); pref.setEnabled(false); } else { if (list.size() == 1) { pref.setSummary(getString(R.string.single_ignored, 1)); } else { pref.setSummary(getString(R.string.multi_ignored, list.size())); } pref.setEnabled(true); } } private static String getProcessLabel(String name, PackageManager pm) { if (pm != null) { try { ApplicationInfo ai = pm.getApplicationInfo(name, 0); if (ai != null) { CharSequence label = pm.getApplicationLabel(ai); if (label != null) { name = label.toString(); } } } catch (NameNotFoundException e) { int idx = name.indexOf(':'); if (idx != -1) { String prefix = name.substring(0, idx); try { ApplicationInfo ai = pm.getApplicationInfo(prefix, 0); if (ai != null) { CharSequence label = pm.getApplicationLabel(ai); if (label != null) { name = label.toString() + name.substring(idx); } } } catch (NameNotFoundException e1) { // ignore this exception } } } } return name; } @Override public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) { final Intent it = getIntent(); final String prefKey = preference.getKey(); if (PREF_KEY_REFRESH_INTERVAL.equals(prefKey)) { OnClickListener listener = new OnClickListener() { public void onClick(DialogInterface dialog, int which) { it.putExtra(PREF_KEY_REFRESH_INTERVAL, which); dialog.dismiss(); refreshInterval(); } }; new AlertDialog.Builder(this).setTitle(R.string.update_speed).setNeutralButton(R.string.close, null) .setSingleChoiceItems( new CharSequence[] { getString(R.string.high), getString(R.string.normal), getString(R.string.low), getString(R.string.paused), }, it.getIntExtra(PREF_KEY_REFRESH_INTERVAL, REFRESH_NORMAL), listener) .create().show(); return true; } else if (PREF_KEY_SHOW_MEM.equals(prefKey)) { it.putExtra(PREF_KEY_SHOW_MEM, ((CheckBoxPreference) findPreference(PREF_KEY_SHOW_MEM)).isChecked()); return true; } else if (PREF_KEY_SHOW_CPU.equals(prefKey)) { it.putExtra(PREF_KEY_SHOW_CPU, ((CheckBoxPreference) findPreference(PREF_KEY_SHOW_CPU)).isChecked()); return true; } else if (PREF_KEY_SHOW_SYS_PROC.equals(prefKey)) { it.putExtra(PREF_KEY_SHOW_SYS_PROC, ((CheckBoxPreference) findPreference(PREF_KEY_SHOW_SYS_PROC)).isChecked()); return true; } else if (PREF_KEY_SHOW_KILL_WARN.equals(prefKey)) { it.putExtra(PREF_KEY_SHOW_KILL_WARN, ((CheckBoxPreference) findPreference(PREF_KEY_SHOW_KILL_WARN)).isChecked()); return true; } else if (PREF_KEY_DEFAULT_TAP_ACTION.equals(prefKey)) { OnClickListener listener = new OnClickListener() { public void onClick(DialogInterface dialog, int which) { it.putExtra(PREF_KEY_DEFAULT_TAP_ACTION, which); dialog.dismiss(); refreshDefaultAction(); } }; new AlertDialog.Builder(this).setTitle(R.string.default_tap_action) .setNeutralButton(R.string.close, null) .setSingleChoiceItems( new String[] { getString(R.string.show_menu), getString(R.string.switch_to), getString(R.string.end_task), getString(R.string.end_others), getString(R.string.ignore), getString(R.string.details), }, it.getIntExtra(PREF_KEY_DEFAULT_TAP_ACTION, ACTION_MENU), listener) .create().show(); return true; } else if (PREF_KEY_SORT_ORDER_TYPE.equals(prefKey)) { OnClickListener listener = new OnClickListener() { public void onClick(DialogInterface dialog, int which) { it.putExtra(PREF_KEY_SORT_ORDER_TYPE, which); dialog.dismiss(); refreshSortType(); } }; new AlertDialog.Builder(this).setTitle(R.string.sort_type).setNeutralButton(R.string.close, null) .setSingleChoiceItems( new String[] { getString(R.string.name), getString(R.string.importance), getString(R.string.memory_usage), getString(R.string.cpu_usage), }, it.getIntExtra(PREF_KEY_SORT_ORDER_TYPE, ORDER_TYPE_NAME), listener) .create().show(); return true; } else if (PREF_KEY_SORT_DIRECTION.equals(prefKey)) { OnClickListener listener = new OnClickListener() { public void onClick(DialogInterface dialog, int which) { it.putExtra(PREF_KEY_SORT_DIRECTION, which == 0 ? ORDER_ASC : ORDER_DESC); dialog.dismiss(); refreshSortDirection(); } }; new AlertDialog.Builder(this).setTitle(R.string.sort_direction) .setNeutralButton(R.string.close, null) .setSingleChoiceItems( new String[] { getString(R.string.ascending), getString(R.string.descending), }, it.getIntExtra(PREF_KEY_SORT_DIRECTION, ORDER_ASC) == ORDER_ASC ? 0 : 1, listener) .create().show(); return true; } else if (PREF_KEY_IGNORE_ACTION.equals(prefKey)) { OnClickListener listener = new OnClickListener() { public void onClick(DialogInterface dialog, int which) { it.putExtra(PREF_KEY_IGNORE_ACTION, which); dialog.dismiss(); refreshIgnoreAction(); } }; new AlertDialog.Builder(this).setTitle(R.string.ignored_as).setNeutralButton(R.string.close, null) .setSingleChoiceItems( new String[] { getString(R.string.hidden), getString(R.string.protect), }, it.getIntExtra(PREF_KEY_IGNORE_ACTION, IGNORE_ACTION_HIDDEN), listener) .create().show(); return true; } else if (PREF_KEY_IGNORE_LIST.equals(prefKey)) { final ArrayList<String> list = it.getStringArrayListExtra(PREF_KEY_IGNORE_LIST); final boolean[] state = new boolean[list.size()]; OnClickListener listener = new OnClickListener() { public void onClick(DialogInterface dialog, int which) { ArrayList<String> nlist = new ArrayList<String>(); for (int i = 0, size = list.size(); i < size; i++) { if (!state[i]) { nlist.add(list.get(i)); } } if (list.size() == nlist.size()) { Util.shortToast(ProcessSettings.this, R.string.no_item_remove); } else { if (nlist.size() == 0) { it.removeExtra(PREF_KEY_IGNORE_LIST); } else { it.putStringArrayListExtra(PREF_KEY_IGNORE_LIST, nlist); } dialog.dismiss(); refreshIgnoreList(); } } }; OnMultiChoiceClickListener multiListener = new OnMultiChoiceClickListener() { public void onClick(DialogInterface dialog, int which, boolean isChecked) { state[which] = isChecked; } }; final PackageManager pm = getPackageManager(); final String[] labels = new String[list.size()]; for (int i = 0, size = list.size(); i < size; i++) { labels[i] = getProcessLabel(list.get(i), pm); } new AlertDialog.Builder(this).setTitle(R.string.ignored_list) .setPositiveButton(R.string.remove, listener).setNegativeButton(R.string.close, null) .setMultiChoiceItems(labels, state, multiListener).create().show(); return true; } return false; } } /** * ProcessItem */ private static final class ProcessItem { RunningAppProcessInfo procInfo; String label; Drawable icon; boolean sys; long rss; String mem; long cputime; long lastcputime; ProcessItem() { } @Override public boolean equals(Object o) { if (!(o instanceof ProcessItem)) { return false; } return this.procInfo.pid == ((ProcessItem) o).procInfo.pid; } } /** * ProcessCache */ private static final class ProcessCache { HashMap<String, ProcessItem> resCache; ArrayList<ProcessItem> procList; ProcessCache() { resCache = new HashMap<String, ProcessItem>(); procList = new ArrayList<ProcessItem>(); } synchronized void clear() { resCache.clear(); procList.clear(); } synchronized ArrayList<ProcessItem> generateLocalList() { ArrayList<ProcessItem> local = new ArrayList<ProcessItem>(); local.addAll(procList); return local; } synchronized void reOrder(int type, final int direction) { switch (type) { case ORDER_TYPE_NAME: Collections.sort(procList, new Comparator<ProcessItem>() { Collator clt = Collator.getInstance(); public int compare(ProcessItem obj1, ProcessItem obj2) { String lb1 = obj1.label == null ? obj1.procInfo.processName : obj1.label; String lb2 = obj2.label == null ? obj2.procInfo.processName : obj2.label; return clt.compare(lb1, lb2) * direction; } }); break; case ORDER_TYPE_IMPORTANCE: Collections.sort(procList, new Comparator<ProcessItem>() { public int compare(ProcessItem obj1, ProcessItem obj2) { // result should be reversed return (obj2.procInfo.importance - obj1.procInfo.importance) * direction; } }); break; case ORDER_TYPE_MEM: Collections.sort(procList, new Comparator<ProcessItem>() { public int compare(ProcessItem obj1, ProcessItem obj2) { return (obj1.rss == obj2.rss ? 0 : (obj1.rss < obj2.rss ? -1 : 1)) * direction; } }); break; case ORDER_TYPE_CPU: Collections.sort(procList, new Comparator<ProcessItem>() { public int compare(ProcessItem obj1, ProcessItem obj2) { long c1 = obj1.lastcputime == 0 ? 0 : (obj1.cputime - obj1.lastcputime); long c2 = obj2.lastcputime == 0 ? 0 : (obj2.cputime - obj2.lastcputime); return (c1 == c2 ? 0 : (c1 < c2 ? -1 : 1)) * direction; } }); break; } } } }