Merge "Hide three malformed GL bindings"
diff --git a/Android.mk b/Android.mk
index 8986af5..a57b3fa 100644
--- a/Android.mk
+++ b/Android.mk
@@ -275,9 +275,6 @@
 	telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl \
 	telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl \
 	telephony/java/com/android/internal/telephony/ITelephony.aidl \
-	telephony/java/com/android/internal/telephony/IThirdPartyCallListener.aidl \
-	telephony/java/com/android/internal/telephony/IThirdPartyCallProvider.aidl \
-	telephony/java/com/android/internal/telephony/IThirdPartyCallService.aidl \
 	telephony/java/com/android/internal/telephony/ISms.aidl \
 	telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl \
 	telephony/java/com/android/internal/telephony/IWapPushManager.aidl \
diff --git a/api/current.txt b/api/current.txt
index 1382e3d..956d52a 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -345,6 +345,7 @@
     field public static final int canRetrieveWindowContent = 16843653; // 0x1010385
     field public static final int candidatesTextStyleSpans = 16843312; // 0x1010230
     field public static final deprecated int capitalize = 16843113; // 0x1010169
+    field public static final int castsShadow = 16843778; // 0x1010402
     field public static final int category = 16843752; // 0x10103e8
     field public static final int centerBright = 16842956; // 0x10100cc
     field public static final int centerColor = 16843275; // 0x101020b
@@ -7614,6 +7615,7 @@
     field public static final java.lang.String EXTRA_VERIFICATION_RESULT = "android.content.pm.extra.VERIFICATION_RESULT";
     field public static final java.lang.String FEATURE_APP_WIDGETS = "android.software.app_widgets";
     field public static final java.lang.String FEATURE_AUDIO_LOW_LATENCY = "android.hardware.audio.low_latency";
+    field public static final java.lang.String FEATURE_BACKUP = "android.software.backup";
     field public static final java.lang.String FEATURE_BLUETOOTH = "android.hardware.bluetooth";
     field public static final java.lang.String FEATURE_BLUETOOTH_LE = "android.hardware.bluetooth_le";
     field public static final java.lang.String FEATURE_CAMERA = "android.hardware.camera";
@@ -7635,6 +7637,7 @@
     field public static final java.lang.String FEATURE_MICROPHONE = "android.hardware.microphone";
     field public static final java.lang.String FEATURE_NFC = "android.hardware.nfc";
     field public static final java.lang.String FEATURE_NFC_HOST_CARD_EMULATION = "android.hardware.nfc.hce";
+    field public static final java.lang.String FEATURE_PRINTING = "android.software.print";
     field public static final java.lang.String FEATURE_SCREEN_LANDSCAPE = "android.hardware.screen.landscape";
     field public static final java.lang.String FEATURE_SCREEN_PORTRAIT = "android.hardware.screen.portrait";
     field public static final java.lang.String FEATURE_SENSOR_ACCELEROMETER = "android.hardware.sensor.accelerometer";
@@ -24565,32 +24568,6 @@
     field public static final int SIM_STATE_UNKNOWN = 0; // 0x0
   }
 
-  public class ThirdPartyCallListener {
-    ctor public ThirdPartyCallListener(com.android.internal.telephony.IThirdPartyCallListener);
-    method public void onCallEnded(int);
-    method public void onCallEstablished();
-    method public void onCallProviderAttached(android.telephony.ThirdPartyCallProvider);
-    method public void onRingingStarted();
-    field public static final int CALL_END_INCOMING_MISSED = 2; // 0x2
-    field public static final int CALL_END_NORMAL = 1; // 0x1
-    field public static final int CALL_END_OTHER = 3; // 0x3
-  }
-
-  public class ThirdPartyCallProvider {
-    ctor public ThirdPartyCallProvider();
-    method public void hangup();
-    method public void incomingCallAccept();
-    method public void mute(boolean);
-    method public void sendDtmf(char);
-  }
-
-  public class ThirdPartyCallService {
-    ctor public ThirdPartyCallService();
-    method public android.os.IBinder getBinder();
-    method public void incomingCallAttach(android.telephony.ThirdPartyCallListener, java.lang.String);
-    method public void outgoingCallInitiate(android.telephony.ThirdPartyCallListener, java.lang.String);
-  }
-
 }
 
 package android.telephony.cdma {
@@ -28711,7 +28688,9 @@
     method protected float getBottomFadingEdgeStrength();
     method protected int getBottomPaddingOffset();
     method public float getCameraDistance();
+    method public final boolean getCastsShadow();
     method public android.graphics.Rect getClipBounds();
+    method public final boolean getClipToOutline();
     method public java.lang.CharSequence getContentDescription();
     method public final android.content.Context getContext();
     method protected android.view.ContextMenu.ContextMenuInfo getContextMenuInfo();
@@ -28763,6 +28742,7 @@
     method public int getNextFocusRightId();
     method public int getNextFocusUpId();
     method public android.view.View.OnFocusChangeListener getOnFocusChangeListener();
+    method public final void getOutline(android.graphics.Path);
     method public int getOverScrollMode();
     method public android.view.ViewOverlay getOverlay();
     method public int getPaddingBottom();
@@ -28978,8 +28958,10 @@
     method public void setBackgroundResource(int);
     method public final void setBottom(int);
     method public void setCameraDistance(float);
+    method public void setCastsShadow(boolean);
     method public void setClickable(boolean);
     method public void setClipBounds(android.graphics.Rect);
+    method public void setClipToOutline(boolean);
     method public void setContentDescription(java.lang.CharSequence);
     method public void setDrawingCacheBackgroundColor(int);
     method public void setDrawingCacheEnabled(boolean);
@@ -29025,6 +29007,7 @@
     method public void setOnLongClickListener(android.view.View.OnLongClickListener);
     method public void setOnSystemUiVisibilityChangeListener(android.view.View.OnSystemUiVisibilityChangeListener);
     method public void setOnTouchListener(android.view.View.OnTouchListener);
+    method public void setOutline(android.graphics.Path);
     method public void setOverScrollMode(int);
     method public void setPadding(int, int, int, int);
     method public void setPaddingRelative(int, int, int, int);
@@ -34074,24 +34057,6 @@
 
 }
 
-package com.android.internal.telephony {
-
-  public abstract interface IThirdPartyCallListener implements android.os.IInterface {
-    method public abstract void onCallEnded(int) throws android.os.RemoteException;
-    method public abstract void onCallEstablished() throws android.os.RemoteException;
-    method public abstract void onCallProviderAttached(com.android.internal.telephony.IThirdPartyCallProvider) throws android.os.RemoteException;
-    method public abstract void onRingingStarted() throws android.os.RemoteException;
-  }
-
-  public abstract interface IThirdPartyCallProvider implements android.os.IInterface {
-    method public abstract void hangup() throws android.os.RemoteException;
-    method public abstract void incomingCallAccept() throws android.os.RemoteException;
-    method public abstract void mute(boolean) throws android.os.RemoteException;
-    method public abstract void sendDtmf(char) throws android.os.RemoteException;
-  }
-
-}
-
 package com.android.internal.util {
 
   public abstract interface Predicate {
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 30c1e62..3258585 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -3949,6 +3949,7 @@
         ArrayList<ComponentCallbacks2> callbacks = collectComponentCallbacks(false, config);
 
         // Cleanup hardware accelerated stuff
+        // TODO: Do we actually want to do this in response to all config changes?
         WindowManagerGlobal.getInstance().trimLocalMemory();
 
         freeTextLayoutCachesIfNeeded(configDiff);
diff --git a/core/java/android/app/FragmentManager.java b/core/java/android/app/FragmentManager.java
index ee8d457..bf2a629 100644
--- a/core/java/android/app/FragmentManager.java
+++ b/core/java/android/app/FragmentManager.java
@@ -972,7 +972,7 @@
                                         if (fragment.mAnimatingAway != null) {
                                             fragment.mAnimatingAway = null;
                                             moveToState(fragment, fragment.mStateAfterAnimating,
-                                                    0, 0, true);
+                                                    0, 0, false);
                                         }
                                     }
                                 });
diff --git a/core/java/android/app/PendingIntent.java b/core/java/android/app/PendingIntent.java
index d3b0763..d4de112 100644
--- a/core/java/android/app/PendingIntent.java
+++ b/core/java/android/app/PendingIntent.java
@@ -231,7 +231,7 @@
      * <p class="note">For security reasons, the {@link android.content.Intent}
      * you supply here should almost always be an <em>explicit intent</em>,
      * that is specify an explicit component to be delivered to through
-     * {@link Intent#setClass(android.content.Context, Class)} Intent.setClass</p>
+     * {@link Intent#setClass(android.content.Context, Class) Intent.setClass}</p>
      *
      * @param context The Context in which this PendingIntent should start
      * the activity.
@@ -262,7 +262,7 @@
      * <p class="note">For security reasons, the {@link android.content.Intent}
      * you supply here should almost always be an <em>explicit intent</em>,
      * that is specify an explicit component to be delivered to through
-     * {@link Intent#setClass(android.content.Context, Class)} Intent.setClass</p>
+     * {@link Intent#setClass(android.content.Context, Class) Intent.setClass}</p>
      *
      * @param context The Context in which this PendingIntent should start
      * the activity.
@@ -354,7 +354,7 @@
      * <p class="note">For security reasons, the {@link android.content.Intent} objects
      * you supply here should almost always be <em>explicit intents</em>,
      * that is specify an explicit component to be delivered to through
-     * {@link Intent#setClass(android.content.Context, Class)} Intent.setClass</p>
+     * {@link Intent#setClass(android.content.Context, Class) Intent.setClass}</p>
      *
      * @param context The Context in which this PendingIntent should start
      * the activity.
@@ -404,7 +404,7 @@
      * <p class="note">For security reasons, the {@link android.content.Intent} objects
      * you supply here should almost always be <em>explicit intents</em>,
      * that is specify an explicit component to be delivered to through
-     * {@link Intent#setClass(android.content.Context, Class)} Intent.setClass</p>
+     * {@link Intent#setClass(android.content.Context, Class) Intent.setClass}</p>
      *
      * @param context The Context in which this PendingIntent should start
      * the activity.
@@ -474,7 +474,7 @@
      * <p class="note">For security reasons, the {@link android.content.Intent}
      * you supply here should almost always be an <em>explicit intent</em>,
      * that is specify an explicit component to be delivered to through
-     * {@link Intent#setClass(android.content.Context, Class)} Intent.setClass</p>
+     * {@link Intent#setClass(android.content.Context, Class) Intent.setClass}</p>
      *
      * @param context The Context in which this PendingIntent should perform
      * the broadcast.
@@ -528,7 +528,7 @@
      * <p class="note">For security reasons, the {@link android.content.Intent}
      * you supply here should almost always be an <em>explicit intent</em>,
      * that is specify an explicit component to be delivered to through
-     * {@link Intent#setClass(android.content.Context, Class)} Intent.setClass</p>
+     * {@link Intent#setClass(android.content.Context, Class) Intent.setClass}</p>
      *
      * @param context The Context in which this PendingIntent should start
      * the service.
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 40bdb73..0cc878e 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -1690,16 +1690,16 @@
      * user. Also, this method must be called before the user has been used for the first time.
      * @param packageName the package name of the application to be registered as profile owner.
      * @param ownerName the human readable name of the organisation associated with this DPM.
+     * @param userHandle the userId to set the profile owner for.
      * @return whether the package was successfully registered as the profile owner.
      * @throws IllegalArgumentException if packageName is null, the package isn't installed, or
      *         the user has already been set up.
      */
-    public boolean setProfileOwner(String packageName, String ownerName)
+    public boolean setProfileOwner(String packageName, String ownerName, int userHandle)
             throws IllegalArgumentException {
         if (mService != null) {
             try {
-                return mService.setProfileOwner(packageName, ownerName,
-                        Process.myUserHandle().getIdentifier());
+                return mService.setProfileOwner(packageName, ownerName, userHandle);
             } catch (RemoteException re) {
                 Log.w(TAG, "Failed to set profile owner", re);
                 throw new IllegalArgumentException("Couldn't set profile owner.", re);
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 0192a30..40d9606 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -1257,6 +1257,20 @@
     public static final String FEATURE_TELEVISION = "android.hardware.type.television";
 
     /**
+     * Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}:
+     * The device supports printing.
+     */
+    @SdkConstant(SdkConstantType.FEATURE)
+    public static final String FEATURE_PRINTING = "android.software.print";
+
+    /**
+     * Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}:
+     * The device can perform backup and restore operations on installed applications.
+     */
+    @SdkConstant(SdkConstantType.FEATURE)
+    public static final String FEATURE_BACKUP = "android.software.backup";
+
+    /**
      * Action to external storage service to clean out removed apps.
      * @hide
      */
diff --git a/core/java/android/hardware/camera2/CaptureRequest.java b/core/java/android/hardware/camera2/CaptureRequest.java
index 408e532..dfde11b 100644
--- a/core/java/android/hardware/camera2/CaptureRequest.java
+++ b/core/java/android/hardware/camera2/CaptureRequest.java
@@ -1329,7 +1329,7 @@
      * <p>Each channel's curve is defined by an array of control points:</p>
      * <pre><code>{@link CaptureRequest#TONEMAP_CURVE_RED android.tonemap.curveRed} =
      * [ P0in, P0out, P1in, P1out, P2in, P2out, P3in, P3out, ..., PNin, PNout ]
-     * 2 &amp;lt;= N &amp;lt;= {@link CameraCharacteristics#TONEMAP_MAX_CURVE_POINTS android.tonemap.maxCurvePoints}</code></pre>
+     * 2 &lt;= N &lt;= {@link CameraCharacteristics#TONEMAP_MAX_CURVE_POINTS android.tonemap.maxCurvePoints}</code></pre>
      * <p>These are sorted in order of increasing <code>Pin</code>; it is always
      * guaranteed that input values 0.0 and 1.0 are included in the list to
      * define a complete mapping. For input values between control points,
diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java
index 345b52c..32526bd 100644
--- a/core/java/android/hardware/camera2/CaptureResult.java
+++ b/core/java/android/hardware/camera2/CaptureResult.java
@@ -1788,7 +1788,7 @@
      * <p>Each channel's curve is defined by an array of control points:</p>
      * <pre><code>{@link CaptureRequest#TONEMAP_CURVE_RED android.tonemap.curveRed} =
      * [ P0in, P0out, P1in, P1out, P2in, P2out, P3in, P3out, ..., PNin, PNout ]
-     * 2 &amp;lt;= N &amp;lt;= {@link CameraCharacteristics#TONEMAP_MAX_CURVE_POINTS android.tonemap.maxCurvePoints}</code></pre>
+     * 2 &lt;= N &lt;= {@link CameraCharacteristics#TONEMAP_MAX_CURVE_POINTS android.tonemap.maxCurvePoints}</code></pre>
      * <p>These are sorted in order of increasing <code>Pin</code>; it is always
      * guaranteed that input values 0.0 and 1.0 are included in the list to
      * define a complete mapping. For input values between control points,
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index a9b6073..dfba208 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -171,6 +171,10 @@
     private static final String SIGNAL_STRENGTH_COUNT_DATA = "sgc";
     private static final String DATA_CONNECTION_TIME_DATA = "dct";
     private static final String DATA_CONNECTION_COUNT_DATA = "dcc";
+    private static final String WIFI_STATE_TIME_DATA = "wst";
+    private static final String WIFI_STATE_COUNT_DATA = "wsc";
+    private static final String BLUETOOTH_STATE_TIME_DATA = "bst";
+    private static final String BLUETOOTH_STATE_COUNT_DATA = "bsc";
     private static final String POWER_USE_SUMMARY_DATA = "pws";
     private static final String POWER_USE_ITEM_DATA = "pwi";
 
@@ -275,22 +279,22 @@
          */
         public abstract int getUid();
 
-        public abstract void noteWifiRunningLocked();
-        public abstract void noteWifiStoppedLocked();
-        public abstract void noteFullWifiLockAcquiredLocked();
-        public abstract void noteFullWifiLockReleasedLocked();
-        public abstract void noteWifiScanStartedLocked();
-        public abstract void noteWifiScanStoppedLocked();
-        public abstract void noteWifiBatchedScanStartedLocked(int csph);
-        public abstract void noteWifiBatchedScanStoppedLocked();
-        public abstract void noteWifiMulticastEnabledLocked();
-        public abstract void noteWifiMulticastDisabledLocked();
-        public abstract void noteAudioTurnedOnLocked();
-        public abstract void noteAudioTurnedOffLocked();
-        public abstract void noteVideoTurnedOnLocked();
-        public abstract void noteVideoTurnedOffLocked();
-        public abstract void noteActivityResumedLocked();
-        public abstract void noteActivityPausedLocked();
+        public abstract void noteWifiRunningLocked(long elapsedRealtime);
+        public abstract void noteWifiStoppedLocked(long elapsedRealtime);
+        public abstract void noteFullWifiLockAcquiredLocked(long elapsedRealtime);
+        public abstract void noteFullWifiLockReleasedLocked(long elapsedRealtime);
+        public abstract void noteWifiScanStartedLocked(long elapsedRealtime);
+        public abstract void noteWifiScanStoppedLocked(long elapsedRealtime);
+        public abstract void noteWifiBatchedScanStartedLocked(int csph, long elapsedRealtime);
+        public abstract void noteWifiBatchedScanStoppedLocked(long elapsedRealtime);
+        public abstract void noteWifiMulticastEnabledLocked(long elapsedRealtime);
+        public abstract void noteWifiMulticastDisabledLocked(long elapsedRealtime);
+        public abstract void noteAudioTurnedOnLocked(long elapsedRealtime);
+        public abstract void noteAudioTurnedOffLocked(long elapsedRealtime);
+        public abstract void noteVideoTurnedOnLocked(long elapsedRealtime);
+        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);
@@ -994,6 +998,37 @@
      */
     public abstract long getGlobalWifiRunningTime(long batteryRealtime, int which);
 
+    public static final int WIFI_STATE_OFF = 0;
+    public static final int WIFI_STATE_OFF_SCANNING = 1;
+    public static final int WIFI_STATE_ON_NO_NETWORKS = 2;
+    public static final int WIFI_STATE_ON_DISCONNECTED = 3;
+    public static final int WIFI_STATE_ON_CONNECTED_STA = 4;
+    public static final int WIFI_STATE_ON_CONNECTED_P2P = 5;
+    public static final int WIFI_STATE_ON_CONNECTED_STA_P2P = 6;
+    public static final int WIFI_STATE_SOFT_AP = 7;
+
+    static final String[] WIFI_STATE_NAMES = {
+        "off", "scanning", "no_net", "disconn",
+        "sta", "p2p", "sta_p2p", "soft_ap"
+    };
+
+    public static final int NUM_WIFI_STATES = WIFI_STATE_SOFT_AP+1;
+
+    /**
+     * Returns the time in microseconds that WiFi has been running in the given state.
+     *
+     * {@hide}
+     */
+    public abstract long getWifiStateTime(int wifiState,
+            long batteryRealtime, int which);
+
+    /**
+     * Returns the number of times that WiFi has entered the given state.
+     *
+     * {@hide}
+     */
+    public abstract int getWifiStateCount(int wifiState, int which);
+
     /**
      * Returns the time in microseconds that bluetooth has been on while the device was
      * running on battery.
@@ -1004,16 +1039,16 @@
     
     public abstract int getBluetoothPingCount();
 
-    public static final int BLUETOOTH_INACTIVE = 0;
-    public static final int BLUETOOTH_ACTIVE_LOW = 1;
-    public static final int BLUETOOTH_ACTIVE_MEDIUM = 2;
-    public static final int BLUETOOTH_ACTIVE_HIGH = 3;
+    public static final int BLUETOOTH_STATE_INACTIVE = 0;
+    public static final int BLUETOOTH_STATE_LOW = 1;
+    public static final int BLUETOOTH_STATE_MEDIUM = 2;
+    public static final int BLUETOOTH_STATE_HIGH = 3;
 
-    static final String[] BLUETOOTH_ACTIVE_NAMES = {
-        "none", "low", "med", "high"
+    static final String[] BLUETOOTH_STATE_NAMES = {
+        "inactive", "low", "med", "high"
     };
 
-    public static final int NUM_BLUETOOTH_ACTIVE_TYPES = BLUETOOTH_ACTIVE_HIGH+1;
+    public static final int NUM_BLUETOOTH_STATES = BLUETOOTH_STATE_HIGH +1;
 
     /**
      * Returns the time in microseconds that Bluetooth has been running in the
@@ -1021,15 +1056,15 @@
      *
      * {@hide}
      */
-    public abstract long getBluetoothActiveTime(int activeType,
+    public abstract long getBluetoothStateTime(int bluetoothState,
             long batteryRealtime, int which);
 
     /**
-     * Returns the number of times the Bluetooth has entered the given active state.
+     * Returns the number of times that Bluetooth has entered the given active state.
      *
      * {@hide}
      */
-    public abstract int getBluetoothActiveCount(int activeType, int which);
+    public abstract int getBluetoothStateCount(int bluetoothState, int which);
 
     public static final int NETWORK_MOBILE_RX_DATA = 0;
     public static final int NETWORK_MOBILE_TX_DATA = 1;
@@ -1431,7 +1466,29 @@
             args[i] = getPhoneDataConnectionCount(i, which);
         }
         dumpLine(pw, 0 /* uid */, category, DATA_CONNECTION_COUNT_DATA, args);
-        
+
+        // 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;
+        }
+        dumpLine(pw, 0 /* uid */, category, WIFI_STATE_TIME_DATA, args);
+        for (int i=0; i<NUM_WIFI_STATES; i++) {
+            args[i] = getWifiStateCount(i, which);
+        }
+        dumpLine(pw, 0 /* uid */, category, WIFI_STATE_COUNT_DATA, args);
+
+        // 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;
+        }
+        dumpLine(pw, 0 /* uid */, category, BLUETOOTH_STATE_TIME_DATA, args);
+        for (int i=0; i<NUM_BLUETOOTH_STATES; i++) {
+            args[i] = getBluetoothStateCount(i, which);
+        }
+        dumpLine(pw, 0 /* uid */, category, BLUETOOTH_STATE_COUNT_DATA, args);
+
         if (which == STATS_SINCE_UNPLUGGED) {
             dumpLine(pw, 0 /* uid */, category, BATTERY_LEVEL_DATA, getDischargeStartLevel(),
                     getDischargeCurrentLevel());
@@ -1941,12 +1998,63 @@
                 sb.append("("); sb.append(formatRatioLocked(wifiOnTime, whichBatteryRealtime));
                 sb.append("), Wifi running: "); formatTimeMs(sb, wifiRunningTime / 1000);
                 sb.append("("); sb.append(formatRatioLocked(wifiRunningTime, whichBatteryRealtime));
-                sb.append("), Bluetooth on: "); formatTimeMs(sb, bluetoothOnTime / 1000);
+                sb.append(")");
+        pw.println(sb.toString());
+
+        sb.setLength(0);
+        sb.append(prefix);
+        sb.append("  Wifi states:");
+        didOne = false;
+        for (int i=0; i<NUM_WIFI_STATES; i++) {
+            final long time = getWifiStateTime(i, batteryRealtime, which);
+            if (time == 0) {
+                continue;
+            }
+            sb.append("\n    ");
+            didOne = true;
+            sb.append(WIFI_STATE_NAMES[i]);
+            sb.append(" ");
+            formatTimeMs(sb, time/1000);
+            sb.append("(");
+            sb.append(formatRatioLocked(time, whichBatteryRealtime));
+            sb.append(") ");
+            sb.append(getPhoneDataConnectionCount(i, which));
+            sb.append("x");
+        }
+        if (!didOne) sb.append(" (no activity)");
+        pw.println(sb.toString());
+
+        sb.setLength(0);
+        sb.append(prefix);
+                sb.append("  Bluetooth on: "); formatTimeMs(sb, bluetoothOnTime / 1000);
                 sb.append("("); sb.append(formatRatioLocked(bluetoothOnTime, whichBatteryRealtime));
                 sb.append(")");
         pw.println(sb.toString());
-        
-        pw.println(" ");
+
+        sb.setLength(0);
+        sb.append(prefix);
+        sb.append("  Bluetooth states:");
+        didOne = false;
+        for (int i=0; i<NUM_BLUETOOTH_STATES; i++) {
+            final long time = getBluetoothStateTime(i, batteryRealtime, which);
+            if (time == 0) {
+                continue;
+            }
+            sb.append("\n    ");
+            didOne = true;
+            sb.append(BLUETOOTH_STATE_NAMES[i]);
+            sb.append(" ");
+            formatTimeMs(sb, time/1000);
+            sb.append("(");
+            sb.append(formatRatioLocked(time, whichBatteryRealtime));
+            sb.append(") ");
+            sb.append(getPhoneDataConnectionCount(i, which));
+            sb.append("x");
+        }
+        if (!didOne) sb.append(" (no activity)");
+        pw.println(sb.toString());
+
+        pw.println();
 
         if (which == STATS_SINCE_UNPLUGGED) {
             if (getIsOnBattery()) {
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 9332578..76ada09 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -3468,12 +3468,12 @@
             "lock_screen_owner_info_enabled";
 
         /**
-         * This preference enables expanding the notification panel even over a securely
-         * locked screen, showing only "public" notifications in this case.
+         * When set by a user, allows notifications to be shown atop a securely locked screen
+         * in their full "private" form (same as when the device is unlocked).
          * @hide
          */
-        public static final String LOCK_SCREEN_ALLOW_NOTIFICATIONS =
-                "lock_screen_allow_notifications";
+        public static final String LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS =
+                "lock_screen_allow_private_notifications";
 
         /**
          * The Logging ID (a unique 64-bit value) as a hex string.
@@ -6066,6 +6066,15 @@
          */
         public static final String POLICY_CONTROL = "policy_control";
 
+
+        /**
+         * This preference enables notification display even over a securely
+         * locked screen.
+         * @hide
+         */
+        public static final String LOCK_SCREEN_SHOW_NOTIFICATIONS =
+                "lock_screen_show_notifications";
+
         /**
          * Settings to backup. This is here so that it's in the same place as the settings
          * keys and easy to update.
diff --git a/core/java/android/text/SpannableStringBuilder.java b/core/java/android/text/SpannableStringBuilder.java
index 34274a6..b55cd6a 100644
--- a/core/java/android/text/SpannableStringBuilder.java
+++ b/core/java/android/text/SpannableStringBuilder.java
@@ -29,6 +29,7 @@
  */
 public class SpannableStringBuilder implements CharSequence, GetChars, Spannable, Editable,
         Appendable, GraphicsOperations {
+    private final static String TAG = "SpannableStringBuilder";
     /**
      * Create a new SpannableStringBuilder with empty contents
      */
@@ -436,10 +437,26 @@
     }
 
     // Documentation from interface
-    public SpannableStringBuilder replace(final int start, final int end,
+    public SpannableStringBuilder replace(int start, int end,
             CharSequence tb, int tbstart, int tbend) {
         checkRange("replace", start, end);
 
+        // Sanity check
+        if (start > end) {
+            Log.w(TAG, "Bad arguments to #replace : "
+                    + "start = " + start + ", end = " + end);
+            final int tmp = start;
+            start = end;
+            end = tmp;
+        }
+        if (tbstart > tbend) {
+            Log.w(TAG, "Bad arguments to #replace : "
+                    + "tbstart = " + tbstart + ", tbend = " + tbend);
+            final int tmp = tbstart;
+            tbstart = tbend;
+            tbend = tmp;
+        }
+
         int filtercount = mFilters.length;
         for (int i = 0; i < filtercount; i++) {
             CharSequence repl = mFilters[i].filter(tb, tbstart, tbend, this, start, end);
@@ -613,8 +630,9 @@
 
         // 0-length Spanned.SPAN_EXCLUSIVE_EXCLUSIVE
         if (flagsStart == POINT && flagsEnd == MARK && start == end) {
-            if (send) Log.e("SpannableStringBuilder",
-                    "SPAN_EXCLUSIVE_EXCLUSIVE spans cannot have a zero length");
+            if (send) {
+                Log.e(TAG, "SPAN_EXCLUSIVE_EXCLUSIVE spans cannot have a zero length");
+            }
             // Silently ignore invalid spans when they are created from this class.
             // This avoids the duplication of the above test code before all the
             // calls to setSpan that are done in this class
diff --git a/core/java/android/util/JsonReader.java b/core/java/android/util/JsonReader.java
index f2a86c9..7d1c6c4 100644
--- a/core/java/android/util/JsonReader.java
+++ b/core/java/android/util/JsonReader.java
@@ -546,6 +546,9 @@
     public void skipValue() throws IOException {
         skipping = true;
         try {
+            if (!hasNext() || peek() == JsonToken.END_DOCUMENT) {
+                throw new IllegalStateException("No element left to skip");
+            }
             int count = 0;
             do {
                 JsonToken token = advance();
diff --git a/core/java/android/view/DisplayList.java b/core/java/android/view/DisplayList.java
index 9aecbea..dfc74ea 100644
--- a/core/java/android/view/DisplayList.java
+++ b/core/java/android/view/DisplayList.java
@@ -484,9 +484,9 @@
      *
      * If set to true, camera distance will be ignored. Defaults to false.
      */
-    public void setSharesGlobalCamera(boolean sharesGlobalCamera) {
+    public void setUsesGlobalCamera(boolean usesGlobalCamera) {
         if (hasNativeDisplayList()) {
-            nSetSharesGlobalCamera(mFinalizer.mNativeDisplayList, sharesGlobalCamera);
+            nSetUsesGlobalCamera(mFinalizer.mNativeDisplayList, usesGlobalCamera);
         }
     }
 
@@ -1116,7 +1116,7 @@
     private static native void nSetOutline(long displayList, long nativePath);
     private static native void nSetClipToOutline(long displayList, boolean clipToOutline);
     private static native void nSetCastsShadow(long displayList, boolean castsShadow);
-    private static native void nSetSharesGlobalCamera(long displayList, boolean sharesGlobalCamera);
+    private static native void nSetUsesGlobalCamera(long displayList, boolean usesGlobalCamera);
     private static native void nSetAlpha(long displayList, float alpha);
     private static native void nSetHasOverlappingRendering(long displayList,
             boolean hasOverlappingRendering);
diff --git a/core/java/android/view/GLRenderer.java b/core/java/android/view/GLRenderer.java
index c1eb6b7..859468a 100644
--- a/core/java/android/view/GLRenderer.java
+++ b/core/java/android/view/GLRenderer.java
@@ -477,17 +477,21 @@
 
     @Override
     void flushLayerUpdates() {
-        mGlCanvas.flushLayerUpdates();
+        if (validate()) {
+            mGlCanvas.flushLayerUpdates();
+        }
     }
 
     @Override
     HardwareLayer createTextureLayer() {
+        validate();
         return HardwareLayer.createTextureLayer(this);
     }
 
     @Override
     public HardwareLayer createDisplayListLayer(int width, int height) {
-        return HardwareLayer.createRenderLayer(this, width, height);
+        validate();
+        return HardwareLayer.createDisplayListLayer(this, width, height);
     }
 
     @Override
@@ -510,6 +514,9 @@
 
     @Override
     boolean copyLayerInto(HardwareLayer layer, Bitmap bitmap) {
+        if (!validate()) {
+            throw new IllegalStateException("Could not acquire hardware rendering context");
+        }
         layer.flushChanges();
         return GLES20Canvas.nCopyLayer(layer.getLayer(), bitmap.mNativeBitmap);
     }
@@ -538,35 +545,6 @@
     }
 
     @Override
-    void destroyLayers(final View view) {
-        if (view != null) {
-            safelyRun(new Runnable() {
-                @Override
-                public void run() {
-                    if (mCanvas != null) {
-                        mCanvas.clearLayerUpdates();
-                    }
-                    destroyHardwareLayer(view);
-                    GLES20Canvas.flushCaches(GLES20Canvas.FLUSH_CACHES_LAYERS);
-                }
-            });
-        }
-    }
-
-    private static void destroyHardwareLayer(View view) {
-        view.destroyLayer(true);
-
-        if (view instanceof ViewGroup) {
-            ViewGroup group = (ViewGroup) view;
-
-            int count = group.getChildCount();
-            for (int i = 0; i < count; i++) {
-                destroyHardwareLayer(group.getChildAt(i));
-            }
-        }
-    }
-
-    @Override
     void destroyHardwareResources(final View view) {
         if (view != null) {
             safelyRun(new Runnable() {
@@ -1069,7 +1047,6 @@
         return true;
     }
 
-    @Override
     boolean validate() {
         return checkRenderContext() != SURFACE_STATE_ERROR;
     }
diff --git a/core/java/android/view/HardwareLayer.java b/core/java/android/view/HardwareLayer.java
index 9bbcf7c..958c071 100644
--- a/core/java/android/view/HardwareLayer.java
+++ b/core/java/android/view/HardwareLayer.java
@@ -33,7 +33,7 @@
  */
 final class HardwareLayer {
     private static final int LAYER_TYPE_TEXTURE = 1;
-    private static final int LAYER_TYPE_RENDER = 2;
+    private static final int LAYER_TYPE_DISPLAY_LIST = 2;
 
     private HardwareRenderer mRenderer;
     private Finalizer mFinalizer;
@@ -99,6 +99,10 @@
         doDestroyLayerUpdater();
     }
 
+    public long getDeferredLayerUpdater() {
+        return mFinalizer.mDeferredUpdater;
+    }
+
     /**
      * Destroys the deferred layer updater but not the backing layer. The
      * backing layer is instead returned and is the caller's responsibility
@@ -120,7 +124,7 @@
     }
 
     public DisplayList startRecording() {
-        assertType(LAYER_TYPE_RENDER);
+        assertType(LAYER_TYPE_DISPLAY_LIST);
 
         if (mDisplayList == null) {
             mDisplayList = DisplayList.create("HardwareLayer");
@@ -172,9 +176,17 @@
     /**
      * Indicates that this layer has lost its texture.
      */
-    public void onTextureDestroyed() {
+    public void detachSurfaceTexture(final SurfaceTexture surface) {
         assertType(LAYER_TYPE_TEXTURE);
-        nOnTextureDestroyed(mFinalizer.mDeferredUpdater);
+        mRenderer.safelyRun(new Runnable() {
+            @Override
+            public void run() {
+                surface.detachFromGLContext();
+                // SurfaceTexture owns the texture name and detachFromGLContext
+                // should have deleted it
+                nOnTextureDestroyed(mFinalizer.mDeferredUpdater);
+            }
+        });
     }
 
     /**
@@ -226,12 +238,20 @@
         return new HardwareLayer(renderer, nCreateTextureLayer(), LAYER_TYPE_TEXTURE);
     }
 
+    static HardwareLayer adoptTextureLayer(HardwareRenderer renderer, long layer) {
+        return new HardwareLayer(renderer, layer, LAYER_TYPE_TEXTURE);
+    }
+
     /**
      * This should only be used by HardwareRenderer! Do not call directly
      */
-    static HardwareLayer createRenderLayer(HardwareRenderer renderer,
+    static HardwareLayer createDisplayListLayer(HardwareRenderer renderer,
             int width, int height) {
-        return new HardwareLayer(renderer, nCreateRenderLayer(width, height), LAYER_TYPE_RENDER);
+        return new HardwareLayer(renderer, nCreateRenderLayer(width, height), LAYER_TYPE_DISPLAY_LIST);
+    }
+
+    static HardwareLayer adoptDisplayListLayer(HardwareRenderer renderer, long layer) {
+        return new HardwareLayer(renderer, layer, LAYER_TYPE_DISPLAY_LIST);
     }
 
     /** This also creates the underlying layer */
diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java
index 93cc9d1..7a943f0 100644
--- a/core/java/android/view/HardwareRenderer.java
+++ b/core/java/android/view/HardwareRenderer.java
@@ -234,13 +234,6 @@
     abstract void updateSurface(Surface surface) throws OutOfResourcesException;
 
     /**
-     * Destroys the layers used by the specified view hierarchy.
-     *
-     * @param view The root of the view hierarchy
-     */
-    abstract void destroyLayers(View view);
-
-    /**
      * Destroys all hardware rendering resources associated with the specified
      * view hierarchy.
      *
@@ -257,15 +250,6 @@
     abstract void invalidate(Surface surface);
 
     /**
-     * This method should be invoked to ensure the hardware renderer is in
-     * valid state (for instance, to ensure the correct EGL context is bound
-     * to the current thread.)
-     *
-     * @return true if the renderer is now valid, false otherwise
-     */
-    abstract boolean validate();
-
-    /**
      * This method ensures the hardware renderer is in a valid state
      * before executing the specified action.
      *
diff --git a/core/java/android/view/TextureView.java b/core/java/android/view/TextureView.java
index e789407..ef0d80d 100644
--- a/core/java/android/view/TextureView.java
+++ b/core/java/android/view/TextureView.java
@@ -231,26 +231,12 @@
     @Override
     protected void onDetachedFromWindow() {
         super.onDetachedFromWindow();
-        if (mLayer != null) {
-            boolean success = executeHardwareAction(new Runnable() {
-                @Override
-                public void run() {
-                    destroySurface();
-                }
-            });
-
-            if (!success) {
-                Log.w(LOG_TAG, "TextureView was not able to destroy its surface: " + this);
-            }
-        }
+        destroySurface();
     }
 
     private void destroySurface() {
         if (mLayer != null) {
-            mSurface.detachFromGLContext();
-            // SurfaceTexture owns the texture name and detachFromGLContext
-            // should have deleted it
-            mLayer.onTextureDestroyed();
+            mLayer.detachSurfaceTexture(mSurface);
 
             boolean shouldRelease = true;
             if (mListener != null) {
@@ -608,14 +594,6 @@
      */
     public Bitmap getBitmap(Bitmap bitmap) {
         if (bitmap != null && isAvailable()) {
-            AttachInfo info = mAttachInfo;
-            if (info != null && info.mHardwareRenderer != null &&
-                    info.mHardwareRenderer.isEnabled()) {
-                if (!info.mHardwareRenderer.validate()) {
-                    throw new IllegalStateException("Could not acquire hardware rendering context");
-                }
-            }
-
             applyUpdate();
             applyTransformMatrix();
 
diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java
index 1d7e5b2..e8f5e45 100644
--- a/core/java/android/view/ThreadedRenderer.java
+++ b/core/java/android/view/ThreadedRenderer.java
@@ -76,13 +76,7 @@
     }
 
     @Override
-    void destroyLayers(View view) {
-        throw new NoSuchMethodError();
-    }
-
-    @Override
     void destroyHardwareResources(View view) {
-        // TODO: canvas.clearLayerUpdates()
         destroyResources(view);
         // TODO: GLES20Canvas.flushCaches(GLES20Canvas.FLUSH_CACHES_LAYERS);
     }
@@ -106,12 +100,6 @@
     }
 
     @Override
-    boolean validate() {
-        // TODO Remove users of this API
-        return false;
-    }
-
-    @Override
     boolean safelyRun(Runnable action) {
         nRunWithGlContext(mNativeProxy, action);
         return true;
@@ -150,26 +138,6 @@
         return false;
     }
 
-    @Override
-    void pushLayerUpdate(HardwareLayer layer) {
-        throw new NoSuchMethodError();
-    }
-
-    @Override
-    void onLayerCreated(HardwareLayer layer) {
-        throw new NoSuchMethodError();
-    }
-
-    @Override
-    void onLayerDestroyed(HardwareLayer layer) {
-        throw new NoSuchMethodError();
-    }
-
-    @Override
-    void flushLayerUpdates() {
-        throw new NoSuchMethodError();
-    }
-
     /**
      * TODO: Remove
      * Temporary hack to allow RenderThreadTest prototype app to trigger
@@ -203,26 +171,6 @@
     }
 
     @Override
-    HardwareLayer createTextureLayer() {
-        throw new NoSuchMethodError();
-    }
-
-    @Override
-    HardwareLayer createDisplayListLayer(int width, int height) {
-        throw new NoSuchMethodError();
-    }
-
-    @Override
-    SurfaceTexture createSurfaceTexture(HardwareLayer layer) {
-        throw new NoSuchMethodError();
-    }
-
-    @Override
-    boolean copyLayerInto(HardwareLayer layer, Bitmap bitmap) {
-        throw new NoSuchMethodError();
-    }
-
-    @Override
     void detachFunctor(long functor) {
         nDetachFunctor(mNativeProxy, functor);
     }
@@ -233,6 +181,56 @@
     }
 
     @Override
+    HardwareLayer createDisplayListLayer(int width, int height) {
+        long layer = nCreateDisplayListLayer(mNativeProxy, width, height);
+        return HardwareLayer.adoptDisplayListLayer(this, layer);
+    }
+
+    @Override
+    HardwareLayer createTextureLayer() {
+        long layer = nCreateTextureLayer(mNativeProxy);
+        return HardwareLayer.adoptTextureLayer(this, layer);
+    }
+
+    @Override
+    SurfaceTexture createSurfaceTexture(final HardwareLayer layer) {
+        final SurfaceTexture[] ret = new SurfaceTexture[1];
+        nRunWithGlContext(mNativeProxy, new Runnable() {
+            @Override
+            public void run() {
+                ret[0] = layer.createSurfaceTexture();
+            }
+        });
+        return ret[0];
+    }
+
+    @Override
+    boolean copyLayerInto(final HardwareLayer layer, final Bitmap bitmap) {
+        return nCopyLayerInto(mNativeProxy,
+                layer.getDeferredLayerUpdater(), bitmap.mNativeBitmap);
+    }
+
+    @Override
+    void pushLayerUpdate(HardwareLayer layer) {
+        // TODO: Remove this, it's not needed outside of GLRenderer
+    }
+
+    @Override
+    void onLayerCreated(HardwareLayer layer) {
+        // TODO: Is this actually useful?
+    }
+
+    @Override
+    void flushLayerUpdates() {
+        // TODO: Figure out what this should do or remove it
+    }
+
+    @Override
+    void onLayerDestroyed(HardwareLayer layer) {
+        nDestroyLayer(mNativeProxy, layer.getDeferredLayerUpdater());
+    }
+
+    @Override
     void setName(String name) {
     }
 
@@ -261,4 +259,9 @@
 
     private static native void nAttachFunctor(long nativeProxy, long functor);
     private static native void nDetachFunctor(long nativeProxy, long functor);
+
+    private static native long nCreateDisplayListLayer(long nativeProxy, int width, int height);
+    private static native long nCreateTextureLayer(long nativeProxy);
+    private static native boolean nCopyLayerInto(long nativeProxy, long layer, long bitmap);
+    private static native void nDestroyLayer(long nativeProxy, long layer);
 }
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 49dc572..089f816 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -2393,7 +2393,7 @@
      * Flag indicating that view will be transformed by the global camera if rotated in 3d, or given
      * a non-0 Z translation.
      */
-    static final int PFLAG3_SHARES_GLOBAL_CAMERA = 0x200;
+    static final int PFLAG3_USES_GLOBAL_CAMERA = 0x200;
 
     /* End of masks for mPrivateFlags3 */
 
@@ -4037,6 +4037,11 @@
                 case R.styleable.View_layerType:
                     setLayerType(a.getInt(attr, LAYER_TYPE_NONE), null);
                     break;
+                case R.styleable.View_castsShadow:
+                    if (a.getBoolean(attr, false)) {
+                        mPrivateFlags3 |= PFLAG3_CASTS_SHADOW;
+                    }
+                    break;
                 case R.styleable.View_textDirection:
                     // Clear any text direction flag already set
                     mPrivateFlags2 &= ~PFLAG2_TEXT_DIRECTION_MASK;
@@ -10809,9 +10814,20 @@
     }
 
     /**
-     * @hide
+     * Copies the Outline of the View into the Path parameter.
+     * <p>
+     * If the outline is not set, the parameter Path is set to empty.
+     *
+     * @param outline Path into which View's outline will be copied. Must be non-null.
+     *
+     * @see #setOutline(Path)
+     * @see #getClipToOutline()
+     * @see #setClipToOutline(boolean)
      */
-    public final void getOutline(Path outline) {
+    public final void getOutline(@NonNull Path outline) {
+        if (outline == null) {
+            throw new IllegalArgumentException("Path must be non-null");
+        }
         if (mOutline == null) {
             outline.reset();
         } else {
@@ -10820,30 +10836,58 @@
     }
 
     /**
-     * @hide
+     * Sets the outline of the view, which defines the shape of the shadow it
+     * casts, and can used for clipping.
+     * <p>
+     * If the outline is not set, or {@link Path#isEmpty()}, shadows will be
+     * cast from the bounds of the View, and clipToOutline will be ignored.
+     *
+     * @param outline The new outline of the view. Must be non-null.
+     *
+     * @see #getOutline(Path)
+     * @see #getClipToOutline()
+     * @see #setClipToOutline(boolean)
      */
-    public void setOutline(Path path) {
+    public void setOutline(@NonNull Path outline) {
+        if (outline == null) {
+            throw new IllegalArgumentException("Path must be non-null");
+        }
         // always copy the path since caller may reuse
         if (mOutline == null) {
-            mOutline = new Path(path);
+            mOutline = new Path(outline);
         } else {
-            mOutline.set(path);
+            mOutline.set(outline);
         }
 
         if (mDisplayList != null) {
-            mDisplayList.setOutline(path);
+            mDisplayList.setOutline(outline);
         }
     }
 
     /**
-     * @hide
+     * Returns whether the outline of the View will be used for clipping.
+     *
+     * @see #getOutline(Path)
+     * @see #setOutline(Path)
      */
     public final boolean getClipToOutline() {
         return ((mPrivateFlags3 & PFLAG3_CLIP_TO_OUTLINE) != 0);
     }
 
     /**
-     * @hide
+     * Sets whether the outline of the View will be used for clipping.
+     * <p>
+     * The current implementation of outline clipping uses Canvas#clipPath(),
+     * and thus does not support anti-aliasing, and is expensive in terms of
+     * graphics performance. Therefore, it is strongly recommended that this
+     * property only be set temporarily, as in an animation. For the same
+     * reasons, there is no parallel XML attribute for this property.
+     * <p>
+     * If the outline of the view is not set or is empty, no clipping will be
+     * performed.
+     *
+     * @see #getOutline(Path)
+     * @see #setOutline(Path)
      */
     public void setClipToOutline(boolean clipToOutline) {
         // TODO : Add a fast invalidation here.
@@ -10860,14 +10904,35 @@
     }
 
     /**
-     * @hide
+     * Returns whether the View will cast shadows when its
+     * {@link #setTranslationZ(float) z translation} is greater than 0, or it is
+     * rotated in 3D.
+     *
+     * @see #setTranslationZ(float)
+     * @see #setRotationX(float)
+     * @see #setRotationY(float)
+     * @see #setCastsShadow(boolean)
+     * @attr ref android.R.styleable#View_castsShadow
      */
     public final boolean getCastsShadow() {
         return ((mPrivateFlags3 & PFLAG3_CASTS_SHADOW) != 0);
     }
 
     /**
-     * @hide
+     * Set to true to enable this View to cast shadows.
+     * <p>
+     * If enabled, and the View has a z translation greater than 0, or is
+     * rotated in 3D, the shadow will be cast onto the current
+     * {@link ViewGroup#setIsolatedZVolume(boolean) isolated Z volume},
+     * at the z = 0 plane.
+     * <p>
+     * The shape of the shadow being cast is defined by the
+     * {@link #setOutline(Path) outline} of the view, or the rectangular bounds
+     * of the view if the outline is not set or is empty.
+     *
+     * @see #setTranslationZ(float)
+     * @see #getCastsShadow()
+     * @attr ref android.R.styleable#View_castsShadow
      */
     public void setCastsShadow(boolean castsShadow) {
         // TODO : Add a fast invalidation here.
@@ -10884,25 +10949,46 @@
     }
 
     /**
+     * Returns whether the View will be transformed by the global camera.
+     *
+     * @see #setUsesGlobalCamera(boolean)
+     *
      * @hide
      */
-    public final boolean getSharesGlobalCamera() {
-        return ((mPrivateFlags3 & PFLAG3_SHARES_GLOBAL_CAMERA) != 0);
+    public final boolean getUsesGlobalCamera() {
+        return ((mPrivateFlags3 & PFLAG3_USES_GLOBAL_CAMERA) != 0);
     }
 
     /**
+     * Sets whether the View should be transformed by the global camera.
+     * <p>
+     * If the view has a Z translation or 3D rotation, perspective from the
+     * global camera will be applied. This enables an app to transform multiple
+     * views in 3D with coherent perspective projection among them all.
+     * <p>
+     * Setting this to true will cause {@link #setCameraDistance() camera distance}
+     * to be ignored, as the global camera's position will dictate perspective
+     * transform.
+     * <p>
+     * This should not be used in conjunction with {@link android.graphics.Camera}.
+     *
+     * @see #getUsesGlobalCamera()
+     * @see #setTranslationZ(float)
+     * @see #setRotationX(float)
+     * @see #setRotationY(float)
+     *
      * @hide
      */
-    public void setSharesGlobalCamera(boolean sharesGlobalCamera) {
+    public void setUsesGlobalCamera(boolean usesGlobalCamera) {
         // TODO : Add a fast invalidation here.
-        if (getSharesGlobalCamera() != sharesGlobalCamera) {
-            if (sharesGlobalCamera) {
-                mPrivateFlags3 |= PFLAG3_SHARES_GLOBAL_CAMERA;
+        if (getUsesGlobalCamera() != usesGlobalCamera) {
+            if (usesGlobalCamera) {
+                mPrivateFlags3 |= PFLAG3_USES_GLOBAL_CAMERA;
             } else {
-                mPrivateFlags3 &= ~PFLAG3_SHARES_GLOBAL_CAMERA;
+                mPrivateFlags3 &= ~PFLAG3_USES_GLOBAL_CAMERA;
             }
             if (mDisplayList != null) {
-                mDisplayList.setSharesGlobalCamera(sharesGlobalCamera);
+                mDisplayList.setUsesGlobalCamera(usesGlobalCamera);
             }
         }
     }
@@ -13584,19 +13670,15 @@
 
         switch (mLayerType) {
             case LAYER_TYPE_HARDWARE:
-                if (attachInfo.mHardwareRenderer != null &&
-                        attachInfo.mHardwareRenderer.isEnabled() &&
-                        attachInfo.mHardwareRenderer.validate()) {
-                    getHardwareLayer();
-                    // TODO: We need a better way to handle this case
-                    // If views have registered pre-draw listeners they need
-                    // to be notified before we build the layer. Those listeners
-                    // may however rely on other events to happen first so we
-                    // cannot just invoke them here until they don't cancel the
-                    // current frame
-                    if (!attachInfo.mTreeObserver.hasOnPreDrawListeners()) {
-                        attachInfo.mViewRootImpl.dispatchFlushHardwareLayerUpdates();
-                    }
+                getHardwareLayer();
+                // TODO: We need a better way to handle this case
+                // If views have registered pre-draw listeners they need
+                // to be notified before we build the layer. Those listeners
+                // may however rely on other events to happen first so we
+                // cannot just invoke them here until they don't cancel the
+                // current frame
+                if (!attachInfo.mTreeObserver.hasOnPreDrawListeners()) {
+                    attachInfo.mViewRootImpl.dispatchFlushHardwareLayerUpdates();
                 }
                 break;
             case LAYER_TYPE_SOFTWARE:
@@ -13617,8 +13699,6 @@
             return null;
         }
 
-        if (!mAttachInfo.mHardwareRenderer.validate()) return null;
-
         final int width = mRight - mLeft;
         final int height = mBottom - mTop;
 
@@ -14536,7 +14616,7 @@
             displayList.setOutline(mOutline);
             displayList.setClipToOutline(getClipToOutline());
             displayList.setCastsShadow(getCastsShadow());
-            displayList.setSharesGlobalCamera(getSharesGlobalCamera());
+            displayList.setUsesGlobalCamera(getUsesGlobalCamera());
             float alpha = 1;
             if (mParent instanceof ViewGroup && (((ViewGroup) mParent).mGroupFlags &
                     ViewGroup.FLAG_SUPPORT_STATIC_TRANSFORMATIONS) != 0) {
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index c3bf533..9cd3c9d 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -3176,6 +3176,7 @@
      * @return True if the group should be an isolated Z volume with its own Z
      *         ordering space, false if its decendents should inhabit the
      *         inherited Z ordering volume.
+     * @attr ref android.R.styleable#ViewGroup_isolatedZVolume
      */
     public void setIsolatedZVolume(boolean isolateZVolume) {
         boolean previousValue = (mGroupFlags & FLAG_ISOLATED_Z_VOLUME) != 0;
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 11030d9..a68d06a 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -631,16 +631,25 @@
             }
         } else {
             invalidateDisplayLists();
-            if (mAttachInfo.mHardwareRenderer != null &&
-                    mAttachInfo.mHardwareRenderer.isEnabled()) {
-                mAttachInfo.mHardwareRenderer.destroyLayers(mView);
+            destroyHardwareLayer(mView);
+        }
+    }
+
+    private static void destroyHardwareLayer(View view) {
+        view.destroyLayer(true);
+
+        if (view instanceof ViewGroup) {
+            ViewGroup group = (ViewGroup) view;
+
+            int count = group.getChildCount();
+            for (int i = 0; i < count; i++) {
+                destroyHardwareLayer(group.getChildAt(i));
             }
         }
     }
 
     void flushHardwareLayerUpdates() {
-        if (mAttachInfo.mHardwareRenderer != null && mAttachInfo.mHardwareRenderer.isEnabled() &&
-                mAttachInfo.mHardwareRenderer.validate()) {
+        if (mAttachInfo.mHardwareRenderer != null && mAttachInfo.mHardwareRenderer.isEnabled()) {
             mAttachInfo.mHardwareRenderer.flushLayerUpdates();
         }
     }
@@ -2845,10 +2854,6 @@
 
     void dispatchDetachedFromWindow() {
         if (mView != null && mView.mAttachInfo != null) {
-            if (mAttachInfo.mHardwareRenderer != null &&
-                    mAttachInfo.mHardwareRenderer.isEnabled()) {
-                mAttachInfo.mHardwareRenderer.validate();
-            }
             mAttachInfo.mTreeObserver.dispatchOnWindowAttachedChange(false);
             mView.dispatchDetachedFromWindow();
         }
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index 63ce5a3..93b95bf6e 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -7155,7 +7155,7 @@
             float endSubRow = targetRow;
             if (boundPosition != INVALID_POSITION) {
                 final int boundRow = getRowForPosition(boundPosition);
-                if (boundRow >= firstRow && boundRow < lastRow) {
+                if (boundRow >= firstRow && boundRow < lastRow && boundRow != targetRow) {
                     endSubRow = computeBoundSubRow(targetRow, boundRow);
                 }
             }
@@ -7185,15 +7185,18 @@
         }
 
         private float computeBoundSubRow(int targetRow, int boundRow) {
-            // Compute the target and offset as a sub-position.
+            // If the final offset is greater than 0, we're aiming above the
+            // suggested target row. Compute the actual target row and offset
+            // within that row by subtracting the height of each preceeding row.
             int remainingOffset = mOffset;
-            int targetHeight = getHeightForRow(targetRow - 1);
-            while (remainingOffset > 0) {
-                remainingOffset -= targetHeight;
+            int targetHeight = getHeightForRow(targetRow);
+            while (targetRow > 0 && remainingOffset > targetHeight) {
                 targetRow--;
-                targetHeight = getHeightForRow(targetRow - 1);
+                remainingOffset -= targetHeight;
+                targetHeight = getHeightForRow(targetRow);
             }
 
+            // Compute the offset within the actual target row.
             final float targetOffsetRatio;
             if (targetHeight == 0) {
                 targetOffsetRatio = 1;
@@ -7201,6 +7204,7 @@
                 targetOffsetRatio = remainingOffset / (float) targetHeight;
             }
 
+            // The final offset has been accounted for, reset it.
             final float targetSubRow = targetRow - targetOffsetRatio;
             mOffset = 0;
 
diff --git a/core/java/android/widget/SpellChecker.java b/core/java/android/widget/SpellChecker.java
index b204dfd..1cda631 100644
--- a/core/java/android/widget/SpellChecker.java
+++ b/core/java/android/widget/SpellChecker.java
@@ -731,10 +731,14 @@
                 }
             }
 
-            if (scheduleOtherSpellCheck) {
+            if (scheduleOtherSpellCheck && wordStart <= end) {
                 // Update range span: start new spell check from last wordStart
                 setRangeSpan(editable, wordStart, end);
             } else {
+                if (DBG && scheduleOtherSpellCheck) {
+                    Log.w(TAG, "Trying to schedule spellcheck for invalid region, from "
+                            + wordStart + " to " + end);
+                }
                 removeRangeSpan(editable);
             }
 
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 65b79fc..e5cb16f 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -5809,6 +5809,7 @@
                 int end = text.partialEndOffset;
                 if (end > N) end = N;
                 removeParcelableSpans(content, start, end);
+                // If start > end, content.replace will swap them before using them.
                 content.replace(start, end, text.text);
             }
         }
diff --git a/core/java/com/android/internal/app/IBatteryStats.aidl b/core/java/com/android/internal/app/IBatteryStats.aidl
index 18d5668..1155cbb 100644
--- a/core/java/com/android/internal/app/IBatteryStats.aidl
+++ b/core/java/com/android/internal/app/IBatteryStats.aidl
@@ -62,9 +62,10 @@
     void noteWifiRunning(in WorkSource ws);
     void noteWifiRunningChanged(in WorkSource oldWs, in WorkSource newWs);
     void noteWifiStopped(in WorkSource ws);
+    void noteWifiState(int wifiState, String accessPoint);
     void noteBluetoothOn();
     void noteBluetoothOff();
-    void noteBluetoothActiveState(int actType);
+    void noteBluetoothState(int bluetoothState);
     void noteFullWifiLockAcquired(int uid);
     void noteFullWifiLockReleased(int uid);
     void noteWifiScanStarted(int uid);
diff --git a/core/java/com/android/internal/app/ProcessStats.java b/core/java/com/android/internal/app/ProcessStats.java
index 4dd4a45..b1535e3 100644
--- a/core/java/com/android/internal/app/ProcessStats.java
+++ b/core/java/com/android/internal/app/ProcessStats.java
@@ -1018,7 +1018,7 @@
                     for (int iproc=pkgState.mProcesses.size()-1; iproc>=0; iproc--) {
                         final ProcessState ps = pkgState.mProcesses.valueAt(iproc);
                         if (ps.isInUse()) {
-                            pkgState.mProcesses.valueAt(iproc).resetSafely(now);
+                            ps.resetSafely(now);
                             ps.mCommonProcess.mTmpNumInUse++;
                             ps.mCommonProcess.mTmpFoundSubProc = ps;
                         } else {
@@ -1029,7 +1029,7 @@
                     for (int isvc=pkgState.mServices.size()-1; isvc>=0; isvc--) {
                         final ServiceState ss = pkgState.mServices.valueAt(isvc);
                         if (ss.isInUse()) {
-                            pkgState.mServices.valueAt(isvc).resetSafely(now);
+                            ss.resetSafely(now);
                         } else {
                             pkgState.mServices.removeAt(isvc);
                         }
@@ -3142,7 +3142,7 @@
         }
 
         public boolean isInUse() {
-            return mOwner != null;
+            return mOwner != null || mRestarting;
         }
 
         void add(ServiceState other) {
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index e50e281..274e267 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -23,6 +23,7 @@
 import android.content.Context;
 import android.net.ConnectivityManager;
 import android.net.NetworkStats;
+import android.os.BadParcelableException;
 import android.os.BatteryManager;
 import android.os.BatteryStats;
 import android.os.FileUtils;
@@ -86,7 +87,7 @@
     private static final int MAGIC = 0xBA757475; // 'BATSTATS'
 
     // Current on-disk Parcel version
-    private static final int VERSION = 84 + (USE_OLD_HISTORY ? 1000 : 0);
+    private static final int VERSION = 85 + (USE_OLD_HISTORY ? 1000 : 0);
 
     // Maximum number of items we will record in the history.
     private static final int MAX_HISTORY_ITEMS = 2000;
@@ -271,12 +272,14 @@
     boolean mGlobalWifiRunning;
     StopwatchTimer mGlobalWifiRunningTimer;
 
+    int mWifiState = -1;
+    final StopwatchTimer[] mWifiStateTimer = new StopwatchTimer[NUM_WIFI_STATES];
+
     boolean mBluetoothOn;
     StopwatchTimer mBluetoothOnTimer;
 
-    int mBluetoothActiveType = -1;
-    final StopwatchTimer[] mBluetoothActiveTimer =
-            new StopwatchTimer[NUM_BLUETOOTH_ACTIVE_TYPES];
+    int mBluetoothState = -1;
+    final StopwatchTimer[] mBluetoothStateTimer = new StopwatchTimer[NUM_BLUETOOTH_STATES];
 
     boolean mMobileRadioActive;
     StopwatchTimer mMobileRadioActiveTimer;
@@ -1166,10 +1169,9 @@
                     + " mAcquireTime=" + mAcquireTime);
         }
 
-        void startRunningLocked(BatteryStatsImpl stats) {
+        void startRunningLocked(BatteryStatsImpl stats, long elapsedRealtime) {
             if (mNesting++ == 0) {
-                mUpdateTime = stats.getBatteryRealtimeLocked(
-                        SystemClock.elapsedRealtime() * 1000);
+                mUpdateTime = stats.getBatteryRealtimeLocked(elapsedRealtime * 1000);
                 if (mTimerPool != null) {
                     // Accumulate time to all currently active timers before adding
                     // this new one to the pool.
@@ -1192,7 +1194,7 @@
             return mNesting > 0;
         }
 
-        void stopRunningLocked(BatteryStatsImpl stats) {
+        void stopRunningLocked(BatteryStatsImpl stats, long elapsedRealtime) {
             // Ignore attempt to stop a timer that isn't running
             if (mNesting == 0) {
                 return;
@@ -1205,8 +1207,8 @@
                     // Remove this timer from the active pool
                     mTimerPool.remove(this);
                 } else {
-                    final long realtime = SystemClock.elapsedRealtime() * 1000;
-                    final long batteryRealtime = stats.getBatteryRealtimeLocked(realtime);
+                    final long batteryRealtime = stats.getBatteryRealtimeLocked(
+                            elapsedRealtime * 1000);
                     mNesting = 1;
                     mTotalTime = computeRunTimeLocked(batteryRealtime);
                     mNesting = 0;
@@ -2007,6 +2009,7 @@
     public void noteStartWakeLocked(int uid, int pid, String name, int type,
             boolean unimportantForLogging) {
         uid = mapUid(uid);
+        final long elapsedRealtime = SystemClock.elapsedRealtime();
         if (type == WAKE_TYPE_PARTIAL) {
             // Only care about partial wake locks, since full wake locks
             // will be canceled when the user puts the screen to sleep.
@@ -2018,7 +2021,7 @@
                 mHistoryCur.wakelockTag.string = name;
                 mHistoryCur.wakelockTag.uid = uid;
                 mWakeLockImportant = !unimportantForLogging;
-                addHistoryRecordLocked(SystemClock.elapsedRealtime());
+                addHistoryRecordLocked(elapsedRealtime);
             } else if (!mWakeLockImportant && !unimportantForLogging) {
                 if (mHistoryLastWritten.wakelockTag != null) {
                     // We'll try to update the last tag.
@@ -2026,7 +2029,7 @@
                     mHistoryCur.wakelockTag = mHistoryCur.localWakelockTag;
                     mHistoryCur.wakelockTag.string = name;
                     mHistoryCur.wakelockTag.uid = uid;
-                    addHistoryRecordLocked(SystemClock.elapsedRealtime());
+                    addHistoryRecordLocked(elapsedRealtime);
                 }
                 mWakeLockImportant = true;
             }
@@ -2037,19 +2040,20 @@
                 Message m = mHandler.obtainMessage(MSG_UPDATE_WAKELOCKS);
                 mHandler.sendMessageDelayed(m, DELAY_UPDATE_WAKELOCKS);
             }
-            getUidStatsLocked(uid).noteStartWakeLocked(pid, name, type);
+            getUidStatsLocked(uid).noteStartWakeLocked(pid, name, type, elapsedRealtime);
         }
     }
 
     public void noteStopWakeLocked(int uid, int pid, String name, int type) {
         uid = mapUid(uid);
+        final long elapsedRealtime = SystemClock.elapsedRealtime();
         if (type == WAKE_TYPE_PARTIAL) {
             mWakeLockNesting--;
             if (mWakeLockNesting == 0) {
                 mHistoryCur.states &= ~HistoryItem.STATE_WAKE_LOCK_FLAG;
                 if (DEBUG_HISTORY) Slog.v(TAG, "Stop wake lock to: "
                         + Integer.toHexString(mHistoryCur.states));
-                addHistoryRecordLocked(SystemClock.elapsedRealtime());
+                addHistoryRecordLocked(elapsedRealtime);
             }
         }
         if (uid >= 0) {
@@ -2057,7 +2061,7 @@
                 Message m = mHandler.obtainMessage(MSG_UPDATE_WAKELOCKS);
                 mHandler.sendMessageDelayed(m, DELAY_UPDATE_WAKELOCKS);
             }
-            getUidStatsLocked(uid).noteStopWakeLocked(pid, name, type);
+            getUidStatsLocked(uid).noteStopWakeLocked(pid, name, type, elapsedRealtime);
         }
     }
 
@@ -2214,64 +2218,70 @@
 
     public void noteStartSensorLocked(int uid, int sensor) {
         uid = mapUid(uid);
+        final long elapsedRealtime = SystemClock.elapsedRealtime();
         if (mSensorNesting == 0) {
             mHistoryCur.states |= HistoryItem.STATE_SENSOR_ON_FLAG;
             if (DEBUG_HISTORY) Slog.v(TAG, "Start sensor to: "
                     + Integer.toHexString(mHistoryCur.states));
-            addHistoryRecordLocked(SystemClock.elapsedRealtime());
+            addHistoryRecordLocked(elapsedRealtime);
         }
         mSensorNesting++;
-        getUidStatsLocked(uid).noteStartSensor(sensor);
+        getUidStatsLocked(uid).noteStartSensor(sensor, elapsedRealtime);
     }
 
     public void noteStopSensorLocked(int uid, int sensor) {
         uid = mapUid(uid);
+        final long elapsedRealtime = SystemClock.elapsedRealtime();
         mSensorNesting--;
         if (mSensorNesting == 0) {
             mHistoryCur.states &= ~HistoryItem.STATE_SENSOR_ON_FLAG;
             if (DEBUG_HISTORY) Slog.v(TAG, "Stop sensor to: "
                     + Integer.toHexString(mHistoryCur.states));
-            addHistoryRecordLocked(SystemClock.elapsedRealtime());
+            addHistoryRecordLocked(elapsedRealtime);
         }
-        getUidStatsLocked(uid).noteStopSensor(sensor);
+        getUidStatsLocked(uid).noteStopSensor(sensor, elapsedRealtime);
     }
 
     int mGpsNesting;
 
     public void noteStartGpsLocked(int uid) {
         uid = mapUid(uid);
+        final long elapsedRealtime = SystemClock.elapsedRealtime();
         if (mGpsNesting == 0) {
             mHistoryCur.states |= HistoryItem.STATE_GPS_ON_FLAG;
             if (DEBUG_HISTORY) Slog.v(TAG, "Start GPS to: "
                     + Integer.toHexString(mHistoryCur.states));
-            addHistoryRecordLocked(SystemClock.elapsedRealtime());
+            addHistoryRecordLocked(elapsedRealtime);
         }
         mGpsNesting++;
-        getUidStatsLocked(uid).noteStartGps();
+        getUidStatsLocked(uid).noteStartGps(elapsedRealtime);
     }
 
     public void noteStopGpsLocked(int uid) {
         uid = mapUid(uid);
+        final long elapsedRealtime = SystemClock.elapsedRealtime();
         mGpsNesting--;
         if (mGpsNesting == 0) {
             mHistoryCur.states &= ~HistoryItem.STATE_GPS_ON_FLAG;
             if (DEBUG_HISTORY) Slog.v(TAG, "Stop GPS to: "
                     + Integer.toHexString(mHistoryCur.states));
-            addHistoryRecordLocked(SystemClock.elapsedRealtime());
+            addHistoryRecordLocked(elapsedRealtime);
         }
-        getUidStatsLocked(uid).noteStopGps();
+        getUidStatsLocked(uid).noteStopGps(elapsedRealtime);
     }
 
     public void noteScreenOnLocked() {
         if (!mScreenOn) {
+            final long elapsedRealtime = SystemClock.elapsedRealtime();
             mHistoryCur.states |= HistoryItem.STATE_SCREEN_ON_FLAG;
             if (DEBUG_HISTORY) Slog.v(TAG, "Screen on to: "
                     + Integer.toHexString(mHistoryCur.states));
-            addHistoryRecordLocked(SystemClock.elapsedRealtime());
+            addHistoryRecordLocked(elapsedRealtime);
             mScreenOn = true;
-            mScreenOnTimer.startRunningLocked(this);
+            mScreenOnTimer.startRunningLocked(this, elapsedRealtime);
             if (mScreenBrightnessBin >= 0) {
-                mScreenBrightnessTimer[mScreenBrightnessBin].startRunningLocked(this);
+                mScreenBrightnessTimer[mScreenBrightnessBin].startRunningLocked(this,
+                        elapsedRealtime);
             }
 
             // Fake a wake lock, so we consider the device waked as long
@@ -2287,14 +2297,16 @@
 
     public void noteScreenOffLocked() {
         if (mScreenOn) {
+            final long elapsedRealtime = SystemClock.elapsedRealtime();
             mHistoryCur.states &= ~HistoryItem.STATE_SCREEN_ON_FLAG;
             if (DEBUG_HISTORY) Slog.v(TAG, "Screen off to: "
                     + Integer.toHexString(mHistoryCur.states));
-            addHistoryRecordLocked(SystemClock.elapsedRealtime());
+            addHistoryRecordLocked(elapsedRealtime);
             mScreenOn = false;
-            mScreenOnTimer.stopRunningLocked(this);
+            mScreenOnTimer.stopRunningLocked(this, elapsedRealtime);
             if (mScreenBrightnessBin >= 0) {
-                mScreenBrightnessTimer[mScreenBrightnessBin].stopRunningLocked(this);
+                mScreenBrightnessTimer[mScreenBrightnessBin].stopRunningLocked(this,
+                        elapsedRealtime);
             }
 
             noteStopWakeLocked(-1, -1, "dummy", WAKE_TYPE_PARTIAL);
@@ -2312,16 +2324,18 @@
         if (bin < 0) bin = 0;
         else if (bin >= NUM_SCREEN_BRIGHTNESS_BINS) bin = NUM_SCREEN_BRIGHTNESS_BINS-1;
         if (mScreenBrightnessBin != bin) {
+            final long elapsedRealtime = SystemClock.elapsedRealtime();
             mHistoryCur.states = (mHistoryCur.states&~HistoryItem.STATE_BRIGHTNESS_MASK)
                     | (bin << HistoryItem.STATE_BRIGHTNESS_SHIFT);
             if (DEBUG_HISTORY) Slog.v(TAG, "Screen brightness " + bin + " to: "
                     + Integer.toHexString(mHistoryCur.states));
-            addHistoryRecordLocked(SystemClock.elapsedRealtime());
+            addHistoryRecordLocked(elapsedRealtime);
             if (mScreenOn) {
                 if (mScreenBrightnessBin >= 0) {
-                    mScreenBrightnessTimer[mScreenBrightnessBin].stopRunningLocked(this);
+                    mScreenBrightnessTimer[mScreenBrightnessBin].stopRunningLocked(this,
+                            elapsedRealtime);
                 }
-                mScreenBrightnessTimer[bin].startRunningLocked(this);
+                mScreenBrightnessTimer[bin].startRunningLocked(this, elapsedRealtime);
             }
             mScreenBrightnessBin = bin;
         }
@@ -2340,15 +2354,16 @@
         try {
             int type = Integer.parseInt(label);
             if (ConnectivityManager.isNetworkTypeMobile(type)) {
+                final long elapsedRealtime = SystemClock.elapsedRealtime();
                 if (mMobileRadioActive != active) {
                     if (active) mHistoryCur.states |= HistoryItem.STATE_MOBILE_RADIO_ACTIVE_FLAG;
                     else mHistoryCur.states &= ~HistoryItem.STATE_MOBILE_RADIO_ACTIVE_FLAG;
                     if (DEBUG_HISTORY) Slog.v(TAG, "Mobile network active " + active + " to: "
                             + Integer.toHexString(mHistoryCur.states));
-                    addHistoryRecordLocked(SystemClock.elapsedRealtime());
+                    addHistoryRecordLocked(elapsedRealtime);
                     mMobileRadioActive = active;
-                    if (active) mMobileRadioActiveTimer.startRunningLocked(this);
-                    else mMobileRadioActiveTimer.stopRunningLocked(this);
+                    if (active) mMobileRadioActiveTimer.startRunningLocked(this, elapsedRealtime);
+                    else mMobileRadioActiveTimer.stopRunningLocked(this, elapsedRealtime);
                 }
             }
         } catch (NumberFormatException e) {
@@ -2359,33 +2374,36 @@
 
     public void notePhoneOnLocked() {
         if (!mPhoneOn) {
+            final long elapsedRealtime = SystemClock.elapsedRealtime();
             mHistoryCur.states |= HistoryItem.STATE_PHONE_IN_CALL_FLAG;
             if (DEBUG_HISTORY) Slog.v(TAG, "Phone on to: "
                     + Integer.toHexString(mHistoryCur.states));
-            addHistoryRecordLocked(SystemClock.elapsedRealtime());
+            addHistoryRecordLocked(elapsedRealtime);
             mPhoneOn = true;
-            mPhoneOnTimer.startRunningLocked(this);
+            mPhoneOnTimer.startRunningLocked(this, elapsedRealtime);
         }
     }
 
     public void notePhoneOffLocked() {
         if (mPhoneOn) {
+            final long elapsedRealtime = SystemClock.elapsedRealtime();
             mHistoryCur.states &= ~HistoryItem.STATE_PHONE_IN_CALL_FLAG;
             if (DEBUG_HISTORY) Slog.v(TAG, "Phone off to: "
                     + Integer.toHexString(mHistoryCur.states));
-            addHistoryRecordLocked(SystemClock.elapsedRealtime());
+            addHistoryRecordLocked(elapsedRealtime);
             mPhoneOn = false;
-            mPhoneOnTimer.stopRunningLocked(this);
+            mPhoneOnTimer.stopRunningLocked(this, elapsedRealtime);
         }
     }
 
     void stopAllSignalStrengthTimersLocked(int except) {
+        final long elapsedRealtime = SystemClock.elapsedRealtime();
         for (int i = 0; i < SignalStrength.NUM_SIGNAL_STRENGTH_BINS; i++) {
             if (i == except) {
                 continue;
             }
             while (mPhoneSignalStrengthsTimer[i].isRunningLocked()) {
-                mPhoneSignalStrengthsTimer[i].stopRunningLocked(this);
+                mPhoneSignalStrengthsTimer[i].stopRunningLocked(this, elapsedRealtime);
             }
         }
     }
@@ -2403,26 +2421,28 @@
         return state;
     }
 
-    private void updateAllPhoneStateLocked(int state, int simState, int bin) {
+    private void updateAllPhoneStateLocked(int state, int simState, int strengthBin) {
         boolean scanning = false;
         boolean newHistory = false;
 
         mPhoneServiceStateRaw = state;
         mPhoneSimStateRaw = simState;
-        mPhoneSignalStrengthBinRaw = bin;
+        mPhoneSignalStrengthBinRaw = strengthBin;
+
+        final long elapsedRealtime = SystemClock.elapsedRealtime();
 
         if (simState == TelephonyManager.SIM_STATE_ABSENT) {
             // In this case we will always be STATE_OUT_OF_SERVICE, so need
             // to infer that we are scanning from other data.
             if (state == ServiceState.STATE_OUT_OF_SERVICE
-                    && bin > SignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN) {
+                    && strengthBin > SignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN) {
                 state = ServiceState.STATE_IN_SERVICE;
             }
         }
 
         // If the phone is powered off, stop all timers.
         if (state == ServiceState.STATE_POWER_OFF) {
-            bin = -1;
+            strengthBin = -1;
 
         // If we are in service, make sure the correct signal string timer is running.
         } else if (state == ServiceState.STATE_IN_SERVICE) {
@@ -2432,13 +2452,13 @@
         // bin and have the scanning bit set.
         } else if (state == ServiceState.STATE_OUT_OF_SERVICE) {
             scanning = true;
-            bin = SignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
+            strengthBin = SignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
             if (!mPhoneSignalScanningTimer.isRunningLocked()) {
                 mHistoryCur.states |= HistoryItem.STATE_PHONE_SCANNING_FLAG;
                 newHistory = true;
                 if (DEBUG_HISTORY) Slog.v(TAG, "Phone started scanning to: "
                         + Integer.toHexString(mHistoryCur.states));
-                mPhoneSignalScanningTimer.startRunningLocked(this);
+                mPhoneSignalScanningTimer.startRunningLocked(this, elapsedRealtime);
             }
         }
 
@@ -2449,7 +2469,7 @@
                 if (DEBUG_HISTORY) Slog.v(TAG, "Phone stopped scanning to: "
                         + Integer.toHexString(mHistoryCur.states));
                 newHistory = true;
-                mPhoneSignalScanningTimer.stopRunningLocked(this);
+                mPhoneSignalScanningTimer.stopRunningLocked(this, elapsedRealtime);
             }
         }
 
@@ -2462,27 +2482,29 @@
             mPhoneServiceState = state;
         }
 
-        if (mPhoneSignalStrengthBin != bin) {
+        if (mPhoneSignalStrengthBin != strengthBin) {
             if (mPhoneSignalStrengthBin >= 0) {
-                mPhoneSignalStrengthsTimer[mPhoneSignalStrengthBin].stopRunningLocked(this);
+                mPhoneSignalStrengthsTimer[mPhoneSignalStrengthBin].stopRunningLocked(this,
+                        elapsedRealtime);
             }
-            if (bin >= 0) {
-                if (!mPhoneSignalStrengthsTimer[bin].isRunningLocked()) {
-                    mPhoneSignalStrengthsTimer[bin].startRunningLocked(this);
+            if (strengthBin >= 0) {
+                if (!mPhoneSignalStrengthsTimer[strengthBin].isRunningLocked()) {
+                    mPhoneSignalStrengthsTimer[strengthBin].startRunningLocked(this,
+                            elapsedRealtime);
                 }
                 mHistoryCur.states = (mHistoryCur.states&~HistoryItem.STATE_SIGNAL_STRENGTH_MASK)
-                        | (bin << HistoryItem.STATE_SIGNAL_STRENGTH_SHIFT);
-                if (DEBUG_HISTORY) Slog.v(TAG, "Signal strength " + bin + " to: "
+                        | (strengthBin << HistoryItem.STATE_SIGNAL_STRENGTH_SHIFT);
+                if (DEBUG_HISTORY) Slog.v(TAG, "Signal strength " + strengthBin + " to: "
                         + Integer.toHexString(mHistoryCur.states));
                 newHistory = true;
             } else {
                 stopAllSignalStrengthTimersLocked(-1);
             }
-            mPhoneSignalStrengthBin = bin;
+            mPhoneSignalStrengthBin = strengthBin;
         }
 
         if (newHistory) {
-            addHistoryRecordLocked(SystemClock.elapsedRealtime());
+            addHistoryRecordLocked(elapsedRealtime);
         }
     }
 
@@ -2556,105 +2578,113 @@
         }
         if (DEBUG) Log.i(TAG, "Phone Data Connection -> " + dataType + " = " + hasData);
         if (mPhoneDataConnectionType != bin) {
+            final long elapsedRealtime = SystemClock.elapsedRealtime();
             mHistoryCur.states = (mHistoryCur.states&~HistoryItem.STATE_DATA_CONNECTION_MASK)
                     | (bin << HistoryItem.STATE_DATA_CONNECTION_SHIFT);
             if (DEBUG_HISTORY) Slog.v(TAG, "Data connection " + bin + " to: "
                     + Integer.toHexString(mHistoryCur.states));
-            addHistoryRecordLocked(SystemClock.elapsedRealtime());
+            addHistoryRecordLocked(elapsedRealtime);
             if (mPhoneDataConnectionType >= 0) {
-                mPhoneDataConnectionsTimer[mPhoneDataConnectionType].stopRunningLocked(this);
+                mPhoneDataConnectionsTimer[mPhoneDataConnectionType].stopRunningLocked(this,
+                        elapsedRealtime);
             }
             mPhoneDataConnectionType = bin;
-            mPhoneDataConnectionsTimer[bin].startRunningLocked(this);
+            mPhoneDataConnectionsTimer[bin].startRunningLocked(this, elapsedRealtime);
         }
     }
 
     public void noteWifiOnLocked() {
         if (!mWifiOn) {
+            final long elapsedRealtime = SystemClock.elapsedRealtime();
             mHistoryCur.states |= HistoryItem.STATE_WIFI_ON_FLAG;
             if (DEBUG_HISTORY) Slog.v(TAG, "WIFI on to: "
                     + Integer.toHexString(mHistoryCur.states));
-            addHistoryRecordLocked(SystemClock.elapsedRealtime());
+            addHistoryRecordLocked(elapsedRealtime);
             mWifiOn = true;
-            mWifiOnTimer.startRunningLocked(this);
+            mWifiOnTimer.startRunningLocked(this, elapsedRealtime);
         }
     }
 
     public void noteWifiOffLocked() {
+        final long elapsedRealtime = SystemClock.elapsedRealtime();
         if (mWifiOn) {
             mHistoryCur.states &= ~HistoryItem.STATE_WIFI_ON_FLAG;
             if (DEBUG_HISTORY) Slog.v(TAG, "WIFI off to: "
                     + Integer.toHexString(mHistoryCur.states));
-            addHistoryRecordLocked(SystemClock.elapsedRealtime());
+            addHistoryRecordLocked(elapsedRealtime);
             mWifiOn = false;
-            mWifiOnTimer.stopRunningLocked(this);
+            mWifiOnTimer.stopRunningLocked(this, elapsedRealtime);
         }
         if (mWifiOnUid >= 0) {
-            getUidStatsLocked(mWifiOnUid).noteWifiStoppedLocked();
+            getUidStatsLocked(mWifiOnUid).noteWifiStoppedLocked(elapsedRealtime);
             mWifiOnUid = -1;
         }
     }
 
     public void noteAudioOnLocked(int uid) {
         uid = mapUid(uid);
+        final long elapsedRealtime = SystemClock.elapsedRealtime();
         if (!mAudioOn) {
             mHistoryCur.states |= HistoryItem.STATE_AUDIO_ON_FLAG;
             if (DEBUG_HISTORY) Slog.v(TAG, "Audio on to: "
                     + Integer.toHexString(mHistoryCur.states));
             addHistoryRecordLocked(SystemClock.elapsedRealtime());
             mAudioOn = true;
-            mAudioOnTimer.startRunningLocked(this);
+            mAudioOnTimer.startRunningLocked(this, elapsedRealtime);
         }
-        getUidStatsLocked(uid).noteAudioTurnedOnLocked();
+        getUidStatsLocked(uid).noteAudioTurnedOnLocked(elapsedRealtime);
     }
 
     public void noteAudioOffLocked(int uid) {
         uid = mapUid(uid);
+        final long elapsedRealtime = SystemClock.elapsedRealtime();
         if (mAudioOn) {
             mHistoryCur.states &= ~HistoryItem.STATE_AUDIO_ON_FLAG;
             if (DEBUG_HISTORY) Slog.v(TAG, "Audio off to: "
                     + Integer.toHexString(mHistoryCur.states));
             addHistoryRecordLocked(SystemClock.elapsedRealtime());
             mAudioOn = false;
-            mAudioOnTimer.stopRunningLocked(this);
+            mAudioOnTimer.stopRunningLocked(this, elapsedRealtime);
         }
-        getUidStatsLocked(uid).noteAudioTurnedOffLocked();
+        getUidStatsLocked(uid).noteAudioTurnedOffLocked(elapsedRealtime);
     }
 
     public void noteVideoOnLocked(int uid) {
         uid = mapUid(uid);
+        final long elapsedRealtime = SystemClock.elapsedRealtime();
         if (!mVideoOn) {
             mHistoryCur.states |= HistoryItem.STATE_VIDEO_ON_FLAG;
             if (DEBUG_HISTORY) Slog.v(TAG, "Video on to: "
                     + Integer.toHexString(mHistoryCur.states));
             addHistoryRecordLocked(SystemClock.elapsedRealtime());
             mVideoOn = true;
-            mVideoOnTimer.startRunningLocked(this);
+            mVideoOnTimer.startRunningLocked(this, elapsedRealtime);
         }
-        getUidStatsLocked(uid).noteVideoTurnedOnLocked();
+        getUidStatsLocked(uid).noteVideoTurnedOnLocked(elapsedRealtime);
     }
 
     public void noteVideoOffLocked(int uid) {
         uid = mapUid(uid);
+        final long elapsedRealtime = SystemClock.elapsedRealtime();
         if (mVideoOn) {
             mHistoryCur.states &= ~HistoryItem.STATE_VIDEO_ON_FLAG;
             if (DEBUG_HISTORY) Slog.v(TAG, "Video off to: "
                     + Integer.toHexString(mHistoryCur.states));
             addHistoryRecordLocked(SystemClock.elapsedRealtime());
             mVideoOn = false;
-            mVideoOnTimer.stopRunningLocked(this);
+            mVideoOnTimer.stopRunningLocked(this, elapsedRealtime);
         }
-        getUidStatsLocked(uid).noteVideoTurnedOffLocked();
+        getUidStatsLocked(uid).noteVideoTurnedOffLocked(elapsedRealtime);
     }
 
     public void noteActivityResumedLocked(int uid) {
         uid = mapUid(uid);
-        getUidStatsLocked(uid).noteActivityResumedLocked();
+        getUidStatsLocked(uid).noteActivityResumedLocked(SystemClock.elapsedRealtime());
     }
 
     public void noteActivityPausedLocked(int uid) {
         uid = mapUid(uid);
-        getUidStatsLocked(uid).noteActivityPausedLocked();
+        getUidStatsLocked(uid).noteActivityPausedLocked(SystemClock.elapsedRealtime());
     }
 
     public void noteVibratorOnLocked(int uid, long durationMillis) {
@@ -2669,16 +2699,17 @@
 
     public void noteWifiRunningLocked(WorkSource ws) {
         if (!mGlobalWifiRunning) {
+            final long elapsedRealtime = SystemClock.elapsedRealtime();
             mHistoryCur.states |= HistoryItem.STATE_WIFI_RUNNING_FLAG;
             if (DEBUG_HISTORY) Slog.v(TAG, "WIFI running to: "
                     + Integer.toHexString(mHistoryCur.states));
             addHistoryRecordLocked(SystemClock.elapsedRealtime());
             mGlobalWifiRunning = true;
-            mGlobalWifiRunningTimer.startRunningLocked(this);
+            mGlobalWifiRunningTimer.startRunningLocked(this, elapsedRealtime);
             int N = ws.size();
             for (int i=0; i<N; i++) {
                 int uid = mapUid(ws.get(i));
-                getUidStatsLocked(uid).noteWifiRunningLocked();
+                getUidStatsLocked(uid).noteWifiRunningLocked(elapsedRealtime);
             }
         } else {
             Log.w(TAG, "noteWifiRunningLocked -- called while WIFI running");
@@ -2687,15 +2718,16 @@
 
     public void noteWifiRunningChangedLocked(WorkSource oldWs, WorkSource newWs) {
         if (mGlobalWifiRunning) {
+            final long elapsedRealtime = SystemClock.elapsedRealtime();
             int N = oldWs.size();
             for (int i=0; i<N; i++) {
                 int uid = mapUid(oldWs.get(i));
-                getUidStatsLocked(uid).noteWifiStoppedLocked();
+                getUidStatsLocked(uid).noteWifiStoppedLocked(elapsedRealtime);
             }
             N = newWs.size();
             for (int i=0; i<N; i++) {
                 int uid = mapUid(newWs.get(i));
-                getUidStatsLocked(uid).noteWifiRunningLocked();
+                getUidStatsLocked(uid).noteWifiRunningLocked(elapsedRealtime);
             }
         } else {
             Log.w(TAG, "noteWifiRunningChangedLocked -- called while WIFI not running");
@@ -2704,52 +2736,69 @@
 
     public void noteWifiStoppedLocked(WorkSource ws) {
         if (mGlobalWifiRunning) {
+            final long elapsedRealtime = SystemClock.elapsedRealtime();
             mHistoryCur.states &= ~HistoryItem.STATE_WIFI_RUNNING_FLAG;
             if (DEBUG_HISTORY) Slog.v(TAG, "WIFI stopped to: "
                     + Integer.toHexString(mHistoryCur.states));
-            addHistoryRecordLocked(SystemClock.elapsedRealtime());
+            addHistoryRecordLocked(elapsedRealtime);
             mGlobalWifiRunning = false;
-            mGlobalWifiRunningTimer.stopRunningLocked(this);
+            mGlobalWifiRunningTimer.stopRunningLocked(this, elapsedRealtime);
             int N = ws.size();
             for (int i=0; i<N; i++) {
                 int uid = mapUid(ws.get(i));
-                getUidStatsLocked(uid).noteWifiStoppedLocked();
+                getUidStatsLocked(uid).noteWifiStoppedLocked(elapsedRealtime);
             }
         } else {
             Log.w(TAG, "noteWifiStoppedLocked -- called while WIFI not running");
         }
     }
 
+    public void noteWifiStateLocked(int wifiState, String accessPoint) {
+        if (DEBUG) Log.i(TAG, "WiFi state -> " + wifiState);
+        if (mWifiState != wifiState) {
+            final long elapsedRealtime = SystemClock.elapsedRealtime();
+            if (mWifiState >= 0) {
+                mWifiStateTimer[mWifiState].stopRunningLocked(this, elapsedRealtime);
+            }
+            mWifiState = wifiState;
+            mWifiStateTimer[wifiState].startRunningLocked(this, elapsedRealtime);
+        }
+    }
+
     public void noteBluetoothOnLocked() {
         if (!mBluetoothOn) {
+            final long elapsedRealtime = SystemClock.elapsedRealtime();
             mHistoryCur.states |= HistoryItem.STATE_BLUETOOTH_ON_FLAG;
             if (DEBUG_HISTORY) Slog.v(TAG, "Bluetooth on to: "
                     + Integer.toHexString(mHistoryCur.states));
-            addHistoryRecordLocked(SystemClock.elapsedRealtime());
+            addHistoryRecordLocked(elapsedRealtime);
             mBluetoothOn = true;
-            mBluetoothOnTimer.startRunningLocked(this);
+            mBluetoothOnTimer.startRunningLocked(this, elapsedRealtime);
         }
     }
 
     public void noteBluetoothOffLocked() {
         if (mBluetoothOn) {
+            final long elapsedRealtime = SystemClock.elapsedRealtime();
             mHistoryCur.states &= ~HistoryItem.STATE_BLUETOOTH_ON_FLAG;
             if (DEBUG_HISTORY) Slog.v(TAG, "Bluetooth off to: "
                     + Integer.toHexString(mHistoryCur.states));
-            addHistoryRecordLocked(SystemClock.elapsedRealtime());
+            addHistoryRecordLocked(elapsedRealtime);
             mBluetoothOn = false;
-            mBluetoothOnTimer.stopRunningLocked(this);
+            mBluetoothOnTimer.stopRunningLocked(this, elapsedRealtime);
         }
     }
 
-    public void noteBluetoothActiveStateLocked(int actType) {
-        if (DEBUG) Log.i(TAG, "Bluetooth active -> " + actType);
-        if (mBluetoothActiveType != actType) {
-            if (mBluetoothActiveType >= 0) {
-                mBluetoothActiveTimer[mBluetoothActiveType].stopRunningLocked(this);
+    public void noteBluetoothStateLocked(int bluetoothState) {
+        if (DEBUG) Log.i(TAG, "Bluetooth state -> " + bluetoothState);
+        if (mBluetoothState != bluetoothState) {
+            final long elapsedRealtime = SystemClock.elapsedRealtime();
+            if (mBluetoothState >= 0) {
+                mBluetoothStateTimer[mBluetoothState].stopRunningLocked(this,
+                        elapsedRealtime);
             }
-            mBluetoothActiveType = actType;
-            mBluetoothActiveTimer[actType].startRunningLocked(this);
+            mBluetoothState = bluetoothState;
+            mBluetoothStateTimer[bluetoothState].startRunningLocked(this, elapsedRealtime);
         }
     }
 
@@ -2757,88 +2806,96 @@
 
     public void noteFullWifiLockAcquiredLocked(int uid) {
         uid = mapUid(uid);
+        final long elapsedRealtime = SystemClock.elapsedRealtime();
         if (mWifiFullLockNesting == 0) {
             mHistoryCur.states |= HistoryItem.STATE_WIFI_FULL_LOCK_FLAG;
             if (DEBUG_HISTORY) Slog.v(TAG, "WIFI full lock on to: "
                     + Integer.toHexString(mHistoryCur.states));
-            addHistoryRecordLocked(SystemClock.elapsedRealtime());
+            addHistoryRecordLocked(elapsedRealtime);
         }
         mWifiFullLockNesting++;
-        getUidStatsLocked(uid).noteFullWifiLockAcquiredLocked();
+        getUidStatsLocked(uid).noteFullWifiLockAcquiredLocked(elapsedRealtime);
     }
 
     public void noteFullWifiLockReleasedLocked(int uid) {
         uid = mapUid(uid);
+        final long elapsedRealtime = SystemClock.elapsedRealtime();
         mWifiFullLockNesting--;
         if (mWifiFullLockNesting == 0) {
             mHistoryCur.states &= ~HistoryItem.STATE_WIFI_FULL_LOCK_FLAG;
             if (DEBUG_HISTORY) Slog.v(TAG, "WIFI full lock off to: "
                     + Integer.toHexString(mHistoryCur.states));
-            addHistoryRecordLocked(SystemClock.elapsedRealtime());
+            addHistoryRecordLocked(elapsedRealtime);
         }
-        getUidStatsLocked(uid).noteFullWifiLockReleasedLocked();
+        getUidStatsLocked(uid).noteFullWifiLockReleasedLocked(elapsedRealtime);
     }
 
     int mWifiScanNesting = 0;
 
     public void noteWifiScanStartedLocked(int uid) {
         uid = mapUid(uid);
+        final long elapsedRealtime = SystemClock.elapsedRealtime();
         if (mWifiScanNesting == 0) {
             mHistoryCur.states |= HistoryItem.STATE_WIFI_SCAN_FLAG;
             if (DEBUG_HISTORY) Slog.v(TAG, "WIFI scan started for: "
                     + Integer.toHexString(mHistoryCur.states));
-            addHistoryRecordLocked(SystemClock.elapsedRealtime());
+            addHistoryRecordLocked(elapsedRealtime);
         }
         mWifiScanNesting++;
-        getUidStatsLocked(uid).noteWifiScanStartedLocked();
+        getUidStatsLocked(uid).noteWifiScanStartedLocked(elapsedRealtime);
     }
 
     public void noteWifiScanStoppedLocked(int uid) {
         uid = mapUid(uid);
+        final long elapsedRealtime = SystemClock.elapsedRealtime();
         mWifiScanNesting--;
         if (mWifiScanNesting == 0) {
             mHistoryCur.states &= ~HistoryItem.STATE_WIFI_SCAN_FLAG;
             if (DEBUG_HISTORY) Slog.v(TAG, "WIFI scan stopped for: "
                     + Integer.toHexString(mHistoryCur.states));
-            addHistoryRecordLocked(SystemClock.elapsedRealtime());
+            addHistoryRecordLocked(elapsedRealtime);
         }
-        getUidStatsLocked(uid).noteWifiScanStoppedLocked();
+        getUidStatsLocked(uid).noteWifiScanStoppedLocked(elapsedRealtime);
     }
 
     public void noteWifiBatchedScanStartedLocked(int uid, int csph) {
         uid = mapUid(uid);
-        getUidStatsLocked(uid).noteWifiBatchedScanStartedLocked(csph);
+        final long elapsedRealtime = SystemClock.elapsedRealtime();
+        getUidStatsLocked(uid).noteWifiBatchedScanStartedLocked(csph, elapsedRealtime);
     }
 
     public void noteWifiBatchedScanStoppedLocked(int uid) {
         uid = mapUid(uid);
-        getUidStatsLocked(uid).noteWifiBatchedScanStoppedLocked();
+        final long elapsedRealtime = SystemClock.elapsedRealtime();
+        getUidStatsLocked(uid).noteWifiBatchedScanStoppedLocked(elapsedRealtime);
     }
 
     int mWifiMulticastNesting = 0;
 
     public void noteWifiMulticastEnabledLocked(int uid) {
         uid = mapUid(uid);
+        final long elapsedRealtime = SystemClock.elapsedRealtime();
         if (mWifiMulticastNesting == 0) {
             mHistoryCur.states |= HistoryItem.STATE_WIFI_MULTICAST_ON_FLAG;
             if (DEBUG_HISTORY) Slog.v(TAG, "WIFI multicast on to: "
                     + Integer.toHexString(mHistoryCur.states));
-            addHistoryRecordLocked(SystemClock.elapsedRealtime());
+            addHistoryRecordLocked(elapsedRealtime);
         }
         mWifiMulticastNesting++;
-        getUidStatsLocked(uid).noteWifiMulticastEnabledLocked();
+        getUidStatsLocked(uid).noteWifiMulticastEnabledLocked(elapsedRealtime);
     }
 
     public void noteWifiMulticastDisabledLocked(int uid) {
         uid = mapUid(uid);
+        final long elapsedRealtime = SystemClock.elapsedRealtime();
         mWifiMulticastNesting--;
         if (mWifiMulticastNesting == 0) {
             mHistoryCur.states &= ~HistoryItem.STATE_WIFI_MULTICAST_ON_FLAG;
             if (DEBUG_HISTORY) Slog.v(TAG, "WIFI multicast off to: "
                     + Integer.toHexString(mHistoryCur.states));
-            addHistoryRecordLocked(SystemClock.elapsedRealtime());
+            addHistoryRecordLocked(elapsedRealtime);
         }
-        getUidStatsLocked(uid).noteWifiMulticastDisabledLocked();
+        getUidStatsLocked(uid).noteWifiMulticastDisabledLocked(elapsedRealtime);
     }
 
     public void noteFullWifiLockAcquiredFromSourceLocked(WorkSource ws) {
@@ -2973,18 +3030,28 @@
         return mGlobalWifiRunningTimer.getTotalTimeLocked(batteryRealtime, which);
     }
 
+    @Override public long getWifiStateTime(int wifiState,
+            long batteryRealtime, int which) {
+        return mWifiStateTimer[wifiState].getTotalTimeLocked(
+                batteryRealtime, 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 getBluetoothActiveTime(int actType,
+    @Override public long getBluetoothStateTime(int bluetoothState,
             long batteryRealtime, int which) {
-        return mBluetoothActiveTimer[actType].getTotalTimeLocked(
+        return mBluetoothStateTimer[bluetoothState].getTotalTimeLocked(
                 batteryRealtime, which);
     }
 
-    @Override public int getBluetoothActiveCount(int actType, int which) {
-        return mBluetoothActiveTimer[actType].getCountLocked(which);
+    @Override public int getBluetoothStateCount(int bluetoothState, int which) {
+        return mBluetoothStateTimer[bluetoothState].getCountLocked(which);
     }
 
     @Override
@@ -3119,67 +3186,67 @@
         }
 
         @Override
-        public void noteWifiRunningLocked() {
+        public void noteWifiRunningLocked(long elapsedRealtime) {
             if (!mWifiRunning) {
                 mWifiRunning = true;
                 if (mWifiRunningTimer == null) {
                     mWifiRunningTimer = new StopwatchTimer(Uid.this, WIFI_RUNNING,
                             mWifiRunningTimers, mUnpluggables);
                 }
-                mWifiRunningTimer.startRunningLocked(BatteryStatsImpl.this);
+                mWifiRunningTimer.startRunningLocked(BatteryStatsImpl.this, elapsedRealtime);
             }
         }
 
         @Override
-        public void noteWifiStoppedLocked() {
+        public void noteWifiStoppedLocked(long elapsedRealtime) {
             if (mWifiRunning) {
                 mWifiRunning = false;
-                mWifiRunningTimer.stopRunningLocked(BatteryStatsImpl.this);
+                mWifiRunningTimer.stopRunningLocked(BatteryStatsImpl.this, elapsedRealtime);
             }
         }
 
         @Override
-        public void noteFullWifiLockAcquiredLocked() {
+        public void noteFullWifiLockAcquiredLocked(long elapsedRealtime) {
             if (!mFullWifiLockOut) {
                 mFullWifiLockOut = true;
                 if (mFullWifiLockTimer == null) {
                     mFullWifiLockTimer = new StopwatchTimer(Uid.this, FULL_WIFI_LOCK,
                             mFullWifiLockTimers, mUnpluggables);
                 }
-                mFullWifiLockTimer.startRunningLocked(BatteryStatsImpl.this);
+                mFullWifiLockTimer.startRunningLocked(BatteryStatsImpl.this, elapsedRealtime);
             }
         }
 
         @Override
-        public void noteFullWifiLockReleasedLocked() {
+        public void noteFullWifiLockReleasedLocked(long elapsedRealtime) {
             if (mFullWifiLockOut) {
                 mFullWifiLockOut = false;
-                mFullWifiLockTimer.stopRunningLocked(BatteryStatsImpl.this);
+                mFullWifiLockTimer.stopRunningLocked(BatteryStatsImpl.this, elapsedRealtime);
             }
         }
 
         @Override
-        public void noteWifiScanStartedLocked() {
+        public void noteWifiScanStartedLocked(long elapsedRealtime) {
             if (!mWifiScanStarted) {
                 mWifiScanStarted = true;
                 if (mWifiScanTimer == null) {
                     mWifiScanTimer = new StopwatchTimer(Uid.this, WIFI_SCAN,
                             mWifiScanTimers, mUnpluggables);
                 }
-                mWifiScanTimer.startRunningLocked(BatteryStatsImpl.this);
+                mWifiScanTimer.startRunningLocked(BatteryStatsImpl.this, elapsedRealtime);
             }
         }
 
         @Override
-        public void noteWifiScanStoppedLocked() {
+        public void noteWifiScanStoppedLocked(long elapsedRealtime) {
             if (mWifiScanStarted) {
                 mWifiScanStarted = false;
-                mWifiScanTimer.stopRunningLocked(BatteryStatsImpl.this);
+                mWifiScanTimer.stopRunningLocked(BatteryStatsImpl.this, elapsedRealtime);
             }
         }
 
         @Override
-        public void noteWifiBatchedScanStartedLocked(int csph) {
+        public void noteWifiBatchedScanStartedLocked(int csph, long elapsedRealtime) {
             int bin = 0;
             while (csph > 8 && bin < NUM_WIFI_BATCHED_SCAN_BINS) {
                 csph = csph >> 3;
@@ -3190,41 +3257,41 @@
 
             if (mWifiBatchedScanBinStarted != NO_BATCHED_SCAN_STARTED) {
                 mWifiBatchedScanTimer[mWifiBatchedScanBinStarted].
-                        stopRunningLocked(BatteryStatsImpl.this);
+                        stopRunningLocked(BatteryStatsImpl.this, elapsedRealtime);
             }
             mWifiBatchedScanBinStarted = bin;
             if (mWifiBatchedScanTimer[bin] == null) {
                 makeWifiBatchedScanBin(bin, null);
             }
-            mWifiBatchedScanTimer[bin].startRunningLocked(BatteryStatsImpl.this);
+            mWifiBatchedScanTimer[bin].startRunningLocked(BatteryStatsImpl.this, elapsedRealtime);
         }
 
         @Override
-        public void noteWifiBatchedScanStoppedLocked() {
+        public void noteWifiBatchedScanStoppedLocked(long elapsedRealtime) {
             if (mWifiBatchedScanBinStarted != NO_BATCHED_SCAN_STARTED) {
                 mWifiBatchedScanTimer[mWifiBatchedScanBinStarted].
-                        stopRunningLocked(BatteryStatsImpl.this);
+                        stopRunningLocked(BatteryStatsImpl.this, elapsedRealtime);
                 mWifiBatchedScanBinStarted = NO_BATCHED_SCAN_STARTED;
             }
         }
 
         @Override
-        public void noteWifiMulticastEnabledLocked() {
+        public void noteWifiMulticastEnabledLocked(long elapsedRealtime) {
             if (!mWifiMulticastEnabled) {
                 mWifiMulticastEnabled = true;
                 if (mWifiMulticastTimer == null) {
                     mWifiMulticastTimer = new StopwatchTimer(Uid.this, WIFI_MULTICAST_ENABLED,
                             mWifiMulticastTimers, mUnpluggables);
                 }
-                mWifiMulticastTimer.startRunningLocked(BatteryStatsImpl.this);
+                mWifiMulticastTimer.startRunningLocked(BatteryStatsImpl.this, elapsedRealtime);
             }
         }
 
         @Override
-        public void noteWifiMulticastDisabledLocked() {
+        public void noteWifiMulticastDisabledLocked(long elapsedRealtime) {
             if (mWifiMulticastEnabled) {
                 mWifiMulticastEnabled = false;
-                mWifiMulticastTimer.stopRunningLocked(BatteryStatsImpl.this);
+                mWifiMulticastTimer.stopRunningLocked(BatteryStatsImpl.this, elapsedRealtime);
             }
         }
 
@@ -3237,19 +3304,20 @@
         }
 
         @Override
-        public void noteAudioTurnedOnLocked() {
+        public void noteAudioTurnedOnLocked(long elapsedRealtime) {
             if (!mAudioTurnedOn) {
                 mAudioTurnedOn = true;
-                createAudioTurnedOnTimerLocked().startRunningLocked(BatteryStatsImpl.this);
+                createAudioTurnedOnTimerLocked().startRunningLocked(BatteryStatsImpl.this,
+                        elapsedRealtime);
             }
         }
 
         @Override
-        public void noteAudioTurnedOffLocked() {
+        public void noteAudioTurnedOffLocked(long elapsedRealtime) {
             if (mAudioTurnedOn) {
                 mAudioTurnedOn = false;
                 if (mAudioTurnedOnTimer != null) {
-                    mAudioTurnedOnTimer.stopRunningLocked(BatteryStatsImpl.this);
+                    mAudioTurnedOnTimer.stopRunningLocked(BatteryStatsImpl.this, elapsedRealtime);
                 }
             }
         }
@@ -3263,19 +3331,20 @@
         }
 
         @Override
-        public void noteVideoTurnedOnLocked() {
+        public void noteVideoTurnedOnLocked(long elapsedRealtime) {
             if (!mVideoTurnedOn) {
                 mVideoTurnedOn = true;
-                createVideoTurnedOnTimerLocked().startRunningLocked(BatteryStatsImpl.this);
+                createVideoTurnedOnTimerLocked().startRunningLocked(BatteryStatsImpl.this,
+                        elapsedRealtime);
             }
         }
 
         @Override
-        public void noteVideoTurnedOffLocked() {
+        public void noteVideoTurnedOffLocked(long elapsedRealtime) {
             if (mVideoTurnedOn) {
                 mVideoTurnedOn = false;
                 if (mVideoTurnedOnTimer != null) {
-                    mVideoTurnedOnTimer.stopRunningLocked(BatteryStatsImpl.this);
+                    mVideoTurnedOnTimer.stopRunningLocked(BatteryStatsImpl.this, elapsedRealtime);
                 }
             }
         }
@@ -3289,15 +3358,16 @@
         }
 
         @Override
-        public void noteActivityResumedLocked() {
+        public void noteActivityResumedLocked(long elapsedRealtime) {
             // We always start, since we want multiple foreground PIDs to nest
-            createForegroundActivityTimerLocked().startRunningLocked(BatteryStatsImpl.this);
+            createForegroundActivityTimerLocked().startRunningLocked(BatteryStatsImpl.this,
+                    elapsedRealtime);
         }
 
         @Override
-        public void noteActivityPausedLocked() {
+        public void noteActivityPausedLocked(long elapsedRealtime) {
             if (mForegroundActivityTimer != null) {
-                mForegroundActivityTimer.stopRunningLocked(BatteryStatsImpl.this);
+                mForegroundActivityTimer.stopRunningLocked(BatteryStatsImpl.this, elapsedRealtime);
             }
         }
 
@@ -4874,28 +4944,28 @@
             return t;
         }
 
-        public void noteStartWakeLocked(int pid, String name, int type) {
+        public void noteStartWakeLocked(int pid, String name, int type, long elapsedRealtime) {
             StopwatchTimer t = getWakeTimerLocked(name, type);
             if (t != null) {
-                t.startRunningLocked(BatteryStatsImpl.this);
+                t.startRunningLocked(BatteryStatsImpl.this, elapsedRealtime);
             }
             if (pid >= 0 && type == WAKE_TYPE_PARTIAL) {
                 Pid p = getPidStatsLocked(pid);
                 if (p.mWakeStart == 0) {
-                    p.mWakeStart = SystemClock.elapsedRealtime();
+                    p.mWakeStart = elapsedRealtime;
                 }
             }
         }
 
-        public void noteStopWakeLocked(int pid, String name, int type) {
+        public void noteStopWakeLocked(int pid, String name, int type, long elapsedRealtime) {
             StopwatchTimer t = getWakeTimerLocked(name, type);
             if (t != null) {
-                t.stopRunningLocked(BatteryStatsImpl.this);
+                t.stopRunningLocked(BatteryStatsImpl.this, elapsedRealtime);
             }
             if (pid >= 0 && type == WAKE_TYPE_PARTIAL) {
                 Pid p = mPids.get(pid);
                 if (p != null && p.mWakeStart != 0) {
-                    p.mWakeSum += SystemClock.elapsedRealtime() - p.mWakeStart;
+                    p.mWakeSum += elapsedRealtime - p.mWakeStart;
                     p.mWakeStart = 0;
                 }
             }
@@ -4915,32 +4985,32 @@
             }
         }
 
-        public void noteStartSensor(int sensor) {
+        public void noteStartSensor(int sensor, long elapsedRealtime) {
             StopwatchTimer t = getSensorTimerLocked(sensor, true);
             if (t != null) {
-                t.startRunningLocked(BatteryStatsImpl.this);
+                t.startRunningLocked(BatteryStatsImpl.this, elapsedRealtime);
             }
         }
 
-        public void noteStopSensor(int sensor) {
+        public void noteStopSensor(int sensor, long elapsedRealtime) {
             // Don't create a timer if one doesn't already exist
             StopwatchTimer t = getSensorTimerLocked(sensor, false);
             if (t != null) {
-                t.stopRunningLocked(BatteryStatsImpl.this);
+                t.stopRunningLocked(BatteryStatsImpl.this, elapsedRealtime);
             }
         }
 
-        public void noteStartGps() {
+        public void noteStartGps(long elapsedRealtime) {
             StopwatchTimer t = getSensorTimerLocked(Sensor.GPS, true);
             if (t != null) {
-                t.startRunningLocked(BatteryStatsImpl.this);
+                t.startRunningLocked(BatteryStatsImpl.this, elapsedRealtime);
             }
         }
 
-        public void noteStopGps() {
+        public void noteStopGps(long elapsedRealtime) {
             StopwatchTimer t = getSensorTimerLocked(Sensor.GPS, false);
             if (t != null) {
-                t.stopRunningLocked(BatteryStatsImpl.this);
+                t.stopRunningLocked(BatteryStatsImpl.this, elapsedRealtime);
             }
         }
 
@@ -4973,9 +5043,12 @@
         mMobileRadioActiveTimer = new StopwatchTimer(null, -400, null, mUnpluggables);
         mWifiOnTimer = new StopwatchTimer(null, -3, null, mUnpluggables);
         mGlobalWifiRunningTimer = new StopwatchTimer(null, -4, null, mUnpluggables);
+        for (int i=0; i<NUM_WIFI_STATES; i++) {
+            mWifiStateTimer[i] = new StopwatchTimer(null, -600-i, null, mUnpluggables);
+        }
         mBluetoothOnTimer = new StopwatchTimer(null, -5, null, mUnpluggables);
-        for (int i=0; i<NUM_BLUETOOTH_ACTIVE_TYPES; i++) {
-            mBluetoothActiveTimer[i] = new StopwatchTimer(null, -500-i, null, mUnpluggables);
+        for (int i=0; i< NUM_BLUETOOTH_STATES; i++) {
+            mBluetoothStateTimer[i] = new StopwatchTimer(null, -500-i, null, mUnpluggables);
         }
         mAudioOnTimer = new StopwatchTimer(null, -6, null, mUnpluggables);
         mVideoOnTimer = new StopwatchTimer(null, -7, null, mUnpluggables);
@@ -5236,9 +5309,12 @@
         mMobileRadioActiveTimer.reset(this, false);
         mWifiOnTimer.reset(this, false);
         mGlobalWifiRunningTimer.reset(this, false);
+        for (int i=0; i<NUM_WIFI_STATES; i++) {
+            mWifiStateTimer[i].reset(this, false);
+        }
         mBluetoothOnTimer.reset(this, false);
-        for (int i=0; i<NUM_BLUETOOTH_ACTIVE_TYPES; i++) {
-            mBluetoothActiveTimer[i].reset(this, false);
+        for (int i=0; i< NUM_BLUETOOTH_STATES; i++) {
+            mBluetoothStateTimer[i].reset(this, false);
         }
 
         for (int i=0; i<mUidStats.size(); i++) {
@@ -5951,7 +6027,7 @@
             stream.close();
 
             readSummaryFromParcel(in);
-        } catch(java.io.IOException e) {
+        } catch(Exception e) {
             Slog.e("BatteryStats", "Error reading battery statistics", e);
         }
 
@@ -6137,10 +6213,13 @@
         mWifiOnTimer.readSummaryFromParcelLocked(in);
         mGlobalWifiRunning = false;
         mGlobalWifiRunningTimer.readSummaryFromParcelLocked(in);
+        for (int i=0; i<NUM_WIFI_STATES; i++) {
+            mWifiStateTimer[i].readSummaryFromParcelLocked(in);
+        }
         mBluetoothOn = false;
         mBluetoothOnTimer.readSummaryFromParcelLocked(in);
-        for (int i=0; i<NUM_BLUETOOTH_ACTIVE_TYPES; i++) {
-            mBluetoothActiveTimer[i].readSummaryFromParcelLocked(in);
+        for (int i=0; i< NUM_BLUETOOTH_STATES; i++) {
+            mBluetoothStateTimer[i].readSummaryFromParcelLocked(in);
         }
 
         int NKW = in.readInt();
@@ -6156,6 +6235,9 @@
         }
 
         sNumSpeedSteps = in.readInt();
+        if (sNumSpeedSteps < 0 || sNumSpeedSteps > 100) {
+            throw new BadParcelableException("Bad speed steps in data: " + sNumSpeedSteps);
+        }
 
         final int NU = in.readInt();
         if (NU > 10000) {
@@ -6360,9 +6442,12 @@
         mMobileRadioActiveTimer.writeSummaryFromParcelLocked(out, NOWREAL);
         mWifiOnTimer.writeSummaryFromParcelLocked(out, NOWREAL);
         mGlobalWifiRunningTimer.writeSummaryFromParcelLocked(out, NOWREAL);
+        for (int i=0; i<NUM_WIFI_STATES; i++) {
+            mWifiStateTimer[i].writeSummaryFromParcelLocked(out, NOWREAL);
+        }
         mBluetoothOnTimer.writeSummaryFromParcelLocked(out, NOWREAL);
-        for (int i=0; i<NUM_BLUETOOTH_ACTIVE_TYPES; i++) {
-            mBluetoothActiveTimer[i].writeSummaryFromParcelLocked(out, NOWREAL);
+        for (int i=0; i< NUM_BLUETOOTH_STATES; i++) {
+            mBluetoothStateTimer[i].writeSummaryFromParcelLocked(out, NOWREAL);
         }
 
         out.writeInt(mKernelWakelockStats.size());
@@ -6601,10 +6686,14 @@
         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_ACTIVE_TYPES; i++) {
-            mBluetoothActiveTimer[i] = new StopwatchTimer(null, -500-i,
+        for (int i=0; i< NUM_BLUETOOTH_STATES; i++) {
+            mBluetoothStateTimer[i] = new StopwatchTimer(null, -500-i,
                     null, mUnpluggables, in);
         }
         mUptime = in.readLong();
@@ -6712,9 +6801,12 @@
         mMobileRadioActiveTimer.writeToParcel(out, batteryRealtime);
         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_ACTIVE_TYPES; i++) {
-            mBluetoothActiveTimer[i].writeToParcel(out, batteryRealtime);
+        for (int i=0; i< NUM_BLUETOOTH_STATES; i++) {
+            mBluetoothStateTimer[i].writeToParcel(out, batteryRealtime);
         }
         out.writeLong(mUptime);
         out.writeLong(mUptimeStart);
@@ -6817,11 +6909,15 @@
             mWifiOnTimer.logState(pr, "  ");
             pr.println("*** WifiRunning timer:");
             mGlobalWifiRunningTimer.logState(pr, "  ");
+            for (int i=0; i<NUM_WIFI_STATES; i++) {
+                pr.println("*** Wifi state #" + i + ":");
+                mWifiStateTimer[i].logState(pr, "  ");
+            }
             pr.println("*** Bluetooth timer:");
             mBluetoothOnTimer.logState(pr, "  ");
-            for (int i=0; i<NUM_BLUETOOTH_ACTIVE_TYPES; i++) {
+            for (int i=0; i< NUM_BLUETOOTH_STATES; i++) {
                 pr.println("*** Bluetooth active type #" + i + ":");
-                mBluetoothActiveTimer[i].logState(pr, "  ");
+                mBluetoothStateTimer[i].logState(pr, "  ");
             }
         }
         super.dumpLocked(context, pw, isUnpluggedOnly, reqUid, historyOnly);
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 77c5c18..100f71d 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -761,13 +761,6 @@
         mOptions.add(opt);
     }
 
-    /*
-     * We don't have /tmp on the device, but we often have an SD card.  Apps
-     * shouldn't use this, but some test suites might want to exercise it.
-     */
-    opt.optionString = "-Djava.io.tmpdir=/sdcard";
-    mOptions.add(opt);
-
     initArgs.version = JNI_VERSION_1_4;
     initArgs.options = mOptions.editArray();
     initArgs.nOptions = mOptions.size();
diff --git a/core/jni/android_view_DisplayList.cpp b/core/jni/android_view_DisplayList.cpp
index de68b97..e47e23c 100644
--- a/core/jni/android_view_DisplayList.cpp
+++ b/core/jni/android_view_DisplayList.cpp
@@ -142,10 +142,10 @@
     displayList->setCastsShadow(castsShadow);
 }
 
-static void android_view_DisplayList_setSharesGlobalCamera(JNIEnv* env,
-        jobject clazz, jlong displayListPtr, jboolean sharesGlobalCamera) {
+static void android_view_DisplayList_setUsesGlobalCamera(JNIEnv* env,
+        jobject clazz, jlong displayListPtr, jboolean usesGlobalCamera) {
     DisplayList* displayList = reinterpret_cast<DisplayList*>(displayListPtr);
-    displayList->setSharesGlobalCamera(sharesGlobalCamera);
+    displayList->setUsesGlobalCamera(usesGlobalCamera);
 }
 
 static void android_view_DisplayList_setAlpha(JNIEnv* env,
@@ -420,7 +420,7 @@
     { "nSetOutline",           "(JJ)V",  (void*) android_view_DisplayList_setOutline },
     { "nSetClipToOutline",     "(JZ)V",  (void*) android_view_DisplayList_setClipToOutline },
     { "nSetCastsShadow",       "(JZ)V",  (void*) android_view_DisplayList_setCastsShadow },
-    { "nSetSharesGlobalCamera","(JZ)V",  (void*) android_view_DisplayList_setSharesGlobalCamera },
+    { "nSetUsesGlobalCamera",  "(JZ)V",  (void*) android_view_DisplayList_setUsesGlobalCamera },
     { "nSetAlpha",             "(JF)V",  (void*) android_view_DisplayList_setAlpha },
     { "nSetHasOverlappingRendering", "(JZ)V",
             (void*) android_view_DisplayList_setHasOverlappingRendering },
diff --git a/core/jni/android_view_ThreadedRenderer.cpp b/core/jni/android_view_ThreadedRenderer.cpp
index e86a2d4..bc5c06e 100644
--- a/core/jni/android_view_ThreadedRenderer.cpp
+++ b/core/jni/android_view_ThreadedRenderer.cpp
@@ -76,20 +76,20 @@
 
 static void android_view_ThreadedRenderer_deleteProxy(JNIEnv* env, jobject clazz,
         jlong proxyPtr) {
-    RenderProxy* proxy = reinterpret_cast<RenderProxy*>( proxyPtr);
+    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
     delete proxy;
 }
 
 static jboolean android_view_ThreadedRenderer_initialize(JNIEnv* env, jobject clazz,
         jlong proxyPtr, jobject jsurface) {
-    RenderProxy* proxy = reinterpret_cast<RenderProxy*>( proxyPtr);
+    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
     sp<ANativeWindow> window = android_view_Surface_getNativeWindow(env, jsurface);
     return proxy->initialize(window.get());
 }
 
 static void android_view_ThreadedRenderer_updateSurface(JNIEnv* env, jobject clazz,
         jlong proxyPtr, jobject jsurface) {
-    RenderProxy* proxy = reinterpret_cast<RenderProxy*>( proxyPtr);
+    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
     sp<ANativeWindow> window;
     if (jsurface) {
         window = android_view_Surface_getNativeWindow(env, jsurface);
@@ -99,45 +99,74 @@
 
 static void android_view_ThreadedRenderer_setup(JNIEnv* env, jobject clazz,
         jlong proxyPtr, jint width, jint height) {
-    RenderProxy* proxy = reinterpret_cast<RenderProxy*>( proxyPtr);
+    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
     proxy->setup(width, height);
 }
 
 static void android_view_ThreadedRenderer_drawDisplayList(JNIEnv* env, jobject clazz,
         jlong proxyPtr, jlong displayListPtr, jint dirtyLeft, jint dirtyTop,
         jint dirtyRight, jint dirtyBottom) {
-    RenderProxy* proxy = reinterpret_cast<RenderProxy*>( proxyPtr);
-    DisplayList* displayList = reinterpret_cast<DisplayList*>( displayListPtr);
+    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
+    DisplayList* displayList = reinterpret_cast<DisplayList*>(displayListPtr);
     proxy->drawDisplayList(displayList, dirtyLeft, dirtyTop, dirtyRight, dirtyBottom);
 }
 
 static void android_view_ThreadedRenderer_destroyCanvas(JNIEnv* env, jobject clazz,
         jlong proxyPtr) {
-    RenderProxy* proxy = reinterpret_cast<RenderProxy*>( proxyPtr);
+    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
     proxy->destroyCanvas();
 }
 
 static void android_view_ThreadedRenderer_attachFunctor(JNIEnv* env, jobject clazz,
         jlong proxyPtr, jlong functorPtr) {
-    RenderProxy* proxy = reinterpret_cast<RenderProxy*>( proxyPtr);
+    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
     Functor* functor = reinterpret_cast<Functor*>(functorPtr);
     proxy->attachFunctor(functor);
 }
 
 static void android_view_ThreadedRenderer_detachFunctor(JNIEnv* env, jobject clazz,
         jlong proxyPtr, jlong functorPtr) {
-    RenderProxy* proxy = reinterpret_cast<RenderProxy*>( proxyPtr);
+    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
     Functor* functor = reinterpret_cast<Functor*>(functorPtr);
     proxy->detachFunctor(functor);
 }
 
 static void android_view_ThreadedRenderer_runWithGlContext(JNIEnv* env, jobject clazz,
         jlong proxyPtr, jobject jrunnable) {
-    RenderProxy* proxy = reinterpret_cast<RenderProxy*>( proxyPtr);
+    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
     RenderTask* task = new JavaTask(env, jrunnable);
     proxy->runWithGlContext(task);
 }
 
+static jlong android_view_ThreadedRenderer_createDisplayListLayer(JNIEnv* env, jobject clazz,
+        jlong proxyPtr, jint width, jint height) {
+    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
+    DeferredLayerUpdater* layer = proxy->createDisplayListLayer(width, height);
+    return reinterpret_cast<jlong>(layer);
+}
+
+static jlong android_view_ThreadedRenderer_createTextureLayer(JNIEnv* env, jobject clazz,
+        jlong proxyPtr) {
+    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
+    DeferredLayerUpdater* layer = proxy->createTextureLayer();
+    return reinterpret_cast<jlong>(layer);
+}
+
+static jboolean android_view_ThreadedRenderer_copyLayerInto(JNIEnv* env, jobject clazz,
+        jlong proxyPtr, jlong layerPtr, jlong bitmapPtr) {
+    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
+    DeferredLayerUpdater* layer = reinterpret_cast<DeferredLayerUpdater*>(layerPtr);
+    SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapPtr);
+    return proxy->copyLayerInto(layer, bitmap);
+}
+
+static void android_view_ThreadedRenderer_destroyLayer(JNIEnv* env, jobject clazz,
+        jlong proxyPtr, jlong layerPtr) {
+    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
+    DeferredLayerUpdater* layer = reinterpret_cast<DeferredLayerUpdater*>(layerPtr);
+    proxy->destroyLayer(layer);
+}
+
 #endif
 
 // ----------------------------------------------------------------------------
@@ -159,6 +188,10 @@
     { "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 },
+    { "nCopyLayerInto", "(JJJ)Z", (void*) android_view_ThreadedRenderer_copyLayerInto },
+    { "nDestroyLayer", "(JJ)V", (void*) android_view_ThreadedRenderer_destroyLayer },
 #endif
 };
 
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 943cbfe..30e6161 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1214,7 +1214,7 @@
         android:permissionGroup="android.permission-group.STORAGE"
         android:label="@string/permlab_manageDocs"
         android:description="@string/permdesc_manageDocs"
-        android:protectionLevel="signature|system" />
+        android:protectionLevel="signature" />
 
     <!-- ================================== -->
     <!-- Permissions for screenlock         -->
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 2d9c959..c5524d7 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -2123,6 +2123,10 @@
         <!-- scale of the view in the y direction. -->
         <attr name="scaleY" format="float" />
 
+        <!-- Defines whether the View casts a shadow when it has a 3D rotation or Z
+             translation.-->
+        <attr name="castsShadow" format="boolean" />
+
         <!-- Determines which side the vertical scroll bar should be placed on. -->
         <attr name="verticalScrollbarPosition">
             <!-- Place the scroll bar wherever the system default determines. -->
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 722f965..794d6a5 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2108,6 +2108,7 @@
   <public type="attr" name="toSceneName" />
   <public type="attr" name="sharedElementName" />
   <public type="attr" name="transitionGroup" />
+  <public type="attr" name="castsShadow" />
 
   <public type="id" name="shared_element_name" />
 
diff --git a/libs/hwui/Caches.cpp b/libs/hwui/Caches.cpp
index 8bd9de0..21cf658 100644
--- a/libs/hwui/Caches.cpp
+++ b/libs/hwui/Caches.cpp
@@ -685,7 +685,8 @@
     propertyDirtyViewport = false;
     propertyEnable3d = false;
     propertyCameraDistance = 1.0f;
-    propertyShadowStrength = 0x3f;
+    propertyAmbientShadowStrength = 0x3f;
+    propertySpotShadowStrength = 0x3f;
 
     propertyLightPosXScale = 0.5f;
     propertyLightPosYScale = 0.0f;
@@ -704,9 +705,13 @@
         propertyDirtyViewport = true;
         ALOGD("camera dist multiplier = %.2f", propertyCameraDistance);
         return;
-    } else if (!strcmp(name, "shadowStrength")) {
-        propertyShadowStrength = atoi(value);
-        ALOGD("shadow strength = 0x%x out of 0xff", propertyShadowStrength);
+    } else if (!strcmp(name, "ambientShadowStrength")) {
+        propertyAmbientShadowStrength = atoi(value);
+        ALOGD("ambient shadow strength = 0x%x out of 0xff", propertyAmbientShadowStrength);
+        return;
+    } else if (!strcmp(name, "spotShadowStrength")) {
+        propertySpotShadowStrength = atoi(value);
+        ALOGD("spot shadow strength = 0x%x out of 0xff", propertySpotShadowStrength);
         return;
     } else if (!strcmp(name, "lightPosXScale")) {
         propertyLightPosXScale = fmin(fmax(atof(value), 0.0), 1.0);
diff --git a/libs/hwui/Caches.h b/libs/hwui/Caches.h
index e7ba9ac..2cc15cc 100644
--- a/libs/hwui/Caches.h
+++ b/libs/hwui/Caches.h
@@ -367,7 +367,8 @@
     float propertyLightPosXScale;
     float propertyLightPosYScale;
     float propertyLightPosZScale;
-    int propertyShadowStrength;
+    int propertyAmbientShadowStrength;
+    int propertySpotShadowStrength;
 
 private:
     enum OverdrawColorSet {
diff --git a/libs/hwui/DeferredLayerUpdater.cpp b/libs/hwui/DeferredLayerUpdater.cpp
index 5d3d393..efb1298 100644
--- a/libs/hwui/DeferredLayerUpdater.cpp
+++ b/libs/hwui/DeferredLayerUpdater.cpp
@@ -123,27 +123,5 @@
     }
 }
 
-void DeferredLayerUpdater::applyDeferred(DeferredLayerUpdater* deferredApply) {
-    // Default assignment operator doesn't quite work, and fails due to mCaches anyway
-    deferredApply->mWidth = mWidth;
-    deferredApply->mHeight = mHeight;
-    deferredApply->mBlend = mBlend;
-    deferredApply->mAlpha = mAlpha;
-    deferredApply->mMode = mMode;
-    deferredApply->mDirtyRect.set(mDirtyRect);
-    deferredApply->mDisplayList = mDisplayList;
-    deferredApply->mSurfaceTexture = mSurfaceTexture;
-    deferredApply->mNeedsGLContextAttach = mNeedsGLContextAttach;
-    deferredApply->mUpdateTexImage = mUpdateTexImage;
-    deferredApply->setColorFilter(mColorFilter);
-    deferredApply->setTransform(mTransform);
-
-    mDisplayList = 0;
-    mDirtyRect.setEmpty();
-    mTransform = 0;
-    mNeedsGLContextAttach = false;
-    mUpdateTexImage = false;
-}
-
 } /* namespace uirenderer */
 } /* namespace android */
diff --git a/libs/hwui/DeferredLayerUpdater.h b/libs/hwui/DeferredLayerUpdater.h
index 9800c2f..624db2c 100644
--- a/libs/hwui/DeferredLayerUpdater.h
+++ b/libs/hwui/DeferredLayerUpdater.h
@@ -82,7 +82,6 @@
     ANDROID_API void setColorFilter(SkColorFilter* colorFilter);
 
     ANDROID_API bool apply();
-    ANDROID_API void applyDeferred(DeferredLayerUpdater* deferredApply);
 
     ANDROID_API Layer* backingLayer() {
         return mLayer;
diff --git a/libs/hwui/DisplayList.cpp b/libs/hwui/DisplayList.cpp
index a5e66fa..6144f3d 100644
--- a/libs/hwui/DisplayList.cpp
+++ b/libs/hwui/DisplayList.cpp
@@ -232,7 +232,7 @@
     mOutline.rewind();
     mClipToOutline = false;
     mCastsShadow = false;
-    mSharesGlobalCamera = false;
+    mUsesGlobalCamera = false;
     mAlpha = 1;
     mHasOverlappingRendering = true;
     mTranslationX = 0;
diff --git a/libs/hwui/DisplayList.h b/libs/hwui/DisplayList.h
index c3d9fd7..9487fae 100644
--- a/libs/hwui/DisplayList.h
+++ b/libs/hwui/DisplayList.h
@@ -196,8 +196,8 @@
         mCastsShadow = castsShadow;
     }
 
-    void setSharesGlobalCamera(bool sharesGlobalCamera) {
-        mSharesGlobalCamera = sharesGlobalCamera;
+    void setUsesGlobalCamera(bool usesGlobalCamera) {
+        mUsesGlobalCamera = usesGlobalCamera;
     }
 
     void setProjectBackwards(bool shouldProject) {
@@ -621,7 +621,7 @@
     SkPath mOutline;
     bool mClipToOutline;
     bool mCastsShadow;
-    bool mSharesGlobalCamera; // TODO: respect value when rendering
+    bool mUsesGlobalCamera; // TODO: respect value when rendering
     float mAlpha;
     bool mHasOverlappingRendering;
     float mTranslationX, mTranslationY, mTranslationZ;
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index fee916b..9b253a6 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -3214,7 +3214,6 @@
     mCaches.enableScissor();
 
     SkPaint paint;
-    paint.setARGB(mCaches.propertyShadowStrength, 0, 0, 0);
     paint.setAntiAlias(true); // want to use AlphaVertex
 
     // tessellate caster outline into a 2d polygon
@@ -3238,19 +3237,25 @@
     }
 
     // draw caster's shadows
-    VertexBuffer ambientShadowVertexBuffer;
-    ShadowTessellator::tessellateAmbientShadow(casterPolygon, casterVertexCount,
-            ambientShadowVertexBuffer);
-    drawVertexBuffer(ambientShadowVertexBuffer, &paint);
+    if (mCaches.propertyAmbientShadowStrength > 0) {
+        paint.setARGB(mCaches.propertyAmbientShadowStrength, 0, 0, 0);
+        VertexBuffer ambientShadowVertexBuffer;
+        ShadowTessellator::tessellateAmbientShadow(casterPolygon, casterVertexCount,
+                ambientShadowVertexBuffer);
+        drawVertexBuffer(ambientShadowVertexBuffer, &paint);
+    }
 
-    VertexBuffer spotShadowVertexBuffer;
-    Vector3 lightPosScale(mCaches.propertyLightPosXScale,
-            mCaches.propertyLightPosYScale, mCaches.propertyLightPosZScale);
-    ShadowTessellator::tessellateSpotShadow(casterPolygon, casterVertexCount,
-            lightPosScale, *currentTransform(), getWidth(), getHeight(),
-            spotShadowVertexBuffer);
+    if (mCaches.propertySpotShadowStrength > 0) {
+        paint.setARGB(mCaches.propertySpotShadowStrength, 0, 0, 0);
+        VertexBuffer spotShadowVertexBuffer;
+        Vector3 lightPosScale(mCaches.propertyLightPosXScale,
+                mCaches.propertyLightPosYScale, mCaches.propertyLightPosZScale);
+        ShadowTessellator::tessellateSpotShadow(casterPolygon, casterVertexCount,
+                lightPosScale, *currentTransform(), getWidth(), getHeight(),
+                spotShadowVertexBuffer);
 
-    drawVertexBuffer(spotShadowVertexBuffer, &paint);
+        drawVertexBuffer(spotShadowVertexBuffer, &paint);
+    }
 
     return DrawGlInfo::kStatusDrew;
 }
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index 4e665d9..fe781bd 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -24,6 +24,8 @@
 
 #include "RenderThread.h"
 #include "../Caches.h"
+#include "../DeferredLayerUpdater.h"
+#include "../LayerRenderer.h"
 #include "../OpenGLRenderer.h"
 #include "../Stencil.h"
 
@@ -371,6 +373,17 @@
     mCanvas->setViewport(width, height);
 }
 
+void CanvasContext::processLayerUpdates(const Vector<DeferredLayerUpdater*>* layerUpdaters) {
+    mGlobalContext->makeCurrent(mEglSurface);
+    for (size_t i = 0; i < layerUpdaters->size(); i++) {
+        DeferredLayerUpdater* update = layerUpdaters->itemAt(i);
+        LOG_ALWAYS_FATAL_IF(!update->apply(), "Failed to update layer!");
+        if (update->backingLayer()->deferredUpdateScheduled) {
+            mCanvas->pushLayerUpdate(update->backingLayer());
+        }
+    }
+}
+
 void CanvasContext::drawDisplayList(DisplayList* displayList, Rect* dirty) {
     LOG_ALWAYS_FATAL_IF(!mCanvas || mEglSurface == EGL_NO_SURFACE,
             "drawDisplayList called on a context with no canvas or surface!");
@@ -462,14 +475,23 @@
     mRenderThread.queueDelayed(&mInvokeFunctorsTask, delayMs);
 }
 
+bool CanvasContext::copyLayerInto(DeferredLayerUpdater* layer, SkBitmap* bitmap) {
+    requireGlContext();
+    layer->apply();
+    return LayerRenderer::copyLayer(layer->backingLayer(), bitmap);
+}
+
 void CanvasContext::runWithGlContext(RenderTask* task) {
+    requireGlContext();
+    task->run();
+}
+
+void CanvasContext::requireGlContext() {
     if (mEglSurface != EGL_NO_SURFACE) {
         mGlobalContext->makeCurrent(mEglSurface);
     } else {
         mGlobalContext->usePBufferSurface();
     }
-
-    task->run();
 }
 
 } /* namespace renderthread */
diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h
index 3197df3..5fac582 100644
--- a/libs/hwui/renderthread/CanvasContext.h
+++ b/libs/hwui/renderthread/CanvasContext.h
@@ -19,7 +19,9 @@
 
 #include <cutils/compiler.h>
 #include <EGL/egl.h>
+#include <SkBitmap.h>
 #include <utils/Functor.h>
+#include <utils/Vector.h>
 
 #include "RenderTask.h"
 
@@ -28,6 +30,7 @@
 namespace android {
 namespace uirenderer {
 
+class DeferredLayerUpdater;
 class DisplayList;
 class OpenGLRenderer;
 class Rect;
@@ -59,9 +62,12 @@
     bool initialize(EGLNativeWindowType window);
     void updateSurface(EGLNativeWindowType window);
     void setup(int width, int height);
+    void processLayerUpdates(const Vector<DeferredLayerUpdater*>* layerUpdaters);
     void drawDisplayList(DisplayList* displayList, Rect* dirty);
     void destroyCanvas();
 
+    bool copyLayerInto(DeferredLayerUpdater* layer, SkBitmap* bitmap);
+
     void attachFunctor(Functor* functor);
     void detachFunctor(Functor* functor);
 
@@ -78,6 +84,8 @@
     void removeFunctorsTask();
     void queueFunctorsTask(int delayMs = FUNCTOR_PROCESS_DELAY);
 
+    void requireGlContext();
+
     GlobalContext* mGlobalContext;
     RenderThread& mRenderThread;
     EGLSurface mEglSurface;
diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp
index 34f1961..0c667fd 100644
--- a/libs/hwui/renderthread/RenderProxy.cpp
+++ b/libs/hwui/renderthread/RenderProxy.cpp
@@ -22,7 +22,9 @@
 #include "RenderTask.h"
 #include "RenderThread.h"
 
+#include "../DeferredLayerUpdater.h"
 #include "../DisplayList.h"
+#include "../LayerRenderer.h"
 #include "../Rect.h"
 
 namespace android {
@@ -31,6 +33,7 @@
 
 #define ARGS(method) method ## Args
 
+#define CREATE_BRIDGE0(name) CREATE_BRIDGE(name,,,,,,,,)
 #define CREATE_BRIDGE1(name, a1) CREATE_BRIDGE(name, a1,,,,,,,)
 #define CREATE_BRIDGE2(name, a1, a2) CREATE_BRIDGE(name, a1,a2,,,,,,)
 #define CREATE_BRIDGE3(name, a1, a2, a3) CREATE_BRIDGE(name, a1,a2,a3,,,,,)
@@ -114,13 +117,14 @@
     post(task);
 }
 
-CREATE_BRIDGE3(drawDisplayList, CanvasContext* context, DisplayList* displayList,
-        Rect dirty) {
+CREATE_BRIDGE4(drawDisplayList, CanvasContext* context, DisplayList* displayList,
+        Rect dirty, const Vector<DeferredLayerUpdater*>* layerUpdates) {
     Rect* dirty = &args->dirty;
     if (dirty->bottom == -1 && dirty->left == -1 &&
             dirty->top == -1 && dirty->right == -1) {
         dirty = 0;
     }
+    args->context->processLayerUpdates(args->layerUpdates);
     args->context->drawDisplayList(args->displayList, dirty);
     return NULL;
 }
@@ -131,6 +135,7 @@
     args->context = mContext;
     args->displayList = displayList;
     args->dirty.set(dirtyLeft, dirtyTop, dirtyRight, dirtyBottom);
+    args->layerUpdates = &mLayers;
     // TODO: Switch to post() once some form of thread safety strategy is in place
     postAndWait(task);
 }
@@ -182,6 +187,70 @@
     postAndWait(task);
 }
 
+CREATE_BRIDGE2(createDisplayListLayer, int width, int height) {
+    Layer* layer = LayerRenderer::createRenderLayer(args->width, args->height);
+    if (!layer) return 0;
+
+    OpenGLRenderer* renderer = new LayerRenderer(layer);
+    renderer->initProperties();
+    return new DeferredLayerUpdater(layer, renderer);
+}
+
+DeferredLayerUpdater* RenderProxy::createDisplayListLayer(int width, int height) {
+    SETUP_TASK(createDisplayListLayer);
+    args->width = width;
+    args->height = height;
+    void* retval = postAndWait(task);
+    DeferredLayerUpdater* layer = reinterpret_cast<DeferredLayerUpdater*>(retval);
+    mLayers.push(layer);
+    return layer;
+}
+
+CREATE_BRIDGE0(createTextureLayer) {
+    Layer* layer = LayerRenderer::createTextureLayer();
+    if (!layer) return 0;
+    return new DeferredLayerUpdater(layer);
+}
+
+DeferredLayerUpdater* RenderProxy::createTextureLayer() {
+    SETUP_TASK(createTextureLayer);
+    void* retval = postAndWait(task);
+    DeferredLayerUpdater* layer = reinterpret_cast<DeferredLayerUpdater*>(retval);
+    mLayers.push(layer);
+    return layer;
+}
+
+CREATE_BRIDGE1(destroyLayer, Layer* layer) {
+    LayerRenderer::destroyLayer(args->layer);
+    return NULL;
+}
+
+CREATE_BRIDGE3(copyLayerInto, CanvasContext* context, DeferredLayerUpdater* layer,
+        SkBitmap* bitmap) {
+    bool success = args->context->copyLayerInto(args->layer, args->bitmap);
+    return (void*) success;
+}
+
+bool RenderProxy::copyLayerInto(DeferredLayerUpdater* layer, SkBitmap* bitmap) {
+    SETUP_TASK(copyLayerInto);
+    args->context = mContext;
+    args->layer = layer;
+    args->bitmap = bitmap;
+    return (bool) postAndWait(task);
+}
+
+void RenderProxy::destroyLayer(DeferredLayerUpdater* layer) {
+    for (size_t i = 0; i < mLayers.size(); i++) {
+        if (mLayers[i] == layer) {
+            mLayers.removeAt(i);
+            break;
+        }
+    }
+    SETUP_TASK(destroyLayer);
+    args->layer = layer->detachBackingLayer();
+    post(task);
+}
+
 MethodInvokeRenderTask* RenderProxy::createTask(RunnableMethod method) {
     // TODO: Consider having a small pool of these to avoid alloc churn
     return new MethodInvokeRenderTask(method);
diff --git a/libs/hwui/renderthread/RenderProxy.h b/libs/hwui/renderthread/RenderProxy.h
index 1ad0c2d..8ff3d63 100644
--- a/libs/hwui/renderthread/RenderProxy.h
+++ b/libs/hwui/renderthread/RenderProxy.h
@@ -21,15 +21,19 @@
 
 #include <cutils/compiler.h>
 #include <EGL/egl.h>
+#include <SkBitmap.h>
 #include <utils/Condition.h>
 #include <utils/Functor.h>
 #include <utils/Mutex.h>
 #include <utils/StrongPointer.h>
+#include <utils/Vector.h>
 
 namespace android {
 namespace uirenderer {
 
+class DeferredLayerUpdater;
 class DisplayList;
+class Layer;
 class Rect;
 
 namespace renderthread {
@@ -64,6 +68,11 @@
 
     ANDROID_API void runWithGlContext(RenderTask* task);
 
+    ANDROID_API DeferredLayerUpdater* createDisplayListLayer(int width, int height);
+    ANDROID_API DeferredLayerUpdater* createTextureLayer();
+    ANDROID_API bool copyLayerInto(DeferredLayerUpdater* layer, SkBitmap* bitmap);
+    ANDROID_API void destroyLayer(DeferredLayerUpdater* layer);
+
 private:
     RenderThread& mRenderThread;
     CanvasContext* mContext;
@@ -71,6 +80,8 @@
     Mutex mSyncMutex;
     Condition mSyncCondition;
 
+    Vector<DeferredLayerUpdater*> mLayers;
+
     void destroyContext();
 
     MethodInvokeRenderTask* createTask(RunnableMethod method);
diff --git a/media/java/android/media/MediaScanner.java b/media/java/android/media/MediaScanner.java
index 01485b8..72f3e1a 100644
--- a/media/java/android/media/MediaScanner.java
+++ b/media/java/android/media/MediaScanner.java
@@ -1426,7 +1426,7 @@
         }
 
         int firstSlash = path.lastIndexOf('/');
-        if (firstSlash == 0) {
+        if (firstSlash <= 0) {
             return false;
         }
         String parent = path.substring(0,  firstSlash);
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardViewManager.java b/packages/Keyguard/src/com/android/keyguard/KeyguardViewManager.java
index baf520e..43165eb 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardViewManager.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardViewManager.java
@@ -330,7 +330,7 @@
 
     private boolean allowNotificationsOnSecureKeyguard() {
         ContentResolver cr = mContext.getContentResolver();
-        return Settings.Secure.getInt(cr, Settings.Secure.LOCK_SCREEN_ALLOW_NOTIFICATIONS, 0) == 1;
+        return Settings.Global.getInt(cr, Settings.Global.LOCK_SCREEN_SHOW_NOTIFICATIONS, 0) == 1;
     }
 
     private KeyguardViewBase inflateKeyguardView(Bundle options, int layoutId) {
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardViewMediator.java b/packages/Keyguard/src/com/android/keyguard/KeyguardViewMediator.java
index 914fdc4..e0ee4e0 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardViewMediator.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardViewMediator.java
@@ -151,13 +151,13 @@
 
     /**
      * Allow the user to expand the status bar when a SECURE keyguard is engaged
-     * and {@link Settings.Secure#LOCK_SCREEN_ALLOW_NOTIFICATIONS} is set
+     * and {@link Settings.Global#LOCK_SCREEN_SHOW_NOTIFICATIONS} is set
      * (private notifications will be masked).
      */
     private static final boolean ENABLE_SECURE_STATUS_BAR_EXPAND = true;
 
     /**
-     * Default value of {@link Settings.Secure#LOCK_SCREEN_ALLOW_NOTIFICATIONS}.
+     * Default value of {@link Settings.Global#LOCK_SCREEN_SHOW_NOTIFICATIONS}.
      */
     private static final boolean ALLOW_NOTIFICATIONS_DEFAULT = false;
 
@@ -258,7 +258,7 @@
     private int mLockSoundStreamId;
 
     /**
-     * Tracks value of {@link Settings.Secure#LOCK_SCREEN_ALLOW_NOTIFICATIONS}.
+     * Tracks value of {@link Settings.Global#LOCK_SCREEN_SHOW_NOTIFICATIONS}.
      */
     private boolean mAllowNotificationsWhenSecure;
 
@@ -913,9 +913,9 @@
 
         // note whether notification access should be allowed
         mAllowNotificationsWhenSecure = ENABLE_SECURE_STATUS_BAR_EXPAND
-                && 0 != Settings.Secure.getInt(
+                && 0 != Settings.Global.getInt(
                         mContext.getContentResolver(),
-                        Settings.Secure.LOCK_SCREEN_ALLOW_NOTIFICATIONS,
+                        Settings.Global.LOCK_SCREEN_SHOW_NOTIFICATIONS,
                         ALLOW_NOTIFICATIONS_DEFAULT ? 1 : 0);
 
         // if the keyguard is already showing, don't bother
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index 649b51b..7ff52de 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -46,6 +46,7 @@
 import android.service.notification.StatusBarNotification;
 import android.text.TextUtils;
 import android.util.Log;
+import android.util.SparseBooleanArray;
 import android.view.Display;
 import android.view.IWindowManager;
 import android.view.LayoutInflater;
@@ -131,7 +132,10 @@
     protected IDreamManager mDreamManager;
     PowerManager mPowerManager;
     protected int mRowHeight;
-    private boolean mPublicMode = false;
+
+    // public mode, private notifications, etc
+    private boolean mLockscreenPublicMode = false;
+    private final SparseBooleanArray mUsersAllowingPrivateNotifications = new SparseBooleanArray();
 
     // UI-specific methods
 
@@ -159,7 +163,7 @@
         return mDeviceProvisioned;
     }
 
-    private ContentObserver mProvisioningObserver = new ContentObserver(new Handler()) {
+    private final ContentObserver mProvisioningObserver = new ContentObserver(mHandler) {
         @Override
         public void onChange(boolean selfChange) {
             final boolean provisioned = 0 != Settings.Global.getInt(
@@ -171,6 +175,17 @@
         }
     };
 
+    private final ContentObserver mLockscreenSettingsObserver = new ContentObserver(mHandler) {
+        @Override
+        public void onChange(boolean selfChange) {
+            // We don't know which user changed LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS,
+            // so we just dump our cache ...
+            mUsersAllowingPrivateNotifications.clear();
+            // ... and refresh all the notifications
+            updateNotificationIcons();
+        }
+    };
+
     private RemoteViews.OnClickHandler mOnClickHandler = new RemoteViews.OnClickHandler() {
         @Override
         public boolean onClickHandler(View view, PendingIntent pendingIntent, Intent fillInIntent) {
@@ -229,6 +244,12 @@
                 Settings.Global.getUriFor(Settings.Global.DEVICE_PROVISIONED), true,
                 mProvisioningObserver);
 
+        mContext.getContentResolver().registerContentObserver(
+                Settings.Secure.getUriFor(Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS),
+                true,
+                mLockscreenSettingsObserver,
+                UserHandle.USER_ALL);
+
         mBarService = IStatusBarService.Stub.asInterface(
                 ServiceManager.getService(Context.STATUS_BAR_SERVICE));
 
@@ -550,12 +571,35 @@
 
     public abstract void resetHeadsUpDecayTimer();
 
-    public void setPublicMode(boolean publicMode) {
-        mPublicMode = publicMode;
+    /**
+     * Save the current "public" (locked and secure) state of the lockscreen.
+     */
+    public void setLockscreenPublicMode(boolean publicMode) {
+        mLockscreenPublicMode = publicMode;
     }
 
-    public boolean isPublicMode() {
-        return mPublicMode;
+    public boolean isLockscreenPublicMode() {
+        return mLockscreenPublicMode;
+    }
+
+    /**
+     * Has the given user chosen to allow their private (full) notifications to be shown even
+     * when the lockscreen is in "public" (secure & locked) mode?
+     */
+    public boolean userAllowsPrivateNotificationsInPublic(int userHandle) {
+        if (userHandle == UserHandle.USER_ALL) {
+            return true;
+        }
+
+        if (mUsersAllowingPrivateNotifications.indexOfKey(userHandle) < 0) {
+            final boolean allowed = 0 != Settings.Secure.getIntForUser(
+                    mContext.getContentResolver(),
+                    Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS, 0, userHandle);
+            mUsersAllowingPrivateNotifications.append(userHandle, allowed);
+            return allowed;
+        }
+
+        return mUsersAllowingPrivateNotifications.get(userHandle);
     }
 
     protected class H extends Handler {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index e5bdd59..2114991 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -1033,8 +1033,10 @@
             if (!notificationIsForCurrentUser(ent.notification)) continue;
             final int vis = ent.notification.getNotification().visibility;
             if (vis != Notification.VISIBILITY_SECRET) {
-                // when isPublicMode() we show the public form of VISIBILITY_PRIVATE notifications
-                ent.row.setShowingPublic(isPublicMode() && vis == Notification.VISIBILITY_PRIVATE);
+                // when isLockscreenPublicMode() we show the public form of VISIBILITY_PRIVATE notifications
+                ent.row.setShowingPublic(isLockscreenPublicMode()
+                        && vis == Notification.VISIBILITY_PRIVATE
+                        && !userAllowsPrivateNotificationsInPublic(ent.notification.getUserId()));
                 toShow.add(ent.row);
             }
         }
@@ -1087,9 +1089,10 @@
             if (!((provisioned && ent.notification.getScore() >= HIDE_ICONS_BELOW_SCORE)
                     || showNotificationEvenIfUnprovisioned(ent.notification))) continue;
             if (!notificationIsForCurrentUser(ent.notification)) continue;
-            if (isPublicMode()
+            if (isLockscreenPublicMode()
                     && ent.notification.getNotification().visibility
-                            == Notification.VISIBILITY_SECRET) {
+                            == Notification.VISIBILITY_SECRET
+                    && !userAllowsPrivateNotificationsInPublic(ent.notification.getUserId())) {
                 // in "public" mode (atop a secure keyguard), secret notifs are totally hidden
                 continue;
             }
@@ -1343,10 +1346,10 @@
         } else if ((diff & StatusBarManager.DISABLE_PRIVATE_NOTIFICATIONS) != 0) {
             if ((state & StatusBarManager.DISABLE_PRIVATE_NOTIFICATIONS) != 0) {
                 // we are outside a secure keyguard, so we need to switch to "public" mode
-                setPublicMode(true);
+                setLockscreenPublicMode(true);
             } else {
                 // user has authenticated the device; full notifications may be shown
-                setPublicMode(false);
+                setLockscreenPublicMode(false);
             }
             updateNotificationIcons();
         }
diff --git a/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java b/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java
index 2c36ab7..0adb32f 100644
--- a/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java
+++ b/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java
@@ -311,6 +311,8 @@
             }
 
             mUsbStorageNotification.setLatestEventInfo(mContext, title, message, pi);
+            mUsbStorageNotification.visibility = Notification.VISIBILITY_PUBLIC;
+
             final boolean adbOn = 1 == Settings.Global.getInt(
                 mContext.getContentResolver(),
                 Settings.Global.ADB_ENABLED,
@@ -401,6 +403,7 @@
 
             mMediaStorageNotification.icon = icon;
             mMediaStorageNotification.setLatestEventInfo(mContext, title, message, pi);
+            mMediaStorageNotification.visibility = Notification.VISIBILITY_PUBLIC;
         }
 
         final int notificationId = mMediaStorageNotification.icon;
diff --git a/policy/src/com/android/internal/policy/impl/ImmersiveModeConfirmation.java b/policy/src/com/android/internal/policy/impl/ImmersiveModeConfirmation.java
index 3cc74fc..5602206 100644
--- a/policy/src/com/android/internal/policy/impl/ImmersiveModeConfirmation.java
+++ b/policy/src/com/android/internal/policy/impl/ImmersiveModeConfirmation.java
@@ -84,9 +84,9 @@
         return exit != null ? exit.getDuration() : 0;
     }
 
-    public void loadSetting() {
+    public void loadSetting(int currentUserId) {
         mConfirmed = false;
-        mCurrentUserId = getCurrentUser();
+        mCurrentUserId = currentUserId;
         if (DEBUG) Slog.d(TAG, String.format("loadSetting() mCurrentUserId=%d resetForPanic=%s",
                 mCurrentUserId, mUserPanicResets.get(mCurrentUserId, false)));
         String value = null;
@@ -159,14 +159,6 @@
         saveSetting();
     }
 
-    private int getCurrentUser() {
-        try {
-            return ActivityManagerNative.getDefault().getCurrentUser().id;
-        } catch (RemoteException e) {
-            throw new IllegalStateException(e); // local call
-        }
-    }
-
     private void handleHide() {
         if (mClingWindow != null) {
             if (DEBUG) Slog.d(TAG, "Hiding immersive mode confirmation");
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index ece4fe7..ada649d 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -1168,7 +1168,7 @@
                 updateRotation = true;
             }
             if (mImmersiveModeConfirmation != null) {
-                mImmersiveModeConfirmation.loadSetting();
+                mImmersiveModeConfirmation.loadSetting(mCurrentUserId);
             }
             PolicyControl.reloadFromSetting(mContext);
         }
@@ -2569,7 +2569,8 @@
     @Override
     public void getContentInsetHintLw(WindowManager.LayoutParams attrs, Rect contentInset) {
         final int fl = PolicyControl.getWindowFlags(null, attrs);
-        final int systemUiVisibility = (attrs.systemUiVisibility|attrs.subtreeSystemUiVisibility);
+        final int sysuiVis = PolicyControl.getSystemUiVisibility(null, attrs);
+        final int systemUiVisibility = (sysuiVis | attrs.subtreeSystemUiVisibility);
 
         if ((fl & (FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR))
                 == (FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR)) {
@@ -2953,7 +2954,7 @@
 
         final int fl = PolicyControl.getWindowFlags(win, attrs);
         final int sim = attrs.softInputMode;
-        final int sysUiFl = PolicyControl.getSystemUiVisibility(win);
+        final int sysUiFl = PolicyControl.getSystemUiVisibility(win, null);
 
         final Rect pf = mTmpParentFrame;
         final Rect df = mTmpDisplayFrame;
@@ -5078,7 +5079,7 @@
             return 0;
         }
 
-        int tmpVisibility = PolicyControl.getSystemUiVisibility(win)
+        int tmpVisibility = PolicyControl.getSystemUiVisibility(win, null)
                 & ~mResettingSystemUiFlags
                 & ~mForceClearedSystemUiFlags;
         if (mForcingShowNavBar && win.getSurfaceLayer() < mForcingShowNavBarLayer) {
diff --git a/policy/src/com/android/internal/policy/impl/PolicyControl.java b/policy/src/com/android/internal/policy/impl/PolicyControl.java
index 4f355dd..ffdb520 100644
--- a/policy/src/com/android/internal/policy/impl/PolicyControl.java
+++ b/policy/src/com/android/internal/policy/impl/PolicyControl.java
@@ -61,16 +61,17 @@
     private static Filter sImmersiveStatusFilter;
     private static Filter sImmersiveNavigationFilter;
 
-    public static int getSystemUiVisibility(WindowState win) {
-        int vis = win.getSystemUiVisibility();
-        if (sImmersiveStatusFilter != null && sImmersiveStatusFilter.matches(win)) {
+    public static int getSystemUiVisibility(WindowState win, LayoutParams attrs) {
+        attrs = attrs != null ? attrs : win.getAttrs();
+        int vis = win != null ? win.getSystemUiVisibility() : attrs.systemUiVisibility;
+        if (sImmersiveStatusFilter != null && sImmersiveStatusFilter.matches(attrs)) {
             vis |= View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
                     | View.SYSTEM_UI_FLAG_FULLSCREEN
                     | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
             vis &= ~(View.SYSTEM_UI_FLAG_LAYOUT_STABLE
                     | View.STATUS_BAR_TRANSLUCENT);
         }
-        if (sImmersiveNavigationFilter != null && sImmersiveNavigationFilter.matches(win)) {
+        if (sImmersiveNavigationFilter != null && sImmersiveNavigationFilter.matches(attrs)) {
             vis |= View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
                     | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
                     | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;
@@ -81,20 +82,22 @@
     }
 
     public static int getWindowFlags(WindowState win, LayoutParams attrs) {
-        int flags = (attrs != null ? attrs : win.getAttrs()).flags;
-        if (sImmersiveStatusFilter != null && sImmersiveStatusFilter.matches(win)) {
+        attrs = attrs != null ? attrs : win.getAttrs();
+        int flags = attrs.flags;
+        if (sImmersiveStatusFilter != null && sImmersiveStatusFilter.matches(attrs)) {
             flags |= WindowManager.LayoutParams.FLAG_FULLSCREEN;
             flags &= ~(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS
                     | WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
         }
-        if (sImmersiveNavigationFilter != null && sImmersiveNavigationFilter.matches(win)) {
+        if (sImmersiveNavigationFilter != null && sImmersiveNavigationFilter.matches(attrs)) {
             flags &= ~WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION;
         }
         return flags;
     }
 
     public static int adjustClearableFlags(WindowState win, int clearableFlags) {
-        if (sImmersiveStatusFilter != null && sImmersiveStatusFilter.matches(win)) {
+        final LayoutParams attrs = win != null ? win.getAttrs() : null;
+        if (sImmersiveStatusFilter != null && sImmersiveStatusFilter.matches(attrs)) {
             clearableFlags &= ~View.SYSTEM_UI_FLAG_FULLSCREEN;
         }
         return clearableFlags;
@@ -187,9 +190,7 @@
             mBlacklist = blacklist;
         }
 
-        boolean matches(WindowState win) {
-            if (win == null) return false;
-            LayoutParams attrs = win.getAttrs();
+        boolean matches(LayoutParams attrs) {
             if (attrs == null) return false;
             boolean isApp = attrs.type >= WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW
                     && attrs.type <= WindowManager.LayoutParams.LAST_APPLICATION_WINDOW;
diff --git a/services/core/java/com/android/server/MountService.java b/services/core/java/com/android/server/MountService.java
index 0f2e56c..607def6 100644
--- a/services/core/java/com/android/server/MountService.java
+++ b/services/core/java/com/android/server/MountService.java
@@ -94,6 +94,7 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
+import java.util.concurrent.atomic.AtomicInteger;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 
@@ -397,18 +398,37 @@
     }
 
     class ShutdownCallBack extends UnmountCallBack {
-        IMountShutdownObserver observer;
-        ShutdownCallBack(String path, IMountShutdownObserver observer) {
+        MountShutdownLatch mMountShutdownLatch;
+        ShutdownCallBack(String path, final MountShutdownLatch mountShutdownLatch) {
             super(path, true, false);
-            this.observer = observer;
+            mMountShutdownLatch = mountShutdownLatch;
         }
 
         @Override
         void handleFinished() {
             int ret = doUnmountVolume(path, true, removeEncryption);
-            if (observer != null) {
+            Slog.i(TAG, "Unmount completed: " + path + ", result code: " + ret);
+            mMountShutdownLatch.countDown();
+        }
+    }
+
+    static class MountShutdownLatch {
+        private IMountShutdownObserver mObserver;
+        private AtomicInteger mCount;
+
+        MountShutdownLatch(final IMountShutdownObserver observer, int count) {
+            mObserver = observer;
+            mCount = new AtomicInteger(count);
+        }
+
+        void countDown() {
+            boolean sendShutdown = false;
+            if (mCount.decrementAndGet() == 0) {
+                sendShutdown = true;
+            }
+            if (sendShutdown && mObserver != null) {
                 try {
-                    observer.onShutDownComplete(ret);
+                    mObserver.onShutDownComplete(StorageResultCode.OperationSucceeded);
                 } catch (RemoteException e) {
                     Slog.w(TAG, "RemoteException when shutting down");
                 }
@@ -1436,6 +1456,10 @@
 
         Slog.i(TAG, "Shutting down");
         synchronized (mVolumesLock) {
+            // Get all volumes to be unmounted.
+            MountShutdownLatch mountShutdownLatch = new MountShutdownLatch(observer,
+                                                            mVolumeStates.size());
+
             for (String path : mVolumeStates.keySet()) {
                 String state = mVolumeStates.get(path);
 
@@ -1471,19 +1495,16 @@
 
                 if (state.equals(Environment.MEDIA_MOUNTED)) {
                     // Post a unmount message.
-                    ShutdownCallBack ucb = new ShutdownCallBack(path, observer);
+                    ShutdownCallBack ucb = new ShutdownCallBack(path, mountShutdownLatch);
                     mHandler.sendMessage(mHandler.obtainMessage(H_UNMOUNT_PM_UPDATE, ucb));
                 } else if (observer != null) {
                     /*
-                     * Observer is waiting for onShutDownComplete when we are done.
-                     * Since nothing will be done send notification directly so shutdown
-                     * sequence can continue.
+                     * Count down, since nothing will be done. The observer will be
+                     * notified when we are done so shutdown sequence can continue.
                      */
-                    try {
-                        observer.onShutDownComplete(StorageResultCode.OperationSucceeded);
-                    } catch (RemoteException e) {
-                        Slog.w(TAG, "RemoteException when shutting down");
-                    }
+                    mountShutdownLatch.countDown();
+                    Slog.i(TAG, "Unmount completed: " + path +
+                        ", result code: " + StorageResultCode.OperationSucceeded);
                 }
             }
         }
diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java
index f1a3ba5..3924fe8 100644
--- a/services/core/java/com/android/server/NetworkManagementService.java
+++ b/services/core/java/com/android/server/NetworkManagementService.java
@@ -82,6 +82,7 @@
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 import java.util.NoSuchElementException;
 import java.util.StringTokenizer;
@@ -1038,6 +1039,15 @@
         }
     }
 
+    private List<InterfaceAddress> excludeLinkLocal(List<InterfaceAddress> addresses) {
+        ArrayList<InterfaceAddress> filtered = new ArrayList<InterfaceAddress>(addresses.size());
+        for (InterfaceAddress ia : addresses) {
+            if (!ia.getAddress().isLinkLocalAddress())
+                filtered.add(ia);
+        }
+        return filtered;
+    }
+
     private void modifyNat(String action, String internalInterface, String externalInterface)
             throws SocketException {
         final Command cmd = new Command("nat", action, internalInterface, externalInterface);
@@ -1047,8 +1057,10 @@
         if (internalNetworkInterface == null) {
             cmd.appendArg("0");
         } else {
-            Collection<InterfaceAddress> interfaceAddresses = internalNetworkInterface
-                    .getInterfaceAddresses();
+            // Don't touch link-local routes, as link-local addresses aren't routable,
+            // kernel creates link-local routes on all interfaces automatically
+            List<InterfaceAddress> interfaceAddresses = excludeLinkLocal(
+                    internalNetworkInterface.getInterfaceAddresses());
             cmd.appendArg(interfaceAddresses.size());
             for (InterfaceAddress ia : interfaceAddresses) {
                 InetAddress addr = NetworkUtils.getNetworkPart(
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
old mode 100644
new mode 100755
index be2df04..a845127
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -204,6 +204,7 @@
                     Slog.i(TAG, "Waited long enough for: " + r);
                     mStartingBackground.remove(i);
                     N--;
+                    i--;
                 }
             }
             while (mDelayedStartList.size() > 0
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index 2941a18..059aa2b 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -337,6 +337,13 @@
         }
     }
 
+    public void noteWifiState(int wifiState, String accessPoint) {
+        enforceCallingPermission();
+        synchronized (mStats) {
+            mStats.noteWifiStateLocked(wifiState, accessPoint);
+        }
+    }
+
     public void noteBluetoothOn() {
         enforceCallingPermission();
         BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
@@ -380,10 +387,10 @@
         }
     }
     
-    public void noteBluetoothActiveState(int actType) {
+    public void noteBluetoothState(int bluetoothState) {
         enforceCallingPermission();
         synchronized (mStats) {
-            mStats.noteBluetoothActiveStateLocked(actType);
+            mStats.noteBluetoothStateLocked(bluetoothState);
         }
     }
 
diff --git a/services/core/java/com/android/server/connectivity/Tethering.java b/services/core/java/com/android/server/connectivity/Tethering.java
index 5971737..b233943 100644
--- a/services/core/java/com/android/server/connectivity/Tethering.java
+++ b/services/core/java/com/android/server/connectivity/Tethering.java
@@ -470,6 +470,7 @@
         mTetheredNotification.defaults &= ~Notification.DEFAULT_SOUND;
         mTetheredNotification.flags = Notification.FLAG_ONGOING_EVENT;
         mTetheredNotification.tickerText = title;
+        mTetheredNotification.visibility = Notification.VISIBILITY_PUBLIC;
         mTetheredNotification.setLatestEventInfo(mContext, title, message, pi);
 
         notificationManager.notifyAsUser(null, mTetheredNotification.icon,
diff --git a/services/core/java/com/android/server/storage/DeviceStorageMonitorService.java b/services/core/java/com/android/server/storage/DeviceStorageMonitorService.java
index 43a99e0..260e97a 100644
--- a/services/core/java/com/android/server/storage/DeviceStorageMonitorService.java
+++ b/services/core/java/com/android/server/storage/DeviceStorageMonitorService.java
@@ -454,6 +454,7 @@
         notification.tickerText = title;
         notification.flags |= Notification.FLAG_NO_CLEAR;
         notification.setLatestEventInfo(context, title, details, intent);
+        notification.visibility = Notification.VISIBILITY_PUBLIC;
         mNotificationMgr.notifyAsUser(null, LOW_MEMORY_NOTIFICATION_ID, notification,
                 UserHandle.ALL);
         context.sendStickyBroadcastAsUser(mStorageLowIntent, UserHandle.ALL);
diff --git a/services/core/java/com/android/server/usb/UsbDeviceManager.java b/services/core/java/com/android/server/usb/UsbDeviceManager.java
index c1a3646..2312288 100644
--- a/services/core/java/com/android/server/usb/UsbDeviceManager.java
+++ b/services/core/java/com/android/server/usb/UsbDeviceManager.java
@@ -697,6 +697,7 @@
                     PendingIntent pi = PendingIntent.getActivityAsUser(mContext, 0,
                             intent, 0, null, UserHandle.CURRENT);
                     notification.setLatestEventInfo(mContext, title, message, pi);
+                    notification.visibility = Notification.VISIBILITY_PUBLIC;
                     mNotificationManager.notifyAsUser(null, id, notification,
                             UserHandle.ALL);
                     mUsbNotificationId = id;
@@ -732,6 +733,7 @@
                     PendingIntent pi = PendingIntent.getActivityAsUser(mContext, 0,
                             intent, 0, null, UserHandle.CURRENT);
                     notification.setLatestEventInfo(mContext, title, message, pi);
+                    notification.visibility = Notification.VISIBILITY_PUBLIC;
                     mAdbNotificationShown = true;
                     mNotificationManager.notifyAsUser(null, id, notification,
                             UserHandle.ALL);
diff --git a/services/core/jni/com_android_server_UsbHostManager.cpp b/services/core/jni/com_android_server_UsbHostManager.cpp
index f1fa6cf..fc6de60 100644
--- a/services/core/jni/com_android_server_UsbHostManager.cpp
+++ b/services/core/jni/com_android_server_UsbHostManager.cpp
@@ -163,8 +163,10 @@
         return NULL;
 
     int fd = usb_device_get_fd(device);
-    if (fd < 0)
+    if (fd < 0) {
+        usb_device_close(device);
         return NULL;
+    }
     int newFD = dup(fd);
     usb_device_close(device);
 
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index bb96544..12f0114 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -2830,6 +2830,14 @@
             return false;
         }
         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USERS, null);
+
+        UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
+        if (um.getUserInfo(userHandle) == null) {
+            // User doesn't exist.
+            throw new IllegalArgumentException(
+                    "Attempted to set profile owner for invalid userId: " + userHandle);
+        }
+
         if (packageName == null
                 || !DeviceOwner.isInstalledForUser(packageName, userHandle)) {
             throw new IllegalArgumentException("Package name " + packageName
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 943471a..5221f1f 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -529,7 +529,7 @@
                 }
 
                 try {
-                    if (pm.hasSystemFeature("android.software.device_admin")) {
+                    if (pm.hasSystemFeature(PackageManager.FEATURE_DEVICE_ADMIN)) {
                         mSystemServiceManager.startServiceIfExists(
                                 DEVICE_POLICY_MANAGER_SERVICE_CLASS);
                     }
@@ -778,7 +778,7 @@
 
             if (!disableNonCoreServices) {
                 try {
-                    if (pm.hasSystemFeature("android.software.backup")) {
+                    if (pm.hasSystemFeature(PackageManager.FEATURE_BACKUP)) {
                         mSystemServiceManager.startServiceIfExists(BACKUP_MANAGER_SERVICE_CLASS);
                     }
                 } catch (Throwable e) {
@@ -786,7 +786,7 @@
                 }
 
                 try {
-                    if (pm.hasSystemFeature("android.software.app_widgets")) {
+                    if (pm.hasSystemFeature(PackageManager.FEATURE_APP_WIDGETS)) {
                         mSystemServiceManager.startServiceIfExists(APPWIDGET_SERVICE_CLASS);
                     }
                 } catch (Throwable e) {
@@ -872,7 +872,7 @@
             }
 
             try {
-                if (pm.hasSystemFeature("android.software.print")) {
+                if (pm.hasSystemFeature(PackageManager.FEATURE_PRINTING)) {
                     mSystemServiceManager.startServiceIfExists(PRINT_MANAGER_SERVICE_CLASS);
                 }
             } catch (Throwable e) {
diff --git a/telephony/java/android/telephony/ThirdPartyCallListener.java b/telephony/java/android/telephony/ThirdPartyCallListener.java
deleted file mode 100644
index 00265f8..0000000
--- a/telephony/java/android/telephony/ThirdPartyCallListener.java
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * 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.
- */
-
-package android.telephony;
-
-import android.os.RemoteException;
-
-import com.android.internal.telephony.IThirdPartyCallListener;
-
-/**
- * Interface provided to {@link android.telephony.ThirdPartyCallService}. The service can use this
- * to notify the listener of changes to the call state.
- */
-public class ThirdPartyCallListener {
-    private final IThirdPartyCallListener mListener;
-
-    // Call end reason. TODO: rename this to DisconnectCause once they are public.
-    public static final int CALL_END_NORMAL = 1;
-    public static final int CALL_END_INCOMING_MISSED = 2;
-    public static final int CALL_END_OTHER = 3;
-
-    public ThirdPartyCallListener(IThirdPartyCallListener listener) {
-        if (listener == null) {
-            throw new IllegalArgumentException("Invalid listener");
-        }
-        mListener = listener;
-    }
-
-    /**
-     * Called by the service when a call provider is available to perform the outgoing or incoming
-     * call.
-     */
-    public void onCallProviderAttached(ThirdPartyCallProvider callProvider) {
-        try {
-            mListener.onCallProviderAttached(callProvider.getCallback());
-        } catch (RemoteException e) {
-        }
-    }
-
-    /**
-     * Notifies the listener that ringing has started for this call.
-     */
-    public void onRingingStarted() {
-        try {
-            mListener.onRingingStarted();
-        } catch (RemoteException e) {
-        }
-    }
-
-    /**
-     * Notifies the listener that the call has been successfully established.
-     */
-    public void onCallEstablished() {
-        try {
-            mListener.onCallEstablished();
-        } catch (RemoteException e) {
-        }
-    }
-
-    /**
-     * Notifies the listener that the call has ended.
-     */
-    public void onCallEnded(int reason) {
-        try {
-            mListener.onCallEnded(reason);
-        } catch (RemoteException e) {
-        }
-    }
-}
diff --git a/telephony/java/android/telephony/ThirdPartyCallProvider.java b/telephony/java/android/telephony/ThirdPartyCallProvider.java
deleted file mode 100644
index bd8a1ea..0000000
--- a/telephony/java/android/telephony/ThirdPartyCallProvider.java
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * 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.
- */
-
-package android.telephony;
-
-import android.os.Handler;
-import android.os.Message;
-
-import com.android.internal.telephony.IThirdPartyCallProvider;
-
-/**
- * Interface sent to {@link android.telephony.ThirdPartyCallListener#onCallProviderAttached
- * onCallProviderAttached}. This is used to control an outgoing or an incoming call.
- */
-public class ThirdPartyCallProvider {
-    private static final int MSG_MUTE = 1;
-    private static final int MSG_HANGUP = 2;
-    private static final int MSG_INCOMING_CALL_ACCEPT = 3;
-    private static final int MSG_SEND_DTMF = 4;
-
-    /**
-     * Mutes or unmutes the call.
-     */
-    public void mute(boolean shouldMute) {
-        // default implementation empty
-    }
-
-    /**
-     * Ends the current call. If this is an unanswered incoming call then the call is rejected.
-     */
-    public void hangup() {
-        // default implementation empty
-    }
-
-   /**
-     * Accepts the incoming call.
-     */
-    public void incomingCallAccept() {
-        // default implementation empty
-    }
-
-    /**
-     * Sends the given DTMF code. The code can be '0'-'9', 'A'-'D', '#', or '*'.
-     */
-    public void sendDtmf(char c) {
-        // default implementation empty
-    }
-
-    IThirdPartyCallProvider getCallback() {
-        return mCallback;
-    }
-
-    private final IThirdPartyCallProvider mCallback = new IThirdPartyCallProvider.Stub() {
-        @Override
-        public void mute(boolean shouldMute) {
-            Message.obtain(mHandler, MSG_MUTE, shouldMute ? 1 : 0, 0).sendToTarget();
-        }
-
-        @Override
-        public void hangup() {
-            Message.obtain(mHandler, MSG_HANGUP).sendToTarget();
-        }
-
-        @Override
-        public void incomingCallAccept() {
-            Message.obtain(mHandler, MSG_INCOMING_CALL_ACCEPT).sendToTarget();
-        }
-
-        @Override
-        public void sendDtmf(char c) {
-            Message.obtain(mHandler, MSG_SEND_DTMF, (int) c, 0).sendToTarget();
-        }
-    };
-
-    private final Handler mHandler = new Handler() {
-        @Override
-        public void handleMessage(Message msg) {
-            switch (msg.what) {
-                case MSG_MUTE:
-                    mute(msg.arg1 != 0);
-                    break;
-                case MSG_HANGUP:
-                    hangup();
-                    break;
-                case MSG_INCOMING_CALL_ACCEPT:
-                    incomingCallAccept();
-                    break;
-                case MSG_SEND_DTMF:
-                    sendDtmf((char) msg.arg1);
-                    break;
-            }
-        }
-    };
-}
diff --git a/telephony/java/android/telephony/ThirdPartyCallService.java b/telephony/java/android/telephony/ThirdPartyCallService.java
deleted file mode 100644
index 6eddb43..0000000
--- a/telephony/java/android/telephony/ThirdPartyCallService.java
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * 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.
- */
-
-package android.telephony;
-
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.Message;
-import android.util.Pair;
-
-import com.android.internal.telephony.IThirdPartyCallListener;
-import com.android.internal.telephony.IThirdPartyCallService;
-
-/**
- * Interface provided by a service to start outgoing calls and attach to incoming calls.
- */
-public class ThirdPartyCallService {
-    private static final int MSG_OUTGOING_CALL_INITIATE = 1;
-    private static final int MSG_INCOMING_CALL_ATTACH = 2;
-
-    /**
-     * Call to start a new outgoing call.
-     */
-    public void outgoingCallInitiate(ThirdPartyCallListener listener, String number) {
-        // default implementation empty
-    }
-
-    /**
-     * Call to attach to an incoming call.
-     */
-    public void incomingCallAttach(ThirdPartyCallListener listener, String callId) {
-        // default implementation empty
-    }
-
-    /**
-     * Returns an IBinder instance that can returned from the service's onBind function.
-     */
-    public IBinder getBinder() {
-        return mCallback;
-    }
-
-    private final IThirdPartyCallService.Stub mCallback = new IThirdPartyCallService.Stub() {
-        @Override
-        public void outgoingCallInitiate(IThirdPartyCallListener listener, String number) {
-            Rlog.w("ThirdPartyPhone", "ThirdPartyCallService.IThirdPartyCallService.out");
-            Message.obtain(mHandler, MSG_OUTGOING_CALL_INITIATE,
-                    Pair.create(listener, number)).sendToTarget();
-        }
-
-        @Override
-        public void incomingCallAttach(IThirdPartyCallListener listener, String callId) {
-            Rlog.w("ThirdPartyPhone", "ThirdPartyCallService.IThirdPartyCallService.in");
-            Message.obtain(mHandler, MSG_INCOMING_CALL_ATTACH,
-                    Pair.create(listener, callId)).sendToTarget();
-        }
-    };
-
-    private final Handler mHandler = new Handler() {
-        public void handleMessage(Message msg) {
-            Rlog.w("ThirdPartyPhone", "ThirdPartyCallService.handleMessage: " + msg.what);
-            switch (msg.what) {
-                case MSG_OUTGOING_CALL_INITIATE: {
-                    Rlog.w("ThirdPartyPhone", "ThirdPartyCallService.handleMessage out");
-                    Pair<IThirdPartyCallListener, String> pair =
-                            (Pair<IThirdPartyCallListener, String>) msg.obj;
-                    ThirdPartyCallListener listener = new ThirdPartyCallListener(pair.first);
-                    outgoingCallInitiate(listener, pair.second);
-                    break;
-                }
-                case MSG_INCOMING_CALL_ATTACH: {
-                    Rlog.w("ThirdPartyPhone", "ThirdPartyCallService.handleMessage in");
-                    Pair<IThirdPartyCallListener, String> pair =
-                            (Pair<IThirdPartyCallListener, String>) msg.obj;
-                    ThirdPartyCallListener listener = new ThirdPartyCallListener(pair.first);
-                    incomingCallAttach(listener, pair.second);
-                    break;
-                }
-            }
-        }
-    };
-}
diff --git a/telephony/java/com/android/internal/telephony/IThirdPartyCallListener.aidl b/telephony/java/com/android/internal/telephony/IThirdPartyCallListener.aidl
deleted file mode 100644
index bcf2d81..0000000
--- a/telephony/java/com/android/internal/telephony/IThirdPartyCallListener.aidl
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * 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.
- */
-
-package com.android.internal.telephony;
-
-import com.android.internal.telephony.IThirdPartyCallProvider;
-
-/**
- * Interface provided to ThirdPartyCallService. The service can use this to notify the listener of
- * changes to the call state.
- */
-oneway interface IThirdPartyCallListener {
-    /**
-     * Called by the service when a call provider is available to perform the outgoing or incoming
-     * call.
-     */
-    void onCallProviderAttached(IThirdPartyCallProvider callProvider);
-
-    /**
-     * Notifies the listener that ringing has started for this call.
-     */
-    void onRingingStarted();
-
-    /**
-     * Notifies the listener that the call has been successfully established.
-     */
-    void onCallEstablished();
-
-    /**
-     * Notifies the listener that the call has ended.
-     */
-    void onCallEnded(int reason);
-}
diff --git a/telephony/java/com/android/internal/telephony/IThirdPartyCallProvider.aidl b/telephony/java/com/android/internal/telephony/IThirdPartyCallProvider.aidl
deleted file mode 100644
index a9d67a4..0000000
--- a/telephony/java/com/android/internal/telephony/IThirdPartyCallProvider.aidl
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * 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.
- */
-
-package com.android.internal.telephony;
-
-import com.android.internal.telephony.IThirdPartyCallListener;
-
-/**
- * Interface sent to ThirdPartyCallListener.onCallProviderAttached. This is used to control an
- * outgoing or incoming call.
- */
-oneway interface IThirdPartyCallProvider {
-    /**
-     * Mutes or unmutes the call.
-     */
-    void mute(boolean shouldMute);
-
-    /**
-     * Ends the current call. If this is an unanswered incoming call then the call is rejected (for
-     * example, a notification is sent to a server that the user declined the call).
-     */
-    void hangup();
-
-    /**
-     * Accepts the incoming call.
-     */
-    void incomingCallAccept();
-
-    /**
-     * Sends the given DTMF code. The code can be '0'-'9', 'A'-'D', '#', or '*'.
-     */
-    void sendDtmf(char c);
-}
diff --git a/telephony/java/com/android/internal/telephony/IThirdPartyCallService.aidl b/telephony/java/com/android/internal/telephony/IThirdPartyCallService.aidl
deleted file mode 100644
index c9ee4ed..0000000
--- a/telephony/java/com/android/internal/telephony/IThirdPartyCallService.aidl
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * 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.
- */
-
-package com.android.internal.telephony;
-
-import com.android.internal.telephony.IThirdPartyCallListener;
-
-/**
- * Interface provided by a service to start outgoing calls and attach to incoming calls.
- */
-oneway interface IThirdPartyCallService {
-    /**
-     * Call to start a new outgoing call.
-     */
-    void outgoingCallInitiate(IThirdPartyCallListener listener, String number);
-
-    /**
-     * Call to attach to an incoming call.
-     */
-    void incomingCallAttach(IThirdPartyCallListener listener, String callId);
-}
diff --git a/tools/layoutlib/bridge/src/android/graphics/ColorFilter_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/ColorFilter_Delegate.java
index 38174f1..bf03a5e 100644
--- a/tools/layoutlib/bridge/src/android/graphics/ColorFilter_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/ColorFilter_Delegate.java
@@ -56,7 +56,7 @@
     // ---- native methods ----
 
     @LayoutlibDelegate
-    /*package*/ static void destroyFilter(long native_instance, long nativeColorFilter) {
+    /*package*/ static void destroyFilter(long native_instance) {
         sManager.removeJavaReferenceFor(native_instance);
     }
 
diff --git a/tools/layoutlib/bridge/src/android/graphics/ColorMatrixColorFilter_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/ColorMatrixColorFilter_Delegate.java
index ca8f450..9aac2bd 100644
--- a/tools/layoutlib/bridge/src/android/graphics/ColorMatrixColorFilter_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/ColorMatrixColorFilter_Delegate.java
@@ -60,11 +60,5 @@
         return sManager.addNewDelegate(newDelegate);
     }
 
-    @LayoutlibDelegate
-    /*package*/ static long nColorMatrixFilter(long nativeFilter, float[] array) {
-        // pass
-        return 0;
-    }
-
     // ---- Private delegate/helper methods ----
 }
diff --git a/tools/layoutlib/bridge/src/android/graphics/LightingColorFilter_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/LightingColorFilter_Delegate.java
index defaac3..501d55c 100644
--- a/tools/layoutlib/bridge/src/android/graphics/LightingColorFilter_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/LightingColorFilter_Delegate.java
@@ -60,11 +60,5 @@
         return sManager.addNewDelegate(newDelegate);
     }
 
-    @LayoutlibDelegate
-    /*package*/ static int nCreateLightingFilter(long nativeFilter, int mul, int add) {
-        // pass
-        return 0;
-    }
-
     // ---- Private delegate/helper methods ----
 }
diff --git a/tools/layoutlib/bridge/src/android/graphics/Path_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Path_Delegate.java
index 49f314c..77468ec 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Path_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Path_Delegate.java
@@ -490,20 +490,6 @@
         return new float[0];
     }
 
-    @LayoutlibDelegate
-    /*package*/ static long native_trim(long nPath, long nTargetPath, long nPathMeasure,
-            float trimStart, float trimEnd, float trimOffset) {
-        // TODO: add trim.
-        Bridge.getLog().error(LayoutLog.TAG_UNSUPPORTED, "Path.trim() not supported", null);
-        return nPathMeasure;
-
-    }
-
-    @LayoutlibDelegate
-    private static void native_destroyMeasure(long nPathMeasure) {
-        // Do nothing.
-    }
-
     // ---- Private helper methods ----
 
     private void set(Path_Delegate delegate) {
diff --git a/tools/layoutlib/bridge/src/android/graphics/PorterDuffColorFilter_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/PorterDuffColorFilter_Delegate.java
index 6049919..1bc3033 100644
--- a/tools/layoutlib/bridge/src/android/graphics/PorterDuffColorFilter_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/PorterDuffColorFilter_Delegate.java
@@ -60,12 +60,5 @@
         return sManager.addNewDelegate(newDelegate);
     }
 
-    @LayoutlibDelegate
-    /*package*/ static long nCreatePorterDuffFilter(long nativeFilter, int srcColor,
-            int porterDuffMode) {
-        // pass
-        return 0;
-    }
-
     // ---- Private delegate/helper methods ----
 }