summaryrefslogtreecommitdiffstats
path: root/src/com/android/settings/applications/ProcessStatsDetail.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/com/android/settings/applications/ProcessStatsDetail.java')
-rw-r--r--src/com/android/settings/applications/ProcessStatsDetail.java258
1 files changed, 258 insertions, 0 deletions
diff --git a/src/com/android/settings/applications/ProcessStatsDetail.java b/src/com/android/settings/applications/ProcessStatsDetail.java
new file mode 100644
index 0000000..5ec3b07
--- /dev/null
+++ b/src/com/android/settings/applications/ProcessStatsDetail.java
@@ -0,0 +1,258 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.applications;
+
+import android.app.Activity;
+import android.app.ActivityManager;
+import android.app.Fragment;
+import android.app.admin.DevicePolicyManager;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.res.Resources;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.Process;
+import android.preference.PreferenceActivity;
+import android.text.format.Formatter;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Button;
+import android.widget.ImageView;
+import android.widget.ProgressBar;
+import android.widget.TextView;
+import com.android.settings.R;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+
+import static com.android.settings.Utils.prepareCustomPreferencesList;
+
+public class ProcessStatsDetail extends Fragment implements Button.OnClickListener {
+ private static final String TAG = "ProcessStatsDetail";
+
+ public static final int ACTION_FORCE_STOP = 1;
+
+ public static final String EXTRA_ENTRY = "entry";
+ public static final String EXTRA_MAX_WEIGHT = "max_weight";
+ public static final String EXTRA_TOTAL_TIME = "total_time";
+
+ private PackageManager mPm;
+ private DevicePolicyManager mDpm;
+
+ private ProcStatsEntry mEntry;
+ private long mMaxWeight;
+ private long mTotalTime;
+
+ private View mRootView;
+ private TextView mTitleView;
+ private ViewGroup mTwoButtonsPanel;
+ private Button mForceStopButton;
+ private Button mReportButton;
+ private ViewGroup mDetailsParent;
+ private ViewGroup mServicesParent;
+
+ public static String makePercentString(Resources res, long amount, long total) {
+ final double percent = (((double)amount) / total) * 100;
+ return res.getString(R.string.percentage, (int) Math.ceil(percent));
+ }
+
+ @Override
+ public void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+ mPm = getActivity().getPackageManager();
+ mDpm = (DevicePolicyManager)getActivity().getSystemService(Context.DEVICE_POLICY_SERVICE);
+ final Bundle args = getArguments();
+ mEntry = (ProcStatsEntry)args.getParcelable(EXTRA_ENTRY);
+ mEntry.retrieveUiData(mPm);
+ mMaxWeight = args.getLong(EXTRA_MAX_WEIGHT);
+ mTotalTime = args.getLong(EXTRA_TOTAL_TIME);
+ }
+
+ @Override
+ public View onCreateView(
+ LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
+ final View view = inflater.inflate(R.layout.process_stats_details, container, false);
+ prepareCustomPreferencesList(container, view, view, false);
+
+ mRootView = view;
+ createDetails();
+ return view;
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ checkForceStop();
+ }
+
+ @Override
+ public void onPause() {
+ super.onPause();
+ }
+
+ private void createDetails() {
+ final double percentOfWeight = (((double)mEntry.mWeight) / mMaxWeight) * 100;
+
+ int appLevel = (int) Math.ceil(percentOfWeight);
+ String appLevelText = makePercentString(getResources(), mEntry.mDuration, mTotalTime);
+
+ // Set all values in the header.
+ final TextView summary = (TextView) mRootView.findViewById(android.R.id.summary);
+ summary.setText(mEntry.mName);
+ summary.setVisibility(View.VISIBLE);
+ mTitleView = (TextView) mRootView.findViewById(android.R.id.title);
+ mTitleView.setText(mEntry.mUiBaseLabel);
+ final TextView text1 = (TextView)mRootView.findViewById(android.R.id.text1);
+ text1.setText(appLevelText);
+ final ProgressBar progress = (ProgressBar) mRootView.findViewById(android.R.id.progress);
+ progress.setProgress(appLevel);
+ final ImageView icon = (ImageView) mRootView.findViewById(android.R.id.icon);
+ if (mEntry.mUiTargetApp != null) {
+ icon.setImageDrawable(mEntry.mUiTargetApp.loadIcon(mPm));
+ }
+
+ mTwoButtonsPanel = (ViewGroup)mRootView.findViewById(R.id.two_buttons_panel);
+ mForceStopButton = (Button)mRootView.findViewById(R.id.right_button);
+ mReportButton = (Button)mRootView.findViewById(R.id.left_button);
+ mForceStopButton.setEnabled(false);
+ mReportButton.setVisibility(View.INVISIBLE);
+
+ mDetailsParent = (ViewGroup)mRootView.findViewById(R.id.details);
+ mServicesParent = (ViewGroup)mRootView.findViewById(R.id.services);
+
+ fillDetailsSection();
+ fillServicesSection();
+
+ if (mEntry.mUid >= android.os.Process.FIRST_APPLICATION_UID) {
+ mForceStopButton.setText(R.string.force_stop);
+ mForceStopButton.setTag(ACTION_FORCE_STOP);
+ mForceStopButton.setOnClickListener(this);
+ mTwoButtonsPanel.setVisibility(View.VISIBLE);
+ } else {
+ mTwoButtonsPanel.setVisibility(View.GONE);
+ }
+ }
+
+ public void onClick(View v) {
+ doAction((Integer) v.getTag());
+ }
+
+ private void doAction(int action) {
+ PreferenceActivity pa = (PreferenceActivity)getActivity();
+ switch (action) {
+ case ACTION_FORCE_STOP:
+ killProcesses();
+ break;
+ }
+ }
+
+ private void addDetailsItem(ViewGroup parent, CharSequence label, CharSequence value) {
+ LayoutInflater inflater = getActivity().getLayoutInflater();
+ ViewGroup item = (ViewGroup) inflater.inflate(R.layout.power_usage_detail_item_text,
+ null);
+ parent.addView(item);
+ TextView labelView = (TextView) item.findViewById(R.id.label);
+ TextView valueView = (TextView) item.findViewById(R.id.value);
+ labelView.setText(label);
+ valueView.setText(value);
+ }
+
+ private void fillDetailsSection() {
+ addDetailsItem(mDetailsParent, getResources().getText(R.string.process_stats_ram_use),
+ Formatter.formatShortFileSize(getActivity(), mEntry.mAvgPss * 1024));
+ addDetailsItem(mDetailsParent, getResources().getText(R.string.process_stats_run_time),
+ makePercentString(getResources(), mEntry.mDuration, mTotalTime));
+ }
+
+ final static Comparator<ProcStatsEntry.Service> sServiceCompare
+ = new Comparator<ProcStatsEntry.Service>() {
+ @Override
+ public int compare(ProcStatsEntry.Service lhs, ProcStatsEntry.Service rhs) {
+ if (lhs.mDuration < rhs.mDuration) {
+ return 1;
+ } else if (lhs.mDuration > rhs.mDuration) {
+ return -1;
+ }
+ return 0;
+ }
+ };
+
+ private void fillServicesSection() {
+ LayoutInflater inflater = getActivity().getLayoutInflater();
+ if (mEntry.mServices.size() > 0) {
+ ArrayList<ProcStatsEntry.Service> services =
+ (ArrayList<ProcStatsEntry.Service>)mEntry.mServices.clone();
+ Collections.sort(services, sServiceCompare);
+ for (int i=0; i<services.size(); i++) {
+ ProcStatsEntry.Service service = services.get(i);
+ String label = service.mName;
+ int tail = label.lastIndexOf('.');
+ if (tail >= 0 && tail < (label.length()-1)) {
+ label = label.substring(tail+1);
+ }
+ long duration = service.mDuration;
+ final double percentOfTime = (((double)duration) / mTotalTime) * 100;
+ addDetailsItem(mServicesParent, label, getActivity().getResources().getString(
+ R.string.percentage, (int) Math.ceil(percentOfTime)));
+ }
+ }
+ }
+
+ private void killProcesses() {
+ ActivityManager am = (ActivityManager)getActivity().getSystemService(
+ Context.ACTIVITY_SERVICE);
+ am.forceStopPackage(mEntry.mUiPackage);
+ checkForceStop();
+ }
+
+ private final BroadcastReceiver mCheckKillProcessesReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ mForceStopButton.setEnabled(getResultCode() != Activity.RESULT_CANCELED);
+ }
+ };
+
+ private void checkForceStop() {
+ if (mEntry.mUiPackage == null || mEntry.mUid < Process.FIRST_APPLICATION_UID) {
+ mForceStopButton.setEnabled(false);
+ return;
+ }
+ if (mDpm.packageHasActiveAdmins(mEntry.mUiPackage)) {
+ mForceStopButton.setEnabled(false);
+ return;
+ }
+ try {
+ ApplicationInfo info = mPm.getApplicationInfo(mEntry.mUiPackage, 0);
+ if ((info.flags&ApplicationInfo.FLAG_STOPPED) == 0) {
+ mForceStopButton.setEnabled(true);
+ }
+ } catch (PackageManager.NameNotFoundException e) {
+ }
+ Intent intent = new Intent(Intent.ACTION_QUERY_PACKAGE_RESTART,
+ Uri.fromParts("package", mEntry.mUiPackage, null));
+ intent.putExtra(Intent.EXTRA_PACKAGES, new String[] { mEntry.mUiPackage });
+ intent.putExtra(Intent.EXTRA_UID, mEntry.mUid);
+ intent.putExtra(Intent.EXTRA_USER_HANDLE, mEntry.mUid);
+ getActivity().sendOrderedBroadcast(intent, null, mCheckKillProcessesReceiver, null,
+ Activity.RESULT_CANCELED, null, null);
+ }
+}