ProcessStatsDetail.java revision 04486738342fa5e11a78df836efe34b85bee125a
1/* 2 * Copyright (C) 2013 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.android.settings.applications; 18 19import android.app.Activity; 20import android.app.ActivityManager; 21import android.app.Fragment; 22import android.app.admin.DevicePolicyManager; 23import android.content.BroadcastReceiver; 24import android.content.Context; 25import android.content.Intent; 26import android.content.pm.ApplicationInfo; 27import android.content.pm.PackageManager; 28import android.content.res.Resources; 29import android.net.Uri; 30import android.os.Bundle; 31import android.os.Process; 32import android.preference.PreferenceActivity; 33import android.text.format.Formatter; 34import android.view.LayoutInflater; 35import android.view.View; 36import android.view.ViewGroup; 37import android.widget.Button; 38import android.widget.ImageView; 39import android.widget.ProgressBar; 40import android.widget.TextView; 41import com.android.settings.R; 42 43import java.util.ArrayList; 44import java.util.Collections; 45import java.util.Comparator; 46 47import static com.android.settings.Utils.prepareCustomPreferencesList; 48 49public class ProcessStatsDetail extends Fragment implements Button.OnClickListener { 50 private static final String TAG = "ProcessStatsDetail"; 51 52 public static final int ACTION_FORCE_STOP = 1; 53 54 public static final String EXTRA_ENTRY = "entry"; 55 public static final String EXTRA_MAX_WEIGHT = "max_weight"; 56 public static final String EXTRA_TOTAL_TIME = "total_time"; 57 58 private PackageManager mPm; 59 private DevicePolicyManager mDpm; 60 61 private ProcStatsEntry mEntry; 62 private long mMaxWeight; 63 private long mTotalTime; 64 65 private View mRootView; 66 private TextView mTitleView; 67 private ViewGroup mTwoButtonsPanel; 68 private Button mForceStopButton; 69 private Button mReportButton; 70 private ViewGroup mDetailsParent; 71 private ViewGroup mServicesParent; 72 73 public static String makePercentString(Resources res, long amount, long total) { 74 final double percent = (((double)amount) / total) * 100; 75 return res.getString(R.string.percentage, (int) Math.ceil(percent)); 76 } 77 78 @Override 79 public void onCreate(Bundle icicle) { 80 super.onCreate(icicle); 81 mPm = getActivity().getPackageManager(); 82 mDpm = (DevicePolicyManager)getActivity().getSystemService(Context.DEVICE_POLICY_SERVICE); 83 final Bundle args = getArguments(); 84 mEntry = (ProcStatsEntry)args.getParcelable(EXTRA_ENTRY); 85 mEntry.retrieveUiData(mPm); 86 mMaxWeight = args.getLong(EXTRA_MAX_WEIGHT); 87 mTotalTime = args.getLong(EXTRA_TOTAL_TIME); 88 } 89 90 @Override 91 public View onCreateView( 92 LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 93 final View view = inflater.inflate(R.layout.process_stats_details, container, false); 94 prepareCustomPreferencesList(container, view, view, false); 95 96 mRootView = view; 97 createDetails(); 98 return view; 99 } 100 101 @Override 102 public void onResume() { 103 super.onResume(); 104 checkForceStop(); 105 } 106 107 @Override 108 public void onPause() { 109 super.onPause(); 110 } 111 112 private void createDetails() { 113 final double percentOfWeight = (((double)mEntry.mWeight) / mMaxWeight) * 100; 114 115 int appLevel = (int) Math.ceil(percentOfWeight); 116 String appLevelText = makePercentString(getResources(), mEntry.mDuration, mTotalTime); 117 118 // Set all values in the header. 119 final TextView summary = (TextView) mRootView.findViewById(android.R.id.summary); 120 summary.setText(mEntry.mName); 121 summary.setVisibility(View.VISIBLE); 122 mTitleView = (TextView) mRootView.findViewById(android.R.id.title); 123 mTitleView.setText(mEntry.mUiBaseLabel); 124 final TextView text1 = (TextView)mRootView.findViewById(android.R.id.text1); 125 text1.setText(appLevelText); 126 final ProgressBar progress = (ProgressBar) mRootView.findViewById(android.R.id.progress); 127 progress.setProgress(appLevel); 128 final ImageView icon = (ImageView) mRootView.findViewById(android.R.id.icon); 129 if (mEntry.mUiTargetApp != null) { 130 icon.setImageDrawable(mEntry.mUiTargetApp.loadIcon(mPm)); 131 } 132 133 mTwoButtonsPanel = (ViewGroup)mRootView.findViewById(R.id.two_buttons_panel); 134 mForceStopButton = (Button)mRootView.findViewById(R.id.right_button); 135 mReportButton = (Button)mRootView.findViewById(R.id.left_button); 136 mForceStopButton.setEnabled(false); 137 mReportButton.setVisibility(View.INVISIBLE); 138 139 mDetailsParent = (ViewGroup)mRootView.findViewById(R.id.details); 140 mServicesParent = (ViewGroup)mRootView.findViewById(R.id.services); 141 142 fillDetailsSection(); 143 fillServicesSection(); 144 145 if (mEntry.mUid >= android.os.Process.FIRST_APPLICATION_UID) { 146 mForceStopButton.setText(R.string.force_stop); 147 mForceStopButton.setTag(ACTION_FORCE_STOP); 148 mForceStopButton.setOnClickListener(this); 149 mTwoButtonsPanel.setVisibility(View.VISIBLE); 150 } else { 151 mTwoButtonsPanel.setVisibility(View.GONE); 152 } 153 } 154 155 public void onClick(View v) { 156 doAction((Integer) v.getTag()); 157 } 158 159 private void doAction(int action) { 160 PreferenceActivity pa = (PreferenceActivity)getActivity(); 161 switch (action) { 162 case ACTION_FORCE_STOP: 163 killProcesses(); 164 break; 165 } 166 } 167 168 private void addDetailsItem(ViewGroup parent, CharSequence label, CharSequence value) { 169 LayoutInflater inflater = getActivity().getLayoutInflater(); 170 ViewGroup item = (ViewGroup) inflater.inflate(R.layout.power_usage_detail_item_text, 171 null); 172 parent.addView(item); 173 TextView labelView = (TextView) item.findViewById(R.id.label); 174 TextView valueView = (TextView) item.findViewById(R.id.value); 175 labelView.setText(label); 176 valueView.setText(value); 177 } 178 179 private void fillDetailsSection() { 180 addDetailsItem(mDetailsParent, getResources().getText(R.string.process_stats_ram_use), 181 Formatter.formatShortFileSize(getActivity(), mEntry.mAvgPss * 1024)); 182 addDetailsItem(mDetailsParent, getResources().getText(R.string.process_stats_run_time), 183 makePercentString(getResources(), mEntry.mDuration, mTotalTime)); 184 } 185 186 final static Comparator<ProcStatsEntry.Service> sServiceCompare 187 = new Comparator<ProcStatsEntry.Service>() { 188 @Override 189 public int compare(ProcStatsEntry.Service lhs, ProcStatsEntry.Service rhs) { 190 if (lhs.mDuration < rhs.mDuration) { 191 return 1; 192 } else if (lhs.mDuration > rhs.mDuration) { 193 return -1; 194 } 195 return 0; 196 } 197 }; 198 199 private void fillServicesSection() { 200 LayoutInflater inflater = getActivity().getLayoutInflater(); 201 if (mEntry.mServices.size() > 0) { 202 ArrayList<ProcStatsEntry.Service> services = 203 (ArrayList<ProcStatsEntry.Service>)mEntry.mServices.clone(); 204 Collections.sort(services, sServiceCompare); 205 for (int i=0; i<services.size(); i++) { 206 ProcStatsEntry.Service service = services.get(i); 207 String label = service.mName; 208 int tail = label.lastIndexOf('.'); 209 if (tail >= 0 && tail < (label.length()-1)) { 210 label = label.substring(tail+1); 211 } 212 long duration = service.mDuration; 213 final double percentOfTime = (((double)duration) / mTotalTime) * 100; 214 addDetailsItem(mServicesParent, label, getActivity().getResources().getString( 215 R.string.percentage, (int) Math.ceil(percentOfTime))); 216 } 217 } 218 } 219 220 private void killProcesses() { 221 ActivityManager am = (ActivityManager)getActivity().getSystemService( 222 Context.ACTIVITY_SERVICE); 223 am.forceStopPackage(mEntry.mUiPackage); 224 checkForceStop(); 225 } 226 227 private final BroadcastReceiver mCheckKillProcessesReceiver = new BroadcastReceiver() { 228 @Override 229 public void onReceive(Context context, Intent intent) { 230 mForceStopButton.setEnabled(getResultCode() != Activity.RESULT_CANCELED); 231 } 232 }; 233 234 private void checkForceStop() { 235 if (mEntry.mUiPackage == null || mEntry.mUid < Process.FIRST_APPLICATION_UID) { 236 mForceStopButton.setEnabled(false); 237 return; 238 } 239 if (mDpm.packageHasActiveAdmins(mEntry.mUiPackage)) { 240 mForceStopButton.setEnabled(false); 241 return; 242 } 243 try { 244 ApplicationInfo info = mPm.getApplicationInfo(mEntry.mUiPackage, 0); 245 if ((info.flags&ApplicationInfo.FLAG_STOPPED) == 0) { 246 mForceStopButton.setEnabled(true); 247 } 248 } catch (PackageManager.NameNotFoundException e) { 249 } 250 Intent intent = new Intent(Intent.ACTION_QUERY_PACKAGE_RESTART, 251 Uri.fromParts("package", mEntry.mUiPackage, null)); 252 intent.putExtra(Intent.EXTRA_PACKAGES, new String[] { mEntry.mUiPackage }); 253 intent.putExtra(Intent.EXTRA_UID, mEntry.mUid); 254 intent.putExtra(Intent.EXTRA_USER_HANDLE, mEntry.mUid); 255 getActivity().sendOrderedBroadcast(intent, null, mCheckKillProcessesReceiver, null, 256 Activity.RESULT_CANCELED, null, null); 257 } 258} 259