diff options
author | Amith Yamasani <yamasani@google.com> | 2009-06-03 15:45:40 -0700 |
---|---|---|
committer | Amith Yamasani <yamasani@google.com> | 2009-06-03 16:31:15 -0700 |
commit | 7f6aa6283ae759c5b013c142be036617cf79f725 (patch) | |
tree | cd5f60bdf8707632db5f070a16715b6b69e8976d | |
parent | 110b75cde7ca21e83fb84cab70b7d11bdff54f2c (diff) | |
download | packages_apps_Settings-7f6aa6283ae759c5b013c142be036617cf79f725.zip packages_apps_Settings-7f6aa6283ae759c5b013c142be036617cf79f725.tar.gz packages_apps_Settings-7f6aa6283ae759c5b013c142be036617cf79f725.tar.bz2 |
Add detail page for Battery usage and track GPS and foreground CPU.
Show details such as Cpu time, Cpu foreground time, data sent/received,
and GPS usage.
-rw-r--r-- | AndroidManifest.xml | 11 | ||||
-rw-r--r-- | res/layout/power_usage_detail_item_text.xml | 43 | ||||
-rw-r--r-- | res/layout/power_usage_details.xml | 90 | ||||
-rw-r--r-- | res/values/strings.xml | 46 | ||||
-rw-r--r-- | res/xml/power_usage_summary.xml | 6 | ||||
-rw-r--r-- | src/com/android/settings/fuelgauge/PowerGaugePreference.java | 9 | ||||
-rw-r--r-- | src/com/android/settings/fuelgauge/PowerUsageDetail.java | 156 | ||||
-rw-r--r-- | src/com/android/settings/fuelgauge/PowerUsageSummary.java | 200 |
8 files changed, 520 insertions, 41 deletions
diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 60d9616..204da69 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -505,7 +505,16 @@ </intent-filter> </activity> - <activity android:name=".fuelgauge.PowerUsageSummary" android:label="@string/power_usage_summary_title"> + <activity android:name=".fuelgauge.PowerUsageSummary" + android:label="@string/power_usage_summary_title"> + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="android.intent.category.DEFAULT" /> + </intent-filter> + </activity> + + <activity android:name=".fuelgauge.PowerUsageDetail" + android:label="@string/details_title"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.DEFAULT" /> diff --git a/res/layout/power_usage_detail_item_text.xml b/res/layout/power_usage_detail_item_text.xml new file mode 100644 index 0000000..097469b --- /dev/null +++ b/res/layout/power_usage_detail_item_text.xml @@ -0,0 +1,43 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> + +<RelativeLayout + xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="fill_parent" + android:layout_height="wrap_content"> + <!--Label for the item--> + <TextView + android:id="@+id/label" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:textAppearance="?android:attr/textAppearanceMedium" + android:textStyle="bold" + android:singleLine="true" + android:layout_alignParentLeft="true" + android:layout_marginBottom="2dip" + android:layout_marginTop="2dip" /> + <TextView + android:id="@+id/value" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_alignParentRight="true" + android:textAppearance="?android:attr/textAppearanceMedium" + android:textStyle="normal" + android:singleLine="true" + android:layout_marginBottom="2dip" + android:layout_marginTop="2dip" + android:layout_marginRight="4dip"/> +</RelativeLayout> diff --git a/res/layout/power_usage_details.xml b/res/layout/power_usage_details.xml new file mode 100644 index 0000000..dd8d486 --- /dev/null +++ b/res/layout/power_usage_details.xml @@ -0,0 +1,90 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> + +<ScrollView + xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="fill_parent" + android:layout_height="fill_parent"> + <LinearLayout + android:id="@+id/all_details" + android:layout_width="fill_parent" + android:layout_height="fill_parent" + android:paddingRight="6dip" + android:paddingTop="5dip" + android:paddingBottom="5dip" + android:orientation="vertical"> + + <!-- Details header - icon, label and percentage --> + <RelativeLayout + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:layout_gravity="center_vertical"> + + <LinearLayout + android:orientation="vertical" + android:layout_alignParentLeft="true" + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:paddingTop="6dip" + android:paddingBottom="6dip" + android:paddingRight="6dip" + android:paddingLeft="6dip" > + <!-- application name --> + <TextView android:id="@+id/name" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:textAppearance="?android:attr/textAppearanceMedium" + android:textStyle="bold" + android:singleLine="true" + android:ellipsize="marquee" + android:layout_marginBottom="2dip" /> + <!-- application version --> + <TextView android:id="@+id/battery_percentage" + android:layout_marginTop="-4dip" + android:layout_gravity="center_vertical" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:textAppearance="?android:attr/textAppearanceSmall" /> + </LinearLayout> + + <!-- application icon --> + <ImageView android:id="@+id/icon" + android:layout_width="@android:dimen/app_icon_size" + android:layout_height="@android:dimen/app_icon_size" + android:layout_alignParentRight="true" + android:paddingTop="6dip" + android:paddingBottom="6dip" + android:paddingRight="6dip" + android:scaleType="fitCenter" /> + </RelativeLayout> + + + <TextView + style="?android:attr/listSeparatorTextViewStyle" + android:text="@string/details_subtitle" /> + + <LinearLayout + android:id="@+id/details" + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:paddingLeft="6dip" + android:orientation="vertical"> + + <!-- Insert detail items here --> + + </LinearLayout> + </LinearLayout> +</ScrollView> diff --git a/res/values/strings.xml b/res/values/strings.xml index 94dcaf4..08252f6 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -1503,16 +1503,16 @@ found in the list of installed applications.</string> <string name="battery_history_starts">Starts: <xliff:g id="starts">%1$d</xliff:g></string> <!-- Used to show an amount of time in the form "d days, h hours, m minutes, s seconds" in BatteryHistory --> - <string name="battery_history_days"><xliff:g id="days">%1$d</xliff:g> days, <xliff:g id="hours">%2$d</xliff:g> hours, <xliff:g id="minutes">%3$d</xliff:g> minutes, <xliff:g id="seconds">%4$d</xliff:g> seconds</string> + <string name="battery_history_days"><xliff:g id="days">%1$d</xliff:g> d, <xliff:g id="hours">%2$d</xliff:g> h, <xliff:g id="minutes">%3$d</xliff:g> m, <xliff:g id="seconds">%4$d</xliff:g> s</string> <!-- Used to show an amount of time in the form "h hours, m minutes, s seconds" in BatteryHistory --> - <string name="battery_history_hours"><xliff:g id="hours">%1$d</xliff:g> hours, <xliff:g id="minutes">%2$d</xliff:g> minutes, <xliff:g id="seconds">%3$d</xliff:g> seconds</string> + <string name="battery_history_hours"><xliff:g id="hours">%1$d</xliff:g> h, <xliff:g id="minutes">%2$d</xliff:g> m, <xliff:g id="seconds">%3$d</xliff:g> s</string> <!-- Used to show an amount of time in the form "m minutes, s seconds" in BatteryHistory --> - <string name="battery_history_minutes"><xliff:g id="minutes">%1$d</xliff:g> minutes, <xliff:g id="seconds">%2$d</xliff:g> seconds</string> + <string name="battery_history_minutes"><xliff:g id="minutes">%1$d</xliff:g> m, <xliff:g id="seconds">%2$d</xliff:g> s</string> <!-- Used to show an amount of time in the form "s seconds" in BatteryHistory --> - <string name="battery_history_seconds"><xliff:g id="seconds">%1$d</xliff:g> seconds</string> + <string name="battery_history_seconds"><xliff:g id="seconds">%1$d</xliff:g> s</string> <!-- Used to head a list of packages that share a given user id BatteryHistory --> <string name="battery_history_packages_sharing_this_uid">Packages sharing this UID:</string> @@ -1604,12 +1604,23 @@ found in the list of installed applications.</string> <skip/> <!-- Activity title for App Fuel Gauge summary --> - <string name="power_usage_summary_title">Power usage summary</string> + <string name="power_usage_summary_title">Battery usage</string> + <!-- Battery usage since unplugged --> + <string name="battery_since_unplugged">Battery usage since unplugged</string> + <!-- Battery usage since user reset the stats --> + <string name="battery_since_reset">Battery usage since reset</string> <!-- CPU awake time title --> <string name="awake">Device awake time</string> <!-- Wifi on time --> <string name="wifi_on_time">WiFi on time</string> + <!-- Activity title for battery usage details for an app. or power consumer --> + <string name="details_title">Battery usage details</string> + <!-- Subtitle for application/subsystem details --> + <string name="details_subtitle">Usage details</string> + <!-- Subtitle for possible options --> + <string name="controls_subtitle">Controls</string> + <!-- Label for power consumed by the screen --> <string name="power_screen">Screen on</string> <!-- Label for power consumed by WiFi --> @@ -1620,6 +1631,31 @@ found in the list of installed applications.</string> <string name="power_phone">Voice</string> <!-- Label for power consumed when Idle --> <string name="power_idle">Standby</string> + + <!-- Label for CPU usage time --> + <string name="usage_type_cpu">CPU total</string> + <!-- Label for CPU usage in foreground --> + <string name="usage_type_cpu_foreground">CPU foreground</string> + <!-- Label for GPU usage time --> + <string name="usage_type_gps">GPS</string> + <!-- Label for Phone usage time --> + <string name="usage_type_phone">Phone</string> + <!-- Label for Data sent --> + <string name="usage_type_data_send">Data sent</string> + <!-- Label for Data received --> + <string name="usage_type_data_recv">Data received</string> + <!-- Label for Audio usage time --> + <string name="usage_type_audio">Audio</string> + <!-- Label for Video usage time --> + <string name="usage_type_video">Video</string> + + <!-- Menu label for viewing battery usage since unplugged --> + <string name="menu_stats_unplugged">Usage since unplugged</string> + <!-- Menu label for viewing battery usage total --> + <string name="menu_stats_total">Usage totals</string> + <!-- Menu label for refreshing with latest usage numbers --> + <string name="menu_stats_refresh">Refresh</string> + </resources> diff --git a/res/xml/power_usage_summary.xml b/res/xml/power_usage_summary.xml index 0c35905..80342a8 100644 --- a/res/xml/power_usage_summary.xml +++ b/res/xml/power_usage_summary.xml @@ -15,10 +15,6 @@ --> <PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" - android:title="@string/power_usage_summary_title"> - - <PreferenceCategory - android:key="app_list" - android:title="Application usage"/> + android:title="@string/battery_since_unplugged"> </PreferenceScreen> diff --git a/src/com/android/settings/fuelgauge/PowerGaugePreference.java b/src/com/android/settings/fuelgauge/PowerGaugePreference.java index 5e89535..0bfa12d 100644 --- a/src/com/android/settings/fuelgauge/PowerGaugePreference.java +++ b/src/com/android/settings/fuelgauge/PowerGaugePreference.java @@ -26,6 +26,7 @@ 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 @@ -37,13 +38,15 @@ public class PowerGaugePreference extends Preference { private Drawable mIcon; private GaugeDrawable mGauge; private double mValue; + private BatterySipper mInfo; - public PowerGaugePreference(Context context, Drawable icon) { + 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; } /** @@ -55,6 +58,10 @@ public class PowerGaugePreference extends Preference { mGauge.percent = mValue; } + BatterySipper getInfo() { + return mInfo; + } + @Override protected void onBindView(View view) { super.onBindView(view); 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 index 3abd858..296a9c7 100644 --- a/src/com/android/settings/fuelgauge/PowerUsageSummary.java +++ b/src/com/android/settings/fuelgauge/PowerUsageSummary.java @@ -16,22 +16,31 @@ 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; @@ -52,7 +61,19 @@ public class PowerUsageSummary extends PreferenceActivity { private static final boolean DEBUG = true; private static final String TAG = "PowerUsageSummary"; - private static final String PREF_APP_LIST = "app_list"; + + 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; @@ -72,8 +93,6 @@ public class PowerUsageSummary extends PreferenceActivity { private PowerProfile mPowerProfile; - private static final long BATTERY_SIZE = 1200; - @Override protected void onCreate(Bundle icicle) { super.onCreate(icicle); @@ -81,7 +100,7 @@ public class PowerUsageSummary extends PreferenceActivity { addPreferencesFromResource(R.xml.power_usage_summary); mBatteryInfo = IBatteryStats.Stub.asInterface( ServiceManager.getService("batteryinfo")); - mAppListGroup = (PreferenceGroup) findPreference(PREF_APP_LIST); + mAppListGroup = getPreferenceScreen(); mPowerProfile = new PowerProfile(this, "power_profile_default"); } @@ -92,14 +111,100 @@ public class PowerUsageSummary extends PreferenceActivity { 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(); - processCpuUsage(); + processAppUsage(); processMiscUsage(); mAppListGroup.setOrderingAsAdded(false); @@ -107,11 +212,10 @@ public class PowerUsageSummary extends PreferenceActivity { Collections.sort(mUsageList); for (BatterySipper g : mUsageList) { if (g.getSortValue() < MIN_POWER_THRESHOLD) continue; - double percent = ((g.getSortValue() / mTotalPower) * 100 / BATTERY_SIZE); - PowerGaugePreference pref = new PowerGaugePreference(this, g.getIcon()); - double scaleByMax = (g.getSortValue() * 100) / mTotalPower; - pref.setSummary(g.getLabel() + " ( " + (int) g.getSortValue() + "mA, " - + String.format("%3.2f", scaleByMax) + "% )"); + 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); @@ -119,7 +223,8 @@ public class PowerUsageSummary extends PreferenceActivity { } } - private void processCpuUsage() { + 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; @@ -131,6 +236,9 @@ public class PowerUsageSummary extends PreferenceActivity { 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()) { @@ -138,12 +246,20 @@ public class PowerUsageSummary extends PreferenceActivity { Uid.Proc ps = ent.getValue(); long userTime = ps.getUserTime(which); long systemTime = ps.getSystemTime(which); - //long starts = ps.getStarts(which); - power += (userTime + systemTime) * 10 /* convert to milliseconds */ - * powerCpuNormal; + 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(); @@ -152,17 +268,32 @@ public class PowerUsageSummary extends PreferenceActivity { Uid.Sensor sensor = sensorEntry.getValue(); int sensorType = sensor.getHandle(); BatteryStats.Timer timer = sensor.getSensorTime(); - long sensorTime = timer.getTotalTimeLocked(uSecTime, which); + 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; + power += (multiplier * sensorTime) / 1000; } if (power != 0) { - BatterySipper app = new BatterySipper(null, 0, u.getUid(), new double[] {power}); + 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; @@ -183,7 +314,8 @@ public class PowerUsageSummary extends PreferenceActivity { final double screenFullPower = mPowerProfile.getAveragePower(PowerProfile.POWER_SCREEN_FULL); for (int i = 0; i < BatteryStats.NUM_SCREEN_BRIGHTNESS_BINS; i++) { - double screenBinPower = screenFullPower * i / BatteryStats.NUM_SCREEN_BRIGHTNESS_BINS; + double screenBinPower = screenFullPower * (i + 0.5f) + / BatteryStats.NUM_SCREEN_BRIGHTNESS_BINS; long brightnessTime = mStats.getScreenBrightnessTime(i, uSecNow, mStatsType) / 1000; power += screenBinPower * brightnessTime; if (DEBUG) { @@ -215,30 +347,34 @@ public class PowerUsageSummary extends PreferenceActivity { } double phoneOnPower = getPhoneOnPower(uSecNow); - addEntry(getString(R.string.power_phone), android.R.drawable.ic_menu_call, phoneOnPower); + 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), android.R.drawable.ic_menu_view, screenOnPower); + 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), R.drawable.ic_wifi_signal_4, wifiPower); + 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), android.R.drawable.ic_lock_power_off, idlePower); + 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), + addEntry(getString(R.string.power_cell), DrainType.CELL, android.R.drawable.ic_menu_sort_by_size, radioPower); } - private void addEntry(String label, int iconId, double power) { + private void addEntry(String label, DrainType drainType, int iconId, double power) { if (power > mMaxPower) mMaxPower = power; mTotalPower += power; - BatterySipper bs = new BatterySipper(label, iconId, 0, new double[] {power}); + BatterySipper bs = new BatterySipper(label, drainType, iconId, null, new double[] {power}); mUsageList.add(bs); } @@ -258,21 +394,27 @@ public class PowerUsageSummary extends PreferenceActivity { class BatterySipper implements Comparable<BatterySipper> { String mLabel; Drawable mIcon; - int mUid; + Uid mUid; double mValue; double[] mValues; + DrainType mDrainType; + long mCpuTime; + long mGpsTime; + long mCpuFgTime; - BatterySipper(String label, int iconId, int uid, double[] values) { + 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 > 0) { - getNameForUid(uid); + if ((label == null || iconId == 0) && uid!= null) { + getNameForUid(uid.getUid()); } + mUid = uid; } double getSortValue() { |