| /* |
| * Copyright (C) 2006 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.battery_history; |
| |
| import java.util.ArrayList; |
| import java.util.Collections; |
| import java.util.HashSet; |
| import java.util.List; |
| import java.util.Map; |
| |
| import com.android.internal.app.IBatteryStats; |
| import com.android.settings.R; |
| |
| import android.app.Activity; |
| import android.content.pm.ApplicationInfo; |
| import android.content.pm.PackageInfo; |
| import android.content.pm.PackageManager; |
| import android.content.pm.PackageManager.NameNotFoundException; |
| 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.util.Log; |
| import android.util.LogPrinter; |
| import android.util.SparseArray; |
| import android.view.KeyEvent; |
| import android.view.View; |
| import android.view.View.OnClickListener; |
| import android.widget.AdapterView; |
| import android.widget.Button; |
| import android.widget.LinearLayout; |
| import android.widget.Spinner; |
| import android.widget.TextView; |
| import android.widget.AdapterView.OnItemSelectedListener; |
| |
| public class BatteryHistory extends Activity implements OnClickListener, OnItemSelectedListener { |
| private static final String TAG = "BatteryHistory"; |
| |
| 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; |
| |
| // Must be in sync with the values in res/values/array.xml (id battery_history_type_spinner) |
| private static final int CPU_USAGE = 0; |
| private static final int NETWORK_USAGE = 1; |
| private static final int GPS_USAGE = 2; |
| private static final int SENSOR_USAGE = 3; |
| private static final int WAKELOCK_USAGE = 4; |
| private static final int MISC_USAGE = 5; |
| |
| // Must be in sync with the values in res/values/array.xml (id battery_history_which_spinner) |
| private static final int UNPLUGGED = 0; |
| private static final int CURRENT = 1; |
| private static final int TOTAL = 2; |
| |
| private BatteryStats mStats; |
| private int mWhich = BatteryStats.STATS_UNPLUGGED; |
| private int mType = CPU_USAGE; |
| |
| private GraphableButton[] mButtons; |
| IBatteryStats mBatteryInfo; |
| |
| private List<CpuUsage> mCpuUsage = new ArrayList<CpuUsage>(); |
| private List<NetworkUsage> mNetworkUsage = new ArrayList<NetworkUsage>(); |
| private List<SensorUsage> mSensorUsage = new ArrayList<SensorUsage>(); |
| private List<SensorUsage> mGpsUsage = new ArrayList<SensorUsage>(); |
| private List<WakelockUsage> mWakelockUsage = new ArrayList<WakelockUsage>(); |
| private List<MiscUsage> mMiscUsage = new ArrayList<MiscUsage>(); |
| |
| private boolean mHaveCpuUsage, mHaveNetworkUsage, mHaveSensorUsage, |
| mHaveWakelockUsage, mHaveMiscUsage; |
| |
| private LinearLayout mGraphLayout; |
| private LinearLayout mTextLayout; |
| private TextView mMessageText; |
| private TextView mDetailsText; |
| private Button mDetailsBackButton; |
| private Spinner mTypeSpinner; |
| private Spinner mWhichSpinner; |
| |
| private boolean mDetailsShown = false; |
| |
| private static String getLabel(String packageName, PackageManager pm) { |
| try { |
| ApplicationInfo ai = pm.getApplicationInfo(packageName, 0); |
| CharSequence label = ai.loadLabel(pm); |
| if (label != null) { |
| return label.toString(); |
| } |
| } catch (NameNotFoundException e) { |
| return packageName; |
| } |
| |
| return ""; |
| } |
| |
| void formatTime(double millis, StringBuilder sb) { |
| 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)); |
| } |
| } |
| |
| abstract class Graphable implements Comparable<Graphable> { |
| protected String mName; |
| protected String mNamePackage; |
| protected boolean mUniqueName; |
| protected String[] mPackages; |
| protected String[] mPackageNames; |
| |
| public abstract String getLabel(); |
| public abstract double getSortValue(); |
| public abstract double[] getValues(); |
| public abstract void getInfo(StringBuilder info); |
| |
| public double getMaxValue() { |
| return -Double.MAX_VALUE; |
| } |
| |
| public int compareTo(Graphable o) { |
| double t = getSortValue(); |
| double ot = o.getSortValue(); |
| if (t < ot) { |
| // Largest first |
| return 1; |
| } else if (t > ot) { |
| return -1; |
| } else { |
| return 0; |
| } |
| } |
| |
| // Side effects: sets mName and mUniqueName |
| void getNameForUid(int uid) { |
| PackageManager pm = getPackageManager(); |
| mPackages = pm.getPackagesForUid(uid); |
| if (mPackages == null) { |
| mName = Integer.toString(uid); |
| mNamePackage = null; |
| return; |
| } |
| |
| mPackageNames = new String[mPackages.length]; |
| System.arraycopy(mPackages, 0, mPackageNames, 0, mPackages.length); |
| |
| // Convert package names to user-facing labels where possible |
| for (int i = 0; i < mPackageNames.length; i++) { |
| mPackageNames[i] = BatteryHistory.getLabel(mPackageNames[i], pm); |
| } |
| |
| if (mPackageNames.length == 1) { |
| mNamePackage = mPackages[0]; |
| mName = mPackageNames[0]; |
| mUniqueName = true; |
| } else { |
| mName = getString(R.string.battery_history_uid, uid); // Default name |
| // Look for an official name for this UID. |
| for (String name : mPackages) { |
| try { |
| PackageInfo pi = pm.getPackageInfo(name, 0); |
| if (pi.sharedUserLabel != 0) { |
| CharSequence nm = pm.getText(name, |
| pi.sharedUserLabel, pi.applicationInfo); |
| if (nm != null) { |
| mName = nm.toString(); |
| break; |
| } |
| } |
| } catch (PackageManager.NameNotFoundException e) { |
| } |
| } |
| } |
| } |
| } |
| |
| class CpuUsage extends Graphable { |
| String mProcess; |
| double[] mUsage; |
| double mTotalRuntime; |
| long mStarts; |
| |
| public CpuUsage(int uid, String process, long userTime, long systemTime, |
| long starts, long totalRuntime) { |
| getNameForUid(uid); |
| mProcess = process; |
| PackageManager pm = BatteryHistory.this.getPackageManager(); |
| mName = BatteryHistory.getLabel(process, pm); |
| mUsage = new double[2]; |
| |
| mUsage[0] = userTime; |
| mUsage[1] = userTime + systemTime; |
| mTotalRuntime = totalRuntime; |
| mStarts = starts; |
| } |
| |
| public String getLabel() { |
| return mName; |
| } |
| |
| public double getSortValue() { |
| return mUsage[1]; |
| } |
| |
| public double[] getValues() { |
| return mUsage; |
| } |
| |
| public double getMaxValue() { |
| return mTotalRuntime; |
| } |
| |
| public void getInfo(StringBuilder info) { |
| info.append(getString(R.string.battery_history_cpu_usage, mProcess)); |
| info.append("\n\n"); |
| info.append(getString(R.string.battery_history_user_time)); |
| formatTime(mUsage[0] * 10, info); |
| info.append('\n'); |
| info.append(getString(R.string.battery_history_system_time)); |
| formatTime((mUsage[1] - mUsage[0]) * 10, info); |
| info.append('\n'); |
| info.append(getString(R.string.battery_history_total_time)); |
| formatTime((mUsage[1]) * 10, info); |
| info.append('\n'); |
| info.append(getString(R.string.battery_history_starts, mStarts)); |
| } |
| } |
| |
| class NetworkUsage extends Graphable { |
| double[] mUsage; |
| |
| public NetworkUsage(int uid, long received, long sent) { |
| getNameForUid(uid); |
| |
| mUsage = new double[2]; |
| mUsage[0] = received; |
| mUsage[1] = received + sent; |
| } |
| |
| public String getLabel() { |
| return mName; |
| } |
| |
| public double getSortValue() { |
| return mUsage[1]; |
| } |
| |
| public double[] getValues() { |
| return mUsage; |
| } |
| |
| public void getInfo(StringBuilder info) { |
| info.append(getString(R.string.battery_history_network_usage, mName)); |
| info.append("\n\n"); |
| info.append(getString(R.string.battery_history_bytes_received, (long) mUsage[0])); |
| info.append('\n'); |
| info.append(getString(R.string.battery_history_bytes_sent, |
| (long) mUsage[1] - (long) mUsage[0])); |
| info.append('\n'); |
| info.append(getString(R.string.battery_history_bytes_total, (long) mUsage[1])); |
| |
| if (!mUniqueName) { |
| info.append("\n\n"); |
| info.append(getString(R.string.battery_history_packages_sharing_this_uid)); |
| info.append('\n'); |
| |
| PackageManager pm = BatteryHistory.this.getPackageManager(); |
| List<String> names = new ArrayList<String>(); |
| for (String name : mPackageNames) { |
| names.add(BatteryHistory.getLabel(name, pm)); |
| } |
| Collections.sort(names); |
| for (String name : names) { |
| info.append(" "); |
| info.append(name); |
| info.append('\n'); |
| } |
| } |
| } |
| } |
| |
| class SensorUsage extends Graphable { |
| double[] mUsage; |
| double mTotalRealtime; |
| int mCount; |
| |
| public SensorUsage(int uid, long time, int count, long totalRealtime) { |
| getNameForUid(uid); |
| |
| mUsage = new double[1]; |
| mUsage[0] = time; |
| mTotalRealtime = totalRealtime; |
| |
| mCount = count; |
| } |
| |
| public String getLabel() { |
| return mName; |
| } |
| |
| public double getSortValue() { |
| return mUsage[0]; |
| } |
| |
| public double[] getValues() { |
| return mUsage; |
| } |
| |
| public double getMaxValue() { |
| return mTotalRealtime; |
| } |
| |
| public void getInfo(StringBuilder info) { |
| info.append(getString(R.string.battery_history_sensor)); |
| info.append(mName); |
| info.append("\n\n"); |
| info.append(getString(R.string.battery_history_total_time)); |
| formatTime(mUsage[0], info); |
| info.append("\n\n"); |
| } |
| } |
| |
| |
| class WakelockUsage extends Graphable { |
| double[] mUsage; |
| double mTotalRealtime; |
| int mCount; |
| |
| public WakelockUsage(int uid, long time, int count, long totalRealtime) { |
| getNameForUid(uid); |
| |
| mUsage = new double[1]; |
| mUsage[0] = time; |
| mTotalRealtime = totalRealtime; |
| |
| mCount = count; |
| } |
| |
| public String getLabel() { |
| return mName; |
| } |
| |
| public double getSortValue() { |
| return mUsage[0]; |
| } |
| |
| public double[] getValues() { |
| return mUsage; |
| } |
| |
| public double getMaxValue() { |
| return mTotalRealtime; |
| } |
| |
| public void getInfo(StringBuilder info) { |
| info.append(getString(R.string.battery_history_wakelock)); |
| info.append(mName); |
| info.append("\n\n"); |
| info.append(getString(R.string.battery_history_total_time)); |
| formatTime(mUsage[0], info); |
| info.append("\n\n"); |
| } |
| } |
| |
| class MiscUsage extends Graphable { |
| int mInfoLabelRes; |
| double[] mUsage; |
| double mTotalRealtime; |
| |
| public MiscUsage(String name, int infoLabelRes, long value, |
| long totalRealtime) { |
| mName = name; |
| |
| mInfoLabelRes = infoLabelRes; |
| |
| mUsage = new double[2]; |
| mUsage[0] = value; |
| mTotalRealtime = totalRealtime; |
| } |
| |
| public String getLabel() { |
| return mName; |
| } |
| |
| public double getSortValue() { |
| return mUsage[1]; |
| } |
| |
| public double[] getValues() { |
| return mUsage; |
| } |
| |
| public double getMaxValue() { |
| return mTotalRealtime; |
| } |
| |
| public void getInfo(StringBuilder info) { |
| info.append(getString(mInfoLabelRes)); |
| info.append(' '); |
| formatTime(mUsage[0], info); |
| info.append(" ("); |
| info.append((mUsage[0]*100)/mTotalRealtime); |
| info.append("%)"); |
| } |
| } |
| |
| private List<? extends Graphable> getGraphRecords() { |
| switch (mType) { |
| case CPU_USAGE: return mCpuUsage; |
| case NETWORK_USAGE : return mNetworkUsage; |
| case SENSOR_USAGE: return mSensorUsage; |
| case GPS_USAGE: return mGpsUsage; |
| case WAKELOCK_USAGE: return mWakelockUsage; |
| case MISC_USAGE: return mMiscUsage; |
| default: |
| return (List<? extends Graphable>) null; // TODO |
| } |
| } |
| |
| private void displayGraph() { |
| Log.i(TAG, "displayGraph"); |
| |
| collectStatistics(); |
| |
| // Hide the UI and selectively enable it below |
| mMessageText.setVisibility(View.GONE); |
| for (int i = 0; i < mButtons.length; i++) { |
| mButtons[i].setVisibility(View.INVISIBLE); |
| } |
| |
| double maxValue = -Double.MAX_VALUE; |
| |
| List<? extends Graphable> records = getGraphRecords(); |
| for (Graphable g : records) { |
| double[] values = g.getValues(); |
| maxValue = Math.max(maxValue, values[values.length - 1]); |
| maxValue = Math.max(maxValue, g.getMaxValue()); |
| } |
| |
| int[] colors = new int[2]; |
| colors[0] = 0xff0000ff; |
| colors[1] = 0xffff0000; |
| |
| for (int i = 0; i < mButtons.length; i++) { |
| mButtons[i].setVisibility(View.INVISIBLE); |
| } |
| |
| int numRecords = Math.min(records.size(), mButtons.length); |
| if (numRecords == 0) { |
| mMessageText.setVisibility(View.VISIBLE); |
| mMessageText.setText(R.string.battery_history_no_data); |
| } else { |
| for (int i = 0; i < numRecords; i++) { |
| Graphable r = records.get(i); |
| |
| mButtons[i].setText(r.getLabel()); |
| mButtons[i].setValues(r.getValues(), maxValue); |
| mButtons[i].setVisibility(View.VISIBLE); |
| } |
| } |
| } |
| |
| private void hideDetails() { |
| mTextLayout.setVisibility(View.GONE); |
| mGraphLayout.setVisibility(View.VISIBLE); |
| mDetailsShown = false; |
| } |
| |
| private void showDetails(int id) { |
| mGraphLayout.setVisibility(View.GONE); |
| mTextLayout.setVisibility(View.VISIBLE); |
| |
| StringBuilder info = new StringBuilder(); |
| List<? extends Graphable> records = getGraphRecords(); |
| if (id < records.size()) { |
| Graphable record = records.get(id); |
| record.getInfo(info); |
| } else { |
| info.append(getString(R.string.battery_history_details_for, id)); |
| } |
| mDetailsText.setText(info.toString()); |
| mDetailsShown = true; |
| } |
| |
| private void processCpuUsage() { |
| mCpuUsage.clear(); |
| |
| long uSecTime = SystemClock.uptimeMillis() * 1000; |
| final long uSecNow = mStats.computeBatteryUptime(uSecTime, mWhich) / 1000; |
| |
| SparseArray<? extends Uid> uidStats = mStats.getUidStats(); |
| final int NU = uidStats.size(); |
| for (int iu = 0; iu < NU; iu++) { |
| Uid u = uidStats.valueAt(iu); |
| |
| Map<String, ? extends BatteryStats.Uid.Proc> processStats = u.getProcessStats(); |
| if (processStats.size() > 0) { |
| for (Map.Entry<String, ? extends BatteryStats.Uid.Proc> ent |
| : processStats.entrySet()) { |
| |
| Uid.Proc ps = ent.getValue(); |
| long userTime = ps.getUserTime(mWhich); |
| long systemTime = ps.getSystemTime(mWhich); |
| long starts = ps.getStarts(mWhich); |
| |
| if (userTime != 0 || systemTime != 0) { |
| mCpuUsage.add(new CpuUsage(u.getUid(), ent.getKey(), |
| userTime, systemTime, starts, uSecNow)); |
| } |
| } |
| } |
| } |
| Collections.sort(mCpuUsage); |
| } |
| |
| private void processNetworkUsage() { |
| mNetworkUsage.clear(); |
| |
| SparseArray<? extends Uid> uidStats = mStats.getUidStats(); |
| final int NU = uidStats.size(); |
| for (int iu = 0; iu < NU; iu++) { |
| Uid u = uidStats.valueAt(iu); |
| |
| long received = u.getTcpBytesReceived(mWhich); |
| long sent = u.getTcpBytesSent(mWhich); |
| if (received + sent > 0) { |
| mNetworkUsage.add(new NetworkUsage(u.getUid(), received, sent)); |
| } |
| } |
| Collections.sort(mNetworkUsage); |
| } |
| |
| private void processSensorUsage() { |
| mGpsUsage.clear(); |
| mSensorUsage.clear(); |
| |
| long uSecTime = SystemClock.elapsedRealtime() * 1000; |
| final long uSecNow = mStats.computeBatteryRealtime(uSecTime, mWhich) / 1000; |
| |
| SparseArray<? extends Uid> uidStats = mStats.getUidStats(); |
| final int NU = uidStats.size(); |
| for (int iu = 0; iu < NU; iu++) { |
| Uid u = uidStats.valueAt(iu); |
| int uid = u.getUid(); |
| |
| Map<Integer, ? extends BatteryStats.Uid.Sensor> sensorStats = u.getSensorStats(); |
| long timeGps = 0; |
| int countGps = 0; |
| long timeOther = 0; |
| int countOther = 0; |
| if (sensorStats.size() > 0) { |
| for (Map.Entry<Integer, ? extends BatteryStats.Uid.Sensor> ent |
| : sensorStats.entrySet()) { |
| |
| Uid.Sensor se = ent.getValue(); |
| int handle = se.getHandle(); |
| Timer timer = se.getSensorTime(); |
| if (timer != null) { |
| // Convert from microseconds to milliseconds with rounding |
| long totalTime = (timer.getTotalTime(uSecNow, mWhich) + 500) / 1000; |
| int count = timer.getCount(mWhich); |
| if (handle == BatteryStats.Uid.Sensor.GPS) { |
| timeGps += totalTime; |
| countGps += count; |
| } else { |
| timeOther += totalTime; |
| countOther += count; |
| } |
| } |
| } |
| } |
| |
| if (timeGps > 0) { |
| mGpsUsage.add(new SensorUsage(uid, timeGps, countGps, uSecNow)); |
| } |
| if (timeOther > 0) { |
| mSensorUsage.add(new SensorUsage(uid, timeOther, countOther, uSecNow)); |
| } |
| } |
| |
| Collections.sort(mGpsUsage); |
| Collections.sort(mSensorUsage); |
| } |
| |
| private void processWakelockUsage() { |
| mWakelockUsage.clear(); |
| |
| long uSecTime = SystemClock.elapsedRealtime() * 1000; |
| final long uSecNow = mStats.computeBatteryRealtime(uSecTime, mWhich) / 1000; |
| |
| SparseArray<? extends Uid> uidStats = mStats.getUidStats(); |
| final int NU = uidStats.size(); |
| for (int iu = 0; iu < NU; iu++) { |
| Uid u = uidStats.valueAt(iu); |
| int uid = u.getUid(); |
| |
| Map<String, ? extends BatteryStats.Uid.Wakelock> wakelockStats = u.getWakelockStats(); |
| long time = 0; |
| int count = 0; |
| if (wakelockStats.size() > 0) { |
| for (Map.Entry<String, ? extends BatteryStats.Uid.Wakelock> ent |
| : wakelockStats.entrySet()) { |
| |
| Uid.Wakelock wl = ent.getValue(); |
| Timer timer = wl.getWakeTime(BatteryStats.WAKE_TYPE_PARTIAL); |
| if (timer != null) { |
| // Convert from microseconds to milliseconds with rounding |
| time += (timer.getTotalTime(uSecNow, mWhich) + 500) / 1000; |
| count += timer.getCount(mWhich); |
| } |
| } |
| } |
| |
| if (time > 0) { |
| mWakelockUsage.add(new WakelockUsage(uid, time, count, uSecNow)); |
| } |
| } |
| |
| Collections.sort(mWakelockUsage); |
| } |
| |
| private void processMiscUsage() { |
| mMiscUsage.clear(); |
| |
| long rawRealtime = SystemClock.elapsedRealtime() * 1000; |
| final long batteryRealtime = mStats.getBatteryRealtime(rawRealtime); |
| final long whichRealtime = mStats.computeBatteryRealtime(rawRealtime, mWhich) / 1000; |
| |
| long time = mStats.computeBatteryUptime(SystemClock.uptimeMillis() * 1000, mWhich) / 1000; |
| if (time > 0) { |
| mMiscUsage.add(new MiscUsage(getString( |
| R.string.battery_history_awake_label), |
| R.string.battery_history_awake, |
| time, whichRealtime)); |
| } |
| |
| time = mStats.getScreenOnTime(batteryRealtime, mWhich) / 1000; |
| if (time > 0) { |
| mMiscUsage.add(new MiscUsage(getString( |
| R.string.battery_history_screen_on_label), |
| R.string.battery_history_screen_on, |
| time, whichRealtime)); |
| } |
| |
| time = mStats.getPhoneOnTime(batteryRealtime, mWhich) / 1000; |
| if (time > 0) { |
| mMiscUsage.add(new MiscUsage(getString( |
| R.string.battery_history_phone_on_label), |
| R.string.battery_history_phone_on, |
| time, whichRealtime)); |
| } |
| |
| Collections.sort(mMiscUsage); |
| } |
| |
| private void collectStatistics() { |
| if (mType == CPU_USAGE) { |
| if (!mHaveCpuUsage) { |
| mHaveCpuUsage = true; |
| processCpuUsage(); |
| } |
| } |
| if (mType == NETWORK_USAGE) { |
| if (!mHaveNetworkUsage) { |
| mHaveNetworkUsage = true; |
| processNetworkUsage(); |
| } |
| } |
| if (mType == GPS_USAGE || mType == SENSOR_USAGE) { |
| if (!mHaveSensorUsage) { |
| mHaveSensorUsage = true; |
| processSensorUsage(); |
| } |
| } |
| if (mType == WAKELOCK_USAGE) { |
| if (!mHaveWakelockUsage) { |
| mHaveWakelockUsage = true; |
| processWakelockUsage(); |
| } |
| } |
| if (mType == MISC_USAGE) { |
| if (!mHaveMiscUsage) { |
| mHaveMiscUsage = true; |
| processMiscUsage(); |
| } |
| } |
| } |
| |
| private void load() { |
| try { |
| byte[] data = mBatteryInfo.getStatistics(); |
| Parcel parcel = Parcel.obtain(); |
| //Log.i(TAG, "Got data: " + data.length + " bytes"); |
| parcel.unmarshall(data, 0, data.length); |
| parcel.setDataPosition(0); |
| mStats = com.android.internal.os.BatteryStatsImpl.CREATOR |
| .createFromParcel(parcel); |
| //Log.i(TAG, "RECEIVED BATTERY INFO:"); |
| //mStats.dumpLocked(new LogPrinter(Log.INFO, TAG)); |
| |
| mHaveCpuUsage = mHaveNetworkUsage = mHaveSensorUsage |
| = mHaveWakelockUsage = mHaveMiscUsage = false; |
| } catch (RemoteException e) { |
| Log.e(TAG, "RemoteException:", e); |
| } |
| } |
| |
| public void onClick(View v) { |
| if (v == mDetailsBackButton) { |
| hideDetails(); |
| return; |
| } |
| |
| int id = ((Integer) v.getTag()).intValue(); |
| showDetails(id); |
| } |
| |
| public boolean onKeyDown(int keyCode, KeyEvent event) { |
| if (keyCode == KeyEvent.KEYCODE_BACK && mDetailsShown) { |
| hideDetails(); |
| return true; |
| } |
| return super.onKeyDown(keyCode, event); |
| } |
| |
| public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { |
| int oldWhich = mWhich; |
| |
| if (parent.equals(mTypeSpinner)) { |
| mType = position; |
| } else if (parent.equals(mWhichSpinner)) { |
| switch (position) { |
| case UNPLUGGED: |
| mWhich = BatteryStats.STATS_UNPLUGGED; |
| break; |
| case CURRENT: |
| mWhich = BatteryStats.STATS_CURRENT; |
| break; |
| case TOTAL: |
| mWhich = BatteryStats.STATS_TOTAL; |
| break; |
| } |
| } |
| |
| if (oldWhich != mWhich) { |
| mHaveCpuUsage = mHaveNetworkUsage = mHaveSensorUsage |
| = mHaveWakelockUsage = mHaveMiscUsage = false; |
| } |
| |
| displayGraph(); |
| } |
| |
| public void onNothingSelected(AdapterView<?> parent) { |
| // Do nothing |
| } |
| |
| @Override |
| public Object onRetainNonConfigurationInstance() { |
| BatteryStats stats = mStats; |
| mStats = null; |
| return stats; |
| } |
| |
| @Override |
| protected void onSaveInstanceState(Bundle outState) { |
| super.onSaveInstanceState(outState); |
| if (mStats != null) { |
| outState.putParcelable("stats", mStats); |
| } |
| outState.putInt("type", mType); |
| outState.putInt("which", mWhich); |
| } |
| |
| @Override |
| public void onCreate(Bundle icicle) { |
| super.onCreate(icicle); |
| Log.i(TAG, "onCreate"); |
| |
| setContentView(R.layout.battery_history); |
| |
| mGraphLayout = (LinearLayout) findViewById(R.id.graphLayout); |
| mTextLayout = (LinearLayout) findViewById(R.id.textLayout); |
| mDetailsText = (TextView) findViewById(R.id.detailsText); |
| mMessageText = (TextView) findViewById(R.id.messageText); |
| |
| mTypeSpinner = (Spinner) findViewById(R.id.typeSpinner); |
| mTypeSpinner.setOnItemSelectedListener(this); |
| |
| mWhichSpinner = (Spinner) findViewById(R.id.whichSpinner); |
| mWhichSpinner.setOnItemSelectedListener(this); |
| mWhichSpinner.setEnabled(true); |
| |
| mButtons = new GraphableButton[8]; |
| mButtons[0] = (GraphableButton) findViewById(R.id.button0); |
| mButtons[1] = (GraphableButton) findViewById(R.id.button1); |
| mButtons[2] = (GraphableButton) findViewById(R.id.button2); |
| mButtons[3] = (GraphableButton) findViewById(R.id.button3); |
| mButtons[4] = (GraphableButton) findViewById(R.id.button4); |
| mButtons[5] = (GraphableButton) findViewById(R.id.button5); |
| mButtons[6] = (GraphableButton) findViewById(R.id.button6); |
| mButtons[7] = (GraphableButton) findViewById(R.id.button7); |
| |
| for (int i = 0; i < mButtons.length; i++) { |
| mButtons[i].setTag(i); |
| mButtons[i].setOnClickListener(this); |
| } |
| |
| mBatteryInfo = IBatteryStats.Stub.asInterface( |
| ServiceManager.getService("batteryinfo")); |
| |
| mStats = (BatteryStats)getLastNonConfigurationInstance(); |
| if (icicle != null) { |
| if (mStats == null) { |
| mStats = (BatteryStats)icicle.getParcelable("stats"); |
| } |
| mType = icicle.getInt("type"); |
| mWhich = icicle.getInt("which"); |
| } |
| if (mStats == null) { |
| load(); |
| } |
| displayGraph(); |
| } |
| } |