Loading res/values/strings.xml +3 −0 Original line number Diff line number Diff line Loading @@ -1788,6 +1788,9 @@ found in the list of installed applications.</string> <!-- Running service details, default description for services that are started. --> <string name="service_stop_description">This service was started by its application. Stopping it may cause the application to fail.</string> <!-- Running service details, description for running heavy-weight process. --> <string name="heavy_weight_stop_description">This application can not safely be stopped. Doing so may lose some of your current work.</string> <!-- Running service details, default description for services that are managed. --> <string name="service_manage_description"><xliff:g id="client_name">%1$s</xliff:g>: currently in use. Touch Settings to control it.</string> Loading src/com/android/settings/applications/RunningProcessesView.java +10 −2 Original line number Diff line number Diff line Loading @@ -130,8 +130,16 @@ public class RunningProcessesView extends FrameLayout uptimeView.setText(DateUtils.formatElapsedTime(builder, (SystemClock.uptimeMillis()-mFirstRunTime)/1000)); } else { boolean isService = false; if (mItem instanceof RunningState.MergedItem) { isService = ((RunningState.MergedItem)mItem).mServices.size() > 0; } if (isService) { uptimeView.setText(context.getResources().getText( R.string.service_restarting)); } else { uptimeView.setText(""); } } } } Loading src/com/android/settings/applications/RunningServiceDetails.java +141 −113 Original line number Diff line number Diff line Loading @@ -55,6 +55,8 @@ public class RunningServiceDetails extends Activity { RunningProcessesView.ActiveItem mSnippetActiveItem; RunningProcessesView.ViewHolder mSnippetViewHolder; int mNumServices, mNumProcesses; TextView mServicesHeader; TextView mProcessesHeader; final ArrayList<ActiveDetail> mActiveDetails = new ArrayList<ActiveDetail>(); Loading @@ -79,7 +81,7 @@ public class RunningServiceDetails extends Activity { } catch (ActivityNotFoundException e) { Log.w(TAG, e); } } else { } else if (mActiveItem.mItem instanceof RunningState.ServiceItem) { RunningState.ServiceItem si = (RunningState.ServiceItem)mActiveItem.mItem; stopService(new Intent().setComponent(si.mRunningService.service)); if (mMergedItem == null || mMergedItem.mServices.size() <= 1) { Loading @@ -91,6 +93,10 @@ public class RunningServiceDetails extends Activity { mBackgroundHandler.sendEmptyMessage(MSG_UPDATE_CONTENTS); } } } else { // Heavy-weight process. We'll do a force-stop on it. mAm.forceStopPackage(mActiveItem.mItem.mPackageInfo.packageName); finish(); } } } Loading Loading @@ -163,46 +169,32 @@ public class RunningServiceDetails extends Activity { return false; } void addDetailViews() { for (int i=mActiveDetails.size()-1; i>=0; i--) { mAllDetails.removeView(mActiveDetails.get(i).mRootView); } mActiveDetails.clear(); if (mServicesHeader != null) { mAllDetails.removeView(mServicesHeader); mServicesHeader = null; } if (mProcessesHeader != null) { mAllDetails.removeView(mProcessesHeader); mProcessesHeader = null; } if (mMergedItem != null) { for (int i=0; i<mMergedItem.mServices.size(); i++) { if (i == 0) { void addServiceDetailsView(RunningState.ServiceItem si, RunningState.MergedItem mi) { if (mNumServices == 0) { mServicesHeader = (TextView)mInflater.inflate(R.layout.separator_label, mAllDetails, false); mServicesHeader.setText(R.string.runningservicedetails_services_title); mAllDetails.addView(mServicesHeader); } RunningState.ServiceItem si = mMergedItem.mServices.get(i); mNumServices++; RunningState.BaseItem bi = si != null ? si : mi; ActiveDetail detail = new ActiveDetail(); View root = mInflater.inflate(R.layout.running_service_details_service, mAllDetails, false); mAllDetails.addView(root); detail.mRootView = root; detail.mViewHolder = new RunningProcessesView.ViewHolder(root); detail.mActiveItem = detail.mViewHolder.bind(mState, si, mBuilder); detail.mActiveItem = detail.mViewHolder.bind(mState, bi, mBuilder); if (si.mRunningService.clientLabel != 0) { if (si != null && si.mRunningService.clientLabel != 0) { detail.mManageIntent = mAm.getRunningServiceControlPanel( si.mRunningService.service); } TextView description = (TextView)root.findViewById(R.id.comp_description); if (si.mServiceInfo.descriptionRes != 0) { if (si != null && si.mServiceInfo.descriptionRes != 0) { description.setText(getPackageManager().getText( si.mServiceInfo.packageName, si.mServiceInfo.descriptionRes, si.mServiceInfo.applicationInfo)); Loading @@ -217,7 +209,9 @@ public class RunningServiceDetails extends Activity { } catch (PackageManager.NameNotFoundException e) { } } else { description.setText(getText(R.string.service_stop_description)); description.setText(getText(si != null ? R.string.service_stop_description : R.string.heavy_weight_stop_description)); } } Loading @@ -230,21 +224,15 @@ public class RunningServiceDetails extends Activity { mActiveDetails.add(detail); } boolean didProcess = false; for (int i=-1; i<mMergedItem.mOtherProcesses.size(); i++) { RunningState.ProcessItem pi = i < 0 ? mMergedItem.mProcess : mMergedItem.mOtherProcesses.get(i); if (pi.mPid <= 0) { continue; } if (!didProcess) { void addProcessDetailsView(RunningState.ProcessItem pi, boolean isMain) { if (mNumProcesses == 0) { mProcessesHeader = (TextView)mInflater.inflate(R.layout.separator_label, mAllDetails, false); mProcessesHeader.setText(R.string.runningservicedetails_processes_title); mAllDetails.addView(mProcessesHeader); didProcess = true; } mNumProcesses++; ActiveDetail detail = new ActiveDetail(); View root = mInflater.inflate(R.layout.running_service_details_process, mAllDetails, false); Loading @@ -254,7 +242,7 @@ public class RunningServiceDetails extends Activity { detail.mActiveItem = detail.mViewHolder.bind(mState, pi, mBuilder); TextView description = (TextView)root.findViewById(R.id.comp_description); if (i < 0) { if (isMain) { description.setText(R.string.main_running_process_description); } else { int textid = 0; Loading @@ -274,7 +262,7 @@ public class RunningServiceDetails extends Activity { } if (providers != null) { for (int j=0; j<providers.size(); j++) { ProviderInfo prov = providers.get(i); ProviderInfo prov = providers.get(j); if (comp.getClassName().equals(prov.name)) { label = RunningState.makeLabel(getPackageManager(), prov.name, prov); Loading Loading @@ -303,6 +291,46 @@ public class RunningServiceDetails extends Activity { mActiveDetails.add(detail); } void addDetailViews() { for (int i=mActiveDetails.size()-1; i>=0; i--) { mAllDetails.removeView(mActiveDetails.get(i).mRootView); } mActiveDetails.clear(); if (mServicesHeader != null) { mAllDetails.removeView(mServicesHeader); mServicesHeader = null; } if (mProcessesHeader != null) { mAllDetails.removeView(mProcessesHeader); mProcessesHeader = null; } mNumServices = mNumProcesses = 0; if (mMergedItem != null) { for (int i=0; i<mMergedItem.mServices.size(); i++) { addServiceDetailsView(mMergedItem.mServices.get(i), mMergedItem); } if (mMergedItem.mServices.size() <= 0) { // This item does not have any services, so it must be // a heavy-weight process... we will put a fake service // entry for it, to allow the user to "stop" it. addServiceDetailsView(null, mMergedItem); } for (int i=-1; i<mMergedItem.mOtherProcesses.size(); i++) { RunningState.ProcessItem pi = i < 0 ? mMergedItem.mProcess : mMergedItem.mOtherProcesses.get(i); if (pi.mPid <= 0) { continue; } addProcessDetailsView(pi, i < 0); } } } Loading src/com/android/settings/applications/RunningState.java +78 −19 Original line number Diff line number Diff line Loading @@ -47,18 +47,34 @@ import java.util.List; */ public class RunningState { final SparseArray<HashMap<String, ProcessItem>> mProcesses // Processes that are hosting a service we are interested in, organized // by uid and name. Note that this mapping does not change even across // service restarts, and during a restart there will still be a process // entry. final SparseArray<HashMap<String, ProcessItem>> mServiceProcessesByName = new SparseArray<HashMap<String, ProcessItem>>(); final SparseArray<ProcessItem> mActiveProcesses // Processes that are hosting a service we are interested in, organized // by their pid. These disappear and re-appear as services are restarted. final SparseArray<ProcessItem> mServiceProcessesByPid = new SparseArray<ProcessItem>(); // Used to sort the interesting processes. final ServiceProcessComparator mServiceProcessComparator = new ServiceProcessComparator(); // Temporary for finding process dependencies. // Additional heavy-weight processes to be shown to the user, even if // there is no service running in them. final ArrayList<ProcessItem> mHeavyProcesses = new ArrayList<ProcessItem>(); // All currently running processes, for finding dependencies etc. final SparseArray<ProcessItem> mRunningProcesses = new SparseArray<ProcessItem>(); // The processes associated with services, in sorted order. final ArrayList<ProcessItem> mProcessItems = new ArrayList<ProcessItem>(); // All processes, used for retrieving memory information. final ArrayList<ProcessItem> mAllProcessItems = new ArrayList<ProcessItem>(); int mSequence = 0; Loading Loading @@ -128,6 +144,8 @@ public class RunningState { int mRunningSeq; ActivityManager.RunningAppProcessInfo mRunningProcessInfo; MergedItem mMergedItem; // Purely for sorting. boolean mIsSystem; boolean mIsStarted; Loading Loading @@ -435,10 +453,10 @@ public class RunningState { continue; } HashMap<String, ProcessItem> procs = mProcesses.get(si.uid); HashMap<String, ProcessItem> procs = mServiceProcessesByName.get(si.uid); if (procs == null) { procs = new HashMap<String, ProcessItem>(); mProcesses.put(si.uid, procs); mServiceProcessesByName.put(si.uid, procs); } ProcessItem proc = procs.get(si.process); if (proc == null) { Loading @@ -453,10 +471,10 @@ public class RunningState { changed = true; if (proc.mPid != pid) { if (proc.mPid != 0) { mActiveProcesses.remove(proc.mPid); mServiceProcessesByPid.remove(proc.mPid); } if (pid != 0) { mActiveProcesses.put(pid, proc); mServiceProcessesByPid.put(pid, proc); } proc.mPid = pid; } Loading @@ -474,19 +492,30 @@ public class RunningState { final int NP = processes != null ? processes.size() : 0; for (int i=0; i<NP; i++) { ActivityManager.RunningAppProcessInfo pi = processes.get(i); ProcessItem proc = mActiveProcesses.get(pi.pid); ProcessItem proc = mServiceProcessesByPid.get(pi.pid); if (proc == null) { // This process is not one that is a direct container // of a service, so look for it in the secondary // running list. proc = mRunningProcesses.get(pi.pid); if (proc == null) { changed = true; proc = new ProcessItem(context, pi.uid, pi.processName); proc.mPid = pi.pid; mRunningProcesses.put(pi.pid, proc); } proc.mDependentProcesses.clear(); } if ((pi.flags&ActivityManager.RunningAppProcessInfo.FLAG_HEAVY_WEIGHT) != 0) { if (!mHeavyProcesses.contains(proc)) { changed = true; mHeavyProcesses.add(proc); } proc.mCurSeq = mSequence; proc.ensureLabel(pm); } proc.mRunningSeq = mSequence; proc.mRunningProcessInfo = pi; } Loading @@ -499,7 +528,7 @@ public class RunningState { if (proc.mRunningSeq == mSequence) { int clientPid = proc.mRunningProcessInfo.importanceReasonPid; if (clientPid != 0) { ProcessItem client = mActiveProcesses.get(clientPid); ProcessItem client = mServiceProcessesByPid.get(clientPid); if (client == null) { client = mRunningProcesses.get(clientPid); } Loading @@ -508,29 +537,42 @@ public class RunningState { } } else { // In this pass the process doesn't have a client. // Clear to make sure if it later gets the same one // that we will detect the change. // Clear to make sure that, if it later gets the same one, // we will detect the change. proc.mClient = null; } } else { changed = true; mRunningProcesses.remove(mRunningProcesses.keyAt(i)); } } // Remove any old heavy processes. int NHP = mHeavyProcesses.size(); for (int i=0; i<NHP; i++) { ProcessItem proc = mHeavyProcesses.get(i); if (mRunningProcesses.get(proc.mPid) == null) { changed = true; mHeavyProcesses.remove(i); i--; NHP--; } } // Follow the tree from all primary service processes to all // processes they are dependent on, marking these processes as // still being active and determining if anything has changed. final int NAP = mActiveProcesses.size(); final int NAP = mServiceProcessesByPid.size(); for (int i=0; i<NAP; i++) { ProcessItem proc = mActiveProcesses.valueAt(i); ProcessItem proc = mServiceProcessesByPid.valueAt(i); if (proc.mCurSeq == mSequence) { changed |= proc.buildDependencyChain(context, pm, mSequence); } } // Look for services and their primary processes that no longer exist... for (int i=0; i<mProcesses.size(); i++) { HashMap<String, ProcessItem> procs = mProcesses.valueAt(i); for (int i=0; i<mServiceProcessesByName.size(); i++) { HashMap<String, ProcessItem> procs = mServiceProcessesByName.valueAt(i); Iterator<ProcessItem> pit = procs.values().iterator(); while (pit.hasNext()) { ProcessItem pi = pit.next(); Loading @@ -545,10 +587,10 @@ public class RunningState { changed = true; pit.remove(); if (procs.size() == 0) { mProcesses.remove(mProcesses.keyAt(i)); mServiceProcessesByName.remove(mServiceProcessesByName.keyAt(i)); } if (pi.mPid != 0) { mActiveProcesses.remove(pi.mPid); mServiceProcessesByPid.remove(pi.mPid); } continue; } Loading @@ -566,8 +608,8 @@ public class RunningState { if (changed) { // First determine an order for the services. ArrayList<ProcessItem> sortedProcesses = new ArrayList<ProcessItem>(); for (int i=0; i<mProcesses.size(); i++) { for (ProcessItem pi : mProcesses.valueAt(i).values()) { for (int i=0; i<mServiceProcessesByName.size(); i++) { for (ProcessItem pi : mServiceProcessesByName.valueAt(i).values()) { pi.mIsSystem = false; pi.mIsStarted = true; pi.mActiveSince = Long.MAX_VALUE; Loading Loading @@ -643,6 +685,23 @@ public class RunningState { mergedItem.update(context); newMergedItems.add(mergedItem); } // Finally, heavy-weight processes need to be shown and will // go at the top. NHP = mHeavyProcesses.size(); for (int i=0; i<NHP; i++) { ProcessItem proc = mHeavyProcesses.get(i); if (proc.mClient == null && proc.mServices.size() <= 0) { if (proc.mMergedItem == null) { proc.mMergedItem = new MergedItem(); proc.mMergedItem.mProcess = proc; } proc.mMergedItem.update(context); newMergedItems.add(0, proc.mMergedItem); mProcessItems.add(proc); } } synchronized (mLock) { mItems = newItems; mMergedItems = newMergedItems; Loading src/com/android/settings/fuelgauge/BatteryHistoryChart.java +10 −14 Original line number Diff line number Diff line Loading @@ -288,9 +288,9 @@ public class BatteryHistoryChart extends View { } void finishPaths(int w, int h, int levelh, int startX, int y, Path curLevelPath, int lastBatX, boolean lastCharging, boolean lastScreenOn, Path lastPath) { int lastX, boolean lastCharging, boolean lastScreenOn, Path lastPath) { if (curLevelPath != null) { if (lastBatX >= 0) { if (lastX >= 0 && lastX < w) { if (lastPath != null) { lastPath.lineTo(w, y); } Loading @@ -301,10 +301,10 @@ public class BatteryHistoryChart extends View { curLevelPath.close(); } if (lastCharging) { if (lastCharging && lastX < w) { mChargingPath.lineTo(w, h-mChargingOffset); } if (lastScreenOn) { if (lastScreenOn && lastX < w) { mScreenOnPath.lineTo(w, h-mScreenOnOffset); } } Loading @@ -329,7 +329,7 @@ public class BatteryHistoryChart extends View { final int levelh = h - mLevelOffset; BatteryStats.HistoryItem rec = mHistFirst; int x = 0, y = 0, startX = 0, lastX = -1, lastY = -1, lastBatX = -1; int x = 0, y = 0, startX = 0, lastX = -1, lastY = -1; int i = 0; Path curLevelPath = null; Path lastLinePath = null; Loading @@ -342,11 +342,8 @@ public class BatteryHistoryChart extends View { if (lastX != x) { // We have moved by at least a pixel. if (lastY == y) { // Battery level is still the same; don't plot, // but remember it. lastBatX = x; } else { if (lastY != y) { // Don't plot changes within a pixel. Path path; byte value = rec.batteryLevel; if (value <= BATTERY_CRITICAL) path = mBatCriticalPath; Loading @@ -372,7 +369,6 @@ public class BatteryHistoryChart extends View { } lastX = x; lastY = y; lastBatX = -1; final boolean charging = (rec.states&HistoryItem.STATE_BATTERY_PLUGGED_FLAG) != 0; Loading @@ -399,9 +395,9 @@ public class BatteryHistoryChart extends View { } } else if (curLevelPath != null) { finishPaths(x+1, h, levelh, startX, lastY, curLevelPath, lastBatX, finishPaths(x+1, h, levelh, startX, lastY, curLevelPath, lastX, lastCharging, lastScreenOn, lastLinePath); lastX = lastY = lastBatX = -1; lastX = lastY = -1; curLevelPath = null; lastLinePath = null; lastCharging = lastScreenOn = false; Loading @@ -411,7 +407,7 @@ public class BatteryHistoryChart extends View { i++; } finishPaths(w, h, levelh, startX, lastY, curLevelPath, lastBatX, finishPaths(w, h, levelh, startX, lastY, curLevelPath, lastX, lastCharging, lastScreenOn, lastLinePath); } Loading Loading
res/values/strings.xml +3 −0 Original line number Diff line number Diff line Loading @@ -1788,6 +1788,9 @@ found in the list of installed applications.</string> <!-- Running service details, default description for services that are started. --> <string name="service_stop_description">This service was started by its application. Stopping it may cause the application to fail.</string> <!-- Running service details, description for running heavy-weight process. --> <string name="heavy_weight_stop_description">This application can not safely be stopped. Doing so may lose some of your current work.</string> <!-- Running service details, default description for services that are managed. --> <string name="service_manage_description"><xliff:g id="client_name">%1$s</xliff:g>: currently in use. Touch Settings to control it.</string> Loading
src/com/android/settings/applications/RunningProcessesView.java +10 −2 Original line number Diff line number Diff line Loading @@ -130,8 +130,16 @@ public class RunningProcessesView extends FrameLayout uptimeView.setText(DateUtils.formatElapsedTime(builder, (SystemClock.uptimeMillis()-mFirstRunTime)/1000)); } else { boolean isService = false; if (mItem instanceof RunningState.MergedItem) { isService = ((RunningState.MergedItem)mItem).mServices.size() > 0; } if (isService) { uptimeView.setText(context.getResources().getText( R.string.service_restarting)); } else { uptimeView.setText(""); } } } } Loading
src/com/android/settings/applications/RunningServiceDetails.java +141 −113 Original line number Diff line number Diff line Loading @@ -55,6 +55,8 @@ public class RunningServiceDetails extends Activity { RunningProcessesView.ActiveItem mSnippetActiveItem; RunningProcessesView.ViewHolder mSnippetViewHolder; int mNumServices, mNumProcesses; TextView mServicesHeader; TextView mProcessesHeader; final ArrayList<ActiveDetail> mActiveDetails = new ArrayList<ActiveDetail>(); Loading @@ -79,7 +81,7 @@ public class RunningServiceDetails extends Activity { } catch (ActivityNotFoundException e) { Log.w(TAG, e); } } else { } else if (mActiveItem.mItem instanceof RunningState.ServiceItem) { RunningState.ServiceItem si = (RunningState.ServiceItem)mActiveItem.mItem; stopService(new Intent().setComponent(si.mRunningService.service)); if (mMergedItem == null || mMergedItem.mServices.size() <= 1) { Loading @@ -91,6 +93,10 @@ public class RunningServiceDetails extends Activity { mBackgroundHandler.sendEmptyMessage(MSG_UPDATE_CONTENTS); } } } else { // Heavy-weight process. We'll do a force-stop on it. mAm.forceStopPackage(mActiveItem.mItem.mPackageInfo.packageName); finish(); } } } Loading Loading @@ -163,46 +169,32 @@ public class RunningServiceDetails extends Activity { return false; } void addDetailViews() { for (int i=mActiveDetails.size()-1; i>=0; i--) { mAllDetails.removeView(mActiveDetails.get(i).mRootView); } mActiveDetails.clear(); if (mServicesHeader != null) { mAllDetails.removeView(mServicesHeader); mServicesHeader = null; } if (mProcessesHeader != null) { mAllDetails.removeView(mProcessesHeader); mProcessesHeader = null; } if (mMergedItem != null) { for (int i=0; i<mMergedItem.mServices.size(); i++) { if (i == 0) { void addServiceDetailsView(RunningState.ServiceItem si, RunningState.MergedItem mi) { if (mNumServices == 0) { mServicesHeader = (TextView)mInflater.inflate(R.layout.separator_label, mAllDetails, false); mServicesHeader.setText(R.string.runningservicedetails_services_title); mAllDetails.addView(mServicesHeader); } RunningState.ServiceItem si = mMergedItem.mServices.get(i); mNumServices++; RunningState.BaseItem bi = si != null ? si : mi; ActiveDetail detail = new ActiveDetail(); View root = mInflater.inflate(R.layout.running_service_details_service, mAllDetails, false); mAllDetails.addView(root); detail.mRootView = root; detail.mViewHolder = new RunningProcessesView.ViewHolder(root); detail.mActiveItem = detail.mViewHolder.bind(mState, si, mBuilder); detail.mActiveItem = detail.mViewHolder.bind(mState, bi, mBuilder); if (si.mRunningService.clientLabel != 0) { if (si != null && si.mRunningService.clientLabel != 0) { detail.mManageIntent = mAm.getRunningServiceControlPanel( si.mRunningService.service); } TextView description = (TextView)root.findViewById(R.id.comp_description); if (si.mServiceInfo.descriptionRes != 0) { if (si != null && si.mServiceInfo.descriptionRes != 0) { description.setText(getPackageManager().getText( si.mServiceInfo.packageName, si.mServiceInfo.descriptionRes, si.mServiceInfo.applicationInfo)); Loading @@ -217,7 +209,9 @@ public class RunningServiceDetails extends Activity { } catch (PackageManager.NameNotFoundException e) { } } else { description.setText(getText(R.string.service_stop_description)); description.setText(getText(si != null ? R.string.service_stop_description : R.string.heavy_weight_stop_description)); } } Loading @@ -230,21 +224,15 @@ public class RunningServiceDetails extends Activity { mActiveDetails.add(detail); } boolean didProcess = false; for (int i=-1; i<mMergedItem.mOtherProcesses.size(); i++) { RunningState.ProcessItem pi = i < 0 ? mMergedItem.mProcess : mMergedItem.mOtherProcesses.get(i); if (pi.mPid <= 0) { continue; } if (!didProcess) { void addProcessDetailsView(RunningState.ProcessItem pi, boolean isMain) { if (mNumProcesses == 0) { mProcessesHeader = (TextView)mInflater.inflate(R.layout.separator_label, mAllDetails, false); mProcessesHeader.setText(R.string.runningservicedetails_processes_title); mAllDetails.addView(mProcessesHeader); didProcess = true; } mNumProcesses++; ActiveDetail detail = new ActiveDetail(); View root = mInflater.inflate(R.layout.running_service_details_process, mAllDetails, false); Loading @@ -254,7 +242,7 @@ public class RunningServiceDetails extends Activity { detail.mActiveItem = detail.mViewHolder.bind(mState, pi, mBuilder); TextView description = (TextView)root.findViewById(R.id.comp_description); if (i < 0) { if (isMain) { description.setText(R.string.main_running_process_description); } else { int textid = 0; Loading @@ -274,7 +262,7 @@ public class RunningServiceDetails extends Activity { } if (providers != null) { for (int j=0; j<providers.size(); j++) { ProviderInfo prov = providers.get(i); ProviderInfo prov = providers.get(j); if (comp.getClassName().equals(prov.name)) { label = RunningState.makeLabel(getPackageManager(), prov.name, prov); Loading Loading @@ -303,6 +291,46 @@ public class RunningServiceDetails extends Activity { mActiveDetails.add(detail); } void addDetailViews() { for (int i=mActiveDetails.size()-1; i>=0; i--) { mAllDetails.removeView(mActiveDetails.get(i).mRootView); } mActiveDetails.clear(); if (mServicesHeader != null) { mAllDetails.removeView(mServicesHeader); mServicesHeader = null; } if (mProcessesHeader != null) { mAllDetails.removeView(mProcessesHeader); mProcessesHeader = null; } mNumServices = mNumProcesses = 0; if (mMergedItem != null) { for (int i=0; i<mMergedItem.mServices.size(); i++) { addServiceDetailsView(mMergedItem.mServices.get(i), mMergedItem); } if (mMergedItem.mServices.size() <= 0) { // This item does not have any services, so it must be // a heavy-weight process... we will put a fake service // entry for it, to allow the user to "stop" it. addServiceDetailsView(null, mMergedItem); } for (int i=-1; i<mMergedItem.mOtherProcesses.size(); i++) { RunningState.ProcessItem pi = i < 0 ? mMergedItem.mProcess : mMergedItem.mOtherProcesses.get(i); if (pi.mPid <= 0) { continue; } addProcessDetailsView(pi, i < 0); } } } Loading
src/com/android/settings/applications/RunningState.java +78 −19 Original line number Diff line number Diff line Loading @@ -47,18 +47,34 @@ import java.util.List; */ public class RunningState { final SparseArray<HashMap<String, ProcessItem>> mProcesses // Processes that are hosting a service we are interested in, organized // by uid and name. Note that this mapping does not change even across // service restarts, and during a restart there will still be a process // entry. final SparseArray<HashMap<String, ProcessItem>> mServiceProcessesByName = new SparseArray<HashMap<String, ProcessItem>>(); final SparseArray<ProcessItem> mActiveProcesses // Processes that are hosting a service we are interested in, organized // by their pid. These disappear and re-appear as services are restarted. final SparseArray<ProcessItem> mServiceProcessesByPid = new SparseArray<ProcessItem>(); // Used to sort the interesting processes. final ServiceProcessComparator mServiceProcessComparator = new ServiceProcessComparator(); // Temporary for finding process dependencies. // Additional heavy-weight processes to be shown to the user, even if // there is no service running in them. final ArrayList<ProcessItem> mHeavyProcesses = new ArrayList<ProcessItem>(); // All currently running processes, for finding dependencies etc. final SparseArray<ProcessItem> mRunningProcesses = new SparseArray<ProcessItem>(); // The processes associated with services, in sorted order. final ArrayList<ProcessItem> mProcessItems = new ArrayList<ProcessItem>(); // All processes, used for retrieving memory information. final ArrayList<ProcessItem> mAllProcessItems = new ArrayList<ProcessItem>(); int mSequence = 0; Loading Loading @@ -128,6 +144,8 @@ public class RunningState { int mRunningSeq; ActivityManager.RunningAppProcessInfo mRunningProcessInfo; MergedItem mMergedItem; // Purely for sorting. boolean mIsSystem; boolean mIsStarted; Loading Loading @@ -435,10 +453,10 @@ public class RunningState { continue; } HashMap<String, ProcessItem> procs = mProcesses.get(si.uid); HashMap<String, ProcessItem> procs = mServiceProcessesByName.get(si.uid); if (procs == null) { procs = new HashMap<String, ProcessItem>(); mProcesses.put(si.uid, procs); mServiceProcessesByName.put(si.uid, procs); } ProcessItem proc = procs.get(si.process); if (proc == null) { Loading @@ -453,10 +471,10 @@ public class RunningState { changed = true; if (proc.mPid != pid) { if (proc.mPid != 0) { mActiveProcesses.remove(proc.mPid); mServiceProcessesByPid.remove(proc.mPid); } if (pid != 0) { mActiveProcesses.put(pid, proc); mServiceProcessesByPid.put(pid, proc); } proc.mPid = pid; } Loading @@ -474,19 +492,30 @@ public class RunningState { final int NP = processes != null ? processes.size() : 0; for (int i=0; i<NP; i++) { ActivityManager.RunningAppProcessInfo pi = processes.get(i); ProcessItem proc = mActiveProcesses.get(pi.pid); ProcessItem proc = mServiceProcessesByPid.get(pi.pid); if (proc == null) { // This process is not one that is a direct container // of a service, so look for it in the secondary // running list. proc = mRunningProcesses.get(pi.pid); if (proc == null) { changed = true; proc = new ProcessItem(context, pi.uid, pi.processName); proc.mPid = pi.pid; mRunningProcesses.put(pi.pid, proc); } proc.mDependentProcesses.clear(); } if ((pi.flags&ActivityManager.RunningAppProcessInfo.FLAG_HEAVY_WEIGHT) != 0) { if (!mHeavyProcesses.contains(proc)) { changed = true; mHeavyProcesses.add(proc); } proc.mCurSeq = mSequence; proc.ensureLabel(pm); } proc.mRunningSeq = mSequence; proc.mRunningProcessInfo = pi; } Loading @@ -499,7 +528,7 @@ public class RunningState { if (proc.mRunningSeq == mSequence) { int clientPid = proc.mRunningProcessInfo.importanceReasonPid; if (clientPid != 0) { ProcessItem client = mActiveProcesses.get(clientPid); ProcessItem client = mServiceProcessesByPid.get(clientPid); if (client == null) { client = mRunningProcesses.get(clientPid); } Loading @@ -508,29 +537,42 @@ public class RunningState { } } else { // In this pass the process doesn't have a client. // Clear to make sure if it later gets the same one // that we will detect the change. // Clear to make sure that, if it later gets the same one, // we will detect the change. proc.mClient = null; } } else { changed = true; mRunningProcesses.remove(mRunningProcesses.keyAt(i)); } } // Remove any old heavy processes. int NHP = mHeavyProcesses.size(); for (int i=0; i<NHP; i++) { ProcessItem proc = mHeavyProcesses.get(i); if (mRunningProcesses.get(proc.mPid) == null) { changed = true; mHeavyProcesses.remove(i); i--; NHP--; } } // Follow the tree from all primary service processes to all // processes they are dependent on, marking these processes as // still being active and determining if anything has changed. final int NAP = mActiveProcesses.size(); final int NAP = mServiceProcessesByPid.size(); for (int i=0; i<NAP; i++) { ProcessItem proc = mActiveProcesses.valueAt(i); ProcessItem proc = mServiceProcessesByPid.valueAt(i); if (proc.mCurSeq == mSequence) { changed |= proc.buildDependencyChain(context, pm, mSequence); } } // Look for services and their primary processes that no longer exist... for (int i=0; i<mProcesses.size(); i++) { HashMap<String, ProcessItem> procs = mProcesses.valueAt(i); for (int i=0; i<mServiceProcessesByName.size(); i++) { HashMap<String, ProcessItem> procs = mServiceProcessesByName.valueAt(i); Iterator<ProcessItem> pit = procs.values().iterator(); while (pit.hasNext()) { ProcessItem pi = pit.next(); Loading @@ -545,10 +587,10 @@ public class RunningState { changed = true; pit.remove(); if (procs.size() == 0) { mProcesses.remove(mProcesses.keyAt(i)); mServiceProcessesByName.remove(mServiceProcessesByName.keyAt(i)); } if (pi.mPid != 0) { mActiveProcesses.remove(pi.mPid); mServiceProcessesByPid.remove(pi.mPid); } continue; } Loading @@ -566,8 +608,8 @@ public class RunningState { if (changed) { // First determine an order for the services. ArrayList<ProcessItem> sortedProcesses = new ArrayList<ProcessItem>(); for (int i=0; i<mProcesses.size(); i++) { for (ProcessItem pi : mProcesses.valueAt(i).values()) { for (int i=0; i<mServiceProcessesByName.size(); i++) { for (ProcessItem pi : mServiceProcessesByName.valueAt(i).values()) { pi.mIsSystem = false; pi.mIsStarted = true; pi.mActiveSince = Long.MAX_VALUE; Loading Loading @@ -643,6 +685,23 @@ public class RunningState { mergedItem.update(context); newMergedItems.add(mergedItem); } // Finally, heavy-weight processes need to be shown and will // go at the top. NHP = mHeavyProcesses.size(); for (int i=0; i<NHP; i++) { ProcessItem proc = mHeavyProcesses.get(i); if (proc.mClient == null && proc.mServices.size() <= 0) { if (proc.mMergedItem == null) { proc.mMergedItem = new MergedItem(); proc.mMergedItem.mProcess = proc; } proc.mMergedItem.update(context); newMergedItems.add(0, proc.mMergedItem); mProcessItems.add(proc); } } synchronized (mLock) { mItems = newItems; mMergedItems = newMergedItems; Loading
src/com/android/settings/fuelgauge/BatteryHistoryChart.java +10 −14 Original line number Diff line number Diff line Loading @@ -288,9 +288,9 @@ public class BatteryHistoryChart extends View { } void finishPaths(int w, int h, int levelh, int startX, int y, Path curLevelPath, int lastBatX, boolean lastCharging, boolean lastScreenOn, Path lastPath) { int lastX, boolean lastCharging, boolean lastScreenOn, Path lastPath) { if (curLevelPath != null) { if (lastBatX >= 0) { if (lastX >= 0 && lastX < w) { if (lastPath != null) { lastPath.lineTo(w, y); } Loading @@ -301,10 +301,10 @@ public class BatteryHistoryChart extends View { curLevelPath.close(); } if (lastCharging) { if (lastCharging && lastX < w) { mChargingPath.lineTo(w, h-mChargingOffset); } if (lastScreenOn) { if (lastScreenOn && lastX < w) { mScreenOnPath.lineTo(w, h-mScreenOnOffset); } } Loading @@ -329,7 +329,7 @@ public class BatteryHistoryChart extends View { final int levelh = h - mLevelOffset; BatteryStats.HistoryItem rec = mHistFirst; int x = 0, y = 0, startX = 0, lastX = -1, lastY = -1, lastBatX = -1; int x = 0, y = 0, startX = 0, lastX = -1, lastY = -1; int i = 0; Path curLevelPath = null; Path lastLinePath = null; Loading @@ -342,11 +342,8 @@ public class BatteryHistoryChart extends View { if (lastX != x) { // We have moved by at least a pixel. if (lastY == y) { // Battery level is still the same; don't plot, // but remember it. lastBatX = x; } else { if (lastY != y) { // Don't plot changes within a pixel. Path path; byte value = rec.batteryLevel; if (value <= BATTERY_CRITICAL) path = mBatCriticalPath; Loading @@ -372,7 +369,6 @@ public class BatteryHistoryChart extends View { } lastX = x; lastY = y; lastBatX = -1; final boolean charging = (rec.states&HistoryItem.STATE_BATTERY_PLUGGED_FLAG) != 0; Loading @@ -399,9 +395,9 @@ public class BatteryHistoryChart extends View { } } else if (curLevelPath != null) { finishPaths(x+1, h, levelh, startX, lastY, curLevelPath, lastBatX, finishPaths(x+1, h, levelh, startX, lastY, curLevelPath, lastX, lastCharging, lastScreenOn, lastLinePath); lastX = lastY = lastBatX = -1; lastX = lastY = -1; curLevelPath = null; lastLinePath = null; lastCharging = lastScreenOn = false; Loading @@ -411,7 +407,7 @@ public class BatteryHistoryChart extends View { i++; } finishPaths(w, h, levelh, startX, lastY, curLevelPath, lastBatX, finishPaths(w, h, levelh, startX, lastY, curLevelPath, lastX, lastCharging, lastScreenOn, lastLinePath); } Loading