Merge "Import translations. DO NOT MERGE"
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/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java
index 1b5cc68..11678a6 100644
--- a/core/java/android/provider/ContactsContract.java
+++ b/core/java/android/provider/ContactsContract.java
@@ -901,6 +901,14 @@
         public static final String PHOTO_THUMBNAIL_URI = "photo_thumb_uri";
 
         /**
+         * Flag that reflects whether the contact exists inside the default directory.
+         * Ie, whether the contact is designed to only be visible outside search.
+         *
+         * @hide
+         */
+        public static final String IN_DEFAULT_DIRECTORY = "in_default_directory";
+
+        /**
          * Flag that reflects the {@link Groups#GROUP_VISIBLE} state of any
          * {@link CommonDataKinds.GroupMembership} for this contact.
          */
diff --git a/core/java/android/view/DisplayList.java b/core/java/android/view/DisplayList.java
index dfc74ea..0ae36c1 100644
--- a/core/java/android/view/DisplayList.java
+++ b/core/java/android/view/DisplayList.java
@@ -19,8 +19,6 @@
 import android.graphics.Matrix;
 import android.graphics.Path;
 
-import java.util.ArrayList;
-
 /**
  * <p>A display list records a series of graphics related operations and can replay
  * them later. Display lists are usually built by recording operations on a
@@ -124,18 +122,8 @@
  * @hide
  */
 public class DisplayList {
-    private boolean mDirty;
-    private ArrayList<DisplayList> mChildDisplayLists;
-
-    private GLES20RecordingCanvas mCanvas;
     private boolean mValid;
-
-    // Used for debugging
-    private final String mName;
-
-    // The native display list will be destroyed when this object dies.
-    // DO NOT overwrite this reference once it is set.
-    private DisplayListFinalizer mFinalizer;
+    private final long mNativeDisplayList;
 
     /**
      * Flag used when calling
@@ -188,7 +176,8 @@
     public static final int STATUS_DREW = 0x4;
 
     private DisplayList(String name) {
-        mName = name;
+        mNativeDisplayList = nCreate();
+        nSetDisplayListName(mNativeDisplayList, name);
     }
 
     /**
@@ -221,19 +210,11 @@
      * @see #isValid()
      */
     public HardwareCanvas start(int width, int height) {
-        if (mCanvas != null) {
-            throw new IllegalStateException("Recording has already started");
-        }
-
-        mValid = false;
-        mCanvas = GLES20RecordingCanvas.obtain(this);
-        mCanvas.start();
-
-        mCanvas.setViewport(width, height);
+        HardwareCanvas canvas = GLES20RecordingCanvas.obtain();
+        canvas.setViewport(width, height);
         // The dirty rect should always be null for a display list
-        mCanvas.onPreDraw(null);
-
-        return mCanvas;
+        canvas.onPreDraw(null);
+        return canvas;
     }
 
     /**
@@ -244,47 +225,17 @@
      * @see #start(int, int)
      * @see #isValid()
      */
-    public void end() {
-        if (mCanvas != null) {
-            mCanvas.onPostDraw();
-            if (mFinalizer != null) {
-                mCanvas.end(mFinalizer.mNativeDisplayList);
-            } else {
-                mFinalizer = new DisplayListFinalizer(mCanvas.end(0));
-                nSetDisplayListName(mFinalizer.mNativeDisplayList, mName);
-            }
-            mCanvas.recycle();
-            mCanvas = null;
-            mValid = true;
+    public void end(HardwareRenderer renderer, HardwareCanvas endCanvas) {
+        if (!(endCanvas instanceof GLES20RecordingCanvas)) {
+            throw new IllegalArgumentException("Passed an invalid canvas to end!");
         }
-    }
 
-    /**
-     * Clears resources held onto by this display list. After calling this method
-     * {@link #isValid()} will return false.
-     *
-     * @see #isValid()
-     * @see #reset()
-     */
-    public void clear() {
-        clearDirty();
-
-        if (mCanvas != null) {
-            mCanvas.recycle();
-            mCanvas = null;
-        }
-        mValid = false;
-
-        clearReferences();
-    }
-
-    void clearReferences() {
-        if (mChildDisplayLists != null) mChildDisplayLists.clear();
-    }
-
-    ArrayList<DisplayList> getChildDisplayLists() {
-        if (mChildDisplayLists == null) mChildDisplayLists = new ArrayList<DisplayList>();
-        return mChildDisplayLists;
+        GLES20RecordingCanvas canvas = (GLES20RecordingCanvas) endCanvas;
+        canvas.onPostDraw();
+        long displayListData = canvas.finishRecording();
+        renderer.swapDisplayListData(mNativeDisplayList, displayListData);
+        canvas.recycle();
+        mValid = true;
     }
 
     /**
@@ -292,53 +243,14 @@
      * during destruction of hardware resources, to ensure that we do not hold onto
      * obsolete resources after related resources are gone.
      *
-     * @see #clear()
-     *
      * @hide
      */
-    public void reset() {
-        if (hasNativeDisplayList()) {
-            nReset(mFinalizer.mNativeDisplayList);
+    public void destroyDisplayListData(HardwareRenderer renderer) {
+        if (renderer == null) {
+            throw new IllegalArgumentException("Cannot destroyDisplayListData with a null renderer");
         }
-        clear();
-    }
-
-    /**
-     * Sets the dirty flag. When a display list is dirty, {@link #clear()} should
-     * be invoked whenever possible.
-     *
-     * @see #isDirty()
-     * @see #clear()
-     *
-     * @hide
-     */
-    public void markDirty() {
-        mDirty = true;
-    }
-
-    /**
-     * Removes the dirty flag. This method can be used to cancel a cleanup
-     * previously scheduled by setting the dirty flag.
-     *
-     * @see #isDirty()
-     * @see #clear()
-     *
-     * @hide
-     */
-    protected void clearDirty() {
-        mDirty = false;
-    }
-
-    /**
-     * Indicates whether the display list is dirty.
-     *
-     * @see #markDirty()
-     * @see #clear()
-     *
-     * @hide
-     */
-    public boolean isDirty() {
-        return mDirty;
+        renderer.swapDisplayListData(mNativeDisplayList, 0);
+        mValid = false;
     }
 
     /**
@@ -349,27 +261,11 @@
      */
     public boolean isValid() { return mValid; }
 
-    /**
-     * Return the amount of memory used by this display list.
-     *
-     * @return The size of this display list in bytes
-     *
-     * @hide
-     */
-    public int getSize() {
-        if (mFinalizer == null) return 0;
-        return nGetDisplayListSize(mFinalizer.mNativeDisplayList);
-    }
-
-    boolean hasNativeDisplayList() {
-        return mValid && mFinalizer != null;
-    }
-
     long getNativeDisplayList() {
-        if (!mValid || mFinalizer == null) {
+        if (!mValid) {
             throw new IllegalStateException("The display list is not valid.");
         }
-        return mFinalizer.mNativeDisplayList;
+        return mNativeDisplayList;
     }
 
     ///////////////////////////////////////////////////////////////////////////
@@ -386,9 +282,7 @@
      * @hide
      */
     public void setCaching(boolean caching) {
-        if (hasNativeDisplayList()) {
-            nSetCaching(mFinalizer.mNativeDisplayList, caching);
-        }
+        nSetCaching(mNativeDisplayList, caching);
     }
 
     /**
@@ -398,9 +292,7 @@
      * @param clipToBounds true if the display list should clip to its bounds
      */
     public void setClipToBounds(boolean clipToBounds) {
-        if (hasNativeDisplayList()) {
-            nSetClipToBounds(mFinalizer.mNativeDisplayList, clipToBounds);
-        }
+        nSetClipToBounds(mNativeDisplayList, clipToBounds);
     }
 
     /**
@@ -410,9 +302,7 @@
      * @param isolatedZVolume true if the display list should collect and Z order descendents.
      */
     public void setIsolatedZVolume(boolean isolatedZVolume) {
-        if (hasNativeDisplayList()) {
-            nSetIsolatedZVolume(mFinalizer.mNativeDisplayList, isolatedZVolume);
-        }
+        nSetIsolatedZVolume(mNativeDisplayList, isolatedZVolume);
     }
 
     /**
@@ -425,9 +315,7 @@
      *            containing volume.
      */
     public void setProjectBackwards(boolean shouldProject) {
-        if (hasNativeDisplayList()) {
-            nSetProjectBackwards(mFinalizer.mNativeDisplayList, shouldProject);
-        }
+        nSetProjectBackwards(mNativeDisplayList, shouldProject);
     }
 
     /**
@@ -436,9 +324,7 @@
      * ProjectBackwards=true directly on top of it. Default value is false.
      */
     public void setProjectionReceiver(boolean shouldRecieve) {
-        if (hasNativeDisplayList()) {
-            nSetProjectionReceiver(mFinalizer.mNativeDisplayList, shouldRecieve);
-        }
+        nSetProjectionReceiver(mNativeDisplayList, shouldRecieve);
     }
 
     /**
@@ -450,10 +336,8 @@
      * @param outline Convex, CW Path to store in the DisplayList. May be null.
      */
     public void setOutline(Path outline) {
-        if (hasNativeDisplayList()) {
-            long nativePath = (outline == null) ? 0 : outline.mNativePath;
-            nSetOutline(mFinalizer.mNativeDisplayList, nativePath);
-        }
+        long nativePath = (outline == null) ? 0 : outline.mNativePath;
+        nSetOutline(mNativeDisplayList, nativePath);
     }
 
     /**
@@ -462,9 +346,7 @@
      * @param clipToOutline true if clipping to the outline.
      */
     public void setClipToOutline(boolean clipToOutline) {
-        if (hasNativeDisplayList()) {
-            nSetClipToOutline(mFinalizer.mNativeDisplayList, clipToOutline);
-        }
+        nSetClipToOutline(mNativeDisplayList, clipToOutline);
     }
 
     /**
@@ -474,9 +356,7 @@
      * and non-empty, otherwise it will be the bounds rect.
      */
     public void setCastsShadow(boolean castsShadow) {
-        if (hasNativeDisplayList()) {
-            nSetCastsShadow(mFinalizer.mNativeDisplayList, castsShadow);
-        }
+        nSetCastsShadow(mNativeDisplayList, castsShadow);
     }
 
     /**
@@ -485,9 +365,7 @@
      * If set to true, camera distance will be ignored. Defaults to false.
      */
     public void setUsesGlobalCamera(boolean usesGlobalCamera) {
-        if (hasNativeDisplayList()) {
-            nSetUsesGlobalCamera(mFinalizer.mNativeDisplayList, usesGlobalCamera);
-        }
+        nSetUsesGlobalCamera(mNativeDisplayList, usesGlobalCamera);
     }
 
     /**
@@ -499,41 +377,8 @@
      * @see #getMatrix(android.graphics.Matrix)
      * @see #getMatrix()
      */
-    public void setMatrix(Matrix matrix) {
-        if (hasNativeDisplayList()) {
-            nSetStaticMatrix(mFinalizer.mNativeDisplayList, matrix.native_instance);
-        }
-    }
-
-    /**
-     * Returns the static matrix set on this display list.
-     *
-     * @return A new {@link Matrix} instance populated with this display list's static
-     *         matrix
-     *
-     * @see #getMatrix(android.graphics.Matrix)
-     * @see #setMatrix(android.graphics.Matrix)
-     */
-    public Matrix getMatrix() {
-        return getMatrix(new Matrix());
-    }
-
-    /**
-     * Copies this display list's static matrix into the specified matrix.
-     *
-     * @param matrix The {@link Matrix} instance in which to copy this display
-     *               list's static matrix. Cannot be null
-     *
-     * @return The <code>matrix</code> parameter, for convenience
-     *
-     * @see #getMatrix()
-     * @see #setMatrix(android.graphics.Matrix)
-     */
-    public Matrix getMatrix(Matrix matrix) {
-        if (hasNativeDisplayList()) {
-            nGetMatrix(mFinalizer.mNativeDisplayList, matrix.native_instance);
-        }
-        return matrix;
+    public void setStaticMatrix(Matrix matrix) {
+        nSetStaticMatrix(mNativeDisplayList, matrix.native_instance);
     }
 
     /**
@@ -547,10 +392,8 @@
      * @hide
      */
     public void setAnimationMatrix(Matrix matrix) {
-        if (hasNativeDisplayList()) {
-            nSetAnimationMatrix(mFinalizer.mNativeDisplayList,
-                    (matrix != null) ? matrix.native_instance : 0);
-        }
+        nSetAnimationMatrix(mNativeDisplayList,
+                (matrix != null) ? matrix.native_instance : 0);
     }
 
     /**
@@ -562,9 +405,7 @@
      * @see #getAlpha()
      */
     public void setAlpha(float alpha) {
-        if (hasNativeDisplayList()) {
-            nSetAlpha(mFinalizer.mNativeDisplayList, alpha);
-        }
+        nSetAlpha(mNativeDisplayList, alpha);
     }
 
     /**
@@ -575,10 +416,7 @@
      * @see #setAlpha(float)
      */
     public float getAlpha() {
-        if (hasNativeDisplayList()) {
-            return nGetAlpha(mFinalizer.mNativeDisplayList);
-        }
-        return 1.0f;
+        return nGetAlpha(mNativeDisplayList);
     }
 
     /**
@@ -593,9 +431,7 @@
      * @see #hasOverlappingRendering()
      */
     public void setHasOverlappingRendering(boolean hasOverlappingRendering) {
-        if (hasNativeDisplayList()) {
-            nSetHasOverlappingRendering(mFinalizer.mNativeDisplayList, hasOverlappingRendering);
-        }
+        nSetHasOverlappingRendering(mNativeDisplayList, hasOverlappingRendering);
     }
 
     /**
@@ -607,10 +443,7 @@
      */
     public boolean hasOverlappingRendering() {
         //noinspection SimplifiableIfStatement
-        if (hasNativeDisplayList()) {
-            return nHasOverlappingRendering(mFinalizer.mNativeDisplayList);
-        }
-        return true;
+        return nHasOverlappingRendering(mNativeDisplayList);
     }
 
     /**
@@ -622,9 +455,7 @@
      * @see #getTranslationX()
      */
     public void setTranslationX(float translationX) {
-        if (hasNativeDisplayList()) {
-            nSetTranslationX(mFinalizer.mNativeDisplayList, translationX);
-        }
+        nSetTranslationX(mNativeDisplayList, translationX);
     }
 
     /**
@@ -633,10 +464,7 @@
      * @see #setTranslationX(float)
      */
     public float getTranslationX() {
-        if (hasNativeDisplayList()) {
-            return nGetTranslationX(mFinalizer.mNativeDisplayList);
-        }
-        return 0.0f;
+        return nGetTranslationX(mNativeDisplayList);
     }
 
     /**
@@ -648,9 +476,7 @@
      * @see #getTranslationY()
      */
     public void setTranslationY(float translationY) {
-        if (hasNativeDisplayList()) {
-            nSetTranslationY(mFinalizer.mNativeDisplayList, translationY);
-        }
+        nSetTranslationY(mNativeDisplayList, translationY);
     }
 
     /**
@@ -659,10 +485,7 @@
      * @see #setTranslationY(float)
      */
     public float getTranslationY() {
-        if (hasNativeDisplayList()) {
-            return nGetTranslationY(mFinalizer.mNativeDisplayList);
-        }
-        return 0.0f;
+        return nGetTranslationY(mNativeDisplayList);
     }
 
     /**
@@ -672,9 +495,7 @@
      * @see #getTranslationZ()
      */
     public void setTranslationZ(float translationZ) {
-        if (hasNativeDisplayList()) {
-            nSetTranslationZ(mFinalizer.mNativeDisplayList, translationZ);
-        }
+        nSetTranslationZ(mNativeDisplayList, translationZ);
     }
 
     /**
@@ -683,10 +504,7 @@
      * @see #setTranslationZ(float)
      */
     public float getTranslationZ() {
-        if (hasNativeDisplayList()) {
-            return nGetTranslationZ(mFinalizer.mNativeDisplayList);
-        }
-        return 0.0f;
+        return nGetTranslationZ(mNativeDisplayList);
     }
 
     /**
@@ -698,9 +516,7 @@
      * @see #getRotation()
      */
     public void setRotation(float rotation) {
-        if (hasNativeDisplayList()) {
-            nSetRotation(mFinalizer.mNativeDisplayList, rotation);
-        }
+        nSetRotation(mNativeDisplayList, rotation);
     }
 
     /**
@@ -709,10 +525,7 @@
      * @see #setRotation(float)
      */
     public float getRotation() {
-        if (hasNativeDisplayList()) {
-            return nGetRotation(mFinalizer.mNativeDisplayList);
-        }
-        return 0.0f;
+        return nGetRotation(mNativeDisplayList);
     }
 
     /**
@@ -724,9 +537,7 @@
      * @see #getRotationX()
      */
     public void setRotationX(float rotationX) {
-        if (hasNativeDisplayList()) {
-            nSetRotationX(mFinalizer.mNativeDisplayList, rotationX);
-        }
+        nSetRotationX(mNativeDisplayList, rotationX);
     }
 
     /**
@@ -735,10 +546,7 @@
      * @see #setRotationX(float)
      */
     public float getRotationX() {
-        if (hasNativeDisplayList()) {
-            return nGetRotationX(mFinalizer.mNativeDisplayList);
-        }
-        return 0.0f;
+        return nGetRotationX(mNativeDisplayList);
     }
 
     /**
@@ -750,9 +558,7 @@
      * @see #getRotationY()
      */
     public void setRotationY(float rotationY) {
-        if (hasNativeDisplayList()) {
-            nSetRotationY(mFinalizer.mNativeDisplayList, rotationY);
-        }
+        nSetRotationY(mNativeDisplayList, rotationY);
     }
 
     /**
@@ -761,10 +567,7 @@
      * @see #setRotationY(float)
      */
     public float getRotationY() {
-        if (hasNativeDisplayList()) {
-            return nGetRotationY(mFinalizer.mNativeDisplayList);
-        }
-        return 0.0f;
+        return nGetRotationY(mNativeDisplayList);
     }
 
     /**
@@ -776,9 +579,7 @@
      * @see #getScaleX()
      */
     public void setScaleX(float scaleX) {
-        if (hasNativeDisplayList()) {
-            nSetScaleX(mFinalizer.mNativeDisplayList, scaleX);
-        }
+        nSetScaleX(mNativeDisplayList, scaleX);
     }
 
     /**
@@ -787,10 +588,7 @@
      * @see #setScaleX(float)
      */
     public float getScaleX() {
-        if (hasNativeDisplayList()) {
-            return nGetScaleX(mFinalizer.mNativeDisplayList);
-        }
-        return 1.0f;
+        return nGetScaleX(mNativeDisplayList);
     }
 
     /**
@@ -802,9 +600,7 @@
      * @see #getScaleY()
      */
     public void setScaleY(float scaleY) {
-        if (hasNativeDisplayList()) {
-            nSetScaleY(mFinalizer.mNativeDisplayList, scaleY);
-        }
+        nSetScaleY(mNativeDisplayList, scaleY);
     }
 
     /**
@@ -813,10 +609,7 @@
      * @see #setScaleY(float)
      */
     public float getScaleY() {
-        if (hasNativeDisplayList()) {
-            return nGetScaleY(mFinalizer.mNativeDisplayList);
-        }
-        return 1.0f;
+        return nGetScaleY(mNativeDisplayList);
     }
 
     /**
@@ -836,11 +629,9 @@
     public void setTransformationInfo(float alpha,
             float translationX, float translationY, float translationZ,
             float rotation, float rotationX, float rotationY, float scaleX, float scaleY) {
-        if (hasNativeDisplayList()) {
-            nSetTransformationInfo(mFinalizer.mNativeDisplayList, alpha,
-                    translationX, translationY, translationZ,
-                    rotation, rotationX, rotationY, scaleX, scaleY);
-        }
+        nSetTransformationInfo(mNativeDisplayList, alpha,
+                translationX, translationY, translationZ,
+                rotation, rotationX, rotationY, scaleX, scaleY);
     }
 
     /**
@@ -852,9 +643,7 @@
      * @see #getPivotX()
      */
     public void setPivotX(float pivotX) {
-        if (hasNativeDisplayList()) {
-            nSetPivotX(mFinalizer.mNativeDisplayList, pivotX);
-        }
+        nSetPivotX(mNativeDisplayList, pivotX);
     }
 
     /**
@@ -863,10 +652,7 @@
      * @see #setPivotX(float)
      */
     public float getPivotX() {
-        if (hasNativeDisplayList()) {
-            return nGetPivotX(mFinalizer.mNativeDisplayList);
-        }
-        return 0.0f;
+        return nGetPivotX(mNativeDisplayList);
     }
 
     /**
@@ -878,9 +664,7 @@
      * @see #getPivotY()
      */
     public void setPivotY(float pivotY) {
-        if (hasNativeDisplayList()) {
-            nSetPivotY(mFinalizer.mNativeDisplayList, pivotY);
-        }
+        nSetPivotY(mNativeDisplayList, pivotY);
     }
 
     /**
@@ -889,10 +673,7 @@
      * @see #setPivotY(float)
      */
     public float getPivotY() {
-        if (hasNativeDisplayList()) {
-            return nGetPivotY(mFinalizer.mNativeDisplayList);
-        }
-        return 0.0f;
+        return nGetPivotY(mNativeDisplayList);
     }
 
     /**
@@ -906,9 +687,7 @@
      * @see #getCameraDistance()
      */
     public void setCameraDistance(float distance) {
-        if (hasNativeDisplayList()) {
-            nSetCameraDistance(mFinalizer.mNativeDisplayList, distance);
-        }
+        nSetCameraDistance(mNativeDisplayList, distance);
     }
 
     /**
@@ -917,10 +696,7 @@
      * @see #setCameraDistance(float)
      */
     public float getCameraDistance() {
-        if (hasNativeDisplayList()) {
-            return nGetCameraDistance(mFinalizer.mNativeDisplayList);
-        }
-        return 0.0f;
+        return nGetCameraDistance(mNativeDisplayList);
     }
 
     /**
@@ -932,9 +708,7 @@
      * @see #getLeft()
      */
     public void setLeft(int left) {
-        if (hasNativeDisplayList()) {
-            nSetLeft(mFinalizer.mNativeDisplayList, left);
-        }
+        nSetLeft(mNativeDisplayList, left);
     }
 
     /**
@@ -943,10 +717,7 @@
      * @see #setLeft(int)
      */
     public float getLeft() {
-        if (hasNativeDisplayList()) {
-            return nGetLeft(mFinalizer.mNativeDisplayList);
-        }
-        return 0.0f;
+        return nGetLeft(mNativeDisplayList);
     }
 
     /**
@@ -958,9 +729,7 @@
      * @see #getTop()
      */
     public void setTop(int top) {
-        if (hasNativeDisplayList()) {
-            nSetTop(mFinalizer.mNativeDisplayList, top);
-        }
+        nSetTop(mNativeDisplayList, top);
     }
 
     /**
@@ -969,10 +738,7 @@
      * @see #setTop(int)
      */
     public float getTop() {
-        if (hasNativeDisplayList()) {
-            return nGetTop(mFinalizer.mNativeDisplayList);
-        }
-        return 0.0f;
+        return nGetTop(mNativeDisplayList);
     }
 
     /**
@@ -984,9 +750,7 @@
      * @see #getRight()
      */
     public void setRight(int right) {
-        if (hasNativeDisplayList()) {
-            nSetRight(mFinalizer.mNativeDisplayList, right);
-        }
+        nSetRight(mNativeDisplayList, right);
     }
 
     /**
@@ -995,10 +759,7 @@
      * @see #setRight(int)
      */
     public float getRight() {
-        if (hasNativeDisplayList()) {
-            return nGetRight(mFinalizer.mNativeDisplayList);
-        }
-        return 0.0f;
+        return nGetRight(mNativeDisplayList);
     }
 
     /**
@@ -1010,9 +771,7 @@
      * @see #getBottom()
      */
     public void setBottom(int bottom) {
-        if (hasNativeDisplayList()) {
-            nSetBottom(mFinalizer.mNativeDisplayList, bottom);
-        }
+        nSetBottom(mNativeDisplayList, bottom);
     }
 
     /**
@@ -1021,10 +780,7 @@
      * @see #setBottom(int)
      */
     public float getBottom() {
-        if (hasNativeDisplayList()) {
-            return nGetBottom(mFinalizer.mNativeDisplayList);
-        }
-        return 0.0f;
+        return nGetBottom(mNativeDisplayList);
     }
 
     /**
@@ -1041,9 +797,7 @@
      * @see View#setBottom(int)
      */
     public void setLeftTopRightBottom(int left, int top, int right, int bottom) {
-        if (hasNativeDisplayList()) {
-            nSetLeftTopRightBottom(mFinalizer.mNativeDisplayList, left, top, right, bottom);
-        }
+        nSetLeftTopRightBottom(mNativeDisplayList, left, top, right, bottom);
     }
 
     /**
@@ -1055,9 +809,7 @@
      * @see View#offsetLeftAndRight(int)
      */
     public void offsetLeftAndRight(float offset) {
-        if (hasNativeDisplayList()) {
-            nOffsetLeftAndRight(mFinalizer.mNativeDisplayList, offset);
-        }
+        nOffsetLeftAndRight(mNativeDisplayList, offset);
     }
 
     /**
@@ -1069,9 +821,7 @@
      * @see View#offsetTopAndBottom(int)
      */
     public void offsetTopAndBottom(float offset) {
-        if (hasNativeDisplayList()) {
-            nOffsetTopAndBottom(mFinalizer.mNativeDisplayList, offset);
-        }
+        nOffsetTopAndBottom(mNativeDisplayList, offset);
     }
 
     /**
@@ -1081,22 +831,19 @@
      * @hide
      */
     public void output() {
-        if (hasNativeDisplayList()) {
-            nOutput(mFinalizer.mNativeDisplayList);
-        }
+        nOutput(mNativeDisplayList);
     }
 
     ///////////////////////////////////////////////////////////////////////////
     // Native methods
     ///////////////////////////////////////////////////////////////////////////
 
+    private static native long nCreate();
     private static native void nDestroyDisplayList(long displayList);
-    private static native int nGetDisplayListSize(long displayList);
     private static native void nSetDisplayListName(long displayList, String name);
 
     // Properties
 
-    private static native void nReset(long displayList);
     private static native void nOffsetTopAndBottom(long displayList, float offset);
     private static native void nOffsetLeftAndRight(long displayList, float offset);
     private static native void nSetLeftTopRightBottom(long displayList, int left, int top,
@@ -1135,7 +882,6 @@
     private static native void nSetAnimationMatrix(long displayList, long animationMatrix);
 
     private static native boolean nHasOverlappingRendering(long displayList);
-    private static native void nGetMatrix(long displayList, long matrix);
     private static native float nGetAlpha(long displayList);
     private static native float nGetLeft(long displayList);
     private static native float nGetTop(long displayList);
@@ -1158,20 +904,12 @@
     // Finalization
     ///////////////////////////////////////////////////////////////////////////
 
-    private static class DisplayListFinalizer {
-        final long mNativeDisplayList;
-
-        public DisplayListFinalizer(long nativeDisplayList) {
-            mNativeDisplayList = nativeDisplayList;
-        }
-
-        @Override
-        protected void finalize() throws Throwable {
-            try {
-                nDestroyDisplayList(mNativeDisplayList);
-            } finally {
-                super.finalize();
-            }
+    @Override
+    protected void finalize() throws Throwable {
+        try {
+            nDestroyDisplayList(mNativeDisplayList);
+        } finally {
+            super.finalize();
         }
     }
 }
diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/GLES20Canvas.java
index a08d83a..6c6fc9b 100644
--- a/core/java/android/view/GLES20Canvas.java
+++ b/core/java/android/view/GLES20Canvas.java
@@ -18,7 +18,6 @@
 
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
-import android.graphics.ColorFilter;
 import android.graphics.DrawFilter;
 import android.graphics.Matrix;
 import android.graphics.NinePatch;
@@ -47,7 +46,7 @@
     private static final int MODIFIER_SHADER = 2;
 
     private final boolean mOpaque;
-    private long mRenderer;
+    protected long mRenderer;
 
     // The native renderer will be destroyed when this object dies.
     // DO NOT overwrite this reference once it is set.
@@ -107,10 +106,6 @@
         }
     }
 
-    protected void resetDisplayListRenderer() {
-        nResetDisplayListRenderer(mRenderer);
-    }
-
     private static native long nCreateRenderer();
     private static native long nCreateDisplayListRenderer();
     private static native void nResetDisplayListRenderer(long renderer);
@@ -361,11 +356,7 @@
     // Display list
     ///////////////////////////////////////////////////////////////////////////
 
-    long getDisplayList(long displayList) {
-        return nGetDisplayList(mRenderer, displayList);
-    }
-
-    private static native long nGetDisplayList(long renderer, long displayList);
+    protected static native long nFinishRecording(long renderer);
 
     @Override
     public int drawDisplayList(DisplayList displayList, Rect dirty, int flags) {
diff --git a/core/java/android/view/GLES20RecordingCanvas.java b/core/java/android/view/GLES20RecordingCanvas.java
index b7b6883..2b29e5c 100644
--- a/core/java/android/view/GLES20RecordingCanvas.java
+++ b/core/java/android/view/GLES20RecordingCanvas.java
@@ -16,7 +16,6 @@
 
 package android.view;
 
-import android.graphics.Rect;
 import android.util.Pools.SynchronizedPool;
 
 /**
@@ -33,39 +32,23 @@
     private static final SynchronizedPool<GLES20RecordingCanvas> sPool =
             new SynchronizedPool<GLES20RecordingCanvas>(POOL_LIMIT);
 
-    private DisplayList mDisplayList;
-
     private GLES20RecordingCanvas() {
         super(true, true);
     }
 
-    static GLES20RecordingCanvas obtain(DisplayList displayList) {
+    static GLES20RecordingCanvas obtain() {
         GLES20RecordingCanvas canvas = sPool.acquire();
         if (canvas == null) {
             canvas = new GLES20RecordingCanvas();
         }
-        canvas.mDisplayList = displayList;
         return canvas;
     }
 
     void recycle() {
-        mDisplayList = null;
-        resetDisplayListRenderer();
         sPool.release(this);
     }
 
-    void start() {
-        mDisplayList.clearReferences();
-    }
-
-    long end(long nativeDisplayList) {
-        return getDisplayList(nativeDisplayList);
-    }
-
-    @Override
-    public int drawDisplayList(DisplayList displayList, Rect dirty, int flags) {
-        int status = super.drawDisplayList(displayList, dirty, flags);
-        mDisplayList.getChildDisplayLists().add(displayList);
-        return status;
+    long finishRecording() {
+        return nFinishRecording(mRenderer);
     }
 }
diff --git a/core/java/android/view/GLRenderer.java b/core/java/android/view/GLRenderer.java
index 4c92e950..c90e4b0 100644
--- a/core/java/android/view/GLRenderer.java
+++ b/core/java/android/view/GLRenderer.java
@@ -1196,6 +1196,11 @@
         }
     }
 
+    void swapDisplayListData(long displayList, long newData) {
+        nSwapDisplayListData(displayList, newData);
+    }
+    private static native void nSwapDisplayListData(long displayList, long newData);
+
     private DisplayList buildDisplayList(View view, HardwareCanvas canvas) {
         if (mDrawDelta <= 0) {
             return view.mDisplayList;
diff --git a/core/java/android/view/HardwareLayer.java b/core/java/android/view/HardwareLayer.java
index 8900d23..c526dd2 100644
--- a/core/java/android/view/HardwareLayer.java
+++ b/core/java/android/view/HardwareLayer.java
@@ -88,7 +88,7 @@
         }
 
         if (mDisplayList != null) {
-            mDisplayList.reset();
+            mDisplayList.destroyDisplayListData(mRenderer);
             mDisplayList = null;
         }
         if (mRenderer != null) {
diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java
index 7a943f0..bcc28e3 100644
--- a/core/java/android/view/HardwareRenderer.java
+++ b/core/java/android/view/HardwareRenderer.java
@@ -562,6 +562,8 @@
         mRequested = requested;
     }
 
+    abstract void swapDisplayListData(long displayList, long newData);
+
     /**
      * Describes a series of frames that should be drawn on screen as a graph.
      * Each frame is composed of 1 or more elements.
diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java
index e8f5e45..3dcfbb3 100644
--- a/core/java/android/view/ThreadedRenderer.java
+++ b/core/java/android/view/ThreadedRenderer.java
@@ -148,6 +148,11 @@
     }
 
     @Override
+    void swapDisplayListData(long displayList, long newData) {
+        nSwapDisplayListData(mNativeProxy, displayList, newData);
+    }
+
+    @Override
     void draw(View view, AttachInfo attachInfo, HardwareDrawCallbacks callbacks, Rect dirty) {
         attachInfo.mIgnoreDirtyState = true;
         attachInfo.mDrawingTime = SystemClock.uptimeMillis();
@@ -252,6 +257,8 @@
     private static native boolean nInitialize(long nativeProxy, Surface window);
     private static native void nUpdateSurface(long nativeProxy, Surface window);
     private static native void nSetup(long nativeProxy, int width, int height);
+    private static native void nSwapDisplayListData(long nativeProxy, long displayList,
+            long newData);
     private static native void nDrawDisplayList(long nativeProxy, long displayList,
             int dirtyLeft, int dirtyTop, int dirtyRight, int dirtyBottom);
     private static native void nRunWithGlContext(long nativeProxy, Runnable runnable);
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 39dc3f4..a57b311 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -7983,8 +7983,6 @@
      * @hide
      */
     public void dispatchStartTemporaryDetach() {
-        clearDisplayList();
-
         onStartTemporaryDetach();
     }
 
@@ -9385,7 +9383,7 @@
 
         if ((changed & VISIBILITY_MASK) != 0) {
             // If the view is invisible, cleanup its display list to free up resources
-            if (newVisibility != VISIBLE) {
+            if (newVisibility != VISIBLE && mAttachInfo != null) {
                 cleanupDraw();
             }
 
@@ -12812,14 +12810,6 @@
             InputMethodManager imm = InputMethodManager.peekInstance();
             imm.focusIn(this);
         }
-
-        if (mDisplayList != null) {
-            mDisplayList.clearDirty();
-        }
-
-        if (mBackgroundDisplayList != null) {
-            mBackgroundDisplayList.clearDirty();
-        }
     }
 
     /**
@@ -13137,20 +13127,9 @@
     }
 
     private void cleanupDraw() {
+        resetDisplayList();
         if (mAttachInfo != null) {
-            // Ensure the display lists are reset when the view root dies.
-            if (mDisplayList != null) {
-                mDisplayList.markDirty();
-                mAttachInfo.mViewRootImpl.enqueueDisplayList(mDisplayList);
-            }
-            if (mBackgroundDisplayList != null) {
-                mBackgroundDisplayList.markDirty();
-                mAttachInfo.mViewRootImpl.enqueueDisplayList(mBackgroundDisplayList);
-            }
             mAttachInfo.mViewRootImpl.cancelInvalidate(this);
-        } else {
-            // Should never happen.
-            resetDisplayList();
         }
     }
 
@@ -14027,7 +14006,7 @@
                     }
                 }
             } finally {
-                displayList.end();
+                displayList.end(getHardwareRenderer(), canvas);
                 displayList.setCaching(caching);
                 if (isLayer) {
                     displayList.setLeftTopRightBottom(0, 0, width, height);
@@ -14056,23 +14035,14 @@
         return mDisplayList;
     }
 
-    private void clearDisplayList() {
-        if (mDisplayList != null) {
-            mDisplayList.clear();
-        }
-
-        if (mBackgroundDisplayList != null) {
-            mBackgroundDisplayList.clear();
-        }
-    }
-
     private void resetDisplayList() {
-        if (mDisplayList != null) {
-            mDisplayList.reset();
+        HardwareRenderer renderer = getHardwareRenderer();
+        if (mDisplayList != null && mDisplayList.isValid()) {
+            mDisplayList.destroyDisplayListData(renderer);
         }
 
-        if (mBackgroundDisplayList != null) {
-            mBackgroundDisplayList.reset();
+        if (mBackgroundDisplayList != null && mBackgroundDisplayList.isValid()) {
+            mBackgroundDisplayList.destroyDisplayListData(renderer);
         }
     }
 
@@ -14695,7 +14665,7 @@
                             alpha = t.getAlpha();
                         }
                         if ((transformType & Transformation.TYPE_MATRIX) != 0) {
-                            displayList.setMatrix(t.getMatrix());
+                            displayList.setStaticMatrix(t.getMatrix());
                         }
                     }
                 }
@@ -15286,9 +15256,9 @@
             mBackgroundSizeChanged = false;
         }
 
-
         // Attempt to use a display list if requested.
-        if (canvas != null && canvas.isHardwareAccelerated()) {
+        if (canvas.isHardwareAccelerated() && mAttachInfo != null
+                && mAttachInfo.mHardwareRenderer != null) {
             mBackgroundDisplayList = getDrawableDisplayList(background, mBackgroundDisplayList);
 
             final DisplayList displayList = mBackgroundDisplayList;
@@ -15328,7 +15298,7 @@
      * @param displayList Existing display list, or {@code null}
      * @return A valid display list for the specified drawable
      */
-    private static DisplayList getDrawableDisplayList(Drawable drawable, DisplayList displayList) {
+    private DisplayList getDrawableDisplayList(Drawable drawable, DisplayList displayList) {
         if (displayList == null) {
             displayList = DisplayList.create(drawable.getClass().getName());
         }
@@ -15338,7 +15308,7 @@
         final int height = bounds.height();
         final HardwareCanvas canvas = displayList.start(width, height);
         drawable.draw(canvas);
-        displayList.end();
+        displayList.end(getHardwareRenderer(), canvas);
 
         // Set up drawable properties that are view-independent.
         displayList.setLeftTopRightBottom(bounds.left, bounds.top, bounds.right, bounds.bottom);
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 a338e6e..18517c5 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -56,6 +56,7 @@
 import android.util.Log;
 import android.util.Slog;
 import android.util.TypedValue;
+import android.view.Surface.OutOfResourcesException;
 import android.view.View.AttachInfo;
 import android.view.View.MeasureSpec;
 import android.view.accessibility.AccessibilityEvent;
@@ -69,7 +70,6 @@
 import android.view.animation.Interpolator;
 import android.view.inputmethod.InputConnection;
 import android.view.inputmethod.InputMethodManager;
-import android.view.Surface.OutOfResourcesException;
 import android.widget.Scroller;
 
 import com.android.internal.R;
@@ -294,8 +294,6 @@
     private long mFpsPrevTime = -1;
     private int mFpsNumFrames;
 
-    private final ArrayList<DisplayList> mDisplayLists = new ArrayList<DisplayList>();
-
     /**
      * see {@link #playSoundEffect(int)}
      */
@@ -620,7 +618,6 @@
     }
 
     void destroyHardwareResources() {
-        invalidateDisplayLists();
         if (mAttachInfo.mHardwareRenderer != null) {
             mAttachInfo.mHardwareRenderer.destroyHardwareResources(mView);
             mAttachInfo.mHardwareRenderer.destroy(false);
@@ -634,7 +631,6 @@
                 HardwareRenderer.trimMemory(ComponentCallbacks2.TRIM_MEMORY_MODERATE);
             }
         } else {
-            invalidateDisplayLists();
             destroyHardwareLayer(mView);
         }
     }
@@ -1503,7 +1499,7 @@
                                 com.android.internal.R.integer.config_mediumAnimTime);
 
                         layerCanvas.restoreToCount(restoreCount);
-                        layerDisplayList.end();
+                        layerDisplayList.end(mAttachInfo.mHardwareRenderer, layerCanvas);
                         layerDisplayList.setCaching(true);
                         layerDisplayList.setLeftTopRightBottom(0, 0, mWidth, mHeight);
                         mTempRect.set(0, 0, mWidth, mHeight);
@@ -2369,8 +2365,6 @@
                     appScale + ", width=" + mWidth + ", height=" + mHeight);
         }
 
-        invalidateDisplayLists();
-
         attachInfo.mTreeObserver.dispatchOnDraw();
 
         if (!dirty.isEmpty() || mIsAnimating) {
@@ -2588,20 +2582,6 @@
         return null;
     }
 
-    void invalidateDisplayLists() {
-        final ArrayList<DisplayList> displayLists = mDisplayLists;
-        final int count = displayLists.size();
-
-        for (int i = 0; i < count; i++) {
-            final DisplayList displayList = displayLists.get(i);
-            if (displayList.isDirty()) {
-                displayList.reset();
-            }
-        }
-
-        displayLists.clear();
-    }
-
     /**
      * @hide
      */
@@ -2921,7 +2901,7 @@
             }
         }
     }
-
+    
     /**
      * Return true if child is an ancestor of parent, (or equal to the parent).
      */
@@ -5229,7 +5209,7 @@
         DisplayList displayList = view.mDisplayList;
         info[0]++;
         if (displayList != null) {
-            info[1] += displayList.getSize();
+            info[1] += 0; /* TODO: Memory used by display lists */
         }
 
         if (view instanceof ViewGroup) {
@@ -5277,7 +5257,6 @@
             }
 
             if (mAdded && !mFirst) {
-                invalidateDisplayLists();
                 destroyHardwareRenderer();
 
                 if (mView != null) {
@@ -5743,10 +5722,6 @@
         mInvalidateOnAnimationRunnable.addViewRect(info);
     }
 
-    public void enqueueDisplayList(DisplayList displayList) {
-        mDisplayLists.add(displayList);
-    }
-
     public void cancelInvalidate(View view) {
         mHandler.removeMessages(MSG_INVALIDATE, view);
         // fixme: might leak the AttachInfo.InvalidateInfo objects instead of returning
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index ea62bbe..98b43b3 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -23,6 +23,7 @@
 import android.os.Parcelable;
 import android.text.InputFilter;
 import android.text.SpannableString;
+
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.widget.EditableInputConnection;
 
@@ -77,6 +78,7 @@
 import android.view.DragEvent;
 import android.view.Gravity;
 import android.view.HardwareCanvas;
+import android.view.HardwareRenderer;
 import android.view.LayoutInflater;
 import android.view.Menu;
 import android.view.MenuItem;
@@ -135,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;
@@ -260,7 +271,7 @@
             mTextView.removeCallbacks(mShowSuggestionRunnable);
         }
 
-        invalidateTextDisplayList();
+        destroyDisplayListsData();
 
         if (mSpellChecker != null) {
             mSpellChecker.closeSession();
@@ -275,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;
@@ -1314,10 +1338,11 @@
 
         layout.drawBackground(canvas, highlight, highlightPaint, cursorOffsetVertical,
                 firstLine, lastLine);
+        final HardwareRenderer renderer = mTextView.getHardwareRenderer();
 
         if (layout instanceof DynamicLayout) {
             if (mTextDisplayLists == null) {
-                mTextDisplayLists = new DisplayList[ArrayUtils.idealObjectArraySize(0)];
+                mTextDisplayLists = new TextDisplayList[ArrayUtils.idealObjectArraySize(0)];
             }
 
             DynamicLayout dynamicLayout = (DynamicLayout) layout;
@@ -1341,15 +1366,13 @@
                     searchStartIndex = blockIndex + 1;
                 }
 
-                DisplayList blockDisplayList = mTextDisplayLists[blockIndex];
-                if (blockDisplayList == null) {
-                    blockDisplayList = mTextDisplayLists[blockIndex] =
-                            DisplayList.create("Text " + blockIndex);
-                } else {
-                    if (blockIsInvalid) blockDisplayList.clear();
+                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);
@@ -1379,7 +1402,7 @@
                             // No need to untranslate, previous context is popped after
                             // drawDisplayList
                         } finally {
-                            blockDisplayList.end();
+                            blockDisplayList.end(renderer, hardwareCanvas);
                             // Same as drawDisplayList below, handled by our TextView's parent
                             blockDisplayList.setClipToBounds(false);
                         }
@@ -1420,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;
@@ -1459,7 +1482,7 @@
             while (i < numberOfBlocks) {
                 final int blockIndex = blockIndices[i];
                 if (blockIndex != DynamicLayout.INVALID_BLOCK_INDEX) {
-                    mTextDisplayLists[blockIndex].clear();
+                    mTextDisplayLists[blockIndex].isDirty = true;
                 }
                 if (blockEndLines[i] >= lastLine) break;
                 i++;
@@ -1470,7 +1493,7 @@
     void invalidateTextDisplayList() {
         if (mTextDisplayLists != null) {
             for (int i = 0; i < mTextDisplayLists.length; i++) {
-                if (mTextDisplayLists[i] != null) mTextDisplayLists[i].clear();
+                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/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 5bde80d..ee9c18d 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -396,16 +396,16 @@
  *
  * This will cut up "extraOptsBuf" as we chop it into individual options.
  *
+ * If "quotingArg" is non-null, it is passed before each extra option in mOptions.
+ *
  * Adds the strings, if any, to mOptions.
  */
-void AndroidRuntime::parseExtraOpts(char* extraOptsBuf)
+void AndroidRuntime::parseExtraOpts(char* extraOptsBuf, const char* quotingArg)
 {
     JavaVMOption opt;
-    char* start;
-    char* end;
-
     memset(&opt, 0, sizeof(opt));
-    start = extraOptsBuf;
+    char* start = extraOptsBuf;
+    char* end = NULL;
     while (*start != '\0') {
         while (*start == ' ')                   /* skip leading whitespace */
             start++;
@@ -419,6 +419,11 @@
             *end++ = '\0';          /* mark end, advance to indicate more */
 
         opt.optionString = start;
+        if (quotingArg != NULL) {
+            JavaVMOption quotingOpt;
+            quotingOpt.optionString = quotingArg;
+            mOptions.add(quotingOpt);
+        }
         mOptions.add(opt);
         start = end;
     }
@@ -450,6 +455,9 @@
     char gctypeOptsBuf[sizeof("-Xgc:")-1 + PROPERTY_VALUE_MAX];
     char heaptargetutilizationOptsBuf[sizeof("-XX:HeapTargetUtilization=")-1 + PROPERTY_VALUE_MAX];
     char jitcodecachesizeOptsBuf[sizeof("-Xjitcodecachesize:")-1 + PROPERTY_VALUE_MAX];
+    char dalvikVmLibBuf[PROPERTY_VALUE_MAX];
+    char dex2oatFlagsBuf[PROPERTY_VALUE_MAX];
+    char dex2oatImageFlagsBuf[PROPERTY_VALUE_MAX];
     char extraOptsBuf[PROPERTY_VALUE_MAX];
     char* stackTraceFile = NULL;
     bool checkJni = false;
@@ -742,9 +750,22 @@
         mOptions.add(opt);
     }
 
+    // libart tolerates libdvm flags, but not vice versa, so only pass these if libart.
+    property_get("persist.sys.dalvik.vm.lib.1", dalvikVmLibBuf, "libdvm.so");
+    if (strncmp(dalvikVmLibBuf, "libart", 6) == 0) {
+
+        // Extra options for DexClassLoader.
+        property_get("dalvik.vm.dex2oat-flags", dex2oatFlagsBuf, "");
+        parseExtraOpts(dex2oatFlagsBuf, "-Xcompiler-option");
+
+        // Extra options for boot.art/boot.oat image generation.
+        property_get("dalvik.vm.image-dex2oat-flags", dex2oatImageFlagsBuf, "");
+        parseExtraOpts(dex2oatImageFlagsBuf, "-Ximage-compiler-option");
+    }
+
     /* extra options; parse this late so it overrides others */
     property_get("dalvik.vm.extra-opts", extraOptsBuf, "");
-    parseExtraOpts(extraOptsBuf);
+    parseExtraOpts(extraOptsBuf, NULL);
 
     /* Set the properties for locale */
     {
diff --git a/core/jni/android_view_DisplayList.cpp b/core/jni/android_view_DisplayList.cpp
index e47e23c..c8952c1 100644
--- a/core/jni/android_view_DisplayList.cpp
+++ b/core/jni/android_view_DisplayList.cpp
@@ -41,18 +41,6 @@
 // DisplayList view properties
 // ----------------------------------------------------------------------------
 
-static void android_view_DisplayList_reset(JNIEnv* env,
-        jobject clazz, jlong displayListPtr) {
-    DisplayList* displayList = reinterpret_cast<DisplayList*>(displayListPtr);
-    displayList->reset();
-}
-
-static jint android_view_DisplayList_getDisplayListSize(JNIEnv* env,
-        jobject clazz, jlong displayListPtr) {
-    DisplayList* displayList = reinterpret_cast<DisplayList*>(displayListPtr);
-    return displayList->getSize();
-}
-
 static void android_view_DisplayList_setDisplayListName(JNIEnv* env,
         jobject clazz, jlong displayListPtr, jstring name) {
     DisplayList* displayList = reinterpret_cast<DisplayList*>(displayListPtr);
@@ -69,6 +57,11 @@
     displayList->output();
 }
 
+static jlong android_view_DisplayList_create(JNIEnv* env, jobject clazz) {
+    DisplayList* displayList = new DisplayList();
+    return reinterpret_cast<jlong>(displayList);
+}
+
 static void android_view_DisplayList_destroyDisplayList(JNIEnv* env,
         jobject clazz, jlong displayListPtr) {
     DisplayList* displayList = reinterpret_cast<DisplayList*>(displayListPtr);
@@ -285,18 +278,6 @@
     displayList->offsetTopBottom(offset);
 }
 
-static void android_view_DisplayList_getMatrix(JNIEnv* env,
-        jobject clazz, jlong displayListPtr, jlong matrixPtr) {
-    DisplayList* displayList = reinterpret_cast<DisplayList*>(displayListPtr);
-    SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixPtr);
-    SkMatrix* source = displayList->getStaticMatrix();
-    if (source) {
-        matrix->setConcat(SkMatrix::I(), *source);
-    } else {
-        matrix->setIdentity();
-    }
-}
-
 static jboolean android_view_DisplayList_hasOverlappingRendering(JNIEnv* env,
         jobject clazz, jlong displayListPtr) {
     DisplayList* displayList = reinterpret_cast<DisplayList*>(displayListPtr);
@@ -403,13 +384,12 @@
 
 static JNINativeMethod gMethods[] = {
 #ifdef USE_OPENGL_RENDERER
+    { "nCreate",               "()J",    (void*) android_view_DisplayList_create },
     { "nDestroyDisplayList",   "(J)V",   (void*) android_view_DisplayList_destroyDisplayList },
-    { "nGetDisplayListSize",   "(J)I",   (void*) android_view_DisplayList_getDisplayListSize },
     { "nSetDisplayListName",   "(JLjava/lang/String;)V",
             (void*) android_view_DisplayList_setDisplayListName },
     { "nOutput",               "(J)V",  (void*) android_view_DisplayList_output },
 
-    { "nReset",                "(J)V",   (void*) android_view_DisplayList_reset },
     { "nSetCaching",           "(JZ)V",  (void*) android_view_DisplayList_setCaching },
     { "nSetStaticMatrix",      "(JJ)V",  (void*) android_view_DisplayList_setStaticMatrix },
     { "nSetAnimationMatrix",   "(JJ)V",  (void*) android_view_DisplayList_setAnimationMatrix },
@@ -445,7 +425,6 @@
     { "nOffsetLeftAndRight",   "(JF)V",  (void*) android_view_DisplayList_offsetLeftAndRight },
     { "nOffsetTopAndBottom",   "(JF)V",  (void*) android_view_DisplayList_offsetTopAndBottom },
 
-    { "nGetMatrix",               "(JJ)V", (void*) android_view_DisplayList_getMatrix },
     { "nHasOverlappingRendering", "(J)Z",  (void*) android_view_DisplayList_hasOverlappingRendering },
     { "nGetAlpha",                "(J)F",  (void*) android_view_DisplayList_getAlpha },
     { "nGetLeft",                 "(J)F",  (void*) android_view_DisplayList_getLeft },
diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp
index 4e353fa..a4e6679 100644
--- a/core/jni/android_view_GLES20Canvas.cpp
+++ b/core/jni/android_view_GLES20Canvas.cpp
@@ -864,22 +864,15 @@
 // Display lists
 // ----------------------------------------------------------------------------
 
-static jint android_view_GLES20Canvas_getDisplayList(JNIEnv* env,
-        jobject clazz, jlong rendererPtr, jlong displayListPtr) {
-    DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
-    DisplayList* displayList = reinterpret_cast<DisplayList*>(displayListPtr);
-    return reinterpret_cast<jint>(renderer->getDisplayList(displayList));
-}
-
-static jint android_view_GLES20Canvas_createDisplayListRenderer(JNIEnv* env,
-        jobject clazz) {
-    return reinterpret_cast<jint>(new DisplayListRenderer);
-}
-
-static void android_view_GLES20Canvas_resetDisplayListRenderer(JNIEnv* env,
+static jlong android_view_GLES20Canvas_finishRecording(JNIEnv* env,
         jobject clazz, jlong rendererPtr) {
     DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
-    renderer->reset();
+    return reinterpret_cast<jlong>(renderer->finishRecording());
+}
+
+static jlong android_view_GLES20Canvas_createDisplayListRenderer(JNIEnv* env,
+        jobject clazz) {
+    return reinterpret_cast<jlong>(new DisplayListRenderer);
 }
 
 static jint android_view_GLES20Canvas_drawDisplayList(JNIEnv* env,
@@ -1094,12 +1087,11 @@
     { "nGetClipBounds",     "(JLandroid/graphics/Rect;)Z",
             (void*) android_view_GLES20Canvas_getClipBounds },
 
-    { "nGetDisplayList",         "(JJ)J",      (void*) android_view_GLES20Canvas_getDisplayList },
+    { "nFinishRecording",        "(J)J",      (void*) android_view_GLES20Canvas_finishRecording },
     { "nDrawDisplayList",        "(JJLandroid/graphics/Rect;I)I",
             (void*) android_view_GLES20Canvas_drawDisplayList },
 
     { "nCreateDisplayListRenderer", "()J",     (void*) android_view_GLES20Canvas_createDisplayListRenderer },
-    { "nResetDisplayListRenderer",  "(J)V",    (void*) android_view_GLES20Canvas_resetDisplayListRenderer },
 
     { "nInterrupt",              "(J)V",       (void*) android_view_GLES20Canvas_interrupt },
     { "nResume",                 "(J)V",       (void*) android_view_GLES20Canvas_resume },
diff --git a/core/jni/android_view_GLRenderer.cpp b/core/jni/android_view_GLRenderer.cpp
index 5c5b52c..5ea8460 100644
--- a/core/jni/android_view_GLRenderer.cpp
+++ b/core/jni/android_view_GLRenderer.cpp
@@ -27,6 +27,7 @@
 #include <utils/Timers.h>
 
 #include <Caches.h>
+#include <DisplayList.h>
 #include <Extensions.h>
 #include <LayerRenderer.h>
 
@@ -139,6 +140,14 @@
     LayerRenderer::destroyLayer(layer);
 }
 
+static void android_view_GLRenderer_swapDisplayListData(JNIEnv* env, jobject clazz,
+        jlong displayListPtr, jlong newDataPtr) {
+    using namespace android::uirenderer;
+    DisplayList* displayList = reinterpret_cast<DisplayList*>(displayListPtr);
+    DisplayListData* newData = reinterpret_cast<DisplayListData*>(newDataPtr);
+    displayList->setData(newData);
+}
+
 #endif // USE_OPENGL_RENDERER
 
 // ----------------------------------------------------------------------------
@@ -169,6 +178,7 @@
 
     { "getSystemTime",         "()J",   (void*) android_view_GLRenderer_getSystemTime },
     { "nDestroyLayer",         "(J)V",  (void*) android_view_GLRenderer_destroyLayer },
+    { "nSwapDisplayListData",  "(JJ)V", (void*) android_view_GLRenderer_swapDisplayListData },
 #endif
 
     { "setupShadersDiskCache", "(Ljava/lang/String;)V",
diff --git a/core/jni/android_view_ThreadedRenderer.cpp b/core/jni/android_view_ThreadedRenderer.cpp
index bc5c06e..444c8be 100644
--- a/core/jni/android_view_ThreadedRenderer.cpp
+++ b/core/jni/android_view_ThreadedRenderer.cpp
@@ -103,6 +103,14 @@
     proxy->setup(width, height);
 }
 
+static void android_view_ThreadedRenderer_swapDisplayListData(JNIEnv* env, jobject clazz,
+        jlong proxyPtr, jlong displayListPtr, jlong newDataPtr) {
+    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
+    DisplayList* displayList = reinterpret_cast<DisplayList*>(displayListPtr);
+    DisplayListData* newData = reinterpret_cast<DisplayListData*>(newDataPtr);
+    proxy->swapDisplayListData(displayList, newData);
+}
+
 static void android_view_ThreadedRenderer_drawDisplayList(JNIEnv* env, jobject clazz,
         jlong proxyPtr, jlong displayListPtr, jint dirtyLeft, jint dirtyTop,
         jint dirtyRight, jint dirtyBottom) {
@@ -183,10 +191,11 @@
     { "nInitialize", "(JLandroid/view/Surface;)Z", (void*) android_view_ThreadedRenderer_initialize },
     { "nUpdateSurface", "(JLandroid/view/Surface;)V", (void*) android_view_ThreadedRenderer_updateSurface },
     { "nSetup", "(JII)V", (void*) android_view_ThreadedRenderer_setup },
-    { "nDrawDisplayList", "(JJIIII)V", (void*) android_view_ThreadedRenderer_drawDisplayList},
-    { "nDestroyCanvas", "(J)V", (void*) android_view_ThreadedRenderer_destroyCanvas},
-    { "nAttachFunctor", "(JJ)V", (void*) android_view_ThreadedRenderer_attachFunctor},
-    { "nDetachFunctor", "(JJ)V", (void*) android_view_ThreadedRenderer_detachFunctor},
+    { "nSwapDisplayListData", "(JJJ)V", (void*) android_view_ThreadedRenderer_swapDisplayListData },
+    { "nDrawDisplayList", "(JJIIII)V", (void*) android_view_ThreadedRenderer_drawDisplayList },
+    { "nDestroyCanvas", "(J)V", (void*) android_view_ThreadedRenderer_destroyCanvas },
+    { "nAttachFunctor", "(JJ)V", (void*) android_view_ThreadedRenderer_attachFunctor },
+    { "nDetachFunctor", "(JJ)V", (void*) android_view_ThreadedRenderer_detachFunctor },
     { "nRunWithGlContext", "(JLjava/lang/Runnable;)V", (void*) android_view_ThreadedRenderer_runWithGlContext },
     { "nCreateDisplayListLayer", "(JII)J", (void*) android_view_ThreadedRenderer_createDisplayListLayer },
     { "nCreateTextureLayer", "(J)J", (void*) android_view_ThreadedRenderer_createTextureLayer },
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 55e21de..4c0ddeb 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1071,8 +1071,9 @@
         android:permissionGroupFlags="personalInfo"
         android:priority="370" />
 
-    <!-- Allows an application to modify or abort outgoing
-         calls. -->
+    <!-- Allows an application to see the number being dialed during an outgoing
+         call with the option to redirect the call to a different number or
+         abort the call altogether. -->
     <permission android:name="android.permission.PROCESS_OUTGOING_CALLS"
         android:permissionGroup="android.permission-group.PHONE_CALLS"
         android:protectionLevel="dangerous"
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 91bef50..afb7085 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -625,9 +625,9 @@
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_processOutgoingCalls">reroute outgoing calls</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_processOutgoingCalls">Allows the app to process
-      outgoing calls and change the number to be dialed. This permission allows
-      the app to monitor, redirect, or prevent outgoing calls.</string>
+    <string name="permdesc_processOutgoingCalls">Allows the app to see the
+        number being dialed during an outgoing call with the option to redirect
+        the call to a different number or abort the call altogether.</string>
 
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_receiveSms">receive text messages (SMS)</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/include/android_runtime/AndroidRuntime.h b/include/android_runtime/AndroidRuntime.h
index 0b3ce9a..649f4c3 100644
--- a/include/android_runtime/AndroidRuntime.h
+++ b/include/android_runtime/AndroidRuntime.h
@@ -115,7 +115,7 @@
 
 private:
     static int startReg(JNIEnv* env);
-    void parseExtraOpts(char* extraOptsBuf);
+    void parseExtraOpts(char* extraOptsBuf, const char* quotingArg);
     int startVm(JavaVM** pJavaVM, JNIEnv** pEnv);
 
     Vector<JavaVMOption> mOptions;
diff --git a/libs/hwui/DisplayList.cpp b/libs/hwui/DisplayList.cpp
index 23c33ca..bdb2f8d 100644
--- a/libs/hwui/DisplayList.cpp
+++ b/libs/hwui/DisplayList.cpp
@@ -48,179 +48,10 @@
     fflush(file);
 }
 
-DisplayList::DisplayList(const DisplayListRenderer& recorder) :
-    mDestroyed(false), mTransformMatrix(NULL), mTransformCamera(NULL), mTransformMatrix3D(NULL),
-    mStaticMatrix(NULL), mAnimationMatrix(NULL) {
+DisplayList::DisplayList() :
+        mDisplayListData(0), mDestroyed(false), mTransformMatrix(NULL), mTransformCamera(NULL),
+        mTransformMatrix3D(NULL), mStaticMatrix(NULL), mAnimationMatrix(NULL) {
 
-    initFromDisplayListRenderer(recorder);
-}
-
-DisplayList::~DisplayList() {
-    mDestroyed = true;
-    clearResources();
-}
-
-void DisplayList::destroyDisplayListDeferred(DisplayList* displayList) {
-    if (displayList) {
-        DISPLAY_LIST_LOGD("Deferring display list destruction");
-        Caches::getInstance().deleteDisplayListDeferred(displayList);
-    }
-}
-
-void DisplayList::clearResources() {
-    mDisplayListData = NULL;
-
-    delete mTransformMatrix;
-    delete mTransformCamera;
-    delete mTransformMatrix3D;
-    delete mStaticMatrix;
-    delete mAnimationMatrix;
-
-    mTransformMatrix = NULL;
-    mTransformCamera = NULL;
-    mTransformMatrix3D = NULL;
-    mStaticMatrix = NULL;
-    mAnimationMatrix = NULL;
-
-    Caches& caches = Caches::getInstance();
-    caches.unregisterFunctors(mFunctorCount);
-    caches.resourceCache.lock();
-
-    for (size_t i = 0; i < mBitmapResources.size(); i++) {
-        caches.resourceCache.decrementRefcountLocked(mBitmapResources.itemAt(i));
-    }
-
-    for (size_t i = 0; i < mOwnedBitmapResources.size(); i++) {
-        const SkBitmap* bitmap = mOwnedBitmapResources.itemAt(i);
-        caches.resourceCache.decrementRefcountLocked(bitmap);
-        caches.resourceCache.destructorLocked(bitmap);
-    }
-
-    for (size_t i = 0; i < mPatchResources.size(); i++) {
-        caches.resourceCache.decrementRefcountLocked(mPatchResources.itemAt(i));
-    }
-
-    for (size_t i = 0; i < mShaders.size(); i++) {
-        caches.resourceCache.decrementRefcountLocked(mShaders.itemAt(i));
-        caches.resourceCache.destructorLocked(mShaders.itemAt(i));
-    }
-
-    for (size_t i = 0; i < mSourcePaths.size(); i++) {
-        caches.resourceCache.decrementRefcountLocked(mSourcePaths.itemAt(i));
-    }
-
-    for (size_t i = 0; i < mLayers.size(); i++) {
-        caches.resourceCache.decrementRefcountLocked(mLayers.itemAt(i));
-    }
-
-    caches.resourceCache.unlock();
-
-    for (size_t i = 0; i < mPaints.size(); i++) {
-        delete mPaints.itemAt(i);
-    }
-
-    for (size_t i = 0; i < mRegions.size(); i++) {
-        delete mRegions.itemAt(i);
-    }
-
-    for (size_t i = 0; i < mPaths.size(); i++) {
-        delete mPaths.itemAt(i);
-    }
-
-    for (size_t i = 0; i < mMatrices.size(); i++) {
-        delete mMatrices.itemAt(i);
-    }
-
-    mBitmapResources.clear();
-    mOwnedBitmapResources.clear();
-    mPatchResources.clear();
-    mShaders.clear();
-    mSourcePaths.clear();
-    mPaints.clear();
-    mRegions.clear();
-    mPaths.clear();
-    mMatrices.clear();
-    mLayers.clear();
-}
-
-void DisplayList::reset() {
-    clearResources();
-    init();
-}
-
-void DisplayList::initFromDisplayListRenderer(const DisplayListRenderer& recorder, bool reusing) {
-    if (reusing) {
-        // re-using display list - clear out previous allocations
-        clearResources();
-    }
-
-    init();
-
-    mDisplayListData = recorder.getDisplayListData();
-    mSize = mDisplayListData->allocator.usedSize();
-
-    if (mSize == 0) {
-        return;
-    }
-
-    mFunctorCount = recorder.getFunctorCount();
-
-    Caches& caches = Caches::getInstance();
-    caches.registerFunctors(mFunctorCount);
-    caches.resourceCache.lock();
-
-    const Vector<const SkBitmap*>& bitmapResources = recorder.getBitmapResources();
-    for (size_t i = 0; i < bitmapResources.size(); i++) {
-        const SkBitmap* resource = bitmapResources.itemAt(i);
-        mBitmapResources.add(resource);
-        caches.resourceCache.incrementRefcountLocked(resource);
-    }
-
-    const Vector<const SkBitmap*>& ownedBitmapResources = recorder.getOwnedBitmapResources();
-    for (size_t i = 0; i < ownedBitmapResources.size(); i++) {
-        const SkBitmap* resource = ownedBitmapResources.itemAt(i);
-        mOwnedBitmapResources.add(resource);
-        caches.resourceCache.incrementRefcountLocked(resource);
-    }
-
-    const Vector<const Res_png_9patch*>& patchResources = recorder.getPatchResources();
-    for (size_t i = 0; i < patchResources.size(); i++) {
-        const Res_png_9patch* resource = patchResources.itemAt(i);
-        mPatchResources.add(resource);
-        caches.resourceCache.incrementRefcountLocked(resource);
-    }
-
-    const Vector<SkiaShader*>& shaders = recorder.getShaders();
-    for (size_t i = 0; i < shaders.size(); i++) {
-        SkiaShader* resource = shaders.itemAt(i);
-        mShaders.add(resource);
-        caches.resourceCache.incrementRefcountLocked(resource);
-    }
-
-    const SortedVector<const SkPath*>& sourcePaths = recorder.getSourcePaths();
-    for (size_t i = 0; i < sourcePaths.size(); i++) {
-        mSourcePaths.add(sourcePaths.itemAt(i));
-        caches.resourceCache.incrementRefcountLocked(sourcePaths.itemAt(i));
-    }
-
-    const Vector<Layer*>& layers = recorder.getLayers();
-    for (size_t i = 0; i < layers.size(); i++) {
-        mLayers.add(layers.itemAt(i));
-        caches.resourceCache.incrementRefcountLocked(layers.itemAt(i));
-    }
-
-    caches.resourceCache.unlock();
-
-    mPaints.appendVector(recorder.getPaints());
-    mRegions.appendVector(recorder.getRegions());
-    mPaths.appendVector(recorder.getPaths());
-    mMatrices.appendVector(recorder.getMatrices());
-}
-
-void DisplayList::init() {
-    mSize = 0;
-    mIsRenderable = true;
-    mFunctorCount = 0;
     mLeft = 0;
     mTop = 0;
     mRight = 0;
@@ -256,8 +87,28 @@
     mCaching = false;
 }
 
-size_t DisplayList::getSize() {
-    return mSize;
+DisplayList::~DisplayList() {
+    LOG_ALWAYS_FATAL_IF(mDestroyed, "Double destroyed DisplayList %p", this);
+
+    mDestroyed = true;
+    delete mDisplayListData;
+    delete mTransformMatrix;
+    delete mTransformCamera;
+    delete mTransformMatrix3D;
+    delete mStaticMatrix;
+    delete mAnimationMatrix;
+}
+
+void DisplayList::destroyDisplayListDeferred(DisplayList* displayList) {
+    if (displayList) {
+        DISPLAY_LIST_LOGD("Deferring display list destruction");
+        Caches::getInstance().deleteDisplayListDeferred(displayList);
+    }
+}
+
+void DisplayList::setData(DisplayListData* data) {
+    delete mDisplayListData;
+    mDisplayListData = data;
 }
 
 /**
@@ -518,7 +369,7 @@
         const mat4* transformFromProjectionSurface) {
     m3dNodes.clear();
     mProjectedNodes.clear();
-    if (mDisplayListData == NULL || mSize == 0) return;
+    if (mDisplayListData == NULL || mDisplayListData->isEmpty()) return;
 
     // TODO: should avoid this calculation in most cases
     // TODO: just calculate single matrix, down to all leaf composited elements
@@ -716,10 +567,10 @@
 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(), mSize);
+        ALOGW("Error: %s is drawing after destruction", getName());
         CRASH();
     }
-    if (mSize == 0 || mAlpha <= 0) {
+    if (mDisplayListData->isEmpty() || mAlpha <= 0) {
         DISPLAY_LIST_LOGD("%*sEmpty display list (%p, %s)", level * 2, "", this, mName.string());
         return;
     }
@@ -777,5 +628,67 @@
     renderer.setOverrideLayerAlpha(1.0f);
 }
 
+void DisplayListData::cleanupResources() {
+    Caches& caches = Caches::getInstance();
+    caches.unregisterFunctors(functorCount);
+    caches.resourceCache.lock();
+
+    for (size_t i = 0; i < bitmapResources.size(); i++) {
+        caches.resourceCache.decrementRefcountLocked(bitmapResources.itemAt(i));
+    }
+
+    for (size_t i = 0; i < ownedBitmapResources.size(); i++) {
+        const SkBitmap* bitmap = ownedBitmapResources.itemAt(i);
+        caches.resourceCache.decrementRefcountLocked(bitmap);
+        caches.resourceCache.destructorLocked(bitmap);
+    }
+
+    for (size_t i = 0; i < patchResources.size(); i++) {
+        caches.resourceCache.decrementRefcountLocked(patchResources.itemAt(i));
+    }
+
+    for (size_t i = 0; i < shaders.size(); i++) {
+        caches.resourceCache.decrementRefcountLocked(shaders.itemAt(i));
+        caches.resourceCache.destructorLocked(shaders.itemAt(i));
+    }
+
+    for (size_t i = 0; i < sourcePaths.size(); i++) {
+        caches.resourceCache.decrementRefcountLocked(sourcePaths.itemAt(i));
+    }
+
+    for (size_t i = 0; i < layers.size(); i++) {
+        caches.resourceCache.decrementRefcountLocked(layers.itemAt(i));
+    }
+
+    caches.resourceCache.unlock();
+
+    for (size_t i = 0; i < paints.size(); i++) {
+        delete paints.itemAt(i);
+    }
+
+    for (size_t i = 0; i < regions.size(); i++) {
+        delete regions.itemAt(i);
+    }
+
+    for (size_t i = 0; i < paths.size(); i++) {
+        delete paths.itemAt(i);
+    }
+
+    for (size_t i = 0; i < matrices.size(); i++) {
+        delete matrices.itemAt(i);
+    }
+
+    bitmapResources.clear();
+    ownedBitmapResources.clear();
+    patchResources.clear();
+    shaders.clear();
+    sourcePaths.clear();
+    paints.clear();
+    regions.clear();
+    paths.clear();
+    matrices.clear();
+    layers.clear();
+}
+
 }; // namespace uirenderer
 }; // namespace android
diff --git a/libs/hwui/DisplayList.h b/libs/hwui/DisplayList.h
index 9487fae..aba40b6 100644
--- a/libs/hwui/DisplayList.h
+++ b/libs/hwui/DisplayList.h
@@ -107,11 +107,13 @@
 };
 
 /**
- * Refcounted structure that holds the list of commands used in display list stream.
+ * Data structure that holds the list of commands used in display list stream
  */
-class DisplayListData : public LightRefBase<DisplayListData> {
+class DisplayListData {
 public:
-    DisplayListData() : projectionReceiveIndex(-1) {}
+    DisplayListData() : projectionReceiveIndex(-1), functorCount(0), hasDrawOps(false) {}
+    virtual ~DisplayListData() { cleanupResources(); }
+
     // allocator into which all ops were allocated
     LinearAllocator allocator;
 
@@ -123,6 +125,27 @@
 
     // index of DisplayListOp restore, after which projected descendents should be drawn
     int projectionReceiveIndex;
+
+    Vector<const SkBitmap*> bitmapResources;
+    Vector<const SkBitmap*> ownedBitmapResources;
+    Vector<const Res_png_9patch*> patchResources;
+
+    Vector<const SkPaint*> paints;
+    Vector<const SkPath*> paths;
+    SortedVector<const SkPath*> sourcePaths;
+    Vector<const SkRegion*> regions;
+    Vector<const SkMatrix*> matrices;
+    Vector<SkiaShader*> shaders;
+    Vector<Layer*> layers;
+    uint32_t functorCount;
+    bool hasDrawOps;
+
+    bool isEmpty() {
+        return !displayListOps.size();
+    }
+
+private:
+    void cleanupResources();
 };
 
 /**
@@ -139,7 +162,7 @@
  */
 class DisplayList {
 public:
-    DisplayList(const DisplayListRenderer& recorder);
+    ANDROID_API DisplayList();
     ANDROID_API ~DisplayList();
 
     // See flags defined in DisplayList.java
@@ -147,11 +170,10 @@
         kReplayFlag_ClipChildren = 0x1
     };
 
-    ANDROID_API size_t getSize();
     ANDROID_API static void destroyDisplayListDeferred(DisplayList* displayList);
     ANDROID_API static void outputLogBuffer(int fd);
 
-    void initFromDisplayListRenderer(const DisplayListRenderer& recorder, bool reusing = false);
+    ANDROID_API void setData(DisplayListData* newData);
 
     void computeOrdering();
     void defer(DeferStateStruct& deferStruct, const int level);
@@ -159,14 +181,8 @@
 
     ANDROID_API void output(uint32_t level = 1);
 
-    ANDROID_API void reset();
-
-    void setRenderable(bool renderable) {
-        mIsRenderable = renderable;
-    }
-
     bool isRenderable() const {
-        return mIsRenderable;
+        return mDisplayListData && mDisplayListData->hasDrawOps;
     }
 
     void setName(const char* name) {
@@ -571,10 +587,6 @@
     template <class T>
     inline void iterate(OpenGLRenderer& renderer, T& handler, const int level);
 
-    void init();
-
-    void clearResources();
-
     void updateMatrix();
 
     class TextContainer {
@@ -591,24 +603,7 @@
         const char* mText;
     };
 
-    Vector<const SkBitmap*> mBitmapResources;
-    Vector<const SkBitmap*> mOwnedBitmapResources;
-    Vector<const Res_png_9patch*> mPatchResources;
-
-    Vector<const SkPaint*> mPaints;
-    Vector<const SkPath*> mPaths;
-    SortedVector<const SkPath*> mSourcePaths;
-    Vector<const SkRegion*> mRegions;
-    Vector<const SkMatrix*> mMatrices;
-    Vector<SkiaShader*> mShaders;
-    Vector<Layer*> mLayers;
-
-    sp<DisplayListData> mDisplayListData;
-
-    size_t mSize;
-
-    bool mIsRenderable;
-    uint32_t mFunctorCount;
+    DisplayListData* mDisplayListData;
 
     String8 mName;
     bool mDestroyed; // used for debugging crash, TODO: remove once invalid state crash fixed
diff --git a/libs/hwui/DisplayListRenderer.cpp b/libs/hwui/DisplayListRenderer.cpp
index 0cbf088..3b1d567 100644
--- a/libs/hwui/DisplayListRenderer.cpp
+++ b/libs/hwui/DisplayListRenderer.cpp
@@ -32,83 +32,28 @@
 namespace uirenderer {
 
 DisplayListRenderer::DisplayListRenderer():
-        mCaches(Caches::getInstance()), mDisplayListData(new DisplayListData),
+        mCaches(Caches::getInstance()), mDisplayListData(0),
         mTranslateX(0.0f), mTranslateY(0.0f), mHasTranslate(false),
-        mHasDrawOps(false), mFunctorCount(0) {
+        mRestoreSaveCount(-1) {
 }
 
 DisplayListRenderer::~DisplayListRenderer() {
-    reset();
-}
-
-void DisplayListRenderer::reset() {
-    mDisplayListData = new DisplayListData();
-    mCaches.resourceCache.lock();
-
-    for (size_t i = 0; i < mBitmapResources.size(); i++) {
-        mCaches.resourceCache.decrementRefcountLocked(mBitmapResources.itemAt(i));
-    }
-
-    for (size_t i = 0; i < mOwnedBitmapResources.size(); i++) {
-        mCaches.resourceCache.decrementRefcountLocked(mOwnedBitmapResources.itemAt(i));
-    }
-
-    for (size_t i = 0; i < mPatchResources.size(); i++) {
-        mCaches.resourceCache.decrementRefcountLocked(mPatchResources.itemAt(i));
-    }
-
-    for (size_t i = 0; i < mShaders.size(); i++) {
-        mCaches.resourceCache.decrementRefcountLocked(mShaders.itemAt(i));
-    }
-
-    for (size_t i = 0; i < mSourcePaths.size(); i++) {
-        mCaches.resourceCache.decrementRefcountLocked(mSourcePaths.itemAt(i));
-    }
-
-    for (size_t i = 0; i < mLayers.size(); i++) {
-        mCaches.resourceCache.decrementRefcountLocked(mLayers.itemAt(i));
-    }
-
-    mCaches.resourceCache.unlock();
-
-    mBitmapResources.clear();
-    mOwnedBitmapResources.clear();
-    mPatchResources.clear();
-    mSourcePaths.clear();
-
-    mShaders.clear();
-    mShaderMap.clear();
-
-    mPaints.clear();
-    mPaintMap.clear();
-
-    mRegions.clear();
-    mRegionMap.clear();
-
-    mPaths.clear();
-    mPathMap.clear();
-
-    mMatrices.clear();
-
-    mLayers.clear();
-
-    mHasDrawOps = false;
-    mFunctorCount = 0;
+    LOG_ALWAYS_FATAL_IF(mDisplayListData,
+            "Destroyed a DisplayListRenderer during a record!");
 }
 
 ///////////////////////////////////////////////////////////////////////////////
 // Operations
 ///////////////////////////////////////////////////////////////////////////////
 
-DisplayList* DisplayListRenderer::getDisplayList(DisplayList* displayList) {
-    if (!displayList) {
-        displayList = new DisplayList(*this);
-    } else {
-        displayList->initFromDisplayListRenderer(*this, true);
-    }
-    // TODO: should just avoid setting the DisplayList's DisplayListData
-    displayList->setRenderable(mHasDrawOps);
-    return displayList;
+DisplayListData* DisplayListRenderer::finishRecording() {
+    mShaderMap.clear();
+    mPaintMap.clear();
+    mRegionMap.clear();
+    mPathMap.clear();
+    DisplayListData* data = mDisplayListData;
+    mDisplayListData = 0;
+    return data;
 }
 
 void DisplayListRenderer::setViewport(int width, int height) {
@@ -120,6 +65,11 @@
 
 status_t DisplayListRenderer::prepareDirty(float left, float top,
         float right, float bottom, bool opaque) {
+
+    LOG_ALWAYS_FATAL_IF(mDisplayListData,
+            "prepareDirty called a second time during a recording!");
+    mDisplayListData = new DisplayListData();
+
     initializeSaveStack(0, 0, getWidth(), getHeight());
 
     mDirtyClip = opaque;
@@ -142,7 +92,7 @@
 status_t DisplayListRenderer::callDrawGLFunction(Functor *functor, Rect& dirty) {
     // Ignore dirty during recording, it matters only when we replay
     addDrawOp(new (alloc()) DrawFunctorOp(functor));
-    mFunctorCount++;
+    mDisplayListData->functorCount++;
     return DrawGlInfo::kStatusDone; // No invalidate needed at record-time
 }
 
@@ -501,7 +451,7 @@
         op->setQuickRejected(rejected);
     }
 
-    mHasDrawOps = true;
+    mDisplayListData->hasDrawOps = true;
     addOpInternal(op);
 }
 
diff --git a/libs/hwui/DisplayListRenderer.h b/libs/hwui/DisplayListRenderer.h
index 7e62c5d..1fb72ce 100644
--- a/libs/hwui/DisplayListRenderer.h
+++ b/libs/hwui/DisplayListRenderer.h
@@ -61,7 +61,7 @@
     ANDROID_API DisplayListRenderer();
     virtual ~DisplayListRenderer();
 
-    ANDROID_API DisplayList* getDisplayList(DisplayList* displayList);
+    ANDROID_API DisplayListData* finishRecording();
 
     virtual bool isRecording() const { return true; }
 
@@ -162,59 +162,6 @@
     // TODO: rename for consistency
     virtual status_t callDrawGLFunction(Functor* functor, Rect& dirty);
 
-// ----------------------------------------------------------------------------
-// DisplayList / resource management
-// ----------------------------------------------------------------------------
-    ANDROID_API void reset();
-
-    sp<DisplayListData> getDisplayListData() const {
-        return mDisplayListData;
-    }
-
-    const Vector<const SkBitmap*>& getBitmapResources() const {
-        return mBitmapResources;
-    }
-
-    const Vector<const SkBitmap*>& getOwnedBitmapResources() const {
-        return mOwnedBitmapResources;
-    }
-
-    const Vector<const Res_png_9patch*>& getPatchResources() const {
-        return mPatchResources;
-    }
-
-    const Vector<SkiaShader*>& getShaders() const {
-        return mShaders;
-    }
-
-    const Vector<const SkPaint*>& getPaints() const {
-        return mPaints;
-    }
-
-    const Vector<const SkPath*>& getPaths() const {
-        return mPaths;
-    }
-
-    const SortedVector<const SkPath*>& getSourcePaths() const {
-        return mSourcePaths;
-    }
-
-    const Vector<const SkRegion*>& getRegions() const {
-        return mRegions;
-    }
-
-    const Vector<Layer*>& getLayers() const {
-        return mLayers;
-    }
-
-    const Vector<const SkMatrix*>& getMatrices() const {
-        return mMatrices;
-    }
-
-    uint32_t getFunctorCount() const {
-        return mFunctorCount;
-    }
-
 private:
     void insertRestoreToCount();
     void insertTranslate();
@@ -252,11 +199,11 @@
             pathCopy = newPathCopy;
             // replaceValueFor() performs an add if the entry doesn't exist
             mPathMap.replaceValueFor(path, pathCopy);
-            mPaths.add(pathCopy);
+            mDisplayListData->paths.add(pathCopy);
         }
-        if (mSourcePaths.indexOf(path) < 0) {
+        if (mDisplayListData->sourcePaths.indexOf(path) < 0) {
             mCaches.resourceCache.incrementRefcount(path);
-            mSourcePaths.add(path);
+            mDisplayListData->sourcePaths.add(path);
         }
         return pathCopy;
     }
@@ -271,7 +218,7 @@
             paintCopy = new SkPaint(*paint);
             // replaceValueFor() performs an add if the entry doesn't exist
             mPaintMap.replaceValueFor(paint, paintCopy);
-            mPaints.add(paintCopy);
+            mDisplayListData->paints.add(paintCopy);
         }
 
         return paintCopy;
@@ -288,7 +235,7 @@
             regionCopy = new SkRegion(*region);
             // replaceValueFor() performs an add if the entry doesn't exist
             mRegionMap.replaceValueFor(region, regionCopy);
-            mRegions.add(regionCopy);
+            mDisplayListData->regions.add(regionCopy);
         }
 
         return regionCopy;
@@ -299,14 +246,14 @@
             // Copying the matrix is cheap and prevents against the user changing
             // the original matrix before the operation that uses it
             const SkMatrix* copy = new SkMatrix(*matrix);
-            mMatrices.add(copy);
+            mDisplayListData->matrices.add(copy);
             return copy;
         }
         return matrix;
     }
 
     inline Layer* refLayer(Layer* layer) {
-        mLayers.add(layer);
+        mDisplayListData->layers.add(layer);
         mCaches.resourceCache.incrementRefcount(layer);
         return layer;
     }
@@ -316,13 +263,13 @@
         // correctly, such as creating the bitmap from scratch, drawing with it, changing its
         // contents, and drawing again. The only fix would be to always copy it the first time,
         // which doesn't seem worth the extra cycles for this unlikely case.
-        mBitmapResources.add(bitmap);
+        mDisplayListData->bitmapResources.add(bitmap);
         mCaches.resourceCache.incrementRefcount(bitmap);
         return bitmap;
     }
 
     inline const SkBitmap* refBitmapData(const SkBitmap* bitmap) {
-        mOwnedBitmapResources.add(bitmap);
+        mDisplayListData->ownedBitmapResources.add(bitmap);
         mCaches.resourceCache.incrementRefcount(bitmap);
         return bitmap;
     }
@@ -336,52 +283,31 @@
             shaderCopy = shader->copy();
             // replaceValueFor() performs an add if the entry doesn't exist
             mShaderMap.replaceValueFor(shader, shaderCopy);
-            mShaders.add(shaderCopy);
+            mDisplayListData->shaders.add(shaderCopy);
             mCaches.resourceCache.incrementRefcount(shaderCopy);
         }
         return shaderCopy;
     }
 
     inline const Res_png_9patch* refPatch(const Res_png_9patch* patch) {
-        mPatchResources.add(patch);
+        mDisplayListData->patchResources.add(patch);
         mCaches.resourceCache.incrementRefcount(patch);
         return patch;
     }
 
-    // TODO: move these to DisplayListData
-    Vector<const SkBitmap*> mBitmapResources;
-    Vector<const SkBitmap*> mOwnedBitmapResources;
-    Vector<const Res_png_9patch*> mPatchResources;
-
-    Vector<const SkPaint*> mPaints;
     DefaultKeyedVector<const SkPaint*, const SkPaint*> mPaintMap;
-
-    Vector<const SkPath*> mPaths;
     DefaultKeyedVector<const SkPath*, const SkPath*> mPathMap;
-
-    SortedVector<const SkPath*> mSourcePaths;
-
-    Vector<const SkRegion*> mRegions;
     DefaultKeyedVector<const SkRegion*, const SkRegion*> mRegionMap;
-
-    Vector<SkiaShader*> mShaders;
     DefaultKeyedVector<SkiaShader*, SkiaShader*> mShaderMap;
 
-    Vector<const SkMatrix*> mMatrices;
-
-    Vector<Layer*> mLayers;
-
-    int mRestoreSaveCount;
-
     Caches& mCaches;
-    sp<DisplayListData> mDisplayListData;
+    DisplayListData* mDisplayListData;
 
     float mTranslateX;
     float mTranslateY;
     bool mHasTranslate;
-    bool mHasDrawOps;
 
-    uint32_t mFunctorCount;
+    int mRestoreSaveCount;
 
     friend class DisplayList;
 
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index fe781bd..0568851 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -373,6 +373,10 @@
     mCanvas->setViewport(width, height);
 }
 
+void CanvasContext::swapDisplayListData(DisplayList* displayList, DisplayListData* newData) {
+    displayList->setData(newData);
+}
+
 void CanvasContext::processLayerUpdates(const Vector<DeferredLayerUpdater*>* layerUpdaters) {
     mGlobalContext->makeCurrent(mEglSurface);
     for (size_t i = 0; i < layerUpdaters->size(); i++) {
diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h
index 5fac582..2c9348c 100644
--- a/libs/hwui/renderthread/CanvasContext.h
+++ b/libs/hwui/renderthread/CanvasContext.h
@@ -32,6 +32,7 @@
 
 class DeferredLayerUpdater;
 class DisplayList;
+class DisplayListData;
 class OpenGLRenderer;
 class Rect;
 
@@ -62,6 +63,7 @@
     bool initialize(EGLNativeWindowType window);
     void updateSurface(EGLNativeWindowType window);
     void setup(int width, int height);
+    void swapDisplayListData(DisplayList* displayList, DisplayListData* newData);
     void processLayerUpdates(const Vector<DeferredLayerUpdater*>* layerUpdaters);
     void drawDisplayList(DisplayList* displayList, Rect* dirty);
     void destroyCanvas();
diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp
index 0c667fd..c3bf404 100644
--- a/libs/hwui/renderthread/RenderProxy.cpp
+++ b/libs/hwui/renderthread/RenderProxy.cpp
@@ -117,6 +117,20 @@
     post(task);
 }
 
+CREATE_BRIDGE3(swapDisplayListData, CanvasContext* context, DisplayList* displayList,
+        DisplayListData* newData) {
+    args->context->swapDisplayListData(args->displayList, args->newData);
+    return NULL;
+}
+
+void RenderProxy::swapDisplayListData(DisplayList* displayList, DisplayListData* newData) {
+    SETUP_TASK(swapDisplayListData);
+    args->context = mContext;
+    args->displayList = displayList;
+    args->newData = newData;
+    post(task);
+}
+
 CREATE_BRIDGE4(drawDisplayList, CanvasContext* context, DisplayList* displayList,
         Rect dirty, const Vector<DeferredLayerUpdater*>* layerUpdates) {
     Rect* dirty = &args->dirty;
diff --git a/libs/hwui/renderthread/RenderProxy.h b/libs/hwui/renderthread/RenderProxy.h
index 8ff3d63..0934b98 100644
--- a/libs/hwui/renderthread/RenderProxy.h
+++ b/libs/hwui/renderthread/RenderProxy.h
@@ -33,6 +33,7 @@
 
 class DeferredLayerUpdater;
 class DisplayList;
+class DisplayListData;
 class Layer;
 class Rect;
 
@@ -59,6 +60,7 @@
     ANDROID_API bool initialize(EGLNativeWindowType window);
     ANDROID_API void updateSurface(EGLNativeWindowType window);
     ANDROID_API void setup(int width, int height);
+    ANDROID_API void swapDisplayListData(DisplayList* displayList, DisplayListData* newData);
     ANDROID_API void drawDisplayList(DisplayList* displayList,
             int dirtyLeft, int dirtyTop, int dirtyRight, int dirtyBottom);
     ANDROID_API void destroyCanvas();
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/preloaded-classes b/preloaded-classes
index 4d79e4b..35c52ad 100644
--- a/preloaded-classes
+++ b/preloaded-classes
@@ -400,7 +400,6 @@
 android.ddm.DdmHandleThread
 android.ddm.DdmHandleViewDebug
 android.ddm.DdmRegister
-android.debug.JNITest
 android.drm.DrmManagerClient
 android.emoji.EmojiFactory
 android.graphics.AvoidXfermode
@@ -661,7 +660,6 @@
 android.net.wifi.IWifiManager$Stub$Proxy
 android.net.wifi.WifiManager
 android.net.wifi.WifiManager$ServiceHandler
-android.net.wifi.WifiNative
 android.nfc.IAppCallback
 android.nfc.IAppCallback$Stub
 android.nfc.INfcAdapter
@@ -984,10 +982,7 @@
 android.view.FocusFinder$SequentialFocusComparator
 android.view.GLES20Canvas
 android.view.GLES20Canvas$CanvasFinalizer
-android.view.GLES20Layer
-android.view.GLES20Layer$Finalizer
 android.view.GLES20RecordingCanvas
-android.view.GLES20RenderLayer
 android.view.GestureDetector
 android.view.GestureDetector$GestureHandler
 android.view.GestureDetector$OnDoubleTapListener
@@ -997,12 +992,6 @@
 android.view.HardwareCanvas
 android.view.HardwareLayer
 android.view.HardwareRenderer
-android.view.HardwareRenderer$Gl20Renderer
-android.view.HardwareRenderer$Gl20Renderer$1
-android.view.HardwareRenderer$Gl20Renderer$2
-android.view.HardwareRenderer$Gl20Renderer$Gl20RendererEglContext
-android.view.HardwareRenderer$GlRenderer
-android.view.HardwareRenderer$GlRenderer$FunctorsRunnable
 android.view.HardwareRenderer$HardwareDrawCallbacks
 android.view.IRotationWatcher
 android.view.IRotationWatcher$Stub
@@ -1113,7 +1102,6 @@
 android.view.ViewParent
 android.view.ViewRootImpl
 android.view.ViewRootImpl$3
-android.view.ViewRootImpl$4
 android.view.ViewRootImpl$AccessibilityInteractionConnectionManager
 android.view.ViewRootImpl$AsyncInputStage
 android.view.ViewRootImpl$ConsumeBatchedInputRunnable
@@ -1452,14 +1440,6 @@
 com.android.internal.view.RootViewSurfaceTaker
 com.android.internal.view.menu.ActionMenuItem
 com.android.internal.view.menu.ActionMenuItemView
-com.android.internal.view.menu.ActionMenuPresenter
-com.android.internal.view.menu.ActionMenuPresenter$OverflowMenuButton
-com.android.internal.view.menu.ActionMenuPresenter$PopupPresenterCallback
-com.android.internal.view.menu.ActionMenuPresenter$SavedState
-com.android.internal.view.menu.ActionMenuPresenter$SavedState$1
-com.android.internal.view.menu.ActionMenuView
-com.android.internal.view.menu.ActionMenuView$ActionMenuChildView
-com.android.internal.view.menu.ActionMenuView$LayoutParams
 com.android.internal.view.menu.BaseMenuPresenter
 com.android.internal.view.menu.ListMenuItemView
 com.android.internal.view.menu.MenuBuilder
@@ -1700,7 +1680,6 @@
 com.android.org.conscrypt.OpenSSLX509CertificateFactory$Parser
 com.android.org.conscrypt.ProtocolVersion
 com.android.org.conscrypt.SSLClientSessionCache
-com.android.org.conscrypt.SSLContextImpl
 com.android.org.conscrypt.SSLParametersImpl
 com.android.org.conscrypt.ServerSessionContext
 com.android.org.conscrypt.TrustManagerFactoryImpl
@@ -1887,7 +1866,6 @@
 java.lang.ThreadLocal$Values
 java.lang.Throwable
 java.lang.TypeNotPresentException
-java.lang.UnsafeByteSequence
 java.lang.UnsatisfiedLinkError
 java.lang.UnsupportedOperationException
 java.lang.VMClassLoader
@@ -2196,8 +2174,6 @@
 java.util.concurrent.Callable
 java.util.concurrent.CancellationException
 java.util.concurrent.ConcurrentHashMap
-java.util.concurrent.ConcurrentHashMap$HashEntry
-java.util.concurrent.ConcurrentHashMap$HashIterator
 java.util.concurrent.ConcurrentHashMap$Segment
 java.util.concurrent.ConcurrentLinkedQueue
 java.util.concurrent.ConcurrentLinkedQueue$Node
@@ -2257,7 +2233,6 @@
 java.util.jar.Attributes$Name
 java.util.jar.JarEntry
 java.util.jar.JarFile
-java.util.jar.JarFile$1JarFileEnumerator
 java.util.jar.JarVerifier
 java.util.jar.Manifest
 java.util.logging.ConsoleHandler
@@ -2382,7 +2357,6 @@
 libcore.io.StructUtsname
 libcore.math.MathUtils
 libcore.net.MimeUtils
-libcore.net.RawSocket
 libcore.net.UriCodec
 libcore.net.http.HttpDate
 libcore.net.http.HttpDate$1
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/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java
index 473aa34..3dcb488 100644
--- a/services/core/java/com/android/server/LocationManagerService.java
+++ b/services/core/java/com/android/server/LocationManagerService.java
@@ -2229,7 +2229,7 @@
         synchronized (mLock) {
 
             // These methods can't be called after removing the test provider, so first make sure
-            // we don't leave anything dangling (cf b/11446702).
+            // we don't leave anything dangling.
             clearTestProviderEnabled(provider);
             clearTestProviderLocation(provider);
             clearTestProviderStatus(provider);
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index f8d7821..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) {
@@ -16119,8 +16129,10 @@
                     return false;
                 }
 
-                mWindowManager.startFreezingScreen(R.anim.screen_user_exit,
-                        R.anim.screen_user_enter);
+                if (foreground) {
+                    mWindowManager.startFreezingScreen(R.anim.screen_user_exit,
+                            R.anim.screen_user_enter);
+                }
 
                 boolean needStart = false;
 
@@ -16139,16 +16151,15 @@
                 if (foreground) {
                     mCurrentUserId = userId;
                     mWindowManager.setCurrentUser(userId);
+                    // Once the internal notion of the active user has switched, we lock the device
+                    // with the option to show the user switcher on the keyguard.
+                    mWindowManager.lockNow(null);
                 } else {
                     final Integer currentUserIdInt = Integer.valueOf(mCurrentUserId);
                     mUserLru.remove(currentUserIdInt);
                     mUserLru.add(currentUserIdInt);
                 }
 
-                // Once the internal notion of the active user has switched, we lock the device
-                // with the option to show the user switcher on the keyguard.
-                mWindowManager.lockNow(null);
-
                 final UserStartedState uss = mStartedUsers.get(userId);
 
                 // Make sure user is in the started state.  If it is currently
@@ -16364,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
@@ -16378,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()) {
@@ -16429,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 e37bb9c..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",
@@ -985,8 +987,8 @@
 
         @Override
         public boolean allowDisable(int what, IBinder token, String pkg) {
-            if (mZenMode == Settings.Global.ZEN_MODE_FULL && isCall(pkg, null)) {
-                return false;
+            if (isCall(pkg, null)) {
+                return mZenMode == Settings.Global.ZEN_MODE_OFF;
             }
             return true;
         }
@@ -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();
@@ -2505,40 +2509,72 @@
                 Settings.Global.MODE_RINGER, -1);
         final boolean nonSilentRingerMode = ringerMode == AudioManager.RINGER_MODE_NORMAL
                 || ringerMode == AudioManager.RINGER_MODE_VIBRATE;
-        if (mZenMode == Settings.Global.ZEN_MODE_FULL && nonSilentRingerMode) {
+        if (mZenMode != Settings.Global.ZEN_MODE_OFF && nonSilentRingerMode) {
             Settings.Global.putInt(getContext().getContentResolver(),
                     Settings.Global.ZEN_MODE, Settings.Global.ZEN_MODE_OFF);
         }
     }
 
     private void updateZenMode() {
-        mZenMode = Settings.Global.getInt(getContext().getContentResolver(),
+        final int mode = Settings.Global.getInt(getContext().getContentResolver(),
                 Settings.Global.ZEN_MODE, Settings.Global.ZEN_MODE_OFF);
-        if (DBG) Slog.d(TAG, "updateZenMode " + Settings.Global.zenModeToString(mZenMode));
+        if (mode != mZenMode) {
+            Slog.d(TAG, String.format("updateZenMode: %s -> %s",
+                    Settings.Global.zenModeToString(mZenMode),
+                    Settings.Global.zenModeToString(mode)));
+        }
+        mZenMode = mode;
         if (mAudioManager != null) {
-            if (mZenMode == Settings.Global.ZEN_MODE_FULL) {
+            // call audio
+            final boolean muteCalls = mZenMode != Settings.Global.ZEN_MODE_OFF;
+            if (muteCalls) {
+                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
-                mPreZenRingerMode = mAudioManager.getRingerMode();
-                if (DBG) Slog.d(TAG, "Muting calls mPreZenRingerMode=" + mPreZenRingerMode);
-                mAudioManager.setStreamMute(AudioManager.STREAM_RING, true);
-                mAudioManager.setRingerMode(AudioManager.RINGER_MODE_SILENT);
-                // alarms don't simply respect mute, so set the volume as well
-                mPreZenAlarmVolume = mAudioManager.getStreamVolume(AudioManager.STREAM_ALARM);
-                if (DBG) Slog.d(TAG, "Muting alarms mPreZenAlarmVolume=" + mPreZenAlarmVolume);
-                mAudioManager.setStreamMute(AudioManager.STREAM_ALARM, true);
-                mAudioManager.setStreamVolume(AudioManager.STREAM_ALARM, 0, 0);
+                final int ringerMode = mAudioManager.getRingerMode();
+                if (ringerMode != AudioManager.RINGER_MODE_SILENT) {
+                    if (DBG) Slog.d(TAG, "Saving ringer mode of " + ringerMode);
+                    mPreZenRingerMode = ringerMode;
+                    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);
                     mPreZenRingerMode = -1;
                 }
-                if (DBG) Slog.d(TAG, "Unmuting alarms");
-                mAudioManager.setStreamMute(AudioManager.STREAM_ALARM, false);
+            }
+            // alarm audio
+            final boolean muteAlarms = mZenMode == Settings.Global.ZEN_MODE_FULL;
+            if (muteAlarms) {
+                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) {
+                    if (DBG) Slog.d(TAG, "Saving STREAM_ALARM volume of " + volume);
+                    mPreZenAlarmVolume = volume;
+                    mAudioManager.setStreamVolume(AudioManager.STREAM_ALARM, 0, 0);
+                }
+            } else {
+                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 to " + mPreZenAlarmVolume);
+                    if (DBG) Slog.d(TAG, "Restoring STREAM_ALARM volume to " + mPreZenAlarmVolume);
                     mAudioManager.setStreamVolume(AudioManager.STREAM_ALARM, mPreZenAlarmVolume, 0);
                     mPreZenAlarmVolume = -1;
                 }
@@ -2556,7 +2592,7 @@
 
     private boolean shouldIntercept(String pkg, Notification n) {
         if (mZenMode == Settings.Global.ZEN_MODE_LIMITED) {
-            return !isCall(pkg, n) && !isAlarm(pkg, n);
+            return !isAlarm(pkg, n);
         } else if (mZenMode == Settings.Global.ZEN_MODE_FULL) {
             return true;
         }
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index d28d76d..ec4d574 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -1841,4 +1841,41 @@
         }
         return false;
     }
+
+    /**
+     * Get the preferred network type.
+     * Used for device configuration by some CDMA operators.
+     *
+     * @return the preferred network type, defined in RILConstants.java.
+     * @hide
+     */
+    public int getPreferredNetworkType() {
+        try {
+            return getITelephony().getPreferredNetworkType();
+        } catch (RemoteException ex) {
+            Rlog.e(TAG, "getPreferredNetworkType RemoteException", ex);
+        } catch (NullPointerException ex) {
+            Rlog.e(TAG, "getPreferredNetworkType NPE", ex);
+        }
+        return -1;
+    }
+
+    /**
+     * Set the preferred network type.
+     * Used for device configuration by some CDMA operators.
+     *
+     * @param networkType the preferred network type, defined in RILConstants.java.
+     * @return true on success; false on any failure.
+     * @hide
+     */
+    public boolean setPreferredNetworkType(int networkType) {
+        try {
+            return getITelephony().setPreferredNetworkType(networkType);
+        } catch (RemoteException ex) {
+            Rlog.e(TAG, "setPreferredNetworkType RemoteException", ex);
+        } catch (NullPointerException ex) {
+            Rlog.e(TAG, "setPreferredNetworkType NPE", ex);
+        }
+        return false;
+    }
 }
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index 554a9cb..7c338ac 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -403,4 +403,21 @@
      * @return true on success; false on any failure.
      */
     boolean nvResetConfig(int resetType);
+
+    /**
+     * Get the preferred network type.
+     * Used for device configuration by some CDMA operators.
+     *
+     * @return the preferred network type, defined in RILConstants.java.
+     */
+    int getPreferredNetworkType();
+
+    /**
+     * Set the preferred network type.
+     * Used for device configuration by some CDMA operators.
+     *
+     * @param networkType the preferred network type, defined in RILConstants.java.
+     * @return true on success; false on any failure.
+     */
+    boolean setPreferredNetworkType(int networkType);
 }
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;