Merge "Update the comment in sendEnvelope." into lmp-dev
diff --git a/Android.mk b/Android.mk
index 03aa762..35d13d7 100644
--- a/Android.mk
+++ b/Android.mk
@@ -204,6 +204,7 @@
 	core/java/android/os/IUserManager.aidl \
 	core/java/android/os/IVibratorService.aidl \
 	core/java/android/service/notification/INotificationListener.aidl \
+	core/java/android/service/notification/IStatusBarNotificationHolder.aidl \
 	core/java/android/service/notification/IConditionListener.aidl \
 	core/java/android/service/notification/IConditionProvider.aidl \
 	core/java/android/print/ILayoutResultCallback.aidl \
diff --git a/api/current.txt b/api/current.txt
index eb1aedc..39772dd 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -8686,7 +8686,7 @@
     method public java.util.List<android.content.pm.PackageInstaller.SessionInfo> getAllSessions();
     method public java.util.List<android.content.pm.PackageInstaller.SessionInfo> getMySessions();
     method public android.content.pm.PackageInstaller.SessionInfo getSessionInfo(int);
-    method public android.content.pm.PackageInstaller.Session openSession(int);
+    method public android.content.pm.PackageInstaller.Session openSession(int) throws java.io.IOException;
     method public void registerSessionCallback(android.content.pm.PackageInstaller.SessionCallback);
     method public void registerSessionCallback(android.content.pm.PackageInstaller.SessionCallback, android.os.Handler);
     method public void uninstall(java.lang.String, android.content.IntentSender);
@@ -8719,16 +8719,15 @@
     method public java.lang.String[] getNames() throws java.io.IOException;
     method public java.io.InputStream openRead(java.lang.String) throws java.io.IOException;
     method public java.io.OutputStream openWrite(java.lang.String, long, long) throws java.io.IOException;
-    method public void setProgress(float);
+    method public void setStagingProgress(float);
   }
 
   public static abstract class PackageInstaller.SessionCallback {
     ctor public PackageInstaller.SessionCallback();
+    method public abstract void onActiveChanged(int, boolean);
     method public abstract void onBadgingChanged(int);
-    method public abstract void onClosed(int);
     method public abstract void onCreated(int);
     method public abstract void onFinished(int, boolean);
-    method public abstract void onOpened(int);
     method public abstract void onProgressChanged(int, float);
   }
 
@@ -8741,7 +8740,7 @@
     method public java.lang.String getInstallerPackageName();
     method public float getProgress();
     method public int getSessionId();
-    method public boolean isOpen();
+    method public boolean isActive();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator CREATOR;
   }
@@ -14051,6 +14050,7 @@
     field public static final int CONTENT_TYPE_SONIFICATION = 4; // 0x4
     field public static final int CONTENT_TYPE_SPEECH = 1; // 0x1
     field public static final int CONTENT_TYPE_UNKNOWN = 0; // 0x0
+    field public static final android.os.Parcelable.Creator CREATOR;
     field public static final int FLAG_AUDIBILITY_ENFORCED = 1; // 0x1
     field public static final int USAGE_ALARM = 4; // 0x4
     field public static final int USAGE_ASSISTANCE_ACCESSIBILITY = 11; // 0xb
@@ -14236,9 +14236,9 @@
     field public static final int AUDIO_SESSION_ID_GENERATE = 0; // 0x0
     field public static final int ERROR = -1; // 0xffffffff
     field public static final int ERROR_DEAD_OBJECT = -6; // 0xfffffffa
-    field public static final java.lang.String EXTRA_AUDIO_PLUG_STATE = "android.media.extra.audio_plug_state";
-    field public static final java.lang.String EXTRA_ENCODINGS = "android.media.extra.encodings";
-    field public static final java.lang.String EXTRA_MAX_CHANNEL_COUNT = "android.media.extra.max_channel_count";
+    field public static final java.lang.String EXTRA_AUDIO_PLUG_STATE = "android.media.extra.AUDIO_PLUG_STATE";
+    field public static final java.lang.String EXTRA_ENCODINGS = "android.media.extra.ENCODINGS";
+    field public static final java.lang.String EXTRA_MAX_CHANNEL_COUNT = "android.media.extra.MAX_CHANNEL_COUNT";
     field public static final java.lang.String EXTRA_RINGER_MODE = "android.media.EXTRA_RINGER_MODE";
     field public static final java.lang.String EXTRA_SCO_AUDIO_PREVIOUS_STATE = "android.media.extra.SCO_AUDIO_PREVIOUS_STATE";
     field public static final java.lang.String EXTRA_SCO_AUDIO_STATE = "android.media.extra.SCO_AUDIO_STATE";
@@ -14710,7 +14710,7 @@
 
   public static final class MediaCodecInfo.CodecCapabilities {
     ctor public MediaCodecInfo.CodecCapabilities();
-    method public static android.media.MediaCodecInfo.CodecCapabilities CreateFromProfileLevel(java.lang.String, int, int);
+    method public static android.media.MediaCodecInfo.CodecCapabilities createFromProfileLevel(java.lang.String, int, int);
     method public android.media.MediaCodecInfo.AudioCapabilities getAudioCapabilities();
     method public android.media.MediaFormat getDefaultFormat();
     method public android.media.MediaCodecInfo.EncoderCapabilities getEncoderCapabilities();
@@ -28231,17 +28231,19 @@
 
   public abstract class Conference {
     ctor public Conference(android.telecomm.PhoneAccountHandle);
-    method public boolean addConnection(android.telecomm.Connection);
-    method public void destroy();
+    method public final boolean addConnection(android.telecomm.Connection);
+    method public final void destroy();
     method public final int getCapabilities();
     method public final java.util.List<android.telecomm.Connection> getConnections();
     method public final android.telecomm.PhoneAccountHandle getPhoneAccount();
     method public final int getState();
     method public void onDisconnect();
     method public void onHold();
+    method public void onMerge();
     method public void onSeparate(android.telecomm.Connection);
+    method public void onSwap();
     method public void onUnhold();
-    method public void removeConnection(android.telecomm.Connection);
+    method public final void removeConnection(android.telecomm.Connection);
     method public final void setActive();
     method public final void setCapabilities(int);
     method public final void setDisconnected(int, java.lang.String);
@@ -28392,13 +28394,13 @@
     method public static java.lang.String toString(int);
     field public static final int ADD_CALL = 16; // 0x10
     field public static final int ALL = 255; // 0xff
-    field public static final int GENERIC_CONFERENCE = 128; // 0x80
     field public static final int HOLD = 1; // 0x1
-    field public static final int MERGE_CALLS = 4; // 0x4
+    field public static final int MANAGE_CONFERENCE = 128; // 0x80
+    field public static final int MERGE_CONFERENCE = 4; // 0x4
     field public static final int MUTE = 64; // 0x40
     field public static final int RESPOND_VIA_TEXT = 32; // 0x20
     field public static final int SUPPORT_HOLD = 2; // 0x2
-    field public static final int SWAP_CALLS = 8; // 0x8
+    field public static final int SWAP_CONFERENCE = 8; // 0x8
   }
 
   public class PropertyPresentation {
@@ -28410,7 +28412,7 @@
   }
 
   public final class RemoteConference {
-    method public final void addListener(android.telecomm.RemoteConference.Listener);
+    method public final void addCallback(android.telecomm.RemoteConference.Callback);
     method public void disconnect();
     method public final int getCallCapabilities();
     method public final java.util.List<android.telecomm.RemoteConnection> getConnections();
@@ -28418,13 +28420,13 @@
     method public java.lang.String getDisconnectMessage();
     method public final int getState();
     method public void hold();
-    method public final void removeListener(android.telecomm.RemoteConference.Listener);
+    method public final void removeCallback(android.telecomm.RemoteConference.Callback);
     method public void separate(android.telecomm.RemoteConnection);
     method public void unhold();
   }
 
-  public static abstract class RemoteConference.Listener {
-    ctor public RemoteConference.Listener();
+  public static abstract class RemoteConference.Callback {
+    ctor public RemoteConference.Callback();
     method public void onCapabilitiesChanged(android.telecomm.RemoteConference, int);
     method public void onConnectionAdded(android.telecomm.RemoteConference, android.telecomm.RemoteConnection);
     method public void onConnectionRemoved(android.telecomm.RemoteConference, android.telecomm.RemoteConnection);
@@ -28515,17 +28517,17 @@
     method public void registerPhoneAccount(android.telecomm.PhoneAccount);
     method public void showInCallScreen(boolean);
     method public void unregisterPhoneAccount(android.telecomm.PhoneAccountHandle);
-    field public static final java.lang.String ACTION_CHANGE_PHONE_ACCOUNTS = "android.telecomm.intent.action.CHANGE_PHONE_ACCOUNTS";
-    field public static final java.lang.String ACTION_CONNECTION_SERVICE_CONFIGURE = "android.intent.action.CONNECTION_SERVICE_CONFIGURE";
-    field public static final java.lang.String ACTION_SHOW_CALL_SETTINGS = "android.telecomm.intent.action.SHOW_CALL_SETTINGS";
+    field public static final java.lang.String ACTION_CHANGE_PHONE_ACCOUNTS = "android.telecomm.action.CHANGE_PHONE_ACCOUNTS";
+    field public static final java.lang.String ACTION_CONNECTION_SERVICE_CONFIGURE = "android.telecomm.action.CONNECTION_SERVICE_CONFIGURE";
+    field public static final java.lang.String ACTION_SHOW_CALL_SETTINGS = "android.telecomm.action.SHOW_CALL_SETTINGS";
     field public static final char DTMF_CHARACTER_PAUSE = 44; // 0x002c ','
     field public static final char DTMF_CHARACTER_WAIT = 59; // 0x003b ';'
     field public static final java.lang.String EXTRA_CALL_BACK_NUMBER = "android.telecomm.extra.CALL_BACK_NUMBER";
     field public static final java.lang.String EXTRA_CALL_DISCONNECT_CAUSE = "android.telecomm.extra.CALL_DISCONNECT_CAUSE";
     field public static final java.lang.String EXTRA_CALL_DISCONNECT_MESSAGE = "android.telecomm.extra.CALL_DISCONNECT_MESSAGE";
     field public static final java.lang.String EXTRA_CONNECTION_SERVICE = "android.telecomm.extra.CONNECTION_SERVICE";
-    field public static final java.lang.String EXTRA_PHONE_ACCOUNT_HANDLE = "android.intent.extra.PHONE_ACCOUNT_HANDLE";
-    field public static final java.lang.String EXTRA_START_CALL_WITH_SPEAKERPHONE = "android.intent.extra.START_CALL_WITH_SPEAKERPHONE";
+    field public static final java.lang.String EXTRA_PHONE_ACCOUNT_HANDLE = "android.telecomm.extra.PHONE_ACCOUNT_HANDLE";
+    field public static final java.lang.String EXTRA_START_CALL_WITH_SPEAKERPHONE = "android.telecomm.extra.START_CALL_WITH_SPEAKERPHONE";
   }
 
 }
@@ -29049,7 +29051,7 @@
     method public boolean setCdmaSubscription(int);
     method public void setLine1NumberForDisplay(java.lang.String, java.lang.String);
     method public void setLine1NumberForDisplay(long, java.lang.String, java.lang.String);
-    method public boolean setOperatorBrandOverride(java.lang.String, java.lang.String);
+    method public boolean setOperatorBrandOverride(java.lang.String);
     method public boolean setPreferredNetworkType(int);
     field public static final java.lang.String ACTION_PHONE_STATE_CHANGED = "android.intent.action.PHONE_STATE";
     field public static final java.lang.String ACTION_RESPOND_VIA_MESSAGE = "android.intent.action.RESPOND_VIA_MESSAGE";
diff --git a/core/java/android/content/pm/IPackageInstallerCallback.aidl b/core/java/android/content/pm/IPackageInstallerCallback.aidl
index fe98ee7..974eb1e 100644
--- a/core/java/android/content/pm/IPackageInstallerCallback.aidl
+++ b/core/java/android/content/pm/IPackageInstallerCallback.aidl
@@ -20,8 +20,7 @@
 oneway interface IPackageInstallerCallback {
     void onSessionCreated(int sessionId);
     void onSessionBadgingChanged(int sessionId);
-    void onSessionOpened(int sessionId);
+    void onSessionActiveChanged(int sessionId, boolean active);
     void onSessionProgressChanged(int sessionId, float progress);
-    void onSessionClosed(int sessionId);
     void onSessionFinished(int sessionId, boolean success);
 }
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index 7c34a65..0a211cf 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -304,9 +304,12 @@
      * Open an existing session to actively perform work. To succeed, the caller
      * must be the owner of the install session.
      */
-    public @NonNull Session openSession(int sessionId) {
+    public @NonNull Session openSession(int sessionId) throws IOException {
         try {
             return new Session(mInstaller.openSession(sessionId));
+        } catch (RuntimeException e) {
+            ExceptionUtils.maybeUnwrapIOException(e);
+            throw e;
         } catch (RemoteException e) {
             throw e.rethrowAsRuntimeException();
         }
@@ -363,7 +366,7 @@
     public @NonNull List<SessionInfo> getAllSessions() {
         final ApplicationInfo info = mContext.getApplicationInfo();
         if ("com.google.android.googlequicksearchbox".equals(info.packageName)
-                && info.versionCode <= 300400070) {
+                && info.versionCode <= 300400110) {
             Log.d(TAG, "Ignoring callback request from old prebuilt");
             return Collections.EMPTY_LIST;
         }
@@ -436,27 +439,32 @@
         public abstract void onBadgingChanged(int sessionId);
 
         /**
-         * Session has been opened. A session is usually opened when the
-         * installer is actively writing data.
+         * Active state for session has been changed.
+         * <p>
+         * A session is considered active whenever there is ongoing forward
+         * progress being made, such as the installer holding an open
+         * {@link Session} instance while streaming data into place, or the
+         * system optimizing code as the result of
+         * {@link Session#commit(IntentSender)}.
+         * <p>
+         * If the installer closes the {@link Session} without committing, the
+         * session is considered inactive until the installer opens the session
+         * again.
          */
-        public abstract void onOpened(int sessionId);
+        public abstract void onActiveChanged(int sessionId, boolean active);
 
         /**
          * Progress for given session has been updated.
          * <p>
          * Note that this progress may not directly correspond to the value
-         * reported by {@link PackageInstaller.Session#setProgress(float)}, as
-         * the system may carve out a portion of the overall progress to
-         * represent its own internal installation work.
+         * reported by
+         * {@link PackageInstaller.Session#setStagingProgress(float)}, as the
+         * system may carve out a portion of the overall progress to represent
+         * its own internal installation work.
          */
         public abstract void onProgressChanged(int sessionId, float progress);
 
         /**
-         * Session has been closed.
-         */
-        public abstract void onClosed(int sessionId);
-
-        /**
          * Session has completely finished, either with success or failure.
          */
         public abstract void onFinished(int sessionId, boolean success);
@@ -467,10 +475,9 @@
             Handler.Callback {
         private static final int MSG_SESSION_CREATED = 1;
         private static final int MSG_SESSION_BADGING_CHANGED = 2;
-        private static final int MSG_SESSION_OPENED = 3;
+        private static final int MSG_SESSION_ACTIVE_CHANGED = 3;
         private static final int MSG_SESSION_PROGRESS_CHANGED = 4;
-        private static final int MSG_SESSION_CLOSED = 5;
-        private static final int MSG_SESSION_FINISHED = 6;
+        private static final int MSG_SESSION_FINISHED = 5;
 
         final SessionCallback mCallback;
         final Handler mHandler;
@@ -482,24 +489,23 @@
 
         @Override
         public boolean handleMessage(Message msg) {
+            final int sessionId = msg.arg1;
             switch (msg.what) {
                 case MSG_SESSION_CREATED:
-                    mCallback.onCreated(msg.arg1);
+                    mCallback.onCreated(sessionId);
                     return true;
                 case MSG_SESSION_BADGING_CHANGED:
-                    mCallback.onBadgingChanged(msg.arg1);
+                    mCallback.onBadgingChanged(sessionId);
                     return true;
-                case MSG_SESSION_OPENED:
-                    mCallback.onOpened(msg.arg1);
+                case MSG_SESSION_ACTIVE_CHANGED:
+                    final boolean active = msg.arg2 != 0;
+                    mCallback.onActiveChanged(sessionId, active);
                     return true;
                 case MSG_SESSION_PROGRESS_CHANGED:
-                    mCallback.onProgressChanged(msg.arg1, (float) msg.obj);
-                    return true;
-                case MSG_SESSION_CLOSED:
-                    mCallback.onClosed(msg.arg1);
+                    mCallback.onProgressChanged(sessionId, (float) msg.obj);
                     return true;
                 case MSG_SESSION_FINISHED:
-                    mCallback.onFinished(msg.arg1, msg.arg2 != 0);
+                    mCallback.onFinished(sessionId, msg.arg2 != 0);
                     return true;
             }
             return false;
@@ -516,8 +522,9 @@
         }
 
         @Override
-        public void onSessionOpened(int sessionId) {
-            mHandler.obtainMessage(MSG_SESSION_OPENED, sessionId, 0).sendToTarget();
+        public void onSessionActiveChanged(int sessionId, boolean active) {
+            mHandler.obtainMessage(MSG_SESSION_ACTIVE_CHANGED, sessionId, active ? 1 : 0)
+                    .sendToTarget();
         }
 
         @Override
@@ -527,11 +534,6 @@
         }
 
         @Override
-        public void onSessionClosed(int sessionId) {
-            mHandler.obtainMessage(MSG_SESSION_CLOSED, sessionId, 0).sendToTarget();
-        }
-
-        @Override
         public void onSessionFinished(int sessionId, boolean success) {
             mHandler.obtainMessage(MSG_SESSION_FINISHED, sessionId, success ? 1 : 0)
                     .sendToTarget();
@@ -567,7 +569,7 @@
         // TODO: remove this temporary guard once we have new prebuilts
         final ApplicationInfo info = mContext.getApplicationInfo();
         if ("com.google.android.googlequicksearchbox".equals(info.packageName)
-                && info.versionCode <= 300400070) {
+                && info.versionCode <= 300400110) {
             Log.d(TAG, "Ignoring callback request from old prebuilt");
             return;
         }
@@ -629,10 +631,22 @@
             mSession = session;
         }
 
-        /**
-         * Set current progress. Valid values are anywhere between 0 and 1.
-         */
+        /** {@hide} */
+        @Deprecated
         public void setProgress(float progress) {
+            setStagingProgress(progress);
+        }
+
+        /**
+         * Set current progress of staging this session. Valid values are
+         * anywhere between 0 and 1.
+         * <p>
+         * Note that this progress may not directly correspond to the value
+         * reported by {@link SessionCallback#onProgressChanged(int, float)}, as
+         * the system may carve out a portion of the overall progress to
+         * represent its own internal installation work.
+         */
+        public void setStagingProgress(float progress) {
             try {
                 mSession.setClientProgress(progress);
             } catch (RemoteException e) {
@@ -986,7 +1000,7 @@
         /** {@hide} */
         public boolean sealed;
         /** {@hide} */
-        public boolean open;
+        public boolean active;
 
         /** {@hide} */
         public int mode;
@@ -1010,7 +1024,7 @@
             resolvedBaseCodePath = source.readString();
             progress = source.readFloat();
             sealed = source.readInt() != 0;
-            open = source.readInt() != 0;
+            active = source.readInt() != 0;
 
             mode = source.readInt();
             sizeBytes = source.readLong();
@@ -1036,20 +1050,37 @@
         /**
          * Return current overall progress of this session, between 0 and 1.
          * <p>
-         * Note that this progress may not directly correspond to the value reported
-         * by {@link PackageInstaller.Session#setProgress(float)}, as the system may
-         * carve out a portion of the overall progress to represent its own internal
-         * installation work.
+         * Note that this progress may not directly correspond to the value
+         * reported by
+         * {@link PackageInstaller.Session#setStagingProgress(float)}, as the
+         * system may carve out a portion of the overall progress to represent
+         * its own internal installation work.
          */
         public float getProgress() {
             return progress;
         }
 
         /**
-         * Return if this session is currently open.
+         * Return if this session is currently active.
+         * <p>
+         * A session is considered active whenever there is ongoing forward
+         * progress being made, such as the installer holding an open
+         * {@link Session} instance while streaming data into place, or the
+         * system optimizing code as the result of
+         * {@link Session#commit(IntentSender)}.
+         * <p>
+         * If the installer closes the {@link Session} without committing, the
+         * session is considered inactive until the installer opens the session
+         * again.
          */
+        public boolean isActive() {
+            return active;
+        }
+
+        /** {@hide} */
+        @Deprecated
         public boolean isOpen() {
-            return open;
+            return isActive();
         }
 
         /**
@@ -1105,7 +1136,7 @@
             dest.writeString(resolvedBaseCodePath);
             dest.writeFloat(progress);
             dest.writeInt(sealed ? 1 : 0);
-            dest.writeInt(open ? 1 : 0);
+            dest.writeInt(active ? 1 : 0);
 
             dest.writeInt(mode);
             dest.writeLong(sizeBytes);
diff --git a/core/java/android/print/PrintManager.java b/core/java/android/print/PrintManager.java
index 9361286..bf8ac65 100644
--- a/core/java/android/print/PrintManager.java
+++ b/core/java/android/print/PrintManager.java
@@ -535,7 +535,7 @@
                 destroyed = isDestroyedLocked();
             }
 
-            if (destroyed) {
+            if (destroyed && observer != null) {
                 try {
                     observer.onDestroy();
                 } catch (RemoteException re) {
diff --git a/core/java/android/service/notification/INotificationListener.aidl b/core/java/android/service/notification/INotificationListener.aidl
index 8ca9b6c..e6bf6ba 100644
--- a/core/java/android/service/notification/INotificationListener.aidl
+++ b/core/java/android/service/notification/INotificationListener.aidl
@@ -16,6 +16,7 @@
 
 package android.service.notification;
 
+import android.service.notification.IStatusBarNotificationHolder;
 import android.service.notification.StatusBarNotification;
 import android.service.notification.NotificationRankingUpdate;
 
@@ -23,9 +24,9 @@
 oneway interface INotificationListener
 {
     void onListenerConnected(in NotificationRankingUpdate update);
-    void onNotificationPosted(in StatusBarNotification notification,
+    void onNotificationPosted(in IStatusBarNotificationHolder notificationHolder,
             in NotificationRankingUpdate update);
-    void onNotificationRemoved(in StatusBarNotification notification,
+    void onNotificationRemoved(in IStatusBarNotificationHolder notificationHolder,
             in NotificationRankingUpdate update);
     void onNotificationRankingUpdate(in NotificationRankingUpdate update);
     void onListenerHintsChanged(int hints);
diff --git a/core/java/android/service/notification/IStatusBarNotificationHolder.aidl b/core/java/android/service/notification/IStatusBarNotificationHolder.aidl
new file mode 100644
index 0000000..fd6b59e
--- /dev/null
+++ b/core/java/android/service/notification/IStatusBarNotificationHolder.aidl
@@ -0,0 +1,24 @@
+/**
+ * Copyright (c) 2014, 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.service.notification;
+
+import android.service.notification.StatusBarNotification;
+
+/** @hide */
+interface IStatusBarNotificationHolder {
+    StatusBarNotification get();
+}
diff --git a/core/java/android/service/notification/NotificationListenerService.java b/core/java/android/service/notification/NotificationListenerService.java
index 2ca8098..d744070 100644
--- a/core/java/android/service/notification/NotificationListenerService.java
+++ b/core/java/android/service/notification/NotificationListenerService.java
@@ -603,8 +603,15 @@
 
     private class INotificationListenerWrapper extends INotificationListener.Stub {
         @Override
-        public void onNotificationPosted(StatusBarNotification sbn,
+        public void onNotificationPosted(IStatusBarNotificationHolder sbnHolder,
                 NotificationRankingUpdate update) {
+            StatusBarNotification sbn;
+            try {
+                sbn = sbnHolder.get();
+            } catch (RemoteException e) {
+                Log.w(TAG, "onNotificationPosted: Error receiving StatusBarNotification", e);
+                return;
+            }
             Notification.Builder.rebuild(getContext(), sbn.getNotification());
 
             // protect subclass from concurrent modifications of (@link mNotificationKeys}.
@@ -618,8 +625,15 @@
             }
         }
         @Override
-        public void onNotificationRemoved(StatusBarNotification sbn,
+        public void onNotificationRemoved(IStatusBarNotificationHolder sbnHolder,
                 NotificationRankingUpdate update) {
+            StatusBarNotification sbn;
+            try {
+                sbn = sbnHolder.get();
+            } catch (RemoteException e) {
+                Log.w(TAG, "onNotificationRemoved: Error receiving StatusBarNotification", e);
+                return;
+            }
             // protect subclass from concurrent modifications of (@link mNotificationKeys}.
             synchronized (mWrapper) {
                 applyUpdate(update);
diff --git a/core/java/android/view/RenderNode.java b/core/java/android/view/RenderNode.java
index 9dc9766..47f72a8 100644
--- a/core/java/android/view/RenderNode.java
+++ b/core/java/android/view/RenderNode.java
@@ -367,6 +367,10 @@
         throw new IllegalArgumentException("Unrecognized outline?");
     }
 
+    public boolean hasShadow() {
+        return nHasShadow(mNativeRenderNode);
+    }
+
     /**
      * Enables or disables clipping to the outline.
      *
@@ -861,6 +865,7 @@
             float alpha);
     private static native boolean nSetOutlineEmpty(long renderNode);
     private static native boolean nSetOutlineNone(long renderNode);
+    private static native boolean nHasShadow(long renderNode);
     private static native boolean nSetClipToOutline(long renderNode, boolean clipToOutline);
     private static native boolean nSetRevealClip(long renderNode,
             boolean shouldClip, float x, float y, float radius);
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 92ad4e8..770e78c 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -10224,6 +10224,7 @@
      *
      * @return true if the content in this view might overlap, false otherwise.
      */
+    @ViewDebug.ExportedProperty(category = "drawing")
     public boolean hasOverlappingRendering() {
         return true;
     }
@@ -10926,6 +10927,17 @@
         invalidateViewProperty(false, false);
     }
 
+    /**
+     * HierarchyViewer only
+     *
+     * @hide
+     */
+    @ViewDebug.ExportedProperty(category = "drawing")
+    public boolean hasShadow() {
+        return mRenderNode.hasShadow();
+    }
+
+
     /** @hide */
     public void setRevealClip(boolean shouldClip, float x, float y, float radius) {
         mRenderNode.setRevealClip(shouldClip, x, y, radius);
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 974fe4e..ac1b6a9 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -3301,6 +3301,7 @@
      * @return True if the group's children will be clipped to their bounds,
      * false otherwise.
      */
+    @ViewDebug.ExportedProperty(category = "drawing")
     public boolean getClipChildren() {
         return ((mGroupFlags & FLAG_CLIP_CHILDREN) != 0);
     }
@@ -3349,6 +3350,7 @@
      *
      * @attr ref android.R.styleable#ViewGroup_clipToPadding
      */
+    @ViewDebug.ExportedProperty(category = "drawing")
     public boolean getClipToPadding() {
         return hasBooleanFlag(FLAG_CLIP_TO_PADDING);
     }
diff --git a/core/jni/android_view_RenderNode.cpp b/core/jni/android_view_RenderNode.cpp
index 949f4ff..050037e 100644
--- a/core/jni/android_view_RenderNode.cpp
+++ b/core/jni/android_view_RenderNode.cpp
@@ -173,6 +173,12 @@
     return true;
 }
 
+static jboolean android_view_RenderNode_hasShadow(JNIEnv* env,
+        jobject clazz, jlong renderNodePtr) {
+    RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
+    return renderNode->stagingProperties().hasShadow();
+}
+
 static jboolean android_view_RenderNode_setClipToOutline(JNIEnv* env,
         jobject clazz, jlong renderNodePtr, jboolean clipToOutline) {
     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
@@ -491,6 +497,7 @@
     { "nSetOutlineConvexPath", "(JJF)Z", (void*) android_view_RenderNode_setOutlineConvexPath },
     { "nSetOutlineEmpty",      "(J)Z",   (void*) android_view_RenderNode_setOutlineEmpty },
     { "nSetOutlineNone",       "(J)Z",   (void*) android_view_RenderNode_setOutlineNone },
+    { "nHasShadow",            "(J)Z",   (void*) android_view_RenderNode_hasShadow },
     { "nSetClipToOutline",     "(JZ)Z",  (void*) android_view_RenderNode_setClipToOutline },
     { "nSetRevealClip",        "(JZFFF)Z", (void*) android_view_RenderNode_setRevealClip },
 
diff --git a/core/jni/android_view_ThreadedRenderer.cpp b/core/jni/android_view_ThreadedRenderer.cpp
index 7e6d335..a8edb77 100644
--- a/core/jni/android_view_ThreadedRenderer.cpp
+++ b/core/jni/android_view_ThreadedRenderer.cpp
@@ -158,9 +158,11 @@
 
     // Marks the start of a frame, which will update the frame time and move all
     // next frame animations into the current frame
-    virtual void startFrame() {
-        mRootNode->doAttachAnimatingNodes(this);
-        AnimationContext::startFrame();
+    virtual void startFrame(TreeInfo::TraversalMode mode) {
+        if (mode == TreeInfo::MODE_FULL) {
+            mRootNode->doAttachAnimatingNodes(this);
+        }
+        AnimationContext::startFrame(mode);
     }
 
     // Runs any animations still left in mCurrentFrameAnimations
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 7c5233c..72dd930 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -182,11 +182,11 @@
     <protected-broadcast android:name="android.hardware.usb.action.USB_DEVICE_DETACHED" />
 
     <protected-broadcast android:name="android.intent.action.HEADSET_PLUG" />
-    <protected-broadcast android:name="android.intent.action.ANALOG_AUDIO_DOCK_PLUG" />
-    <protected-broadcast android:name="android.intent.action.DIGITAL_AUDIO_DOCK_PLUG" />
-    <protected-broadcast android:name="android.intent.action.HDMI_AUDIO_PLUG" />
-    <protected-broadcast android:name="android.intent.action.USB_AUDIO_ACCESSORY_PLUG" />
-    <protected-broadcast android:name="android.intent.action.USB_AUDIO_DEVICE_PLUG" />
+    <protected-broadcast android:name="android.media.action.ANALOG_AUDIO_DOCK_PLUG" />
+    <protected-broadcast android:name="android.media.action.DIGITAL_AUDIO_DOCK_PLUG" />
+    <protected-broadcast android:name="android.media.action.HDMI_AUDIO_PLUG" />
+    <protected-broadcast android:name="android.media.action.USB_AUDIO_ACCESSORY_PLUG" />
+    <protected-broadcast android:name="android.media.action.USB_AUDIO_DEVICE_PLUG" />
 
     <protected-broadcast android:name="android.media.AUDIO_BECOMING_NOISY" />
     <protected-broadcast android:name="android.media.RINGER_MODE_CHANGED" />
diff --git a/core/res/res/values/colors_material.xml b/core/res/res/values/colors_material.xml
index d8e14a0..939cbf1 100644
--- a/core/res/res/values/colors_material.xml
+++ b/core/res/res/values/colors_material.xml
@@ -19,8 +19,8 @@
     <color name="background_material_dark">#ff212121</color>
     <color name="background_material_light">#fffafafa</color>
 
-    <color name="ripple_material_light">#20444444</color>
-    <color name="ripple_material_dark">#20ffffff</color>
+    <color name="ripple_material_light">#40000000</color>
+    <color name="ripple_material_dark">#40ffffff</color>
 
     <color name="button_material_dark">#ff5a595b</color>
     <color name="button_material_light">#ffd6d7d7</color>
diff --git a/graphics/java/android/graphics/drawable/Ripple.java b/graphics/java/android/graphics/drawable/Ripple.java
index 43922b8..6f95f91 100644
--- a/graphics/java/android/graphics/drawable/Ripple.java
+++ b/graphics/java/android/graphics/drawable/Ripple.java
@@ -22,6 +22,7 @@
 import android.animation.TimeInterpolator;
 import android.graphics.Canvas;
 import android.graphics.CanvasProperty;
+import android.graphics.Color;
 import android.graphics.Paint;
 import android.graphics.Paint.Style;
 import android.graphics.Rect;
@@ -58,7 +59,7 @@
     private final Rect mBounds;
 
     /** Full-opacity color for drawing this ripple. */
-    private int mColor;
+    private int mColorOpaque;
 
     /** Maximum ripple radius. */
     private float mOuterRadius;
@@ -120,7 +121,7 @@
     }
 
     public void setup(int maxRadius, int color, float density) {
-        mColor = color | 0xFF000000;
+        mColorOpaque = color | 0xFF000000;
 
         if (maxRadius != RippleDrawable.RADIUS_AUTO) {
             mHasMaxRadius = true;
@@ -236,6 +237,9 @@
         if (N > 0) {
             cancelHardwareAnimations(false);
 
+            // We canceled old animations, but we're about to run new ones.
+            mHardwareAnimating = true;
+
             for (int i = 0; i < N; i++) {
                 pendingAnimations.get(i).setTarget(c);
                 pendingAnimations.get(i).start();
@@ -253,9 +257,8 @@
     private boolean drawSoftware(Canvas c, Paint p) {
         boolean hasContent = false;
 
-        // Cache the paint alpha so we can restore it later.
-        final int paintAlpha = p.getAlpha();
-        final int alpha = (int) (paintAlpha * mOpacity + 0.5f);
+        p.setColor(mColorOpaque);
+        final int alpha = (int) (255 * mOpacity + 0.5f);
         final float radius = MathUtils.lerp(0, mOuterRadius, mTweenRadius);
         if (alpha > 0 && radius > 0) {
             final float x = MathUtils.lerp(
@@ -268,8 +271,6 @@
             hasContent = true;
         }
 
-        p.setAlpha(paintAlpha);
-
         return hasContent;
     }
 
@@ -369,7 +370,7 @@
         final float startRadius = MathUtils.lerp(0, mOuterRadius, mTweenRadius);
         final Paint paint = getTempPaint();
         paint.setAntiAlias(true);
-        paint.setColor(mColor);
+        paint.setColor(mColorOpaque);
         paint.setAlpha((int) (255 * mOpacity + 0.5f));
         paint.setStyle(Style.FILL);
         mPropPaint = CanvasProperty.createPaint(paint);
@@ -402,6 +403,12 @@
 
         mHardwareAnimating = true;
 
+        // Set up the software values to match the hardware end values.
+        mOpacity = 0;
+        mTweenX = 1;
+        mTweenY = 1;
+        mTweenRadius = 1;
+
         invalidateSelf();
     }
 
@@ -412,7 +419,7 @@
     public void jump() {
         mCanceled = true;
         endSoftwareAnimations();
-        endHardwareAnimations();
+        cancelHardwareAnimations(true);
         mCanceled = false;
     }
 
@@ -438,24 +445,6 @@
         }
     }
 
-    private void endHardwareAnimations() {
-        final ArrayList<RenderNodeAnimator> runningAnimations = mRunningAnimations;
-        final int N = runningAnimations.size();
-        for (int i = 0; i < N; i++) {
-            runningAnimations.get(i).end();
-        }
-        runningAnimations.clear();
-
-        // Abort any pending animations. Since we always have a completion
-        // listener on a pending animation, we also need to remove ourselves.
-        if (!mPendingAnimations.isEmpty()) {
-            mPendingAnimations.clear();
-            removeSelf();
-        }
-
-        mHardwareAnimating = false;
-    }
-
     private Paint getTempPaint() {
         if (mTempPaint == null) {
             mTempPaint = new Paint();
diff --git a/graphics/java/android/graphics/drawable/RippleBackground.java b/graphics/java/android/graphics/drawable/RippleBackground.java
index 80ecea3..bc6f5fb 100644
--- a/graphics/java/android/graphics/drawable/RippleBackground.java
+++ b/graphics/java/android/graphics/drawable/RippleBackground.java
@@ -22,6 +22,7 @@
 import android.animation.TimeInterpolator;
 import android.graphics.Canvas;
 import android.graphics.CanvasProperty;
+import android.graphics.Color;
 import android.graphics.Paint;
 import android.graphics.Paint.Style;
 import android.graphics.Rect;
@@ -46,8 +47,6 @@
     private static final float WAVE_OUTER_SIZE_INFLUENCE_MAX = 200f;
     private static final float WAVE_OUTER_SIZE_INFLUENCE_MIN = 40f;
 
-    private static final long RIPPLE_ENTER_DELAY = 80;
-
     // Hardware animators.
     private final ArrayList<RenderNodeAnimator> mRunningAnimations =
             new ArrayList<RenderNodeAnimator>();
@@ -60,7 +59,10 @@
     private final Rect mBounds;
 
     /** Full-opacity color for drawing this ripple. */
-    private int mColor;
+    private int mColorOpaque;
+
+    /** Maximum alpha value for drawing this ripple. */
+    private int mColorAlpha;
 
     /** Maximum ripple radius. */
     private float mOuterRadius;
@@ -103,7 +105,8 @@
     }
 
     public void setup(int maxRadius, int color, float density) {
-        mColor = color | 0xFF000000;
+        mColorOpaque = color | 0xFF000000;
+        mColorAlpha = Color.alpha(color);
 
         if (maxRadius != RippleDrawable.RADIUS_AUTO) {
             mHasMaxRadius = true;
@@ -159,6 +162,11 @@
         return hasContent;
     }
 
+    public boolean shouldDraw() {
+        final int outerAlpha = (int) (mColorAlpha * mOuterOpacity + 0.5f);
+        return mCanUseHardware && mHardwareAnimating || outerAlpha > 0 && mOuterRadius > 0;
+    }
+
     private boolean drawHardware(HardwareCanvas c) {
         // If we have any pending hardware animations, cancel any running
         // animations and start those now.
@@ -167,6 +175,9 @@
         if (N > 0) {
             cancelHardwareAnimations(false);
 
+            // We canceled old animations, but we're about to run new ones.
+            mHardwareAnimating = true;
+
             for (int i = 0; i < N; i++) {
                 pendingAnimations.get(i).setTarget(c);
                 pendingAnimations.get(i).start();
@@ -184,10 +195,8 @@
     private boolean drawSoftware(Canvas c, Paint p) {
         boolean hasContent = false;
 
-        // Cache the paint alpha so we can restore it later.
-        final int paintAlpha = p.getAlpha();
-
-        final int outerAlpha = (int) (paintAlpha * mOuterOpacity + 0.5f);
+        p.setColor(mColorOpaque);
+        final int outerAlpha = (int) (mColorAlpha * mOuterOpacity + 0.5f);
         if (outerAlpha > 0 && mOuterRadius > 0) {
             p.setAlpha(outerAlpha);
             p.setStyle(Style.FILL);
@@ -195,8 +204,6 @@
             hasContent = true;
         }
 
-        p.setAlpha(paintAlpha);
-
         return hasContent;
     }
 
@@ -248,25 +255,25 @@
         // Determine at what time the inner and outer opacity intersect.
         // inner(t) = mOpacity - t * WAVE_OPACITY_DECAY_VELOCITY / 1000
         // outer(t) = mOuterOpacity + t * WAVE_OUTER_OPACITY_VELOCITY / 1000
-        final int outerInflection = Math.max(0, (int) (1000 * (1 - mOuterOpacity)
+        final int inflectionDuration = Math.max(0, (int) (1000 * (1 - mOuterOpacity)
                 / (WAVE_OPACITY_DECAY_VELOCITY + outerOpacityVelocity) + 0.5f));
-        final int inflectionOpacity = (int) (255 * (mOuterOpacity + outerInflection
-                * outerOpacityVelocity * outerSizeInfluence / 1000) + 0.5f);
+        final int inflectionOpacity = (int) (mColorAlpha * (mOuterOpacity
+                + inflectionDuration * outerOpacityVelocity * outerSizeInfluence / 1000) + 0.5f);
 
         if (mCanUseHardware) {
-            exitHardware(opacityDuration, outerInflection, inflectionOpacity);
+            exitHardware(opacityDuration, inflectionDuration, inflectionOpacity);
         } else {
-            exitSoftware(opacityDuration, outerInflection, inflectionOpacity);
+            exitSoftware(opacityDuration, inflectionDuration, inflectionOpacity);
         }
     }
 
-    private void exitHardware(int opacityDuration, int outerInflection, int inflectionOpacity) {
+    private void exitHardware(int opacityDuration, int inflectionDuration, int inflectionOpacity) {
         mPendingAnimations.clear();
 
         final Paint outerPaint = getTempPaint();
         outerPaint.setAntiAlias(true);
-        outerPaint.setColor(mColor);
-        outerPaint.setAlpha((int) (255 * mOuterOpacity + 0.5f));
+        outerPaint.setColor(mColorOpaque);
+        outerPaint.setAlpha((int) (mColorAlpha * mOuterOpacity + 0.5f));
         outerPaint.setStyle(Style.FILL);
         mPropOuterPaint = CanvasProperty.createPaint(outerPaint);
         mPropOuterRadius = CanvasProperty.createFloat(mOuterRadius);
@@ -274,21 +281,21 @@
         mPropOuterY = CanvasProperty.createFloat(mOuterY);
 
         final RenderNodeAnimator outerOpacityAnim;
-        if (outerInflection > 0) {
+        if (inflectionDuration > 0) {
             // Outer opacity continues to increase for a bit.
-            outerOpacityAnim = new RenderNodeAnimator(
-                    mPropOuterPaint, RenderNodeAnimator.PAINT_ALPHA, inflectionOpacity);
-            outerOpacityAnim.setDuration(outerInflection);
+            outerOpacityAnim = new RenderNodeAnimator(mPropOuterPaint,
+                    RenderNodeAnimator.PAINT_ALPHA, inflectionOpacity);
+            outerOpacityAnim.setDuration(inflectionDuration);
             outerOpacityAnim.setInterpolator(LINEAR_INTERPOLATOR);
 
             // Chain the outer opacity exit animation.
-            final int outerDuration = opacityDuration - outerInflection;
+            final int outerDuration = opacityDuration - inflectionDuration;
             if (outerDuration > 0) {
                 final RenderNodeAnimator outerFadeOutAnim = new RenderNodeAnimator(
                         mPropOuterPaint, RenderNodeAnimator.PAINT_ALPHA, 0);
                 outerFadeOutAnim.setDuration(outerDuration);
                 outerFadeOutAnim.setInterpolator(LINEAR_INTERPOLATOR);
-                outerFadeOutAnim.setStartDelay(outerInflection);
+                outerFadeOutAnim.setStartDelay(inflectionDuration);
                 outerFadeOutAnim.setStartValue(inflectionOpacity);
                 outerFadeOutAnim.addListener(mAnimationListener);
 
@@ -320,7 +327,7 @@
      */
     public void jump() {
         endSoftwareAnimations();
-        endHardwareAnimations();
+        cancelHardwareAnimations(true);
     }
 
     private void endSoftwareAnimations() {
@@ -330,23 +337,6 @@
         }
     }
 
-    private void endHardwareAnimations() {
-        final ArrayList<RenderNodeAnimator> runningAnimations = mRunningAnimations;
-        final int N = runningAnimations.size();
-        for (int i = 0; i < N; i++) {
-            runningAnimations.get(i).end();
-        }
-        runningAnimations.clear();
-
-        // Abort any pending animations. Since we always have a completion
-        // listener on a pending animation, we also need to remove ourselves.
-        if (!mPendingAnimations.isEmpty()) {
-            mPendingAnimations.clear();
-        }
-
-        mHardwareAnimating = false;
-    }
-
     private Paint getTempPaint() {
         if (mTempPaint == null) {
             mTempPaint = new Paint();
@@ -354,18 +344,18 @@
         return mTempPaint;
     }
 
-    private void exitSoftware(int opacityDuration, int outerInflection, int inflectionOpacity) {
+    private void exitSoftware(int opacityDuration, int inflectionDuration, int inflectionOpacity) {
         final ObjectAnimator outerOpacityAnim;
-        if (outerInflection > 0) {
+        if (inflectionDuration > 0) {
             // Outer opacity continues to increase for a bit.
             outerOpacityAnim = ObjectAnimator.ofFloat(this,
                     "outerOpacity", inflectionOpacity / 255.0f);
             outerOpacityAnim.setAutoCancel(true);
-            outerOpacityAnim.setDuration(outerInflection);
+            outerOpacityAnim.setDuration(inflectionDuration);
             outerOpacityAnim.setInterpolator(LINEAR_INTERPOLATOR);
 
             // Chain the outer opacity exit animation.
-            final int outerDuration = opacityDuration - outerInflection;
+            final int outerDuration = opacityDuration - inflectionDuration;
             if (outerDuration > 0) {
                 outerOpacityAnim.addListener(new AnimatorListenerAdapter() {
                     @Override
@@ -446,14 +436,4 @@
             mHardwareAnimating = false;
         }
     };
-
-    /**
-    * Interpolator with a smooth log deceleration
-    */
-    private static final class LogInterpolator implements TimeInterpolator {
-        @Override
-        public float getInterpolation(float input) {
-            return 1 - (float) Math.pow(400, -input * 1.4);
-        }
-    }
 }
diff --git a/graphics/java/android/graphics/drawable/RippleDrawable.java b/graphics/java/android/graphics/drawable/RippleDrawable.java
index fa762b7..b05fb61 100644
--- a/graphics/java/android/graphics/drawable/RippleDrawable.java
+++ b/graphics/java/android/graphics/drawable/RippleDrawable.java
@@ -242,7 +242,7 @@
 
     @Override
     protected boolean onStateChange(int[] stateSet) {
-        super.onStateChange(stateSet);
+        final boolean changed = super.onStateChange(stateSet);
 
         boolean enabled = false;
         boolean pressed = false;
@@ -263,19 +263,7 @@
         setRippleActive(enabled && pressed);
         setBackgroundActive(focused || (enabled && pressed));
 
-        // Update the paint color. Only applicable when animated in software.
-        if (mRipplePaint != null && mState.mColor != null) {
-            final ColorStateList stateList = mState.mColor;
-            final int newColor = stateList.getColorForState(stateSet, 0);
-            final int oldColor = mRipplePaint.getColor();
-            if (oldColor != newColor) {
-                mRipplePaint.setColor(newColor);
-                invalidateSelf();
-                return true;
-            }
-        }
-
-        return false;
+        return changed;
     }
 
     private void setRippleActive(boolean active) {
@@ -587,6 +575,10 @@
             ripples[i].onHotspotBoundsChanged();
         }
 
+        if (mRipple != null) {
+            mRipple.onHotspotBoundsChanged();
+        }
+
         if (mBackground != null) {
             mBackground.onHotspotBoundsChanged();
         }
@@ -617,17 +609,23 @@
         final boolean drawNonMaskContent = mLayerState.mNum > (hasMask ? 1 : 0);
         final boolean drawMask = hasMask && mMask.getOpacity() != PixelFormat.OPAQUE;
         final Rect bounds = getDirtyBounds();
+        final int saveCount = canvas.save(Canvas.CLIP_SAVE_FLAG);
+        canvas.clipRect(bounds);
 
         // If we have content, draw it into a layer first.
-        final int contentLayer = drawNonMaskContent ?
-                drawContentLayer(canvas, bounds, SRC_OVER) : -1;
+        final int contentLayer;
+        if (drawNonMaskContent) {
+            contentLayer = drawContentLayer(canvas, bounds, SRC_OVER);
+        } else {
+            contentLayer = -1;
+        }
 
         // Next, try to draw the ripples (into a layer if necessary). If we need
         // to mask against the underlying content, set the xfermode to SRC_ATOP.
         final PorterDuffXfermode xfermode = (hasMask || !drawNonMaskContent) ? SRC_OVER : SRC_ATOP;
 
         // If we have a background and a non-opaque mask, draw the masking layer.
-        final int backgroundLayer = drawBackgroundLayer(canvas, bounds, xfermode);
+        final int backgroundLayer = drawBackgroundLayer(canvas, bounds, xfermode, drawMask);
         if (backgroundLayer >= 0) {
             if (drawMask) {
                 drawMaskingLayer(canvas, bounds, DST_IN);
@@ -644,10 +642,13 @@
             canvas.restoreToCount(rippleLayer);
         }
 
-        // Composite the layers if needed.
-        if (contentLayer >= 0) {
-            canvas.restoreToCount(contentLayer);
+        // If we failed to draw anything, at least draw a color so that
+        // invalidation works correctly.
+        if (contentLayer < 0 && backgroundLayer < 0 && rippleLayer < 0) {
+            canvas.drawColor(Color.TRANSPARENT);
         }
+
+        canvas.restoreToCount(saveCount);
     }
 
     /**
@@ -711,81 +712,29 @@
         return restoreToCount;
     }
 
-    private int drawBackgroundLayer(Canvas canvas, Rect bounds, PorterDuffXfermode mode) {
-        // Separate the ripple color and alpha channel. The alpha will be
-        // applied when we merge the ripples down to the canvas.
-        final int rippleARGB;
-        if (mState.mColor != null) {
-            rippleARGB = mState.mColor.getColorForState(getState(), Color.TRANSPARENT);
-        } else {
-            rippleARGB = Color.TRANSPARENT;
+    private int drawBackgroundLayer(
+            Canvas canvas, Rect bounds, PorterDuffXfermode mode, boolean drawMask) {
+        int saveCount = -1;
+
+        if (mBackground != null && mBackground.shouldDraw()) {
+            // TODO: We can avoid saveLayer here if we push the xfermode into
+            // the background's render thread animator at exit() time.
+            if (drawMask || mode != SRC_OVER) {
+                saveCount = canvas.saveLayer(bounds.left, bounds.top, bounds.right,
+                        bounds.bottom, getMaskingPaint(mode));
+            }
+
+            final float x = mHotspotBounds.exactCenterX();
+            final float y = mHotspotBounds.exactCenterY();
+            canvas.translate(x, y);
+            mBackground.draw(canvas, getRipplePaint());
+            canvas.translate(-x, -y);
         }
 
-        if (mRipplePaint == null) {
-            mRipplePaint = new Paint();
-            mRipplePaint.setAntiAlias(true);
-        }
-
-        final int rippleAlpha = Color.alpha(rippleARGB);
-        final Paint ripplePaint = mRipplePaint;
-        ripplePaint.setColor(rippleARGB);
-        ripplePaint.setAlpha(0xFF);
-
-        boolean drewRipples = false;
-        int restoreToCount = -1;
-        int restoreTranslate = -1;
-
-        // Draw background.
-        final RippleBackground background = mBackground;
-        if (background != null) {
-            // If we're masking the ripple layer, make sure we have a layer
-            // first. This will merge SRC_OVER (directly) onto the canvas.
-            final Paint maskingPaint = getMaskingPaint(mode);
-            maskingPaint.setAlpha(rippleAlpha);
-            restoreToCount = canvas.saveLayer(bounds.left, bounds.top,
-                    bounds.right, bounds.bottom, maskingPaint);
-
-            restoreTranslate = canvas.save();
-            // Translate the canvas to the current hotspot bounds.
-            canvas.translate(mHotspotBounds.exactCenterX(), mHotspotBounds.exactCenterY());
-
-            drewRipples = background.draw(canvas, ripplePaint);
-        }
-
-        // Always restore the translation.
-        if (restoreTranslate >= 0) {
-            canvas.restoreToCount(restoreTranslate);
-        }
-
-        // If we created a layer with no content, merge it immediately.
-        if (restoreToCount >= 0 && !drewRipples) {
-            canvas.restoreToCount(restoreToCount);
-            restoreToCount = -1;
-        }
-
-        return restoreToCount;
+        return saveCount;
     }
 
     private int drawRippleLayer(Canvas canvas, Rect bounds, PorterDuffXfermode mode) {
-        // Separate the ripple color and alpha channel. The alpha will be
-        // applied when we merge the ripples down to the canvas.
-        final int rippleARGB;
-        if (mState.mColor != null) {
-            rippleARGB = mState.mColor.getColorForState(getState(), Color.TRANSPARENT);
-        } else {
-            rippleARGB = Color.TRANSPARENT;
-        }
-
-        if (mRipplePaint == null) {
-            mRipplePaint = new Paint();
-            mRipplePaint.setAntiAlias(true);
-        }
-
-        final int rippleAlpha = Color.alpha(rippleARGB);
-        final Paint ripplePaint = mRipplePaint;
-        ripplePaint.setColor(rippleARGB);
-        ripplePaint.setAlpha(0xFF);
-
         boolean drewRipples = false;
         int restoreToCount = -1;
         int restoreTranslate = -1;
@@ -807,16 +756,21 @@
             // first. This will merge SRC_OVER (directly) onto the canvas.
             if (restoreToCount < 0) {
                 final Paint maskingPaint = getMaskingPaint(mode);
-                maskingPaint.setAlpha(rippleAlpha);
+                final int color = mState.mColor.getColorForState(getState(), Color.TRANSPARENT);
+                final int alpha = Color.alpha(color);
+                maskingPaint.setAlpha(alpha / 2);
+
+                // TODO: We can avoid saveLayer here if we're only drawing one
+                // ripple and we don't have content or a translucent mask.
                 restoreToCount = canvas.saveLayer(bounds.left, bounds.top,
                         bounds.right, bounds.bottom, maskingPaint);
 
-                restoreTranslate = canvas.save();
                 // Translate the canvas to the current hotspot bounds.
+                restoreTranslate = canvas.save();
                 canvas.translate(mHotspotBounds.exactCenterX(), mHotspotBounds.exactCenterY());
             }
 
-            drewRipples |= ripple.draw(canvas, ripplePaint);
+            drewRipples |= ripple.draw(canvas, getRipplePaint());
         }
 
         // Always restore the translation.
@@ -845,6 +799,14 @@
         return restoreToCount;
     }
 
+    private Paint getRipplePaint() {
+        if (mRipplePaint == null) {
+            mRipplePaint = new Paint();
+            mRipplePaint.setAntiAlias(true);
+        }
+        return mRipplePaint;
+    }
+
     private Paint getMaskingPaint(PorterDuffXfermode xfermode) {
         if (mMaskingPaint == null) {
             mMaskingPaint = new Paint();
diff --git a/libs/hwui/AnimationContext.cpp b/libs/hwui/AnimationContext.cpp
index 716dcf5..a20bdae 100644
--- a/libs/hwui/AnimationContext.cpp
+++ b/libs/hwui/AnimationContext.cpp
@@ -17,7 +17,6 @@
 
 #include "Animator.h"
 #include "RenderNode.h"
-#include "TreeInfo.h"
 #include "renderthread/TimeLord.h"
 
 namespace android {
@@ -34,7 +33,7 @@
 }
 
 void AnimationContext::destroy() {
-    startFrame();
+    startFrame(TreeInfo::MODE_RT_ONLY);
     while (mCurrentFrameAnimations.mNextHandle) {
         AnimationHandle* current = mCurrentFrameAnimations.mNextHandle;
         AnimatorManager& animators = current->mRenderNode->animators();
@@ -55,7 +54,7 @@
     handle->insertAfter(&mNextFrameAnimations);
 }
 
-void AnimationContext::startFrame() {
+void AnimationContext::startFrame(TreeInfo::TraversalMode mode) {
     LOG_ALWAYS_FATAL_IF(mCurrentFrameAnimations.mNextHandle,
             "Missed running animations last frame!");
     AnimationHandle* head = mNextFrameAnimations.mNextHandle;
diff --git a/libs/hwui/AnimationContext.h b/libs/hwui/AnimationContext.h
index 9b3d5f4..909ed36 100644
--- a/libs/hwui/AnimationContext.h
+++ b/libs/hwui/AnimationContext.h
@@ -20,6 +20,7 @@
 #include <utils/RefBase.h>
 #include <utils/StrongPointer.h>
 
+#include "TreeInfo.h"
 #include "renderthread/TimeLord.h"
 #include "utils/Macros.h"
 
@@ -30,7 +31,6 @@
 class AnimationListener;
 class BaseRenderNodeAnimator;
 class RenderNode;
-class TreeInfo;
 
 /*
  * AnimationHandle is several classes merged into one.
@@ -90,7 +90,7 @@
 
     // Marks the start of a frame, which will update the frame time and move all
     // next frame animations into the current frame
-    ANDROID_API virtual void startFrame();
+    ANDROID_API virtual void startFrame(TreeInfo::TraversalMode mode);
 
     // Runs any animations still left in mCurrentFrameAnimations that were not run
     // as part of the standard RenderNode:prepareTree pass.
diff --git a/libs/hwui/RenderProperties.h b/libs/hwui/RenderProperties.h
index 0c8d07f..46eeb6a 100644
--- a/libs/hwui/RenderProperties.h
+++ b/libs/hwui/RenderProperties.h
@@ -569,6 +569,10 @@
         return getClipToBounds() && (getZ() <= 0 || getOutline().isEmpty());
     }
 
+    bool hasShadow() const {
+        return getZ() >= 0.0f && getOutline().getPath() != NULL;
+    }
+
 private:
     // Rendering properties
     struct PrimitiveFields {
diff --git a/libs/hwui/RenderState.cpp b/libs/hwui/RenderState.cpp
index a7c5e85..ec8307f 100644
--- a/libs/hwui/RenderState.cpp
+++ b/libs/hwui/RenderState.cpp
@@ -38,6 +38,7 @@
 }
 
 void RenderState::onGLContextDestroyed() {
+    AutoMutex _lock(mLayerLock);
     if (CC_UNLIKELY(!mActiveLayers.empty())) {
         mCaches->dumpMemoryUsage();
         for (std::set<renderthread::CanvasContext*>::iterator cit = mRegisteredContexts.begin();
@@ -51,6 +52,13 @@
             }
             context->mRootRenderNode->debugDumpLayers("  ");
         }
+
+        for (std::set<const Layer*>::iterator lit = mActiveLayers.begin();
+             lit != mActiveLayers.end(); lit++) {
+            const Layer* layer = *(lit);
+            ALOGD("Layer %p, fbo %d, buildlayered %d",
+                    layer, layer->getFbo(), layer->wasBuildLayered);
+        }
         LOG_ALWAYS_FATAL("layers have survived gl context destruction");
     }
 }
diff --git a/libs/hwui/RenderState.h b/libs/hwui/RenderState.h
index c7ab197..74bafca 100644
--- a/libs/hwui/RenderState.h
+++ b/libs/hwui/RenderState.h
@@ -19,6 +19,7 @@
 #include <set>
 #include <GLES2/gl2.h>
 #include <GLES2/gl2ext.h>
+#include <utils/Mutex.h>
 
 #include <private/hwui/DrawGlInfo.h>
 
@@ -52,9 +53,11 @@
     void debugOverdraw(bool enable, bool clear);
 
     void registerLayer(const Layer* layer) {
+        AutoMutex _lock(mLayerLock);
         mActiveLayers.insert(layer);
     }
     void unregisterLayer(const Layer* layer) {
+        AutoMutex _lock(mLayerLock);
         mActiveLayers.erase(layer);
     }
 
@@ -83,6 +86,7 @@
     GLsizei mViewportWidth;
     GLsizei mViewportHeight;
     GLuint mFramebuffer;
+    Mutex mLayerLock;
 };
 
 } /* namespace uirenderer */
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index 4129a89..5e6796c 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -150,7 +150,7 @@
     if (mPrefetechedLayers.size() && info.mode == TreeInfo::MODE_FULL) {
         info.canvasContext = this;
     }
-    mAnimationContext->startFrame();
+    mAnimationContext->startFrame(info.mode);
     mRootRenderNode->prepareTree(info);
     mAnimationContext->runRemainingAnimations(info);
 
diff --git a/media/java/android/media/AudioAttributes.java b/media/java/android/media/AudioAttributes.java
index 308f783..9b644f4 100644
--- a/media/java/android/media/AudioAttributes.java
+++ b/media/java/android/media/AudioAttributes.java
@@ -530,7 +530,6 @@
         }
     }
 
-    /** @hide */
     public static final Parcelable.Creator<AudioAttributes> CREATOR
             = new Parcelable.Creator<AudioAttributes>() {
         /**
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index 9ee7027..e3b8985 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -243,7 +243,7 @@
      * or unplugged.
      * An integer value of 1 indicates a plugged-in state, 0 is unplugged.
      */
-    public static final String EXTRA_AUDIO_PLUG_STATE = "android.media.extra.audio_plug_state";
+    public static final String EXTRA_AUDIO_PLUG_STATE = "android.media.extra.AUDIO_PLUG_STATE";
 
     /**
      * Extra used in {@link #ACTION_HDMI_AUDIO_PLUG} to define the maximum number of channels
@@ -251,7 +251,7 @@
      * The corresponding integer value is only available when the device is plugged in (as expressed
      * by {@link #EXTRA_AUDIO_PLUG_STATE}).
      */
-    public static final String EXTRA_MAX_CHANNEL_COUNT = "android.media.extra.max_channel_count";
+    public static final String EXTRA_MAX_CHANNEL_COUNT = "android.media.extra.MAX_CHANNEL_COUNT";
 
     /**
      * Extra used in {@link #ACTION_HDMI_AUDIO_PLUG} to define the audio encodings supported by
@@ -261,7 +261,7 @@
      * {@link AudioFormat} (for instance see {@link AudioFormat#ENCODING_PCM_16BIT}). Use
      * {@link android.content.Intent#getIntArrayExtra(String)} to retrieve the encoding values.
      */
-    public static final String EXTRA_ENCODINGS = "android.media.extra.encodings";
+    public static final String EXTRA_ENCODINGS = "android.media.extra.ENCODINGS";
 
     /**
      * Broadcast Action: An analog audio speaker/headset plugged in or unplugged.
diff --git a/media/java/android/media/MediaCodec.java b/media/java/android/media/MediaCodec.java
index 3e8ee93..675916b 100644
--- a/media/java/android/media/MediaCodec.java
+++ b/media/java/android/media/MediaCodec.java
@@ -1622,8 +1622,7 @@
      * @throws IllegalStateException if in the Uninitialized state.
      */
     public MediaCodecInfo getCodecInfo() {
-        return MediaCodecList.getCodecInfoAt(
-                   MediaCodecList.findCodecByName(getName()));
+        return MediaCodecList.getInfoFor(getName());
     }
 
     private native final ByteBuffer[] getBuffers(boolean input);
diff --git a/media/java/android/media/MediaCodecInfo.java b/media/java/android/media/MediaCodecInfo.java
index 323a3e3..01f8193 100644
--- a/media/java/android/media/MediaCodecInfo.java
+++ b/media/java/android/media/MediaCodecInfo.java
@@ -321,6 +321,9 @@
             // check feature support
             for (Feature feat: getValidFeatures()) {
                 Integer yesNo = (Integer)map.get(MediaFormat.KEY_FEATURE_ + feat.mName);
+                if (yesNo == null) {
+                    continue;
+                }
                 if ((yesNo == 1 && !isFeatureSupported(feat.mName)) ||
                         (yesNo == 0 && isFeatureRequired(feat.mName))) {
                     return false;
@@ -414,7 +417,7 @@
          * profile} and {@code level}.  If the type, or profile-level combination
          * is not understood by the framework, it returns null.
          */
-        public static CodecCapabilities CreateFromProfileLevel(
+        public static CodecCapabilities createFromProfileLevel(
                 String mime, int profile, int level) {
             CodecProfileLevel pl = new CodecProfileLevel();
             pl.profile = profile;
@@ -470,13 +473,12 @@
                 Integer yesNo = (Integer)map.get(key);
                 if (yesNo == null) {
                     continue;
-                } else if (yesNo > 0) {
-                    mFlagsRequired |= feat.mValue;
-                    mDefaultFormat.setInteger(key, 1);
-                } else {
-                    mFlagsSupported |= feat.mValue;
-                    mDefaultFormat.setInteger(key, 1);
                 }
+                if (yesNo > 0) {
+                    mFlagsRequired |= feat.mValue;
+                }
+                mFlagsSupported |= feat.mValue;
+                mDefaultFormat.setInteger(key, 1);
                 // TODO restrict features by mFlagsVerified once all codecs reliably verify them
             }
         }
diff --git a/media/java/android/media/MediaCodecList.java b/media/java/android/media/MediaCodecList.java
index 5084c5c..85e9b16 100644
--- a/media/java/android/media/MediaCodecList.java
+++ b/media/java/android/media/MediaCodecList.java
@@ -116,6 +116,11 @@
 
     /* package private */ static native final int findCodecByName(String codec);
 
+    /** @hide */
+    public static MediaCodecInfo getInfoFor(String codec) {
+        return sAllCodecInfos[findCodecByName(codec)];
+    }
+
     private static native final void native_init();
 
     /**
diff --git a/packages/PrintSpooler/res/layout/preview_page_loading.xml b/packages/PrintSpooler/res/layout/preview_page_loading.xml
new file mode 100644
index 0000000..1af3a17
--- /dev/null
+++ b/packages/PrintSpooler/res/layout/preview_page_loading.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 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.
+-->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="fill_parent"
+    android:layout_height="fill_parent">
+
+    <ImageView
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_margin="36dip"
+        android:layout_gravity="center"
+        android:src="@drawable/ic_grayedout_printer"
+        android:contentDescription="@null"
+        android:scaleType="centerInside"
+        android:adjustViewBounds="true">
+    </ImageView>
+
+</FrameLayout>
diff --git a/packages/PrintSpooler/res/values-land/constants.xml b/packages/PrintSpooler/res/values-land/constants.xml
index 6cf9754b5..84fc050 100644
--- a/packages/PrintSpooler/res/values-land/constants.xml
+++ b/packages/PrintSpooler/res/values-land/constants.xml
@@ -16,7 +16,7 @@
 
 <resources>
 
-    <integer name="preview_page_per_row_count">2</integer>
+    <integer name="preview_page_per_row_count">4</integer>
 
     <integer name="print_option_column_count">3</integer>
 
diff --git a/packages/PrintSpooler/res/values/strings.xml b/packages/PrintSpooler/res/values/strings.xml
index 5b7fda3..27e1d51 100644
--- a/packages/PrintSpooler/res/values/strings.xml
+++ b/packages/PrintSpooler/res/values/strings.xml
@@ -76,7 +76,6 @@
     <!-- Title for the print dialog announced to the user for accessibility. Not shown in the UI. [CHAR LIMIT=none] -->
     <string name="print_dialog">Print dialog</string>
 
-
     <!-- Template for the message that shows the current page out of the total number of pages -->
     <string name="current_page_template"><xliff:g id="current_page">%1$d</xliff:g>
         /<xliff:g id="page_count">%2$d</xliff:g></string>
diff --git a/packages/PrintSpooler/src/com/android/printspooler/model/RemotePrintDocument.java b/packages/PrintSpooler/src/com/android/printspooler/model/RemotePrintDocument.java
index 09e8b39..1e7a011 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/model/RemotePrintDocument.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/model/RemotePrintDocument.java
@@ -317,6 +317,11 @@
         return mState == STATE_FAILED;
     }
 
+    public boolean hasLaidOutPages() {
+        return mDocumentInfo.info != null
+                && mDocumentInfo.info.getPageCount() > 0;
+    }
+
     public void clearUpdateError() {
         if (!hasUpdateError()) {
             throw new IllegalStateException("No update error to clear");
diff --git a/packages/PrintSpooler/src/com/android/printspooler/ui/PageAdapter.java b/packages/PrintSpooler/src/com/android/printspooler/ui/PageAdapter.java
index d949673..ce0b9b6 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/ui/PageAdapter.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/ui/PageAdapter.java
@@ -17,6 +17,9 @@
 package com.android.printspooler.ui;
 
 import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.drawable.BitmapDrawable;
 import android.os.ParcelFileDescriptor;
 import android.print.PageRange;
 import android.print.PrintAttributes.MediaSize;
@@ -26,12 +29,12 @@
 import android.support.v7.widget.RecyclerView.ViewHolder;
 import android.util.Log;
 import android.util.SparseArray;
-import android.util.TypedValue;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.View.OnClickListener;
 import android.view.ViewGroup;
 import android.view.ViewGroup.LayoutParams;
+import android.view.View.MeasureSpec;
 import android.widget.TextView;
 import com.android.printspooler.R;
 import com.android.printspooler.model.PageContentRepository;
@@ -48,7 +51,7 @@
  * This class represents the adapter for the pages in the print preview list.
  */
 public final class PageAdapter extends Adapter implements
-        PageContentRepository.OnMalformedPdfFileListener{
+        PageContentRepository.OnMalformedPdfFileListener {
     private static final String LOG_TAG = "PageAdapter";
 
     private static final int MAX_PREVIEW_PAGES_BATCH = 50;
@@ -86,6 +89,8 @@
     // Pages the user selected in the UI.
     private PageRange[] mSelectedPages;
 
+    private BitmapDrawable mEmptyState;
+
     private int mDocumentPageCount = PrintDocumentInfo.PAGE_COUNT_UNKNOWN;
     private int mSelectedPageCount;
 
@@ -257,7 +262,7 @@
         }
 
         if (updatePreviewAreaAndPageSize) {
-            updatePreviewAreaAndPageSize();
+            updatePreviewAreaPageSizeAndEmptyState();
         }
 
         if (documentChanged) {
@@ -318,12 +323,12 @@
             }
 
             // OK, there are bugs in recycler view which tries to bind views
-            // without recycling them which would give us a chane to clean up.
+            // without recycling them which would give us a chance to clean up.
             PageContentProvider boundProvider = mPageContentRepository
-                   .peekPageContentProvider(pageIndexInFile);
+                    .peekPageContentProvider(pageIndexInFile);
             if (boundProvider != null) {
                 PageContentView owner = (PageContentView) boundProvider.getOwner();
-                owner.init(null, mMediaSize, mMinMargins);
+                owner.init(null, mEmptyState, mMediaSize, mMinMargins);
                 mPageContentRepository.releasePageContentProvider(boundProvider);
             }
 
@@ -333,7 +338,7 @@
         } else {
             onSelectedPageNotInFile(pageInDocument);
         }
-        content.init(provider, mMediaSize, mMinMargins);
+        content.init(provider, mEmptyState, mMediaSize, mMinMargins);
 
         View pageSelector = page.findViewById(R.id.page_selector);
         pageSelector.setTag(myHolder);
@@ -384,7 +389,7 @@
             mSelectedPages = selectedPages;
             mSelectedPageCount = PageRangeUtils.getNormalizedPageCount(
                     mSelectedPages, mDocumentPageCount);
-            updatePreviewAreaAndPageSize();
+            updatePreviewAreaPageSizeAndEmptyState();
             notifyDataSetChanged();
         }
         return mSelectedPages;
@@ -392,12 +397,12 @@
 
     public void onPreviewAreaSizeChanged() {
         if (mMediaSize != null) {
-            updatePreviewAreaAndPageSize();
+            updatePreviewAreaPageSizeAndEmptyState();
             notifyDataSetChanged();
         }
     }
 
-    private void updatePreviewAreaAndPageSize() {
+    private void updatePreviewAreaPageSizeAndEmptyState() {
         final int availableWidth = mPreviewArea.getWidth();
         final int availableHeight = mPreviewArea.getHeight();
 
@@ -419,7 +424,7 @@
         final int pageContentDesiredHeight = (int) (((float) pageContentDesiredWidth
                 / pageAspectRatio) + 0.5f);
 
-        // If the page does not fit entirely in a vertial direction,
+        // If the page does not fit entirely in a vertical direction,
         // we shirk it but not less than the minimal page width.
         final int pageContentMinHeight = (int) (mPreviewPageMinWidth / pageAspectRatio + 0.5f);
         final int pageContentMaxHeight = Math.max(pageContentMinHeight,
@@ -448,6 +453,23 @@
 
         mPreviewArea.setPadding(horizontalPadding, verticalPadding,
                 horizontalPadding, verticalPadding);
+
+        // Now update the empty state drawable, as it depends on the page
+        // size and is reused for all views for better performance.
+        LayoutInflater inflater = LayoutInflater.from(mContext);
+        View content = inflater.inflate(R.layout.preview_page_loading, null, false);
+        content.measure(MeasureSpec.makeMeasureSpec(mPageContentWidth, MeasureSpec.EXACTLY),
+                MeasureSpec.makeMeasureSpec(mPageContentHeight, MeasureSpec.EXACTLY));
+        content.layout(0, 0, content.getMeasuredWidth(), content.getMeasuredHeight());
+
+        Bitmap bitmap = Bitmap.createBitmap(mPageContentWidth, mPageContentHeight,
+                Bitmap.Config.ARGB_8888);
+        Canvas canvas = new Canvas(bitmap);
+        content.draw(canvas);
+
+        // Do not recycle the old bitmap if such as it may be set as an empty
+        // state to any of the page views. Just let the GC take care of it.
+        mEmptyState = new BitmapDrawable(mContext.getResources(), bitmap);
     }
 
     private PageRange[] computeSelectedPages() {
@@ -718,7 +740,7 @@
     private void recyclePageView(PageContentView page, int pageIndexInAdapter) {
         PageContentProvider provider = page.getPageContentProvider();
         if (provider != null) {
-            page.init(null, null, null);
+            page.init(null, null, null, null);
             mPageContentRepository.releasePageContentProvider(provider);
             mBoundPagesInAdapter.remove(pageIndexInAdapter);
         }
diff --git a/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java b/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
index 022e0d0..535081f 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
@@ -114,14 +114,15 @@
     private static final int DEST_ADAPTER_ITEM_ID_SAVE_AS_PDF = Integer.MAX_VALUE;
     private static final int DEST_ADAPTER_ITEM_ID_ALL_PRINTERS = Integer.MAX_VALUE - 1;
 
-    private static final int STATE_CONFIGURING = 0;
-    private static final int STATE_PRINT_CONFIRMED = 1;
-    private static final int STATE_PRINT_CANCELED = 2;
-    private static final int STATE_UPDATE_FAILED = 3;
-    private static final int STATE_CREATE_FILE_FAILED = 4;
-    private static final int STATE_PRINTER_UNAVAILABLE = 5;
-    private static final int STATE_UPDATE_SLOW = 6;
-    private static final int STATE_PRINT_COMPLETED = 7;
+    private static final int STATE_INITIALIZING = 0;
+    private static final int STATE_CONFIGURING = 1;
+    private static final int STATE_PRINT_CONFIRMED = 2;
+    private static final int STATE_PRINT_CANCELED = 3;
+    private static final int STATE_UPDATE_FAILED = 4;
+    private static final int STATE_CREATE_FILE_FAILED = 5;
+    private static final int STATE_PRINTER_UNAVAILABLE = 6;
+    private static final int STATE_UPDATE_SLOW = 7;
+    private static final int STATE_PRINT_COMPLETED = 8;
 
     private static final int UI_STATE_PREVIEW = 0;
     private static final int UI_STATE_ERROR = 1;
@@ -196,7 +197,7 @@
 
     private int mCurrentPageCount;
 
-    private int mState;
+    private int mState = STATE_INITIALIZING;
 
     private int mUiState = UI_STATE_PREVIEW;
 
@@ -290,10 +291,17 @@
         mPrintedDocument.start();
 
         ensurePreviewUiShown();
+
+        setState(STATE_CONFIGURING);
     }
 
     @Override
     public void onPause() {
+        if (mState == STATE_INITIALIZING) {
+            super.onPause();
+            return;
+        }
+
         if (isFinishing()) {
             PrintSpoolerService spooler = mSpoolerProvider.getSpooler();
             spooler.updatePrintJobUserConfigurableOptionsNoPersistence(mPrintJob);
@@ -341,9 +349,13 @@
 
     @Override
     public boolean onKeyUp(int keyCode, KeyEvent event) {
+        if (mState == STATE_INITIALIZING) {
+            return super.onKeyUp(keyCode, event);
+        }
+
         if (keyCode == KeyEvent.KEYCODE_BACK
                 && event.isTracking() && !event.isCanceled()) {
-            if (mPrintPreviewController != null&&mPrintPreviewController.isOptionsOpened()
+            if (mPrintPreviewController != null && mPrintPreviewController.isOptionsOpened()
                     && !hasErrors()) {
                 mPrintPreviewController.closeOptions();
             } else {
@@ -900,7 +912,7 @@
         final boolean willUpdate = mPrintedDocument.update(mPrintJob.getAttributes(),
                 pages, preview);
 
-        if (willUpdate) {
+        if (willUpdate && !mPrintedDocument.hasLaidOutPages()) {
             // When the update is done we update the print preview.
             mProgressMessageController.post();
             return true;
diff --git a/packages/PrintSpooler/src/com/android/printspooler/ui/PrintPreviewController.java b/packages/PrintSpooler/src/com/android/printspooler/ui/PrintPreviewController.java
index 2b5b41b..a25e05e 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/ui/PrintPreviewController.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/ui/PrintPreviewController.java
@@ -195,6 +195,7 @@
         if (mPageAdapter.isOpened()) {
             mPageAdapter.close(null);
         }
+        mRecyclerView.setAdapter(null);
         mPageAdapter.destroy();
     }
 
diff --git a/packages/PrintSpooler/src/com/android/printspooler/widget/PageContentView.java b/packages/PrintSpooler/src/com/android/printspooler/widget/PageContentView.java
index 23a01bd..e2ae758 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/widget/PageContentView.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/widget/PageContentView.java
@@ -17,17 +17,15 @@
 package com.android.printspooler.widget;
 
 import android.content.Context;
-import android.graphics.Canvas;
 import android.graphics.drawable.BitmapDrawable;
-import android.graphics.drawable.ColorDrawable;
+import android.graphics.drawable.Drawable;
 import android.print.PrintAttributes.MediaSize;
 import android.print.PrintAttributes.Margins;
 import android.util.AttributeSet;
-import android.util.TypedValue;
 import android.view.View;
 import com.android.printspooler.model.PageContentRepository;
-import com.android.printspooler.model.PageContentRepository.PageContentProvider;
 import com.android.printspooler.model.PageContentRepository.RenderSpec;
+import com.android.printspooler.model.PageContentRepository.PageContentProvider;
 
 /**
  * This class represents a page in the print preview list. The width of the page
@@ -37,35 +35,20 @@
  */
 public class PageContentView extends View
         implements PageContentRepository.OnPageContentAvailableCallback {
-
-    private final ColorDrawable mEmptyState;
-
     private PageContentProvider mProvider;
 
     private MediaSize mMediaSize;
 
     private Margins mMinMargins;
 
+    private Drawable mEmptyState;
+
     private boolean mContentRequested;
 
     private boolean mNeedsLayout;
 
     public PageContentView(Context context, AttributeSet attrs) {
         super(context, attrs);
-
-        TypedValue typedValue = new TypedValue();
-        context.getTheme().resolveAttribute(com.android.internal.R.attr.textColorPrimary,
-                typedValue, true);
-
-        mEmptyState = new ColorDrawable(typedValue.data);
-
-        setBackground(mEmptyState);
-    }
-
-    @Override
-    protected void onDraw(Canvas canvas) {
-        super.onDraw(canvas);
-        requestPageContentIfNeeded();
     }
 
     @Override
@@ -85,15 +68,19 @@
         return mProvider;
     }
 
-    public void init(PageContentProvider provider, MediaSize mediaSize, Margins minMargins) {
+    public void init(PageContentProvider provider, Drawable emptyState,
+            MediaSize mediaSize, Margins minMargins) {
         final boolean providerChanged = (mProvider == null)
                 ? provider != null : !mProvider.equals(provider);
+        final boolean loadingDrawableChanged = (mEmptyState == null)
+                ? mEmptyState != null : !mEmptyState.equals(emptyState);
         final boolean mediaSizeChanged = (mMediaSize == null)
                 ? mediaSize != null : !mMediaSize.equals(mediaSize);
         final boolean marginsChanged = (mMinMargins == null)
                 ? minMargins != null : !mMinMargins.equals(minMargins);
 
-        if (!providerChanged && !mediaSizeChanged && !marginsChanged) {
+        if (!providerChanged && !mediaSizeChanged
+                && !marginsChanged && !loadingDrawableChanged) {
             return;
         }
 
@@ -101,6 +88,7 @@
         mMediaSize = mediaSize;
         mMinMargins = minMargins;
 
+        mEmptyState = emptyState;
         mContentRequested = false;
         mNeedsLayout = mNeedsLayout || mediaSizeChanged || marginsChanged;
 
diff --git a/services/core/java/com/android/server/NativeDaemonEvent.java b/services/core/java/com/android/server/NativeDaemonEvent.java
index 2095152..59d50bd 100644
--- a/services/core/java/com/android/server/NativeDaemonEvent.java
+++ b/services/core/java/com/android/server/NativeDaemonEvent.java
@@ -201,20 +201,16 @@
         }
         while (current < length) {
             // find the end of the word
-            if (quoted) {
-                wordEnd = current;
-                while ((wordEnd = rawEvent.indexOf('\"', wordEnd)) != -1) {
-                    if (rawEvent.charAt(wordEnd - 1) != '\\') {
-                        break;
-                    } else {
-                        wordEnd++; // skip this escaped quote and keep looking
-                    }
+            char terminator = quoted ? '\"' : ' ';
+            wordEnd = current;
+            while (wordEnd < length && rawEvent.charAt(wordEnd) != terminator) {
+                if (rawEvent.charAt(wordEnd) == '\\') {
+                    // skip the escaped char
+                    ++wordEnd;
                 }
-            } else {
-                wordEnd = rawEvent.indexOf(' ', current);
+                ++wordEnd;
             }
-            // if we didn't find the end-o-word token, take the rest of the string
-            if (wordEnd == -1) wordEnd = length;
+            if (wordEnd > length) wordEnd = length;
             String word = rawEvent.substring(current, wordEnd);
             current += word.length();
             if (!quoted) {
diff --git a/services/core/java/com/android/server/NsdService.java b/services/core/java/com/android/server/NsdService.java
index cf7e65c..cb1748d 100644
--- a/services/core/java/com/android/server/NsdService.java
+++ b/services/core/java/com/android/server/NsdService.java
@@ -397,8 +397,7 @@
                         break;
                     case NsdManager.NATIVE_DAEMON_EVENT:
                         NativeEvent event = (NativeEvent) msg.obj;
-                        if (!handleNativeEvent(event.code, event.raw,
-                                NativeDaemonEvent.unescapeArgs(event.raw))) {
+                        if (!handleNativeEvent(event.code, event.raw, event.cooked)) {
                             result = NOT_HANDLED;
                         }
                         break;
@@ -474,8 +473,14 @@
                     case NativeResponseCode.SERVICE_RESOLVED:
                         /* NNN resolveId fullName hostName port txtlen txtdata */
                         if (DBG) Slog.d(TAG, "SERVICE_RESOLVED Raw: " + raw);
-                        int index = cooked[2].indexOf(".");
-                        if (index == -1) {
+                        int index = 0;
+                        while (index < cooked[2].length() && cooked[2].charAt(index) != '.') {
+                            if (cooked[2].charAt(index) == '\\') {
+                                ++index;
+                            }
+                            ++index;
+                        }
+                        if (index >= cooked[2].length()) {
                             Slog.e(TAG, "Invalid service found " + raw);
                             break;
                         }
@@ -483,6 +488,8 @@
                         String rest = cooked[2].substring(index);
                         String type = rest.replace(".local.", "");
 
+                        name = unescape(name);
+
                         clientInfo.mResolvedService.setServiceName(name);
                         clientInfo.mResolvedService.setServiceType(type);
                         clientInfo.mResolvedService.setPort(Integer.parseInt(cooked[4]));
@@ -541,6 +548,30 @@
        }
     }
 
+    private String unescape(String s) {
+        StringBuilder sb = new StringBuilder(s.length());
+        for (int i = 0; i < s.length(); ++i) {
+            char c = s.charAt(i);
+            if (c == '\\') {
+                if (++i >= s.length()) {
+                    Slog.e(TAG, "Unexpected end of escape sequence in: " + s);
+                    break;
+                }
+                c = s.charAt(i);
+                if (c != '.' && c != '\\') {
+                    if (i + 2 >= s.length()) {
+                        Slog.e(TAG, "Unexpected end of escape sequence in: " + s);
+                        break;
+                    }
+                    c = (char) ((c-'0') * 100 + (s.charAt(i+1)-'0') * 10 + (s.charAt(i+2)-'0'));
+                    i += 2;
+                }
+            }
+            sb.append(c);
+        }
+        return sb.toString();
+    }
+
     private NativeDaemonConnector mNativeConnector;
     private final CountDownLatch mNativeDaemonConnected = new CountDownLatch(1);
 
@@ -625,10 +656,12 @@
     private class NativeEvent {
         final int code;
         final String raw;
+        final String[] cooked;
 
-        NativeEvent(int code, String raw) {
+        NativeEvent(int code, String raw, String[] cooked) {
             this.code = code;
             this.raw = raw;
+            this.cooked = cooked;
         }
     }
 
@@ -644,7 +677,7 @@
         public boolean onEvent(int code, String raw, String[] cooked) {
             // TODO: NDC translates a message to a callback, we could enhance NDC to
             // directly interact with a state machine through messages
-            NativeEvent event = new NativeEvent(code, raw);
+            NativeEvent event = new NativeEvent(code, raw, cooked);
             mNsdStateMachine.sendMessage(NsdManager.NATIVE_DAEMON_EVENT, event);
             return true;
         }
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index bc538ed..54f043d 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -69,6 +69,7 @@
 import android.service.notification.IConditionListener;
 import android.service.notification.IConditionProvider;
 import android.service.notification.INotificationListener;
+import android.service.notification.IStatusBarNotificationHolder;
 import android.service.notification.NotificationListenerService;
 import android.service.notification.NotificationRankingUpdate;
 import android.service.notification.StatusBarNotification;
@@ -2848,8 +2849,9 @@
         private void notifyPosted(final ManagedServiceInfo info,
                 final StatusBarNotification sbn, NotificationRankingUpdate rankingUpdate) {
             final INotificationListener listener = (INotificationListener)info.service;
+            StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn);
             try {
-                listener.onNotificationPosted(sbn, rankingUpdate);
+                listener.onNotificationPosted(sbnHolder, rankingUpdate);
             } catch (RemoteException ex) {
                 Log.e(TAG, "unable to notify listener (posted): " + listener, ex);
             }
@@ -2861,8 +2863,9 @@
                 return;
             }
             final INotificationListener listener = (INotificationListener) info.service;
+            StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn);
             try {
-                listener.onNotificationRemoved(sbn, rankingUpdate);
+                listener.onNotificationRemoved(sbnHolder, rankingUpdate);
             } catch (RemoteException ex) {
                 Log.e(TAG, "unable to notify listener (removed): " + listener, ex);
             }
@@ -2950,4 +2953,22 @@
             return zen ? "zen" : ('\'' + pkgFilter + '\'');
         }
     }
+
+    /**
+     * Wrapper for a StatusBarNotification object that allows transfer across a oneway
+     * binder without sending large amounts of data over a oneway transaction.
+     */
+    private static final class StatusBarNotificationHolder
+            extends IStatusBarNotificationHolder.Stub {
+        private final StatusBarNotification mValue;
+
+        public StatusBarNotificationHolder(StatusBarNotification value) {
+            mValue = value;
+        }
+
+        @Override
+        public StatusBarNotification get() {
+            return mValue;
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index 9a00923..89ea905 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -897,10 +897,9 @@
     private static class Callbacks extends Handler {
         private static final int MSG_SESSION_CREATED = 1;
         private static final int MSG_SESSION_BADGING_CHANGED = 2;
-        private static final int MSG_SESSION_OPENED = 3;
+        private static final int MSG_SESSION_ACTIVE_CHANGED = 3;
         private static final int MSG_SESSION_PROGRESS_CHANGED = 4;
-        private static final int MSG_SESSION_CLOSED = 5;
-        private static final int MSG_SESSION_FINISHED = 6;
+        private static final int MSG_SESSION_FINISHED = 5;
 
         private final RemoteCallbackList<IPackageInstallerCallback>
                 mCallbacks = new RemoteCallbackList<>();
@@ -945,15 +944,12 @@
                 case MSG_SESSION_BADGING_CHANGED:
                     callback.onSessionBadgingChanged(sessionId);
                     break;
-                case MSG_SESSION_OPENED:
-                    callback.onSessionOpened(sessionId);
+                case MSG_SESSION_ACTIVE_CHANGED:
+                    callback.onSessionActiveChanged(sessionId, (boolean) msg.obj);
                     break;
                 case MSG_SESSION_PROGRESS_CHANGED:
                     callback.onSessionProgressChanged(sessionId, (float) msg.obj);
                     break;
-                case MSG_SESSION_CLOSED:
-                    callback.onSessionClosed(sessionId);
-                    break;
                 case MSG_SESSION_FINISHED:
                     callback.onSessionFinished(sessionId, (boolean) msg.obj);
                     break;
@@ -968,18 +964,14 @@
             obtainMessage(MSG_SESSION_BADGING_CHANGED, sessionId, userId).sendToTarget();
         }
 
-        private void notifySessionOpened(int sessionId, int userId) {
-            obtainMessage(MSG_SESSION_OPENED, sessionId, userId).sendToTarget();
+        private void notifySessionActiveChanged(int sessionId, int userId, boolean active) {
+            obtainMessage(MSG_SESSION_ACTIVE_CHANGED, sessionId, userId, active).sendToTarget();
         }
 
         private void notifySessionProgressChanged(int sessionId, int userId, float progress) {
             obtainMessage(MSG_SESSION_PROGRESS_CHANGED, sessionId, userId, progress).sendToTarget();
         }
 
-        private void notifySessionClosed(int sessionId, int userId) {
-            obtainMessage(MSG_SESSION_CLOSED, sessionId, userId).sendToTarget();
-        }
-
         public void notifySessionFinished(int sessionId, int userId, boolean success) {
             obtainMessage(MSG_SESSION_FINISHED, sessionId, userId, success).sendToTarget();
         }
@@ -1022,18 +1014,14 @@
             writeSessionsAsync();
         }
 
-        public void onSessionOpened(PackageInstallerSession session) {
-            mCallbacks.notifySessionOpened(session.sessionId, session.userId);
+        public void onSessionActiveChanged(PackageInstallerSession session, boolean active) {
+            mCallbacks.notifySessionActiveChanged(session.sessionId, session.userId, active);
         }
 
         public void onSessionProgressChanged(PackageInstallerSession session, float progress) {
             mCallbacks.notifySessionProgressChanged(session.sessionId, session.userId, progress);
         }
 
-        public void onSessionClosed(PackageInstallerSession session) {
-            mCallbacks.notifySessionClosed(session.sessionId, session.userId);
-        }
-
         public void onSessionFinished(PackageInstallerSession session, boolean success) {
             mCallbacks.notifySessionFinished(session.sessionId, session.userId, success);
             synchronized (mSessions) {
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 85ff54e..f8273c0 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -227,7 +227,7 @@
                     mResolvedBaseFile.getAbsolutePath() : null;
             info.progress = mProgress;
             info.sealed = mSealed;
-            info.open = mOpenCount.get() > 0;
+            info.active = mOpenCount.get() > 0;
 
             info.mode = params.mode;
             info.sizeBytes = params.sizeBytes;
@@ -833,14 +833,14 @@
 
     public void open() {
         if (mOpenCount.getAndIncrement() == 0) {
-            mCallback.onSessionOpened(this);
+            mCallback.onSessionActiveChanged(this, true);
         }
     }
 
     @Override
     public void close() {
         if (mOpenCount.decrementAndGet() == 0) {
-            mCallback.onSessionClosed(this);
+            mCallback.onSessionActiveChanged(this, false);
         }
     }
 
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index d2a627e..7b4270b 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -3783,21 +3783,25 @@
         } else {
             pi = generatePackageInfoFromSettingsLPw(ps.name, flags, userId);
         }
-        if ((flags&PackageManager.GET_PERMISSIONS) == 0) {
-            if (numMatch == permissions.length) {
-                pi.requestedPermissions = permissions;
-            } else {
-                pi.requestedPermissions = new String[numMatch];
-                numMatch = 0;
-                for (int i=0; i<permissions.length; i++) {
-                    if (tmp[i]) {
-                        pi.requestedPermissions[numMatch] = permissions[i];
-                        numMatch++;
+        // The above might return null in cases of uninstalled apps or install-state
+        // skew across users/profiles.
+        if (pi != null) {
+            if ((flags&PackageManager.GET_PERMISSIONS) == 0) {
+                if (numMatch == permissions.length) {
+                    pi.requestedPermissions = permissions;
+                } else {
+                    pi.requestedPermissions = new String[numMatch];
+                    numMatch = 0;
+                    for (int i=0; i<permissions.length; i++) {
+                        if (tmp[i]) {
+                            pi.requestedPermissions[numMatch] = permissions[i];
+                            numMatch++;
+                        }
                     }
                 }
             }
+            list.add(pi);
         }
-        list.add(pi);
     }
 
     @Override
@@ -10260,7 +10264,7 @@
                             || !bp.packageSetting.keySetData.isUsingUpgradeKeySets()
                             || ((PackageSetting) bp.packageSetting).sharedUser != null) {
                         sigsOk = compareSignatures(bp.packageSetting.signatures.mSignatures,
-                                pkg.mSignatures) != PackageManager.SIGNATURE_MATCH;
+                                pkg.mSignatures) == PackageManager.SIGNATURE_MATCH;
                     } else {
                         sigsOk = checkUpgradeKeySetLP((PackageSetting) bp.packageSetting, pkg);
                     }
diff --git a/telecomm/java/android/telecomm/Call.java b/telecomm/java/android/telecomm/Call.java
index 5bf0855..c3aa2a0 100644
--- a/telecomm/java/android/telecomm/Call.java
+++ b/telecomm/java/android/telecomm/Call.java
@@ -517,6 +517,20 @@
     }
 
     /**
+     * Merges the calls within this conference. See {@link PhoneCapabilities#MERGE_CONFERENCE}.
+     */
+    public void mergeConference() {
+        mInCallAdapter.mergeConference(mTelecommCallId);
+    }
+
+    /**
+     * Swaps the calls within this conference. See {@link PhoneCapabilities#SWAP_CONFERENCE}.
+     */
+    public void swapConference() {
+        mInCallAdapter.swapConference(mTelecommCallId);
+    }
+
+    /**
      * Obtains the parent of this {@code Call} in a conference, if any.
      *
      * @return The parent {@code Call}, or {@code null} if this {@code Call} is not a
diff --git a/telecomm/java/android/telecomm/Conference.java b/telecomm/java/android/telecomm/Conference.java
index 879ff66..c838b48 100644
--- a/telecomm/java/android/telecomm/Conference.java
+++ b/telecomm/java/android/telecomm/Conference.java
@@ -93,6 +93,18 @@
     public void onUnhold() {}
 
     /**
+     * Invoked when the child calls should be merged. Only invoked if the conference contains the
+     * capability {@link PhoneCapabilities#MERGE_CONFERENCE}.
+     */
+    public void onMerge() {}
+
+    /**
+     * Invoked when the child calls should be swapped. Only invoked if the conference contains the
+     * capability {@link PhoneCapabilities#SWAP_CONFERENCE}.
+     */
+    public void onSwap() {}
+
+    /**
      * Sets state to be on hold.
      */
     public final void setOnHold() {
@@ -141,7 +153,7 @@
      * @param connection The connection to add.
      * @return True if the connection was successfully added.
      */
-    public boolean addConnection(Connection connection) {
+    public final boolean addConnection(Connection connection) {
         if (connection != null && !mChildConnections.contains(connection)) {
             if (connection.setConference(this)) {
                 mChildConnections.add(connection);
@@ -160,7 +172,7 @@
      * @param connection The connection to remove.
      * @return True if the connection was successfully removed.
      */
-    public void removeConnection(Connection connection) {
+    public final void removeConnection(Connection connection) {
         Log.d(this, "removing %s from %s", connection, mChildConnections);
         if (connection != null && mChildConnections.remove(connection)) {
             connection.resetConference();
@@ -173,7 +185,7 @@
     /**
      * Tears down the conference object and any of it's current connections.
      */
-    public void destroy() {
+    public final void destroy() {
         Log.d(this, "destroying conference : %s", this);
         // Tear down the children.
         for (Connection connection : mChildConnections) {
diff --git a/telecomm/java/android/telecomm/Connection.java b/telecomm/java/android/telecomm/Connection.java
index 4d6e267..6df117e 100644
--- a/telecomm/java/android/telecomm/Connection.java
+++ b/telecomm/java/android/telecomm/Connection.java
@@ -1068,10 +1068,10 @@
         if (mState != state) {
             Log.d(this, "setState: %s", stateToString(state));
             mState = state;
+            onSetState(state);
             for (Listener l : mListeners) {
                 l.onStateChanged(this, state);
             }
-            onSetState(state);
         }
     }
 
diff --git a/telecomm/java/android/telecomm/ConnectionService.java b/telecomm/java/android/telecomm/ConnectionService.java
index 2dc6910..833aa26 100644
--- a/telecomm/java/android/telecomm/ConnectionService.java
+++ b/telecomm/java/android/telecomm/ConnectionService.java
@@ -72,6 +72,8 @@
     private static final int MSG_ON_PHONE_ACCOUNT_CLICKED = 15;
     private static final int MSG_REMOVE_CONNECTION_SERVICE_ADAPTER = 16;
     private static final int MSG_ANSWER_VIDEO = 17;
+    private static final int MSG_MERGE_CONFERENCE = 18;
+    private static final int MSG_SWAP_CONFERENCE = 19;
 
     private static Connection sNullConnection;
 
@@ -182,6 +184,16 @@
         }
 
         @Override
+        public void mergeConference(String callId) {
+            mHandler.obtainMessage(MSG_MERGE_CONFERENCE, callId).sendToTarget();
+        }
+
+        @Override
+        public void swapConference(String callId) {
+            mHandler.obtainMessage(MSG_SWAP_CONFERENCE, callId).sendToTarget();
+        }
+
+        @Override
         public void onPostDialContinue(String callId, boolean proceed) {
             SomeArgs args = SomeArgs.obtain();
             args.arg1 = callId;
@@ -298,6 +310,12 @@
                 case MSG_SPLIT_FROM_CONFERENCE:
                     splitFromConference((String) msg.obj);
                     break;
+                case MSG_MERGE_CONFERENCE:
+                    mergeConference((String) msg.obj);
+                    break;
+                case MSG_SWAP_CONFERENCE:
+                    swapConference((String) msg.obj);
+                    break;
                 case MSG_ON_POST_DIAL_CONTINUE: {
                     SomeArgs args = (SomeArgs) msg.obj;
                     try {
@@ -639,6 +657,22 @@
         }
     }
 
+    private void mergeConference(String callId) {
+        Log.d(this, "mergeConference(%s)", callId);
+        Conference conference = findConferenceForAction(callId, "mergeConference");
+        if (conference != null) {
+            conference.onMerge();
+        }
+    }
+
+    private void swapConference(String callId) {
+        Log.d(this, "swapConference(%s)", callId);
+        Conference conference = findConferenceForAction(callId, "swapConference");
+        if (conference != null) {
+            conference.onSwap();
+        }
+    }
+
     private void onPostDialContinue(String callId, boolean proceed) {
         Log.d(this, "onPostDialContinue(%s)", callId);
         findConnectionForAction(callId, "stopDtmfTone").onPostDialContinue(proceed);
diff --git a/telecomm/java/android/telecomm/InCallAdapter.java b/telecomm/java/android/telecomm/InCallAdapter.java
index 80f7b57..96ea5a6 100644
--- a/telecomm/java/android/telecomm/InCallAdapter.java
+++ b/telecomm/java/android/telecomm/InCallAdapter.java
@@ -241,6 +241,26 @@
     }
 
     /**
+     * Instructs Telecomm to merge child calls of the specified conference call.
+     */
+    public void mergeConference(String callId) {
+        try {
+            mAdapter.mergeConference(callId);
+        } catch (RemoteException ignored) {
+        }
+    }
+
+    /**
+     * Instructs Telecomm to swap the child calls of the specified conference call.
+     */
+    public void swapConference(String callId) {
+        try {
+            mAdapter.swapConference(callId);
+        } catch (RemoteException ignored) {
+        }
+    }
+
+    /**
      * Instructs Telecomm to turn the proximity sensor on.
      */
     public void turnProximitySensorOn() {
diff --git a/telecomm/java/android/telecomm/PhoneCapabilities.java b/telecomm/java/android/telecomm/PhoneCapabilities.java
index 3d76608..7a338b4 100644
--- a/telecomm/java/android/telecomm/PhoneCapabilities.java
+++ b/telecomm/java/android/telecomm/PhoneCapabilities.java
@@ -27,11 +27,17 @@
     /** Call supports the hold feature. */
     public static final int SUPPORT_HOLD       = 0x00000002;
 
-    /** Call can currently be merged. */
-    public static final int MERGE_CALLS        = 0x00000004;
+    /**
+     * Calls within a conference can be merged. Some connection services create a conference call
+     * only after two calls have been merged.  However, a conference call can also be added the
+     * moment there are more than one call. CDMA calls are implemented in this way because the call
+     * actions are more limited when more than one call exists. This flag allows merge to be exposed
+     * as a capability on the conference call instead of individual calls.
+     */
+    public static final int MERGE_CONFERENCE   = 0x00000004;
 
-    /** Call can currently be swapped with another call. */
-    public static final int SWAP_CALLS         = 0x00000008;
+    /** Calls withing a conference can be swapped between foreground and background. */
+    public static final int SWAP_CONFERENCE    = 0x00000008;
 
     /** Call currently supports adding another call to this one. */
     public static final int ADD_CALL           = 0x00000010;
@@ -42,8 +48,11 @@
     /** Call can be muted. */
     public static final int MUTE               = 0x00000040;
 
-    /** Call supports generic conference mode. */
-    public static final int GENERIC_CONFERENCE = 0x00000080;
+    /**
+     * Call supports conference call management. This capability only applies to conference calls
+     * which can have other calls as children.
+     */
+    public static final int MANAGE_CONFERENCE = 0x00000080;
 
     /**
      * Local device supports video telephony.
@@ -69,8 +78,8 @@
      */
     public static final int VoWIFI = 0x00000800;
 
-    public static final int ALL = HOLD | SUPPORT_HOLD | MERGE_CALLS | SWAP_CALLS | ADD_CALL
-            | RESPOND_VIA_TEXT | MUTE | GENERIC_CONFERENCE;
+    public static final int ALL = HOLD | SUPPORT_HOLD | MERGE_CONFERENCE | SWAP_CONFERENCE | ADD_CALL
+            | RESPOND_VIA_TEXT | MUTE | MANAGE_CONFERENCE;
 
     public static String toString(int capabilities) {
         StringBuilder builder = new StringBuilder();
@@ -81,11 +90,11 @@
         if ((capabilities & SUPPORT_HOLD) != 0) {
             builder.append(" SUPPORT_HOLD");
         }
-        if ((capabilities & MERGE_CALLS) != 0) {
-            builder.append(" MERGE_CALLS");
+        if ((capabilities & MERGE_CONFERENCE) != 0) {
+            builder.append(" MERGE_CONFERENCE");
         }
-        if ((capabilities & SWAP_CALLS) != 0) {
-            builder.append(" SWAP_CALLS");
+        if ((capabilities & SWAP_CONFERENCE) != 0) {
+            builder.append(" SWAP_CONFERENCE");
         }
         if ((capabilities & ADD_CALL) != 0) {
             builder.append(" ADD_CALL");
@@ -96,8 +105,8 @@
         if ((capabilities & MUTE) != 0) {
             builder.append(" MUTE");
         }
-        if ((capabilities & GENERIC_CONFERENCE) != 0) {
-            builder.append(" GENERIC_CONFERENCE");
+        if ((capabilities & MANAGE_CONFERENCE) != 0) {
+            builder.append(" MANAGE_CONFERENCE");
         }
         if ((capabilities & SUPPORTS_VT_LOCAL) != 0) {
             builder.append(" SUPPORTS_VT_LOCAL");
diff --git a/telecomm/java/android/telecomm/RemoteConference.java b/telecomm/java/android/telecomm/RemoteConference.java
index 02f6de6..b073827 100644
--- a/telecomm/java/android/telecomm/RemoteConference.java
+++ b/telecomm/java/android/telecomm/RemoteConference.java
@@ -32,7 +32,7 @@
  */
 public final class RemoteConference {
 
-    public abstract static class Listener {
+    public abstract static class Callback {
         public void onStateChanged(RemoteConference conference, int oldState, int newState) {}
         public void onDisconnected(RemoteConference conference, int cause, String message) {}
         public void onConnectionAdded(RemoteConference conference, RemoteConnection connection) {}
@@ -44,7 +44,7 @@
     private final String mId;
     private final IConnectionService mConnectionService;
 
-    private final Set<Listener> mListeners = new CopyOnWriteArraySet<>();
+    private final Set<Callback> mCallbacks = new CopyOnWriteArraySet<>();
     private final List<RemoteConnection> mChildConnections = new CopyOnWriteArrayList<>();
     private final List<RemoteConnection> mUnmodifiableChildConnections =
             Collections.unmodifiableList(mChildConnections);
@@ -70,8 +70,8 @@
         for (RemoteConnection connection : mChildConnections) {
             connection.setConference(null);
         }
-        for (Listener l : mListeners) {
-            l.onDestroyed(this);
+        for (Callback c : mCallbacks) {
+            c.onDestroyed(this);
         }
     }
 
@@ -88,8 +88,8 @@
         if (mState != newState) {
             int oldState = mState;
             mState = newState;
-            for (Listener l : mListeners) {
-                l.onStateChanged(this, oldState, newState);
+            for (Callback c : mCallbacks) {
+                c.onStateChanged(this, oldState, newState);
             }
         }
     }
@@ -99,8 +99,8 @@
         if (!mChildConnections.contains(connection)) {
             mChildConnections.add(connection);
             connection.setConference(this);
-            for (Listener l : mListeners) {
-                l.onConnectionAdded(this, connection);
+            for (Callback c : mCallbacks) {
+                c.onConnectionAdded(this, connection);
             }
         }
     }
@@ -110,8 +110,8 @@
         if (mChildConnections.contains(connection)) {
             mChildConnections.remove(connection);
             connection.setConference(null);
-            for (Listener l : mListeners) {
-                l.onConnectionRemoved(this, connection);
+            for (Callback c : mCallbacks) {
+                c.onConnectionRemoved(this, connection);
             }
         }
     }
@@ -120,8 +120,8 @@
     void setCallCapabilities(int capabilities) {
         if (mCallCapabilities != capabilities) {
             mCallCapabilities = capabilities;
-            for (Listener l : mListeners) {
-                l.onCapabilitiesChanged(this, mCallCapabilities);
+            for (Callback c : mCallbacks) {
+                c.onCapabilitiesChanged(this, mCallCapabilities);
             }
         }
     }
@@ -132,8 +132,8 @@
             mDisconnectCause = cause;
             mDisconnectMessage = message;
             setState(Connection.STATE_DISCONNECTED);
-            for (Listener l : mListeners) {
-                l.onDisconnected(this, cause, message);
+            for (Callback c : mCallbacks) {
+                c.onDisconnected(this, cause, message);
             }
         }
     }
@@ -188,11 +188,11 @@
         return mDisconnectMessage;
     }
 
-    public final void addListener(Listener listener) {
-        mListeners.add(listener);
+    public final void addCallback(Callback callback) {
+        mCallbacks.add(callback);
     }
 
-    public final void removeListener(Listener listener) {
-        mListeners.remove(listener);
+    public final void removeCallback(Callback callback) {
+        mCallbacks.remove(callback);
     }
 }
diff --git a/telecomm/java/android/telecomm/RemoteConnectionService.java b/telecomm/java/android/telecomm/RemoteConnectionService.java
index 0b6badb..79193c2 100644
--- a/telecomm/java/android/telecomm/RemoteConnectionService.java
+++ b/telecomm/java/android/telecomm/RemoteConnectionService.java
@@ -191,7 +191,7 @@
             conference.setState(parcel.getState());
             conference.setCallCapabilities(parcel.getCapabilities());
             mConferenceById.put(callId, conference);
-            conference.addListener(new RemoteConference.Listener() {
+            conference.addCallback(new RemoteConference.Callback() {
                 @Override
                 public void onDestroyed(RemoteConference c) {
                     mConferenceById.remove(callId);
diff --git a/telecomm/java/android/telecomm/TelecommManager.java b/telecomm/java/android/telecomm/TelecommManager.java
index b8f6964..5e9e6d0 100644
--- a/telecomm/java/android/telecomm/TelecommManager.java
+++ b/telecomm/java/android/telecomm/TelecommManager.java
@@ -46,34 +46,34 @@
      *
      * @hide
      */
-    public static final String ACTION_INCOMING_CALL = "android.intent.action.INCOMING_CALL";
+    public static final String ACTION_INCOMING_CALL = "android.telecomm.action.INCOMING_CALL";
 
     /**
      * The {@link android.content.Intent} action used to configure a
      * {@link android.telecomm.ConnectionService}.
      */
     public static final String ACTION_CONNECTION_SERVICE_CONFIGURE =
-            "android.intent.action.CONNECTION_SERVICE_CONFIGURE";
+            "android.telecomm.action.CONNECTION_SERVICE_CONFIGURE";
 
     /**
      * The {@link android.content.Intent} action used to show the call settings page.
      */
     public static final String ACTION_SHOW_CALL_SETTINGS =
-            "android.telecomm.intent.action.SHOW_CALL_SETTINGS";
+            "android.telecomm.action.SHOW_CALL_SETTINGS";
 
     /**
      * The {@link android.content.Intent} action used to show the settings page used to configure
      * {@link PhoneAccount} preferences.
      */
     public static final String ACTION_CHANGE_PHONE_ACCOUNTS =
-            "android.telecomm.intent.action.CHANGE_PHONE_ACCOUNTS";
+            "android.telecomm.action.CHANGE_PHONE_ACCOUNTS";
 
     /**
      * Optional extra for {@link android.content.Intent#ACTION_CALL} containing a boolean that
      * determines whether the speakerphone should be automatically turned on for an outgoing call.
      */
     public static final String EXTRA_START_CALL_WITH_SPEAKERPHONE =
-            "android.intent.extra.START_CALL_WITH_SPEAKERPHONE";
+            "android.telecomm.extra.START_CALL_WITH_SPEAKERPHONE";
 
     /**
      * Optional extra for {@link android.content.Intent#ACTION_CALL} containing an integer that
@@ -86,7 +86,7 @@
      * @hide
      */
     public static final String EXTRA_START_CALL_WITH_VIDEO_STATE =
-            "android.intent.extra.START_CALL_WITH_VIDEO_STATE";
+            "android.telecomm.extra.START_CALL_WITH_VIDEO_STATE";
 
     /**
      * The extra used with an {@link android.content.Intent#ACTION_CALL} and
@@ -96,7 +96,7 @@
      * Retrieve with {@link android.content.Intent#getParcelableExtra(String)}.
      */
     public static final String EXTRA_PHONE_ACCOUNT_HANDLE =
-            "android.intent.extra.PHONE_ACCOUNT_HANDLE";
+            "android.telecomm.extra.PHONE_ACCOUNT_HANDLE";
 
     /**
      * Optional extra for {@link #ACTION_INCOMING_CALL} containing a {@link Bundle} which contains
@@ -106,7 +106,7 @@
      * @hide
      */
     public static final String EXTRA_INCOMING_CALL_EXTRAS =
-            "android.intent.extra.INCOMING_CALL_EXTRAS";
+            "android.telecomm.extra.INCOMING_CALL_EXTRAS";
 
     /**
      * Optional extra for {@link android.content.Intent#ACTION_CALL} and
@@ -117,7 +117,7 @@
      * @hide
      */
     public static final String EXTRA_OUTGOING_CALL_EXTRAS =
-            "android.intent.extra.OUTGOING_CALL_EXTRAS";
+            "android.telecomm.extra.OUTGOING_CALL_EXTRAS";
 
     /**
      * Optional extra for {@link android.telephony.TelephonyManager#ACTION_PHONE_STATE_CHANGED}
@@ -203,7 +203,7 @@
      * @hide
      */
     public static final String ACTION_CURRENT_TTY_MODE_CHANGED =
-            "android.telecomm.intent.action.CURRENT_TTY_MODE_CHANGED";
+            "android.telecomm.action.CURRENT_TTY_MODE_CHANGED";
 
     /**
      * The lookup key for an int that indicates the current TTY mode.
@@ -226,7 +226,7 @@
      * @hide
      */
     public static final String ACTION_TTY_PREFERRED_MODE_CHANGED =
-            "android.telecomm.intent.action.TTY_PREFERRED_MODE_CHANGED";
+            "android.telecomm.action.TTY_PREFERRED_MODE_CHANGED";
 
     /**
      * The lookup key for an int that indicates preferred TTY mode. Valid modes are: -
diff --git a/telecomm/java/com/android/internal/telecomm/IConnectionService.aidl b/telecomm/java/com/android/internal/telecomm/IConnectionService.aidl
index 32b877d..a673733 100644
--- a/telecomm/java/com/android/internal/telecomm/IConnectionService.aidl
+++ b/telecomm/java/com/android/internal/telecomm/IConnectionService.aidl
@@ -65,6 +65,10 @@
 
     void splitFromConference(String callId);
 
+    void mergeConference(String conferenceCallId);
+
+    void swapConference(String conferenceCallId);
+
     void onPostDialContinue(String callId, boolean proceed);
 
     void onPhoneAccountClicked(String callId);
diff --git a/telecomm/java/com/android/internal/telecomm/IInCallAdapter.aidl b/telecomm/java/com/android/internal/telecomm/IInCallAdapter.aidl
index 2ce5c6b..626bb91 100644
--- a/telecomm/java/com/android/internal/telecomm/IInCallAdapter.aidl
+++ b/telecomm/java/com/android/internal/telecomm/IInCallAdapter.aidl
@@ -54,6 +54,10 @@
 
     void splitFromConference(String callId);
 
+    void mergeConference(String callId);
+
+    void swapConference(String callId);
+
     void turnOnProximitySensor();
 
     void turnOffProximitySensor(boolean screenOnImmediately);
diff --git a/telephony/java/android/telephony/PhoneNumberUtils.java b/telephony/java/android/telephony/PhoneNumberUtils.java
index 8af5e98..1d9e6a9 100644
--- a/telephony/java/android/telephony/PhoneNumberUtils.java
+++ b/telephony/java/android/telephony/PhoneNumberUtils.java
@@ -38,8 +38,8 @@
 
 import static com.android.internal.telephony.PhoneConstants.SUBSCRIPTION_KEY;
 import static com.android.internal.telephony.TelephonyProperties.PROPERTY_ICC_OPERATOR_ISO_COUNTRY;
-import static com.android.internal.telephony.TelephonyProperties.PROPERTY_IDP_STRING;
 import static com.android.internal.telephony.TelephonyProperties.PROPERTY_OPERATOR_ISO_COUNTRY;
+import static com.android.internal.telephony.TelephonyProperties.PROPERTY_OPERATOR_IDP_STRING;
 
 import java.util.Locale;
 import java.util.regex.Matcher;
@@ -2215,81 +2215,79 @@
     cdmaCheckAndProcessPlusCodeByNumberFormat(String dialStr,int currFormat,int defaultFormat) {
         String retStr = dialStr;
 
+        boolean useNanp = (currFormat == defaultFormat) && (currFormat == FORMAT_NANP);
+
         // Checks if the plus sign character is in the passed-in dial string
         if (dialStr != null &&
             dialStr.lastIndexOf(PLUS_SIGN_STRING) != -1) {
-            // Format the string based on the rules for the country the number is from,
-            // and the current country the phone is camped on.
-            if ((currFormat == defaultFormat) && (currFormat == FORMAT_NANP)) {
-                // Handle case where default and current telephone numbering plans are NANP.
-                String postDialStr = null;
-                String tempDialStr = dialStr;
 
-                // Sets the retStr to null since the conversion will be performed below.
-                retStr = null;
-                if (DBG) log("checkAndProcessPlusCode,dialStr=" + dialStr);
-                // This routine is to process the plus sign in the dial string by loop through
-                // the network portion, post dial portion 1, post dial portion 2... etc. if
-                // applied
-                do {
-                    String networkDialStr;
+            // Handle case where default and current telephone numbering plans are NANP.
+            String postDialStr = null;
+            String tempDialStr = dialStr;
+
+            // Sets the retStr to null since the conversion will be performed below.
+            retStr = null;
+            if (DBG) log("checkAndProcessPlusCode,dialStr=" + dialStr);
+            // This routine is to process the plus sign in the dial string by loop through
+            // the network portion, post dial portion 1, post dial portion 2... etc. if
+            // applied
+            do {
+                String networkDialStr;
+                // Format the string based on the rules for the country the number is from,
+                // and the current country the phone is camped
+                if (useNanp) {
                     networkDialStr = extractNetworkPortion(tempDialStr);
-                    // Handles the conversion within NANP
-                    networkDialStr = processPlusCodeWithinNanp(networkDialStr);
+                } else  {
+                    networkDialStr = extractNetworkPortionAlt(tempDialStr);
 
-                    // Concatenates the string that is converted from network portion
-                    if (!TextUtils.isEmpty(networkDialStr)) {
-                        if (retStr == null) {
-                            retStr = networkDialStr;
-                        } else {
-                            retStr = retStr.concat(networkDialStr);
-                        }
+                }
+
+                networkDialStr = processPlusCode(networkDialStr, useNanp);
+
+                // Concatenates the string that is converted from network portion
+                if (!TextUtils.isEmpty(networkDialStr)) {
+                    if (retStr == null) {
+                        retStr = networkDialStr;
                     } else {
-                        // This should never happen since we checked the if dialStr is null
-                        // and if it contains the plus sign in the beginning of this function.
-                        // The plus sign is part of the network portion.
-                        Rlog.e("checkAndProcessPlusCode: null newDialStr", networkDialStr);
-                        return dialStr;
+                        retStr = retStr.concat(networkDialStr);
                     }
-                    postDialStr = extractPostDialPortion(tempDialStr);
-                    if (!TextUtils.isEmpty(postDialStr)) {
-                        int dialableIndex = findDialableIndexFromPostDialStr(postDialStr);
+                } else {
+                    // This should never happen since we checked the if dialStr is null
+                    // and if it contains the plus sign in the beginning of this function.
+                    // The plus sign is part of the network portion.
+                    Rlog.e("checkAndProcessPlusCode: null newDialStr", networkDialStr);
+                    return dialStr;
+                }
+                postDialStr = extractPostDialPortion(tempDialStr);
+                if (!TextUtils.isEmpty(postDialStr)) {
+                    int dialableIndex = findDialableIndexFromPostDialStr(postDialStr);
 
-                        // dialableIndex should always be greater than 0
-                        if (dialableIndex >= 1) {
-                            retStr = appendPwCharBackToOrigDialStr(dialableIndex,
-                                     retStr,postDialStr);
-                            // Skips the P/W character, extracts the dialable portion
-                            tempDialStr = postDialStr.substring(dialableIndex);
-                        } else {
-                            // Non-dialable character such as P/W should not be at the end of
-                            // the dial string after P/W processing in CdmaConnection.java
-                            // Set the postDialStr to "" to break out of the loop
-                            if (dialableIndex < 0) {
-                                postDialStr = "";
-                            }
-                            Rlog.e("wrong postDialStr=", postDialStr);
+                    // dialableIndex should always be greater than 0
+                    if (dialableIndex >= 1) {
+                        retStr = appendPwCharBackToOrigDialStr(dialableIndex,
+                                 retStr,postDialStr);
+                        // Skips the P/W character, extracts the dialable portion
+                        tempDialStr = postDialStr.substring(dialableIndex);
+                    } else {
+                        // Non-dialable character such as P/W should not be at the end of
+                        // the dial string after P/W processing in CdmaConnection.java
+                        // Set the postDialStr to "" to break out of the loop
+                        if (dialableIndex < 0) {
+                            postDialStr = "";
                         }
+                        Rlog.e("wrong postDialStr=", postDialStr);
                     }
-                    if (DBG) log("checkAndProcessPlusCode,postDialStr=" + postDialStr);
-                } while (!TextUtils.isEmpty(postDialStr) && !TextUtils.isEmpty(tempDialStr));
-            } else {
-                // TODO: Support NANP international conversion and other telephone numbering plans.
-                // Currently the phone is never used in non-NANP system, so return the original
-                // dial string.
-                Rlog.e("checkAndProcessPlusCode:non-NANP not supported", dialStr);
-            }
+                }
+                if (DBG) log("checkAndProcessPlusCode,postDialStr=" + postDialStr);
+            } while (!TextUtils.isEmpty(postDialStr) && !TextUtils.isEmpty(tempDialStr));
         }
         return retStr;
-     }
+    }
 
-    // This function gets the default international dialing prefix
-    private static String getDefaultIdp( ) {
-        String ps = null;
-        SystemProperties.get(PROPERTY_IDP_STRING, ps);
-        if (TextUtils.isEmpty(ps)) {
-            ps = NANP_IDP_STRING;
-        }
+    private static String getCurrentIdp(boolean useNanp) {
+        // in case, there is no IDD is found, we shouldn't convert it.
+        String ps = SystemProperties.get(
+                PROPERTY_OPERATOR_IDP_STRING, useNanp ? NANP_IDP_STRING : PLUS_SIGN_STRING);
         return ps;
     }
 
@@ -2399,31 +2397,32 @@
     }
 
     /**
-     * This function handles the plus code conversion within NANP CDMA network
+     * This function handles the plus code conversion
      * If the number format is
      * 1)+1NANP,remove +,
      * 2)other than +1NANP, any + numbers,replace + with the current IDP
      */
-    private static String processPlusCodeWithinNanp(String networkDialStr) {
+    private static String processPlusCode(String networkDialStr, boolean useNanp) {
         String retStr = networkDialStr;
 
-        if (DBG) log("processPlusCodeWithinNanp,networkDialStr=" + networkDialStr);
+        if (DBG) log("processPlusCode, networkDialStr = " + networkDialStr
+                + "for NANP = " + useNanp);
         // If there is a plus sign at the beginning of the dial string,
         // Convert the plus sign to the default IDP since it's an international number
         if (networkDialStr != null &&
             networkDialStr.charAt(0) == PLUS_SIGN_CHAR &&
             networkDialStr.length() > 1) {
             String newStr = networkDialStr.substring(1);
-            if (isOneNanp(newStr)) {
+            // TODO: for nonNanp, should the '+' be removed if following number is country code
+            if (useNanp && isOneNanp(newStr)) {
                 // Remove the leading plus sign
                 retStr = newStr;
-             } else {
-                 String idpStr = getDefaultIdp();
-                 // Replaces the plus sign with the default IDP
-                 retStr = networkDialStr.replaceFirst("[+]", idpStr);
+            } else {
+                // Replaces the plus sign with the default IDP
+                retStr = networkDialStr.replaceFirst("[+]", getCurrentIdp(useNanp));
             }
         }
-        if (DBG) log("processPlusCodeWithinNanp,retStr=" + retStr);
+        if (DBG) log("processPlusCode, retStr=" + retStr);
         return retStr;
     }
 
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index ab63e1d..6c35058 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -3023,9 +3023,9 @@
     }
 
     /**
-     * Override the branding for the input ICCID.
+     * Override the branding for the current ICCID.
      *
-     * Once set, whenever the ICCID is inserted into the device, the service
+     * Once set, whenever the SIM is present in the device, the service
      * provider name (SPN) and the operator name will both be replaced by the
      * brand value input. To unset the value, the same function should be
      * called with a null brand value.
@@ -3034,14 +3034,12 @@
      *   {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}
      *  or has to be carrier app - see #hasCarrierPrivileges.
      *
-     * @param iccId The ICCID of that the branding applies to.
      * @param brand The brand name to display/set.
      * @return true if the operation was executed correctly.
      */
-    public boolean setOperatorBrandOverride(String iccId, String brand) {
-        // TODO: Validate ICCID format.
+    public boolean setOperatorBrandOverride(String brand) {
         try {
-            return getITelephony().setOperatorBrandOverride(iccId, brand);
+            return getITelephony().setOperatorBrandOverride(brand);
         } catch (RemoteException ex) {
             Rlog.e(TAG, "setOperatorBrandOverride RemoteException", ex);
         } catch (NullPointerException ex) {
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index 5c3dcdb..f587d72 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -766,9 +766,9 @@
     String getLine1AlphaTagForDisplay(long subId);
 
     /**
-     * Override the operator branding for the input ICCID.
+     * Override the operator branding for the current ICCID.
      *
-     * Once set, whenever the ICCID is inserted into the device, the service
+     * Once set, whenever the SIM is present in the device, the service
      * provider name (SPN) and the operator name will both be replaced by the
      * brand value input. To unset the value, the same function should be
      * called with a null brand value.
@@ -777,11 +777,10 @@
      *   {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}
      *  or has to be carrier app - see #hasCarrierPrivileges.
      *
-     * @param iccid The ICCID of that the branding applies to.
      * @param brand The brand name to display/set.
      * @return true if the operation was executed correctly.
      */
-    boolean setOperatorBrandOverride(String iccId, String brand);
+    boolean setOperatorBrandOverride(String brand);
 
     /**
      * Returns the result and response from RIL for oem request
diff --git a/telephony/java/com/android/internal/telephony/TelephonyProperties.java b/telephony/java/com/android/internal/telephony/TelephonyProperties.java
index 5ec4247..34992b8 100644
--- a/telephony/java/com/android/internal/telephony/TelephonyProperties.java
+++ b/telephony/java/com/android/internal/telephony/TelephonyProperties.java
@@ -123,8 +123,8 @@
     /** Indicate the timer value for exiting emergency callback mode */
     static final String PROPERTY_ECM_EXIT_TIMER = "ro.cdma.ecmexittimer";
 
-    /** The international dialing prefix conversion string */
-    static final String PROPERTY_IDP_STRING = "ro.cdma.idpstring";
+    /** the international dialing prefix of current operator network */
+    static final String PROPERTY_OPERATOR_IDP_STRING = "telephony.operator.idpstring";
 
     /**
      * Defines the schema for the carrier specified OTASP number