diff options
Diffstat (limited to 'src/com/android/settings/fuelgauge')
3 files changed, 769 insertions, 0 deletions
diff --git a/src/com/android/settings/fuelgauge/PowerGaugePreference.java b/src/com/android/settings/fuelgauge/PowerGaugePreference.java new file mode 100644 index 0000000..0bfa12d --- /dev/null +++ b/src/com/android/settings/fuelgauge/PowerGaugePreference.java @@ -0,0 +1,119 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settings.fuelgauge; + +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.ColorFilter; +import android.graphics.PixelFormat; +import android.graphics.drawable.Drawable; +import android.preference.Preference; +import android.view.View; +import android.widget.ImageView; + +import com.android.settings.R; +import com.android.settings.fuelgauge.PowerUsageSummary.BatterySipper; + +/** + * Custom preference for displaying power consumption as a bar and an icon on the left for the + * subsystem/app type. + * + */ +public class PowerGaugePreference extends Preference { + + private Drawable mIcon; + private GaugeDrawable mGauge; + private double mValue; + private BatterySipper mInfo; + + public PowerGaugePreference(Context context, Drawable icon, BatterySipper info) { + super(context); + setLayoutResource(R.layout.preference_powergauge); + mIcon = icon; + mGauge = new GaugeDrawable(); + mGauge.bar = context.getResources().getDrawable(R.drawable.app_gauge); + mInfo = info; + } + + /** + * Sets the width of the gauge in percentage (0 - 100) + * @param percent + */ + void setGaugeValue(double percent) { + mValue = percent; + mGauge.percent = mValue; + } + + BatterySipper getInfo() { + return mInfo; + } + + @Override + protected void onBindView(View view) { + super.onBindView(view); + + ImageView appIcon = (ImageView) view.findViewById(R.id.appIcon); + if (mIcon == null) { + mIcon = getContext().getResources().getDrawable(android.R.drawable.sym_def_app_icon); + } + appIcon.setImageDrawable(mIcon); + + ImageView appGauge = (ImageView) view.findViewById(R.id.appGauge); + appGauge.setImageDrawable(mGauge); + } + + static class GaugeDrawable extends Drawable { + Drawable bar; + double percent; + int lastWidth = -1; + + @Override + public void draw(Canvas canvas) { + if (lastWidth == -1) { + lastWidth = getBarWidth(); + bar.setBounds(0, 0, lastWidth, bar.getIntrinsicHeight()); + } + bar.draw(canvas); + } + + @Override + public int getOpacity() { + return PixelFormat.TRANSLUCENT; + } + + @Override + public void setAlpha(int alpha) { + // Ignore + } + + @Override + public void setColorFilter(ColorFilter cf) { + // Ignore + } + + private int getBarWidth() { + int width = (int) ((this.getBounds().width() * percent) / 100); + int intrinsicWidth = bar.getIntrinsicWidth(); + return Math.max(width, intrinsicWidth); + } + + @Override + public int getIntrinsicHeight() { + return bar.getIntrinsicHeight(); + } + } +} diff --git a/src/com/android/settings/fuelgauge/PowerUsageDetail.java b/src/com/android/settings/fuelgauge/PowerUsageDetail.java new file mode 100644 index 0000000..eeb8663 --- /dev/null +++ b/src/com/android/settings/fuelgauge/PowerUsageDetail.java @@ -0,0 +1,156 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settings.fuelgauge; + +import android.app.Activity; +import android.content.Intent; +import android.os.Bundle; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.ViewGroup; +import android.widget.TextView; + +import com.android.settings.R; + +public class PowerUsageDetail extends Activity { + + public static final int USAGE_SINCE_UNPLUGGED = 1; + public static final int USAGE_SINCE_RESET = 2; + + public static final String EXTRA_TITLE = "title"; + public static final String EXTRA_PERCENT = "percent"; + public static final String EXTRA_USAGE_SINCE = "since"; + public static final String EXTRA_USAGE_DURATION = "duration"; + public static final String EXTRA_DETAIL_TYPES = "types"; + public static final String EXTRA_DETAIL_VALUES = "values"; + + private static final int SECONDS_PER_MINUTE = 60; + private static final int SECONDS_PER_HOUR = 60 * 60; + private static final int SECONDS_PER_DAY = 24 * 60 * 60; + + private static final boolean DEBUG = true; + private String mTitle; + private double mPercentage; + private int mUsageSince; + private int[] mTypes; + private double[] mValues; + private TextView mTitleView; + private ViewGroup mDetailsParent; + private long mStartTime; + + private static final String TAG = "PowerUsageDetail"; + + @Override + protected void onCreate(Bundle icicle) { + super.onCreate(icicle); + setContentView(R.layout.power_usage_details); + createDetails(); + } + + @Override + protected void onResume() { + super.onResume(); + mStartTime = android.os.Process.getElapsedCpuTime(); + } + + @Override + protected void onPause() { + super.onPause(); + } + + private void createDetails() { + final Intent intent = getIntent(); + mTitle = intent.getStringExtra(EXTRA_TITLE); + mPercentage = intent.getDoubleExtra(EXTRA_PERCENT, -1); + mUsageSince = intent.getIntExtra(EXTRA_USAGE_SINCE, USAGE_SINCE_UNPLUGGED); + + mTypes = intent.getIntArrayExtra(EXTRA_DETAIL_TYPES); + mValues = intent.getDoubleArrayExtra(EXTRA_DETAIL_VALUES); + + mTitleView = (TextView) findViewById(R.id.name); + mTitleView.setText(mTitle); + // TODO: I18N + ((TextView)findViewById(R.id.battery_percentage)) + .setText(String.format("%3.2f%% of battery usage since last unplugged", mPercentage)); + + mDetailsParent = (ViewGroup) findViewById(R.id.details); + LayoutInflater inflater = getLayoutInflater(); + if (mTypes != null && mValues != null) { + for (int i = 0; i < mTypes.length; i++) { + // Only add an item if the time is greater than zero + if (mValues[i] <= 0) continue; + final String label = getString(mTypes[i]); + String value = null; + switch (mTypes[i]) { + case R.string.usage_type_data_recv: + case R.string.usage_type_data_send: + value = formatBytes(mValues[i]); + break; + default: + value = formatTime(mValues[i]); + } + ViewGroup item = (ViewGroup) inflater.inflate(R.layout.power_usage_detail_item_text, + null); + mDetailsParent.addView(item); + TextView labelView = (TextView) item.findViewById(R.id.label); + TextView valueView = (TextView) item.findViewById(R.id.value); + labelView.setText(label); + valueView.setText(value); + } + } + } + + private String formatTime(double millis) { + StringBuilder sb = new StringBuilder(); + int seconds = (int) Math.floor(millis / 1000); + + int days = 0, hours = 0, minutes = 0; + if (seconds > SECONDS_PER_DAY) { + days = seconds / SECONDS_PER_DAY; + seconds -= days * SECONDS_PER_DAY; + } + if (seconds > SECONDS_PER_HOUR) { + hours = seconds / SECONDS_PER_HOUR; + seconds -= hours * SECONDS_PER_HOUR; + } + if (seconds > SECONDS_PER_MINUTE) { + minutes = seconds / SECONDS_PER_MINUTE; + seconds -= minutes * SECONDS_PER_MINUTE; + } + if (days > 0) { + sb.append(getString(R.string.battery_history_days, days, hours, minutes, seconds)); + } else if (hours > 0) { + sb.append(getString(R.string.battery_history_hours, hours, minutes, seconds)); + } else if (minutes > 0) { + sb.append(getString(R.string.battery_history_minutes, minutes, seconds)); + } else { + sb.append(getString(R.string.battery_history_seconds, seconds)); + } + return sb.toString(); + } + + private String formatBytes(double bytes) { + // TODO: I18N + if (bytes > 1000 * 1000) { + return String.format("%.2f MB", ((int) (bytes / 1000)) / 1000f); + } else if (bytes > 1024) { + return String.format("%.2f KB", ((int) (bytes / 10)) / 100f); + } else { + return String.format("%d bytes", (int) bytes); + } + } +} diff --git a/src/com/android/settings/fuelgauge/PowerUsageSummary.java b/src/com/android/settings/fuelgauge/PowerUsageSummary.java new file mode 100644 index 0000000..296a9c7 --- /dev/null +++ b/src/com/android/settings/fuelgauge/PowerUsageSummary.java @@ -0,0 +1,494 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settings.fuelgauge; + +import android.content.Context; +import android.content.Intent; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; +import android.content.pm.PackageManager.NameNotFoundException; +import android.graphics.drawable.Drawable; +import android.hardware.SensorManager; +import android.os.BatteryStats; +import android.os.Bundle; +import android.os.Parcel; +import android.os.RemoteException; +import android.os.ServiceManager; +import android.os.SystemClock; +import android.os.BatteryStats.Timer; +import android.os.BatteryStats.Uid; +import android.os.BatteryStats.Uid.Sensor; +import android.preference.Preference; +import android.preference.PreferenceActivity; +import android.preference.PreferenceGroup; +import android.preference.PreferenceScreen; +import android.util.Log; +import android.util.SparseArray; +import android.view.Menu; +import android.view.MenuItem; + +import com.android.internal.app.IBatteryStats; +import com.android.internal.os.BatteryStatsImpl; +import com.android.internal.os.PowerProfile; +import com.android.settings.R; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +/** + * Displays a list of apps and subsystems that consume power, ordered by how much power was + * consumed since the last time it was unplugged. + */ +public class PowerUsageSummary extends PreferenceActivity { + + private static final boolean DEBUG = true; + + private static final String TAG = "PowerUsageSummary"; + + private static final int MENU_STATS_TYPE = Menu.FIRST; + private static final int MENU_STATS_REFRESH = Menu.FIRST + 1; + + enum DrainType { + IDLE, + CELL, + PHONE, + WIFI, + BLUETOOTH, + SCREEN, + APP + } + + IBatteryStats mBatteryInfo; + BatteryStatsImpl mStats; + private List<BatterySipper> mUsageList = new ArrayList<BatterySipper>(); + + private PreferenceGroup mAppListGroup; + + private int mStatsType = BatteryStats.STATS_UNPLUGGED; + + private static final int MIN_POWER_THRESHOLD = 5; + private static final int MAX_ITEMS_TO_LIST = 10; + + private double mMaxPower = 1; + private double mTotalPower; + + private boolean mScaleByMax = true; + + private PowerProfile mPowerProfile; + + @Override + protected void onCreate(Bundle icicle) { + super.onCreate(icicle); + + addPreferencesFromResource(R.xml.power_usage_summary); + mBatteryInfo = IBatteryStats.Stub.asInterface( + ServiceManager.getService("batteryinfo")); + mAppListGroup = getPreferenceScreen(); + mPowerProfile = new PowerProfile(this, "power_profile_default"); + } + + @Override + protected void onResume() { + super.onResume(); + + updateAppsList(); + } + + @Override + public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) { + PowerGaugePreference pgp = (PowerGaugePreference) preference; + BatterySipper sipper = pgp.getInfo(); + Intent intent = new Intent(this, PowerUsageDetail.class); + intent.putExtra(PowerUsageDetail.EXTRA_TITLE, sipper.mLabel); + intent.putExtra(PowerUsageDetail.EXTRA_PERCENT, sipper.getSortValue() * 100 / mTotalPower); + + switch (sipper.mDrainType) { + case APP: + { + Uid uid = sipper.mUid; + int[] types = new int[] { + R.string.usage_type_cpu, + R.string.usage_type_cpu_foreground, + R.string.usage_type_gps, + R.string.usage_type_data_send, + R.string.usage_type_data_recv, + R.string.usage_type_audio, + R.string.usage_type_video, + }; + double[] values = new double[] { + sipper.mCpuTime, + sipper.mCpuFgTime, + sipper.mGpsTime, + uid != null? uid.getTcpBytesSent(mStatsType) : 0, + uid != null? uid.getTcpBytesReceived(mStatsType) : 0, + 0, + 0 + }; + intent.putExtra(PowerUsageDetail.EXTRA_DETAIL_TYPES, types); + intent.putExtra(PowerUsageDetail.EXTRA_DETAIL_VALUES, values); + + } + break; + } + startActivity(intent); + + return super.onPreferenceTreeClick(preferenceScreen, preference); + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + /* + menu.add(0, MENU_STATS_TYPE, 0, R.string.menu_stats_total) + .setIcon(com.android.internal.R.drawable.ic_menu_info_details) + .setAlphabeticShortcut('t'); + */ + menu.add(0, MENU_STATS_REFRESH, 0, R.string.menu_stats_refresh) + .setIcon(com.android.internal.R.drawable.ic_menu_refresh) + .setAlphabeticShortcut('r'); + return true; + } + + @Override + public boolean onPrepareOptionsMenu(Menu menu) { + /* + menu.findItem(MENU_STATS_TYPE).setTitle(mStatsType == BatteryStats.STATS_TOTAL + ? R.string.menu_stats_unplugged + : R.string.menu_stats_total); + */ + return true; + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + case MENU_STATS_TYPE: + if (mStatsType == BatteryStats.STATS_TOTAL) { + mStatsType = BatteryStats.STATS_UNPLUGGED; + } else { + mStatsType = BatteryStats.STATS_TOTAL; + } + updateAppsList(); + return true; + case MENU_STATS_REFRESH: + mStats = null; + updateAppsList(); + return true; + default: + return false; + } + } + + private void updateAppsList() { + if (mStats == null) { + load(); + } + mMaxPower = 0; + mTotalPower = 0; + + mAppListGroup.removeAll(); + mUsageList.clear(); + processAppUsage(); + processMiscUsage(); + + mAppListGroup.setOrderingAsAdded(false); + + Collections.sort(mUsageList); + for (BatterySipper g : mUsageList) { + if (g.getSortValue() < MIN_POWER_THRESHOLD) continue; + double percent = ((g.getSortValue() / mTotalPower) * 100); + PowerGaugePreference pref = new PowerGaugePreference(this, g.getIcon(), g); + double scaleByMax = (g.getSortValue() * 100) / mMaxPower; + pref.setSummary(g.getLabel() + " ( " + String.format("%3.2f", percent) + "% )"); + pref.setOrder(Integer.MAX_VALUE - (int) g.getSortValue()); // Invert the order + pref.setGaugeValue(mScaleByMax ? scaleByMax : percent); + mAppListGroup.addPreference(pref); + if (mAppListGroup.getPreferenceCount() > MAX_ITEMS_TO_LIST) break; + } + } + + private void processAppUsage() { + SensorManager sensorManager = (SensorManager)getSystemService(Context.SENSOR_SERVICE); + final int which = mStatsType; + final double powerCpuNormal = mPowerProfile.getAveragePower(PowerProfile.POWER_CPU_NORMAL); + long uSecTime = mStats.computeBatteryRealtime(SystemClock.elapsedRealtime(), which) * 1000; + SparseArray<? extends Uid> uidStats = mStats.getUidStats(); + final int NU = uidStats.size(); + if (DEBUG) Log.i(TAG, "uidStats size = " + NU); + for (int iu = 0; iu < NU; iu++) { + Uid u = uidStats.valueAt(iu); + double power = 0; + //mUsageList.add(new AppUsage(u.getUid(), new double[] {power})); + Map<String, ? extends BatteryStats.Uid.Proc> processStats = u.getProcessStats(); + long cpuTime = 0; + long cpuFgTime = 0; + long gpsTime = 0; + if (processStats.size() > 0) { + for (Map.Entry<String, ? extends BatteryStats.Uid.Proc> ent + : processStats.entrySet()) { + + Uid.Proc ps = ent.getValue(); + long userTime = ps.getUserTime(which); + long systemTime = ps.getSystemTime(which); + long foregroundTime = ps.getForegroundTime(which); + cpuFgTime += foregroundTime * 10; // convert to millis + if (DEBUG) Log.i(TAG, "CPU Fg time for " + u.getUid() + " = " + foregroundTime); + cpuTime = (userTime + systemTime) * 10; // convert to millis + power += cpuTime * powerCpuNormal; + + } + } + if (cpuFgTime > cpuTime) { + if (DEBUG && cpuFgTime > cpuTime + 10000) { + Log.i(TAG, "WARNING! Cputime is more than 10 seconds behind Foreground time"); + } + cpuTime = cpuFgTime; // Statistics may not have been gathered yet. + } + power /= 1000; + + Map<Integer, ? extends BatteryStats.Uid.Sensor> sensorStats = u.getSensorStats(); + for (Map.Entry<Integer, ? extends BatteryStats.Uid.Sensor> sensorEntry + : sensorStats.entrySet()) { + Uid.Sensor sensor = sensorEntry.getValue(); + int sensorType = sensor.getHandle(); + BatteryStats.Timer timer = sensor.getSensorTime(); + long sensorTime = timer.getTotalTimeLocked(uSecTime, which) / 1000; + double multiplier = 0; + switch (sensorType) { + case Uid.Sensor.GPS: + multiplier = mPowerProfile.getAveragePower(PowerProfile.POWER_GPS_ON); + gpsTime = sensorTime; + break; + default: + android.hardware.Sensor sensorData = + sensorManager.getDefaultSensor(sensorType); + if (sensorData != null) { + multiplier = sensorData.getPower(); + if (DEBUG) { + Log.i(TAG, "Got sensor " + sensorData.getName() + " with power = " + + multiplier); + } + } + } + power += (multiplier * sensorTime) / 1000; + } + if (power != 0) { + BatterySipper app = new BatterySipper(null, DrainType.APP, 0, u, + new double[] {power}); + app.mCpuTime = cpuTime; + app.mGpsTime = gpsTime; + app.mCpuFgTime = cpuFgTime; + mUsageList.add(app); + } + if (power > mMaxPower) mMaxPower = power; + mTotalPower += power; + if (DEBUG) Log.i(TAG, "Added power = " + power); + } + } + + private double getPhoneOnPower(long uSecNow) { + return mPowerProfile.getAveragePower(PowerProfile.POWER_RADIO_ACTIVE) + * mStats.getPhoneOnTime(uSecNow, mStatsType) / 1000 / 1000; + } + + private double getScreenOnPower(long uSecNow) { + double power = 0; + power += mStats.getScreenOnTime(uSecNow, mStatsType) + * mPowerProfile.getAveragePower(PowerProfile.POWER_SCREEN_ON) / 1000; // millis + final double screenFullPower = + mPowerProfile.getAveragePower(PowerProfile.POWER_SCREEN_FULL); + for (int i = 0; i < BatteryStats.NUM_SCREEN_BRIGHTNESS_BINS; i++) { + double screenBinPower = screenFullPower * (i + 0.5f) + / BatteryStats.NUM_SCREEN_BRIGHTNESS_BINS; + long brightnessTime = mStats.getScreenBrightnessTime(i, uSecNow, mStatsType) / 1000; + power += screenBinPower * brightnessTime; + if (DEBUG) { + Log.i(TAG, "Screen bin power = " + (int) screenBinPower + ", time = " + + brightnessTime); + } + } + return power / 1000; + } + + private double getRadioPower(long uSecNow, int which) { + double power = 0; + final int BINS = BatteryStats.NUM_SIGNAL_STRENGTH_BINS; + for (int i = 0; i < BINS; i++) { + power += mStats.getPhoneSignalStrengthTime(i, uSecNow, which) / 1000 / 1000 * + mPowerProfile.getAveragePower(PowerProfile.POWER_RADIO_ON) + * ((BINS - i) / (double) BINS); + } + return power; + } + + private void processMiscUsage() { + final int which = mStatsType; + long uSecTime = SystemClock.elapsedRealtime() * 1000; + final long uSecNow = mStats.computeBatteryRealtime(uSecTime, which); + final long timeSinceUnplugged = uSecNow; + if (DEBUG) { + Log.i(TAG, "Uptime since last unplugged = " + (timeSinceUnplugged / 1000)); + } + + double phoneOnPower = getPhoneOnPower(uSecNow); + addEntry(getString(R.string.power_phone), DrainType.PHONE, + android.R.drawable.ic_menu_call, phoneOnPower); + + double screenOnPower = getScreenOnPower(uSecNow); + addEntry(getString(R.string.power_screen), DrainType.SCREEN, + android.R.drawable.ic_menu_view, screenOnPower); + + double wifiPower = (mStats.getWifiOnTime(uSecNow, which) * 0 /* TODO */ + * mPowerProfile.getAveragePower(PowerProfile.POWER_WIFI_ON) + + mStats.getWifiRunningTime(uSecNow, which) + * mPowerProfile.getAveragePower(PowerProfile.POWER_WIFI_ON)) / 1000 / 1000; + addEntry(getString(R.string.power_wifi), DrainType.WIFI, + R.drawable.ic_wifi_signal_4, wifiPower); + + double idlePower = ((timeSinceUnplugged - mStats.getScreenOnTime(uSecNow, mStatsType)) + * mPowerProfile.getAveragePower(PowerProfile.POWER_CPU_IDLE)) / 1000 / 1000; + addEntry(getString(R.string.power_idle), DrainType.IDLE, + android.R.drawable.ic_lock_power_off, idlePower); + + double radioPower = getRadioPower(uSecNow, which); + addEntry(getString(R.string.power_cell), DrainType.CELL, + android.R.drawable.ic_menu_sort_by_size, radioPower); + } + + private void addEntry(String label, DrainType drainType, int iconId, double power) { + if (power > mMaxPower) mMaxPower = power; + mTotalPower += power; + BatterySipper bs = new BatterySipper(label, drainType, iconId, null, new double[] {power}); + mUsageList.add(bs); + } + + private void load() { + try { + byte[] data = mBatteryInfo.getStatistics(); + Parcel parcel = Parcel.obtain(); + parcel.unmarshall(data, 0, data.length); + parcel.setDataPosition(0); + mStats = com.android.internal.os.BatteryStatsImpl.CREATOR + .createFromParcel(parcel); + } catch (RemoteException e) { + Log.e(TAG, "RemoteException:", e); + } + } + + class BatterySipper implements Comparable<BatterySipper> { + String mLabel; + Drawable mIcon; + Uid mUid; + double mValue; + double[] mValues; + DrainType mDrainType; + long mCpuTime; + long mGpsTime; + long mCpuFgTime; + + BatterySipper(String label, DrainType drainType, int iconId, Uid uid, double[] values) { + mValues = values; + mLabel = label; + mDrainType = drainType; + if (iconId > 0) { + mIcon = getResources().getDrawable(iconId); + } + if (mValues != null) mValue = mValues[0]; + //if (uid > 0 && (mLabel == null || mIcon == null) // TODO: + if ((label == null || iconId == 0) && uid!= null) { + getNameForUid(uid.getUid()); + } + mUid = uid; + } + + double getSortValue() { + return mValue; + } + + double[] getValues() { + return mValues; + } + + Drawable getIcon() { + return mIcon; + } + + public int compareTo(BatterySipper other) { + // Return the flipped value because we want the items in descending order + return (int) (other.getSortValue() - getSortValue()); + } + + String getLabel() { + return mLabel; + } + + /** + * Sets mLabel and mIcon + * @param uid Uid of the application + */ + void getNameForUid(int uid) { + // TODO: Do this on a separate thread + PackageManager pm = getPackageManager(); + String[] packages = pm.getPackagesForUid(uid); + if (packages == null) { + mLabel = Integer.toString(uid); + return; + } + + String[] packageNames = new String[packages.length]; + System.arraycopy(packages, 0, packageNames, 0, packages.length); + + // Convert package names to user-facing labels where possible + for (int i = 0; i < packageNames.length; i++) { + //packageNames[i] = PowerUsageSummary.getLabel(packageNames[i], pm); + try { + ApplicationInfo ai = pm.getApplicationInfo(packageNames[i], 0); + CharSequence label = ai.loadLabel(pm); + if (label != null) { + packageNames[i] = label.toString(); + } + if (mIcon == null) { + mIcon = ai.loadIcon(pm); + } + } catch (NameNotFoundException e) { + } + } + + if (packageNames.length == 1) { + mLabel = packageNames[0]; + } else { + // Look for an official name for this UID. + for (String name : packages) { + try { + PackageInfo pi = pm.getPackageInfo(name, 0); + if (pi.sharedUserLabel != 0) { + CharSequence nm = pm.getText(name, + pi.sharedUserLabel, pi.applicationInfo); + if (nm != null) { + mLabel = nm.toString(); + break; + } + } + } catch (PackageManager.NameNotFoundException e) { + } + } + } + } + } +}
\ No newline at end of file |