Merge "Draw shadows from casters together if the Z values are similar"
diff --git a/api/current.txt b/api/current.txt
index e24dd3b..f1aa8bf 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -4293,7 +4293,9 @@
   public static class Notification.Builder {
     ctor public Notification.Builder(android.content.Context);
     method public android.app.Notification.Builder addAction(int, java.lang.CharSequence, android.app.PendingIntent);
+    method public android.app.Notification.Builder addExtras(android.os.Bundle);
     method public android.app.Notification build();
+    method public android.os.Bundle getExtras();
     method public deprecated android.app.Notification getNotification();
     method public android.app.Notification.Builder setAutoCancel(boolean);
     method public android.app.Notification.Builder setContent(android.widget.RemoteViews);
diff --git a/cmds/bootanimation/BootAnimation.cpp b/cmds/bootanimation/BootAnimation.cpp
index e12e961c..41afa39 100644
--- a/cmds/bootanimation/BootAnimation.cpp
+++ b/cmds/bootanimation/BootAnimation.cpp
@@ -36,7 +36,6 @@
 #include <ui/Rect.h>
 #include <ui/Region.h>
 #include <ui/DisplayInfo.h>
-#include <ui/FramebufferNativeWindow.h>
 
 #include <gui/ISurfaceComposer.h>
 #include <gui/Surface.h>
diff --git a/cmds/pm/src/com/android/commands/pm/Pm.java b/cmds/pm/src/com/android/commands/pm/Pm.java
index 9ad2e76..d513a10 100644
--- a/cmds/pm/src/com/android/commands/pm/Pm.java
+++ b/cmds/pm/src/com/android/commands/pm/Pm.java
@@ -18,6 +18,7 @@
 
 import android.app.ActivityManager;
 import android.app.ActivityManagerNative;
+import android.app.IActivityManager;
 import android.content.ComponentName;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.ContainerEncryptionParams;
@@ -1089,13 +1090,16 @@
 
     public void runListUsers() {
         try {
+            IActivityManager am = ActivityManagerNative.getDefault();
+
             List<UserInfo> users = mUm.getUsers(false);
             if (users == null) {
                 System.err.println("Error: couldn't get users");
             } else {
                 System.out.println("Users:");
                 for (int i = 0; i < users.size(); i++) {
-                    System.out.println("\t" + users.get(i).toString());
+                    String running = am.isUserRunning(users.get(i).id, false) ? " running" : "";
+                    System.out.println("\t" + users.get(i).toString() + running);
                 }
             }
         } catch (RemoteException e) {
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index b067cd0..cd1fbf6f 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -1680,12 +1680,31 @@
         }
 
         /**
-         * Add metadata to this notification.
+         * Merge additional metadata into this notification.
          *
-         * A reference to the Bundle is held for the lifetime of this Builder, and the Bundle's
+         * <p>Values within the Bundle will replace existing extras values in this Builder.
+         *
+         * @see Notification#extras
+         */
+        public Builder addExtras(Bundle bag) {
+            if (mExtras == null) {
+                mExtras = new Bundle(bag);
+            } else {
+                mExtras.putAll(bag);
+            }
+            return this;
+        }
+
+        /**
+         * Set metadata for this notification.
+         *
+         * <p>A reference to the Bundle is held for the lifetime of this Builder, and the Bundle's
          * current contents are copied into the Notification each time {@link #build()} is
          * called.
          *
+         * <p>Replaces any existing extras values with those from the provided Bundle.
+         * Use {@link #addExtras} to merge in metadata instead.
+         *
          * @see Notification#extras
          */
         public Builder setExtras(Bundle bag) {
@@ -1694,6 +1713,23 @@
         }
 
         /**
+         * Get the current metadata Bundle used by this notification Builder.
+         *
+         * <p>The returned Bundle is shared with this Builder.
+         *
+         * <p>The current contents of this Bundle are copied into the Notification each time
+         * {@link #build()} is called.
+         *
+         * @see Notification#extras
+         */
+        public Bundle getExtras() {
+            if (mExtras == null) {
+                mExtras = new Bundle();
+            }
+            return mExtras;
+        }
+
+        /**
          * Add an action to this notification. Actions are typically displayed by
          * the system as a button adjacent to the notification content.
          * <p>
@@ -1989,7 +2025,7 @@
          * this Notification object.
          * @hide
          */
-        public void addExtras(Bundle extras) {
+        public void populateExtras(Bundle extras) {
             // Store original information used in the construction of this object
             extras.putCharSequence(EXTRA_TITLE, mContentTitle);
             extras.putCharSequence(EXTRA_TEXT, mContentText);
@@ -2027,7 +2063,7 @@
 
             n.extras = mExtras != null ? new Bundle(mExtras) : new Bundle();
 
-            addExtras(n.extras);
+            populateExtras(n.extras);
             if (mStyle != null) {
                 mStyle.addExtras(n.extras);
             }
diff --git a/core/java/android/nfc/tech/Ndef.java b/core/java/android/nfc/tech/Ndef.java
index 8240ea6..5852ce4 100644
--- a/core/java/android/nfc/tech/Ndef.java
+++ b/core/java/android/nfc/tech/Ndef.java
@@ -277,6 +277,8 @@
                     throw new TagLostException();
                 }
                 return msg;
+            } else if (!tagService.isPresent(serviceHandle)) {
+                throw new TagLostException();
             } else {
                 return null;
             }
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index a965e00..cc4bb51 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -217,11 +217,11 @@
          * Returns the total time in microseconds associated with this Timer for the
          * selected type of statistics.
          *
-         * @param batteryRealtime system realtime on  battery in microseconds
+         * @param elapsedRealtimeUs current elapsed realtime of system in microseconds
          * @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT
          * @return a time in microseconds
          */
-        public abstract long getTotalTimeLocked(long batteryRealtime, int which);
+        public abstract long getTotalTimeLocked(long elapsedRealtimeUs, int which);
 
         /**
          * Temporary for debugging.
@@ -295,14 +295,13 @@
         public abstract void noteVideoTurnedOffLocked(long elapsedRealtime);
         public abstract void noteActivityResumedLocked(long elapsedRealtime);
         public abstract void noteActivityPausedLocked(long elapsedRealtime);
-        public abstract long getWifiRunningTime(long batteryRealtime, int which);
-        public abstract long getFullWifiLockTime(long batteryRealtime, int which);
-        public abstract long getWifiScanTime(long batteryRealtime, int which);
-        public abstract long getWifiBatchedScanTime(int csphBin, long batteryRealtime, int which);
-        public abstract long getWifiMulticastTime(long batteryRealtime,
-                                                  int which);
-        public abstract long getAudioTurnedOnTime(long batteryRealtime, int which);
-        public abstract long getVideoTurnedOnTime(long batteryRealtime, int which);
+        public abstract long getWifiRunningTime(long elapsedRealtimeUs, int which);
+        public abstract long getFullWifiLockTime(long elapsedRealtimeUs, int which);
+        public abstract long getWifiScanTime(long elapsedRealtimeUs, int which);
+        public abstract long getWifiBatchedScanTime(int csphBin, long elapsedRealtimeUs, int which);
+        public abstract long getWifiMulticastTime(long elapsedRealtimeUs, int which);
+        public abstract long getAudioTurnedOnTime(long elapsedRealtimeUs, int which);
+        public abstract long getVideoTurnedOnTime(long elapsedRealtimeUs, int which);
         public abstract Timer getForegroundActivityTimer();
         public abstract Timer getVibratorOnTimer();
 
@@ -831,7 +830,7 @@
      * 
      * {@hide}
      */
-    public abstract long getScreenOnTime(long batteryRealtime, int which);
+    public abstract long getScreenOnTime(long elapsedRealtimeUs, int which);
     
     /**
      * Returns the number of times the screen was turned on.
@@ -863,7 +862,7 @@
      * {@hide}
      */
     public abstract long getScreenBrightnessTime(int brightnessBin,
-            long batteryRealtime, int which);
+            long elapsedRealtimeUs, int which);
 
     public abstract int getInputEventCount(int which);
     
@@ -873,7 +872,7 @@
      * 
      * {@hide}
      */
-    public abstract long getPhoneOnTime(long batteryRealtime, int which);
+    public abstract long getPhoneOnTime(long elapsedRealtimeUs, int which);
     
     /**
      * Returns the number of times a phone call was activated.
@@ -889,7 +888,7 @@
      * {@hide}
      */
     public abstract long getPhoneSignalStrengthTime(int strengthBin,
-            long batteryRealtime, int which);
+            long elapsedRealtimeUs, int which);
 
     /**
      * Returns the time in microseconds that the phone has been trying to
@@ -898,7 +897,7 @@
      * {@hide}
      */
     public abstract long getPhoneSignalScanningTime(
-            long batteryRealtime, int which);
+            long elapsedRealtimeUs, int which);
 
     /**
      * Returns the number of times the phone has entered the given signal strength.
@@ -913,7 +912,7 @@
      *
      * {@hide}
      */
-    public abstract long getMobileRadioActiveTime(long batteryRealtime, int which);
+    public abstract long getMobileRadioActiveTime(long elapsedRealtimeUs, int which);
 
     /**
      * Returns the number of times that the mobile network has transitioned to the
@@ -971,7 +970,7 @@
      * {@hide}
      */
     public abstract long getPhoneDataConnectionTime(int dataType,
-            long batteryRealtime, int which);
+            long elapsedRealtimeUs, int which);
 
     /**
      * Returns the number of times the phone has entered the given data
@@ -1030,7 +1029,7 @@
      * 
      * {@hide}
      */
-    public abstract long getWifiOnTime(long batteryRealtime, int which);
+    public abstract long getWifiOnTime(long elapsedRealtimeUs, int which);
 
     /**
      * Returns the time in microseconds that wifi has been on and the driver has
@@ -1038,7 +1037,7 @@
      *
      * {@hide}
      */
-    public abstract long getGlobalWifiRunningTime(long batteryRealtime, int which);
+    public abstract long getGlobalWifiRunningTime(long elapsedRealtimeUs, int which);
 
     public static final int WIFI_STATE_OFF = 0;
     public static final int WIFI_STATE_OFF_SCANNING = 1;
@@ -1062,7 +1061,7 @@
      * {@hide}
      */
     public abstract long getWifiStateTime(int wifiState,
-            long batteryRealtime, int which);
+            long elapsedRealtimeUs, int which);
 
     /**
      * Returns the number of times that WiFi has entered the given state.
@@ -1077,7 +1076,7 @@
      * 
      * {@hide}
      */
-    public abstract long getBluetoothOnTime(long batteryRealtime, int which);
+    public abstract long getBluetoothOnTime(long elapsedRealtimeUs, int which);
     
     public abstract int getBluetoothPingCount();
 
@@ -1099,7 +1098,7 @@
      * {@hide}
      */
     public abstract long getBluetoothStateTime(int bluetoothState,
-            long batteryRealtime, int which);
+            long elapsedRealtimeUs, int which);
 
     /**
      * Returns the number of times that Bluetooth has entered the given active state.
@@ -1212,6 +1211,22 @@
     public abstract long computeBatteryRealtime(long curTime, int which);
 
     /**
+     * Returns the total, last, or current battery screen off uptime in microseconds.
+     *
+     * @param curTime the elapsed realtime in microseconds.
+     * @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT.
+     */
+    public abstract long computeBatteryScreenOffUptime(long curTime, int which);
+
+    /**
+     * Returns the total, last, or current battery screen off realtime in microseconds.
+     *
+     * @param curTime the current elapsed realtime in microseconds.
+     * @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT.
+     */
+    public abstract long computeBatteryScreenOffRealtime(long curTime, int which);
+
+    /**
      * Returns the total, last, or current uptime in microseconds.
      *
      * @param curTime the current elapsed realtime in microseconds.
@@ -1262,28 +1277,28 @@
         }
     }
 
-    private final static void formatTime(StringBuilder sb, long time) {
+    public final static void formatTime(StringBuilder sb, long time) {
         long sec = time / 100;
         formatTimeRaw(sb, sec);
         sb.append((time - (sec * 100)) * 10);
         sb.append("ms ");
     }
 
-    private final static void formatTimeMs(StringBuilder sb, long time) {
+    public final static void formatTimeMs(StringBuilder sb, long time) {
         long sec = time / 1000;
         formatTimeRaw(sb, sec);
         sb.append(time - (sec * 1000));
         sb.append("ms ");
     }
 
-    private final static void formatTimeMsNoSpace(StringBuilder sb, long time) {
+    public final static void formatTimeMsNoSpace(StringBuilder sb, long time) {
         long sec = time / 1000;
         formatTimeRaw(sb, sec);
         sb.append(time - (sec * 1000));
         sb.append("ms");
     }
 
-    private final String formatRatioLocked(long num, long den) {
+    public final String formatRatioLocked(long num, long den) {
         if (den == 0L) {
             return "--%";
         }
@@ -1293,7 +1308,7 @@
         return mFormatBuilder.toString();
     }
 
-    private final String formatBytesLocked(long bytes) {
+    final String formatBytesLocked(long bytes) {
         mFormatBuilder.setLength(0);
         
         if (bytes < BYTES_PER_KB) {
@@ -1310,10 +1325,10 @@
         }
     }
 
-    private static long computeWakeLock(Timer timer, long batteryRealtime, int which) {
+    private static long computeWakeLock(Timer timer, long elapsedRealtimeUs, int which) {
         if (timer != null) {
             // Convert from microseconds to milliseconds with rounding
-            long totalTimeMicros = timer.getTotalTimeLocked(batteryRealtime, which);
+            long totalTimeMicros = timer.getTotalTimeLocked(elapsedRealtimeUs, which);
             long totalTimeMillis = (totalTimeMicros + 500) / 1000;
             return totalTimeMillis;
         }
@@ -1324,17 +1339,17 @@
      *
      * @param sb a StringBuilder object.
      * @param timer a Timer object contining the wakelock times.
-     * @param batteryRealtime the current on-battery time in microseconds.
+     * @param elapsedRealtimeUs the current on-battery time in microseconds.
      * @param name the name of the wakelock.
      * @param which which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT.
      * @param linePrefix a String to be prepended to each line of output.
      * @return the line prefix
      */
     private static final String printWakeLock(StringBuilder sb, Timer timer,
-            long batteryRealtime, String name, int which, String linePrefix) {
+            long elapsedRealtimeUs, String name, int which, String linePrefix) {
         
         if (timer != null) {
-            long totalTimeMillis = computeWakeLock(timer, batteryRealtime, which);
+            long totalTimeMillis = computeWakeLock(timer, elapsedRealtimeUs, which);
             
             int count = timer.getCountLocked(which);
             if (totalTimeMillis != 0) {
@@ -1358,18 +1373,18 @@
      * 
      * @param sb a StringBuilder object.
      * @param timer a Timer object contining the wakelock times.
-     * @param now the current time in microseconds.
+     * @param elapsedRealtimeUs the current time in microseconds.
      * @param name the name of the wakelock.
      * @param which which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT.
      * @param linePrefix a String to be prepended to each line of output.
      * @return the line prefix
      */
-    private static final String printWakeLockCheckin(StringBuilder sb, Timer timer, long now,
-            String name, int which, String linePrefix) {
+    private static final String printWakeLockCheckin(StringBuilder sb, Timer timer,
+            long elapsedRealtimeUs, String name, int which, String linePrefix) {
         long totalTimeMicros = 0;
         int count = 0;
         if (timer != null) {
-            totalTimeMicros = timer.getTotalTimeLocked(now, which);
+            totalTimeMicros = timer.getTotalTimeLocked(elapsedRealtimeUs, which);
             count = timer.getCountLocked(which); 
         }
         sb.append(linePrefix);
@@ -1411,16 +1426,18 @@
         final long rawUptime = SystemClock.uptimeMillis() * 1000;
         final long rawRealtime = SystemClock.elapsedRealtime() * 1000;
         final long batteryUptime = getBatteryUptime(rawUptime);
-        final long batteryRealtime = getBatteryRealtime(rawRealtime);
         final long whichBatteryUptime = computeBatteryUptime(rawUptime, which);
         final long whichBatteryRealtime = computeBatteryRealtime(rawRealtime, which);
+        final long whichBatteryScreenOffUptime = computeBatteryScreenOffUptime(rawUptime, which);
+        final long whichBatteryScreenOffRealtime = computeBatteryScreenOffRealtime(rawRealtime,
+                which);
         final long totalRealtime = computeRealtime(rawRealtime, which);
         final long totalUptime = computeUptime(rawUptime, which);
-        final long screenOnTime = getScreenOnTime(batteryRealtime, which);
-        final long phoneOnTime = getPhoneOnTime(batteryRealtime, which);
-        final long wifiOnTime = getWifiOnTime(batteryRealtime, which);
-        final long wifiRunningTime = getGlobalWifiRunningTime(batteryRealtime, which);
-        final long bluetoothOnTime = getBluetoothOnTime(batteryRealtime, which);
+        final long screenOnTime = getScreenOnTime(rawRealtime, which);
+        final long phoneOnTime = getPhoneOnTime(rawRealtime, which);
+        final long wifiOnTime = getWifiOnTime(rawRealtime, which);
+        final long wifiRunningTime = getGlobalWifiRunningTime(rawRealtime, which);
+        final long bluetoothOnTime = getBluetoothOnTime(rawRealtime, which);
        
         StringBuilder sb = new StringBuilder(128);
         
@@ -1434,7 +1451,8 @@
                 which == STATS_SINCE_CHARGED ? getStartCount() : "N/A",
                 whichBatteryRealtime / 1000, whichBatteryUptime / 1000,
                 totalRealtime / 1000, totalUptime / 1000,
-                getStartClockTime());
+                getStartClockTime(),
+                whichBatteryScreenOffRealtime / 1000, whichBatteryScreenOffUptime / 1000);
         
         // Calculate wakelock times across all uids.
         long fullWakeLockTimeTotal = 0;
@@ -1451,13 +1469,14 @@
                     
                     Timer fullWakeTimer = wl.getWakeTime(WAKE_TYPE_FULL);
                     if (fullWakeTimer != null) {
-                        fullWakeLockTimeTotal += fullWakeTimer.getTotalTimeLocked(batteryRealtime, which);
+                        fullWakeLockTimeTotal += fullWakeTimer.getTotalTimeLocked(rawRealtime,
+                                which);
                     }
 
                     Timer partialWakeTimer = wl.getWakeTime(WAKE_TYPE_PARTIAL);
                     if (partialWakeTimer != null) {
                         partialWakeLockTimeTotal += partialWakeTimer.getTotalTimeLocked(
-                            batteryRealtime, which);
+                            rawRealtime, which);
                     }
                 }
             }
@@ -1483,23 +1502,23 @@
                 wifiRunningTime / 1000, bluetoothOnTime / 1000,
                 mobileRxTotalBytes, mobileTxTotalBytes, wifiRxTotalBytes, wifiTxTotalBytes,
                 fullWakeLockTimeTotal, partialWakeLockTimeTotal,
-                getInputEventCount(which), getMobileRadioActiveTime(batteryRealtime, which));
+                getInputEventCount(which), getMobileRadioActiveTime(rawRealtime, 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;
+            args[i] = getScreenBrightnessTime(i, rawRealtime, which) / 1000;
         }
         dumpLine(pw, 0 /* uid */, category, SCREEN_BRIGHTNESS_DATA, args);
         
         // Dump signal strength stats
         args = new Object[SignalStrength.NUM_SIGNAL_STRENGTH_BINS];
         for (int i=0; i<SignalStrength.NUM_SIGNAL_STRENGTH_BINS; i++) {
-            args[i] = getPhoneSignalStrengthTime(i, batteryRealtime, which) / 1000;
+            args[i] = getPhoneSignalStrengthTime(i, rawRealtime, which) / 1000;
         }
         dumpLine(pw, 0 /* uid */, category, SIGNAL_STRENGTH_TIME_DATA, args);
         dumpLine(pw, 0 /* uid */, category, SIGNAL_SCANNING_TIME_DATA,
-                getPhoneSignalScanningTime(batteryRealtime, which) / 1000);
+                getPhoneSignalScanningTime(rawRealtime, which) / 1000);
         for (int i=0; i<SignalStrength.NUM_SIGNAL_STRENGTH_BINS; i++) {
             args[i] = getPhoneSignalStrengthCount(i, which);
         }
@@ -1508,7 +1527,7 @@
         // 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;
+            args[i] = getPhoneDataConnectionTime(i, rawRealtime, which) / 1000;
         }
         dumpLine(pw, 0 /* uid */, category, DATA_CONNECTION_TIME_DATA, args);
         for (int i=0; i<NUM_DATA_CONNECTION_TYPES; i++) {
@@ -1519,7 +1538,7 @@
         // Dump wifi state stats
         args = new Object[NUM_WIFI_STATES];
         for (int i=0; i<NUM_WIFI_STATES; i++) {
-            args[i] = getWifiStateTime(i, batteryRealtime, which) / 1000;
+            args[i] = getWifiStateTime(i, rawRealtime, which) / 1000;
         }
         dumpLine(pw, 0 /* uid */, category, WIFI_STATE_TIME_DATA, args);
         for (int i=0; i<NUM_WIFI_STATES; i++) {
@@ -1530,7 +1549,7 @@
         // Dump bluetooth state stats
         args = new Object[NUM_BLUETOOTH_STATES];
         for (int i=0; i<NUM_BLUETOOTH_STATES; i++) {
-            args[i] = getBluetoothStateTime(i, batteryRealtime, which) / 1000;
+            args[i] = getBluetoothStateTime(i, rawRealtime, which) / 1000;
         }
         dumpLine(pw, 0 /* uid */, category, BLUETOOTH_STATE_TIME_DATA, args);
         for (int i=0; i<NUM_BLUETOOTH_STATES; i++) {
@@ -1559,7 +1578,7 @@
             if (kernelWakelocks.size() > 0) {
                 for (Map.Entry<String, ? extends BatteryStats.Timer> ent : kernelWakelocks.entrySet()) {
                     sb.setLength(0);
-                    printWakeLockCheckin(sb, ent.getValue(), batteryRealtime, null, which, "");
+                    printWakeLockCheckin(sb, ent.getValue(), rawRealtime, null, which, "");
     
                     dumpLine(pw, 0 /* uid */, category, KERNEL_WAKELOCK_DATA, ent.getKey(), 
                             sb.toString());
@@ -1639,9 +1658,9 @@
             int mobileActiveCount = u.getMobileRadioActiveCount(which);
             long wifiPacketsRx = u.getNetworkActivityPackets(NETWORK_WIFI_RX_DATA, which);
             long wifiPacketsTx = u.getNetworkActivityPackets(NETWORK_WIFI_TX_DATA, which);
-            long fullWifiLockOnTime = u.getFullWifiLockTime(batteryRealtime, which);
-            long wifiScanTime = u.getWifiScanTime(batteryRealtime, which);
-            long uidWifiRunningTime = u.getWifiRunningTime(batteryRealtime, which);
+            long fullWifiLockOnTime = u.getFullWifiLockTime(rawRealtime, which);
+            long wifiScanTime = u.getWifiScanTime(rawRealtime, which);
+            long uidWifiRunningTime = u.getWifiRunningTime(rawRealtime, which);
 
             if (mobileBytesRx > 0 || mobileBytesTx > 0 || wifiBytesRx > 0 || wifiBytesTx > 0
                     || mobilePacketsRx > 0 || mobilePacketsTx > 0 || wifiPacketsRx > 0
@@ -1680,11 +1699,11 @@
                     String linePrefix = "";
                     sb.setLength(0);
                     linePrefix = printWakeLockCheckin(sb, wl.getWakeTime(WAKE_TYPE_FULL), 
-                            batteryRealtime, "f", which, linePrefix);
+                            rawRealtime, "f", which, linePrefix);
                     linePrefix = printWakeLockCheckin(sb, wl.getWakeTime(WAKE_TYPE_PARTIAL), 
-                            batteryRealtime, "p", which, linePrefix);
+                            rawRealtime, "p", which, linePrefix);
                     linePrefix = printWakeLockCheckin(sb, wl.getWakeTime(WAKE_TYPE_WINDOW), 
-                            batteryRealtime, "w", which, linePrefix);
+                            rawRealtime, "w", which, linePrefix);
                     
                     // Only log if we had at lease one wakelock...
                     if (sb.length() > 0) {
@@ -1706,7 +1725,7 @@
                     Timer timer = se.getSensorTime();
                     if (timer != null) {
                         // Convert from microseconds to milliseconds with rounding
-                        long totalTime = (timer.getTotalTimeLocked(batteryRealtime, which) + 500) / 1000;
+                        long totalTime = (timer.getTotalTimeLocked(rawRealtime, which) + 500) / 1000;
                         int count = timer.getCountLocked(which);
                         if (totalTime != 0) {
                             dumpLine(pw, uid, category, SENSOR_DATA, sensorNumber, totalTime, count);
@@ -1718,7 +1737,7 @@
             Timer vibTimer = u.getVibratorOnTimer();
             if (vibTimer != null) {
                 // Convert from microseconds to milliseconds with rounding
-                long totalTime = (vibTimer.getTotalTimeLocked(batteryRealtime, which) + 500) / 1000;
+                long totalTime = (vibTimer.getTotalTimeLocked(rawRealtime, which) + 500) / 1000;
                 int count = vibTimer.getCountLocked(which);
                 if (totalTime != 0) {
                     dumpLine(pw, uid, category, VIBRATOR_DATA, totalTime, count);
@@ -1728,7 +1747,7 @@
             Timer fgTimer = u.getForegroundActivityTimer();
             if (fgTimer != null) {
                 // Convert from microseconds to milliseconds with rounding
-                long totalTime = (fgTimer.getTotalTimeLocked(batteryRealtime, which) + 500) / 1000;
+                long totalTime = (fgTimer.getTotalTimeLocked(rawRealtime, which) + 500) / 1000;
                 int count = fgTimer.getCountLocked(which);
                 if (totalTime != 0) {
                     dumpLine(pw, uid, category, FOREGROUND_DATA, totalTime, count);
@@ -1806,13 +1825,15 @@
         final long rawUptime = SystemClock.uptimeMillis() * 1000;
         final long rawRealtime = SystemClock.elapsedRealtime() * 1000;
         final long batteryUptime = getBatteryUptime(rawUptime);
-        final long batteryRealtime = getBatteryRealtime(rawRealtime);
 
         final long whichBatteryUptime = computeBatteryUptime(rawUptime, which);
         final long whichBatteryRealtime = computeBatteryRealtime(rawRealtime, which);
         final long totalRealtime = computeRealtime(rawRealtime, which);
         final long totalUptime = computeUptime(rawUptime, which);
-        
+        final long whichBatteryScreenOffUptime = computeBatteryScreenOffUptime(rawUptime, which);
+        final long whichBatteryScreenOffRealtime = computeBatteryScreenOffRealtime(rawRealtime,
+                which);
+
         StringBuilder sb = new StringBuilder(128);
         
         SparseArray<? extends Uid> uidStats = getUidStats();
@@ -1830,6 +1851,17 @@
         pw.println(sb.toString());
         sb.setLength(0);
         sb.append(prefix);
+                sb.append("  Time on battery screen off: ");
+                formatTimeMs(sb, whichBatteryScreenOffRealtime / 1000); sb.append("(");
+                sb.append(formatRatioLocked(whichBatteryScreenOffRealtime, totalRealtime));
+                sb.append(") realtime, ");
+                formatTimeMs(sb, whichBatteryScreenOffUptime / 1000);
+                sb.append("(");
+                sb.append(formatRatioLocked(whichBatteryScreenOffUptime, totalRealtime));
+                sb.append(") uptime");
+        pw.println(sb.toString());
+        sb.setLength(0);
+        sb.append(prefix);
                 sb.append("  Total run time: ");
                 formatTimeMs(sb, totalRealtime / 1000);
                 sb.append("realtime, ");
@@ -1839,11 +1871,11 @@
         pw.print("  Start clock time: ");
         pw.println(DateFormat.format("yyyy-MM-dd-HH-mm-ss", getStartClockTime()).toString());
 
-        final long screenOnTime = getScreenOnTime(batteryRealtime, which);
-        final long phoneOnTime = getPhoneOnTime(batteryRealtime, which);
-        final long wifiRunningTime = getGlobalWifiRunningTime(batteryRealtime, which);
-        final long wifiOnTime = getWifiOnTime(batteryRealtime, which);
-        final long bluetoothOnTime = getBluetoothOnTime(batteryRealtime, which);
+        final long screenOnTime = getScreenOnTime(rawRealtime, which);
+        final long phoneOnTime = getPhoneOnTime(rawRealtime, which);
+        final long wifiRunningTime = getGlobalWifiRunningTime(rawRealtime, which);
+        final long wifiOnTime = getWifiOnTime(rawRealtime, which);
+        final long bluetoothOnTime = getBluetoothOnTime(rawRealtime, which);
         sb.setLength(0);
         sb.append(prefix);
                 sb.append("  Screen on: "); formatTimeMs(sb, screenOnTime / 1000);
@@ -1863,7 +1895,7 @@
         sb.append("  Screen brightnesses:");
         boolean didOne = false;
         for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
-            final long time = getScreenBrightnessTime(i, batteryRealtime, which);
+            final long time = getScreenBrightnessTime(i, rawRealtime, which);
             if (time == 0) {
                 continue;
             }
@@ -1905,7 +1937,7 @@
                 final ArrayList<TimerEntry> timers = new ArrayList<TimerEntry>();
                 for (Map.Entry<String, ? extends BatteryStats.Timer> ent : kernelWakelocks.entrySet()) {
                     BatteryStats.Timer timer = ent.getValue();
-                    long totalTimeMillis = computeWakeLock(timer, batteryRealtime, which);
+                    long totalTimeMillis = computeWakeLock(timer, rawRealtime, which);
                     if (totalTimeMillis > 0) {
                         timers.add(new TimerEntry(ent.getKey(), 0, timer, totalTimeMillis));
                     }
@@ -1918,7 +1950,7 @@
                     sb.append(prefix);
                     sb.append("  Kernel Wake lock ");
                     sb.append(timer.mName);
-                    linePrefix = printWakeLock(sb, timer.mTimer, batteryRealtime, null,
+                    linePrefix = printWakeLock(sb, timer.mTimer, rawRealtime, null,
                             which, linePrefix);
                     if (!linePrefix.equals(": ")) {
                         sb.append(" realtime");
@@ -1943,13 +1975,13 @@
                     Timer fullWakeTimer = wl.getWakeTime(WAKE_TYPE_FULL);
                     if (fullWakeTimer != null) {
                         fullWakeLockTimeTotalMicros += fullWakeTimer.getTotalTimeLocked(
-                                batteryRealtime, which);
+                                rawRealtime, which);
                     }
 
                     Timer partialWakeTimer = wl.getWakeTime(WAKE_TYPE_PARTIAL);
                     if (partialWakeTimer != null) {
                         long totalTimeMicros = partialWakeTimer.getTotalTimeLocked(
-                                batteryRealtime, which);
+                                rawRealtime, which);
                         if (totalTimeMicros > 0) {
                             if (reqUid < 0) {
                                 // Only show the ordered list of all wake
@@ -2000,7 +2032,7 @@
         sb.append("  Signal levels:");
         didOne = false;
         for (int i=0; i<SignalStrength.NUM_SIGNAL_STRENGTH_BINS; i++) {
-            final long time = getPhoneSignalStrengthTime(i, batteryRealtime, which);
+            final long time = getPhoneSignalStrengthTime(i, rawRealtime, which);
             if (time == 0) {
                 continue;
             }
@@ -2022,7 +2054,7 @@
         sb.setLength(0);
         sb.append(prefix);
         sb.append("  Signal scanning time: ");
-        formatTimeMsNoSpace(sb, getPhoneSignalScanningTime(batteryRealtime, which) / 1000);
+        formatTimeMsNoSpace(sb, getPhoneSignalScanningTime(rawRealtime, which) / 1000);
         pw.println(sb.toString());
 
         sb.setLength(0);
@@ -2030,7 +2062,7 @@
         sb.append("  Radio types:");
         didOne = false;
         for (int i=0; i<NUM_DATA_CONNECTION_TYPES; i++) {
-            final long time = getPhoneDataConnectionTime(i, batteryRealtime, which);
+            final long time = getPhoneDataConnectionTime(i, rawRealtime, which);
             if (time == 0) {
                 continue;
             }
@@ -2052,7 +2084,7 @@
         sb.setLength(0);
         sb.append(prefix);
         sb.append("  Mobile radio active time: ");
-        final long mobileActiveTime = getMobileRadioActiveTime(batteryRealtime, which);
+        final long mobileActiveTime = getMobileRadioActiveTime(rawRealtime, which);
         formatTimeMs(sb, mobileActiveTime / 1000);
         sb.append("("); sb.append(formatRatioLocked(mobileActiveTime, whichBatteryRealtime));
         sb.append(") "); sb.append(getMobileRadioActiveCount(which));
@@ -2091,7 +2123,7 @@
         sb.append("  Wifi states:");
         didOne = false;
         for (int i=0; i<NUM_WIFI_STATES; i++) {
-            final long time = getWifiStateTime(i, batteryRealtime, which);
+            final long time = getWifiStateTime(i, rawRealtime, which);
             if (time == 0) {
                 continue;
             }
@@ -2121,7 +2153,7 @@
         sb.append("  Bluetooth states:");
         didOne = false;
         for (int i=0; i<NUM_BLUETOOTH_STATES; i++) {
-            final long time = getBluetoothStateTime(i, batteryRealtime, which);
+            final long time = getBluetoothStateTime(i, rawRealtime, which);
             if (time == 0) {
                 continue;
             }
@@ -2270,7 +2302,7 @@
                 UserHandle.formatUid(sb, timer.mId);
                 sb.append(" ");
                 sb.append(timer.mName);
-                printWakeLock(sb, timer.mTimer, batteryRealtime, null, which, ": ");
+                printWakeLock(sb, timer.mTimer, rawRealtime, null, which, ": ");
                 sb.append(" realtime");
                 pw.println(sb.toString());
             }
@@ -2302,9 +2334,9 @@
             int uidMobileActiveCount = u.getMobileRadioActiveCount(which);
             long wifiRxPackets = u.getNetworkActivityPackets(NETWORK_WIFI_RX_DATA, which);
             long wifiTxPackets = u.getNetworkActivityPackets(NETWORK_WIFI_TX_DATA, which);
-            long fullWifiLockOnTime = u.getFullWifiLockTime(batteryRealtime, which);
-            long wifiScanTime = u.getWifiScanTime(batteryRealtime, which);
-            long uidWifiRunningTime = u.getWifiRunningTime(batteryRealtime, which);
+            long fullWifiLockOnTime = u.getFullWifiLockTime(rawRealtime, which);
+            long wifiScanTime = u.getWifiScanTime(rawRealtime, which);
+            long uidWifiRunningTime = u.getWifiRunningTime(rawRealtime, which);
 
             if (mobileRxBytes > 0 || mobileTxBytes > 0
                     || mobileRxPackets > 0 || mobileTxPackets > 0) {
@@ -2391,11 +2423,11 @@
                     sb.append(prefix);
                     sb.append("    Wake lock ");
                     sb.append(ent.getKey());
-                    linePrefix = printWakeLock(sb, wl.getWakeTime(WAKE_TYPE_FULL), batteryRealtime,
+                    linePrefix = printWakeLock(sb, wl.getWakeTime(WAKE_TYPE_FULL), rawRealtime,
                             "full", which, linePrefix);
-                    linePrefix = printWakeLock(sb, wl.getWakeTime(WAKE_TYPE_PARTIAL), batteryRealtime,
+                    linePrefix = printWakeLock(sb, wl.getWakeTime(WAKE_TYPE_PARTIAL), rawRealtime,
                             "partial", which, linePrefix);
-                    linePrefix = printWakeLock(sb, wl.getWakeTime(WAKE_TYPE_WINDOW), batteryRealtime,
+                    linePrefix = printWakeLock(sb, wl.getWakeTime(WAKE_TYPE_WINDOW), rawRealtime,
                             "window", which, linePrefix);
                     if (!linePrefix.equals(": ")) {
                         sb.append(" realtime");
@@ -2405,11 +2437,11 @@
                         count++;
                     }
                     totalFull += computeWakeLock(wl.getWakeTime(WAKE_TYPE_FULL),
-                            batteryRealtime, which);
+                            rawRealtime, which);
                     totalPartial += computeWakeLock(wl.getWakeTime(WAKE_TYPE_PARTIAL),
-                            batteryRealtime, which);
+                            rawRealtime, which);
                     totalWindow += computeWakeLock(wl.getWakeTime(WAKE_TYPE_WINDOW),
-                            batteryRealtime, which);
+                            rawRealtime, which);
                 }
                 if (count > 1) {
                     if (totalFull != 0 || totalPartial != 0 || totalWindow != 0) {
@@ -2465,7 +2497,7 @@
                     if (timer != null) {
                         // Convert from microseconds to milliseconds with rounding
                         long totalTime = (timer.getTotalTimeLocked(
-                                batteryRealtime, which) + 500) / 1000;
+                                rawRealtime, which) + 500) / 1000;
                         int count = timer.getCountLocked(which);
                         //timer.logState();
                         if (totalTime != 0) {
@@ -2489,7 +2521,7 @@
             if (vibTimer != null) {
                 // Convert from microseconds to milliseconds with rounding
                 long totalTime = (vibTimer.getTotalTimeLocked(
-                        batteryRealtime, which) + 500) / 1000;
+                        rawRealtime, which) + 500) / 1000;
                 int count = vibTimer.getCountLocked(which);
                 //timer.logState();
                 if (totalTime != 0) {
@@ -2508,7 +2540,7 @@
             Timer fgTimer = u.getForegroundActivityTimer();
             if (fgTimer != null) {
                 // Convert from microseconds to milliseconds with rounding
-                long totalTime = (fgTimer.getTotalTimeLocked(batteryRealtime, which) + 500) / 1000;
+                long totalTime = (fgTimer.getTotalTimeLocked(rawRealtime, which) + 500) / 1000;
                 int count = fgTimer.getCountLocked(which);
                 if (totalTime != 0) {
                     sb.setLength(0);
diff --git a/core/java/android/view/DisplayList.java b/core/java/android/view/DisplayList.java
index 3060e6e..0ae36c1 100644
--- a/core/java/android/view/DisplayList.java
+++ b/core/java/android/view/DisplayList.java
@@ -239,16 +239,6 @@
     }
 
     /**
-    * After calling this method {@link #isValid()} will return false.
-    * TODO: Have Editor stop using this
-    *
-    * @see #isValid()
-    */
-    public void markInvalid() {
-        mValid = false;
-    }
-
-    /**
      * Reset native resources. This is called when cleaning up the state of display lists
      * during destruction of hardware resources, to ensure that we do not hold onto
      * obsolete resources after related resources are gone.
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index cf5e8cf..9c50323 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -515,7 +515,8 @@
 
     private void initFromAttributes(
             Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
-        final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ViewGroup);
+        final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ViewGroup, defStyleAttr,
+                defStyleRes);
 
         final int N = a.getIndexCount();
         for (int i = 0; i < N; i++) {
@@ -2637,6 +2638,7 @@
         for (int i = 0; i < count; i++) {
             children[i].dispatchDetachedFromWindow();
         }
+        clearDisappearingChildren();
         super.dispatchDetachedFromWindow();
     }
 
@@ -5304,8 +5306,17 @@
      * this if you don't want animations for exiting views to stack up.
      */
     public void clearDisappearingChildren() {
-        if (mDisappearingChildren != null) {
-            mDisappearingChildren.clear();
+        final ArrayList<View> disappearingChildren = mDisappearingChildren;
+        if (disappearingChildren != null) {
+            final int count = disappearingChildren.size();
+            for (int i = 0; i < count; i++) {
+                final View view = disappearingChildren.get(i);
+                if (view.mAttachInfo != null) {
+                    view.dispatchDetachedFromWindow();
+                }
+                view.clearAnimation();
+            }
+            disappearingChildren.clear();
             invalidate();
         }
     }
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 3af1c4f..18517c5 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -2901,7 +2901,7 @@
             }
         }
     }
-
+    
     /**
      * Return true if child is an ancestor of parent, (or equal to the parent).
      */
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index 84c1586..98b43b3 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -137,7 +137,16 @@
     InputContentType mInputContentType;
     InputMethodState mInputMethodState;
 
-    DisplayList[] mTextDisplayLists;
+    private static class TextDisplayList {
+        DisplayList displayList;
+        boolean isDirty;
+        public TextDisplayList(String name) {
+            isDirty = true;
+            displayList = DisplayList.create(name);
+        }
+        boolean needsRecord() { return isDirty || !displayList.isValid(); }
+    }
+    TextDisplayList[] mTextDisplayLists;
 
     boolean mFrozenWithFocus;
     boolean mSelectionMoved;
@@ -262,7 +271,7 @@
             mTextView.removeCallbacks(mShowSuggestionRunnable);
         }
 
-        invalidateTextDisplayList();
+        destroyDisplayListsData();
 
         if (mSpellChecker != null) {
             mSpellChecker.closeSession();
@@ -277,6 +286,19 @@
         mTemporaryDetach = false;
     }
 
+    private void destroyDisplayListsData() {
+        HardwareRenderer renderer = mTextView.getHardwareRenderer();
+        if (mTextDisplayLists != null) {
+            for (int i = 0; i < mTextDisplayLists.length; i++) {
+                DisplayList displayList = mTextDisplayLists[i] != null
+                        ? mTextDisplayLists[i].displayList : null;
+                if (displayList != null && displayList.isValid()) {
+                    displayList.destroyDisplayListData(renderer);
+                }
+            }
+        }
+    }
+
     private void showError() {
         if (mTextView.getWindowToken() == null) {
             mShowErrorAfterAttach = true;
@@ -1320,7 +1342,7 @@
 
         if (layout instanceof DynamicLayout) {
             if (mTextDisplayLists == null) {
-                mTextDisplayLists = new DisplayList[ArrayUtils.idealObjectArraySize(0)];
+                mTextDisplayLists = new TextDisplayList[ArrayUtils.idealObjectArraySize(0)];
             }
 
             DynamicLayout dynamicLayout = (DynamicLayout) layout;
@@ -1344,13 +1366,13 @@
                     searchStartIndex = blockIndex + 1;
                 }
 
-                DisplayList blockDisplayList = mTextDisplayLists[blockIndex];
-                if (blockDisplayList == null) {
-                    blockDisplayList = mTextDisplayLists[blockIndex] =
-                            DisplayList.create("Text " + blockIndex);
+                if (mTextDisplayLists[blockIndex] == null) {
+                    mTextDisplayLists[blockIndex] =
+                            new TextDisplayList("Text " + blockIndex);
                 }
 
-                final boolean blockDisplayListIsInvalid = !blockDisplayList.isValid();
+                final boolean blockDisplayListIsInvalid = mTextDisplayLists[blockIndex].needsRecord();
+                DisplayList blockDisplayList = mTextDisplayLists[blockIndex].displayList;
                 if (i >= indexFirstChangedBlock || blockDisplayListIsInvalid) {
                     final int blockBeginLine = endOfPreviousBlock + 1;
                     final int top = layout.getLineTop(blockBeginLine);
@@ -1421,7 +1443,7 @@
 
         // No available index found, the pool has to grow
         int newSize = ArrayUtils.idealIntArraySize(length + 1);
-        DisplayList[] displayLists = new DisplayList[newSize];
+        TextDisplayList[] displayLists = new TextDisplayList[newSize];
         System.arraycopy(mTextDisplayLists, 0, displayLists, 0, length);
         mTextDisplayLists = displayLists;
         return length;
@@ -1460,7 +1482,7 @@
             while (i < numberOfBlocks) {
                 final int blockIndex = blockIndices[i];
                 if (blockIndex != DynamicLayout.INVALID_BLOCK_INDEX) {
-                    mTextDisplayLists[blockIndex].markInvalid();
+                    mTextDisplayLists[blockIndex].isDirty = true;
                 }
                 if (blockEndLines[i] >= lastLine) break;
                 i++;
@@ -1471,7 +1493,7 @@
     void invalidateTextDisplayList() {
         if (mTextDisplayLists != null) {
             for (int i = 0; i < mTextDisplayLists.length; i++) {
-                if (mTextDisplayLists[i] != null) mTextDisplayLists[i].markInvalid();
+                if (mTextDisplayLists[i] != null) mTextDisplayLists[i].isDirty = true;
             }
         }
     }
diff --git a/core/java/android/widget/NumberPicker.java b/core/java/android/widget/NumberPicker.java
index 44c4987..00b2c13 100644
--- a/core/java/android/widget/NumberPicker.java
+++ b/core/java/android/widget/NumberPicker.java
@@ -430,12 +430,12 @@
      * Flag whether to ignore move events - we ignore such when we show in IME
      * to prevent the content from scrolling.
      */
-    private boolean mIngonreMoveEvents;
+    private boolean mIgnoreMoveEvents;
 
     /**
-     * Flag whether to show soft input on tap.
+     * Flag whether to perform a click on tap.
      */
-    private boolean mShowSoftInputOnTap;
+    private boolean mPerformClickOnTap;
 
     /**
      * The top of the top selection divider.
@@ -834,8 +834,8 @@
                 mInputText.setVisibility(View.INVISIBLE);
                 mLastDownOrMoveEventY = mLastDownEventY = event.getY();
                 mLastDownEventTime = event.getEventTime();
-                mIngonreMoveEvents = false;
-                mShowSoftInputOnTap = false;
+                mIgnoreMoveEvents = false;
+                mPerformClickOnTap = false;
                 // Handle pressed state before any state change.
                 if (mLastDownEventY < mTopSelectionDividerTop) {
                     if (mScrollState == OnScrollListener.SCROLL_STATE_IDLE) {
@@ -866,7 +866,7 @@
                     postChangeCurrentByOneFromLongPress(
                             true, ViewConfiguration.getLongPressTimeout());
                 } else {
-                    mShowSoftInputOnTap = true;
+                    mPerformClickOnTap = true;
                     postBeginSoftInputOnLongPressCommand();
                 }
                 return true;
@@ -887,7 +887,7 @@
         int action = event.getActionMasked();
         switch (action) {
             case MotionEvent.ACTION_MOVE: {
-                if (mIngonreMoveEvents) {
+                if (mIgnoreMoveEvents) {
                     break;
                 }
                 float currentMoveY = event.getY();
@@ -919,9 +919,9 @@
                     int deltaMoveY = (int) Math.abs(eventY - mLastDownEventY);
                     long deltaTime = event.getEventTime() - mLastDownEventTime;
                     if (deltaMoveY <= mTouchSlop && deltaTime < ViewConfiguration.getTapTimeout()) {
-                        if (mShowSoftInputOnTap) {
-                            mShowSoftInputOnTap = false;
-                            showSoftInput();
+                        if (mPerformClickOnTap) {
+                            mPerformClickOnTap = false;
+                            performClick();
                         } else {
                             int selectorIndexOffset = (eventY / mSelectorElementHeight)
                                     - SELECTOR_MIDDLE_ITEM_INDEX;
@@ -1214,6 +1214,27 @@
         setValueInternal(value, false);
     }
 
+    @Override
+    public boolean performClick() {
+        if (!mHasSelectorWheel) {
+            return super.performClick();
+        } else if (!super.performClick()) {
+            showSoftInput();
+        }
+        return true;
+    }
+
+    @Override
+    public boolean performLongClick() {
+        if (!mHasSelectorWheel) {
+            return super.performLongClick();
+        } else if (!super.performLongClick()) {
+            showSoftInput();
+            mIgnoreMoveEvents = true;
+        }
+        return true;
+    }
+
     /**
      * Shows the soft input for its input text.
      */
@@ -2192,8 +2213,7 @@
 
         @Override
         public void run() {
-            showSoftInput();
-            mIngonreMoveEvents = true;
+            performLongClick();
         }
     }
 
@@ -2321,7 +2341,14 @@
                         }
                         case AccessibilityNodeInfo.ACTION_CLICK: {
                             if (NumberPicker.this.isEnabled()) {
-                                showSoftInput();
+                                performClick();
+                                return true;
+                            }
+                            return false;
+                        }
+                        case AccessibilityNodeInfo.ACTION_LONG_CLICK: {
+                            if (NumberPicker.this.isEnabled()) {
+                                performLongClick();
                                 return true;
                             }
                             return false;
diff --git a/core/java/com/android/internal/os/BatteryStatsHelper.java b/core/java/com/android/internal/os/BatteryStatsHelper.java
index 6f95937..1dd1f5e 100644
--- a/core/java/com/android/internal/os/BatteryStatsHelper.java
+++ b/core/java/com/android/internal/os/BatteryStatsHelper.java
@@ -79,6 +79,8 @@
     private int mStatsType = BatteryStats.STATS_SINCE_CHARGED;
     private int mAsUser = 0;
 
+    long mRawRealtime;
+    long mRawUptime;
     long mBatteryRealtime;
     long mBatteryUptime;
     long mTypeBatteryRealtime;
@@ -157,7 +159,7 @@
                 SystemClock.uptimeMillis() * 1000);
     }
 
-    public void refreshStats(int statsType, int asUser, long rawRealtimeNano, long rawUptimeNano) {
+    public void refreshStats(int statsType, int asUser, long rawRealtimeUs, long rawUptimeUs) {
         // Initialize mStats if necessary.
         getStats();
 
@@ -182,14 +184,16 @@
 
         mStatsType = statsType;
         mAsUser = asUser;
-        mBatteryUptime = mStats.getBatteryUptime(rawUptimeNano);
-        mBatteryRealtime = mStats.getBatteryRealtime(rawRealtimeNano);
-        mTypeBatteryUptime = mStats.computeBatteryUptime(rawUptimeNano, mStatsType);
-        mTypeBatteryRealtime = mStats.computeBatteryRealtime(rawRealtimeNano, mStatsType);
+        mRawUptime = rawUptimeUs;
+        mRawRealtime = rawRealtimeUs;
+        mBatteryUptime = mStats.getBatteryUptime(rawUptimeUs);
+        mBatteryRealtime = mStats.getBatteryRealtime(rawRealtimeUs);
+        mTypeBatteryUptime = mStats.computeBatteryUptime(rawUptimeUs, mStatsType);
+        mTypeBatteryRealtime = mStats.computeBatteryRealtime(rawRealtimeUs, mStatsType);
 
         if (DEBUG) {
-            Log.d(TAG, "Raw time: realtime=" + (rawRealtimeNano/1000) + " uptime="
-                    + (rawUptimeNano/1000));
+            Log.d(TAG, "Raw time: realtime=" + (rawRealtimeUs/1000) + " uptime="
+                    + (rawUptimeUs/1000));
             Log.d(TAG, "Battery time: realtime=" + (mBatteryRealtime/1000) + " uptime="
                     + (mBatteryUptime/1000));
             Log.d(TAG, "Battery type time: realtime=" + (mTypeBatteryRealtime/1000) + " uptime="
@@ -266,7 +270,7 @@
         final double mobilePowerPerPacket = getMobilePowerPerPacket();
         final double mobilePowerPerMs = getMobilePowerPerMs();
         final double wifiPowerPerPacket = getWifiPowerPerPacket();
-        long appWakelockTime = 0;
+        long appWakelockTimeUs = 0;
         BatterySipper osApp = null;
         mStatsPeriod = mTypeBatteryRealtime;
         SparseArray<? extends Uid> uidStats = mStats.getUidStats();
@@ -342,11 +346,11 @@
                 // are canceled when the user turns the screen off.
                 BatteryStats.Timer timer = wakelock.getWakeTime(BatteryStats.WAKE_TYPE_PARTIAL);
                 if (timer != null) {
-                    wakelockTime += timer.getTotalTimeLocked(mBatteryRealtime, which);
+                    wakelockTime += timer.getTotalTimeLocked(mRawRealtime, which);
                 }
             }
+            appWakelockTimeUs += wakelockTime;
             wakelockTime /= 1000; // convert to millis
-            appWakelockTime += wakelockTime;
 
             // Add cost of holding a wake lock
             p = (wakelockTime
@@ -387,7 +391,7 @@
             power += p;
 
             // Add cost of keeping WIFI running.
-            long wifiRunningTimeMs = u.getWifiRunningTime(mBatteryRealtime, which) / 1000;
+            long wifiRunningTimeMs = u.getWifiRunningTime(mRawRealtime, which) / 1000;
             mAppWifiRunning += wifiRunningTimeMs;
             p = (wifiRunningTimeMs
                     * mPowerProfile.getAveragePower(PowerProfile.POWER_WIFI_ON)) / (60*60*1000);
@@ -396,14 +400,14 @@
             power += p;
 
             // Add cost of WIFI scans
-            long wifiScanTimeMs = u.getWifiScanTime(mBatteryRealtime, which) / 1000;
+            long wifiScanTimeMs = u.getWifiScanTime(mRawRealtime, which) / 1000;
             p = (wifiScanTimeMs
                     * mPowerProfile.getAveragePower(PowerProfile.POWER_WIFI_SCAN)) / (60*60*1000);
             if (DEBUG) Log.d(TAG, "UID " + u.getUid() + ": wifi scan " + wifiScanTimeMs
                     + " power=" + makemAh(p));
             power += p;
             for (int bin = 0; bin < BatteryStats.Uid.NUM_WIFI_BATCHED_SCAN_BINS; bin++) {
-                long batchScanTimeMs = u.getWifiBatchedScanTime(bin, mBatteryRealtime, which) / 1000;
+                long batchScanTimeMs = u.getWifiBatchedScanTime(bin, mRawRealtime, which) / 1000;
                 p = ((batchScanTimeMs
                         * mPowerProfile.getAveragePower(PowerProfile.POWER_WIFI_BATCHED_SCAN, bin))
                     ) / (60*60*1000);
@@ -419,7 +423,7 @@
                 Uid.Sensor sensor = sensorEntry.getValue();
                 int sensorHandle = sensor.getHandle();
                 BatteryStats.Timer timer = sensor.getSensorTime();
-                long sensorTime = timer.getTotalTimeLocked(mBatteryRealtime, which) / 1000;
+                long sensorTime = timer.getTotalTimeLocked(mRawRealtime, which) / 1000;
                 double multiplier = 0;
                 switch (sensorHandle) {
                     case Uid.Sensor.GPS:
@@ -505,8 +509,8 @@
         // this remainder to the OS, if possible.
         if (osApp != null) {
             long wakeTimeMillis = mBatteryUptime / 1000;
-            wakeTimeMillis -= appWakelockTime
-                    + (mStats.getScreenOnTime(mBatteryRealtime, which) / 1000);
+            wakeTimeMillis -= (appWakelockTimeUs / 1000)
+                    + (mStats.getScreenOnTime(mRawRealtime, which) / 1000);
             if (wakeTimeMillis > 0) {
                 double power = (wakeTimeMillis
                         * mPowerProfile.getAveragePower(PowerProfile.POWER_CPU_AWAKE))
@@ -523,7 +527,7 @@
     }
 
     private void addPhoneUsage() {
-        long phoneOnTimeMs = mStats.getPhoneOnTime(mBatteryRealtime, mStatsType) / 1000;
+        long phoneOnTimeMs = mStats.getPhoneOnTime(mRawRealtime, mStatsType) / 1000;
         double phoneOnPower = mPowerProfile.getAveragePower(PowerProfile.POWER_RADIO_ACTIVE)
                 * phoneOnTimeMs / (60*60*1000);
         if (phoneOnPower != 0) {
@@ -533,14 +537,14 @@
 
     private void addScreenUsage() {
         double power = 0;
-        long screenOnTimeMs = mStats.getScreenOnTime(mBatteryRealtime, mStatsType) / 1000;
+        long screenOnTimeMs = mStats.getScreenOnTime(mRawRealtime, mStatsType) / 1000;
         power += screenOnTimeMs * mPowerProfile.getAveragePower(PowerProfile.POWER_SCREEN_ON);
         final double screenFullPower =
                 mPowerProfile.getAveragePower(PowerProfile.POWER_SCREEN_FULL);
         for (int i = 0; i < BatteryStats.NUM_SCREEN_BRIGHTNESS_BINS; i++) {
             double screenBinPower = screenFullPower * (i + 0.5f)
                     / BatteryStats.NUM_SCREEN_BRIGHTNESS_BINS;
-            long brightnessTime = mStats.getScreenBrightnessTime(i, mBatteryRealtime, mStatsType)
+            long brightnessTime = mStats.getScreenBrightnessTime(i, mRawRealtime, mStatsType)
                     / 1000;
             double p = screenBinPower*brightnessTime;
             if (DEBUG && p != 0) {
@@ -561,7 +565,7 @@
         long signalTimeMs = 0;
         long noCoverageTimeMs = 0;
         for (int i = 0; i < BINS; i++) {
-            long strengthTimeMs = mStats.getPhoneSignalStrengthTime(i, mBatteryRealtime, mStatsType)
+            long strengthTimeMs = mStats.getPhoneSignalStrengthTime(i, mRawRealtime, mStatsType)
                     / 1000;
             double p = (strengthTimeMs * mPowerProfile.getAveragePower(PowerProfile.POWER_RADIO_ON, i))
                         / (60*60*1000);
@@ -575,7 +579,7 @@
                 noCoverageTimeMs = strengthTimeMs;
             }
         }
-        long scanningTimeMs = mStats.getPhoneSignalScanningTime(mBatteryRealtime, mStatsType)
+        long scanningTimeMs = mStats.getPhoneSignalScanningTime(mRawRealtime, mStatsType)
                 / 1000;
         double p = (scanningTimeMs * mPowerProfile.getAveragePower(
                         PowerProfile.POWER_RADIO_SCANNING))
@@ -584,7 +588,7 @@
             Log.d(TAG, "Cell radio scanning: time=" + scanningTimeMs + " power=" + makemAh(p));
         }
         power += p;
-        long radioActiveTimeUs = mStats.getMobileRadioActiveTime(mBatteryRealtime, mStatsType);
+        long radioActiveTimeUs = mStats.getMobileRadioActiveTime(mRawRealtime, mStatsType);
         long remainingActiveTime = (radioActiveTimeUs - mAppMobileActive) / 1000;
         if (remainingActiveTime > 0) {
             power += getMobilePowerPerMs() * remainingActiveTime;
@@ -624,8 +628,8 @@
     }
 
     private void addWiFiUsage() {
-        long onTimeMs = mStats.getWifiOnTime(mBatteryRealtime, mStatsType) / 1000;
-        long runningTimeMs = mStats.getGlobalWifiRunningTime(mBatteryRealtime, mStatsType) / 1000;
+        long onTimeMs = mStats.getWifiOnTime(mRawRealtime, mStatsType) / 1000;
+        long runningTimeMs = mStats.getGlobalWifiRunningTime(mRawRealtime, mStatsType) / 1000;
         if (DEBUG) Log.d(TAG, "WIFI runningTime=" + runningTimeMs
                 + " app runningTime=" + mAppWifiRunning);
         runningTimeMs -= mAppWifiRunning;
@@ -646,7 +650,7 @@
 
     private void addIdleUsage() {
         long idleTimeMs = (mTypeBatteryRealtime
-                - mStats.getScreenOnTime(mBatteryRealtime, mStatsType)) / 1000;
+                - mStats.getScreenOnTime(mRawRealtime, mStatsType)) / 1000;
         double idlePower = (idleTimeMs * mPowerProfile.getAveragePower(PowerProfile.POWER_CPU_IDLE))
                 / (60*60*1000);
         if (DEBUG && idlePower != 0) {
@@ -658,7 +662,7 @@
     }
 
     private void addBluetoothUsage() {
-        long btOnTimeMs = mStats.getBluetoothOnTime(mBatteryRealtime, mStatsType) / 1000;
+        long btOnTimeMs = mStats.getBluetoothOnTime(mRawRealtime, mStatsType) / 1000;
         double btPower = btOnTimeMs * mPowerProfile.getAveragePower(PowerProfile.POWER_BLUETOOTH_ON)
                 / (60*60*1000);
         if (DEBUG && btPower != 0) {
@@ -704,7 +708,7 @@
         final long mobileData = mobileRx + mobileTx;
 
         final long radioDataUptimeMs
-                = mStats.getMobileRadioActiveTime(mBatteryRealtime, mStatsType) / 1000;
+                = mStats.getMobileRadioActiveTime(mRawRealtime, mStatsType) / 1000;
         final double mobilePps = (mobileData != 0 && radioDataUptimeMs != 0)
                 ? (mobileData / (double)radioDataUptimeMs)
                 : (((double)MOBILE_BPS) / 8 / 2048);
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index fdb090b..fd93604 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -87,7 +87,7 @@
     private static final int MAGIC = 0xBA757475; // 'BATSTATS'
 
     // Current on-disk Parcel version
-    private static final int VERSION = 94 + (USE_OLD_HISTORY ? 1000 : 0);
+    private static final int VERSION = 97 + (USE_OLD_HISTORY ? 1000 : 0);
 
     // Maximum number of items we will record in the history.
     private static final int MAX_HISTORY_ITEMS = 2000;
@@ -174,7 +174,15 @@
 
     // These are the objects that will want to do something when the device
     // is unplugged from power.
-    final ArrayList<Unpluggable> mUnpluggables = new ArrayList<Unpluggable>();
+    final TimeBase mOnBatteryTimeBase = new TimeBase();
+
+    // These are the objects that will want to do something when the device
+    // is unplugged from power *and* the screen is off.
+    final TimeBase mOnBatteryScreenOffTimeBase = new TimeBase();
+
+    // Set to true when we want to distribute CPU across wakelocks for the next
+    // CPU update, even if we aren't currently running wake locks.
+    boolean mDistributeWakelockCpu;
 
     boolean mShuttingDown;
 
@@ -217,11 +225,6 @@
 
     long mStartClockTime;
 
-    long mBatteryUptime;
-    long mBatteryLastUptime;
-    long mBatteryRealtime;
-    long mBatteryLastRealtime;
-
     long mUptime;
     long mUptimeStart;
     long mLastUptime;
@@ -296,13 +299,6 @@
      */
     boolean mOnBattery;
     boolean mOnBatteryInternal;
-    long mTrackBatteryPastUptime;
-    long mTrackBatteryUptimeStart;
-    long mTrackBatteryPastRealtime;
-    long mTrackBatteryRealtimeStart;
-
-    long mUnpluggedBatteryUptime;
-    long mUnpluggedBatteryRealtime;
 
     /*
      * These keep track of battery levels (1-100) at the last plug event and the last unplug event.
@@ -391,35 +387,235 @@
         mHandler = null;
     }
 
-    public static interface Unpluggable {
-        void unplug(long elapsedRealtime, long batteryUptime, long batteryRealtime);
-        void plug(long elapsedRealtime, long batteryUptime, long batteryRealtime);
+    public static interface TimeBaseObs {
+        void onTimeStarted(long elapsedRealtime, long baseUptime, long baseRealtime);
+        void onTimeStopped(long elapsedRealtime, long baseUptime, long baseRealtime);
+    }
+
+    static class TimeBase {
+        private final ArrayList<TimeBaseObs> mObservers = new ArrayList<TimeBaseObs>();
+
+        private long mUptime;
+        private long mLastUptime;
+        private long mRealtime;
+        private long mLastRealtime;
+
+        private boolean mRunning;
+
+        private long mPastUptime;
+        private long mUptimeStart;
+        private long mPastRealtime;
+        private long mRealtimeStart;
+        private long mUnpluggedUptime;
+        private long mUnpluggedRealtime;
+
+        public void dump(PrintWriter pw, String prefix) {
+            StringBuilder sb = new StringBuilder(128);
+            pw.print(prefix); pw.print("mRunning="); pw.println(mRunning);
+            sb.setLength(0);
+            sb.append(prefix);
+                    sb.append("mUptime=");
+                    formatTimeMs(sb, mUptime / 1000); sb.append("mLastUptime=");
+                    formatTimeMs(sb, mLastUptime / 1000);
+            pw.println(sb.toString());
+            sb.setLength(0);
+            sb.append(prefix);
+                    sb.append("mRealtime=");
+                    formatTimeMs(sb, mRealtime / 1000); sb.append("mLastRealtime=");
+                    formatTimeMs(sb, mLastRealtime / 1000);
+            pw.println(sb.toString());
+            sb.setLength(0);
+            sb.append(prefix);
+                    sb.append("mPastUptime=");
+                    formatTimeMs(sb, mPastUptime / 1000); sb.append("mUptimeStart=");
+                    formatTimeMs(sb, mUptimeStart / 1000);
+                    sb.append("mUnpluggedUptime="); formatTimeMs(sb, mUnpluggedUptime / 1000);
+            pw.println(sb.toString());
+            sb.setLength(0);
+            sb.append(prefix);
+                    sb.append("mPastRealtime=");
+                    formatTimeMs(sb, mPastRealtime / 1000); sb.append("mRealtimeStart=");
+                    formatTimeMs(sb, mRealtimeStart / 1000);
+                    sb.append("mUnpluggedRealtime="); formatTimeMs(sb, mUnpluggedRealtime / 1000);
+            pw.println(sb.toString());
+        }
+
+        public void add(TimeBaseObs observer) {
+            mObservers.add(observer);
+        }
+
+        public void remove(TimeBaseObs observer) {
+            if (!mObservers.remove(observer)) {
+                Slog.wtf(TAG, "Removed unknown observer: " + observer);
+            }
+        }
+
+        public void init(long uptime, long realtime) {
+            mRealtime = 0;
+            mUptime = 0;
+            mPastUptime = 0;
+            mPastRealtime = 0;
+            mUptimeStart = uptime;
+            mRealtimeStart = realtime;
+            mUnpluggedUptime = getUptime(mUptimeStart);
+            mUnpluggedRealtime = getRealtime(mRealtimeStart);
+        }
+
+        public void reset(long uptime, long realtime) {
+            if (!mRunning) {
+                mPastUptime = 0;
+                mPastRealtime = 0;
+            } else {
+                mUptimeStart = uptime;
+                mRealtimeStart = realtime;
+                mUnpluggedUptime = getUptime(uptime);
+                mUnpluggedRealtime = getRealtime(realtime);
+            }
+        }
+
+        public long computeUptime(long curTime, int which) {
+            switch (which) {
+                case STATS_SINCE_CHARGED:
+                    return mUptime + getUptime(curTime);
+                case STATS_LAST:
+                    return mLastUptime;
+                case STATS_CURRENT:
+                    return getUptime(curTime);
+                case STATS_SINCE_UNPLUGGED:
+                    return getUptime(curTime) - mUnpluggedUptime;
+            }
+            return 0;
+        }
+
+        public long computeRealtime(long curTime, int which) {
+            switch (which) {
+                case STATS_SINCE_CHARGED:
+                    return mRealtime + getRealtime(curTime);
+                case STATS_LAST:
+                    return mLastRealtime;
+                case STATS_CURRENT:
+                    return getRealtime(curTime);
+                case STATS_SINCE_UNPLUGGED:
+                    return getRealtime(curTime) - mUnpluggedRealtime;
+            }
+            return 0;
+        }
+
+        public long getUptime(long curTime) {
+            long time = mPastUptime;
+            if (mRunning) {
+                time += curTime - mUptimeStart;
+            }
+            return time;
+        }
+
+        public long getRealtime(long curTime) {
+            long time = mPastRealtime;
+            if (mRunning) {
+                time += curTime - mRealtimeStart;
+            }
+            return time;
+        }
+
+        public long getUptimeStart() {
+            return mUptimeStart;
+        }
+
+        public long getRealtimeStart() {
+            return mRealtimeStart;
+        }
+
+        public boolean isRunning() {
+            return mRunning;
+        }
+
+        public boolean setRunning(boolean running, long uptime, long realtime) {
+            if (mRunning != running) {
+                mRunning = running;
+                if (running) {
+                    mUptimeStart = uptime;
+                    mRealtimeStart = realtime;
+                    long batteryUptime = mUnpluggedUptime = getUptime(uptime);
+                    long batteryRealtime = mUnpluggedRealtime = getRealtime(realtime);
+
+                    for (int i = mObservers.size() - 1; i >= 0; i--) {
+                        mObservers.get(i).onTimeStarted(realtime, batteryUptime, batteryRealtime);
+                    }
+                } else {
+                    mPastUptime += uptime - mUptimeStart;
+                    mPastRealtime += realtime - mRealtimeStart;
+
+                    long batteryUptime = getUptime(uptime);
+                    long batteryRealtime = getRealtime(realtime);
+
+                    for (int i = mObservers.size() - 1; i >= 0; i--) {
+                        mObservers.get(i).onTimeStopped(realtime, batteryUptime, batteryRealtime);
+                    }
+                }
+                return true;
+            }
+            return false;
+        }
+
+        public void readSummaryFromParcel(Parcel in) {
+            mUptime = in.readLong();
+            mRealtime = in.readLong();
+        }
+
+        public void writeSummaryToParcel(Parcel out, long uptime, long realtime) {
+            out.writeLong(computeUptime(uptime, STATS_SINCE_CHARGED));
+            out.writeLong(computeRealtime(realtime, STATS_SINCE_CHARGED));
+        }
+
+        public void readFromParcel(Parcel in) {
+            mRunning = false;
+            mUptime = in.readLong();
+            mLastUptime = 0;
+            mPastUptime = in.readLong();
+            mUptimeStart = in.readLong();
+            mPastRealtime = in.readLong();
+            mRealtimeStart = in.readLong();
+            mUnpluggedUptime = in.readLong();
+            mUnpluggedRealtime = in.readLong();
+        }
+
+        public void writeToParcel(Parcel out, long uptime, long realtime) {
+            final long runningUptime = getUptime(uptime);
+            final long runningRealtime = getRealtime(realtime);
+            out.writeLong(mUptime);
+            out.writeLong(runningUptime);
+            out.writeLong(mUptimeStart);
+            out.writeLong(runningRealtime);
+            out.writeLong(mRealtimeStart);
+            out.writeLong(mUnpluggedUptime);
+            out.writeLong(mUnpluggedRealtime);
+        }
     }
 
     /**
      * State for keeping track of counting information.
      */
-    public static class Counter extends BatteryStats.Counter implements Unpluggable {
+    public static class Counter extends BatteryStats.Counter implements TimeBaseObs {
         final AtomicInteger mCount = new AtomicInteger();
-        final ArrayList<Unpluggable> mUnpluggables;
+        final TimeBase mTimeBase;
         int mLoadedCount;
         int mLastCount;
         int mUnpluggedCount;
         int mPluggedCount;
 
-        Counter(ArrayList<Unpluggable> unpluggables, Parcel in) {
-            mUnpluggables = unpluggables;
+        Counter(TimeBase timeBase, Parcel in) {
+            mTimeBase = timeBase;
             mPluggedCount = in.readInt();
             mCount.set(mPluggedCount);
             mLoadedCount = in.readInt();
             mLastCount = 0;
             mUnpluggedCount = in.readInt();
-            unpluggables.add(this);
+            timeBase.add(this);
         }
 
-        Counter(ArrayList<Unpluggable> unpluggables) {
-            mUnpluggables = unpluggables;
-            unpluggables.add(this);
+        Counter(TimeBase timeBase) {
+            mTimeBase = timeBase;
+            timeBase.add(this);
         }
 
         public void writeToParcel(Parcel out) {
@@ -428,12 +624,12 @@
             out.writeInt(mUnpluggedCount);
         }
 
-        public void unplug(long elapsedRealtime, long batteryUptime, long batteryRealtime) {
+        public void onTimeStarted(long elapsedRealtime, long baseUptime, long baseRealtime) {
             mUnpluggedCount = mPluggedCount;
             mCount.set(mPluggedCount);
         }
 
-        public void plug(long elapsedRealtime, long batteryUptime, long batteryRealtime) {
+        public void onTimeStopped(long elapsedRealtime, long baseUptime, long baseRealtime) {
             mPluggedCount = mCount.get();
         }
 
@@ -493,7 +689,7 @@
         }
 
         void detach() {
-            mUnpluggables.remove(this);
+            mTimeBase.remove(this);
         }
 
         void writeSummaryFromParcelLocked(Parcel out) {
@@ -510,12 +706,12 @@
     }
 
     public static class SamplingCounter extends Counter {
-        SamplingCounter(ArrayList<Unpluggable> unpluggables, Parcel in) {
-            super(unpluggables, in);
+        SamplingCounter(TimeBase timeBase, Parcel in) {
+            super(timeBase, in);
         }
 
-        SamplingCounter(ArrayList<Unpluggable> unpluggables) {
-            super(unpluggables);
+        SamplingCounter(TimeBase timeBase) {
+            super(timeBase);
         }
 
         public void addCountAtomic(long count) {
@@ -523,27 +719,27 @@
         }
     }
 
-    public static class LongSamplingCounter implements Unpluggable {
-        final ArrayList<Unpluggable> mUnpluggables;
+    public static class LongSamplingCounter implements TimeBaseObs {
+        final TimeBase mTimeBase;
         long mCount;
         long mLoadedCount;
         long mLastCount;
         long mUnpluggedCount;
         long mPluggedCount;
 
-        LongSamplingCounter(ArrayList<Unpluggable> unpluggables, Parcel in) {
-            mUnpluggables = unpluggables;
+        LongSamplingCounter(TimeBase timeBase, Parcel in) {
+            mTimeBase = timeBase;
             mPluggedCount = in.readLong();
             mCount = mPluggedCount;
             mLoadedCount = in.readLong();
             mLastCount = 0;
             mUnpluggedCount = in.readLong();
-            unpluggables.add(this);
+            timeBase.add(this);
         }
 
-        LongSamplingCounter(ArrayList<Unpluggable> unpluggables) {
-            mUnpluggables = unpluggables;
-            unpluggables.add(this);
+        LongSamplingCounter(TimeBase timeBase) {
+            mTimeBase = timeBase;
+            timeBase.add(this);
         }
 
         public void writeToParcel(Parcel out) {
@@ -553,13 +749,13 @@
         }
 
         @Override
-        public void unplug(long elapsedRealtime, long batteryUptime, long batteryRealtime) {
+        public void onTimeStarted(long elapsedRealtime, long baseUptime, long baseRealtime) {
             mUnpluggedCount = mPluggedCount;
             mCount = mPluggedCount;
         }
 
         @Override
-        public void plug(long elapsedRealtime, long batteryUptime, long batteryRealtime) {
+        public void onTimeStopped(long elapsedRealtime, long baseUptime, long baseRealtime) {
             mPluggedCount = mCount;
         }
 
@@ -595,7 +791,7 @@
         }
 
         void detach() {
-            mUnpluggables.remove(this);
+            mTimeBase.remove(this);
         }
 
         void writeSummaryFromParcelLocked(Parcel out) {
@@ -613,9 +809,9 @@
     /**
      * State for keeping track of timing information.
      */
-    public static abstract class Timer extends BatteryStats.Timer implements Unpluggable {
+    public static abstract class Timer extends BatteryStats.Timer implements TimeBaseObs {
         final int mType;
-        final ArrayList<Unpluggable> mUnpluggables;
+        final TimeBase mTimeBase;
 
         int mCount;
         int mLoadedCount;
@@ -654,12 +850,12 @@
         /**
          * Constructs from a parcel.
          * @param type
-         * @param unpluggables
+         * @param timeBase
          * @param in
          */
-        Timer(int type, ArrayList<Unpluggable> unpluggables, Parcel in) {
+        Timer(int type, TimeBase timeBase, Parcel in) {
             mType = type;
-            mUnpluggables = unpluggables;
+            mTimeBase = timeBase;
 
             mCount = in.readInt();
             mLoadedCount = in.readInt();
@@ -669,13 +865,13 @@
             mLoadedTime = in.readLong();
             mLastTime = 0;
             mUnpluggedTime = in.readLong();
-            unpluggables.add(this);
+            timeBase.add(this);
         }
 
-        Timer(int type, ArrayList<Unpluggable> unpluggables) {
+        Timer(int type, TimeBase timeBase) {
             mType = type;
-            mUnpluggables = unpluggables;
-            unpluggables.add(this);
+            mTimeBase = timeBase;
+            timeBase.add(this);
         }
 
         protected abstract long computeRunTimeLocked(long curBatteryRealtime);
@@ -686,7 +882,7 @@
          * Clear state of this timer.  Returns true if the timer is inactive
          * so can be completely dropped.
          */
-        boolean reset(BatteryStatsImpl stats, boolean detachIfReset) {
+        boolean reset(boolean detachIfReset) {
             mTotalTime = mLoadedTime = mLastTime = 0;
             mCount = mLoadedCount = mLastCount = 0;
             if (detachIfReset) {
@@ -696,25 +892,25 @@
         }
 
         void detach() {
-            mUnpluggables.remove(this);
+            mTimeBase.remove(this);
         }
 
-        public void writeToParcel(Parcel out, long batteryRealtime) {
+        public void writeToParcel(Parcel out, long elapsedRealtimeUs) {
             out.writeInt(mCount);
             out.writeInt(mLoadedCount);
             out.writeInt(mUnpluggedCount);
-            out.writeLong(computeRunTimeLocked(batteryRealtime));
+            out.writeLong(computeRunTimeLocked(mTimeBase.getRealtime(elapsedRealtimeUs)));
             out.writeLong(mLoadedTime);
             out.writeLong(mUnpluggedTime);
         }
 
-        public void unplug(long elapsedRealtime, long batteryUptime, long batteryRealtime) {
+        public void onTimeStarted(long elapsedRealtime, long timeBaseUptime, long baseRealtime) {
             if (DEBUG && mType < 0) {
-                Log.v(TAG, "unplug #" + mType + ": realtime=" + batteryRealtime
+                Log.v(TAG, "unplug #" + mType + ": realtime=" + baseRealtime
                         + " old mUnpluggedTime=" + mUnpluggedTime
                         + " old mUnpluggedCount=" + mUnpluggedCount);
             }
-            mUnpluggedTime = computeRunTimeLocked(batteryRealtime);
+            mUnpluggedTime = computeRunTimeLocked(baseRealtime);
             mUnpluggedCount = mCount;
             if (DEBUG && mType < 0) {
                 Log.v(TAG, "unplug #" + mType
@@ -723,12 +919,12 @@
             }
         }
 
-        public void plug(long elapsedRealtime, long batteryUptime, long batteryRealtime) {
+        public void onTimeStopped(long elapsedRealtime, long baseUptime, long baseRealtime) {
             if (DEBUG && mType < 0) {
-                Log.v(TAG, "plug #" + mType + ": realtime=" + batteryRealtime
+                Log.v(TAG, "plug #" + mType + ": realtime=" + baseRealtime
                         + " old mTotalTime=" + mTotalTime);
             }
-            mTotalTime = computeRunTimeLocked(batteryRealtime);
+            mTotalTime = computeRunTimeLocked(baseRealtime);
             mCount = computeCurrentCountLocked();
             if (DEBUG && mType < 0) {
                 Log.v(TAG, "plug #" + mType
@@ -742,24 +938,23 @@
          * @param out the Parcel to be written to.
          * @param timer a Timer, or null.
          */
-        public static void writeTimerToParcel(Parcel out, Timer timer,
-                long batteryRealtime) {
+        public static void writeTimerToParcel(Parcel out, Timer timer, long elapsedRealtimeUs) {
             if (timer == null) {
                 out.writeInt(0); // indicates null
                 return;
             }
             out.writeInt(1); // indicates non-null
 
-            timer.writeToParcel(out, batteryRealtime);
+            timer.writeToParcel(out, elapsedRealtimeUs);
         }
 
         @Override
-        public long getTotalTimeLocked(long batteryRealtime, int which) {
+        public long getTotalTimeLocked(long elapsedRealtimeUs, int which) {
             long val;
             if (which == STATS_LAST) {
                 val = mLastTime;
             } else {
-                val = computeRunTimeLocked(batteryRealtime);
+                val = computeRunTimeLocked(mTimeBase.getRealtime(elapsedRealtimeUs));
                 if (which == STATS_SINCE_UNPLUGGED) {
                     val -= mUnpluggedTime;
                 } else if (which != STATS_SINCE_CHARGED) {
@@ -798,16 +993,15 @@
         }
 
 
-        void writeSummaryFromParcelLocked(Parcel out, long batteryRealtime) {
-            long runTime = computeRunTimeLocked(batteryRealtime);
-            // Divide by 1000 for backwards compatibility
-            out.writeLong((runTime + 500) / 1000);
+        void writeSummaryFromParcelLocked(Parcel out, long elapsedRealtimeUs) {
+            long runTime = computeRunTimeLocked(mTimeBase.getRealtime(elapsedRealtimeUs));
+            out.writeLong(runTime);
             out.writeInt(mCount);
         }
 
         void readSummaryFromParcelLocked(Parcel in) {
             // Multiply by 1000 for backwards compatibility
-            mTotalTime = mLoadedTime = in.readLong() * 1000;
+            mTotalTime = mLoadedTime = in.readLong();
             mLastTime = 0;
             mUnpluggedTime = mTotalTime;
             mCount = mLoadedCount = in.readInt();
@@ -844,7 +1038,7 @@
         /**
          * Whether we are currently in a discharge cycle.
          */
-        boolean mInDischarge;
+        boolean mTimeBaseRunning;
 
         /**
          * Whether we are currently recording reported values.
@@ -856,21 +1050,20 @@
          */
         int mUpdateVersion;
 
-        SamplingTimer(ArrayList<Unpluggable> unpluggables, boolean inDischarge, Parcel in) {
-            super(0, unpluggables, in);
+        SamplingTimer(TimeBase timeBase, Parcel in) {
+            super(0, timeBase, in);
             mCurrentReportedCount = in.readInt();
             mUnpluggedReportedCount = in.readInt();
             mCurrentReportedTotalTime = in.readLong();
             mUnpluggedReportedTotalTime = in.readLong();
             mTrackingReportedValues = in.readInt() == 1;
-            mInDischarge = inDischarge;
+            mTimeBaseRunning = timeBase.isRunning();
         }
 
-        SamplingTimer(ArrayList<Unpluggable> unpluggables, boolean inDischarge,
-                boolean trackReportedValues) {
-            super(0, unpluggables);
+        SamplingTimer(TimeBase timeBase, boolean trackReportedValues) {
+            super(0, timeBase);
             mTrackingReportedValues = trackReportedValues;
-            mInDischarge = inDischarge;
+            mTimeBaseRunning = timeBase.isRunning();
         }
 
         public void setStale() {
@@ -888,7 +1081,7 @@
         }
 
         public void updateCurrentReportedCount(int count) {
-            if (mInDischarge && mUnpluggedReportedCount == 0) {
+            if (mTimeBaseRunning && mUnpluggedReportedCount == 0) {
                 // Updating the reported value for the first time.
                 mUnpluggedReportedCount = count;
                 // If we are receiving an update update mTrackingReportedValues;
@@ -898,7 +1091,7 @@
         }
 
         public void updateCurrentReportedTotalTime(long totalTime) {
-            if (mInDischarge && mUnpluggedReportedTotalTime == 0) {
+            if (mTimeBaseRunning && mUnpluggedReportedTotalTime == 0) {
                 // Updating the reported value for the first time.
                 mUnpluggedReportedTotalTime = totalTime;
                 // If we are receiving an update update mTrackingReportedValues;
@@ -907,18 +1100,18 @@
             mCurrentReportedTotalTime = totalTime;
         }
 
-        public void unplug(long elapsedRealtime, long batteryUptime, long batteryRealtime) {
-            super.unplug(elapsedRealtime, batteryUptime, batteryRealtime);
+        public void onTimeStarted(long elapsedRealtime, long baseUptime, long baseRealtime) {
+            super.onTimeStarted(elapsedRealtime, baseUptime, baseRealtime);
             if (mTrackingReportedValues) {
                 mUnpluggedReportedTotalTime = mCurrentReportedTotalTime;
                 mUnpluggedReportedCount = mCurrentReportedCount;
             }
-            mInDischarge = true;
+            mTimeBaseRunning = true;
         }
 
-        public void plug(long elapsedRealtime, long batteryUptime, long batteryRealtime) {
-            super.plug(elapsedRealtime, batteryUptime, batteryRealtime);
-            mInDischarge = false;
+        public void onTimeStopped(long elapsedRealtime, long baseUptime, long baseRealtime) {
+            super.onTimeStopped(elapsedRealtime, baseUptime, baseRealtime);
+            mTimeBaseRunning = false;
         }
 
         public void logState(Printer pw, String prefix) {
@@ -930,17 +1123,17 @@
         }
 
         protected long computeRunTimeLocked(long curBatteryRealtime) {
-            return mTotalTime + (mInDischarge && mTrackingReportedValues
+            return mTotalTime + (mTimeBaseRunning && mTrackingReportedValues
                     ? mCurrentReportedTotalTime - mUnpluggedReportedTotalTime : 0);
         }
 
         protected int computeCurrentCountLocked() {
-            return mCount + (mInDischarge && mTrackingReportedValues
+            return mCount + (mTimeBaseRunning && mTrackingReportedValues
                     ? mCurrentReportedCount - mUnpluggedReportedCount : 0);
         }
 
-        public void writeToParcel(Parcel out, long batteryRealtime) {
-            super.writeToParcel(out, batteryRealtime);
+        public void writeToParcel(Parcel out, long elapsedRealtimeUs) {
+            super.writeToParcel(out, elapsedRealtimeUs);
             out.writeInt(mCurrentReportedCount);
             out.writeInt(mUnpluggedReportedCount);
             out.writeLong(mCurrentReportedTotalTime);
@@ -948,8 +1141,8 @@
             out.writeInt(mTrackingReportedValues ? 1 : 0);
         }
 
-        boolean reset(BatteryStatsImpl stats, boolean detachIfReset) {
-            super.reset(stats, detachIfReset);
+        boolean reset(boolean detachIfReset) {
+            super.reset(detachIfReset);
             setStale();
             return true;
         }
@@ -991,45 +1184,43 @@
          */
         boolean mInDischarge;
 
-        BatchTimer(Uid uid, int type, ArrayList<Unpluggable> unpluggables,
-                boolean inDischarge, Parcel in) {
-            super(type, unpluggables, in);
+        BatchTimer(Uid uid, int type, TimeBase timeBase, Parcel in) {
+            super(type, timeBase, in);
             mUid = uid;
             mLastAddedTime = in.readLong();
             mLastAddedDuration = in.readLong();
-            mInDischarge = inDischarge;
+            mInDischarge = timeBase.isRunning();
         }
 
-        BatchTimer(Uid uid, int type, ArrayList<Unpluggable> unpluggables,
-                boolean inDischarge) {
-            super(type, unpluggables);
+        BatchTimer(Uid uid, int type, TimeBase timeBase) {
+            super(type, timeBase);
             mUid = uid;
-            mInDischarge = inDischarge;
+            mInDischarge = timeBase.isRunning();
         }
 
         @Override
-        public void writeToParcel(Parcel out, long batteryRealtime) {
-            super.writeToParcel(out, batteryRealtime);
+        public void writeToParcel(Parcel out, long elapsedRealtimeUs) {
+            super.writeToParcel(out, elapsedRealtimeUs);
             out.writeLong(mLastAddedTime);
             out.writeLong(mLastAddedDuration);
         }
 
         @Override
-        public void plug(long elapsedRealtime, long batteryUptime, long batteryRealtime) {
+        public void onTimeStopped(long elapsedRealtime, long baseUptime, long baseRealtime) {
             recomputeLastDuration(SystemClock.elapsedRealtime() * 1000, false);
             mInDischarge = false;
-            super.plug(elapsedRealtime, batteryUptime, batteryRealtime);
+            super.onTimeStopped(elapsedRealtime, baseUptime, baseRealtime);
         }
 
         @Override
-        public void unplug(long elapsedRealtime, long batteryUptime, long batteryRealtime) {
+        public void onTimeStarted(long elapsedRealtime, long baseUptime, long baseRealtime) {
             recomputeLastDuration(elapsedRealtime, false);
             mInDischarge = true;
             // If we are still within the last added duration, then re-added whatever remains.
             if (mLastAddedTime == elapsedRealtime) {
                 mTotalTime += mLastAddedDuration;
             }
-            super.unplug(elapsedRealtime, batteryUptime, batteryRealtime);
+            super.onTimeStarted(elapsedRealtime, baseUptime, baseRealtime);
         }
 
         @Override
@@ -1095,11 +1286,11 @@
         }
 
         @Override
-        boolean reset(BatteryStatsImpl stats, boolean detachIfReset) {
+        boolean reset(boolean detachIfReset) {
             final long now = SystemClock.elapsedRealtime() * 1000;
             recomputeLastDuration(now, true);
             boolean stillActive = mLastAddedTime == now;
-            super.reset(stats, !stillActive && detachIfReset);
+            super.reset(!stillActive && detachIfReset);
             return !stillActive;
         }
     }
@@ -1135,16 +1326,16 @@
         boolean mInList;
 
         StopwatchTimer(Uid uid, int type, ArrayList<StopwatchTimer> timerPool,
-                ArrayList<Unpluggable> unpluggables, Parcel in) {
-            super(type, unpluggables, in);
+                TimeBase timeBase, Parcel in) {
+            super(type, timeBase, in);
             mUid = uid;
             mTimerPool = timerPool;
             mUpdateTime = in.readLong();
         }
 
         StopwatchTimer(Uid uid, int type, ArrayList<StopwatchTimer> timerPool,
-                ArrayList<Unpluggable> unpluggables) {
-            super(type, unpluggables);
+                TimeBase timeBase) {
+            super(type, timeBase);
             mUid = uid;
             mTimerPool = timerPool;
         }
@@ -1153,18 +1344,18 @@
             mTimeout = timeout;
         }
 
-        public void writeToParcel(Parcel out, long batteryRealtime) {
-            super.writeToParcel(out, batteryRealtime);
+        public void writeToParcel(Parcel out, long elapsedRealtimeUs) {
+            super.writeToParcel(out, elapsedRealtimeUs);
             out.writeLong(mUpdateTime);
         }
 
-        public void plug(long elapsedRealtime, long batteryUptime, long batteryRealtime) {
+        public void onTimeStopped(long elapsedRealtime, long baseUptime, long baseRealtime) {
             if (mNesting > 0) {
                 if (DEBUG && mType < 0) {
                     Log.v(TAG, "old mUpdateTime=" + mUpdateTime);
                 }
-                super.plug(elapsedRealtime, batteryUptime, batteryRealtime);
-                mUpdateTime = batteryRealtime;
+                super.onTimeStopped(elapsedRealtime, baseUptime, baseRealtime);
+                mUpdateTime = baseRealtime;
                 if (DEBUG && mType < 0) {
                     Log.v(TAG, "new mUpdateTime=" + mUpdateTime);
                 }
@@ -1177,14 +1368,14 @@
                     + " mAcquireTime=" + mAcquireTime);
         }
 
-        void startRunningLocked(BatteryStatsImpl stats, long elapsedRealtime) {
+        void startRunningLocked(long elapsedRealtimeMs) {
             if (mNesting++ == 0) {
-                final long batteryRealtime = stats.getBatteryRealtimeLocked(elapsedRealtime * 1000);
+                final long batteryRealtime = mTimeBase.getRealtime(elapsedRealtimeMs * 1000);
                 mUpdateTime = batteryRealtime;
                 if (mTimerPool != null) {
                     // Accumulate time to all currently active timers before adding
                     // this new one to the pool.
-                    refreshTimersLocked(stats, batteryRealtime, mTimerPool, null);
+                    refreshTimersLocked(batteryRealtime, mTimerPool, null);
                     // Add this timer to the active pool
                     mTimerPool.add(this);
                 }
@@ -1203,12 +1394,12 @@
             return mNesting > 0;
         }
 
-        long checkpointRunningLocked(BatteryStatsImpl stats, long elapsedRealtime) {
+        long checkpointRunningLocked(long elapsedRealtimeMs) {
             if (mNesting > 0) {
                 // We are running...
-                final long batteryRealtime = stats.getBatteryRealtimeLocked(elapsedRealtime * 1000);
+                final long batteryRealtime = mTimeBase.getRealtime(elapsedRealtimeMs * 1000);
                 if (mTimerPool != null) {
-                    return refreshTimersLocked(stats, batteryRealtime, mTimerPool, this);
+                    return refreshTimersLocked(batteryRealtime, mTimerPool, this);
                 }
                 final long heldTime = batteryRealtime - mUpdateTime;
                 mUpdateTime = batteryRealtime;
@@ -1218,17 +1409,17 @@
             return 0;
         }
 
-        void stopRunningLocked(BatteryStatsImpl stats, long elapsedRealtime) {
+        void stopRunningLocked(long elapsedRealtimeMs) {
             // Ignore attempt to stop a timer that isn't running
             if (mNesting == 0) {
                 return;
             }
             if (--mNesting == 0) {
-                final long batteryRealtime = stats.getBatteryRealtimeLocked(elapsedRealtime * 1000);
+                final long batteryRealtime = mTimeBase.getRealtime(elapsedRealtimeMs * 1000);
                 if (mTimerPool != null) {
                     // Accumulate time to all active counters, scaled by the total
                     // active in the pool, before taking this one out of the pool.
-                    refreshTimersLocked(stats, batteryRealtime, mTimerPool, null);
+                    refreshTimersLocked(batteryRealtime, mTimerPool, null);
                     // Remove this timer from the active pool
                     mTimerPool.remove(this);
                 } else {
@@ -1253,8 +1444,8 @@
 
         // Update the total time for all other running Timers with the same type as this Timer
         // due to a change in timer count
-        private static long refreshTimersLocked(final BatteryStatsImpl stats,
-                long batteryRealtime, final ArrayList<StopwatchTimer> pool, StopwatchTimer self) {
+        private static long refreshTimersLocked(long batteryRealtime,
+                final ArrayList<StopwatchTimer> pool, StopwatchTimer self) {
             long selfTime = 0;
             final int N = pool.size();
             for (int i=N-1; i>= 0; i--) {
@@ -1288,12 +1479,11 @@
             return mCount;
         }
 
-        boolean reset(BatteryStatsImpl stats, boolean detachIfReset) {
+        boolean reset(boolean detachIfReset) {
             boolean canDetach = mNesting <= 0;
-            super.reset(stats, canDetach && detachIfReset);
+            super.reset(canDetach && detachIfReset);
             if (mNesting > 0) {
-                mUpdateTime = stats.getBatteryRealtimeLocked(
-                        SystemClock.elapsedRealtime() * 1000);
+                mUpdateTime = mTimeBase.getRealtime(SystemClock.elapsedRealtime() * 1000);
             }
             mAcquireTime = mTotalTime;
             return canDetach;
@@ -1456,8 +1646,7 @@
     public SamplingTimer getKernelWakelockTimerLocked(String name) {
         SamplingTimer kwlt = mKernelWakelockStats.get(name);
         if (kwlt == null) {
-            kwlt = new SamplingTimer(mUnpluggables, mOnBatteryInternal,
-                    true /* track reported values */);
+            kwlt = new SamplingTimer(mOnBatteryScreenOffTimeBase, true /* track reported values */);
             mKernelWakelockStats.put(name, kwlt);
         }
         return kwlt;
@@ -1953,24 +2142,31 @@
         mHistoryOverflow = false;
     }
 
-    public void doUnplugLocked(long elapsedRealtime, long batteryUptime, long batteryRealtime) {
-        for (int i = mUnpluggables.size() - 1; i >= 0; i--) {
-            mUnpluggables.get(i).unplug(elapsedRealtime, batteryUptime, batteryRealtime);
+    public void updateTimeBasesLocked(boolean unplugged, boolean screenOff, long uptime,
+            long realtime) {
+        if (mOnBatteryTimeBase.setRunning(unplugged, uptime, realtime)) {
+            if (unplugged) {
+                // Track bt headset ping count
+                mBluetoothPingStart = getCurrentBluetoothPingCount();
+                mBluetoothPingCount = 0;
+            } else {
+                // Track bt headset ping count
+                mBluetoothPingCount = getBluetoothPingCount();
+                mBluetoothPingStart = -1;
+            }
         }
 
-        // Track bt headset ping count
-        mBluetoothPingStart = getCurrentBluetoothPingCount();
-        mBluetoothPingCount = 0;
-    }
-
-    public void doPlugLocked(long elapsedRealtime, long batteryUptime, long batteryRealtime) {
-        for (int i = mUnpluggables.size() - 1; i >= 0; i--) {
-            mUnpluggables.get(i).plug(elapsedRealtime, batteryUptime, batteryRealtime);
+        boolean unpluggedScreenOff = unplugged && screenOff;
+        if (unpluggedScreenOff != mOnBatteryScreenOffTimeBase.isRunning()) {
+            updateKernelWakelocksLocked();
+            requestWakelockCpuUpdate();
+            if (!unpluggedScreenOff) {
+                // We are switching to no longer tracking wake locks, but we want
+                // the next CPU update we receive to take them in to account.
+                mDistributeWakelockCpu = true;
+            }
+            mOnBatteryScreenOffTimeBase.setRunning(unpluggedScreenOff, uptime, realtime);
         }
-
-        // Track bt headset ping count
-        mBluetoothPingCount = getBluetoothPingCount();
-        mBluetoothPingStart = -1;
     }
 
     public void addIsolatedUidLocked(int isolatedUid, int appUid) {
@@ -2033,6 +2229,13 @@
         addHistoryEventLocked(SystemClock.elapsedRealtime(), code, name, uid);
     }
 
+    private void requestWakelockCpuUpdate() {
+        if (!mHandler.hasMessages(MSG_UPDATE_WAKELOCKS)) {
+            Message m = mHandler.obtainMessage(MSG_UPDATE_WAKELOCKS);
+            mHandler.sendMessageDelayed(m, DELAY_UPDATE_WAKELOCKS);
+        }
+    }
+
     public void noteStartWakeLocked(int uid, int pid, String name, String historyName, int type,
             boolean unimportantForLogging) {
         uid = mapUid(uid);
@@ -2063,10 +2266,7 @@
             mWakeLockNesting++;
         }
         if (uid >= 0) {
-            if (!mHandler.hasMessages(MSG_UPDATE_WAKELOCKS)) {
-                Message m = mHandler.obtainMessage(MSG_UPDATE_WAKELOCKS);
-                mHandler.sendMessageDelayed(m, DELAY_UPDATE_WAKELOCKS);
-            }
+            requestWakelockCpuUpdate();
             getUidStatsLocked(uid).noteStartWakeLocked(pid, name, type, elapsedRealtime);
         }
     }
@@ -2084,10 +2284,7 @@
             }
         }
         if (uid >= 0) {
-            if (!mHandler.hasMessages(MSG_UPDATE_WAKELOCKS)) {
-                Message m = mHandler.obtainMessage(MSG_UPDATE_WAKELOCKS);
-                mHandler.sendMessageDelayed(m, DELAY_UPDATE_WAKELOCKS);
-            }
+            requestWakelockCpuUpdate();
             getUidStatsLocked(uid).noteStopWakeLocked(pid, name, type, elapsedRealtime);
         }
     }
@@ -2110,16 +2307,19 @@
     public int startAddingCpuLocked() {
         mHandler.removeMessages(MSG_UPDATE_WAKELOCKS);
 
-        if (mScreenOn) {
-            return 0;
-        }
-
         final int N = mPartialTimers.size();
         if (N == 0) {
             mLastPartialTimers.clear();
+            mDistributeWakelockCpu = false;
             return 0;
         }
 
+        if (!mOnBatteryScreenOffTimeBase.isRunning() && !mDistributeWakelockCpu) {
+            return 0;
+        }
+
+        mDistributeWakelockCpu = false;
+
         // How many timers should consume CPU?  Only want to include ones
         // that have already been in the list.
         for (int i=0; i<N; i++) {
@@ -2305,16 +2505,17 @@
                     + Integer.toHexString(mHistoryCur.states));
             addHistoryRecordLocked(elapsedRealtime);
             mScreenOn = true;
-            mScreenOnTimer.startRunningLocked(this, elapsedRealtime);
+            mScreenOnTimer.startRunningLocked(elapsedRealtime);
             if (mScreenBrightnessBin >= 0) {
-                mScreenBrightnessTimer[mScreenBrightnessBin].startRunningLocked(this,
-                        elapsedRealtime);
+                mScreenBrightnessTimer[mScreenBrightnessBin].startRunningLocked(elapsedRealtime);
             }
 
+            updateTimeBasesLocked(mOnBatteryTimeBase.isRunning(), false,
+                    SystemClock.uptimeMillis() * 1000, elapsedRealtime * 1000);
+
             // Fake a wake lock, so we consider the device waked as long
             // as the screen is on.
-            noteStartWakeLocked(Process.myUid(), Process.myPid(), "screen", null,
-                    WAKE_TYPE_PARTIAL, false);
+            noteStartWakeLocked(-1, -1, "screen", null, WAKE_TYPE_PARTIAL, false);
             
             // Update discharge amounts.
             if (mOnBatteryInternal) {
@@ -2331,14 +2532,16 @@
                     + Integer.toHexString(mHistoryCur.states));
             addHistoryRecordLocked(elapsedRealtime);
             mScreenOn = false;
-            mScreenOnTimer.stopRunningLocked(this, elapsedRealtime);
+            mScreenOnTimer.stopRunningLocked(elapsedRealtime);
             if (mScreenBrightnessBin >= 0) {
-                mScreenBrightnessTimer[mScreenBrightnessBin].stopRunningLocked(this,
-                        elapsedRealtime);
+                mScreenBrightnessTimer[mScreenBrightnessBin].stopRunningLocked(elapsedRealtime);
             }
 
-            noteStopWakeLocked(-1, -1, "dummy", WAKE_TYPE_PARTIAL);
-            
+            noteStopWakeLocked(-1, -1, "screen", WAKE_TYPE_PARTIAL);
+
+            updateTimeBasesLocked(mOnBatteryTimeBase.isRunning(), true,
+                    SystemClock.uptimeMillis() * 1000, elapsedRealtime * 1000);
+
             // Update discharge amounts.
             if (mOnBatteryInternal) {
                 updateDischargeScreenLevelsLocked(true, false);
@@ -2360,10 +2563,9 @@
             addHistoryRecordLocked(elapsedRealtime);
             if (mScreenOn) {
                 if (mScreenBrightnessBin >= 0) {
-                    mScreenBrightnessTimer[mScreenBrightnessBin].stopRunningLocked(this,
-                            elapsedRealtime);
+                    mScreenBrightnessTimer[mScreenBrightnessBin].stopRunningLocked(elapsedRealtime);
                 }
-                mScreenBrightnessTimer[bin].startRunningLocked(this, elapsedRealtime);
+                mScreenBrightnessTimer[bin].startRunningLocked(elapsedRealtime);
             }
             mScreenBrightnessBin = bin;
         }
@@ -2391,12 +2593,12 @@
                 addHistoryRecordLocked(elapsedRealtime);
                 mMobileRadioActive = active;
                 if (active) {
-                    mMobileRadioActiveTimer.startRunningLocked(this, elapsedRealtime);
-                    mMobileRadioActivePerAppTimer.startRunningLocked(this, elapsedRealtime);
+                    mMobileRadioActiveTimer.startRunningLocked(elapsedRealtime);
+                    mMobileRadioActivePerAppTimer.startRunningLocked(elapsedRealtime);
                 } else {
                     updateNetworkActivityLocked(NET_UPDATE_MOBILE, elapsedRealtime);
-                    mMobileRadioActiveTimer.stopRunningLocked(this, elapsedRealtime);
-                    mMobileRadioActivePerAppTimer.stopRunningLocked(this, elapsedRealtime);
+                    mMobileRadioActiveTimer.stopRunningLocked(elapsedRealtime);
+                    mMobileRadioActivePerAppTimer.stopRunningLocked(elapsedRealtime);
                 }
             }
         }
@@ -2410,7 +2612,7 @@
                     + Integer.toHexString(mHistoryCur.states));
             addHistoryRecordLocked(elapsedRealtime);
             mPhoneOn = true;
-            mPhoneOnTimer.startRunningLocked(this, elapsedRealtime);
+            mPhoneOnTimer.startRunningLocked(elapsedRealtime);
         }
     }
 
@@ -2422,7 +2624,7 @@
                     + Integer.toHexString(mHistoryCur.states));
             addHistoryRecordLocked(elapsedRealtime);
             mPhoneOn = false;
-            mPhoneOnTimer.stopRunningLocked(this, elapsedRealtime);
+            mPhoneOnTimer.stopRunningLocked(elapsedRealtime);
         }
     }
 
@@ -2433,7 +2635,7 @@
                 continue;
             }
             while (mPhoneSignalStrengthsTimer[i].isRunningLocked()) {
-                mPhoneSignalStrengthsTimer[i].stopRunningLocked(this, elapsedRealtime);
+                mPhoneSignalStrengthsTimer[i].stopRunningLocked(elapsedRealtime);
             }
         }
     }
@@ -2488,7 +2690,7 @@
                 newHistory = true;
                 if (DEBUG_HISTORY) Slog.v(TAG, "Phone started scanning to: "
                         + Integer.toHexString(mHistoryCur.states));
-                mPhoneSignalScanningTimer.startRunningLocked(this, elapsedRealtime);
+                mPhoneSignalScanningTimer.startRunningLocked(elapsedRealtime);
             }
         }
 
@@ -2499,7 +2701,7 @@
                 if (DEBUG_HISTORY) Slog.v(TAG, "Phone stopped scanning to: "
                         + Integer.toHexString(mHistoryCur.states));
                 newHistory = true;
-                mPhoneSignalScanningTimer.stopRunningLocked(this, elapsedRealtime);
+                mPhoneSignalScanningTimer.stopRunningLocked(elapsedRealtime);
             }
         }
 
@@ -2514,13 +2716,12 @@
 
         if (mPhoneSignalStrengthBin != strengthBin) {
             if (mPhoneSignalStrengthBin >= 0) {
-                mPhoneSignalStrengthsTimer[mPhoneSignalStrengthBin].stopRunningLocked(this,
+                mPhoneSignalStrengthsTimer[mPhoneSignalStrengthBin].stopRunningLocked(
                         elapsedRealtime);
             }
             if (strengthBin >= 0) {
                 if (!mPhoneSignalStrengthsTimer[strengthBin].isRunningLocked()) {
-                    mPhoneSignalStrengthsTimer[strengthBin].startRunningLocked(this,
-                            elapsedRealtime);
+                    mPhoneSignalStrengthsTimer[strengthBin].startRunningLocked(elapsedRealtime);
                 }
                 mHistoryCur.states = (mHistoryCur.states&~HistoryItem.STATE_SIGNAL_STRENGTH_MASK)
                         | (strengthBin << HistoryItem.STATE_SIGNAL_STRENGTH_SHIFT);
@@ -2615,11 +2816,11 @@
                     + Integer.toHexString(mHistoryCur.states));
             addHistoryRecordLocked(elapsedRealtime);
             if (mPhoneDataConnectionType >= 0) {
-                mPhoneDataConnectionsTimer[mPhoneDataConnectionType].stopRunningLocked(this,
+                mPhoneDataConnectionsTimer[mPhoneDataConnectionType].stopRunningLocked(
                         elapsedRealtime);
             }
             mPhoneDataConnectionType = bin;
-            mPhoneDataConnectionsTimer[bin].startRunningLocked(this, elapsedRealtime);
+            mPhoneDataConnectionsTimer[bin].startRunningLocked(elapsedRealtime);
         }
     }
 
@@ -2631,7 +2832,7 @@
                     + Integer.toHexString(mHistoryCur.states));
             addHistoryRecordLocked(elapsedRealtime);
             mWifiOn = true;
-            mWifiOnTimer.startRunningLocked(this, elapsedRealtime);
+            mWifiOnTimer.startRunningLocked(elapsedRealtime);
         }
     }
 
@@ -2643,7 +2844,7 @@
                     + Integer.toHexString(mHistoryCur.states));
             addHistoryRecordLocked(elapsedRealtime);
             mWifiOn = false;
-            mWifiOnTimer.stopRunningLocked(this, elapsedRealtime);
+            mWifiOnTimer.stopRunningLocked(elapsedRealtime);
         }
         if (mWifiOnUid >= 0) {
             getUidStatsLocked(mWifiOnUid).noteWifiStoppedLocked(elapsedRealtime);
@@ -2660,7 +2861,7 @@
                     + Integer.toHexString(mHistoryCur.states));
             addHistoryRecordLocked(SystemClock.elapsedRealtime());
             mAudioOn = true;
-            mAudioOnTimer.startRunningLocked(this, elapsedRealtime);
+            mAudioOnTimer.startRunningLocked(elapsedRealtime);
         }
         getUidStatsLocked(uid).noteAudioTurnedOnLocked(elapsedRealtime);
     }
@@ -2674,7 +2875,7 @@
                     + Integer.toHexString(mHistoryCur.states));
             addHistoryRecordLocked(SystemClock.elapsedRealtime());
             mAudioOn = false;
-            mAudioOnTimer.stopRunningLocked(this, elapsedRealtime);
+            mAudioOnTimer.stopRunningLocked(elapsedRealtime);
         }
         getUidStatsLocked(uid).noteAudioTurnedOffLocked(elapsedRealtime);
     }
@@ -2688,7 +2889,7 @@
                     + Integer.toHexString(mHistoryCur.states));
             addHistoryRecordLocked(SystemClock.elapsedRealtime());
             mVideoOn = true;
-            mVideoOnTimer.startRunningLocked(this, elapsedRealtime);
+            mVideoOnTimer.startRunningLocked(elapsedRealtime);
         }
         getUidStatsLocked(uid).noteVideoTurnedOnLocked(elapsedRealtime);
     }
@@ -2702,7 +2903,7 @@
                     + Integer.toHexString(mHistoryCur.states));
             addHistoryRecordLocked(SystemClock.elapsedRealtime());
             mVideoOn = false;
-            mVideoOnTimer.stopRunningLocked(this, elapsedRealtime);
+            mVideoOnTimer.stopRunningLocked(elapsedRealtime);
         }
         getUidStatsLocked(uid).noteVideoTurnedOffLocked(elapsedRealtime);
     }
@@ -2735,7 +2936,7 @@
                     + Integer.toHexString(mHistoryCur.states));
             addHistoryRecordLocked(SystemClock.elapsedRealtime());
             mGlobalWifiRunning = true;
-            mGlobalWifiRunningTimer.startRunningLocked(this, elapsedRealtime);
+            mGlobalWifiRunningTimer.startRunningLocked(elapsedRealtime);
             int N = ws.size();
             for (int i=0; i<N; i++) {
                 int uid = mapUid(ws.get(i));
@@ -2772,7 +2973,7 @@
                     + Integer.toHexString(mHistoryCur.states));
             addHistoryRecordLocked(elapsedRealtime);
             mGlobalWifiRunning = false;
-            mGlobalWifiRunningTimer.stopRunningLocked(this, elapsedRealtime);
+            mGlobalWifiRunningTimer.stopRunningLocked(elapsedRealtime);
             int N = ws.size();
             for (int i=0; i<N; i++) {
                 int uid = mapUid(ws.get(i));
@@ -2788,10 +2989,10 @@
         if (mWifiState != wifiState) {
             final long elapsedRealtime = SystemClock.elapsedRealtime();
             if (mWifiState >= 0) {
-                mWifiStateTimer[mWifiState].stopRunningLocked(this, elapsedRealtime);
+                mWifiStateTimer[mWifiState].stopRunningLocked(elapsedRealtime);
             }
             mWifiState = wifiState;
-            mWifiStateTimer[wifiState].startRunningLocked(this, elapsedRealtime);
+            mWifiStateTimer[wifiState].startRunningLocked(elapsedRealtime);
         }
     }
 
@@ -2803,7 +3004,7 @@
                     + Integer.toHexString(mHistoryCur.states));
             addHistoryRecordLocked(elapsedRealtime);
             mBluetoothOn = true;
-            mBluetoothOnTimer.startRunningLocked(this, elapsedRealtime);
+            mBluetoothOnTimer.startRunningLocked(elapsedRealtime);
         }
     }
 
@@ -2815,7 +3016,7 @@
                     + Integer.toHexString(mHistoryCur.states));
             addHistoryRecordLocked(elapsedRealtime);
             mBluetoothOn = false;
-            mBluetoothOnTimer.stopRunningLocked(this, elapsedRealtime);
+            mBluetoothOnTimer.stopRunningLocked(elapsedRealtime);
         }
     }
 
@@ -2824,11 +3025,10 @@
         if (mBluetoothState != bluetoothState) {
             final long elapsedRealtime = SystemClock.elapsedRealtime();
             if (mBluetoothState >= 0) {
-                mBluetoothStateTimer[mBluetoothState].stopRunningLocked(this,
-                        elapsedRealtime);
+                mBluetoothStateTimer[mBluetoothState].stopRunningLocked(elapsedRealtime);
             }
             mBluetoothState = bluetoothState;
-            mBluetoothStateTimer[bluetoothState].startRunningLocked(this, elapsedRealtime);
+            mBluetoothStateTimer[bluetoothState].startRunningLocked(elapsedRealtime);
         }
     }
 
@@ -3033,8 +3233,8 @@
         updateNetworkActivityLocked(NET_UPDATE_ALL, SystemClock.elapsedRealtime());
     }
 
-    @Override public long getScreenOnTime(long batteryRealtime, int which) {
-        return mScreenOnTimer.getTotalTimeLocked(batteryRealtime, which);
+    @Override public long getScreenOnTime(long elapsedRealtimeUs, int which) {
+        return mScreenOnTimer.getTotalTimeLocked(elapsedRealtimeUs, which);
     }
 
     @Override public int getScreenOnCount(int which) {
@@ -3042,17 +3242,17 @@
     }
 
     @Override public long getScreenBrightnessTime(int brightnessBin,
-            long batteryRealtime, int which) {
+            long elapsedRealtimeUs, int which) {
         return mScreenBrightnessTimer[brightnessBin].getTotalTimeLocked(
-                batteryRealtime, which);
+                elapsedRealtimeUs, which);
     }
 
     @Override public int getInputEventCount(int which) {
         return mInputEventCounter.getCountLocked(which);
     }
 
-    @Override public long getPhoneOnTime(long batteryRealtime, int which) {
-        return mPhoneOnTimer.getTotalTimeLocked(batteryRealtime, which);
+    @Override public long getPhoneOnTime(long elapsedRealtimeUs, int which) {
+        return mPhoneOnTimer.getTotalTimeLocked(elapsedRealtimeUs, which);
     }
 
     @Override public int getPhoneOnCount(int which) {
@@ -3060,15 +3260,15 @@
     }
 
     @Override public long getPhoneSignalStrengthTime(int strengthBin,
-            long batteryRealtime, int which) {
+            long elapsedRealtimeUs, int which) {
         return mPhoneSignalStrengthsTimer[strengthBin].getTotalTimeLocked(
-                batteryRealtime, which);
+                elapsedRealtimeUs, which);
     }
 
     @Override public long getPhoneSignalScanningTime(
-            long batteryRealtime, int which) {
+            long elapsedRealtimeUs, int which) {
         return mPhoneSignalScanningTimer.getTotalTimeLocked(
-                batteryRealtime, which);
+                elapsedRealtimeUs, which);
     }
 
     @Override public int getPhoneSignalStrengthCount(int strengthBin, int which) {
@@ -3076,17 +3276,17 @@
     }
 
     @Override public long getPhoneDataConnectionTime(int dataType,
-            long batteryRealtime, int which) {
+            long elapsedRealtimeUs, int which) {
         return mPhoneDataConnectionsTimer[dataType].getTotalTimeLocked(
-                batteryRealtime, which);
+                elapsedRealtimeUs, which);
     }
 
     @Override public int getPhoneDataConnectionCount(int dataType, int which) {
         return mPhoneDataConnectionsTimer[dataType].getCountLocked(which);
     }
 
-    @Override public long getMobileRadioActiveTime(long batteryRealtime, int which) {
-        return mMobileRadioActiveTimer.getTotalTimeLocked(batteryRealtime, which);
+    @Override public long getMobileRadioActiveTime(long elapsedRealtimeUs, int which) {
+        return mMobileRadioActiveTimer.getTotalTimeLocked(elapsedRealtimeUs, which);
     }
 
     @Override public int getMobileRadioActiveCount(int which) {
@@ -3101,32 +3301,32 @@
         return (int)mMobileRadioActiveUnknownCount.getCountLocked(which);
     }
 
-    @Override public long getWifiOnTime(long batteryRealtime, int which) {
-        return mWifiOnTimer.getTotalTimeLocked(batteryRealtime, which);
+    @Override public long getWifiOnTime(long elapsedRealtimeUs, int which) {
+        return mWifiOnTimer.getTotalTimeLocked(elapsedRealtimeUs, which);
     }
 
-    @Override public long getGlobalWifiRunningTime(long batteryRealtime, int which) {
-        return mGlobalWifiRunningTimer.getTotalTimeLocked(batteryRealtime, which);
+    @Override public long getGlobalWifiRunningTime(long elapsedRealtimeUs, int which) {
+        return mGlobalWifiRunningTimer.getTotalTimeLocked(elapsedRealtimeUs, which);
     }
 
     @Override public long getWifiStateTime(int wifiState,
-            long batteryRealtime, int which) {
+            long elapsedRealtimeUs, int which) {
         return mWifiStateTimer[wifiState].getTotalTimeLocked(
-                batteryRealtime, which);
+                elapsedRealtimeUs, which);
     }
 
     @Override public int getWifiStateCount(int wifiState, int which) {
         return mWifiStateTimer[wifiState].getCountLocked(which);
     }
 
-    @Override public long getBluetoothOnTime(long batteryRealtime, int which) {
-        return mBluetoothOnTimer.getTotalTimeLocked(batteryRealtime, which);
+    @Override public long getBluetoothOnTime(long elapsedRealtimeUs, int which) {
+        return mBluetoothOnTimer.getTotalTimeLocked(elapsedRealtimeUs, which);
     }
 
     @Override public long getBluetoothStateTime(int bluetoothState,
-            long batteryRealtime, int which) {
+            long elapsedRealtimeUs, int which) {
         return mBluetoothStateTimer[bluetoothState].getTotalTimeLocked(
-                batteryRealtime, which);
+                elapsedRealtimeUs, which);
     }
 
     @Override public int getBluetoothStateCount(int bluetoothState, int which) {
@@ -3231,14 +3431,14 @@
         public Uid(int uid) {
             mUid = uid;
             mWifiRunningTimer = new StopwatchTimer(Uid.this, WIFI_RUNNING,
-                    mWifiRunningTimers, mUnpluggables);
+                    mWifiRunningTimers, mOnBatteryTimeBase);
             mFullWifiLockTimer = new StopwatchTimer(Uid.this, FULL_WIFI_LOCK,
-                    mFullWifiLockTimers, mUnpluggables);
+                    mFullWifiLockTimers, mOnBatteryTimeBase);
             mWifiScanTimer = new StopwatchTimer(Uid.this, WIFI_SCAN,
-                    mWifiScanTimers, mUnpluggables);
+                    mWifiScanTimers, mOnBatteryTimeBase);
             mWifiBatchedScanTimer = new StopwatchTimer[NUM_WIFI_BATCHED_SCAN_BINS];
             mWifiMulticastTimer = new StopwatchTimer(Uid.this, WIFI_MULTICAST_ENABLED,
-                    mWifiMulticastTimers, mUnpluggables);
+                    mWifiMulticastTimers, mOnBatteryTimeBase);
         }
 
         @Override
@@ -3267,67 +3467,67 @@
         }
 
         @Override
-        public void noteWifiRunningLocked(long elapsedRealtime) {
+        public void noteWifiRunningLocked(long elapsedRealtimeMs) {
             if (!mWifiRunning) {
                 mWifiRunning = true;
                 if (mWifiRunningTimer == null) {
                     mWifiRunningTimer = new StopwatchTimer(Uid.this, WIFI_RUNNING,
-                            mWifiRunningTimers, mUnpluggables);
+                            mWifiRunningTimers, mOnBatteryTimeBase);
                 }
-                mWifiRunningTimer.startRunningLocked(BatteryStatsImpl.this, elapsedRealtime);
+                mWifiRunningTimer.startRunningLocked(elapsedRealtimeMs);
             }
         }
 
         @Override
-        public void noteWifiStoppedLocked(long elapsedRealtime) {
+        public void noteWifiStoppedLocked(long elapsedRealtimeMs) {
             if (mWifiRunning) {
                 mWifiRunning = false;
-                mWifiRunningTimer.stopRunningLocked(BatteryStatsImpl.this, elapsedRealtime);
+                mWifiRunningTimer.stopRunningLocked(elapsedRealtimeMs);
             }
         }
 
         @Override
-        public void noteFullWifiLockAcquiredLocked(long elapsedRealtime) {
+        public void noteFullWifiLockAcquiredLocked(long elapsedRealtimeMs) {
             if (!mFullWifiLockOut) {
                 mFullWifiLockOut = true;
                 if (mFullWifiLockTimer == null) {
                     mFullWifiLockTimer = new StopwatchTimer(Uid.this, FULL_WIFI_LOCK,
-                            mFullWifiLockTimers, mUnpluggables);
+                            mFullWifiLockTimers, mOnBatteryTimeBase);
                 }
-                mFullWifiLockTimer.startRunningLocked(BatteryStatsImpl.this, elapsedRealtime);
+                mFullWifiLockTimer.startRunningLocked(elapsedRealtimeMs);
             }
         }
 
         @Override
-        public void noteFullWifiLockReleasedLocked(long elapsedRealtime) {
+        public void noteFullWifiLockReleasedLocked(long elapsedRealtimeMs) {
             if (mFullWifiLockOut) {
                 mFullWifiLockOut = false;
-                mFullWifiLockTimer.stopRunningLocked(BatteryStatsImpl.this, elapsedRealtime);
+                mFullWifiLockTimer.stopRunningLocked(elapsedRealtimeMs);
             }
         }
 
         @Override
-        public void noteWifiScanStartedLocked(long elapsedRealtime) {
+        public void noteWifiScanStartedLocked(long elapsedRealtimeMs) {
             if (!mWifiScanStarted) {
                 mWifiScanStarted = true;
                 if (mWifiScanTimer == null) {
                     mWifiScanTimer = new StopwatchTimer(Uid.this, WIFI_SCAN,
-                            mWifiScanTimers, mUnpluggables);
+                            mWifiScanTimers, mOnBatteryTimeBase);
                 }
-                mWifiScanTimer.startRunningLocked(BatteryStatsImpl.this, elapsedRealtime);
+                mWifiScanTimer.startRunningLocked(elapsedRealtimeMs);
             }
         }
 
         @Override
-        public void noteWifiScanStoppedLocked(long elapsedRealtime) {
+        public void noteWifiScanStoppedLocked(long elapsedRealtimeMs) {
             if (mWifiScanStarted) {
                 mWifiScanStarted = false;
-                mWifiScanTimer.stopRunningLocked(BatteryStatsImpl.this, elapsedRealtime);
+                mWifiScanTimer.stopRunningLocked(elapsedRealtimeMs);
             }
         }
 
         @Override
-        public void noteWifiBatchedScanStartedLocked(int csph, long elapsedRealtime) {
+        public void noteWifiBatchedScanStartedLocked(int csph, long elapsedRealtimeMs) {
             int bin = 0;
             while (csph > 8 && bin < NUM_WIFI_BATCHED_SCAN_BINS) {
                 csph = csph >> 3;
@@ -3338,67 +3538,66 @@
 
             if (mWifiBatchedScanBinStarted != NO_BATCHED_SCAN_STARTED) {
                 mWifiBatchedScanTimer[mWifiBatchedScanBinStarted].
-                        stopRunningLocked(BatteryStatsImpl.this, elapsedRealtime);
+                        stopRunningLocked(elapsedRealtimeMs);
             }
             mWifiBatchedScanBinStarted = bin;
             if (mWifiBatchedScanTimer[bin] == null) {
                 makeWifiBatchedScanBin(bin, null);
             }
-            mWifiBatchedScanTimer[bin].startRunningLocked(BatteryStatsImpl.this, elapsedRealtime);
+            mWifiBatchedScanTimer[bin].startRunningLocked(elapsedRealtimeMs);
         }
 
         @Override
-        public void noteWifiBatchedScanStoppedLocked(long elapsedRealtime) {
+        public void noteWifiBatchedScanStoppedLocked(long elapsedRealtimeMs) {
             if (mWifiBatchedScanBinStarted != NO_BATCHED_SCAN_STARTED) {
                 mWifiBatchedScanTimer[mWifiBatchedScanBinStarted].
-                        stopRunningLocked(BatteryStatsImpl.this, elapsedRealtime);
+                        stopRunningLocked(elapsedRealtimeMs);
                 mWifiBatchedScanBinStarted = NO_BATCHED_SCAN_STARTED;
             }
         }
 
         @Override
-        public void noteWifiMulticastEnabledLocked(long elapsedRealtime) {
+        public void noteWifiMulticastEnabledLocked(long elapsedRealtimeMs) {
             if (!mWifiMulticastEnabled) {
                 mWifiMulticastEnabled = true;
                 if (mWifiMulticastTimer == null) {
                     mWifiMulticastTimer = new StopwatchTimer(Uid.this, WIFI_MULTICAST_ENABLED,
-                            mWifiMulticastTimers, mUnpluggables);
+                            mWifiMulticastTimers, mOnBatteryTimeBase);
                 }
-                mWifiMulticastTimer.startRunningLocked(BatteryStatsImpl.this, elapsedRealtime);
+                mWifiMulticastTimer.startRunningLocked(elapsedRealtimeMs);
             }
         }
 
         @Override
-        public void noteWifiMulticastDisabledLocked(long elapsedRealtime) {
+        public void noteWifiMulticastDisabledLocked(long elapsedRealtimeMs) {
             if (mWifiMulticastEnabled) {
                 mWifiMulticastEnabled = false;
-                mWifiMulticastTimer.stopRunningLocked(BatteryStatsImpl.this, elapsedRealtime);
+                mWifiMulticastTimer.stopRunningLocked(elapsedRealtimeMs);
             }
         }
 
         public StopwatchTimer createAudioTurnedOnTimerLocked() {
             if (mAudioTurnedOnTimer == null) {
                 mAudioTurnedOnTimer = new StopwatchTimer(Uid.this, AUDIO_TURNED_ON,
-                        null, mUnpluggables);
+                        null, mOnBatteryTimeBase);
             }
             return mAudioTurnedOnTimer;
         }
 
         @Override
-        public void noteAudioTurnedOnLocked(long elapsedRealtime) {
+        public void noteAudioTurnedOnLocked(long elapsedRealtimeMs) {
             if (!mAudioTurnedOn) {
                 mAudioTurnedOn = true;
-                createAudioTurnedOnTimerLocked().startRunningLocked(BatteryStatsImpl.this,
-                        elapsedRealtime);
+                createAudioTurnedOnTimerLocked().startRunningLocked(elapsedRealtimeMs);
             }
         }
 
         @Override
-        public void noteAudioTurnedOffLocked(long elapsedRealtime) {
+        public void noteAudioTurnedOffLocked(long elapsedRealtimeMs) {
             if (mAudioTurnedOn) {
                 mAudioTurnedOn = false;
                 if (mAudioTurnedOnTimer != null) {
-                    mAudioTurnedOnTimer.stopRunningLocked(BatteryStatsImpl.this, elapsedRealtime);
+                    mAudioTurnedOnTimer.stopRunningLocked(elapsedRealtimeMs);
                 }
             }
         }
@@ -3406,26 +3605,25 @@
         public StopwatchTimer createVideoTurnedOnTimerLocked() {
             if (mVideoTurnedOnTimer == null) {
                 mVideoTurnedOnTimer = new StopwatchTimer(Uid.this, VIDEO_TURNED_ON,
-                        null, mUnpluggables);
+                        null, mOnBatteryTimeBase);
             }
             return mVideoTurnedOnTimer;
         }
 
         @Override
-        public void noteVideoTurnedOnLocked(long elapsedRealtime) {
+        public void noteVideoTurnedOnLocked(long elapsedRealtimeMs) {
             if (!mVideoTurnedOn) {
                 mVideoTurnedOn = true;
-                createVideoTurnedOnTimerLocked().startRunningLocked(BatteryStatsImpl.this,
-                        elapsedRealtime);
+                createVideoTurnedOnTimerLocked().startRunningLocked(elapsedRealtimeMs);
             }
         }
 
         @Override
-        public void noteVideoTurnedOffLocked(long elapsedRealtime) {
+        public void noteVideoTurnedOffLocked(long elapsedRealtimeMs) {
             if (mVideoTurnedOn) {
                 mVideoTurnedOn = false;
                 if (mVideoTurnedOnTimer != null) {
-                    mVideoTurnedOnTimer.stopRunningLocked(BatteryStatsImpl.this, elapsedRealtime);
+                    mVideoTurnedOnTimer.stopRunningLocked(elapsedRealtimeMs);
                 }
             }
         }
@@ -3433,29 +3631,27 @@
         public StopwatchTimer createForegroundActivityTimerLocked() {
             if (mForegroundActivityTimer == null) {
                 mForegroundActivityTimer = new StopwatchTimer(
-                        Uid.this, FOREGROUND_ACTIVITY, null, mUnpluggables);
+                        Uid.this, FOREGROUND_ACTIVITY, null, mOnBatteryTimeBase);
             }
             return mForegroundActivityTimer;
         }
 
         @Override
-        public void noteActivityResumedLocked(long elapsedRealtime) {
+        public void noteActivityResumedLocked(long elapsedRealtimeMs) {
             // We always start, since we want multiple foreground PIDs to nest
-            createForegroundActivityTimerLocked().startRunningLocked(BatteryStatsImpl.this,
-                    elapsedRealtime);
+            createForegroundActivityTimerLocked().startRunningLocked(elapsedRealtimeMs);
         }
 
         @Override
-        public void noteActivityPausedLocked(long elapsedRealtime) {
+        public void noteActivityPausedLocked(long elapsedRealtimeMs) {
             if (mForegroundActivityTimer != null) {
-                mForegroundActivityTimer.stopRunningLocked(BatteryStatsImpl.this, elapsedRealtime);
+                mForegroundActivityTimer.stopRunningLocked(elapsedRealtimeMs);
             }
         }
 
         public BatchTimer createVibratorOnTimerLocked() {
             if (mVibratorOnTimer == null) {
-                mVibratorOnTimer = new BatchTimer(Uid.this, VIBRATOR_ON,
-                        mUnpluggables, BatteryStatsImpl.this.mOnBatteryInternal);
+                mVibratorOnTimer = new BatchTimer(Uid.this, VIBRATOR_ON, mOnBatteryTimeBase);
             }
             return mVibratorOnTimer;
         }
@@ -3471,61 +3667,60 @@
         }
 
         @Override
-        public long getWifiRunningTime(long batteryRealtime, int which) {
+        public long getWifiRunningTime(long elapsedRealtimeUs, int which) {
             if (mWifiRunningTimer == null) {
                 return 0;
             }
-            return mWifiRunningTimer.getTotalTimeLocked(batteryRealtime, which);
+            return mWifiRunningTimer.getTotalTimeLocked(elapsedRealtimeUs, which);
         }
 
         @Override
-        public long getFullWifiLockTime(long batteryRealtime, int which) {
+        public long getFullWifiLockTime(long elapsedRealtimeUs, int which) {
             if (mFullWifiLockTimer == null) {
                 return 0;
             }
-            return mFullWifiLockTimer.getTotalTimeLocked(batteryRealtime, which);
+            return mFullWifiLockTimer.getTotalTimeLocked(elapsedRealtimeUs, which);
         }
 
         @Override
-        public long getWifiScanTime(long batteryRealtime, int which) {
+        public long getWifiScanTime(long elapsedRealtimeUs, int which) {
             if (mWifiScanTimer == null) {
                 return 0;
             }
-            return mWifiScanTimer.getTotalTimeLocked(batteryRealtime, which);
+            return mWifiScanTimer.getTotalTimeLocked(elapsedRealtimeUs, which);
         }
 
         @Override
-        public long getWifiBatchedScanTime(int csphBin, long batteryRealtime, int which) {
+        public long getWifiBatchedScanTime(int csphBin, long elapsedRealtimeUs, int which) {
             if (csphBin < 0 || csphBin >= NUM_WIFI_BATCHED_SCAN_BINS) return 0;
             if (mWifiBatchedScanTimer[csphBin] == null) {
                 return 0;
             }
-            return mWifiBatchedScanTimer[csphBin].getTotalTimeLocked(batteryRealtime, which);
+            return mWifiBatchedScanTimer[csphBin].getTotalTimeLocked(elapsedRealtimeUs, which);
         }
 
         @Override
-        public long getWifiMulticastTime(long batteryRealtime, int which) {
+        public long getWifiMulticastTime(long elapsedRealtimeUs, int which) {
             if (mWifiMulticastTimer == null) {
                 return 0;
             }
-            return mWifiMulticastTimer.getTotalTimeLocked(batteryRealtime,
-                                                          which);
+            return mWifiMulticastTimer.getTotalTimeLocked(elapsedRealtimeUs, which);
         }
 
         @Override
-        public long getAudioTurnedOnTime(long batteryRealtime, int which) {
+        public long getAudioTurnedOnTime(long elapsedRealtimeUs, int which) {
             if (mAudioTurnedOnTimer == null) {
                 return 0;
             }
-            return mAudioTurnedOnTimer.getTotalTimeLocked(batteryRealtime, which);
+            return mAudioTurnedOnTimer.getTotalTimeLocked(elapsedRealtimeUs, which);
         }
 
         @Override
-        public long getVideoTurnedOnTime(long batteryRealtime, int which) {
+        public long getVideoTurnedOnTime(long elapsedRealtimeUs, int which) {
             if (mVideoTurnedOnTimer == null) {
                 return 0;
             }
-            return mVideoTurnedOnTimer.getTotalTimeLocked(batteryRealtime, which);
+            return mVideoTurnedOnTimer.getTotalTimeLocked(elapsedRealtimeUs, which);
         }
 
         @Override
@@ -3574,10 +3769,10 @@
             }
             if (in == null) {
                 mWifiBatchedScanTimer[i] = new StopwatchTimer(this, WIFI_BATCHED_SCAN, collected,
-                        mUnpluggables);
+                        mOnBatteryTimeBase);
             } else {
                 mWifiBatchedScanTimer[i] = new StopwatchTimer(this, WIFI_BATCHED_SCAN, collected,
-                        mUnpluggables, in);
+                        mOnBatteryTimeBase, in);
             }
         }
 
@@ -3585,7 +3780,7 @@
         void initUserActivityLocked() {
             mUserActivityCounters = new Counter[NUM_USER_ACTIVITY_TYPES];
             for (int i=0; i<NUM_USER_ACTIVITY_TYPES; i++) {
-                mUserActivityCounters[i] = new Counter(mUnpluggables);
+                mUserActivityCounters[i] = new Counter(mOnBatteryTimeBase);
             }
         }
 
@@ -3651,11 +3846,11 @@
             mNetworkByteActivityCounters = new LongSamplingCounter[NUM_NETWORK_ACTIVITY_TYPES];
             mNetworkPacketActivityCounters = new LongSamplingCounter[NUM_NETWORK_ACTIVITY_TYPES];
             for (int i = 0; i < NUM_NETWORK_ACTIVITY_TYPES; i++) {
-                mNetworkByteActivityCounters[i] = new LongSamplingCounter(mUnpluggables);
-                mNetworkPacketActivityCounters[i] = new LongSamplingCounter(mUnpluggables);
+                mNetworkByteActivityCounters[i] = new LongSamplingCounter(mOnBatteryTimeBase);
+                mNetworkPacketActivityCounters[i] = new LongSamplingCounter(mOnBatteryTimeBase);
             }
-            mMobileRadioActiveTime = new LongSamplingCounter(mUnpluggables);
-            mMobileRadioActiveCount = new LongSamplingCounter(mUnpluggables);
+            mMobileRadioActiveTime = new LongSamplingCounter(mOnBatteryTimeBase);
+            mMobileRadioActiveCount = new LongSamplingCounter(mOnBatteryTimeBase);
         }
 
         /**
@@ -3666,42 +3861,42 @@
             boolean active = false;
 
             if (mWifiRunningTimer != null) {
-                active |= !mWifiRunningTimer.reset(BatteryStatsImpl.this, false);
+                active |= !mWifiRunningTimer.reset(false);
                 active |= mWifiRunning;
             }
             if (mFullWifiLockTimer != null) {
-                active |= !mFullWifiLockTimer.reset(BatteryStatsImpl.this, false);
+                active |= !mFullWifiLockTimer.reset(false);
                 active |= mFullWifiLockOut;
             }
             if (mWifiScanTimer != null) {
-                active |= !mWifiScanTimer.reset(BatteryStatsImpl.this, false);
+                active |= !mWifiScanTimer.reset(false);
                 active |= mWifiScanStarted;
             }
             if (mWifiBatchedScanTimer != null) {
                 for (int i = 0; i < NUM_WIFI_BATCHED_SCAN_BINS; i++) {
                     if (mWifiBatchedScanTimer[i] != null) {
-                        active |= !mWifiBatchedScanTimer[i].reset(BatteryStatsImpl.this, false);
+                        active |= !mWifiBatchedScanTimer[i].reset(false);
                     }
                 }
                 active |= (mWifiBatchedScanBinStarted != NO_BATCHED_SCAN_STARTED);
             }
             if (mWifiMulticastTimer != null) {
-                active |= !mWifiMulticastTimer.reset(BatteryStatsImpl.this, false);
+                active |= !mWifiMulticastTimer.reset(false);
                 active |= mWifiMulticastEnabled;
             }
             if (mAudioTurnedOnTimer != null) {
-                active |= !mAudioTurnedOnTimer.reset(BatteryStatsImpl.this, false);
+                active |= !mAudioTurnedOnTimer.reset(false);
                 active |= mAudioTurnedOn;
             }
             if (mVideoTurnedOnTimer != null) {
-                active |= !mVideoTurnedOnTimer.reset(BatteryStatsImpl.this, false);
+                active |= !mVideoTurnedOnTimer.reset(false);
                 active |= mVideoTurnedOn;
             }
             if (mForegroundActivityTimer != null) {
-                active |= !mForegroundActivityTimer.reset(BatteryStatsImpl.this, false);
+                active |= !mForegroundActivityTimer.reset(false);
             }
             if (mVibratorOnTimer != null) {
-                if (mVibratorOnTimer.reset(BatteryStatsImpl.this, false)) {
+                if (mVibratorOnTimer.reset(false)) {
                     mVibratorOnTimer.detach();
                     mVibratorOnTimer = null;
                 } else {
@@ -3830,19 +4025,19 @@
             return !active;
         }
 
-        void writeToParcelLocked(Parcel out, long batteryRealtime) {
+        void writeToParcelLocked(Parcel out, long elapsedRealtimeUs) {
             out.writeInt(mWakelockStats.size());
             for (Map.Entry<String, Uid.Wakelock> wakelockEntry : mWakelockStats.entrySet()) {
                 out.writeString(wakelockEntry.getKey());
                 Uid.Wakelock wakelock = wakelockEntry.getValue();
-                wakelock.writeToParcelLocked(out, batteryRealtime);
+                wakelock.writeToParcelLocked(out, elapsedRealtimeUs);
             }
 
             out.writeInt(mSensorStats.size());
             for (Map.Entry<Integer, Uid.Sensor> sensorEntry : mSensorStats.entrySet()) {
                 out.writeInt(sensorEntry.getKey());
                 Uid.Sensor sensor = sensorEntry.getValue();
-                sensor.writeToParcelLocked(out, batteryRealtime);
+                sensor.writeToParcelLocked(out, elapsedRealtimeUs);
             }
 
             out.writeInt(mProcessStats.size());
@@ -3861,57 +4056,57 @@
 
             if (mWifiRunningTimer != null) {
                 out.writeInt(1);
-                mWifiRunningTimer.writeToParcel(out, batteryRealtime);
+                mWifiRunningTimer.writeToParcel(out, elapsedRealtimeUs);
             } else {
                 out.writeInt(0);
             }
             if (mFullWifiLockTimer != null) {
                 out.writeInt(1);
-                mFullWifiLockTimer.writeToParcel(out, batteryRealtime);
+                mFullWifiLockTimer.writeToParcel(out, elapsedRealtimeUs);
             } else {
                 out.writeInt(0);
             }
             if (mWifiScanTimer != null) {
                 out.writeInt(1);
-                mWifiScanTimer.writeToParcel(out, batteryRealtime);
+                mWifiScanTimer.writeToParcel(out, elapsedRealtimeUs);
             } else {
                 out.writeInt(0);
             }
             for (int i = 0; i < NUM_WIFI_BATCHED_SCAN_BINS; i++) {
                 if (mWifiBatchedScanTimer[i] != null) {
                     out.writeInt(1);
-                    mWifiBatchedScanTimer[i].writeToParcel(out, batteryRealtime);
+                    mWifiBatchedScanTimer[i].writeToParcel(out, elapsedRealtimeUs);
                 } else {
                     out.writeInt(0);
                 }
             }
             if (mWifiMulticastTimer != null) {
                 out.writeInt(1);
-                mWifiMulticastTimer.writeToParcel(out, batteryRealtime);
+                mWifiMulticastTimer.writeToParcel(out, elapsedRealtimeUs);
             } else {
                 out.writeInt(0);
             }
             if (mAudioTurnedOnTimer != null) {
                 out.writeInt(1);
-                mAudioTurnedOnTimer.writeToParcel(out, batteryRealtime);
+                mAudioTurnedOnTimer.writeToParcel(out, elapsedRealtimeUs);
             } else {
                 out.writeInt(0);
             }
             if (mVideoTurnedOnTimer != null) {
                 out.writeInt(1);
-                mVideoTurnedOnTimer.writeToParcel(out, batteryRealtime);
+                mVideoTurnedOnTimer.writeToParcel(out, elapsedRealtimeUs);
             } else {
                 out.writeInt(0);
             }
             if (mForegroundActivityTimer != null) {
                 out.writeInt(1);
-                mForegroundActivityTimer.writeToParcel(out, batteryRealtime);
+                mForegroundActivityTimer.writeToParcel(out, elapsedRealtimeUs);
             } else {
                 out.writeInt(0);
             }
             if (mVibratorOnTimer != null) {
                 out.writeInt(1);
-                mVibratorOnTimer.writeToParcel(out, batteryRealtime);
+                mVibratorOnTimer.writeToParcel(out, elapsedRealtimeUs);
             } else {
                 out.writeInt(0);
             }
@@ -3936,13 +4131,13 @@
             }
         }
 
-        void readFromParcelLocked(ArrayList<Unpluggable> unpluggables, Parcel in) {
+        void readFromParcelLocked(TimeBase timeBase, TimeBase screenOffTimeBase, Parcel in) {
             int numWakelocks = in.readInt();
             mWakelockStats.clear();
             for (int j = 0; j < numWakelocks; j++) {
                 String wakelockName = in.readString();
                 Uid.Wakelock wakelock = new Wakelock();
-                wakelock.readFromParcelLocked(unpluggables, in);
+                wakelock.readFromParcelLocked(timeBase, screenOffTimeBase, in);
                 // We will just drop some random set of wakelocks if
                 // the previous run of the system was an older version
                 // that didn't impose a limit.
@@ -3954,7 +4149,7 @@
             for (int k = 0; k < numSensors; k++) {
                 int sensorNumber = in.readInt();
                 Uid.Sensor sensor = new Sensor(sensorNumber);
-                sensor.readFromParcelLocked(mUnpluggables, in);
+                sensor.readFromParcelLocked(mOnBatteryTimeBase, in);
                 mSensorStats.put(sensorNumber, sensor);
             }
 
@@ -3979,21 +4174,21 @@
             mWifiRunning = false;
             if (in.readInt() != 0) {
                 mWifiRunningTimer = new StopwatchTimer(Uid.this, WIFI_RUNNING,
-                        mWifiRunningTimers, mUnpluggables, in);
+                        mWifiRunningTimers, mOnBatteryTimeBase, in);
             } else {
                 mWifiRunningTimer = null;
             }
             mFullWifiLockOut = false;
             if (in.readInt() != 0) {
                 mFullWifiLockTimer = new StopwatchTimer(Uid.this, FULL_WIFI_LOCK,
-                        mFullWifiLockTimers, mUnpluggables, in);
+                        mFullWifiLockTimers, mOnBatteryTimeBase, in);
             } else {
                 mFullWifiLockTimer = null;
             }
             mWifiScanStarted = false;
             if (in.readInt() != 0) {
                 mWifiScanTimer = new StopwatchTimer(Uid.this, WIFI_SCAN,
-                        mWifiScanTimers, mUnpluggables, in);
+                        mWifiScanTimers, mOnBatteryTimeBase, in);
             } else {
                 mWifiScanTimer = null;
             }
@@ -4008,40 +4203,39 @@
             mWifiMulticastEnabled = false;
             if (in.readInt() != 0) {
                 mWifiMulticastTimer = new StopwatchTimer(Uid.this, WIFI_MULTICAST_ENABLED,
-                        mWifiMulticastTimers, mUnpluggables, in);
+                        mWifiMulticastTimers, mOnBatteryTimeBase, in);
             } else {
                 mWifiMulticastTimer = null;
             }
             mAudioTurnedOn = false;
             if (in.readInt() != 0) {
                 mAudioTurnedOnTimer = new StopwatchTimer(Uid.this, AUDIO_TURNED_ON,
-                        null, mUnpluggables, in);
+                        null, mOnBatteryTimeBase, in);
             } else {
                 mAudioTurnedOnTimer = null;
             }
             mVideoTurnedOn = false;
             if (in.readInt() != 0) {
                 mVideoTurnedOnTimer = new StopwatchTimer(Uid.this, VIDEO_TURNED_ON,
-                        null, mUnpluggables, in);
+                        null, mOnBatteryTimeBase, in);
             } else {
                 mVideoTurnedOnTimer = null;
             }
             if (in.readInt() != 0) {
                 mForegroundActivityTimer = new StopwatchTimer(
-                        Uid.this, FOREGROUND_ACTIVITY, null, mUnpluggables, in);
+                        Uid.this, FOREGROUND_ACTIVITY, null, mOnBatteryTimeBase, in);
             } else {
                 mForegroundActivityTimer = null;
             }
             if (in.readInt() != 0) {
-                mVibratorOnTimer = new BatchTimer(Uid.this, VIBRATOR_ON,
-                        mUnpluggables, BatteryStatsImpl.this.mOnBatteryInternal, in);
+                mVibratorOnTimer = new BatchTimer(Uid.this, VIBRATOR_ON, mOnBatteryTimeBase, in);
             } else {
                 mVibratorOnTimer = null;
             }
             if (in.readInt() != 0) {
                 mUserActivityCounters = new Counter[NUM_USER_ACTIVITY_TYPES];
                 for (int i=0; i<NUM_USER_ACTIVITY_TYPES; i++) {
-                    mUserActivityCounters[i] = new Counter(mUnpluggables, in);
+                    mUserActivityCounters[i] = new Counter(mOnBatteryTimeBase, in);
                 }
             } else {
                 mUserActivityCounters = null;
@@ -4051,11 +4245,13 @@
                 mNetworkPacketActivityCounters
                         = new LongSamplingCounter[NUM_NETWORK_ACTIVITY_TYPES];
                 for (int i = 0; i < NUM_NETWORK_ACTIVITY_TYPES; i++) {
-                    mNetworkByteActivityCounters[i] = new LongSamplingCounter(mUnpluggables, in);
-                    mNetworkPacketActivityCounters[i] = new LongSamplingCounter(mUnpluggables, in);
+                    mNetworkByteActivityCounters[i]
+                            = new LongSamplingCounter(mOnBatteryTimeBase, in);
+                    mNetworkPacketActivityCounters[i]
+                            = new LongSamplingCounter(mOnBatteryTimeBase, in);
                 }
-                mMobileRadioActiveTime = new LongSamplingCounter(mUnpluggables, in);
-                mMobileRadioActiveCount = new LongSamplingCounter(mUnpluggables, in);
+                mMobileRadioActiveTime = new LongSamplingCounter(mOnBatteryTimeBase, in);
+                mMobileRadioActiveCount = new LongSamplingCounter(mOnBatteryTimeBase, in);
             } else {
                 mNetworkByteActivityCounters = null;
                 mNetworkPacketActivityCounters = null;
@@ -4089,24 +4285,24 @@
              * return a new Timer, or null.
              */
             private StopwatchTimer readTimerFromParcel(int type, ArrayList<StopwatchTimer> pool,
-                    ArrayList<Unpluggable> unpluggables, Parcel in) {
+                    TimeBase timeBase, Parcel in) {
                 if (in.readInt() == 0) {
                     return null;
                 }
 
-                return new StopwatchTimer(Uid.this, type, pool, unpluggables, in);
+                return new StopwatchTimer(Uid.this, type, pool, timeBase, in);
             }
 
             boolean reset() {
                 boolean wlactive = false;
                 if (mTimerFull != null) {
-                    wlactive |= !mTimerFull.reset(BatteryStatsImpl.this, false);
+                    wlactive |= !mTimerFull.reset(false);
                 }
                 if (mTimerPartial != null) {
-                    wlactive |= !mTimerPartial.reset(BatteryStatsImpl.this, false);
+                    wlactive |= !mTimerPartial.reset(false);
                 }
                 if (mTimerWindow != null) {
-                    wlactive |= !mTimerWindow.reset(BatteryStatsImpl.this, false);
+                    wlactive |= !mTimerWindow.reset(false);
                 }
                 if (!wlactive) {
                     if (mTimerFull != null) {
@@ -4125,19 +4321,19 @@
                 return !wlactive;
             }
 
-            void readFromParcelLocked(ArrayList<Unpluggable> unpluggables, Parcel in) {
+            void readFromParcelLocked(TimeBase timeBase, TimeBase screenOffTimeBase, Parcel in) {
                 mTimerPartial = readTimerFromParcel(WAKE_TYPE_PARTIAL,
-                        mPartialTimers, unpluggables, in);
+                        mPartialTimers, screenOffTimeBase, in);
                 mTimerFull = readTimerFromParcel(WAKE_TYPE_FULL,
-                        mFullTimers, unpluggables, in);
+                        mFullTimers, timeBase, in);
                 mTimerWindow = readTimerFromParcel(WAKE_TYPE_WINDOW,
-                        mWindowTimers, unpluggables, in);
+                        mWindowTimers, timeBase, in);
             }
 
-            void writeToParcelLocked(Parcel out, long batteryRealtime) {
-                Timer.writeTimerToParcel(out, mTimerPartial, batteryRealtime);
-                Timer.writeTimerToParcel(out, mTimerFull, batteryRealtime);
-                Timer.writeTimerToParcel(out, mTimerWindow, batteryRealtime);
+            void writeToParcelLocked(Parcel out, long elapsedRealtimeUs) {
+                Timer.writeTimerToParcel(out, mTimerPartial, elapsedRealtimeUs);
+                Timer.writeTimerToParcel(out, mTimerFull, elapsedRealtimeUs);
+                Timer.writeTimerToParcel(out, mTimerWindow, elapsedRealtimeUs);
             }
 
             @Override
@@ -4159,8 +4355,7 @@
                 mHandle = handle;
             }
 
-            private StopwatchTimer readTimerFromParcel(ArrayList<Unpluggable> unpluggables,
-                    Parcel in) {
+            private StopwatchTimer readTimerFromParcel(TimeBase timeBase, Parcel in) {
                 if (in.readInt() == 0) {
                     return null;
                 }
@@ -4170,23 +4365,23 @@
                     pool = new ArrayList<StopwatchTimer>();
                     mSensorTimers.put(mHandle, pool);
                 }
-                return new StopwatchTimer(Uid.this, 0, pool, unpluggables, in);
+                return new StopwatchTimer(Uid.this, 0, pool, timeBase, in);
             }
 
             boolean reset() {
-                if (mTimer.reset(BatteryStatsImpl.this, true)) {
+                if (mTimer.reset(true)) {
                     mTimer = null;
                     return true;
                 }
                 return false;
             }
 
-            void readFromParcelLocked(ArrayList<Unpluggable> unpluggables, Parcel in) {
-                mTimer = readTimerFromParcel(unpluggables, in);
+            void readFromParcelLocked(TimeBase timeBase, Parcel in) {
+                mTimer = readTimerFromParcel(timeBase, in);
             }
 
-            void writeToParcelLocked(Parcel out, long batteryRealtime) {
-                Timer.writeTimerToParcel(out, mTimer, batteryRealtime);
+            void writeToParcelLocked(Parcel out, long elapsedRealtimeUs) {
+                Timer.writeTimerToParcel(out, mTimer, elapsedRealtimeUs);
             }
 
             @Override
@@ -4203,7 +4398,7 @@
         /**
          * The statistics associated with a particular process.
          */
-        public final class Proc extends BatteryStats.Uid.Proc implements Unpluggable {
+        public final class Proc extends BatteryStats.Uid.Proc implements TimeBaseObs {
             /**
              * Remains true until removed from the stats.
              */
@@ -4294,27 +4489,27 @@
             ArrayList<ExcessivePower> mExcessivePower;
 
             Proc() {
-                mUnpluggables.add(this);
+                mOnBatteryTimeBase.add(this);
                 mSpeedBins = new SamplingCounter[getCpuSpeedSteps()];
             }
 
-            public void unplug(long elapsedRealtime, long batteryUptime, long batteryRealtime) {
+            public void onTimeStarted(long elapsedRealtime, long baseUptime, long baseRealtime) {
                 mUnpluggedUserTime = mUserTime;
                 mUnpluggedSystemTime = mSystemTime;
                 mUnpluggedForegroundTime = mForegroundTime;
                 mUnpluggedStarts = mStarts;
             }
 
-            public void plug(long elapsedRealtime, long batteryUptime, long batteryRealtime) {
+            public void onTimeStopped(long elapsedRealtime, long baseUptime, long baseRealtime) {
             }
 
             void detach() {
                 mActive = false;
-                mUnpluggables.remove(this);
+                mOnBatteryTimeBase.remove(this);
                 for (int i = 0; i < mSpeedBins.length; i++) {
                     SamplingCounter c = mSpeedBins[i];
                     if (c != null) {
-                        mUnpluggables.remove(c);
+                        mOnBatteryTimeBase.remove(c);
                         mSpeedBins[i] = null;
                     }
                 }
@@ -4443,7 +4638,7 @@
                 mSpeedBins = new SamplingCounter[bins >= steps ? bins : steps];
                 for (int i = 0; i < bins; i++) {
                     if (in.readInt() != 0) {
-                        mSpeedBins[i] = new SamplingCounter(mUnpluggables, in);
+                        mSpeedBins[i] = new SamplingCounter(mOnBatteryTimeBase, in);
                     }
                 }
 
@@ -4543,7 +4738,7 @@
                     if (amt != 0) {
                         SamplingCounter c = mSpeedBins[i];
                         if (c == null) {
-                            mSpeedBins[i] = c = new SamplingCounter(mUnpluggables);
+                            mSpeedBins[i] = c = new SamplingCounter(mOnBatteryTimeBase);
                         }
                         c.addCountAtomic(values[i]);
                     }
@@ -4564,7 +4759,7 @@
         /**
          * The statistics associated with a particular package.
          */
-        public final class Pkg extends BatteryStats.Uid.Pkg implements Unpluggable {
+        public final class Pkg extends BatteryStats.Uid.Pkg implements TimeBaseObs {
             /**
              * Number of times this package has done something that could wake up the
              * device from sleep.
@@ -4595,18 +4790,18 @@
             final HashMap<String, Serv> mServiceStats = new HashMap<String, Serv>();
 
             Pkg() {
-                mUnpluggables.add(this);
+                mOnBatteryScreenOffTimeBase.add(this);
             }
 
-            public void unplug(long elapsedRealtime, long batteryUptime, long batteryRealtime) {
+            public void onTimeStarted(long elapsedRealtime, long baseUptime, long baseRealtime) {
                 mUnpluggedWakeups = mWakeups;
             }
 
-            public void plug(long elapsedRealtime, long batteryUptime, long batteryRealtime) {
+            public void onTimeStopped(long elapsedRealtime, long baseUptime, long baseRealtime) {
             }
 
             void detach() {
-                mUnpluggables.remove(this);
+                mOnBatteryScreenOffTimeBase.remove(this);
             }
 
             void readFromParcelLocked(Parcel in) {
@@ -4665,7 +4860,7 @@
             /**
              * The statistics associated with a particular service.
              */
-            public final class Serv extends BatteryStats.Uid.Pkg.Serv implements Unpluggable {
+            public final class Serv extends BatteryStats.Uid.Pkg.Serv implements TimeBaseObs {
                 /**
                  * Total time (ms in battery uptime) the service has been left started.
                  */
@@ -4757,20 +4952,22 @@
                 int mUnpluggedLaunches;
 
                 Serv() {
-                    mUnpluggables.add(this);
+                    mOnBatteryTimeBase.add(this);
                 }
 
-                public void unplug(long elapsedRealtime, long batteryUptime, long batteryRealtime) {
-                    mUnpluggedStartTime = getStartTimeToNowLocked(batteryUptime);
+                public void onTimeStarted(long elapsedRealtime, long baseUptime,
+                        long baseRealtime) {
+                    mUnpluggedStartTime = getStartTimeToNowLocked(baseUptime);
                     mUnpluggedStarts = mStarts;
                     mUnpluggedLaunches = mLaunches;
                 }
 
-                public void plug(long elapsedRealtime, long batteryUptime, long batteryRealtime) {
+                public void onTimeStopped(long elapsedRealtime, long baseUptime,
+                        long baseRealtime) {
                 }
 
                 void detach() {
-                    mUnpluggables.remove(this);
+                    mOnBatteryTimeBase.remove(this);
                 }
 
                 void readFromParcelLocked(Parcel in) {
@@ -5005,7 +5202,7 @@
                     t = wl.mTimerPartial;
                     if (t == null) {
                         t = new StopwatchTimer(Uid.this, WAKE_TYPE_PARTIAL,
-                                mPartialTimers, mUnpluggables);
+                                mPartialTimers, mOnBatteryScreenOffTimeBase);
                         wl.mTimerPartial = t;
                     }
                     return t;
@@ -5013,7 +5210,7 @@
                     t = wl.mTimerFull;
                     if (t == null) {
                         t = new StopwatchTimer(Uid.this, WAKE_TYPE_FULL,
-                                mFullTimers, mUnpluggables);
+                                mFullTimers, mOnBatteryTimeBase);
                         wl.mTimerFull = t;
                     }
                     return t;
@@ -5021,7 +5218,7 @@
                     t = wl.mTimerWindow;
                     if (t == null) {
                         t = new StopwatchTimer(Uid.this, WAKE_TYPE_WINDOW,
-                                mWindowTimers, mUnpluggables);
+                                mWindowTimers, mOnBatteryTimeBase);
                         wl.mTimerWindow = t;
                     }
                     return t;
@@ -5048,33 +5245,33 @@
                 timers = new ArrayList<StopwatchTimer>();
                 mSensorTimers.put(sensor, timers);
             }
-            t = new StopwatchTimer(Uid.this, BatteryStats.SENSOR, timers, mUnpluggables);
+            t = new StopwatchTimer(Uid.this, BatteryStats.SENSOR, timers, mOnBatteryTimeBase);
             se.mTimer = t;
             return t;
         }
 
-        public void noteStartWakeLocked(int pid, String name, int type, long elapsedRealtime) {
+        public void noteStartWakeLocked(int pid, String name, int type, long elapsedRealtimeMs) {
             StopwatchTimer t = getWakeTimerLocked(name, type);
             if (t != null) {
-                t.startRunningLocked(BatteryStatsImpl.this, elapsedRealtime);
+                t.startRunningLocked(elapsedRealtimeMs);
             }
             if (pid >= 0 && type == WAKE_TYPE_PARTIAL) {
                 Pid p = getPidStatsLocked(pid);
                 if (p.mWakeStart == 0) {
-                    p.mWakeStart = elapsedRealtime;
+                    p.mWakeStart = elapsedRealtimeMs;
                 }
             }
         }
 
-        public void noteStopWakeLocked(int pid, String name, int type, long elapsedRealtime) {
+        public void noteStopWakeLocked(int pid, String name, int type, long elapsedRealtimeMs) {
             StopwatchTimer t = getWakeTimerLocked(name, type);
             if (t != null) {
-                t.stopRunningLocked(BatteryStatsImpl.this, elapsedRealtime);
+                t.stopRunningLocked(elapsedRealtimeMs);
             }
             if (pid >= 0 && type == WAKE_TYPE_PARTIAL) {
                 Pid p = mPids.get(pid);
                 if (p != null && p.mWakeStart != 0) {
-                    p.mWakeSum += elapsedRealtime - p.mWakeStart;
+                    p.mWakeSum += elapsedRealtimeMs - p.mWakeStart;
                     p.mWakeStart = 0;
                 }
             }
@@ -5094,32 +5291,32 @@
             }
         }
 
-        public void noteStartSensor(int sensor, long elapsedRealtime) {
+        public void noteStartSensor(int sensor, long elapsedRealtimeMs) {
             StopwatchTimer t = getSensorTimerLocked(sensor, true);
             if (t != null) {
-                t.startRunningLocked(BatteryStatsImpl.this, elapsedRealtime);
+                t.startRunningLocked(elapsedRealtimeMs);
             }
         }
 
-        public void noteStopSensor(int sensor, long elapsedRealtime) {
+        public void noteStopSensor(int sensor, long elapsedRealtimeMs) {
             // Don't create a timer if one doesn't already exist
             StopwatchTimer t = getSensorTimerLocked(sensor, false);
             if (t != null) {
-                t.stopRunningLocked(BatteryStatsImpl.this, elapsedRealtime);
+                t.stopRunningLocked(elapsedRealtimeMs);
             }
         }
 
-        public void noteStartGps(long elapsedRealtime) {
+        public void noteStartGps(long elapsedRealtimeMs) {
             StopwatchTimer t = getSensorTimerLocked(Sensor.GPS, true);
             if (t != null) {
-                t.startRunningLocked(BatteryStatsImpl.this, elapsedRealtime);
+                t.startRunningLocked(elapsedRealtimeMs);
             }
         }
 
-        public void noteStopGps(long elapsedRealtime) {
+        public void noteStopGps(long elapsedRealtimeMs) {
             StopwatchTimer t = getSensorTimerLocked(Sensor.GPS, false);
             if (t != null) {
-                t.stopRunningLocked(BatteryStatsImpl.this, elapsedRealtime);
+                t.stopRunningLocked(elapsedRealtimeMs);
             }
         }
 
@@ -5132,46 +5329,46 @@
         mFile = new JournaledFile(new File(filename), new File(filename + ".tmp"));
         mHandler = new MyHandler(handler.getLooper());
         mStartCount++;
-        mScreenOnTimer = new StopwatchTimer(null, -1, null, mUnpluggables);
+        mScreenOnTimer = new StopwatchTimer(null, -1, null, mOnBatteryTimeBase);
         for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
-            mScreenBrightnessTimer[i] = new StopwatchTimer(null, -100-i, null, mUnpluggables);
+            mScreenBrightnessTimer[i] = new StopwatchTimer(null, -100-i, null, mOnBatteryTimeBase);
         }
-        mInputEventCounter = new Counter(mUnpluggables);
-        mPhoneOnTimer = new StopwatchTimer(null, -2, null, mUnpluggables);
+        mInputEventCounter = new Counter(mOnBatteryTimeBase);
+        mPhoneOnTimer = new StopwatchTimer(null, -2, null, mOnBatteryTimeBase);
         for (int i=0; i<SignalStrength.NUM_SIGNAL_STRENGTH_BINS; i++) {
-            mPhoneSignalStrengthsTimer[i] = new StopwatchTimer(null, -200-i, null, mUnpluggables);
+            mPhoneSignalStrengthsTimer[i] = new StopwatchTimer(null, -200-i, null,
+                    mOnBatteryTimeBase);
         }
-        mPhoneSignalScanningTimer = new StopwatchTimer(null, -200+1, null, mUnpluggables);
+        mPhoneSignalScanningTimer = new StopwatchTimer(null, -200+1, null, mOnBatteryTimeBase);
         for (int i=0; i<NUM_DATA_CONNECTION_TYPES; i++) {
-            mPhoneDataConnectionsTimer[i] = new StopwatchTimer(null, -300-i, null, mUnpluggables);
+            mPhoneDataConnectionsTimer[i] = new StopwatchTimer(null, -300-i, null,
+                    mOnBatteryTimeBase);
         }
         for (int i = 0; i < NUM_NETWORK_ACTIVITY_TYPES; i++) {
-            mNetworkByteActivityCounters[i] = new LongSamplingCounter(mUnpluggables);
-            mNetworkPacketActivityCounters[i] = new LongSamplingCounter(mUnpluggables);
+            mNetworkByteActivityCounters[i] = new LongSamplingCounter(mOnBatteryTimeBase);
+            mNetworkPacketActivityCounters[i] = new LongSamplingCounter(mOnBatteryTimeBase);
         }
-        mMobileRadioActiveTimer = new StopwatchTimer(null, -400, null, mUnpluggables);
-        mMobileRadioActivePerAppTimer = new StopwatchTimer(null, -401, null, mUnpluggables);
-        mMobileRadioActiveUnknownTime = new LongSamplingCounter(mUnpluggables);
-        mMobileRadioActiveUnknownCount = new LongSamplingCounter(mUnpluggables);
-        mWifiOnTimer = new StopwatchTimer(null, -3, null, mUnpluggables);
-        mGlobalWifiRunningTimer = new StopwatchTimer(null, -4, null, mUnpluggables);
+        mMobileRadioActiveTimer = new StopwatchTimer(null, -400, null, mOnBatteryTimeBase);
+        mMobileRadioActivePerAppTimer = new StopwatchTimer(null, -401, null, mOnBatteryTimeBase);
+        mMobileRadioActiveUnknownTime = new LongSamplingCounter(mOnBatteryTimeBase);
+        mMobileRadioActiveUnknownCount = new LongSamplingCounter(mOnBatteryTimeBase);
+        mWifiOnTimer = new StopwatchTimer(null, -3, null, mOnBatteryTimeBase);
+        mGlobalWifiRunningTimer = new StopwatchTimer(null, -4, null, mOnBatteryTimeBase);
         for (int i=0; i<NUM_WIFI_STATES; i++) {
-            mWifiStateTimer[i] = new StopwatchTimer(null, -600-i, null, mUnpluggables);
+            mWifiStateTimer[i] = new StopwatchTimer(null, -600-i, null, mOnBatteryTimeBase);
         }
-        mBluetoothOnTimer = new StopwatchTimer(null, -5, null, mUnpluggables);
+        mBluetoothOnTimer = new StopwatchTimer(null, -5, null, mOnBatteryTimeBase);
         for (int i=0; i< NUM_BLUETOOTH_STATES; i++) {
-            mBluetoothStateTimer[i] = new StopwatchTimer(null, -500-i, null, mUnpluggables);
+            mBluetoothStateTimer[i] = new StopwatchTimer(null, -500-i, null, mOnBatteryTimeBase);
         }
-        mAudioOnTimer = new StopwatchTimer(null, -6, null, mUnpluggables);
-        mVideoOnTimer = new StopwatchTimer(null, -7, null, mUnpluggables);
+        mAudioOnTimer = new StopwatchTimer(null, -6, null, mOnBatteryTimeBase);
+        mVideoOnTimer = new StopwatchTimer(null, -7, null, mOnBatteryTimeBase);
         mOnBattery = mOnBatteryInternal = false;
-        initTimes();
-        mTrackBatteryPastUptime = 0;
-        mTrackBatteryPastRealtime = 0;
-        mUptimeStart = mTrackBatteryUptimeStart = SystemClock.uptimeMillis() * 1000;
-        mRealtimeStart = mTrackBatteryRealtimeStart = SystemClock.elapsedRealtime() * 1000;
-        mUnpluggedBatteryUptime = getBatteryUptimeLocked(mUptimeStart);
-        mUnpluggedBatteryRealtime = getBatteryRealtimeLocked(mRealtimeStart);
+        long uptime = SystemClock.uptimeMillis() * 1000;
+        long realtime = SystemClock.elapsedRealtime() * 1000;
+        initTimes(uptime, realtime);
+        mUptimeStart = uptime;
+        mRealtimeStart = realtime;
         mDischargeStartLevel = 0;
         mDischargeUnplugLevel = 0;
         mDischargeCurrentLevel = 0;
@@ -5347,14 +5544,12 @@
         return mScreenOn;
     }
 
-    void initTimes() {
+    void initTimes(long uptime, long realtime) {
         mStartClockTime = System.currentTimeMillis();
-        mBatteryRealtime = mTrackBatteryPastUptime = 0;
-        mBatteryUptime = mTrackBatteryPastRealtime = 0;
-        mUptimeStart = mTrackBatteryUptimeStart = SystemClock.uptimeMillis() * 1000;
-        mRealtimeStart = mTrackBatteryRealtimeStart = SystemClock.elapsedRealtime() * 1000;
-        mUnpluggedBatteryUptime = getBatteryUptimeLocked(mUptimeStart);
-        mUnpluggedBatteryRealtime = getBatteryRealtimeLocked(mRealtimeStart);
+        mOnBatteryTimeBase.init(uptime, realtime);
+        mOnBatteryScreenOffTimeBase.init(uptime, realtime);
+        mUptimeStart = uptime;
+        mRealtimeStart = realtime;
     }
 
     void initDischarge() {
@@ -5375,14 +5570,9 @@
         pullPendingStateUpdatesLocked();
         addHistoryRecordLocked(mSecRealtime);
         mDischargeCurrentLevel = mDischargeUnplugLevel = mHistoryCur.batteryLevel;
-        if ((mHistoryCur.states&HistoryItem.STATE_BATTERY_PLUGGED_FLAG) != 0) {
-            mTrackBatteryPastUptime = 0;
-            mTrackBatteryPastRealtime = 0;
-        } else {
-            mTrackBatteryUptimeStart = uptime;
-            mTrackBatteryRealtimeStart = realtime;
-            mUnpluggedBatteryUptime = getBatteryUptimeLocked(uptime);
-            mUnpluggedBatteryRealtime = getBatteryRealtimeLocked(realtime);
+        mOnBatteryTimeBase.reset(uptime, realtime);
+        mOnBatteryScreenOffTimeBase.reset(uptime, realtime);
+        if ((mHistoryCur.states&HistoryItem.STATE_BATTERY_PLUGGED_FLAG) == 0) {
             if (mScreenOn) {
                 mDischargeScreenOnUnplugLevel = mHistoryCur.batteryLevel;
                 mDischargeScreenOffUnplugLevel = 0;
@@ -5398,38 +5588,38 @@
 
     private void resetAllStatsLocked() {
         mStartCount = 0;
-        initTimes();
-        mScreenOnTimer.reset(this, false);
+        initTimes(SystemClock.uptimeMillis() * 1000, SystemClock.elapsedRealtime() * 1000);
+        mScreenOnTimer.reset(false);
         for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
-            mScreenBrightnessTimer[i].reset(this, false);
+            mScreenBrightnessTimer[i].reset(false);
         }
         mInputEventCounter.reset(false);
-        mPhoneOnTimer.reset(this, false);
-        mAudioOnTimer.reset(this, false);
-        mVideoOnTimer.reset(this, false);
+        mPhoneOnTimer.reset(false);
+        mAudioOnTimer.reset(false);
+        mVideoOnTimer.reset(false);
         for (int i=0; i<SignalStrength.NUM_SIGNAL_STRENGTH_BINS; i++) {
-            mPhoneSignalStrengthsTimer[i].reset(this, false);
+            mPhoneSignalStrengthsTimer[i].reset(false);
         }
-        mPhoneSignalScanningTimer.reset(this, false);
+        mPhoneSignalScanningTimer.reset(false);
         for (int i=0; i<NUM_DATA_CONNECTION_TYPES; i++) {
-            mPhoneDataConnectionsTimer[i].reset(this, false);
+            mPhoneDataConnectionsTimer[i].reset(false);
         }
         for (int i = 0; i < NUM_NETWORK_ACTIVITY_TYPES; i++) {
             mNetworkByteActivityCounters[i].reset(false);
             mNetworkPacketActivityCounters[i].reset(false);
         }
-        mMobileRadioActiveTimer.reset(this, false);
-        mMobileRadioActivePerAppTimer.reset(this, false);
+        mMobileRadioActiveTimer.reset(false);
+        mMobileRadioActivePerAppTimer.reset(false);
         mMobileRadioActiveUnknownTime.reset(false);
         mMobileRadioActiveUnknownCount.reset(false);
-        mWifiOnTimer.reset(this, false);
-        mGlobalWifiRunningTimer.reset(this, false);
+        mWifiOnTimer.reset(false);
+        mGlobalWifiRunningTimer.reset(false);
         for (int i=0; i<NUM_WIFI_STATES; i++) {
-            mWifiStateTimer[i].reset(this, false);
+            mWifiStateTimer[i].reset(false);
         }
-        mBluetoothOnTimer.reset(this, false);
+        mBluetoothOnTimer.reset(false);
         for (int i=0; i< NUM_BLUETOOTH_STATES; i++) {
-            mBluetoothStateTimer[i].reset(this, false);
+            mBluetoothStateTimer[i].reset(false);
         }
 
         for (int i=0; i<mUidStats.size(); i++) {
@@ -5441,7 +5631,7 @@
 
         if (mKernelWakelockStats.size() > 0) {
             for (SamplingTimer timer : mKernelWakelockStats.values()) {
-                mUnpluggables.remove(timer);
+                mOnBatteryScreenOffTimeBase.remove(timer);
             }
             mKernelWakelockStats.clear();
         }
@@ -5491,12 +5681,6 @@
         }
     }
     
-    void setOnBattery(boolean onBattery, int oldStatus, int level) {
-        synchronized(this) {
-            setOnBatteryLocked(onBattery, oldStatus, level);
-        }
-    }
-
     public void pullPendingStateUpdatesLocked() {
         updateKernelWakelocksLocked();
         updateNetworkActivityLocked(NET_UPDATE_ALL, SystemClock.elapsedRealtime());
@@ -5535,10 +5719,6 @@
             if (DEBUG_HISTORY) Slog.v(TAG, "Battery unplugged to: "
                     + Integer.toHexString(mHistoryCur.states));
             addHistoryRecordLocked(mSecRealtime);
-            mTrackBatteryUptimeStart = uptime;
-            mTrackBatteryRealtimeStart = realtime;
-            mUnpluggedBatteryUptime = getBatteryUptimeLocked(uptime);
-            mUnpluggedBatteryRealtime = getBatteryRealtimeLocked(realtime);
             mDischargeCurrentLevel = mDischargeUnplugLevel = level;
             if (mScreenOn) {
                 mDischargeScreenOnUnplugLevel = level;
@@ -5549,7 +5729,7 @@
             }
             mDischargeAmountScreenOn = 0;
             mDischargeAmountScreenOff = 0;
-            doUnplugLocked(realtime, mUnpluggedBatteryUptime, mUnpluggedBatteryRealtime);
+            updateTimeBasesLocked(true, !mScreenOn, uptime, realtime);
             if (reset) {
                 initActiveHistoryEventsLocked(mSecRealtime);
             }
@@ -5560,15 +5740,13 @@
             if (DEBUG_HISTORY) Slog.v(TAG, "Battery plugged to: "
                     + Integer.toHexString(mHistoryCur.states));
             addHistoryRecordLocked(mSecRealtime);
-            mTrackBatteryPastUptime += uptime - mTrackBatteryUptimeStart;
-            mTrackBatteryPastRealtime += realtime - mTrackBatteryRealtimeStart;
             mDischargeCurrentLevel = level;
             if (level < mDischargeUnplugLevel) {
                 mLowDischargeAmountSinceCharge += mDischargeUnplugLevel-level-1;
                 mHighDischargeAmountSinceCharge += mDischargeUnplugLevel-level;
             }
             updateDischargeScreenLevelsLocked(mScreenOn, mScreenOn);
-            doPlugLocked(realtime, getBatteryUptimeLocked(uptime), getBatteryRealtimeLocked(realtime));
+            updateTimeBasesLocked(false, !mScreenOn, uptime, realtime);
         }
         if (doWrite || (mLastWriteTime + (60 * 1000)) < mSecRealtime) {
             if (mFile != null) {
@@ -5667,8 +5845,8 @@
 
             SamplingTimer kwlt = mKernelWakelockStats.get(name);
             if (kwlt == null) {
-                kwlt = new SamplingTimer(mUnpluggables, mOnBatteryInternal,
-                        true /* track reported values */);
+                kwlt = new SamplingTimer(mOnBatteryScreenOffTimeBase,
+                        true /* track reported val */);
                 mKernelWakelockStats.put(name, kwlt);
             }
             kwlt.updateCurrentReportedCount(kws.mCount);
@@ -5691,7 +5869,7 @@
     static final int NET_UPDATE_WIFI = 1<<1;
     static final int NET_UPDATE_ALL = 0xffff;
 
-    private void updateNetworkActivityLocked(int which, long elapsedRealtime) {
+    private void updateNetworkActivityLocked(int which, long elapsedRealtimeMs) {
         if (!SystemProperties.getBoolean(PROP_QTAGUID_ENABLED, false)) return;
 
         if ((which&NET_UPDATE_MOBILE) != 0 && mMobileIfaces.length > 0) {
@@ -5713,8 +5891,8 @@
                         null, null, mTmpNetworkStats);
                 mTmpNetworkStats = delta;
 
-                long radioTime = mMobileRadioActivePerAppTimer.checkpointRunningLocked(this,
-                        elapsedRealtime);
+                long radioTime = mMobileRadioActivePerAppTimer.checkpointRunningLocked(
+                        elapsedRealtimeMs);
                 long totalPackets = delta.getTotalPackets();
 
                 final int size = delta.size();
@@ -5823,7 +6001,7 @@
             case STATS_SINCE_CHARGED: return mUptime + (curTime-mUptimeStart);
             case STATS_LAST: return mLastUptime;
             case STATS_CURRENT: return (curTime-mUptimeStart);
-            case STATS_SINCE_UNPLUGGED: return (curTime-mTrackBatteryUptimeStart);
+            case STATS_SINCE_UNPLUGGED: return (curTime- mOnBatteryTimeBase.getUptimeStart());
         }
         return 0;
     }
@@ -5834,69 +6012,43 @@
             case STATS_SINCE_CHARGED: return mRealtime + (curTime-mRealtimeStart);
             case STATS_LAST: return mLastRealtime;
             case STATS_CURRENT: return (curTime-mRealtimeStart);
-            case STATS_SINCE_UNPLUGGED: return (curTime-mTrackBatteryRealtimeStart);
+            case STATS_SINCE_UNPLUGGED: return (curTime- mOnBatteryTimeBase.getRealtimeStart());
         }
         return 0;
     }
 
     @Override
     public long computeBatteryUptime(long curTime, int which) {
-        switch (which) {
-            case STATS_SINCE_CHARGED:
-                return mBatteryUptime + getBatteryUptime(curTime);
-            case STATS_LAST:
-                return mBatteryLastUptime;
-            case STATS_CURRENT:
-                return getBatteryUptime(curTime);
-            case STATS_SINCE_UNPLUGGED:
-                return getBatteryUptimeLocked(curTime) - mUnpluggedBatteryUptime;
-        }
-        return 0;
+        return mOnBatteryTimeBase.computeUptime(curTime, which);
     }
 
     @Override
     public long computeBatteryRealtime(long curTime, int which) {
-        switch (which) {
-            case STATS_SINCE_CHARGED:
-                return mBatteryRealtime + getBatteryRealtimeLocked(curTime);
-            case STATS_LAST:
-                return mBatteryLastRealtime;
-            case STATS_CURRENT:
-                return getBatteryRealtimeLocked(curTime);
-            case STATS_SINCE_UNPLUGGED:
-                return getBatteryRealtimeLocked(curTime) - mUnpluggedBatteryRealtime;
-        }
-        return 0;
+        return mOnBatteryTimeBase.computeRealtime(curTime, which);
     }
 
-    long getBatteryUptimeLocked(long curTime) {
-        long time = mTrackBatteryPastUptime;
-        if (mOnBatteryInternal) {
-            time += curTime - mTrackBatteryUptimeStart;
-        }
-        return time;
+    @Override
+    public long computeBatteryScreenOffUptime(long curTime, int which) {
+        return mOnBatteryScreenOffTimeBase.computeUptime(curTime, which);
+    }
+
+    @Override
+    public long computeBatteryScreenOffRealtime(long curTime, int which) {
+        return mOnBatteryScreenOffTimeBase.computeRealtime(curTime, which);
     }
 
     long getBatteryUptimeLocked() {
-        return getBatteryUptime(SystemClock.uptimeMillis() * 1000);
+        return mOnBatteryTimeBase.getUptime(SystemClock.uptimeMillis() * 1000);
     }
 
     @Override
     public long getBatteryUptime(long curTime) {
-        return getBatteryUptimeLocked(curTime);
-    }
-
-    long getBatteryRealtimeLocked(long curTime) {
-        long time = mTrackBatteryPastRealtime;
-        if (mOnBatteryInternal) {
-            time += curTime - mTrackBatteryRealtimeStart;
-        }
-        return time;
+        return mOnBatteryTimeBase.getUptime(curTime);
     }
 
     @Override
     public long getBatteryRealtime(long curTime) {
-        return getBatteryRealtimeLocked(curTime);
+        return mOnBatteryTimeBase.getRealtime(curTime);
     }
 
     @Override
@@ -6074,7 +6226,7 @@
                                     time = (time*uidRunningTime)/totalRunningTime;
                                     SamplingCounter uidSc = uidProc.mSpeedBins[sb];
                                     if (uidSc == null) {
-                                        uidSc = new SamplingCounter(mUnpluggables);
+                                        uidSc = new SamplingCounter(mOnBatteryTimeBase);
                                         uidProc.mSpeedBins[sb] = uidSc;
                                     }
                                     uidSc.mCount.addAndGet((int)time);
@@ -6358,11 +6510,11 @@
         readHistory(in, true);
 
         mStartCount = in.readInt();
-        mBatteryUptime = in.readLong();
-        mBatteryRealtime = in.readLong();
         mUptime = in.readLong();
         mRealtime = in.readLong();
         mStartClockTime = in.readLong();
+        mOnBatteryTimeBase.readSummaryFromParcel(in);
+        mOnBatteryScreenOffTimeBase.readSummaryFromParcel(in);
         mDischargeUnplugLevel = in.readInt();
         mDischargeCurrentLevel = in.readInt();
         mLowDischargeAmountSinceCharge = in.readInt();
@@ -6546,7 +6698,7 @@
                 p.mSpeedBins = new SamplingCounter[NSB];
                 for (int i=0; i<NSB; i++) {
                     if (in.readInt() != 0) {
-                        p.mSpeedBins[i] = new SamplingCounter(mUnpluggables);
+                        p.mSpeedBins[i] = new SamplingCounter(mOnBatteryTimeBase);
                         p.mSpeedBins[i].readSummaryFromParcelLocked(in);
                     }
                 }
@@ -6591,55 +6743,53 @@
 
         final long NOW_SYS = SystemClock.uptimeMillis() * 1000;
         final long NOWREAL_SYS = SystemClock.elapsedRealtime() * 1000;
-        final long NOW = getBatteryUptimeLocked(NOW_SYS);
-        final long NOWREAL = getBatteryRealtimeLocked(NOWREAL_SYS);
 
         out.writeInt(VERSION);
 
         writeHistory(out, true);
 
         out.writeInt(mStartCount);
-        out.writeLong(computeBatteryUptime(NOW_SYS, STATS_SINCE_CHARGED));
-        out.writeLong(computeBatteryRealtime(NOWREAL_SYS, STATS_SINCE_CHARGED));
         out.writeLong(computeUptime(NOW_SYS, STATS_SINCE_CHARGED));
         out.writeLong(computeRealtime(NOWREAL_SYS, STATS_SINCE_CHARGED));
         out.writeLong(mStartClockTime);
+        mOnBatteryTimeBase.writeSummaryToParcel(out, NOW_SYS, NOWREAL_SYS);
+        mOnBatteryScreenOffTimeBase.writeSummaryToParcel(out, NOW_SYS, NOWREAL_SYS);
         out.writeInt(mDischargeUnplugLevel);
         out.writeInt(mDischargeCurrentLevel);
         out.writeInt(getLowDischargeAmountSinceCharge());
         out.writeInt(getHighDischargeAmountSinceCharge());
         out.writeInt(getDischargeAmountScreenOnSinceCharge());
         out.writeInt(getDischargeAmountScreenOffSinceCharge());
-        
-        mScreenOnTimer.writeSummaryFromParcelLocked(out, NOWREAL);
+
+        mScreenOnTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
         for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
-            mScreenBrightnessTimer[i].writeSummaryFromParcelLocked(out, NOWREAL);
+            mScreenBrightnessTimer[i].writeSummaryFromParcelLocked(out, NOWREAL_SYS);
         }
         mInputEventCounter.writeSummaryFromParcelLocked(out);
-        mPhoneOnTimer.writeSummaryFromParcelLocked(out, NOWREAL);
+        mPhoneOnTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
         for (int i=0; i<SignalStrength.NUM_SIGNAL_STRENGTH_BINS; i++) {
-            mPhoneSignalStrengthsTimer[i].writeSummaryFromParcelLocked(out, NOWREAL);
+            mPhoneSignalStrengthsTimer[i].writeSummaryFromParcelLocked(out, NOWREAL_SYS);
         }
-        mPhoneSignalScanningTimer.writeSummaryFromParcelLocked(out, NOWREAL);
+        mPhoneSignalScanningTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
         for (int i=0; i<NUM_DATA_CONNECTION_TYPES; i++) {
-            mPhoneDataConnectionsTimer[i].writeSummaryFromParcelLocked(out, NOWREAL);
+            mPhoneDataConnectionsTimer[i].writeSummaryFromParcelLocked(out, NOWREAL_SYS);
         }
         for (int i = 0; i < NUM_NETWORK_ACTIVITY_TYPES; i++) {
             mNetworkByteActivityCounters[i].writeSummaryFromParcelLocked(out);
             mNetworkPacketActivityCounters[i].writeSummaryFromParcelLocked(out);
         }
-        mMobileRadioActiveTimer.writeSummaryFromParcelLocked(out, NOWREAL);
-        mMobileRadioActivePerAppTimer.writeSummaryFromParcelLocked(out, NOWREAL);
+        mMobileRadioActiveTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
+        mMobileRadioActivePerAppTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
         mMobileRadioActiveUnknownTime.writeSummaryFromParcelLocked(out);
         mMobileRadioActiveUnknownCount.writeSummaryFromParcelLocked(out);
-        mWifiOnTimer.writeSummaryFromParcelLocked(out, NOWREAL);
-        mGlobalWifiRunningTimer.writeSummaryFromParcelLocked(out, NOWREAL);
+        mWifiOnTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
+        mGlobalWifiRunningTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
         for (int i=0; i<NUM_WIFI_STATES; i++) {
-            mWifiStateTimer[i].writeSummaryFromParcelLocked(out, NOWREAL);
+            mWifiStateTimer[i].writeSummaryFromParcelLocked(out, NOWREAL_SYS);
         }
-        mBluetoothOnTimer.writeSummaryFromParcelLocked(out, NOWREAL);
+        mBluetoothOnTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
         for (int i=0; i< NUM_BLUETOOTH_STATES; i++) {
-            mBluetoothStateTimer[i].writeSummaryFromParcelLocked(out, NOWREAL);
+            mBluetoothStateTimer[i].writeSummaryFromParcelLocked(out, NOWREAL_SYS);
         }
 
         out.writeInt(mKernelWakelockStats.size());
@@ -6648,7 +6798,7 @@
             if (kwlt != null) {
                 out.writeInt(1);
                 out.writeString(ent.getKey());
-                ent.getValue().writeSummaryFromParcelLocked(out, NOWREAL);
+                ent.getValue().writeSummaryFromParcelLocked(out, NOWREAL_SYS);
             } else {
                 out.writeInt(0);
             }
@@ -6663,57 +6813,57 @@
 
             if (u.mWifiRunningTimer != null) {
                 out.writeInt(1);
-                u.mWifiRunningTimer.writeSummaryFromParcelLocked(out, NOWREAL);
+                u.mWifiRunningTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
             } else {
                 out.writeInt(0);
             }
             if (u.mFullWifiLockTimer != null) {
                 out.writeInt(1);
-                u.mFullWifiLockTimer.writeSummaryFromParcelLocked(out, NOWREAL);
+                u.mFullWifiLockTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
             } else {
                 out.writeInt(0);
             }
             if (u.mWifiScanTimer != null) {
                 out.writeInt(1);
-                u.mWifiScanTimer.writeSummaryFromParcelLocked(out, NOWREAL);
+                u.mWifiScanTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
             } else {
                 out.writeInt(0);
             }
             for (int i = 0; i < Uid.NUM_WIFI_BATCHED_SCAN_BINS; i++) {
                 if (u.mWifiBatchedScanTimer[i] != null) {
                     out.writeInt(1);
-                    u.mWifiBatchedScanTimer[i].writeSummaryFromParcelLocked(out, NOWREAL);
+                    u.mWifiBatchedScanTimer[i].writeSummaryFromParcelLocked(out, NOWREAL_SYS);
                 } else {
                     out.writeInt(0);
                 }
             }
             if (u.mWifiMulticastTimer != null) {
                 out.writeInt(1);
-                u.mWifiMulticastTimer.writeSummaryFromParcelLocked(out, NOWREAL);
+                u.mWifiMulticastTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
             } else {
                 out.writeInt(0);
             }
             if (u.mAudioTurnedOnTimer != null) {
                 out.writeInt(1);
-                u.mAudioTurnedOnTimer.writeSummaryFromParcelLocked(out, NOWREAL);
+                u.mAudioTurnedOnTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
             } else {
                 out.writeInt(0);
             }
             if (u.mVideoTurnedOnTimer != null) {
                 out.writeInt(1);
-                u.mVideoTurnedOnTimer.writeSummaryFromParcelLocked(out, NOWREAL);
+                u.mVideoTurnedOnTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
             } else {
                 out.writeInt(0);
             }
             if (u.mForegroundActivityTimer != null) {
                 out.writeInt(1);
-                u.mForegroundActivityTimer.writeSummaryFromParcelLocked(out, NOWREAL);
+                u.mForegroundActivityTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
             } else {
                 out.writeInt(0);
             }
             if (u.mVibratorOnTimer != null) {
                 out.writeInt(1);
-                u.mVibratorOnTimer.writeSummaryFromParcelLocked(out, NOWREAL);
+                u.mVibratorOnTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
             } else {
                 out.writeInt(0);
             }
@@ -6748,19 +6898,19 @@
                     Uid.Wakelock wl = ent.getValue();
                     if (wl.mTimerFull != null) {
                         out.writeInt(1);
-                        wl.mTimerFull.writeSummaryFromParcelLocked(out, NOWREAL);
+                        wl.mTimerFull.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
                     } else {
                         out.writeInt(0);
                     }
                     if (wl.mTimerPartial != null) {
                         out.writeInt(1);
-                        wl.mTimerPartial.writeSummaryFromParcelLocked(out, NOWREAL);
+                        wl.mTimerPartial.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
                     } else {
                         out.writeInt(0);
                     }
                     if (wl.mTimerWindow != null) {
                         out.writeInt(1);
-                        wl.mTimerWindow.writeSummaryFromParcelLocked(out, NOWREAL);
+                        wl.mTimerWindow.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
                     } else {
                         out.writeInt(0);
                     }
@@ -6776,7 +6926,7 @@
                     Uid.Sensor se = ent.getValue();
                     if (se.mTimer != null) {
                         out.writeInt(1);
-                        se.mTimer.writeSummaryFromParcelLocked(out, NOWREAL);
+                        se.mTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
                     } else {
                         out.writeInt(0);
                     }
@@ -6823,7 +6973,8 @@
                                 : ps.mServiceStats.entrySet()) {
                             out.writeString(sent.getKey());
                             BatteryStatsImpl.Uid.Pkg.Serv ss = sent.getValue();
-                            long time = ss.getStartTimeToNowLocked(NOW);
+                            long time = ss.getStartTimeToNowLocked(
+                                    mOnBatteryTimeBase.getUptime(NOW_SYS));
                             out.writeLong(time);
                             out.writeInt(ss.mStarts);
                             out.writeInt(ss.mLaunches);
@@ -6847,52 +6998,7 @@
         readHistory(in, false);
 
         mStartCount = in.readInt();
-        mBatteryUptime = in.readLong();
-        mBatteryLastUptime = 0;
-        mBatteryRealtime = in.readLong();
-        mBatteryLastRealtime = 0;
         mStartClockTime = in.readLong();
-        mScreenOn = false;
-        mScreenOnTimer = new StopwatchTimer(null, -1, null, mUnpluggables, in);
-        for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
-            mScreenBrightnessTimer[i] = new StopwatchTimer(null, -100-i,
-                    null, mUnpluggables, in);
-        }
-        mInputEventCounter = new Counter(mUnpluggables, in);
-        mPhoneOn = false;
-        mPhoneOnTimer = new StopwatchTimer(null, -2, null, mUnpluggables, in);
-        for (int i=0; i<SignalStrength.NUM_SIGNAL_STRENGTH_BINS; i++) {
-            mPhoneSignalStrengthsTimer[i] = new StopwatchTimer(null, -200-i,
-                    null, mUnpluggables, in);
-        }
-        mPhoneSignalScanningTimer = new StopwatchTimer(null, -200+1, null, mUnpluggables, in);
-        for (int i=0; i<NUM_DATA_CONNECTION_TYPES; i++) {
-            mPhoneDataConnectionsTimer[i] = new StopwatchTimer(null, -300-i,
-                    null, mUnpluggables, in);
-        }
-        for (int i = 0; i < NUM_NETWORK_ACTIVITY_TYPES; i++) {
-            mNetworkByteActivityCounters[i] = new LongSamplingCounter(mUnpluggables, in);
-            mNetworkPacketActivityCounters[i] = new LongSamplingCounter(mUnpluggables, in);
-        }
-        mMobileRadioActive = false;
-        mMobileRadioActiveTimer = new StopwatchTimer(null, -400, null, mUnpluggables, in);
-        mMobileRadioActivePerAppTimer = new StopwatchTimer(null, -401, null, mUnpluggables, in);
-        mMobileRadioActiveUnknownTime = new LongSamplingCounter(mUnpluggables, in);
-        mMobileRadioActiveUnknownCount = new LongSamplingCounter(mUnpluggables, in);
-        mWifiOn = false;
-        mWifiOnTimer = new StopwatchTimer(null, -2, null, mUnpluggables, in);
-        mGlobalWifiRunning = false;
-        mGlobalWifiRunningTimer = new StopwatchTimer(null, -2, null, mUnpluggables, in);
-        for (int i=0; i<NUM_WIFI_STATES; i++) {
-            mWifiStateTimer[i] = new StopwatchTimer(null, -600-i,
-                    null, mUnpluggables, in);
-        }
-        mBluetoothOn = false;
-        mBluetoothOnTimer = new StopwatchTimer(null, -2, null, mUnpluggables, in);
-        for (int i=0; i< NUM_BLUETOOTH_STATES; i++) {
-            mBluetoothStateTimer[i] = new StopwatchTimer(null, -500-i,
-                    null, mUnpluggables, in);
-        }
         mUptime = in.readLong();
         mUptimeStart = in.readLong();
         mLastUptime = 0;
@@ -6901,12 +7007,51 @@
         mLastRealtime = 0;
         mOnBattery = in.readInt() != 0;
         mOnBatteryInternal = false; // we are no longer really running.
-        mTrackBatteryPastUptime = in.readLong();
-        mTrackBatteryUptimeStart = in.readLong();
-        mTrackBatteryPastRealtime = in.readLong();
-        mTrackBatteryRealtimeStart = in.readLong();
-        mUnpluggedBatteryUptime = in.readLong();
-        mUnpluggedBatteryRealtime = in.readLong();
+        mOnBatteryTimeBase.readFromParcel(in);
+        mOnBatteryScreenOffTimeBase.readFromParcel(in);
+
+        mScreenOn = false;
+        mScreenOnTimer = new StopwatchTimer(null, -1, null, mOnBatteryTimeBase, in);
+        for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
+            mScreenBrightnessTimer[i] = new StopwatchTimer(null, -100-i, null, mOnBatteryTimeBase,
+                    in);
+        }
+        mInputEventCounter = new Counter(mOnBatteryTimeBase, in);
+        mPhoneOn = false;
+        mPhoneOnTimer = new StopwatchTimer(null, -2, null, mOnBatteryTimeBase, in);
+        for (int i=0; i<SignalStrength.NUM_SIGNAL_STRENGTH_BINS; i++) {
+            mPhoneSignalStrengthsTimer[i] = new StopwatchTimer(null, -200-i,
+                    null, mOnBatteryTimeBase, in);
+        }
+        mPhoneSignalScanningTimer = new StopwatchTimer(null, -200+1, null, mOnBatteryTimeBase, in);
+        for (int i=0; i<NUM_DATA_CONNECTION_TYPES; i++) {
+            mPhoneDataConnectionsTimer[i] = new StopwatchTimer(null, -300-i,
+                    null, mOnBatteryTimeBase, in);
+        }
+        for (int i = 0; i < NUM_NETWORK_ACTIVITY_TYPES; i++) {
+            mNetworkByteActivityCounters[i] = new LongSamplingCounter(mOnBatteryTimeBase, in);
+            mNetworkPacketActivityCounters[i] = new LongSamplingCounter(mOnBatteryTimeBase, in);
+        }
+        mMobileRadioActive = false;
+        mMobileRadioActiveTimer = new StopwatchTimer(null, -400, null, mOnBatteryTimeBase, in);
+        mMobileRadioActivePerAppTimer = new StopwatchTimer(null, -401, null, mOnBatteryTimeBase,
+                in);
+        mMobileRadioActiveUnknownTime = new LongSamplingCounter(mOnBatteryTimeBase, in);
+        mMobileRadioActiveUnknownCount = new LongSamplingCounter(mOnBatteryTimeBase, in);
+        mWifiOn = false;
+        mWifiOnTimer = new StopwatchTimer(null, -2, null, mOnBatteryTimeBase, in);
+        mGlobalWifiRunning = false;
+        mGlobalWifiRunningTimer = new StopwatchTimer(null, -2, null, mOnBatteryTimeBase, in);
+        for (int i=0; i<NUM_WIFI_STATES; i++) {
+            mWifiStateTimer[i] = new StopwatchTimer(null, -600-i,
+                    null, mOnBatteryTimeBase, in);
+        }
+        mBluetoothOn = false;
+        mBluetoothOnTimer = new StopwatchTimer(null, -2, null, mOnBatteryTimeBase, in);
+        for (int i=0; i< NUM_BLUETOOTH_STATES; i++) {
+            mBluetoothStateTimer[i] = new StopwatchTimer(null, -500-i,
+                    null, mOnBatteryTimeBase, in);
+        }
         mDischargeUnplugLevel = in.readInt();
         mDischargeCurrentLevel = in.readInt();
         mLowDischargeAmountSinceCharge = in.readInt();
@@ -6926,7 +7071,7 @@
             if (in.readInt() != 0) {
                 String wakelockName = in.readString();
                 in.readInt(); // Extra 0/1 written by Timer.writeTimerToParcel
-                SamplingTimer kwlt = new SamplingTimer(mUnpluggables, mOnBattery, in);
+                SamplingTimer kwlt = new SamplingTimer(mOnBatteryTimeBase, in);
                 mKernelWakelockStats.put(wakelockName, kwlt);
             }
         }
@@ -6947,7 +7092,7 @@
         for (int i = 0; i < numUids; i++) {
             int uid = in.readInt();
             Uid u = new Uid(uid);
-            u.readFromParcelLocked(mUnpluggables, in);
+            u.readFromParcelLocked(mOnBatteryTimeBase, mOnBatteryScreenOffTimeBase, in);
             mUidStats.append(uid, u);
         }
     }
@@ -6967,58 +7112,53 @@
 
         final long uSecUptime = SystemClock.uptimeMillis() * 1000;
         final long uSecRealtime = SystemClock.elapsedRealtime() * 1000;
-        final long batteryUptime = getBatteryUptimeLocked(uSecUptime);
-        final long batteryRealtime = getBatteryRealtimeLocked(uSecRealtime);
+        final long batteryRealtime = mOnBatteryTimeBase.getRealtime(uSecRealtime);
+        final long batteryScreenOffRealtime = mOnBatteryScreenOffTimeBase.getRealtime(uSecRealtime);
 
         out.writeInt(MAGIC);
 
         writeHistory(out, false);
 
         out.writeInt(mStartCount);
-        out.writeLong(mBatteryUptime);
-        out.writeLong(mBatteryRealtime);
         out.writeLong(mStartClockTime);
-        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<SignalStrength.NUM_SIGNAL_STRENGTH_BINS; i++) {
-            mPhoneSignalStrengthsTimer[i].writeToParcel(out, batteryRealtime);
-        }
-        mPhoneSignalScanningTimer.writeToParcel(out, batteryRealtime);
-        for (int i=0; i<NUM_DATA_CONNECTION_TYPES; i++) {
-            mPhoneDataConnectionsTimer[i].writeToParcel(out, batteryRealtime);
-        }
-        for (int i = 0; i < NUM_NETWORK_ACTIVITY_TYPES; i++) {
-            mNetworkByteActivityCounters[i].writeToParcel(out);
-            mNetworkPacketActivityCounters[i].writeToParcel(out);
-        }
-        mMobileRadioActiveTimer.writeToParcel(out, batteryRealtime);
-        mMobileRadioActivePerAppTimer.writeToParcel(out, batteryRealtime);
-        mMobileRadioActiveUnknownTime.writeToParcel(out);
-        mMobileRadioActiveUnknownCount.writeToParcel(out);
-        mWifiOnTimer.writeToParcel(out, batteryRealtime);
-        mGlobalWifiRunningTimer.writeToParcel(out, batteryRealtime);
-        for (int i=0; i<NUM_WIFI_STATES; i++) {
-            mWifiStateTimer[i].writeToParcel(out, batteryRealtime);
-        }
-        mBluetoothOnTimer.writeToParcel(out, batteryRealtime);
-        for (int i=0; i< NUM_BLUETOOTH_STATES; i++) {
-            mBluetoothStateTimer[i].writeToParcel(out, batteryRealtime);
-        }
         out.writeLong(mUptime);
         out.writeLong(mUptimeStart);
         out.writeLong(mRealtime);
         out.writeLong(mRealtimeStart);
         out.writeInt(mOnBattery ? 1 : 0);
-        out.writeLong(batteryUptime);
-        out.writeLong(mTrackBatteryUptimeStart);
-        out.writeLong(batteryRealtime);
-        out.writeLong(mTrackBatteryRealtimeStart);
-        out.writeLong(mUnpluggedBatteryUptime);
-        out.writeLong(mUnpluggedBatteryRealtime);
+        mOnBatteryTimeBase.writeToParcel(out, uSecUptime, uSecRealtime);
+        mOnBatteryScreenOffTimeBase.writeToParcel(out, uSecUptime, uSecRealtime);
+
+        mScreenOnTimer.writeToParcel(out, uSecRealtime);
+        for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
+            mScreenBrightnessTimer[i].writeToParcel(out, uSecRealtime);
+        }
+        mInputEventCounter.writeToParcel(out);
+        mPhoneOnTimer.writeToParcel(out, uSecRealtime);
+        for (int i=0; i<SignalStrength.NUM_SIGNAL_STRENGTH_BINS; i++) {
+            mPhoneSignalStrengthsTimer[i].writeToParcel(out, uSecRealtime);
+        }
+        mPhoneSignalScanningTimer.writeToParcel(out, uSecRealtime);
+        for (int i=0; i<NUM_DATA_CONNECTION_TYPES; i++) {
+            mPhoneDataConnectionsTimer[i].writeToParcel(out, uSecRealtime);
+        }
+        for (int i = 0; i < NUM_NETWORK_ACTIVITY_TYPES; i++) {
+            mNetworkByteActivityCounters[i].writeToParcel(out);
+            mNetworkPacketActivityCounters[i].writeToParcel(out);
+        }
+        mMobileRadioActiveTimer.writeToParcel(out, uSecRealtime);
+        mMobileRadioActivePerAppTimer.writeToParcel(out, uSecRealtime);
+        mMobileRadioActiveUnknownTime.writeToParcel(out);
+        mMobileRadioActiveUnknownCount.writeToParcel(out);
+        mWifiOnTimer.writeToParcel(out, uSecRealtime);
+        mGlobalWifiRunningTimer.writeToParcel(out, uSecRealtime);
+        for (int i=0; i<NUM_WIFI_STATES; i++) {
+            mWifiStateTimer[i].writeToParcel(out, uSecRealtime);
+        }
+        mBluetoothOnTimer.writeToParcel(out, uSecRealtime);
+        for (int i=0; i< NUM_BLUETOOTH_STATES; i++) {
+            mBluetoothStateTimer[i].writeToParcel(out, uSecRealtime);
+        }
         out.writeInt(mDischargeUnplugLevel);
         out.writeInt(mDischargeCurrentLevel);
         out.writeInt(mLowDischargeAmountSinceCharge);
@@ -7038,7 +7178,7 @@
                 if (kwlt != null) {
                     out.writeInt(1);
                     out.writeString(ent.getKey());
-                    Timer.writeTimerToParcel(out, kwlt, batteryRealtime);
+                    Timer.writeTimerToParcel(out, kwlt, uSecRealtime);
                 } else {
                     out.writeInt(0);
                 }
@@ -7056,7 +7196,7 @@
                 out.writeInt(mUidStats.keyAt(i));
                 Uid uid = mUidStats.valueAt(i);
 
-                uid.writeToParcelLocked(out, batteryRealtime);
+                uid.writeToParcelLocked(out, uSecRealtime);
             }
         } else {
             out.writeInt(0);
@@ -7082,6 +7222,10 @@
     public void dumpLocked(Context context, PrintWriter pw, boolean isUnpluggedOnly, int reqUid,
             boolean historyOnly) {
         if (DEBUG) {
+            pw.println("mOnBatteryTimeBase:");
+            mOnBatteryTimeBase.dump(pw, "  ");
+            pw.println("mOnBatteryScreenOffTimeBase:");
+            mOnBatteryScreenOffTimeBase.dump(pw, "  ");
             Printer pr = new PrintWriterPrinter(pw);
             pr.println("*** Screen timer:");
             mScreenOnTimer.logState(pr, "  ");
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index 096c4ed..d3e1cdd 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -605,7 +605,7 @@
     <string name="permlab_accessNetworkState" msgid="4951027964348974773">"הצג חיבורי רשת"</string>
     <string name="permdesc_accessNetworkState" msgid="8318964424675960975">"מאפשר לאפליקציה להציג מידע לגבי חיבורי רשת, למשל, אילו רשתות קיימות ומחוברות."</string>
     <string name="permlab_createNetworkSockets" msgid="8018758136404323658">"גישת רשת מלאה"</string>
-    <string name="permdesc_createNetworkSockets" msgid="3403062187779724185">"‏מאפשר לאפליקציה ליצור Sockets ולהשתמש בפרוטוקולי רשת מותאמים אישית. הדפדפן ואפליקציות  אחרות מספקות אמצעים לשליחת נתונים לאינטרנט, כך שאישור זה אינו נחוץ לשליחת נתונים לאינטרנט."</string>
+    <string name="permdesc_createNetworkSockets" msgid="3403062187779724185">"‏מאפשר לאפליקציה ליצור Sockets ולהשתמש בפרוטוקולי רשת מותאמים אישית. הדפדפן, כמו אפליקציות  אחרות, מספק אמצעים לשליחת נתונים לאינטרנט, כך שאישור זה אינו נחוץ לשליחת נתונים לאינטרנט."</string>
     <string name="permlab_writeApnSettings" msgid="505660159675751896">"שנה/עכב הגדרות רשת ותנועה"</string>
     <string name="permdesc_writeApnSettings" msgid="5333798886412714193">"‏מאפשר לאפליקציה לשנות את הגדרות הרשת ולעכב ולבדוק את כל תנועת הרשת, לדוגמה, לשנות את ה-proxy והיציאה של כל רשת APN. אפליקציות זדוניות עלולות לעקוב אחר חבילות רשת, לבצע הפניה מחדש שלהן או לשנות אותן, ללא ידיעתך."</string>
     <string name="permlab_changeNetworkState" msgid="958884291454327309">"שנה את קישוריות הרשת"</string>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index ad2f63c..544fd5b 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -1138,7 +1138,7 @@
     <string name="chooseUsbActivity" msgid="6894748416073583509">"選取要以 USB 裝置存取的應用程式"</string>
     <string name="noApplications" msgid="2991814273936504689">"沒有應用程式可執行這項操作。"</string>
     <string name="aerr_title" msgid="1905800560317137752"></string>
-    <string name="aerr_application" msgid="932628488013092776">"很抱歉,<xliff:g id="APPLICATION">%1$s</xliff:g> 已停止。"</string>
+    <string name="aerr_application" msgid="932628488013092776">"很抱歉,<xliff:g id="APPLICATION">%1$s</xliff:g>已停止運作。"</string>
     <string name="aerr_process" msgid="4507058997035697579">"很抱歉,處理程序 <xliff:g id="PROCESS">%1$s</xliff:g> 已停止。"</string>
     <string name="anr_title" msgid="4351948481459135709"></string>
     <string name="anr_activity_application" msgid="1904477189057199066">"<xliff:g id="APPLICATION">%2$s</xliff:g> 沒有回應。\n\n您要結束嗎?"</string>
diff --git a/core/res/res/values/styles_micro.xml b/core/res/res/values/styles_micro.xml
index b368b65..c35bd48 100644
--- a/core/res/res/values/styles_micro.xml
+++ b/core/res/res/values/styles_micro.xml
@@ -29,5 +29,6 @@
         <item name="android:internalMinWidth">64dip</item>
         <item name="android:internalMaxHeight">180dip</item>
         <item name="virtualButtonPressedDrawable">?android:attr/selectableItemBackground</item>
+        <item name="android:descendantFocusability">blocksDescendants</item>
     </style>
 </resources>
diff --git a/core/res/res/values/themes_micro.xml b/core/res/res/values/themes_micro.xml
index 42f64fe..e429f96 100644
--- a/core/res/res/values/themes_micro.xml
+++ b/core/res/res/values/themes_micro.xml
@@ -31,7 +31,7 @@
         <item name="windowSwipeToDismiss">true</item>
     </style>
     <style name="Theme.Micro.Light" parent="Theme.Holo.Light">
-		<item name="numberPickerStyle">@android:style/Widget.Micro.NumberPicker</item>
+        <item name="numberPickerStyle">@android:style/Widget.Micro.NumberPicker</item>
         <item name="windowAnimationStyle">@android:style/Animation.SwipeDismiss</item>
         <item name="windowIsFloating">false</item>
         <item name="windowIsTranslucent">true</item>
@@ -47,7 +47,7 @@
     </style>
     <style name="Theme.Micro.Light.DarkActionBar" parent="Theme.Holo.Light.DarkActionBar">
         <item name="textViewStyle">@android:style/Widget.Micro.TextView</item>
-		<item name="numberPickerStyle">@android:style/Widget.Micro.NumberPicker</item>
+        <item name="numberPickerStyle">@android:style/Widget.Micro.NumberPicker</item>
         <item name="windowAnimationStyle">@android:style/Animation.SwipeDismiss</item>
         <item name="windowIsFloating">false</item>
         <item name="windowIsTranslucent">true</item>
diff --git a/data/keyboards/Vendor_18d1_Product_2c40.kl b/data/keyboards/Vendor_18d1_Product_2c40.kl
new file mode 100644
index 0000000..903f13b6
--- /dev/null
+++ b/data/keyboards/Vendor_18d1_Product_2c40.kl
@@ -0,0 +1,42 @@
+# Copyright (C) 2013 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.
+
+# Odie
+
+key 304 BUTTON_A
+key 305 BUTTON_B
+key 307 BUTTON_X
+key 308 BUTTON_Y
+key 310 BUTTON_L1
+key 311 BUTTON_R1
+key 316 BUTTON_MODE
+key 317 BUTTON_THUMBL
+key 318 BUTTON_THUMBR
+
+key 158 BACK            WAKE_DROPPED
+key 172 HOME
+
+axis 0x00 X
+axis 0x01 Y
+axis 0x02 Z
+axis 0x05 RZ
+axis 0x09 RTRIGGER
+axis 0x0a LTRIGGER
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
+
+led 0x00 CONTROLLER_1
+led 0x01 CONTROLLER_2
+led 0x02 CONTROLLER_3
+led 0x03 CONTROLLER_4
diff --git a/libs/hwui/DisplayList.cpp b/libs/hwui/DisplayList.cpp
index 8d52b4e..c3aa733 100644
--- a/libs/hwui/DisplayList.cpp
+++ b/libs/hwui/DisplayList.cpp
@@ -601,7 +601,7 @@
 template <class T>
 void DisplayList::iterate(OpenGLRenderer& renderer, T& handler, const int level) {
     if (CC_UNLIKELY(mDestroyed)) { // temporary debug logging
-        ALOGW("Error: %s is drawing after destruction, size %d", getName());
+        ALOGW("Error: %s is drawing after destruction", getName());
         CRASH();
     }
     if (mDisplayListData->isEmpty() || mAlpha <= 0) {
diff --git a/libs/hwui/DisplayListRenderer.cpp b/libs/hwui/DisplayListRenderer.cpp
index 5abfe79..3b1d567 100644
--- a/libs/hwui/DisplayListRenderer.cpp
+++ b/libs/hwui/DisplayListRenderer.cpp
@@ -32,9 +32,9 @@
 namespace uirenderer {
 
 DisplayListRenderer::DisplayListRenderer():
-        mCaches(Caches::getInstance()),
+        mCaches(Caches::getInstance()), mDisplayListData(0),
         mTranslateX(0.0f), mTranslateY(0.0f), mHasTranslate(false),
-        mRestoreSaveCount(-1), mDisplayListData(0) {
+        mRestoreSaveCount(-1) {
 }
 
 DisplayListRenderer::~DisplayListRenderer() {
diff --git a/libs/hwui/DisplayListRenderer.h b/libs/hwui/DisplayListRenderer.h
index 6c11e59..1fb72ce 100644
--- a/libs/hwui/DisplayListRenderer.h
+++ b/libs/hwui/DisplayListRenderer.h
@@ -300,8 +300,6 @@
     DefaultKeyedVector<const SkRegion*, const SkRegion*> mRegionMap;
     DefaultKeyedVector<SkiaShader*, SkiaShader*> mShaderMap;
 
-    int mRestoreSaveCount;
-
     Caches& mCaches;
     DisplayListData* mDisplayListData;
 
@@ -309,6 +307,8 @@
     float mTranslateY;
     bool mHasTranslate;
 
+    int mRestoreSaveCount;
+
     friend class DisplayList;
 
 }; // class DisplayListRenderer
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index 797f713..29ca84a9 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -69,7 +69,7 @@
     <string name="screenshot_failed_title" msgid="705781116746922771">"Nepavyko užfiksuoti ekrano kopijos."</string>
     <string name="screenshot_failed_text" msgid="8134011269572415402">"Nepavyko išsaugoti ekrano kopijos. Gali būti naudojama atmintis."</string>
     <string name="usb_preference_title" msgid="6551050377388882787">"USB failo perdavimo parinktys"</string>
-    <string name="use_mtp_button_title" msgid="4333504413563023626">"Įmontuoti kaip medijos grotuvą (MTP)"</string>
+    <string name="use_mtp_button_title" msgid="4333504413563023626">"Įmontuoti kaip medijos leistuvą (MTP)"</string>
     <string name="use_ptp_button_title" msgid="7517127540301625751">"Įmontuoti kaip fotoaparatą (PTP)"</string>
     <string name="installer_cd_button_title" msgid="2312667578562201583">"Įdiegti „Mac“ skirtą „Android“ perkėl. priem. pr."</string>
     <string name="accessibility_back" msgid="567011538994429120">"Atgal"</string>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index 83fdd12..bf2d7ce 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -199,7 +199,7 @@
     <string name="quick_settings_wifi_label" msgid="9135344704899546041">"Wi-Fi"</string>
     <string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"未連線"</string>
     <string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"沒有網路"</string>
-    <string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"關閉 Wi-Fi"</string>
+    <string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi:關閉"</string>
     <string name="quick_settings_remote_display_no_connection_label" msgid="372107699274391290">"投放螢幕"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"亮度"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"自動"</string>
diff --git a/rs/java/android/renderscript/RenderScript.java b/rs/java/android/renderscript/RenderScript.java
index 4dd6045..d4fa5a7 100644
--- a/rs/java/android/renderscript/RenderScript.java
+++ b/rs/java/android/renderscript/RenderScript.java
@@ -1000,6 +1000,14 @@
         }
     }
 
+    void validateObject(BaseObj o) {
+        if (o != null) {
+            if (o.mRS != this) {
+                throw new RSIllegalArgumentException("Attempting to use an object across contexts.");
+            }
+        }
+    }
+
     void validate() {
         if (mContext == 0) {
             throw new RSInvalidStateException("Calling RS with no Context active.");
diff --git a/rs/java/android/renderscript/Script.java b/rs/java/android/renderscript/Script.java
index a1f2287..0e46f94 100644
--- a/rs/java/android/renderscript/Script.java
+++ b/rs/java/android/renderscript/Script.java
@@ -128,6 +128,9 @@
      *
      */
     protected void forEach(int slot, Allocation ain, Allocation aout, FieldPacker v) {
+        mRS.validate();
+        mRS.validateObject(ain);
+        mRS.validateObject(aout);
         if (ain == null && aout == null) {
             throw new RSIllegalArgumentException(
                 "At least one of ain or aout is required to be non-null.");
@@ -152,6 +155,9 @@
      *
      */
     protected void forEach(int slot, Allocation ain, Allocation aout, FieldPacker v, LaunchOptions sc) {
+        mRS.validate();
+        mRS.validateObject(ain);
+        mRS.validateObject(aout);
         if (ain == null && aout == null) {
             throw new RSIllegalArgumentException(
                 "At least one of ain or aout is required to be non-null.");
@@ -187,6 +193,7 @@
      */
     public void bindAllocation(Allocation va, int slot) {
         mRS.validate();
+        mRS.validateObject(va);
         if (va != null) {
             if (mRS.getApplicationContext().getApplicationInfo().targetSdkVersion >= 20) {
                 final Type t = va.mType;
@@ -263,6 +270,8 @@
      *
      */
     public void setVar(int index, BaseObj o) {
+        mRS.validate();
+        mRS.validateObject(o);
         mRS.nScriptSetVarObj(getID(mRS), index, (o == null) ? 0 : o.getID(mRS));
     }
 
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 0b0b4ef..782868e 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -1073,6 +1073,7 @@
     static final int IMMERSIVE_MODE_LOCK_MSG = 37;
     static final int PERSIST_URI_GRANTS_MSG = 38;
     static final int REQUEST_ALL_PSS_MSG = 39;
+    static final int START_RELATED_USERS_MSG = 40;
 
     static final int FIRST_ACTIVITY_STACK_MSG = 100;
     static final int FIRST_BROADCAST_QUEUE_MSG = 200;
@@ -1686,6 +1687,12 @@
                 requestPssAllProcsLocked(SystemClock.uptimeMillis(), true, false);
                 break;
             }
+            case START_RELATED_USERS_MSG: {
+                synchronized (ActivityManagerService.this) {
+                    startRelatedUsersLocked();
+                }
+                break;
+            }
             }
         }
     };
@@ -5164,10 +5171,11 @@
                                 userId);
                     }
                 }
+                scheduleStartRelatedUsersLocked();
             }
         }
     }
-    
+
     final void ensureBootCompleted() {
         boolean booting;
         boolean enableScreen;
@@ -5177,7 +5185,7 @@
             enableScreen = !mBooted;
             mBooted = true;
         }
-        
+
         if (booting) {
             finishBooting();
         }
@@ -16105,6 +16113,8 @@
             throw new SecurityException(msg);
         }
 
+        if (DEBUG_MU) Slog.i(TAG_MU, "starting userid:" + userId + " fore:" + foreground);
+
         final long ident = Binder.clearCallingIdentity();
         try {
             synchronized (this) {
@@ -16365,6 +16375,32 @@
         }
     }
 
+    void scheduleStartRelatedUsersLocked() {
+        if (!mHandler.hasMessages(START_RELATED_USERS_MSG)) {
+            mHandler.sendMessageDelayed(mHandler.obtainMessage(START_RELATED_USERS_MSG),
+                    DateUtils.SECOND_IN_MILLIS);
+        }
+    }
+
+    void startRelatedUsersLocked() {
+        if (DEBUG_MU) Slog.i(TAG_MU, "startRelatedUsersLocked");
+        List<UserInfo> relatedUsers = getUserManagerLocked().getRelatedUsers(mCurrentUserId);
+        List<UserInfo> toStart = new ArrayList<UserInfo>(relatedUsers.size());
+        for (UserInfo relatedUser : relatedUsers) {
+            if ((relatedUser.flags & UserInfo.FLAG_INITIALIZED) == UserInfo.FLAG_INITIALIZED) {
+                toStart.add(relatedUser);
+            }
+        }
+        final int n = toStart.size();
+        int i = 0;
+        for (; i < n && i < (MAX_RUNNING_USERS - 1); ++i) {
+            startUserInBackground(toStart.get(i).id);
+        }
+        if (i < n) {
+            Slog.w(TAG_MU, "More related users than MAX_RUNNING_USERS");
+        }
+    }
+
     void finishUserSwitch(UserStartedState uss) {
         synchronized (this) {
             if (uss.mState == UserStartedState.STATE_BOOTING
@@ -16379,6 +16415,9 @@
                         android.Manifest.permission.RECEIVE_BOOT_COMPLETED, AppOpsManager.OP_NONE,
                         true, false, MY_PID, Process.SYSTEM_UID, userId);
             }
+
+            startRelatedUsersLocked();
+
             int num = mUserLru.size();
             int i = 0;
             while (num > MAX_RUNNING_USERS && i < mUserLru.size()) {
@@ -16430,6 +16469,7 @@
     }
 
     private int stopUserLocked(final int userId, final IStopUserCallback callback) {
+        if (DEBUG_MU) Slog.i(TAG_MU, "stopUserLocked userId=" + userId);
         if (mCurrentUserId == userId) {
             return ActivityManager.USER_OP_IS_CURRENT;
         }
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index fcfa50c..ce13a7a 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -205,6 +205,8 @@
     private int mZenMode;
     private int mPreZenAlarmVolume = -1;
     private int mPreZenRingerMode = -1;
+    private boolean mZenMutingAlarm;
+    private boolean mZenMutingRinger;
     // temporary, until we update apps to provide metadata
     private static final Set<String> CALL_PACKAGES = new HashSet<String>(Arrays.asList(
             "com.google.android.dialer",
@@ -1666,6 +1668,8 @@
             pw.println("  mZenMode=" + Settings.Global.zenModeToString(mZenMode));
             pw.println("  mPreZenAlarmVolume=" + mPreZenAlarmVolume);
             pw.println("  mPreZenRingerMode=" + mPreZenRingerMode);
+            pw.println("  mZenMutingAlarm=" + mZenMutingAlarm);
+            pw.println("  mZenMutingRinger=" + mZenMutingRinger);
             pw.println("  mSystemReady=" + mSystemReady);
             pw.println("  mArchive=" + mArchive.toString());
             Iterator<StatusBarNotification> iter = mArchive.descendingIterator();
@@ -2515,15 +2519,20 @@
         final int mode = Settings.Global.getInt(getContext().getContentResolver(),
                 Settings.Global.ZEN_MODE, Settings.Global.ZEN_MODE_OFF);
         if (mode != mZenMode) {
-            Slog.d(TAG, "updateZenMode: " + Settings.Global.zenModeToString(mZenMode));
+            Slog.d(TAG, String.format("updateZenMode: %s -> %s",
+                    Settings.Global.zenModeToString(mZenMode),
+                    Settings.Global.zenModeToString(mode)));
         }
         mZenMode = mode;
         if (mAudioManager != null) {
             // call audio
             final boolean muteCalls = mZenMode != Settings.Global.ZEN_MODE_OFF;
             if (muteCalls) {
-                if (DBG) Slog.d(TAG, "Muting calls");
-                mAudioManager.setStreamMute(AudioManager.STREAM_RING, true);
+                if (!mZenMutingRinger) {
+                    if (DBG) Slog.d(TAG, "Muting STREAM_RING");
+                    mAudioManager.setStreamMute(AudioManager.STREAM_RING, true);
+                    mZenMutingRinger = true;
+                }
                 // calls vibrate if ringer mode = vibrate, so set the ringer mode as well
                 final int ringerMode = mAudioManager.getRingerMode();
                 if (ringerMode != AudioManager.RINGER_MODE_SILENT) {
@@ -2532,8 +2541,11 @@
                     mAudioManager.setRingerMode(AudioManager.RINGER_MODE_SILENT);
                 }
             } else {
-                if (DBG) Slog.d(TAG, "Unmuting calls");
-                mAudioManager.setStreamMute(AudioManager.STREAM_RING, false);
+                if (mZenMutingRinger) {
+                    if (DBG) Slog.d(TAG, "Unmuting STREAM_RING");
+                    mAudioManager.setStreamMute(AudioManager.STREAM_RING, false);
+                    mZenMutingRinger = false;
+                }
                 if (mPreZenRingerMode != -1) {
                     if (DBG) Slog.d(TAG, "Restoring ringer mode to " + mPreZenRingerMode);
                     mAudioManager.setRingerMode(mPreZenRingerMode);
@@ -2543,8 +2555,11 @@
             // alarm audio
             final boolean muteAlarms = mZenMode == Settings.Global.ZEN_MODE_FULL;
             if (muteAlarms) {
-                if (DBG) Slog.d(TAG, "Muting alarms");
-                mAudioManager.setStreamMute(AudioManager.STREAM_ALARM, true);
+                if (!mZenMutingAlarm) {
+                    if (DBG) Slog.d(TAG, "Muting STREAM_ALARM");
+                    mAudioManager.setStreamMute(AudioManager.STREAM_ALARM, true);
+                    mZenMutingAlarm = true;
+                }
                 // alarms don't simply respect mute, so set the volume as well
                 final int volume = mAudioManager.getStreamVolume(AudioManager.STREAM_ALARM);
                 if (volume != 0) {
@@ -2553,8 +2568,11 @@
                     mAudioManager.setStreamVolume(AudioManager.STREAM_ALARM, 0, 0);
                 }
             } else {
-                if (DBG) Slog.d(TAG, "Unmuting alarms");
-                mAudioManager.setStreamMute(AudioManager.STREAM_ALARM, false);
+                if (mZenMutingAlarm) {
+                    if (DBG) Slog.d(TAG, "Unmuting STREAM_ALARM");
+                    mAudioManager.setStreamMute(AudioManager.STREAM_ALARM, false);
+                    mZenMutingAlarm = false;
+                }
                 if (mPreZenAlarmVolume != -1) {
                     if (DBG) Slog.d(TAG, "Restoring STREAM_ALARM volume to " + mPreZenAlarmVolume);
                     mAudioManager.setStreamVolume(AudioManager.STREAM_ALARM, mPreZenAlarmVolume, 0);
diff --git a/tools/aidl/Type.cpp b/tools/aidl/Type.cpp
index d572af6..2267750 100644
--- a/tools/aidl/Type.cpp
+++ b/tools/aidl/Type.cpp
@@ -1,5 +1,7 @@
 #include "Type.h"
 
+#include <sys/types.h>
+
 Namespace NAMES;
 
 Type* VOID_TYPE;