AI 143800: am: CL 143748 Fix issue #1743326 (More battery stats)
  Adds stats for:
  - Number of raw user events that have happened in the system.
  - Number of times user activity has been reported, dividied by UID and type of activity.
  - Duration of screen brightness levels in 4 buckets.
  - Per-UID tracking of who has turned on Wifi and how long we can attribute it being on because of them.
  Original author: hackbod
  Merged from: //branches/cupcake/...

Automated import of CL 143800
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index c747c43..17594d4 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -41,18 +41,25 @@
     public static final int SENSOR = 3;
     
     /**
+     * A constant indicating a a wifi turn on timer
+     *
+     * {@hide}
+     */
+    public static final int WIFI_TURNED_ON = 4;
+    
+    /**
      * A constant indicating a full wifi lock timer
      *
      * {@hide}
      */
-    public static final int FULL_WIFI_LOCK = 4;
+    public static final int FULL_WIFI_LOCK = 5;
     
     /**
      * A constant indicating a scan wifi lock timer
      *
      * {@hide}
      */
-    public static final int SCAN_WIFI_LOCK = 5;
+    public static final int SCAN_WIFI_LOCK = 6;
 
     /**
      * Include all of the data in the stats, including previously saved data.
@@ -77,7 +84,7 @@
     /**
      * Bump the version on this if the checkin format changes.
      */
-    private static final int BATTERY_STATS_CHECKIN_VERSION = 2;
+    private static final int BATTERY_STATS_CHECKIN_VERSION = 3;
     
     private static final long BYTES_PER_KB = 1024;
     private static final long BYTES_PER_MB = 1048576; // 1024^2
@@ -91,16 +98,39 @@
     private static final String SENSOR_DATA = "sensor";
     private static final String WAKELOCK_DATA = "wakelock";
     private static final String NETWORK_DATA = "network";
+    private static final String USER_ACTIVITY_DATA = "useract";
     private static final String BATTERY_DATA = "battery";
     private static final String WIFI_LOCK_DATA = "wifilock";
     private static final String MISC_DATA = "misc";
-    private static final String SIGNAL_STRENGTH_DATA = "signal";
-    private static final String DATA_CONNECTION_DATA = "dataconn";
+    private static final String SCREEN_BRIGHTNESS_DATA = "brightness";
+    private static final String SIGNAL_STRENGTH_TIME_DATA = "sigtime";
+    private static final String SIGNAL_STRENGTH_COUNT_DATA = "sigcnt";
+    private static final String DATA_CONNECTION_TIME_DATA = "dconntime";
+    private static final String DATA_CONNECTION_COUNT_DATA = "dconncnt";
 
     private final StringBuilder mFormatBuilder = new StringBuilder(8);
     private final Formatter mFormatter = new Formatter(mFormatBuilder);
 
     /**
+     * State for keeping track of counting information.
+     */
+    public static abstract class Counter {
+
+        /**
+         * Returns the count associated with this Counter for the
+         * selected type of statistics.
+         *
+         * @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT
+         */
+        public abstract int getCount(int which);
+
+        /**
+         * Temporary for debugging.
+         */
+        public abstract void logState(Printer pw, String prefix);
+    }
+
+    /**
      * State for keeping track of timing information.
      */
     public static abstract class Timer {
@@ -184,13 +214,29 @@
          */
         public abstract long getTcpBytesSent(int which);
         
+        public abstract void noteWifiTurnedOnLocked();
+        public abstract void noteWifiTurnedOffLocked();
         public abstract void noteFullWifiLockAcquiredLocked();
         public abstract void noteFullWifiLockReleasedLocked();
         public abstract void noteScanWifiLockAcquiredLocked();
         public abstract void noteScanWifiLockReleasedLocked();
+        public abstract long getWifiTurnedOnTime(long batteryRealtime, int which);
         public abstract long getFullWifiLockTime(long batteryRealtime, int which);
         public abstract long getScanWifiLockTime(long batteryRealtime, int which);
 
+        /**
+         * Note that these must match the constants in android.os.LocalPowerManager.
+         */
+        static final String[] USER_ACTIVITY_TYPES = {
+            "other", "cheek", "touch", "long_touch", "touch_up", "button", "unknown"
+        };
+        
+        public static final int NUM_USER_ACTIVITY_TYPES = 7;
+        
+        public abstract void noteUserActivityLocked(int type);
+        public abstract boolean hasUserActivity();
+        public abstract int getUserActivityCount(int type, int which);
+        
         public static abstract class Sensor {
             // Magic sensor number for the GPS.
             public static final int GPS = -10000;
@@ -289,6 +335,29 @@
      */
     public abstract long getScreenOnTime(long batteryRealtime, int which);
     
+    public static final int SCREEN_BRIGHTNESS_DARK = 0;
+    public static final int SCREEN_BRIGHTNESS_DIM = 1;
+    public static final int SCREEN_BRIGHTNESS_MEDIUM = 2;
+    public static final int SCREEN_BRIGHTNESS_LIGHT = 3;
+    public static final int SCREEN_BRIGHTNESS_BRIGHT = 4;
+    
+    static final String[] SCREEN_BRIGHTNESS_NAMES = {
+        "dark", "dim", "medium", "light", "bright"
+    };
+    
+    public static final int NUM_SCREEN_BRIGHTNESS_BINS = 5;
+    
+    /**
+     * Returns the time in milliseconds that the screen has been on with
+     * the given brightness
+     * 
+     * {@hide}
+     */
+    public abstract long getScreenBrightnessTime(int brightnessBin,
+            long batteryRealtime, int which);
+
+    public abstract int getInputEventCount(int which);
+    
     /**
      * Returns the time in milliseconds that the phone has been on while the device was
      * running on battery.
@@ -318,6 +387,13 @@
     public abstract long getPhoneSignalStrengthTime(int strengthBin,
             long batteryRealtime, int which);
 
+    /**
+     * Returns the number of times the phone has entered the given signal strength.
+     * 
+     * {@hide}
+     */
+    public abstract int getPhoneSignalStrengthCount(int strengthBin, int which);
+
     public static final int DATA_CONNECTION_NONE = 0;
     public static final int DATA_CONNECTION_GPRS = 1;
     public static final int DATA_CONNECTION_EDGE = 2;
@@ -340,6 +416,14 @@
             long batteryRealtime, int which);
 
     /**
+     * Returns the number of times the phone has entered the given data
+     * connection type.
+     * 
+     * {@hide}
+     */
+    public abstract int getPhoneDataConnectionCount(int dataType, int which);
+
+    /**
      * Returns the time in milliseconds that wifi has been on while the device was
      * running on battery.
      * 
@@ -619,8 +703,8 @@
         // Dump "battery" stat
         dumpLine(pw, 0 /* uid */, category, BATTERY_DATA, 
                 which == STATS_TOTAL ? getStartCount() : "N/A",
-                whichBatteryUptime / 1000, whichBatteryRealtime / 1000, 
-                totalUptime / 1000, totalRealtime / 1000); 
+                whichBatteryRealtime / 1000, whichBatteryUptime / 1000,
+                totalRealtime / 1000, totalUptime / 1000); 
         
         // Calculate total network and wakelock times across all uids.
         long rxTotal = 0;
@@ -657,21 +741,37 @@
         dumpLine(pw, 0 /* uid */, category, MISC_DATA,
                 screenOnTime / 1000, phoneOnTime / 1000, wifiOnTime / 1000,
                 wifiRunningTime / 1000, bluetoothOnTime / 1000, rxTotal, txTotal, 
-                fullWakeLockTimeTotal, partialWakeLockTimeTotal);
+                fullWakeLockTimeTotal, partialWakeLockTimeTotal,
+                getInputEventCount(which));
+        
+        // Dump screen brightness stats
+        Object[] args = new Object[NUM_SCREEN_BRIGHTNESS_BINS];
+        for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
+            args[i] = getScreenBrightnessTime(i, batteryRealtime, which) / 1000;
+        }
+        dumpLine(pw, 0 /* uid */, category, SCREEN_BRIGHTNESS_DATA, args);
         
         // Dump signal strength stats
-        Object[] args = new Object[NUM_SIGNAL_STRENGTH_BINS];
+        args = new Object[NUM_SIGNAL_STRENGTH_BINS];
         for (int i=0; i<NUM_SIGNAL_STRENGTH_BINS; i++) {
             args[i] = getPhoneSignalStrengthTime(i, batteryRealtime, which) / 1000;
         }
-        dumpLine(pw, 0 /* uid */, category, SIGNAL_STRENGTH_DATA, args);
+        dumpLine(pw, 0 /* uid */, category, SIGNAL_STRENGTH_TIME_DATA, args);
+        for (int i=0; i<NUM_SIGNAL_STRENGTH_BINS; i++) {
+            args[i] = getPhoneSignalStrengthCount(i, which);
+        }
+        dumpLine(pw, 0 /* uid */, category, SIGNAL_STRENGTH_COUNT_DATA, args);
         
         // Dump network type stats
         args = new Object[NUM_DATA_CONNECTION_TYPES];
         for (int i=0; i<NUM_DATA_CONNECTION_TYPES; i++) {
             args[i] = getPhoneDataConnectionTime(i, batteryRealtime, which) / 1000;
         }
-        dumpLine(pw, 0 /* uid */, category, DATA_CONNECTION_DATA, args);
+        dumpLine(pw, 0 /* uid */, category, DATA_CONNECTION_TIME_DATA, args);
+        for (int i=0; i<NUM_DATA_CONNECTION_TYPES; i++) {
+            args[i] = getPhoneDataConnectionCount(i, which);
+        }
+        dumpLine(pw, 0 /* uid */, category, DATA_CONNECTION_COUNT_DATA, args);
         
         if (which == STATS_UNPLUGGED) {
             dumpLine(pw, 0 /* uid */, category, BATTERY_DATA, getUnpluggedStartLevel(), 
@@ -686,14 +786,29 @@
             long tx = u.getTcpBytesSent(which);
             long fullWifiLockOnTime = u.getFullWifiLockTime(batteryRealtime, which);
             long scanWifiLockOnTime = u.getScanWifiLockTime(batteryRealtime, which);
+            long wifiTurnedOnTime = u.getWifiTurnedOnTime(batteryRealtime, which);
             
             if (rx > 0 || tx > 0) dumpLine(pw, uid, category, NETWORK_DATA, rx, tx);
             
-            if (fullWifiLockOnTime != 0 || scanWifiLockOnTime != 0) {
+            if (fullWifiLockOnTime != 0 || scanWifiLockOnTime != 0
+                    || wifiTurnedOnTime != 0) {
                 dumpLine(pw, uid, category, WIFI_LOCK_DATA, 
-                        fullWifiLockOnTime, scanWifiLockOnTime);
+                        fullWifiLockOnTime, scanWifiLockOnTime, wifiTurnedOnTime);
             }
 
+            if (u.hasUserActivity()) {
+                args = new Object[Uid.NUM_USER_ACTIVITY_TYPES];
+                boolean hasData = false;
+                for (int i=0; i<Uid.NUM_USER_ACTIVITY_TYPES; i++) {
+                    int val = u.getUserActivityCount(i, which);
+                    args[i] = val;
+                    if (val != 0) hasData = true;
+                }
+                if (hasData) {
+                    dumpLine(pw, 0 /* uid */, category, USER_ACTIVITY_DATA, args);
+                }
+            }
+            
             Map<String, ? extends BatteryStats.Uid.Wakelock> wakelocks = u.getWakelockStats();
             if (wakelocks.size() > 0) {
                 for (Map.Entry<String, ? extends BatteryStats.Uid.Wakelock> ent
@@ -800,18 +915,19 @@
         final int NU = uidStats.size();
 
         pw.println(prefix
-                + "  Time on battery: " + formatTimeMs(whichBatteryUptime / 1000)
-                + "(" + formatRatioLocked(whichBatteryUptime, totalRealtime)
-                + ") uptime, "
+                + "  Time on battery: "
                 + formatTimeMs(whichBatteryRealtime / 1000) + "("
                 + formatRatioLocked(whichBatteryRealtime, totalRealtime)
-                + ") realtime");
+                + ") realtime, "
+                + formatTimeMs(whichBatteryUptime / 1000)
+                + "(" + formatRatioLocked(whichBatteryUptime, totalRealtime)
+                + ") uptime");
         pw.println(prefix
-                + "  Total: "
-                + formatTimeMs(totalUptime / 1000)
-                + "uptime, "
+                + "  Total run time: "
                 + formatTimeMs(totalRealtime / 1000)
-                + "realtime");
+                + "realtime, "
+                + formatTimeMs(totalUptime / 1000)
+                + "uptime, ");
         
         final long screenOnTime = getScreenOnTime(batteryRealtime, which);
         final long phoneOnTime = getPhoneOnTime(batteryRealtime, which);
@@ -821,15 +937,28 @@
         pw.println(prefix
                 + "  Screen on: " + formatTimeMs(screenOnTime / 1000)
                 + "(" + formatRatioLocked(screenOnTime, whichBatteryRealtime)
-                + "), Phone on: " + formatTimeMs(phoneOnTime / 1000)
-                + "(" + formatRatioLocked(phoneOnTime, whichBatteryRealtime));
-        pw.println(prefix
-                + "  Wifi on: " + formatTimeMs(wifiOnTime / 1000)
-                + "(" + formatRatioLocked(wifiOnTime, whichBatteryRealtime)
-                + "), Wifi running: " + formatTimeMs(wifiRunningTime / 1000)
-                + "(" + formatRatioLocked(wifiRunningTime, whichBatteryRealtime)
-                + "), Bluetooth on: " + formatTimeMs(bluetoothOnTime / 1000)
-                + "(" + formatRatioLocked(bluetoothOnTime, whichBatteryRealtime)+ ")");
+                + "), Input events: " + getInputEventCount(which)
+                + ", Active phone call: " + formatTimeMs(phoneOnTime / 1000)
+                + "(" + formatRatioLocked(phoneOnTime, whichBatteryRealtime) + ")");
+        sb.setLength(0);
+        sb.append("  Screen brightnesses: ");
+        boolean didOne = false;
+        for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
+            final long time = getScreenBrightnessTime(i, batteryRealtime, which);
+            if (time == 0) {
+                continue;
+            }
+            if (didOne) sb.append(", ");
+            didOne = true;
+            sb.append(SCREEN_BRIGHTNESS_NAMES[i]);
+            sb.append(" ");
+            sb.append(formatTimeMs(time/1000));
+            sb.append("(");
+            sb.append(formatRatioLocked(time, screenOnTime));
+            sb.append(")");
+        }
+        if (!didOne) sb.append("No activity");
+        pw.println(sb.toString());
         
         // Calculate total network and wakelock times across all uids.
         long rxTotal = 0;
@@ -873,8 +1002,8 @@
                         (partialWakeLockTimeTotalMicros + 500) / 1000));
         
         sb.setLength(0);
-        sb.append("  Signal strengths: ");
-        boolean didOne = false;
+        sb.append("  Signal levels: ");
+        didOne = false;
         for (int i=0; i<NUM_SIGNAL_STRENGTH_BINS; i++) {
             final long time = getPhoneSignalStrengthTime(i, batteryRealtime, which);
             if (time == 0) {
@@ -887,13 +1016,15 @@
             sb.append(formatTimeMs(time/1000));
             sb.append("(");
             sb.append(formatRatioLocked(time, whichBatteryRealtime));
-            sb.append(")");
+            sb.append(") ");
+            sb.append(getPhoneSignalStrengthCount(i, which));
+            sb.append("x");
         }
         if (!didOne) sb.append("No activity");
         pw.println(sb.toString());
         
         sb.setLength(0);
-        sb.append("  Data types: ");
+        sb.append("  Radio types: ");
         didOne = false;
         for (int i=0; i<NUM_DATA_CONNECTION_TYPES; i++) {
             final long time = getPhoneDataConnectionTime(i, batteryRealtime, which);
@@ -907,11 +1038,21 @@
             sb.append(formatTimeMs(time/1000));
             sb.append("(");
             sb.append(formatRatioLocked(time, whichBatteryRealtime));
-            sb.append(")");
+            sb.append(") ");
+            sb.append(getPhoneDataConnectionCount(i, which));
+            sb.append("x");
         }
         if (!didOne) sb.append("No activity");
         pw.println(sb.toString());
         
+        pw.println(prefix
+                + "  Wifi on: " + formatTimeMs(wifiOnTime / 1000)
+                + "(" + formatRatioLocked(wifiOnTime, whichBatteryRealtime)
+                + "), Wifi running: " + formatTimeMs(wifiRunningTime / 1000)
+                + "(" + formatRatioLocked(wifiRunningTime, whichBatteryRealtime)
+                + "), Bluetooth on: " + formatTimeMs(bluetoothOnTime / 1000)
+                + "(" + formatRatioLocked(bluetoothOnTime, whichBatteryRealtime)+ ")");
+        
         pw.println(" ");
 
         if (which == STATS_UNPLUGGED) {
@@ -926,10 +1067,9 @@
                 pw.println(prefix + "    Last discharge cycle end level: " + 
                         getPluggedStartLevel());
             }
+            pw.println(" ");
         }
         
-        pw.println(" ");
-
 
         for (int iu=0; iu<NU; iu++) {
             final int uid = uidStats.keyAt(iu);
@@ -941,12 +1081,41 @@
             long tcpSent = u.getTcpBytesSent(which);
             long fullWifiLockOnTime = u.getFullWifiLockTime(batteryRealtime, which);
             long scanWifiLockOnTime = u.getScanWifiLockTime(batteryRealtime, which);
+            long wifiTurnedOnTime = u.getWifiTurnedOnTime(batteryRealtime, which);
             
             if (tcpReceived != 0 || tcpSent != 0) {
                 pw.println(prefix + "    Network: " + formatBytesLocked(tcpReceived) + " received, "
                         + formatBytesLocked(tcpSent) + " sent");
             }
-            if (fullWifiLockOnTime != 0 || scanWifiLockOnTime != 0) {
+            
+            if (u.hasUserActivity()) {
+                boolean hasData = false;
+                for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
+                    int val = u.getUserActivityCount(i, which);
+                    if (val != 0) {
+                        if (!hasData) {
+                            sb.setLength(0);
+                            sb.append("    User activity: ");
+                            hasData = true;
+                        } else {
+                            sb.append(", ");
+                        }
+                        sb.append(val);
+                        sb.append(" ");
+                        sb.append(Uid.USER_ACTIVITY_TYPES[i]);
+                    }
+                }
+                if (hasData) {
+                    pw.println(sb.toString());
+                }
+            }
+            
+            if (fullWifiLockOnTime != 0 || scanWifiLockOnTime != 0
+                    || wifiTurnedOnTime != 0) {
+                pw.println(prefix + "    Turned Wifi On Time: " 
+                        + formatTimeMs(wifiTurnedOnTime / 1000) 
+                        + "(" + formatRatioLocked(wifiTurnedOnTime, 
+                                whichBatteryRealtime)+ ")");
                 pw.println(prefix + "    Full Wifi Lock Time: " 
                         + formatTimeMs(fullWifiLockOnTime / 1000) 
                         + "(" + formatRatioLocked(fullWifiLockOnTime, 
diff --git a/core/java/android/os/LocalPowerManager.java b/core/java/android/os/LocalPowerManager.java
index 9e88f5a..2c6b29a 100644
--- a/core/java/android/os/LocalPowerManager.java
+++ b/core/java/android/os/LocalPowerManager.java
@@ -18,6 +18,8 @@
 
 /** @hide */
 public interface LocalPowerManager {
+    // Note: be sure to update BatteryStats if adding or modifying event constants.
+    
     public static final int OTHER_EVENT = 0;
     public static final int CHEEK_EVENT = 1;
     public static final int TOUCH_EVENT = 2;  // touch events are TOUCH for 300ms, and then either
diff --git a/core/java/com/android/internal/app/IBatteryStats.aidl b/core/java/com/android/internal/app/IBatteryStats.aidl
index fff8dcf..bb0c912 100644
--- a/core/java/com/android/internal/app/IBatteryStats.aidl
+++ b/core/java/com/android/internal/app/IBatteryStats.aidl
@@ -27,13 +27,16 @@
     void noteStartGps(int uid);
     void noteStopGps(int uid);
     void noteScreenOn();
+    void noteScreenBrightness(int brightness);
     void noteScreenOff();
+    void noteInputEvent();
+    void noteUserActivity(int uid, int event);
     void notePhoneOn();
     void notePhoneOff();
     void notePhoneSignalStrength(int asu);
     void notePhoneDataConnectionState(int dataType, boolean hasData);
-    void noteWifiOn();
-    void noteWifiOff();
+    void noteWifiOn(int uid);
+    void noteWifiOff(int uid);
     void noteWifiRunning();
     void noteWifiStopped();
     void noteBluetoothOn();
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 9e07fd8..8085080 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -48,7 +48,7 @@
     private static final int MAGIC = 0xBA757475; // 'BATSTATS' 
 
     // Current on-disk Parcel version
-    private static final int VERSION = 29;
+    private static final int VERSION = 32;
 
     private final File mFile;
     private final File mBackupFile;
@@ -90,6 +90,11 @@
     boolean mScreenOn;
     Timer mScreenOnTimer;
     
+    int mScreenBrightnessBin = -1;
+    final Timer[] mScreenBrightnessTimer = new Timer[NUM_SCREEN_BRIGHTNESS_BINS];
+    
+    Counter mInputEventCounter;
+    
     boolean mPhoneOn;
     Timer mPhoneOnTimer;
     
@@ -101,6 +106,7 @@
     
     boolean mWifiOn;
     Timer mWifiOnTimer;
+    int mWifiOnUid = -1;
 
     boolean mWifiRunning;
     Timer mWifiRunningTimer;
@@ -141,6 +147,99 @@
     }
     
     /**
+     * State for keeping track of counting information.
+     */
+    public static final class Counter extends BatteryStats.Counter implements Unpluggable {
+        int mCount;
+        int mLoadedCount;
+        int mLastCount;
+        int mUnpluggedCount;
+        int mPluggedCount;
+        
+        Counter(ArrayList<Unpluggable> unpluggables, Parcel in) {
+            mPluggedCount = mCount = in.readInt();
+            mLoadedCount = in.readInt();
+            mLastCount = in.readInt();
+            mUnpluggedCount = in.readInt();
+            unpluggables.add(this);
+        }
+
+        Counter(ArrayList<Unpluggable> unpluggables) {
+            unpluggables.add(this);
+        }
+        
+        public void writeToParcel(Parcel out) {
+            out.writeInt(mCount);
+            out.writeInt(mLoadedCount);
+            out.writeInt(mLastCount);
+            out.writeInt(mUnpluggedCount);
+        }
+
+        public void unplug(long batteryUptime, long batteryRealtime) {
+            mUnpluggedCount = mCount = mPluggedCount;
+        }
+
+        public void plug(long batteryUptime, long batteryRealtime) {
+            mPluggedCount = mCount;
+        }
+        
+        /**
+         * Writes a possibly null Counter to a Parcel.
+         *
+         * @param out the Parcel to be written to.
+         * @param counter a Counter, or null.
+         */
+        public static void writeCounterToParcel(Parcel out, Counter counter) {
+            if (counter == null) {
+                out.writeInt(0); // indicates null
+                return;
+            }
+            out.writeInt(1); // indicates non-null
+
+            counter.writeToParcel(out);
+        }
+
+        @Override
+        public int getCount(int which) {
+            int val;
+            if (which == STATS_LAST) {
+                val = mLastCount;
+            } else {
+                val = mCount;
+                if (which == STATS_UNPLUGGED) {
+                    val -= mUnpluggedCount;
+                } else if (which != STATS_TOTAL) {
+                    val -= mLoadedCount;
+                }
+            }
+
+            return val;
+        }
+
+        public void logState(Printer pw, String prefix) {
+            pw.println(prefix + "mCount=" + mCount
+                    + " mLoadedCount=" + mLoadedCount + " mLastCount=" + mLastCount
+                    + " mUnpluggedCount=" + mUnpluggedCount
+                    + " mPluggedCount=" + mPluggedCount);
+        }
+        
+        void stepLocked() {
+            mCount++;
+        }
+
+        void writeSummaryFromParcelLocked(Parcel out) {
+            out.writeInt(mCount);
+            out.writeInt(mCount - mLoadedCount);
+        }
+
+        void readSummaryFromParcelLocked(Parcel in) {
+            mCount = mLoadedCount = in.readInt();
+            mLastCount = in.readInt();
+            mUnpluggedCount = mPluggedCount = mCount;
+        }
+    }
+    
+    /**
      * State for keeping track of timing information.
      */
     public static final class Timer extends BatteryStats.Timer implements Unpluggable {
@@ -469,6 +568,9 @@
         if (!mScreenOn) {
             mScreenOn = true;
             mScreenOnTimer.startRunningLocked(this);
+            if (mScreenBrightnessBin >= 0) {
+                mScreenBrightnessTimer[mScreenBrightnessBin].startRunningLocked(this);
+            }
         }
     }
     
@@ -476,6 +578,36 @@
         if (mScreenOn) {
             mScreenOn = false;
             mScreenOnTimer.stopRunningLocked(this);
+            if (mScreenBrightnessBin >= 0) {
+                mScreenBrightnessTimer[mScreenBrightnessBin].stopRunningLocked(this);
+            }
+        }
+    }
+    
+    public void noteScreenBrightnessLocked(int brightness) {
+        // Bin the brightness.
+        int bin = brightness / (256/NUM_SCREEN_BRIGHTNESS_BINS);
+        if (bin < 0) bin = 0;
+        else if (bin >= NUM_SCREEN_BRIGHTNESS_BINS) bin = NUM_SCREEN_BRIGHTNESS_BINS-1;
+        if (mScreenBrightnessBin != bin) {
+            if (mScreenOn) {
+                if (mScreenBrightnessBin >= 0) {
+                    mScreenBrightnessTimer[mScreenBrightnessBin].stopRunningLocked(this);
+                }
+                mScreenBrightnessTimer[bin].startRunningLocked(this);
+            }
+            mScreenBrightnessBin = bin;
+        }
+    }
+    
+    public void noteInputEventLocked() {
+        mInputEventCounter.stepLocked();
+    }
+    
+    public void noteUserActivityLocked(int uid, int event) {
+        Uid u = mUidStats.get(uid);
+        if (u != null) {
+            u.noteUserActivityLocked(event);
         }
     }
     
@@ -537,18 +669,38 @@
         }
     }
     
-    public void noteWifiOnLocked() {
+    public void noteWifiOnLocked(int uid) {
         if (!mWifiOn) {
             mWifiOn = true;
             mWifiOnTimer.startRunningLocked(this);
         }
+        if (mWifiOnUid != uid) {
+            if (mWifiOnUid >= 0) {
+                Uid u = mUidStats.get(mWifiOnUid);
+                if (u != null) {
+                    u.noteWifiTurnedOffLocked();
+                }
+            }
+            mWifiOnUid = uid;
+            Uid u = mUidStats.get(uid);
+            if (u != null) {
+                u.noteWifiTurnedOnLocked();
+            }
+        }
     }
     
-    public void noteWifiOffLocked() {
+    public void noteWifiOffLocked(int uid) {
         if (mWifiOn) {
             mWifiOn = false;
             mWifiOnTimer.stopRunningLocked(this);
         }
+        if (mWifiOnUid >= 0) {
+            Uid u = mUidStats.get(mWifiOnUid);
+            if (u != null) {
+                u.noteWifiTurnedOffLocked();
+            }
+            mWifiOnUid = -1;
+        }
     }
     
     public void noteWifiRunningLocked() {
@@ -611,6 +763,16 @@
         return mScreenOnTimer.getTotalTime(batteryRealtime, which);
     }
     
+    @Override public long getScreenBrightnessTime(int brightnessBin,
+            long batteryRealtime, int which) {
+        return mScreenBrightnessTimer[brightnessBin].getTotalTime(
+                batteryRealtime, which);
+    }
+    
+    @Override public int getInputEventCount(int which) {
+        return mInputEventCounter.getCount(which);
+    }
+    
     @Override public long getPhoneOnTime(long batteryRealtime, int which) {
         return mPhoneOnTimer.getTotalTime(batteryRealtime, which);
     }
@@ -621,12 +783,20 @@
                 batteryRealtime, which);
     }
     
+    @Override public int getPhoneSignalStrengthCount(int dataType, int which) {
+        return mPhoneDataConnectionsTimer[dataType].getCount(which);
+    }
+    
     @Override public long getPhoneDataConnectionTime(int dataType,
             long batteryRealtime, int which) {
         return mPhoneDataConnectionsTimer[dataType].getTotalTime(
                 batteryRealtime, which);
     }
     
+    @Override public int getPhoneDataConnectionCount(int dataType, int which) {
+        return mPhoneDataConnectionsTimer[dataType].getCount(which);
+    }
+    
     @Override public long getWifiOnTime(long batteryRealtime, int which) {
         return mWifiOnTimer.getTotalTime(batteryRealtime, which);
     }
@@ -665,12 +835,17 @@
         long mStartedTcpBytesReceived = -1;
         long mStartedTcpBytesSent = -1;
         
+        boolean mWifiTurnedOn;
+        Timer mWifiTurnedOnTimer;
+        
         boolean mFullWifiLockOut;
         Timer mFullWifiLockTimer;
         
         boolean mScanWifiLockOut;
         Timer mScanWifiLockTimer;
         
+        Counter[] mUserActivityCounters;
+        
         /**
          * The statistics we have collected for this uid's wake locks.
          */
@@ -693,6 +868,7 @@
         
         public Uid(int uid) {
             mUid = uid;
+            mWifiTurnedOnTimer = new Timer(WIFI_TURNED_ON, null, mUnpluggables);
             mFullWifiLockTimer = new Timer(FULL_WIFI_LOCK, null, mUnpluggables);
             mScanWifiLockTimer = new Timer(SCAN_WIFI_LOCK, null, mUnpluggables);
         }
@@ -755,6 +931,22 @@
         }
         
         @Override
+        public void noteWifiTurnedOnLocked() {
+            if (!mWifiTurnedOn) {
+                mWifiTurnedOn = true;
+                mWifiTurnedOnTimer.startRunningLocked(BatteryStatsImpl.this);
+            }
+        }
+        
+        @Override
+        public void noteWifiTurnedOffLocked() {
+            if (mWifiTurnedOn) {
+                mWifiTurnedOn = false;
+                mWifiTurnedOnTimer.stopRunningLocked(BatteryStatsImpl.this);
+            }
+        }
+        
+        @Override
         public void noteFullWifiLockAcquiredLocked() {
             if (!mFullWifiLockOut) {
                 mFullWifiLockOut = true;
@@ -785,6 +977,12 @@
                 mScanWifiLockTimer.stopRunningLocked(BatteryStatsImpl.this);
             }
         }
+        
+        @Override 
+        public long getWifiTurnedOnTime(long batteryRealtime, int which) {
+            return mWifiTurnedOnTimer.getTotalTime(batteryRealtime, which);
+        }
+        
         @Override 
         public long getFullWifiLockTime(long batteryRealtime, int which) {
             return mFullWifiLockTimer.getTotalTime(batteryRealtime, which);
@@ -795,6 +993,36 @@
             return mScanWifiLockTimer.getTotalTime(batteryRealtime, which);
         }
         
+        @Override
+        public void noteUserActivityLocked(int type) {
+            if (mUserActivityCounters == null) {
+                initUserActivityLocked();
+            }
+            if (type < 0) type = 0;
+            else if (type >= NUM_USER_ACTIVITY_TYPES) type = NUM_USER_ACTIVITY_TYPES-1;
+            mUserActivityCounters[type].stepLocked();
+        }
+        
+        @Override
+        public boolean hasUserActivity() {
+            return mUserActivityCounters != null;
+        }
+        
+        @Override
+        public int getUserActivityCount(int type, int which) {
+            if (mUserActivityCounters == null) {
+                return 0;
+            }
+            return mUserActivityCounters[type].getCount(which);
+        }
+        
+        void initUserActivityLocked() {
+            mUserActivityCounters = new Counter[NUM_USER_ACTIVITY_TYPES];
+            for (int i=0; i<NUM_USER_ACTIVITY_TYPES; i++) {
+                mUserActivityCounters[i] = new Counter(mUnpluggables);
+            }
+        }
+        
         public long computeCurrentTcpBytesSent() {
             return mCurrentTcpBytesSent + (mStartedTcpBytesSent >= 0
                     ? (NetStat.getUidTxBytes(mUid) - mStartedTcpBytesSent) : 0);
@@ -835,8 +1063,17 @@
             out.writeLong(computeCurrentTcpBytesSent());
             out.writeLong(mTcpBytesReceivedAtLastUnplug);
             out.writeLong(mTcpBytesSentAtLastUnplug);
+            mWifiTurnedOnTimer.writeToParcel(out, batteryRealtime);
             mFullWifiLockTimer.writeToParcel(out, batteryRealtime);
             mScanWifiLockTimer.writeToParcel(out, batteryRealtime);
+            if (mUserActivityCounters == null) {
+                out.writeInt(0);
+            } else {
+                out.writeInt(1);
+                for (int i=0; i<NUM_USER_ACTIVITY_TYPES; i++) {
+                    mUserActivityCounters[i].writeToParcel(out);
+                }
+            }
         }
 
         void readFromParcelLocked(ArrayList<Unpluggable> unpluggables, Parcel in) {
@@ -882,10 +1119,20 @@
             mCurrentTcpBytesSent = in.readLong();
             mTcpBytesReceivedAtLastUnplug = in.readLong();
             mTcpBytesSentAtLastUnplug = in.readLong();
+            mWifiTurnedOn = false;
+            mWifiTurnedOnTimer = new Timer(WIFI_TURNED_ON, null, mUnpluggables, in);
             mFullWifiLockOut = false;
             mFullWifiLockTimer = new Timer(FULL_WIFI_LOCK, null, mUnpluggables, in);
             mScanWifiLockOut = false;
             mScanWifiLockTimer = new Timer(SCAN_WIFI_LOCK, null, mUnpluggables, in);
+            if (in.readInt() == 0) {
+                mUserActivityCounters = null;
+            } else {
+                mUserActivityCounters = new Counter[NUM_USER_ACTIVITY_TYPES];
+                for (int i=0; i<NUM_USER_ACTIVITY_TYPES; i++) {
+                    mUserActivityCounters[i] = new Counter(mUnpluggables, in);
+                }
+            }
         }
 
         /**
@@ -1679,12 +1926,16 @@
         mBackupFile = new File(filename + ".bak");
         mStartCount++;
         mScreenOnTimer = new Timer(-1, null, mUnpluggables);
+        for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
+            mScreenBrightnessTimer[i] = new Timer(-100-i, null, mUnpluggables);
+        }
+        mInputEventCounter = new Counter(mUnpluggables);
         mPhoneOnTimer = new Timer(-2, null, mUnpluggables);
         for (int i=0; i<NUM_SIGNAL_STRENGTH_BINS; i++) {
-            mPhoneSignalStrengthsTimer[i] = new Timer(-100-i, null, mUnpluggables);
+            mPhoneSignalStrengthsTimer[i] = new Timer(-200-i, null, mUnpluggables);
         }
         for (int i=0; i<NUM_DATA_CONNECTION_TYPES; i++) {
-            mPhoneDataConnectionsTimer[i] = new Timer(-200-i, null, mUnpluggables);
+            mPhoneDataConnectionsTimer[i] = new Timer(-300-i, null, mUnpluggables);
         }
         mWifiOnTimer = new Timer(-3, null, mUnpluggables);
         mWifiRunningTimer = new Timer(-4, null, mUnpluggables);
@@ -2022,6 +2273,10 @@
         
         mScreenOn = false;
         mScreenOnTimer.readSummaryFromParcelLocked(in);
+        for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
+            mScreenBrightnessTimer[i].readSummaryFromParcelLocked(in);
+        }
+        mInputEventCounter.readSummaryFromParcelLocked(in);
         mPhoneOn = false;
         mPhoneOnTimer.readSummaryFromParcelLocked(in);
         for (int i=0; i<NUM_SIGNAL_STRENGTH_BINS; i++) {
@@ -2043,11 +2298,22 @@
             Uid u = new Uid(uid);
             mUidStats.put(uid, u);
 
+            u.mWifiTurnedOn = false;
+            u.mWifiTurnedOnTimer.readSummaryFromParcelLocked(in);
             u.mFullWifiLockOut = false;
             u.mFullWifiLockTimer.readSummaryFromParcelLocked(in);
             u.mScanWifiLockOut = false;
             u.mScanWifiLockTimer.readSummaryFromParcelLocked(in);
             
+            if (in.readInt() != 0) {
+                if (u.mUserActivityCounters == null) {
+                    u.initUserActivityLocked();
+                }
+                for (int i=0; i<Uid.NUM_USER_ACTIVITY_TYPES; i++) {
+                    u.mUserActivityCounters[i].readSummaryFromParcelLocked(in);
+                }
+            }
+            
             int NW = in.readInt();
             for (int iw = 0; iw < NW; iw++) {
                 String wlName = in.readString();
@@ -2135,6 +2401,10 @@
         
         
         mScreenOnTimer.writeSummaryFromParcelLocked(out, NOWREAL);
+        for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
+            mScreenBrightnessTimer[i].writeSummaryFromParcelLocked(out, NOWREAL);
+        }
+        mInputEventCounter.writeSummaryFromParcelLocked(out);
         mPhoneOnTimer.writeSummaryFromParcelLocked(out, NOWREAL);
         for (int i=0; i<NUM_SIGNAL_STRENGTH_BINS; i++) {
             mPhoneSignalStrengthsTimer[i].writeSummaryFromParcelLocked(out, NOWREAL);
@@ -2152,9 +2422,19 @@
             out.writeInt(mUidStats.keyAt(iu));
             Uid u = mUidStats.valueAt(iu);
             
+            u.mWifiTurnedOnTimer.writeSummaryFromParcelLocked(out, NOWREAL);
             u.mFullWifiLockTimer.writeSummaryFromParcelLocked(out, NOWREAL);
             u.mScanWifiLockTimer.writeSummaryFromParcelLocked(out, NOWREAL);
 
+            if (u.mUserActivityCounters == null) {
+                out.writeInt(0);
+            } else {
+                out.writeInt(1);
+                for (int i=0; i<Uid.NUM_USER_ACTIVITY_TYPES; i++) {
+                    u.mUserActivityCounters[i].writeSummaryFromParcelLocked(out);
+                }
+            }
+            
             int NW = u.mWakelockStats.size();
             out.writeInt(NW);
             if (NW > 0) {
@@ -2265,13 +2545,17 @@
         mBatteryLastRealtime = in.readLong();
         mScreenOn = false;
         mScreenOnTimer = new Timer(-1, null, mUnpluggables, in);
+        for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
+            mScreenBrightnessTimer[i] = new Timer(-100-i, null, mUnpluggables, in);
+        }
+        mInputEventCounter = new Counter(mUnpluggables, in);
         mPhoneOn = false;
         mPhoneOnTimer = new Timer(-2, null, mUnpluggables, in);
         for (int i=0; i<NUM_SIGNAL_STRENGTH_BINS; i++) {
-            mPhoneSignalStrengthsTimer[i] = new Timer(-100-i, null, mUnpluggables, in);
+            mPhoneSignalStrengthsTimer[i] = new Timer(-200-i, null, mUnpluggables, in);
         }
         for (int i=0; i<NUM_DATA_CONNECTION_TYPES; i++) {
-            mPhoneDataConnectionsTimer[i] = new Timer(-200-i, null, mUnpluggables, in);
+            mPhoneDataConnectionsTimer[i] = new Timer(-300-i, null, mUnpluggables, in);
         }
         mWifiOn = false;
         mWifiOnTimer = new Timer(-2, null, mUnpluggables, in);
@@ -2329,6 +2613,10 @@
         out.writeLong(mBatteryRealtime);
         out.writeLong(mBatteryLastRealtime);
         mScreenOnTimer.writeToParcel(out, batteryRealtime);
+        for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
+            mScreenBrightnessTimer[i].writeToParcel(out, batteryRealtime);
+        }
+        mInputEventCounter.writeToParcel(out);
         mPhoneOnTimer.writeToParcel(out, batteryRealtime);
         for (int i=0; i<NUM_SIGNAL_STRENGTH_BINS; i++) {
             mPhoneSignalStrengthsTimer[i].writeToParcel(out, batteryRealtime);
@@ -2381,6 +2669,12 @@
         if (DEBUG) {
             pw.println("*** Screen timer:");
             mScreenOnTimer.logState(pw, "  ");
+            for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
+                pw.println("*** Screen brightness #" + i + ":");
+                mScreenBrightnessTimer[i].logState(pw, "  ");
+            }
+            pw.println("*** Input event counter:");
+            mInputEventCounter.logState(pw, "  ");
             pw.println("*** Phone timer:");
             mPhoneOnTimer.logState(pw, "  ");
             for (int i=0; i<NUM_SIGNAL_STRENGTH_BINS; i++) {
diff --git a/services/java/com/android/server/HardwareService.java b/services/java/com/android/server/HardwareService.java
index 42367ef..5bc9b5f 100755
--- a/services/java/com/android/server/HardwareService.java
+++ b/services/java/com/android/server/HardwareService.java
@@ -16,6 +16,9 @@
 
 package com.android.server;
 
+import com.android.internal.app.IBatteryStats;
+import com.android.server.am.BatteryStatsService;
+
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
@@ -63,6 +66,8 @@
         mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
         mWakeLock.setReferenceCounted(true);
 
+        mBatteryStats = BatteryStatsService.getService();
+        
         IntentFilter filter = new IntentFilter();
         filter.addAction(Intent.ACTION_SCREEN_OFF);
         context.registerReceiver(mIntentReceiver, filter);
@@ -200,6 +205,14 @@
         setLightBrightness_UNCHECKED(LIGHT_ID_BACKLIGHT, brightness);
         setLightBrightness_UNCHECKED(LIGHT_ID_KEYBOARD, brightness);
         setLightBrightness_UNCHECKED(LIGHT_ID_BUTTONS, brightness);
+        long identity = Binder.clearCallingIdentity();
+        try {
+            mBatteryStats.noteScreenBrightness(brightness);
+        } catch (RemoteException e) {
+            Log.w(TAG, "RemoteException calling noteScreenBrightness on BatteryStatsService", e);
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
     }
 
     void setLightOff_UNCHECKED(int light) {
@@ -388,9 +401,11 @@
     private static native void setLight_native(int ptr, int light, int color, int mode,
             int onMS, int offMS);
 
-    private Context mContext;
-    private PowerManager.WakeLock mWakeLock;
+    private final Context mContext;
+    private final PowerManager.WakeLock mWakeLock;
 
+    private final IBatteryStats mBatteryStats;
+    
     volatile VibrateThread mThread;
     volatile Death mDeath;
     volatile IBinder mToken;
diff --git a/services/java/com/android/server/PowerManagerService.java b/services/java/com/android/server/PowerManagerService.java
index bbca401..9c6e9dc 100644
--- a/services/java/com/android/server/PowerManagerService.java
+++ b/services/java/com/android/server/PowerManagerService.java
@@ -1301,6 +1301,8 @@
                         err = Power.setScreenState(true);
                         long identity = Binder.clearCallingIdentity();
                         try {
+                            mBatteryStats.noteScreenBrightness(
+                                    getPreferredBrightness());
                             mBatteryStats.noteScreenOn();
                         } catch (RemoteException e) {
                             Log.w(TAG, "RemoteException calling noteScreenOn on BatteryStatsService", e);
@@ -1455,6 +1457,8 @@
                             break;
                     }
                 }
+                int brightness = preferredBrightness;
+                int steps = ANIM_STEPS;
                 if ((newState & SCREEN_BRIGHT_BIT) == 0) {
                     // dim or turn off backlight, depending on if the screen is on
                     // the scale is because the brightness ramp isn't linear and this biases
@@ -1463,7 +1467,6 @@
                     float ratio = (((float)Power.BRIGHTNESS_DIM)/preferredBrightness);
                     if (ratio > 1.0f) ratio = 1.0f;
                     if ((newState & SCREEN_ON_BIT) == 0) {
-                        int steps;
                         if ((oldState & SCREEN_BRIGHT_BIT) != 0) {
                             // was bright
                             steps = ANIM_STEPS;
@@ -1471,10 +1474,8 @@
                             // was dim
                             steps = (int)(ANIM_STEPS*ratio*scale);
                         }
-                        mScreenBrightness.setTargetLocked(Power.BRIGHTNESS_OFF,
-                                steps, INITIAL_SCREEN_BRIGHTNESS, nominalCurrentValue);
+                        brightness = Power.BRIGHTNESS_OFF;
                     } else {
-                        int steps;
                         if ((oldState & SCREEN_ON_BIT) != 0) {
                             // was bright
                             steps = (int)(ANIM_STEPS*(1.0f-ratio)*scale);
@@ -1490,13 +1491,19 @@
                             // will then count going dim as turning off.
                             mScreenOffTime = SystemClock.elapsedRealtime();
                         }
-                        mScreenBrightness.setTargetLocked(Power.BRIGHTNESS_DIM,
-                                steps, INITIAL_SCREEN_BRIGHTNESS, nominalCurrentValue);
+                        brightness = Power.BRIGHTNESS_DIM;
                     }
-                } else {
-                    mScreenBrightness.setTargetLocked(preferredBrightness,
-                            ANIM_STEPS, INITIAL_SCREEN_BRIGHTNESS, nominalCurrentValue);
                 }
+                long identity = Binder.clearCallingIdentity();
+                try {
+                    mBatteryStats.noteScreenBrightness(brightness);
+                } catch (RemoteException e) {
+                    // Nothing interesting to do.
+                } finally {
+                    Binder.restoreCallingIdentity(identity);
+                }
+                mScreenBrightness.setTargetLocked(brightness,
+                        steps, INITIAL_SCREEN_BRIGHTNESS, nominalCurrentValue);
                 startAnimation = true;
             } else {
                 if ((newState & SCREEN_BRIGHT_BIT) == 0) {
@@ -1735,6 +1742,16 @@
                         mUserState |= SCREEN_BRIGHT;
                     }
 
+                    int uid = Binder.getCallingUid();
+                    long ident = Binder.clearCallingIdentity();
+                    try {
+                        mBatteryStats.noteUserActivity(uid, eventType);
+                    } catch (RemoteException e) {
+                        // Ignore
+                    } finally {
+                        Binder.restoreCallingIdentity(ident);
+                    }
+                    
                     reactivateWakeLocksLocked();
                     mWakeLockState = mLocks.gatherState();
                     setPowerState(mUserState | mWakeLockState, noChangeLights, true);
@@ -1951,6 +1968,15 @@
         synchronized (mLocks) {
             Log.d(TAG, "system ready!");
             mDoneBooting = true;
+            long identity = Binder.clearCallingIdentity();
+            try {
+                mBatteryStats.noteScreenBrightness(getPreferredBrightness());
+                mBatteryStats.noteScreenOn();
+            } catch (RemoteException e) {
+                // Nothing interesting to do.
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
             userActivity(SystemClock.uptimeMillis(), false, BUTTON_EVENT, true);
             updateWakeLockLocked();
             mLocks.notifyAll();
diff --git a/services/java/com/android/server/WifiService.java b/services/java/com/android/server/WifiService.java
index 8e1d053..54e77f0 100644
--- a/services/java/com/android/server/WifiService.java
+++ b/services/java/com/android/server/WifiService.java
@@ -47,6 +47,7 @@
 import android.os.Looper;
 import android.os.Message;
 import android.os.PowerManager;
+import android.os.Process;
 import android.os.RemoteException;
 import android.provider.Settings;
 import android.util.Log;
@@ -167,6 +168,11 @@
     private char[] mScanResultBuffer;
     private boolean mNeedReconfig;
 
+    /*
+     * Last UID that asked to enable WIFI.
+     */
+    private int mLastEnableUid = Process.myUid();
+    
     /**
      * Number of allowed radio frequency channels in various regulatory domains.
      * This list is sufficient for 802.11b/g networks (2.4GHz range).
@@ -239,7 +245,7 @@
                 },
                 new IntentFilter(Intent.ACTION_AIRPLANE_MODE_CHANGED));
 
-        setWifiEnabledBlocking(wifiEnabled, false);
+        setWifiEnabledBlocking(wifiEnabled, false, Process.myUid());
     }
 
     /**
@@ -455,7 +461,8 @@
 
         synchronized (mWifiHandler) {
             sWakeLock.acquire();
-            sendEnableMessage(enable, true);
+            mLastEnableUid = Binder.getCallingUid();
+            sendEnableMessage(enable, true, Binder.getCallingUid());
         }
 
         return true;
@@ -465,10 +472,11 @@
      * Enables/disables Wi-Fi synchronously.
      * @param enable {@code true} to turn Wi-Fi on, {@code false} to turn it off.
      * @param persist {@code true} if the setting should be persisted.
+     * @param uid The UID of the process making the request.
      * @return {@code true} if the operation succeeds (or if the existing state
      *         is the same as the requested state)
      */
-    private boolean setWifiEnabledBlocking(boolean enable, boolean persist) {
+    private boolean setWifiEnabledBlocking(boolean enable, boolean persist, int uid) {
         final int eventualWifiState = enable ? WIFI_STATE_ENABLED : WIFI_STATE_DISABLED;
 
         if (mWifiState == eventualWifiState) {
@@ -478,18 +486,18 @@
             return false;
         }
 
-        setWifiEnabledState(enable ? WIFI_STATE_ENABLING : WIFI_STATE_DISABLING);
+        setWifiEnabledState(enable ? WIFI_STATE_ENABLING : WIFI_STATE_DISABLING, uid);
 
         if (enable) {
             if (!WifiNative.loadDriver()) {
                 Log.e(TAG, "Failed to load Wi-Fi driver.");
-                setWifiEnabledState(WIFI_STATE_UNKNOWN);
+                setWifiEnabledState(WIFI_STATE_UNKNOWN, uid);
                 return false;
             }
             if (!WifiNative.startSupplicant()) {
                 WifiNative.unloadDriver();
                 Log.e(TAG, "Failed to start supplicant daemon.");
-                setWifiEnabledState(WIFI_STATE_UNKNOWN);
+                setWifiEnabledState(WIFI_STATE_UNKNOWN, uid);
                 return false;
             }
             registerForBroadcasts();
@@ -503,7 +511,7 @@
             boolean failedToStopSupplicantOrUnloadDriver = false;
             if (!WifiNative.stopSupplicant()) {
                 Log.e(TAG, "Failed to stop supplicant daemon.");
-                setWifiEnabledState(WIFI_STATE_UNKNOWN);
+                setWifiEnabledState(WIFI_STATE_UNKNOWN, uid);
                 failedToStopSupplicantOrUnloadDriver = true;
             }
 
@@ -513,7 +521,7 @@
             if (!WifiNative.unloadDriver()) {
                 Log.e(TAG, "Failed to unload Wi-Fi driver.");
                 if (!failedToStopSupplicantOrUnloadDriver) {
-                    setWifiEnabledState(WIFI_STATE_UNKNOWN);
+                    setWifiEnabledState(WIFI_STATE_UNKNOWN, uid);
                     failedToStopSupplicantOrUnloadDriver = true;
                 }
             }
@@ -527,7 +535,7 @@
         if (persist) {
             persistWifiEnabled(enable);
         }
-        setWifiEnabledState(eventualWifiState);
+        setWifiEnabledState(eventualWifiState, uid);
 
         /*
          * Initialize the hidden networks state and the number of allowed
@@ -541,15 +549,15 @@
         return true;
     }
 
-    private void setWifiEnabledState(int wifiState) {
+    private void setWifiEnabledState(int wifiState, int uid) {
         final int previousWifiState = mWifiState;
 
         long ident = Binder.clearCallingIdentity();
         try {
             if (wifiState == WIFI_STATE_ENABLED) {
-                mBatteryStats.noteWifiOn();
+                mBatteryStats.noteWifiOn(uid);
             } else if (wifiState == WIFI_STATE_DISABLED) {
-                mBatteryStats.noteWifiOff();
+                mBatteryStats.noteWifiOff(uid);
             }
         } catch (RemoteException e) {
         } finally {
@@ -1571,10 +1579,10 @@
         }
     };
 
-    private void sendEnableMessage(boolean enable, boolean persist) {
+    private void sendEnableMessage(boolean enable, boolean persist, int uid) {
         Message msg = Message.obtain(mWifiHandler,
                                      (enable ? MESSAGE_ENABLE_WIFI : MESSAGE_DISABLE_WIFI),
-                                     (persist ? 1 : 0), 0);
+                                     (persist ? 1 : 0), uid);
         msg.sendToTarget();
     }
 
@@ -1602,7 +1610,7 @@
             if (wifiShouldBeEnabled) {
                 if (wifiShouldBeStarted) {
                     sWakeLock.acquire();
-                    sendEnableMessage(true, false);
+                    sendEnableMessage(true, false, mLastEnableUid);
                     sWakeLock.acquire();
                     sendStartMessage(strongestLockMode == WifiManager.WIFI_MODE_SCAN_ONLY);
                 } else {
@@ -1626,7 +1634,7 @@
                 }
             } else {
                 sWakeLock.acquire();
-                sendEnableMessage(false, false);
+                sendEnableMessage(false, false, mLastEnableUid);
             }
         }
     }
@@ -1671,7 +1679,7 @@
             switch (msg.what) {
 
                 case MESSAGE_ENABLE_WIFI:
-                    setWifiEnabledBlocking(true, msg.arg1 == 1);
+                    setWifiEnabledBlocking(true, msg.arg1 == 1, msg.arg2);
                     sWakeLock.release();
                     break;
 
@@ -1684,7 +1692,7 @@
                 case MESSAGE_DISABLE_WIFI:
                     // a non-zero msg.arg1 value means the "enabled" setting
                     // should be persisted
-                    setWifiEnabledBlocking(false, msg.arg1 == 1);
+                    setWifiEnabledBlocking(false, msg.arg1 == 1, msg.arg2);
                     sWakeLock.release();
                     break;
 
diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java
index 2e16157..270d15f 100644
--- a/services/java/com/android/server/WindowManagerService.java
+++ b/services/java/com/android/server/WindowManagerService.java
@@ -5085,6 +5085,11 @@
                         } else {
                             eventType = LocalPowerManager.OTHER_EVENT;
                         }
+                        try {
+                            mBatteryStats.noteInputEvent();
+                        } catch (RemoteException e) {
+                            // Ignore
+                        }
                         mPowerManager.userActivity(curTime, false, eventType);
                         switch (ev.classType) {
                             case RawInputEvent.CLASS_KEYBOARD:
diff --git a/services/java/com/android/server/am/BatteryStatsService.java b/services/java/com/android/server/am/BatteryStatsService.java
index 2192e06..9ad994c 100644
--- a/services/java/com/android/server/am/BatteryStatsService.java
+++ b/services/java/com/android/server/am/BatteryStatsService.java
@@ -129,6 +129,13 @@
         }
     }
     
+    public void noteScreenBrightness(int brightness) {
+        enforceCallingPermission();
+        synchronized (mStats) {
+            mStats.noteScreenBrightnessLocked(brightness);
+        }
+    }
+    
     public void noteScreenOff() {
         enforceCallingPermission();
         synchronized (mStats) {
@@ -136,6 +143,20 @@
         }
     }
 
+    public void noteInputEvent() {
+        enforceCallingPermission();
+        synchronized (mStats) {
+            mStats.noteInputEventLocked();
+        }
+    }
+    
+    public void noteUserActivity(int uid, int event) {
+        enforceCallingPermission();
+        synchronized (mStats) {
+            mStats.noteUserActivityLocked(uid, event);
+        }
+    }
+    
     public void notePhoneOn() {
         enforceCallingPermission();
         synchronized (mStats) {
@@ -164,17 +185,17 @@
         }
     }
     
-    public void noteWifiOn() {
+    public void noteWifiOn(int uid) {
         enforceCallingPermission();
         synchronized (mStats) {
-            mStats.noteWifiOnLocked();
+            mStats.noteWifiOnLocked(uid);
         }
     }
     
-    public void noteWifiOff() {
+    public void noteWifiOff(int uid) {
         enforceCallingPermission();
         synchronized (mStats) {
-            mStats.noteWifiOffLocked();
+            mStats.noteWifiOffLocked(uid);
         }
     }