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 17 package com.android.settings.applications; 18 19 import android.content.Context; 20 import android.content.pm.PackageManager; 21 import android.os.Bundle; 22 import android.preference.Preference; 23 import android.preference.PreferenceGroup; 24 import android.preference.PreferenceScreen; 25 import android.util.Log; 26 import android.util.TimeUtils; 27 import android.view.Menu; 28 import android.view.MenuInflater; 29 import android.view.MenuItem; 30 31 import com.android.internal.app.ProcessStats; 32 import com.android.internal.logging.MetricsLogger; 33 import com.android.settings.R; 34 import com.android.settings.SettingsActivity; 35 import com.android.settings.applications.ProcStatsData.MemInfo; 36 37 import java.util.Collections; 38 import java.util.Comparator; 39 import java.util.List; 40 41 public class ProcessStatsUi extends ProcessStatsBase { 42 static final String TAG = "ProcessStatsUi"; 43 static final boolean DEBUG = false; 44 45 private static final String KEY_APP_LIST = "app_list"; 46 47 private static final int MENU_SHOW_AVG = Menu.FIRST; 48 private static final int MENU_SHOW_MAX = Menu.FIRST + 1; 49 50 private PreferenceGroup mAppListGroup; 51 private PackageManager mPm; 52 53 private boolean mShowMax; 54 private MenuItem mMenuAvg; 55 private MenuItem mMenuMax; 56 57 @Override onCreate(Bundle icicle)58 public void onCreate(Bundle icicle) { 59 super.onCreate(icicle); 60 61 mPm = getActivity().getPackageManager(); 62 63 addPreferencesFromResource(R.xml.process_stats_ui); 64 mAppListGroup = (PreferenceGroup) findPreference(KEY_APP_LIST); 65 setHasOptionsMenu(true); 66 } 67 68 @Override onCreateOptionsMenu(Menu menu, MenuInflater inflater)69 public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { 70 super.onCreateOptionsMenu(menu, inflater); 71 mMenuAvg = menu.add(0, MENU_SHOW_AVG, 0, R.string.sort_avg_use); 72 mMenuMax = menu.add(0, MENU_SHOW_MAX, 0, R.string.sort_max_use); 73 updateMenu(); 74 } 75 76 @Override onOptionsItemSelected(MenuItem item)77 public boolean onOptionsItemSelected(MenuItem item) { 78 switch (item.getItemId()) { 79 case MENU_SHOW_AVG: 80 case MENU_SHOW_MAX: 81 mShowMax = !mShowMax; 82 refreshUi(); 83 updateMenu(); 84 return true; 85 } 86 return super.onOptionsItemSelected(item); 87 } 88 updateMenu()89 private void updateMenu() { 90 mMenuMax.setVisible(!mShowMax); 91 mMenuAvg.setVisible(mShowMax); 92 } 93 94 @Override getMetricsCategory()95 protected int getMetricsCategory() { 96 return MetricsLogger.APPLICATIONS_PROCESS_STATS_UI; 97 } 98 99 @Override onSaveInstanceState(Bundle outState)100 public void onSaveInstanceState(Bundle outState) { 101 super.onSaveInstanceState(outState); 102 } 103 104 @Override onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference)105 public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) { 106 if (!(preference instanceof ProcessStatsPreference)) { 107 return false; 108 } 109 ProcessStatsPreference pgp = (ProcessStatsPreference) preference; 110 MemInfo memInfo = mStatsManager.getMemInfo(); 111 launchMemoryDetail((SettingsActivity) getActivity(), memInfo, pgp.getEntry()); 112 113 return super.onPreferenceTreeClick(preferenceScreen, preference); 114 } 115 116 /** 117 * All states in which we consider a process to be actively running (rather than 118 * something that can be freely killed to reclaim RAM). Note this also includes 119 * the HOME state, because we prioritize home over all cached processes even when 120 * it is in the background, so it is effectively always running from the perspective 121 * of the information we want to show the user here. 122 */ 123 public static final int[] BACKGROUND_AND_SYSTEM_PROC_STATES = new int[] { 124 ProcessStats.STATE_PERSISTENT, ProcessStats.STATE_IMPORTANT_FOREGROUND, 125 ProcessStats.STATE_IMPORTANT_BACKGROUND, ProcessStats.STATE_BACKUP, 126 ProcessStats.STATE_HEAVY_WEIGHT, ProcessStats.STATE_SERVICE, 127 ProcessStats.STATE_SERVICE_RESTARTING, ProcessStats.STATE_RECEIVER, 128 ProcessStats.STATE_HOME 129 }; 130 131 public static final int[] FOREGROUND_PROC_STATES = new int[] { 132 ProcessStats.STATE_TOP 133 }; 134 135 public static final int[] CACHED_PROC_STATES = new int[] { 136 ProcessStats.STATE_CACHED_ACTIVITY, ProcessStats.STATE_CACHED_ACTIVITY_CLIENT, 137 ProcessStats.STATE_CACHED_EMPTY 138 }; 139 makeDuration(long time)140 public static String makeDuration(long time) { 141 StringBuilder sb = new StringBuilder(32); 142 TimeUtils.formatDuration(time, sb); 143 return sb.toString(); 144 } 145 146 @Override refreshUi()147 public void refreshUi() { 148 mAppListGroup.removeAll(); 149 mAppListGroup.setOrderingAsAdded(false); 150 mAppListGroup.setTitle(mShowMax ? R.string.maximum_memory_use 151 : R.string.average_memory_use); 152 153 final Context context = getActivity(); 154 MemInfo memInfo = mStatsManager.getMemInfo(); 155 156 List<ProcStatsPackageEntry> pkgEntries = mStatsManager.getEntries(); 157 158 // Update everything and get the absolute maximum of memory usage for scaling. 159 for (int i=0, N=pkgEntries.size(); i<N; i++) { 160 ProcStatsPackageEntry pkg = pkgEntries.get(i); 161 pkg.updateMetrics(); 162 } 163 164 Collections.sort(pkgEntries, mShowMax ? sMaxPackageEntryCompare : sPackageEntryCompare); 165 166 // Now collect the per-process information into applications, so that applications 167 // running as multiple processes will have only one entry representing all of them. 168 169 if (DEBUG) Log.d(TAG, "-------------------- BUILDING UI"); 170 171 double maxMemory = mShowMax ? memInfo.realTotalRam 172 : memInfo.usedWeight * memInfo.weightToRam; 173 for (int i = 0; i < pkgEntries.size(); i++) { 174 ProcStatsPackageEntry pkg = pkgEntries.get(i); 175 ProcessStatsPreference pref = new ProcessStatsPreference(context); 176 pkg.retrieveUiData(context, mPm); 177 pref.init(pkg, mPm, maxMemory, memInfo.weightToRam, 178 memInfo.totalScale, !mShowMax); 179 pref.setOrder(i); 180 mAppListGroup.addPreference(pref); 181 } 182 } 183 184 final static Comparator<ProcStatsPackageEntry> sPackageEntryCompare 185 = new Comparator<ProcStatsPackageEntry>() { 186 @Override 187 public int compare(ProcStatsPackageEntry lhs, ProcStatsPackageEntry rhs) { 188 double rhsWeight = Math.max(rhs.mRunWeight, rhs.mBgWeight); 189 double lhsWeight = Math.max(lhs.mRunWeight, lhs.mBgWeight); 190 if (lhsWeight == rhsWeight) { 191 return 0; 192 } 193 return lhsWeight < rhsWeight ? 1 : -1; 194 } 195 }; 196 197 final static Comparator<ProcStatsPackageEntry> sMaxPackageEntryCompare 198 = new Comparator<ProcStatsPackageEntry>() { 199 @Override 200 public int compare(ProcStatsPackageEntry lhs, ProcStatsPackageEntry rhs) { 201 double rhsMax = Math.max(rhs.mMaxBgMem, rhs.mMaxRunMem); 202 double lhsMax = Math.max(lhs.mMaxBgMem, lhs.mMaxRunMem); 203 if (lhsMax == rhsMax) { 204 return 0; 205 } 206 return lhsMax < rhsMax ? 1 : -1; 207 } 208 }; 209 } 210