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