Merge "Improve dialog padding when title or body text are missing" into lmp-dev
diff --git a/api/current.txt b/api/current.txt
index 65c15b0..5c05305 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -12682,7 +12682,7 @@
     method public void onCaptureProgressed(android.hardware.camera2.CameraCaptureSession, android.hardware.camera2.CaptureRequest, android.hardware.camera2.CaptureResult);
     method public void onCaptureSequenceAborted(android.hardware.camera2.CameraCaptureSession, int);
     method public void onCaptureSequenceCompleted(android.hardware.camera2.CameraCaptureSession, int, long);
-    method public void onCaptureStarted(android.hardware.camera2.CameraCaptureSession, android.hardware.camera2.CaptureRequest, long);
+    method public void onCaptureStarted(android.hardware.camera2.CameraCaptureSession, android.hardware.camera2.CaptureRequest, long, long);
   }
 
   public static abstract class CameraCaptureSession.StateCallback {
@@ -14672,6 +14672,7 @@
   public static final class MediaCodec.CryptoException extends java.lang.RuntimeException {
     ctor public MediaCodec.CryptoException(int, java.lang.String);
     method public int getErrorCode();
+    field public static final int ERROR_INSUFFICIENT_OUTPUT_PROTECTION = 4; // 0x4
     field public static final int ERROR_KEY_EXPIRED = 2; // 0x2
     field public static final int ERROR_NO_KEY = 1; // 0x1
     field public static final int ERROR_RESOURCE_BUSY = 3; // 0x3
@@ -29034,7 +29035,6 @@
     method public java.lang.String sendEnvelopeWithStatus(java.lang.String);
     method public boolean setGlobalPreferredNetworkType();
     method public void setLine1NumberForDisplay(java.lang.String, java.lang.String);
-    method public void setLine1NumberForDisplay(long, java.lang.String, java.lang.String);
     method public boolean setOperatorBrandOverride(java.lang.String);
     field public static final java.lang.String ACTION_PHONE_STATE_CHANGED = "android.intent.action.PHONE_STATE";
     field public static final java.lang.String ACTION_RESPOND_VIA_MESSAGE = "android.intent.action.RESPOND_VIA_MESSAGE";
diff --git a/core/java/android/app/backup/BackupManager.java b/core/java/android/app/backup/BackupManager.java
index 1bb4eba..9151a16 100644
--- a/core/java/android/app/backup/BackupManager.java
+++ b/core/java/android/app/backup/BackupManager.java
@@ -218,6 +218,7 @@
      */
     @SystemApi
     public boolean isBackupEnabled() {
+        checkServiceBinder();
         if (sService != null) {
             try {
                 return sService.isBackupEnabled();
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index e0fd532..ddb0a6d 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -1099,9 +1099,12 @@
                     }
                 }
             }
-        } catch (GeneralSecurityException | IOException | RuntimeException e) {
+        } catch (GeneralSecurityException e) {
             throw new PackageParserException(INSTALL_PARSE_FAILED_CERTIFICATE_ENCODING,
                     "Failed to collect certificates from " + apkPath, e);
+        } catch (IOException | RuntimeException e) {
+            throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES,
+                    "Failed to collect certificates from " + apkPath, e);
         } finally {
             closeQuietly(jarFile);
         }
diff --git a/core/java/android/content/pm/UserInfo.java b/core/java/android/content/pm/UserInfo.java
index c0383a3..c03be32 100644
--- a/core/java/android/content/pm/UserInfo.java
+++ b/core/java/android/content/pm/UserInfo.java
@@ -89,6 +89,7 @@
 
     /** User is only partially created. */
     public boolean partial;
+    public boolean guestToRemove;
 
     public UserInfo(int id, String name, int flags) {
         this(id, name, null, flags);
@@ -147,6 +148,7 @@
         lastLoggedInTime = orig.lastLoggedInTime;
         partial = orig.partial;
         profileGroupId = orig.profileGroupId;
+        guestToRemove = orig.guestToRemove;
     }
 
     public UserHandle getUserHandle() {
@@ -172,6 +174,7 @@
         dest.writeLong(lastLoggedInTime);
         dest.writeInt(partial ? 1 : 0);
         dest.writeInt(profileGroupId);
+        dest.writeInt(guestToRemove ? 1 : 0);
     }
 
     public static final Parcelable.Creator<UserInfo> CREATOR
@@ -194,5 +197,6 @@
         lastLoggedInTime = source.readLong();
         partial = source.readInt() != 0;
         profileGroupId = source.readInt();
+        guestToRemove = source.readInt() != 0;
     }
 }
diff --git a/core/java/android/hardware/camera2/CameraCaptureSession.java b/core/java/android/hardware/camera2/CameraCaptureSession.java
index 29e42ea..ce83028 100644
--- a/core/java/android/hardware/camera2/CameraCaptureSession.java
+++ b/core/java/android/hardware/camera2/CameraCaptureSession.java
@@ -483,7 +483,9 @@
          * and in the buffers sent to each output Surface. These buffer
          * timestamps are accessible through, for example,
          * {@link android.media.Image#getTimestamp() Image.getTimestamp()} or
-         * {@link android.graphics.SurfaceTexture#getTimestamp()}.</p>
+         * {@link android.graphics.SurfaceTexture#getTimestamp()}.
+         * The frame number included is equal to the frame number that will be included in
+         * {@link CaptureResult#getFrameNumber}.</p>
          *
          * <p>For the simplest way to play a shutter sound camera shutter or a
          * video recording start/stop sound, see the
@@ -494,10 +496,21 @@
          * @param session the session returned by {@link CameraDevice#createCaptureSession}
          * @param request the request for the capture that just begun
          * @param timestamp the timestamp at start of capture, in nanoseconds.
+         * @param frameNumber the frame number for this capture
          *
          * @see android.media.MediaActionSound
          */
         public void onCaptureStarted(CameraCaptureSession session,
+                CaptureRequest request, long timestamp, long frameNumber) {
+            // Temporary trampoline for API change transition
+            onCaptureStarted(session, request, timestamp);
+        }
+
+        /**
+         * Temporary for API change transition
+         * @hide
+         */
+        public void onCaptureStarted(CameraCaptureSession session,
                 CaptureRequest request, long timestamp) {
             // default empty implementation
         }
diff --git a/core/java/android/hardware/camera2/CaptureRequest.java b/core/java/android/hardware/camera2/CaptureRequest.java
index 6d0d505..93eb3de 100644
--- a/core/java/android/hardware/camera2/CaptureRequest.java
+++ b/core/java/android/hardware/camera2/CaptureRequest.java
@@ -731,6 +731,8 @@
     /**
      * <p>List of areas to use for
      * metering.</p>
+     * <p>Optional. Not available if {@link CameraCharacteristics#CONTROL_MAX_REGIONS_AE android.control.maxRegionsAe} is 0.
+     * Otherwise will always be present.</p>
      * <p>The coordinate system is based on the active pixel array,
      * with (0,0) being the top-left pixel in the active pixel array, and
      * ({@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.width - 1,
@@ -746,7 +748,9 @@
      * outside the used {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion} returned in capture result metadata,
      * the camera device will ignore the sections outside the region and output the
      * used sections in the result metadata.</p>
+     * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
      *
+     * @see CameraCharacteristics#CONTROL_MAX_REGIONS_AE
      * @see CaptureRequest#SCALER_CROP_REGION
      * @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE
      */
@@ -820,6 +824,8 @@
     /**
      * <p>List of areas to use for focus
      * estimation.</p>
+     * <p>Optional. Not available if {@link CameraCharacteristics#CONTROL_MAX_REGIONS_AF android.control.maxRegionsAf} is 0.
+     * Otherwise will always be present.</p>
      * <p>The coordinate system is based on the active pixel array,
      * with (0,0) being the top-left pixel in the active pixel array, and
      * ({@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.width - 1,
@@ -835,7 +841,9 @@
      * outside the used {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion} returned in capture result metadata,
      * the camera device will ignore the sections outside the region and output the
      * used sections in the result metadata.</p>
+     * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
      *
+     * @see CameraCharacteristics#CONTROL_MAX_REGIONS_AF
      * @see CaptureRequest#SCALER_CROP_REGION
      * @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE
      */
@@ -921,6 +929,8 @@
     /**
      * <p>List of areas to use for illuminant
      * estimation.</p>
+     * <p>Optional. Not available if {@link CameraCharacteristics#CONTROL_MAX_REGIONS_AWB android.control.maxRegionsAwb} is 0.
+     * Otherwise will always be present.</p>
      * <p>The coordinate system is based on the active pixel array,
      * with (0,0) being the top-left pixel in the active pixel array, and
      * ({@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.width - 1,
@@ -936,7 +946,9 @@
      * outside the used {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion} returned in capture result metadata,
      * the camera device will ignore the sections outside the region and output the
      * used sections in the result metadata.</p>
+     * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
      *
+     * @see CameraCharacteristics#CONTROL_MAX_REGIONS_AWB
      * @see CaptureRequest#SCALER_CROP_REGION
      * @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE
      */
diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java
index 754d83e..01276a2 100644
--- a/core/java/android/hardware/camera2/CaptureResult.java
+++ b/core/java/android/hardware/camera2/CaptureResult.java
@@ -582,6 +582,8 @@
     /**
      * <p>List of areas to use for
      * metering.</p>
+     * <p>Optional. Not available if {@link CameraCharacteristics#CONTROL_MAX_REGIONS_AE android.control.maxRegionsAe} is 0.
+     * Otherwise will always be present.</p>
      * <p>The coordinate system is based on the active pixel array,
      * with (0,0) being the top-left pixel in the active pixel array, and
      * ({@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.width - 1,
@@ -597,7 +599,9 @@
      * outside the used {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion} returned in capture result metadata,
      * the camera device will ignore the sections outside the region and output the
      * used sections in the result metadata.</p>
+     * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
      *
+     * @see CameraCharacteristics#CONTROL_MAX_REGIONS_AE
      * @see CaptureRequest#SCALER_CROP_REGION
      * @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE
      */
@@ -870,6 +874,8 @@
     /**
      * <p>List of areas to use for focus
      * estimation.</p>
+     * <p>Optional. Not available if {@link CameraCharacteristics#CONTROL_MAX_REGIONS_AF android.control.maxRegionsAf} is 0.
+     * Otherwise will always be present.</p>
      * <p>The coordinate system is based on the active pixel array,
      * with (0,0) being the top-left pixel in the active pixel array, and
      * ({@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.width - 1,
@@ -885,7 +891,9 @@
      * outside the used {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion} returned in capture result metadata,
      * the camera device will ignore the sections outside the region and output the
      * used sections in the result metadata.</p>
+     * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
      *
+     * @see CameraCharacteristics#CONTROL_MAX_REGIONS_AF
      * @see CaptureRequest#SCALER_CROP_REGION
      * @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE
      */
@@ -1369,6 +1377,8 @@
     /**
      * <p>List of areas to use for illuminant
      * estimation.</p>
+     * <p>Optional. Not available if {@link CameraCharacteristics#CONTROL_MAX_REGIONS_AWB android.control.maxRegionsAwb} is 0.
+     * Otherwise will always be present.</p>
      * <p>The coordinate system is based on the active pixel array,
      * with (0,0) being the top-left pixel in the active pixel array, and
      * ({@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.width - 1,
@@ -1384,7 +1394,9 @@
      * outside the used {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion} returned in capture result metadata,
      * the camera device will ignore the sections outside the region and output the
      * used sections in the result metadata.</p>
+     * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
      *
+     * @see CameraCharacteristics#CONTROL_MAX_REGIONS_AWB
      * @see CaptureRequest#SCALER_CROP_REGION
      * @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE
      */
diff --git a/core/java/android/hardware/camera2/dispatch/MethodNameInvoker.java b/core/java/android/hardware/camera2/dispatch/MethodNameInvoker.java
index 02c3d87..c66a3a4 100644
--- a/core/java/android/hardware/camera2/dispatch/MethodNameInvoker.java
+++ b/core/java/android/hardware/camera2/dispatch/MethodNameInvoker.java
@@ -48,7 +48,8 @@
     /**
      * Invoke a method by its name.
      *
-     * <p>If more than one method exists in {@code targetClass}, the first method will be used.</p>
+     * <p>If more than one method exists in {@code targetClass}, the first method with the right
+     * number of arguments will be used, and later calls will all use that method.</p>
      *
      * @param methodName
      *          The name of the method, which will be matched 1:1 to the destination method
@@ -68,8 +69,9 @@
         Method targetMethod = mMethods.get(methodName);
         if (targetMethod == null) {
             for (Method method : mTargetClass.getMethods()) {
-                // TODO future: match by # of params and types of params if possible
-                if (method.getName().equals(methodName)) {
+                // TODO future: match types of params if possible
+                if (method.getName().equals(methodName) &&
+                        (params.length == method.getParameterTypes().length) ) {
                     targetMethod = method;
                     mMethods.put(methodName, targetMethod);
                     break;
diff --git a/core/java/android/hardware/camera2/impl/CallbackProxies.java b/core/java/android/hardware/camera2/impl/CallbackProxies.java
index e5ddb7a..f0217ac 100644
--- a/core/java/android/hardware/camera2/impl/CallbackProxies.java
+++ b/core/java/android/hardware/camera2/impl/CallbackProxies.java
@@ -98,8 +98,8 @@
 
         @Override
         public void onCaptureStarted(CameraDevice camera,
-                CaptureRequest request, long timestamp) {
-            mProxy.invoke("onCaptureStarted", camera, request, timestamp);
+                CaptureRequest request, long timestamp, long frameNumber) {
+            mProxy.invoke("onCaptureStarted", camera, request, timestamp, frameNumber);
         }
 
         @Override
diff --git a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
index d454092..f011d60 100644
--- a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
@@ -803,7 +803,7 @@
          * @see android.media.MediaActionSound
          */
         public void onCaptureStarted(CameraDevice camera,
-                CaptureRequest request, long timestamp) {
+                CaptureRequest request, long timestamp, long frameNumber) {
             // default empty implementation
         }
 
@@ -1237,8 +1237,10 @@
         @Override
         public void onCaptureStarted(final CaptureResultExtras resultExtras, final long timestamp) {
             int requestId = resultExtras.getRequestId();
+            final long frameNumber = resultExtras.getFrameNumber();
+
             if (DEBUG) {
-                Log.d(TAG, "Capture started for id " + requestId);
+                Log.d(TAG, "Capture started for id " + requestId + " frame number " + frameNumber);
             }
             final CaptureCallbackHolder holder;
 
@@ -1263,7 +1265,7 @@
                                 holder.getCallback().onCaptureStarted(
                                     CameraDeviceImpl.this,
                                     holder.getRequest(resultExtras.getSubsequenceId()),
-                                    timestamp);
+                                    timestamp, frameNumber);
                             }
                         }
                     });
diff --git a/core/java/android/hardware/camera2/legacy/LegacyMetadataMapper.java b/core/java/android/hardware/camera2/legacy/LegacyMetadataMapper.java
index a8d1018..3c0e0e4 100644
--- a/core/java/android/hardware/camera2/legacy/LegacyMetadataMapper.java
+++ b/core/java/android/hardware/camera2/legacy/LegacyMetadataMapper.java
@@ -675,15 +675,13 @@
          * request.availableRequestKeys
          */
         {
-            CaptureRequest.Key<?> availableKeys[] = new CaptureRequest.Key<?>[] {
+            CaptureRequest.Key<?> defaultAvailableKeys[] = new CaptureRequest.Key<?>[] {
                     CaptureRequest.CONTROL_AE_ANTIBANDING_MODE,
                     CaptureRequest.CONTROL_AE_EXPOSURE_COMPENSATION,
                     CaptureRequest.CONTROL_AE_LOCK,
                     CaptureRequest.CONTROL_AE_MODE,
-                    CaptureRequest.CONTROL_AE_REGIONS,
                     CaptureRequest.CONTROL_AE_TARGET_FPS_RANGE,
                     CaptureRequest.CONTROL_AF_MODE,
-                    CaptureRequest.CONTROL_AF_REGIONS,
                     CaptureRequest.CONTROL_AF_TRIGGER,
                     CaptureRequest.CONTROL_AWB_LOCK,
                     CaptureRequest.CONTROL_AWB_MODE,
@@ -704,21 +702,32 @@
                     CaptureRequest.SCALER_CROP_REGION,
                     CaptureRequest.STATISTICS_FACE_DETECT_MODE,
             };
-            m.set(REQUEST_AVAILABLE_REQUEST_KEYS, getTagsForKeys(availableKeys));
+            ArrayList<CaptureRequest.Key<?>> availableKeys =
+                    new ArrayList<CaptureRequest.Key<?>>(Arrays.asList(defaultAvailableKeys));
+
+            if (p.getMaxNumMeteringAreas() > 0) {
+                availableKeys.add(CaptureRequest.CONTROL_AE_REGIONS);
+            }
+            if (p.getMaxNumFocusAreas() > 0) {
+                availableKeys.add(CaptureRequest.CONTROL_AF_REGIONS);
+            }
+
+            CaptureRequest.Key<?> availableRequestKeys[] =
+                    new CaptureRequest.Key<?>[availableKeys.size()];
+            availableKeys.toArray(availableRequestKeys);
+            m.set(REQUEST_AVAILABLE_REQUEST_KEYS, getTagsForKeys(availableRequestKeys));
         }
 
         /*
          * request.availableResultKeys
          */
         {
-            CaptureResult.Key<?> availableKeys[] = new CaptureResult.Key<?>[] {
+            CaptureResult.Key<?> defaultAvailableKeys[] = new CaptureResult.Key<?>[] {
                     CaptureResult.CONTROL_AE_ANTIBANDING_MODE                      ,
                     CaptureResult.CONTROL_AE_EXPOSURE_COMPENSATION                 ,
                     CaptureResult.CONTROL_AE_LOCK                                  ,
                     CaptureResult.CONTROL_AE_MODE                                  ,
-                    CaptureResult.CONTROL_AE_REGIONS                               ,
                     CaptureResult.CONTROL_AF_MODE                                  ,
-                    CaptureResult.CONTROL_AF_REGIONS                               ,
                     CaptureResult.CONTROL_AF_STATE                                 ,
                     CaptureResult.CONTROL_AWB_MODE                                 ,
                     CaptureResult.CONTROL_AWB_LOCK                                 ,
@@ -737,7 +746,20 @@
                     CaptureResult.STATISTICS_FACE_DETECT_MODE                      ,
 //                    CaptureResult.STATISTICS_FACES                                 ,
             };
-            m.set(REQUEST_AVAILABLE_RESULT_KEYS, getTagsForKeys(availableKeys));
+            List<CaptureResult.Key<?>> availableKeys =
+                    new ArrayList<CaptureResult.Key<?>>(Arrays.asList(defaultAvailableKeys));
+
+            if (p.getMaxNumMeteringAreas() > 0) {
+                availableKeys.add(CaptureResult.CONTROL_AE_REGIONS);
+            }
+            if (p.getMaxNumFocusAreas() > 0) {
+                availableKeys.add(CaptureResult.CONTROL_AF_REGIONS);
+            }
+
+            CaptureResult.Key<?> availableResultKeys[] =
+                    new CaptureResult.Key<?>[availableKeys.size()];
+            availableKeys.toArray(availableResultKeys);
+            m.set(REQUEST_AVAILABLE_RESULT_KEYS, getTagsForKeys(availableResultKeys));
         }
 
         /*
diff --git a/core/java/android/hardware/camera2/legacy/LegacyResultMapper.java b/core/java/android/hardware/camera2/legacy/LegacyResultMapper.java
index 090a822..ddaa6ee 100644
--- a/core/java/android/hardware/camera2/legacy/LegacyResultMapper.java
+++ b/core/java/android/hardware/camera2/legacy/LegacyResultMapper.java
@@ -322,7 +322,7 @@
         }
 
         // control.aeRegions
-        {
+        if (p.getMaxNumMeteringAreas() > 0) {
             if (VERBOSE) {
                 String meteringAreas = p.get("metering-areas");
                 Log.v(TAG, "mapAe - parameter dump; metering-areas: " + meteringAreas);
@@ -342,7 +342,7 @@
         m.set(CaptureResult.CONTROL_AF_MODE, convertLegacyAfMode(p.getFocusMode()));
 
         // control.afRegions
-        {
+        if (p.getMaxNumFocusAreas() > 0) {
             if (VERBOSE) {
                 String focusAreas = p.get("focus-areas");
                 Log.v(TAG, "mapAe - parameter dump; focus-areas: " + focusAreas);
diff --git a/core/java/android/widget/ActionMenuView.java b/core/java/android/widget/ActionMenuView.java
index 6ca4a9e..7198e52 100644
--- a/core/java/android/widget/ActionMenuView.java
+++ b/core/java/android/widget/ActionMenuView.java
@@ -611,6 +611,7 @@
             mMenu = new MenuBuilder(context);
             mMenu.setCallback(new MenuBuilderCallback());
             mPresenter = new ActionMenuPresenter(context);
+            mPresenter.setReserveOverflow(true);
             mPresenter.setCallback(mActionMenuPresenterCallback != null
                     ? mActionMenuPresenterCallback : new ActionMenuPresenterCallback());
             mMenu.addMenuPresenter(mPresenter, mPopupContext);
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 3e1b674..80ea6ea 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -8423,6 +8423,33 @@
     @Override
     public boolean performAccessibilityAction(int action, Bundle arguments) {
         switch (action) {
+            case AccessibilityNodeInfo.ACTION_CLICK: {
+                boolean handled = false;
+
+                // Simulate View.onTouchEvent for an ACTION_UP event.
+                if (isClickable() || isLongClickable()) {
+                    if (isFocusable() && !isFocused()) {
+                        requestFocus();
+                    }
+
+                    performClick();
+                    handled = true;
+                }
+
+                // Simulate TextView.onTouchEvent for an ACTION_UP event.
+                if ((mMovement != null || onCheckIsTextEditor()) && isEnabled()
+                        && mText instanceof Spannable && mLayout != null
+                        && (isTextEditable() || isTextSelectable()) && isFocused()) {
+                    // Show the IME, except when selecting in read-only text.
+                    final InputMethodManager imm = InputMethodManager.peekInstance();
+                    viewClicked(imm);
+                    if (!isTextSelectable() && mEditor.mShowSoftInputOnFocus && imm != null) {
+                        handled |= imm.showSoftInput(this, 0);
+                    }
+                }
+
+                return handled;
+            }
             case AccessibilityNodeInfo.ACTION_COPY: {
                 if (isFocused() && canCopy()) {
                     if (onTextContextMenuItem(ID_COPY)) {
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index 2106d38..dbaa4b8 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -129,6 +129,7 @@
 	android/graphics/Xfermode.cpp \
 	android/graphics/YuvToJpegEncoder.cpp \
 	android/graphics/pdf/PdfDocument.cpp \
+	android/graphics/pdf/PdfEditor.cpp \
 	android/graphics/pdf/PdfRenderer.cpp \
 	android_media_AudioRecord.cpp \
 	android_media_AudioSystem.cpp \
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 62d8036..a63258c 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -126,6 +126,7 @@
 extern int register_android_graphics_SurfaceTexture(JNIEnv* env);
 extern int register_android_graphics_Xfermode(JNIEnv* env);
 extern int register_android_graphics_pdf_PdfDocument(JNIEnv* env);
+extern int register_android_graphics_pdf_PdfEditor(JNIEnv* env);
 extern int register_android_graphics_pdf_PdfRenderer(JNIEnv* env);
 extern int register_android_view_DisplayEventReceiver(JNIEnv* env);
 extern int register_android_view_RenderNode(JNIEnv* env);
@@ -1305,6 +1306,7 @@
     REG_JNI(register_android_graphics_Xfermode),
     REG_JNI(register_android_graphics_YuvImage),
     REG_JNI(register_android_graphics_pdf_PdfDocument),
+    REG_JNI(register_android_graphics_pdf_PdfEditor),
     REG_JNI(register_android_graphics_pdf_PdfRenderer),
 
     REG_JNI(register_android_database_CursorWindow),
diff --git a/core/jni/android/graphics/pdf/PdfEditor.cpp b/core/jni/android/graphics/pdf/PdfEditor.cpp
new file mode 100644
index 0000000..5f60c9e
--- /dev/null
+++ b/core/jni/android/graphics/pdf/PdfEditor.cpp
@@ -0,0 +1,161 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "jni.h"
+#include "JNIHelp.h"
+#include "fpdfview.h"
+#include "fpdfedit.h"
+#include "fpdfsave.h"
+
+#include <android_runtime/AndroidRuntime.h>
+#include <vector>
+#include <utils/Log.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+namespace android {
+
+static Mutex sLock;
+
+static int sUnmatchedInitRequestCount = 0;
+
+static void initializeLibraryIfNeeded() {
+    Mutex::Autolock _l(sLock);
+    if (sUnmatchedInitRequestCount == 0) {
+        FPDF_InitLibrary(NULL);
+    }
+    sUnmatchedInitRequestCount++;
+}
+
+static void destroyLibraryIfNeeded() {
+    Mutex::Autolock _l(sLock);
+    sUnmatchedInitRequestCount--;
+    if (sUnmatchedInitRequestCount == 0) {
+       FPDF_DestroyLibrary();
+    }
+}
+
+static int getBlock(void* param, unsigned long position, unsigned char* outBuffer,
+        unsigned long size) {
+    const int fd = reinterpret_cast<intptr_t>(param);
+    const int readCount = pread(fd, outBuffer, size, position);
+    if (readCount < 0) {
+        ALOGE("Cannot read from file descriptor. Error:%d", errno);
+        return 0;
+    }
+    return 1;
+}
+
+static jlong nativeOpen(JNIEnv* env, jclass thiz, jint fd, jlong size) {
+    initializeLibraryIfNeeded();
+
+    FPDF_FILEACCESS loader;
+    loader.m_FileLen = size;
+    loader.m_Param = reinterpret_cast<void*>(intptr_t(fd));
+    loader.m_GetBlock = &getBlock;
+
+    FPDF_DOCUMENT document = FPDF_LoadCustomDocument(&loader, NULL);
+
+    if (!document) {
+        const long error = FPDF_GetLastError();
+        jniThrowException(env, "java/io/IOException",
+                "cannot create document. Error:" + error);
+        destroyLibraryIfNeeded();
+        return -1;
+    }
+
+    return reinterpret_cast<jlong>(document);
+}
+
+static void nativeClose(JNIEnv* env, jclass thiz, jlong documentPtr) {
+    FPDF_DOCUMENT document = reinterpret_cast<FPDF_DOCUMENT>(documentPtr);
+    FPDF_CloseDocument(document);
+    destroyLibraryIfNeeded();
+}
+
+static jint nativeGetPageCount(JNIEnv* env, jclass thiz, jlong documentPtr) {
+    FPDF_DOCUMENT document = reinterpret_cast<FPDF_DOCUMENT>(documentPtr);
+    return FPDF_GetPageCount(document);
+}
+
+static jint nativeRemovePage(JNIEnv* env, jclass thiz, jlong documentPtr, jint pageIndex) {
+    FPDF_DOCUMENT document = reinterpret_cast<FPDF_DOCUMENT>(documentPtr);
+    FPDFPage_Delete(document, pageIndex);
+    return FPDF_GetPageCount(document);
+}
+
+struct PdfToFdWriter : FPDF_FILEWRITE {
+    int dstFd;
+};
+
+static bool writeAllBytes(const int fd, const void* buffer, const size_t byteCount) {
+    char* writeBuffer = static_cast<char*>(const_cast<void*>(buffer));
+    size_t remainingBytes = byteCount;
+    while (remainingBytes > 0) {
+        ssize_t writtenByteCount = write(fd, writeBuffer, remainingBytes);
+        if (writtenByteCount == -1) {
+            if (errno == EINTR) {
+                continue;
+            }
+            __android_log_print(ANDROID_LOG_ERROR, LOG_TAG,
+                    "Error writing to buffer: %d", errno);
+            return false;
+        }
+        remainingBytes -= writtenByteCount;
+        writeBuffer += writtenByteCount;
+    }
+    return true;
+}
+
+static int writeBlock(FPDF_FILEWRITE* owner, const void* buffer, unsigned long size) {
+    const PdfToFdWriter* writer = reinterpret_cast<PdfToFdWriter*>(owner);
+    const bool success = writeAllBytes(writer->dstFd, buffer, size);
+    if (success < 0) {
+        ALOGE("Cannot write to file descriptor. Error:%d", errno);
+        return 0;
+    }
+    return 1;
+}
+
+static void nativeWrite(JNIEnv* env, jclass thiz, jlong documentPtr, jint fd) {
+    FPDF_DOCUMENT document = reinterpret_cast<FPDF_DOCUMENT>(documentPtr);
+    PdfToFdWriter writer;
+    writer.dstFd = fd;
+    writer.WriteBlock = &writeBlock;
+    const bool success = FPDF_SaveAsCopy(document, &writer, FPDF_NO_INCREMENTAL);
+    if (!success) {
+        jniThrowException(env, "java/io/IOException",
+                "cannot write to fd. Error:" + errno);
+        destroyLibraryIfNeeded();
+    }
+}
+
+static JNINativeMethod gPdfEditor_Methods[] = {
+    {"nativeOpen", "(IJ)J", (void*) nativeOpen},
+    {"nativeClose", "(J)V", (void*) nativeClose},
+    {"nativeGetPageCount", "(J)I", (void*) nativeGetPageCount},
+    {"nativeRemovePage", "(JI)I", (void*) nativeRemovePage},
+    {"nativeWrite", "(JI)V", (void*) nativeWrite}
+};
+
+int register_android_graphics_pdf_PdfEditor(JNIEnv* env) {
+    return android::AndroidRuntime::registerNativeMethods(
+            env, "android/graphics/pdf/PdfEditor", gPdfEditor_Methods,
+            NELEM(gPdfEditor_Methods));
+};
+
+};
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 72dd930..8a1d5af 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -2502,7 +2502,7 @@
     <permission android:name="android.permission.PACKAGE_USAGE_STATS"
         android:label="@string/permlab_pkgUsageStats"
         android:description="@string/permdesc_pkgUsageStats"
-        android:protectionLevel="signature|system|development|appop" />
+        android:protectionLevel="signature|development|appop" />
     <uses-permission android:name="android.permission.PACKAGE_USAGE_STATS" />
 
     <!-- @SystemApi Allows an application to collect battery statistics -->
diff --git a/core/res/res/values-mcc310-mnc004/config.xml b/core/res/res/values-mcc310-mnc004/config.xml
index 2778b6e..423e250 100644
--- a/core/res/res/values-mcc310-mnc004/config.xml
+++ b/core/res/res/values-mcc310-mnc004/config.xml
@@ -34,11 +34,4 @@
     </string-array>
 
     <bool name="config_auto_attach_data_on_creation">false</bool>
-
-    <!-- Values for GPS configuration (Verizon) -->
-    <string-array translatable="false" name="config_gpsParameters">
-        <item>CAPABILITIES=0x31</item>
-        <item>LPP_PROFILE=3</item>
-        <item>GPS_LOCK=3</item>
-    </string-array>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc120/config.xml b/core/res/res/values-mcc310-mnc120/config.xml
index 3b95db5..62001d9 100644
--- a/core/res/res/values-mcc310-mnc120/config.xml
+++ b/core/res/res/values-mcc310-mnc120/config.xml
@@ -25,10 +25,4 @@
     -->
     <integer name="config_mobile_mtu">1422</integer>
 
-    <!-- Values for GPS configuration (Sprint) -->
-    <string-array translatable="false" name="config_gpsParameters">
-        <item>CAPABILITIES=0x31</item>
-        <item>GPS_LOCK=3</item>
-        <item>LPP_PROFILE=2</item>
-    </string-array>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc150/config.xml b/core/res/res/values-mcc310-mnc150/config.xml
index 00d2db8..f1936f4 100644
--- a/core/res/res/values-mcc310-mnc150/config.xml
+++ b/core/res/res/values-mcc310-mnc150/config.xml
@@ -33,10 +33,4 @@
         <item>315</item>
         <item>316</item>
     </string-array>
-    <!-- Values for GPS configuration (AT&T) -->
-    <string-array translatable="false" name="config_gpsParameters">
-        <item>CAPABILITIES=0x33</item>
-        <item>LPP_PROFILE=3</item>
-        <item>GPS_LOCK=1</item>
-    </string-array>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc260/config.xml b/core/res/res/values-mcc310-mnc260/config.xml
index f8fff3b..28cd695 100644
--- a/core/res/res/values-mcc310-mnc260/config.xml
+++ b/core/res/res/values-mcc310-mnc260/config.xml
@@ -29,11 +29,4 @@
          carrier provisioning. If false: hard disabled. If true: then depends on carrier
          provisioning, availability etc -->
     <bool name="config_carrier_volte_vt_available">true</bool>
-
-    <!-- Values for GPS configuration (T-Mobile) -->
-    <string-array translatable="false" name="config_gpsParameters">
-        <item>CAPABILITEIS=0x33</item>
-        <item>GPS_LOCK=1</item>
-        <item>LPP_PROFILE=2</item>
-    </string-array>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc410/config.xml b/core/res/res/values-mcc310-mnc410/config.xml
index edf6d9f..b863aae 100644
--- a/core/res/res/values-mcc310-mnc410/config.xml
+++ b/core/res/res/values-mcc310-mnc410/config.xml
@@ -40,12 +40,6 @@
         <item>315</item>
         <item>316</item>
     </string-array>
-    <!-- Values for GPS configuration (AT&T) -->
-    <string-array translatable="false" name="config_gpsParameters">
-        <item>CAPABILITIES=0x33</item>
-        <item>GPS_LOCK=1</item>
-        <item>LPP_PROFILE=3</item>
-    </string-array>
     <!-- Do not translate. Defines the slots is Two Digit Number for dialing normally not USSD -->
     <string-array name="config_twoDigitNumberPattern">
         <item>"0"</item>
diff --git a/core/res/res/values-mcc311-mnc190/config.xml b/core/res/res/values-mcc311-mnc190/config.xml
index b4e436d..a6c4d1b 100644
--- a/core/res/res/values-mcc311-mnc190/config.xml
+++ b/core/res/res/values-mcc311-mnc190/config.xml
@@ -37,11 +37,4 @@
          note that empty fields can be ommitted: "name,apn,,,,,,,,,310,260,,DUN" -->
     <string translatable="false" name="config_tether_apndata">Tether,broadband.cellular1.net,,,,,,,,,311,190,,DUN</string>
 
-    <!-- Values for GPS configuration (Sprint) -->
-    <string-array translatable="false" name="config_gpsParameters">
-        <item>CAPABILITIES=0x31</item>
-        <item>GPS_LOCK=3</item>
-        <item>LPP_PROFILE=2</item>
-    </string-array>
-
 </resources>
diff --git a/core/res/res/values-mcc311-mnc480/config.xml b/core/res/res/values-mcc311-mnc480/config.xml
index 57ecd31..cf19235 100644
--- a/core/res/res/values-mcc311-mnc480/config.xml
+++ b/core/res/res/values-mcc311-mnc480/config.xml
@@ -44,11 +44,4 @@
     <bool name="config_carrier_volte_vt_available">false</bool>
 
     <bool name="config_auto_attach_data_on_creation">false</bool>
-
-    <!-- Values for GPS configuration (Verizon) -->
-    <string-array translatable="false" name="config_gpsParameters">
-        <item>CAPABILITIES=0x31</item>
-        <item>GPS_LOCK=3</item>
-        <item>LPP_PROFILE=3</item>
-    </string-array>
 </resources>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 1b12ff2..b36387f 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -351,6 +351,9 @@
          point on the move. A value of 0 means no periodic scans will be used in the framework. -->
     <integer translatable="false" name="config_wifi_framework_scan_interval">300000</integer>
 
+    <!-- Integer indicating associated scan interval in milliseconds -->
+    <integer translatable="false" name="config_wifi_framework_associated_scan_interval">10000</integer>
+
     <!-- Wifi driver stop delay, in milliseconds.
          Default value is 2 minutes. -->
     <integer translatable="false" name="config_wifi_driver_stop_delay">120000</integer>
@@ -1719,16 +1722,22 @@
     <string-array translatable="false" name="config_gpsParameters">
         <item>SUPL_HOST=supl.google.com</item>
         <item>SUPL_PORT=7275</item>
-        <item>XTRA_SERVER_1=http://xtrapath1.izatcloud.net/xtra2.bin</item>
-        <item>XTRA_SERVER_2=http://xtrapath2.izatcloud.net/xtra2.bin</item>
-        <item>XTRA_SERVER_3=http://xtrapath3.izatcloud.net/xtra2.bin</item>
         <item>NTP_SERVER=north-america.pool.ntp.org</item>
         <item>SUPL_VER=0x20000</item>
-        <item>CAPABILITIES=0x33</item>
-        <item>LPP_PROFILE=0</item>
-        <item>NMEA_PROVIDER=0</item>
-        <item>A_GLONASS_POS_PROTOCOL_SELECT=0</item>
-        <item>ERR_ESTIMATE=0</item>
-        <item>INTERMEDIATE_POS=0</item>
     </string-array>
+
+    <!-- If there is no preload VM number in the sim card, carriers such as
+         Verizon require to load a default vm number from the configurantion.
+         Define config_default_vm_number for this purpose. And there are two
+         optional formats for this configuration as below:
+         (1)<item>voicemail number</item>
+         (2)<item>voicemail number;gid</item>
+         The logic to pick up the correct voicemail number:
+         (1) If the config_default_vm_number array has no gid special item, the last one will be
+         picked
+         (2) If the config_default_vm_number array has gid special item and  it matches the current
+         sim's gid, it will be picked.
+         (3) If the config_default_vm_number array has gid special item but it doesn't match the
+         current sim's gid, the last one without gid will be picked -->
+    <string-array translatable="false" name="config_default_vm_number" />
 </resources>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index f5197ec..c28f3a6 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -313,6 +313,7 @@
   <java-symbol type="integer" name="config_shortPressOnPowerBehavior" />
   <java-symbol type="integer" name="config_toastDefaultGravity" />
   <java-symbol type="integer" name="config_wifi_framework_scan_interval" />
+  <java-symbol type="integer" name="config_wifi_framework_associated_scan_interval" />
   <java-symbol type="integer" name="config_wifi_supplicant_scan_interval" />
   <java-symbol type="integer" name="config_wifi_scan_interval_p2p_connected" />
   <java-symbol type="integer" name="db_connection_pool_size" />
@@ -2007,4 +2008,5 @@
   <java-symbol type="id" name="date_picker_month_day_year_layout" />
   <java-symbol type="attr" name="closeItemLayout" />
   <java-symbol type="layout" name="resolver_different_item_header" />
+  <java-symbol type="array" name="config_default_vm_number" />
 </resources>
diff --git a/docs/html/about/dashboards/index.jd b/docs/html/about/dashboards/index.jd
index 1e5fc4d..808f04a 100644
--- a/docs/html/about/dashboards/index.jd
+++ b/docs/html/about/dashboards/index.jd
@@ -64,7 +64,7 @@
 </div>
 
 
-<p style="clear:both"><em>Data collected during a 7-day period ending on August 12, 2014.
+<p style="clear:both"><em>Data collected during a 7-day period ending on September 9, 2014.
 <br/>Any versions with less than 0.1% distribution are not shown.</em>
 </p>
 
@@ -95,7 +95,8 @@
 </div>
 
 
-<p style="clear:both"><em>Data collected during a 7-day period ending on August 12, 2014.
+<p style="clear:both"><em>Data collected during a 7-day period ending on September 9, 2014.
+
 <br/>Any screen configurations with less than 0.1% distribution are not shown.</em></p>
 
 
@@ -114,7 +115,7 @@
 
 
 <img alt="" style="float:right"
-src="//chart.googleapis.com/chart?chs=400x250&cht=p&chd=t%3A0.1%2C80.2%2C19.7&chf=bg%2Cs%2C00000000&chl=GL%201.1%20only%7CGL%202.0%7CGL%203.0&chco=c4df9b%2C6fad0c" />
+src="//chart.googleapis.com/chart?chs=400x250&cht=p&chd=t%3A77.5%2C22.5&chf=bg%2Cs%2C00000000&chl=GL%202.0%7CGL%203.0&chco=c4df9b%2C6fad0c" />
 
 <p>To declare which version of OpenGL ES your application requires, you should use the {@code
 android:glEsVersion} attribute of the <a
@@ -131,22 +132,18 @@
 <th scope="col">Distribution</th>
 </tr>
 <tr>
-<td>1.1 only</th>
-<td>0.1%</td>
+<td>2.0</td>
+<td>77.5%</td>
 </tr>
 <tr>
-<td>2.0</th>
-<td>80.2%</td>
-</tr>
-<tr>
-<td>3.0</th>
-<td>19.7%</td>
+<td>3.0</td>
+<td>22.5%</td>
 </tr>
 </table>
 
 
 
-<p style="clear:both"><em>Data collected during a 7-day period ending on August 12, 2014</em></p>
+<p style="clear:both"><em>Data collected during a 7-day period ending on September 9, 2014</em></p>
 
 
 
@@ -164,7 +161,7 @@
 var VERSION_DATA =
 [
   {
-    "chart": "//chart.googleapis.com/chart?cht=p&chs=500x250&chl=Froyo%7CGingerbread%7CIce%20Cream%20Sandwich%7CJelly%20Bean%7CKitKat&chd=t%3A0.7%2C13.6%2C10.6%2C54.2%2C20.9&chf=bg%2Cs%2C00000000&chco=c4df9b%2C6fad0c",
+    "chart": "//chart.googleapis.com/chart?chco=c4df9b%2C6fad0c&cht=p&chs=500x250&chl=Froyo%7CGingerbread%7CIce%20Cream%20Sandwich%7CJelly%20Bean%7CKitKat&chd=t%3A0.7%2C11.4%2C9.6%2C53.8%2C24.5&chf=bg%2Cs%2C00000000",
     "data": [
       {
         "api": 8,
@@ -174,41 +171,38 @@
       {
         "api": 10,
         "name": "Gingerbread",
-        "perc": "13.6"
+        "perc": "11.4"
       },
       {
         "api": 15,
         "name": "Ice Cream Sandwich",
-        "perc": "10.6"
+        "perc": "9.6"
       },
       {
         "api": 16,
         "name": "Jelly Bean",
-        "perc": "26.5"
+        "perc": "25.1"
       },
       {
         "api": 17,
         "name": "Jelly Bean",
-        "perc": "19.8"
+        "perc": "20.7"
       },
       {
         "api": 18,
         "name": "Jelly Bean",
-        "perc": "7.9"
+        "perc": "8.0"
       },
       {
         "api": 19,
         "name": "KitKat",
-        "perc": "20.9"
+        "perc": "24.5"
       }
     ]
   }
 ];
 
 
-
-
-
 var SCREEN_DATA =
 [
   {
@@ -216,27 +210,27 @@
       "Large": {
         "hdpi": "0.6",
         "ldpi": "0.5",
-        "mdpi": "4.2",
-        "tvdpi": "1.6",
-        "xhdpi": "0.5"
+        "mdpi": "4.3",
+        "tvdpi": "1.7",
+        "xhdpi": "0.6"
       },
       "Normal": {
-        "hdpi": "35.5",
-        "mdpi": "11.8",
-        "xhdpi": "18.4",
-        "xxhdpi": "15.2"
+        "hdpi": "35.7",
+        "mdpi": "10.6",
+        "xhdpi": "19.2",
+        "xxhdpi": "16.2"
       },
       "Small": {
-        "ldpi": "7.4"
+        "ldpi": "6.2"
       },
       "Xlarge": {
         "hdpi": "0.3",
-        "mdpi": "3.6",
+        "mdpi": "3.7",
         "xhdpi": "0.4"
       }
     },
-    "densitychart": "//chart.googleapis.com/chart?cht=p&chs=400x250&chl=ldpi%7Cmdpi%7Ctvdpi%7Chdpi%7Cxhdpi%7Cxxhdpi&chd=t%3A7.9%2C19.6%2C1.6%2C36.4%2C19.3%2C15.2&chf=bg%2Cs%2C00000000&chco=c4df9b%2C6fad0c",
-    "layoutchart": "//chart.googleapis.com/chart?cht=p&chs=400x250&chl=Xlarge%7CLarge%7CNormal%7CSmall&chd=t%3A4.3%2C7.4%2C80.9%2C7.4&chf=bg%2Cs%2C00000000&chco=c4df9b%2C6fad0c"
+    "densitychart": "//chart.googleapis.com/chart?chco=c4df9b%2C6fad0c&cht=p&chs=400x250&chl=ldpi%7Cmdpi%7Ctvdpi%7Chdpi%7Cxhdpi%7Cxxhdpi&chd=t%3A6.7%2C18.6%2C1.7%2C36.6%2C20.2%2C16.2&chf=bg%2Cs%2C00000000",
+    "layoutchart": "//chart.googleapis.com/chart?chco=c4df9b%2C6fad0c&cht=p&chs=400x250&chl=Xlarge%7CLarge%7CNormal%7CSmall&chd=t%3A4.4%2C7.7%2C81.7%2C6.2&chf=bg%2Cs%2C00000000"
   }
 ];
 
diff --git a/graphics/java/android/graphics/pdf/PdfEditor.java b/graphics/java/android/graphics/pdf/PdfEditor.java
new file mode 100644
index 0000000..9837139
--- /dev/null
+++ b/graphics/java/android/graphics/pdf/PdfEditor.java
@@ -0,0 +1,162 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.graphics.pdf;
+
+import android.annotation.NonNull;
+import android.os.ParcelFileDescriptor;
+import android.system.ErrnoException;
+import android.system.OsConstants;
+import dalvik.system.CloseGuard;
+import libcore.io.IoUtils;
+import libcore.io.Libcore;
+
+import java.io.IOException;
+
+/**
+ * Class for editing PDF files.
+ *
+ * @hide
+ */
+public final class PdfEditor {
+
+    private final CloseGuard mCloseGuard = CloseGuard.get();
+
+    private final long mNativeDocument;
+
+    private int mPageCount;
+
+    private ParcelFileDescriptor mInput;
+
+    /**
+     * Creates a new instance.
+     * <p>
+     * <strong>Note:</strong> The provided file descriptor must be <strong>seekable</strong>,
+     * i.e. its data being randomly accessed, e.g. pointing to a file. After finishing
+     * with this class you must call {@link #close()}.
+     * </p>
+     * <p>
+     * <strong>Note:</strong> This class takes ownership of the passed in file descriptor
+     * and is responsible for closing it when the editor is closed.
+     * </p>
+     *
+     * @param input Seekable file descriptor to read from.
+     *
+     * @see #close()
+     */
+    public PdfEditor(@NonNull ParcelFileDescriptor input) throws IOException {
+        if (input == null) {
+            throw new NullPointerException("input cannot be null");
+        }
+
+        final long size;
+        try {
+            Libcore.os.lseek(input.getFileDescriptor(), 0, OsConstants.SEEK_SET);
+            size = Libcore.os.fstat(input.getFileDescriptor()).st_size;
+        } catch (ErrnoException ee) {
+            throw new IllegalArgumentException("file descriptor not seekable");
+        }
+
+        mInput = input;
+        mNativeDocument = nativeOpen(mInput.getFd(), size);
+        mPageCount = nativeGetPageCount(mNativeDocument);
+        mCloseGuard.open("close");
+    }
+
+    /**
+     * Gets the number of pages in the document.
+     *
+     * @return The page count.
+     */
+    public int getPageCount() {
+        throwIfClosed();
+        return mPageCount;
+    }
+
+    /**
+     * Removes the page with a given index.
+     *
+     * @param pageIndex The page to remove.
+     */
+    public void removePage(int pageIndex) {
+        throwIfClosed();
+        throwIfPageNotInDocument(pageIndex);
+        mPageCount = nativeRemovePage(mNativeDocument, pageIndex);
+    }
+
+    /**
+     * Writes the PDF file to the provided destination.
+     * <p>
+     * <strong>Note:</strong> This method takes ownership of the passed in file
+     * descriptor and is responsible for closing it when writing completes.
+     * </p>
+     * @param output The destination.
+     */
+    public void write(ParcelFileDescriptor output) throws IOException {
+        try {
+            throwIfClosed();
+            nativeWrite(mNativeDocument, output.getFd());
+        } finally {
+            IoUtils.closeQuietly(output);
+        }
+    }
+
+    /**
+     * Closes this editor. You should not use this instance
+     * after this method is called.
+     */
+    public void close() {
+        throwIfClosed();
+        doClose();
+    }
+
+    @Override
+    protected void finalize() throws Throwable {
+        try {
+            mCloseGuard.warnIfOpen();
+            if (mInput != null) {
+                doClose();
+            }
+        } finally {
+            super.finalize();
+        }
+    }
+
+    private void doClose() {
+        nativeClose(mNativeDocument);
+        IoUtils.closeQuietly(mInput);
+        mInput = null;
+        mCloseGuard.close();
+    }
+
+    private void throwIfClosed() {
+        if (mInput == null) {
+            throw new IllegalStateException("Already closed");
+        }
+    }
+
+    private void throwIfPageNotInDocument(int pageIndex) {
+        if (pageIndex < 0 || pageIndex >= mPageCount) {
+            throw new IllegalArgumentException("Invalid page index");
+        }
+    }
+
+    private static native long nativeOpen(int fd, long size);
+    private static native void nativeClose(long documentPtr);
+    private static native int nativeGetPageCount(long documentPtr);
+    private static native int nativeRemovePage(long documentPtr, int pageIndex);
+    private static native void nativeWrite(long documentPtr, int fd);
+}
diff --git a/graphics/java/android/graphics/pdf/PdfRenderer.java b/graphics/java/android/graphics/pdf/PdfRenderer.java
index 1072b3c..359c294 100644
--- a/graphics/java/android/graphics/pdf/PdfRenderer.java
+++ b/graphics/java/android/graphics/pdf/PdfRenderer.java
@@ -239,7 +239,7 @@
     }
 
     private void throwIfPageNotInDocument(int pageIndex) {
-        if (pageIndex >= mPageCount) {
+        if (pageIndex < 0 || pageIndex >= mPageCount) {
             throw new IllegalArgumentException("Invalid page index");
         }
     }
diff --git a/media/java/android/media/MediaCodec.java b/media/java/android/media/MediaCodec.java
index 675916b..81ebb14 100644
--- a/media/java/android/media/MediaCodec.java
+++ b/media/java/android/media/MediaCodec.java
@@ -737,6 +737,13 @@
         public static final int ERROR_RESOURCE_BUSY = 3;
 
         /**
+         * This indicates that the output protection levels supported by the
+         * device are not sufficient to meet the requirements set by the
+         * content owner in the license policy.
+         */
+        public static final int ERROR_INSUFFICIENT_OUTPUT_PROTECTION = 4;
+
+        /**
          * Retrieve the error code associated with a CryptoException
          */
         public int getErrorCode() {
diff --git a/media/java/android/media/MediaCodecList.java b/media/java/android/media/MediaCodecList.java
index 85e9b16..0dcbd65 100644
--- a/media/java/android/media/MediaCodecList.java
+++ b/media/java/android/media/MediaCodecList.java
@@ -118,6 +118,7 @@
 
     /** @hide */
     public static MediaCodecInfo getInfoFor(String codec) {
+        initCodecList();
         return sAllCodecInfos[findCodecByName(codec)];
     }
 
diff --git a/media/jni/android_media_MediaCodec.cpp b/media/jni/android_media_MediaCodec.cpp
index f1e1099..1cf589d 100644
--- a/media/jni/android_media_MediaCodec.cpp
+++ b/media/jni/android_media_MediaCodec.cpp
@@ -62,6 +62,7 @@
     jint cryptoErrorNoKey;
     jint cryptoErrorKeyExpired;
     jint cryptoErrorResourceBusy;
+    jint cryptoErrorInsufficientOutputProtection;
 } gCryptoErrorCodes;
 
 static struct CodecActionCodes {
@@ -756,6 +757,9 @@
         case ERROR_DRM_RESOURCE_BUSY:
             err = gCryptoErrorCodes.cryptoErrorResourceBusy;
             break;
+        case ERROR_DRM_INSUFFICIENT_OUTPUT_PROTECTION:
+            err = gCryptoErrorCodes.cryptoErrorInsufficientOutputProtection;
+            break;
         default:  /* Other negative DRM error codes go out as is. */
             break;
     }
@@ -1434,6 +1438,11 @@
     gCryptoErrorCodes.cryptoErrorResourceBusy =
         env->GetStaticIntField(clazz.get(), field);
 
+    field = env->GetStaticFieldID(clazz.get(), "ERROR_INSUFFICIENT_OUTPUT_PROTECTION", "I");
+    CHECK(field != NULL);
+    gCryptoErrorCodes.cryptoErrorInsufficientOutputProtection =
+        env->GetStaticIntField(clazz.get(), field);
+
     clazz.reset(env->FindClass("android/media/MediaCodec$CodecException"));
     CHECK(clazz.get() != NULL);
     field = env->GetStaticFieldID(clazz.get(), "ACTION_TRANSIENT", "I");
diff --git a/packages/PrintSpooler/Android.mk b/packages/PrintSpooler/Android.mk
index c4a55d1..27d1b23 100644
--- a/packages/PrintSpooler/Android.mk
+++ b/packages/PrintSpooler/Android.mk
@@ -19,7 +19,9 @@
 LOCAL_MODULE_TAGS := optional
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
-LOCAL_SRC_FILES += src/com/android/printspooler/renderer/IPdfRenderer.aidl
+LOCAL_SRC_FILES += \
+        src/com/android/printspooler/renderer/IPdfRenderer.aidl \
+        src/com/android/printspooler/renderer/IPdfEditor.aidl
 
 LOCAL_PACKAGE_NAME := PrintSpooler
 
diff --git a/packages/PrintSpooler/AndroidManifest.xml b/packages/PrintSpooler/AndroidManifest.xml
index 9efda2f..adff596 100644
--- a/packages/PrintSpooler/AndroidManifest.xml
+++ b/packages/PrintSpooler/AndroidManifest.xml
@@ -54,7 +54,7 @@
         </service>
 
         <service
-            android:name=".renderer.PdfRendererService"
+            android:name=".renderer.PdfManipulationService"
             android:isolatedProcess="true">
         </service>
 
diff --git a/packages/PrintSpooler/src/com/android/printspooler/model/PageContentRepository.java b/packages/PrintSpooler/src/com/android/printspooler/model/PageContentRepository.java
index a581e8a..1d8261b 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/model/PageContentRepository.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/model/PageContentRepository.java
@@ -37,7 +37,7 @@
 import android.view.View;
 import com.android.internal.annotations.GuardedBy;
 import com.android.printspooler.renderer.IPdfRenderer;
-import com.android.printspooler.renderer.PdfRendererService;
+import com.android.printspooler.renderer.PdfManipulationService;
 import com.android.printspooler.util.BitmapSerializeUtils;
 import dalvik.system.CloseGuard;
 import libcore.io.IoUtils;
@@ -490,7 +490,8 @@
             new AsyncTask<Void, Void, Integer>() {
                 @Override
                 protected void onPreExecute() {
-                    Intent intent = new Intent(mContext, PdfRendererService.class);
+                    Intent intent = new Intent(PdfManipulationService.ACTION_GET_RENDERER);
+                    intent.setClass(mContext, PdfManipulationService.class);
                     mContext.bindService(intent, AsyncRenderer.this, Context.BIND_AUTO_CREATE);
                 }
 
@@ -555,7 +556,7 @@
                         callback.run();
                     }
                 }
-            }.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR, (Void[]) null);
+            }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void[]) null);
         }
 
         public void destroy() {
diff --git a/packages/PrintSpooler/src/com/android/printspooler/renderer/IPdfEditor.aidl b/packages/PrintSpooler/src/com/android/printspooler/renderer/IPdfEditor.aidl
new file mode 100644
index 0000000..b450ccb
--- /dev/null
+++ b/packages/PrintSpooler/src/com/android/printspooler/renderer/IPdfEditor.aidl
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.printspooler.renderer;
+
+import android.os.ParcelFileDescriptor;
+import android.print.PageRange;
+
+/**
+ * Interface for communication with a remote pdf editor.
+ */
+interface IPdfEditor {
+    int openDocument(in ParcelFileDescriptor source);
+    void removePages(in PageRange[] pages);
+    void write(in ParcelFileDescriptor destination);
+    void closeDocument();
+}
diff --git a/packages/PrintSpooler/src/com/android/printspooler/renderer/IPdfRenderer.aidl b/packages/PrintSpooler/src/com/android/printspooler/renderer/IPdfRenderer.aidl
index 1fba2b1..8e595d7 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/renderer/IPdfRenderer.aidl
+++ b/packages/PrintSpooler/src/com/android/printspooler/renderer/IPdfRenderer.aidl
@@ -29,5 +29,4 @@
     oneway void renderPage(int pageIndex, int bitmapWidth, int bitmapHeight,
         in PrintAttributes attributes, in ParcelFileDescriptor destination);
     oneway void closeDocument();
-    oneway void writePages(in PageRange[] pages);
 }
diff --git a/packages/PrintSpooler/src/com/android/printspooler/renderer/PdfRendererService.java b/packages/PrintSpooler/src/com/android/printspooler/renderer/PdfManipulationService.java
similarity index 62%
rename from packages/PrintSpooler/src/com/android/printspooler/renderer/PdfRendererService.java
rename to packages/PrintSpooler/src/com/android/printspooler/renderer/PdfManipulationService.java
index 4d02c01..62716b2 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/renderer/PdfRendererService.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/renderer/PdfManipulationService.java
@@ -23,6 +23,7 @@
 import android.graphics.Color;
 import android.graphics.Matrix;
 import android.graphics.Rect;
+import android.graphics.pdf.PdfEditor;
 import android.graphics.pdf.PdfRenderer;
 import android.os.IBinder;
 import android.os.ParcelFileDescriptor;
@@ -32,15 +33,21 @@
 import android.print.PrintAttributes.Margins;
 import android.util.Log;
 import android.view.View;
+import com.android.printspooler.util.PageRangeUtils;
 import libcore.io.IoUtils;
 import com.android.printspooler.util.BitmapSerializeUtils;
 import java.io.IOException;
 
 /**
- * Service for rendering PDF documents in an isolated process.
+ * Service for manipulation of PDF documents in an isolated process.
  */
-public final class PdfRendererService extends Service {
-    private static final String LOG_TAG = "PdfRendererService";
+public final class PdfManipulationService extends Service {
+    public static final String ACTION_GET_RENDERER =
+            "com.android.printspooler.renderer.ACTION_GET_RENDERER";
+    public static final String ACTION_GET_EDITOR =
+            "com.android.printspooler.renderer.ACTION_GET_EDITOR";
+
+    private static final String LOG_TAG = "PdfManipulationService";
     private static final boolean DEBUG = false;
 
     private static final int MILS_PER_INCH = 1000;
@@ -48,7 +55,18 @@
 
     @Override
     public IBinder onBind(Intent intent) {
-        return new PdfRendererImpl();
+        String action = intent.getAction();
+        switch (action) {
+            case ACTION_GET_RENDERER: {
+                return new PdfRendererImpl();
+            }
+            case ACTION_GET_EDITOR: {
+                return new PdfEditorImpl();
+            }
+            default: {
+                throw new IllegalArgumentException("Invalid intent action:" + action);
+            }
+        }
     }
 
     private final class PdfRendererImpl extends IPdfRenderer.Stub {
@@ -60,15 +78,17 @@
         @Override
         public int openDocument(ParcelFileDescriptor source) throws RemoteException {
             synchronized (mLock) {
-                throwIfOpened();
-                if (DEBUG) {
-                    Log.i(LOG_TAG, "openDocument()");
-                }
                 try {
+                    throwIfOpened();
+                    if (DEBUG) {
+                        Log.i(LOG_TAG, "openDocument()");
+                    }
                     mRenderer = new PdfRenderer(source);
                     return mRenderer.getPageCount();
-                } catch (IOException ioe) {
-                    throw new RemoteException("Cannot open file");
+                } catch (IOException|IllegalStateException e) {
+                    IoUtils.closeQuietly(source);
+                    Log.e(LOG_TAG, "Cannot open file", e);
+                    throw new RemoteException(e.toString());
                 }
             }
         }
@@ -108,7 +128,7 @@
                     }
                     matrix.postScale(displayScale, displayScale);
 
-                    Configuration configuration = PdfRendererService.this.getResources()
+                    Configuration configuration = PdfManipulationService.this.getResources()
                             .getConfiguration();
                     if (configuration.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL) {
                         matrix.postTranslate(bitmapWidth - srcWidthPts * displayScale, 0);
@@ -147,24 +167,13 @@
             synchronized (mLock) {
                 throwIfNotOpened();
                 if (DEBUG) {
-                    Log.i(LOG_TAG, "openDocument()");
+                    Log.i(LOG_TAG, "closeDocument()");
                 }
                 mRenderer.close();
                 mRenderer = null;
             }
         }
 
-        @Override
-        public void writePages(PageRange[] pages) {
-            synchronized (mLock) {
-                throwIfNotOpened();
-                if (DEBUG) {
-                    Log.i(LOG_TAG, "writePages()");
-                }
-                // TODO: Implement dropping undesired pages.
-            }
-        }
-
         private Bitmap getBitmapForSize(int width, int height) {
             if (mBitmap != null) {
                 if (mBitmap.getWidth() == width && mBitmap.getHeight() == height) {
@@ -191,6 +200,91 @@
         }
     }
 
+    private final class PdfEditorImpl extends IPdfEditor.Stub {
+        private final Object mLock = new Object();
+
+        private PdfEditor mEditor;
+
+        @Override
+        public int openDocument(ParcelFileDescriptor source) throws RemoteException {
+            synchronized (mLock) {
+                try {
+                    throwIfOpened();
+                    if (DEBUG) {
+                        Log.i(LOG_TAG, "openDocument()");
+                    }
+                    mEditor = new PdfEditor(source);
+                    return mEditor.getPageCount();
+                } catch (IOException|IllegalStateException e) {
+                    IoUtils.closeQuietly(source);
+                    Log.e(LOG_TAG, "Cannot open file", e);
+                    throw new RemoteException(e.toString());
+                }
+            }
+        }
+
+        @Override
+        public void removePages(PageRange[] ranges) {
+            synchronized (mLock) {
+                throwIfNotOpened();
+                if (DEBUG) {
+                    Log.i(LOG_TAG, "removePages()");
+                }
+
+                ranges = PageRangeUtils.normalize(ranges);
+
+                final int rangeCount = ranges.length;
+                for (int i = rangeCount - 1; i >= 0; i--) {
+                    PageRange range = ranges[i];
+                    for (int j = range.getEnd(); j >= range.getStart(); j--) {
+                        mEditor.removePage(j);
+                    }
+                }
+            }
+        }
+
+        @Override
+        public void write(ParcelFileDescriptor destination) throws RemoteException {
+            synchronized (mLock) {
+                try {
+                    throwIfNotOpened();
+                    if (DEBUG) {
+                        Log.i(LOG_TAG, "write()");
+                    }
+                    mEditor.write(destination);
+                } catch (IOException | IllegalStateException e) {
+                    IoUtils.closeQuietly(destination);
+                    Log.e(LOG_TAG, "Error writing PDF to file.", e);
+                    throw new RemoteException(e.toString());
+                }
+            }
+        }
+
+        @Override
+        public void closeDocument() {
+            synchronized (mLock) {
+                throwIfNotOpened();
+                if (DEBUG) {
+                    Log.i(LOG_TAG, "closeDocument()");
+                }
+                mEditor.close();
+                mEditor = null;
+            }
+        }
+
+        private void throwIfOpened() {
+            if (mEditor != null) {
+                throw new IllegalStateException("Already opened");
+            }
+        }
+
+        private void throwIfNotOpened() {
+            if (mEditor == null) {
+                throw new IllegalStateException("Not opened");
+            }
+        }
+    }
+
     private static int pointsFromMils(int mils) {
         return (int) (((float) mils / MILS_PER_INCH) * POINTS_IN_INCH);
     }
diff --git a/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java b/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
index 535081f..c517f2d 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
@@ -23,6 +23,7 @@
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
+import android.content.ServiceConnection;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.ResolveInfo;
@@ -30,9 +31,12 @@
 import android.database.DataSetObserver;
 import android.graphics.drawable.Drawable;
 import android.net.Uri;
+import android.os.AsyncTask;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.IBinder;
+import android.os.ParcelFileDescriptor;
+import android.os.RemoteException;
 import android.print.IPrintDocumentAdapter;
 import android.print.PageRange;
 import android.print.PrintAttributes;
@@ -74,6 +78,8 @@
 import com.android.printspooler.model.PrintSpoolerService;
 import com.android.printspooler.model.RemotePrintDocument;
 import com.android.printspooler.model.RemotePrintDocument.RemotePrintDocumentInfo;
+import com.android.printspooler.renderer.IPdfEditor;
+import com.android.printspooler.renderer.PdfManipulationService;
 import com.android.printspooler.util.MediaSizeUtils;
 import com.android.printspooler.util.MediaSizeUtils.MediaSizeComparator;
 import com.android.printspooler.util.PageRangeUtils;
@@ -81,8 +87,15 @@
 import com.android.printspooler.widget.PrintContentView;
 import com.android.printspooler.widget.PrintContentView.OptionsStateChangeListener;
 import com.android.printspooler.widget.PrintContentView.OptionsStateController;
+import libcore.io.IoUtils;
+import libcore.io.Streams;
 
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
 import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
@@ -186,6 +199,7 @@
     private ImageView mPrintButton;
 
     private ProgressMessageController mProgressMessageController;
+    private MutexFileProvider mFileProvider;
 
     private MediaSizeComparator mMediaSizeComparator;
 
@@ -257,9 +271,8 @@
         setTitle(R.string.print_dialog);
         setContentView(R.layout.print_activity);
 
-        final MutexFileProvider fileProvider;
         try {
-            fileProvider = new MutexFileProvider(
+            mFileProvider = new MutexFileProvider(
                     PrintSpoolerService.generateFileForPrintJob(
                             PrintActivity.this, mPrintJob.getId()));
         } catch (IOException ioe) {
@@ -268,12 +281,13 @@
         }
 
         mPrintPreviewController = new PrintPreviewController(PrintActivity.this,
-                fileProvider);
+                mFileProvider);
         mPrintedDocument = new RemotePrintDocument(PrintActivity.this,
                 IPrintDocumentAdapter.Stub.asInterface(documentAdapter),
-                fileProvider, new RemotePrintDocument.DocumentObserver() {
+                mFileProvider, new RemotePrintDocument.DocumentObserver() {
             @Override
             public void onDestroy() {
+                setState(STATE_PRINT_CANCELED);
                 finish();
             }
         }, PrintActivity.this);
@@ -369,7 +383,7 @@
     @Override
     public void onRequestContentUpdate() {
         if (canUpdateDocument()) {
-            updateDocument(true, false);
+            updateDocument(false);
         }
     }
 
@@ -386,7 +400,7 @@
     @Override
     public void onActionPerformed() {
         if (mState == STATE_UPDATE_FAILED
-                && canUpdateDocument() && updateDocument(true, true)) {
+                && canUpdateDocument() && updateDocument(true)) {
             ensurePreviewUiShown();
             setState(STATE_CONFIGURING);
             updateOptionsUi();
@@ -557,14 +571,13 @@
         if (resultCode == RESULT_OK && data != null) {
             setState(STATE_PRINT_COMPLETED);
             updateOptionsUi();
-            Uri uri = data.getData();
-            mPrintedDocument.writeContent(getContentResolver(), uri);
+            final Uri uri = data.getData();
             // Calling finish here does not invoke lifecycle callbacks but we
             // update the print job in onPause if finishing, hence post a message.
             mDestinationSpinner.post(new Runnable() {
                 @Override
                 public void run() {
-                    finish();
+                    shredPagesAndFinish(uri);
                 }
             });
         } else if (resultCode == RESULT_CANCELED) {
@@ -708,7 +721,7 @@
 
         // Update the content if needed.
         if (canUpdateDocument()) {
-            updateDocument(true, false);
+            updateDocument(false);
         }
     }
 
@@ -840,7 +853,7 @@
         if (mCurrentPrinter == mDestinationSpinnerAdapter.getPdfPrinter()) {
             startCreateDocumentActivity();
         } else {
-            finish();
+            shredPagesAndFinish(null);
         }
     }
 
@@ -893,7 +906,7 @@
         attributes.setMinMargins(defaults.getMinMargins());
     }
 
-    private boolean updateDocument(boolean preview, boolean clearLastError) {
+    private boolean updateDocument(boolean clearLastError) {
         if (!clearLastError && mPrintedDocument.hasUpdateError()) {
             return false;
         }
@@ -902,6 +915,7 @@
             mPrintedDocument.clearUpdateError();
         }
 
+        final boolean preview = mState != STATE_PRINT_CONFIRMED;
         final PageRange[] pages;
         if (preview) {
             pages = mPrintPreviewController.getRequestedPages();
@@ -959,7 +973,7 @@
         mPrintPreviewController.closeOptions();
 
         if (canUpdateDocument()) {
-            updateDocument(false, false);
+            updateDocument(false);
         }
 
         if (!mPrintedDocument.isUpdating()) {
@@ -1433,7 +1447,7 @@
         if (mCurrentPrinter.equals(printer)) {
             setState(STATE_CONFIGURING);
             if (canUpdateDocument()) {
-                updateDocument(true, false);
+                updateDocument(false);
             }
             ensurePreviewUiShown();
             updateOptionsUi();
@@ -1492,6 +1506,18 @@
         return true;
     }
 
+    private void shredPagesAndFinish(final Uri writeToUri) {
+        new PageShredder(this, mPrintJob, mFileProvider, new Runnable() {
+            @Override
+            public void run() {
+                if (writeToUri != null) {
+                    mPrintedDocument.writeContent(getContentResolver(), writeToUri);
+                }
+                finish();
+            }
+        }).shred();
+    }
+
     private final class SpinnerItem<T> {
         final T value;
         final CharSequence label;
@@ -1942,7 +1968,7 @@
                     || (becameActive && hasCapab) || (isActive && gotCapab));
 
             if (updateNeeded && canUpdateDocument()) {
-                updateDocument(true, false);
+                updateDocument(false);
             }
 
             updateOptionsUi();
@@ -2033,7 +2059,7 @@
             }
 
             if (canUpdateDocument()) {
-                updateDocument(true, false);
+                updateDocument(false);
             }
 
             updateOptionsUi();
@@ -2158,7 +2184,7 @@
             updateOptionsUi();
 
             if (hadErrors && canUpdateDocument()) {
-                updateDocument(true, false);
+                updateDocument(false);
             }
         }
     }
@@ -2198,4 +2224,176 @@
             updateOptionsUi();
         }
     }
+
+    private static final class PageShredder implements ServiceConnection {
+        private static final String TEMP_FILE_PREFIX = "print_job";
+        private static final String TEMP_FILE_EXTENSION = ".pdf";
+
+        private final Context mContext;
+
+        private final MutexFileProvider mFileProvider;
+
+        private final PrintJobInfo mPrintJob;
+
+        private final PageRange[] mPagesToShred;
+
+        private final Runnable mCallback;
+
+        public PageShredder(Context context, PrintJobInfo printJob,
+                MutexFileProvider fileProvider, Runnable callback) {
+            mContext = context;
+            mPrintJob = printJob;
+            mFileProvider = fileProvider;
+            mCallback = callback;
+            mPagesToShred = computePagesToShred(mPrintJob);
+        }
+
+        public void shred() {
+            // If we have only the pages we want, done.
+            if (mPagesToShred.length <= 0) {
+                mCallback.run();
+                return;
+            }
+
+            // Bind to the manipulation service and the work
+            // will be performed upon connection to the service.
+            Intent intent = new Intent(PdfManipulationService.ACTION_GET_EDITOR);
+            intent.setClass(mContext, PdfManipulationService.class);
+            mContext.bindService(intent, this, Context.BIND_AUTO_CREATE);
+        }
+
+        @Override
+        public void onServiceConnected(ComponentName name, IBinder service) {
+            final IPdfEditor editor = IPdfEditor.Stub.asInterface(service);
+            new AsyncTask<Void, Void, Void>() {
+                @Override
+                protected Void doInBackground(Void... params) {
+                    try {
+                        // It's OK to access the data members as they are
+                        // final and this code is the last one to touch
+                        // them as shredding is the very last step, so the
+                        // UI is not interactive at this point.
+                        shredPages(editor);
+                        updatePrintJob();
+                    } finally {
+                        mContext.unbindService(PageShredder.this);
+                        mCallback.run();
+                    }
+                    return null;
+                }
+            }.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR);
+        }
+
+        @Override
+        public void onServiceDisconnected(ComponentName name) {
+            /* do nothing */
+        }
+
+        private void shredPages(IPdfEditor editor) {
+            File tempFile = null;
+            ParcelFileDescriptor src = null;
+            ParcelFileDescriptor dst = null;
+            InputStream in = null;
+            OutputStream out = null;
+            try {
+                File jobFile = mFileProvider.acquireFile(null);
+                src = ParcelFileDescriptor.open(jobFile, ParcelFileDescriptor.MODE_READ_WRITE);
+
+                // Open the document.
+                editor.openDocument(src);
+
+                // We passed the fd over IPC, close this one.
+                src.close();
+
+                // Drop the pages.
+                editor.removePages(mPagesToShred);
+
+                // Write the modified PDF to a temp file.
+                tempFile = File.createTempFile(TEMP_FILE_PREFIX, TEMP_FILE_EXTENSION,
+                        mContext.getCacheDir());
+                dst = ParcelFileDescriptor.open(tempFile, ParcelFileDescriptor.MODE_READ_WRITE);
+                editor.write(dst);
+                dst.close();
+
+                // Close the document.
+                editor.closeDocument();
+
+                // Copy the temp file over the print job file.
+                jobFile.delete();
+                in = new FileInputStream(tempFile);
+                out = new FileOutputStream(jobFile);
+                Streams.copy(in, out);
+            } catch (IOException|RemoteException e) {
+                Log.e(LOG_TAG, "Error dropping pages", e);
+            } finally {
+                IoUtils.closeQuietly(src);
+                IoUtils.closeQuietly(dst);
+                IoUtils.closeQuietly(in);
+                IoUtils.closeQuietly(out);
+                if (tempFile != null) {
+                    tempFile.delete();
+                }
+            }
+        }
+
+        private void updatePrintJob() {
+            // Update the print job pages.
+            final int newPageCount = PageRangeUtils.getNormalizedPageCount(
+                    mPrintJob.getPages(), 0);
+            mPrintJob.setPages(new PageRange[]{PageRange.ALL_PAGES});
+
+            // Update the print job document info.
+            PrintDocumentInfo oldDocInfo = mPrintJob.getDocumentInfo();
+            PrintDocumentInfo newDocInfo = new PrintDocumentInfo
+                    .Builder(oldDocInfo.getName())
+                    .setContentType(oldDocInfo.getContentType())
+                    .setPageCount(newPageCount)
+                    .build();
+            mPrintJob.setDocumentInfo(newDocInfo);
+        }
+
+        private static PageRange[] computePagesToShred(PrintJobInfo printJob) {
+            List<PageRange> rangesToShred = new ArrayList<>();
+            PageRange previousRange = null;
+
+            final int pageCount = printJob.getDocumentInfo().getPageCount();
+
+            PageRange[] printedPages = printJob.getPages();
+            final int rangeCount = printedPages.length;
+            for (int i = 0; i < rangeCount; i++) {
+                PageRange range = PageRangeUtils.asAbsoluteRange(printedPages[i], pageCount);
+
+                if (previousRange == null) {
+                    final int startPageIdx = 0;
+                    final int endPageIdx = range.getStart() - 1;
+                    if (startPageIdx <= endPageIdx) {
+                        PageRange removedRange = new PageRange(startPageIdx, endPageIdx);
+                        rangesToShred.add(removedRange);
+                    }
+                } else {
+                    final int startPageIdx = previousRange.getEnd() + 1;
+                    final int endPageIdx = range.getStart() - 1;
+                    if (startPageIdx <= endPageIdx) {
+                        PageRange removedRange = new PageRange(startPageIdx, endPageIdx);
+                        rangesToShred.add(removedRange);
+                    }
+                }
+
+                if (i == rangeCount - 1) {
+                    final int startPageIdx = range.getEnd() + 1;
+                    final int endPageIdx = printJob.getDocumentInfo().getPageCount() - 1;
+                    if (startPageIdx <= endPageIdx) {
+                        PageRange removedRange = new PageRange(startPageIdx, endPageIdx);
+                        rangesToShred.add(removedRange);
+                    }
+                }
+
+                previousRange = range;
+            }
+
+            PageRange[] result = new PageRange[rangesToShred.size()];
+            rangesToShred.toArray(result);
+            return result;
+        }
+    }
 }
diff --git a/packages/PrintSpooler/src/com/android/printspooler/ui/PrintPreviewController.java b/packages/PrintSpooler/src/com/android/printspooler/ui/PrintPreviewController.java
index a25e05e..5d858ca 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/ui/PrintPreviewController.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/ui/PrintPreviewController.java
@@ -185,8 +185,10 @@
             public void run() {
                 // At this point the other end will write to the file, hence
                 // we have to close it and reopen after the write completes.
-                Message operation = mHandler.obtainMessage(MyHandler.MSG_CLOSE);
-                mHandler.enqueueOperation(operation);
+                if (mPageAdapter.isOpened()) {
+                    Message operation = mHandler.obtainMessage(MyHandler.MSG_CLOSE);
+                    mHandler.enqueueOperation(operation);
+                }
             }
         });
     }
diff --git a/packages/SystemUI/res/anim/recents_launch_next_affiliated_task_bounce.xml b/packages/SystemUI/res/anim/recents_launch_next_affiliated_task_bounce.xml
new file mode 100644
index 0000000..a571cbc
--- /dev/null
+++ b/packages/SystemUI/res/anim/recents_launch_next_affiliated_task_bounce.xml
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2014, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+     android:background="#ff000000" android:shareInterpolator="false" android:zAdjustment="normal">
+
+    <alpha android:fromAlpha="1.0" android:toAlpha="0.6"
+        android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
+        android:interpolator="@android:interpolator/accelerate_cubic"
+        android:duration="133"/>
+
+    <translate android:fromYDelta="0" android:toYDelta="10%"
+        android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
+        android:interpolator="@android:interpolator/accelerate_cubic"
+        android:duration="350"/>
+
+    <scale android:fromXScale="1.0" android:toXScale="0.9"
+        android:fromYScale="1.0" android:toYScale="0.9"
+        android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
+        android:pivotX="50%p" android:pivotY="50%p"
+        android:interpolator="@android:interpolator/fast_out_slow_in"
+        android:duration="350" />
+
+    <alpha android:fromAlpha="1.0" android:toAlpha="1.6666666666"
+        android:fillEnabled="true" android:fillBefore="false" android:fillAfter="true"
+        android:interpolator="@android:interpolator/decelerate_cubic"
+        android:startOffset="350"
+        android:duration="133"/>
+
+    <translate android:fromYDelta="0%" android:toYDelta="-8.8888888888%"
+        android:fillEnabled="true" android:fillBefore="false" android:fillAfter="true"
+        android:interpolator="@android:interpolator/decelerate_cubic"
+        android:startOffset="350"
+        android:duration="350"/>
+
+    <scale android:fromXScale="1.0" android:toXScale="1.1111111111"
+        android:fromYScale="1.0" android:toYScale="1.1111111111"
+        android:fillEnabled="true" android:fillBefore="false" android:fillAfter="true"
+        android:pivotX="50%p" android:pivotY="50%p"
+        android:interpolator="@android:interpolator/decelerate_cubic"
+        android:startOffset="350"
+        android:duration="350" />
+</set>
\ No newline at end of file
diff --git a/packages/SystemUI/res/anim/recents_launch_next_affiliated_task_source.xml b/packages/SystemUI/res/anim/recents_launch_next_affiliated_task_source.xml
new file mode 100644
index 0000000..f0fd684
--- /dev/null
+++ b/packages/SystemUI/res/anim/recents_launch_next_affiliated_task_source.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2014, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+     android:background="#ff000000" android:shareInterpolator="false" android:zAdjustment="normal">
+
+    <alpha android:fromAlpha="1.0" android:toAlpha="0.6"
+        android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
+        android:interpolator="@android:interpolator/accelerate_cubic"
+        android:duration="150"/>
+
+    <scale android:fromXScale="1.0" android:toXScale="0.9"
+        android:fromYScale="1.0" android:toYScale="0.9"
+        android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
+        android:pivotX="50%p" android:pivotY="50%p"
+        android:interpolator="@android:interpolator/fast_out_slow_in"
+        android:duration="300" />
+</set>
\ No newline at end of file
diff --git a/packages/SystemUI/res/anim/recents_launch_next_affiliated_task_target.xml b/packages/SystemUI/res/anim/recents_launch_next_affiliated_task_target.xml
new file mode 100644
index 0000000..170ac82
--- /dev/null
+++ b/packages/SystemUI/res/anim/recents_launch_next_affiliated_task_target.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2014, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+     android:background="#ff000000" android:shareInterpolator="false" android:zAdjustment="top">
+
+    <translate android:fromYDelta="110%" android:toYDelta="0%"
+               android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
+               android:interpolator="@android:interpolator/decelerate_quint"
+               android:startOffset="50"
+               android:duration="250" />
+</set>
\ No newline at end of file
diff --git a/packages/SystemUI/res/anim/recents_launch_prev_affiliated_task_bounce.xml b/packages/SystemUI/res/anim/recents_launch_prev_affiliated_task_bounce.xml
new file mode 100644
index 0000000..46045ac
--- /dev/null
+++ b/packages/SystemUI/res/anim/recents_launch_prev_affiliated_task_bounce.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2014, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+     android:background="#ff000000" android:shareInterpolator="false" android:zAdjustment="top">
+
+    <translate android:fromYDelta="0%" android:toYDelta="10%"
+               android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
+               android:interpolator="@android:interpolator/decelerate_quint"
+               android:duration="300" />
+
+    <translate android:fromYDelta="10%" android:toYDelta="0%"
+               android:fillEnabled="true" android:fillBefore="false" android:fillAfter="true"
+               android:interpolator="@android:interpolator/accelerate_quint"
+               android:startOffset="300"
+               android:duration="300" />
+</set>
\ No newline at end of file
diff --git a/packages/SystemUI/res/anim/recents_launch_prev_affiliated_task_source.xml b/packages/SystemUI/res/anim/recents_launch_prev_affiliated_task_source.xml
new file mode 100644
index 0000000..ad5341b
--- /dev/null
+++ b/packages/SystemUI/res/anim/recents_launch_prev_affiliated_task_source.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2014, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+     android:background="#ff000000" android:shareInterpolator="false" android:zAdjustment="top">
+
+    <translate android:fromYDelta="0%" android:toYDelta="110%"
+               android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
+               android:interpolator="@android:interpolator/accelerate_quint"
+               android:duration="300" />
+</set>
\ No newline at end of file
diff --git a/packages/SystemUI/res/anim/recents_launch_prev_affiliated_task_target.xml b/packages/SystemUI/res/anim/recents_launch_prev_affiliated_task_target.xml
new file mode 100644
index 0000000..7687f02
--- /dev/null
+++ b/packages/SystemUI/res/anim/recents_launch_prev_affiliated_task_target.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2014, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+     android:background="#ff000000" android:shareInterpolator="false" android:zAdjustment="normal">
+
+    <alpha android:fromAlpha="0.6" android:toAlpha="1.0"
+        android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
+        android:interpolator="@android:interpolator/decelerate_cubic"
+        android:startOffset="75"
+        android:duration="150"/>
+
+    <scale android:fromXScale="0.9" android:toXScale="1.0"
+        android:fromYScale="0.9" android:toYScale="1.0"
+        android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
+        android:interpolator="@android:interpolator/linear_out_slow_in"
+        android:pivotX="50%p" android:pivotY="50%p"
+        android:startOffset="75"
+        android:duration="225" />
+</set>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/recents_button_bg.xml b/packages/SystemUI/res/drawable/recents_button_bg.xml
index a4cb088..7456365 100644
--- a/packages/SystemUI/res/drawable/recents_button_bg.xml
+++ b/packages/SystemUI/res/drawable/recents_button_bg.xml
@@ -15,4 +15,5 @@
 -->
 
 <ripple xmlns:android="http://schemas.android.com/apk/res/android"
-    android:color="?android:attr/colorControlHighlight" />
\ No newline at end of file
+    android:color="#40ffffff">
+</ripple>
diff --git a/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java b/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java
index f23f9f2..787de4e 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java
@@ -139,7 +139,8 @@
                 // Notify recents to hide itself
                 Intent intent = new Intent(ACTION_HIDE_RECENTS_ACTIVITY);
                 intent.setPackage(mContext.getPackageName());
-                intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
+                intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT |
+                        Intent.FLAG_RECEIVER_FOREGROUND);
                 intent.putExtra(EXTRA_TRIGGERED_FROM_ALT_TAB, triggeredFromAltTab);
                 intent.putExtra(EXTRA_TRIGGERED_FROM_HOME_KEY, triggeredFromHomeKey);
                 mContext.sendBroadcastAsUser(intent, UserHandle.CURRENT);
@@ -190,10 +191,14 @@
                 Task.TaskKey toTaskKey;
                 if (showNextTask) {
                     toTaskKey = group.getNextTaskInGroup(task);
-                    // XXX: We will actually set the appropriate launch animations here
+                    launchOpts = ActivityOptions.makeCustomAnimation(mContext,
+                            R.anim.recents_launch_next_affiliated_task_target,
+                            R.anim.recents_launch_next_affiliated_task_source);
                 } else {
                     toTaskKey = group.getPrevTaskInGroup(task);
-                    // XXX: We will actually set the appropriate launch animations here
+                    launchOpts = ActivityOptions.makeCustomAnimation(mContext,
+                            R.anim.recents_launch_prev_affiliated_task_target,
+                            R.anim.recents_launch_prev_affiliated_task_source);
                 }
                 if (toTaskKey != null) {
                     toTask = stack.findTaskWithId(toTaskKey.id);
@@ -204,7 +209,11 @@
 
         // Return early if there is no next task
         if (toTask == null) {
-            // XXX: We will actually show a bounce animation here
+            if (showNextTask) {
+                // XXX: Show the next-task bounce animation
+            } else {
+                // XXX: Show the prev-task bounce animation
+            }
             return;
         }
 
@@ -316,7 +325,8 @@
             // Notify recents to toggle itself
             Intent intent = new Intent(ACTION_TOGGLE_RECENTS_ACTIVITY);
             intent.setPackage(mContext.getPackageName());
-            intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
+            intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT |
+                    Intent.FLAG_RECEIVER_FOREGROUND);
             mContext.sendBroadcastAsUser(intent, UserHandle.CURRENT);
             mLastToggleTime = System.currentTimeMillis();
             return;
@@ -590,7 +600,8 @@
             // Send the broadcast to notify Recents that the animation has started
             Intent intent = new Intent(ACTION_START_ENTER_ANIMATION);
             intent.setPackage(mContext.getPackageName());
-            intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
+            intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT |
+                    Intent.FLAG_RECEIVER_FOREGROUND);
             mContext.sendOrderedBroadcastAsUser(intent, UserHandle.CURRENT, null,
                     fallbackReceiver, null, Activity.RESULT_CANCELED, null, null);
         }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
index 887cbac..bbd0a0d 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
@@ -56,6 +56,7 @@
 import android.view.DisplayInfo;
 import android.view.SurfaceControl;
 import android.view.WindowManager;
+import android.view.accessibility.AccessibilityManager;
 import com.android.systemui.recents.Constants;
 
 import java.io.IOException;
@@ -73,6 +74,7 @@
 
     final static BitmapFactory.Options sBitmapOptions;
 
+    AccessibilityManager mAccm;
     ActivityManager mAm;
     IActivityManager mIam;
     AppWidgetManager mAwm;
@@ -97,6 +99,7 @@
 
     /** Private constructor */
     public SystemServicesProxy(Context context) {
+        mAccm = AccessibilityManager.getInstance(context);
         mAm = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
         mIam = ActivityManagerNative.getDefault();
         mAwm = AppWidgetManager.getInstance(context);
@@ -442,6 +445,15 @@
     }
 
     /**
+     * Returns whether touch exploration is currently enabled.
+     */
+    public boolean isTouchExplorationEnabled() {
+        if (mAccm == null) return false;
+
+        return mAccm.isEnabled() && mAccm.isTouchExplorationEnabled();
+    }
+
+    /**
      * Returns a global setting.
      */
     public int getGlobalSetting(Context context, String setting) {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
index dbed136..895b9d1 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
@@ -22,11 +22,15 @@
 import android.view.LayoutInflater;
 import android.view.MotionEvent;
 import android.view.View;
+import android.view.accessibility.AccessibilityEvent;
+import android.view.accessibility.AccessibilityManager;
+import android.view.accessibility.AccessibilityNodeInfo;
 import android.widget.FrameLayout;
 import com.android.systemui.R;
 import com.android.systemui.recents.Constants;
 import com.android.systemui.recents.RecentsConfiguration;
 import com.android.systemui.recents.misc.DozeTrigger;
+import com.android.systemui.recents.misc.SystemServicesProxy;
 import com.android.systemui.recents.model.RecentsPackageMonitor;
 import com.android.systemui.recents.model.RecentsTaskLoader;
 import com.android.systemui.recents.model.Task;
@@ -67,6 +71,7 @@
     DebugOverlayView mDebugOverlay;
     Rect mTaskStackBounds = new Rect();
     int mFocusedTaskIndex = -1;
+    int mPrevAccessibilityFocusedIndex = -1;
 
     // Optimizations
     int mStackViewsAnimationDuration;
@@ -244,6 +249,9 @@
     /** Synchronizes the views with the model */
     boolean synchronizeStackViewsWithModel() {
         if (mStackViewsDirty) {
+            RecentsTaskLoader loader = RecentsTaskLoader.getInstance();
+            SystemServicesProxy ssp = loader.getSystemServicesProxy();
+
             // Get all the task transforms
             ArrayList<Task> tasks = mStack.getTasks();
             float stackScroll = mStackScroller.getStackScroll();
@@ -293,6 +301,18 @@
                 // Animate the task into place
                 tv.updateViewPropertiesToTaskTransform(mCurrentTaskTransforms.get(taskIndex),
                         mStackViewsAnimationDuration);
+
+                // Request accessibility focus on the next view if we removed the task
+                // that previously held accessibility focus
+                childCount = getChildCount();
+                if (childCount > 0 && ssp.isTouchExplorationEnabled()) {
+                    TaskView atv = (TaskView) getChildAt(childCount - 1);
+                    int indexOfTask = mStack.indexOfTask(atv.getTask());
+                    if (mPrevAccessibilityFocusedIndex != indexOfTask) {
+                        tv.requestAccessibilityFocus();
+                        mPrevAccessibilityFocusedIndex = indexOfTask;
+                    }
+                }
             }
 
             // Reset the request-synchronize params
@@ -432,6 +452,22 @@
     }
 
     @Override
+    public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
+        super.onInitializeAccessibilityEvent(event);
+        int childCount = getChildCount();
+        if (childCount > 0) {
+            TaskView backMostTask = (TaskView) getChildAt(0);
+            TaskView frontMostTask = (TaskView) getChildAt(childCount - 1);
+            event.setFromIndex(mStack.indexOfTask(backMostTask.getTask()));
+            event.setToIndex(mStack.indexOfTask(frontMostTask.getTask()));
+            event.setContentDescription(frontMostTask.getTask().activityLabel);
+        }
+        event.setItemCount(mStack.getTaskCount());
+        event.setScrollY(mStackScroller.mScroller.getCurrY());
+        event.setMaxScrollY(mStackScroller.progressToScrollRange(mLayoutAlgorithm.mMaxScrollP));
+    }
+
+    @Override
     public boolean onInterceptTouchEvent(MotionEvent ev) {
         return mTouchHandler.onInterceptTouchEvent(ev);
     }
@@ -447,6 +483,8 @@
         // Synchronize the views
         synchronizeStackViewsWithModel();
         clipTaskViews();
+        // Notify accessibility
+        sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SCROLLED);
     }
 
     /** Computes the stack and task rects */
@@ -623,6 +661,15 @@
                     mStartEnterAnimationCompleted = true;
                     // Start dozing
                     mUIDozeTrigger.startDozing();
+                    // Focus the first view if accessibility is enabled
+                    RecentsTaskLoader loader = RecentsTaskLoader.getInstance();
+                    SystemServicesProxy ssp = loader.getSystemServicesProxy();
+                    int childCount = getChildCount();
+                    if (childCount > 0 && ssp.isTouchExplorationEnabled()) {
+                        TaskView tv = ((TaskView) getChildAt(childCount - 1));
+                        tv.requestAccessibilityFocus();
+                        mPrevAccessibilityFocusedIndex = mStack.indexOfTask(tv.getTask());
+                    }
                 }
             });
         }
@@ -812,6 +859,11 @@
     public void prepareViewToEnterPool(TaskView tv) {
         Task task = tv.getTask();
 
+        // Clear the accessibility focus for that view
+        if (tv.isAccessibilityFocused()) {
+            tv.clearAccessibilityFocus();
+        }
+
         // Report that this tasks's data is no longer being used
         RecentsTaskLoader.getInstance().unloadTaskData(task);
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarViewTaskSwitchHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarViewTaskSwitchHelper.java
index b633453..79bb1cd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarViewTaskSwitchHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarViewTaskSwitchHelper.java
@@ -31,7 +31,6 @@
     private final GestureDetector mTaskSwitcherDetector;
     private final int mScrollTouchSlop;
     private final int mMinFlingVelocity;
-    private boolean mInterceptTouches;
     private int mTouchDownX;
     private int mTouchDownY;
 
@@ -56,11 +55,11 @@
         // task switcher detector
         mTaskSwitcherDetector.onTouchEvent(event);
         int action = event.getAction();
+        boolean interceptTouches = false;
         switch (action & MotionEvent.ACTION_MASK) {
             case MotionEvent.ACTION_DOWN: {
                 mTouchDownX = (int) event.getX();
                 mTouchDownY = (int) event.getY();
-                mInterceptTouches = false;
                 break;
             }
             case MotionEvent.ACTION_MOVE: {
@@ -72,21 +71,19 @@
                         ? xDiff > mScrollTouchSlop && xDiff > yDiff
                         : yDiff > mScrollTouchSlop && yDiff > xDiff;
                 if (exceededTouchSlop) {
-                    mInterceptTouches = true;
+                    interceptTouches = true;
                     return true;
                 }
                 break;
             }
             case MotionEvent.ACTION_CANCEL:
             case MotionEvent.ACTION_UP:
-                mInterceptTouches = false;
                 break;
         }
-        return mInterceptTouches;
+        return interceptTouches;
     }
 
     public boolean onTouchEvent(MotionEvent event) {
-        if (!mInterceptTouches) return false;
         return mTaskSwitcherDetector.onTouchEvent(event);
     }
 
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 0bdb964..599c3b9 100755
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -308,7 +308,14 @@
             return new ComponentName("!", res.permission != null
                     ? res.permission : "private to package");
         }
+
         ServiceRecord r = res.record;
+
+        if (!mAm.getUserManagerLocked().exists(r.userId)) {
+            Slog.d(TAG, "Trying to start service with non-existent user! " + r.userId);
+            return null;
+        }
+
         NeededUriGrants neededGrants = mAm.checkGrantUriPermissionFromIntentLocked(
                 callingUid, r.packageName, service, service.getFlags(), null, r.userId);
         if (unscheduleServiceRestartLocked(r, callingUid, false)) {
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java
index 38c6fb3..5cd7c01 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java
@@ -256,7 +256,7 @@
     private List<HdmiDeviceInfo> mMhlDevices;
 
     @Nullable
-    private HdmiMhlController mMhlController;
+    private HdmiMhlControllerStub mMhlController;
 
     // Last input port before switching to the MHL port. Should switch back to this port
     // when the mobile device sends the request one touch play with off.
@@ -305,7 +305,7 @@
             Slog.i(TAG, "Device does not support HDMI-CEC.");
         }
 
-        mMhlController = HdmiMhlController.create(this);
+        mMhlController = HdmiMhlControllerStub.create(this);
         if (!mMhlController.isReady()) {
             Slog.i(TAG, "Device does not support MHL-control.");
         }
diff --git a/services/core/java/com/android/server/hdmi/HdmiMhlControllerStub.java b/services/core/java/com/android/server/hdmi/HdmiMhlControllerStub.java
new file mode 100644
index 0000000..c27cf18
--- /dev/null
+++ b/services/core/java/com/android/server/hdmi/HdmiMhlControllerStub.java
@@ -0,0 +1,149 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.hdmi;
+
+import android.hardware.hdmi.HdmiPortInfo;
+import android.util.SparseArray;
+
+import com.android.server.hdmi.HdmiControlService.SendMessageCallback;
+
+/**
+ * A handler class for MHL control command. It converts user's command into MHL command and pass it
+ * to MHL HAL layer.
+ * <p>
+ * It can be created only by {@link HdmiMhlControllerStub#create}.
+ */
+final class HdmiMhlControllerStub {
+
+    private static final SparseArray<HdmiMhlLocalDevice> mLocalDevices = new SparseArray<>();
+    private static final HdmiPortInfo[] EMPTY_PORT_INFO = new HdmiPortInfo[0];
+    private static final int INVALID_MHL_VERSION = 0;
+    private static final int NO_SUPPORTED_FEATURES = 0;
+    private static final int INVALID_DEVICE_ROLES = 0;
+
+    // Private constructor. Use HdmiMhlControllerStub.create().
+    private HdmiMhlControllerStub(HdmiControlService service) {
+    }
+
+    // Returns true if MHL controller is initialized and ready to use.
+    boolean isReady() {
+        return false;
+    }
+
+    static HdmiMhlControllerStub create(HdmiControlService service) {
+        return new HdmiMhlControllerStub(service);
+    }
+
+    HdmiPortInfo[] getPortInfos() {
+        return EMPTY_PORT_INFO;
+    }
+
+    /**
+     * Return {@link HdmiMhlLocalDevice} matched with the given port id.
+     *
+     * @return null if has no matched port id
+     */
+    HdmiMhlLocalDevice getLocalDevice(int portId) {
+        return null;
+    }
+
+    /**
+     * Return {@link HdmiMhlLocalDevice} matched with the given device id.
+     *
+     * @return null if has no matched id
+     */
+    HdmiMhlLocalDevice getLocalDeviceById(int deviceId) {
+        return null;
+    }
+
+    SparseArray<HdmiMhlLocalDevice> getAllLocalDevices() {
+        return mLocalDevices;
+    }
+
+    /**
+     * Remove a {@link HdmiMhlLocalDevice} matched with the given port id.
+     *
+     * @return removed {@link HdmiMhlLocalDevice}. Return null if no matched port id.
+     */
+    HdmiMhlLocalDevice removeLocalDevice(int portId) {
+        return null;
+    }
+
+    /**
+     * Add a new {@link HdmiMhlLocalDevice}.
+     *
+     * @return old {@link HdmiMhlLocalDevice} having same port id
+     */
+    HdmiMhlLocalDevice addLocalDevice(HdmiMhlLocalDevice device) {
+        return null;
+    }
+
+    void clearAllLocalDevices() {
+    }
+
+    /**
+     * Send MHL MSC-Subcommand to the device connected to the given port.
+     */
+    void sendSubcommand(int portId, HdmiMhlSubcommand command) {
+    }
+
+    void sendSubcommand(final int portId, final HdmiMhlSubcommand command,
+            SendMessageCallback callback) {
+    }
+
+
+    void sendScratchpadCommand(int portId, int offset, int length, byte[] data) {
+    }
+
+    void setOption(int flag, int value) {
+    }
+
+    /**
+     * Get the MHL version supported by underlying hardware port of the given {@code portId}.
+     * MHL specification version 2.0 returns 0x20, 3.0 will return 0x30 respectively.
+     * The return value is stored in 'version'. Return INVALID_VERSION if MHL hardware layer
+     * is not ready.
+     */
+    int getMhlVersion(int portId) {
+        return INVALID_MHL_VERSION;
+    }
+
+    /**
+     * Get MHL version of a device which is connected to a port of the given {@code portId}.
+     * MHL specification version 2.0 returns 0x20, 3.0 will return 0x30 respectively.
+     * The return value is stored in 'version'.
+     */
+    int getPeerMhlVersion(int portId) {
+        return INVALID_MHL_VERSION;
+    }
+
+    /**
+     * Get the bit flags describing the features supported by the system. Refer to feature support
+     * flag register info in MHL specification.
+     */
+    int getSupportedFeatures(int portId) {
+        return NO_SUPPORTED_FEATURES;
+    }
+
+    /**
+     * Get the bit flags describing the roles which ECBUS device can play. Refer to the
+     * ECBUS_DEV_ROLES Register info MHL3.0 specification
+     */
+    int getEcbusDeviceRoles(int portId) {
+        return INVALID_DEVICE_ROLES;
+    }
+}
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index adca46a..06f550d 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -579,8 +579,7 @@
             try {
                 apk = PackageParser.parseApkLite(file, PackageParser.PARSE_COLLECT_CERTIFICATES);
             } catch (PackageParserException e) {
-                throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
-                        "Failed to parse " + file + ": " + e);
+                throw PackageManagerException.from(e);
             }
 
             if (!stagedSplits.add(apk.splitName)) {
@@ -646,8 +645,7 @@
                 existingBase = PackageParser.parseApkLite(new File(app.getBaseCodePath()),
                         PackageParser.PARSE_COLLECT_CERTIFICATES);
             } catch (PackageParserException e) {
-                throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
-                        "Failed to parse existing package " + app.getCodePath() + ": " + e);
+                throw PackageManagerException.from(e);
             }
 
             assertApkConsistent("Existing base", existingBase);
@@ -699,8 +697,7 @@
         try {
             baseApk = PackageParser.parseApkLite(mResolvedBaseFile, 0);
         } catch (PackageParserException e) {
-            throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
-                    "Failed to parse base package " + mResolvedBaseFile + ": " + e);
+            throw PackageManagerException.from(e);
         }
 
         final List<String> splitPaths = new ArrayList<>();
diff --git a/services/core/java/com/android/server/pm/PackageManagerException.java b/services/core/java/com/android/server/pm/PackageManagerException.java
index 0cbdcdc..a41636e 100644
--- a/services/core/java/com/android/server/pm/PackageManagerException.java
+++ b/services/core/java/com/android/server/pm/PackageManagerException.java
@@ -16,6 +16,8 @@
 
 package com.android.server.pm;
 
+import android.content.pm.PackageParser.PackageParserException;
+
 /** {@hide} */
 public class PackageManagerException extends Exception {
     public final int error;
@@ -29,4 +31,9 @@
         super(detailMessage, throwable);
         this.error = error;
     }
+
+    public static PackageManagerException from(PackageParserException e)
+            throws PackageManagerException {
+        throw new PackageManagerException(e.error, e.getMessage(), e.getCause());
+    }
 }
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index d1bc35b..d821fc1 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -4162,8 +4162,7 @@
             pp.collectCertificates(pkg, parseFlags);
             pp.collectManifestDigest(pkg);
         } catch (PackageParserException e) {
-            throw new PackageManagerException(e.error, "Failed to collect certificates for "
-                    + pkg.packageName + ": " + e.getMessage());
+            throw PackageManagerException.from(e);
         }
     }
 
@@ -4188,8 +4187,7 @@
         try {
             pkg = pp.parsePackage(scanFile, parseFlags);
         } catch (PackageParserException e) {
-            throw new PackageManagerException(e.error,
-                    "Failed to scan " + scanFile + ": " + e.getMessage());
+            throw PackageManagerException.from(e);
         }
 
         PackageSetting ps = null;
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 6dd6d2ef..d032d29 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -21,7 +21,6 @@
 import android.app.Activity;
 import android.app.ActivityManager;
 import android.app.ActivityManagerNative;
-import android.app.ActivityThread;
 import android.app.IStopUserCallback;
 import android.content.BroadcastReceiver;
 import android.content.Context;
@@ -92,6 +91,7 @@
     private static final String ATTR_SERIAL_NO = "serialNumber";
     private static final String ATTR_NEXT_SERIAL_NO = "nextSerialNumber";
     private static final String ATTR_PARTIAL = "partial";
+    private static final String ATTR_GUEST_TO_REMOVE = "guestToRemove";
     private static final String ATTR_USER_VERSION = "version";
     private static final String ATTR_PROFILE_GROUP_ID = "profileGroupId";
     private static final String TAG_GUEST_RESTRICTIONS = "guestRestrictions";
@@ -228,7 +228,7 @@
                 ArrayList<UserInfo> partials = new ArrayList<UserInfo>();
                 for (int i = 0; i < mUsers.size(); i++) {
                     UserInfo ui = mUsers.valueAt(i);
-                    if (ui.partial && i != 0) {
+                    if ((ui.partial || ui.guestToRemove) && i != 0) {
                         partials.add(ui);
                     }
                 }
@@ -759,6 +759,9 @@
             if (userInfo.partial) {
                 serializer.attribute(null, ATTR_PARTIAL, "true");
             }
+            if (userInfo.guestToRemove) {
+                serializer.attribute(null, ATTR_GUEST_TO_REMOVE, "true");
+            }
             if (userInfo.profileGroupId != UserInfo.NO_PROFILE_GROUP_ID) {
                 serializer.attribute(null, ATTR_PROFILE_GROUP_ID,
                         Integer.toString(userInfo.profileGroupId));
@@ -806,7 +809,7 @@
             serializer.attribute(null, ATTR_NEXT_SERIAL_NO, Integer.toString(mNextSerialNumber));
             serializer.attribute(null, ATTR_USER_VERSION, Integer.toString(mUserVersion));
 
-            serializer.startTag(null,  TAG_GUEST_RESTRICTIONS);
+            serializer.startTag(null, TAG_GUEST_RESTRICTIONS);
             writeRestrictionsLocked(serializer, mGuestRestrictions);
             serializer.endTag(null, TAG_GUEST_RESTRICTIONS);
             for (int i = 0; i < mUsers.size(); i++) {
@@ -873,6 +876,7 @@
         int profileGroupId = UserInfo.NO_PROFILE_GROUP_ID;
         long lastAttemptTime = 0L;
         boolean partial = false;
+        boolean guestToRemove = false;
         Bundle restrictions = new Bundle();
 
         FileInputStream fis = null;
@@ -920,6 +924,10 @@
                 if ("true".equals(valueString)) {
                     partial = true;
                 }
+                valueString = parser.getAttributeValue(null, ATTR_GUEST_TO_REMOVE);
+                if ("true".equals(valueString)) {
+                    guestToRemove = true;
+                }
 
                 int outerDepth = parser.getDepth();
                 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
@@ -944,6 +952,7 @@
             userInfo.creationTime = creationTime;
             userInfo.lastLoggedInTime = lastLoggedInTime;
             userInfo.partial = partial;
+            userInfo.guestToRemove = guestToRemove;
             userInfo.profileGroupId = profileGroupId;
             mUserRestrictions.append(id, restrictions);
             if (salt != 0L) {
@@ -1123,7 +1132,7 @@
                         return null;
                     }
                     // If we're adding a guest and there already exists one, bail.
-                    if (isGuest && numberOfUsersOfTypeLocked(UserInfo.FLAG_GUEST, true) > 0) {
+                    if (isGuest && findCurrentGuestUserLocked() != null) {
                         return null;
                     }
                     // Limit number of managed profiles that can be created
@@ -1184,6 +1193,23 @@
     }
 
     /**
+     * Find the current guest user. If the Guest user is partial,
+     * then do not include it in the results as it is about to die.
+     * This is different than {@link #numberOfUsersOfTypeLocked(int, boolean)} due to
+     * the special handling of Guests being removed.
+     */
+    private UserInfo findCurrentGuestUserLocked() {
+        final int size = mUsers.size();
+        for (int i = 0; i < size; i++) {
+            final UserInfo user = mUsers.valueAt(i);
+            if (user.isGuest() && !user.guestToRemove && !mRemovingUserIds.get(user.id)) {
+                return user;
+            }
+        }
+        return null;
+    }
+
+    /**
      * Mark this guest user for deletion to allow us to create another guest
      * and switch to that user before actually removing this guest.
      * @param userHandle the userid of the current guest
@@ -1208,14 +1234,15 @@
                 if (!user.isGuest()) {
                     return false;
                 }
-                // Set this to a partially created user, so that the user will be purged
-                // on next startup, in case the runtime stops now before stopping and
-                // removing the user completely.
-                user.partial = true;
+                // We set this to a guest user that is to be removed. This is a temporary state
+                // where we are allowed to add new Guest users, even if this one is still not
+                // removed. This user will still show up in getUserInfo() calls.
+                // If we don't get around to removing this Guest user, it will be purged on next
+                // startup.
+                user.guestToRemove = true;
                 // Mark it as disabled, so that it isn't returned any more when
                 // profiles are queried.
                 user.flags |= UserInfo.FLAG_DISABLED;
-                user.flags &= ~UserInfo.FLAG_GUEST;
                 writeUserLocked(user);
             }
         } finally {
diff --git a/services/core/jni/Android.mk b/services/core/jni/Android.mk
index 1f377c7..d81cdd9 100644
--- a/services/core/jni/Android.mk
+++ b/services/core/jni/Android.mk
@@ -11,7 +11,6 @@
     $(LOCAL_REL_DIR)/com_android_server_connectivity_Vpn.cpp \
     $(LOCAL_REL_DIR)/com_android_server_ConsumerIrService.cpp \
     $(LOCAL_REL_DIR)/com_android_server_hdmi_HdmiCecController.cpp \
-    $(LOCAL_REL_DIR)/com_android_server_hdmi_HdmiMhlController.cpp \
     $(LOCAL_REL_DIR)/com_android_server_input_InputApplicationHandle.cpp \
     $(LOCAL_REL_DIR)/com_android_server_input_InputManagerService.cpp \
     $(LOCAL_REL_DIR)/com_android_server_input_InputWindowHandle.cpp \
diff --git a/services/core/jni/onload.cpp b/services/core/jni/onload.cpp
index 39b70a8..7b2e408 100644
--- a/services/core/jni/onload.cpp
+++ b/services/core/jni/onload.cpp
@@ -38,7 +38,6 @@
 int register_android_server_location_FlpHardwareProvider(JNIEnv* env);
 int register_android_server_connectivity_Vpn(JNIEnv* env);
 int register_android_server_hdmi_HdmiCecController(JNIEnv* env);
-int register_android_server_hdmi_HdmiMhlController(JNIEnv* env);
 int register_android_server_tv_TvInputHal(JNIEnv* env);
 int register_android_server_PersistentDataBlockService(JNIEnv* env);
 int register_android_server_fingerprint_FingerprintService(JNIEnv* env);
@@ -76,7 +75,6 @@
     register_android_server_ConsumerIrService(env);
     register_android_server_BatteryStatsService(env);
     register_android_server_hdmi_HdmiCecController(env);
-    register_android_server_hdmi_HdmiMhlController(env);
     register_android_server_tv_TvInputHal(env);
     register_android_server_PersistentDataBlockService(env);
     register_android_server_fingerprint_FingerprintService(env);
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/SoundTriggerHelper.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/SoundTriggerHelper.java
index 376230b..ad38b22 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/SoundTriggerHelper.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/SoundTriggerHelper.java
@@ -67,7 +67,7 @@
     final ModuleProperties moduleProperties;
 
     /** The properties for the DSP module */
-    private final SoundTriggerModule mModule;
+    private SoundTriggerModule mModule;
     private final Object mLock = new Object();
     private final Context mContext;
     private final TelephonyManager mTelephonyManager;
@@ -105,7 +105,6 @@
         } else {
             // TODO: Figure out how to determine which module corresponds to the DSP hardware.
             moduleProperties = modules.get(0);
-            mModule = SoundTrigger.attachModule(moduleProperties.id, this, null);
         }
     }
 
@@ -155,10 +154,17 @@
                 mIsPowerSaveMode = mPowerManager.isPowerSaveMode();
             }
 
-            if (moduleProperties == null || mModule == null) {
+            if (moduleProperties == null) {
                 Slog.w(TAG, "Attempting startRecognition without the capability");
                 return STATUS_ERROR;
             }
+            if (mModule == null) {
+                mModule = SoundTrigger.attachModule(moduleProperties.id, this, null);
+                if (mModule == null) {
+                    Slog.w(TAG, "startRecognition cannot attach to sound trigger module");
+                    return STATUS_ERROR;
+                }
+            }
 
             if (mCurrentSoundModelHandle != INVALID_VALUE
                     && !soundModel.uuid.equals(mCurrentSoundModelUuid)) {
@@ -446,6 +452,10 @@
             Slog.w(TAG, "RemoteException in onError", e);
         } finally {
             internalClearStateLocked();
+            if (mModule != null) {
+                mModule.detach();
+                mModule = null;
+            }
         }
     }
 
diff --git a/telecomm/java/android/telecomm/PhoneAccount.java b/telecomm/java/android/telecomm/PhoneAccount.java
index d3da2ec..f709a86 100644
--- a/telecomm/java/android/telecomm/PhoneAccount.java
+++ b/telecomm/java/android/telecomm/PhoneAccount.java
@@ -246,7 +246,6 @@
      * {@link #getAddress()}. For the majority of {@code PhoneAccount}s this should be registered
      * as {@code null}.  It is used by the system for SIM-based {@code PhoneAccount} registration
      * where {@link android.telephony.TelephonyManager#setLine1NumberForDisplay(String, String)}
-     * or {@link android.telephony.TelephonyManager#setLine1NumberForDisplay(long, String, String)}
      * has been used to alter the callback number.
      * <p>
      *
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 164fc3c..d53be4f 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -1704,7 +1704,7 @@
      *   {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
      */
     public String getLine1Number() {
-        return getLine1Number(getDefaultSubscription());
+        return getLine1NumberForSubscriber(getDefaultSubscription());
     }
 
     /**
@@ -1717,7 +1717,7 @@
      * @param subId whose phone number for line 1 is returned
      */
     /** {@hide} */
-    public String getLine1Number(long subId) {
+    public String getLine1NumberForSubscriber(long subId) {
         String number = null;
         try {
             number = getITelephony().getLine1NumberForDisplay(subId);
@@ -1751,7 +1751,7 @@
      * @param number The dialing number
      */
     public void setLine1NumberForDisplay(String alphaTag, String number) {
-        setLine1NumberForDisplay(getDefaultSubscription(), alphaTag, number);
+        setLine1NumberForDisplayForSubscriber(getDefaultSubscription(), alphaTag, number);
     }
 
     /**
@@ -1767,10 +1767,11 @@
      * @param subId the subscriber that the alphatag and dialing number belongs to.
      * @param alphaTag alpha-tagging of the dailing nubmer
      * @param number The dialing number
+     * @hide
      */
-    public void setLine1NumberForDisplay(long subId, String alphaTag, String number) {
+    public void setLine1NumberForDisplayForSubscriber(long subId, String alphaTag, String number) {
         try {
-            getITelephony().setLine1NumberForDisplay(subId, alphaTag, number);
+            getITelephony().setLine1NumberForDisplayForSubscriber(subId, alphaTag, number);
         } catch (RemoteException ex) {
         } catch (NullPointerException ex) {
         }
@@ -1786,7 +1787,7 @@
      * nobody seems to call this.
      */
     public String getLine1AlphaTag() {
-        return getLine1AlphaTag(getDefaultSubscription());
+        return getLine1AlphaTagForSubscriber(getDefaultSubscription());
     }
 
     /**
@@ -1800,7 +1801,7 @@
      * nobody seems to call this.
      */
     /** {@hide} */
-    public String getLine1AlphaTag(long subId) {
+    public String getLine1AlphaTagForSubscriber(long subId) {
         String alphaTag = null;
         try {
             alphaTag = getITelephony().getLine1AlphaTagForDisplay(subId);
@@ -3369,7 +3370,7 @@
      * @hide
      */
     public void enableSimplifiedNetworkSettings(boolean enable) {
-        enableSimplifiedNetworkSettings(getDefaultSubscription(), enable);
+        enableSimplifiedNetworkSettingsForSubscriber(getDefaultSubscription(), enable);
     }
 
     /**
@@ -3384,9 +3385,9 @@
      * @param enable true means enabling the simplified UI.
      * @hide
      */
-    public void enableSimplifiedNetworkSettings(long subId, boolean enable) {
+    public void enableSimplifiedNetworkSettingsForSubscriber(long subId, boolean enable) {
         try {
-            getITelephony().enableSimplifiedNetworkSettings(subId, enable);
+            getITelephony().enableSimplifiedNetworkSettingsForSubscriber(subId, enable);
         } catch (RemoteException ex) {
         } catch (NullPointerException ex) {
         }
@@ -3402,7 +3403,7 @@
      * @hide
      */
     public boolean getSimplifiedNetworkSettingsEnabled() {
-        return getSimplifiedNetworkSettingsEnabled(getDefaultSubscription());
+        return getSimplifiedNetworkSettingsEnabledForSubscriber(getDefaultSubscription());
     }
 
     /**
@@ -3415,9 +3416,9 @@
      * @return true if the simplified UI is enabled.
      * @hide
      */
-    public boolean getSimplifiedNetworkSettingsEnabled(long subId) {
+    public boolean getSimplifiedNetworkSettingsEnabledForSubscriber(long subId) {
         try {
-            return getITelephony().getSimplifiedNetworkSettingsEnabled(subId);
+            return getITelephony().getSimplifiedNetworkSettingsEnabledForSubscriber(subId);
         } catch (RemoteException ex) {
         } catch (NullPointerException ex) {
         }
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index 5b280ff..fa9cad4 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -715,7 +715,7 @@
      * @param subId for which the simplified UI should be enabled or disabled.
      * @param enable true means enabling the simplified UI.
      */
-    void enableSimplifiedNetworkSettings(long subId, boolean enable);
+    void enableSimplifiedNetworkSettingsForSubscriber(long subId, boolean enable);
 
     /**
      * Get whether a simplified Mobile Network Settings UI is enabled.
@@ -723,7 +723,7 @@
      * @param subId for which the simplified UI should be enabled or disabled.
      * @return true if the simplified UI is enabled.
      */
-    boolean getSimplifiedNetworkSettingsEnabled(long subId);
+    boolean getSimplifiedNetworkSettingsEnabledForSubscriber(long subId);
 
     /**
      * Set the phone number string and its alphatag for line 1 for display
@@ -735,7 +735,7 @@
      * @param alphaTag alpha-tagging of the dailing nubmer
      * @param number The dialing number
      */
-    void setLine1NumberForDisplay(long subId, String alphaTag, String number);
+    void setLine1NumberForDisplayForSubscriber(long subId, String alphaTag, String number);
 
     /**
      * Returns the displayed dialing number string if it was set previously via
diff --git a/tests/Compatibility/src/com/android/compatibilitytest/AppCompatibility.java b/tests/Compatibility/src/com/android/compatibilitytest/AppCompatibility.java
index 5bf59c7..a2e9117 100644
--- a/tests/Compatibility/src/com/android/compatibilitytest/AppCompatibility.java
+++ b/tests/Compatibility/src/com/android/compatibilitytest/AppCompatibility.java
@@ -208,6 +208,12 @@
                 Log.d(TAG, "Found process " + app.processName);
                 return true;
             }
+            for (String relatedPackage : app.pkgList) {
+                if (relatedPackage.equalsIgnoreCase(processName)) {
+                    Log.d(TAG, "Found process " + app.processName);
+                    return true;
+                }
+            }
         }
         Log.d(TAG, "Failed to find process " + processName + " with package name "
                 + packageName);
diff --git a/tools/aapt/ResourceTable.cpp b/tools/aapt/ResourceTable.cpp
index b3c364b..8341de6 100644
--- a/tools/aapt/ResourceTable.cpp
+++ b/tools/aapt/ResourceTable.cpp
@@ -2574,8 +2574,12 @@
                 continue;
             }
             const size_t N = t->getOrderedConfigs().size();
-            sp<AaptSymbols> typeSymbols;
-            typeSymbols = outSymbols->addNestedSymbol(String8(t->getName()), t->getPos());
+            sp<AaptSymbols> typeSymbols =
+                    outSymbols->addNestedSymbol(String8(t->getName()), t->getPos());
+            if (typeSymbols == NULL) {
+                return UNKNOWN_ERROR;
+            }
+
             for (size_t ci=0; ci<N; ci++) {
                 sp<ConfigList> c = t->getOrderedConfigs().itemAt(ci);
                 if (c == NULL) {
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java
index 130500a..0ed6ab1 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java
@@ -174,6 +174,11 @@
     }
 
     @Override
+    public void setWallpaperDisplayOffset(IBinder windowToken, int x, int y) {
+        // pass for now.
+    }
+
+    @Override
     public Bundle sendWallpaperCommand(IBinder window, String action, int x, int y,
             int z, Bundle extras, boolean sync) {
         // pass for now.