diff options
Diffstat (limited to 'src/com/android/settings/applications/ProcessStatsDetail.java')
-rw-r--r-- | src/com/android/settings/applications/ProcessStatsDetail.java | 258 |
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); + } +} |