Merge "MidiManager: Add MIDI device status notifications"
diff --git a/api/current.txt b/api/current.txt
index 612d16d..c1c6dc8 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -24062,6 +24062,7 @@
     field public static final java.lang.String CACHED_NUMBER_LABEL = "numberlabel";
     field public static final java.lang.String CACHED_NUMBER_TYPE = "numbertype";
     field public static final java.lang.String CACHED_PHOTO_ID = "photo_id";
+    field public static final java.lang.String CACHED_PHOTO_URI = "photo_uri";
     field public static final android.net.Uri CONTENT_FILTER_URI;
     field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/calls";
     field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/calls";
@@ -25930,7 +25931,6 @@
     field public static final deprecated java.lang.String ALWAYS_FINISH_ACTIVITIES = "always_finish_activities";
     field public static final deprecated java.lang.String ANDROID_ID = "android_id";
     field public static final deprecated java.lang.String ANIMATOR_DURATION_SCALE = "animator_duration_scale";
-    field public static final java.lang.String APPEND_FOR_LAST_AUDIBLE = "_last_audible";
     field public static final deprecated java.lang.String AUTO_TIME = "auto_time";
     field public static final deprecated java.lang.String AUTO_TIME_ZONE = "auto_time_zone";
     field public static final java.lang.String BLUETOOTH_DISCOVERABILITY = "bluetooth_discoverability";
@@ -25993,14 +25993,6 @@
     field public static final java.lang.String USER_ROTATION = "user_rotation";
     field public static final deprecated java.lang.String USE_GOOGLE_MAIL = "use_google_mail";
     field public static final java.lang.String VIBRATE_ON = "vibrate_on";
-    field public static final java.lang.String VOLUME_ALARM = "volume_alarm";
-    field public static final java.lang.String VOLUME_BLUETOOTH_SCO = "volume_bluetooth_sco";
-    field public static final java.lang.String VOLUME_MUSIC = "volume_music";
-    field public static final java.lang.String VOLUME_NOTIFICATION = "volume_notification";
-    field public static final java.lang.String VOLUME_RING = "volume_ring";
-    field public static final java.lang.String[] VOLUME_SETTINGS;
-    field public static final java.lang.String VOLUME_SYSTEM = "volume_system";
-    field public static final java.lang.String VOLUME_VOICE = "volume_voice";
     field public static final deprecated java.lang.String WAIT_FOR_DEBUGGER = "wait_for_debugger";
     field public static final deprecated java.lang.String WALLPAPER_ACTIVITY = "wallpaper_activity";
     field public static final deprecated java.lang.String WIFI_MAX_DHCP_RETRY_COUNT = "wifi_max_dhcp_retry_count";
@@ -36933,6 +36925,26 @@
     method public abstract void onReceivedIcon(java.lang.String, android.graphics.Bitmap);
   }
 
+  public class WebMessage {
+    ctor public WebMessage(java.lang.String);
+    ctor public WebMessage(java.lang.String, android.webkit.WebMessagePort[]);
+    method public java.lang.String getData();
+    method public android.webkit.WebMessagePort[] getPorts();
+  }
+
+  public abstract class WebMessagePort {
+    ctor public WebMessagePort();
+    method public abstract void close();
+    method public abstract void postMessage(android.webkit.WebMessage);
+    method public abstract void setWebMessageCallback(android.webkit.WebMessagePort.WebMessageCallback);
+    method public abstract void setWebMessageCallback(android.webkit.WebMessagePort.WebMessageCallback, android.os.Handler);
+  }
+
+  public static abstract class WebMessagePort.WebMessageCallback {
+    ctor public WebMessagePort.WebMessageCallback();
+    method public void onMessage(android.webkit.WebMessagePort, android.webkit.WebMessage);
+  }
+
   public abstract class WebResourceError {
     ctor public WebResourceError();
     method public abstract java.lang.String getDescription();
@@ -37176,6 +37188,7 @@
     method public android.webkit.WebBackForwardList copyBackForwardList();
     method public deprecated android.print.PrintDocumentAdapter createPrintDocumentAdapter();
     method public android.print.PrintDocumentAdapter createPrintDocumentAdapter(java.lang.String);
+    method public android.webkit.WebMessagePort[] createWebMessageChannel();
     method public void destroy();
     method public void documentHasImages(android.os.Message);
     method public static void enableSlowWholeDocumentDraw();
@@ -37216,6 +37229,7 @@
     method public boolean pageDown(boolean);
     method public boolean pageUp(boolean);
     method public void pauseTimers();
+    method public void postMessageToMainFrame(android.webkit.WebMessage, android.net.Uri);
     method public void postUrl(java.lang.String, byte[]);
     method public void reload();
     method public void removeJavascriptInterface(java.lang.String);
diff --git a/api/removed.txt b/api/removed.txt
index 8668a77..1b209a9 100644
--- a/api/removed.txt
+++ b/api/removed.txt
@@ -34,6 +34,22 @@
 
 }
 
+package android.provider {
+
+  public static final class Settings.System extends android.provider.Settings.NameValueTable {
+    field public static final java.lang.String APPEND_FOR_LAST_AUDIBLE = "_last_audible";
+    field public static final java.lang.String VOLUME_ALARM = "volume_alarm";
+    field public static final java.lang.String VOLUME_BLUETOOTH_SCO = "volume_bluetooth_sco";
+    field public static final java.lang.String VOLUME_MUSIC = "volume_music";
+    field public static final java.lang.String VOLUME_NOTIFICATION = "volume_notification";
+    field public static final java.lang.String VOLUME_RING = "volume_ring";
+    field public static final java.lang.String[] VOLUME_SETTINGS;
+    field public static final java.lang.String VOLUME_SYSTEM = "volume_system";
+    field public static final java.lang.String VOLUME_VOICE = "volume_voice";
+  }
+
+}
+
 package android.text.format {
 
   public class DateFormat {
diff --git a/api/system-current.txt b/api/system-current.txt
index ff9809f..e94a3cf 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -25667,6 +25667,7 @@
     field public static final java.lang.String CACHED_NUMBER_LABEL = "numberlabel";
     field public static final java.lang.String CACHED_NUMBER_TYPE = "numbertype";
     field public static final java.lang.String CACHED_PHOTO_ID = "photo_id";
+    field public static final java.lang.String CACHED_PHOTO_URI = "photo_uri";
     field public static final android.net.Uri CONTENT_FILTER_URI;
     field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/calls";
     field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/calls";
@@ -27536,7 +27537,6 @@
     field public static final deprecated java.lang.String ALWAYS_FINISH_ACTIVITIES = "always_finish_activities";
     field public static final deprecated java.lang.String ANDROID_ID = "android_id";
     field public static final deprecated java.lang.String ANIMATOR_DURATION_SCALE = "animator_duration_scale";
-    field public static final java.lang.String APPEND_FOR_LAST_AUDIBLE = "_last_audible";
     field public static final deprecated java.lang.String AUTO_TIME = "auto_time";
     field public static final deprecated java.lang.String AUTO_TIME_ZONE = "auto_time_zone";
     field public static final java.lang.String BLUETOOTH_DISCOVERABILITY = "bluetooth_discoverability";
@@ -27599,14 +27599,6 @@
     field public static final java.lang.String USER_ROTATION = "user_rotation";
     field public static final deprecated java.lang.String USE_GOOGLE_MAIL = "use_google_mail";
     field public static final java.lang.String VIBRATE_ON = "vibrate_on";
-    field public static final java.lang.String VOLUME_ALARM = "volume_alarm";
-    field public static final java.lang.String VOLUME_BLUETOOTH_SCO = "volume_bluetooth_sco";
-    field public static final java.lang.String VOLUME_MUSIC = "volume_music";
-    field public static final java.lang.String VOLUME_NOTIFICATION = "volume_notification";
-    field public static final java.lang.String VOLUME_RING = "volume_ring";
-    field public static final java.lang.String[] VOLUME_SETTINGS;
-    field public static final java.lang.String VOLUME_SYSTEM = "volume_system";
-    field public static final java.lang.String VOLUME_VOICE = "volume_voice";
     field public static final deprecated java.lang.String WAIT_FOR_DEBUGGER = "wait_for_debugger";
     field public static final deprecated java.lang.String WALLPAPER_ACTIVITY = "wallpaper_activity";
     field public static final deprecated java.lang.String WIFI_MAX_DHCP_RETRY_COUNT = "wifi_max_dhcp_retry_count";
@@ -39162,6 +39154,26 @@
     method public abstract void onReceivedIcon(java.lang.String, android.graphics.Bitmap);
   }
 
+  public class WebMessage {
+    ctor public WebMessage(java.lang.String);
+    ctor public WebMessage(java.lang.String, android.webkit.WebMessagePort[]);
+    method public java.lang.String getData();
+    method public android.webkit.WebMessagePort[] getPorts();
+  }
+
+  public abstract class WebMessagePort {
+    ctor public WebMessagePort();
+    method public abstract void close();
+    method public abstract void postMessage(android.webkit.WebMessage);
+    method public abstract void setWebMessageCallback(android.webkit.WebMessagePort.WebMessageCallback);
+    method public abstract void setWebMessageCallback(android.webkit.WebMessagePort.WebMessageCallback, android.os.Handler);
+  }
+
+  public static abstract class WebMessagePort.WebMessageCallback {
+    ctor public WebMessagePort.WebMessageCallback();
+    method public void onMessage(android.webkit.WebMessagePort, android.webkit.WebMessage);
+  }
+
   public abstract class WebResourceError {
     ctor public WebResourceError();
     method public abstract java.lang.String getDescription();
@@ -39419,6 +39431,7 @@
     method public android.webkit.WebBackForwardList copyBackForwardList();
     method public deprecated android.print.PrintDocumentAdapter createPrintDocumentAdapter();
     method public android.print.PrintDocumentAdapter createPrintDocumentAdapter(java.lang.String);
+    method public android.webkit.WebMessagePort[] createWebMessageChannel();
     method public void destroy();
     method public void documentHasImages(android.os.Message);
     method public static void enableSlowWholeDocumentDraw();
@@ -39460,6 +39473,7 @@
     method public boolean pageDown(boolean);
     method public boolean pageUp(boolean);
     method public void pauseTimers();
+    method public void postMessageToMainFrame(android.webkit.WebMessage, android.net.Uri);
     method public void postUrl(java.lang.String, byte[]);
     method public void reload();
     method public void removeJavascriptInterface(java.lang.String);
@@ -39672,6 +39686,7 @@
     method public abstract void clearView();
     method public abstract android.webkit.WebBackForwardList copyBackForwardList();
     method public abstract android.print.PrintDocumentAdapter createPrintDocumentAdapter(java.lang.String);
+    method public abstract android.webkit.WebMessagePort[] createWebMessageChannel();
     method public abstract void destroy();
     method public abstract void documentHasImages(android.os.Message);
     method public abstract void dumpViewHierarchyWithProperties(java.io.BufferedWriter, int);
@@ -39718,6 +39733,7 @@
     method public abstract boolean pageDown(boolean);
     method public abstract boolean pageUp(boolean);
     method public abstract void pauseTimers();
+    method public abstract void postMessageToMainFrame(android.webkit.WebMessage, android.net.Uri);
     method public abstract void postUrl(java.lang.String, byte[]);
     method public abstract void reload();
     method public abstract void removeJavascriptInterface(java.lang.String);
diff --git a/api/system-removed.txt b/api/system-removed.txt
index 8668a77..1b209a9 100644
--- a/api/system-removed.txt
+++ b/api/system-removed.txt
@@ -34,6 +34,22 @@
 
 }
 
+package android.provider {
+
+  public static final class Settings.System extends android.provider.Settings.NameValueTable {
+    field public static final java.lang.String APPEND_FOR_LAST_AUDIBLE = "_last_audible";
+    field public static final java.lang.String VOLUME_ALARM = "volume_alarm";
+    field public static final java.lang.String VOLUME_BLUETOOTH_SCO = "volume_bluetooth_sco";
+    field public static final java.lang.String VOLUME_MUSIC = "volume_music";
+    field public static final java.lang.String VOLUME_NOTIFICATION = "volume_notification";
+    field public static final java.lang.String VOLUME_RING = "volume_ring";
+    field public static final java.lang.String[] VOLUME_SETTINGS;
+    field public static final java.lang.String VOLUME_SYSTEM = "volume_system";
+    field public static final java.lang.String VOLUME_VOICE = "volume_voice";
+  }
+
+}
+
 package android.text.format {
 
   public class DateFormat {
diff --git a/core/java/android/annotation/ColorInt.java b/core/java/android/annotation/ColorInt.java
index c4c93ee..69d196c 100644
--- a/core/java/android/annotation/ColorInt.java
+++ b/core/java/android/annotation/ColorInt.java
@@ -29,6 +29,8 @@
  * int, {@code AARRGGBB}. If applied to an int array, every element
  * in the array represents a color integer.
  * <p>
+ * Example:
+ * <pre>{@code
  *  public abstract void setTextColor(&#64;ColorInt int color);
  * }</pre>
  *
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 4a3650f..e23ffe4 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -3681,9 +3681,14 @@
     /**
      * Check whether the current user has been blocked by device policy from uninstalling a package.
      * Requires the caller to be the profile owner if checking a specific admin's policy.
+     * <p>
+     * <strong>Note:</strong> Starting from {@link android.os.Build.VERSION_CODES#LOLLIPOP_MR1}, the
+     * behavior of this API is changed such that passing <code>null</code> as the <code>admin</code>
+     * parameter will return if any admin has blocked the uninstallation. Before L MR1, passing
+     * <code>null</code> will cause a NullPointerException to be raised.
      *
      * @param admin The name of the admin component whose blocking policy will be checked, or null
-     *        to check if any admin has blocked the uninstallation.
+     *            to check if any admin has blocked the uninstallation.
      * @param packageName package to check.
      * @return true if uninstallation is blocked.
      */
diff --git a/core/java/android/provider/CallLog.java b/core/java/android/provider/CallLog.java
index 2df9dbf..6517f35 100644
--- a/core/java/android/provider/CallLog.java
+++ b/core/java/android/provider/CallLog.java
@@ -328,6 +328,14 @@
         public static final String CACHED_PHOTO_ID = "photo_id";
 
         /**
+         * The cached photo URI of the picture associated with the phone number, if it exists.
+         * This value may not be current if the contact information associated with this number
+         * has changed.
+         * <P>Type: TEXT (URI)</P>
+         */
+        public static final String CACHED_PHOTO_URI = "photo_uri";
+
+        /**
          * The cached phone number, formatted with formatting rules based on the country the
          * user was in when the call was made or received.
          * This value is not guaranteed to be present, and may not be current if the contact
diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java
index cc7783f..91a19dc 100644
--- a/core/java/android/provider/ContactsContract.java
+++ b/core/java/android/provider/ContactsContract.java
@@ -4600,6 +4600,15 @@
         public static final Uri CONTENT_URI = Uri.withAppendedPath(AUTHORITY_URI, "data");
 
         /**
+        * The content:// style URI for this table in managed profile, which requests a directory
+        * of data rows matching the selection criteria.
+        *
+        * @hide
+        */
+        static final Uri ENTERPRISE_CONTENT_URI = Uri.withAppendedPath(AUTHORITY_URI,
+                "data_enterprise");
+
+        /**
          * A boolean parameter for {@link Data#CONTENT_URI}.
          * This specifies whether or not the returned data items should be filtered to show
          * data items belonging to visible contacts only.
@@ -5751,6 +5760,20 @@
                     "phones");
 
             /**
+            * URI used for getting all contacts from primary and managed profile.
+            *
+            * It supports the same semantics as {@link #CONTENT_URI} and returns the same
+            * columns.  If the device has no corp profile that is linked to the current profile, it
+            * behaves in the exact same way as {@link #CONTENT_URI}.  If there is a corp profile
+            * linked to the current profile, it will merge corp profile and current profile's
+            * results and return
+            *
+            * @hide
+            */
+            public static final Uri ENTERPRISE_CONTENT_URI =
+                    Uri.withAppendedPath(Data.ENTERPRISE_CONTENT_URI, "phones");
+
+            /**
              * The content:// style URL for phone lookup using a filter. The filter returns
              * records of MIME type {@link #CONTENT_ITEM_TYPE}. The filter is applied
              * to display names as well as phone numbers. The filter argument should be passed
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index c60a906..cc84932 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -2254,54 +2254,66 @@
         /**
          * Ringer volume. This is used internally, changing this value will not
          * change the volume. See AudioManager.
+         *
+         * @removed Not used by anything since API 2.
          */
         public static final String VOLUME_RING = "volume_ring";
 
         /**
          * System/notifications volume. This is used internally, changing this
          * value will not change the volume. See AudioManager.
+         *
+         * @removed Not used by anything since API 2.
          */
         public static final String VOLUME_SYSTEM = "volume_system";
 
         /**
          * Voice call volume. This is used internally, changing this value will
          * not change the volume. See AudioManager.
+         *
+         * @removed Not used by anything since API 2.
          */
         public static final String VOLUME_VOICE = "volume_voice";
 
         /**
          * Music/media/gaming volume. This is used internally, changing this
          * value will not change the volume. See AudioManager.
+         *
+         * @removed Not used by anything since API 2.
          */
         public static final String VOLUME_MUSIC = "volume_music";
 
         /**
          * Alarm volume. This is used internally, changing this
          * value will not change the volume. See AudioManager.
+         *
+         * @removed Not used by anything since API 2.
          */
         public static final String VOLUME_ALARM = "volume_alarm";
 
         /**
          * Notification volume. This is used internally, changing this
          * value will not change the volume. See AudioManager.
+         *
+         * @removed Not used by anything since API 2.
          */
         public static final String VOLUME_NOTIFICATION = "volume_notification";
 
         /**
          * Bluetooth Headset volume. This is used internally, changing this value will
          * not change the volume. See AudioManager.
+         *
+         * @removed Not used by anything since API 2.
          */
         public static final String VOLUME_BLUETOOTH_SCO = "volume_bluetooth_sco";
 
         /**
          * Master volume (float in the range 0.0f to 1.0f).
+         *
          * @hide
          */
         public static final String VOLUME_MASTER = "volume_master";
 
-        private static final Validator VOLUME_MASTER_VALIDATOR =
-                new InclusiveFloatRangeValidator(0, 1);
-
         /**
          * Master volume mute (int 1 = mute, 0 = not muted).
          *
@@ -2358,6 +2370,8 @@
 
         /**
          * The mapping of stream type (integer) to its setting.
+         *
+         * @removed  Not used by anything since API 2.
          */
         public static final String[] VOLUME_SETTINGS = {
             VOLUME_VOICE, VOLUME_SYSTEM, VOLUME_RING, VOLUME_MUSIC,
@@ -2368,6 +2382,8 @@
          * Appended to various volume related settings to record the previous
          * values before they the settings were affected by a silent/vibrate
          * ringer mode change.
+         *
+         * @removed  Not used by anything since API 2.
          */
         public static final String APPEND_FOR_LAST_AUDIBLE = "_last_audible";
 
@@ -2981,20 +2997,6 @@
             SCREEN_AUTO_BRIGHTNESS_ADJ,
             VIBRATE_INPUT_DEVICES,
             MODE_RINGER_STREAMS_AFFECTED,
-            VOLUME_VOICE,
-            VOLUME_SYSTEM,
-            VOLUME_RING,
-            VOLUME_MUSIC,
-            VOLUME_ALARM,
-            VOLUME_NOTIFICATION,
-            VOLUME_BLUETOOTH_SCO,
-            VOLUME_VOICE + APPEND_FOR_LAST_AUDIBLE,
-            VOLUME_SYSTEM + APPEND_FOR_LAST_AUDIBLE,
-            VOLUME_RING + APPEND_FOR_LAST_AUDIBLE,
-            VOLUME_MUSIC + APPEND_FOR_LAST_AUDIBLE,
-            VOLUME_ALARM + APPEND_FOR_LAST_AUDIBLE,
-            VOLUME_NOTIFICATION + APPEND_FOR_LAST_AUDIBLE,
-            VOLUME_BLUETOOTH_SCO + APPEND_FOR_LAST_AUDIBLE,
             TEXT_AUTO_REPLACE,
             TEXT_AUTO_CAPS,
             TEXT_AUTO_PUNCTUATE,
@@ -3167,7 +3169,6 @@
             VALIDATORS.put(ADVANCED_SETTINGS, ADVANCED_SETTINGS_VALIDATOR);
             VALIDATORS.put(SCREEN_AUTO_BRIGHTNESS_ADJ, SCREEN_AUTO_BRIGHTNESS_ADJ_VALIDATOR);
             VALIDATORS.put(VIBRATE_INPUT_DEVICES, VIBRATE_INPUT_DEVICES_VALIDATOR);
-            VALIDATORS.put(VOLUME_MASTER, VOLUME_MASTER_VALIDATOR);
             VALIDATORS.put(VOLUME_MASTER_MUTE, VOLUME_MASTER_MUTE_VALIDATOR);
             VALIDATORS.put(MICROPHONE_MUTE, MICROPHONE_MUTE_VALIDATOR);
             VALIDATORS.put(NOTIFICATIONS_USE_RING_VOLUME, NOTIFICATIONS_USE_RING_VOLUME_VALIDATOR);
diff --git a/core/java/android/service/trust/TrustAgentService.java b/core/java/android/service/trust/TrustAgentService.java
index 706b934..a3178e2 100644
--- a/core/java/android/service/trust/TrustAgentService.java
+++ b/core/java/android/service/trust/TrustAgentService.java
@@ -122,12 +122,14 @@
                 case MSG_CONFIGURE:
                     ConfigurationData data = (ConfigurationData) msg.obj;
                     boolean result = onConfigure(data.options);
-                    try {
-                        synchronized (mLock) {
-                            mCallback.onConfigureCompleted(result, data.token);
+                    if (data.token != null) {
+                        try {
+                            synchronized (mLock) {
+                                mCallback.onConfigureCompleted(result, data.token);
+                            }
+                        } catch (RemoteException e) {
+                            onError("calling onSetTrustAgentFeaturesEnabledCompleted()");
                         }
-                    } catch (RemoteException e) {
-                        onError("calling onSetTrustAgentFeaturesEnabledCompleted()");
                     }
                     break;
                 case MSG_TRUST_TIMEOUT:
@@ -203,7 +205,7 @@
      * PersistableBundle)}.
      * <p>Agents that support configuration options should overload this method and return 'true'.
      *
-     * @param options bundle containing all options or null if none.
+     * @param options The aggregated list of options or an empty list if no restrictions apply.
      * @return true if the {@link TrustAgentService} supports configuration options.
      */
     public boolean onConfigure(List<PersistableBundle> options) {
diff --git a/core/java/android/text/StaticLayout.java b/core/java/android/text/StaticLayout.java
index 967e80c..0d35f9c 100644
--- a/core/java/android/text/StaticLayout.java
+++ b/core/java/android/text/StaticLayout.java
@@ -540,7 +540,7 @@
                 while (breakIndex < breakCount && paraStart + breaks[breakIndex] <= spanEnd) {
                     int endPos = paraStart + breaks[breakIndex];
 
-                    boolean moreChars = (endPos < paraEnd); // XXX is this the right way to calculate this?
+                    boolean moreChars = (endPos < bufEnd);
 
                     v = out(source, here, endPos,
                             fmAscent, fmDescent, fmTop, fmBottom,
diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/DisplayListCanvas.java
similarity index 85%
rename from core/java/android/view/GLES20Canvas.java
rename to core/java/android/view/DisplayListCanvas.java
index 06e196d..90e1f86 100644
--- a/core/java/android/view/GLES20Canvas.java
+++ b/core/java/android/view/DisplayListCanvas.java
@@ -16,6 +16,7 @@
 
 package android.view;
 
+import android.annotation.NonNull;
 import android.graphics.Bitmap;
 import android.graphics.CanvasProperty;
 import android.graphics.NinePatch;
@@ -24,19 +25,50 @@
 import android.graphics.Picture;
 import android.graphics.Rect;
 import android.graphics.RectF;
+import android.util.Pools.SynchronizedPool;
 
 /**
- * An implementation of Canvas on top of OpenGL ES 2.0.
+ * An implementation of a GL canvas that records drawing operations.
+ * This is intended for use with a DisplayList. This class keeps a list of all the Paint and
+ * Bitmap objects that it draws, preventing the backing memory of Bitmaps from being freed while
+ * the DisplayList is still holding a native reference to the memory.
  */
-class GLES20Canvas extends HardwareCanvas {
+class DisplayListCanvas extends HardwareCanvas {
+    // The recording canvas pool should be large enough to handle a deeply nested
+    // view hierarchy because display lists are generated recursively.
+    private static final int POOL_LIMIT = 25;
+
+    private static final SynchronizedPool<DisplayListCanvas> sPool =
+            new SynchronizedPool<DisplayListCanvas>(POOL_LIMIT);
+
+    RenderNode mNode;
     private int mWidth;
     private int mHeight;
 
-    private float[] mPoint;
-    private float[] mLine;
 
-    private Rect mClipBounds;
-    private RectF mPathBounds;
+    static DisplayListCanvas obtain(@NonNull RenderNode node) {
+        if (node == null) throw new IllegalArgumentException("node cannot be null");
+        DisplayListCanvas canvas = sPool.acquire();
+        if (canvas == null) {
+            canvas = new DisplayListCanvas();
+        }
+        canvas.mNode = node;
+        return canvas;
+    }
+
+    void recycle() {
+        mNode = null;
+        sPool.release(this);
+    }
+
+    long finishRecording() {
+        return nFinishRecording(mNativeCanvasWrapper);
+    }
+
+    @Override
+    public boolean isRecordingFor(Object o) {
+        return o == mNode;
+    }
 
     ///////////////////////////////////////////////////////////////////////////
     // JNI
@@ -53,8 +85,8 @@
     // Constructors
     ///////////////////////////////////////////////////////////////////////////
 
-    // TODO: Merge with GLES20RecordingCanvas
-    protected GLES20Canvas() {
+
+    private DisplayListCanvas() {
         super(nCreateDisplayListRenderer());
     }
 
diff --git a/core/java/android/view/GLES20RecordingCanvas.java b/core/java/android/view/GLES20RecordingCanvas.java
deleted file mode 100644
index 6c780c9..0000000
--- a/core/java/android/view/GLES20RecordingCanvas.java
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.view;
-
-import android.annotation.NonNull;
-import android.util.Pools.SynchronizedPool;
-
-/**
- * An implementation of a GL canvas that records drawing operations.
- * This is intended for use with a DisplayList. This class keeps a list of all the Paint and
- * Bitmap objects that it draws, preventing the backing memory of Bitmaps from being freed while
- * the DisplayList is still holding a native reference to the memory.
- */
-class GLES20RecordingCanvas extends GLES20Canvas {
-    // The recording canvas pool should be large enough to handle a deeply nested
-    // view hierarchy because display lists are generated recursively.
-    private static final int POOL_LIMIT = 25;
-
-    private static final SynchronizedPool<GLES20RecordingCanvas> sPool =
-            new SynchronizedPool<GLES20RecordingCanvas>(POOL_LIMIT);
-
-    RenderNode mNode;
-
-    private GLES20RecordingCanvas() {
-        super();
-    }
-
-    static GLES20RecordingCanvas obtain(@NonNull RenderNode node) {
-        if (node == null) throw new IllegalArgumentException("node cannot be null");
-        GLES20RecordingCanvas canvas = sPool.acquire();
-        if (canvas == null) {
-            canvas = new GLES20RecordingCanvas();
-        }
-        canvas.mNode = node;
-        return canvas;
-    }
-
-    void recycle() {
-        mNode = null;
-        sPool.release(this);
-    }
-
-    long finishRecording() {
-        return nFinishRecording(mNativeCanvasWrapper);
-    }
-
-    @Override
-    public boolean isRecordingFor(Object o) {
-        return o == mNode;
-    }
-}
diff --git a/core/java/android/view/HardwareCanvas.java b/core/java/android/view/HardwareCanvas.java
index cdb350f..fc2b55b 100644
--- a/core/java/android/view/HardwareCanvas.java
+++ b/core/java/android/view/HardwareCanvas.java
@@ -119,6 +119,6 @@
             CanvasProperty<Paint> paint);
 
     public static void setProperty(String name, String value) {
-        GLES20Canvas.setProperty(name, value);
+        DisplayListCanvas.setProperty(name, value);
     }
 }
diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java
index 9921be2..afa7f51 100644
--- a/core/java/android/view/HardwareRenderer.java
+++ b/core/java/android/view/HardwareRenderer.java
@@ -205,7 +205,7 @@
      *         false otherwise
      */
     public static boolean isAvailable() {
-        return GLES20Canvas.isAvailable();
+        return DisplayListCanvas.isAvailable();
     }
 
     /**
@@ -423,7 +423,7 @@
      */
     static HardwareRenderer create(Context context, boolean translucent) {
         HardwareRenderer renderer = null;
-        if (GLES20Canvas.isAvailable()) {
+        if (DisplayListCanvas.isAvailable()) {
             renderer = new ThreadedRenderer(context, translucent);
         }
         return renderer;
diff --git a/core/java/android/view/RenderNode.java b/core/java/android/view/RenderNode.java
index 09eb486..38867a8 100644
--- a/core/java/android/view/RenderNode.java
+++ b/core/java/android/view/RenderNode.java
@@ -225,7 +225,7 @@
      * @see #isValid()
      */
     public HardwareCanvas start(int width, int height) {
-        HardwareCanvas canvas = GLES20RecordingCanvas.obtain(this);
+        HardwareCanvas canvas = DisplayListCanvas.obtain(this);
         canvas.setViewport(width, height);
         // The dirty rect should always be null for a display list
         canvas.onPreDraw(null);
@@ -241,11 +241,11 @@
      * @see #isValid()
      */
     public void end(HardwareCanvas endCanvas) {
-        if (!(endCanvas instanceof GLES20RecordingCanvas)) {
+        if (!(endCanvas instanceof DisplayListCanvas)) {
             throw new IllegalArgumentException("Passed an invalid canvas to end!");
         }
 
-        GLES20RecordingCanvas canvas = (GLES20RecordingCanvas) endCanvas;
+        DisplayListCanvas canvas = (DisplayListCanvas) endCanvas;
         canvas.onPostDraw();
         long renderNodeData = canvas.finishRecording();
         nSetDisplayListData(mNativeRenderNode, renderNodeData);
diff --git a/core/java/android/view/RenderNodeAnimator.java b/core/java/android/view/RenderNodeAnimator.java
index 7b35a3b..379796d 100644
--- a/core/java/android/view/RenderNodeAnimator.java
+++ b/core/java/android/view/RenderNodeAnimator.java
@@ -283,10 +283,10 @@
     }
 
     public void setTarget(Canvas canvas) {
-        if (!(canvas instanceof GLES20RecordingCanvas)) {
+        if (!(canvas instanceof DisplayListCanvas)) {
             throw new IllegalArgumentException("Not a GLES20RecordingCanvas");
         }
-        final GLES20RecordingCanvas recordingCanvas = (GLES20RecordingCanvas) canvas;
+        final DisplayListCanvas recordingCanvas = (DisplayListCanvas) canvas;
         setTarget(recordingCanvas.mNode);
     }
 
diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java
index 69b4c47..51fefe9 100644
--- a/core/java/android/view/ThreadedRenderer.java
+++ b/core/java/android/view/ThreadedRenderer.java
@@ -102,7 +102,6 @@
     private final float mLightRadius;
     private final int mAmbientShadowAlpha;
     private final int mSpotShadowAlpha;
-    private final float mDensity;
 
     private long mNativeProxy;
     private boolean mInitialized = false;
@@ -119,7 +118,6 @@
                 (int) (255 * a.getFloat(R.styleable.Lighting_ambientShadowAlpha, 0) + 0.5f);
         mSpotShadowAlpha = (int) (255 * a.getFloat(R.styleable.Lighting_spotShadowAlpha, 0) + 0.5f);
         a.recycle();
-        mDensity = context.getResources().getDisplayMetrics().density;
 
         long rootNodePtr = nCreateRootRenderNode();
         mRootNode = RenderNode.adopt(rootNodePtr);
@@ -128,10 +126,6 @@
 
         AtlasInitializer.sInstance.init(context, mNativeProxy);
 
-        // Setup timing
-        mChoreographer = Choreographer.getInstance();
-        nSetFrameInterval(mNativeProxy, mChoreographer.getFrameIntervalNanos());
-
         loadSystemProperties();
     }
 
@@ -224,7 +218,7 @@
         mRootNode.setLeftTopRightBottom(-mInsetLeft, -mInsetTop, mSurfaceWidth, mSurfaceHeight);
         nSetup(mNativeProxy, mSurfaceWidth, mSurfaceHeight,
                 lightX, mLightY, mLightZ, mLightRadius,
-                mAmbientShadowAlpha, mSpotShadowAlpha, mDensity);
+                mAmbientShadowAlpha, mSpotShadowAlpha);
     }
 
     @Override
@@ -379,6 +373,7 @@
 
     @Override
     void setName(String name) {
+        nSetName(mNativeProxy, name);
     }
 
     @Override
@@ -487,15 +482,15 @@
     private static native long nCreateProxy(boolean translucent, long rootRenderNode);
     private static native void nDeleteProxy(long nativeProxy);
 
-    private static native void nSetFrameInterval(long nativeProxy, long frameIntervalNanos);
     private static native boolean nLoadSystemProperties(long nativeProxy);
+    private static native void nSetName(long nativeProxy, String name);
 
     private static native boolean nInitialize(long nativeProxy, Surface window);
     private static native void nUpdateSurface(long nativeProxy, Surface window);
     private static native boolean nPauseSurface(long nativeProxy, Surface window);
     private static native void nSetup(long nativeProxy, int width, int height,
             float lightX, float lightY, float lightZ, float lightRadius,
-            int ambientShadowAlpha, int spotShadowAlpha, float density);
+            int ambientShadowAlpha, int spotShadowAlpha);
     private static native void nSetOpaque(long nativeProxy, boolean opaque);
     private static native int nSyncAndDrawFrame(long nativeProxy, long[] frameInfo, int size);
     private static native void nDestroy(long nativeProxy);
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 7d49969..085a3f2 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -13089,6 +13089,7 @@
      *
      * @see #onDetachedFromWindow()
      */
+    @CallSuper
     protected void onAttachedToWindow() {
         if ((mPrivateFlags & PFLAG_REQUEST_TRANSPARENT_REGIONS) != 0) {
             mParent.requestTransparentRegion(this);
@@ -13421,6 +13422,7 @@
      *
      * @see #onAttachedToWindow()
      */
+    @CallSuper
     protected void onDetachedFromWindow() {
     }
 
@@ -13741,6 +13743,7 @@
      * @see #dispatchSaveInstanceState(android.util.SparseArray)
      * @see #setSaveEnabled(boolean)
      */
+    @CallSuper
     protected Parcelable onSaveInstanceState() {
         mPrivateFlags |= PFLAG_SAVE_STATE_CALLED;
         return BaseSavedState.EMPTY_STATE;
@@ -13799,6 +13802,7 @@
      * @see #restoreHierarchyState(android.util.SparseArray)
      * @see #dispatchRestoreInstanceState(android.util.SparseArray)
      */
+    @CallSuper
     protected void onRestoreInstanceState(Parcelable state) {
         mPrivateFlags |= PFLAG_SAVE_STATE_CALLED;
         if (state != BaseSavedState.EMPTY_STATE && state != null) {
@@ -17987,6 +17991,7 @@
      * @see #setAnimation(android.view.animation.Animation)
      * @see #getAnimation()
      */
+    @CallSuper
     protected void onAnimationStart() {
         mPrivateFlags |= PFLAG_ANIMATION_STARTED;
     }
@@ -17999,6 +18004,7 @@
      * @see #setAnimation(android.view.animation.Animation)
      * @see #getAnimation()
      */
+    @CallSuper
     protected void onAnimationEnd() {
         mPrivateFlags &= ~PFLAG_ANIMATION_STARTED;
     }
diff --git a/core/java/android/webkit/WebMessage.java b/core/java/android/webkit/WebMessage.java
new file mode 100644
index 0000000..7683a40
--- /dev/null
+++ b/core/java/android/webkit/WebMessage.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.webkit;
+
+/**
+ * The Java representation of the HTML5 PostMessage event. See
+ * https://html.spec.whatwg.org/multipage/comms.html#the-messageevent-interfaces
+ * for definition of a MessageEvent in HTML5.
+ *
+ */
+public class WebMessage {
+
+    private String mData;
+    private WebMessagePort[] mPorts;
+
+    /**
+     * Creates a WebMessage.
+     * @param data  the data of the message.
+     */
+    public WebMessage(String data) {
+        mData = data;
+    }
+
+    /**
+     * Creates a WebMessage.
+     * @param data  the data of the message.
+     * @param ports  the ports that are sent with the message.
+     */
+    public WebMessage(String data, WebMessagePort[] ports) {
+        mData = data;
+        mPorts = ports;
+    }
+
+    /**
+     * Returns the data of the message.
+     */
+    public String getData() {
+        return mData;
+    }
+
+    /**
+     * Returns the ports that are sent with the message, or null if no port
+     * is sent.
+     */
+    public WebMessagePort[] getPorts() {
+        return mPorts;
+    }
+}
diff --git a/core/java/android/webkit/WebMessagePort.java b/core/java/android/webkit/WebMessagePort.java
new file mode 100644
index 0000000..eab27bd
--- /dev/null
+++ b/core/java/android/webkit/WebMessagePort.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.webkit;
+
+import android.os.Handler;
+
+/**
+ * The Java representation of the HTML5 Message Port. See
+ * https://html.spec.whatwg.org/multipage/comms.html#messageport
+ * for definition of MessagePort in HTML5.
+ *
+ * A Message port represents one endpoint of a Message Channel. In Android
+ * webview, there is no separate Message Channel object. When a message channel
+ * is created, both ports are tangled to each other and started, and then
+ * returned in a MessagePort array, see {@link WebView#createWebMessageChannel}
+ * for creating a message channel.
+ *
+ * When a message port is first created or received via transfer, it does not
+ * have a WebMessageCallback to receive web messages. The messages are queued until
+ * a WebMessageCallback is set.
+ */
+public abstract class WebMessagePort {
+
+    /**
+     * The listener for handling MessagePort events. The message callback
+     * methods are called on the main thread. If the embedder application
+     * wants to receive the messages on a different thread, it can do this
+     * by passing a Handler in
+     *  {@link WebMessagePort#setWebMessageCallback(WebMessageCallback, Handler)}.
+     * In the latter case, the application should be extra careful for thread safety
+     * since WebMessagePort methods should be called on main thread.
+     */
+    public static abstract class WebMessageCallback {
+        /**
+         * Message callback for receiving onMessage events.
+         *
+         * @param port  the WebMessagePort that the message is destined for
+         * @param message  the message from the entangled port.
+         */
+        public void onMessage(WebMessagePort port, WebMessage message) { }
+    }
+
+    /**
+     * Post a WebMessage to the entangled port.
+     *
+     * @param message  the message from Java to JS.
+     *
+     * @throws IllegalStateException If message port is already transferred or closed.
+     */
+    public abstract void postMessage(WebMessage message);
+
+    /**
+     * Close the message port and free any resources associated with it.
+     */
+    public abstract void close();
+
+    /**
+     * Sets a callback to receive message events on the main thread.
+     *
+     * @param callback  the message callback.
+     */
+    public abstract void setWebMessageCallback(WebMessageCallback callback);
+
+    /**
+     * Sets a callback to receive message events on the handler that is provided
+     * by the application.
+     *
+     * @param callback  the message callback.
+     * @param handler   the handler to receive the message messages.
+     */
+    public abstract void setWebMessageCallback(WebMessageCallback callback, Handler handler);
+}
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 01a506c..67ad642 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -27,6 +27,7 @@
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
 import android.net.http.SslCertificate;
+import android.net.Uri;
 import android.os.Build;
 import android.os.Bundle;
 import android.os.Looper;
@@ -1825,6 +1826,37 @@
     }
 
     /**
+     * Creates a message channel to communicate with JS and returns the message
+     * ports that represent the endpoints of this message channel. The HTML5 message
+     * channel functionality is described here:
+     * https://html.spec.whatwg.org/multipage/comms.html#messagechannel
+     *
+     * The returned message channels are entangled and already in started state.
+     *
+     * @return the two message ports that form the message channel.
+     */
+    public WebMessagePort[] createWebMessageChannel() {
+        checkThread();
+        if (TRACE) Log.d(LOGTAG, "createWebMessageChannel");
+        return mProvider.createWebMessageChannel();
+    }
+
+    /**
+     * Post a message to main frame. The embedded application can restrict the
+     * messages to a certain target origin. See
+     *    https://html.spec.whatwg.org/multipage/comms.html#posting-messages
+     * for how target origin can be used.
+     *
+     * @param message the WebMessage
+     * @param targetOrigin the target origin.
+     */
+    public void postMessageToMainFrame(WebMessage message, Uri targetOrigin) {
+        checkThread();
+        if (TRACE) Log.d(LOGTAG, "postMessageToMainFrame. TargetOrigin=" + targetOrigin);
+        mProvider.postMessageToMainFrame(message, targetOrigin);
+    }
+
+    /**
      * Gets the WebSettings object used to control the settings for this
      * WebView.
      *
diff --git a/core/java/android/webkit/WebViewProvider.java b/core/java/android/webkit/WebViewProvider.java
index 379a732..0cdb875 100644
--- a/core/java/android/webkit/WebViewProvider.java
+++ b/core/java/android/webkit/WebViewProvider.java
@@ -25,6 +25,7 @@
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
 import android.net.http.SslCertificate;
+import android.net.Uri;
 import android.os.Bundle;
 import android.os.Message;
 import android.print.PrintDocumentAdapter;
@@ -227,6 +228,10 @@
 
     public void removeJavascriptInterface(String interfaceName);
 
+    public WebMessagePort[] createWebMessageChannel();
+
+    public void postMessageToMainFrame(WebMessage message, Uri targetOrigin);
+
     public WebSettings getSettings();
 
     public void setMapTrackballToArrowKeys(boolean setMap);
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index 0f99e88..cc44577 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -4887,9 +4887,10 @@
                     text.insert(newTextInsertAt, newText);
                 }
             }
-            // Restore the cursor position.
+            // Restore the cursor position. If there wasn't an old cursor (newCursorPos == -1) then
+            // don't explicitly set it and rely on SpannableStringBuilder to position it.
             // TODO: Select all the text that was undone.
-            if (newCursorPos <= text.length()) {
+            if (0 <= newCursorPos && newCursorPos <= text.length()) {
                 Selection.setSelection(text, newCursorPos);
             }
         }
diff --git a/core/java/android/widget/RelativeLayout.java b/core/java/android/widget/RelativeLayout.java
index a224f5e..d12739f 100644
--- a/core/java/android/widget/RelativeLayout.java
+++ b/core/java/android/widget/RelativeLayout.java
@@ -515,6 +515,23 @@
             }
         }
 
+        // Use the top-start-most laid out view as the baseline. RTL offsets are
+        // applied later, so we can use the left-most edge as the starting edge.
+        View baselineView = null;
+        LayoutParams baselineParams = null;
+        for (int i = 0; i < count; i++) {
+            final View child = getChildAt(i);
+            if (child.getVisibility() != GONE) {
+                final LayoutParams childParams = (LayoutParams) child.getLayoutParams();
+                if (baselineView == null || baselineParams == null
+                        || compareLayoutPosition(childParams, baselineParams) < 0) {
+                    baselineView = child;
+                    baselineParams = childParams;
+                }
+            }
+        }
+        mBaselineView = baselineView;
+
         if (isWrapContentWidth) {
             // Width already has left padding in it since it was calculated by looking at
             // the right of each child view
@@ -616,25 +633,24 @@
             }
         }
 
-        // Use the bottom-most laid out view as the baseline.
-        View baselineView = null;
-        int baseline = 0;
-        for (int i = 0; i < count; i++) {
-            final View child = getChildAt(i);
-            if (child.getVisibility() != GONE) {
-                final int childBaseline = child.getBaseline();
-                if (childBaseline >= baseline) {
-                    baselineView = child;
-                    baseline = childBaseline;
-                }
-            }
-        }
-        mBaselineView = baselineView;
-
         setMeasuredDimension(width, height);
     }
 
     /**
+     * @return a negative number if the top of {@code p1} is above the top of
+     *         {@code p2} or if they have identical top values and the left of
+     *         {@code p1} is to the left of {@code p2}, or a positive number
+     *         otherwise
+     */
+    private int compareLayoutPosition(LayoutParams p1, LayoutParams p2) {
+        final int topDiff = p1.mTop - p2.mTop;
+        if (topDiff != 0) {
+            return topDiff;
+        }
+        return p1.mLeft - p2.mLeft;
+    }
+
+    /**
      * Measure a child. The child should have left, top, right and bottom information
      * stored in its LayoutParams. If any of these values is VALUE_NOT_SET it means
      * that the view can extend up to the corresponding edge.
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index a410e45..3ceea9d 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -342,6 +342,9 @@
                         return;
                     }
 
+                    // Do not show the profile switch message anymore.
+                    mProfileSwitchMessageId = -1;
+
                     final Intent intent = intentForDisplayResolveInfo(dri);
                     onIntentSelected(dri.ri, intent, false);
                     finish();
diff --git a/core/java/com/android/internal/os/InstallerConnection.java b/core/java/com/android/internal/os/InstallerConnection.java
index 2f30ebc..433a54b 100644
--- a/core/java/com/android/internal/os/InstallerConnection.java
+++ b/core/java/com/android/internal/os/InstallerConnection.java
@@ -91,11 +91,11 @@
     }
 
     public int dexopt(String apkPath, int uid, boolean isPublic, String instructionSet) {
-        return dexopt(apkPath, uid, isPublic, "*", instructionSet, false);
+        return dexopt(apkPath, uid, isPublic, "*", instructionSet, false, false);
     }
 
     public int dexopt(String apkPath, int uid, boolean isPublic, String pkgName,
-            String instructionSet, boolean vmSafeMode) {
+            String instructionSet, boolean vmSafeMode, boolean debuggable) {
         StringBuilder builder = new StringBuilder("dexopt");
         builder.append(' ');
         builder.append(apkPath);
@@ -106,8 +106,8 @@
         builder.append(pkgName);
         builder.append(' ');
         builder.append(instructionSet);
-        builder.append(' ');
         builder.append(vmSafeMode ? " 1" : " 0");
+        builder.append(debuggable ? " 1" : " 0");
         return execute(builder.toString());
     }
 
diff --git a/core/java/com/android/internal/os/ZygoteConnection.java b/core/java/com/android/internal/os/ZygoteConnection.java
index 5fc5b58..7acd8f5 100644
--- a/core/java/com/android/internal/os/ZygoteConnection.java
+++ b/core/java/com/android/internal/os/ZygoteConnection.java
@@ -76,7 +76,6 @@
     private final DataOutputStream mSocketOutStream;
     private final BufferedReader mSocketReader;
     private final Credentials peer;
-    private final String peerSecurityContext;
     private final String abiList;
 
     /**
@@ -97,15 +96,13 @@
                 new InputStreamReader(socket.getInputStream()), 256);
 
         mSocket.setSoTimeout(CONNECTION_TIMEOUT_MILLIS);
-                
+
         try {
             peer = mSocket.getPeerCredentials();
         } catch (IOException ex) {
             Log.e(TAG, "Cannot read peer credentials", ex);
             throw ex;
         }
-
-        peerSecurityContext = SELinux.getPeerContext(mSocket.getFileDescriptor());
     }
 
     /**
@@ -177,10 +174,8 @@
                         ", effective=0x" + Long.toHexString(parsedArgs.effectiveCapabilities));
             }
 
-            applyUidSecurityPolicy(parsedArgs, peer, peerSecurityContext);
-            applyRlimitSecurityPolicy(parsedArgs, peer, peerSecurityContext);
-            applyInvokeWithSecurityPolicy(parsedArgs, peer, peerSecurityContext);
-            applyseInfoSecurityPolicy(parsedArgs, peer, peerSecurityContext);
+            applyUidSecurityPolicy(parsedArgs, peer);
+            applyInvokeWithSecurityPolicy(parsedArgs, peer);
 
             applyDebuggerSystemProperty(parsedArgs);
             applyInvokeWithSystemProperty(parsedArgs);
@@ -581,7 +576,7 @@
         }
 
         // See bug 1092107: large argc can be used for a DOS attack
-        if (argc > MAX_ZYGOTE_ARGC) {   
+        if (argc > MAX_ZYGOTE_ARGC) {
             throw new IOException("max arg count exceeded");
         }
 
@@ -598,63 +593,30 @@
     }
 
     /**
-     * Applies zygote security policy per bugs #875058 and #1082165. 
-     * Based on the credentials of the process issuing a zygote command:
-     * <ol>
-     * <li> uid 0 (root) may specify any uid, gid, and setgroups() list
-     * <li> uid 1000 (Process.SYSTEM_UID) may specify any uid &gt; 1000 in normal
+     * uid 1000 (Process.SYSTEM_UID) may specify any uid &gt; 1000 in normal
      * operation. It may also specify any gid and setgroups() list it chooses.
      * In factory test mode, it may specify any UID.
-     * <li> Any other uid may not specify any uid, gid, or setgroups list. The
-     * uid and gid will be inherited from the requesting process.
-     * </ul>
      *
      * @param args non-null; zygote spawner arguments
      * @param peer non-null; peer credentials
      * @throws ZygoteSecurityException
      */
-    private static void applyUidSecurityPolicy(Arguments args, Credentials peer,
-            String peerSecurityContext)
+    private static void applyUidSecurityPolicy(Arguments args, Credentials peer)
             throws ZygoteSecurityException {
 
-        int peerUid = peer.getUid();
-
-        if (peerUid == 0) {
-            // Root can do what it wants
-        } else if (peerUid == Process.SYSTEM_UID ) {
-            // System UID is restricted, except in factory test mode
+        if (peer.getUid() == Process.SYSTEM_UID) {
             String factoryTest = SystemProperties.get("ro.factorytest");
             boolean uidRestricted;
 
             /* In normal operation, SYSTEM_UID can only specify a restricted
              * set of UIDs. In factory test mode, SYSTEM_UID may specify any uid.
              */
-            uidRestricted  
-                 = !(factoryTest.equals("1") || factoryTest.equals("2"));
+            uidRestricted = !(factoryTest.equals("1") || factoryTest.equals("2"));
 
-            if (uidRestricted
-                    && args.uidSpecified && (args.uid < Process.SYSTEM_UID)) {
+            if (uidRestricted && args.uidSpecified && (args.uid < Process.SYSTEM_UID)) {
                 throw new ZygoteSecurityException(
                         "System UID may not launch process with UID < "
-                                + Process.SYSTEM_UID);
-            }
-        } else {
-            // Everything else
-            if (args.uidSpecified || args.gidSpecified
-                || args.gids != null) {
-                throw new ZygoteSecurityException(
-                        "App UIDs may not specify uid's or gid's");
-            }
-        }
-
-        if (args.uidSpecified || args.gidSpecified || args.gids != null) {
-            boolean allowed = SELinux.checkSELinuxAccess(peerSecurityContext,
-                                                         peerSecurityContext,
-                                                         "zygote",
-                                                         "specifyids");
-            if (!allowed) {
-                throw new ZygoteSecurityException(
-                        "Peer may not specify uid's or gid's");
+                        + Process.SYSTEM_UID);
             }
         }
 
@@ -669,7 +631,6 @@
         }
     }
 
-
     /**
      * Applies debugger system properties to the zygote arguments.
      *
@@ -686,44 +647,6 @@
     }
 
     /**
-     * Applies zygote security policy per bug #1042973. Based on the credentials
-     * of the process issuing a zygote command:
-     * <ol>
-     * <li> peers of  uid 0 (root) and uid 1000 (Process.SYSTEM_UID)
-     * may specify any rlimits.
-     * <li> All other uids may not specify rlimits.
-     * </ul>
-     * @param args non-null; zygote spawner arguments
-     * @param peer non-null; peer credentials
-     * @throws ZygoteSecurityException
-     */
-    private static void applyRlimitSecurityPolicy(
-            Arguments args, Credentials peer, String peerSecurityContext)
-            throws ZygoteSecurityException {
-
-        int peerUid = peer.getUid();
-
-        if (!(peerUid == 0 || peerUid == Process.SYSTEM_UID)) {
-            // All peers with UID other than root or SYSTEM_UID
-            if (args.rlimits != null) {
-                throw new ZygoteSecurityException(
-                        "This UID may not specify rlimits.");
-            }
-        }
-
-        if (args.rlimits != null) {
-            boolean allowed = SELinux.checkSELinuxAccess(peerSecurityContext,
-                                                         peerSecurityContext,
-                                                         "zygote",
-                                                         "specifyrlimits");
-            if (!allowed) {
-                throw new ZygoteSecurityException(
-                        "Peer may not specify rlimits");
-            }
-         }
-    }
-
-    /**
      * Applies zygote security policy.
      * Based on the credentials of the process issuing a zygote command:
      * <ol>
@@ -736,8 +659,7 @@
      * @param peer non-null; peer credentials
      * @throws ZygoteSecurityException
      */
-    private static void applyInvokeWithSecurityPolicy(Arguments args, Credentials peer,
-            String peerSecurityContext)
+    private static void applyInvokeWithSecurityPolicy(Arguments args, Credentials peer)
             throws ZygoteSecurityException {
         int peerUid = peer.getUid();
 
@@ -745,52 +667,6 @@
             throw new ZygoteSecurityException("Peer is not permitted to specify "
                     + "an explicit invoke-with wrapper command");
         }
-
-        if (args.invokeWith != null) {
-            boolean allowed = SELinux.checkSELinuxAccess(peerSecurityContext,
-                                                         peerSecurityContext,
-                                                         "zygote",
-                                                         "specifyinvokewith");
-            if (!allowed) {
-                throw new ZygoteSecurityException("Peer is not permitted to specify "
-                    + "an explicit invoke-with wrapper command");
-            }
-        }
-    }
-
-    /**
-     * Applies zygote security policy for SELinux information.
-     *
-     * @param args non-null; zygote spawner arguments
-     * @param peer non-null; peer credentials
-     * @throws ZygoteSecurityException
-     */
-    private static void applyseInfoSecurityPolicy(
-            Arguments args, Credentials peer, String peerSecurityContext)
-            throws ZygoteSecurityException {
-        int peerUid = peer.getUid();
-
-        if (args.seInfo == null) {
-            // nothing to check
-            return;
-        }
-
-        if (!(peerUid == 0 || peerUid == Process.SYSTEM_UID)) {
-            // All peers with UID other than root or SYSTEM_UID
-            throw new ZygoteSecurityException(
-                    "This UID may not specify SELinux info.");
-        }
-
-        boolean allowed = SELinux.checkSELinuxAccess(peerSecurityContext,
-                                                     peerSecurityContext,
-                                                     "zygote",
-                                                     "specifyseinfo");
-        if (!allowed) {
-            throw new ZygoteSecurityException(
-                    "Peer may not specify SELinux info");
-        }
-
-        return;
     }
 
     /**
@@ -800,20 +676,18 @@
      */
     public static void applyInvokeWithSystemProperty(Arguments args) {
         if (args.invokeWith == null && args.niceName != null) {
-            if (args.niceName != null) {
-                String property = "wrap." + args.niceName;
-                if (property.length() > 31) {
-                    // Properties with a trailing "." are illegal.
-                    if (property.charAt(30) != '.') {
-                        property = property.substring(0, 31);
-                    } else {
-                        property = property.substring(0, 30);
-                    }
+            String property = "wrap." + args.niceName;
+            if (property.length() > 31) {
+                // Properties with a trailing "." are illegal.
+                if (property.charAt(30) != '.') {
+                    property = property.substring(0, 31);
+                } else {
+                    property = property.substring(0, 30);
                 }
-                args.invokeWith = SystemProperties.get(property);
-                if (args.invokeWith != null && args.invokeWith.length() == 0) {
-                    args.invokeWith = null;
-                }
+            }
+            args.invokeWith = SystemProperties.get(property);
+            if (args.invokeWith != null && args.invokeWith.length() == 0) {
+                args.invokeWith = null;
             }
         }
     }
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index 97744ea..30a7e68 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -18,6 +18,8 @@
 
 LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES
 
+LOCAL_CFLAGS += -DU_USING_ICU_NAMESPACE=0
+
 LOCAL_SRC_FILES:= \
     AndroidRuntime.cpp \
     com_android_internal_content_NativeLibraryHelper.cpp \
@@ -41,25 +43,25 @@
     android_database_SQLiteDebug.cpp \
     android_emoji_EmojiFactory.cpp \
     android_view_DisplayEventReceiver.cpp \
-    android_view_Surface.cpp \
-    android_view_SurfaceControl.cpp \
-    android_view_SurfaceSession.cpp \
-    android_view_TextureView.cpp \
+    android_view_DisplayListCanvas.cpp \
+    android_view_GraphicBuffer.cpp \
+    android_view_HardwareLayer.cpp \
     android_view_InputChannel.cpp \
     android_view_InputDevice.cpp \
     android_view_InputEventReceiver.cpp \
     android_view_InputEventSender.cpp \
     android_view_InputQueue.cpp \
-    android_view_KeyEvent.cpp \
     android_view_KeyCharacterMap.cpp \
-    android_view_GraphicBuffer.cpp \
-    android_view_GLES20Canvas.cpp \
-    android_view_HardwareLayer.cpp \
-    android_view_ThreadedRenderer.cpp \
+    android_view_KeyEvent.cpp \
     android_view_MotionEvent.cpp \
     android_view_PointerIcon.cpp \
     android_view_RenderNode.cpp \
     android_view_RenderNodeAnimator.cpp \
+    android_view_Surface.cpp \
+    android_view_SurfaceControl.cpp \
+    android_view_SurfaceSession.cpp \
+    android_view_TextureView.cpp \
+    android_view_ThreadedRenderer.cpp \
     android_view_VelocityTracker.cpp \
     android_text_AndroidCharacter.cpp \
     android_text_AndroidBidi.cpp \
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 77afd05..ad52e3f 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -127,16 +127,16 @@
 extern int register_android_graphics_pdf_PdfEditor(JNIEnv* env);
 extern int register_android_graphics_pdf_PdfRenderer(JNIEnv* env);
 extern int register_android_view_DisplayEventReceiver(JNIEnv* env);
+extern int register_android_view_DisplayListCanvas(JNIEnv* env);
+extern int register_android_view_GraphicBuffer(JNIEnv* env);
+extern int register_android_view_HardwareLayer(JNIEnv* env);
 extern int register_android_view_RenderNode(JNIEnv* env);
 extern int register_android_view_RenderNodeAnimator(JNIEnv* env);
-extern int register_android_view_GraphicBuffer(JNIEnv* env);
-extern int register_android_view_GLES20Canvas(JNIEnv* env);
-extern int register_android_view_HardwareLayer(JNIEnv* env);
-extern int register_android_view_ThreadedRenderer(JNIEnv* env);
 extern int register_android_view_Surface(JNIEnv* env);
 extern int register_android_view_SurfaceControl(JNIEnv* env);
 extern int register_android_view_SurfaceSession(JNIEnv* env);
 extern int register_android_view_TextureView(JNIEnv* env);
+extern int register_android_view_ThreadedRenderer(JNIEnv* env);
 extern int register_com_android_internal_view_animation_NativeInterpolatorFactoryHelper(JNIEnv *env);
 extern int register_android_database_CursorWindow(JNIEnv* env);
 extern int register_android_database_SQLiteConnection(JNIEnv* env);
@@ -1179,7 +1179,7 @@
     REG_JNI(register_android_view_RenderNode),
     REG_JNI(register_android_view_RenderNodeAnimator),
     REG_JNI(register_android_view_GraphicBuffer),
-    REG_JNI(register_android_view_GLES20Canvas),
+    REG_JNI(register_android_view_DisplayListCanvas),
     REG_JNI(register_android_view_HardwareLayer),
     REG_JNI(register_android_view_ThreadedRenderer),
     REG_JNI(register_android_view_Surface),
diff --git a/core/jni/android_text_StaticLayout.cpp b/core/jni/android_text_StaticLayout.cpp
index a6f19b1..e5ae147 100644
--- a/core/jni/android_text_StaticLayout.cpp
+++ b/core/jni/android_text_StaticLayout.cpp
@@ -48,10 +48,10 @@
             delete mBreakIterator;
         }
 
-        void setLocale(const Locale& locale) {
+        void setLocale(const icu::Locale& locale) {
             delete mBreakIterator;
             UErrorCode status = U_ZERO_ERROR;
-            mBreakIterator = BreakIterator::createLineInstance(locale, status);
+            mBreakIterator = icu::BreakIterator::createLineInstance(locale, status);
             // TODO: check status
         }
 
@@ -77,13 +77,13 @@
             }
         }
 
-        BreakIterator* breakIterator() const {
+        icu::BreakIterator* breakIterator() const {
             return mBreakIterator;
         }
 
     private:
         const size_t MAX_TEXT_BUF_RETAIN = 32678;
-        BreakIterator* mBreakIterator = nullptr;
+        icu::BreakIterator* mBreakIterator = nullptr;
         UText mUText = UTEXT_INITIALIZER;
         std::vector<uint16_t>mTextBuf;
 };
@@ -560,9 +560,9 @@
     // TODO: this array access is pretty inefficient, but we'll replace it anyway
     ScopedFloatArrayRO widthsScopedArr(env, widths);
 
-    BreakIterator* breakIterator = b->breakIterator();
+    icu::BreakIterator* breakIterator = b->breakIterator();
     int loc = breakIterator->first();
-    while ((loc = breakIterator->next()) != BreakIterator::DONE) {
+    while ((loc = breakIterator->next()) != icu::BreakIterator::DONE) {
         breaks.push_back(loc);
     }
 
diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_DisplayListCanvas.cpp
similarity index 82%
rename from core/jni/android_view_GLES20Canvas.cpp
rename to core/jni/android_view_DisplayListCanvas.cpp
index 0bee7ae..f2e6c4b 100644
--- a/core/jni/android_view_GLES20Canvas.cpp
+++ b/core/jni/android_view_DisplayListCanvas.cpp
@@ -50,43 +50,43 @@
 // Setup
 // ----------------------------------------------------------------------------
 
-static void android_view_GLES20Canvas_setViewport(JNIEnv* env, jobject clazz,
+static void android_view_DisplayListCanvas_setViewport(JNIEnv* env, jobject clazz,
         jlong rendererPtr, jint width, jint height) {
     DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
     renderer->setViewport(width, height);
 }
 
-static void android_view_GLES20Canvas_setHighContrastText(JNIEnv* env, jobject clazz,
+static void android_view_DisplayListCanvas_setHighContrastText(JNIEnv* env, jobject clazz,
         jlong rendererPtr, jboolean highContrastText) {
     DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
     renderer->setHighContrastText(highContrastText);
 }
 
-static void android_view_GLES20Canvas_insertReorderBarrier(JNIEnv* env, jobject clazz,
+static void android_view_DisplayListCanvas_insertReorderBarrier(JNIEnv* env, jobject clazz,
         jlong rendererPtr, jboolean reorderEnable) {
     DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
     renderer->insertReorderBarrier(reorderEnable);
 }
 
-static void android_view_GLES20Canvas_prepare(JNIEnv* env, jobject clazz,
+static void android_view_DisplayListCanvas_prepare(JNIEnv* env, jobject clazz,
         jlong rendererPtr) {
     DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
     renderer->prepare();
 }
 
-static void android_view_GLES20Canvas_prepareDirty(JNIEnv* env, jobject clazz,
+static void android_view_DisplayListCanvas_prepareDirty(JNIEnv* env, jobject clazz,
         jlong rendererPtr, jint left, jint top, jint right, jint bottom) {
     DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
     renderer->prepareDirty(left, top, right, bottom);
 }
 
-static void android_view_GLES20Canvas_finish(JNIEnv* env, jobject clazz,
+static void android_view_DisplayListCanvas_finish(JNIEnv* env, jobject clazz,
         jlong rendererPtr) {
     DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
     renderer->finish();
 }
 
-static void android_view_GLES20Canvas_setProperty(JNIEnv* env,
+static void android_view_DisplayListCanvas_setProperty(JNIEnv* env,
         jobject clazz, jstring name, jstring value) {
     if (!Caches::hasInstance()) {
         ALOGW("can't set property, no Caches instance");
@@ -108,7 +108,7 @@
 // Functor
 // ----------------------------------------------------------------------------
 
-static void android_view_GLES20Canvas_callDrawGLFunction(JNIEnv* env, jobject clazz,
+static void android_view_DisplayListCanvas_callDrawGLFunction(JNIEnv* env, jobject clazz,
         jlong rendererPtr, jlong functorPtr) {
     DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
     Functor* functor = reinterpret_cast<Functor*>(functorPtr);
@@ -120,11 +120,11 @@
 // Misc
 // ----------------------------------------------------------------------------
 
-static jint android_view_GLES20Canvas_getMaxTextureWidth(JNIEnv* env, jobject clazz) {
+static jint android_view_DisplayListCanvas_getMaxTextureWidth(JNIEnv* env, jobject clazz) {
     return Caches::getInstance().maxTextureSize;
 }
 
-static jint android_view_GLES20Canvas_getMaxTextureHeight(JNIEnv* env, jobject clazz) {
+static jint android_view_DisplayListCanvas_getMaxTextureHeight(JNIEnv* env, jobject clazz) {
     return Caches::getInstance().maxTextureSize;
 }
 
@@ -132,7 +132,7 @@
 // Drawing
 // ----------------------------------------------------------------------------
 
-static void android_view_GLES20Canvas_drawPatch(JNIEnv* env, jobject clazz,
+static void android_view_DisplayListCanvas_drawPatch(JNIEnv* env, jobject clazz,
         jlong rendererPtr, jlong bitmapPtr, jlong patchPtr,
         float left, float top, float right, float bottom, jlong paintPtr) {
     SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapPtr);
@@ -143,7 +143,7 @@
     renderer->drawPatch(bitmap, patch, left, top, right, bottom, paint);
 }
 
-static void android_view_GLES20Canvas_drawRoundRectProps(JNIEnv* env, jobject clazz,
+static void android_view_DisplayListCanvas_drawRoundRectProps(JNIEnv* env, jobject clazz,
         jlong rendererPtr, jlong leftPropPtr, jlong topPropPtr, jlong rightPropPtr,
         jlong bottomPropPtr, jlong rxPropPtr, jlong ryPropPtr, jlong paintPropPtr) {
     DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
@@ -157,7 +157,7 @@
     renderer->drawRoundRect(leftProp, topProp, rightProp, bottomProp, rxProp, ryProp, paintProp);
 }
 
-static void android_view_GLES20Canvas_drawCircleProps(JNIEnv* env, jobject clazz,
+static void android_view_DisplayListCanvas_drawCircleProps(JNIEnv* env, jobject clazz,
         jlong rendererPtr, jlong xPropPtr, jlong yPropPtr, jlong radiusPropPtr, jlong paintPropPtr) {
     DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
     CanvasPropertyPrimitive* xProp = reinterpret_cast<CanvasPropertyPrimitive*>(xPropPtr);
@@ -167,7 +167,7 @@
     renderer->drawCircle(xProp, yProp, radiusProp, paintProp);
 }
 
-static void android_view_GLES20Canvas_drawRegionAsRects(JNIEnv* env, jobject clazz,
+static void android_view_DisplayListCanvas_drawRegionAsRects(JNIEnv* env, jobject clazz,
         jlong rendererPtr, jlong regionPtr, jlong paintPtr) {
     DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
     SkRegion* region = reinterpret_cast<SkRegion*>(regionPtr);
@@ -201,17 +201,17 @@
 // Display lists
 // ----------------------------------------------------------------------------
 
-static jlong android_view_GLES20Canvas_finishRecording(JNIEnv* env,
+static jlong android_view_DisplayListCanvas_finishRecording(JNIEnv* env,
         jobject clazz, jlong rendererPtr) {
     DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
     return reinterpret_cast<jlong>(renderer->finishRecording());
 }
 
-static jlong android_view_GLES20Canvas_createDisplayListRenderer(JNIEnv* env, jobject clazz) {
+static jlong android_view_DisplayListCanvas_createDisplayListRenderer(JNIEnv* env, jobject clazz) {
     return reinterpret_cast<jlong>(new DisplayListRenderer);
 }
 
-static void android_view_GLES20Canvas_drawRenderNode(JNIEnv* env,
+static void android_view_DisplayListCanvas_drawRenderNode(JNIEnv* env,
         jobject clazz, jlong rendererPtr, jlong renderNodePtr,
         jint flags) {
     DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
@@ -224,7 +224,7 @@
 // Layers
 // ----------------------------------------------------------------------------
 
-static void android_view_GLES20Canvas_drawLayer(JNIEnv* env, jobject clazz,
+static void android_view_DisplayListCanvas_drawLayer(JNIEnv* env, jobject clazz,
         jlong rendererPtr, jlong layerPtr, jfloat x, jfloat y) {
     DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
     DeferredLayerUpdater* layer = reinterpret_cast<DeferredLayerUpdater*>(layerPtr);
@@ -235,7 +235,7 @@
 // Common
 // ----------------------------------------------------------------------------
 
-static jboolean android_view_GLES20Canvas_isAvailable(JNIEnv* env, jobject clazz) {
+static jboolean android_view_DisplayListCanvas_isAvailable(JNIEnv* env, jobject clazz) {
     char prop[PROPERTY_VALUE_MAX];
     if (property_get("ro.kernel.qemu", prop, NULL) == 0) {
         // not in the emulator
@@ -261,36 +261,36 @@
 // JNI Glue
 // ----------------------------------------------------------------------------
 
-const char* const kClassPathName = "android/view/GLES20Canvas";
+const char* const kClassPathName = "android/view/DisplayListCanvas";
 
 static JNINativeMethod gMethods[] = {
-    { "nIsAvailable",       "()Z",             (void*) android_view_GLES20Canvas_isAvailable },
-    { "nSetViewport",       "(JII)V",          (void*) android_view_GLES20Canvas_setViewport },
-    { "nSetHighContrastText","(JZ)V",          (void*) android_view_GLES20Canvas_setHighContrastText },
-    { "nInsertReorderBarrier","(JZ)V",         (void*) android_view_GLES20Canvas_insertReorderBarrier },
-    { "nPrepare",           "(J)V",            (void*) android_view_GLES20Canvas_prepare },
-    { "nPrepareDirty",      "(JIIII)V",        (void*) android_view_GLES20Canvas_prepareDirty },
-    { "nFinish",            "(J)V",            (void*) android_view_GLES20Canvas_finish },
+    { "nIsAvailable",       "()Z",             (void*) android_view_DisplayListCanvas_isAvailable },
+    { "nSetViewport",       "(JII)V",          (void*) android_view_DisplayListCanvas_setViewport },
+    { "nSetHighContrastText","(JZ)V",          (void*) android_view_DisplayListCanvas_setHighContrastText },
+    { "nInsertReorderBarrier","(JZ)V",         (void*) android_view_DisplayListCanvas_insertReorderBarrier },
+    { "nPrepare",           "(J)V",            (void*) android_view_DisplayListCanvas_prepare },
+    { "nPrepareDirty",      "(JIIII)V",        (void*) android_view_DisplayListCanvas_prepareDirty },
+    { "nFinish",            "(J)V",            (void*) android_view_DisplayListCanvas_finish },
     { "nSetProperty",       "(Ljava/lang/String;Ljava/lang/String;)V",
-            (void*) android_view_GLES20Canvas_setProperty },
+            (void*) android_view_DisplayListCanvas_setProperty },
 
-    { "nCallDrawGLFunction", "(JJ)V",          (void*) android_view_GLES20Canvas_callDrawGLFunction },
+    { "nCallDrawGLFunction", "(JJ)V",          (void*) android_view_DisplayListCanvas_callDrawGLFunction },
 
-    { "nDrawPatch",         "(JJJFFFFJ)V",     (void*) android_view_GLES20Canvas_drawPatch },
+    { "nDrawPatch",         "(JJJFFFFJ)V",     (void*) android_view_DisplayListCanvas_drawPatch },
 
-    { "nDrawRects",         "(JJJ)V",          (void*) android_view_GLES20Canvas_drawRegionAsRects },
-    { "nDrawRoundRect",     "(JJJJJJJJ)V",     (void*) android_view_GLES20Canvas_drawRoundRectProps },
-    { "nDrawCircle",        "(JJJJJ)V",        (void*) android_view_GLES20Canvas_drawCircleProps },
+    { "nDrawRects",         "(JJJ)V",          (void*) android_view_DisplayListCanvas_drawRegionAsRects },
+    { "nDrawRoundRect",     "(JJJJJJJJ)V",     (void*) android_view_DisplayListCanvas_drawRoundRectProps },
+    { "nDrawCircle",        "(JJJJJ)V",        (void*) android_view_DisplayListCanvas_drawCircleProps },
 
-    { "nFinishRecording",   "(J)J",            (void*) android_view_GLES20Canvas_finishRecording },
-    { "nDrawRenderNode",    "(JJI)V",          (void*) android_view_GLES20Canvas_drawRenderNode },
+    { "nFinishRecording",   "(J)J",            (void*) android_view_DisplayListCanvas_finishRecording },
+    { "nDrawRenderNode",    "(JJI)V",          (void*) android_view_DisplayListCanvas_drawRenderNode },
 
-    { "nCreateDisplayListRenderer", "()J",     (void*) android_view_GLES20Canvas_createDisplayListRenderer },
+    { "nCreateDisplayListRenderer", "()J",     (void*) android_view_DisplayListCanvas_createDisplayListRenderer },
 
-    { "nDrawLayer",               "(JJFF)V",   (void*) android_view_GLES20Canvas_drawLayer },
+    { "nDrawLayer",               "(JJFF)V",   (void*) android_view_DisplayListCanvas_drawLayer },
 
-    { "nGetMaximumTextureWidth",  "()I",       (void*) android_view_GLES20Canvas_getMaxTextureWidth },
-    { "nGetMaximumTextureHeight", "()I",       (void*) android_view_GLES20Canvas_getMaxTextureHeight },
+    { "nGetMaximumTextureWidth",  "()I",       (void*) android_view_DisplayListCanvas_getMaxTextureWidth },
+    { "nGetMaximumTextureHeight", "()I",       (void*) android_view_DisplayListCanvas_getMaxTextureHeight },
 };
 
 static JNINativeMethod gActivityThreadMethods[] = {
@@ -298,7 +298,7 @@
                                                (void*) android_app_ActivityThread_dumpGraphics }
 };
 
-int register_android_view_GLES20Canvas(JNIEnv* env) {
+int register_android_view_DisplayListCanvas(JNIEnv* env) {
     jclass clazz = FindClassOrDie(env, "android/graphics/Rect");
     gRectClassInfo.set = GetMethodIDOrDie(env, clazz, "set", "(IIII)V");
 
diff --git a/core/jni/android_view_Surface.cpp b/core/jni/android_view_Surface.cpp
index 39064ed..fff8604 100644
--- a/core/jni/android_view_Surface.cpp
+++ b/core/jni/android_view_Surface.cpp
@@ -489,7 +489,7 @@
     proxy->initialize(surface);
     // Shadows can't be used via this interface, so just set the light source
     // to all 0s. (and width & height are unused, TODO remove them)
-    proxy->setup(0, 0, (Vector3){0, 0, 0}, 0, 0, 0, 1.0f);
+    proxy->setup(0, 0, (Vector3){0, 0, 0}, 0, 0, 0);
     return (jlong) proxy;
 }
 
diff --git a/core/jni/android_view_ThreadedRenderer.cpp b/core/jni/android_view_ThreadedRenderer.cpp
index ad93301..3d9a9ed 100644
--- a/core/jni/android_view_ThreadedRenderer.cpp
+++ b/core/jni/android_view_ThreadedRenderer.cpp
@@ -239,18 +239,20 @@
     delete proxy;
 }
 
-static void android_view_ThreadedRenderer_setFrameInterval(JNIEnv* env, jobject clazz,
-        jlong proxyPtr, jlong frameIntervalNanos) {
-    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
-    proxy->setFrameInterval(frameIntervalNanos);
-}
-
 static jboolean android_view_ThreadedRenderer_loadSystemProperties(JNIEnv* env, jobject clazz,
         jlong proxyPtr) {
     RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
     return proxy->loadSystemProperties();
 }
 
+static void android_view_ThreadedRenderer_setName(JNIEnv* env, jobject clazz,
+        jlong proxyPtr, jstring jname) {
+    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
+    const char* name = env->GetStringUTFChars(jname, NULL);
+    proxy->setName(name);
+    env->ReleaseStringUTFChars(jname, name);
+}
+
 static jboolean android_view_ThreadedRenderer_initialize(JNIEnv* env, jobject clazz,
         jlong proxyPtr, jobject jsurface) {
     RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
@@ -284,7 +286,7 @@
         jint ambientShadowAlpha, jint spotShadowAlpha, jfloat density) {
     RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
     proxy->setup(width, height, (Vector3){lightX, lightY, lightZ}, lightRadius,
-            ambientShadowAlpha, spotShadowAlpha, density);
+            ambientShadowAlpha, spotShadowAlpha);
 }
 
 static void android_view_ThreadedRenderer_setOpaque(JNIEnv* env, jobject clazz,
@@ -424,12 +426,12 @@
     { "nCreateRootRenderNode", "()J", (void*) android_view_ThreadedRenderer_createRootRenderNode },
     { "nCreateProxy", "(ZJ)J", (void*) android_view_ThreadedRenderer_createProxy },
     { "nDeleteProxy", "(J)V", (void*) android_view_ThreadedRenderer_deleteProxy },
-    { "nSetFrameInterval", "(JJ)V", (void*) android_view_ThreadedRenderer_setFrameInterval },
     { "nLoadSystemProperties", "(J)Z", (void*) android_view_ThreadedRenderer_loadSystemProperties },
+    { "nSetName", "(JLjava/lang/String;)V", (void*) android_view_ThreadedRenderer_setName },
     { "nInitialize", "(JLandroid/view/Surface;)Z", (void*) android_view_ThreadedRenderer_initialize },
     { "nUpdateSurface", "(JLandroid/view/Surface;)V", (void*) android_view_ThreadedRenderer_updateSurface },
     { "nPauseSurface", "(JLandroid/view/Surface;)Z", (void*) android_view_ThreadedRenderer_pauseSurface },
-    { "nSetup", "(JIIFFFFIIF)V", (void*) android_view_ThreadedRenderer_setup },
+    { "nSetup", "(JIIFFFFII)V", (void*) android_view_ThreadedRenderer_setup },
     { "nSetOpaque", "(JZ)V", (void*) android_view_ThreadedRenderer_setOpaque },
     { "nSyncAndDrawFrame", "(J[JI)I", (void*) android_view_ThreadedRenderer_syncAndDrawFrame },
     { "nDestroy", "(J)V", (void*) android_view_ThreadedRenderer_destroy },
diff --git a/core/res/res/values-gl-rES/strings.xml b/core/res/res/values-gl-rES/strings.xml
index e593f88..8df4d62 100644
--- a/core/res/res/values-gl-rES/strings.xml
+++ b/core/res/res/values-gl-rES/strings.xml
@@ -796,8 +796,8 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Permite á aplicación recuperar, examinar e borrar notificacións, incluídas as publicadas por outras aplicacións."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"vincular a un servizo de axente de escoita de notificacións"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Permite ao propietario vincularse á interface de nivel superior dun servizo axente de escoita de notificacións.  Non debería ser nunca necesario para as aplicacións normais."</string>
-    <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"vincular a un servizo de segmento de seleccionador"</string>
-    <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"Permite ao propietario vincularse á interface de nivel superior dun servizo de segmento de seleccionador. Non debería ser nunca necesario para as aplicacións normais."</string>
+    <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"vincular a un servizo de destino de selector"</string>
+    <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"Permite ao propietario vincularse á interface de nivel superior dun servizo de destino de selector. Non se debería necesitar para as aplicacións normais."</string>
     <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"vincular a un servizo de provedor de condicións"</string>
     <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Permite ao propietario vincularse á interface de nivel superior dun servizo provedor de condicións. As aplicacións normais non deberían necesitar este permiso."</string>
     <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"vincular a un servizo de ruta de medios"</string>
diff --git a/core/res/res/values-mr-rIN/strings.xml b/core/res/res/values-mr-rIN/strings.xml
index 884687e..cea3828 100644
--- a/core/res/res/values-mr-rIN/strings.xml
+++ b/core/res/res/values-mr-rIN/strings.xml
@@ -1786,7 +1786,7 @@
       <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> सेकंदांमध्ये पुन्हा प्रयत्न करा</item>
     </plurals>
     <string name="restr_pin_try_later" msgid="973144472490532377">"नंतर पुन्हा प्रयत्न करा"</string>
-    <string name="immersive_cling_title" msgid="8394201622932303336">"पूर्ण स्क्रीन पाहत आहे"</string>
+    <string name="immersive_cling_title" msgid="8394201622932303336">"पूर्ण स्क्रीन पाहत आहात"</string>
     <string name="immersive_cling_description" msgid="3482371193207536040">"बाहेर पडण्यासाठी, वरून खाली स्वाइप करा."</string>
     <string name="immersive_cling_positive" msgid="5016839404568297683">"समजले"</string>
     <string name="done_label" msgid="2093726099505892398">"पूर्ण झाले"</string>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index a03d02d..617065c 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -799,7 +799,7 @@
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"Подключение к службе просмотра уведомлений"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Приложение сможет подключаться к базовому интерфейсу службы просмотра уведомлений. Это разрешение не используется обычными приложениями."</string>
     <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"Подключение к сервису выбора цели"</string>
-    <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"Подключение к базовому интерфейсу для выбора цели. Это разрешение не требуется для работы обычных приложений."</string>
+    <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"Подключение к интерфейсу верхнего уровня для выбора цели. Это разрешение не требуется для работы обычных приложений."</string>
     <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"Подключение к серверам поставщиков условий"</string>
     <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Приложение сможет подключаться к базовому интерфейсу поставщиков условий. Это разрешение обычно используется только специальными приложениями."</string>
     <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"Привязка к средству передачи медиафайлов"</string>
diff --git a/core/res/res/values-si-rLK/strings.xml b/core/res/res/values-si-rLK/strings.xml
index 8e04673..8d0619d 100644
--- a/core/res/res/values-si-rLK/strings.xml
+++ b/core/res/res/values-si-rLK/strings.xml
@@ -796,8 +796,8 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"වෙනත් යෙදුම් විසින් කළ පල කිරීම්ද ඇතුළත්ව දැන්වීම් ලබා ගැනීමට, පරීක්ෂා කිරීමට සහ හිස් කිරීමට යෙදුමට අවසර දෙන්න."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"දැනුම්දීම ඇහුම්කන් දීම් සේවාවක් වෙත බඳින්න"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"දැනුම්දීම් අසන්නාගේ සේවාවේ ඉහළ මට්ටමේ අතුරුමුහුණතට බැඳීමට දරන්නාට අවසර දේ. සාමාන්‍ය යෙදුම් සඳහා කිසිසේත් අවශ්‍ය නොවේ."</string>
-    <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"තෝරන්නා ඉලක්ක කරගත් සේවාවකට සම්බන්ධ කරන්න"</string>
-    <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"තෝරන්නා ඉලක්ක කරගත් සේවාවක ඉහළ මට්ට‍‍‍මේ අතුරු මුහුණත වෙත සම්බන්ධ වීමට ධාරකයාට ඉඩ‍‍දෙන්න. සාමාන්ය යෙදුම් සඳහා කිසිදා අවශ්ය නොවනු ඇත."</string>
+    <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"තෝරන්නා ඉලක්ක කරගත් සේවාවකට සම්බන්ධ කරන්න"</string>
+    <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"තෝරන්නා ඉලක්ක කරගත් සේවාවක ඉහළ මට්ට‍‍‍මේ අතුරු මුහුණත වෙත සම්බන්ධ වීමට ධාරකයාට ඉඩ‍‍දෙන්න. සාමාන්ය යෙදුම් සඳහා කිසිදා අවශ්ය නොවනු ඇත."</string>
     <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"තත්ත්වය සපයන්නාගේ සේවාවට බඳින්න"</string>
     <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"තත්ත්වය සපයන්නාගේ සේවාවට ඉහළ-මට්ටමේ අතුරු මුහුණතක් බැඳිමට ධාරකයාට අවසර දෙන්න. සාමාන්‍ය යෙදුම් සඳහා කවදාවත් අවශ්‍යය නොවෙයි."</string>
     <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"මාධ්‍ය ගමන් කරන සේවාව බඳින්න"</string>
@@ -1788,7 +1788,7 @@
       <item quantity="other">තත්පර <xliff:g id="COUNT">%d</xliff:g> කින් නැවත උත්සාහ කරන්න</item>
     </plurals>
     <string name="restr_pin_try_later" msgid="973144472490532377">"පසුව නැවත උත්සාහ කරන්න"</string>
-    <string name="immersive_cling_title" msgid="8394201622932303336">"මුළු තිරය ​​නරඹමින්"</string>
+    <string name="immersive_cling_title" msgid="8394201622932303336">"මුළු තිරය බලමින්"</string>
     <string name="immersive_cling_description" msgid="3482371193207536040">"ඉවත් වීමට, ඉහළ සිට පහළට ස්වයිප් කරන්න"</string>
     <string name="immersive_cling_positive" msgid="5016839404568297683">"වැටහුණි"</string>
     <string name="done_label" msgid="2093726099505892398">"අවසන්"</string>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index 7a753eb..1043b2c 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -1820,8 +1820,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Тражи шаблон за откључавање пре откачињања"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Тражи лозинку пре откачињања"</string>
     <string name="battery_saver_description" msgid="1960431123816253034">"Да би продужила време трајања батерије, уштеда батерије смањује перформансе уређаја и ограничава вибрацију, услуге локације и већину позадинских података. Имејл, размена порука и друге апликације које се ослањају на синхронизацију можда неће да се ажурирају ако их не отворите.\n\nУштеда батерије се аутоматски искључује када се уређај пуни."</string>
-    <string name="downtime_condition_summary" msgid="8761776337475705749">"Док се прекид рада не заврши у <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
-    <string name="downtime_condition_line_one" msgid="8762708714645352010">"Док се време одмора не заврши"</string>
+    <string name="downtime_condition_summary" msgid="8761776337475705749">"Док се одмор не заврши у <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
+    <string name="downtime_condition_line_one" msgid="8762708714645352010">"Док се одмор не заврши"</string>
     <plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
       <item quantity="one">%1$d минут (до <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
       <item quantity="few">%1$d минута (до <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index 497a9dc..7a9da40 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -796,10 +796,8 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"允许该应用检索、检查并清除通知,包括其他应用发布的通知。"</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"绑定到通知侦听器服务"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"允许应用绑定到通知侦听器服务的顶级接口(普通应用绝不需要此权限)。"</string>
-    <!-- no translation found for permlab_bindChooserTargetService (3443261076710185673) -->
-    <skip />
-    <!-- no translation found for permdesc_bindChooserTargetService (1413908999583734970) -->
-    <skip />
+    <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"绑定到选择器目标服务"</string>
+    <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"允许该应用绑定到选择器目标服务的顶级接口。普通应用绝不需要此权限。"</string>
     <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"绑定到条件提供程序服务"</string>
     <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"允许应用绑定到条件提供程序服务的顶级接口。普通应用绝不需要此权限。"</string>
     <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"绑定至媒体转接服务"</string>
@@ -1788,12 +1786,9 @@
       <item quantity="one">1 秒后重试</item>
     </plurals>
     <string name="restr_pin_try_later" msgid="973144472490532377">"稍后重试"</string>
-    <!-- no translation found for immersive_cling_title (8394201622932303336) -->
-    <skip />
-    <!-- no translation found for immersive_cling_description (3482371193207536040) -->
-    <skip />
-    <!-- no translation found for immersive_cling_positive (5016839404568297683) -->
-    <skip />
+    <string name="immersive_cling_title" msgid="8394201622932303336">"正在全屏模式下查看"</string>
+    <string name="immersive_cling_description" msgid="3482371193207536040">"要退出,请从顶部向下滑动。"</string>
+    <string name="immersive_cling_positive" msgid="5016839404568297683">"知道了"</string>
     <string name="done_label" msgid="2093726099505892398">"完成"</string>
     <string name="hour_picker_description" msgid="6698199186859736512">"小时转盘"</string>
     <string name="minute_picker_description" msgid="8606010966873791190">"分钟转盘"</string>
diff --git a/docs/html/guide/topics/manifest/data-element.jd b/docs/html/guide/topics/manifest/data-element.jd
index ecba508..77f16dd 100644
--- a/docs/html/guide/topics/manifest/data-element.jd
+++ b/docs/html/guide/topics/manifest/data-element.jd
@@ -24,7 +24,7 @@
 attributes for each of its parts:
 
 <p style="margin-left: 2em">
-{@code &lt;scheme>://&lt;host>:&lt;port>/[&lt;path>|&lt;pathPrefix>|&lt;pathPattern>]}</p>
+{@code &lt;scheme>://&lt;host>:&lt;port>[&lt;path>|&lt;pathPrefix>|&lt;pathPattern>]}</p>
 
 <p>
 These attributes that specify the URL format are optional, but also mutually dependent:
@@ -115,7 +115,8 @@
 <dt><a name="path"></a>{@code android:path}
 <br/>{@code android:pathPrefix}
 <br/>{@code android:pathPattern}</dt>
-<dd>The path part of a URI.  The {@code path} attribute specifies a complete
+<dd>The path part of a URI which must begin with a /.
+The {@code path} attribute specifies a complete
 path that is matched against the complete path in an Intent object.  The
 {@code pathPrefix} attribute specifies a partial path that is matched against
 only the initial part of the path in the Intent object.  The {@code pathPattern}
diff --git a/docs/html/images/training/geofence.png b/docs/html/images/training/geofence.png
new file mode 100644
index 0000000..2d5d3aa
--- /dev/null
+++ b/docs/html/images/training/geofence.png
Binary files differ
diff --git a/docs/html/images/training/geofence@2x.png b/docs/html/images/training/geofence@2x.png
new file mode 100644
index 0000000..2f83105
--- /dev/null
+++ b/docs/html/images/training/geofence@2x.png
Binary files differ
diff --git a/docs/html/tools/revisions/build-tools.jd b/docs/html/tools/revisions/build-tools.jd
index 593770a..b08fbcf 100644
--- a/docs/html/tools/revisions/build-tools.jd
+++ b/docs/html/tools/revisions/build-tools.jd
@@ -78,6 +78,28 @@
 <div class="toggle-content opened">
   <p><a href="#" onclick="return toggleContent(this)">
     <img src="{@docRoot}assets/images/triangle-opened.png" class="toggle-content-img"
+      alt=""/>Build Tools, Revision 22.0.0</a> <em>(March 2015)</em>
+  </p>
+  <div class="toggle-content-toggleme">
+    <p>Added support for Android 5.1 (API level 22).</p>
+  </div>
+</div>
+
+
+<div class="toggle-content closed">
+  <p><a href="#" onclick="return toggleContent(this)">
+    <img src="{@docRoot}assets/images/triangle-closed.png" class="toggle-content-img"
+      alt=""/>Build Tools, Revision 21.1.2</a> <em>(February 2015)</em>
+  </p>
+  <div class="toggle-content-toggleme">
+    <p>Fixed problem with building data layouts in 32-bit mode.</p>
+  </div>
+</div>
+
+
+<div class="toggle-content closed">
+  <p><a href="#" onclick="return toggleContent(this)">
+    <img src="{@docRoot}assets/images/triangle-closed.png" class="toggle-content-img"
       alt=""/>Build Tools, Revision 21.1.1</a> <em>(November 2014)</em>
   </p>
   <div class="toggle-content-toggleme">
@@ -92,7 +114,7 @@
       alt=""/>Build Tools, Revision 21.1</a> <em>(October 2014)</em>
   </p>
   <div class="toggle-content-toggleme">
-    <p>Added multidex file support for APKs and Jack suppport to address the 64K method reference
+    <p>Added multidex file support for APKs and Jack support to address the 64K method reference
     limit.</p>
   </div>
 </div>
diff --git a/docs/html/tools/revisions/gradle-plugin.jd b/docs/html/tools/revisions/gradle-plugin.jd
index e083792..fd294d2 100644
--- a/docs/html/tools/revisions/gradle-plugin.jd
+++ b/docs/html/tools/revisions/gradle-plugin.jd
@@ -39,6 +39,36 @@
 <div class="toggle-content opened">
   <p><a href="#" onclick="return toggleContent(this)">
     <img src="{@docRoot}assets/images/triangle-opened.png" class="toggle-content-img"
+      alt=""/>Android Plugin for Gradle, Revision 1.1.3</a> <em>(March 2015)</em>
+  </p>
+
+  <div class="toggle-content-toggleme">
+
+    <dl>
+    <dt>Dependencies:</dt>
+
+    <dd>
+      <ul>
+        <li>Gradle 2.2.1 or higher.</li>
+        <li>Build Tools 21.1.1 or higher.</li>
+      </ul>
+    </dd>
+
+    <dt>General Notes:</dt>
+    <dd>
+    <ul>
+      <li>Fixed issue with duplicated dependencies on a test app that triggered a ProGuard failure. </li>
+      <li>Fixed Comparator implementation which did not comply with the JDK Comparator contract and
+      generated a JDK 7 error.</li>
+    </ul>
+    </dd>
+  </div>
+</div>
+
+
+<div class="toggle-content closed">
+  <p><a href="#" onclick="return toggleContent(this)">
+    <img src="{@docRoot}assets/images/triangle-closed.png" class="toggle-content-img"
       alt=""/>Android Plugin for Gradle, Revision 1.1.2</a> <em>(February 2015)</em>
   </p>
 
@@ -68,7 +98,6 @@
 
 
 
-
 <div class="toggle-content closed">
   <p><a href="#" onclick="return toggleContent(this)">
     <img src="{@docRoot}assets/images/triangle-closed.png" class="toggle-content-img"
diff --git a/docs/html/training/location/geofencing.jd b/docs/html/training/location/geofencing.jd
index 748b6ec..59fc4c6 100644
--- a/docs/html/training/location/geofencing.jd
+++ b/docs/html/training/location/geofencing.jd
@@ -9,9 +9,11 @@
 
 <h2>This lesson teaches you to</h2>
 <ol>
-    <li><a href="#RequestGeofences">Request Geofence Monitoring</a></li>
+    <li><a href="#RequestGeofences">Set up for Geofence Monitoring</a></li>
+    <li><a href="#CreateAdd">Create and Add Geofences</a></li>
     <li><a href="#HandleGeofenceTransitions">Handle Geofence Transitions</a></li>
     <li><a href="#StopGeofenceMonitoring">Stop Geofence Monitoring</a></li>
+
 </ol>
 
 <h2>You should also read</h2>
@@ -23,577 +25,148 @@
 
 <h2>Try it out</h2>
 
-<div class="download-box">
-  <a href="http://developer.android.com/shareables/training/GeofenceDetection.zip" class="button">Download the sample</a>
-  <p class="filename">GeofenceDetection.zip</p>
-</div>
+   <ul>
+      <li>
+        <a href="https://github.com/googlesamples/android-play-location/tree/master/Geofencing"
+        class="external-link">Geofencing</a>
+      </li>
+    </ul>
 
 </div>
 </div>
 <p>
-    Geofencing combines awareness of the user's current location with awareness of nearby
-    features, defined as the user's proximity to locations that may be of interest. To mark a
+    Geofencing combines awareness of the user's current location with awareness of the user's
+    proximity to locations that may be of interest. To mark a
     location of interest, you specify its latitude and longitude. To adjust the proximity for the
-    location, you add a radius. The latitude, longitude, and radius define a geofence.
-    You can have multiple active geofences at one time.
+    location, you add a radius. The latitude, longitude, and radius define a geofence, creating a
+    circular area, or fence, around the location of interest.
 </p>
 <p>
-    Location Services treats a geofences as an area rather than as a points and proximity. This
-    allows it to detect when the user enters or exits a geofence. For each geofence, you can ask
-    Location Services to send you entrance events or exit events or both. You can also limit the
-    duration of a geofence by specifying an expiration duration in milliseconds. After the geofence
-    expires, Location Services automatically removes it.
+    You can have multiple active geofences, with a limit of 100 per device user. For each geofence,
+    you can ask Location Services to send you entrance and exit events, or you can specify a
+    duration within the geofence area to wait, or <em>dwell</em>, before triggering an event. You
+    can limit the duration of any geofence by specifying an expiration duration in milliseconds.
+    After the geofence expires, Location Services automatically removes it.
 </p>
-<!--
-    Send geofences to Location Services
- -->
-<h2 id="RequestGeofences">Request Geofence Monitoring</h2>
+
+<img src="{@docRoot}images/training/geofence@2x.png"
+srcset="{@docRoot}images/training/geofence.png 1x, {@docRoot}images/training/geofence@2x.png 2x" alt=""
+  width="400" height="400"/>
+<p>
+    This lesson shows you how to add and remove geofences, and then listen for geofence transitions
+    using an {@link android.app.IntentService}.</p>
+
+<h2 id="RequestGeofences">Set up for Geofence Monitoring</h2>
 <p>
     The first step in requesting geofence monitoring is to request the necessary permission.
     To use geofencing, your app must request
     {@link android.Manifest.permission#ACCESS_FINE_LOCATION ACCESS_FINE_LOCATION}. To request this
     permission, add the following element as a child element of the
 <code><a href="{@docRoot}guide/topics/manifest/manifest-element.html">&lt;manifest&gt;</a></code>
-    element:
+    element in your app manifest:
 </p>
 <pre>
 &lt;uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/&gt;
 </pre>
-<!-- Check for Google Play services -->
-<h3>Check for Google Play Services</h3>
-<p>
-    Location Services is part of the Google Play services APK. Since it's hard to anticipate the
-    state of the user's device, you should always check that the APK is installed before you attempt
-    to connect to Location Services. To check that the APK is installed, call
-<code><a href="{@docRoot}reference/com/google/android/gms/common/GooglePlayServicesUtil.html#isGooglePlayServicesAvailable(android.content.Context)">GooglePlayServicesUtil.isGooglePlayServicesAvailable()</a></code>,
-    which returns one of the
-    integer result codes listed in the API reference documentation. If you encounter an error,
-    call
-<code><a href="{@docRoot}reference/com/google/android/gms/common/GooglePlayServicesUtil.html#getErrorDialog(int, android.app.Activity, int)">GooglePlayServicesUtil.getErrorDialog()</a></code>
-    to retrieve localized dialog that prompts users to take the correct action, then display
-    the dialog in a {@link android.support.v4.app.DialogFragment}. The dialog may allow the
-    user to correct the problem, in which case Google Play services may send a result back to your
-    activity. To handle this result, override the method
-    {@link android.support.v4.app.FragmentActivity#onActivityResult onActivityResult()}
 
-</p>
-<p class="note">
-    <strong>Note:</strong> To make your app compatible with
-    platform version 1.6 and later, the activity that displays the
-    {@link android.support.v4.app.DialogFragment} must subclass
-    {@link android.support.v4.app.FragmentActivity} instead of {@link android.app.Activity}. Using
-    {@link android.support.v4.app.FragmentActivity} also allows you to call
-    {@link android.support.v4.app.FragmentActivity#getSupportFragmentManager
-    getSupportFragmentManager()} to display the {@link android.support.v4.app.DialogFragment}.
-</p>
 <p>
-    Since you usually need to check for Google Play services in more than one place in your code,
-    define a method that encapsulates the check, then call the method before each connection
-    attempt. The following snippet contains all of the code required to check for Google
-    Play services:
+    If you want to use an {@link android.app.IntentService} to listen for geofence transitions,
+    add an element specifying the service name. This element must be
+    a child of the <code><a href="{@docRoot}guide/topics/manifest/application-element.html">
+    &lt;application&gt;</a></code> element:
+</p>
+
+<pre>
+&lt;application
+   android:allowBackup=&quot;true&quot;&gt;
+   ...
+   &lt;service android:name=".GeofenceTransitionsIntentService"/&gt;
+&lt;application/&gt;
+</pre>
+
+<p>To access the location APIs, you need to create an instance of the
+  Google Play services API client. To learn how to connect your client, see
+  <a href="{@docRoot}training/location/retrieve-current.html#play-services">Connect
+  to Google Play Services</a>.</p>
+
+<h2 id="CreateAdd">Create and Add Geofences</h2>
+
+<p>Your app needs to create and add geofences using the location API's builder class for
+ creating Geofence objects, and the convenience class for adding them. Also, to handle the
+ intents sent from Location Services when geofence transitions occur, you can define a
+ {@link android.app.PendingIntent} as shown in this section.
+</p>
+
+<h3>Create geofence objects</h3>
+
+<p>
+    First, use <code><a href="{@docRoot}reference/com/google/android/gms/location/Geofence.Builder.
+    html">Geofence.Builder</a></code> to create a geofence, setting the desired radius, duration, and
+    transition types for the geofence. For example, to populate a list object named
+    {@code mGeofenceList}:
+    </p>
+
+<pre>
+mGeofenceList.add(new Geofence.Builder()
+    // Set the request ID of the geofence. This is a string to identify this
+    // geofence.
+    .setRequestId(entry.getKey())
+
+    .setCircularRegion(
+            entry.getValue().latitude,
+            entry.getValue().longitude,
+            Constants.GEOFENCE_RADIUS_IN_METERS
+    )
+    .setExpirationDuration(Constants.GEOFENCE_EXPIRATION_IN_MILLISECONDS)
+    .setTransitionTypes(Geofence.GEOFENCE_TRANSITION_ENTER |
+            Geofence.GEOFENCE_TRANSITION_EXIT)
+    .build());
+</pre>
+
+<p>This example pulls data from a constants file. In actual practice, apps might
+    dynamically create geofences based on the user's location.</p>
+
+<h3>Specify geofences and initial triggers</h3>
+
+<p>
+    The following snippet uses the <code><a href="{@docRoot}reference/com/google/android/gms/location/GeofencingRequest.html">
+    GeofencingRequest</a></code> class
+    and its nested <code><a href="{@docRoot}reference/com/google/android/gms/location/GeofencingRequest.Builder.html">
+    GeofencingRequestBuilder</a></code> class to
+    specify the geofences to monitor and to set how related geofence events are triggered:
 </p>
 <pre>
-public class MainActivity extends FragmentActivity {
-    ...
-    // Global constants
-    /*
-     * Define a request code to send to Google Play services
-     * This code is returned in Activity.onActivityResult
-     */
-    private final static int
-            CONNECTION_FAILURE_RESOLUTION_REQUEST = 9000;
-    ...
-    // Define a DialogFragment that displays the error dialog
-    public static class ErrorDialogFragment extends DialogFragment {
-        // Global field to contain the error dialog
-        private Dialog mDialog;
-        ...
-        // Default constructor. Sets the dialog field to null
-        public ErrorDialogFragment() {
-            super();
-            mDialog = null;
-        }
-        ...
-        // Set the dialog to display
-        public void setDialog(Dialog dialog) {
-            mDialog = dialog;
-        }
-        ...
-        // Return a Dialog to the DialogFragment.
-        &#64;Override
-        public Dialog onCreateDialog(Bundle savedInstanceState) {
-            return mDialog;
-        }
-        ...
-    }
-    ...
-    /*
-     * Handle results returned to the FragmentActivity
-     * by Google Play services
-     */
-     &#64;Override
-    protected void onActivityResult(
-            int requestCode, int resultCode, Intent data) {
-        // Decide what to do based on the original request code
-        switch (requestCode) {
-            ...
-            case CONNECTION_FAILURE_RESOLUTION_REQUEST :
-            /*
-             * If the result code is Activity.RESULT_OK, try
-             * to connect again
-             */
-                switch (resultCode) {
-                    ...
-                    case Activity.RESULT_OK :
-                    /*
-                     * Try the request again
-                     */
-                    ...
-                    break;
-                }
-            ...
-        }
-        ...
-    }
-    ...
-    private boolean servicesConnected() {
-        // Check that Google Play services is available
-        int resultCode =
-                GooglePlayServicesUtil.
-                        isGooglePlayServicesAvailable(this);
-        // If Google Play services is available
-        if (ConnectionResult.SUCCESS == resultCode) {
-            // In debug mode, log the status
-            Log.d("Geofence Detection",
-                    "Google Play services is available.");
-            // Continue
-            return true;
-        // Google Play services was not available for some reason
-        } else {
-            // Get the error code
-            int errorCode = connectionResult.getErrorCode();
-            // Get the error dialog from Google Play services
-            Dialog errorDialog = GooglePlayServicesUtil.getErrorDialog(
-                    errorCode,
-                    this,
-                    CONNECTION_FAILURE_RESOLUTION_REQUEST);
-
-            // If Google Play services can provide an error dialog
-            if (errorDialog != null) {
-                // Create a new DialogFragment for the error dialog
-                ErrorDialogFragment errorFragment =
-                        new ErrorDialogFragment();
-                // Set the dialog in the DialogFragment
-                errorFragment.setDialog(errorDialog);
-                // Show the error dialog in the DialogFragment
-                errorFragment.show(
-                        getSupportFragmentManager(),
-                        "Geofence Detection");
-            }
-        }
-    }
-    ...
+private GeofencingRequest getGeofencingRequest() {
+    GeofencingRequest.Builder builder = new GeofencingRequest.Builder();
+    builder.setInitialTrigger(GeofencingRequest.INITIAL_TRIGGER_ENTER);
+    builder.addGeofences(mGeofenceList);
+    return builder.build();
 }
 </pre>
-<p>
-    Snippets in the following sections call this method to verify that Google Play services is
-    available.
-</p>
-<p>
-    To use geofencing, start by defining the geofences you want to monitor. Although you usually
-    store geofence data in a local database or download it from the network, you need to send
-    a geofence to Location Services as an instance of
-<code><a href="{@docRoot}reference/com/google/android/gms/location/Geofence.html">Geofence</a></code>,
-    which you create with
-<code><a href="{@docRoot}reference/com/google/android/gms/location/Geofence.Builder.html">Geofence.Builder</a></code>.
-    Each
-<code><a href="{@docRoot}reference/com/google/android/gms/location/Geofence.html">Geofence</a></code>
-    object contains the following information:
-</p>
-<dl>
-    <dt>Latitude, longitude, and radius</dt>
-    <dd>
-        Define a circular area for the geofence. Use the latitude and longitude to mark a location
-        of interest, and then use the radius to adjust how close the user needs to approach the
-        location before the geofence is detected. The larger the radius, the more likely the
-        user will trigger a geofence transition alert by approaching the geofence. For example,
-        providing a large radius for a geofencing app that turns on lights in the user's house as
-        the user returns home might cause the lights to go on even if the user is simply passing by.
-    </dd>
-    <dt>Expiration time</dt>
-    <dd>
-        How long the geofence should remain active. Once the expiration time is reached, Location
-        Services deletes the geofence. Most of the time, you should specify an expiration time, but
-        you may want to keep permanent geofences for the user's home or place of work.
-    </dd>
-    <dt>Transition type</dt>
-    <dd>
-        Location Services can detect when the user steps within the radius of the geofence ("entry")
-        and when the user steps outside the radius of the geofence ("exit"), or both.
-    </dd>
-    <dt>Geofence ID</dt>
-    <dd>
-        A string that is stored with the geofence. You should make this unique, so that you can
-        use it to remove a geofence from Location Services tracking.
-    </dd>
-</dl>
-<h3>Define geofence storage</h3>
-<p>
-    A geofencing app needs to read and write geofence data to persistent storage. You shouldn't use
-<code><a href="{@docRoot}reference/com/google/android/gms/location/Geofence.html">Geofence</a></code>
-    objects to do this; instead, use storage techniques such as databases that can store groups of
-    related data.
-</p>
-<p>
-    As an example of storing geofence data, the following snippet defines two classes that use
-    the app's {@link android.content.SharedPreferences} instance for persistent storage. The class
-    {@code SimpleGeofence}, analogous to a database record, stores the
-    data for a single
-<code><a href="{@docRoot}reference/com/google/android/gms/location/Geofence.html">Geofence</a></code>
-    object in a "flattened" form. The class {@code SimpleGeofenceStore}, analogous to a database,
-    reads and writes {@code SimpleGeofence} data to the
-    {@link android.content.SharedPreferences} instance.
-</p>
-<pre>
-public class MainActivity extends FragmentActivity {
-    ...
-    /**
-     * A single Geofence object, defined by its center and radius.
-     */
-    public class SimpleGeofence {
-            // Instance variables
-            private final String mId;
-            private final double mLatitude;
-            private final double mLongitude;
-            private final float mRadius;
-            private long mExpirationDuration;
-            private int mTransitionType;
 
-        /**
-         * @param geofenceId The Geofence's request ID
-         * @param latitude Latitude of the Geofence's center.
-         * @param longitude Longitude of the Geofence's center.
-         * @param radius Radius of the geofence circle.
-         * @param expiration Geofence expiration duration
-         * @param transition Type of Geofence transition.
-         */
-        public SimpleGeofence(
-                String geofenceId,
-                double latitude,
-                double longitude,
-                float radius,
-                long expiration,
-                int transition) {
-            // Set the instance fields from the constructor
-            this.mId = geofenceId;
-            this.mLatitude = latitude;
-            this.mLongitude = longitude;
-            this.mRadius = radius;
-            this.mExpirationDuration = expiration;
-            this.mTransitionType = transition;
-        }
-        // Instance field getters
-        public String getId() {
-            return mId;
-        }
-        public double getLatitude() {
-            return mLatitude;
-        }
-        public double getLongitude() {
-            return mLongitude;
-        }
-        public float getRadius() {
-            return mRadius;
-        }
-        public long getExpirationDuration() {
-            return mExpirationDuration;
-        }
-        public int getTransitionType() {
-            return mTransitionType;
-        }
-        /**
-         * Creates a Location Services Geofence object from a
-         * SimpleGeofence.
-         *
-         * @return A Geofence object
-         */
-        public Geofence toGeofence() {
-            // Build a new Geofence object
-            return new Geofence.Builder()
-                    .setRequestId(getId())
-                    .setTransitionTypes(mTransitionType)
-                    .setCircularRegion(
-                            getLatitude(), getLongitude(), getRadius())
-                    .setExpirationDuration(mExpirationDuration)
-                    .build();
-        }
-    }
-    ...
-    /**
-     * Storage for geofence values, implemented in SharedPreferences.
-     */
-    public class SimpleGeofenceStore {
-        // Keys for flattened geofences stored in SharedPreferences
-        public static final String KEY_LATITUDE =
-                "com.example.android.geofence.KEY_LATITUDE";
-        public static final String KEY_LONGITUDE =
-                "com.example.android.geofence.KEY_LONGITUDE";
-        public static final String KEY_RADIUS =
-                "com.example.android.geofence.KEY_RADIUS";
-        public static final String KEY_EXPIRATION_DURATION =
-                "com.example.android.geofence.KEY_EXPIRATION_DURATION";
-        public static final String KEY_TRANSITION_TYPE =
-                "com.example.android.geofence.KEY_TRANSITION_TYPE";
-        // The prefix for flattened geofence keys
-        public static final String KEY_PREFIX =
-                "com.example.android.geofence.KEY";
-        /*
-         * Invalid values, used to test geofence storage when
-         * retrieving geofences
-         */
-        public static final long INVALID_LONG_VALUE = -999l;
-        public static final float INVALID_FLOAT_VALUE = -999.0f;
-        public static final int INVALID_INT_VALUE = -999;
-        // The SharedPreferences object in which geofences are stored
-        private final SharedPreferences mPrefs;
-        // The name of the SharedPreferences
-        private static final String SHARED_PREFERENCES =
-                "SharedPreferences";
-        // Create the SharedPreferences storage with private access only
-        public SimpleGeofenceStore(Context context) {
-            mPrefs =
-                    context.getSharedPreferences(
-                            SHARED_PREFERENCES,
-                            Context.MODE_PRIVATE);
-        }
-        /**
-         * Returns a stored geofence by its id, or returns {@code null}
-         * if it's not found.
-         *
-         * @param id The ID of a stored geofence
-         * @return A geofence defined by its center and radius. See
-         */
-        public SimpleGeofence getGeofence(String id) {
-            /*
-             * Get the latitude for the geofence identified by id, or
-             * INVALID_FLOAT_VALUE if it doesn't exist
-             */
-            double lat = mPrefs.getFloat(
-                    getGeofenceFieldKey(id, KEY_LATITUDE),
-                    INVALID_FLOAT_VALUE);
-            /*
-             * Get the longitude for the geofence identified by id, or
-             * INVALID_FLOAT_VALUE if it doesn't exist
-             */
-            double lng = mPrefs.getFloat(
-                    getGeofenceFieldKey(id, KEY_LONGITUDE),
-                    INVALID_FLOAT_VALUE);
-            /*
-             * Get the radius for the geofence identified by id, or
-             * INVALID_FLOAT_VALUE if it doesn't exist
-             */
-            float radius = mPrefs.getFloat(
-                    getGeofenceFieldKey(id, KEY_RADIUS),
-                    INVALID_FLOAT_VALUE);
-            /*
-             * Get the expiration duration for the geofence identified
-             * by id, or INVALID_LONG_VALUE if it doesn't exist
-             */
-            long expirationDuration = mPrefs.getLong(
-                    getGeofenceFieldKey(id, KEY_EXPIRATION_DURATION),
-                    INVALID_LONG_VALUE);
-            /*
-             * Get the transition type for the geofence identified by
-             * id, or INVALID_INT_VALUE if it doesn't exist
-             */
-            int transitionType = mPrefs.getInt(
-                    getGeofenceFieldKey(id, KEY_TRANSITION_TYPE),
-                    INVALID_INT_VALUE);
-            // If none of the values is incorrect, return the object
-            if (
-                lat != GeofenceUtils.INVALID_FLOAT_VALUE &amp;&amp;
-                lng != GeofenceUtils.INVALID_FLOAT_VALUE &amp;&amp;
-                radius != GeofenceUtils.INVALID_FLOAT_VALUE &amp;&amp;
-                expirationDuration !=
-                        GeofenceUtils.INVALID_LONG_VALUE &amp;&amp;
-                transitionType != GeofenceUtils.INVALID_INT_VALUE) {
-
-                // Return a true Geofence object
-                return new SimpleGeofence(
-                        id, lat, lng, radius, expirationDuration,
-                        transitionType);
-            // Otherwise, return null.
-            } else {
-                return null;
-            }
-        }
-        /**
-         * Save a geofence.
-         * @param geofence The SimpleGeofence containing the
-         * values you want to save in SharedPreferences
-         */
-        public void setGeofence(String id, SimpleGeofence geofence) {
-            /*
-             * Get a SharedPreferences editor instance. Among other
-             * things, SharedPreferences ensures that updates are atomic
-             * and non-concurrent
-             */
-            Editor editor = mPrefs.edit();
-            // Write the Geofence values to SharedPreferences
-            editor.putFloat(
-                    getGeofenceFieldKey(id, KEY_LATITUDE),
-                    (float) geofence.getLatitude());
-            editor.putFloat(
-                    getGeofenceFieldKey(id, KEY_LONGITUDE),
-                    (float) geofence.getLongitude());
-            editor.putFloat(
-                    getGeofenceFieldKey(id, KEY_RADIUS),
-                    geofence.getRadius());
-            editor.putLong(
-                    getGeofenceFieldKey(id, KEY_EXPIRATION_DURATION),
-                    geofence.getExpirationDuration());
-            editor.putInt(
-                    getGeofenceFieldKey(id, KEY_TRANSITION_TYPE),
-                    geofence.getTransitionType());
-            // Commit the changes
-            editor.commit();
-        }
-        public void clearGeofence(String id) {
-            /*
-             * Remove a flattened geofence object from storage by
-             * removing all of its keys
-             */
-            Editor editor = mPrefs.edit();
-            editor.remove(getGeofenceFieldKey(id, KEY_LATITUDE));
-            editor.remove(getGeofenceFieldKey(id, KEY_LONGITUDE));
-            editor.remove(getGeofenceFieldKey(id, KEY_RADIUS));
-            editor.remove(getGeofenceFieldKey(id,
-                    KEY_EXPIRATION_DURATION));
-            editor.remove(getGeofenceFieldKey(id, KEY_TRANSITION_TYPE));
-            editor.commit();
-        }
-        /**
-         * Given a Geofence object's ID and the name of a field
-         * (for example, KEY_LATITUDE), return the key name of the
-         * object's values in SharedPreferences.
-         *
-         * @param id The ID of a Geofence object
-         * @param fieldName The field represented by the key
-         * @return The full key name of a value in SharedPreferences
-         */
-        private String getGeofenceFieldKey(String id,
-                String fieldName) {
-            return KEY_PREFIX + "_" + id + "_" + fieldName;
-        }
-    }
-    ...
-}
-</pre>
-<h3>Create Geofence objects</h3>
 <p>
-    The following snippet uses the {@code SimpleGeofence} and {@code SimpleGeofenceStore} classes
-    gets geofence data from the UI, stores it in {@code SimpleGeofence} objects, stores these
-    objects in a {@code SimpleGeofenceStore} object, and then creates
-<code><a href="{@docRoot}reference/com/google/android/gms/location/Geofence.html">Geofence</a></code>
-    objects:
+    This example shows the use of two geofence triggers. The <code><a href="{@docRoot}reference/com/google/android/gms/location/Geofence.html#GEOFENCE_TRANSITION_ENTER">
+    GEOFENCE_TRANSITION_ENTER</a></code>
+    transition triggers when a device enters a geofence, and the <code><a href="{@docRoot}reference/com/google/android/gms/location/Geofence.html#GEOFENCE_TRANSITION_EXIT">
+    GEOFENCE_TRANSITION_EXIT</a></code>
+    transition triggers when a device exits a geofence. Specifying
+    <code><a href="{@docRoot}reference/com/google/android/gms/location/GeofencingRequest.html#INITIAL_TRIGGER_ENTER">
+        INITIAL_TRIGGER_ENTER</a></code> tells Location services that
+    <code><a href="{@docRoot}reference/com/google/android/gms/location/Geofence.html#GEOFENCE_TRANSITION_ENTER">
+        GEOFENCE_TRANSITION_ENTER</a></code>
+    should be triggered if the the device is already inside the geofence.</p>
 </p>
-<pre>
-public class MainActivity extends FragmentActivity {
-    ...
-    /*
-     * Use to set an expiration time for a geofence. After this amount
-     * of time Location Services will stop tracking the geofence.
-     */
-    private static final long SECONDS_PER_HOUR = 60;
-    private static final long MILLISECONDS_PER_SECOND = 1000;
-    private static final long GEOFENCE_EXPIRATION_IN_HOURS = 12;
-    private static final long GEOFENCE_EXPIRATION_TIME =
-            GEOFENCE_EXPIRATION_IN_HOURS *
-            SECONDS_PER_HOUR *
-            MILLISECONDS_PER_SECOND;
-    ...
-    /*
-     * Handles to UI views containing geofence data
-     */
-    // Handle to geofence 1 latitude in the UI
-    private EditText mLatitude1;
-    // Handle to geofence 1 longitude in the UI
-    private EditText mLongitude1;
-    // Handle to geofence 1 radius in the UI
-    private EditText mRadius1;
-    // Handle to geofence 2 latitude in the UI
-    private EditText mLatitude2;
-    // Handle to geofence 2 longitude in the UI
-    private EditText mLongitude2;
-    // Handle to geofence 2 radius in the UI
-    private EditText mRadius2;
-    /*
-     * Internal geofence objects for geofence 1 and 2
-     */
-    private SimpleGeofence mUIGeofence1;
-    private SimpleGeofence mUIGeofence2;
-    ...
-    // Internal List of Geofence objects
-    List&lt;Geofence&gt; mGeofenceList;
-    // Persistent storage for geofences
-    private SimpleGeofenceStore mGeofenceStorage;
-    ...
-    &#64;Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        ...
-        // Instantiate a new geofence storage area
-        mGeofenceStorage = new SimpleGeofenceStore(this);
 
-        // Instantiate the current List of geofences
-        mCurrentGeofences = new ArrayList&lt;Geofence&gt;();
-    }
-    ...
-    /**
-     * Get the geofence parameters for each geofence from the UI
-     * and add them to a List.
-     */
-    public void createGeofences() {
-        /*
-         * Create an internal object to store the data. Set its
-         * ID to "1". This is a "flattened" object that contains
-         * a set of strings
-         */
-        mUIGeofence1 = new SimpleGeofence(
-                "1",
-                Double.valueOf(mLatitude1.getText().toString()),
-                Double.valueOf(mLongitude1.getText().toString()),
-                Float.valueOf(mRadius1.getText().toString()),
-                GEOFENCE_EXPIRATION_TIME,
-                // This geofence records only entry transitions
-                Geofence.GEOFENCE_TRANSITION_ENTER);
-        // Store this flat version
-        mGeofenceStorage.setGeofence("1", mUIGeofence1);
-        // Create another internal object. Set its ID to "2"
-        mUIGeofence2 = new SimpleGeofence(
-                "2",
-                Double.valueOf(mLatitude2.getText().toString()),
-                Double.valueOf(mLongitude2.getText().toString()),
-                Float.valueOf(mRadius2.getText().toString()),
-                GEOFENCE_EXPIRATION_TIME,
-                // This geofence records both entry and exit transitions
-                Geofence.GEOFENCE_TRANSITION_ENTER |
-                Geofence.GEOFENCE_TRANSITION_EXIT);
-        // Store this flat version
-        mGeofenceStorage.setGeofence(2, mUIGeofence2);
-        mGeofenceList.add(mUIGeofence1.toGeofence());
-        mGeofenceList.add(mUIGeofence2.toGeofence());
-    }
-    ...
-}
-</pre>
-<p>
-    In addition to the {@link java.util.List} of
-<code><a href="{@docRoot}reference/com/google/android/gms/location/Geofence.html">Geofence</a></code>
-    objects you want to monitor, you need to provide Location Services with the
-    {@link android.content.Intent} that it sends to your app when it detects geofence
-    transitions.
-<h4>Define a Intent for geofence transitions</h4>
+<p>In many cases, it may be preferable to use instead <code><a href="{@docRoot}reference/com/google/android/gms/location/GeofencingRequest.html#INITIAL_TRIGGER_DWELL">
+    INITIAL_TRIGGER_DWELL</a></code>,
+    which triggers events only when the user stops for a defined duration within a geofence.
+    This approach can help reduce "alert spam" resulting from large numbers notifications when a
+    device briefly enters and exits geofences. Another strategy for getting best results from your
+    geofences is to set a minimum radius of 100 meters. This helps account for the location accuracy
+    of typical WiFi networks, and also helps reduce device power consumption.
+</p>
+
+<h3>Define an Intent for geofence transitions</h3>
 <p>
     The {@link android.content.Intent} sent from Location Services can trigger various actions in
     your app, but you should <i>not</i> have it start an activity or fragment, because components
@@ -601,807 +174,133 @@
     {@link android.app.IntentService} is a good way to handle the intent. An
     {@link android.app.IntentService} can post a notification, do long-running background work,
     send intents to other services, or send a broadcast intent. The following snippet shows how
-    how to define a {@link android.app.PendingIntent} that starts an
-    {@link android.app.IntentService}:
+    to define a {@link android.app.PendingIntent} that starts an {@link android.app.IntentService}:
 </p>
 <pre>
 public class MainActivity extends FragmentActivity {
     ...
-    /*
-     * Create a PendingIntent that triggers an IntentService in your
-     * app when a geofence transition occurs.
-     */
-    private PendingIntent getTransitionPendingIntent() {
-        // Create an explicit Intent
-        Intent intent = new Intent(this,
-                ReceiveTransitionsIntentService.class);
-        /*
-         * Return the PendingIntent
-         */
-        return PendingIntent.getService(
-                this,
-                0,
-                intent,
-                PendingIntent.FLAG_UPDATE_CURRENT);
-    }
-    ...
-}
-</pre>
-<p>
-    Now you have all the code you need to send a request to monitor geofences to Location
-    Services.
-</p>
-<!-- Send the monitoring request -->
-<h3 id="requestmonitoring">Send the monitoring request</h3>
-<p>
-    Sending the monitoring request requires two asynchronous operations. The first operation gets a
-    location client for the request, and the second makes the request using the client. In both
-    cases, Location Services invokes a callback method when it finishes the operation. The best way
-    to handle these operations is to chain together the method calls. The following snippets
-    demonstrate how to set up an activity, define the methods, and call them in the proper order.
-</p>
-<p>
-     First, modify the activity's class definition to implement the necessary callback interfaces.
-     Add the following interfaces:
-</p>
-<dl>
-    <dt>
-<code><a href="{@docRoot}reference/com/google/android/gms/common/GooglePlayServicesClient.ConnectionCallbacks.html">ConnectionCallbacks</a></code>
-    </dt>
-    <dd>
-        Specifies methods that Location Services calls when a location client is connected or
-        disconnected.
-    </dd>
-    <dt>
-<code><a href="{@docRoot}reference/com/google/android/gms/common/GooglePlayServicesClient.OnConnectionFailedListener.html">OnConnectionFailedListener</a></code>
-    </dt>
-    <dd>
-        Specifies a method that Location Services calls if an error occurs while attempting to
-        connect the location client.
-    </dd>
-    <dt>
-<code><a href="{@docRoot}reference/com/google/android/gms/location/LocationClient.OnAddGeofencesResultListener.html">OnAddGeofencesResultListener</a></code>
-    </dt>
-    <dd>
-        Specifies a method that Location Services calls once it has added the geofences.
-    </dd>
-</dl>
-<p>
-    For example:
-</p>
-<pre>
-public class MainActivity extends FragmentActivity implements
-        ConnectionCallbacks,
-        OnConnectionFailedListener,
-        OnAddGeofencesResultListener {
-    ...
-}
-</pre>
-<h4>Start the request process</h4>
-<p>
-    Next, define a method that starts the request process by connecting to Location Services.
-    Mark this as a request to add a geofence by setting a global variable. This allows you to
-    use the callback
-<code><a href="{@docRoot}reference/com/google/android/gms/common/GooglePlayServicesClient.ConnectionCallbacks.html#onConnected(android.os.Bundle)">ConnectionCallbacks.onConnected()</a></code>
-    to add geofences and to remove them, as described in succeeding sections.
-</p>
-<p>
-<p>
-    To guard against race conditions that might arise if your app tries to start another request
-    before the first one finishes, define a boolean flag that tracks the state of the current
-    request:
-</p>
-<pre>
-public class MainActivity extends FragmentActivity implements
-        ConnectionCallbacks,
-        OnConnectionFailedListener,
-        OnAddGeofencesResultListener {
-    ...
-    // Holds the location client
-    private LocationClient mLocationClient;
-    // Stores the PendingIntent used to request geofence monitoring
-    private PendingIntent mGeofenceRequestIntent;
-    // Defines the allowable request types.
-    public enum REQUEST_TYPE = {ADD}
-    private REQUEST_TYPE mRequestType;
-    // Flag that indicates if a request is underway.
-    private boolean mInProgress;
-    ...
-    &#64;Override
-    protected void onCreate(Bundle savedInstanceState) {
-        ...
-        // Start with the request flag set to false
-        mInProgress = false;
-        ...
-    }
-    ...
-    /**
-     * Start a request for geofence monitoring by calling
-     * LocationClient.connect().
-     */
-    public void addGeofences() {
-        // Start a request to add geofences
-        mRequestType = ADD;
-        /*
-         * Test for Google Play services after setting the request type.
-         * If Google Play services isn't present, the proper request
-         * can be restarted.
-         */
-        if (!servicesConnected()) {
-            return;
+    private PendingIntent getGeofencePendingIntent() {
+        // Reuse the PendingIntent if we already have it.
+        if (mGeofencePendingIntent != null) {
+            return mGeofencePendingIntent;
         }
-        /*
-         * Create a new location client object. Since the current
-         * activity class implements ConnectionCallbacks and
-         * OnConnectionFailedListener, pass the current activity object
-         * as the listener for both parameters
-         */
-        mLocationClient = new LocationClient(this, this, this)
-        // If a request is not already underway
-        if (!mInProgress) {
-            // Indicate that a request is underway
-            mInProgress = true;
-            // Request a connection from the client to Location Services
-            mLocationClient.connect();
-        } else {
-            /*
-             * A request is already underway. You can handle
-             * this situation by disconnecting the client,
-             * re-setting the flag, and then re-trying the
-             * request.
-             */
-        }
+        Intent intent = new Intent(this, GeofenceTransitionsIntentService.class);
+        // We use FLAG_UPDATE_CURRENT so that we get the same pending intent back when
+        // calling addGeofences() and removeGeofences().
+        return PendingIntent.getService(this, 0, intent, PendingIntent.
+                FLAG_UPDATE_CURRENT);
     }
-    ...
-}
 </pre>
-<h4>Send a request to add the geofences</h4>
+
+<h3>Add geofences</h3>
+
 <p>
-    In your implementation of
-<code><a href="{@docRoot}reference/com/google/android/gms/common/GooglePlayServicesClient.ConnectionCallbacks.html#onConnected(android.os.Bundle)">ConnectionCallbacks.onConnected()</a></code>,
-    call
-<code><a href="{@docRoot}reference/com/google/android/gms/location/LocationClient.html#addGeofences(java.util.List<com.google.android.gms.location.Geofence>, android.app.PendingIntent, com.google.android.gms.location.LocationClient.OnAddGeofencesResultListener)">LocationClient.addGeofences()</a></code>.
-    Notice that if the connection fails,
-<code><a href="{@docRoot}reference/com/google/android/gms/common/GooglePlayServicesClient.ConnectionCallbacks.html#onConnected(android.os.Bundle)">onConnected()</a></code>
-    isn't called, and the request stops.
+    To add geofences, use the <code><a href="{@docRoot}reference/com/google/android/gms/location/GeofencingApi.html#addGeofences(com.google.android.gms.common.api.GoogleApiClient, com.google.android.gms.location.GeofencingRequest, android.app.PendingIntent)">{@code GeoencingApi.addGeofences()}</a></code> method.
+    Provide the Google API client, the <code><a href="{@docRoot}reference/com/google/android/gms/location/GeofencingRequest">
+    GeofencingRequest</a></code> object, and the {@link android.app.PendingIntent}.
+    The following snippet, which processes the results in <code><a href="{@docRoot}reference/com/google/android/gms/common/api/ResultCallback.html#onResult(R)">
+    onResult()</a></code>, assumes that the main activity implements <code><a href="{@docRoot}reference/com/google/android/gms/common/api/ResultCallback.html">
+    ResultCallback</a></code>:
 </p>
 <pre>
-public class MainActivity extends FragmentActivity implements
-        ConnectionCallbacks,
-        OnConnectionFailedListener,
-        OnAddGeofencesResultListener {
+public class MainActivity extends FragmentActivity {
     ...
-    /*
-     * Provide the implementation of ConnectionCallbacks.onConnected()
-     * Once the connection is available, send a request to add the
-     * Geofences
-     */
-    &#64;Override
-    private void onConnected(Bundle dataBundle) {
-        ...
-        switch (mRequestType) {
-            case ADD :
-                // Get the PendingIntent for the request
-                mTransitionPendingIntent =
-                        getTransitionPendingIntent();
-                // Send a request to add the current geofences
-                mLocationClient.addGeofences(
-                        mCurrentGeofences, pendingIntent, this);
-            ...
-        }
-    }
-    ...
-}
+    LocationServices.GeofencingApi.addGeofences(
+                mGoogleApiClient,
+                getGeofencingRequest(),
+                getGeofencePendingIntent()
+        ).setResultCallback(this);
 </pre>
-<p>
-    Notice that
-<code><a href="{@docRoot}reference/com/google/android/gms/location/LocationClient.html#addGeofences(java.util.List<com.google.android.gms.location.Geofence>, android.app.PendingIntent, com.google.android.gms.location.LocationClient.OnAddGeofencesResultListener)">addGeofences()</a></code>
-    returns immediately, but the status of the request is indeterminate until Location Services
-    calls
-<code><a href="{@docRoot}reference/com/google/android/gms/location/LocationClient.OnAddGeofencesResultListener.html#onAddGeofencesResult(int, java.lang.String[])">onAddGeofencesResult()</a></code>
-    Once this method is called, you can determine if the request was successful or not.
-</p>
-<h4>Check the result returned by Location Services</h4>
-<p>
-    When Location Services invokes your implementation of the callback method
-<code><a href="{@docRoot}reference/com/google/android/gms/location/LocationClient.OnAddGeofencesResultListener.html#onAddGeofencesResult(int, java.lang.String[])">onAddGeofencesResult()</a></code>,
-    indicating that the request is complete, examine the incoming status code. If the request
-    was successful, the geofences you requested are active. If the request was unsuccessful,
-    the geofences aren't active, and you need to re-try the request or report an error. For example:
-</p>
-<pre>
-public class MainActivity extends FragmentActivity implements
-        ConnectionCallbacks,
-        OnConnectionFailedListener,
-        OnAddGeofencesResultListener {
-        ...
-    /*
-     * Provide the implementation of
-     * OnAddGeofencesResultListener.onAddGeofencesResult.
-     * Handle the result of adding the geofences
-     *
-     */
-    &#64;Override
-    public void onAddGeofencesResult(
-            int statusCode, String[] geofenceRequestIds) {
-        // If adding the geofences was successful
-        if (LocationStatusCodes.SUCCESS == statusCode) {
-            /*
-             * Handle successful addition of geofences here.
-             * You can send out a broadcast intent or update the UI.
-             * geofences into the Intent's extended data.
-             */
-        } else {
-        // If adding the geofences failed
-            /*
-             * Report errors here.
-             * You can log the error using Log.e() or update
-             * the UI.
-             */
-        }
-        // Turn off the in progress flag and disconnect the client
-        mInProgress = false;
-        mLocationClient.disconnect();
-    }
-    ...
-}
-</pre>
-<!-- Handle disconnections -->
-<h3>Handle disconnections</h3>
-<p>
-    In some cases, Location Services may disconnect from the activity recognition client before
-    you call
-<code><a href="{@docRoot}reference/com/google/android/gms/location/LocationClient.html#disconnect()">disconnect()</a></code>.
-    To handle this situation, implement <code>
-<a href="{@docRoot}reference/com/google/android/gms/common/GooglePlayServicesClient.ConnectionCallbacks.html#onDisconnected()">onDisconnected()</a></code>.
-    In this method, set the request flag to indicate that a request is not in progress, and
-    delete the client:
-</p>
-<pre>
-public class MainActivity extends FragmentActivity implements
-        ConnectionCallbacks,
-        OnConnectionFailedListener,
-        OnAddGeofencesResultListener {
-    ...
-    /*
-     * Implement ConnectionCallbacks.onDisconnected()
-     * Called by Location Services once the location client is
-     * disconnected.
-     */
-    &#64;Override
-    public void onDisconnected() {
-        // Turn off the request flag
-        mInProgress = false;
-        // Destroy the current location client
-        mLocationClient = null;
-    }
-    ...
-}
-</pre>
-<!-- Handle connection errors -->
-<h3>Handle connection errors</h3>
-<p>
-    Besides handling the normal callbacks from Location Services, you have to provide a callback
-    method that Location Services calls if a connection error occurs. This callback method
-    can re-use the {@link android.support.v4.app.DialogFragment} class that you defined to
-    handle the check for Google Play services. It can also re-use the override you defined
-    for {@link android.support.v4.app.FragmentActivity#onActivityResult onActivityResult()} that
-    receives any Google Play services results that occur when the user interacts with the
-    error dialog. The following snippet shows you a sample implementation of the callback method:
-</p>
-<pre>
-public class MainActivity extends FragmentActivity implements
-        ConnectionCallbacks,
-        OnConnectionFailedListener,
-        OnAddGeofencesResultListener {
-    ...
-    // Implementation of OnConnectionFailedListener.onConnectionFailed
-    &#64;Override
-    public void onConnectionFailed(ConnectionResult connectionResult) {
-        // Turn off the request flag
-        mInProgress = false;
-        /*
-         * If the error has a resolution, start a Google Play services
-         * activity to resolve it.
-         */
-        if (connectionResult.hasResolution()) {
-            try {
-                connectionResult.startResolutionForResult(
-                        this,
-                        CONNECTION_FAILURE_RESOLUTION_REQUEST);
-            } catch (SendIntentException e) {
-                // Log the error
-                e.printStackTrace();
-            }
-        // If no resolution is available, display an error dialog
-        } else {
-            // Get the error code
-            int errorCode = connectionResult.getErrorCode();
-            // Get the error dialog from Google Play services
-            Dialog errorDialog = GooglePlayServicesUtil.getErrorDialog(
-                    errorCode,
-                    this,
-                    CONNECTION_FAILURE_RESOLUTION_REQUEST);
-            // If Google Play services can provide an error dialog
-            if (errorDialog != null) {
-                // Create a new DialogFragment for the error dialog
-                ErrorDialogFragment errorFragment =
-                        new ErrorDialogFragment();
-                // Set the dialog in the DialogFragment
-                errorFragment.setDialog(errorDialog);
-                // Show the error dialog in the DialogFragment
-                errorFragment.show(
-                        getSupportFragmentManager(),
-                        "Geofence Detection");
-            }
-        }
-    }
-    ...
-}
-</pre>
-<!--
-    Handle Geofence Transitions
- -->
+
+
 <h2 id="HandleGeofenceTransitions">Handle Geofence Transitions</h2>
 <p>
     When Location Services detects that the user has entered or exited a geofence, it
     sends out the {@link android.content.Intent} contained in the {@link android.app.PendingIntent}
-    you included in the request to add geofences. This {@link android.content.Intent} is
+    you included in the request to add geofences. This {@link android.content.Intent} is received
+    by a service like <code>GeofenceTransitionsIntentService</code>,
+    which obtains the geofencing event from the intent, determines the type of Geofence transition(s),
+    and determines which of the defined geofences was triggered. It then sends a notification as
+    the output.
 </p>
-<h3>Define an IntentService</h3>
 <p>
     The following snippet shows how to define an {@link android.app.IntentService} that posts a
     notification when a geofence transition occurs. When the user clicks the notification, the
     app's main activity appears:
 </p>
 <pre>
-public class ReceiveTransitionsIntentService extends IntentService {
-    ...
-    /**
-     * Sets an identifier for the service
-     */
-    public ReceiveTransitionsIntentService() {
-        super("ReceiveTransitionsIntentService");
-    }
-    /**
-     * Handles incoming intents
-     *&#64;param intent The Intent sent by Location Services. This
-     * Intent is provided
-     * to Location Services (inside a PendingIntent) when you call
-     * addGeofences()
-     */
-    &#64;Override
+public class GeofenceTransitionsIntentService extends IntentService {
+   ...
     protected void onHandleIntent(Intent intent) {
-        // First check for errors
-        if (LocationClient.hasError(intent)) {
-            // Get the error code with a static method
-            int errorCode = LocationClient.getErrorCode(intent);
-            // Log the error
-            Log.e("ReceiveTransitionsIntentService",
-                    "Location Services error: " +
-                    Integer.toString(errorCode));
-            /*
-             * You can also send the error code to an Activity or
-             * Fragment with a broadcast Intent
-             */
-        /*
-         * If there's no error, get the transition type and the IDs
-         * of the geofence or geofences that triggered the transition
-         */
-        } else {
-            // Get the type of transition (entry or exit)
-            int transitionType =
-                    LocationClient.getGeofenceTransition(intent);
-            // Test that a valid transition was reported
-            if (
-                (transitionType == Geofence.GEOFENCE_TRANSITION_ENTER)
-                 ||
-                (transitionType == Geofence.GEOFENCE_TRANSITION_EXIT)
-               ) {
-                List &lt;Geofence&gt; triggerList =
-                        getTriggeringGeofences(intent);
+        GeofencingEvent geofencingEvent = GeofencingEvent.fromIntent(intent);
+        if (geofencingEvent.hasError()) {
+            String errorMessage = GeofenceErrorMessages.getErrorString(this,
+                    geofencingEvent.getErrorCode());
+            Log.e(TAG, errorMessage);
+            return;
+        }
 
-                String[] triggerIds = new String[geofenceList.size()];
+        // Get the transition type.
+        int geofenceTransition = geofencingEvent.getGeofenceTransition();
 
-                for (int i = 0; i &lt; triggerIds.length; i++) {
-                    // Store the Id of each geofence
-                    triggerIds[i] = triggerList.get(i).getRequestId();
-                }
-                /*
-                 * At this point, you can store the IDs for further use
-                 * display them, or display the details associated with
-                 * them.
-                 */
-            }
-        // An invalid transition was reported
+        // Test that the reported transition was of interest.
+        if (geofenceTransition == Geofence.GEOFENCE_TRANSITION_ENTER ||
+                geofenceTransition == Geofence.GEOFENCE_TRANSITION_EXIT) {
+
+            // Get the geofences that were triggered. A single event can trigger
+            // multiple geofences.
+            List<Geofence> triggeringGeofences = geofencingEvent.getTriggeringGeofences();
+
+            // Get the transition details as a String.
+            String geofenceTransitionDetails = getGeofenceTransitionDetails(
+                    this,
+                    geofenceTransition,
+                    triggeringGeofences
+            );
+
+            // Send notification and log the transition details.
+            sendNotification(geofenceTransitionDetails);
+            Log.i(TAG, geofenceTransitionDetails);
         } else {
-            Log.e("ReceiveTransitionsIntentService",
-                    "Geofence transition error: " +
-                    Integer.toString()transitionType));
+            // Log the error.
+            Log.e(TAG, getString(R.string.geofence_transition_invalid_type,
+                    geofenceTransition));
         }
     }
-    ...
-}
 </pre>
-<!-- Specify the IntentService in the manifest -->
-<h3>Specify the IntentService in the manifest</h3>
-<p>
-    To identify the {@link android.app.IntentService} to the system, add a
-    <code><a href="{@docRoot}guide/topics/manifest/service-element.html">&lt;service&gt;</a></code>
-    element to the app manifest. For example:
-</p>
-<pre>
-&lt;service
-    android:name="com.example.android.location.ReceiveTransitionsIntentService"
-    android:label="&#64;string/app_name"
-    android:exported="false"&gt;
-&lt;/service&gt;
-</pre>
-<p>
-    Notice that you don't have to specify intent filters for the service, because it only receives
-    explicit intents. How the incoming geofence transition intents are created is described in the
-    section <a href="#requestmonitoring">Send the monitoring request</a>.
-</p>
+
+<p>After detecting the transition event via the {@link android.app.PendingIntent},
+    this {@link android.app.IntentService} gets the geofence transition type and tests whether
+    it is one of the events the app uses to trigger notifications -- either
+    <code><a href="{@docRoot}reference/com/google/android/gms/location/Geofence.html#GEOFENCE_TRANSITION_ENTER">GEOFENCE_TRANSITION_ENTER</a></code>
+     or <code><a href="{@docRoot}reference/com/google/android/gms/location/Geofence.html#GEOFENCE_TRANSITION_EXIT">GEOFENCE_TRANSITION_EXIT</a></code>
+    in this case. The service then sends a notification and logs the transition details.</p>
 <!--
     Remove Geofences
  -->
 <h2 id="StopGeofenceMonitoring">Stop Geofence Monitoring</h2>
-<p>
-    To stop geofence monitoring, you remove the geofences themselves. You can remove a specific
-    set of geofences or all the geofences associated with a {@link android.app.PendingIntent}. The
-    procedure is similar to adding geofences. The first operation gets a location
-    client for the removal request, and the second makes the request using the client.
+
+<p>Stopping geofence monitoring when it is no longer needed or desired can help save battery
+    power and CPU cycles on the device. You can stop geofence monitoring
+    in the main activity used to add and remove geofences; removing a geofence stops it
+    immediately. The API provides methods to
+    remove geofences either by request IDs, or by removing geofences associated with a given
+    {@link android.app.PendingIntent}.
 </p>
 <p>
-    The callback methods that Location Services invokes when it has finished removing geofences
-    are defined in the interface
-<code><a href="{@docRoot}reference/com/google/android/gms/location/LocationClient.OnRemoveGeofencesResultListener.html">LocationClient.OnRemoveGeofencesResultListener</a></code>. Declare
-    this interface as part of your class definition, and then add definitions for its two methods:
-</p>
-<dl>
-    <dt>
-<code><a href="{@docRoot}reference/com/google/android/gms/location/LocationClient.OnRemoveGeofencesResultListener.html#onRemoveGeofencesByPendingIntentResult(int, android.app.PendingIntent)">onRemoveGeofencesByPendingIntentResult()</a></code>
-    </dt>
-    <dd>
-        Callback invoked when Location Services finishes a request to remove all geofences made
-        by the method
-<code><a href="{@docRoot}reference/com/google/android/gms/location/LocationClient.html#removeGeofences(android.app.PendingIntent, com.google.android.gms.location.LocationClient.OnRemoveGeofencesResultListener)">removeGeofences(PendingIntent, LocationClient.OnRemoveGeofencesResultListener)</a></code>.
-    </dd>
-    <dt>
-<code><a href="{@docRoot}reference/com/google/android/gms/location/LocationClient.OnRemoveGeofencesResultListener.html#onRemoveGeofencesByRequestIdsResult(int, java.lang.String[])">onRemoveGeofencesByRequestIdsResult(List&lt;String&gt;, LocationClient.OnRemoveGeofencesResultListener)</a></code>
-    </dt>
-    <dd>
-        Callback invoked when Location Services finished a request to remove a set of geofences,
-        specified by their geofence IDs, by the method
-<code><a href="{@docRoot}reference/com/google/android/gms/location/LocationClient.html#removeGeofences(java.util.List<java.lang.String>, com.google.android.gms.location.LocationClient.OnRemoveGeofencesResultListener)">removeGeofences(List&lt;String&gt;, LocationClient.OnRemoveGeofencesResultListener)</a></code>.
-    </dd>
-</dl>
-<p>
-    Examples of implementing these methods are shown in the next snippets.
-</p>
-<h3>Remove all geofences</h3>
-<p>
-    Since removing geofences uses some of the methods you use to add geofences, start by defining
-    another request type:
+    The following snippet removes geofences by {@link android.app.PendingIntent}, stopping all
+    further notification when the device enters or exits previously added geofences:
 </p>
 <pre>
-public class MainActivity extends FragmentActivity implements
-        ConnectionCallbacks,
-        OnConnectionFailedListener,
-        OnAddGeofencesResultListener {
-    ...
-    // Enum type for controlling the type of removal requested
-    public enum REQUEST_TYPE = {ADD, REMOVE_INTENT}
-    ...
+LocationServices.GeofencingApi.removeGeofences(
+            mGoogleApiClient,
+            // This is the same pending intent that was used in addGeofences().
+            getGeofencePendingIntent()
+    ).setResultCallback(this); // Result processed in onResult().
 }
 </pre>
+
 <p>
-    Start the removal request by getting a connection to Location Services. If the connection fails,
-<code><a href="{@docRoot}reference/com/google/android/gms/common/GooglePlayServicesClient.ConnectionCallbacks.html#onConnected(android.os.Bundle)">onConnected()</a></code> isn't called,
-    and the request stops. The following snippet shows how to start the request:
-</p>
-<pre>
-public class MainActivity extends FragmentActivity implements
-        ConnectionCallbacks,
-        OnConnectionFailedListener,
-        OnAddGeofencesResultListener {
-    ...
-    /**
-     * Start a request to remove geofences by calling
-     * LocationClient.connect()
-     */
-    public void removeGeofences(PendingIntent requestIntent) {
-        // Record the type of removal request
-        mRequestType = REMOVE_INTENT;
-        /*
-         * Test for Google Play services after setting the request type.
-         * If Google Play services isn't present, the request can be
-         * restarted.
-         */
-        if (!servicesConnected()) {
-            return;
-        }
-        // Store the PendingIntent
-        mGeofenceRequestIntent = requestIntent;
-        /*
-         * Create a new location client object. Since the current
-         * activity class implements ConnectionCallbacks and
-         * OnConnectionFailedListener, pass the current activity object
-         * as the listener for both parameters
-         */
-        mLocationClient = new LocationClient(this, this, this);
-        // If a request is not already underway
-        if (!mInProgress) {
-            // Indicate that a request is underway
-            mInProgress = true;
-            // Request a connection from the client to Location Services
-            mLocationClient.connect();
-        } else {
-            /*
-             * A request is already underway. You can handle
-             * this situation by disconnecting the client,
-             * re-setting the flag, and then re-trying the
-             * request.
-             */
-        }
-    }
-    ...
-}
-</pre>
-<p>
-   When Location Services invokes the callback method indicating that the connection is open,
-   make the request to remove all geofences. Disconnect the client after making the request.
-   For example:
-</p>
-<pre>
-public class MainActivity extends FragmentActivity implements
-        ConnectionCallbacks,
-        OnConnectionFailedListener,
-        OnAddGeofencesResultListener {
-    ...
-    /**
-     * Once the connection is available, send a request to remove the
-     * Geofences. The method signature used depends on which type of
-     * remove request was originally received.
-     */
-    private void onConnected(Bundle dataBundle) {
-        /*
-         * Choose what to do based on the request type set in
-         * removeGeofences
-         */
-        switch (mRequestType) {
-            ...
-            case REMOVE_INTENT :
-                mLocationClient.removeGeofences(
-                        mGeofenceRequestIntent, this);
-                break;
-            ...
-        }
-    }
-    ...
-}
-</pre>
-<p>
-    Although the call to
-<code><a href="{@docRoot}reference/com/google/android/gms/location/LocationClient.html#removeGeofences(android.app.PendingIntent, com.google.android.gms.location.LocationClient.OnRemoveGeofencesResultListener)">removeGeofences(PendingIntent, LocationClient.OnRemoveGeofencesResultListener)</a></code>    Services calls
-    returns immediately, the result of the removal request is indeterminate until Location Services
-    calls
-<code><a href="{@docRoot}reference/com/google/android/gms/location/LocationClient.OnRemoveGeofencesResultListener.html#onRemoveGeofencesByPendingIntentResult(int, android.app.PendingIntent)">onRemoveGeofencesByPendingIntentResult()</a></code>.
-    The following snippet shows how to define this method:
-</p>
-<pre>
-public class MainActivity extends FragmentActivity implements
-        ConnectionCallbacks,
-        OnConnectionFailedListener,
-        OnAddGeofencesResultListener {
-    ...
-    /**
-     * When the request to remove geofences by PendingIntent returns,
-     * handle the result.
-     *
-     *&#64;param statusCode the code returned by Location Services
-     *&#64;param requestIntent The Intent used to request the removal.
-     */
-    &#64;Override
-    public void onRemoveGeofencesByPendingIntentResult(int statusCode,
-            PendingIntent requestIntent) {
-        // If removing the geofences was successful
-        if (statusCode == LocationStatusCodes.SUCCESS) {
-            /*
-             * Handle successful removal of geofences here.
-             * You can send out a broadcast intent or update the UI.
-             * geofences into the Intent's extended data.
-             */
-        } else {
-        // If adding the geocodes failed
-            /*
-             * Report errors here.
-             * You can log the error using Log.e() or update
-             * the UI.
-             */
-        }
-        /*
-         * Disconnect the location client regardless of the
-         * request status, and indicate that a request is no
-         * longer in progress
-         */
-        mInProgress = false;
-        mLocationClient.disconnect();
-    }
-    ...
-}
-</pre>
-<h3>Remove individual geofences</h3>
-<p>
-    The procedure for removing an individual geofence or set of geofences is similar to the
-    removal of all geofences. To specify the geofences you want remove, add their geofence ID
-    values to a {@link java.util.List} of String objects. Pass this {@link java.util.List} to a
-    different definition of {@code removeGeofences} with the appropriate signature. This method
-    then starts the removal process.
-</p>
-<p>
-    Start by adding a request type for removing geofences by a list, and also add a global variable
-    for storing the list of geofences:
-</p>
-<pre>
-    ...
-    // Enum type for controlling the type of removal requested
-    public enum REQUEST_TYPE = {ADD, REMOVE_INTENT, REMOVE_LIST}
-    // Store the list of geofence Ids to remove
-    String&lt;List&gt; mGeofencesToRemove;
-</pre>
-<p>
-    Next, define a list of geofences you want to remove. For example, this snippet removes the
-<code><a href="{@docRoot}reference/com/google/android/gms/location/Geofence.html">Geofence</a></code>
-    defined by the geofence ID "1":
-</p>
-<pre>
-public class MainActivity extends FragmentActivity implements
-        ConnectionCallbacks,
-        OnConnectionFailedListener,
-        OnAddGeofencesResultListener {
-    ...
-        List&lt;String&gt; listOfGeofences =
-                Collections.singletonList("1");
-        removeGeofences(listOfGeofences);
-    ...
-}
-</pre>
-<p>
-    The following snippet defines the {@code removeGeofences()} method:
-</p>
-<pre>
-public class MainActivity extends FragmentActivity implements
-        ConnectionCallbacks,
-        OnConnectionFailedListener,
-        OnAddGeofencesResultListener {
-    ...
-    /**
-     * Start a request to remove monitoring by
-     * calling LocationClient.connect()
-     *
-     */
-    public void removeGeofences(List&lt;String&gt; geofenceIds) {
-        // If Google Play services is unavailable, exit
-        // Record the type of removal request
-        mRequestType = REMOVE_LIST;
-        /*
-         * Test for Google Play services after setting the request type.
-         * If Google Play services isn't present, the request can be
-         * restarted.
-         */
-        if (!servicesConnected()) {
-            return;
-        }
-        // Store the list of geofences to remove
-        mGeofencesToRemove = geofenceIds;
-        /*
-         * Create a new location client object. Since the current
-         * activity class implements ConnectionCallbacks and
-         * OnConnectionFailedListener, pass the current activity object
-         * as the listener for both parameters
-         */
-        mLocationClient = new LocationClient(this, this, this);
-        // If a request is not already underway
-        if (!mInProgress) {
-            // Indicate that a request is underway
-            mInProgress = true;
-            // Request a connection from the client to Location Services
-            mLocationClient.connect();
-        } else {
-            /*
-             * A request is already underway. You can handle
-             * this situation by disconnecting the client,
-             * re-setting the flag, and then re-trying the
-             * request.
-             */
-        }
-    }
-    ...
-}
-</pre>
-<p>
-   When Location Services invokes the callback method indicating that the connection is open,
-   make the request to remove the list of geofences. Disconnect the client after making the request.
-   For example:
-</p>
-<pre>
-public class MainActivity extends FragmentActivity implements
-        ConnectionCallbacks,
-        OnConnectionFailedListener,
-        OnAddGeofencesResultListener {
-    ...
-    private void onConnected(Bundle dataBundle) {
-        ...
-        switch (mRequestType) {
-        ...
-        // If removeGeofencesById was called
-            case REMOVE_LIST :
-                mLocationClient.removeGeofences(
-                        mGeofencesToRemove, this);
-                break;
-        ...
-        }
-        ...
-    }
-    ...
-}
-</pre>
-<p>
-    Define an implementation of
-<code><a href="{@docRoot}reference/com/google/android/gms/location/LocationClient.OnRemoveGeofencesResultListener.html#onRemoveGeofencesByRequestIdsResult(int, java.lang.String[])">onRemoveGeofencesByRequestIdsResult()</a></code>.
-    Location Services invokes this callback method to indicate that the request to remove a list of
-    geofences is complete. In this method, examine the incoming status code and take the
-    appropriate action:
-</p>
-<pre>
-public class MainActivity extends FragmentActivity implements
-        ConnectionCallbacks,
-        OnConnectionFailedListener,
-        OnAddGeofencesResultListener {
-    ...
-    /**
-     * When the request to remove geofences by IDs returns, handle the
-     * result.
-     *
-     * &#64;param statusCode The code returned by Location Services
-     * &#64;param geofenceRequestIds The IDs removed
-     */
-    &#64;Override
-    public void onRemoveGeofencesByRequestIdsResult(
-            int statusCode, String[] geofenceRequestIds) {
-        // If removing the geocodes was successful
-        if (LocationStatusCodes.SUCCESS == statusCode) {
-            /*
-             * Handle successful removal of geofences here.
-             * You can send out a broadcast intent or update the UI.
-             * geofences into the Intent's extended data.
-             */
-        } else {
-        // If removing the geofences failed
-            /*
-             * Report errors here.
-             * You can log the error using Log.e() or update
-             * the UI.
-             */
-        }
-        // Indicate that a request is no longer in progress
-        mInProgress = false;
-        // Disconnect the location client
-        mLocationClient.disconnect();
-    }
-    ...
-}
-</pre>
-<p>
-    You can combine geofencing with other location-aware features, such as periodic location updates
-    or activity recognition, which are described in other lessons in this class.
-</p>
-<p>
-    The next lesson,
-    <a href="activity-recognition.html">Recognizing the User's Current Activity</a>, shows you how
-    to request and receive activity updates. At regular intervals, Location Services can send you
-    information about the user's current physical activity. Based on this information, you can
-    change your app's behavior; for example, you can switch to a longer update interval if you
-    detect that the user is walking instead of driving.
+    You can combine geofencing with other location-aware features, such as periodic location updates.
+    For more information, see the other lessons in this class.
 </p>
diff --git a/docs/html/training/location/index.jd b/docs/html/training/location/index.jd
index 35e177f..c4dec99 100644
--- a/docs/html/training/location/index.jd
+++ b/docs/html/training/location/index.jd
@@ -81,4 +81,10 @@
     Learn how to convert a location's latitude and longitude into an address
     (reverse geocoding).
   </dd>
+  <dt>
+    <b><a href="geofencing.html">Creating and Monitoring Geofences</a></b>
+  </dt> <dd>
+    Learn how to define one or more geographic areas as locations of interest,
+    called geofences, and detect when the user is close to or inside a geofence.
+  </dd>
 </dl>
diff --git a/docs/html/training/training_toc.cs b/docs/html/training/training_toc.cs
index 89e72f1..11ae1a6 100644
--- a/docs/html/training/training_toc.cs
+++ b/docs/html/training/training_toc.cs
@@ -736,6 +736,10 @@
             Displaying a Location Address
           </a>
           </li>
+          <li><a href="<?cs var:toroot ?>training/location/geofencing.html">
+            Creating and Monitoring Geofences
+          </a>
+          </li>
         </ul>
       </li>
     </ul>
diff --git a/docs/html/wear/images/partners/acer.png b/docs/html/wear/images/partners/acer.png
new file mode 100644
index 0000000..439de80
--- /dev/null
+++ b/docs/html/wear/images/partners/acer.png
Binary files differ
diff --git a/docs/html/wear/images/partners/arm.png b/docs/html/wear/images/partners/arm.png
new file mode 100644
index 0000000..3e2f642
--- /dev/null
+++ b/docs/html/wear/images/partners/arm.png
Binary files differ
diff --git a/docs/html/wear/images/partners/huawei.png b/docs/html/wear/images/partners/huawei.png
new file mode 100644
index 0000000..9099ed4
--- /dev/null
+++ b/docs/html/wear/images/partners/huawei.png
Binary files differ
diff --git a/docs/html/wear/index.jd b/docs/html/wear/index.jd
index 27e8098..316f5ca 100644
--- a/docs/html/wear/index.jd
+++ b/docs/html/wear/index.jd
@@ -202,6 +202,12 @@
 
           <div class="landing-partners cols">
             <div class="col-4">
+              <img src="/wear/images/partners/acer.png" alt="Acer">
+            </div>
+            <div class="col-4">
+              <img src="/wear/images/partners/arm.png" alt="ARM">
+            </div>
+            <div class="col-4">
               <img src="/wear/images/partners/asus.png" alt="Asus">
             </div>
             <div class="col-4">
@@ -214,6 +220,9 @@
               <img src="/wear/images/partners/htc.png" alt="HTC">
             </div>
             <div class="col-4">
+              <img src="/wear/images/partners/huawei.png" alt="Huawei">
+            </div>
+            <div class="col-4">
               <img src="/wear/images/partners/intel.png" alt="Intel">
             </div>
             <div class="col-4">
diff --git a/graphics/java/android/graphics/drawable/RippleComponent.java b/graphics/java/android/graphics/drawable/RippleComponent.java
index fd3e06c..79407f7 100644
--- a/graphics/java/android/graphics/drawable/RippleComponent.java
+++ b/graphics/java/android/graphics/drawable/RippleComponent.java
@@ -69,7 +69,6 @@
 
         mDensity = density;
 
-        onSetup();
         onTargetRadiusChanged(mTargetRadius);
     }
 
@@ -82,7 +81,10 @@
         cancel();
 
         mSoftwareAnimator = createSoftwareEnter(fast);
-        mSoftwareAnimator.start();
+
+        if (mSoftwareAnimator != null) {
+            mSoftwareAnimator.start();
+        }
     }
 
     /**
@@ -250,14 +252,6 @@
         // Stub.
     }
 
-    /**
-     * Called during ripple setup, which occurs before the first enter
-     * animation.
-     */
-    protected void onSetup() {
-        // Stub.
-    }
-
     protected abstract Animator createSoftwareEnter(boolean fast);
 
     protected abstract Animator createSoftwareExit();
diff --git a/graphics/java/android/graphics/drawable/RippleDrawable.java b/graphics/java/android/graphics/drawable/RippleDrawable.java
index bc8c7d2..66160c0 100644
--- a/graphics/java/android/graphics/drawable/RippleDrawable.java
+++ b/graphics/java/android/graphics/drawable/RippleDrawable.java
@@ -564,7 +564,9 @@
                 x = mHotspotBounds.exactCenterX();
                 y = mHotspotBounds.exactCenterY();
             }
-            mRipple = new RippleForeground(this, mHotspotBounds, x, y);
+
+            final boolean isBounded = !isProjected();
+            mRipple = new RippleForeground(this, mHotspotBounds, x, y, isBounded);
         }
 
         mRipple.setup(mState.mMaxRadius, mDensity);
diff --git a/graphics/java/android/graphics/drawable/RippleForeground.java b/graphics/java/android/graphics/drawable/RippleForeground.java
index 2023f04..334122d 100644
--- a/graphics/java/android/graphics/drawable/RippleForeground.java
+++ b/graphics/java/android/graphics/drawable/RippleForeground.java
@@ -44,9 +44,16 @@
     private static final float WAVE_TOUCH_UP_ACCELERATION = 3400;
     private static final float WAVE_OPACITY_DECAY_VELOCITY = 3;
 
+    // Bounded ripple animation properties.
+    private static final int BOUNDED_ORIGIN_EXIT_DURATION = 300;
+    private static final int BOUNDED_RADIUS_EXIT_DURATION = 800;
+    private static final int BOUNDED_OPACITY_EXIT_DURATION = 400;
+    private static final float MAX_BOUNDED_RADIUS = 350;
+
     private static final int RIPPLE_ENTER_DELAY = 80;
     private static final int OPACITY_ENTER_DURATION_FAST = 120;
 
+    // Parent-relative values for starting position.
     private float mStartingX;
     private float mStartingY;
     private float mClampedStartingX;
@@ -58,30 +65,41 @@
     private CanvasProperty<Float> mPropX;
     private CanvasProperty<Float> mPropY;
 
+    // Target values for tween animations.
+    private float mTargetX = 0;
+    private float mTargetY = 0;
+
+    /** Ripple target radius used when bounded. Not used for clamping. */
+    private float mBoundedRadius = 0;
+
     // Software rendering properties.
     private float mOpacity = 1;
-    private float mOuterX;
-    private float mOuterY;
 
     // Values used to tween between the start and end positions.
     private float mTweenRadius = 0;
     private float mTweenX = 0;
     private float mTweenY = 0;
 
+    /** Whether this ripple is bounded. */
+    private boolean mIsBounded;
+
     /** Whether this ripple has finished its exit animation. */
     private boolean mHasFinishedExit;
 
-    public RippleForeground(RippleDrawable owner, Rect bounds, float startingX, float startingY) {
+    public RippleForeground(RippleDrawable owner, Rect bounds, float startingX, float startingY,
+            boolean isBounded) {
         super(owner, bounds);
 
+        mIsBounded = isBounded;
         mStartingX = startingX;
         mStartingY = startingY;
-    }
 
-    @Override
-    public void onSetup() {
-        mOuterX = 0;
-        mOuterY = 0;
+        if (isBounded) {
+            mBoundedRadius = MAX_BOUNDED_RADIUS * 0.9f
+                    + (float) (MAX_BOUNDED_RADIUS * Math.random() * 0.1);
+        } else {
+            mBoundedRadius = 0;
+        }
     }
 
     @Override
@@ -95,12 +113,10 @@
 
         final int origAlpha = p.getAlpha();
         final int alpha = (int) (origAlpha * mOpacity + 0.5f);
-        final float radius = MathUtils.lerp(0, mTargetRadius, mTweenRadius);
+        final float radius = getCurrentRadius();
         if (alpha > 0 && radius > 0) {
-            final float x = MathUtils.lerp(
-                    mClampedStartingX - mBounds.exactCenterX(), mOuterX, mTweenX);
-            final float y = MathUtils.lerp(
-                    mClampedStartingY - mBounds.exactCenterY(), mOuterY, mTweenY);
+            final float x = getCurrentX();
+            final float y = getCurrentY();
             p.setAlpha(alpha);
             c.drawCircle(x, y, radius, p);
             p.setAlpha(origAlpha);
@@ -120,8 +136,8 @@
      * Returns the maximum bounds of the ripple relative to the ripple center.
      */
     public void getBounds(Rect bounds) {
-        final int outerX = (int) mOuterX;
-        final int outerY = (int) mOuterY;
+        final int outerX = (int) mTargetX;
+        final int outerY = (int) mTargetY;
         final int r = (int) mTargetRadius + 1;
         bounds.set(outerX - r, outerY - r, outerX + r, outerY + r);
     }
@@ -146,14 +162,25 @@
 
     @Override
     protected Animator createSoftwareEnter(boolean fast) {
+        // Bounded ripples don't have enter animations.
+        if (mIsBounded) {
+            return null;
+        }
+
         final int duration = (int)
                 (1000 * Math.sqrt(mTargetRadius / WAVE_TOUCH_DOWN_ACCELERATION * mDensity) + 0.5);
 
-        final ObjectAnimator tweenAll = ObjectAnimator.ofFloat(this, TWEEN_ALL, 1);
-        tweenAll.setAutoCancel(true);
-        tweenAll.setDuration(duration);
-        tweenAll.setInterpolator(LINEAR_INTERPOLATOR);
-        tweenAll.setStartDelay(RIPPLE_ENTER_DELAY);
+        final ObjectAnimator tweenRadius = ObjectAnimator.ofFloat(this, TWEEN_RADIUS, 1);
+        tweenRadius.setAutoCancel(true);
+        tweenRadius.setDuration(duration);
+        tweenRadius.setInterpolator(LINEAR_INTERPOLATOR);
+        tweenRadius.setStartDelay(RIPPLE_ENTER_DELAY);
+
+        final ObjectAnimator tweenOrigin = ObjectAnimator.ofFloat(this, TWEEN_ORIGIN, 1);
+        tweenOrigin.setAutoCancel(true);
+        tweenOrigin.setDuration(duration);
+        tweenOrigin.setInterpolator(LINEAR_INTERPOLATOR);
+        tweenOrigin.setStartDelay(RIPPLE_ENTER_DELAY);
 
         final ObjectAnimator opacity = ObjectAnimator.ofFloat(this, OPACITY, 1);
         opacity.setAutoCancel(true);
@@ -161,31 +188,68 @@
         opacity.setInterpolator(LINEAR_INTERPOLATOR);
 
         final AnimatorSet set = new AnimatorSet();
-        set.play(tweenAll).with(opacity);
+        set.play(tweenOrigin).with(tweenRadius).with(opacity);
 
         return set;
     }
 
+    private float getCurrentX() {
+        return MathUtils.lerp(mClampedStartingX - mBounds.exactCenterX(), mTargetX, mTweenX);
+    }
+
+    private float getCurrentY() {
+        return MathUtils.lerp(mClampedStartingY - mBounds.exactCenterY(), mTargetY, mTweenY);
+    }
+
     private int getRadiusExitDuration() {
-        final float radius = MathUtils.lerp(0, mTargetRadius, mTweenRadius);
-        final float remaining = mTargetRadius - radius;
-        return (int) (1000 * Math.sqrt(remaining / (WAVE_TOUCH_UP_ACCELERATION
+        final float remainingRadius = mTargetRadius - getCurrentRadius();
+        return (int) (1000 * Math.sqrt(remainingRadius / (WAVE_TOUCH_UP_ACCELERATION
                 + WAVE_TOUCH_DOWN_ACCELERATION) * mDensity) + 0.5);
     }
 
+    private float getCurrentRadius() {
+        return MathUtils.lerp(0, mTargetRadius, mTweenRadius);
+    }
+
     private int getOpacityExitDuration() {
         return (int) (1000 * mOpacity / WAVE_OPACITY_DECAY_VELOCITY + 0.5f);
     }
 
+    /**
+     * Compute target values that are dependent on bounding.
+     */
+    private void computeBoundedTargetValues() {
+        mTargetX = (mClampedStartingX - mBounds.exactCenterX()) * .7f;
+        mTargetY = (mClampedStartingY - mBounds.exactCenterY()) * .7f;
+        mTargetRadius = mBoundedRadius;
+    }
+
     @Override
     protected Animator createSoftwareExit() {
-        final int radiusDuration = getRadiusExitDuration();
-        final int opacityDuration = getOpacityExitDuration();
+        final int radiusDuration;
+        final int originDuration;
+        final int opacityDuration;
+        if (mIsBounded) {
+            computeBoundedTargetValues();
 
-        final ObjectAnimator tweenAll = ObjectAnimator.ofFloat(this, TWEEN_ALL, 1);
-        tweenAll.setAutoCancel(true);
-        tweenAll.setDuration(radiusDuration);
-        tweenAll.setInterpolator(DECELERATE_INTERPOLATOR);
+            radiusDuration = BOUNDED_RADIUS_EXIT_DURATION;
+            originDuration = BOUNDED_ORIGIN_EXIT_DURATION;
+            opacityDuration = BOUNDED_OPACITY_EXIT_DURATION;
+        } else {
+            radiusDuration = getRadiusExitDuration();
+            originDuration = radiusDuration;
+            opacityDuration = getOpacityExitDuration();
+        }
+
+        final ObjectAnimator tweenRadius = ObjectAnimator.ofFloat(this, TWEEN_RADIUS, 1);
+        tweenRadius.setAutoCancel(true);
+        tweenRadius.setDuration(radiusDuration);
+        tweenRadius.setInterpolator(DECELERATE_INTERPOLATOR);
+
+        final ObjectAnimator tweenOrigin = ObjectAnimator.ofFloat(this, TWEEN_ORIGIN, 1);
+        tweenOrigin.setAutoCancel(true);
+        tweenOrigin.setDuration(originDuration);
+        tweenOrigin.setInterpolator(DECELERATE_INTERPOLATOR);
 
         final ObjectAnimator opacity = ObjectAnimator.ofFloat(this, OPACITY, 0);
         opacity.setAutoCancel(true);
@@ -193,7 +257,7 @@
         opacity.setInterpolator(LINEAR_INTERPOLATOR);
 
         final AnimatorSet set = new AnimatorSet();
-        set.play(tweenAll).with(opacity);
+        set.play(tweenOrigin).with(tweenRadius).with(opacity);
         set.addListener(mAnimationListener);
 
         return set;
@@ -201,15 +265,25 @@
 
     @Override
     protected RenderNodeAnimatorSet createHardwareExit(Paint p) {
-        final int radiusDuration = getRadiusExitDuration();
-        final int opacityDuration = getOpacityExitDuration();
+        final int radiusDuration;
+        final int originDuration;
+        final int opacityDuration;
+        if (mIsBounded) {
+            computeBoundedTargetValues();
 
-        final float startX = MathUtils.lerp(
-                mClampedStartingX - mBounds.exactCenterX(), mOuterX, mTweenX);
-        final float startY = MathUtils.lerp(
-                mClampedStartingY - mBounds.exactCenterY(), mOuterY, mTweenY);
+            radiusDuration = BOUNDED_RADIUS_EXIT_DURATION;
+            originDuration = BOUNDED_ORIGIN_EXIT_DURATION;
+            opacityDuration = BOUNDED_OPACITY_EXIT_DURATION;
+        } else {
+            radiusDuration = getRadiusExitDuration();
+            originDuration = radiusDuration;
+            opacityDuration = getOpacityExitDuration();
+        }
 
-        final float startRadius = MathUtils.lerp(0, mTargetRadius, mTweenRadius);
+        final float startX = getCurrentX();
+        final float startY = getCurrentY();
+        final float startRadius = getCurrentRadius();
+
         p.setAlpha((int) (p.getAlpha() * mOpacity + 0.5f));
 
         mPropPaint = CanvasProperty.createPaint(p);
@@ -221,12 +295,12 @@
         radius.setDuration(radiusDuration);
         radius.setInterpolator(DECELERATE_INTERPOLATOR);
 
-        final RenderNodeAnimator x = new RenderNodeAnimator(mPropX, mOuterX);
-        x.setDuration(radiusDuration);
+        final RenderNodeAnimator x = new RenderNodeAnimator(mPropX, mTargetX);
+        x.setDuration(originDuration);
         x.setInterpolator(DECELERATE_INTERPOLATOR);
 
-        final RenderNodeAnimator y = new RenderNodeAnimator(mPropY, mOuterY);
-        y.setDuration(radiusDuration);
+        final RenderNodeAnimator y = new RenderNodeAnimator(mPropY, mTargetY);
+        y.setDuration(originDuration);
         y.setInterpolator(DECELERATE_INTERPOLATOR);
 
         final RenderNodeAnimator opacity = new RenderNodeAnimator(mPropPaint,
@@ -307,16 +381,13 @@
     }
 
     /**
-     * Property for animating radius, center X, and center Y between their
-     * initial and target values.
+     * Property for animating radius between its initial and target values.
      */
-    private static final FloatProperty<RippleForeground> TWEEN_ALL =
-            new FloatProperty<RippleForeground>("tweenAll") {
+    private static final FloatProperty<RippleForeground> TWEEN_RADIUS =
+            new FloatProperty<RippleForeground>("tweenRadius") {
         @Override
         public void setValue(RippleForeground object, float value) {
             object.mTweenRadius = value;
-            object.mTweenX = value;
-            object.mTweenY = value;
             object.invalidateSelf();
         }
 
@@ -327,6 +398,24 @@
     };
 
     /**
+     * Property for animating origin between its initial and target values.
+     */
+    private static final FloatProperty<RippleForeground> TWEEN_ORIGIN =
+            new FloatProperty<RippleForeground>("tweenOrigin") {
+                @Override
+                public void setValue(RippleForeground object, float value) {
+                    object.mTweenX = value;
+                    object.mTweenY = value;
+                    object.invalidateSelf();
+                }
+
+                @Override
+                public Float get(RippleForeground object) {
+                    return object.mTweenX;
+                }
+            };
+
+    /**
      * Property for animating opacity between 0 and its target value.
      */
     private static final FloatProperty<RippleForeground> OPACITY =
diff --git a/libs/androidfw/ResourceTypes.cpp b/libs/androidfw/ResourceTypes.cpp
index aca3e8c..6f93c820 100644
--- a/libs/androidfw/ResourceTypes.cpp
+++ b/libs/androidfw/ResourceTypes.cpp
@@ -3116,7 +3116,8 @@
         size_t cnt = pi->types[j].numEntries;
         newpi->types[j].numEntries = cnt;
         theme_entry* te = pi->types[j].entries;
-        if (te != NULL) {
+        size_t cnt_max = SIZE_MAX / sizeof(theme_entry);
+        if (te != NULL && (cnt < 0xFFFFFFFF-1) && (cnt < cnt_max)) {
             theme_entry* newte = (theme_entry*)malloc(cnt*sizeof(theme_entry));
             newpi->types[j].entries = newte;
             memcpy(newte, te, cnt*sizeof(theme_entry));
@@ -3183,9 +3184,12 @@
             if (curEntries == NULL) {
                 PackageGroup* const grp = mTable.mPackageGroups[curPackageIndex];
                 const TypeList& typeList = grp->types[t];
-                int cnt = typeList.isEmpty() ? 0 : typeList[0]->entryCount;
-                curEntries = (theme_entry*)malloc(cnt*sizeof(theme_entry));
-                memset(curEntries, Res_value::TYPE_NULL, cnt*sizeof(theme_entry));
+                size_t cnt = typeList.isEmpty() ? 0 : typeList[0]->entryCount;
+                size_t cnt_max = SIZE_MAX / sizeof(theme_entry);
+                size_t buff_size = (cnt < cnt_max && cnt < 0xFFFFFFFF-1) ?
+                                          cnt*sizeof(theme_entry) : 0;
+                curEntries = (theme_entry*)malloc(buff_size);
+                memset(curEntries, Res_value::TYPE_NULL, buff_size);
                 curPI->types[t].numEntries = cnt;
                 curPI->types[t].entries = curEntries;
             }
diff --git a/libs/hwui/DeferredLayerUpdater.cpp b/libs/hwui/DeferredLayerUpdater.cpp
index 6a59a13..6b8c780 100644
--- a/libs/hwui/DeferredLayerUpdater.cpp
+++ b/libs/hwui/DeferredLayerUpdater.cpp
@@ -109,6 +109,9 @@
         mSurfaceTexture->getTransformMatrix(transform);
         GLenum renderTarget = mSurfaceTexture->getCurrentTextureTarget();
 
+        LOG_ALWAYS_FATAL_IF(renderTarget != GL_TEXTURE_2D && renderTarget != GL_TEXTURE_EXTERNAL_OES,
+                "doUpdateTexImage target %x, 2d %x, EXT %x",
+                renderTarget, GL_TEXTURE_2D, GL_TEXTURE_EXTERNAL_OES);
         LayerRenderer::updateTextureLayer(mLayer, mWidth, mHeight,
                 !mBlend, forceFilter, renderTarget, transform);
     }
diff --git a/libs/hwui/DeferredLayerUpdater.h b/libs/hwui/DeferredLayerUpdater.h
index 38d8e4a..82f2741 100644
--- a/libs/hwui/DeferredLayerUpdater.h
+++ b/libs/hwui/DeferredLayerUpdater.h
@@ -59,6 +59,10 @@
         if (texture.get() != mSurfaceTexture.get()) {
             mNeedsGLContextAttach = needsAttach;
             mSurfaceTexture = texture;
+
+            GLenum target = texture->getCurrentTextureTarget();
+            LOG_ALWAYS_FATAL_IF(target != GL_TEXTURE_2D && target != GL_TEXTURE_EXTERNAL_OES,
+                    "set unsupported GLConsumer with target %x", target);
         }
     }
 
diff --git a/libs/hwui/GlopBuilder.cpp b/libs/hwui/GlopBuilder.cpp
index 1d07951..0a46014 100644
--- a/libs/hwui/GlopBuilder.cpp
+++ b/libs/hwui/GlopBuilder.cpp
@@ -208,7 +208,8 @@
 // Fill
 ////////////////////////////////////////////////////////////////////////////////
 
-void GlopBuilder::setFill(int color, float alphaScale, SkXfermode::Mode mode,
+void GlopBuilder::setFill(int color, float alphaScale,
+        SkXfermode::Mode mode, Blend::ModeOrderSwap modeUsage,
         const SkShader* shader, const SkColorFilter* colorFilter) {
     if (mode != SkXfermode::kClear_Mode) {
         float alpha = (SkColorGetA(color) / 255.0f) * alphaScale;
@@ -226,7 +227,6 @@
     } else {
         mOutGlop->fill.color = { 0, 0, 0, 1 };
     }
-    const bool SWAP_SRC_DST = false;
 
     mOutGlop->blend = { GL_ZERO, GL_ZERO };
     if (mOutGlop->fill.color.a < 1.0f
@@ -237,7 +237,7 @@
             || PaintUtils::isBlendedColorFilter(colorFilter)
             || mode != SkXfermode::kSrcOver_Mode) {
         if (CC_LIKELY(mode <= SkXfermode::kScreen_Mode)) {
-            Blend::getFactors(mode, SWAP_SRC_DST,
+            Blend::getFactors(mode, modeUsage,
                     &mOutGlop->blend.src, &mOutGlop->blend.dst);
         } else {
             // These blend modes are not supported by OpenGL directly and have
@@ -247,11 +247,11 @@
             // back to the default SrcOver blend mode instead
             if (CC_UNLIKELY(mCaches.extensions().hasFramebufferFetch())) {
                 mDescription.framebufferMode = mode;
-                mDescription.swapSrcDst = SWAP_SRC_DST;
+                mDescription.swapSrcDst = (modeUsage == Blend::ModeOrderSwap::Swap);
                 // blending in shader, don't enable
             } else {
                 // unsupported
-                Blend::getFactors(SkXfermode::kSrcOver_Mode, SWAP_SRC_DST,
+                Blend::getFactors(SkXfermode::kSrcOver_Mode, modeUsage,
                         &mOutGlop->blend.src, &mOutGlop->blend.dst);
             }
         }
@@ -317,17 +317,17 @@
             color |= 0x00FFFFFF;
             shader = nullptr;
         }
-        setFill(color, alphaScale, PaintUtils::getXfermode(paint->getXfermode()),
+        setFill(color, alphaScale,
+                PaintUtils::getXfermode(paint->getXfermode()), Blend::ModeOrderSwap::NoSwap,
                 shader, paint->getColorFilter());
     } else {
         mOutGlop->fill.color = { alphaScale, alphaScale, alphaScale, alphaScale };
 
-        const bool SWAP_SRC_DST = false;
         if (alphaScale < 1.0f
                 || (mOutGlop->mesh.vertices.attribFlags & VertexAttribFlags::kAlpha)
                 || texture.blend
                 || mOutGlop->roundRectClipState) {
-            Blend::getFactors(SkXfermode::kSrcOver_Mode, SWAP_SRC_DST,
+            Blend::getFactors(SkXfermode::kSrcOver_Mode, Blend::ModeOrderSwap::NoSwap,
                     &mOutGlop->blend.src, &mOutGlop->blend.dst);
         } else {
             mOutGlop->blend = { GL_ZERO, GL_ZERO };
@@ -349,7 +349,8 @@
 
     mOutGlop->fill.texture = { nullptr, GL_INVALID_ENUM, GL_INVALID_ENUM, GL_INVALID_ENUM, nullptr };
 
-    setFill(paint.getColor(), alphaScale, PaintUtils::getXfermode(paint.getXfermode()),
+    setFill(paint.getColor(), alphaScale,
+            PaintUtils::getXfermode(paint.getXfermode()), Blend::ModeOrderSwap::NoSwap,
             paint.getShader(), paint.getColorFilter());
     mDescription.modulate = mOutGlop->fill.color.a < 1.0f;
     return *this;
@@ -363,7 +364,8 @@
     //specify invalid filter/clamp, since these are always static for PathTextures
     mOutGlop->fill.texture = { &texture, GL_TEXTURE_2D, GL_INVALID_ENUM, GL_INVALID_ENUM, nullptr };
 
-    setFill(paint.getColor(), alphaScale, PaintUtils::getXfermode(paint.getXfermode()),
+    setFill(paint.getColor(), alphaScale,
+            PaintUtils::getXfermode(paint.getXfermode()), Blend::ModeOrderSwap::NoSwap,
             paint.getShader(), paint.getColorFilter());
 
     mDescription.hasAlpha8Texture = true;
@@ -386,7 +388,8 @@
         shadowColor &= paint.getColor() | COLOR_BITMASK;
     }
 
-    setFill(shadowColor, alphaScale, PaintUtils::getXfermode(paint.getXfermode()),
+    setFill(shadowColor, alphaScale,
+            PaintUtils::getXfermode(paint.getXfermode()), Blend::ModeOrderSwap::NoSwap,
             paint.getShader(), paint.getColorFilter());
 
     mDescription.hasAlpha8Texture = true;
@@ -399,7 +402,8 @@
     REQUIRE_STAGES(kMeshStage);
 
     mOutGlop->fill.texture = { nullptr, GL_INVALID_ENUM, GL_INVALID_ENUM, GL_INVALID_ENUM, nullptr };
-    setFill(SK_ColorBLACK, 1.0f, SkXfermode::kSrcOver_Mode, nullptr, nullptr);
+    setFill(SK_ColorBLACK, 1.0f, SkXfermode::kSrcOver_Mode, Blend::ModeOrderSwap::NoSwap,
+            nullptr, nullptr);
     return *this;
 }
 
@@ -408,12 +412,13 @@
     REQUIRE_STAGES(kMeshStage);
 
     mOutGlop->fill.texture = { nullptr, GL_INVALID_ENUM, GL_INVALID_ENUM, GL_INVALID_ENUM, nullptr };
-    setFill(SK_ColorBLACK, 1.0f, SkXfermode::kClear_Mode, nullptr, nullptr);
+    setFill(SK_ColorBLACK, 1.0f, SkXfermode::kClear_Mode, Blend::ModeOrderSwap::NoSwap,
+            nullptr, nullptr);
     return *this;
 }
 
 GlopBuilder& GlopBuilder::setFillLayer(Texture& texture, const SkColorFilter* colorFilter,
-        float alpha, SkXfermode::Mode mode) {
+        float alpha, SkXfermode::Mode mode, Blend::ModeOrderSwap modeUsage) {
     TRIGGER_STAGE(kFillStage);
     REQUIRE_STAGES(kMeshStage);
 
@@ -421,7 +426,7 @@
             GL_TEXTURE_2D, GL_LINEAR, GL_CLAMP_TO_EDGE, nullptr };
     mOutGlop->fill.color = { alpha, alpha, alpha, alpha };
 
-    setFill(SK_ColorWHITE, alpha, mode, nullptr, colorFilter);
+    setFill(SK_ColorWHITE, alpha, mode, modeUsage, nullptr, colorFilter);
 
     mDescription.modulate = mOutGlop->fill.color.a < 1.0f;
     return *this;
@@ -435,7 +440,8 @@
             layer.getRenderTarget(), GL_LINEAR, GL_CLAMP_TO_EDGE, &layer.getTexTransform() };
     mOutGlop->fill.color = { alpha, alpha, alpha, alpha };
 
-    setFill(SK_ColorWHITE, alpha, layer.getMode(), nullptr, layer.getColorFilter());
+    setFill(SK_ColorWHITE, alpha, layer.getMode(), Blend::ModeOrderSwap::NoSwap,
+            nullptr, layer.getColorFilter());
 
     mDescription.modulate = mOutGlop->fill.color.a < 1.0f;
     mDescription.hasTextureTransform = true;
@@ -570,8 +576,12 @@
 void GlopBuilder::build() {
     REQUIRE_STAGES(kAllStages);
     if (mOutGlop->mesh.vertices.attribFlags & VertexAttribFlags::kTextureCoord) {
-        mDescription.hasTexture = mOutGlop->fill.texture.target == GL_TEXTURE_2D;
-        mDescription.hasExternalTexture = mOutGlop->fill.texture.target == GL_TEXTURE_EXTERNAL_OES;
+        if (mOutGlop->fill.texture.target == GL_TEXTURE_2D) {
+            mDescription.hasTexture = true;
+        } else {
+            mDescription.hasExternalTexture = true;
+        }
+
     }
     mDescription.hasColors = mOutGlop->mesh.vertices.attribFlags & VertexAttribFlags::kColor;
     mDescription.hasVertexAlpha = mOutGlop->mesh.vertices.attribFlags & VertexAttribFlags::kAlpha;
diff --git a/libs/hwui/GlopBuilder.h b/libs/hwui/GlopBuilder.h
index 74d4889..b335a2c 100644
--- a/libs/hwui/GlopBuilder.h
+++ b/libs/hwui/GlopBuilder.h
@@ -18,6 +18,7 @@
 
 #include "OpenGLRenderer.h"
 #include "Program.h"
+#include "renderstate/Blend.h"
 #include "utils/Macros.h"
 
 class SkPaint;
@@ -65,7 +66,7 @@
     GlopBuilder& setFillBlack();
     GlopBuilder& setFillClear();
     GlopBuilder& setFillLayer(Texture& texture, const SkColorFilter* colorFilter,
-            float alpha, SkXfermode::Mode mode);
+            float alpha, SkXfermode::Mode mode, Blend::ModeOrderSwap modeUsage);
     GlopBuilder& setFillTextureLayer(Layer& layer, float alpha);
 
     GlopBuilder& setTransform(const Matrix4& ortho, const Matrix4& transform, bool fudgingOffset);
@@ -94,7 +95,8 @@
 
     void build();
 private:
-    void setFill(int color, float alphaScale, SkXfermode::Mode mode,
+    void setFill(int color, float alphaScale,
+            SkXfermode::Mode mode, Blend::ModeOrderSwap modeUsage,
             const SkShader* shader, const SkColorFilter* colorFilter);
 
     enum StageFlags {
diff --git a/libs/hwui/JankTracker.cpp b/libs/hwui/JankTracker.cpp
index 46b0945..7df61f27 100644
--- a/libs/hwui/JankTracker.cpp
+++ b/libs/hwui/JankTracker.cpp
@@ -97,8 +97,8 @@
     int64_t totalDuration =
             frame[FrameInfoIndex::kFrameCompleted] - frame[FrameInfoIndex::kIntendedVsync];
     uint32_t framebucket = std::min(
-            static_cast<typeof sizeof(mFrameCounts)>(ns2ms(totalDuration)),
-            sizeof(mFrameCounts) / sizeof(mFrameCounts[0]));
+            static_cast<typeof mFrameCounts.size()>(ns2ms(totalDuration)),
+            mFrameCounts.size());
     // Keep the fast path as fast as possible.
     if (CC_LIKELY(totalDuration < mFrameInterval)) {
         mFrameCounts[framebucket]++;
@@ -137,8 +137,8 @@
 }
 
 void JankTracker::reset() {
-    memset(mBuckets, 0, sizeof(mBuckets));
-    memset(mFrameCounts, 0, sizeof(mFrameCounts));
+    mBuckets.fill({0});
+    mFrameCounts.fill(0);
     mTotalFrameCount = 0;
     mJankFrameCount = 0;
 }
@@ -146,7 +146,7 @@
 uint32_t JankTracker::findPercentile(int percentile) {
     int pos = percentile * mTotalFrameCount / 100;
     int remaining = mTotalFrameCount - pos;
-    for (int i = sizeof(mFrameCounts) / sizeof(mFrameCounts[0]) - 1; i >= 0; i--) {
+    for (int i = mFrameCounts.size() - 1; i >= 0; i--) {
         remaining -= mFrameCounts[i];
         if (remaining <= 0) {
             return i;
diff --git a/libs/hwui/JankTracker.h b/libs/hwui/JankTracker.h
index 3d4929b..ae339ec 100644
--- a/libs/hwui/JankTracker.h
+++ b/libs/hwui/JankTracker.h
@@ -20,6 +20,7 @@
 #include "renderthread/TimeLord.h"
 #include "utils/RingBuffer.h"
 
+#include <array>
 #include <memory>
 
 namespace android {
@@ -56,9 +57,9 @@
 private:
     uint32_t findPercentile(int p);
 
-    JankBucket mBuckets[NUM_BUCKETS];
-    int64_t mThresholds[NUM_BUCKETS];
-    uint32_t mFrameCounts[128];
+    std::array<JankBucket, NUM_BUCKETS> mBuckets;
+    std::array<int64_t, NUM_BUCKETS> mThresholds;
+    std::array<uint32_t, 128> mFrameCounts;
 
     int64_t mFrameInterval;
     uint32_t mTotalFrameCount;
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index a6f6e18..622b570 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -908,15 +908,35 @@
         resetDrawTextureTexCoords(0.0f, 0.0f, 1.0f, 1.0f);
     } else {
         EVENT_LOGD("composeHardwareLayerRect");
+
+        if (USE_GLOPS) {
+            Blend::ModeOrderSwap modeUsage = swap ?
+                    Blend::ModeOrderSwap::Swap : Blend::ModeOrderSwap::NoSwap;
+            const Matrix4& transform = swap ? Matrix4::identity() : *currentTransform();
+            bool snap = !swap
+                    && layer->getWidth() == static_cast<uint32_t>(rect.getWidth())
+                    && layer->getHeight() == static_cast<uint32_t>(rect.getHeight());
+            Glop glop;
+            GlopBuilder(mRenderState, mCaches, &glop)
+                    .setMeshTexturedUvQuad(nullptr, layer->texCoords)
+                    .setFillLayer(layer->getTexture(), layer->getColorFilter(), getLayerAlpha(layer), layer->getMode(), modeUsage)
+                    .setTransform(currentSnapshot()->getOrthoMatrix(), transform, false)
+                    .setModelViewMapUnitToRectOptionalSnap(snap, rect)
+                    .setRoundRectClipState(currentSnapshot()->roundRectClipState)
+                    .build();
+            renderGlop(glop);
+            return;
+        }
+
         const Rect& texCoords = layer->texCoords;
         resetDrawTextureTexCoords(texCoords.left, texCoords.top,
                 texCoords.right, texCoords.bottom);
 
         float x = rect.left;
         float y = rect.top;
-        bool simpleTransform = currentTransform()->isPureTranslate() &&
-                layer->getWidth() == (uint32_t) rect.getWidth() &&
-                layer->getHeight() == (uint32_t) rect.getHeight();
+        bool simpleTransform = currentTransform()->isPureTranslate()
+                && layer->getWidth() == (uint32_t) rect.getWidth()
+                && layer->getHeight() == (uint32_t) rect.getHeight();
 
         if (simpleTransform) {
             // When we're swapping, the layer is already in screen coordinates
@@ -1053,11 +1073,42 @@
         rects = safeRegion.getArray(&count);
     }
 
-    const float alpha = getLayerAlpha(layer);
     const float texX = 1.0f / float(layer->getWidth());
     const float texY = 1.0f / float(layer->getHeight());
     const float height = rect.getHeight();
 
+    if (USE_GLOPS) {
+        TextureVertex quadVertices[count * 4];
+        //std::unique_ptr<TextureVertex[]> quadVertices(new TextureVertex[count * 4]);
+        TextureVertex* mesh = &quadVertices[0];
+        for (size_t i = 0; i < count; i++) {
+            const android::Rect* r = &rects[i];
+
+            const float u1 = r->left * texX;
+            const float v1 = (height - r->top) * texY;
+            const float u2 = r->right * texX;
+            const float v2 = (height - r->bottom) * texY;
+
+            // TODO: Reject quads outside of the clip
+            TextureVertex::set(mesh++, r->left, r->top, u1, v1);
+            TextureVertex::set(mesh++, r->right, r->top, u2, v1);
+            TextureVertex::set(mesh++, r->left, r->bottom, u1, v2);
+            TextureVertex::set(mesh++, r->right, r->bottom, u2, v2);
+        }
+        Glop glop;
+        GlopBuilder(mRenderState, mCaches, &glop)
+                .setMeshTexturedIndexedQuads(&quadVertices[0], count * 6)
+                .setFillLayer(layer->getTexture(), layer->getColorFilter(), getLayerAlpha(layer), layer->getMode(), Blend::ModeOrderSwap::NoSwap)
+                .setTransform(currentSnapshot()->getOrthoMatrix(), *currentTransform(), false)
+                .setModelViewOffsetRectSnap(0, 0, rect)
+                .setRoundRectClipState(currentSnapshot()->roundRectClipState)
+                .build();
+        DRAW_DOUBLE_STENCIL_IF(!layer->hasDrawnSinceUpdate, renderGlop(glop));
+        return;
+    }
+
+    const float alpha = getLayerAlpha(layer);
+
     setupDraw();
 
     // We must get (and therefore bind) the region mesh buffer
@@ -3110,7 +3161,7 @@
                 Glop glop;
                 GlopBuilder(mRenderState, mCaches, &glop)
                         .setMeshTexturedIndexedQuads(layer->mesh, layer->meshElementCount)
-                        .setFillLayer(layer->getTexture(), layer->getColorFilter(), getLayerAlpha(layer), layer->getMode())
+                        .setFillLayer(layer->getTexture(), layer->getColorFilter(), getLayerAlpha(layer), layer->getMode(), Blend::ModeOrderSwap::NoSwap)
                         .setTransform(currentSnapshot()->getOrthoMatrix(), *currentTransform(), false)
                         .setModelViewOffsetRectSnap(x, y, Rect(0, 0, layer->layer.getWidth(), layer->layer.getHeight()))
                         .setRoundRectClipState(currentSnapshot()->roundRectClipState)
@@ -3596,7 +3647,8 @@
                 mode = SkXfermode::kSrcOver_Mode;
             }
         }
-        mRenderState.blend().enable(mode, swapSrcDst);
+        mRenderState.blend().enable(mode,
+                swapSrcDst ? Blend::ModeOrderSwap::Swap : Blend::ModeOrderSwap::NoSwap);
     } else {
         mRenderState.blend().disable();
     }
diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp
index c6fdd3f..e009451 100644
--- a/libs/hwui/RenderNode.cpp
+++ b/libs/hwui/RenderNode.cpp
@@ -139,7 +139,7 @@
 
 void RenderNode::prepareLayer(TreeInfo& info, uint32_t dirtyMask) {
     LayerType layerType = properties().layerProperties().type();
-    if (CC_UNLIKELY(layerType == kLayerTypeRenderLayer)) {
+    if (CC_UNLIKELY(layerType == LayerType::RenderLayer)) {
         // Damage applied so far needs to affect our parent, but does not require
         // the layer to be updated. So we pop/push here to clear out the current
         // damage and get a clean state for display list or children updates to
@@ -156,7 +156,7 @@
     LayerType layerType = properties().layerProperties().type();
     // If we are not a layer OR we cannot be rendered (eg, view was detached)
     // we need to destroy any Layers we may have had previously
-    if (CC_LIKELY(layerType != kLayerTypeRenderLayer) || CC_UNLIKELY(!isRenderable())) {
+    if (CC_LIKELY(layerType != LayerType::RenderLayer) || CC_UNLIKELY(!isRenderable())) {
         if (CC_UNLIKELY(mLayer)) {
             LayerRenderer::destroyLayer(mLayer);
             mLayer = nullptr;
@@ -384,7 +384,7 @@
             renderer.concatMatrix(*properties().getTransformMatrix());
         }
     }
-    const bool isLayer = properties().layerProperties().type() != kLayerTypeNone;
+    const bool isLayer = properties().layerProperties().type() != LayerType::None;
     int clipFlags = properties().getClippingFlags();
     if (properties().getAlpha() < 1) {
         if (isLayer) {
diff --git a/libs/hwui/RenderProperties.cpp b/libs/hwui/RenderProperties.cpp
index bb6d087..9f1ceed 100644
--- a/libs/hwui/RenderProperties.cpp
+++ b/libs/hwui/RenderProperties.cpp
@@ -33,14 +33,12 @@
 namespace android {
 namespace uirenderer {
 
-LayerProperties::LayerProperties()
-        : mType(kLayerTypeNone)
-        , mColorFilter(nullptr) {
+LayerProperties::LayerProperties() {
     reset();
 }
 
 LayerProperties::~LayerProperties() {
-    setType(kLayerTypeNone);
+    setType(LayerType::None);
 }
 
 void LayerProperties::reset() {
@@ -146,7 +144,7 @@
         }
     }
 
-    const bool isLayer = layerProperties().type() != kLayerTypeNone;
+    const bool isLayer = layerProperties().type() != LayerType::None;
     int clipFlags = getClippingFlags();
     if (mPrimitiveFields.mAlpha < 1) {
         if (isLayer) {
diff --git a/libs/hwui/RenderProperties.h b/libs/hwui/RenderProperties.h
index f0e22d6..61e98d2 100644
--- a/libs/hwui/RenderProperties.h
+++ b/libs/hwui/RenderProperties.h
@@ -49,12 +49,12 @@
 #define RP_SET_AND_DIRTY(a, b) RP_SET(a, b, mPrimitiveFields.mMatrixOrPivotDirty = true)
 
 // Keep in sync with View.java:LAYER_TYPE_*
-enum LayerType {
-    kLayerTypeNone = 0,
+enum class LayerType {
+    None = 0,
     // Although we cannot build the software layer directly (must be done at
     // record time), this information is used when applying alpha.
-    kLayerTypeSoftware = 1,
-    kLayerTypeRenderLayer = 2,
+    Software = 1,
+    RenderLayer = 2,
     // TODO: LayerTypeSurfaceTexture? Maybe?
 };
 
@@ -124,12 +124,12 @@
 
     friend class RenderProperties;
 
-    LayerType mType;
+    LayerType mType = LayerType::None;
     // Whether or not that Layer's content is opaque, doesn't include alpha
     bool mOpaque;
     uint8_t mAlpha;
     SkXfermode::Mode mMode;
-    SkColorFilter* mColorFilter;
+    SkColorFilter* mColorFilter = nullptr;
 };
 
 /*
diff --git a/libs/hwui/renderstate/Blend.cpp b/libs/hwui/renderstate/Blend.cpp
index 789f6cc..29927ed 100644
--- a/libs/hwui/renderstate/Blend.cpp
+++ b/libs/hwui/renderstate/Blend.cpp
@@ -78,10 +78,10 @@
     // gl blending off by default
 }
 
-void Blend::enable(SkXfermode::Mode mode, bool swapSrcDst) {
+void Blend::enable(SkXfermode::Mode mode, ModeOrderSwap modeUsage) {
     GLenum srcMode;
     GLenum dstMode;
-    getFactors(mode, swapSrcDst, &srcMode, &dstMode);
+    getFactors(mode, modeUsage, &srcMode, &dstMode);
     setFactors(srcMode, dstMode);
 }
 
@@ -105,9 +105,9 @@
     }
 }
 
-void Blend::getFactors(SkXfermode::Mode mode, bool swapSrcDst, GLenum* outSrc, GLenum* outDst) {
-    *outSrc = swapSrcDst ? kBlendsSwap[mode].src : kBlends[mode].src;
-    *outDst = swapSrcDst ? kBlendsSwap[mode].dst : kBlends[mode].dst;
+void Blend::getFactors(SkXfermode::Mode mode, ModeOrderSwap modeUsage, GLenum* outSrc, GLenum* outDst) {
+    *outSrc = (modeUsage == ModeOrderSwap::Swap) ? kBlendsSwap[mode].src : kBlends[mode].src;
+    *outDst = (modeUsage == ModeOrderSwap::Swap) ? kBlendsSwap[mode].dst : kBlends[mode].dst;
 }
 
 void Blend::setFactors(GLenum srcMode, GLenum dstMode) {
diff --git a/libs/hwui/renderstate/Blend.h b/libs/hwui/renderstate/Blend.h
index 6d0c115c..dcc681d 100644
--- a/libs/hwui/renderstate/Blend.h
+++ b/libs/hwui/renderstate/Blend.h
@@ -29,11 +29,18 @@
 class Blend {
     friend class RenderState;
 public:
-    void enable(SkXfermode::Mode mode, bool swapSrcDst);
+    // dictates whether to swap src/dst
+    enum class ModeOrderSwap {
+        NoSwap,
+        Swap,
+    };
+
+    void enable(SkXfermode::Mode mode, ModeOrderSwap modeUsage);
     void disable();
     void syncEnabled();
 
-    static void getFactors(SkXfermode::Mode mode, bool swapSrcDst, GLenum* outSrc, GLenum* outDst);
+    static void getFactors(SkXfermode::Mode mode, ModeOrderSwap modeUsage,
+            GLenum* outSrc, GLenum* outDst);
     void setFactors(GLenum src, GLenum dst);
 
     void dump();
diff --git a/libs/hwui/renderstate/MeshState.cpp b/libs/hwui/renderstate/MeshState.cpp
index 6b00020..0521f65 100644
--- a/libs/hwui/renderstate/MeshState.cpp
+++ b/libs/hwui/renderstate/MeshState.cpp
@@ -37,7 +37,7 @@
 
     mCurrentBuffer = mUnitQuadBuffer;
 
-    std::unique_ptr<uint16_t[]> regionIndices(new uint16_t[kMaxNumberOfQuads * 6]);
+    uint16_t regionIndices[kMaxNumberOfQuads * 6];
     for (uint32_t i = 0; i < kMaxNumberOfQuads; i++) {
         uint16_t quad = i * 4;
         int index = i * 6;
@@ -50,8 +50,7 @@
     }
     glGenBuffers(1, &mQuadListIndices);
     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mQuadListIndices);
-    glBufferData(GL_ELEMENT_ARRAY_BUFFER, kMaxNumberOfQuads * 6 * sizeof(uint16_t),
-            regionIndices.get(), GL_STATIC_DRAW);
+    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(regionIndices), regionIndices, GL_STATIC_DRAW);
     mCurrentIndicesBuffer = mQuadListIndices;
 
     // position attribute always enabled
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index fcf6eb2..9456073 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -51,6 +51,7 @@
         , mRootRenderNode(rootRenderNode)
         , mCurrentFrameInfo(nullptr) {
     mRenderThread.renderState().registerCanvasContext(this);
+    mProfiler.setDensity(mRenderThread.mainDisplayInfo().density);
 }
 
 CanvasContext::~CanvasContext() {
diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h
index 9a60dc7..c3904c2 100644
--- a/libs/hwui/renderthread/CanvasContext.h
+++ b/libs/hwui/renderthread/CanvasContext.h
@@ -33,6 +33,7 @@
 #include <utils/Vector.h>
 
 #include <set>
+#include <string>
 
 namespace android {
 namespace uirenderer {
@@ -106,6 +107,9 @@
     void dumpFrames(int fd);
     void resetFrameStats();
 
+    void setName(const std::string&& name) { mName = name; }
+    const std::string& name() { return mName; }
+
 private:
     friend class RegisterFrameCallbackTask;
     // TODO: Replace with something better for layer & other GL object
@@ -139,6 +143,7 @@
     FrameInfo* mCurrentFrameInfo;
     // Ring buffer large enough for 1 second worth of frames
     RingBuffer<FrameInfo, 60> mFrames;
+    std::string mName;
 
     std::set<RenderNode*> mPrefetechedLayers;
 };
diff --git a/libs/hwui/renderthread/DrawFrameTask.cpp b/libs/hwui/renderthread/DrawFrameTask.cpp
index f48ee41..35391b2 100644
--- a/libs/hwui/renderthread/DrawFrameTask.cpp
+++ b/libs/hwui/renderthread/DrawFrameTask.cpp
@@ -34,7 +34,6 @@
 DrawFrameTask::DrawFrameTask()
         : mRenderThread(nullptr)
         , mContext(nullptr)
-        , mDensity(1.0f) // safe enough default
         , mSyncResult(kSync_OK) {
 }
 
@@ -84,7 +83,6 @@
 void DrawFrameTask::run() {
     ATRACE_NAME("DrawFrame");
 
-    mContext->profiler().setDensity(mDensity);
     mContext->profiler().startFrame();
 
     bool canUnblockUiThread;
diff --git a/libs/hwui/renderthread/DrawFrameTask.h b/libs/hwui/renderthread/DrawFrameTask.h
index 0e56bea..8039643 100644
--- a/libs/hwui/renderthread/DrawFrameTask.h
+++ b/libs/hwui/renderthread/DrawFrameTask.h
@@ -62,7 +62,6 @@
     void pushLayerUpdate(DeferredLayerUpdater* layer);
     void removeLayerUpdate(DeferredLayerUpdater* layer);
 
-    void setDensity(float density) { mDensity = density; }
     int drawFrame();
 
     int64_t* frameInfo() { return mFrameInfo; }
@@ -83,7 +82,6 @@
     /*********************************************
      *  Single frame data
      *********************************************/
-    float mDensity;
     std::vector< sp<DeferredLayerUpdater> > mLayers;
 
     int mSyncResult;
diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp
index 0fa2f23..ea4216c 100644
--- a/libs/hwui/renderthread/RenderProxy.cpp
+++ b/libs/hwui/renderthread/RenderProxy.cpp
@@ -97,18 +97,6 @@
     }
 }
 
-CREATE_BRIDGE2(setFrameInterval, RenderThread* thread, nsecs_t frameIntervalNanos) {
-    args->thread->setFrameInterval(args->frameIntervalNanos);
-    return nullptr;
-}
-
-void RenderProxy::setFrameInterval(nsecs_t frameIntervalNanos) {
-    SETUP_TASK(setFrameInterval);
-    args->thread = &mRenderThread;
-    args->frameIntervalNanos = frameIntervalNanos;
-    post(task);
-}
-
 CREATE_BRIDGE2(setSwapBehavior, CanvasContext* context, SwapBehavior swapBehavior) {
     args->context->setSwapBehavior(args->swapBehavior);
     return nullptr;
@@ -138,6 +126,18 @@
     return (bool) postAndWait(task);
 }
 
+CREATE_BRIDGE2(setName, CanvasContext* context, const char* name) {
+    args->context->setName(std::string(args->name));
+    return nullptr;
+}
+
+void RenderProxy::setName(const char* name) {
+    SETUP_TASK(setName);
+    args->context = mContext;
+    args->name = name;
+    post(task);
+}
+
 CREATE_BRIDGE2(initialize, CanvasContext* context, ANativeWindow* window) {
     return (void*) args->context->initialize(args->window);
 }
@@ -181,8 +181,7 @@
 }
 
 void RenderProxy::setup(int width, int height, const Vector3& lightCenter, float lightRadius,
-        uint8_t ambientShadowAlpha, uint8_t spotShadowAlpha, float density) {
-    mDrawFrameTask.setDensity(density);
+        uint8_t ambientShadowAlpha, uint8_t spotShadowAlpha) {
     SETUP_TASK(setup);
     args->context = mContext;
     args->width = width;
diff --git a/libs/hwui/renderthread/RenderProxy.h b/libs/hwui/renderthread/RenderProxy.h
index 19e73e5..43cbe07 100644
--- a/libs/hwui/renderthread/RenderProxy.h
+++ b/libs/hwui/renderthread/RenderProxy.h
@@ -62,16 +62,16 @@
     ANDROID_API RenderProxy(bool translucent, RenderNode* rootNode, IContextFactory* contextFactory);
     ANDROID_API virtual ~RenderProxy();
 
-    ANDROID_API void setFrameInterval(nsecs_t frameIntervalNanos);
     // Won't take effect until next EGLSurface creation
     ANDROID_API void setSwapBehavior(SwapBehavior swapBehavior);
     ANDROID_API bool loadSystemProperties();
+    ANDROID_API void setName(const char* name);
 
     ANDROID_API bool initialize(const sp<ANativeWindow>& window);
     ANDROID_API void updateSurface(const sp<ANativeWindow>& window);
     ANDROID_API bool pauseSurface(const sp<ANativeWindow>& window);
     ANDROID_API void setup(int width, int height, const Vector3& lightCenter, float lightRadius,
-            uint8_t ambientShadowAlpha, uint8_t spotShadowAlpha, float density);
+            uint8_t ambientShadowAlpha, uint8_t spotShadowAlpha);
     ANDROID_API void setOpaque(bool opaque);
     ANDROID_API int64_t* frameInfo();
     ANDROID_API int syncAndDrawFrame();
diff --git a/libs/hwui/renderthread/RenderThread.cpp b/libs/hwui/renderthread/RenderThread.cpp
index 2a8baa7..3ac2976 100644
--- a/libs/hwui/renderthread/RenderThread.cpp
+++ b/libs/hwui/renderthread/RenderThread.cpp
@@ -22,6 +22,8 @@
 #include "RenderProxy.h"
 
 #include <gui/DisplayEventReceiver.h>
+#include <gui/ISurfaceComposer.h>
+#include <gui/SurfaceComposerClient.h>
 #include <sys/resource.h>
 #include <utils/Log.h>
 
@@ -151,11 +153,6 @@
     LOG_ALWAYS_FATAL("Can't destroy the render thread");
 }
 
-void RenderThread::setFrameInterval(nsecs_t frameInterval) {
-    mTimeLord.setFrameInterval(frameInterval);
-    mJankTracker->setFrameInterval(frameInterval);
-}
-
 void RenderThread::initializeDisplayEventReceiver() {
     LOG_ALWAYS_FATAL_IF(mDisplayEventReceiver, "Initializing a second DisplayEventReceiver?");
     mDisplayEventReceiver = new DisplayEventReceiver();
@@ -169,10 +166,16 @@
 }
 
 void RenderThread::initThreadLocals() {
+    sp<IBinder> dtoken(SurfaceComposerClient::getBuiltInDisplay(
+            ISurfaceComposer::eDisplayIdMain));
+    status_t status = SurfaceComposerClient::getDisplayInfo(dtoken, &mDisplayInfo);
+    LOG_ALWAYS_FATAL_IF(status, "Failed to get display info\n");
+    nsecs_t frameIntervalNanos = static_cast<nsecs_t>(1000000000 / mDisplayInfo.fps);
+    mTimeLord.setFrameInterval(frameIntervalNanos);
     initializeDisplayEventReceiver();
     mEglManager = new EglManager(*this);
     mRenderState = new RenderState(*this);
-    mJankTracker = new JankTracker(mTimeLord.frameIntervalNanos());
+    mJankTracker = new JankTracker(frameIntervalNanos);
 }
 
 int RenderThread::displayEventReceiverCallback(int fd, int events, void* data) {
diff --git a/libs/hwui/renderthread/RenderThread.h b/libs/hwui/renderthread/RenderThread.h
index f169424..8096099 100644
--- a/libs/hwui/renderthread/RenderThread.h
+++ b/libs/hwui/renderthread/RenderThread.h
@@ -23,6 +23,7 @@
 #include "TimeLord.h"
 
 #include <cutils/compiler.h>
+#include <ui/DisplayInfo.h>
 #include <utils/Looper.h>
 #include <utils/Mutex.h>
 #include <utils/Singleton.h>
@@ -86,13 +87,13 @@
     // the next vsync. If it is not currently registered this does nothing.
     void pushBackFrameCallback(IFrameCallback* callback);
 
-    void setFrameInterval(nsecs_t frameInterval);
-
     TimeLord& timeLord() { return mTimeLord; }
     RenderState& renderState() { return *mRenderState; }
     EglManager& eglManager() { return *mEglManager; }
     JankTracker& jankTracker() { return *mJankTracker; }
 
+    const DisplayInfo& mainDisplayInfo() { return mDisplayInfo; }
+
 protected:
     virtual bool threadLoop() override;
 
@@ -122,6 +123,8 @@
     nsecs_t mNextWakeup;
     TaskQueue mQueue;
 
+    DisplayInfo mDisplayInfo;
+
     DisplayEventReceiver* mDisplayEventReceiver;
     bool mVsyncRequested;
     std::set<IFrameCallback*> mFrameCallbacks;
diff --git a/libs/hwui/tests/main.cpp b/libs/hwui/tests/main.cpp
index 0d1e63e..805989b 100644
--- a/libs/hwui/tests/main.cpp
+++ b/libs/hwui/tests/main.cpp
@@ -85,7 +85,7 @@
         proxy->initialize(surface);
         float lightX = width / 2.0;
         proxy->setup(width, height, (Vector3){lightX, dp(-200.0f), dp(800.0f)},
-                dp(800.0f), 255 * 0.075, 255 * 0.15, gDisplay.density);
+                dp(800.0f), 255 * 0.075, 255 * 0.15);
 
         android::uirenderer::Rect DUMMY;
 
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index 287b646..43c394a 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -230,7 +230,7 @@
             "android.intent.action.HEADSET_PLUG";
 
     /**
-     * Broadcast Action: A sticky broadcast indicating an HMDI cable was plugged or unplugged
+     * Broadcast Action: A sticky broadcast indicating an HDMI cable was plugged or unplugged.
      *
      * The intent will have the following extra values: {@link #EXTRA_AUDIO_PLUG_STATE},
      * {@link #EXTRA_MAX_CHANNEL_COUNT}, {@link #EXTRA_ENCODINGS}.
diff --git a/native/graphics/jni/Android.mk b/native/graphics/jni/Android.mk
index 88954f0..14575ee 100644
--- a/native/graphics/jni/Android.mk
+++ b/native/graphics/jni/Android.mk
@@ -30,5 +30,8 @@
 
 LOCAL_CFLAGS += -Wall -Werror -Wunused -Wunreachable-code
 
+# TODO: This is to work around b/19059885. Remove after root cause is fixed
+LOCAL_LDFLAGS := -Wl,--hash-style=both
+
 include $(BUILD_SHARED_LIBRARY)
 
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
index 0d03ed9..3a8216d 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
@@ -354,6 +354,7 @@
 
             XmlSerializer serializer = Xml.newSerializer();
             serializer.setOutput(out, "utf-8");
+            serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
             serializer.startDocument(null, true);
             serializer.startTag(null, TAG_SETTINGS);
             serializer.attribute(null, ATTR_VERSION, String.valueOf(version));
@@ -383,7 +384,7 @@
             }
 
         } catch (IOException e) {
-            Slog.w(LOG_TAG, "Failed to write settings, restoring backup", e);
+            Slog.wtf(LOG_TAG, "Failed to write settings, restoring backup", e);
             destination.failWrite(out);
         } finally {
             IoUtils.closeQuietly(out);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/Utilities.java b/packages/SystemUI/src/com/android/systemui/recents/misc/Utilities.java
index 925d17e..84544ff 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/misc/Utilities.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/misc/Utilities.java
@@ -33,7 +33,7 @@
     private static Method sPropertyMethod;
     static {
         try {
-            Class<?> c = Class.forName("android.view.GLES20Canvas");
+            Class<?> c = Class.forName("android.view.DisplayListCanvas");
             sPropertyMethod = c.getDeclaredMethod("setProperty", String.class, String.class);
             if (!sPropertyMethod.isAccessible()) sPropertyMethod.setAccessible(true);
         } catch (ClassNotFoundException e) {
diff --git a/services/core/java/com/android/server/LockSettingsStorage.java b/services/core/java/com/android/server/LockSettingsStorage.java
index c03bb58..d81daa9 100644
--- a/services/core/java/com/android/server/LockSettingsStorage.java
+++ b/services/core/java/com/android/server/LockSettingsStorage.java
@@ -238,12 +238,21 @@
 
     public void writePatternHash(byte[] hash, int userId) {
         writeFile(getLockPatternFilename(userId), hash);
+        clearPasswordHash(userId);
+    }
+
+    private void clearPatternHash(int userId) {
+        writeFile(getLockPatternFilename(userId), null);
     }
 
     public void writePasswordHash(byte[] hash, int userId) {
         writeFile(getLockPasswordFilename(userId), hash);
+        clearPatternHash(userId);
     }
 
+    private void clearPasswordHash(int userId) {
+        writeFile(getLockPasswordFilename(userId), null);
+    }
 
     @VisibleForTesting
     String getLockPatternFilename(int userId) {
@@ -279,16 +288,15 @@
         return userId;
     }
 
-
     public void removeUser(int userId) {
         SQLiteDatabase db = mOpenHelper.getWritableDatabase();
 
         final UserManager um = (UserManager) mContext.getSystemService(USER_SERVICE);
         final UserInfo parentInfo = um.getProfileParent(userId);
 
-        synchronized (mFileWriteLock) {
-            if (parentInfo == null) {
-                // This user owns its lock settings files - safe to delete them
+        if (parentInfo == null) {
+            // This user owns its lock settings files - safe to delete them
+            synchronized (mFileWriteLock) {
                 String name = getLockPasswordFilename(userId);
                 File file = new File(name);
                 if (file.exists()) {
diff --git a/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java b/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java
index 03f253b..ae4006d 100644
--- a/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java
+++ b/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java
@@ -76,6 +76,7 @@
 
     static final String POSTFIX_BACKUP = (PREPEND_CATEGORY_NAME) ? "_Backup" : "";
     static final String POSTFIX_BROADCAST = (PREPEND_CATEGORY_NAME) ? "_Broadcast" : "";
+    static final String POSTFIX_CLEANUP = (PREPEND_CATEGORY_NAME) ? "_Cleanup" : "";
     static final String POSTFIX_MU = "_MU";
     static final String POSTFIX_SERVICE = (PREPEND_CATEGORY_NAME) ? "_Service" : "";
     static final String POSTFIX_SERVICE_EXECUTING =
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 46f07cc..c4122e8 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -248,42 +248,39 @@
     // File that stores last updated system version and called preboot receivers
     static final String CALLED_PRE_BOOTS_FILENAME = "called_pre_boots.dat";
 
-    static final String TAG = TAG_WITH_CLASS_NAME ? "ActivityManagerService" : TAG_AM;
+    private static final String TAG = TAG_WITH_CLASS_NAME ? "ActivityManagerService" : TAG_AM;
+    private static final String TAG_BACKUP = TAG + POSTFIX_BACKUP;
+    private static final String TAG_BROADCAST = TAG + POSTFIX_BROADCAST;
+    private static final String TAG_CLEANUP = TAG + POSTFIX_CLEANUP;
     private static final String TAG_MU = TAG + POSTFIX_MU;
 
     // TODO(ogunwale): Migrate all the constants below to use ActivityManagerDebugConfig class.
-    static final boolean localLOGV = DEBUG_ALL || false;
-    static final boolean DEBUG_BACKUP = localLOGV || false;
-    static final boolean DEBUG_BROADCAST = localLOGV || false;
-    static final boolean DEBUG_BROADCAST_LIGHT = DEBUG_BROADCAST || false;
-    static final boolean DEBUG_BACKGROUND_BROADCAST = DEBUG_BROADCAST || false;
-    static final boolean DEBUG_CLEANUP = localLOGV || false;
-    static final boolean DEBUG_CONFIGURATION = localLOGV || false;
+    static final boolean DEBUG_CONFIGURATION = DEBUG_ALL || false;
     static final boolean DEBUG_FOCUS = false;
-    static final boolean DEBUG_IMMERSIVE = localLOGV || false;
-    static final boolean DEBUG_MU = localLOGV || false;
-    static final boolean DEBUG_OOM_ADJ = localLOGV || false;
-    static final boolean DEBUG_LRU = localLOGV || false;
-    static final boolean DEBUG_PAUSE = localLOGV || false;
-    static final boolean DEBUG_POWER = localLOGV || false;
+    static final boolean DEBUG_IMMERSIVE = DEBUG_ALL || false;
+    static final boolean DEBUG_MU = DEBUG_ALL || false;
+    static final boolean DEBUG_OOM_ADJ = DEBUG_ALL || false;
+    static final boolean DEBUG_LRU = DEBUG_ALL || false;
+    static final boolean DEBUG_PAUSE = DEBUG_ALL || false;
+    static final boolean DEBUG_POWER = DEBUG_ALL || false;
     static final boolean DEBUG_POWER_QUICK = DEBUG_POWER || false;
-    static final boolean DEBUG_PROCESS_OBSERVERS = localLOGV || false;
-    static final boolean DEBUG_PROCESSES = localLOGV || false;
-    static final boolean DEBUG_PROVIDER = localLOGV || false;
-    static final boolean DEBUG_RESULTS = localLOGV || false;
-    static final boolean DEBUG_SERVICE = localLOGV || false;
-    static final boolean DEBUG_SERVICE_EXECUTING = localLOGV || false;
-    static final boolean DEBUG_STACK = localLOGV || false;
-    static final boolean DEBUG_SWITCH = localLOGV || false;
-    static final boolean DEBUG_TASKS = localLOGV || false;
-    static final boolean DEBUG_THUMBNAILS = localLOGV || false;
-    static final boolean DEBUG_TRANSITION = localLOGV || false;
-    static final boolean DEBUG_URI_PERMISSION = localLOGV || false;
-    static final boolean DEBUG_USER_LEAVING = localLOGV || false;
-    static final boolean DEBUG_VISBILITY = localLOGV || false;
-    static final boolean DEBUG_PSS = localLOGV || false;
-    static final boolean DEBUG_LOCKSCREEN = localLOGV || false;
-    static final boolean DEBUG_RECENTS = localLOGV || false;
+    static final boolean DEBUG_PROCESS_OBSERVERS = DEBUG_ALL || false;
+    static final boolean DEBUG_PROCESSES = DEBUG_ALL || false;
+    static final boolean DEBUG_PROVIDER = DEBUG_ALL || false;
+    static final boolean DEBUG_RESULTS = DEBUG_ALL || false;
+    static final boolean DEBUG_SERVICE = DEBUG_ALL || false;
+    static final boolean DEBUG_SERVICE_EXECUTING = DEBUG_ALL || false;
+    static final boolean DEBUG_STACK = DEBUG_ALL || false;
+    static final boolean DEBUG_SWITCH = DEBUG_ALL || false;
+    static final boolean DEBUG_TASKS = DEBUG_ALL || false;
+    static final boolean DEBUG_THUMBNAILS = DEBUG_ALL || false;
+    static final boolean DEBUG_TRANSITION = DEBUG_ALL || false;
+    static final boolean DEBUG_URI_PERMISSION = DEBUG_ALL || false;
+    static final boolean DEBUG_USER_LEAVING = DEBUG_ALL || false;
+    static final boolean DEBUG_VISBILITY = DEBUG_ALL || false;
+    static final boolean DEBUG_PSS = DEBUG_ALL || false;
+    static final boolean DEBUG_LOCKSCREEN = DEBUG_ALL || false;
+    static final boolean DEBUG_RECENTS = DEBUG_ALL || false;
     static final boolean VALIDATE_TOKENS = false;
     static final boolean SHOW_ACTIVITY_START_TIME = true;
 
@@ -407,11 +404,9 @@
 
     BroadcastQueue broadcastQueueForIntent(Intent intent) {
         final boolean isFg = (intent.getFlags() & Intent.FLAG_RECEIVER_FOREGROUND) != 0;
-        if (DEBUG_BACKGROUND_BROADCAST) {
-            Slog.i(TAG, "Broadcast intent " + intent + " on "
-                    + (isFg ? "foreground" : "background")
-                    + " queue");
-        }
+        if (DEBUG_BROADCAST_BACKGROUND) Slog.i(TAG_BROADCAST,
+                "Broadcast intent " + intent + " on "
+                + (isFg ? "foreground" : "background") + " queue");
         return (isFg) ? mFgBroadcastQueue : mBgBroadcastQueue;
     }
 
@@ -1215,7 +1210,7 @@
 
         AppDeathRecipient(ProcessRecord app, int pid,
                 IApplicationThread thread) {
-            if (localLOGV) Slog.v(
+            if (DEBUG_ALL) Slog.v(
                 TAG, "New death recipient " + this
                 + " for thread " + thread.asBinder());
             mApp = app;
@@ -1225,7 +1220,7 @@
 
         @Override
         public void binderDied() {
-            if (localLOGV) Slog.v(
+            if (DEBUG_ALL) Slog.v(
                 TAG, "Death received in " + this
                 + " for thread " + mAppThread.asBinder());
             synchronized(ActivityManagerService.this) {
@@ -4316,9 +4311,8 @@
                 doLowMem = false;
             }
             EventLog.writeEvent(EventLogTags.AM_PROC_DIED, app.userId, app.pid, app.processName);
-            if (DEBUG_CLEANUP) Slog.v(
-                TAG, "Dying app: " + app + ", pid: " + pid
-                + ", thread: " + thread.asBinder());
+            if (DEBUG_CLEANUP) Slog.v(TAG_CLEANUP,
+                "Dying app: " + app + ", pid: " + pid + ", thread: " + thread.asBinder());
             handleAppDiedLocked(app, false, true);
 
             if (doOomAdj) {
@@ -5499,7 +5493,7 @@
 
         // Tell the process all about itself.
 
-        if (localLOGV) Slog.v(
+        if (DEBUG_ALL) Slog.v(
                 TAG, "Binding process pid " + pid + " to record " + app);
 
         final String processName = app.processName;
@@ -5535,7 +5529,7 @@
             Slog.i(TAG, "Launching preboot mode app: " + app);
         }
 
-        if (localLOGV) Slog.v(
+        if (DEBUG_ALL) Slog.v(
             TAG, "New app record " + app
             + " thread=" + thread.asBinder() + " pid=" + pid);
         try {
@@ -5656,7 +5650,8 @@
 
         // Check whether the next backup agent is in this process...
         if (!badApp && mBackupTarget != null && mBackupTarget.appInfo.uid == app.uid) {
-            if (DEBUG_BACKUP) Slog.v(TAG, "New app is backup target, launching agent for " + app);
+            if (DEBUG_BACKUP) Slog.v(TAG_BACKUP,
+                    "New app is backup target, launching agent for " + app);
             ensurePackageDexOpt(mBackupTarget.appInfo.packageName);
             try {
                 thread.scheduleCreateBackupAgent(mBackupTarget.appInfo,
@@ -5939,7 +5934,7 @@
     @Override
     public final void activityStopped(IBinder token, Bundle icicle,
             PersistableBundle persistentState, CharSequence description) {
-        if (localLOGV) Slog.v(TAG, "Activity stopped: token=" + token);
+        if (DEBUG_ALL) Slog.v(TAG, "Activity stopped: token=" + token);
 
         // Refuse possible leaked file descriptors
         if (icicle != null && icicle.hasFileDescriptors()) {
@@ -7689,7 +7684,7 @@
         synchronized(this) {
             ArrayList<IAppTask> list = new ArrayList<IAppTask>();
             try {
-                if (localLOGV) Slog.v(TAG, "getAppTasks");
+                if (DEBUG_ALL) Slog.v(TAG, "getAppTasks");
 
                 final int N = mRecentTasks.size();
                 for (int i = 0; i < N; i++) {
@@ -7723,7 +7718,7 @@
         ArrayList<RunningTaskInfo> list = new ArrayList<RunningTaskInfo>();
 
         synchronized(this) {
-            if (localLOGV) Slog.v(
+            if (DEBUG_ALL) Slog.v(
                 TAG, "getTasks: max=" + maxNum + ", flags=" + flags);
 
             final boolean allowed = isGetTasksAllowed("getTasks", Binder.getCallingPid(),
@@ -7878,7 +7873,7 @@
         synchronized (this) {
             enforceCallingPermission(android.Manifest.permission.READ_FRAME_BUFFER,
                     "getTaskThumbnail()");
-            TaskRecord tr = mStackSupervisor.anyTaskForIdLocked(id, false);
+            TaskRecord tr = mStackSupervisor.anyTaskForIdLocked(id);
             if (tr != null) {
                 return tr.getTaskThumbnailLocked();
             }
@@ -7991,7 +7986,7 @@
     @Override
     public void setTaskResizeable(int taskId, boolean resizeable) {
         synchronized (this) {
-            TaskRecord task = mStackSupervisor.anyTaskForIdLocked(taskId, false);
+            TaskRecord task = mStackSupervisor.anyTaskForIdLocked(taskId);
             if (task == null) {
                 Slog.w(TAG, "setTaskResizeable: taskId=" + taskId + " not found");
                 return;
@@ -8011,7 +8006,7 @@
         long ident = Binder.clearCallingIdentity();
         try {
             synchronized (this) {
-                TaskRecord task = mStackSupervisor.anyTaskForIdLocked(taskId, true);
+                TaskRecord task = mStackSupervisor.anyTaskForIdLocked(taskId);
                 if (task == null) {
                     Slog.w(TAG, "resizeTask: taskId=" + taskId + " not found");
                     return;
@@ -8158,7 +8153,7 @@
      * @return Returns true if the given task was found and removed.
      */
     private boolean removeTaskByIdLocked(int taskId, boolean killProcess) {
-        TaskRecord tr = mStackSupervisor.anyTaskForIdLocked(taskId, false);
+        TaskRecord tr = mStackSupervisor.anyTaskForIdLocked(taskId);
         if (tr != null) {
             tr.removeTaskActivitiesLocked();
             cleanUpRemovedTaskLocked(tr, killProcess);
@@ -8411,7 +8406,7 @@
         long ident = Binder.clearCallingIdentity();
         try {
             synchronized (this) {
-                TaskRecord tr = mStackSupervisor.anyTaskForIdLocked(taskId, false);
+                TaskRecord tr = mStackSupervisor.anyTaskForIdLocked(taskId);
                 return tr != null && tr.stack != null && tr.stack.isHomeStack();
             }
         } finally {
@@ -9250,7 +9245,7 @@
             ContentProviderRecord cpr = mProviderMap.getProviderByName(name, userId);
             if(cpr == null) {
                 //remove from mProvidersByClass
-                if(localLOGV) Slog.v(TAG, name+" content provider not found in providers list");
+                if(DEBUG_ALL) Slog.v(TAG, name+" content provider not found in providers list");
                 return;
             }
 
@@ -9787,7 +9782,7 @@
     }
 
     public final void activitySlept(IBinder token) {
-        if (localLOGV) Slog.v(TAG, "Activity slept: token=" + token);
+        if (DEBUG_ALL) Slog.v(TAG, "Activity slept: token=" + token);
 
         final long origId = Binder.clearCallingIdentity();
 
@@ -14738,7 +14733,7 @@
 
         // If the app is undergoing backup, tell the backup manager about it
         if (mBackupTarget != null && app.pid == mBackupTarget.app.pid) {
-            if (DEBUG_BACKUP || DEBUG_CLEANUP) Slog.d(TAG, "App "
+            if (DEBUG_BACKUP || DEBUG_CLEANUP) Slog.d(TAG_CLEANUP, "App "
                     + mBackupTarget.appInfo + " died during backup");
             try {
                 IBackupManager bm = IBackupManager.Stub.asInterface(
@@ -14765,7 +14760,7 @@
         }
 
         if (!app.persistent || app.isolated) {
-            if (DEBUG_PROCESSES || DEBUG_CLEANUP) Slog.v(TAG,
+            if (DEBUG_PROCESSES || DEBUG_CLEANUP) Slog.v(TAG_CLEANUP,
                     "Removing non-persistent process during cleanup: " + app);
             mProcessNames.remove(app.processName, app.uid);
             mIsolatedProcesses.remove(app.uid);
@@ -14783,8 +14778,8 @@
                 restart = true;
             }
         }
-        if ((DEBUG_PROCESSES || DEBUG_CLEANUP) && mProcessesOnHold.contains(app)) Slog.v(TAG,
-                "Clean-up removing on hold: " + app);
+        if ((DEBUG_PROCESSES || DEBUG_CLEANUP) && mProcessesOnHold.contains(app)) Slog.v(
+                TAG_CLEANUP, "Clean-up removing on hold: " + app);
         mProcessesOnHold.remove(app);
 
         if (app == mHomeProcess) {
@@ -15155,7 +15150,8 @@
     // instantiated.  The backup agent will invoke backupAgentCreated() on the
     // activity manager to announce its creation.
     public boolean bindBackupAgent(ApplicationInfo app, int backupMode) {
-        if (DEBUG_BACKUP) Slog.v(TAG, "bindBackupAgent: app=" + app + " mode=" + backupMode);
+        if (DEBUG_BACKUP) Slog.v(TAG_BACKUP,
+                "bindBackupAgent: app=" + app + " mode=" + backupMode);
         enforceCallingPermission("android.permission.CONFIRM_FULL_BACKUP", "bindBackupAgent");
 
         synchronized(this) {
@@ -15198,7 +15194,7 @@
             // If the process is already attached, schedule the creation of the backup agent now.
             // If it is not yet live, this will be done when it attaches to the framework.
             if (proc.thread != null) {
-                if (DEBUG_BACKUP) Slog.v(TAG, "Agent proc already running: " + proc);
+                if (DEBUG_BACKUP) Slog.v(TAG_BACKUP, "Agent proc already running: " + proc);
                 try {
                     proc.thread.scheduleCreateBackupAgent(app,
                             compatibilityInfoForPackageLocked(app), backupMode);
@@ -15206,7 +15202,7 @@
                     // Will time out on the backup manager side
                 }
             } else {
-                if (DEBUG_BACKUP) Slog.v(TAG, "Agent proc not running, waiting for attach");
+                if (DEBUG_BACKUP) Slog.v(TAG_BACKUP, "Agent proc not running, waiting for attach");
             }
             // Invariants: at this point, the target app process exists and the application
             // is either already running or in the process of coming up.  mBackupTarget and
@@ -15219,7 +15215,7 @@
 
     @Override
     public void clearPendingBackup() {
-        if (DEBUG_BACKUP) Slog.v(TAG, "clearPendingBackup");
+        if (DEBUG_BACKUP) Slog.v(TAG_BACKUP, "clearPendingBackup");
         enforceCallingPermission("android.permission.BACKUP", "clearPendingBackup");
 
         synchronized (this) {
@@ -15230,7 +15226,7 @@
 
     // A backup agent has just come up
     public void backupAgentCreated(String agentPackageName, IBinder agent) {
-        if (DEBUG_BACKUP) Slog.v(TAG, "backupAgentCreated: " + agentPackageName
+        if (DEBUG_BACKUP) Slog.v(TAG_BACKUP, "backupAgentCreated: " + agentPackageName
                 + " = " + agent);
 
         synchronized(this) {
@@ -15257,7 +15253,7 @@
 
     // done with this agent
     public void unbindBackupAgent(ApplicationInfo appInfo) {
-        if (DEBUG_BACKUP) Slog.v(TAG, "unbindBackupAgent: " + appInfo);
+        if (DEBUG_BACKUP) Slog.v(TAG_BACKUP, "unbindBackupAgent: " + appInfo);
         if (appInfo == null) {
             Slog.w(TAG, "unbind backup agent for null app");
             return;
@@ -15400,7 +15396,7 @@
 
         // The first sticky in the list is returned directly back to the client.
         Intent sticky = allSticky != null ? allSticky.get(0) : null;
-        if (DEBUG_BROADCAST) Slog.v(TAG, "Register receiver " + filter + ": " + sticky);
+        if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Register receiver " + filter + ": " + sticky);
         if (receiver == null) {
             return sticky;
         }
@@ -15470,7 +15466,7 @@
     }
 
     public void unregisterReceiver(IIntentReceiver receiver) {
-        if (DEBUG_BROADCAST) Slog.v(TAG, "Unregister receiver: " + receiver);
+        if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Unregister receiver: " + receiver);
 
         final long origId = Binder.clearCallingIdentity();
         try {
@@ -15621,9 +15617,9 @@
         // By default broadcasts do not go to stopped apps.
         intent.addFlags(Intent.FLAG_EXCLUDE_STOPPED_PACKAGES);
 
-        if (DEBUG_BROADCAST_LIGHT) Slog.v(
-            TAG, (sticky ? "Broadcast sticky: ": "Broadcast: ") + intent
-            + " ordered=" + ordered + " userid=" + userId);
+        if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST,
+                (sticky ? "Broadcast sticky: ": "Broadcast: ") + intent
+                + " ordered=" + ordered + " userid=" + userId);
         if ((resultTo != null) && !ordered) {
             Slog.w(TAG, "Broadcast " + intent + " not ordered but result callback requested!");
         }
@@ -15945,7 +15941,7 @@
         final boolean replacePending =
                 (intent.getFlags()&Intent.FLAG_RECEIVER_REPLACE_PENDING) != 0;
 
-        if (DEBUG_BROADCAST) Slog.v(TAG, "Enqueing broadcast: " + intent.getAction()
+        if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Enqueing broadcast: " + intent.getAction()
                 + " replacePending=" + replacePending);
 
         int NR = registeredReceivers != null ? registeredReceivers.size() : 0;
@@ -15958,8 +15954,7 @@
                     callerPackage, callingPid, callingUid, resolvedType, requiredPermission,
                     appOp, registeredReceivers, resultTo, resultCode, resultData, map,
                     ordered, sticky, false, userId);
-            if (DEBUG_BROADCAST) Slog.v(
-                    TAG, "Enqueueing parallel broadcast " + r);
+            if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Enqueueing parallel broadcast " + r);
             final boolean replaced = replacePending && queue.replaceParallelBroadcastLocked(r);
             if (!replaced) {
                 queue.enqueueParallelBroadcastLocked(r);
@@ -16049,11 +16044,10 @@
                     requiredPermission, appOp, receivers, resultTo, resultCode,
                     resultData, map, ordered, sticky, false, userId);
 
-            if (DEBUG_BROADCAST) Slog.v(
-                    TAG, "Enqueueing ordered broadcast " + r
+            if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Enqueueing ordered broadcast " + r
                     + ": prev had " + queue.mOrderedBroadcasts.size());
-            if (DEBUG_BROADCAST) Slog.i(
-                    TAG, "Enqueueing broadcast " + r.intent.getAction());
+            if (DEBUG_BROADCAST) Slog.i(TAG_BROADCAST,
+                    "Enqueueing broadcast " + r.intent.getAction());
 
             boolean replaced = replacePending && queue.replaceOrderedBroadcastLocked(r);
             if (!replaced) {
@@ -16182,7 +16176,7 @@
 
     public void finishReceiver(IBinder who, int resultCode, String resultData,
             Bundle resultExtras, boolean resultAbort, int flags) {
-        if (DEBUG_BROADCAST) Slog.v(TAG, "Finish receiver: " + who);
+        if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Finish receiver: " + who);
 
         // Refuse possible leaked file descriptors
         if (resultExtras != null && resultExtras.hasFileDescriptors()) {
@@ -16948,7 +16942,7 @@
         if (mBackupTarget != null && app == mBackupTarget.app) {
             // If possible we want to avoid killing apps while they're being backed up
             if (adj > ProcessList.BACKUP_APP_ADJ) {
-                if (DEBUG_BACKUP) Slog.v(TAG, "oom BACKUP_APP_ADJ for " + app);
+                if (DEBUG_BACKUP) Slog.v(TAG_BACKUP, "oom BACKUP_APP_ADJ for " + app);
                 adj = ProcessList.BACKUP_APP_ADJ;
                 if (procState > ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND) {
                     procState = ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND;
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index 0cbc9d7..09dc426 100755
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -16,6 +16,8 @@
 
 package com.android.server.am;
 
+import static com.android.server.am.ActivityManagerDebugConfig.*;
+import static com.android.server.am.ActivityManagerService.DEBUG_THUMBNAILS;
 import static com.android.server.am.TaskPersister.DEBUG_PERSISTER;
 import static com.android.server.am.TaskPersister.DEBUG_RESTORER;
 import static com.android.server.am.TaskRecord.INVALID_TASK_ID;
@@ -71,7 +73,8 @@
  * An entry in the history stack, representing an activity.
  */
 final class ActivityRecord {
-    static final String TAG = ActivityManagerService.TAG;
+    private static final String TAG = TAG_WITH_CLASS_NAME ? "ActivityRecord" : TAG_AM;
+
     static final boolean DEBUG_SAVED_STATE = ActivityStackSupervisor.DEBUG_SAVED_STATE;
     final public static String RECENTS_PACKAGE_NAME = "com.android.systemui.recents";
 
@@ -319,7 +322,7 @@
         final WeakReference<ActivityRecord> weakActivity;
 
         Token(ActivityRecord activity) {
-            weakActivity = new WeakReference<ActivityRecord>(activity);
+            weakActivity = new WeakReference<>(activity);
         }
 
         @Override public void windowsDrawn() {
@@ -372,7 +375,7 @@
         try {
             return token != null ? ((Token)token).weakActivity.get() : null;
         } catch (ClassCastException e) {
-            Slog.w(ActivityManagerService.TAG, "Bad activity token: " + token, e);
+            Slog.w(TAG, "Bad activity token: " + token, e);
             return null;
         }
     }
@@ -676,11 +679,9 @@
                 app.thread.scheduleNewIntent(ar, appToken);
                 unsent = false;
             } catch (RemoteException e) {
-                Slog.w(ActivityManagerService.TAG,
-                        "Exception thrown sending new intent to " + this, e);
+                Slog.w(TAG, "Exception thrown sending new intent to " + this, e);
             } catch (NullPointerException e) {
-                Slog.w(ActivityManagerService.TAG,
-                        "Exception thrown sending new intent to " + this, e);
+                Slog.w(TAG, "Exception thrown sending new intent to " + this, e);
             }
         }
         if (unsent) {
@@ -820,7 +821,7 @@
 
     void updateThumbnailLocked(Bitmap newThumbnail, CharSequence description) {
         if (newThumbnail != null) {
-            if (ActivityManagerService.DEBUG_THUMBNAILS) Slog.i(ActivityManagerService.TAG,
+            if (DEBUG_THUMBNAILS) Slog.i(TAG,
                     "Setting thumbnail of " + this + " to " + newThumbnail);
             boolean thumbnailUpdated = task.setLastThumbnail(newThumbnail);
             if (thumbnailUpdated && isPersistable()) {
@@ -905,7 +906,7 @@
                     TimeUtils.formatDuration(totalTime, sb);
                     sb.append(")");
                 }
-                Log.i(ActivityManagerService.TAG, sb.toString());
+                Log.i(TAG, sb.toString());
             }
             if (totalTime > 0) {
                 //service.mUsageStatsService.noteFullyDrawnTime(realActivity, (int) totalTime);
@@ -936,7 +937,7 @@
                 TimeUtils.formatDuration(totalTime, sb);
                 sb.append(")");
             }
-            Log.i(ActivityManagerService.TAG, sb.toString());
+            Log.i(TAG, sb.toString());
         }
         mStackSupervisor.reportActivityLaunchedLocked(false, this, thisTime, totalTime);
         if (totalTime > 0) {
@@ -963,8 +964,7 @@
     public void windowsVisible() {
         synchronized(service) {
             mStackSupervisor.reportActivityVisibleLocked(this);
-            if (ActivityManagerService.DEBUG_SWITCH) Log.v(
-                    ActivityManagerService.TAG, "windowsVisible(): " + this);
+            if (ActivityManagerService.DEBUG_SWITCH) Log.v(TAG, "windowsVisible(): " + this);
             if (!nowVisible) {
                 nowVisible = true;
                 lastVisibleTime = SystemClock.uptimeMillis();
@@ -983,8 +983,7 @@
                     if (N > 0) {
                         for (int i=0; i<N; i++) {
                             ActivityRecord r = mStackSupervisor.mWaitingVisibleActivities.get(i);
-                            if (ActivityManagerService.DEBUG_SWITCH) Log.v(
-                                    ActivityManagerService.TAG,
+                            if (ActivityManagerService.DEBUG_SWITCH) Log.v(TAG,
                                     "Was waiting for visible: " + r);
                         }
                         mStackSupervisor.mWaitingVisibleActivities.clear();
@@ -997,8 +996,7 @@
     }
 
     public void windowsGone() {
-        if (ActivityManagerService.DEBUG_SWITCH) Log.v(
-                ActivityManagerService.TAG, "windowsGone(): " + this);
+        if (ActivityManagerService.DEBUG_SWITCH) Log.v(TAG, "windowsGone(): " + this);
         nowVisible = false;
     }
 
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 40a8b86..8b7a6af 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -16,9 +16,7 @@
 
 package com.android.server.am;
 
-import static com.android.server.am.ActivityManagerService.TAG;
-import static com.android.server.am.ActivityManagerService.localLOGV;
-import static com.android.server.am.ActivityManagerService.DEBUG_CLEANUP;
+import static com.android.server.am.ActivityManagerDebugConfig.*;
 import static com.android.server.am.ActivityManagerService.DEBUG_CONFIGURATION;
 import static com.android.server.am.ActivityManagerService.DEBUG_PAUSE;
 import static com.android.server.am.ActivityManagerService.DEBUG_RESULTS;
@@ -97,6 +95,9 @@
  */
 final class ActivityStack {
 
+    private static final String TAG = TAG_WITH_CLASS_NAME ? "ActivityStack" : TAG_AM;
+    private static final String TAG_CLEANUP = TAG + POSTFIX_CLEANUP;
+
     // Ticks during which we check progress while waiting for an app to launch.
     static final int LAUNCH_TICK = 500;
 
@@ -264,9 +265,7 @@
     final Handler mHandler;
 
     final class ActivityStackHandler extends Handler {
-        //public Handler() {
-        //    if (localLOGV) Slog.v(TAG, "Handler started!");
-        //}
+
         ActivityStackHandler(Looper looper) {
             super(looper);
         }
@@ -2912,7 +2911,7 @@
 
         // Need to go through the full pause cycle to get this
         // activity into the stopped state and then finish it.
-        if (localLOGV) Slog.v(TAG, "Enqueueing pending finish: " + r);
+        if (DEBUG_ALL) Slog.v(TAG, "Enqueueing pending finish: " + r);
         mStackSupervisor.mFinishingActivities.add(r);
         r.resumeKeyDispatchingLocked();
         mStackSupervisor.getFocusedStack().resumeTopActivityLocked(null);
@@ -3435,15 +3434,14 @@
     private void removeHistoryRecordsForAppLocked(ArrayList<ActivityRecord> list,
             ProcessRecord app, String listName) {
         int i = list.size();
-        if (DEBUG_CLEANUP) Slog.v(
-            TAG, "Removing app " + app + " from list " + listName
-            + " with " + i + " entries");
+        if (DEBUG_CLEANUP) Slog.v(TAG_CLEANUP,
+            "Removing app " + app + " from list " + listName + " with " + i + " entries");
         while (i > 0) {
             i--;
             ActivityRecord r = list.get(i);
-            if (DEBUG_CLEANUP) Slog.v(TAG, "Record #" + i + " " + r);
+            if (DEBUG_CLEANUP) Slog.v(TAG_CLEANUP, "Record #" + i + " " + r);
             if (r.app == app) {
-                if (DEBUG_CLEANUP) Slog.v(TAG, "---> REMOVING this entry!");
+                if (DEBUG_CLEANUP) Slog.v(TAG_CLEANUP, "---> REMOVING this entry!");
                 list.remove(i);
                 removeTimeoutsForActivityLocked(r);
             }
@@ -3465,15 +3463,15 @@
 
         // Clean out the history list.
         int i = numActivities();
-        if (DEBUG_CLEANUP) Slog.v(
-            TAG, "Removing app " + app + " from history with " + i + " entries");
+        if (DEBUG_CLEANUP) Slog.v(TAG_CLEANUP,
+                "Removing app " + app + " from history with " + i + " entries");
         for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
             final ArrayList<ActivityRecord> activities = mTaskHistory.get(taskNdx).mActivities;
             for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
                 final ActivityRecord r = activities.get(activityNdx);
                 --i;
-                if (DEBUG_CLEANUP) Slog.v(
-                    TAG, "Record #" + i + " " + r + ": app=" + r.app);
+                if (DEBUG_CLEANUP) Slog.v(TAG_CLEANUP,
+                        "Record #" + i + " " + r + ": app=" + r.app);
                 if (r.app == app) {
                     final boolean remove;
                     if ((!r.haveState && !r.stateNotNeeded) || r.finishing) {
@@ -3512,7 +3510,7 @@
                     } else {
                         // We have the current state for this activity, so
                         // it can be restarted later when needed.
-                        if (localLOGV) Slog.v(
+                        if (DEBUG_ALL) Slog.v(
                             TAG, "Keeping entry, setting app to null");
                         if (r.visible) {
                             hasVisibleActivities = true;
@@ -4048,7 +4046,7 @@
                     numRunning++;
                 }
 
-                if (localLOGV) Slog.v(
+                if (DEBUG_ALL) Slog.v(
                     TAG, r.intent.getComponent().flattenToShortString()
                     + ": task=" + r.task);
             }
@@ -4247,8 +4245,6 @@
                 mActivityContainer.onTaskListEmptyLocked();
             }
         }
-
-        task.stack = null;
     }
 
     TaskRecord createTaskRecord(int taskId, ActivityInfo info, Intent intent,
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 8b95ae8..05297d4 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -21,7 +21,6 @@
 import static android.content.Intent.FLAG_ACTIVITY_TASK_ON_HOME;
 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
 import static com.android.server.am.ActivityManagerDebugConfig.*;
-import static com.android.server.am.ActivityManagerService.localLOGV;
 import static com.android.server.am.ActivityManagerService.DEBUG_CONFIGURATION;
 import static com.android.server.am.ActivityManagerService.DEBUG_FOCUS;
 import static com.android.server.am.ActivityManagerService.DEBUG_PAUSE;
@@ -32,7 +31,6 @@
 import static com.android.server.am.ActivityManagerService.DEBUG_TASKS;
 import static com.android.server.am.ActivityManagerService.DEBUG_USER_LEAVING;
 import static com.android.server.am.ActivityManagerService.FIRST_SUPERVISOR_STACK_MSG;
-import static com.android.server.am.ActivityManagerService.TAG;
 import static com.android.server.am.ActivityRecord.HOME_ACTIVITY_TYPE;
 import static com.android.server.am.ActivityRecord.RECENTS_ACTIVITY_TYPE;
 import static com.android.server.am.ActivityRecord.APPLICATION_ACTIVITY_TYPE;
@@ -117,6 +115,8 @@
 import java.util.List;
 
 public final class ActivityStackSupervisor implements DisplayListener {
+    private static final String TAG = TAG_WITH_CLASS_NAME ? "ActivityStackSupervisor" : TAG_AM;
+
     static final boolean DEBUG = DEBUG_ALL || false;
     static final boolean DEBUG_ADD_REMOVE = DEBUG || false;
     static final boolean DEBUG_APP = DEBUG || false;
@@ -471,16 +471,6 @@
     }
 
     TaskRecord anyTaskForIdLocked(int id) {
-        return anyTaskForIdLocked(id, true);
-    }
-
-    /**
-     * Returns a {@link TaskRecord} for the input id if available. Null otherwise.
-     * @param id Id of the task we would like returned.
-     * @param restoreFromRecents If the id was not in the active list, but was found in recents,
-     *                           restore the task from recents to the active list.
-     */
-    TaskRecord anyTaskForIdLocked(int id, boolean restoreFromRecents) {
         int numDisplays = mActivityDisplays.size();
         for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
             ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
@@ -501,10 +491,6 @@
             return null;
         }
 
-        if (!restoreFromRecents) {
-            return task;
-        }
-
         if (!restoreRecentTaskLocked(task)) {
             if (DEBUG_RECENTS) Slog.w(TAG, "Couldn't restore task id=" + id + " found in recents");
             return null;
@@ -539,7 +525,7 @@
             if (mCurTaskId <= 0) {
                 mCurTaskId = 1;
             }
-        } while (anyTaskForIdLocked(mCurTaskId, false) != null);
+        } while (anyTaskForIdLocked(mCurTaskId) != null);
         return mCurTaskId;
     }
 
@@ -1141,7 +1127,7 @@
         r.launchCount++;
         r.lastLaunchTime = SystemClock.uptimeMillis();
 
-        if (localLOGV) Slog.v(TAG, "Launching: " + r);
+        if (DEBUG_ALL) Slog.v(TAG, "Launching: " + r);
 
         int idx = app.activities.indexOf(r);
         if (idx < 0) {
@@ -2297,7 +2283,7 @@
     // Checked.
     final ActivityRecord activityIdleInternalLocked(final IBinder token, boolean fromTimeout,
             Configuration config) {
-        if (localLOGV) Slog.v(TAG, "Activity idle: " + token);
+        if (DEBUG_ALL) Slog.v(TAG, "Activity idle: " + token);
 
         ArrayList<ActivityRecord> stops = null;
         ArrayList<ActivityRecord> finishes = null;
@@ -2731,7 +2717,7 @@
             final ArrayList<ActivityStack> homeDisplayStacks = mHomeStack.mStacks;
             for (int stackNdx = homeDisplayStacks.size() - 1; stackNdx >= 0; --stackNdx) {
                 final ActivityStack tmpStack = homeDisplayStacks.get(stackNdx);
-                if (!tmpStack.isHomeStack() && tmpStack.mFullscreen) {
+                if (!tmpStack.isHomeStack()) {
                     stack = tmpStack;
                     break;
                 }
@@ -3178,7 +3164,7 @@
         for (int activityNdx = mStoppingActivities.size() - 1; activityNdx >= 0; --activityNdx) {
             ActivityRecord s = mStoppingActivities.get(activityNdx);
             final boolean waitingVisible = mWaitingVisibleActivities.contains(s);
-            if (localLOGV) Slog.v(TAG, "Stopping " + s + ": nowVisible=" + nowVisible
+            if (DEBUG_ALL) Slog.v(TAG, "Stopping " + s + ": nowVisible=" + nowVisible
                     + " waitingVisible=" + waitingVisible + " finishing=" + s.finishing);
             if (waitingVisible && nowVisible) {
                 mWaitingVisibleActivities.remove(s);
@@ -3188,12 +3174,12 @@
                     // so get rid of it.  Otherwise, we need to go through the
                     // normal flow and hide it once we determine that it is
                     // hidden by the activities in front of it.
-                    if (localLOGV) Slog.v(TAG, "Before stopping, can hide: " + s);
+                    if (DEBUG_ALL) Slog.v(TAG, "Before stopping, can hide: " + s);
                     mWindowManager.setAppVisibility(s.appToken, false);
                 }
             }
             if ((!waitingVisible || mService.isSleepingOrShuttingDown()) && remove) {
-                if (localLOGV) Slog.v(TAG, "Ready to stop: " + s);
+                if (DEBUG_ALL) Slog.v(TAG, "Ready to stop: " + s);
                 if (stops == null) {
                     stops = new ArrayList<>();
                 }
@@ -3993,10 +3979,6 @@
         }
 
         void onTaskListEmptyLocked() {
-            mHandler.removeMessages(CONTAINER_TASK_LIST_EMPTY_TIMEOUT, this);
-            detachLocked();
-            deleteActivityContainer(this);
-            mHandler.obtainMessage(CONTAINER_CALLBACK_TASK_LIST_EMPTY, this).sendToTarget();
         }
 
         @Override
@@ -4085,6 +4067,13 @@
             return false;
         }
 
+        void onTaskListEmptyLocked() {
+            mHandler.removeMessages(CONTAINER_TASK_LIST_EMPTY_TIMEOUT, this);
+            detachLocked();
+            deleteActivityContainer(this);
+            mHandler.obtainMessage(CONTAINER_CALLBACK_TASK_LIST_EMPTY, this).sendToTarget();
+        }
+
         private void setSurfaceIfReadyLocked() {
             if (DEBUG_STACK) Slog.v(TAG, "setSurfaceIfReadyLocked: mDrawn=" + mDrawn +
                     " mContainerState=" + mContainerState + " mSurface=" + mSurface);
diff --git a/services/core/java/com/android/server/am/CompatModePackages.java b/services/core/java/com/android/server/am/CompatModePackages.java
index ec500c2..ce63d75 100644
--- a/services/core/java/com/android/server/am/CompatModePackages.java
+++ b/services/core/java/com/android/server/am/CompatModePackages.java
@@ -16,6 +16,8 @@
 
 package com.android.server.am;
 
+import static com.android.server.am.ActivityManagerDebugConfig.*;
+
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.FileOutputStream;
@@ -43,7 +45,7 @@
 import android.util.Xml;
 
 public final class CompatModePackages {
-    private final String TAG = ActivityManagerService.TAG;
+    private static final String TAG = TAG_WITH_CLASS_NAME ? "CompatModePackages" : TAG_AM;
     private final boolean DEBUG_CONFIGURATION = ActivityManagerService.DEBUG_CONFIGURATION;
 
     private final ActivityManagerService mService;
diff --git a/services/core/java/com/android/server/am/PendingIntentRecord.java b/services/core/java/com/android/server/am/PendingIntentRecord.java
index 7bdfced..432abd2 100644
--- a/services/core/java/com/android/server/am/PendingIntentRecord.java
+++ b/services/core/java/com/android/server/am/PendingIntentRecord.java
@@ -16,6 +16,9 @@
 
 package com.android.server.am;
 
+import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
+import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
+
 import android.app.ActivityManager;
 import android.app.IActivityContainer;
 import android.content.IIntentSender;
@@ -35,6 +38,8 @@
 import java.lang.ref.WeakReference;
 
 final class PendingIntentRecord extends IIntentSender.Stub {
+    private static final String TAG = TAG_WITH_CLASS_NAME ? "PendingIntentRecord" : TAG_AM;
+
     final ActivityManagerService owner;
     final Key key;
     final int uid;
@@ -45,7 +50,7 @@
     String stringName;
     String lastTagPrefix;
     String lastTag;
-    
+
     final static class Key {
         final int type;
         final String packageName;
@@ -266,8 +271,7 @@
                                         options, userId, container, null);
                             }
                         } catch (RuntimeException e) {
-                            Slog.w(ActivityManagerService.TAG,
-                                    "Unable to send startActivity intent", e);
+                            Slog.w(TAG, "Unable to send startActivity intent", e);
                         }
                         break;
                     case ActivityManager.INTENT_SENDER_ACTIVITY_RESULT:
@@ -286,8 +290,7 @@
                                 sendFinish = false;
                             }
                         } catch (RuntimeException e) {
-                            Slog.w(ActivityManagerService.TAG,
-                                    "Unable to send startActivity intent", e);
+                            Slog.w(TAG, "Unable to send startActivity intent", e);
                         }
                         break;
                     case ActivityManager.INTENT_SENDER_SERVICE:
@@ -295,12 +298,11 @@
                             owner.startServiceInPackage(uid,
                                     finalIntent, resolvedType, userId);
                         } catch (RuntimeException e) {
-                            Slog.w(ActivityManagerService.TAG,
-                                    "Unable to send startService intent", e);
+                            Slog.w(TAG, "Unable to send startService intent", e);
                         }
                         break;
                 }
-                
+
                 if (sendFinish) {
                     try {
                         finishedReceiver.performReceive(new Intent(finalIntent), 0,
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index c380160..c7aa94c 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -16,6 +16,9 @@
 
 package com.android.server.am;
 
+import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
+import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
+
 import java.io.IOException;
 import java.io.OutputStream;
 import java.nio.ByteBuffer;
@@ -38,6 +41,8 @@
  * Activity manager code dealing with processes.
  */
 final class ProcessList {
+    private static final String TAG = TAG_WITH_CLASS_NAME ? "ProcessList" : TAG_AM;
+
     // The minimum time we allow between crashes, for us to consider this
     // application to be bad and stop and its services and reject broadcasts.
     static final int MIN_CRASH_INTERVAL = 60*1000;
@@ -633,8 +638,7 @@
                         LocalSocketAddress.Namespace.RESERVED));
             sLmkdOutputStream = sLmkdSocket.getOutputStream();
         } catch (IOException ex) {
-            Slog.w(ActivityManagerService.TAG,
-                   "lowmemorykiller daemon socket open failed");
+            Slog.w(TAG, "lowmemorykiller daemon socket open failed");
             sLmkdSocket = null;
             return false;
         }
@@ -659,8 +663,7 @@
                 sLmkdOutputStream.write(buf.array(), 0, buf.position());
                 return;
             } catch (IOException ex) {
-                Slog.w(ActivityManagerService.TAG,
-                       "Error writing to lowmemorykiller socket");
+                Slog.w(TAG, "Error writing to lowmemorykiller socket");
 
                 try {
                     sLmkdSocket.close();
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index f374c86..7cf3b51 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -16,6 +16,9 @@
 
 package com.android.server.am;
 
+import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
+import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
+
 import android.util.ArraySet;
 import android.util.DebugUtils;
 import android.util.EventLog;
@@ -49,6 +52,8 @@
  * is currently running.
  */
 final class ProcessRecord {
+    private static final String TAG = TAG_WITH_CLASS_NAME ? "ProcessRecord" : TAG_AM;
+
     private final BatteryStatsImpl mBatteryStats; // where to collect runtime statistics
     final ApplicationInfo info; // all about the first app in the process
     final boolean isolated;     // true if this is a special isolated process
@@ -472,7 +477,7 @@
         }
         return false;
     }
-    
+
     public void stopFreezingAllLocked() {
         int i = activities.size();
         while (i > 0) {
@@ -480,7 +485,7 @@
             activities.get(i).stopFreezingScreenLocked(true);
         }
     }
-    
+
     public void unlinkDeathRecipient() {
         if (deathRecipient != null && thread != null) {
             thread.asBinder().unlinkToDeath(deathRecipient, 0);
@@ -524,8 +529,7 @@
     void kill(String reason, boolean noisy) {
         if (!killedByAm) {
             if (noisy) {
-                Slog.i(ActivityManagerService.TAG, "Killing " + toShortString() + " (adj " + setAdj
-                        + "): " + reason);
+                Slog.i(TAG, "Killing " + toShortString() + " (adj " + setAdj + "): " + reason);
             }
             EventLog.writeEvent(EventLogTags.AM_KILL, userId, pid, processName, setAdj, reason);
             Process.killProcessQuiet(pid);
diff --git a/services/core/java/com/android/server/am/RecentTasks.java b/services/core/java/com/android/server/am/RecentTasks.java
index f454fed..04912d0 100644
--- a/services/core/java/com/android/server/am/RecentTasks.java
+++ b/services/core/java/com/android/server/am/RecentTasks.java
@@ -16,6 +16,12 @@
 
 package com.android.server.am;
 
+import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
+import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
+import static com.android.server.am.ActivityManagerService.DEBUG_RECENTS;
+import static com.android.server.am.ActivityManagerService.DEBUG_TASKS;
+import static com.android.server.am.TaskRecord.INVALID_TASK_ID;
+
 import android.app.ActivityManager;
 import android.app.AppGlobals;
 import android.content.ComponentName;
@@ -28,11 +34,6 @@
 import android.os.UserHandle;
 import android.util.Slog;
 
-import static com.android.server.am.ActivityManagerService.DEBUG_RECENTS;
-import static com.android.server.am.ActivityManagerService.DEBUG_TASKS;
-import static com.android.server.am.ActivityManagerService.TAG;
-import static com.android.server.am.TaskRecord.INVALID_TASK_ID;
-
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Comparator;
@@ -42,6 +43,7 @@
  * Class for managing the recent tasks list.
  */
 class RecentTasks extends ArrayList<TaskRecord> {
+    private static final String TAG = TAG_WITH_CLASS_NAME ? "RecentTasks" : TAG_AM;
 
     // Maximum number recent bitmaps to keep in memory.
     private static final int MAX_RECENT_BITMAPS = 3;
diff --git a/services/core/java/com/android/server/am/ServiceRecord.java b/services/core/java/com/android/server/am/ServiceRecord.java
index 1cb1bb8..6c2e120 100644
--- a/services/core/java/com/android/server/am/ServiceRecord.java
+++ b/services/core/java/com/android/server/am/ServiceRecord.java
@@ -47,10 +47,15 @@
 import java.util.List;
 import java.util.Objects;
 
+import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
+import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
+
 /**
  * A running application service.
  */
 final class ServiceRecord extends Binder {
+    private static final String TAG = TAG_WITH_CLASS_NAME ? "ServiceRecord" : TAG_AM;
+
     // Maximum number of delivery attempts before giving up.
     static final int MAX_DELIVERY_COUNT = 3;
 
@@ -487,8 +492,7 @@
                                 appUid, appPid, null, localForegroundId, localForegroundNoti,
                                 outId, userId);
                     } catch (RuntimeException e) {
-                        Slog.w(ActivityManagerService.TAG,
-                                "Error showing notification for service", e);
+                        Slog.w(TAG, "Error showing notification for service", e);
                         // If it gave us a garbage notification, it doesn't
                         // get to be foreground.
                         ams.setServiceForeground(name, ServiceRecord.this,
@@ -517,8 +521,7 @@
                         inm.cancelNotificationWithTag(localPackageName, null,
                                 localForegroundId, userId);
                     } catch (RuntimeException e) {
-                        Slog.w(ActivityManagerService.TAG,
-                                "Error canceling notification for service", e);
+                        Slog.w(TAG, "Error canceling notification for service", e);
                     } catch (RemoteException e) {
                     }
                 }
diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java
index 76bb498..398f0b3 100644
--- a/services/core/java/com/android/server/am/TaskRecord.java
+++ b/services/core/java/com/android/server/am/TaskRecord.java
@@ -16,7 +16,8 @@
 
 package com.android.server.am;
 
-import static com.android.server.am.ActivityManagerService.TAG;
+import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
+import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.am.ActivityRecord.HOME_ACTIVITY_TYPE;
 import static com.android.server.am.ActivityRecord.APPLICATION_ACTIVITY_TYPE;
 import static com.android.server.am.ActivityRecord.RECENTS_ACTIVITY_TYPE;
@@ -54,6 +55,8 @@
 import java.util.ArrayList;
 
 final class TaskRecord {
+    private static final String TAG = TAG_WITH_CLASS_NAME ? "TaskRecord" : TAG_AM;
+
     static final String ATTR_TASKID = "task_id";
     private static final String TAG_INTENT = "intent";
     private static final String TAG_AFFINITYINTENT = "affinity_intent";
@@ -307,7 +310,7 @@
                     _intent.setSourceBounds(null);
                 }
             }
-            if (ActivityManagerService.DEBUG_TASKS) Slog.v(ActivityManagerService.TAG,
+            if (ActivityManagerService.DEBUG_TASKS) Slog.v(TAG,
                     "Setting Intent of " + this + " to " + _intent);
             intent = _intent;
             realActivity = _intent != null ? _intent.getComponent() : null;
@@ -320,7 +323,7 @@
                 targetIntent.setComponent(targetComponent);
                 targetIntent.setSelector(null);
                 targetIntent.setSourceBounds(null);
-                if (ActivityManagerService.DEBUG_TASKS) Slog.v(ActivityManagerService.TAG,
+                if (ActivityManagerService.DEBUG_TASKS) Slog.v(TAG,
                         "Setting Intent of " + this + " to target " + targetIntent);
                 intent = targetIntent;
                 realActivity = targetComponent;
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 61a7263..fc949e0 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -141,6 +141,9 @@
     /** debug calls to media session apis */
     private static final boolean DEBUG_SESSIONS = Log.isLoggable(TAG + ".SESSIONS", Log.DEBUG);
 
+    /** debug calls to devices APIs */
+    protected static final boolean DEBUG_DEVICES = Log.isLoggable(TAG + ".DEVICES", Log.DEBUG);
+
     /** Allow volume changes to set ringer mode to silent? */
     private static final boolean VOLUME_SETS_RINGER_MODE_SILENT = false;
 
@@ -376,7 +379,32 @@
     private final BroadcastReceiver mReceiver = new AudioServiceBroadcastReceiver();
 
     // Devices currently connected
-    private final HashMap <Integer, String> mConnectedDevices = new HashMap <Integer, String>();
+    // Use makeDeviceListKey() to make a unique key for this list.
+    private class DeviceListSpec {
+        int mDeviceType;
+        String mDeviceName;
+        String mDeviceAddress;
+
+        public DeviceListSpec(int deviceType, String deviceName, String deviceAddress) {
+            mDeviceType = deviceType;
+            mDeviceName = deviceName;
+            mDeviceAddress = deviceAddress;
+        }
+
+        public String toString() {
+            return "[type:0x" + Integer.toHexString(mDeviceType) + " name:" + mDeviceName
+                    + " address:" + mDeviceAddress + "]";
+        }
+    }
+
+    // Generate a unique key for the mConnectedDevices List by composing the device "type"
+    // and the "address" associated with a specific instance of that device type
+    private String makeDeviceListKey(int device, String deviceAddress) {
+        return "0x" + Integer.toHexString(device) + ":" + deviceAddress;
+    }
+
+    private final HashMap<String, DeviceListSpec> mConnectedDevices =
+            new HashMap<String, DeviceListSpec>();
 
     // Forced device usage for communications
     private int mForcedUseForComm;
@@ -520,6 +548,8 @@
         return "card=" + card + ";device=" + device + ";";
     }
 
+    private final String DEVICE_NAME_A2DP = "a2dp-device";
+
     ///////////////////////////////////////////////////////////////////////////
     // Construction
     ///////////////////////////////////////////////////////////////////////////
@@ -2767,14 +2797,17 @@
             }
         }
         public void onServiceDisconnected(int profile) {
-            switch(profile) {
+            switch (profile) {
             case BluetoothProfile.A2DP:
                 synchronized (mConnectedDevices) {
                     synchronized (mA2dpAvrcpLock) {
-                        mA2dp = null;
-                        if (mConnectedDevices.containsKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP)) {
-                            makeA2dpDeviceUnavailableNow(
-                                    mConnectedDevices.get(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP));
+                        // Disconnect ALL DEVICE_OUT_BLUETOOTH_A2DP devices
+                        for(Map.Entry<String, DeviceListSpec> entry
+                                : mConnectedDevices.entrySet()) {
+                            DeviceListSpec deviceSpec = entry.getValue();
+                            if (deviceSpec.mDeviceType == AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP) {
+                                makeA2dpDeviceUnavailableNow(deviceSpec.mDeviceAddress);
+                            }
                         }
                     }
                 }
@@ -2782,9 +2815,13 @@
 
             case BluetoothProfile.A2DP_SINK:
                 synchronized (mConnectedDevices) {
-                    if (mConnectedDevices.containsKey(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP)) {
-                        makeA2dpSrcUnavailable(
-                                mConnectedDevices.get(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP));
+                    // Disconnect ALL DEVICE_IN_BLUETOOTH_A2DP devices
+                    for(Map.Entry<String, DeviceListSpec> entry
+                            : mConnectedDevices.entrySet()) {
+                        DeviceListSpec deviceSpec = entry.getValue();
+                        if (deviceSpec.mDeviceType == AudioSystem.DEVICE_IN_BLUETOOTH_A2DP) {
+                            makeA2dpSrcUnavailable(deviceSpec.mDeviceAddress);
+                        }
                     }
                 }
                 break;
@@ -3272,6 +3309,10 @@
     public void setWiredDeviceConnectionState(int type, int state, String address,
             String name) {
         synchronized (mConnectedDevices) {
+            if (DEBUG_DEVICES) {
+                Slog.i(TAG, "setWiredDeviceConnectionState(" + state + " nm: " + name + " addr:"
+                        + address + ")");
+            }
             int delay = checkSendBecomingNoisyIntent(type, state);
             queueMsgUnderWakeLock(mAudioHandler,
                     MSG_SET_WIRED_DEVICE_CONNECTION_STATE,
@@ -4236,13 +4277,13 @@
                 AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 0, streamState, 0);
         setBluetoothA2dpOnInt(true);
         AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
-                AudioSystem.DEVICE_STATE_AVAILABLE,
-                address,
-                "a2dp-device");
+                AudioSystem.DEVICE_STATE_AVAILABLE, address, DEVICE_NAME_A2DP);
         // Reset A2DP suspend state each time a new sink is connected
         AudioSystem.setParameters("A2dpSuspended=false");
-        mConnectedDevices.put( new Integer(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP),
-                address);
+        mConnectedDevices.put(
+                makeDeviceListKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, address),
+                new DeviceListSpec(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, DEVICE_NAME_A2DP,
+                                   address));
     }
 
     private void onSendBecomingNoisyIntent() {
@@ -4255,10 +4296,9 @@
             mAvrcpAbsVolSupported = false;
         }
         AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
-                AudioSystem.DEVICE_STATE_UNAVAILABLE,
-                address,
-                "a2dp-device");
-        mConnectedDevices.remove(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP);
+                AudioSystem.DEVICE_STATE_UNAVAILABLE, address, DEVICE_NAME_A2DP);
+        mConnectedDevices.remove(
+                makeDeviceListKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, address));
         synchronized (mCurAudioRoutes) {
             // Remove A2DP routes as well
             if (mCurAudioRoutes.bluetoothName != null) {
@@ -4275,7 +4315,8 @@
         // reconnection of the sink.
         AudioSystem.setParameters("A2dpSuspended=true");
         // the device will be made unavailable later, so consider it disconnected right away
-        mConnectedDevices.remove(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP);
+        mConnectedDevices.remove(
+                makeDeviceListKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, address));
         // send the delayed message to make the device unavailable later
         Message msg = mAudioHandler.obtainMessage(MSG_BTA2DP_DOCK_TIMEOUT, address);
         mAudioHandler.sendMessageDelayed(msg, BTA2DP_DOCK_TIMEOUT_MILLIS);
@@ -4285,20 +4326,19 @@
     // must be called synchronized on mConnectedDevices
     private void makeA2dpSrcAvailable(String address) {
         AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP,
-                AudioSystem.DEVICE_STATE_AVAILABLE,
-                address,
-                "a2dp-device");
-        mConnectedDevices.put( new Integer(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP),
-                address);
+                AudioSystem.DEVICE_STATE_AVAILABLE, address, DEVICE_NAME_A2DP);
+        mConnectedDevices.put(
+                makeDeviceListKey(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP, address),
+                new DeviceListSpec(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP, DEVICE_NAME_A2DP,
+                                   address));
     }
 
     // must be called synchronized on mConnectedDevices
     private void makeA2dpSrcUnavailable(String address) {
         AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP,
-                AudioSystem.DEVICE_STATE_UNAVAILABLE,
-                address,
-                "a2dp-device");
-        mConnectedDevices.remove(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP);
+                AudioSystem.DEVICE_STATE_UNAVAILABLE, address, DEVICE_NAME_A2DP);
+        mConnectedDevices.remove(
+                makeDeviceListKey(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP, address));
     }
 
     // must be called synchronized on mConnectedDevices
@@ -4325,9 +4365,10 @@
         }
 
         synchronized (mConnectedDevices) {
-            boolean isConnected =
-                (mConnectedDevices.containsKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP) &&
-                 mConnectedDevices.get(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP).equals(address));
+            String key = makeDeviceListKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
+                                           btDevice.getAddress());
+            DeviceListSpec deviceSpec = mConnectedDevices.get(key);
+            boolean isConnected = deviceSpec != null;
 
             if (isConnected && state != BluetoothProfile.STATE_CONNECTED) {
                 if (btDevice.isBluetoothDock()) {
@@ -4388,9 +4429,9 @@
         }
 
         synchronized (mConnectedDevices) {
-                boolean isConnected =
-                (mConnectedDevices.containsKey(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP) &&
-                 mConnectedDevices.get(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP).equals(address));
+            String key = makeDeviceListKey(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP, address);
+            DeviceListSpec deviceSpec = mConnectedDevices.get(key);
+            boolean isConnected = deviceSpec != null;
 
             if (isConnected && state != BluetoothProfile.STATE_CONNECTED) {
                 makeA2dpSrcUnavailable(address);
@@ -4413,27 +4454,32 @@
         }
     }
 
-    private boolean handleDeviceConnection(boolean connect, int device, String address, String deviceName) {
-        Slog.i(TAG, "handleDeviceConnection(" + connect +
-                " dev:" + Integer.toHexString(device) +
-                " address:" + address +
-                " name:" + deviceName + ")");
+    private boolean handleDeviceConnection(boolean connect, int device, String address,
+            String deviceName) {
+        if (DEBUG_DEVICES) {
+            Slog.i(TAG, "handleDeviceConnection(" + connect + " dev:" + Integer.toHexString(device)
+                    + " address:" + address + " name:" + deviceName + ")");
+        }
         synchronized (mConnectedDevices) {
-            boolean isConnected = (mConnectedDevices.containsKey(device) &&
-                    (address.isEmpty() || mConnectedDevices.get(device).equals(address)));
-
-            if (isConnected && !connect) {
-                AudioSystem.setDeviceConnectionState(device,
-                                              AudioSystem.DEVICE_STATE_UNAVAILABLE,
-                                              address, deviceName);
-                 mConnectedDevices.remove(device);
-                 return true;
-            } else if (!isConnected && connect) {
-                 AudioSystem.setDeviceConnectionState(device,
-                                                      AudioSystem.DEVICE_STATE_AVAILABLE,
-                                                      address, deviceName);
-                 mConnectedDevices.put(new Integer(device), address);
-                 return true;
+            String deviceKey = makeDeviceListKey(device, address);
+            if (DEBUG_DEVICES) {
+                Slog.i(TAG, "deviceKey:" + deviceKey);
+            }
+            DeviceListSpec deviceSpec = mConnectedDevices.get(deviceKey);
+            boolean isConnected = deviceSpec != null;
+            if (DEBUG_DEVICES) {
+                Slog.i(TAG, "deviceSpec:" + deviceSpec + " is(already)Connected:" + isConnected);
+            }
+            if (connect && !isConnected) {
+                AudioSystem.setDeviceConnectionState(device, AudioSystem.DEVICE_STATE_AVAILABLE,
+                        address, deviceName);
+                mConnectedDevices.put(deviceKey, new DeviceListSpec(device, deviceName, address));
+                return true;
+            } else if (!connect && isConnected) {
+                AudioSystem.setDeviceConnectionState(device, AudioSystem.DEVICE_STATE_UNAVAILABLE,
+                        address, deviceName);
+                mConnectedDevices.remove(deviceKey);
+                return true;
             }
         }
         return false;
@@ -4454,10 +4500,11 @@
         int delay = 0;
         if ((state == 0) && ((device & mBecomingNoisyIntentDevices) != 0)) {
             int devices = 0;
-            for (int dev : mConnectedDevices.keySet()) {
-                if (((dev & AudioSystem.DEVICE_BIT_IN) == 0) &&
-                        ((dev & mBecomingNoisyIntentDevices) != 0)) {
-                   devices |= dev;
+            for (String key : mConnectedDevices.keySet()) {
+                int dev = mConnectedDevices.get(key).mDeviceType;
+                if (((dev & AudioSystem.DEVICE_BIT_IN) == 0)
+                        && ((dev & mBecomingNoisyIntentDevices) != 0)) {
+                    devices |= dev;
                 }
             }
             if (devices == device) {
@@ -4485,12 +4532,13 @@
         return delay;
     }
 
-    private void sendDeviceConnectionIntent(int device, int state, String address, String deviceName)
-    {
-        Slog.i(TAG, "sendDeviceConnectionIntent(dev:0x" + Integer.toHexString(device) +
-                " state:0x" + Integer.toHexString(state) +
-                " address:" + address +
-                " name:" + deviceName + ");");
+    private void sendDeviceConnectionIntent(int device, int state, String address,
+            String deviceName) {
+        if (DEBUG_DEVICES) {
+            Slog.i(TAG, "sendDeviceConnectionIntent(dev:0x" + Integer.toHexString(device) +
+                    " state:0x" + Integer.toHexString(state) + " address:" + address +
+                    " name:" + deviceName + ");");
+        }
         Intent intent = new Intent();
 
         intent.putExtra(CONNECT_INTENT_KEY_STATE, state);
@@ -4544,12 +4592,12 @@
     }
 
     private void onSetWiredDeviceConnectionState(int device, int state, String address,
-            String deviceName)
-    {
-        Slog.i(TAG, "onSetWiredDeviceConnectionState(dev:" + Integer.toHexString(device)
-                + " state:" + Integer.toHexString(state)
-                + " address:" + address
-                + " deviceName:" + deviceName + ");");
+            String deviceName) {
+        if (DEBUG_DEVICES) {
+            Slog.i(TAG, "onSetWiredDeviceConnectionState(dev:" + Integer.toHexString(device) +
+                    " state:" + Integer.toHexString(state) + " address:" + address +
+                    " deviceName:" + deviceName + ");");
+        }
 
         synchronized (mConnectedDevices) {
             if ((state == 0) && ((device == AudioSystem.DEVICE_OUT_WIRED_HEADSET) ||
diff --git a/services/core/java/com/android/server/media/MediaSessionRecord.java b/services/core/java/com/android/server/media/MediaSessionRecord.java
index 5363968..b5036db 100644
--- a/services/core/java/com/android/server/media/MediaSessionRecord.java
+++ b/services/core/java/com/android/server/media/MediaSessionRecord.java
@@ -808,6 +808,7 @@
             }
             if (typeChanged) {
                 mService.onSessionPlaybackTypeChanged(MediaSessionRecord.this);
+                mHandler.post(MessageHandler.MSG_UPDATE_VOLUME);
             }
         }
 
@@ -822,6 +823,7 @@
             }
             if (typeChanged) {
                 mService.onSessionPlaybackTypeChanged(MediaSessionRecord.this);
+                mHandler.post(MessageHandler.MSG_UPDATE_VOLUME);
             }
         }
     }
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index bedcabe..bb0aa65c 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -1026,6 +1026,7 @@
     private void updateListenerHintsLocked() {
         final int hints = mListenersDisablingEffects.isEmpty() ? 0 : HINT_HOST_DISABLE_EFFECTS;
         if (hints == mListenerHints) return;
+        ZenLog.traceListenerHintsChanged(mListenerHints, hints, mListenersDisablingEffects.size());
         mListenerHints = hints;
         scheduleListenerHintsChanged(hints);
     }
@@ -1034,6 +1035,7 @@
         final ComponentName suppressor = !mListenersDisablingEffects.isEmpty()
                 ? mListenersDisablingEffects.valueAt(0).component : null;
         if (Objects.equals(suppressor, mEffectsSuppressor)) return;
+        ZenLog.traceEffectsSuppressorChanged(mEffectsSuppressor, suppressor);
         mEffectsSuppressor = suppressor;
         mZenModeHelper.setEffectsSuppressed(suppressor != null);
         getContext().sendBroadcast(new Intent(NotificationManager.ACTION_EFFECTS_SUPPRESSOR_CHANGED)
diff --git a/services/core/java/com/android/server/notification/ZenLog.java b/services/core/java/com/android/server/notification/ZenLog.java
index a83fbc3..1fc967f 100644
--- a/services/core/java/com/android/server/notification/ZenLog.java
+++ b/services/core/java/com/android/server/notification/ZenLog.java
@@ -24,6 +24,7 @@
 import android.provider.Settings.Global;
 import android.service.notification.Condition;
 import android.service.notification.IConditionProvider;
+import android.service.notification.NotificationListenerService;
 import android.service.notification.ZenModeConfig;
 import android.util.Slog;
 
@@ -56,6 +57,8 @@
     private static final int TYPE_CONFIG = 11;
     private static final int TYPE_NOT_INTERCEPTED = 12;
     private static final int TYPE_DISABLE_EFFECTS = 13;
+    private static final int TYPE_SUPPRESSOR_CHANGED = 14;
+    private static final int TYPE_LISTENER_HINTS_CHANGED = 15;
 
     private static int sNext;
     private static int sSize;
@@ -120,6 +123,17 @@
         append(TYPE_DISABLE_EFFECTS, record.getKey() + "," + reason);
     }
 
+    public static void traceEffectsSuppressorChanged(ComponentName oldSuppressor,
+            ComponentName newSuppressor) {
+        append(TYPE_SUPPRESSOR_CHANGED, componentToString(oldSuppressor) + "->"
+            + componentToString(newSuppressor));
+    }
+
+    public static void traceListenerHintsChanged(int oldHints, int newHints, int listenerCount) {
+        append(TYPE_LISTENER_HINTS_CHANGED, hintsToString(oldHints) + "->"
+            + hintsToString(newHints) + ",listeners=" + listenerCount);
+    }
+
     private static String subscribeResult(IConditionProvider provider, RemoteException e) {
         return provider == null ? "no provider" : e != null ? e.getMessage() : "ok";
     }
@@ -139,6 +153,8 @@
             case TYPE_CONFIG: return "config";
             case TYPE_NOT_INTERCEPTED: return "not_intercepted";
             case TYPE_DISABLE_EFFECTS: return "disable_effects";
+            case TYPE_SUPPRESSOR_CHANGED: return "suppressor_changed";
+            case TYPE_LISTENER_HINTS_CHANGED: return "listener_hints_changed";
             default: return "unknown";
         }
     }
@@ -161,6 +177,14 @@
         }
     }
 
+    private static String hintsToString(int hints) {
+        switch (hints) {
+            case 0 : return "none";
+            case NotificationListenerService.HINT_HOST_DISABLE_EFFECTS : return "disable_effects";
+            default: return Integer.toString(hints);
+        }
+    }
+
     private static String componentToString(ComponentName component) {
         return component != null ? component.toShortString() : null;
     }
diff --git a/services/core/java/com/android/server/pm/Installer.java b/services/core/java/com/android/server/pm/Installer.java
index 31c604f..5cde8ea 100644
--- a/services/core/java/com/android/server/pm/Installer.java
+++ b/services/core/java/com/android/server/pm/Installer.java
@@ -83,13 +83,14 @@
     }
 
     public int dexopt(String apkPath, int uid, boolean isPublic, String pkgName,
-            String instructionSet, boolean vmSafeMode) {
+            String instructionSet, boolean vmSafeMode, boolean debuggable) {
         if (!isValidInstructionSet(instructionSet)) {
             Slog.e(TAG, "Invalid instruction set: " + instructionSet);
             return -1;
         }
 
-        return mInstaller.dexopt(apkPath, uid, isPublic, pkgName, instructionSet, vmSafeMode);
+        return mInstaller.dexopt(apkPath, uid, isPublic, pkgName, instructionSet, vmSafeMode,
+                debuggable);
     }
 
     public int idmap(String targetApkPath, String overlayApkPath, int uid) {
diff --git a/services/core/java/com/android/server/pm/PackageDexOptimizer.java b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
index 0a7c5cf..2dbce0a 100644
--- a/services/core/java/com/android/server/pm/PackageDexOptimizer.java
+++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
@@ -93,6 +93,7 @@
         }
 
         final boolean vmSafeMode = (pkg.applicationInfo.flags & ApplicationInfo.FLAG_VM_SAFE_MODE) != 0;
+        final boolean debuggable = (pkg.applicationInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0;
 
         final List<String> paths = pkg.getAllCodePathsExcludingResourceOnly();
         boolean performedDexOpt = false;
@@ -118,11 +119,11 @@
                     if (forceDex || (!defer && isDexOptNeeded == DexFile.DEXOPT_NEEDED)) {
                         Log.i(TAG, "Running dexopt on: " + path + " pkg="
                                 + pkg.applicationInfo.packageName + " isa=" + dexCodeInstructionSet
-                                + " vmSafeMode=" + vmSafeMode);
+                                + " vmSafeMode=" + vmSafeMode + " debuggable=" + debuggable);
                         final int sharedGid = UserHandle.getSharedAppGid(pkg.applicationInfo.uid);
                         final int ret = mPackageManagerService.mInstaller.dexopt(path, sharedGid,
                                 !pkg.isForwardLocked(), pkg.packageName, dexCodeInstructionSet,
-                                vmSafeMode);
+                                vmSafeMode, debuggable);
 
                         if (ret < 0) {
                             // Don't bother running dexopt again if we failed, it will probably
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 2e2f350..7df7eb3 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -9956,7 +9956,7 @@
             PackageParser.Package newPackage = scanPackageLI(pkg, parseFlags, scanFlags,
                     System.currentTimeMillis(), user);
 
-            updateSettingsLI(newPackage, installerPackageName, null, null, res);
+            updateSettingsLI(newPackage, installerPackageName, null, null, res, user);
             // delete the partially installed application. the data directory will have to be
             // restored if it was already existing
             if (res.returnCode != PackageManager.INSTALL_SUCCEEDED) {
@@ -10078,7 +10078,8 @@
             try {
                 final PackageParser.Package newPackage = scanPackageLI(pkg, parseFlags,
                         scanFlags | SCAN_UPDATE_TIME, System.currentTimeMillis(), user);
-                updateSettingsLI(newPackage, installerPackageName, allUsers, perUserInstalled, res);
+                updateSettingsLI(newPackage, installerPackageName, allUsers, perUserInstalled, res,
+                        user);
                 updatedSettings = true;
             } catch (PackageManagerException e) {
                 res.setError("Package couldn't be installed in " + pkg.codePath, e);
@@ -10208,7 +10209,8 @@
             }
 
             if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {
-                updateSettingsLI(newPackage, installerPackageName, allUsers, perUserInstalled, res);
+                updateSettingsLI(newPackage, installerPackageName, allUsers, perUserInstalled, res,
+                        user);
                 updatedSettings = true;
             }
 
@@ -10244,7 +10246,7 @@
 
     private void updateSettingsLI(PackageParser.Package newPackage, String installerPackageName,
             int[] allUsers, boolean[] perUserInstalled,
-            PackageInstalledInfo res) {
+            PackageInstalledInfo res, UserHandle user) {
         String pkgName = newPackage.packageName;
         synchronized (mPackages) {
             //write settings. the installStatus will be incomplete at this stage.
@@ -10263,13 +10265,13 @@
             // For system-bundled packages, we assume that installing an upgraded version
             // of the package implies that the user actually wants to run that new code,
             // so we enable the package.
-            if (isSystemApp(newPackage)) {
-                // NB: implicit assumption that system package upgrades apply to all users
-                if (DEBUG_INSTALL) {
-                    Slog.d(TAG, "Implicitly enabling system package on upgrade: " + pkgName);
-                }
-                PackageSetting ps = mSettings.mPackages.get(pkgName);
-                if (ps != null) {
+            PackageSetting ps = mSettings.mPackages.get(pkgName);
+            if (ps != null) {
+                if (isSystemApp(newPackage)) {
+                    // NB: implicit assumption that system package upgrades apply to all users
+                    if (DEBUG_INSTALL) {
+                        Slog.d(TAG, "Implicitly enabling system package on upgrade: " + pkgName);
+                    }
                     if (res.origUsers != null) {
                         for (int userHandle : res.origUsers) {
                             ps.setEnabled(COMPONENT_ENABLED_STATE_DEFAULT,
@@ -10289,6 +10291,13 @@
                         // upcoming call to mSettings.writeLPr().
                     }
                 }
+                // It's implied that when a user requests installation, they want the app to be
+                // installed and enabled.
+                int userId = user.getIdentifier();
+                if (userId != UserHandle.USER_ALL) {
+                    ps.setInstalled(true, userId);
+                    ps.setEnabled(COMPONENT_ENABLED_STATE_DEFAULT, userId, installerPackageName);
+                }
             }
             res.name = pkgName;
             res.uid = newPackage.applicationInfo.uid;
diff --git a/services/core/java/com/android/server/policy/BurnInProtectionHelper.java b/services/core/java/com/android/server/policy/BurnInProtectionHelper.java
index b8a3155..b99c436 100644
--- a/services/core/java/com/android/server/policy/BurnInProtectionHelper.java
+++ b/services/core/java/com/android/server/policy/BurnInProtectionHelper.java
@@ -25,7 +25,11 @@
 import android.content.res.Resources;
 import android.hardware.display.DisplayManager;
 import android.hardware.display.DisplayManagerInternal;
+import android.os.Build;
+import android.os.Handler;
 import android.os.SystemClock;
+import android.os.SystemProperties;
+import android.util.Log;
 import android.view.Display;
 
 import com.android.server.LocalServices;
@@ -37,7 +41,7 @@
     private static final String TAG = "BurnInProtection";
 
     // Default value when max burnin radius is not set.
-    public static final int BURN_IN_RADIUS_MAX_DEFAULT = -1;
+    public static final int BURN_IN_MAX_RADIUS_DEFAULT = -1;
 
     private static final long BURNIN_PROTECTION_WAKEUP_INTERVAL_MS = TimeUnit.MINUTES.toMillis(1);
     private static final long BURNIN_PROTECTION_MINIMAL_INTERVAL_MS = TimeUnit.SECONDS.toMillis(10);
@@ -74,23 +78,19 @@
             updateBurnInProtection();
         }
     };
-
-    public BurnInProtectionHelper(Context context) {
+    
+    public BurnInProtectionHelper(Context context, int minHorizontalOffset,
+            int maxHorizontalOffset, int minVerticalOffset, int maxVerticalOffset,
+            int maxOffsetRadius) {
         final Resources resources = context.getResources();
-        mMinHorizontalBurnInOffset = resources.getInteger(
-                com.android.internal.R.integer.config_burnInProtectionMinHorizontalOffset);
-        mMaxHorizontalBurnInOffset = resources.getInteger(
-                com.android.internal.R.integer.config_burnInProtectionMaxHorizontalOffset);
-        mMinVerticalBurnInOffset = resources.getInteger(
-                com.android.internal.R.integer.config_burnInProtectionMinVerticalOffset);
-        mMaxVerticalBurnInOffset = resources.getInteger(
-                com.android.internal.R.integer.config_burnInProtectionMaxVerticalOffset);
-        int burnInRadiusMax = resources.getInteger(
-                com.android.internal.R.integer.config_burnInProtectionMaxRadius);
-        if (burnInRadiusMax != BURN_IN_RADIUS_MAX_DEFAULT) {
-            mBurnInRadiusMaxSquared = burnInRadiusMax * burnInRadiusMax;
+        mMinHorizontalBurnInOffset = minHorizontalOffset;
+        mMaxHorizontalBurnInOffset = maxHorizontalOffset;
+        mMinVerticalBurnInOffset = minVerticalOffset;
+        mMaxVerticalBurnInOffset = maxHorizontalOffset;
+        if (maxOffsetRadius != BURN_IN_MAX_RADIUS_DEFAULT) {
+            mBurnInRadiusMaxSquared = maxOffsetRadius * maxOffsetRadius;
         } else {
-            mBurnInRadiusMaxSquared = BURN_IN_RADIUS_MAX_DEFAULT;
+            mBurnInRadiusMaxSquared = BURN_IN_MAX_RADIUS_DEFAULT;
         }
 
         mDisplayManagerInternal = LocalServices.getService(DisplayManagerInternal.class);
@@ -175,7 +175,7 @@
                 }
             }
             // If we are outside of the radius, let's try again.
-        } while (mBurnInRadiusMaxSquared != BURN_IN_RADIUS_MAX_DEFAULT
+        } while (mBurnInRadiusMaxSquared != BURN_IN_MAX_RADIUS_DEFAULT
                 && mLastBurnInXOffset * mLastBurnInXOffset + mLastBurnInYOffset * mLastBurnInYOffset
                         > mBurnInRadiusMaxSquared);
     }
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 62e7af4..29a7fd3 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -49,6 +49,7 @@
 import android.media.Ringtone;
 import android.media.RingtoneManager;
 import android.media.session.MediaSessionLegacyHelper;
+import android.os.Build;
 import android.os.Bundle;
 import android.os.Debug;
 import android.os.FactoryTest;
@@ -94,6 +95,7 @@
 import android.view.Surface;
 import android.view.View;
 import android.view.ViewConfiguration;
+import android.view.ViewRootImpl;
 import android.view.Window;
 import android.view.WindowManager;
 import android.view.WindowManagerGlobal;
@@ -1185,6 +1187,12 @@
         }
     };
 
+    private boolean isRoundWindow() {
+        return mContext.getResources().getBoolean(com.android.internal.R.bool.config_windowIsRound)
+                || (Build.HARDWARE.contains("goldfish")
+                && SystemProperties.getBoolean(ViewRootImpl.PROPERTY_EMULATOR_CIRCULAR, false));
+    }
+
     /** {@inheritDoc} */
     @Override
     public void init(Context context, IWindowManager windowManager,
@@ -1194,9 +1202,40 @@
         mWindowManagerFuncs = windowManagerFuncs;
         mWindowManagerInternal = LocalServices.getService(WindowManagerInternal.class);
         mDreamManagerInternal = LocalServices.getService(DreamManagerInternal.class);
-        if (context.getResources().getBoolean(
-                com.android.internal.R.bool.config_enableBurnInProtection)){
-            mBurnInProtectionHelper = new BurnInProtectionHelper(context);
+
+        // Init display burn-in protection
+        boolean burnInProtectionEnabled = context.getResources().getBoolean(
+                com.android.internal.R.bool.config_enableBurnInProtection);
+        // Allow a system property to override this. Used by developer settings.
+        boolean burnInProtectionDevMode =
+                SystemProperties.getBoolean("persist.debug.force_burn_in", false);
+        if (burnInProtectionEnabled || burnInProtectionDevMode) {
+            final int minHorizontal;
+            final int maxHorizontal;
+            final int minVertical;
+            final int maxVertical;
+            final int maxRadius;
+            if (burnInProtectionDevMode) {
+                minHorizontal = -8;
+                maxHorizontal = 8;
+                minVertical = -8;
+                maxVertical = -4;
+                maxRadius = (isRoundWindow()) ? 6 : -1;
+            } else {
+                Resources resources = context.getResources();
+                minHorizontal = resources.getInteger(
+                        com.android.internal.R.integer.config_burnInProtectionMinHorizontalOffset);
+                maxHorizontal = resources.getInteger(
+                        com.android.internal.R.integer.config_burnInProtectionMaxHorizontalOffset);
+                minVertical = resources.getInteger(
+                        com.android.internal.R.integer.config_burnInProtectionMinVerticalOffset);
+                maxVertical = resources.getInteger(
+                        com.android.internal.R.integer.config_burnInProtectionMaxVerticalOffset);
+                maxRadius = resources.getInteger(
+                        com.android.internal.R.integer.config_burnInProtectionMaxRadius);
+            }
+            mBurnInProtectionHelper = new BurnInProtectionHelper(
+                    context, minHorizontal, maxHorizontal, minVertical, maxVertical, maxRadius);
         }
 
         mHandler = new PolicyHandler();
diff --git a/services/core/java/com/android/server/trust/TrustAgentWrapper.java b/services/core/java/com/android/server/trust/TrustAgentWrapper.java
index 583cc6b..0109313 100644
--- a/services/core/java/com/android/server/trust/TrustAgentWrapper.java
+++ b/services/core/java/com/android/server/trust/TrustAgentWrapper.java
@@ -40,6 +40,7 @@
 import android.service.trust.ITrustAgentService;
 import android.service.trust.ITrustAgentServiceCallback;
 
+import java.util.Collections;
 import java.util.List;
 
 /**
@@ -359,6 +360,8 @@
                         mSetTrustAgentFeaturesToken = new Binder();
                         mTrustAgentService.onConfigure(config, mSetTrustAgentFeaturesToken);
                     }
+                } else {
+                    mTrustAgentService.onConfigure(Collections.EMPTY_LIST, null);
                 }
                 final long maxTimeToLock = dpm.getMaximumTimeToLock(null);
                 if (maxTimeToLock != mMaximumTimeToLock) {
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 7e69e87..a4f3f23 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -496,7 +496,12 @@
     int mLastDisplayFreezeDuration = 0;
     Object mLastFinishedFreezeSource = null;
     boolean mWaitingForConfig = false;
-    boolean mWindowsFreezingScreen = false;
+
+    final static int WINDOWS_FREEZING_SCREENS_NONE = 0;
+    final static int WINDOWS_FREEZING_SCREENS_ACTIVE = 1;
+    final static int WINDOWS_FREEZING_SCREENS_TIMEOUT = 2;
+    private int mWindowsFreezingScreen = WINDOWS_FREEZING_SCREENS_NONE;
+
     boolean mClientFreezingScreen = false;
     int mAppsFreezingScreen = 0;
     int mLastWindowForcedOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
@@ -4699,7 +4704,7 @@
                 if (mAppsFreezingScreen == 1) {
                     startFreezingDisplayLocked(false, 0, 0);
                     mH.removeMessages(H.APP_FREEZE_TIMEOUT);
-                    mH.sendEmptyMessageDelayed(H.APP_FREEZE_TIMEOUT, 5000);
+                    mH.sendEmptyMessageDelayed(H.APP_FREEZE_TIMEOUT, 2000);
                 }
             }
             final int N = wtoken.allAppWindows.size();
@@ -6415,7 +6420,7 @@
         mAltOrientation = altOrientation;
         mPolicy.setRotationLw(mRotation);
 
-        mWindowsFreezingScreen = true;
+        mWindowsFreezingScreen = WINDOWS_FREEZING_SCREENS_ACTIVE;
         mH.removeMessages(H.WINDOW_FREEZE_TIMEOUT);
         mH.sendEmptyMessageDelayed(H.WINDOW_FREEZE_TIMEOUT, WINDOW_FREEZE_TIMEOUT_DURATION);
         mWaitingForConfig = true;
@@ -7784,6 +7789,7 @@
                     // TODO(multidisplay): Can non-default displays rotate?
                     synchronized (mWindowMap) {
                         Slog.w(TAG, "Window freeze timeout expired.");
+                        mWindowsFreezingScreen = WINDOWS_FREEZING_SCREENS_TIMEOUT;
                         final WindowList windows = getDefaultWindowListLocked();
                         int i = windows.size();
                         while (i > 0) {
@@ -7851,6 +7857,7 @@
                 case APP_FREEZE_TIMEOUT: {
                     synchronized (mWindowMap) {
                         Slog.w(TAG, "App freeze timeout expired.");
+                        mWindowsFreezingScreen = WINDOWS_FREEZING_SCREENS_TIMEOUT;
                         final int numStacks = mStackIdToStack.size();
                         for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) {
                             final TaskStack stack = mStackIdToStack.valueAt(stackNdx);
@@ -8914,8 +8921,8 @@
             w.mOrientationChanging = true;
             w.mLastFreezeDuration = 0;
             mInnerFields.mOrientationChangeComplete = false;
-            if (!mWindowsFreezingScreen) {
-                mWindowsFreezingScreen = true;
+            if (mWindowsFreezingScreen == WINDOWS_FREEZING_SCREENS_NONE) {
+                mWindowsFreezingScreen = WINDOWS_FREEZING_SCREENS_ACTIVE;
                 // XXX should probably keep timeout from
                 // when we first froze the display.
                 mH.removeMessages(H.WINDOW_FREEZE_TIMEOUT);
@@ -9905,8 +9912,8 @@
                 "With display frozen, orientationChangeComplete="
                 + mInnerFields.mOrientationChangeComplete);
         if (mInnerFields.mOrientationChangeComplete) {
-            if (mWindowsFreezingScreen) {
-                mWindowsFreezingScreen = false;
+            if (mWindowsFreezingScreen != WINDOWS_FREEZING_SCREENS_NONE) {
+                mWindowsFreezingScreen = WINDOWS_FREEZING_SCREENS_NONE;
                 mLastFinishedFreezeSource = mInnerFields.mLastWindowFreezeSource;
                 mH.removeMessages(H.WINDOW_FREEZE_TIMEOUT);
             }
@@ -10188,7 +10195,7 @@
         } else {
             mInnerFields.mOrientationChangeComplete = true;
             mInnerFields.mLastWindowFreezeSource = mAnimator.mLastWindowFreezeSource;
-            if (mWindowsFreezingScreen) {
+            if (mWindowsFreezingScreen != WINDOWS_FREEZING_SCREENS_NONE) {
                 doRequest = true;
             }
         }
@@ -10524,7 +10531,8 @@
             return;
         }
 
-        if (mWaitingForConfig || mAppsFreezingScreen > 0 || mWindowsFreezingScreen
+        if (mWaitingForConfig || mAppsFreezingScreen > 0
+                || mWindowsFreezingScreen == WINDOWS_FREEZING_SCREENS_ACTIVE
                 || mClientFreezingScreen) {
             if (DEBUG_ORIENTATION) Slog.d(TAG,
                 "stopFreezingDisplayLocked: Returning mWaitingForConfig=" + mWaitingForConfig
diff --git a/services/usb/java/com/android/server/usb/UsbAlsaManager.java b/services/usb/java/com/android/server/usb/UsbAlsaManager.java
index 3f180e7..b0e30b5 100644
--- a/services/usb/java/com/android/server/usb/UsbAlsaManager.java
+++ b/services/usb/java/com/android/server/usb/UsbAlsaManager.java
@@ -73,8 +73,6 @@
 
     private UsbAudioDevice mAccessoryAudioDevice = null;
 
-    private UsbAudioDevice mSelectedAudioDevice = null;
-
     // UsbMidiDevice for USB peripheral mode (gadget) device
     private UsbMidiDevice mPeripheralMidiDevice = null;
 
@@ -186,6 +184,10 @@
                 int device = (audioDevice == mAccessoryAudioDevice ?
                         AudioSystem.DEVICE_OUT_USB_ACCESSORY :
                         AudioSystem.DEVICE_OUT_USB_DEVICE);
+                if (DEBUG) {
+                    Slog.i(TAG, "pre-call device:0x" + Integer.toHexString(device) +
+                            " addr:" + address + " name:" + audioDevice.mDeviceName);
+                }
                 mAudioService.setWiredDeviceConnectionState(
                         device, state, address, audioDevice.mDeviceName);
             }
@@ -282,23 +284,13 @@
     /*
      * Select the default device of the specified card.
      */
-    /* package */ boolean selectAudioCard(int card) {
+    /* package */ UsbAudioDevice selectAudioCard(int card) {
         if (DEBUG) {
             Slog.d(TAG, "selectAudioCard() card:" + card);
         }
         if (!mCardsParser.isCardUsb(card)) {
             // Don't. AudioPolicyManager has logic for falling back to internal devices.
-            return false;
-        }
-
-        if (mSelectedAudioDevice != null) {
-            if (mSelectedAudioDevice.mCard == card) {
-                // Nothing to do here.
-                return false;
-            }
-            // "disconnect" the AudioPolicyManager from the previously selected device.
-            notifyDeviceState(mSelectedAudioDevice, false);
-            mSelectedAudioDevice = null;
+            return null;
         }
 
         mDevicesParser.scan();
@@ -314,30 +306,30 @@
 
         // Playback device file needed/present?
         if (hasPlayback && (waitForAlsaDevice(card, device, AlsaDevice.TYPE_PLAYBACK) == null)) {
-            return false;
+            return null;
         }
 
         // Capture device file needed/present?
         if (hasCapture && (waitForAlsaDevice(card, device, AlsaDevice.TYPE_CAPTURE) == null)) {
-            return false;
+            return null;
         }
 
         if (DEBUG) {
             Slog.d(TAG, "usb: hasPlayback:" + hasPlayback + " hasCapture:" + hasCapture);
         }
 
-        mSelectedAudioDevice =
+        UsbAudioDevice audioDevice =
                 new UsbAudioDevice(card, device, hasPlayback, hasCapture, deviceClass);
-        mSelectedAudioDevice.mDeviceName = mCardsParser.getCardRecordFor(card).mCardName;
-        mSelectedAudioDevice.mDeviceDescription =
-                mCardsParser.getCardRecordFor(card).mCardDescription;
+        AlsaCardsParser.AlsaCardRecord cardRecord = mCardsParser.getCardRecordFor(card);
+        audioDevice.mDeviceName = cardRecord.mCardName;
+        audioDevice.mDeviceDescription = cardRecord.mCardDescription;
 
-        notifyDeviceState(mSelectedAudioDevice, true);
+        notifyDeviceState(audioDevice, true);
 
-        return true;
+        return audioDevice;
     }
 
-    /* package */ boolean selectDefaultDevice() {
+    /* package */ UsbAudioDevice selectDefaultDevice() {
         if (DEBUG) {
             Slog.d(TAG, "UsbAudioManager.selectDefaultDevice()");
         }
@@ -347,7 +339,8 @@
 
     /* package */ void usbDeviceAdded(UsbDevice usbDevice) {
        if (DEBUG) {
-          Slog.d(TAG, "usbDeviceAdded(): " + usbDevice);
+          Slog.d(TAG, "deviceAdded(): " + usbDevice.getManufacturerName() +
+                  "nm:" + usbDevice.getProductName());
         }
 
         // Is there an audio interface in there?
@@ -384,8 +377,10 @@
         // If the default isn't a USB device, let the existing "select internal mechanism"
         // handle the selection.
         if (mCardsParser.isCardUsb(addedCard)) {
-            selectAudioCard(addedCard);
-            mAudioDevices.put(usbDevice, mSelectedAudioDevice);
+            UsbAudioDevice audioDevice = selectAudioCard(addedCard);
+            if (audioDevice != null) {
+                mAudioDevices.put(usbDevice, audioDevice);
+            }
 
             // look for MIDI devices
 
@@ -420,14 +415,14 @@
 
     /* package */ void usbDeviceRemoved(UsbDevice usbDevice) {
         if (DEBUG) {
-          Slog.d(TAG, "deviceRemoved(): " + usbDevice);
+          Slog.d(TAG, "deviceRemoved(): " + usbDevice.getManufacturerName() +
+                  " " + usbDevice.getProductName());
         }
 
         UsbAudioDevice audioDevice = mAudioDevices.remove(usbDevice);
         if (audioDevice != null) {
             if (audioDevice.mHasPlayback || audioDevice.mHasPlayback) {
                 notifyDeviceState(audioDevice, false);
-                mSelectedAudioDevice = null;
 
                 // if there any external devices left, select one of them
                 selectDefaultDevice();
diff --git a/tools/layoutlib/bridge/src/android/text/StaticLayout_Delegate.java b/tools/layoutlib/bridge/src/android/text/StaticLayout_Delegate.java
index 929d625..e24b3d5 100644
--- a/tools/layoutlib/bridge/src/android/text/StaticLayout_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/text/StaticLayout_Delegate.java
@@ -1,6 +1,7 @@
 package android.text;
 
 import com.android.annotations.NonNull;
+import com.android.layoutlib.bridge.impl.DelegateManager;
 import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
 
 import android.text.StaticLayout.LineBreaks;
@@ -27,14 +28,19 @@
     private static final char CHAR_NEWLINE   = 0x0A;
     private static final char CHAR_ZWSP      = 0x200B;  // Zero width space.
 
+    // ---- Builder delegate manager ----
+    private static final DelegateManager<Builder> sBuilderManager =
+        new DelegateManager<Builder>(Builder.class);
+
     @LayoutlibDelegate
-    /*package*/ static int nComputeLineBreaks(String locale, char[] inputText, float[] widths,
+    /*package*/ static int nComputeLineBreaks(long nativeBuilder, char[] inputText, float[] widths,
             int length, float firstWidth, int firstWidthLineCount, float restWidth,
             int[] variableTabStops, int defaultTabStop, boolean optimize, LineBreaks recycle,
             int[] recycleBreaks, float[] recycleWidths, boolean[] recycleFlags, int recycleLength) {
 
+        Builder builder = sBuilderManager.getDelegate(nativeBuilder);
         // compute all possible breakpoints.
-        BreakIterator it = BreakIterator.getLineInstance(new ULocale(locale));
+        BreakIterator it = BreakIterator.getLineInstance(new ULocale(builder.mLocale));
         it.setText(new Segment(inputText, 0, length));
         // average word length in english is 5. So, initialize the possible breaks with a guess.
         List<Integer> breaks = new ArrayList<Integer>((int) Math.ceil(length / 5d));
@@ -97,4 +103,32 @@
                 PrimitiveType.PENALTY.getNewPrimitive(length, 0, -PrimitiveType.PENALTY_INFINITY));
         return primitives;
     }
+
+    @LayoutlibDelegate
+    /*package*/ static long nNewBuilder() {
+        return sBuilderManager.addNewDelegate(new Builder());
+    }
+
+    @LayoutlibDelegate
+    /*package*/ static void nFinishBuilder(long nativeBuilder) {
+    }
+
+    @LayoutlibDelegate
+    /*package*/ static void nFreeBuilder(long nativeBuilder) {
+        sBuilderManager.removeJavaReferenceFor(nativeBuilder);
+    }
+
+    @LayoutlibDelegate
+    /*package*/ static void nBuilderSetLocale(long nativeBuilder, String locale) {
+        Builder builder = sBuilderManager.getDelegate(nativeBuilder);
+        builder.mLocale = locale;
+    }
+
+    /**
+     * Java representation of the native Builder class. It currently only stores the locale
+     * set by nBuilderSetLocale.
+     */
+    static class Builder {
+        String mLocale;
+    }
 }