Multi-user battery settings.

Aggregates battery use from other users into one line item.

Change-Id: I811e681891a9ff098491de1e096232f38bf061a9
diff --git a/src/com/android/settings/Settings.java b/src/com/android/settings/Settings.java
index 6f2002a..88b3e87 100644
--- a/src/com/android/settings/Settings.java
+++ b/src/com/android/settings/Settings.java
@@ -105,6 +105,7 @@
             R.id.display_settings,
             R.id.storage_settings,
             R.id.application_settings,
+            R.id.battery_settings,
             R.id.personal_section,
             R.id.security_settings,
             R.id.user_settings,
diff --git a/src/com/android/settings/fuelgauge/BatterySipper.java b/src/com/android/settings/fuelgauge/BatterySipper.java
index dbd664a..f11d6ca 100644
--- a/src/com/android/settings/fuelgauge/BatterySipper.java
+++ b/src/com/android/settings/fuelgauge/BatterySipper.java
@@ -107,7 +107,6 @@
             return;
         }
         PackageManager pm = mContext.getPackageManager();
-        final Drawable defaultActivityIcon = pm.getDefaultActivityIcon();
         String[] packages = pm.getPackagesForUid(uid);
         icon = pm.getDefaultActivityIcon();
         if (packages == null) {
diff --git a/src/com/android/settings/fuelgauge/PowerGaugePreference.java b/src/com/android/settings/fuelgauge/PowerGaugePreference.java
index 7b11ae1..c8bfa21 100644
--- a/src/com/android/settings/fuelgauge/PowerGaugePreference.java
+++ b/src/com/android/settings/fuelgauge/PowerGaugePreference.java
@@ -17,6 +17,7 @@
 package com.android.settings.fuelgauge;
 
 import android.content.Context;
+import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
 import android.preference.Preference;
 import android.view.View;
@@ -37,7 +38,7 @@
     public PowerGaugePreference(Context context, Drawable icon, BatterySipper info) {
         super(context);
         setLayoutResource(R.layout.app_percentage_item);
-        setIcon(icon);
+        setIcon(icon != null ? icon : new ColorDrawable(0));
         mInfo = info;
     }
 
diff --git a/src/com/android/settings/fuelgauge/PowerUsageDetail.java b/src/com/android/settings/fuelgauge/PowerUsageDetail.java
index 79cbac6..bb96ca9 100644
--- a/src/com/android/settings/fuelgauge/PowerUsageDetail.java
+++ b/src/com/android/settings/fuelgauge/PowerUsageDetail.java
@@ -62,7 +62,8 @@
         WIFI,
         BLUETOOTH,
         SCREEN,
-        APP
+        APP,
+        USER
     }
 
     // Note: Must match the sequence of the DrainType
@@ -73,7 +74,8 @@
         R.string.battery_desc_wifi,
         R.string.battery_desc_bluetooth,
         R.string.battery_desc_display,
-        R.string.battery_desc_apps
+        R.string.battery_desc_apps,
+        R.string.battery_desc_users,
     };
 
     public static final int ACTION_DISPLAY_SETTINGS = 1;
diff --git a/src/com/android/settings/fuelgauge/PowerUsageSummary.java b/src/com/android/settings/fuelgauge/PowerUsageSummary.java
index ab2c891..173efef 100644
--- a/src/com/android/settings/fuelgauge/PowerUsageSummary.java
+++ b/src/com/android/settings/fuelgauge/PowerUsageSummary.java
@@ -20,6 +20,8 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.content.pm.UserInfo;
+import android.graphics.drawable.Drawable;
 import android.hardware.SensorManager;
 import android.net.Uri;
 import android.os.BatteryStats;
@@ -32,6 +34,8 @@
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.SystemClock;
+import android.os.UserHandle;
+import android.os.UserManager;
 import android.preference.Preference;
 import android.preference.PreferenceActivity;
 import android.preference.PreferenceFragment;
@@ -79,10 +83,14 @@
     private static BatteryStatsImpl sStatsXfer;
 
     IBatteryStats mBatteryInfo;
+    UserManager mUm;
     BatteryStatsImpl mStats;
     private final List<BatterySipper> mUsageList = new ArrayList<BatterySipper>();
     private final List<BatterySipper> mWifiSippers = new ArrayList<BatterySipper>();
     private final List<BatterySipper> mBluetoothSippers = new ArrayList<BatterySipper>();
+    private final SparseArray<List<BatterySipper>> mUserSippers
+            = new SparseArray<List<BatterySipper>>();
+    private final SparseArray<Double> mUserPower = new SparseArray<Double>();
 
     private PreferenceGroup mAppListGroup;
     private Preference mBatteryStatusPref;
@@ -134,6 +142,7 @@
         addPreferencesFromResource(R.xml.power_usage_summary);
         mBatteryInfo = IBatteryStats.Stub.asInterface(
                 ServiceManager.getService("batteryinfo"));
+        mUm = (UserManager)getActivity().getSystemService(Context.USER_SERVICE);
         mAppListGroup = (PreferenceGroup) findPreference(KEY_APP_LIST);
         mBatteryStatusPref = mAppListGroup.findPreference(KEY_BATTERY_STATUS);
         mPowerProfile = new PowerProfile(getActivity());
@@ -204,6 +213,7 @@
         double[] values;
         switch (sipper.drainType) {
             case APP:
+            case USER:
             {
                 Uid uid = sipper.uidObj;
                 types = new int[] {
@@ -229,15 +239,18 @@
                     0
                 };
 
-                Writer result = new StringWriter();
-                PrintWriter printWriter = new PrintWriter(result);
-                mStats.dumpLocked(printWriter, "", mStatsType, uid.getUid());
-                args.putString(PowerUsageDetail.EXTRA_REPORT_DETAILS, result.toString());
-                
-                result = new StringWriter();
-                printWriter = new PrintWriter(result);
-                mStats.dumpCheckinLocked(printWriter, mStatsType, uid.getUid());
-                args.putString(PowerUsageDetail.EXTRA_REPORT_CHECKIN_DETAILS, result.toString());
+                if (sipper.drainType == DrainType.APP) {
+                    Writer result = new StringWriter();
+                    PrintWriter printWriter = new PrintWriter(result);
+                    mStats.dumpLocked(printWriter, "", mStatsType, uid.getUid());
+                    args.putString(PowerUsageDetail.EXTRA_REPORT_DETAILS, result.toString());
+
+                    result = new StringWriter();
+                    printWriter = new PrintWriter(result);
+                    mStats.dumpCheckinLocked(printWriter, mStatsType, uid.getUid());
+                    args.putString(PowerUsageDetail.EXTRA_REPORT_CHECKIN_DETAILS,
+                            result.toString());
+                }
             }
             break;
             case CELL:
@@ -373,6 +386,8 @@
         mUsageList.clear();
         mWifiSippers.clear();
         mBluetoothSippers.clear();
+        mUserSippers.clear();
+        mUserPower.clear();
         mAppListGroup.setOrderingAsAdded(false);
 
         mBatteryStatusPref.setOrder(-2);
@@ -570,6 +585,8 @@
             if (DEBUG) Log.i(TAG, String.format("UID %d total power=%.2f", u.getUid(), power));
 
             // Add the app to the list if it is consuming power
+            boolean isOtherUser = false;
+            final int userId = UserHandle.getUserId(u.getUid());
             if (power != 0 || u.getUid() == 0) {
                 BatterySipper app = new BatterySipper(getActivity(), mRequestQueue, mHandler,
                         packageWithHighestDrain, DrainType.APP, 0, u,
@@ -585,6 +602,15 @@
                     mWifiSippers.add(app);
                 } else if (u.getUid() == Process.BLUETOOTH_GID) {
                     mBluetoothSippers.add(app);
+                } else if (userId != UserHandle.myUserId()
+                        && UserHandle.getAppId(u.getUid()) >= Process.FIRST_APPLICATION_UID) {
+                    isOtherUser = true;
+                    List<BatterySipper> list = mUserSippers.get(userId);
+                    if (list == null) {
+                        list = new ArrayList<BatterySipper>();
+                        mUserSippers.put(userId, list);
+                    }
+                    list.add(app);
                 } else {
                     mUsageList.add(app);
                 }
@@ -592,13 +618,23 @@
                     osApp = app;
                 }
             }
-            if (u.getUid() == Process.WIFI_UID) {
-                mWifiPower += power;
-            } else if (u.getUid() == Process.BLUETOOTH_GID) {
-                mBluetoothPower += power;
-            } else {
-                if (power > mMaxPower) mMaxPower = power;
-                mTotalPower += power;
+            if (power != 0) {
+                if (u.getUid() == Process.WIFI_UID) {
+                    mWifiPower += power;
+                } else if (u.getUid() == Process.BLUETOOTH_GID) {
+                    mBluetoothPower += power;
+                } else if (isOtherUser) {
+                    Double userPower = mUserPower.get(userId);
+                    if (userPower == null) {
+                        userPower = power;
+                    } else {
+                        userPower += power;
+                    }
+                    mUserPower.put(userId, userPower);
+                } else {
+                    if (power > mMaxPower) mMaxPower = power;
+                    mTotalPower += power;
+                }
             }
         }
 
@@ -725,6 +761,32 @@
         aggregateSippers(bs, mBluetoothSippers, "Bluetooth");
     }
 
+    private void addUserUsage() {
+        for (int i=0; i<mUserSippers.size(); i++) {
+            final int userId = mUserSippers.keyAt(i);
+            final List<BatterySipper> sippers = mUserSippers.valueAt(i);
+            UserInfo info = mUm.getUserInfo(userId);
+            Drawable icon = null;
+            if (info != null && info.iconPath != null) {
+                try {
+                    icon = Drawable.createFromPath(info.iconPath);
+                } catch (Exception e) {
+                    Log.w(TAG, "Failure loading user picture " + info.iconPath, e);
+                }
+            }
+            String name = info != null ? info.name : null;
+            if (name == null) {
+                name = Integer.toString(info.id);
+            }
+            double power = mUserPower.get(userId);
+            String label = getActivity().getResources().getString(
+                    R.string.running_process_item_user_label, name);
+            BatterySipper bs = addEntry(label, DrainType.USER, 0, 0, power);
+            bs.icon = icon;
+            aggregateSippers(bs, sippers, "User");
+        }
+    }
+
     private double getAverageDataCost() {
         final long WIFI_BPS = 1000000; // TODO: Extract average bit rates from system 
         final long MOBILE_BPS = 200000; // TODO: Extract average bit rates from system
@@ -760,6 +822,7 @@
             Log.i(TAG, "Uptime since last unplugged = " + (timeSinceUnplugged / 1000));
         }
 
+        addUserUsage();
         addPhoneUsage(uSecNow);
         addScreenUsage(uSecNow);
         addWiFiUsage(uSecNow);