BatteryEntry.java revision 7c80af410b09fa14b6fdb5ecec14b6b96562de4c
1/* 2 * Copyright (C) 2014 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.fuelgauge; 18 19import android.content.Context; 20import android.content.pm.ApplicationInfo; 21import android.content.pm.PackageInfo; 22import android.content.pm.PackageManager; 23import android.content.pm.UserInfo; 24import android.graphics.drawable.Drawable; 25import android.os.BatteryStats; 26import android.os.Handler; 27import android.os.UserManager; 28import com.android.internal.os.BatterySipper; 29import com.android.settings.R; 30import com.android.settings.users.UserUtils; 31 32import java.util.ArrayList; 33import java.util.HashMap; 34 35/** 36 * Wraps the power usage data of a BatterySipper with information about package name 37 * and icon image. 38 */ 39public class BatteryEntry { 40 public static final int MSG_UPDATE_NAME_ICON = 1; 41 public static final int MSG_REPORT_FULLY_DRAWN = 2; 42 43 static final HashMap<String,UidToDetail> sUidCache = new HashMap<String,UidToDetail>(); 44 45 static final ArrayList<BatteryEntry> mRequestQueue = new ArrayList<BatteryEntry>(); 46 static Handler mHandler; 47 48 static private class NameAndIconLoader extends Thread { 49 private boolean mAbort = false; 50 51 public NameAndIconLoader() { 52 super("BatteryUsage Icon Loader"); 53 } 54 55 public void abort() { 56 mAbort = true; 57 } 58 59 @Override 60 public void run() { 61 while (true) { 62 BatteryEntry be; 63 synchronized (mRequestQueue) { 64 if (mRequestQueue.isEmpty() || mAbort) { 65 mHandler.sendEmptyMessage(MSG_REPORT_FULLY_DRAWN); 66 mRequestQueue.clear(); 67 return; 68 } 69 be = mRequestQueue.remove(0); 70 } 71 be.loadNameAndIcon(); 72 } 73 } 74 } 75 76 private static NameAndIconLoader mRequestThread; 77 78 public static void startRequestQueue() { 79 if (mHandler != null) { 80 synchronized (mRequestQueue) { 81 if (!mRequestQueue.isEmpty()) { 82 if (mRequestThread != null) { 83 mRequestThread.abort(); 84 } 85 mRequestThread = new NameAndIconLoader(); 86 mRequestThread.setPriority(Thread.MIN_PRIORITY); 87 mRequestThread.start(); 88 mRequestQueue.notify(); 89 } 90 } 91 } 92 } 93 94 public static void stopRequestQueue() { 95 synchronized (mRequestQueue) { 96 if (mRequestThread != null) { 97 mRequestThread.abort(); 98 mRequestThread = null; 99 mHandler = null; 100 } 101 } 102 } 103 104 public static void clearUidCache() { 105 sUidCache.clear(); 106 } 107 108 public final Context context; 109 public final BatterySipper sipper; 110 111 public String name; 112 public Drawable icon; 113 public int iconId; // For passing to the detail screen. 114 public String defaultPackageName; 115 116 static class UidToDetail { 117 String name; 118 String packageName; 119 Drawable icon; 120 } 121 122 public BatteryEntry(Context context, Handler handler, UserManager um, BatterySipper sipper) { 123 mHandler = handler; 124 this.context = context; 125 this.sipper = sipper; 126 switch (sipper.drainType) { 127 case IDLE: 128 name = context.getResources().getString(R.string.power_idle); 129 iconId = R.drawable.ic_settings_phone_idle; 130 break; 131 case CELL: 132 name = context.getResources().getString(R.string.power_cell); 133 iconId = R.drawable.ic_settings_cell_standby; 134 break; 135 case PHONE: 136 name = context.getResources().getString(R.string.power_phone); 137 iconId = R.drawable.ic_settings_voice_calls; 138 break; 139 case WIFI: 140 name = context.getResources().getString(R.string.power_wifi); 141 iconId = R.drawable.ic_settings_wifi; 142 break; 143 case BLUETOOTH: 144 name = context.getResources().getString(R.string.power_bluetooth); 145 iconId = R.drawable.ic_settings_bluetooth; 146 break; 147 case SCREEN: 148 name = context.getResources().getString(R.string.power_screen); 149 iconId = R.drawable.ic_settings_display; 150 break; 151 case APP: 152 name = sipper.packageWithHighestDrain; 153 break; 154 case USER: { 155 UserInfo info = um.getUserInfo(sipper.userId); 156 if (info != null) { 157 icon = UserUtils.getUserIcon(context, um, info, context.getResources()); 158 name = info != null ? info.name : null; 159 if (name == null) { 160 name = Integer.toString(info.id); 161 } 162 name = context.getResources().getString( 163 R.string.running_process_item_user_label, name); 164 } else { 165 icon = null; 166 name = context.getResources().getString( 167 R.string.running_process_item_removed_user_label); 168 } 169 } break; 170 case UNACCOUNTED: 171 name = context.getResources().getString(R.string.power_unaccounted); 172 iconId = R.drawable.ic_power_system; 173 break; 174 case OVERCOUNTED: 175 name = context.getResources().getString(R.string.power_overcounted); 176 iconId = R.drawable.ic_power_system; 177 break; 178 } 179 if (iconId > 0) { 180 icon = context.getResources().getDrawable(iconId); 181 } 182 if ((name == null || iconId == 0) && this.sipper.uidObj != null) { 183 getQuickNameIconForUid(this.sipper.uidObj); 184 } 185 } 186 187 public Drawable getIcon() { 188 return icon; 189 } 190 191 /** 192 * Gets the application name 193 */ 194 public String getLabel() { 195 return name; 196 } 197 198 void getQuickNameIconForUid(BatteryStats.Uid uidObj) { 199 final int uid = uidObj.getUid(); 200 final String uidString = Integer.toString(uid); 201 if (sUidCache.containsKey(uidString)) { 202 UidToDetail utd = sUidCache.get(uidString); 203 defaultPackageName = utd.packageName; 204 name = utd.name; 205 icon = utd.icon; 206 return; 207 } 208 PackageManager pm = context.getPackageManager(); 209 String[] packages = pm.getPackagesForUid(uid); 210 icon = pm.getDefaultActivityIcon(); 211 if (packages == null) { 212 //name = Integer.toString(uid); 213 if (uid == 0) { 214 name = context.getResources().getString(R.string.process_kernel_label); 215 } else if ("mediaserver".equals(name)) { 216 name = context.getResources().getString(R.string.process_mediaserver_label); 217 } 218 iconId = R.drawable.ic_power_system; 219 icon = context.getResources().getDrawable(iconId); 220 return; 221 } else { 222 //name = packages[0]; 223 } 224 if (mHandler != null) { 225 synchronized (mRequestQueue) { 226 mRequestQueue.add(this); 227 } 228 } 229 } 230 231 /** 232 * Loads the app label and icon image and stores into the cache. 233 */ 234 public void loadNameAndIcon() { 235 // Bail out if the current sipper is not an App sipper. 236 if (sipper.uidObj == null) { 237 return; 238 } 239 PackageManager pm = context.getPackageManager(); 240 final int uid = sipper.uidObj.getUid(); 241 final Drawable defaultActivityIcon = pm.getDefaultActivityIcon(); 242 sipper.mPackages = pm.getPackagesForUid(uid); 243 if (sipper.mPackages == null) { 244 name = Integer.toString(uid); 245 return; 246 } 247 248 String[] packageLabels = new String[sipper.mPackages.length]; 249 System.arraycopy(sipper.mPackages, 0, packageLabels, 0, sipper.mPackages.length); 250 251 int preferredIndex = -1; 252 // Convert package names to user-facing labels where possible 253 for (int i = 0; i < packageLabels.length; i++) { 254 // Check if package matches preferred package 255 if (packageLabels[i].equals(name)) preferredIndex = i; 256 try { 257 ApplicationInfo ai = pm.getApplicationInfo(packageLabels[i], 0); 258 CharSequence label = ai.loadLabel(pm); 259 if (label != null) { 260 packageLabels[i] = label.toString(); 261 } 262 if (ai.icon != 0) { 263 defaultPackageName = sipper.mPackages[i]; 264 icon = ai.loadIcon(pm); 265 break; 266 } 267 } catch (PackageManager.NameNotFoundException e) { 268 } 269 } 270 if (icon == null) icon = defaultActivityIcon; 271 272 if (packageLabels.length == 1) { 273 name = packageLabels[0]; 274 } else { 275 // Look for an official name for this UID. 276 for (String pkgName : sipper.mPackages) { 277 try { 278 final PackageInfo pi = pm.getPackageInfo(pkgName, 0); 279 if (pi.sharedUserLabel != 0) { 280 final CharSequence nm = pm.getText(pkgName, 281 pi.sharedUserLabel, pi.applicationInfo); 282 if (nm != null) { 283 name = nm.toString(); 284 if (pi.applicationInfo.icon != 0) { 285 defaultPackageName = pkgName; 286 icon = pi.applicationInfo.loadIcon(pm); 287 } 288 break; 289 } 290 } 291 } catch (PackageManager.NameNotFoundException e) { 292 } 293 } 294 } 295 final String uidString = Integer.toString(sipper.uidObj.getUid()); 296 UidToDetail utd = new UidToDetail(); 297 utd.name = name; 298 utd.icon = icon; 299 utd.packageName = defaultPackageName; 300 sUidCache.put(uidString, utd); 301 if (mHandler != null) { 302 mHandler.sendMessage(mHandler.obtainMessage(MSG_UPDATE_NAME_ICON, this)); 303 } 304 } 305} 306