Merge "Adding SBAS offset to Gps/Gnss SvStatus converter" into nyc-dev
diff --git a/api/current.txt b/api/current.txt
index 8e3b8ff..70ea1c5 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -5048,7 +5048,7 @@
 
   public static class Notification.BigPictureStyle extends android.app.Notification.Style {
     ctor public Notification.BigPictureStyle();
-    ctor public Notification.BigPictureStyle(android.app.Notification.Builder);
+    ctor public deprecated Notification.BigPictureStyle(android.app.Notification.Builder);
     method public android.app.Notification.BigPictureStyle bigLargeIcon(android.graphics.Bitmap);
     method public android.app.Notification.BigPictureStyle bigLargeIcon(android.graphics.drawable.Icon);
     method public android.app.Notification.BigPictureStyle bigPicture(android.graphics.Bitmap);
@@ -5058,7 +5058,7 @@
 
   public static class Notification.BigTextStyle extends android.app.Notification.Style {
     ctor public Notification.BigTextStyle();
-    ctor public Notification.BigTextStyle(android.app.Notification.Builder);
+    ctor public deprecated Notification.BigTextStyle(android.app.Notification.Builder);
     method public android.app.Notification.BigTextStyle bigText(java.lang.CharSequence);
     method public android.app.Notification.BigTextStyle setBigContentTitle(java.lang.CharSequence);
     method public android.app.Notification.BigTextStyle setSummaryText(java.lang.CharSequence);
@@ -5159,12 +5159,10 @@
 
   public static class Notification.DecoratedCustomViewStyle extends android.app.Notification.Style {
     ctor public Notification.DecoratedCustomViewStyle();
-    ctor public Notification.DecoratedCustomViewStyle(android.app.Notification.Builder);
   }
 
   public static class Notification.DecoratedMediaCustomViewStyle extends android.app.Notification.MediaStyle {
     ctor public Notification.DecoratedMediaCustomViewStyle();
-    ctor public Notification.DecoratedMediaCustomViewStyle(android.app.Notification.Builder);
   }
 
   public static abstract interface Notification.Extender {
@@ -5173,7 +5171,7 @@
 
   public static class Notification.InboxStyle extends android.app.Notification.Style {
     ctor public Notification.InboxStyle();
-    ctor public Notification.InboxStyle(android.app.Notification.Builder);
+    ctor public deprecated Notification.InboxStyle(android.app.Notification.Builder);
     method public android.app.Notification.InboxStyle addLine(java.lang.CharSequence);
     method public android.app.Notification.InboxStyle setBigContentTitle(java.lang.CharSequence);
     method public android.app.Notification.InboxStyle setSummaryText(java.lang.CharSequence);
@@ -5181,7 +5179,7 @@
 
   public static class Notification.MediaStyle extends android.app.Notification.Style {
     ctor public Notification.MediaStyle();
-    ctor public Notification.MediaStyle(android.app.Notification.Builder);
+    ctor public deprecated Notification.MediaStyle(android.app.Notification.Builder);
     method public android.app.Notification.MediaStyle setMediaSession(android.media.session.MediaSession.Token);
     method public android.app.Notification.MediaStyle setShowActionsInCompactView(int...);
   }
@@ -19778,6 +19776,7 @@
     method public void stop() throws java.lang.IllegalStateException;
     field public static final int ERROR = -1; // 0xffffffff
     field public static final int ERROR_BAD_VALUE = -2; // 0xfffffffe
+    field public static final int ERROR_DEAD_OBJECT = -6; // 0xfffffffa
     field public static final int ERROR_INVALID_OPERATION = -3; // 0xfffffffd
     field public static final int READ_BLOCKING = 0; // 0x0
     field public static final int READ_NON_BLOCKING = 1; // 0x1
@@ -19900,6 +19899,7 @@
     method public int write(java.nio.ByteBuffer, int, int, long);
     field public static final int ERROR = -1; // 0xffffffff
     field public static final int ERROR_BAD_VALUE = -2; // 0xfffffffe
+    field public static final int ERROR_DEAD_OBJECT = -6; // 0xfffffffa
     field public static final int ERROR_INVALID_OPERATION = -3; // 0xfffffffd
     field public static final int MODE_STATIC = 0; // 0x0
     field public static final int MODE_STREAM = 1; // 0x1
@@ -20557,6 +20557,7 @@
     field public static final int HEVCProfileMain10HDR10 = 4096; // 0x1000
     field public static final int MPEG2LevelH14 = 2; // 0x2
     field public static final int MPEG2LevelHL = 3; // 0x3
+    field public static final int MPEG2LevelHP = 4; // 0x4
     field public static final int MPEG2LevelLL = 0; // 0x0
     field public static final int MPEG2LevelML = 1; // 0x1
     field public static final int MPEG2Profile422 = 2; // 0x2
@@ -20570,9 +20571,11 @@
     field public static final int MPEG4Level1 = 4; // 0x4
     field public static final int MPEG4Level2 = 8; // 0x8
     field public static final int MPEG4Level3 = 16; // 0x10
+    field public static final int MPEG4Level3b = 24; // 0x18
     field public static final int MPEG4Level4 = 32; // 0x20
     field public static final int MPEG4Level4a = 64; // 0x40
     field public static final int MPEG4Level5 = 128; // 0x80
+    field public static final int MPEG4Level6 = 256; // 0x100
     field public static final int MPEG4ProfileAdvancedCoding = 4096; // 0x1000
     field public static final int MPEG4ProfileAdvancedCore = 8192; // 0x2000
     field public static final int MPEG4ProfileAdvancedRealTime = 1024; // 0x400
diff --git a/api/system-current.txt b/api/system-current.txt
index 4623b7b..a6f612d 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -5195,7 +5195,7 @@
 
   public static class Notification.BigPictureStyle extends android.app.Notification.Style {
     ctor public Notification.BigPictureStyle();
-    ctor public Notification.BigPictureStyle(android.app.Notification.Builder);
+    ctor public deprecated Notification.BigPictureStyle(android.app.Notification.Builder);
     method public android.app.Notification.BigPictureStyle bigLargeIcon(android.graphics.Bitmap);
     method public android.app.Notification.BigPictureStyle bigLargeIcon(android.graphics.drawable.Icon);
     method public android.app.Notification.BigPictureStyle bigPicture(android.graphics.Bitmap);
@@ -5205,7 +5205,7 @@
 
   public static class Notification.BigTextStyle extends android.app.Notification.Style {
     ctor public Notification.BigTextStyle();
-    ctor public Notification.BigTextStyle(android.app.Notification.Builder);
+    ctor public deprecated Notification.BigTextStyle(android.app.Notification.Builder);
     method public android.app.Notification.BigTextStyle bigText(java.lang.CharSequence);
     method public android.app.Notification.BigTextStyle setBigContentTitle(java.lang.CharSequence);
     method public android.app.Notification.BigTextStyle setSummaryText(java.lang.CharSequence);
@@ -5306,12 +5306,10 @@
 
   public static class Notification.DecoratedCustomViewStyle extends android.app.Notification.Style {
     ctor public Notification.DecoratedCustomViewStyle();
-    ctor public Notification.DecoratedCustomViewStyle(android.app.Notification.Builder);
   }
 
   public static class Notification.DecoratedMediaCustomViewStyle extends android.app.Notification.MediaStyle {
     ctor public Notification.DecoratedMediaCustomViewStyle();
-    ctor public Notification.DecoratedMediaCustomViewStyle(android.app.Notification.Builder);
   }
 
   public static abstract interface Notification.Extender {
@@ -5320,7 +5318,7 @@
 
   public static class Notification.InboxStyle extends android.app.Notification.Style {
     ctor public Notification.InboxStyle();
-    ctor public Notification.InboxStyle(android.app.Notification.Builder);
+    ctor public deprecated Notification.InboxStyle(android.app.Notification.Builder);
     method public android.app.Notification.InboxStyle addLine(java.lang.CharSequence);
     method public android.app.Notification.InboxStyle setBigContentTitle(java.lang.CharSequence);
     method public android.app.Notification.InboxStyle setSummaryText(java.lang.CharSequence);
@@ -5328,7 +5326,7 @@
 
   public static class Notification.MediaStyle extends android.app.Notification.Style {
     ctor public Notification.MediaStyle();
-    ctor public Notification.MediaStyle(android.app.Notification.Builder);
+    ctor public deprecated Notification.MediaStyle(android.app.Notification.Builder);
     method public android.app.Notification.MediaStyle setMediaSession(android.media.session.MediaSession.Token);
     method public android.app.Notification.MediaStyle setShowActionsInCompactView(int...);
   }
@@ -21294,6 +21292,7 @@
     method public void stop() throws java.lang.IllegalStateException;
     field public static final int ERROR = -1; // 0xffffffff
     field public static final int ERROR_BAD_VALUE = -2; // 0xfffffffe
+    field public static final int ERROR_DEAD_OBJECT = -6; // 0xfffffffa
     field public static final int ERROR_INVALID_OPERATION = -3; // 0xfffffffd
     field public static final int READ_BLOCKING = 0; // 0x0
     field public static final int READ_NON_BLOCKING = 1; // 0x1
@@ -21418,6 +21417,7 @@
     method public int write(java.nio.ByteBuffer, int, int, long);
     field public static final int ERROR = -1; // 0xffffffff
     field public static final int ERROR_BAD_VALUE = -2; // 0xfffffffe
+    field public static final int ERROR_DEAD_OBJECT = -6; // 0xfffffffa
     field public static final int ERROR_INVALID_OPERATION = -3; // 0xfffffffd
     field public static final int MODE_STATIC = 0; // 0x0
     field public static final int MODE_STREAM = 1; // 0x1
@@ -22075,6 +22075,7 @@
     field public static final int HEVCProfileMain10HDR10 = 4096; // 0x1000
     field public static final int MPEG2LevelH14 = 2; // 0x2
     field public static final int MPEG2LevelHL = 3; // 0x3
+    field public static final int MPEG2LevelHP = 4; // 0x4
     field public static final int MPEG2LevelLL = 0; // 0x0
     field public static final int MPEG2LevelML = 1; // 0x1
     field public static final int MPEG2Profile422 = 2; // 0x2
@@ -22088,9 +22089,11 @@
     field public static final int MPEG4Level1 = 4; // 0x4
     field public static final int MPEG4Level2 = 8; // 0x8
     field public static final int MPEG4Level3 = 16; // 0x10
+    field public static final int MPEG4Level3b = 24; // 0x18
     field public static final int MPEG4Level4 = 32; // 0x20
     field public static final int MPEG4Level4a = 64; // 0x40
     field public static final int MPEG4Level5 = 128; // 0x80
+    field public static final int MPEG4Level6 = 256; // 0x100
     field public static final int MPEG4ProfileAdvancedCoding = 4096; // 0x1000
     field public static final int MPEG4ProfileAdvancedCore = 8192; // 0x2000
     field public static final int MPEG4ProfileAdvancedRealTime = 1024; // 0x400
diff --git a/api/test-current.txt b/api/test-current.txt
index 9a4752e..37bc7af 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -5049,7 +5049,7 @@
 
   public static class Notification.BigPictureStyle extends android.app.Notification.Style {
     ctor public Notification.BigPictureStyle();
-    ctor public Notification.BigPictureStyle(android.app.Notification.Builder);
+    ctor public deprecated Notification.BigPictureStyle(android.app.Notification.Builder);
     method public android.app.Notification.BigPictureStyle bigLargeIcon(android.graphics.Bitmap);
     method public android.app.Notification.BigPictureStyle bigLargeIcon(android.graphics.drawable.Icon);
     method public android.app.Notification.BigPictureStyle bigPicture(android.graphics.Bitmap);
@@ -5059,7 +5059,7 @@
 
   public static class Notification.BigTextStyle extends android.app.Notification.Style {
     ctor public Notification.BigTextStyle();
-    ctor public Notification.BigTextStyle(android.app.Notification.Builder);
+    ctor public deprecated Notification.BigTextStyle(android.app.Notification.Builder);
     method public android.app.Notification.BigTextStyle bigText(java.lang.CharSequence);
     method public android.app.Notification.BigTextStyle setBigContentTitle(java.lang.CharSequence);
     method public android.app.Notification.BigTextStyle setSummaryText(java.lang.CharSequence);
@@ -5160,12 +5160,10 @@
 
   public static class Notification.DecoratedCustomViewStyle extends android.app.Notification.Style {
     ctor public Notification.DecoratedCustomViewStyle();
-    ctor public Notification.DecoratedCustomViewStyle(android.app.Notification.Builder);
   }
 
   public static class Notification.DecoratedMediaCustomViewStyle extends android.app.Notification.MediaStyle {
     ctor public Notification.DecoratedMediaCustomViewStyle();
-    ctor public Notification.DecoratedMediaCustomViewStyle(android.app.Notification.Builder);
   }
 
   public static abstract interface Notification.Extender {
@@ -5174,7 +5172,7 @@
 
   public static class Notification.InboxStyle extends android.app.Notification.Style {
     ctor public Notification.InboxStyle();
-    ctor public Notification.InboxStyle(android.app.Notification.Builder);
+    ctor public deprecated Notification.InboxStyle(android.app.Notification.Builder);
     method public android.app.Notification.InboxStyle addLine(java.lang.CharSequence);
     method public android.app.Notification.InboxStyle setBigContentTitle(java.lang.CharSequence);
     method public android.app.Notification.InboxStyle setSummaryText(java.lang.CharSequence);
@@ -5182,7 +5180,7 @@
 
   public static class Notification.MediaStyle extends android.app.Notification.Style {
     ctor public Notification.MediaStyle();
-    ctor public Notification.MediaStyle(android.app.Notification.Builder);
+    ctor public deprecated Notification.MediaStyle(android.app.Notification.Builder);
     method public android.app.Notification.MediaStyle setMediaSession(android.media.session.MediaSession.Token);
     method public android.app.Notification.MediaStyle setShowActionsInCompactView(int...);
   }
@@ -19847,6 +19845,7 @@
     method public void stop() throws java.lang.IllegalStateException;
     field public static final int ERROR = -1; // 0xffffffff
     field public static final int ERROR_BAD_VALUE = -2; // 0xfffffffe
+    field public static final int ERROR_DEAD_OBJECT = -6; // 0xfffffffa
     field public static final int ERROR_INVALID_OPERATION = -3; // 0xfffffffd
     field public static final int READ_BLOCKING = 0; // 0x0
     field public static final int READ_NON_BLOCKING = 1; // 0x1
@@ -19969,6 +19968,7 @@
     method public int write(java.nio.ByteBuffer, int, int, long);
     field public static final int ERROR = -1; // 0xffffffff
     field public static final int ERROR_BAD_VALUE = -2; // 0xfffffffe
+    field public static final int ERROR_DEAD_OBJECT = -6; // 0xfffffffa
     field public static final int ERROR_INVALID_OPERATION = -3; // 0xfffffffd
     field public static final int MODE_STATIC = 0; // 0x0
     field public static final int MODE_STREAM = 1; // 0x1
@@ -20626,6 +20626,7 @@
     field public static final int HEVCProfileMain10HDR10 = 4096; // 0x1000
     field public static final int MPEG2LevelH14 = 2; // 0x2
     field public static final int MPEG2LevelHL = 3; // 0x3
+    field public static final int MPEG2LevelHP = 4; // 0x4
     field public static final int MPEG2LevelLL = 0; // 0x0
     field public static final int MPEG2LevelML = 1; // 0x1
     field public static final int MPEG2Profile422 = 2; // 0x2
@@ -20639,9 +20640,11 @@
     field public static final int MPEG4Level1 = 4; // 0x4
     field public static final int MPEG4Level2 = 8; // 0x8
     field public static final int MPEG4Level3 = 16; // 0x10
+    field public static final int MPEG4Level3b = 24; // 0x18
     field public static final int MPEG4Level4 = 32; // 0x20
     field public static final int MPEG4Level4a = 64; // 0x40
     field public static final int MPEG4Level5 = 128; // 0x80
+    field public static final int MPEG4Level6 = 256; // 0x100
     field public static final int MPEG4ProfileAdvancedCoding = 4096; // 0x1000
     field public static final int MPEG4ProfileAdvancedCore = 8192; // 0x2000
     field public static final int MPEG4ProfileAdvancedRealTime = 1024; // 0x400
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index 6ba6b0f..cd9a05b 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -7015,6 +7015,7 @@
             data.writeInt(0);
         }
         mRemote.transact(SEND_INTENT_SENDER_TRANSACTION, data, reply, 0);
+        reply.readException();
         final int res = reply.readInt();
         data.recycle();
         reply.recycle();
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 5078058..4a8203b 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -4087,6 +4087,10 @@
         public BigPictureStyle() {
         }
 
+        /**
+         * @deprecated use {@code BigPictureStyle()}.
+         */
+        @Deprecated
         public BigPictureStyle(Builder builder) {
             setBuilder(builder);
         }
@@ -4243,6 +4247,10 @@
         public BigTextStyle() {
         }
 
+        /**
+         * @deprecated use {@code BigTextStyle()}.
+         */
+        @Deprecated
         public BigTextStyle(Builder builder) {
             setBuilder(builder);
         }
@@ -4785,6 +4793,10 @@
         public InboxStyle() {
         }
 
+        /**
+         * @deprecated use {@code InboxStyle()}.
+         */
+        @Deprecated
         public InboxStyle(Builder builder) {
             setBuilder(builder);
         }
@@ -4957,6 +4969,10 @@
         public MediaStyle() {
         }
 
+        /**
+         * @deprecated use {@code MediaStyle()}.
+         */
+        @Deprecated
         public MediaStyle(Builder builder) {
             setBuilder(builder);
         }
@@ -5164,10 +5180,6 @@
         public DecoratedCustomViewStyle() {
         }
 
-        public DecoratedCustomViewStyle(Builder builder) {
-            setBuilder(builder);
-        }
-
         /**
          * @hide
          */
@@ -5284,10 +5296,6 @@
         public DecoratedMediaCustomViewStyle() {
         }
 
-        public DecoratedMediaCustomViewStyle(Builder builder) {
-            setBuilder(builder);
-        }
-
         /**
          * @hide
          */
diff --git a/core/java/android/appwidget/AppWidgetHostView.java b/core/java/android/appwidget/AppWidgetHostView.java
index cd8f126..bb5f7a1 100644
--- a/core/java/android/appwidget/AppWidgetHostView.java
+++ b/core/java/android/appwidget/AppWidgetHostView.java
@@ -19,6 +19,7 @@
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.pm.ApplicationInfo;
+import android.content.pm.LauncherApps;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.res.Resources;
@@ -150,7 +151,7 @@
             // We add padding to the AppWidgetHostView if necessary
             Rect padding = getDefaultPaddingForWidget(mContext, info.provider, null);
             setPadding(padding.left, padding.top, padding.right, padding.bottom);
-            setContentDescription(info.label);
+            updateContentDescription(info);
         }
     }
 
@@ -459,6 +460,7 @@
         }
 
         applyContent(content, recycled, exception);
+        updateContentDescription(mInfo);
     }
 
     private void applyContent(View content, boolean recycled, Exception exception) {
@@ -493,6 +495,22 @@
         }
     }
 
+    private void updateContentDescription(AppWidgetProviderInfo info) {
+        if (info != null) {
+            LauncherApps launcherApps = getContext().getSystemService(LauncherApps.class);
+            ApplicationInfo appInfo = launcherApps.getApplicationInfo(
+                    info.provider.getPackageName(), 0, info.getProfile());
+            if (appInfo != null &&
+                    (appInfo.flags & ApplicationInfo.FLAG_SUSPENDED) != 0) {
+                setContentDescription(
+                        Resources.getSystem().getString(
+                        com.android.internal.R.string.suspended_widget_accessibility, info.label));
+            } else {
+                setContentDescription(info.label);
+            }
+        }
+    }
+
     private void inflateAsync(RemoteViews remoteViews) {
         // Prepare a local reference to the remote Context so we're ready to
         // inflate any requested LayoutParams.
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index d036d96..4c86578 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -57,6 +57,7 @@
 import java.util.Set;
 import java.util.UUID;
 import java.util.concurrent.TimeoutException;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
 
 /**
  * Represents the local device Bluetooth adapter. The {@link BluetoothAdapter}
@@ -483,6 +484,8 @@
 
     private final IBluetoothManager mManagerService;
     private IBluetooth mService;
+    private final ReentrantReadWriteLock mServiceLock =
+        new ReentrantReadWriteLock();
 
     private final Object mLock = new Object();
     private final Map<LeScanCallback, ScanCallback> mLeScanClients;
@@ -517,8 +520,13 @@
             throw new IllegalArgumentException("bluetooth manager service is null");
         }
         try {
+            mServiceLock.writeLock().lock();
             mService = managerService.registerAdapter(mManagerCallback);
-        } catch (RemoteException e) {Log.e(TAG, "", e);}
+        } catch (RemoteException e) {
+            Log.e(TAG, "", e);
+        } finally {
+            mServiceLock.writeLock().unlock();
+        }
         mManagerService = managerService;
         mLeScanClients = new HashMap<LeScanCallback, ScanCallback>();
         mToken = new Binder();
@@ -605,10 +613,14 @@
     @RequiresPermission(Manifest.permission.BLUETOOTH)
     public boolean isEnabled() {
         try {
-            synchronized(mManagerCallback) {
-                if (mService != null) return mService.isEnabled();
-            }
-        } catch (RemoteException e) {Log.e(TAG, "", e);}
+            mServiceLock.readLock().lock();
+            if (mService != null) return mService.isEnabled();
+        } catch (RemoteException e) {
+            Log.e(TAG, "", e);
+        } finally {
+            mServiceLock.readLock().unlock();
+        }
+
         return false;
     }
 
@@ -639,12 +651,12 @@
      * or OFF if BT is in BLE_ON state
      */
     private void notifyUserAction(boolean enable) {
-        if (mService == null) {
-            Log.e(TAG, "mService is null");
-            return;
-        }
-
         try {
+            mServiceLock.readLock().lock();
+            if (mService == null) {
+                Log.e(TAG, "mService is null");
+                return;
+            }
             if (enable) {
                 mService.onLeServiceUp(); //NA:TODO implementation pending
             } else {
@@ -652,6 +664,8 @@
             }
         } catch (RemoteException e) {
             Log.e(TAG, "", e);
+        } finally {
+            mServiceLock.readLock().unlock();
         }
     }
 
@@ -783,26 +797,28 @@
     @RequiresPermission(Manifest.permission.BLUETOOTH)
     @AdapterState
     public int getState() {
+        int state = BluetoothAdapter.STATE_OFF;
+
         try {
-            synchronized(mManagerCallback) {
-                if (mService != null)
-                {
-                    int state=  mService.getState();
-                    if (VDBG) Log.d(TAG, "" + hashCode() + ": getState(). Returning " + state);
-                    //consider all internal states as OFF
-                    if (state == BluetoothAdapter.STATE_BLE_ON
-                        || state == BluetoothAdapter.STATE_BLE_TURNING_ON
-                        || state == BluetoothAdapter.STATE_BLE_TURNING_OFF) {
-                        if (VDBG) Log.d(TAG, "Consider internal state as OFF");
-                        state = BluetoothAdapter.STATE_OFF;
-                    }
-                    return state;
-                }
-                // TODO(BT) there might be a small gap during STATE_TURNING_ON that
-                //          mService is null, handle that case
+            mServiceLock.readLock().lock();
+            if (mService != null) {
+                state = mService.getState();
             }
-        } catch (RemoteException e) {Log.e(TAG, "", e);}
-        return STATE_OFF;
+        } catch (RemoteException e) {
+            Log.e(TAG, "", e);
+        } finally {
+            mServiceLock.readLock().unlock();
+        }
+
+        // Consider all internal states as OFF
+        if (state == BluetoothAdapter.STATE_BLE_ON
+            || state == BluetoothAdapter.STATE_BLE_TURNING_ON
+            || state == BluetoothAdapter.STATE_BLE_TURNING_OFF) {
+            if (VDBG) Log.d(TAG, "Consider internal state as OFF");
+            state = BluetoothAdapter.STATE_OFF;
+        }
+        if (VDBG) Log.d(TAG, "" + hashCode() + ": getState(). Returning " + state);
+        return state;
     }
 
     /**
@@ -825,19 +841,21 @@
     @RequiresPermission(Manifest.permission.BLUETOOTH)
     @AdapterState
     public int getLeState() {
+        int state = BluetoothAdapter.STATE_OFF;
+
         try {
-            synchronized(mManagerCallback) {
-                if (mService != null)
-                {
-                    int state=  mService.getState();
-                    if (VDBG) Log.d(TAG,"getLeState() returning " + state);
-                    return state;
-                }
+            mServiceLock.readLock().lock();
+            if (mService != null) {
+                state = mService.getState();
             }
         } catch (RemoteException e) {
             Log.e(TAG, "", e);
+        } finally {
+            mServiceLock.readLock().unlock();
         }
-        return BluetoothAdapter.STATE_OFF;
+
+        if (VDBG) Log.d(TAG,"getLeState() returning " + state);
+        return state;
     }
 
     boolean getLeAccess() {
@@ -879,16 +897,21 @@
      */
     @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
     public boolean enable() {
-        int state = STATE_OFF;
-        if (isEnabled() == true){
+        int state = BluetoothAdapter.STATE_OFF;
+        if (isEnabled() == true) {
             if (DBG) Log.d(TAG, "enable(): BT is already enabled..!");
             return true;
         }
-        //Use service interface to get the exact state
-        if (mService != null) {
-            try {
-               state = mService.getState();
-            } catch (RemoteException e) {Log.e(TAG, "", e);}
+        // Use service interface to get the exact state
+        try {
+            mServiceLock.readLock().lock();
+            if (mService != null) {
+                state = mService.getState();
+            }
+        } catch (RemoteException e) {
+            Log.e(TAG, "", e);
+        } finally {
+            mServiceLock.readLock().unlock();
         }
 
         if (state == BluetoothAdapter.STATE_BLE_ON) {
@@ -993,10 +1016,13 @@
      */
     public boolean configHciSnoopLog(boolean enable) {
         try {
-            synchronized(mManagerCallback) {
-                if (mService != null) return mService.configHciSnoopLog(enable);
-            }
-        } catch (RemoteException e) {Log.e(TAG, "", e);}
+            mServiceLock.readLock().lock();
+            if (mService != null) return mService.configHciSnoopLog(enable);
+        } catch (RemoteException e) {
+            Log.e(TAG, "", e);
+        } finally {
+            mServiceLock.readLock().unlock();
+        }
         return false;
     }
 
@@ -1012,12 +1038,16 @@
      */
     public boolean factoryReset() {
         try {
+            mServiceLock.readLock().lock();
             if (mService != null) {
                 return mService.factoryReset();
-            } else {
-                SystemProperties.set("persist.bluetooth.factoryreset", "true");
             }
-        } catch (RemoteException e) {Log.e(TAG, "", e);}
+            SystemProperties.set("persist.bluetooth.factoryreset", "true");
+        } catch (RemoteException e) {
+            Log.e(TAG, "", e);
+        } finally {
+            mServiceLock.readLock().unlock();
+        }
         return false;
     }
 
@@ -1032,10 +1062,13 @@
     public ParcelUuid[] getUuids() {
         if (getState() != STATE_ON) return null;
         try {
-            synchronized(mManagerCallback) {
-                if (mService != null) return mService.getUuids();
-            }
-        } catch (RemoteException e) {Log.e(TAG, "", e);}
+            mServiceLock.readLock().lock();
+            if (mService != null) return mService.getUuids();
+        } catch (RemoteException e) {
+            Log.e(TAG, "", e);
+        } finally {
+            mServiceLock.readLock().unlock();
+        }
         return null;
     }
 
@@ -1058,10 +1091,13 @@
     public boolean setName(String name) {
         if (getState() != STATE_ON) return false;
         try {
-            synchronized(mManagerCallback) {
-                if (mService != null) return mService.setName(name);
-            }
-        } catch (RemoteException e) {Log.e(TAG, "", e);}
+            mServiceLock.readLock().lock();
+            if (mService != null) return mService.setName(name);
+        } catch (RemoteException e) {
+            Log.e(TAG, "", e);
+        } finally {
+            mServiceLock.readLock().unlock();
+        }
         return false;
     }
 
@@ -1086,10 +1122,13 @@
     public int getScanMode() {
         if (getState() != STATE_ON) return SCAN_MODE_NONE;
         try {
-            synchronized(mManagerCallback) {
-                if (mService != null) return mService.getScanMode();
-            }
-        } catch (RemoteException e) {Log.e(TAG, "", e);}
+            mServiceLock.readLock().lock();
+            if (mService != null) return mService.getScanMode();
+        } catch (RemoteException e) {
+            Log.e(TAG, "", e);
+        } finally {
+            mServiceLock.readLock().unlock();
+        }
         return SCAN_MODE_NONE;
     }
 
@@ -1124,10 +1163,13 @@
     public boolean setScanMode(@ScanMode int mode, int duration) {
         if (getState() != STATE_ON) return false;
         try {
-            synchronized(mManagerCallback) {
-                if (mService != null) return mService.setScanMode(mode, duration);
-            }
-        } catch (RemoteException e) {Log.e(TAG, "", e);}
+            mServiceLock.readLock().lock();
+            if (mService != null) return mService.setScanMode(mode, duration);
+        } catch (RemoteException e) {
+            Log.e(TAG, "", e);
+        } finally {
+            mServiceLock.readLock().unlock();
+        }
         return false;
     }
 
@@ -1142,10 +1184,13 @@
     public int getDiscoverableTimeout() {
         if (getState() != STATE_ON) return -1;
         try {
-            synchronized(mManagerCallback) {
-                if (mService != null) return mService.getDiscoverableTimeout();
-            }
-        } catch (RemoteException e) {Log.e(TAG, "", e);}
+            mServiceLock.readLock().lock();
+            if (mService != null) return mService.getDiscoverableTimeout();
+        } catch (RemoteException e) {
+            Log.e(TAG, "", e);
+        } finally {
+            mServiceLock.readLock().unlock();
+        }
         return -1;
     }
 
@@ -1153,10 +1198,13 @@
     public void setDiscoverableTimeout(int timeout) {
         if (getState() != STATE_ON) return;
         try {
-            synchronized(mManagerCallback) {
-                if (mService != null) mService.setDiscoverableTimeout(timeout);
-            }
-        } catch (RemoteException e) {Log.e(TAG, "", e);}
+            mServiceLock.readLock().lock();
+            if (mService != null) mService.setDiscoverableTimeout(timeout);
+        } catch (RemoteException e) {
+            Log.e(TAG, "", e);
+        } finally {
+            mServiceLock.readLock().unlock();
+        }
     }
 
     /**
@@ -1193,10 +1241,13 @@
     public boolean startDiscovery() {
         if (getState() != STATE_ON) return false;
         try {
-            synchronized(mManagerCallback) {
-                if (mService != null) return mService.startDiscovery();
-            }
-        } catch (RemoteException e) {Log.e(TAG, "", e);}
+            mServiceLock.readLock().lock();
+            if (mService != null) return mService.startDiscovery();
+        } catch (RemoteException e) {
+            Log.e(TAG, "", e);
+        } finally {
+            mServiceLock.readLock().unlock();
+        }
         return false;
     }
 
@@ -1221,10 +1272,13 @@
     public boolean cancelDiscovery() {
         if (getState() != STATE_ON) return false;
         try {
-            synchronized(mManagerCallback) {
-                if (mService != null) return mService.cancelDiscovery();
-            }
-        } catch (RemoteException e) {Log.e(TAG, "", e);}
+            mServiceLock.readLock().lock();
+            if (mService != null) return mService.cancelDiscovery();
+        } catch (RemoteException e) {
+            Log.e(TAG, "", e);
+        } finally {
+            mServiceLock.readLock().unlock();
+        }
         return false;
     }
 
@@ -1251,10 +1305,13 @@
     public boolean isDiscovering() {
         if (getState() != STATE_ON) return false;
         try {
-            synchronized(mManagerCallback) {
-                if (mService != null ) return mService.isDiscovering();
-            }
-        } catch (RemoteException e) {Log.e(TAG, "", e);}
+            mServiceLock.readLock().lock();
+            if (mService != null) return mService.isDiscovering();
+        } catch (RemoteException e) {
+            Log.e(TAG, "", e);
+        } finally {
+            mServiceLock.readLock().unlock();
+        }
         return false;
     }
 
@@ -1266,9 +1323,12 @@
     public boolean isMultipleAdvertisementSupported() {
         if (getState() != STATE_ON) return false;
         try {
-            return mService.isMultiAdvertisementSupported();
+            mServiceLock.readLock().lock();
+            if (mService != null) return mService.isMultiAdvertisementSupported();
         } catch (RemoteException e) {
             Log.e(TAG, "failed to get isMultipleAdvertisementSupported, error: ", e);
+        } finally {
+            mServiceLock.readLock().unlock();
         }
         return false;
     }
@@ -1301,9 +1361,12 @@
     public boolean isPeripheralModeSupported() {
         if (getState() != STATE_ON) return false;
         try {
-            return mService.isPeripheralModeSupported();
+            mServiceLock.readLock().lock();
+            if (mService != null) return mService.isPeripheralModeSupported();
         } catch (RemoteException e) {
             Log.e(TAG, "failed to get peripheral mode capability: ", e);
+        } finally {
+            mServiceLock.readLock().unlock();
         }
         return false;
     }
@@ -1316,9 +1379,12 @@
     public boolean isOffloadedFilteringSupported() {
         if (!getLeAccess()) return false;
         try {
-            return mService.isOffloadedFilteringSupported();
+            mServiceLock.readLock().lock();
+            if (mService != null) return mService.isOffloadedFilteringSupported();
         } catch (RemoteException e) {
             Log.e(TAG, "failed to get isOffloadedFilteringSupported, error: ", e);
+        } finally {
+            mServiceLock.readLock().unlock();
         }
         return false;
     }
@@ -1331,9 +1397,12 @@
     public boolean isOffloadedScanBatchingSupported() {
         if (!getLeAccess()) return false;
         try {
-            return mService.isOffloadedScanBatchingSupported();
+            mServiceLock.readLock().lock();
+            if (mService != null) return mService.isOffloadedScanBatchingSupported();
         } catch (RemoteException e) {
             Log.e(TAG, "failed to get isOffloadedScanBatchingSupported, error: ", e);
+        } finally {
+            mServiceLock.readLock().unlock();
         }
         return false;
     }
@@ -1399,15 +1468,15 @@
      */
     public void requestControllerActivityEnergyInfo(ResultReceiver result) {
         try {
-            synchronized(mManagerCallback) {
-                if (mService != null) {
-                    mService.requestActivityInfo(result);
-                    result = null;
-                }
+            mServiceLock.readLock().lock();
+            if (mService != null) {
+                mService.requestActivityInfo(result);
+                result = null;
             }
         } catch (RemoteException e) {
             Log.e(TAG, "getControllerActivityEnergyInfoCallback: " + e);
         } finally {
+            mServiceLock.readLock().unlock();
             if (result != null) {
                 // Only send an immediate result if we failed.
                 result.send(0, null);
@@ -1432,11 +1501,14 @@
             return toDeviceSet(new BluetoothDevice[0]);
         }
         try {
-            synchronized(mManagerCallback) {
-                if (mService != null) return toDeviceSet(mService.getBondedDevices());
-            }
+            mServiceLock.readLock().lock();
+            if (mService != null) return toDeviceSet(mService.getBondedDevices());
             return toDeviceSet(new BluetoothDevice[0]);
-        } catch (RemoteException e) {Log.e(TAG, "", e);}
+        } catch (RemoteException e) {
+            Log.e(TAG, "", e);
+        } finally {
+            mServiceLock.readLock().unlock();
+        }
         return null;
     }
 
@@ -1456,10 +1528,13 @@
     public int getConnectionState() {
         if (getState() != STATE_ON) return BluetoothAdapter.STATE_DISCONNECTED;
         try {
-            synchronized(mManagerCallback) {
-                if (mService != null) return mService.getAdapterConnectionState();
-            }
-        } catch (RemoteException e) {Log.e(TAG, "getConnectionState:", e);}
+            mServiceLock.readLock().lock();
+            if (mService != null) return mService.getAdapterConnectionState();
+        } catch (RemoteException e) {
+            Log.e(TAG, "getConnectionState:", e);
+        } finally {
+            mServiceLock.readLock().unlock();
+        }
         return BluetoothAdapter.STATE_DISCONNECTED;
     }
 
@@ -1482,11 +1557,12 @@
     public int getProfileConnectionState(int profile) {
         if (getState() != STATE_ON) return BluetoothProfile.STATE_DISCONNECTED;
         try {
-            synchronized(mManagerCallback) {
-                if (mService != null) return mService.getProfileConnectionState(profile);
-            }
+            mServiceLock.readLock().lock();
+            if (mService != null) return mService.getProfileConnectionState(profile);
         } catch (RemoteException e) {
             Log.e(TAG, "getProfileConnectionState:", e);
+        } finally {
+            mServiceLock.readLock().unlock();
         }
         return BluetoothProfile.STATE_DISCONNECTED;
     }
@@ -1790,7 +1866,9 @@
             byte[] hash;
             byte[] randomizer;
 
-            byte[] ret = mService.readOutOfBandData();
+            byte[] ret = null;
+            mServiceLock.readLock().lock();
+            if (mService != null) mService.readOutOfBandData();
 
             if (ret  == null || ret.length != 32) return null;
 
@@ -1803,7 +1881,12 @@
             }
             return new Pair<byte[], byte[]>(hash, randomizer);
 
-        } catch (RemoteException e) {Log.e(TAG, "", e);}*/
+        } catch (RemoteException e) {
+            Log.e(TAG, "", e);
+        } finally {
+            mServiceLock.readLock().unlock();
+        }
+        */
         return null;
     }
 
@@ -1939,17 +2022,21 @@
         new IBluetoothManagerCallback.Stub() {
             public void onBluetoothServiceUp(IBluetooth bluetoothService) {
                 if (VDBG) Log.d(TAG, "onBluetoothServiceUp: " + bluetoothService);
-                synchronized (mManagerCallback) {
-                    mService = bluetoothService;
-                    synchronized (mProxyServiceStateCallbacks) {
-                        for (IBluetoothManagerCallback cb : mProxyServiceStateCallbacks ){
-                            try {
-                                if (cb != null) {
-                                    cb.onBluetoothServiceUp(bluetoothService);
-                                } else {
-                                    Log.d(TAG, "onBluetoothServiceUp: cb is null!!!");
-                                }
-                            } catch (Exception e)  { Log.e(TAG,"",e);}
+
+                mServiceLock.writeLock().lock();
+                mService = bluetoothService;
+                mServiceLock.writeLock().unlock();
+
+                synchronized (mProxyServiceStateCallbacks) {
+                    for (IBluetoothManagerCallback cb : mProxyServiceStateCallbacks ) {
+                        try {
+                            if (cb != null) {
+                                cb.onBluetoothServiceUp(bluetoothService);
+                            } else {
+                                Log.d(TAG, "onBluetoothServiceUp: cb is null!!!");
+                            }
+                        } catch (Exception e) {
+                            Log.e(TAG,"",e);
                         }
                     }
                 }
@@ -1957,20 +2044,24 @@
 
             public void onBluetoothServiceDown() {
                 if (VDBG) Log.d(TAG, "onBluetoothServiceDown: " + mService);
-                synchronized (mManagerCallback) {
-                    mService = null;
-                    if (mLeScanClients != null) mLeScanClients.clear();
-                    if (sBluetoothLeAdvertiser != null) sBluetoothLeAdvertiser.cleanup();
-                    if (sBluetoothLeScanner != null) sBluetoothLeScanner.cleanup();
-                    synchronized (mProxyServiceStateCallbacks) {
-                        for (IBluetoothManagerCallback cb : mProxyServiceStateCallbacks ){
-                            try {
-                                if (cb != null) {
-                                    cb.onBluetoothServiceDown();
-                                } else {
-                                    Log.d(TAG, "onBluetoothServiceDown: cb is null!!!");
-                                }
-                            } catch (Exception e)  { Log.e(TAG,"",e);}
+
+                mServiceLock.writeLock().lock();
+                mService = null;
+                if (mLeScanClients != null) mLeScanClients.clear();
+                if (sBluetoothLeAdvertiser != null) sBluetoothLeAdvertiser.cleanup();
+                if (sBluetoothLeScanner != null) sBluetoothLeScanner.cleanup();
+                mServiceLock.writeLock().unlock();
+
+                synchronized (mProxyServiceStateCallbacks) {
+                    for (IBluetoothManagerCallback cb : mProxyServiceStateCallbacks ){
+                        try {
+                            if (cb != null) {
+                                cb.onBluetoothServiceDown();
+                            } else {
+                                Log.d(TAG, "onBluetoothServiceDown: cb is null!!!");
+                            }
+                        } catch (Exception e) {
+                            Log.e(TAG,"",e);
                         }
                     }
                 }
@@ -2033,11 +2124,17 @@
         //TODO(BT)
         /*
         try {
-            return mService.changeApplicationBluetoothState(on, new
+            mServiceLock.readLock().lock();
+            if (mService != null) {
+                return mService.changeApplicationBluetoothState(on, new
                     StateChangeCallbackWrapper(callback), new Binder());
+            }
         } catch (RemoteException e) {
             Log.e(TAG, "changeBluetoothState", e);
-        }*/
+        } finally {
+            mServiceLock.readLock().unlock();
+        }
+        */
         return false;
     }
 
diff --git a/core/java/android/webkit/WebViewFactory.java b/core/java/android/webkit/WebViewFactory.java
index 5db0f16..2d1e0bd 100644
--- a/core/java/android/webkit/WebViewFactory.java
+++ b/core/java/android/webkit/WebViewFactory.java
@@ -142,13 +142,17 @@
     public static int loadWebViewNativeLibraryFromPackage(String packageName,
                                                           ClassLoader clazzLoader) {
         int ret = waitForProviderAndSetPackageInfo();
-        if (ret != LIBLOAD_SUCCESS) {
+        if (ret != LIBLOAD_SUCCESS && ret != LIBLOAD_FAILED_WAITING_FOR_RELRO) {
             return ret;
         }
         if (!sPackageInfo.packageName.equals(packageName))
             return LIBLOAD_WRONG_PACKAGE_NAME;
 
-        return loadNativeLibrary(clazzLoader);
+        int loadNativeRet = loadNativeLibrary(clazzLoader);
+        // If we failed waiting for relro we want to return that fact even if we successfully load
+        // the relro file.
+        if (loadNativeRet == LIBLOAD_SUCCESS) return ret;
+        return loadNativeRet;
     }
 
     static WebViewFactoryProvider getProvider() {
@@ -240,7 +244,8 @@
             } finally {
                 Trace.traceEnd(Trace.TRACE_TAG_WEBVIEW);
             }
-            if (response.status != LIBLOAD_SUCCESS) {
+            if (response.status != LIBLOAD_SUCCESS
+                    && response.status != LIBLOAD_FAILED_WAITING_FOR_RELRO) {
                 throw new MissingWebViewPackageException("Failed to load WebView provider: "
                         + getWebViewPreparationErrorReason(response.status));
             }
@@ -599,8 +604,10 @@
         try {
             response =
                 getUpdateService().waitForAndGetProvider();
-            if (response.status == WebViewFactory.LIBLOAD_SUCCESS)
+            if (response.status == LIBLOAD_SUCCESS
+                    || response.status == LIBLOAD_FAILED_WAITING_FOR_RELRO) {
                 sPackageInfo = response.packageInfo;
+            }
         } catch (RemoteException e) {
             Log.e(LOGTAG, "error waiting for relro creation", e);
             return LIBLOAD_FAILED_WAITING_FOR_WEBVIEW_REASON_UNKNOWN;
diff --git a/core/jni/android_media_AudioRecord.cpp b/core/jni/android_media_AudioRecord.cpp
index 1bc4285..1fc08ed 100644
--- a/core/jni/android_media_AudioRecord.cpp
+++ b/core/jni/android_media_AudioRecord.cpp
@@ -479,17 +479,13 @@
 
 static inline
 jint interpretReadSizeError(ssize_t readSize) {
-    ALOGE_IF(readSize != WOULD_BLOCK, "Error %zd during AudioRecord native read", readSize);
-    switch (readSize) {
-    case WOULD_BLOCK:
+    if (readSize == WOULD_BLOCK) {
         return (jint)0;
-    case BAD_VALUE:
-        return (jint)AUDIO_JAVA_BAD_VALUE;
-    default:
-        // may be possible for other errors such as
-        // NO_INIT to happen if restoreRecord_l fails.
-    case INVALID_OPERATION:
-        return (jint)AUDIO_JAVA_INVALID_OPERATION;
+    } else if (readSize == NO_INIT) {
+        return AUDIO_JAVA_DEAD_OBJECT;
+    } else {
+        ALOGE("Error %zd during AudioRecord native read", readSize);
+        return nativeToJavaStatus(readSize);
     }
 }
 
diff --git a/core/jni/android_media_AudioTrack.cpp b/core/jni/android_media_AudioTrack.cpp
index 024c21d..982a1f8 100644
--- a/core/jni/android_media_AudioTrack.cpp
+++ b/core/jni/android_media_AudioTrack.cpp
@@ -606,6 +606,18 @@
     env->ReleaseFloatArrayElements(array, elems, mode);
 }
 
+static inline
+jint interpretWriteSizeError(ssize_t writeSize) {
+    if (writeSize == WOULD_BLOCK) {
+        return (jint)0;
+    } else if (writeSize == NO_INIT) {
+        return AUDIO_JAVA_DEAD_OBJECT;
+    } else {
+        ALOGE("Error %zd during AudioTrack native read", writeSize);
+        return nativeToJavaStatus(writeSize);
+    }
+}
+
 // ----------------------------------------------------------------------------
 template <typename T>
 static jint writeToTrack(const sp<AudioTrack>& track, jint audioFormat, const T *data,
@@ -628,11 +640,10 @@
         memcpy(track->sharedBuffer()->pointer(), data + offsetInSamples, sizeInBytes);
         written = sizeInBytes;
     }
-    if (written > 0) {
+    if (written >= 0) {
         return written / sizeof(T);
     }
-    // for compatibility, error codes pass through unchanged
-    return written;
+    return interpretWriteSizeError(written);
 }
 
 // ----------------------------------------------------------------------------
diff --git a/core/res/res/layout/work_widget_mask_view.xml b/core/res/res/layout/work_widget_mask_view.xml
index 3c47705..39e1bbb 100644
--- a/core/res/res/layout/work_widget_mask_view.xml
+++ b/core/res/res/layout/work_widget_mask_view.xml
@@ -19,7 +19,8 @@
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:background="#F3374248"
-    android:clickable="true" >
+    android:importantForAccessibility="noHideDescendants"
+    android:clickable="true">
 
     <ImageView android:id="@+id/work_widget_app_icon"
         android:layout_width="wrap_content"
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index dffab2c..45ee778 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -4317,4 +4317,7 @@
     <!-- Description of notification shown when device has been forced to safe mode after a security compromise. -->
     <string name="audit_safemode_notification_details">Touch to learn more.</string>
 
+    <!-- Accessibilty string added to a widget that has been suspended [CHAR LIMIT=20] -->
+    <string name="suspended_widget_accessibility">Suspended <xliff:g id="label" example="Calendar">%1$s</xliff:g></string>
+
 </resources>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 3cb1876..e99d57f 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -2595,4 +2595,5 @@
   <!-- Pinner Service -->
   <java-symbol type="array" name="config_defaultPinnerServiceFiles" />
 
+  <java-symbol type="string" name="suspended_widget_accessibility" />
 </resources>
diff --git a/docs/html/jd_extras_en.js b/docs/html/jd_extras_en.js
index c85ef7e..3aab5bd 100644
--- a/docs/html/jd_extras_en.js
+++ b/docs/html/jd_extras_en.js
@@ -237,7 +237,7 @@
     "title":"Test Your App",
     "summary":"This document describes key concepts related to Android app testing. It assumes you have a basic knowledge of the JUnit testing framework. Android testing is based on JUnit. In general, a JUnit test is a method whose statements test a part of the application\u2026",
     "url":"studio/test/index.html",
-    "image":"images/testing/test_framework.png",
+    "image":"studio/images/test/test-framework.png",
     "type":"studio",
     "keywords": [],
     "tags": [],
diff --git a/media/java/android/media/AudioRecord.java b/media/java/android/media/AudioRecord.java
index 4504e69..8efd599 100644
--- a/media/java/android/media/AudioRecord.java
+++ b/media/java/android/media/AudioRecord.java
@@ -94,6 +94,11 @@
      * Denotes a failure due to the improper use of a method.
      */
     public  static final int ERROR_INVALID_OPERATION               = AudioSystem.INVALID_OPERATION;
+    /**
+     * An error code indicating that the object reporting it is no longer valid and needs to
+     * be recreated.
+     */
+    public  static final int ERROR_DEAD_OBJECT                     = AudioSystem.DEAD_OBJECT;
 
     // Error codes:
     // to keep in sync with frameworks/base/core/jni/android_media_AudioRecord.cpp
@@ -1046,10 +1051,16 @@
      * @param audioData the array to which the recorded audio data is written.
      * @param offsetInBytes index in audioData from which the data is written expressed in bytes.
      * @param sizeInBytes the number of requested bytes.
-     * @return the number of bytes that were read or {@link #ERROR_INVALID_OPERATION}
-     *    if the object wasn't properly initialized, or {@link #ERROR_BAD_VALUE} if
-     *    the parameters don't resolve to valid data and indexes.
-     *    The number of bytes will not exceed sizeInBytes.
+     * @return zero or the positive number of bytes that were read, or one of the following
+     *    error codes. The number of bytes will not exceed sizeInBytes.
+     * <ul>
+     * <li>{@link #ERROR_INVALID_OPERATION} if the object isn't properly initialized</li>
+     * <li>{@link #ERROR_BAD_VALUE} if the parameters don't resolve to valid data and indexes</li>
+     * <li>{@link #ERROR_DEAD_OBJECT} if the object is not valid anymore and
+     *    needs to be recreated. The dead object error code is not returned if some data was
+     *    successfully transferred. In this case, the error is returned at the next read()</li>
+     * <li>{@link #ERROR} in case of other error</li>
+     * </ul>
      */
     public int read(@NonNull byte[] audioData, int offsetInBytes, int sizeInBytes) {
         return read(audioData, offsetInBytes, sizeInBytes, READ_BLOCKING);
@@ -1070,11 +1081,17 @@
      *     is read.
      *     <br>With {@link #READ_NON_BLOCKING}, the read will return immediately after
      *     reading as much audio data as possible without blocking.
-     * @return the number of bytes that were read or {@link #ERROR_INVALID_OPERATION}
-     *    if the object wasn't properly initialized, or {@link #ERROR_BAD_VALUE} if
-     *    the parameters don't resolve to valid data and indexes.
-     *    The number of bytes will be a multiple of the frame size in bytes
+     * @return zero or the positive number of bytes that were read, or one of the following
+     *    error codes. The number of bytes will be a multiple of the frame size in bytes
      *    not to exceed sizeInBytes.
+     * <ul>
+     * <li>{@link #ERROR_INVALID_OPERATION} if the object isn't properly initialized</li>
+     * <li>{@link #ERROR_BAD_VALUE} if the parameters don't resolve to valid data and indexes</li>
+     * <li>{@link #ERROR_DEAD_OBJECT} if the object is not valid anymore and
+     *    needs to be recreated. The dead object error code is not returned if some data was
+     *    successfully transferred. In this case, the error is returned at the next read()</li>
+     * <li>{@link #ERROR} in case of other error</li>
+     * </ul>
      */
     public int read(@NonNull byte[] audioData, int offsetInBytes, int sizeInBytes,
             @ReadMode int readMode) {
@@ -1106,10 +1123,17 @@
      *        Must not be negative, or cause the data access to go out of bounds of the array.
      * @param sizeInShorts the number of requested shorts.
      *        Must not be negative, or cause the data access to go out of bounds of the array.
-     * @return the number of shorts that were read or {@link #ERROR_INVALID_OPERATION}
-     *    if the object wasn't properly initialized, or {@link #ERROR_BAD_VALUE} if
-     *    the parameters don't resolve to valid data and indexes.
-     *    The number of shorts will be a multiple of the channel count not to exceed sizeInShorts.
+     * @return zero or the positive number of shorts that were read, or one of the following
+     *    error codes. The number of shorts will be a multiple of the channel count not to exceed
+     *    sizeInShorts.
+     * <ul>
+     * <li>{@link #ERROR_INVALID_OPERATION} if the object isn't properly initialized</li>
+     * <li>{@link #ERROR_BAD_VALUE} if the parameters don't resolve to valid data and indexes</li>
+     * <li>{@link #ERROR_DEAD_OBJECT} if the object is not valid anymore and
+     *    needs to be recreated. The dead object error code is not returned if some data was
+     *    successfully transferred. In this case, the error is returned at the next read()</li>
+     * <li>{@link #ERROR} in case of other error</li>
+     * </ul>
      */
     public int read(@NonNull short[] audioData, int offsetInShorts, int sizeInShorts) {
         return read(audioData, offsetInShorts, sizeInShorts, READ_BLOCKING);
@@ -1129,10 +1153,17 @@
      *     is read.
      *     <br>With {@link #READ_NON_BLOCKING}, the read will return immediately after
      *     reading as much audio data as possible without blocking.
-     * @return the number of shorts that were read or {@link #ERROR_INVALID_OPERATION}
-     *    if the object wasn't properly initialized, or {@link #ERROR_BAD_VALUE} if
-     *    the parameters don't resolve to valid data and indexes.
-     *    The number of shorts will be a multiple of the channel count not to exceed sizeInShorts.
+     * @return zero or the positive number of shorts that were read, or one of the following
+     *    error codes. The number of shorts will be a multiple of the channel count not to exceed
+     *    sizeInShorts.
+     * <ul>
+     * <li>{@link #ERROR_INVALID_OPERATION} if the object isn't properly initialized</li>
+     * <li>{@link #ERROR_BAD_VALUE} if the parameters don't resolve to valid data and indexes</li>
+     * <li>{@link #ERROR_DEAD_OBJECT} if the object is not valid anymore and
+     *    needs to be recreated. The dead object error code is not returned if some data was
+     *    successfully transferred. In this case, the error is returned at the next read()</li>
+     * <li>{@link #ERROR} in case of other error</li>
+     * </ul>
      */
     public int read(@NonNull short[] audioData, int offsetInShorts, int sizeInShorts,
             @ReadMode int readMode) {
@@ -1169,10 +1200,17 @@
      *     is read.
      *     <br>With {@link #READ_NON_BLOCKING}, the read will return immediately after
      *     reading as much audio data as possible without blocking.
-     * @return the number of floats that were read or {@link #ERROR_INVALID_OPERATION}
-     *    if the object wasn't properly initialized, or {@link #ERROR_BAD_VALUE} if
-     *    the parameters don't resolve to valid data and indexes.
-     *    The number of floats will be a multiple of the channel count not to exceed sizeInFloats.
+     * @return zero or the positive number of floats that were read, or one of the following
+     *    error codes. The number of floats will be a multiple of the channel count not to exceed
+     *    sizeInFloats.
+     * <ul>
+     * <li>{@link #ERROR_INVALID_OPERATION} if the object isn't properly initialized</li>
+     * <li>{@link #ERROR_BAD_VALUE} if the parameters don't resolve to valid data and indexes</li>
+     * <li>{@link #ERROR_DEAD_OBJECT} if the object is not valid anymore and
+     *    needs to be recreated. The dead object error code is not returned if some data was
+     *    successfully transferred. In this case, the error is returned at the next read()</li>
+     * <li>{@link #ERROR} in case of other error</li>
+     * </ul>
      */
     public int read(@NonNull float[] audioData, int offsetInFloats, int sizeInFloats,
             @ReadMode int readMode) {
@@ -1213,11 +1251,17 @@
      * @param sizeInBytes the number of requested bytes. It is recommended but not enforced
      *    that the number of bytes requested be a multiple of the frame size (sample size in
      *    bytes multiplied by the channel count).
-     * @return the number of bytes that were read or {@link #ERROR_INVALID_OPERATION}
-     *    if the object wasn't properly initialized, or {@link #ERROR_BAD_VALUE} if
-     *    the parameters don't resolve to valid data and indexes.
-     *    The number of bytes will not exceed sizeInBytes.
-     *    The number of bytes read will be truncated to be a multiple of the frame size.
+     * @return zero or the positive number of bytes that were read, or one of the following
+     *    error codes. The number of bytes will not exceed sizeInBytes and will be truncated to be
+     *    a multiple of the frame size.
+     * <ul>
+     * <li>{@link #ERROR_INVALID_OPERATION} if the object isn't properly initialized</li>
+     * <li>{@link #ERROR_BAD_VALUE} if the parameters don't resolve to valid data and indexes</li>
+     * <li>{@link #ERROR_DEAD_OBJECT} if the object is not valid anymore and
+     *    needs to be recreated. The dead object error code is not returned if some data was
+     *    successfully transferred. In this case, the error is returned at the next read()</li>
+     * <li>{@link #ERROR} in case of other error</li>
+     * </ul>
      */
     public int read(@NonNull ByteBuffer audioBuffer, int sizeInBytes) {
         return read(audioBuffer, sizeInBytes, READ_BLOCKING);
@@ -1240,11 +1284,17 @@
      *     is read.
      *     <br>With {@link #READ_NON_BLOCKING}, the read will return immediately after
      *     reading as much audio data as possible without blocking.
-     * @return the number of bytes that were read or {@link #ERROR_INVALID_OPERATION}
-     *    if the object wasn't properly initialized, or {@link #ERROR_BAD_VALUE} if
-     *    the parameters don't resolve to valid data and indexes.
-     *    The number of bytes will not exceed sizeInBytes.
-     *    The number of bytes read will be truncated to be a multiple of the frame size.
+     * @return zero or the positive number of bytes that were read, or one of the following
+     *    error codes. The number of bytes will not exceed sizeInBytes and will be truncated to be
+     *    a multiple of the frame size.
+     * <ul>
+     * <li>{@link #ERROR_INVALID_OPERATION} if the object isn't properly initialized</li>
+     * <li>{@link #ERROR_BAD_VALUE} if the parameters don't resolve to valid data and indexes</li>
+     * <li>{@link #ERROR_DEAD_OBJECT} if the object is not valid anymore and
+     *    needs to be recreated. The dead object error code is not returned if some data was
+     *    successfully transferred. In this case, the error is returned at the next read()</li>
+     * <li>{@link #ERROR} in case of other error</li>
+     * </ul>
      */
     public int read(@NonNull ByteBuffer audioBuffer, int sizeInBytes, @ReadMode int readMode) {
         if (mState != STATE_INITIALIZED) {
diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java
index 12e88a2..9a81668 100644
--- a/media/java/android/media/AudioTrack.java
+++ b/media/java/android/media/AudioTrack.java
@@ -156,7 +156,6 @@
     /**
      * An error code indicating that the object reporting it is no longer valid and needs to
      * be recreated.
-     * @hide
      */
     public  static final int ERROR_DEAD_OBJECT                     = AudioSystem.DEAD_OBJECT;
     /**
@@ -1840,17 +1839,17 @@
      *    Must not be negative, or cause the data access to go out of bounds of the array.
      * @param sizeInBytes the number of bytes to write in audioData after the offset.
      *    Must not be negative, or cause the data access to go out of bounds of the array.
-     * @return zero or the positive number of bytes that were written, or
-     *    {@link #ERROR_INVALID_OPERATION}
-     *    if the track isn't properly initialized, or {@link #ERROR_BAD_VALUE} if
-     *    the parameters don't resolve to valid data and indexes, or
-     *    {@link AudioManager#ERROR_DEAD_OBJECT} if the AudioTrack is not valid anymore and
-     *    needs to be recreated.
-     *    The dead object error code is not returned if some data was successfully transferred.
-     *    In this case, the error is returned at the next write().
-     *    The number of bytes will be a multiple of the frame size in bytes
+     * @return zero or the positive number of bytes that were written, or one of the following
+     *    error codes. The number of bytes will be a multiple of the frame size in bytes
      *    not to exceed sizeInBytes.
-     *
+     * <ul>
+     * <li>{@link #ERROR_INVALID_OPERATION} if the track isn't properly initialized</li>
+     * <li>{@link #ERROR_BAD_VALUE} if the parameters don't resolve to valid data and indexes</li>
+     * <li>{@link #ERROR_DEAD_OBJECT} if the AudioTrack is not valid anymore and
+     *    needs to be recreated. The dead object error code is not returned if some data was
+     *    successfully transferred. In this case, the error is returned at the next write()</li>
+     * <li>{@link #ERROR} in case of other error</li>
+     * </ul>
      * This is equivalent to {@link #write(byte[], int, int, int)} with <code>writeMode</code>
      * set to  {@link #WRITE_BLOCKING}.
      */
@@ -1888,16 +1887,17 @@
      *         to the audio sink.
      *     <br>With {@link #WRITE_NON_BLOCKING}, the write will return immediately after
      *     queuing as much audio data for playback as possible without blocking.
-     * @return zero or the positive number of bytes that were written, or
-     *    {@link #ERROR_INVALID_OPERATION}
-     *    if the track isn't properly initialized, or {@link #ERROR_BAD_VALUE} if
-     *    the parameters don't resolve to valid data and indexes, or
-     *    {@link AudioManager#ERROR_DEAD_OBJECT} if the AudioTrack is not valid anymore and
-     *    needs to be recreated.
-     *    The dead object error code is not returned if some data was successfully transferred.
-     *    In this case, the error is returned at the next write().
-     *    The number of bytes will be a multiple of the frame size in bytes
+     * @return zero or the positive number of bytes that were written, or one of the following
+     *    error codes. The number of bytes will be a multiple of the frame size in bytes
      *    not to exceed sizeInBytes.
+     * <ul>
+     * <li>{@link #ERROR_INVALID_OPERATION} if the track isn't properly initialized</li>
+     * <li>{@link #ERROR_BAD_VALUE} if the parameters don't resolve to valid data and indexes</li>
+     * <li>{@link #ERROR_DEAD_OBJECT} if the AudioTrack is not valid anymore and
+     *    needs to be recreated. The dead object error code is not returned if some data was
+     *    successfully transferred. In this case, the error is returned at the next write()</li>
+     * <li>{@link #ERROR} in case of other error</li>
+     * </ul>
      */
     public int write(@NonNull byte[] audioData, int offsetInBytes, int sizeInBytes,
             @WriteMode int writeMode) {
@@ -1950,16 +1950,17 @@
      *    Must not be negative, or cause the data access to go out of bounds of the array.
      * @param sizeInShorts the number of shorts to read in audioData after the offset.
      *    Must not be negative, or cause the data access to go out of bounds of the array.
-     * @return zero or the positive number of shorts that were written, or
-     *    {@link #ERROR_INVALID_OPERATION}
-     *    if the track isn't properly initialized, or {@link #ERROR_BAD_VALUE} if
-     *    the parameters don't resolve to valid data and indexes, or
-     *    {@link AudioManager#ERROR_DEAD_OBJECT} if the AudioTrack is not valid anymore and
-     *    needs to be recreated.
-     *    The dead object error code is not returned if some data was successfully transferred.
-     *    In this case, the error is returned at the next write().
-     *    The number of shorts will be a multiple of the channel count not to exceed sizeInShorts.
-     *
+     * @return zero or the positive number of shorts that were written, or one of the following
+     *    error codes. The number of shorts will be a multiple of the channel count not to
+     *    exceed sizeInShorts.
+     * <ul>
+     * <li>{@link #ERROR_INVALID_OPERATION} if the track isn't properly initialized</li>
+     * <li>{@link #ERROR_BAD_VALUE} if the parameters don't resolve to valid data and indexes</li>
+     * <li>{@link #ERROR_DEAD_OBJECT} if the AudioTrack is not valid anymore and
+     *    needs to be recreated. The dead object error code is not returned if some data was
+     *    successfully transferred. In this case, the error is returned at the next write()</li>
+     * <li>{@link #ERROR} in case of other error</li>
+     * </ul>
      * This is equivalent to {@link #write(short[], int, int, int)} with <code>writeMode</code>
      * set to  {@link #WRITE_BLOCKING}.
      */
@@ -1995,15 +1996,17 @@
      *         to the audio sink.
      *     <br>With {@link #WRITE_NON_BLOCKING}, the write will return immediately after
      *     queuing as much audio data for playback as possible without blocking.
-     * @return zero or the positive number of shorts that were written, or
-     *    {@link #ERROR_INVALID_OPERATION}
-     *    if the track isn't properly initialized, or {@link #ERROR_BAD_VALUE} if
-     *    the parameters don't resolve to valid data and indexes, or
-     *    {@link AudioManager#ERROR_DEAD_OBJECT} if the AudioTrack is not valid anymore and
-     *    needs to be recreated.
-     *    The dead object error code is not returned if some data was successfully transferred.
-     *    In this case, the error is returned at the next write().
-     *    The number of shorts will be a multiple of the channel count not to exceed sizeInShorts.
+     * @return zero or the positive number of shorts that were written, or one of the following
+     *    error codes. The number of shorts will be a multiple of the channel count not to
+     *    exceed sizeInShorts.
+     * <ul>
+     * <li>{@link #ERROR_INVALID_OPERATION} if the track isn't properly initialized</li>
+     * <li>{@link #ERROR_BAD_VALUE} if the parameters don't resolve to valid data and indexes</li>
+     * <li>{@link #ERROR_DEAD_OBJECT} if the AudioTrack is not valid anymore and
+     *    needs to be recreated. The dead object error code is not returned if some data was
+     *    successfully transferred. In this case, the error is returned at the next write()</li>
+     * <li>{@link #ERROR} in case of other error</li>
+     * </ul>
      */
     public int write(@NonNull short[] audioData, int offsetInShorts, int sizeInShorts,
             @WriteMode int writeMode) {
@@ -2074,15 +2077,17 @@
      *         to the audio sink.
      *     <br>With {@link #WRITE_NON_BLOCKING}, the write will return immediately after
      *     queuing as much audio data for playback as possible without blocking.
-     * @return zero or the positive number of floats that were written, or
-     *    {@link #ERROR_INVALID_OPERATION}
-     *    if the track isn't properly initialized, or {@link #ERROR_BAD_VALUE} if
-     *    the parameters don't resolve to valid data and indexes, or
-     *    {@link AudioManager#ERROR_DEAD_OBJECT} if the AudioTrack is not valid anymore and
-     *    needs to be recreated.
-     *    The dead object error code is not returned if some data was successfully transferred.
-     *    In this case, the error is returned at the next write().
-     *    The number of floats will be a multiple of the channel count not to exceed sizeInFloats.
+     * @return zero or the positive number of floats that were written, or one of the following
+     *    error codes. The number of floats will be a multiple of the channel count not to
+     *    exceed sizeInFloats.
+     * <ul>
+     * <li>{@link #ERROR_INVALID_OPERATION} if the track isn't properly initialized</li>
+     * <li>{@link #ERROR_BAD_VALUE} if the parameters don't resolve to valid data and indexes</li>
+     * <li>{@link #ERROR_DEAD_OBJECT} if the AudioTrack is not valid anymore and
+     *    needs to be recreated. The dead object error code is not returned if some data was
+     *    successfully transferred. In this case, the error is returned at the next write()</li>
+     * <li>{@link #ERROR} in case of other error</li>
+     * </ul>
      */
     public int write(@NonNull float[] audioData, int offsetInFloats, int sizeInFloats,
             @WriteMode int writeMode) {
@@ -2154,12 +2159,16 @@
      *         to the audio sink.
      *     <BR>With {@link #WRITE_NON_BLOCKING}, the write will return immediately after
      *     queuing as much audio data for playback as possible without blocking.
-     * @return zero or the positive number of bytes that were written, or
-     *     {@link #ERROR_BAD_VALUE}, {@link #ERROR_INVALID_OPERATION}, or
-     *     {@link AudioManager#ERROR_DEAD_OBJECT} if the AudioTrack is not valid anymore and
-     *     needs to be recreated.
-     *     The dead object error code is not returned if some data was successfully transferred.
-     *     In this case, the error is returned at the next write().
+     * @return zero or the positive number of bytes that were written, or one of the following
+     *    error codes.
+     * <ul>
+     * <li>{@link #ERROR_INVALID_OPERATION} if the track isn't properly initialized</li>
+     * <li>{@link #ERROR_BAD_VALUE} if the parameters don't resolve to valid data and indexes</li>
+     * <li>{@link #ERROR_DEAD_OBJECT} if the AudioTrack is not valid anymore and
+     *    needs to be recreated. The dead object error code is not returned if some data was
+     *    successfully transferred. In this case, the error is returned at the next write()</li>
+     * <li>{@link #ERROR} in case of other error</li>
+     * </ul>
      */
     public int write(@NonNull ByteBuffer audioData, int sizeInBytes,
             @WriteMode int writeMode) {
@@ -2223,12 +2232,16 @@
      *     <BR>With {@link #WRITE_NON_BLOCKING}, the write will return immediately after
      *     queuing as much audio data for playback as possible without blocking.
      * @param timestamp The timestamp of the first decodable audio frame in the provided audioData.
-     * @return zero or a positive number of bytes that were written, or
-     *     {@link #ERROR_BAD_VALUE}, {@link #ERROR_INVALID_OPERATION}, or
-     *     {@link AudioManager#ERROR_DEAD_OBJECT} if the AudioTrack is not valid anymore and
-     *     needs to be recreated.
-     *     The dead object error code is not returned if some data was successfully transferred.
-     *     In this case, the error is returned at the next write().
+     * @return zero or the positive number of bytes that were written, or one of the following
+     *    error codes.
+     * <ul>
+     * <li>{@link #ERROR_INVALID_OPERATION} if the track isn't properly initialized</li>
+     * <li>{@link #ERROR_BAD_VALUE} if the parameters don't resolve to valid data and indexes</li>
+     * <li>{@link #ERROR_DEAD_OBJECT} if the AudioTrack is not valid anymore and
+     *    needs to be recreated. The dead object error code is not returned if some data was
+     *    successfully transferred. In this case, the error is returned at the next write()</li>
+     * <li>{@link #ERROR} in case of other error</li>
+     * </ul>
      */
     public int write(@NonNull ByteBuffer audioData, int sizeInBytes,
             @WriteMode int writeMode, long timestamp) {
diff --git a/media/java/android/media/MediaCodecInfo.java b/media/java/android/media/MediaCodecInfo.java
index b9ed269..87c6d88 100644
--- a/media/java/android/media/MediaCodecInfo.java
+++ b/media/java/android/media/MediaCodecInfo.java
@@ -1918,13 +1918,15 @@
                         case CodecProfileLevel.MPEG2ProfileMain:
                             switch (profileLevel.level) {
                                 case CodecProfileLevel.MPEG2LevelLL:
-                                    FR = 30; W = 22; H =  18; MBPS =  11880; FS =  396; BR =  4000; break;
+                                    FR = 30; W = 22; H =  18; MBPS =  11880; FS =   396; BR =  4000; break;
                                 case CodecProfileLevel.MPEG2LevelML:
-                                    FR = 30; W = 45; H =  36; MBPS =  48600; FS =  1620; BR =  15000; break;
+                                    FR = 30; W = 45; H =  36; MBPS =  48600; FS =  1620; BR = 15000; break;
                                 case CodecProfileLevel.MPEG2LevelH14:
-                                    FR = 60; W = 90; H =  68; MBPS =  367200; FS =  6120; BR = 60000; break;
+                                    FR = 60; W = 90; H =  68; MBPS = 183600; FS =  6120; BR = 60000; break;
                                 case CodecProfileLevel.MPEG2LevelHL:
-                                    FR = 60; W = 120; H = 68; MBPS =  489600; FS =  8160; BR = 80000; break;
+                                    FR = 60; W = 120; H = 68; MBPS = 244800; FS =  8160; BR = 80000; break;
+                                case CodecProfileLevel.MPEG2LevelHP:
+                                    FR = 60; W = 120; H = 68; MBPS = 489600; FS =  8160; BR = 80000; break;
                                 default:
                                     Log.w(TAG, "Unrecognized profile/level "
                                             + profileLevel.profile + "/"
@@ -1982,15 +1984,12 @@
                                     FR = 30; W = 22; H = 18; MBPS =  5940; FS = 396; BR = 128; break;
                                 case CodecProfileLevel.MPEG4Level3:
                                     FR = 30; W = 22; H = 18; MBPS = 11880; FS = 396; BR = 384; break;
-                                case CodecProfileLevel.MPEG4Level4:
                                 case CodecProfileLevel.MPEG4Level4a:
+                                    FR = 30; W = 40; H = 30; MBPS = 36000; FS = 1200; BR = 4000; break;
                                 case CodecProfileLevel.MPEG4Level5:
-                                    // While MPEG4 SP does not have level 4 or 5, some vendors
-                                    // report it. Use the same limits as level 3, but mark as
-                                    // unsupported.
-                                    FR = 30; W = 22; H = 18; MBPS = 11880; FS = 396; BR = 384;
-                                    supported = false;
-                                    break;
+                                    FR = 30; W = 45; H = 36; MBPS = 40500; FS = 1620; BR = 8000; break;
+                                case CodecProfileLevel.MPEG4Level6:
+                                    FR = 30; W = 80; H = 45; MBPS = 108000; FS = 3600; BR = 12000; break;
                                 default:
                                     Log.w(TAG, "Unrecognized profile/level "
                                             + profileLevel.profile + "/"
@@ -2007,12 +2006,9 @@
                                     FR = 30; W = 22; H = 18; MBPS =  5940; FS =  396; BR =  384; break;
                                 case CodecProfileLevel.MPEG4Level3:
                                     FR = 30; W = 22; H = 18; MBPS = 11880; FS =  396; BR =  768; break;
-                                // case CodecProfileLevel.MPEG4Level3b:
-                                // TODO: MPEG4 level 3b is not defined in OMX
-                                //  MBPS = 11880; FS =  396; BR = 1500; break;
+                                case CodecProfileLevel.MPEG4Level3b:
+                                    FR = 30; W = 22; H = 18; MBPS = 11880; FS =  396; BR = 1500; break;
                                 case CodecProfileLevel.MPEG4Level4:
-                                case CodecProfileLevel.MPEG4Level4a:
-                                    // TODO: MPEG4 level 4a is not defined in spec
                                     FR = 30; W = 44; H = 36; MBPS = 23760; FS =  792; BR = 3000; break;
                                 case CodecProfileLevel.MPEG4Level5:
                                     FR = 30; W = 45; H = 36; MBPS = 48600; FS = 1620; BR = 8000; break;
@@ -2640,9 +2636,11 @@
         public static final int MPEG4Level1      = 0x04;
         public static final int MPEG4Level2      = 0x08;
         public static final int MPEG4Level3      = 0x10;
+        public static final int MPEG4Level3b     = 0x18;
         public static final int MPEG4Level4      = 0x20;
         public static final int MPEG4Level4a     = 0x40;
         public static final int MPEG4Level5      = 0x80;
+        public static final int MPEG4Level6      = 0x100;
 
         // from OMX_VIDEO_MPEG2PROFILETYPE
         public static final int MPEG2ProfileSimple              = 0x00;
@@ -2657,6 +2655,7 @@
         public static final int MPEG2LevelML     = 0x01;
         public static final int MPEG2LevelH14    = 0x02;
         public static final int MPEG2LevelHL     = 0x03;
+        public static final int MPEG2LevelHP     = 0x04;
 
         // from OMX_AUDIO_AACPROFILETYPE
         public static final int AACObjectMain       = 1;
diff --git a/packages/Shell/src/com/android/shell/BugreportProgressService.java b/packages/Shell/src/com/android/shell/BugreportProgressService.java
index 474e3e6..6bc4df7 100644
--- a/packages/Shell/src/com/android/shell/BugreportProgressService.java
+++ b/packages/Shell/src/com/android/shell/BugreportProgressService.java
@@ -815,6 +815,14 @@
      */
     private void onBugreportFinished(int id, Intent intent) {
         final File bugreportFile = getFileExtra(intent, EXTRA_BUGREPORT);
+        // Since BugreportProvider and BugreportProgressService aren't tightly coupled,
+        // we need to make sure they are explicitly tied to a single unique notification URI
+        // so that the service can alert the provider of changes it has done (ie. new bug
+        // reports)
+        // See { @link Cursor#setNotificationUri } and {@link ContentResolver#notifyChanges }
+        final Uri notificationUri = BugreportStorageProvider.getNotificationUri();
+        mContext.getContentResolver().notifyChange(notificationUri, null, false);
+
         if (bugreportFile == null) {
             // Should never happen, dumpstate always set the file.
             Log.wtf(TAG, "Missing " + EXTRA_BUGREPORT + " on intent " + intent);
diff --git a/packages/Shell/src/com/android/shell/BugreportStorageProvider.java b/packages/Shell/src/com/android/shell/BugreportStorageProvider.java
index 0f92fa6..8b07599 100644
--- a/packages/Shell/src/com/android/shell/BugreportStorageProvider.java
+++ b/packages/Shell/src/com/android/shell/BugreportStorageProvider.java
@@ -19,9 +19,11 @@
 import android.database.Cursor;
 import android.database.MatrixCursor;
 import android.database.MatrixCursor.RowBuilder;
+import android.net.Uri;
 import android.os.CancellationSignal;
 import android.os.FileUtils;
 import android.os.ParcelFileDescriptor;
+import android.provider.DocumentsContract;
 import android.provider.DocumentsContract.Document;
 import android.provider.DocumentsContract.Root;
 import android.provider.DocumentsProvider;
@@ -32,6 +34,7 @@
 import java.io.FileNotFoundException;
 
 public class BugreportStorageProvider extends DocumentsProvider {
+    private static final String AUTHORITY = "com.android.shell.documents";
     private static final String DOC_ID_ROOT = "bugreport";
 
     private static final String[] DEFAULT_ROOT_PROJECTION = new String[] {
@@ -103,6 +106,7 @@
                 for (File file : files) {
                     addFileRow(result, file);
                 }
+                result.setNotificationUri(getContext().getContentResolver(), getNotificationUri());
             }
         }
         return result;
@@ -130,6 +134,12 @@
         }
     }
 
+    // This is used by BugreportProgressService so that the notification uri shared by
+    // BugreportProgressService and BugreportStorageProvider are guaranteed the same and unique
+    protected static Uri getNotificationUri() {
+      return DocumentsContract.buildChildDocumentsUri(AUTHORITY, DOC_ID_ROOT);
+    }
+
     private static String[] resolveRootProjection(String[] projection) {
         return projection != null ? projection : DEFAULT_ROOT_PROJECTION;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java
index 493b23f..29b4db1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java
@@ -211,7 +211,7 @@
 
     public void animateToggleQSExpansion() {
         // TODO: Better path to animated panel expansion.
-        mHeader.performClick();
+        mHeader.callOnClick();
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/tv/pip/PipManager.java b/packages/SystemUI/src/com/android/systemui/tv/pip/PipManager.java
index 74f0cd3..476598d 100644
--- a/packages/SystemUI/src/com/android/systemui/tv/pip/PipManager.java
+++ b/packages/SystemUI/src/com/android/systemui/tv/pip/PipManager.java
@@ -227,6 +227,13 @@
     }
 
     /**
+     * Updates the PIP per configuration changed.
+     */
+    void onConfigurationChanged() {
+        mPipRecentsOverlayManager.onConfigurationChanged(mContext);
+    }
+
+    /**
      * Shows the picture-in-picture menu if an activity is in picture-in-picture mode.
      */
     public void showTvPictureInPictureMenu() {
diff --git a/packages/SystemUI/src/com/android/systemui/tv/pip/PipRecentsOverlayManager.java b/packages/SystemUI/src/com/android/systemui/tv/pip/PipRecentsOverlayManager.java
index fe5d8bc..6e4a593 100644
--- a/packages/SystemUI/src/com/android/systemui/tv/pip/PipRecentsOverlayManager.java
+++ b/packages/SystemUI/src/com/android/systemui/tv/pip/PipRecentsOverlayManager.java
@@ -42,9 +42,9 @@
 
     private final PipManager mPipManager = PipManager.getInstance();
     private final WindowManager mWindowManager;
-    private final View mOverlayView;
-    private final PipRecentsControlsView mPipControlsView;
-    private final View mRecentsView;
+    private View mOverlayView;
+    private PipRecentsControlsView mPipControlsView;
+    private View mRecentsView;
 
     private final LayoutParams mPipRecentsControlsViewLayoutParams;
     private final LayoutParams mPipRecentsControlsViewFocusedLayoutParams;
@@ -73,6 +73,21 @@
     PipRecentsOverlayManager(Context context) {
         mWindowManager = (WindowManager) context.getSystemService(WindowManager.class);
 
+        mPipRecentsControlsViewLayoutParams = new WindowManager.LayoutParams(
+                LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT,
+                LayoutParams.TYPE_SYSTEM_DIALOG,
+                LayoutParams.FLAG_NOT_FOCUSABLE | LayoutParams.FLAG_NOT_TOUCHABLE,
+                PixelFormat.TRANSLUCENT);
+        mPipRecentsControlsViewFocusedLayoutParams = new WindowManager.LayoutParams(
+                LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT,
+                LayoutParams.TYPE_SYSTEM_DIALOG,
+                0,
+                PixelFormat.TRANSLUCENT);
+
+        initViews(context);
+    }
+
+    private void initViews(Context context) {
         LayoutInflater inflater = (LayoutInflater) context
                 .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
         mOverlayView = inflater.inflate(R.layout.tv_pip_recents_overlay, null);
@@ -86,17 +101,6 @@
                 }
             }
         });
-
-        mPipRecentsControlsViewLayoutParams = new WindowManager.LayoutParams(
-                LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT,
-                LayoutParams.TYPE_SYSTEM_DIALOG,
-                LayoutParams.FLAG_NOT_FOCUSABLE | LayoutParams.FLAG_NOT_TOUCHABLE,
-                PixelFormat.TRANSLUCENT);
-        mPipRecentsControlsViewFocusedLayoutParams = new WindowManager.LayoutParams(
-                LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT,
-                LayoutParams.TYPE_SYSTEM_DIALOG,
-                0,
-                PixelFormat.TRANSLUCENT);
     }
 
     /**
@@ -210,4 +214,14 @@
     boolean isRecentsShown() {
         return mIsRecentsShown;
     }
+
+    /**
+     * Updates the PIP per configuration changed.
+     */
+    void onConfigurationChanged(Context context) {
+        if (mIsRecentsShown) {
+            Log.w(TAG, "Configuration is changed while Recents is shown");
+        }
+        initViews(context);
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/tv/pip/PipUI.java b/packages/SystemUI/src/com/android/systemui/tv/pip/PipUI.java
index 182b9b0..b3e9f43 100644
--- a/packages/SystemUI/src/com/android/systemui/tv/pip/PipUI.java
+++ b/packages/SystemUI/src/com/android/systemui/tv/pip/PipUI.java
@@ -48,6 +48,6 @@
         if (!mSupportPip) {
             return;
         }
-        // TODO: handle configuration change.
+        PipManager.getInstance().onConfigurationChanged();
     }
 }
diff --git a/services/core/java/com/android/server/AlarmManagerService.java b/services/core/java/com/android/server/AlarmManagerService.java
index 1edc9b1..8ad6e6a 100644
--- a/services/core/java/com/android/server/AlarmManagerService.java
+++ b/services/core/java/com/android/server/AlarmManagerService.java
@@ -125,6 +125,8 @@
     long mNativeData;
     private long mNextWakeup;
     private long mNextNonWakeup;
+    private long mLastWakeupSet;
+    private long mLastWakeup;
     int mBroadcastRefCount = 0;
     PowerManager.WakeLock mWakeLock;
     boolean mLastWakeLockUnimportantForLogging;
@@ -1400,6 +1402,9 @@
                     pw.print(" = "); pw.println(sdf.format(new Date(nextNonWakeupRTC)));
             pw.print("  Next wakeup: "); TimeUtils.formatDuration(mNextWakeup, nowELAPSED, pw);
                     pw.print(" = "); pw.println(sdf.format(new Date(nextWakeupRTC)));
+            pw.print("  Last wakeup: "); TimeUtils.formatDuration(mLastWakeup, nowELAPSED, pw);
+            pw.print(" set at "); TimeUtils.formatDuration(mLastWakeupSet, nowELAPSED, pw);
+            pw.println();
             pw.print("  Num time change events: "); pw.println(mNumTimeChanged);
             pw.println("  mDeviceIdleUserWhitelist=" + Arrays.toString(mDeviceIdleUserWhitelist));
 
@@ -1838,6 +1843,7 @@
             final Batch firstBatch = mAlarmBatches.get(0);
             if (firstWakeup != null && mNextWakeup != firstWakeup.start) {
                 mNextWakeup = firstWakeup.start;
+                mLastWakeupSet = SystemClock.elapsedRealtime();
                 setLocked(ELAPSED_REALTIME_WAKEUP, firstWakeup.start);
             }
             if (firstBatch != firstWakeup) {
@@ -2436,6 +2442,7 @@
             while (true)
             {
                 int result = waitForAlarm(mNativeData);
+                mLastWakeup = SystemClock.elapsedRealtime();
 
                 triggerList.clear();
 
@@ -2536,6 +2543,11 @@
                             deliverAlarmsLocked(triggerList, nowELAPSED);
                         }
                     }
+
+                } else {
+                    // Just in case -- even though no wakeup flag was set, make sure
+                    // we have updated the kernel to the next alarm time.
+                    rescheduleKernelAlarmsLocked();
                 }
             }
         }
diff --git a/services/core/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java
index 5e8687a..f30a126 100644
--- a/services/core/java/com/android/server/BluetoothManagerService.java
+++ b/services/core/java/com/android/server/BluetoothManagerService.java
@@ -52,6 +52,7 @@
 import android.provider.Settings;
 import android.provider.Settings.SettingNotFoundException;
 import android.util.Slog;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -126,6 +127,8 @@
     private IBinder mBluetoothBinder;
     private IBluetooth mBluetooth;
     private IBluetoothGatt mBluetoothGatt;
+    private final ReentrantReadWriteLock mBluetoothLock =
+        new ReentrantReadWriteLock();
     private boolean mBinding;
     private boolean mUnbinding;
     // used inside handler thread
@@ -190,12 +193,15 @@
                     }
 
                     int st = BluetoothAdapter.STATE_OFF;
-                    if (mBluetooth != null) {
-                        try {
+                    try {
+                        mBluetoothLock.readLock().lock();
+                        if (mBluetooth != null) {
                             st = mBluetooth.getState();
-                        } catch (RemoteException e) {
-                            Slog.e(TAG,"Unable to call getState", e);
                         }
+                    } catch (RemoteException e) {
+                        Slog.e(TAG, "Unable to call getState", e);
+                    } finally {
+                        mBluetoothLock.readLock().unlock();
                     }
                     Slog.d(TAG, "state" + st);
 
@@ -208,12 +214,15 @@
                         if (st == BluetoothAdapter.STATE_BLE_ON) {
                             //if state is BLE_ON make sure you trigger disableBLE part
                             try {
+                                mBluetoothLock.readLock().lock();
                                 if (mBluetooth != null) {
                                     mBluetooth.onBrEdrDown();
                                     mEnableExternal = false;
                                 }
-                            } catch(RemoteException e) {
+                            } catch (RemoteException e) {
                                 Slog.e(TAG,"Unable to call onBrEdrDown", e);
+                            } finally {
+                                mBluetoothLock.readLock().lock();
                             }
                         } else if (st == BluetoothAdapter.STATE_ON){
                             // disable without persisting the setting
@@ -366,9 +375,8 @@
         Message msg = mHandler.obtainMessage(MESSAGE_REGISTER_ADAPTER);
         msg.obj = callback;
         mHandler.sendMessage(msg);
-        synchronized(mConnection) {
-            return mBluetooth;
-        }
+
+        return mBluetooth;
     }
 
     public void unregisterAdapter(IBluetoothManagerCallback callback) {
@@ -406,12 +414,13 @@
             return false;
         }
 
-        synchronized(mConnection) {
-            try {
-                return (mBluetooth != null && mBluetooth.isEnabled());
-            } catch (RemoteException e) {
-                Slog.e(TAG, "isEnabled()", e);
-            }
+        try {
+            mBluetoothLock.readLock().lock();
+            if (mBluetooth != null) return mBluetooth.isEnabled();
+        } catch (RemoteException e) {
+            Slog.e(TAG, "isEnabled()", e);
+        } finally {
+            mBluetoothLock.readLock().unlock();
         }
         return false;
     }
@@ -424,11 +433,14 @@
             if (mBleAppCount == 0) {
                 if (DBG) Slog.d(TAG, "Disabling LE only mode after application crash");
                 try {
+                    mBluetoothLock.readLock().lock();
                     if (mBluetooth != null) {
                         mBluetooth.onBrEdrDown();
                     }
-                } catch(RemoteException e) {
+                } catch (RemoteException e) {
                      Slog.e(TAG,"Unable to call onBrEdrDown", e);
+                } finally {
+                    mBluetoothLock.readLock().unlock();
                 }
             }
         }
@@ -456,9 +468,12 @@
                     disableBleScanMode();
                     clearBleApps();
                     try {
+                        mBluetoothLock.readLock().lock();
                         if (mBluetooth != null) mBluetooth.onBrEdrDown();
                     } catch (RemoteException e) {
                         Slog.e(TAG, "error when disabling bluetooth", e);
+                    } finally {
+                        mBluetoothLock.readLock().unlock();
                     }
                 }
             }
@@ -472,12 +487,15 @@
     // Disable ble scan only mode.
     private void disableBleScanMode() {
         try {
+            mBluetoothLock.writeLock().lock();
             if (mBluetooth != null && (mBluetooth.getState() != BluetoothAdapter.STATE_ON)) {
                 if (DBG) Slog.d(TAG, "Reseting the mEnable flag for clean disable");
                 mEnable = false;
             }
         } catch (RemoteException e) {
             Slog.e(TAG, "getState()", e);
+        } finally {
+            mBluetoothLock.writeLock().unlock();
         }
     }
 
@@ -536,7 +554,8 @@
      */
     private void onBluetoothGattServiceUp() {
         if (DBG) Slog.d(TAG,"BluetoothGatt Service is Up");
-        try{
+        try {
+            mBluetoothLock.readLock().lock();
             if (isBleAppPresent() == false && mBluetooth != null
                   && mBluetooth.getState() == BluetoothAdapter.STATE_BLE_ON) {
                 mBluetooth.onLeServiceUp();
@@ -546,8 +565,10 @@
                 persistBluetoothSetting(BLUETOOTH_ON_BLUETOOTH);
                 Binder.restoreCallingIdentity(callingIdentity);
             }
-        } catch(RemoteException e) {
-                Slog.e(TAG,"Unable to call onServiceUp", e);
+        } catch (RemoteException e) {
+            Slog.e(TAG,"Unable to call onServiceUp", e);
+        } finally {
+            mBluetoothLock.readLock().unlock();
         }
     }
 
@@ -558,22 +579,25 @@
     private void sendBrEdrDownCallback() {
         if (DBG) Slog.d(TAG,"Calling sendBrEdrDownCallback callbacks");
 
-        if(mBluetooth == null) {
+        if (mBluetooth == null) {
             Slog.w(TAG, "Bluetooth handle is null");
             return;
         }
 
         if (isBleAppPresent() == false) {
             try {
-                mBluetooth.onBrEdrDown();
-            } catch(RemoteException e) {
+                mBluetoothLock.readLock().lock();
+                if (mBluetooth != null) mBluetooth.onBrEdrDown();
+            } catch (RemoteException e) {
                 Slog.e(TAG, "Call to onBrEdrDown() failed.", e);
+            } finally {
+                mBluetoothLock.readLock().unlock();
             }
         } else {
             // Need to stay at BLE ON. Disconnect all Gatt connections
-            try{
+            try {
                 mBluetoothGatt.unregAll();
-            } catch(RemoteException e) {
+            } catch (RemoteException e) {
                 Slog.e(TAG, "Unable to disconnect all apps.", e);
             }
         }
@@ -673,7 +697,8 @@
                 " mBinding = " + mBinding);
         }
 
-        synchronized (mConnection) {
+        try {
+            mBluetoothLock.writeLock().lock();
             if (mUnbinding) return;
             mUnbinding = true;
             if (mBluetooth != null) {
@@ -695,6 +720,8 @@
                 mUnbinding=false;
             }
             mBluetoothGatt = null;
+        } finally {
+            mBluetoothLock.writeLock().unlock();
         }
     }
 
@@ -1010,14 +1037,13 @@
             return BluetoothAdapter.DEFAULT_MAC_ADDRESS;
         }
 
-        synchronized(mConnection) {
-            if (mBluetooth != null) {
-                try {
-                    return mBluetooth.getAddress();
-                } catch (RemoteException e) {
-                    Slog.e(TAG, "getAddress(): Unable to retrieve address remotely..Returning cached address",e);
-                }
-            }
+        try {
+            mBluetoothLock.readLock().lock();
+            if (mBluetooth != null) return mBluetooth.getAddress();
+        } catch (RemoteException e) {
+            Slog.e(TAG, "getAddress(): Unable to retrieve address remotely. Returning cached address", e);
+        } finally {
+            mBluetoothLock.readLock().unlock();
         }
 
         // mAddress is accessed from outside.
@@ -1036,15 +1062,15 @@
             return null;
         }
 
-        synchronized(mConnection) {
-            if (mBluetooth != null) {
-                try {
-                    return mBluetooth.getName();
-                } catch (RemoteException e) {
-                    Slog.e(TAG, "getName(): Unable to retrieve name remotely..Returning cached name",e);
-                }
-            }
+        try {
+            mBluetoothLock.readLock().lock();
+            if (mBluetooth != null) return mBluetooth.getName();
+        } catch (RemoteException e) {
+            Slog.e(TAG, "getName(): Unable to retrieve name remotely. Returning cached name", e);
+        } finally {
+            mBluetoothLock.readLock().unlock();
         }
+
         // mName is accessed from outside.
         // It alright without a lock. Here, bluetooth is off, no other thread is
         // changing mName
@@ -1101,7 +1127,8 @@
             switch (msg.what) {
                 case MESSAGE_GET_NAME_AND_ADDRESS:
                     if (DBG) Slog.d(TAG, "MESSAGE_GET_NAME_AND_ADDRESS");
-                    synchronized(mConnection) {
+                    try {
+                        mBluetoothLock.writeLock().lock();
                         if ((mBluetooth == null) && (!mBinding)) {
                             if (DBG) Slog.d(TAG, "Binding to service to get name and address");
                             mGetNameAddressOnly = true;
@@ -1127,6 +1154,8 @@
                             }
                             mGetNameAddressOnly = false;
                         }
+                    } finally {
+                        mBluetoothLock.writeLock().unlock();
                     }
                     break;
 
@@ -1209,7 +1238,8 @@
                     if (DBG) Slog.d(TAG,"MESSAGE_BLUETOOTH_SERVICE_CONNECTED: " + msg.arg1);
 
                     IBinder service = (IBinder) msg.obj;
-                    synchronized(mConnection) {
+                    try {
+                        mBluetoothLock.writeLock().lock();
                         if (msg.arg1 == SERVICE_IBLUETOOTHGATT) {
                             mBluetoothGatt = IBluetoothGatt.Stub.asInterface(service);
                             onBluetoothGattServiceUp();
@@ -1264,6 +1294,8 @@
                         } catch (RemoteException e) {
                             Slog.e(TAG,"Unable to call enable()",e);
                         }
+                    } finally {
+                        mBluetoothLock.writeLock().unlock();
                     }
 
                     if (!mEnable) {
@@ -1275,9 +1307,10 @@
                 }
                 case MESSAGE_TIMEOUT_BIND: {
                     Slog.e(TAG, "MESSAGE_TIMEOUT_BIND");
-                    synchronized(mConnection) {
-                        mBinding = false;
-                    }
+                    mBluetoothLock.writeLock().lock();
+                    mBinding = false;
+                    mBluetoothLock.writeLock().unlock();
+
                     break;
                 }
                 case MESSAGE_BLUETOOTH_STATE_CHANGE:
@@ -1312,7 +1345,8 @@
                 case MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED:
                 {
                     Slog.e(TAG, "MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED: " + msg.arg1);
-                    synchronized(mConnection) {
+                    try {
+                        mBluetoothLock.writeLock().lock();
                         if (msg.arg1 == SERVICE_IBLUETOOTH) {
                             // if service is unbinded already, do nothing and return
                             if (mBluetooth == null) break;
@@ -1324,6 +1358,8 @@
                             Slog.e(TAG, "Bad msg.arg1: " + msg.arg1);
                             break;
                         }
+                    } finally {
+                        mBluetoothLock.writeLock().unlock();
                     }
 
                     if (mEnable) {
@@ -1369,9 +1405,9 @@
                 case MESSAGE_TIMEOUT_UNBIND:
                 {
                     Slog.e(TAG, "MESSAGE_TIMEOUT_UNBIND");
-                    synchronized(mConnection) {
-                        mUnbinding = false;
-                    }
+                    mBluetoothLock.writeLock().lock();
+                    mUnbinding = false;
+                    mBluetoothLock.writeLock().unlock();
                     break;
                 }
 
@@ -1381,15 +1417,15 @@
 
                     /* disable and enable BT when detect a user switch */
                     if (mEnable && mBluetooth != null) {
-                        synchronized (mConnection) {
+                        try {
+                            mBluetoothLock.readLock().lock();
                             if (mBluetooth != null) {
-                                //Unregister callback object
-                                try {
-                                    mBluetooth.unregisterCallback(mBluetoothCallback);
-                                } catch (RemoteException re) {
-                                    Slog.e(TAG, "Unable to unregister",re);
-                                }
+                                mBluetooth.unregisterCallback(mBluetoothCallback);
                             }
+                        } catch (RemoteException re) {
+                            Slog.e(TAG, "Unable to unregister", re);
+                        } finally {
+                            mBluetoothLock.readLock().unlock();
                         }
 
                         if (mState == BluetoothAdapter.STATE_TURNING_OFF) {
@@ -1420,14 +1456,16 @@
                         bluetoothStateChangeHandler(BluetoothAdapter.STATE_TURNING_OFF,
                                                     BluetoothAdapter.STATE_OFF);
                         sendBluetoothServiceDownCallback();
-                        synchronized (mConnection) {
-                            if (mBluetooth != null) {
-                                mBluetooth = null;
-                                //Unbind
-                                mContext.unbindService(mConnection);
-                            }
-                            mBluetoothGatt = null;
+
+                        mBluetoothLock.writeLock().lock();
+                        if (mBluetooth != null) {
+                            mBluetooth = null;
+                            // Unbind
+                            mContext.unbindService(mConnection);
                         }
+                        mBluetoothGatt = null;
+                        mBluetoothLock.writeLock().unlock();
+
                         SystemClock.sleep(100);
 
                         mHandler.removeMessages(MESSAGE_BLUETOOTH_STATE_CHANGE);
@@ -1450,14 +1488,12 @@
                     if (DBG) Slog.d(TAG, "MESSAGE_USER_UNLOCKED");
                     mHandler.removeMessages(MESSAGE_USER_SWITCHED);
 
-                    synchronized (mConnection) {
-                        if (mEnable && !mBinding && (mBluetooth == null)) {
-                            // We should be connected, but we gave up for some
-                            // reason; maybe the Bluetooth service wasn't encryption
-                            // aware, so try binding again.
-                            if (DBG) Slog.d(TAG, "Enabled but not bound; retrying after unlock");
-                            handleEnable(mQuietEnable);
-                        }
+                    if (mEnable && !mBinding && (mBluetooth == null)) {
+                        // We should be connected, but we gave up for some
+                        // reason; maybe the Bluetooth service wasn't encryption
+                        // aware, so try binding again.
+                        if (DBG) Slog.d(TAG, "Enabled but not bound; retrying after unlock");
+                        handleEnable(mQuietEnable);
                     }
                 }
             }
@@ -1467,7 +1503,8 @@
     private void handleEnable(boolean quietMode) {
         mQuietEnable = quietMode;
 
-        synchronized(mConnection) {
+        try {
+            mBluetoothLock.writeLock().lock();
             if ((mBluetooth == null) && (!mBinding)) {
                 //Start bind timeout and bind
                 Message timeoutMsg=mHandler.obtainMessage(MESSAGE_TIMEOUT_BIND);
@@ -1496,6 +1533,8 @@
                     Slog.e(TAG,"Unable to call enable()",e);
                 }
             }
+        } finally {
+            mBluetoothLock.writeLock().unlock();
         }
     }
 
@@ -1510,18 +1549,18 @@
     }
 
     private void handleDisable() {
-        synchronized(mConnection) {
+        try {
+            mBluetoothLock.readLock().lock();
             if (mBluetooth != null) {
                 if (DBG) Slog.d(TAG,"Sending off request.");
-
-                try {
-                    if(!mBluetooth.disable()) {
-                        Slog.e(TAG,"IBluetooth.disable() returned false");
-                    }
-                } catch (RemoteException e) {
-                    Slog.e(TAG,"Unable to call disable()",e);
+                if (!mBluetooth.disable()) {
+                    Slog.e(TAG,"IBluetooth.disable() returned false");
                 }
             }
+        } catch (RemoteException e) {
+            Slog.e(TAG,"Unable to call disable()",e);
+        } finally {
+            mBluetoothLock.readLock().unlock();
         }
     }
 
@@ -1648,20 +1687,21 @@
     private boolean waitForOnOff(boolean on, boolean off) {
         int i = 0;
         while (i < 10) {
-            synchronized(mConnection) {
-                try {
-                    if (mBluetooth == null) break;
-                    if (on) {
-                        if (mBluetooth.getState() == BluetoothAdapter.STATE_ON) return true;
-                    } else if (off) {
-                        if (mBluetooth.getState() == BluetoothAdapter.STATE_OFF) return true;
-                    } else {
-                        if (mBluetooth.getState() != BluetoothAdapter.STATE_ON) return true;
-                    }
-                } catch (RemoteException e) {
-                    Slog.e(TAG, "getState()", e);
-                    break;
+            try {
+                mBluetoothLock.readLock().lock();
+                if (mBluetooth == null) break;
+                if (on) {
+                    if (mBluetooth.getState() == BluetoothAdapter.STATE_ON) return true;
+                } else if (off) {
+                    if (mBluetooth.getState() == BluetoothAdapter.STATE_OFF) return true;
+                } else {
+                    if (mBluetooth.getState() != BluetoothAdapter.STATE_ON) return true;
                 }
+            } catch (RemoteException e) {
+                Slog.e(TAG, "getState()", e);
+                break;
+            } finally {
+                mBluetoothLock.readLock().unlock();
             }
             if (on || off) {
                 SystemClock.sleep(300);
@@ -1684,34 +1724,36 @@
     }
 
     private boolean canUnbindBluetoothService() {
-        synchronized(mConnection) {
+        try {
             //Only unbind with mEnable flag not set
             //For race condition: disable and enable back-to-back
             //Avoid unbind right after enable due to callback from disable
             //Only unbind with Bluetooth at OFF state
             //Only unbind without any MESSAGE_BLUETOOTH_STATE_CHANGE message
-            try {
-                if (mEnable || (mBluetooth == null)) return false;
-                if (mHandler.hasMessages(MESSAGE_BLUETOOTH_STATE_CHANGE)) return false;
-                return (mBluetooth.getState() == BluetoothAdapter.STATE_OFF);
-            } catch (RemoteException e) {
-                Slog.e(TAG, "getState()", e);
-            }
+            mBluetoothLock.readLock().lock();
+            if (mEnable || (mBluetooth == null)) return false;
+            if (mHandler.hasMessages(MESSAGE_BLUETOOTH_STATE_CHANGE)) return false;
+            return (mBluetooth.getState() == BluetoothAdapter.STATE_OFF);
+        } catch (RemoteException e) {
+            Slog.e(TAG, "getState()", e);
+        } finally {
+            mBluetoothLock.readLock().unlock();
         }
         return false;
     }
 
     private void recoverBluetoothServiceFromError() {
         Slog.e(TAG,"recoverBluetoothServiceFromError");
-        synchronized (mConnection) {
+        try {
+            mBluetoothLock.readLock().lock();
             if (mBluetooth != null) {
                 //Unregister callback object
-                try {
-                    mBluetooth.unregisterCallback(mBluetoothCallback);
-                } catch (RemoteException re) {
-                    Slog.e(TAG, "Unable to unregister",re);
-                }
+                mBluetooth.unregisterCallback(mBluetoothCallback);
             }
+        } catch (RemoteException re) {
+            Slog.e(TAG, "Unable to unregister", re);
+        } finally {
+            mBluetoothLock.readLock().unlock();
         }
 
         SystemClock.sleep(500);
@@ -1722,14 +1764,15 @@
         waitForOnOff(false, true);
 
         sendBluetoothServiceDownCallback();
-        synchronized (mConnection) {
-            if (mBluetooth != null) {
-                mBluetooth = null;
-                //Unbind
-                mContext.unbindService(mConnection);
-            }
-            mBluetoothGatt = null;
+
+        mBluetoothLock.writeLock().lock();
+        if (mBluetooth != null) {
+            mBluetooth = null;
+            // Unbind
+            mContext.unbindService(mConnection);
         }
+        mBluetoothGatt = null;
+        mBluetoothLock.writeLock().unlock();
 
         mHandler.removeMessages(MESSAGE_BLUETOOTH_STATE_CHANGE);
         mState = BluetoothAdapter.STATE_OFF;
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index c096fa5f..95a9781 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -4066,7 +4066,8 @@
             synchronized(mRulesLock) {
                 uidRules = mUidRules.get(uid, RULE_ALLOW_ALL);
             }
-            if ((uidRules & RULE_ALLOW_ALL) == 0) {
+            if (mRestrictBackground && (uidRules & RULE_ALLOW_METERED) == 0
+                    && (uidRules & RULE_TEMPORARY_ALLOW_METERED) == 0) {
                 // we could silently fail or we can filter the available nets to only give
                 // them those they have access to.  Chose the more useful option.
                 networkCapabilities.addCapability(NET_CAPABILITY_NOT_METERED);
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 04be34a..946e4f7 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -2252,6 +2252,7 @@
                                         .setGroup(newAutoBundleKey)
                                         .setFlag(Notification.FLAG_AUTOGROUP_SUMMARY, true)
                                         .setFlag(Notification.FLAG_GROUP_SUMMARY, true)
+                                        .setColor(adjustedSbn.getNotification().color)
                                         .build();
                         summaryNotification.extras.putAll(extras);
                         Intent appIntent = getContext().getPackageManager()
diff --git a/services/core/java/com/android/server/webkit/WebViewUpdateServiceImpl.java b/services/core/java/com/android/server/webkit/WebViewUpdateServiceImpl.java
index 91de797..ecab009 100644
--- a/services/core/java/com/android/server/webkit/WebViewUpdateServiceImpl.java
+++ b/services/core/java/com/android/server/webkit/WebViewUpdateServiceImpl.java
@@ -217,7 +217,7 @@
             mSystemInterface = systemInterface;
         }
 
-        private static final int WAIT_TIMEOUT_MS = 4500; // KEY_DISPATCHING_TIMEOUT is 5000.
+        private static final int WAIT_TIMEOUT_MS = 1000; // KEY_DISPATCHING_TIMEOUT is 5000.
 
         // Keeps track of the number of running relro creations
         private int mNumRelroCreationsStarted = 0;
@@ -487,6 +487,10 @@
                     // Either the current relro creation  isn't done yet, or the new relro creatioin
                     // hasn't kicked off yet (the last relro creation used an out-of-date WebView).
                     webViewStatus = WebViewFactory.LIBLOAD_FAILED_WAITING_FOR_RELRO;
+                    Slog.e(TAG, "Timed out waiting for relro creation, relros started "
+                            + mNumRelroCreationsStarted
+                            + " relros finished " + mNumRelroCreationsFinished
+                            + " package dirty? " + mWebViewPackageDirty);
                 }
             }
             if (!webViewReady) Slog.w(TAG, "creating relro file timed out");
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index aea395d..42eddd5 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -1334,7 +1334,17 @@
             final WindowState wallpaperTarget = mWallpaperControllerLocked.getWallpaperTarget();
             if (wallpaperTarget != null) {
                 final Task task = wallpaperTarget.getTask();
-                if (task != null && !task.isFullscreen()) {
+                final WindowStateAnimator winAnimator = wallpaperTarget.mWinAnimator;
+                // We can only crop the wallpaper using final crop with stack bounds if the target
+                // is not animating, or if it's animating with clip mode STACK_CLIP_AFTER_ANIM.
+                // If it's animating with mode STACK_CLIP_NONE, we shouldn't crop either the task
+                // itself or the wallpaper. If it's animating with STACK_CLIP_BEFORE_ANIM, the crop
+                // is before the transform on the task itself.
+                final boolean useFinalCropOnWallpaper = !winAnimator.isAnimationSet()
+                        || winAnimator.resolveStackClip() == STACK_CLIP_AFTER_ANIM;
+                if (task != null && !task.isFullscreen()
+                        && task.cropWindowsToStackBounds()
+                        && useFinalCropOnWallpaper){
                     final TaskStack stack = task.mStack;
                     if (stack != null && !stack.isFullscreen()) {
                         stack.getDimBounds(mTmpStackBounds);
@@ -1459,7 +1469,7 @@
             // We need to ensure for each surface, that we disable transformation matrix
             // scaling in the same transaction which we resize the surface in.
             // As we are in SCALING_MODE_SCALE_TO_WINDOW, SurfaceFlinger will
-            // then take over the scaling until the new buffer arrives, and things 
+            // then take over the scaling until the new buffer arrives, and things
             // will be seamless.
             mForceScaleUntilResize = true;
         } else {
diff --git a/services/net/java/android/net/apf/ApfFilter.java b/services/net/java/android/net/apf/ApfFilter.java
index 7079b9e..538e8f8 100644
--- a/services/net/java/android/net/apf/ApfFilter.java
+++ b/services/net/java/android/net/apf/ApfFilter.java
@@ -648,14 +648,31 @@
         // Here's a basic summary of what the IPv6 filter program does:
         //
         // if it's not ICMPv6:
+        //   if it's multicast and we're dropping multicast:
+        //     drop
         //   pass
         // if it's ICMPv6 NA to ff02::1:
         //   drop
 
-        // If not ICMPv6, pass
         gen.addLoad8(Register.R0, IPV6_NEXT_HEADER_OFFSET);
-        // TODO: Drop multicast if the multicast filter is enabled.
-        gen.addJumpIfR0NotEquals(IPPROTO_ICMPV6, gen.PASS_LABEL);
+
+        // Drop multicast if the multicast filter is enabled.
+        if (mMulticastFilter) {
+            // Don't touch ICMPv6 multicast here, we deal with it in more detail later.
+            String skipIpv6MulticastFilterLabel = "skipIPv6MulticastFilter";
+            gen.addJumpIfR0Equals(IPPROTO_ICMPV6, skipIpv6MulticastFilterLabel);
+
+            // Drop all other packets sent to ff00::/8.
+            gen.addLoad8(Register.R0, IPV6_DEST_ADDR_OFFSET);
+            gen.addJumpIfR0Equals(0xff, gen.DROP_LABEL);
+            // Not multicast and not ICMPv6. Pass.
+            gen.addJump(gen.PASS_LABEL);
+            gen.defineLabel(skipIpv6MulticastFilterLabel);
+        } else {
+            // If not ICMPv6, pass.
+            gen.addJumpIfR0NotEquals(IPPROTO_ICMPV6, gen.PASS_LABEL);
+        }
+
         // Add unsolicited multicast neighbor announcements filter
         String skipUnsolicitedMulticastNALabel = "skipUnsolicitedMulticastNA";
         // If not neighbor announcements, skip unsolicited multicast NA filter
diff --git a/services/net/java/android/net/dhcp/DhcpClient.java b/services/net/java/android/net/dhcp/DhcpClient.java
index 505d15a..99b10c3 100644
--- a/services/net/java/android/net/dhcp/DhcpClient.java
+++ b/services/net/java/android/net/dhcp/DhcpClient.java
@@ -125,17 +125,18 @@
     public static final int CMD_CONFIGURE_LINKADDRESS       = PUBLIC_BASE + 8;
     public static final int EVENT_LINKADDRESS_CONFIGURED    = PUBLIC_BASE + 9;
 
-    /* Message.arg1 arguments to CMD_POST_DHCP notification */
+    /* Message.arg1 arguments to CMD_POST_DHCP_ACTION notification */
     public static final int DHCP_SUCCESS = 1;
     public static final int DHCP_FAILURE = 2;
 
-    // Messages.
+    // Internal messages.
     private static final int PRIVATE_BASE         = Protocol.BASE_DHCP + 100;
     private static final int CMD_KICK             = PRIVATE_BASE + 1;
     private static final int CMD_RECEIVED_PACKET  = PRIVATE_BASE + 2;
     private static final int CMD_TIMEOUT          = PRIVATE_BASE + 3;
     private static final int CMD_RENEW_DHCP       = PRIVATE_BASE + 4;
-    private static final int CMD_EXPIRE_DHCP      = PRIVATE_BASE + 5;
+    private static final int CMD_REBIND_DHCP      = PRIVATE_BASE + 5;
+    private static final int CMD_EXPIRE_DHCP      = PRIVATE_BASE + 6;
 
     // For message logging.
     private static final Class[] sMessageClasses = { DhcpClient.class };
@@ -177,6 +178,7 @@
     private final WakeupMessage mKickAlarm;
     private final WakeupMessage mTimeoutAlarm;
     private final WakeupMessage mRenewAlarm;
+    private final WakeupMessage mRebindAlarm;
     private final WakeupMessage mExpiryAlarm;
     private final String mIfaceName;
 
@@ -241,8 +243,9 @@
         mKickAlarm = makeWakeupMessage("KICK", CMD_KICK);
         // Used to time out PacketRetransmittingStates.
         mTimeoutAlarm = makeWakeupMessage("TIMEOUT", CMD_TIMEOUT);
-        // Used to schedule DHCP renews.
+        // Used to schedule DHCP reacquisition.
         mRenewAlarm = makeWakeupMessage("RENEW", CMD_RENEW_DHCP);
+        mRebindAlarm = makeWakeupMessage("REBIND", CMD_REBIND_DHCP);
         mExpiryAlarm = makeWakeupMessage("EXPIRY", CMD_EXPIRE_DHCP);
     }
 
@@ -276,6 +279,10 @@
     }
 
     private boolean initSockets() {
+        return initPacketSocket() && initUdpSocket();
+    }
+
+    private boolean initPacketSocket() {
         try {
             mPacketSock = Os.socket(AF_PACKET, SOCK_RAW, ETH_P_IP);
             PacketSocketAddress addr = new PacketSocketAddress((short) ETH_P_IP, mIface.getIndex());
@@ -285,6 +292,10 @@
             Log.e(TAG, "Error creating packet socket", e);
             return false;
         }
+        return true;
+    }
+
+    private boolean initUdpSocket() {
         try {
             mUdpSock = Os.socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
             Os.setsockoptInt(mUdpSock, SOL_SOCKET, SO_REUSEADDR, 1);
@@ -363,16 +374,25 @@
         return (short) ((SystemClock.elapsedRealtime() - mTransactionStartMillis) / 1000);
     }
 
-    private boolean transmitPacket(ByteBuffer buf, String description, Inet4Address to) {
+    private boolean transmitPacket(ByteBuffer buf, String description, int encap, Inet4Address to) {
         try {
-            if (to.equals(INADDR_BROADCAST)) {
+            if (encap == DhcpPacket.ENCAP_L2) {
                 if (DBG) Log.d(TAG, "Broadcasting " + description);
                 Os.sendto(mPacketSock, buf.array(), 0, buf.limit(), 0, mInterfaceBroadcastAddr);
+            } else if (encap == DhcpPacket.ENCAP_BOOTP && to.equals(INADDR_BROADCAST)) {
+                if (DBG) Log.d(TAG, "Broadcasting " + description);
+                // We only send L3-encapped broadcasts in DhcpRebindingState,
+                // where we have an IP address and an unconnected UDP socket.
+                //
+                // N.B.: We only need this codepath because DhcpRequestPacket
+                // hardcodes the source IP address to 0.0.0.0. We could reuse
+                // the packet socket if this ever changes.
+                Os.sendto(mUdpSock, buf, 0, to, DhcpPacket.DHCP_SERVER);
             } else {
                 // It's safe to call getpeername here, because we only send unicast packets if we
-                // have an IP address, and we connect the UDP socket before
-                // ConfiguringInterfaceState#exit.
-                if (DBG) Log.d(TAG, "Unicasting " + description + " to " + Os.getpeername(mUdpSock));
+                // have an IP address, and we connect the UDP socket in DhcpBoundState#enter.
+                if (DBG) Log.d(TAG, String.format("Unicasting %s to %s",
+                        description, Os.getpeername(mUdpSock)));
                 Os.write(mUdpSock, buf);
             }
         } catch(ErrnoException|IOException e) {
@@ -386,14 +406,15 @@
         ByteBuffer packet = DhcpPacket.buildDiscoverPacket(
                 DhcpPacket.ENCAP_L2, mTransactionId, getSecs(), mHwAddr,
                 DO_UNICAST, REQUESTED_PARAMS);
-        return transmitPacket(packet, "DHCPDISCOVER", INADDR_BROADCAST);
+        return transmitPacket(packet, "DHCPDISCOVER", DhcpPacket.ENCAP_L2, INADDR_BROADCAST);
     }
 
     private boolean sendRequestPacket(
             Inet4Address clientAddress, Inet4Address requestedAddress,
             Inet4Address serverAddress, Inet4Address to) {
         // TODO: should we use the transaction ID from the server?
-        int encap = to.equals(INADDR_BROADCAST) ? DhcpPacket.ENCAP_L2 : DhcpPacket.ENCAP_BOOTP;
+        final int encap = INADDR_ANY.equals(clientAddress)
+                ? DhcpPacket.ENCAP_L2 : DhcpPacket.ENCAP_BOOTP;
 
         ByteBuffer packet = DhcpPacket.buildRequestPacket(
                 encap, mTransactionId, getSecs(), clientAddress,
@@ -403,7 +424,7 @@
         String description = "DHCPREQUEST ciaddr=" + clientAddress.getHostAddress() +
                              " request=" + requestedAddress.getHostAddress() +
                              " serverid=" + serverStr;
-        return transmitPacket(packet, description, to);
+        return transmitPacket(packet, description, encap, to);
     }
 
     private void scheduleLeaseTimers() {
@@ -413,14 +434,21 @@
         }
 
         final long now = SystemClock.elapsedRealtime();
-        long renewTime = (now + mDhcpLeaseExpiry) / 2;
-        mRenewAlarm.schedule(renewTime);
-        long secondsHence = (renewTime - now) / 1000;
-        Log.d(TAG, "Scheduling renewal in " + secondsHence + "s");
 
-        mExpiryAlarm.schedule(mDhcpLeaseExpiry);
-        secondsHence = (mDhcpLeaseExpiry - now) / 1000;
-        Log.d(TAG, "Scheduling expiry in " + secondsHence + "s");
+        // TODO: consider getting the renew and rebind timers from T1 and T2.
+        // See also:
+        //     https://tools.ietf.org/html/rfc2131#section-4.4.5
+        //     https://tools.ietf.org/html/rfc1533#section-9.9
+        //     https://tools.ietf.org/html/rfc1533#section-9.10
+        final long remainingDelay = mDhcpLeaseExpiry - now;
+        final long renewDelay = remainingDelay / 2;
+        final long rebindDelay = remainingDelay * 7 / 8;
+        mRenewAlarm.schedule(now + renewDelay);
+        mRebindAlarm.schedule(now + rebindDelay);
+        mExpiryAlarm.schedule(now + remainingDelay);
+        Log.d(TAG, "Scheduling renewal in " + (renewDelay / 1000) + "s");
+        Log.d(TAG, "Scheduling rebind in " + (rebindDelay / 1000) + "s");
+        Log.d(TAG, "Scheduling expiry in " + (remainingDelay / 1000) + "s");
     }
 
     private void notifySuccess() {
@@ -719,7 +747,6 @@
 
     class DhcpRequestingState extends PacketRetransmittingState {
         public DhcpRequestingState() {
-            super();
             mTimeout = DHCP_TIMEOUT_MS / 2;
         }
 
@@ -777,7 +804,11 @@
 
         @Override
         public void exit() {
+            // Clear any extant alarms.
+            mRenewAlarm.cancel();
+            mRebindAlarm.cancel();
             mExpiryAlarm.cancel();
+            clearDhcpState();
             // Tell IpManager to clear the IPv4 address. There is no need to
             // wait for confirmation since any subsequent packets are sent from
             // INADDR_ANY anyway (DISCOVER, REQUEST).
@@ -797,21 +828,7 @@
             super.processMessage(message);
             switch (message.what) {
                 case EVENT_LINKADDRESS_CONFIGURED:
-                    if (mDhcpLease.serverAddress != null &&
-                            !connectUdpSock(mDhcpLease.serverAddress)) {
-                        // There's likely no point in going into DhcpInitState here, we'll probably
-                        // just repeat the transaction, get the same IP address as before, and fail.
-                        //
-                        // NOTE: It is observed that connectUdpSock() basically never fails, due to
-                        // SO_BINDTODEVICE. Examining the local socket address shows it will happily
-                        // return an IPv4 address from another interface, or even return "0.0.0.0".
-                        //
-                        // TODO: Consider deleting this check, following testing on several kernels.
-                        notifyFailure();
-                        transitionTo(mStoppedState);
-                    } else {
-                        transitionTo(mDhcpBoundState);
-                    }
+                    transitionTo(mDhcpBoundState);
                     return HANDLED;
                 default:
                     return NOT_HANDLED;
@@ -823,8 +840,19 @@
         @Override
         public void enter() {
             super.enter();
-            // TODO: DhcpStateMachine only supported renewing at 50% of the lease time,
-            // and did not support rebinding. Now that the legacy DHCP client is gone, fix this.
+            if (mDhcpLease.serverAddress != null && !connectUdpSock(mDhcpLease.serverAddress)) {
+                // There's likely no point in going into DhcpInitState here, we'll probably
+                // just repeat the transaction, get the same IP address as before, and fail.
+                //
+                // NOTE: It is observed that connectUdpSock() basically never fails, due to
+                // SO_BINDTODEVICE. Examining the local socket address shows it will happily
+                // return an IPv4 address from another interface, or even return "0.0.0.0".
+                //
+                // TODO: Consider deleting this check, following testing on several kernels.
+                notifyFailure();
+                transitionTo(mStoppedState);
+            }
+
             scheduleLeaseTimers();
         }
 
@@ -843,18 +871,10 @@
                     return NOT_HANDLED;
             }
         }
-
-        @Override
-        public void exit() {
-            mRenewAlarm.cancel();
-        }
     }
 
-    class DhcpRenewingState extends PacketRetransmittingState {
-        public DhcpRenewingState() {
-            super();
-            mTimeout = DHCP_TIMEOUT_MS;
-        }
+    abstract class DhcpReacquiringState extends PacketRetransmittingState {
+        protected String mLeaseMsg;
 
         @Override
         public void enter() {
@@ -862,16 +882,14 @@
             startNewTransaction();
         }
 
+        abstract protected Inet4Address packetDestination();
+
         protected boolean sendPacket() {
-            // Not specifying a SERVER_IDENTIFIER option is a violation of RFC 2131, but...
-            // http://b/25343517 . Try to make things work anyway by using broadcast renews.
-            Inet4Address to = (mDhcpLease.serverAddress != null) ?
-                    mDhcpLease.serverAddress : INADDR_BROADCAST;
             return sendRequestPacket(
                     (Inet4Address) mDhcpLease.ipAddress.getAddress(),  // ciaddr
                     INADDR_ANY,                                        // DHCP_REQUESTED_IP
                     null,                                              // DHCP_SERVER_IDENTIFIER
-                    to);                                               // packet destination address
+                    packetDestination());                              // packet destination address
         }
 
         protected void receivePacket(DhcpPacket packet) {
@@ -890,7 +908,7 @@
                     // in IpManager and by any overridden relevant handlers of
                     // the registered IpManager.Callback.  IP address changes
                     // are not supported here.
-                    acceptDhcpResults(results, "Renewed");
+                    acceptDhcpResults(results, mLeaseMsg);
                     transitionTo(mDhcpBoundState);
                 }
             } else if (packet instanceof DhcpNakPacket) {
@@ -901,8 +919,57 @@
         }
     }
 
-    // Not implemented--yet. DhcpStateMachine did not implement it either.
-    class DhcpRebindingState extends LoggingState {
+    class DhcpRenewingState extends DhcpReacquiringState {
+        public DhcpRenewingState() {
+            mLeaseMsg = "Renewed";
+        }
+
+        @Override
+        public boolean processMessage(Message message) {
+            if (super.processMessage(message) == HANDLED) {
+                return HANDLED;
+            }
+
+            switch (message.what) {
+                case CMD_REBIND_DHCP:
+                    transitionTo(mDhcpRebindingState);
+                    return HANDLED;
+                default:
+                    return NOT_HANDLED;
+            }
+        }
+
+        @Override
+        protected Inet4Address packetDestination() {
+            // Not specifying a SERVER_IDENTIFIER option is a violation of RFC 2131, but...
+            // http://b/25343517 . Try to make things work anyway by using broadcast renews.
+            return (mDhcpLease.serverAddress != null) ?
+                    mDhcpLease.serverAddress : INADDR_BROADCAST;
+        }
+    }
+
+    class DhcpRebindingState extends DhcpReacquiringState {
+        public DhcpRebindingState() {
+            mLeaseMsg = "Rebound";
+        }
+
+        @Override
+        public void enter() {
+            super.enter();
+
+            // We need to broadcast and possibly reconnect the socket to a
+            // completely different server.
+            closeQuietly(mUdpSock);
+            if (!initUdpSocket()) {
+                Log.e(TAG, "Failed to recreate UDP socket");
+                transitionTo(mDhcpInitState);
+            }
+        }
+
+        @Override
+        protected Inet4Address packetDestination() {
+            return INADDR_BROADCAST;
+        }
     }
 
     class DhcpInitRebootState extends LoggingState {
diff --git a/services/net/java/android/net/ip/IpManager.java b/services/net/java/android/net/ip/IpManager.java
index d8eab35..cece6c8 100644
--- a/services/net/java/android/net/ip/IpManager.java
+++ b/services/net/java/android/net/ip/IpManager.java
@@ -1027,6 +1027,8 @@
     }
 
     class StartedState extends State {
+        private boolean mDhcpActionInFlight;
+
         @Override
         public void enter() {
             mStartTimeMillis = SystemClock.elapsedRealtime();
@@ -1066,7 +1068,7 @@
         @Override
         public void exit() {
             mProvisioningTimeoutAlarm.cancel();
-            mDhcpActionTimeoutAlarm.cancel();
+            stopDhcpAction();
 
             if (mIpReachabilityMonitor != null) {
                 mIpReachabilityMonitor.stop();
@@ -1086,16 +1088,22 @@
             resetLinkProperties();
         }
 
-        private void startDhcpAction() {
-            mCallback.onPreDhcpAction();
-            final long alarmTime = SystemClock.elapsedRealtime() +
-                    mConfiguration.mRequestedPreDhcpActionMs;
-            mDhcpActionTimeoutAlarm.schedule(alarmTime);
+        private void ensureDhcpAction() {
+            if (!mDhcpActionInFlight) {
+                mCallback.onPreDhcpAction();
+                mDhcpActionInFlight = true;
+                final long alarmTime = SystemClock.elapsedRealtime() +
+                        mConfiguration.mRequestedPreDhcpActionMs;
+                mDhcpActionTimeoutAlarm.schedule(alarmTime);
+            }
         }
 
         private void stopDhcpAction() {
             mDhcpActionTimeoutAlarm.cancel();
-            mCallback.onPostDhcpAction();
+            if (mDhcpActionInFlight) {
+                mCallback.onPostDhcpAction();
+                mDhcpActionInFlight = false;
+            }
         }
 
         @Override
@@ -1165,9 +1173,8 @@
                     break;
 
                 case DhcpClient.CMD_PRE_DHCP_ACTION:
-                    if (VDBG) { Log.d(mTag, "onPreDhcpAction()"); }
                     if (mConfiguration.mRequestedPreDhcpActionMs > 0) {
-                        startDhcpAction();
+                        ensureDhcpAction();
                     } else {
                         sendMessage(EVENT_PRE_DHCP_ACTION_COMPLETE);
                     }
@@ -1193,18 +1200,18 @@
                 // This message is only received when:
                 //
                 //     a) initial address acquisition succeeds,
-                //     b) renew succeeds,
-                //     c) renew fails,
+                //     b) renew succeeds or is NAK'd,
+                //     c) rebind succeeds or is NAK'd, or
+                //     c) the lease expires,
                 //
                 // but never when initial address acquisition fails. The latter
                 // condition is now governed by the provisioning timeout.
-                case DhcpClient.CMD_POST_DHCP_ACTION: {
+                case DhcpClient.CMD_POST_DHCP_ACTION:
                     stopDhcpAction();
 
-                    final DhcpResults dhcpResults = (DhcpResults) msg.obj;
                     switch (msg.arg1) {
                         case DhcpClient.DHCP_SUCCESS:
-                            handleIPv4Success(dhcpResults);
+                            handleIPv4Success((DhcpResults) msg.obj);
                             break;
                         case DhcpClient.DHCP_FAILURE:
                             handleIPv4Failure();
@@ -1213,7 +1220,6 @@
                             Log.e(mTag, "Unknown CMD_POST_DHCP_ACTION status:" + msg.arg1);
                     }
                     break;
-                }
 
                 case DhcpClient.CMD_ON_QUIT:
                     // DHCPv4 quit early for some reason.
diff --git a/services/tests/servicestests/src/android/net/apf/ApfTest.java b/services/tests/servicestests/src/android/net/apf/ApfTest.java
index e9c5bdd..9e04d23 100644
--- a/services/tests/servicestests/src/android/net/apf/ApfTest.java
+++ b/services/tests/servicestests/src/android/net/apf/ApfTest.java
@@ -720,36 +720,52 @@
     }
 
     @LargeTest
-    public void testApfFilterIPv4Multicast() throws Exception {
+    public void testApfFilterMulticast() throws Exception {
         MockIpManagerCallback ipManagerCallback = new MockIpManagerCallback();
         ApfFilter apfFilter = new TestApfFilter(ipManagerCallback, false /* multicastFilter */);
         byte[] program = ipManagerCallback.getApfProgram();
 
+        // Construct IPv4 and IPv6 multicast packets.
+        ByteBuffer v4packet = ByteBuffer.wrap(new byte[100]);
+        v4packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IP);
+        v4packet.position(IPV4_DEST_ADDR_OFFSET);
+        v4packet.put(new byte[]{(byte)224,0,0,1});
+
+        ByteBuffer v6packet = ByteBuffer.wrap(new byte[100]);
+        v6packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IPV6);
+        v6packet.put(IPV6_NEXT_HEADER_OFFSET, (byte)IPPROTO_UDP);
+        v6packet.position(IPV6_DEST_ADDR_OFFSET);
+        v6packet.put(new byte[]{(byte)0xff,2,0,0,0,0,0,0,0,0,0,0,0,0,0,(byte)0xfb});
+
         // Verify initially disabled multicast filter is off
-        ByteBuffer packet = ByteBuffer.wrap(new byte[100]);
-        packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IP);
-        packet.position(IPV4_DEST_ADDR_OFFSET);
-        packet.put(new byte[]{(byte)224,0,0,1});
-        assertPass(program, packet.array(), 0);
+        assertPass(program, v4packet.array(), 0);
+        assertPass(program, v6packet.array(), 0);
 
         // Turn on multicast filter and verify it works
         ipManagerCallback.resetApfProgramWait();
         apfFilter.setMulticastFilter(true);
         program = ipManagerCallback.getApfProgram();
-        assertDrop(program, packet.array(), 0);
+        assertDrop(program, v4packet.array(), 0);
+        assertDrop(program, v6packet.array(), 0);
 
         // Turn off multicast filter and verify it's off
         ipManagerCallback.resetApfProgramWait();
         apfFilter.setMulticastFilter(false);
         program = ipManagerCallback.getApfProgram();
-        assertPass(program, packet.array(), 0);
+        assertPass(program, v4packet.array(), 0);
+        assertPass(program, v6packet.array(), 0);
 
         // Verify it can be initialized to on
         ipManagerCallback.resetApfProgramWait();
         apfFilter.shutdown();
         apfFilter = new TestApfFilter(ipManagerCallback, true /* multicastFilter */);
         program = ipManagerCallback.getApfProgram();
-        assertDrop(program, packet.array(), 0);
+        assertDrop(program, v4packet.array(), 0);
+        assertDrop(program, v6packet.array(), 0);
+
+        // Verify that ICMPv6 multicast is not dropped.
+        v6packet.put(IPV6_NEXT_HEADER_OFFSET, (byte)IPPROTO_ICMPV6);
+        assertPass(program, v6packet.array(), 0);
 
         apfFilter.shutdown();
     }
@@ -839,7 +855,7 @@
     @LargeTest
     public void testApfFilterRa() throws Exception {
         MockIpManagerCallback ipManagerCallback = new MockIpManagerCallback();
-        TestApfFilter apfFilter = new TestApfFilter(ipManagerCallback, false /* multicastFilter */);
+        TestApfFilter apfFilter = new TestApfFilter(ipManagerCallback, true /* multicastFilter */);
         byte[] program = ipManagerCallback.getApfProgram();
 
         // Verify RA is passed the first time
@@ -848,6 +864,8 @@
         basePacket.put(IPV6_NEXT_HEADER_OFFSET, (byte)IPPROTO_ICMPV6);
         basePacket.put(ICMP6_TYPE_OFFSET, (byte)ICMP6_ROUTER_ADVERTISEMENT);
         basePacket.putShort(ICMP6_RA_ROUTER_LIFETIME_OFFSET, (short)1000);
+        basePacket.position(IPV6_DEST_ADDR_OFFSET);
+        basePacket.put(IPV6_ALL_NODES_ADDRESS);
         assertPass(program, basePacket.array(), 0);
 
         testRaLifetime(apfFilter, ipManagerCallback, basePacket, 1000);
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
index 57d68fd..51f5899 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
@@ -1101,7 +1101,7 @@
                 if (hit && doit) {
                     // The user is force stopping our current interactor/recognizer.
                     // Clear the current settings and restore default state.
-                    synchronized (VoiceInteractionManagerService.this) {
+                    synchronized (VoiceInteractionManagerServiceStub.this) {
                         unloadAllKeyphraseModels();
                         if (mImpl != null) {
                             mImpl.shutdownLocked();
@@ -1126,7 +1126,7 @@
                 int userHandle = getChangingUserId();
                 if (DEBUG) Slog.d(TAG, "onSomePackagesChanged user=" + userHandle);
 
-                synchronized (VoiceInteractionManagerService.this) {
+                synchronized (VoiceInteractionManagerServiceStub.this) {
                     ComponentName curInteractor = getCurInteractor(userHandle);
                     ComponentName curRecognizer = getCurRecognizer(userHandle);
                     if (curRecognizer == null) {