ProcessStatsDetail.java revision 5635594c38fb319e050054e42109eb736f274acc
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_USE_USS = "use_uss"; 56 public static final String EXTRA_MAX_WEIGHT = "max_weight"; 57 public static final String EXTRA_TOTAL_TIME = "total_time"; 58 59 private PackageManager mPm; 60 private DevicePolicyManager mDpm; 61 62 private ProcStatsEntry mEntry; 63 private boolean mUseUss; 64 private long mMaxWeight; 65 private long mTotalTime; 66 67 private View mRootView; 68 private TextView mTitleView; 69 private ViewGroup mTwoButtonsPanel; 70 private Button mForceStopButton; 71 private Button mReportButton; 72 private ViewGroup mDetailsParent; 73 private ViewGroup mServicesParent; 74 75 public static String makePercentString(Resources res, long amount, long total) { 76 final double percent = (((double)amount) / total) * 100; 77 return res.getString(R.string.percentage, (int) Math.ceil(percent)); 78 } 79 80 @Override 81 public void onCreate(Bundle icicle) { 82 super.onCreate(icicle); 83 mPm = getActivity().getPackageManager(); 84 mDpm = (DevicePolicyManager)getActivity().getSystemService(Context.DEVICE_POLICY_SERVICE); 85 final Bundle args = getArguments(); 86 mEntry = (ProcStatsEntry)args.getParcelable(EXTRA_ENTRY); 87 mEntry.retrieveUiData(mPm); 88 mUseUss = args.getBoolean(EXTRA_USE_USS); 89 mMaxWeight = args.getLong(EXTRA_MAX_WEIGHT); 90 mTotalTime = args.getLong(EXTRA_TOTAL_TIME); 91 } 92 93 @Override 94 public View onCreateView( 95 LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 96 final View view = inflater.inflate(R.layout.process_stats_details, container, false); 97 prepareCustomPreferencesList(container, view, view, false); 98 99 mRootView = view; 100 createDetails(); 101 return view; 102 } 103 104 @Override 105 public void onResume() { 106 super.onResume(); 107 checkForceStop(); 108 } 109 110 @Override 111 public void onPause() { 112 super.onPause(); 113 } 114 115 private void createDetails() { 116 final double percentOfWeight = (((double)mEntry.mWeight) / mMaxWeight) * 100; 117 118 int appLevel = (int) Math.ceil(percentOfWeight); 119 String appLevelText = makePercentString(getResources(), mEntry.mDuration, mTotalTime); 120 121 // Set all values in the header. 122 final TextView summary = (TextView) mRootView.findViewById(android.R.id.summary); 123 summary.setText(mEntry.mName); 124 summary.setVisibility(View.VISIBLE); 125 mTitleView = (TextView) mRootView.findViewById(android.R.id.title); 126 mTitleView.setText(mEntry.mUiBaseLabel); 127 final TextView text1 = (TextView)mRootView.findViewById(android.R.id.text1); 128 text1.setText(appLevelText); 129 final ProgressBar progress = (ProgressBar) mRootView.findViewById(android.R.id.progress); 130 progress.setProgress(appLevel); 131 final ImageView icon = (ImageView) mRootView.findViewById(android.R.id.icon); 132 if (mEntry.mUiTargetApp != null) { 133 icon.setImageDrawable(mEntry.mUiTargetApp.loadIcon(mPm)); 134 } 135 136 mTwoButtonsPanel = (ViewGroup)mRootView.findViewById(R.id.two_buttons_panel); 137 mForceStopButton = (Button)mRootView.findViewById(R.id.right_button); 138 mReportButton = (Button)mRootView.findViewById(R.id.left_button); 139 mForceStopButton.setEnabled(false); 140 mReportButton.setVisibility(View.INVISIBLE); 141 142 mDetailsParent = (ViewGroup)mRootView.findViewById(R.id.details); 143 mServicesParent = (ViewGroup)mRootView.findViewById(R.id.services); 144 145 fillDetailsSection(); 146 fillServicesSection(); 147 148 if (mEntry.mUid >= android.os.Process.FIRST_APPLICATION_UID) { 149 mForceStopButton.setText(R.string.force_stop); 150 mForceStopButton.setTag(ACTION_FORCE_STOP); 151 mForceStopButton.setOnClickListener(this); 152 mTwoButtonsPanel.setVisibility(View.VISIBLE); 153 } else { 154 mTwoButtonsPanel.setVisibility(View.GONE); 155 } 156 } 157 158 public void onClick(View v) { 159 doAction((Integer) v.getTag()); 160 } 161 162 private void doAction(int action) { 163 PreferenceActivity pa = (PreferenceActivity)getActivity(); 164 switch (action) { 165 case ACTION_FORCE_STOP: 166 killProcesses(); 167 break; 168 } 169 } 170 171 private void addPackageHeaderItem(ViewGroup parent, String packageName) { 172 LayoutInflater inflater = getActivity().getLayoutInflater(); 173 ViewGroup item = (ViewGroup) inflater.inflate(R.layout.running_processes_item, 174 null); 175 parent.addView(item); 176 final ImageView icon = (ImageView) item.findViewById(R.id.icon); 177 TextView nameView = (TextView) item.findViewById(R.id.name); 178 TextView descriptionView = (TextView) item.findViewById(R.id.description); 179 try { 180 ApplicationInfo ai = mPm.getApplicationInfo(packageName, 0); 181 icon.setImageDrawable(ai.loadIcon(mPm)); 182 nameView.setText(ai.loadLabel(mPm)); 183 } catch (PackageManager.NameNotFoundException e) { 184 } 185 descriptionView.setText(packageName); 186 } 187 188 private void addDetailsItem(ViewGroup parent, CharSequence label, CharSequence value) { 189 LayoutInflater inflater = getActivity().getLayoutInflater(); 190 ViewGroup item = (ViewGroup) inflater.inflate(R.layout.power_usage_detail_item_text, 191 null); 192 parent.addView(item); 193 TextView labelView = (TextView) item.findViewById(R.id.label); 194 TextView valueView = (TextView) item.findViewById(R.id.value); 195 labelView.setText(label); 196 valueView.setText(value); 197 } 198 199 private void fillDetailsSection() { 200 addDetailsItem(mDetailsParent, getResources().getText(R.string.process_stats_avg_ram_use), 201 Formatter.formatShortFileSize(getActivity(), 202 (mUseUss ? mEntry.mAvgUss : mEntry.mAvgPss) * 1024)); 203 addDetailsItem(mDetailsParent, getResources().getText(R.string.process_stats_max_ram_use), 204 Formatter.formatShortFileSize(getActivity(), 205 (mUseUss ? mEntry.mMaxUss : mEntry.mMaxPss) * 1024)); 206 addDetailsItem(mDetailsParent, getResources().getText(R.string.process_stats_run_time), 207 makePercentString(getResources(), mEntry.mDuration, mTotalTime)); 208 } 209 210 final static Comparator<ProcStatsEntry.Service> sServiceCompare 211 = new Comparator<ProcStatsEntry.Service>() { 212 @Override 213 public int compare(ProcStatsEntry.Service lhs, ProcStatsEntry.Service rhs) { 214 if (lhs.mDuration < rhs.mDuration) { 215 return 1; 216 } else if (lhs.mDuration > rhs.mDuration) { 217 return -1; 218 } 219 return 0; 220 } 221 }; 222 223 private void fillServicesSection() { 224 if (mEntry.mServices.size() > 0) { 225 boolean addPackageSections = false; 226 if (mEntry.mServices.size() > 1 227 || !mEntry.mServices.valueAt(0).get(0).mPackage.equals(mEntry.mPackage)) { 228 addPackageSections = true; 229 } 230 for (int ip=0; ip<mEntry.mServices.size(); ip++) { 231 ArrayList<ProcStatsEntry.Service> services = 232 (ArrayList<ProcStatsEntry.Service>)mEntry.mServices.valueAt(ip).clone(); 233 Collections.sort(services, sServiceCompare); 234 if (addPackageSections) { 235 addPackageHeaderItem(mServicesParent, services.get(0).mPackage); 236 } 237 for (int is=0; is<services.size(); is++) { 238 ProcStatsEntry.Service service = services.get(is); 239 String label = service.mName; 240 int tail = label.lastIndexOf('.'); 241 if (tail >= 0 && tail < (label.length()-1)) { 242 label = label.substring(tail+1); 243 } 244 long duration = service.mDuration; 245 final double percentOfTime = (((double)duration) / mTotalTime) * 100; 246 addDetailsItem(mServicesParent, label, getActivity().getResources().getString( 247 R.string.percentage, (int) Math.ceil(percentOfTime))); 248 } 249 } 250 } 251 } 252 253 private void killProcesses() { 254 ActivityManager am = (ActivityManager)getActivity().getSystemService( 255 Context.ACTIVITY_SERVICE); 256 am.forceStopPackage(mEntry.mUiPackage); 257 checkForceStop(); 258 } 259 260 private final BroadcastReceiver mCheckKillProcessesReceiver = new BroadcastReceiver() { 261 @Override 262 public void onReceive(Context context, Intent intent) { 263 mForceStopButton.setEnabled(getResultCode() != Activity.RESULT_CANCELED); 264 } 265 }; 266 267 private void checkForceStop() { 268 if (mEntry.mUiPackage == null || mEntry.mUid < Process.FIRST_APPLICATION_UID) { 269 mForceStopButton.setEnabled(false); 270 return; 271 } 272 if (mDpm.packageHasActiveAdmins(mEntry.mUiPackage)) { 273 mForceStopButton.setEnabled(false); 274 return; 275 } 276 try { 277 ApplicationInfo info = mPm.getApplicationInfo(mEntry.mUiPackage, 0); 278 if ((info.flags&ApplicationInfo.FLAG_STOPPED) == 0) { 279 mForceStopButton.setEnabled(true); 280 } 281 } catch (PackageManager.NameNotFoundException e) { 282 } 283 Intent intent = new Intent(Intent.ACTION_QUERY_PACKAGE_RESTART, 284 Uri.fromParts("package", mEntry.mUiPackage, null)); 285 intent.putExtra(Intent.EXTRA_PACKAGES, new String[] { mEntry.mUiPackage }); 286 intent.putExtra(Intent.EXTRA_UID, mEntry.mUid); 287 intent.putExtra(Intent.EXTRA_USER_HANDLE, mEntry.mUid); 288 getActivity().sendOrderedBroadcast(intent, null, mCheckKillProcessesReceiver, null, 289 Activity.RESULT_CANCELED, null, null); 290 } 291} 292