Merge "Expose network scoring APIs to /system apps." into lmp-dev
diff --git a/api/current.txt b/api/current.txt
index b2689bb..87ea82e 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -7191,6 +7191,7 @@
     field public static final java.lang.String SEARCH_SERVICE = "search";
     field public static final java.lang.String SENSOR_SERVICE = "sensor";
     field public static final java.lang.String STORAGE_SERVICE = "storage";
+    field public static final java.lang.String TELECOMM_SERVICE = "telecomm";
     field public static final java.lang.String TELEPHONY_SERVICE = "phone";
     field public static final java.lang.String TEXT_SERVICES_MANAGER_SERVICE = "textservices";
     field public static final java.lang.String TV_INPUT_SERVICE = "tv_input";
@@ -15115,6 +15116,7 @@
     field public static final int AMR_WB = 2; // 0x2
     field public static final int DEFAULT = 0; // 0x0
     field public static final int HE_AAC = 4; // 0x4
+    field public static final int VORBIS = 6; // 0x6
   }
 
   public final class MediaRecorder.AudioSource {
@@ -15145,6 +15147,7 @@
     field public static final int MPEG_4 = 2; // 0x2
     field public static final deprecated int RAW_AMR = 3; // 0x3
     field public static final int THREE_GPP = 1; // 0x1
+    field public static final int WEBM = 9; // 0x9
   }
 
   public final class MediaRecorder.VideoEncoder {
@@ -15152,6 +15155,7 @@
     field public static final int H263 = 1; // 0x1
     field public static final int H264 = 2; // 0x2
     field public static final int MPEG_4_SP = 3; // 0x3
+    field public static final int VP8 = 4; // 0x4
   }
 
   public final class MediaRecorder.VideoSource {
@@ -25393,9 +25397,11 @@
   }
 
   public static abstract interface Telephony.BaseMmsColumns implements android.provider.BaseColumns {
+    field public static final java.lang.String ARCHIVED = "archived";
     field public static final java.lang.String CONTENT_CLASS = "ct_cls";
     field public static final java.lang.String CONTENT_LOCATION = "ct_l";
     field public static final java.lang.String CONTENT_TYPE = "ct_t";
+    field public static final java.lang.String CREATOR = "creator";
     field public static final java.lang.String DATE = "date";
     field public static final java.lang.String DATE_SENT = "date_sent";
     field public static final java.lang.String DELIVERY_REPORT = "d_rpt";
@@ -25618,7 +25624,9 @@
 
   public static abstract interface Telephony.TextBasedSmsColumns {
     field public static final java.lang.String ADDRESS = "address";
+    field public static final java.lang.String ARCHIVED = "archived";
     field public static final java.lang.String BODY = "body";
+    field public static final java.lang.String CREATOR = "creator";
     field public static final java.lang.String DATE = "date";
     field public static final java.lang.String DATE_SENT = "date_sent";
     field public static final java.lang.String ERROR_CODE = "error_code";
@@ -28425,6 +28433,14 @@
     field public static final java.lang.String EXTRA_START_CALL_WITH_VIDEO_STATE = "android.intent.extra.START_CALL_WITH_VIDEO_STATE";
   }
 
+  public class TelecommManager {
+    method public void clearAccounts(java.lang.String);
+    method public java.util.List<android.telecomm.PhoneAccount> getEnabledPhoneAccounts();
+    method public android.telecomm.PhoneAccountMetadata getPhoneAccountMetadata(android.telecomm.PhoneAccount);
+    method public void registerPhoneAccount(android.telecomm.PhoneAccount, android.telecomm.PhoneAccountMetadata);
+    method public void unregisterPhoneAccount(android.telecomm.PhoneAccount);
+  }
+
   public class VideoCallProfile implements android.os.Parcelable {
     ctor public VideoCallProfile(int, int);
     method public int describeContents();
@@ -28642,6 +28658,44 @@
     field public static final int VOICEMAIL_NUMBER_MISSING = 40; // 0x28
   }
 
+  public class MessagingConfigurationManager {
+    method public boolean getCarrierConfigBoolean(java.lang.String, boolean);
+    method public int getCarrierConfigInt(java.lang.String, int);
+    method public java.lang.String getCarrierConfigString(java.lang.String, java.lang.String);
+    method public static android.telephony.MessagingConfigurationManager getDefault();
+    method public void setCarrierConfigBoolean(java.lang.String, boolean);
+    method public void setCarrierConfigInt(java.lang.String, int);
+    method public void setCarrierConfigString(java.lang.String, java.lang.String);
+    field public static final java.lang.String CONF_ALIAS_ENABLED = "aliasEnabled";
+    field public static final java.lang.String CONF_ALIAS_MAX_CHARS = "aliasMaxChars";
+    field public static final java.lang.String CONF_ALIAS_MIN_CHARS = "aliasMinChars";
+    field public static final java.lang.String CONF_ALLOW_ATTACH_AUDIO = "allowAttachAudio";
+    field public static final java.lang.String CONF_APPEND_TRANSACTION_ID = "enabledTransID";
+    field public static final java.lang.String CONF_EMAIL_GATEWAY_NUMBER = "emailGatewayNumber";
+    field public static final java.lang.String CONF_HTTP_PARAMS = "httpParams";
+    field public static final java.lang.String CONF_HTTP_SOCKET_TIMEOUT = "httpSocketTimeout";
+    field public static final java.lang.String CONF_MAX_IMAGE_HEIGHT = "maxImageHeight";
+    field public static final java.lang.String CONF_MAX_IMAGE_WIDTH = "maxImageWidth";
+    field public static final java.lang.String CONF_MAX_MESSAGE_SIZE = "maxMessageSize";
+    field public static final java.lang.String CONF_MESSAGE_TEXT_MAX_SIZE = "maxMessageTextSize";
+    field public static final java.lang.String CONF_MMS_DELIVERY_REPORT_ENABLED = "enableMMSDeliveryReports";
+    field public static final java.lang.String CONF_MMS_ENABLED = "enabledMMS";
+    field public static final java.lang.String CONF_MMS_READ_REPORT_ENABLED = "enableMMSReadReports";
+    field public static final java.lang.String CONF_MULTIPART_SMS_ENABLED = "enableMultipartSMS";
+    field public static final java.lang.String CONF_NAI_SUFFIX = "naiSuffix";
+    field public static final java.lang.String CONF_NOTIFY_WAP_MMSC_ENABLED = "enabledNotifyWapMMSC";
+    field public static final java.lang.String CONF_RECIPIENT_LIMIT = "recipientLimit";
+    field public static final java.lang.String CONF_SEND_MULTIPART_SMS_AS_SEPARATE_MESSAGES = "sendMultipartSmsAsSeparateMessages";
+    field public static final java.lang.String CONF_SMS_DELIVERY_REPORT_ENABLED = "enableSMSDeliveryReports";
+    field public static final java.lang.String CONF_SMS_TO_MMS_TEXT_LENGTH_THRESHOLD = "smsToMmsTextLengthThreshold";
+    field public static final java.lang.String CONF_SMS_TO_MMS_TEXT_THRESHOLD = "smsToMmsTextThreshold";
+    field public static final java.lang.String CONF_SUBJECT_MAX_LENGTH = "maxSubjectLength";
+    field public static final java.lang.String CONF_SUPPORT_MMS_CONTENT_DISPOSITION = "supportMmsContentDisposition";
+    field public static final java.lang.String CONF_UA_PROF_TAG_NAME = "uaProfTagName";
+    field public static final java.lang.String CONF_UA_PROF_URL = "uaProfUrl";
+    field public static final java.lang.String CONF_USER_AGENT = "userAgent";
+  }
+
   public class NeighboringCellInfo implements android.os.Parcelable {
     ctor public deprecated NeighboringCellInfo();
     ctor public deprecated NeighboringCellInfo(int, int);
@@ -28784,19 +28838,43 @@
   }
 
   public final class SmsManager {
+    method public android.net.Uri addMultimediaMessageDraft(byte[]);
+    method public android.net.Uri addTextMessageDraft(java.lang.String, java.lang.String);
+    method public boolean deleteStoredConversation(long);
+    method public boolean deleteStoredMessage(android.net.Uri);
     method public java.util.ArrayList<java.lang.String> divideMessage(java.lang.String);
+    method public void downloadMultimediaMessage(java.lang.String, android.app.PendingIntent);
+    method public boolean getAutoPersisting();
     method public static android.telephony.SmsManager getDefault();
+    method public android.net.Uri importMultimediaMessage(byte[], java.lang.String, long, boolean, boolean);
+    method public android.net.Uri importTextMessage(java.lang.String, int, java.lang.String, long, boolean, boolean);
     method public void injectSmsPdu(byte[], java.lang.String, android.app.PendingIntent);
     method public void sendDataMessage(java.lang.String, java.lang.String, short, byte[], android.app.PendingIntent, android.app.PendingIntent);
+    method public void sendMultimediaMessage(byte[], java.lang.String, android.app.PendingIntent);
     method public void sendMultipartTextMessage(java.lang.String, java.lang.String, java.util.ArrayList<java.lang.String>, java.util.ArrayList<android.app.PendingIntent>, java.util.ArrayList<android.app.PendingIntent>);
+    method public void sendStoredMultimediaMessage(android.net.Uri, android.app.PendingIntent);
+    method public void sendStoredMultipartTextMessage(android.net.Uri, java.lang.String, java.util.ArrayList<android.app.PendingIntent>, java.util.ArrayList<android.app.PendingIntent>);
+    method public void sendStoredTextMessage(android.net.Uri, java.lang.String, android.app.PendingIntent, android.app.PendingIntent);
     method public void sendTextMessage(java.lang.String, java.lang.String, java.lang.String, android.app.PendingIntent, android.app.PendingIntent);
+    method public void setAutoPersisting(boolean);
     method public void updateMmsDownloadStatus(int, byte[]);
     method public void updateMmsSendStatus(int, boolean);
     method public void updateSmsSendStatus(int, boolean);
+    method public boolean updateStoredMessageStatus(android.net.Uri, android.content.ContentValues);
+    field public static final java.lang.String MESSAGE_STATUS_ARCHIVED = "archived";
+    field public static final java.lang.String MESSAGE_STATUS_READ = "read";
+    field public static final java.lang.String MESSAGE_STATUS_SEEN = "seen";
+    field public static final int MMS_ERROR_HTTP_FAILURE = 4; // 0x4
+    field public static final int MMS_ERROR_INVALID_APN = 2; // 0x2
+    field public static final int MMS_ERROR_UNABLE_CONNECT_MMS = 3; // 0x3
+    field public static final int MMS_ERROR_UNSPECIFIED = 1; // 0x1
+    field public static final java.lang.String MMS_EXTRA_DATA = "data";
     field public static final int RESULT_ERROR_GENERIC_FAILURE = 1; // 0x1
     field public static final int RESULT_ERROR_NO_SERVICE = 4; // 0x4
     field public static final int RESULT_ERROR_NULL_PDU = 3; // 0x3
     field public static final int RESULT_ERROR_RADIO_OFF = 2; // 0x2
+    field public static final int SMS_TYPE_INCOMING = 0; // 0x0
+    field public static final int SMS_TYPE_OUTGOING = 1; // 0x1
     field public static final int STATUS_ON_ICC_FREE = 0; // 0x0
     field public static final int STATUS_ON_ICC_READ = 1; // 0x1
     field public static final int STATUS_ON_ICC_SENT = 5; // 0x5
diff --git a/cmds/pm/src/com/android/commands/pm/Pm.java b/cmds/pm/src/com/android/commands/pm/Pm.java
index b7f1ff9..d6c17ae 100644
--- a/cmds/pm/src/com/android/commands/pm/Pm.java
+++ b/cmds/pm/src/com/android/commands/pm/Pm.java
@@ -998,8 +998,8 @@
 
         final InstallSessionParams params = new InstallSessionParams();
         params.installFlags = PackageManager.INSTALL_ALL_USERS;
-        params.mode = InstallSessionParams.MODE_FULL_INSTALL;
-        params.progressMax = -1;
+        params.setModeFullInstall();
+        params.setProgressMax(-1);
 
         String opt;
         while ((opt = nextOption()) != null) {
@@ -1021,10 +1021,11 @@
             } else if (opt.equals("-d")) {
                 params.installFlags |= PackageManager.INSTALL_ALLOW_DOWNGRADE;
             } else if (opt.equals("-p")) {
-                params.mode = InstallSessionParams.MODE_INHERIT_EXISTING;
+                params.setModeInheritExisting();
             } else if (opt.equals("-S")) {
-                params.deltaSize = Long.parseLong(nextOptionData());
-                params.progressMax = (int) params.deltaSize;
+                final long deltaSize = Long.parseLong(nextOptionData());
+                params.setDeltaSize(deltaSize);
+                params.setProgressMax((int) params.deltaSize);
             } else if (opt.equals("--abi")) {
                 params.abiOverride = checkAbiArgument(nextOptionData());
             } else {
diff --git a/core/java/android/animation/FloatKeyframeSet.java b/core/java/android/animation/FloatKeyframeSet.java
index 377b5a05..2d87e13 100644
--- a/core/java/android/animation/FloatKeyframeSet.java
+++ b/core/java/android/animation/FloatKeyframeSet.java
@@ -57,6 +57,11 @@
         return newSet;
     }
 
+    @Override
+    void invalidateCache() {
+        firstTime = true;
+    }
+
     public float getFloatValue(float fraction) {
         if (mNumKeyframes == 2) {
             if (firstTime) {
diff --git a/core/java/android/animation/IntKeyframeSet.java b/core/java/android/animation/IntKeyframeSet.java
index 7b7c876..ce47e2b 100644
--- a/core/java/android/animation/IntKeyframeSet.java
+++ b/core/java/android/animation/IntKeyframeSet.java
@@ -57,6 +57,11 @@
         return newSet;
     }
 
+    @Override
+    void invalidateCache() {
+        firstTime = true;
+    }
+
     public int getIntValue(float fraction) {
         if (mNumKeyframes == 2) {
             if (firstTime) {
diff --git a/core/java/android/animation/Keyframe.java b/core/java/android/animation/Keyframe.java
index dc8538f..5483c49 100644
--- a/core/java/android/animation/Keyframe.java
+++ b/core/java/android/animation/Keyframe.java
@@ -35,6 +35,20 @@
  */
 public abstract class Keyframe implements Cloneable {
     /**
+     * Flag to indicate whether this keyframe has a valid value. This flag is used when an
+     * animation first starts, to populate placeholder keyframes with real values derived
+     * from the target object.
+     */
+    boolean mHasValue;
+
+    /**
+     * Flag to indicate whether the value in the keyframe was read from the target object or not.
+     * If so, its value will be recalculated if target changes.
+     */
+    boolean mValueWasSetOnStart;
+
+
+    /**
      * The time at which mValue will hold true.
      */
     float mFraction;
@@ -51,12 +65,7 @@
      */
     private TimeInterpolator mInterpolator = null;
 
-    /**
-     * Flag to indicate whether this keyframe has a valid value. This flag is used when an
-     * animation first starts, to populate placeholder keyframes with real values derived
-     * from the target object.
-     */
-    boolean mHasValue = false;
+
 
     /**
      * Constructs a Keyframe object with the given time and value. The time defines the
@@ -166,6 +175,20 @@
     }
 
     /**
+     * If the Keyframe's value was acquired from the target object, this flag should be set so that,
+     * if target changes, value will be reset.
+     *
+     * @return boolean Whether this Keyframe's value was retieved from the target object or not.
+     */
+    boolean valueWasSetOnStart() {
+        return mValueWasSetOnStart;
+    }
+
+    void setValueWasSetOnStart(boolean valueWasSetOnStart) {
+        mValueWasSetOnStart = valueWasSetOnStart;
+    }
+
+    /**
      * Gets the value for this Keyframe.
      *
      * @return The value for this Keyframe.
@@ -261,7 +284,8 @@
 
         @Override
         public ObjectKeyframe clone() {
-            ObjectKeyframe kfClone = new ObjectKeyframe(getFraction(), mHasValue ? mValue : null);
+            ObjectKeyframe kfClone = new ObjectKeyframe(getFraction(), hasValue() ? mValue : null);
+            kfClone.mValueWasSetOnStart = mValueWasSetOnStart;
             kfClone.setInterpolator(getInterpolator());
             return kfClone;
         }
@@ -310,6 +334,7 @@
                     new IntKeyframe(getFraction(), mValue) :
                     new IntKeyframe(getFraction());
             kfClone.setInterpolator(getInterpolator());
+            kfClone.mValueWasSetOnStart = mValueWasSetOnStart;
             return kfClone;
         }
     }
@@ -356,6 +381,7 @@
                     new FloatKeyframe(getFraction(), mValue) :
                     new FloatKeyframe(getFraction());
             kfClone.setInterpolator(getInterpolator());
+            kfClone.mValueWasSetOnStart = mValueWasSetOnStart;
             return kfClone;
         }
     }
diff --git a/core/java/android/animation/KeyframeSet.java b/core/java/android/animation/KeyframeSet.java
index 4026f7f..a3db3a1 100644
--- a/core/java/android/animation/KeyframeSet.java
+++ b/core/java/android/animation/KeyframeSet.java
@@ -48,6 +48,13 @@
         mInterpolator = mLastKeyframe.getInterpolator();
     }
 
+    /**
+     * If subclass has variables that it calculates based on the Keyframes, it should reset them
+     * when this method is called because Keyframe contents might have changed.
+     */
+    void invalidateCache() {
+    }
+
     public static KeyframeSet ofInt(int... values) {
         int numKeyframes = values.length;
         IntKeyframe keyframes[] = new IntKeyframe[Math.max(numKeyframes,2)];
diff --git a/core/java/android/animation/ObjectAnimator.java b/core/java/android/animation/ObjectAnimator.java
index da56a77..a4ac73f 100644
--- a/core/java/android/animation/ObjectAnimator.java
+++ b/core/java/android/animation/ObjectAnimator.java
@@ -883,10 +883,7 @@
         final Object oldTarget = getTarget();
         if (oldTarget != target) {
             mTarget = target == null ? null : new WeakReference<Object>(target);
-            if (oldTarget != null && target != null && oldTarget.getClass() == target.getClass()) {
-                return;
-            }
-            // New target type should cause re-initialization prior to starting
+            // New target should cause re-initialization prior to starting
             mInitialized = false;
         }
     }
diff --git a/core/java/android/animation/PropertyValuesHolder.java b/core/java/android/animation/PropertyValuesHolder.java
index bdfbde1..73b83ef 100644
--- a/core/java/android/animation/PropertyValuesHolder.java
+++ b/core/java/android/animation/PropertyValuesHolder.java
@@ -775,16 +775,18 @@
      * @param target The object on which the setter (and possibly getter) exist.
      */
     void setupSetterAndGetter(Object target) {
+        mKeyframeSet.invalidateCache();
         if (mProperty != null) {
             // check to make sure that mProperty is on the class of target
             try {
                 Object testValue = null;
                 for (Keyframe kf : mKeyframeSet.mKeyframes) {
-                    if (!kf.hasValue()) {
+                    if (!kf.hasValue() || kf.valueWasSetOnStart()) {
                         if (testValue == null) {
                             testValue = convertBack(mProperty.get(target));
                         }
                         kf.setValue(testValue);
+                        kf.setValueWasSetOnStart(true);
                     }
                 }
                 return;
@@ -799,7 +801,7 @@
             setupSetter(targetClass);
         }
         for (Keyframe kf : mKeyframeSet.mKeyframes) {
-            if (!kf.hasValue()) {
+            if (!kf.hasValue() || kf.valueWasSetOnStart()) {
                 if (mGetter == null) {
                     setupGetter(targetClass);
                     if (mGetter == null) {
@@ -810,6 +812,7 @@
                 try {
                     Object value = convertBack(mGetter.invoke(target));
                     kf.setValue(value);
+                    kf.setValueWasSetOnStart(true);
                 } catch (InvocationTargetException e) {
                     Log.e("PropertyValuesHolder", e.toString());
                 } catch (IllegalAccessException e) {
diff --git a/core/java/android/animation/StateListAnimator.java b/core/java/android/animation/StateListAnimator.java
index 810f050..7256a06 100644
--- a/core/java/android/animation/StateListAnimator.java
+++ b/core/java/android/animation/StateListAnimator.java
@@ -57,6 +57,7 @@
     private AnimatorListenerAdapter mAnimatorListener = new AnimatorListenerAdapter() {
         @Override
         public void onAnimationEnd(Animator animation) {
+            animation.setTarget(null);
             if (mRunningAnimator == animation) {
                 mRunningAnimator = null;
             }
@@ -151,7 +152,7 @@
 
     private void start(Tuple match) {
         match.mAnimator.setTarget(getTarget());
-        mRunningAnimator = match.mAnimator.clone();
+        mRunningAnimator = match.mAnimator;
         mRunningAnimator.start();
     }
 
diff --git a/core/java/android/app/backup/BackupTransport.java b/core/java/android/app/backup/BackupTransport.java
index ba2930b..28108a0 100644
--- a/core/java/android/app/backup/BackupTransport.java
+++ b/core/java/android/app/backup/BackupTransport.java
@@ -331,6 +331,10 @@
      * its datastore, if appropriate, and close the socket that had been provided in
      * {@link #performFullBackup(PackageInfo, ParcelFileDescriptor)}.
      *
+     * <p class="note">If the transport returns TRANSPORT_OK from this method, then the
+     * OS will always provide a matching call to {@link #finishBackup()} even if sending
+     * data via {@link #sendBackupData(int)} failed at some point.
+     *
      * @param targetPackage The package whose data is to follow.
      * @param socket The socket file descriptor through which the data will be provided.
      *    If the transport returns {@link #TRANSPORT_PACKAGE_REJECTED} here, it must still
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index d068b1f..1569b9f 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -2539,7 +2539,6 @@
      *
      * @see #getSystemService
      * @see android.telecomm.TelecommManager
-     * @hide
      */
     public static final String TELECOMM_SERVICE = "telecomm";
 
diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java
index f2f363a..8c9b819 100644
--- a/core/java/android/view/HardwareRenderer.java
+++ b/core/java/android/view/HardwareRenderer.java
@@ -327,6 +327,12 @@
     }
 
     /**
+     *  Indicates that the content drawn by HardwareDrawCallbacks needs to
+     *  be updated, which will be done by the next call to draw()
+     */
+    abstract void invalidateRoot();
+
+    /**
      * Draws the specified view.
      *
      * @param view The view to draw.
diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java
index e2ebf6e..b033780 100644
--- a/core/java/android/view/ThreadedRenderer.java
+++ b/core/java/android/view/ThreadedRenderer.java
@@ -96,6 +96,7 @@
     private RenderNode mRootNode;
     private Choreographer mChoreographer;
     private boolean mProfilingEnabled;
+    private boolean mRootNodeNeedsUpdate;
 
     ThreadedRenderer(Context context, boolean translucent) {
         final TypedArray a = context.obtainStyledAttributes(
@@ -255,30 +256,41 @@
         return changed;
     }
 
-    private void updateRootDisplayList(View view, HardwareDrawCallbacks callbacks) {
+    private void updateViewTreeDisplayList(View view) {
         view.mPrivateFlags |= View.PFLAG_DRAWN;
-
         view.mRecreateDisplayList = (view.mPrivateFlags & View.PFLAG_INVALIDATED)
                 == View.PFLAG_INVALIDATED;
         view.mPrivateFlags &= ~View.PFLAG_INVALIDATED;
-
-        Trace.traceBegin(Trace.TRACE_TAG_VIEW, "getDisplayList");
-        HardwareCanvas canvas = mRootNode.start(mSurfaceWidth, mSurfaceHeight);
-        try {
-            canvas.save();
-            canvas.translate(mInsetLeft, mInsetTop);
-            callbacks.onHardwarePreDraw(canvas);
-            canvas.drawRenderNode(view.getDisplayList());
-            callbacks.onHardwarePostDraw(canvas);
-            canvas.restore();
-        } finally {
-            mRootNode.end(canvas);
-            Trace.traceEnd(Trace.TRACE_TAG_VIEW);
-        }
-
+        view.getDisplayList();
         view.mRecreateDisplayList = false;
     }
 
+    private void updateRootDisplayList(View view, HardwareDrawCallbacks callbacks) {
+        Trace.traceBegin(Trace.TRACE_TAG_VIEW, "getDisplayList");
+        updateViewTreeDisplayList(view);
+
+        if (mRootNodeNeedsUpdate || !mRootNode.isValid()) {
+            HardwareCanvas canvas = mRootNode.start(mSurfaceWidth, mSurfaceHeight);
+            try {
+                canvas.save();
+                canvas.translate(mInsetLeft, mInsetTop);
+                callbacks.onHardwarePreDraw(canvas);
+                canvas.drawRenderNode(view.getDisplayList());
+                callbacks.onHardwarePostDraw(canvas);
+                canvas.restore();
+                mRootNodeNeedsUpdate = false;
+            } finally {
+                mRootNode.end(canvas);
+            }
+        }
+        Trace.traceEnd(Trace.TRACE_TAG_VIEW);
+    }
+
+    @Override
+    void invalidateRoot() {
+        mRootNodeNeedsUpdate = true;
+    }
+
     @Override
     void draw(View view, AttachInfo attachInfo, HardwareDrawCallbacks callbacks) {
         attachInfo.mIgnoreDirtyState = true;
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index b554548..f3ad988 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -463,8 +463,13 @@
 
                 // Compute surface insets required to draw at specified Z value.
                 // TODO: Use real shadow insets for a constant max Z.
-                final int surfaceInset = (int) Math.ceil(view.getZ() * 2);
-                attrs.surfaceInsets.set(surfaceInset, surfaceInset, surfaceInset, surfaceInset);
+                if (view.isHardwareAccelerated()) {
+                    final int surfaceInset = (int) Math.ceil(view.getZ() * 2);
+                    attrs.surfaceInsets.set(surfaceInset, surfaceInset, surfaceInset, surfaceInset);
+                } else {
+                    // Software accelerated windows can't use insets.
+                    attrs.surfaceInsets.setEmpty();
+                }
 
                 CompatibilityInfo compatibilityInfo = mDisplayAdjustments.getCompatibilityInfo();
                 mTranslator = compatibilityInfo.getTranslator();
@@ -2375,8 +2380,6 @@
             attachInfo.mTreeObserver.dispatchOnScrollChanged();
         }
 
-        final WindowManager.LayoutParams params = mWindowAttributes;
-        final Rect surfaceInsets = params != null ? params.surfaceInsets : null;
         boolean animating = mScroller != null && mScroller.computeScrollOffset();
         final int curScrollY;
         if (animating) {
@@ -2434,14 +2437,27 @@
 
         attachInfo.mTreeObserver.dispatchOnDraw();
 
-        final int xOffset = surfaceInsets != null ? -surfaceInsets.left : 0;
-        final int yOffset = curScrollY + (surfaceInsets != null ? -surfaceInsets.top : 0);
+        int xOffset = 0;
+        int yOffset = curScrollY;
+        final WindowManager.LayoutParams params = mWindowAttributes;
+        final Rect surfaceInsets = params != null ? params.surfaceInsets : null;
+        if (surfaceInsets != null) {
+            xOffset -= surfaceInsets.left;
+            yOffset -= surfaceInsets.top;
+
+            // Offset dirty rect for surface insets.
+            dirty.offset(surfaceInsets.left, surfaceInsets.right);
+        }
+
         if (!dirty.isEmpty() || mIsAnimating) {
             if (attachInfo.mHardwareRenderer != null && attachInfo.mHardwareRenderer.isEnabled()) {
                 // Draw with hardware renderer.
                 mIsAnimating = false;
-                mHardwareYOffset = yOffset;
-                mHardwareXOffset = xOffset;
+                if (mHardwareYOffset != yOffset || mHardwareXOffset != xOffset) {
+                    mHardwareYOffset = yOffset;
+                    mHardwareXOffset = xOffset;
+                    mAttachInfo.mHardwareRenderer.invalidateRoot();
+                }
                 mResizeAlpha = resizeAlpha;
 
                 dirty.setEmpty();
@@ -2493,19 +2509,19 @@
             boolean scalingRequired, Rect dirty) {
 
         // Draw with software renderer.
-        Canvas canvas;
+        final Canvas canvas;
         try {
-            int left = dirty.left;
-            int top = dirty.top;
-            int right = dirty.right;
-            int bottom = dirty.bottom;
+            final int left = dirty.left;
+            final int top = dirty.top;
+            final int right = dirty.right;
+            final int bottom = dirty.bottom;
 
             canvas = mSurface.lockCanvas(dirty);
 
             // The dirty rectangle can be modified by Surface.lockCanvas()
             //noinspection ConstantConditions
-            if (left != dirty.left || top != dirty.top || right != dirty.right ||
-                    bottom != dirty.bottom) {
+            if (left != dirty.left || top != dirty.top || right != dirty.right
+                    || bottom != dirty.bottom) {
                 attachInfo.mIgnoreDirtyState = true;
             }
 
@@ -2827,6 +2843,10 @@
         // Set the new focus host and node.
         mAccessibilityFocusedHost = view;
         mAccessibilityFocusedVirtualView = node;
+
+        if (mAttachInfo.mHardwareRenderer != null) {
+            mAttachInfo.mHardwareRenderer.invalidateRoot();
+        }
     }
 
     @Override
diff --git a/core/java/com/android/internal/app/LocalePicker.java b/core/java/com/android/internal/app/LocalePicker.java
index a866ca7..06fe3bf 100644
--- a/core/java/com/android/internal/app/LocalePicker.java
+++ b/core/java/com/android/internal/app/LocalePicker.java
@@ -16,6 +16,7 @@
 
 package com.android.internal.app;
 
+import android.content.res.TypedArray;
 import com.android.internal.R;
 
 import android.app.ActivityManagerNative;
@@ -227,6 +228,12 @@
     @Override
     public void onActivityCreated(final Bundle savedInstanceState) {
         super.onActivityCreated(savedInstanceState);
+
+        final int[] attrs = { android.R.attr.colorBackground };
+        final TypedArray a = getActivity().getTheme().obtainStyledAttributes(attrs);
+        getListView().setBackgroundColor(a.getColor(0, android.R.color.transparent));
+        a.recycle();
+
         final ArrayAdapter<LocaleInfo> adapter = constructAdapter(getActivity(),
                 isInDeveloperMode());
         setListAdapter(adapter);
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index f40b84c..cc481e1 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -57,6 +57,7 @@
 public class LockPatternUtils {
 
     private static final String TAG = "LockPatternUtils";
+    private static final boolean DEBUG = false;
 
     /**
      * The maximum number of incorrect attempts before the user is prevented
@@ -1046,8 +1047,11 @@
             return false;
         }
 
-
-        return true;
+        // TODO: If we decide not to proceed with Face Unlock as a trustlet, this must be changed
+        // back to returning true.  If we become certain that Face Unlock will be a trustlet, this
+        // entire function and a lot of other code can be removed.
+        if (DEBUG) Log.d(TAG, "Forcing isBiometricWeakInstalled() to return false to disable it");
+        return false;
     }
 
     /**
diff --git a/core/jni/android_view_ThreadedRenderer.cpp b/core/jni/android_view_ThreadedRenderer.cpp
index aab48b3..988d461 100644
--- a/core/jni/android_view_ThreadedRenderer.cpp
+++ b/core/jni/android_view_ThreadedRenderer.cpp
@@ -138,13 +138,6 @@
         }
     }
 
-protected:
-    virtual void damageSelf(TreeInfo& info) {
-        // Intentionally a no-op. As RootRenderNode gets a new DisplayListData
-        // every frame this would result in every draw push being a full inval,
-        // which is wrong. Only RootRenderNode has this issue.
-    }
-
 private:
     sp<Looper> mLooper;
     std::vector<OnFinishedEvent> mOnFinishedEvents;
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 55e02fb..658ef96 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -235,6 +235,7 @@
     <protected-broadcast android:name="com.android.server.WifiManager.action.DELAYED_DRIVER_STOP" />
     <protected-broadcast android:name="android.net.wifi.WIFI_STATE_CHANGED" />
     <protected-broadcast android:name="android.net.wifi.WIFI_AP_STATE_CHANGED" />
+    <protected-broadcast android:name="android.net.wifi.WIFI_CREDENTIAL_CHANGED" />
     <protected-broadcast android:name="android.net.wifi.WIFI_SCAN_AVAILABLE" />
     <protected-broadcast android:name="android.net.wifi.SCAN_RESULTS" />
     <protected-broadcast android:name="android.net.wifi.RSSI_CHANGED" />
@@ -805,6 +806,19 @@
         android:description="@string/permdesc_changeWifiState"
         android:label="@string/permlab_changeWifiState" />
 
+    <!-- @SystemApi @hide Allows applications to read Wi-Fi credential.
+         <p>Not for use by third-party applications. -->
+    <permission android:name="android.permission.READ_WIFI_CREDENTIAL"
+        android:permissionGroup="android.permission-group.NETWORK"
+        android:protectionLevel="signature|system" />
+
+    <!-- @SystemApi @hide Allow system apps to receive broadcast
+         when a wifi network credential is changed.
+         <p>Not for use by third-party applications. -->
+    <permission android:name="android.permission.RECEIVE_WIFI_CREDENTIAL_CHANGE"
+        android:permissionGroup="android.permission-group.NETWORK"
+        android:protectionLevel="signature|system" />
+
     <!-- @hide -->
     <permission android:name="android.permission.ACCESS_WIMAX_STATE"
         android:permissionGroup="android.permission-group.NETWORK"
diff --git a/core/res/res/layout/preference_child_material.xml b/core/res/res/layout/preference_child_material.xml
index 690d64a..e5a8819 100644
--- a/core/res/res/layout/preference_child_material.xml
+++ b/core/res/res/layout/preference_child_material.xml
@@ -29,7 +29,7 @@
         android:layout_width="wrap_content"
         android:layout_height="match_parent"
         android:minWidth="58dip"
-        android:gravity="left|center_vertical"
+        android:gravity="start|center_vertical"
         android:orientation="horizontal">
         <ImageView
             android:id="@+android:id/icon"
@@ -67,7 +67,7 @@
         android:layout_width="wrap_content"
         android:layout_height="match_parent"
         android:minWidth="58dip"
-        android:gravity="right|center_vertical"
+        android:gravity="end|center_vertical"
         android:orientation="vertical" />
 
 </LinearLayout>
diff --git a/core/res/res/layout/preference_information_material.xml b/core/res/res/layout/preference_information_material.xml
index f21640fc..d283f62 100644
--- a/core/res/res/layout/preference_information_material.xml
+++ b/core/res/res/layout/preference_information_material.xml
@@ -30,7 +30,7 @@
         android:layout_width="wrap_content"
         android:layout_height="match_parent"
         android:minWidth="58dip"
-        android:gravity="left|center_vertical"
+        android:gravity="start|center_vertical"
         android:orientation="horizontal">
         <ImageView
             android:id="@+android:id/icon"
@@ -68,7 +68,7 @@
         android:layout_width="wrap_content"
         android:layout_height="match_parent"
         android:minWidth="58dip"
-        android:gravity="right|center_vertical"
+        android:gravity="end|center_vertical"
         android:orientation="vertical" />
 
 </LinearLayout>
diff --git a/core/res/res/layout/preference_material.xml b/core/res/res/layout/preference_material.xml
index a9599139..3919f5f 100644
--- a/core/res/res/layout/preference_material.xml
+++ b/core/res/res/layout/preference_material.xml
@@ -71,7 +71,7 @@
         android:layout_width="wrap_content"
         android:layout_height="match_parent"
         android:minWidth="58dip"
-        android:gravity="right|center_vertical"
+        android:gravity="end|center_vertical"
         android:orientation="vertical" />
 
 </LinearLayout>
diff --git a/docs/html/google/gcm/ccs.jd b/docs/html/google/gcm/ccs.jd
index 4389e3d..90d8d4c 100644
--- a/docs/html/google/gcm/ccs.jd
+++ b/docs/html/google/gcm/ccs.jd
@@ -535,6 +535,8 @@
 import org.jivesoftware.smack.ConnectionListener;
 import org.jivesoftware.smack.PacketInterceptor;
 import org.jivesoftware.smack.PacketListener;
+import org.jivesoftware.smack.SmackException;
+import org.jivesoftware.smack.SmackException.NotConnectedException;
 import org.jivesoftware.smack.XMPPConnection;
 import org.jivesoftware.smack.XMPPException;
 import org.jivesoftware.smack.filter.PacketTypeFilter;
@@ -544,352 +546,378 @@
 import org.jivesoftware.smack.packet.PacketExtension;
 import org.jivesoftware.smack.provider.PacketExtensionProvider;
 import org.jivesoftware.smack.provider.ProviderManager;
+import org.jivesoftware.smack.tcp.XMPPTCPConnection;
 import org.jivesoftware.smack.util.StringUtils;
 import org.json.simple.JSONValue;
 import org.json.simple.parser.ParseException;
 import org.xmlpull.v1.XmlPullParser;
 
+import java.io.IOException;
 import java.util.HashMap;
 import java.util.Map;
-import java.util.Random;
+import java.util.UUID;
 import java.util.logging.Level;
 import java.util.logging.Logger;
 
 import javax.net.ssl.SSLSocketFactory;
+
 /**
- * Sample Smack implementation of a client for GCM Cloud Connection Server.
+ * Sample Smack implementation of a client for GCM Cloud Connection Server. This
+ * code can be run as a standalone CCS client.
  *
  * &lt;p&gt;For illustration purposes only.
  */
 public class SmackCcsClient {
 
-  Logger logger = Logger.getLogger(&quot;SmackCcsClient&quot;);
+    private static final Logger logger = Logger.getLogger(&quot;SmackCcsClient&quot;);
 
-  public static final String GCM_SERVER = &quot;gcm.googleapis.com&quot;;
-  public static final int GCM_PORT = 5235;
+    private static final String GCM_SERVER = &quot;gcm.googleapis.com&quot;;
+    private static final int GCM_PORT = 5235;
 
-  public static final String GCM_ELEMENT_NAME = &quot;gcm&quot;;
-  public static final String GCM_NAMESPACE = &quot;google:mobile:data&quot;;
+    private static final String GCM_ELEMENT_NAME = &quot;gcm&quot;;
+    private static final String GCM_NAMESPACE = &quot;google:mobile:data&quot;;
 
-  static Random random = new Random();
-  XMPPConnection connection;
-  ConnectionConfiguration config;
+    static {
 
-  /**
-   * XMPP Packet Extension for GCM Cloud Connection Server.
-   */
-  class GcmPacketExtension extends DefaultPacketExtension {
-    String json;
-
-    public GcmPacketExtension(String json) {
-      super(GCM_ELEMENT_NAME, GCM_NAMESPACE);
-      this.json = json;
+        ProviderManager.addExtensionProvider(GCM_ELEMENT_NAME, GCM_NAMESPACE,
+            new PacketExtensionProvider() {
+                &#64;Override
+                public PacketExtension parseExtension(XmlPullParser parser) throws
+                        Exception {
+                    String json = parser.nextText();
+                    return new GcmPacketExtension(json);
+                }
+            });
     }
 
-    public String getJson() {
-      return json;
+    private XMPPConnection connection;
+
+    /**
+     * Indicates whether the connection is in draining state, which means that it
+     * will not accept any new downstream messages.
+     */
+    protected volatile boolean connectionDraining = false;
+
+    /**
+     * Sends a downstream message to GCM.
+     *
+     * &#64;return true if the message has been successfully sent.
+     */
+    public boolean sendDownstreamMessage(String jsonRequest) throws
+            NotConnectedException {
+        if (!connectionDraining) {
+            send(jsonRequest);
+            return true;
+        }
+        logger.info(&quot;Dropping downstream message since the connection is draining&quot;);
+        return false;
     }
 
-    &#64;Override
-    public String toXML() {
-      return String.format(&quot;&lt;%s xmlns=\&quot;%s\&quot;&gt;%s&lt;/%s&gt;&quot;, GCM_ELEMENT_NAME,
-          GCM_NAMESPACE, json, GCM_ELEMENT_NAME);
+    /**
+     * Returns a random message id to uniquely identify a message.
+     *
+     * &lt;p&gt;Note: This is generated by a pseudo random number generator for
+     * illustration purpose, and is not guaranteed to be unique.
+     */
+    public String nextMessageId() {
+        return &quot;m-&quot; + UUID.randomUUID().toString();
     }
 
-    &#64;SuppressWarnings(&quot;unused&quot;)
-    public Packet toPacket() {
-      return new Message() {
-        // Must override toXML() because it includes a &lt;body&gt;
+    /**
+     * Sends a packet with contents provided.
+     */
+    protected void send(String jsonRequest) throws NotConnectedException {
+        Packet request = new GcmPacketExtension(jsonRequest).toPacket();
+        connection.sendPacket(request);
+    }
+
+    /**
+     * Handles an upstream data message from a device application.
+     *
+     * &lt;p&gt;This sample echo server sends an echo message back to the device.
+     * Subclasses should override this method to properly process upstream messages.
+     */
+    protected void handleUpstreamMessage(Map&lt;String, Object&gt; jsonObject) {
+        // PackageName of the application that sent this message.
+        String category = (String) jsonObject.get(&quot;category&quot;);
+        String from = (String) jsonObject.get(&quot;from&quot;);
+        &#64;SuppressWarnings(&quot;unchecked&quot;)
+        Map&lt;String, String&gt; payload = (Map&lt;String, String&gt;) jsonObject.get(&quot;data&quot;);
+        payload.put(&quot;ECHO&quot;, &quot;Application: &quot; + category);
+
+        // Send an ECHO response back
+        String echo = createJsonMessage(from, nextMessageId(), payload,
+                &quot;echo:CollapseKey&quot;, null, false);
+
+        try {
+            sendDownstreamMessage(echo);
+        } catch (NotConnectedException e) {
+            logger.log(Level.WARNING, &quot;Not connected anymore, echo message is
+                    not sent&quot;, e);
+        }
+    }
+
+    /**
+     * Handles an ACK.
+     *
+     * &lt;p&gt;Logs a {@code INFO} message, but subclasses could override it to
+     * properly handle ACKs.
+     */
+    protected void handleAckReceipt(Map&lt;String, Object&gt; jsonObject) {
+        String messageId = (String) jsonObject.get(&quot;message_id&quot;);
+        String from = (String) jsonObject.get(&quot;from&quot;);
+        logger.log(Level.INFO, &quot;handleAckReceipt() from: &quot; + from + &quot;,
+                messageId: &quot; + messageId);
+    }
+
+    /**
+     * Handles a NACK.
+     *
+     * &lt;p&gt;Logs a {@code INFO} message, but subclasses could override it to
+     * properly handle NACKs.
+     */
+    protected void handleNackReceipt(Map&lt;String, Object&gt; jsonObject) {
+        String messageId = (String) jsonObject.get(&quot;message_id&quot;);
+        String from = (String) jsonObject.get(&quot;from&quot;);
+        logger.log(Level.INFO, &quot;handleNackReceipt() from: &quot; + from + &quot;,
+                messageId: &quot; + messageId);
+    }
+
+    protected void handleControlMessage(Map&lt;String, Object&gt; jsonObject) {
+        logger.log(Level.INFO, &quot;handleControlMessage(): &quot; + jsonObject);
+        String controlType = (String) jsonObject.get(&quot;control_type&quot;);
+        if (&quot;CONNECTION_DRAINING&quot;.equals(controlType)) {
+            connectionDraining = true;
+        } else {
+            logger.log(Level.INFO, &quot;Unrecognized control type: %s. This could
+                    happen if new features are &quot; + &quot;added to the CCS protocol.&quot;,
+                    controlType);
+        }
+    }
+
+    /**
+     * Creates a JSON encoded GCM message.
+     *
+     * &#64;param to RegistrationId of the target device (Required).
+     * &#64;param messageId Unique messageId for which CCS will send an
+     *         &quot;ack/nack&quot; (Required).
+     * &#64;param payload Message content intended for the application. (Optional).
+     * &#64;param collapseKey GCM collapse_key parameter (Optional).
+     * &#64;param timeToLive GCM time_to_live parameter (Optional).
+     * &#64;param delayWhileIdle GCM delay_while_idle parameter (Optional).
+     * &#64;return JSON encoded GCM message.
+     */
+    public static String createJsonMessage(String to, String messageId,
+            Map&lt;String, String&gt; payload, String collapseKey, Long timeToLive,
+            Boolean delayWhileIdle) {
+        Map&lt;String, Object&gt; message = new HashMap&lt;String, Object&gt;();
+        message.put(&quot;to&quot;, to);
+        if (collapseKey != null) {
+            message.put(&quot;collapse_key&quot;, collapseKey);
+        }
+        if (timeToLive != null) {
+            message.put(&quot;time_to_live&quot;, timeToLive);
+        }
+        if (delayWhileIdle != null &amp;&amp; delayWhileIdle) {
+            message.put(&quot;delay_while_idle&quot;, true);
+        }
+      message.put(&quot;message_id&quot;, messageId);
+      message.put(&quot;data&quot;, payload);
+      return JSONValue.toJSONString(message);
+    }
+
+    /**
+     * Creates a JSON encoded ACK message for an upstream message received
+     * from an application.
+     *
+     * &#64;param to RegistrationId of the device who sent the upstream message.
+     * &#64;param messageId messageId of the upstream message to be acknowledged to CCS.
+     * &#64;return JSON encoded ack.
+     */
+        protected static String createJsonAck(String to, String messageId) {
+        Map&lt;String, Object&gt; message = new HashMap&lt;String, Object&gt;();
+        message.put(&quot;message_type&quot;, &quot;ack&quot;);
+        message.put(&quot;to&quot;, to);
+        message.put(&quot;message_id&quot;, messageId);
+        return JSONValue.toJSONString(message);
+    }
+
+    /**
+     * Connects to GCM Cloud Connection Server using the supplied credentials.
+     *
+     * &#64;param senderId Your GCM project number
+     * &#64;param apiKey API Key of your project
+     */
+    public void connect(long senderId, String apiKey)
+            throws XMPPException, IOException, SmackException {
+        ConnectionConfiguration config =
+                new ConnectionConfiguration(GCM_SERVER, GCM_PORT);
+        config.setSecurityMode(SecurityMode.enabled);
+        config.setReconnectionAllowed(true);
+        config.setRosterLoadedAtLogin(false);
+        config.setSendPresence(false);
+        config.setSocketFactory(SSLSocketFactory.getDefault());
+
+        connection = new XMPPTCPConnection(config);
+        connection.connect();
+
+        connection.addConnectionListener(new LoggingConnectionListener());
+
+        // Handle incoming packets
+        connection.addPacketListener(new PacketListener() {
+
+            &#64;Override
+            public void processPacket(Packet packet) {
+                logger.log(Level.INFO, &quot;Received: &quot; + packet.toXML());
+                Message incomingMessage = (Message) packet;
+                GcmPacketExtension gcmPacket =
+                        (GcmPacketExtension) incomingMessage.
+                        getExtension(GCM_NAMESPACE);
+                String json = gcmPacket.getJson();
+                try {
+                    &#64;SuppressWarnings(&quot;unchecked&quot;)
+                    Map&lt;String, Object&gt; jsonObject =
+                            (Map&lt;String, Object&gt;) JSONValue.
+                            parseWithException(json);
+
+                    // present for &quot;ack&quot;/&quot;nack&quot;, null otherwise
+                    Object messageType = jsonObject.get(&quot;message_type&quot;);
+
+                    if (messageType == null) {
+                        // Normal upstream data message
+                        handleUpstreamMessage(jsonObject);
+
+                        // Send ACK to CCS
+                        String messageId = (String) jsonObject.get(&quot;message_id&quot;);
+                        String from = (String) jsonObject.get(&quot;from&quot;);
+                        String ack = createJsonAck(from, messageId);
+                        send(ack);
+                    } else if (&quot;ack&quot;.equals(messageType.toString())) {
+                          // Process Ack
+                          handleAckReceipt(jsonObject);
+                    } else if (&quot;nack&quot;.equals(messageType.toString())) {
+                          // Process Nack
+                          handleNackReceipt(jsonObject);
+                    } else if (&quot;control&quot;.equals(messageType.toString())) {
+                          // Process control message
+                          handleControlMessage(jsonObject);
+                    } else {
+                          logger.log(Level.WARNING,
+                                  &quot;Unrecognized message type (%s)&quot;,
+                                  messageType.toString());
+                    }
+                } catch (ParseException e) {
+                    logger.log(Level.SEVERE, &quot;Error parsing JSON &quot; + json, e);
+                } catch (Exception e) {
+                    logger.log(Level.SEVERE, &quot;Failed to process packet&quot;, e);
+                }
+            }
+        }, new PacketTypeFilter(Message.class));
+
+        // Log all outgoing packets
+        connection.addPacketInterceptor(new PacketInterceptor() {
+            &#64;Override
+                public void interceptPacket(Packet packet) {
+                    logger.log(Level.INFO, &quot;Sent: {0}&quot;, packet.toXML());
+                }
+            }, new PacketTypeFilter(Message.class));
+
+        connection.login(senderId + &quot;&#64;gcm.googleapis.com&quot;, apiKey);
+    }
+
+    public static void main(String[] args) throws Exception {
+        final long senderId = 1234567890L; // your GCM sender id
+        final String password = &quot;Your API key&quot;;
+
+        SmackCcsClient ccsClient = new SmackCcsClient();
+
+        ccsClient.connect(senderId, password);
+
+        // Send a sample hello downstream message to a device.
+        String toRegId = &quot;RegistrationIdOfTheTargetDevice&quot;;
+        String messageId = ccsClient.nextMessageId();
+        Map&lt;String, String&gt; payload = new HashMap&lt;String, String&gt;();
+        payload.put(&quot;Hello&quot;, &quot;World&quot;);
+        payload.put(&quot;CCS&quot;, &quot;Dummy Message&quot;);
+        payload.put(&quot;EmbeddedMessageId&quot;, messageId);
+        String collapseKey = &quot;sample&quot;;
+        Long timeToLive = 10000L;
+        String message = createJsonMessage(toRegId, messageId, payload,
+                collapseKey, timeToLive, true);
+
+        ccsClient.sendDownstreamMessage(message);
+    }
+
+    /**
+     * XMPP Packet Extension for GCM Cloud Connection Server.
+     */
+    private static final class GcmPacketExtension extends DefaultPacketExtension {
+
+        private final String json;
+
+        public GcmPacketExtension(String json) {
+            super(GCM_ELEMENT_NAME, GCM_NAMESPACE);
+            this.json = json;
+        }
+
+        public String getJson() {
+            return json;
+        }
+
         &#64;Override
         public String toXML() {
-
-          StringBuilder buf = new StringBuilder();
-          buf.append(&quot;&lt;message&quot;);
-          if (getXmlns() != null) {
-            buf.append(&quot; xmlns=\&quot;&quot;).append(getXmlns()).append(&quot;\&quot;&quot;);
-          }
-          if (getLanguage() != null) {
-            buf.append(&quot; xml:lang=\&quot;&quot;).append(getLanguage()).append(&quot;\&quot;&quot;);
-          }
-          if (getPacketID() != null) {
-            buf.append(&quot; id=\&quot;&quot;).append(getPacketID()).append(&quot;\&quot;&quot;);
-          }
-          if (getTo() != null) {
-            buf.append(&quot; to=\&quot;&quot;).append(StringUtils.escapeForXML(getTo())).append(&quot;\&quot;&quot;);
-          }
-          if (getFrom() != null) {
-            buf.append(&quot; from=\&quot;&quot;).append(StringUtils.escapeForXML(getFrom())).append(&quot;\&quot;&quot;);
-          }
-          buf.append(&quot;&gt;&quot;);
-          buf.append(GcmPacketExtension.this.toXML());
-          buf.append(&quot;&lt;/message&gt;&quot;);
-          return buf.toString();
+            return String.format(&quot;&lt;%s xmlns=\&quot;%s\&quot;&gt;%s&lt;/%s&gt;&quot;,
+                    GCM_ELEMENT_NAME, GCM_NAMESPACE,
+                    StringUtils.escapeForXML(json), GCM_ELEMENT_NAME);
         }
-      };
-    }
-  }
 
-  public SmackCcsClient() {
-    // Add GcmPacketExtension
-    ProviderManager.getInstance().addExtensionProvider(GCM_ELEMENT_NAME,
-        GCM_NAMESPACE, new PacketExtensionProvider() {
-
-      &#64;Override
-      public PacketExtension parseExtension(XmlPullParser parser)
-          throws Exception {
-        String json = parser.nextText();
-        GcmPacketExtension packet = new GcmPacketExtension(json);
-        return packet;
-      }
-    });
-  }
-
-  /**
-   * Returns a random message id to uniquely identify a message.
-   *
-   * &lt;p&gt;Note:
-   * This is generated by a pseudo random number generator for illustration purpose,
-   * and is not guaranteed to be unique.
-   *
-   */
-  public String getRandomMessageId() {
-    return &quot;m-&quot; + Long.toString(random.nextLong());
-  }
-
-  /**
-   * Sends a downstream GCM message.
-   */
-  public void send(String jsonRequest) {
-    Packet request = new GcmPacketExtension(jsonRequest).toPacket();
-    connection.sendPacket(request);
-  }
-
-  /**
-   * Handles an upstream data message from a device application.
-   *
-   * &lt;p&gt;This sample echo server sends an echo message back to the device.
-   * Subclasses should override this method to process an upstream message.
-   */
-  public void handleIncomingDataMessage(Map&lt;String, Object&gt; jsonObject) {
-    String from = jsonObject.get(&quot;from&quot;).toString();
-
-    // PackageName of the application that sent this message.
-    String category = jsonObject.get(&quot;category&quot;).toString();
-
-    // Use the packageName as the collapseKey in the echo packet
-    String collapseKey = &quot;echo:CollapseKey&quot;;
-    &#64;SuppressWarnings(&quot;unchecked&quot;)
-    Map&lt;String, String&gt; payload = (Map&lt;String, String&gt;) jsonObject.get(&quot;data&quot;);
-    payload.put(&quot;ECHO&quot;, &quot;Application: &quot; + category);
-
-    // Send an ECHO response back
-    String echo = createJsonMessage(from, getRandomMessageId(), payload, collapseKey, null, false);
-    send(echo);
-  }
-
-  /**
-   * Handles an ACK.
-   *
-   * &lt;p&gt;By default, it only logs a {@code INFO} message, but subclasses could override it to
-   * properly handle ACKS.
-   */
-  public void handleAckReceipt(Map&lt;String, Object&gt; jsonObject) {
-    String messageId = jsonObject.get(&quot;message_id&quot;).toString();
-    String from = jsonObject.get(&quot;from&quot;).toString();
-    logger.log(Level.INFO, &quot;handleAckReceipt() from: &quot; + from + &quot;, messageId: &quot; + messageId);
-  }
-
-  /**
-   * Handles a NACK.
-   *
-   * &lt;p&gt;By default, it only logs a {@code INFO} message, but subclasses could override it to
-   * properly handle NACKS.
-   */
-  public void handleNackReceipt(Map&lt;String, Object&gt; jsonObject) {
-    String messageId = jsonObject.get(&quot;message_id&quot;).toString();
-    String from = jsonObject.get(&quot;from&quot;).toString();
-    logger.log(Level.INFO, &quot;handleNackReceipt() from: &quot; + from + &quot;, messageId: &quot; + messageId);
-  }
-
-  /**
-   * Creates a JSON encoded GCM message.
-   *
-   * &#64;param to RegistrationId of the target device (Required).
-   * &#64;param messageId Unique messageId for which CCS will send an &quot;ack/nack&quot; (Required).
-   * &#64;param payload Message content intended for the application. (Optional).
-   * &#64;param collapseKey GCM collapse_key parameter (Optional).
-   * &#64;param timeToLive GCM time_to_live parameter (Optional).
-   * &#64;param delayWhileIdle GCM delay_while_idle parameter (Optional).
-   * &#64;return JSON encoded GCM message.
-   */
-  public static String createJsonMessage(String to, String messageId, Map&lt;String, String&gt; payload,
-      String collapseKey, Long timeToLive, Boolean delayWhileIdle) {
-    Map&lt;String, Object&gt; message = new HashMap&lt;String, Object&gt;();
-    message.put(&quot;to&quot;, to);
-    if (collapseKey != null) {
-      message.put(&quot;collapse_key&quot;, collapseKey);
-    }
-    if (timeToLive != null) {
-      message.put(&quot;time_to_live&quot;, timeToLive);
-    }
-    if (delayWhileIdle != null &amp;&amp; delayWhileIdle) {
-      message.put(&quot;delay_while_idle&quot;, true);
-    }
-    message.put(&quot;message_id&quot;, messageId);
-    message.put(&quot;data&quot;, payload);
-    return JSONValue.toJSONString(message);
-  }
-
-  /**
-   * Creates a JSON encoded ACK message for an upstream message received from an application.
-   *
-   * &#64;param to RegistrationId of the device who sent the upstream message.
-   * &#64;param messageId messageId of the upstream message to be acknowledged to CCS.
-   * &#64;return JSON encoded ack.
-   */
-  public static String createJsonAck(String to, String messageId) {
-    Map&lt;String, Object&gt; message = new HashMap&lt;String, Object&gt;();
-    message.put(&quot;message_type&quot;, &quot;ack&quot;);
-    message.put(&quot;to&quot;, to);
-    message.put(&quot;message_id&quot;, messageId);
-    return JSONValue.toJSONString(message);
-  }
-
-  /**
-   * Connects to GCM Cloud Connection Server using the supplied credentials.
-   *
-   * &#64;param username GCM_SENDER_ID&#64;gcm.googleapis.com
-   * &#64;param password API Key
-   * &#64;throws XMPPException
-   */
-  public void connect(String username, String password) throws XMPPException {
-    config = new ConnectionConfiguration(GCM_SERVER, GCM_PORT);
-    config.setSecurityMode(SecurityMode.enabled);
-    config.setReconnectionAllowed(true);
-    config.setRosterLoadedAtLogin(false);
-    config.setSendPresence(false);
-    config.setSocketFactory(SSLSocketFactory.getDefault());
-
-    // NOTE: Set to true to launch a window with information about packets sent and received
-    config.setDebuggerEnabled(true);
-
-    // -Dsmack.debugEnabled=true
-    XMPPConnection.DEBUG_ENABLED = true;
-
-    connection = new XMPPConnection(config);
-    connection.connect();
-
-    connection.addConnectionListener(new ConnectionListener() {
-
-      &#64;Override
-      public void reconnectionSuccessful() {
-        logger.info(&quot;Reconnecting..&quot;);
-      }
-
-      &#64;Override
-      public void reconnectionFailed(Exception e) {
-        logger.log(Level.INFO, &quot;Reconnection failed.. &quot;, e);
-      }
-
-      &#64;Override
-      public void reconnectingIn(int seconds) {
-        logger.log(Level.INFO, &quot;Reconnecting in %d secs&quot;, seconds);
-      }
-
-      &#64;Override
-      public void connectionClosedOnError(Exception e) {
-        logger.log(Level.INFO, &quot;Connection closed on error.&quot;);
-      }
-
-      &#64;Override
-      public void connectionClosed() {
-        logger.info(&quot;Connection closed.&quot;);
-      }
-    });
-
-    // Handle incoming packets
-    connection.addPacketListener(new PacketListener() {
-
-      &#64;Override
-      public void processPacket(Packet packet) {
-        logger.log(Level.INFO, &quot;Received: &quot; + packet.toXML());
-        Message incomingMessage = (Message) packet;
-        GcmPacketExtension gcmPacket =
-            (GcmPacketExtension) incomingMessage.getExtension(GCM_NAMESPACE);
-        String json = gcmPacket.getJson();
-        try {
-          &#64;SuppressWarnings(&quot;unchecked&quot;)
-          Map&lt;String, Object&gt; jsonObject =
-              (Map&lt;String, Object&gt;) JSONValue.parseWithException(json);
-
-          // present for &quot;ack&quot;/&quot;nack&quot;, null otherwise
-          Object messageType = jsonObject.get(&quot;message_type&quot;);
-
-          if (messageType == null) {
-            // Normal upstream data message
-            handleIncomingDataMessage(jsonObject);
-
-            // Send ACK to CCS
-            String messageId = jsonObject.get(&quot;message_id&quot;).toString();
-            String from = jsonObject.get(&quot;from&quot;).toString();
-            String ack = createJsonAck(from, messageId);
-            send(ack);
-          } else if (&quot;ack&quot;.equals(messageType.toString())) {
-            // Process Ack
-            handleAckReceipt(jsonObject);
-          } else if (&quot;nack&quot;.equals(messageType.toString())) {
-            // Process Nack
-            handleNackReceipt(jsonObject);
-          } else {
-            logger.log(Level.WARNING, &quot;Unrecognized message type (%s)&quot;,
-                messageType.toString());
-          }
-        } catch (ParseException e) {
-          logger.log(Level.SEVERE, &quot;Error parsing JSON &quot; + json, e);
-        } catch (Exception e) {
-          logger.log(Level.SEVERE, &quot;Couldn't send echo.&quot;, e);
+        public Packet toPacket() {
+            Message message = new Message();
+            message.addExtension(this);
+            return message;
         }
-      }
-    }, new PacketTypeFilter(Message.class));
-
-
-    // Log all outgoing packets
-    connection.addPacketInterceptor(new PacketInterceptor() {
-      &#64;Override
-      public void interceptPacket(Packet packet) {
-        logger.log(Level.INFO, &quot;Sent: {0}&quot;,  packet.toXML());
-      }
-    }, new PacketTypeFilter(Message.class));
-
-    connection.login(username, password);
-  }
-
-  public static void main(String [] args) {
-    final String userName = &quot;Your GCM Sender Id&quot; + &quot;&#64;gcm.googleapis.com&quot;;
-    final String password = &quot;API Key&quot;;
-
-    SmackCcsClient ccsClient = new SmackCcsClient();
-
-    try {
-      ccsClient.connect(userName, password);
-    } catch (XMPPException e) {
-      e.printStackTrace();
     }
 
-    // Send a sample hello downstream message to a device.
-    String toRegId = &quot;RegistrationIdOfTheTargetDevice&quot;;
-    String messageId = ccsClient.getRandomMessageId();
-    Map&lt;String, String&gt; payload = new HashMap&lt;String, String&gt;();
-    payload.put(&quot;Hello&quot;, &quot;World&quot;);
-    payload.put(&quot;CCS&quot;, &quot;Dummy Message&quot;);
-    payload.put(&quot;EmbeddedMessageId&quot;, messageId);
-    String collapseKey = &quot;sample&quot;;
-    Long timeToLive = 10000L;
-    Boolean delayWhileIdle = true;
-    ccsClient.send(createJsonMessage(toRegId, messageId, payload, collapseKey,
-        timeToLive, delayWhileIdle));
-  }
+    private static final class LoggingConnectionListener
+            implements ConnectionListener {
+
+        &#64;Override
+        public void connected(XMPPConnection xmppConnection) {
+            logger.info(&quot;Connected.&quot;);
+        }
+
+        &#64;Override
+        public void authenticated(XMPPConnection xmppConnection) {
+            logger.info(&quot;Authenticated.&quot;);
+        }
+
+        &#64;Override
+        public void reconnectionSuccessful() {
+            logger.info(&quot;Reconnecting..&quot;);
+        }
+
+        &#64;Override
+        public void reconnectionFailed(Exception e) {
+            logger.log(Level.INFO, &quot;Reconnection failed.. &quot;, e);
+        }
+
+        &#64;Override
+        public void reconnectingIn(int seconds) {
+            logger.log(Level.INFO, &quot;Reconnecting in %d secs&quot;, seconds);
+        }
+
+        &#64;Override
+        public void connectionClosedOnError(Exception e) {
+            logger.info(&quot;Connection closed on error.&quot;);
+        }
+
+        &#64;Override
+        public void connectionClosed() {
+            logger.info(&quot;Connection closed.&quot;);
+        }
+    }
 }</pre>
+
 <h3 id="python">Python sample</h3>
 
 <p>Here is an example of a CCS app server written in Python. This sample echo
diff --git a/libs/hwui/RenderNode.h b/libs/hwui/RenderNode.h
index 54fa143..8cc65b2 100644
--- a/libs/hwui/RenderNode.h
+++ b/libs/hwui/RenderNode.h
@@ -173,9 +173,6 @@
     // UI thread only!
     ANDROID_API void addAnimator(const sp<BaseRenderNodeAnimator>& animator);
 
-protected:
-    virtual void damageSelf(TreeInfo& info);
-
 private:
     typedef key_value_pair_t<float, DrawRenderNodeOp*> ZDrawRenderNodeOpPair;
 
@@ -250,6 +247,7 @@
     void prepareLayer(TreeInfo& info);
     void pushLayerUpdate(TreeInfo& info);
     void deleteDisplayListData();
+    void damageSelf(TreeInfo& info);
 
     void incParentRefCount() { mParentCount++; }
     void decParentRefCount();
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index 57279b7..a4ac262 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -185,6 +185,11 @@
     } else if (!mDirtyRegionsEnabled || mHaveNewSurface) {
         dirty.setEmpty();
     } else {
+        if (!dirty.intersect(0, 0, width, height)) {
+            ALOGW("Dirty " RECT_STRING " doesn't intersect with 0 0 %d %d ?",
+                    SK_RECT_ARGS(dirty), width, height);
+            dirty.setEmpty();
+        }
         profiler().unionDirty(&dirty);
     }
 
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index c65961d..ef95c11 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -2954,15 +2954,12 @@
      * Set Hdmi Cec system audio mode.
      *
      * @param on whether to be on system audio mode
-     * @param device out device type to be used for system audio mode.
-     *               Ignored if {@code on} is {@code false}
-     * @param name name of system audio device
      * @return output device type. 0 (DEVICE_NONE) if failed to set device.
      * @hide
      */
-    public int setHdmiSystemAudioSupported(boolean on, int device, String name) {
+    public int setHdmiSystemAudioSupported(boolean on) {
         try {
-            return getService().setHdmiSystemAudioSupported(on, device, name);
+            return getService().setHdmiSystemAudioSupported(on);
         } catch (RemoteException e) {
             Log.w(TAG, "Error setting system audio mode", e);
             return AudioSystem.DEVICE_NONE;
diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java
index ab63145..9d5fe23 100644
--- a/media/java/android/media/AudioService.java
+++ b/media/java/android/media/AudioService.java
@@ -393,10 +393,16 @@
     // Indicates the mode used for SCO audio connection. The mode is virtual call if the request
     // originated from an app targeting an API version before JB MR2 and raw audio after that.
     private int mScoAudioMode;
+    // SCO audio mode is undefined
+    private static final int SCO_MODE_UNDEFINED = -1;
     // SCO audio mode is virtual voice call (BluetoothHeadset.startScoUsingVirtualVoiceCall())
     private static final int SCO_MODE_VIRTUAL_CALL = 0;
     // SCO audio mode is raw audio (BluetoothHeadset.connectAudio())
     private static final int SCO_MODE_RAW = 1;
+    // SCO audio mode is Voice Recognition (BluetoothHeadset.startVoiceRecognition())
+    private static final int SCO_MODE_VR = 2;
+
+    private static final int SCO_MODE_MAX = 2;
 
     // Current connection state indicated by bluetooth headset
     private int mScoConnectionState;
@@ -2117,7 +2123,7 @@
     public void startBluetoothSco(IBinder cb, int targetSdkVersion) {
         int scoAudioMode =
                 (targetSdkVersion < Build.VERSION_CODES.JELLY_BEAN_MR2) ?
-                        SCO_MODE_VIRTUAL_CALL : SCO_MODE_RAW;
+                        SCO_MODE_VIRTUAL_CALL : SCO_MODE_UNDEFINED;
         startBluetoothScoInt(cb, scoAudioMode);
     }
 
@@ -2272,14 +2278,28 @@
                                  mScoAudioState == SCO_STATE_DEACTIVATE_REQ)) {
                             if (mScoAudioState == SCO_STATE_INACTIVE) {
                                 mScoAudioMode = scoAudioMode;
+                                if (scoAudioMode == SCO_MODE_UNDEFINED) {
+                                    mScoAudioMode = new Integer(Settings.Global.getInt(
+                                                            mContentResolver,
+                                                            "bluetooth_sco_channel_"+
+                                                            mBluetoothHeadsetDevice.getAddress(),
+                                                            SCO_MODE_VIRTUAL_CALL));
+                                    if (mScoAudioMode > SCO_MODE_MAX || mScoAudioMode < 0) {
+                                        mScoAudioMode = SCO_MODE_VIRTUAL_CALL;
+                                    }
+                                }
                                 if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null) {
-                                    boolean status;
+                                    boolean status = false;
                                     if (mScoAudioMode == SCO_MODE_RAW) {
                                         status = mBluetoothHeadset.connectAudio();
-                                    } else {
+                                    } else if (mScoAudioMode == SCO_MODE_VIRTUAL_CALL) {
                                         status = mBluetoothHeadset.startScoUsingVirtualVoiceCall(
                                                                             mBluetoothHeadsetDevice);
+                                    } else if (mScoAudioMode == SCO_MODE_VR) {
+                                        status = mBluetoothHeadset.startVoiceRecognition(
+                                                                           mBluetoothHeadsetDevice);
                                     }
+
                                     if (status) {
                                         mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
                                     } else {
@@ -2302,13 +2322,17 @@
                                mScoAudioState == SCO_STATE_ACTIVATE_REQ)) {
                     if (mScoAudioState == SCO_STATE_ACTIVE_INTERNAL) {
                         if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null) {
-                            boolean status;
+                            boolean status = false;
                             if (mScoAudioMode == SCO_MODE_RAW) {
                                 status = mBluetoothHeadset.disconnectAudio();
-                            } else {
+                            } else if (mScoAudioMode == SCO_MODE_VIRTUAL_CALL) {
                                 status = mBluetoothHeadset.stopScoUsingVirtualVoiceCall(
                                                                         mBluetoothHeadsetDevice);
+                            } else if (mScoAudioMode == SCO_MODE_VR) {
+                                        status = mBluetoothHeadset.stopVoiceRecognition(
+                                                                      mBluetoothHeadsetDevice);
                             }
+
                             if (!status) {
                                 mScoAudioState = SCO_STATE_INACTIVE;
                                 broadcastScoConnectionState(
@@ -2502,17 +2526,23 @@
                                 mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
                                 if (mScoAudioMode == SCO_MODE_RAW) {
                                     status = mBluetoothHeadset.connectAudio();
-                                } else {
+                                } else if (mScoAudioMode == SCO_MODE_VIRTUAL_CALL) {
                                     status = mBluetoothHeadset.startScoUsingVirtualVoiceCall(
                                                                         mBluetoothHeadsetDevice);
+                                } else if (mScoAudioMode == SCO_MODE_VR) {
+                                    status = mBluetoothHeadset.startVoiceRecognition(
+                                                                      mBluetoothHeadsetDevice);
                                 }
                                 break;
                             case SCO_STATE_DEACTIVATE_REQ:
                                 if (mScoAudioMode == SCO_MODE_RAW) {
                                     status = mBluetoothHeadset.disconnectAudio();
-                                } else {
+                                } else if (mScoAudioMode == SCO_MODE_VIRTUAL_CALL) {
                                     status = mBluetoothHeadset.stopScoUsingVirtualVoiceCall(
                                                                         mBluetoothHeadsetDevice);
+                                } else if (mScoAudioMode == SCO_MODE_VR) {
+                                    status = mBluetoothHeadset.stopVoiceRecognition(
+                                                                      mBluetoothHeadsetDevice);
                                 }
                                 break;
                             case SCO_STATE_DEACTIVATE_EXT_REQ:
@@ -3792,8 +3822,7 @@
                     }
 
                     if (mHdmiTvClient != null) {
-                        setHdmiSystemAudioSupported(mHdmiSystemAudioSupported,
-                                mHdmiSystemAudioOutputDevice, "");
+                        setHdmiSystemAudioSupported(mHdmiSystemAudioSupported);
                     }
 
                     // indicate the end of reconfiguration phase to audio HAL
@@ -4774,113 +4803,25 @@
     private boolean mHdmiSystemAudioSupported = false;
     // Set only when device is tv.
     private HdmiTvClient mHdmiTvClient;
-    private int mHdmiSystemAudioOutputDevice = AudioSystem.DEVICE_NONE;
-    private int[] mSpeakerGains;
 
     @Override
-    public int setHdmiSystemAudioSupported(boolean on, int device, String name) {
+    public int setHdmiSystemAudioSupported(boolean on) {
         if (mHdmiTvClient == null) {
             Log.w(TAG, "Only Hdmi-Cec enabled TV device supports system audio mode.");
             return AudioSystem.DEVICE_NONE;
         }
 
-        if (on && !checkHdmiSystemAudioOutput(device)) {
-            return AudioSystem.DEVICE_NONE;
-        }
-
         synchronized (mHdmiTvClient) {
-            if (on) {
-                mHdmiSystemAudioOutputDevice = device;
-            }
             if (mHdmiSystemAudioSupported == on) {
                 return AudioSystem.getDevicesForStream(AudioSystem.STREAM_MUSIC);
             }
             mHdmiSystemAudioSupported = on;
-            updateHdmiSystemAudioVolumeLocked(on);
+            AudioSystem.setForceUse(AudioSystem.FOR_HDMI_SYSTEM_AUDIO,
+                    on ? AudioSystem.FORCE_HDMI_SYSTEM_AUDIO_ENFORCED : AudioSystem.FORCE_NONE);
         }
         return AudioSystem.getDevicesForStream(AudioSystem.STREAM_MUSIC);
     }
 
-    private boolean checkHdmiSystemAudioOutput(int device) {
-        if ((device & AudioSystem.DEVICE_OUT_ALL_HDMI_SYSTEM_AUDIO) == 0) {
-            Log.w(TAG, "Unsupported Hdmi-Cec system audio output:" + device);
-            return false;
-        }
-
-        int streamDevice = AudioSystem.getDevicesForStream(AudioSystem.STREAM_MUSIC);
-        // If other devices except for system audio and speaker are available,
-        // fails to start system audio mode.
-        if ((streamDevice & ~AudioSystem.DEVICE_ALL_HDMI_SYSTEM_AUDIO_AND_SPEAKER) != 0) {
-            Log.w(TAG, "Should turn off other devices before starting system audio:"
-                    + streamDevice);
-            return false;
-        }
-        if (AudioSystem.getDeviceConnectionState(device, "") !=
-            AudioSystem.DEVICE_STATE_AVAILABLE) {
-            Log.w(TAG, "Output device is not connected:" + device);
-            return false;
-        }
-        return true;
-    }
-
-    private void updateHdmiSystemAudioVolumeLocked(boolean on) {
-        AudioDevicePort speaker = findAudioDevicePort(AudioSystem.DEVICE_OUT_SPEAKER);
-        if (speaker == null) {
-            Log.w(TAG, "Has no speaker output.");
-            return;
-        }
-
-        AudioPortConfig portConfig = speaker.activeConfig();
-        AudioGainConfig gainConfig = portConfig.gain();
-        int[] newGains;
-        // When system audio is on, backup original gains and mute all channels of speaker by
-        // setting gains to 0; otherwise, restore gains of speaker.
-        if (on) {
-            if (gainConfig == null) {
-                Log.w(TAG, "Speaker has no gain control.");
-                return;
-            }
-            // Back up original gains.
-            mSpeakerGains = Arrays.copyOf(gainConfig.values(), gainConfig.values().length);
-            // Set all gains to 0.
-            newGains = new int[gainConfig.values().length];
-        } else {
-            if (mSpeakerGains == null) {
-                Log.w(TAG, "mSpeakerGains should not be null.");
-                return;
-            }
-            newGains = Arrays.copyOf(mSpeakerGains, mSpeakerGains.length);
-        }
-
-        gainConfig = gainConfig.mGain.buildConfig(gainConfig.mode(),
-                gainConfig.channelMask(),
-                newGains,
-                gainConfig.rampDurationMs());
-
-        AudioManager audioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
-        if (AudioSystem.SUCCESS !=  audioManager.setAudioPortGain(speaker, gainConfig)) {
-            Log.w(TAG, "Failed to update audio port config.");
-        }
-    }
-
-    private AudioDevicePort findAudioDevicePort(int type) {
-        ArrayList<AudioPort> devicePorts = new ArrayList<>();
-        AudioManager audioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
-        int status = audioManager.listAudioDevicePorts(devicePorts);
-        if (status != AudioSystem.SUCCESS)  {
-            Log.w(TAG, "Failed to list up all audio ports");
-            return null;
-        }
-
-        for (AudioPort port : devicePorts) {
-            AudioDevicePort devicePort = (AudioDevicePort) port;
-            if (devicePort.type() == type) {
-                return devicePort;
-            }
-        }
-        return null;
-    }
-
     //==========================================================================================
     // Camera shutter sound policy.
     // config_camera_sound_forced configuration option in config.xml defines if the camera shutter
diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java
index 72367c8..8e2ca95 100644
--- a/media/java/android/media/AudioSystem.java
+++ b/media/java/android/media/AudioSystem.java
@@ -254,6 +254,7 @@
     public static final int DEVICE_OUT_HDMI_ARC = 0x40000;
     public static final int DEVICE_OUT_SPDIF = 0x80000;
     public static final int DEVICE_OUT_FM = 0x100000;
+    public static final int DEVICE_OUT_AUX_LINE = 0x200000;
 
     public static final int DEVICE_OUT_DEFAULT = DEVICE_BIT_DEFAULT;
 
@@ -278,6 +279,7 @@
                                               DEVICE_OUT_HDMI_ARC |
                                               DEVICE_OUT_SPDIF |
                                               DEVICE_OUT_FM |
+                                              DEVICE_OUT_AUX_LINE |
                                               DEVICE_OUT_DEFAULT);
     public static final int DEVICE_OUT_ALL_A2DP = (DEVICE_OUT_BLUETOOTH_A2DP |
                                                    DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES |
@@ -287,7 +289,7 @@
                                                   DEVICE_OUT_BLUETOOTH_SCO_CARKIT);
     public static final int DEVICE_OUT_ALL_USB = (DEVICE_OUT_USB_ACCESSORY |
                                                   DEVICE_OUT_USB_DEVICE);
-    public static final int DEVICE_OUT_ALL_HDMI_SYSTEM_AUDIO = (DEVICE_OUT_LINE |
+    public static final int DEVICE_OUT_ALL_HDMI_SYSTEM_AUDIO = (DEVICE_OUT_AUX_LINE |
                                                                 DEVICE_OUT_HDMI_ARC |
                                                                 DEVICE_OUT_SPDIF);
     public static final int DEVICE_ALL_HDMI_SYSTEM_AUDIO_AND_SPEAKER =
@@ -440,7 +442,8 @@
     public static final int FORCE_DIGITAL_DOCK = 9;
     public static final int FORCE_NO_BT_A2DP = 10;
     public static final int FORCE_SYSTEM_ENFORCED = 11;
-    private static final int NUM_FORCE_CONFIG = 12;
+    public static final int FORCE_HDMI_SYSTEM_AUDIO_ENFORCED = 12;
+    private static final int NUM_FORCE_CONFIG = 13;
     public static final int FORCE_DEFAULT = FORCE_NONE;
 
     // usage for setForceUse, must match AudioSystem::force_use
@@ -449,7 +452,8 @@
     public static final int FOR_RECORD = 2;
     public static final int FOR_DOCK = 3;
     public static final int FOR_SYSTEM = 4;
-    private static final int NUM_FORCE_USE = 5;
+    public static final int FOR_HDMI_SYSTEM_AUDIO = 5;
+    private static final int NUM_FORCE_USE = 6;
 
     // usage for AudioRecord.startRecordingSync(), must match AudioSystem::sync_event_t
     public static final int SYNC_EVENT_NONE = 0;
diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl
index 4f7021e..7318660 100644
--- a/media/java/android/media/IAudioService.aidl
+++ b/media/java/android/media/IAudioService.aidl
@@ -201,7 +201,7 @@
 
     void disableSafeMediaVolume();
 
-    int setHdmiSystemAudioSupported(boolean on, int device, String name);
+    int setHdmiSystemAudioSupported(boolean on);
 
            boolean registerAudioPolicy(in AudioPolicyConfig policyConfig, IBinder cb);
     oneway void unregisterAudioPolicyAsync(in IBinder cb);
diff --git a/media/java/android/media/MediaRecorder.java b/media/java/android/media/MediaRecorder.java
index 3917bf1..59307d0 100644
--- a/media/java/android/media/MediaRecorder.java
+++ b/media/java/android/media/MediaRecorder.java
@@ -299,6 +299,9 @@
 
         /** @hide H.264/AAC data encapsulated in MPEG2/TS */
         public static final int OUTPUT_FORMAT_MPEG2TS = 8;
+
+        /** VP8/VORBIS data in a WEBM container */
+        public static final int WEBM = 9;
     };
 
     /**
@@ -321,6 +324,8 @@
         public static final int HE_AAC = 4;
         /** Enhanced Low Delay AAC (AAC-ELD) audio codec */
         public static final int AAC_ELD = 5;
+        /** Ogg Vorbis audio codec */
+        public static final int VORBIS = 6;
     }
 
     /**
@@ -336,6 +341,7 @@
         public static final int H263 = 1;
         public static final int H264 = 2;
         public static final int MPEG_4_SP = 3;
+        public static final int VP8 = 4;
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
index 1bb36dd..8b5ff67 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
@@ -27,11 +27,12 @@
 import android.os.Handler;
 import android.os.UserHandle;
 import android.provider.Settings.Global;
+import android.telecomm.TelecommConstants;
+import android.telecomm.TelecommManager;
 import android.util.Log;
 
 import com.android.internal.telephony.IccCardConstants;
 import com.android.internal.telephony.TelephonyIntents;
-import com.android.internal.telephony.cdma.TtyIntent;
 import com.android.systemui.R;
 
 /**
@@ -89,7 +90,7 @@
             else if (action.equals(TelephonyIntents.ACTION_SIM_STATE_CHANGED)) {
                 updateSimState(intent);
             }
-            else if (action.equals(TtyIntent.TTY_ENABLED_CHANGE_ACTION)) {
+            else if (action.equals(TelecommConstants.ACTION_CURRENT_TTY_MODE_CHANGED)) {
                 updateTTY(intent);
             }
             else if (action.equals(Intent.ACTION_USER_SWITCHED)) {
@@ -110,7 +111,7 @@
         filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
         filter.addAction(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED);
         filter.addAction(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
-        filter.addAction(TtyIntent.TTY_ENABLED_CHANGE_ACTION);
+        filter.addAction(TelecommConstants.ACTION_CURRENT_TTY_MODE_CHANGED);
         filter.addAction(Intent.ACTION_USER_SWITCHED);
         mContext.registerReceiver(mIntentReceiver, filter, null, mHandler);
 
@@ -269,7 +270,9 @@
     }
 
     private final void updateTTY(Intent intent) {
-        final boolean enabled = intent.getBooleanExtra(TtyIntent.TTY_ENABLED, false);
+        int currentTtyMode = intent.getIntExtra(TelecommConstants.EXTRA_CURRENT_TTY_MODE,
+                TelecommConstants.TTY_MODE_OFF);
+        boolean enabled = currentTtyMode != TelecommConstants.TTY_MODE_OFF;
 
         if (DEBUG) Log.v(TAG, "updateTTY: enabled: " + enabled);
 
diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java
index c3a9dbe..e8e2813 100644
--- a/services/backup/java/com/android/server/backup/BackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/BackupManagerService.java
@@ -3535,19 +3535,30 @@
                                 }
                             } while (nRead > 0 && result == BackupTransport.TRANSPORT_OK);
 
-                            // Done -- how did it turn out?
-                            if (result == BackupTransport.TRANSPORT_OK){
-                                result = transport.finishBackup();
-                            } else {
-                                Slog.w(TAG, "Error backing up " + target.packageName);
+                            // In all cases we need to give the transport its finish callback
+                            int finishResult = transport.finishBackup();
+
+                            // If we were otherwise in a good state, now interpret the final
+                            // result based on what finishBackup() returned.  If we're in a
+                            // failure case already, preserve that result and ignore whatever
+                            // finishBackup() reported.
+                            if (result == BackupTransport.TRANSPORT_OK) {
+                                result = finishResult;
                             }
-                        } else if (result == BackupTransport.TRANSPORT_PACKAGE_REJECTED) {
+
+                            if (result != BackupTransport.TRANSPORT_OK) {
+                                Slog.e(TAG, "Error " + result
+                                        + " backing up " + target.packageName);
+                            }
+                        }
+
+                        if (result == BackupTransport.TRANSPORT_PACKAGE_REJECTED) {
                             if (DEBUG) {
                                 Slog.i(TAG, "Transport rejected backup of " + target.packageName
                                         + ", skipping");
                             }
                             // do nothing, clean up, and continue looping
-                        } else {
+                        } else if (result != BackupTransport.TRANSPORT_OK) {
                             if (DEBUG) {
                                 Slog.i(TAG, "Transport failed; aborting backup");
                                 return;
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 86f8777..9945909 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -5720,6 +5720,17 @@
         oldNetwork.asyncChannel.disconnect();
     }
 
+    private void makeDefault(NetworkAgentInfo newNetwork) {
+        if (VDBG) log("Switching to new default network: " + newNetwork);
+        setupDataActivityTracking(newNetwork);
+        try {
+            mNetd.setDefaultNetId(newNetwork.network.netId);
+        } catch (Exception e) {
+            loge("Exception setting default network :" + e);
+        }
+        handleApplyDefaultProxy(newNetwork.linkProperties.getHttpProxy());
+    }
+
     private void handleConnectionValidated(NetworkAgentInfo newNetwork) {
         if (newNetwork == null) {
             loge("Unknown NetworkAgentInfo in handleConnectionValidated");
@@ -5813,16 +5824,7 @@
         }
         if (keep) {
             if (isNewDefault) {
-                if (VDBG) log("Switching to new default network: " + newNetwork);
-                setupDataActivityTracking(newNetwork);
-                try {
-                    mNetd.setDefaultNetId(newNetwork.network.netId);
-                } catch (Exception e) {
-                    loge("Exception setting default network :" + e);
-                }
-                if (newNetwork.equals(mNetworkForRequestId.get(mDefaultRequest.requestId))) {
-                    handleApplyDefaultProxy(newNetwork.linkProperties.getHttpProxy());
-                }
+                makeDefault(newNetwork);
                 synchronized (ConnectivityService.this) {
                     // have a new default network, release the transition wakelock in
                     // a second if it's held.  The second pause is to allow apps
@@ -5919,6 +5921,13 @@
                 }
                 // TODO: support proxy per network.
             }
+            // Make default network if we have no default.  Any network is better than no network.
+            if (mNetworkForRequestId.get(mDefaultRequest.requestId) == null &&
+                    networkAgent.isVPN() == false &&
+                    mDefaultRequest.networkCapabilities.satisfiedByNetworkCapabilities(
+                    networkAgent.networkCapabilities)) {
+                makeDefault(networkAgent);
+            }
         } else if (state == NetworkInfo.State.DISCONNECTED ||
                 state == NetworkInfo.State.SUSPENDED) {
             networkAgent.asyncChannel.disconnect();
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index a19eb15..87084d5 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -1069,27 +1069,31 @@
         synchronized (mRecords) {
             final int recordCount = mRecords.size();
             pw.println("last known state:");
-            pw.println("  mCallState=" + mCallState);
-            pw.println("  mCallIncomingNumber=" + mCallIncomingNumber);
-            pw.println("  mServiceState=" + mServiceState);
-            pw.println("  mSignalStrength=" + mSignalStrength);
-            pw.println("  mMessageWaiting=" + mMessageWaiting);
-            pw.println("  mCallForwarding=" + mCallForwarding);
-            pw.println("  mDataActivity=" + mDataActivity);
-            pw.println("  mDataConnectionState=" + mDataConnectionState);
-            pw.println("  mDataConnectionPossible=" + mDataConnectionPossible);
-            pw.println("  mDataConnectionReason=" + mDataConnectionReason);
-            pw.println("  mDataConnectionApn=" + mDataConnectionApn);
-            pw.println("  mDataConnectionLinkProperties=" + mDataConnectionLinkProperties);
-            pw.println("  mDataConnectionNetworkCapabilities=" +
-                    mDataConnectionNetworkCapabilities);
+            for (int i = 0; i < TelephonyManager.getDefault().getPhoneCount(); i++) {
+                pw.println("  Phone Id=" + i);
+                pw.println("  mCallState=" + mCallState[i]);
+                pw.println("  mCallIncomingNumber=" + mCallIncomingNumber[i]);
+                pw.println("  mServiceState=" + mServiceState[i]);
+                pw.println("  mSignalStrength=" + mSignalStrength[i]);
+                pw.println("  mMessageWaiting=" + mMessageWaiting[i]);
+                pw.println("  mCallForwarding=" + mCallForwarding[i]);
+                pw.println("  mDataActivity=" + mDataActivity[i]);
+                pw.println("  mDataConnectionState=" + mDataConnectionState[i]);
+                pw.println("  mDataConnectionPossible=" + mDataConnectionPossible[i]);
+                pw.println("  mDataConnectionReason=" + mDataConnectionReason[i]);
+                pw.println("  mDataConnectionApn=" + mDataConnectionApn[i]);
+                pw.println("  mDataConnectionLinkProperties=" + mDataConnectionLinkProperties[i]);
+                pw.println("  mDataConnectionNetworkCapabilities=" +
+                        mDataConnectionNetworkCapabilities[i]);
+                pw.println("  mCellLocation=" + mCellLocation[i]);
+                pw.println("  mCellInfo=" + mCellInfo.get(i));
+            }
             pw.println("  mDefaultSubId=" + mDefaultSubId);
-            pw.println("  mCellLocation=" + mCellLocation);
-            pw.println("  mCellInfo=" + mCellInfo);
             pw.println("  mDcRtInfo=" + mDcRtInfo);
             pw.println("registrations: count=" + recordCount);
             for (Record r : mRecords) {
                 pw.println("  " + r.pkgForDebug + " 0x" + Integer.toHexString(r.events));
+                pw.println("is Legacy = " + r.isLegacyApp + " subId = " + r.subId);
             }
         }
     }
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index 190e87c..db915e2 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -76,6 +76,10 @@
     @GuardedBy("mSessions")
     private final SparseArray<PackageInstallerSession> mSessions = new SparseArray<>();
 
+    /** Historical sessions kept around for debugging purposes */
+    @GuardedBy("mSessions")
+    private final SparseArray<PackageInstallerSession> mHistoricalSessions = new SparseArray<>();
+
     private RemoteCallbackList<IPackageInstallerObserver> mObservers = new RemoteCallbackList<>();
 
     private static final FilenameFilter sStageFilter = new FilenameFilter() {
@@ -344,18 +348,29 @@
     }
 
     void dump(IndentingPrintWriter pw) {
-        pw.println("Active install sessions:");
-        pw.increaseIndent();
         synchronized (mSessions) {
-            final int N = mSessions.size();
+            pw.println("Active install sessions:");
+            pw.increaseIndent();
+            int N = mSessions.size();
             for (int i = 0; i < N; i++) {
                 final PackageInstallerSession session = mSessions.valueAt(i);
                 session.dump(pw);
                 pw.println();
             }
+            pw.println();
+            pw.decreaseIndent();
+
+            pw.println("Historical install sessions:");
+            pw.increaseIndent();
+            N = mHistoricalSessions.size();
+            for (int i = 0; i < N; i++) {
+                final PackageInstallerSession session = mHistoricalSessions.valueAt(i);
+                session.dump(pw);
+                pw.println();
+            }
+            pw.println();
+            pw.decreaseIndent();
         }
-        pw.println();
-        pw.decreaseIndent();
     }
 
     class Callback {
@@ -367,6 +382,7 @@
             notifySessionFinished(session.sessionId, success);
             synchronized (mSessions) {
                 mSessions.remove(session.sessionId);
+                mHistoricalSessions.put(session.sessionId, session);
             }
             writeSessionsAsync();
         }
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 31d9704..0e6a3f0 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -65,6 +65,7 @@
 
 public class PackageInstallerSession extends IPackageInstallerSession.Stub {
     private static final String TAG = "PackageInstaller";
+    private static final boolean LOGD = true;
 
     // TODO: enforce INSTALL_ALLOW_TEST
     // TODO: enforce INSTALL_ALLOW_DOWNGRADE
@@ -435,35 +436,25 @@
      */
     private void spliceExistingFilesIntoStage() throws PackageManagerException {
         final ApplicationInfo app = mPm.getApplicationInfo(mPackageName, 0, userId);
-        final File existingDir = new File(app.getBaseCodePath());
 
-        try {
-            linkTreeIgnoringExisting(existingDir, sessionStageDir);
-        } catch (ErrnoException e) {
-            throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
-                    "Failed to splice into stage");
-        }
-    }
+        int n = 0;
+        final File[] oldFiles = new File(app.getCodePath()).listFiles();
+        if (!ArrayUtils.isEmpty(oldFiles)) {
+            for (File oldFile : oldFiles) {
+                if (!PackageParser.isApkFile(oldFile)) continue;
 
-    /**
-     * Recursively hard link all files from source directory tree to target.
-     * When a file already exists in the target tree, it leaves that file
-     * intact.
-     */
-    private void linkTreeIgnoringExisting(File sourceDir, File targetDir) throws ErrnoException {
-        final File[] sourceContents = sourceDir.listFiles();
-        if (ArrayUtils.isEmpty(sourceContents)) return;
-
-        for (File sourceFile : sourceContents) {
-            final File targetFile = new File(targetDir, sourceFile.getName());
-
-            if (sourceFile.isDirectory()) {
-                targetFile.mkdir();
-                linkTreeIgnoringExisting(sourceFile, targetFile);
-            } else {
-                Libcore.os.link(sourceFile.getAbsolutePath(), targetFile.getAbsolutePath());
+                final File newFile = new File(sessionStageDir, oldFile.getName());
+                try {
+                    Os.link(oldFile.getAbsolutePath(), newFile.getAbsolutePath());
+                    n++;
+                } catch (ErrnoException e) {
+                    throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
+                            "Failed to splice into stage", e);
+                }
             }
         }
+
+        if (LOGD) Slog.d(TAG, "Spliced " + n + " existing APKs into stage");
     }
 
     @Override
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 0ad3a68..727cff0 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -10026,9 +10026,6 @@
             }
         }
 
-        // Nuke any cached code
-        deleteCodeCacheDirsLI(pkgName);
-
         boolean sysPkg = (isSystemApp(oldPackage));
         if (sysPkg) {
             replaceSystemPackageLI(oldPackage, pkg, parseFlags, scanMode,
@@ -10066,6 +10063,7 @@
             deletedPkg = false;
         } else {
             // Successfully deleted the old package. Now proceed with re-installation
+            deleteCodeCacheDirsLI(pkgName);
             try {
                 final PackageParser.Package newPackage = scanPackageLI(pkg, parseFlags,
                         scanMode | SCAN_UPDATE_TIME, System.currentTimeMillis(), user, abiOverride);
@@ -10177,6 +10175,8 @@
         }
 
         // Successfully disabled the old package. Now proceed with re-installation
+        deleteCodeCacheDirsLI(packageName);
+
         res.returnCode = PackageManager.INSTALL_SUCCEEDED;
         pkg.applicationInfo.flags |= ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
 
diff --git a/telecomm/java/android/telecomm/Connection.java b/telecomm/java/android/telecomm/Connection.java
index fb820f0..db834a4 100644
--- a/telecomm/java/android/telecomm/Connection.java
+++ b/telecomm/java/android/telecomm/Connection.java
@@ -44,9 +44,9 @@
         public void onDestroyed(Connection c) {}
         public void onCallCapabilitiesChanged(Connection c, int callCapabilities) {}
         public void onParentConnectionChanged(Connection c, Connection parent) {}
-        public void onSetCallVideoProvider(Connection c, CallVideoProvider callVideoProvider) {}
-        public void onSetAudioModeIsVoip(Connection c, boolean isVoip) {}
-        public void onSetStatusHints(Connection c, StatusHints statusHints) {}
+        public void onCallVideoProviderChanged(Connection c, CallVideoProvider callVideoProvider) {}
+        public void onAudioModeIsVoipChanged(Connection c, boolean isVoip) {}
+        public void onStatusHintsChanged(Connection c, StatusHints statusHints) {}
     }
 
     public final class State {
@@ -321,7 +321,7 @@
     public final void setCallVideoProvider(CallVideoProvider callVideoProvider) {
         mCallVideoProvider = callVideoProvider;
         for (Listener l : mListeners) {
-            l.onSetCallVideoProvider(this, callVideoProvider);
+            l.onCallVideoProviderChanged(this, callVideoProvider);
         }
     }
 
@@ -415,7 +415,7 @@
     public final void setAudioModeIsVoip(boolean isVoip) {
         mAudioModeIsVoip = isVoip;
         for (Listener l : mListeners) {
-            l.onSetAudioModeIsVoip(this, isVoip);
+            l.onAudioModeIsVoipChanged(this, isVoip);
         }
     }
 
@@ -427,7 +427,7 @@
     public final void setStatusHints(StatusHints statusHints) {
         mStatusHints = statusHints;
         for (Listener l : mListeners) {
-            l.onSetStatusHints(this, statusHints);
+            l.onStatusHintsChanged(this, statusHints);
         }
     }
 
@@ -516,7 +516,6 @@
      */
     protected void onPhoneAccountClicked() {}
 
-
     private void addChild(Connection connection) {
         Log.d(this, "adding child %s", connection);
         mChildConnections.add(connection);
diff --git a/telecomm/java/android/telecomm/ConnectionService.java b/telecomm/java/android/telecomm/ConnectionService.java
index 178cee8..2a6804b 100644
--- a/telecomm/java/android/telecomm/ConnectionService.java
+++ b/telecomm/java/android/telecomm/ConnectionService.java
@@ -364,19 +364,19 @@
         }
 
         @Override
-        public void onSetCallVideoProvider(Connection c, CallVideoProvider callVideoProvider) {
+        public void onCallVideoProviderChanged(Connection c, CallVideoProvider callVideoProvider) {
             String id = mIdByConnection.get(c);
             mAdapter.setCallVideoProvider(id, callVideoProvider);
         }
 
         @Override
-        public void onSetAudioModeIsVoip(Connection c, boolean isVoip) {
+        public void onAudioModeIsVoipChanged(Connection c, boolean isVoip) {
             String id = mIdByConnection.get(c);
             mAdapter.setAudioModeIsVoip(id, isVoip);
         }
 
         @Override
-        public void onSetStatusHints(Connection c, StatusHints statusHints) {
+        public void onStatusHintsChanged(Connection c, StatusHints statusHints) {
             String id = mIdByConnection.get(c);
             mAdapter.setStatusHints(id, statusHints);
         }
diff --git a/telecomm/java/android/telecomm/TelecommConstants.java b/telecomm/java/android/telecomm/TelecommConstants.java
index a94841f..b50c1d7 100644
--- a/telecomm/java/android/telecomm/TelecommConstants.java
+++ b/telecomm/java/android/telecomm/TelecommConstants.java
@@ -121,4 +121,83 @@
      * wait for user confirmation before proceeding.
      */
     public static final char DTMF_CHARACTER_WAIT = ';';
+
+    /**
+     * TTY (teletypewriter) mode is off.
+     *
+     * @hide
+     */
+    public static final int TTY_MODE_OFF = 0;
+
+    /**
+     * TTY (teletypewriter) mode is on. The speaker is off and the microphone is muted. The user
+     * will communicate with the remote party by sending and receiving text messages.
+     *
+     * @hide
+     */
+    public static final int TTY_MODE_FULL = 1;
+
+    /**
+     * TTY (teletypewriter) mode is in hearing carryover mode (HCO). The microphone is muted but the
+     * speaker is on. The user will communicate with the remote party by sending text messages and
+     * hearing an audible reply.
+     *
+     * @hide
+     */
+    public static final int TTY_MODE_HCO = 2;
+
+    /**
+     * TTY (teletypewriter) mode is in voice carryover mode (VCO). The speaker is off but the
+     * microphone is still on. User will communicate with the remote party by speaking and receiving
+     * text message replies.
+     *
+     * @hide
+     */
+    public static final int TTY_MODE_VCO = 3;
+
+    /**
+     * Broadcast intent action indicating that the current TTY mode has changed. An intent extra
+     * provides this state as an int.
+     * @see #EXTRA_CURRENT_TTY_MODE
+     *
+     * @hide
+     */
+    public static final String ACTION_CURRENT_TTY_MODE_CHANGED =
+            "android.telecomm.intent.action.CURRENT_TTY_MODE_CHANGED";
+
+    /**
+     * The lookup key for an int that indicates the current TTY mode.
+     * Valid modes are:
+     * - {@link #TTY_MODE_OFF}
+     * - {@link #TTY_MODE_FULL}
+     * - {@link #TTY_MODE_HCO}
+     * - {@link #TTY_MODE_VCO}
+     *
+     * @hide
+     */
+    public static final String EXTRA_CURRENT_TTY_MODE =
+            "android.telecomm.intent.extra.CURRENT_TTY_MODE";
+
+    /**
+     * Broadcast intent action indicating that the TTY preferred operating mode
+     * has changed. An intent extra provides the new mode as an int.
+     * @see #EXTRA_TTY_PREFERRED_MODE
+     *
+     * @hide
+     */
+    public static final String ACTION_TTY_PREFERRED_MODE_CHANGED =
+            "android.telecomm.intent.action.TTY_PREFERRED_MODE_CHANGED";
+
+    /**
+     * The lookup key for an int that indicates preferred TTY mode.
+     * Valid modes are:
+     * - {@link #TTY_MODE_OFF}
+     * - {@link #TTY_MODE_FULL}
+     * - {@link #TTY_MODE_HCO}
+     * - {@link #TTY_MODE_VCO}
+     *
+     * @hide
+     */
+    public static final String EXTRA_TTY_PREFERRED_MODE =
+            "android.telecomm.intent.extra.TTY_PREFERRED";
 }
diff --git a/telecomm/java/android/telecomm/TelecommManager.java b/telecomm/java/android/telecomm/TelecommManager.java
index fcd2eba..8bf80bb 100644
--- a/telecomm/java/android/telecomm/TelecommManager.java
+++ b/telecomm/java/android/telecomm/TelecommManager.java
@@ -28,21 +28,9 @@
 /**
  * Provides access to Telecomm-related functionality.
  * TODO(santoscordon): Move this all into PhoneManager.
- * @hide
  */
 public class TelecommManager {
 
-    /**
-     * The extra used with an {@link android.content.Intent#ACTION_CALL} or
-     * {@link android.content.Intent#ACTION_DIAL} {@code Intent} to specify a {@link PhoneAccount}
-     * to use when making the call.
-     *
-     * <p class="note">
-     * Retrieve with
-     * {@link android.content.Intent#getParcelableExtra(String)}.
-     */
-    public static final String EXTRA_PHONE_ACCOUNT = "account";
-
     private static final String TAG = "TelecommManager";
     private static final String TELECOMM_SERVICE_NAME = "telecomm";
 
@@ -138,8 +126,6 @@
      * Remove all Accounts for a given package from the system.
      *
      * @param packageName A package name that may have registered Accounts.
-     *
-     * @hide
      */
     @SystemApi
     public void clearAccounts(String packageName) {
@@ -254,6 +240,44 @@
         }
     }
 
+    /**
+     * Returns whether TTY is supported on this device.
+     *
+     * @hide
+     */
+    @SystemApi
+    public boolean isTtySupported() {
+        try {
+            if (isServiceConnected()) {
+                return getTelecommService().isTtySupported();
+            }
+        } catch (RemoteException e) {
+            Log.e(TAG, "RemoteException attempting to get TTY supported state.", e);
+        }
+        return false;
+    }
+
+    /**
+     * Returns the current TTY mode of the device. For TTY to be on the user must enable it in
+     * settings and have a wired headset plugged in. Valid modes are:
+     * - {@link android.telecomm.TelecommConstants#TTY_MODE_OFF}
+     * - {@link android.telecomm.TelecommConstants#TTY_MODE_FULL}
+     * - {@link android.telecomm.TelecommConstants#TTY_MODE_HCO}
+     * - {@link android.telecomm.TelecommConstants#TTY_MODE_VCO}
+     *
+     * @hide
+     */
+    public int getCurrentTtyMode() {
+        try {
+            if (isServiceConnected()) {
+                return getTelecommService().getCurrentTtyMode();
+            }
+        } catch (RemoteException e) {
+            Log.e(TAG, "RemoteException attempting to get the current TTY mode.", e);
+        }
+        return TelecommConstants.TTY_MODE_OFF;
+    }
+
     private ITelecommService getTelecommService() {
         return ITelecommService.Stub.asInterface(ServiceManager.getService(TELECOMM_SERVICE_NAME));
     }
diff --git a/telecomm/java/com/android/internal/telecomm/ITelecommService.aidl b/telecomm/java/com/android/internal/telecomm/ITelecommService.aidl
index 3334385..43caa1e 100644
--- a/telecomm/java/com/android/internal/telecomm/ITelecommService.aidl
+++ b/telecomm/java/com/android/internal/telecomm/ITelecommService.aidl
@@ -101,4 +101,14 @@
      * @see PhoneManager#handlePinMmi
      */
     boolean handlePinMmi(String dialString);
+
+    /**
+     * @see TelecomManager#isTtySupported
+     */
+    boolean isTtySupported();
+
+    /**
+     * @see TelecomManager#getCurrentTtyMode
+     */
+    int getCurrentTtyMode();
 }
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index cf4cb89..7ad05ab 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -18,6 +18,7 @@
 
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
+import android.annotation.SystemApi;
 import android.content.Context;
 import android.net.DhcpInfo;
 import android.net.wifi.ScanSettings;
@@ -82,7 +83,29 @@
      * Extra int indicating scan availability, WIFI_STATE_ENABLED and WIFI_STATE_DISABLED
      * @hide
      */
-     public static final String EXTRA_SCAN_AVAILABLE = "scan_enabled";
+    public static final String EXTRA_SCAN_AVAILABLE = "scan_enabled";
+
+    /**
+     * Broadcast intent action indicating that the credential of a Wi-Fi network
+     * has been changed. One extra provides the ssid of the network. Another
+     * extra provides the event type, whether the credential is saved or forgot.
+     * @hide
+     */
+    @SystemApi
+    public static final String WIFI_CREDENTIAL_CHANGED_ACTION =
+            "android.net.wifi.WIFI_CREDENTIAL_CHANGED";
+    /** @hide */
+    @SystemApi
+    public static final String EXTRA_WIFI_CREDENTIAL_EVENT_TYPE = "et";
+    /** @hide */
+    @SystemApi
+    public static final String EXTRA_WIFI_CREDENTIAL_SSID = "ssid";
+    /** @hide */
+    @SystemApi
+    public static final int WIFI_CREDENTIAL_SAVED = 0;
+    /** @hide */
+    @SystemApi
+    public static final int WIFI_CREDENTIAL_FORGOT = 1;
 
     /**
      * Broadcast intent action indicating that Wi-Fi has been enabled, disabled,