Merge "Allowing isRound and outsetBottom properties to be passed to ActivityView." into lmp-dev
diff --git a/api/current.txt b/api/current.txt
index 6723108..c796cdb 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -2166,18 +2166,22 @@
     field public static final int Theme_Material_Dialog = 16974386; // 0x1030232
     field public static final int Theme_Material_DialogWhenLarge = 16974390; // 0x1030236
     field public static final int Theme_Material_DialogWhenLarge_NoActionBar = 16974391; // 0x1030237
+    field public static final int Theme_Material_Dialog_Alert = 16974570; // 0x10302ea
     field public static final int Theme_Material_Dialog_MinWidth = 16974387; // 0x1030233
     field public static final int Theme_Material_Dialog_NoActionBar = 16974388; // 0x1030234
     field public static final int Theme_Material_Dialog_NoActionBar_MinWidth = 16974389; // 0x1030235
+    field public static final int Theme_Material_Dialog_Presentation = 16974571; // 0x10302eb
     field public static final int Theme_Material_InputMethod = 16974392; // 0x1030238
     field public static final int Theme_Material_Light = 16974402; // 0x1030242
     field public static final int Theme_Material_Light_DarkActionBar = 16974403; // 0x1030243
     field public static final int Theme_Material_Light_Dialog = 16974404; // 0x1030244
     field public static final int Theme_Material_Light_DialogWhenLarge = 16974408; // 0x1030248
     field public static final int Theme_Material_Light_DialogWhenLarge_NoActionBar = 16974409; // 0x1030249
+    field public static final int Theme_Material_Light_Dialog_Alert = 16974572; // 0x10302ec
     field public static final int Theme_Material_Light_Dialog_MinWidth = 16974405; // 0x1030245
     field public static final int Theme_Material_Light_Dialog_NoActionBar = 16974406; // 0x1030246
     field public static final int Theme_Material_Light_Dialog_NoActionBar_MinWidth = 16974407; // 0x1030247
+    field public static final int Theme_Material_Light_Dialog_Presentation = 16974573; // 0x10302ed
     field public static final int Theme_Material_Light_NoActionBar = 16974410; // 0x103024a
     field public static final int Theme_Material_Light_NoActionBar_Fullscreen = 16974411; // 0x103024b
     field public static final int Theme_Material_Light_NoActionBar_Overscan = 16974412; // 0x103024c
@@ -2566,7 +2570,7 @@
     field public static final int Widget_Material_Light_SeekBar = 16974534; // 0x10302c6
     field public static final int Widget_Material_Light_SegmentedButton = 16974535; // 0x10302c7
     field public static final int Widget_Material_Light_Spinner = 16974537; // 0x10302c9
-    field public static final int Widget_Material_Light_Spinner_Form = 16974567; // 0x10302e7
+    field public static final int Widget_Material_Light_Spinner_Underlined = 16974567; // 0x10302e7
     field public static final int Widget_Material_Light_StackView = 16974536; // 0x10302c8
     field public static final int Widget_Material_Light_Tab = 16974538; // 0x10302ca
     field public static final int Widget_Material_Light_TabWidget = 16974539; // 0x10302cb
@@ -2593,7 +2597,7 @@
     field public static final int Widget_Material_SeekBar = 16974471; // 0x1030287
     field public static final int Widget_Material_SegmentedButton = 16974472; // 0x1030288
     field public static final int Widget_Material_Spinner = 16974474; // 0x103028a
-    field public static final int Widget_Material_Spinner_Form = 16974566; // 0x10302e6
+    field public static final int Widget_Material_Spinner_Underlined = 16974566; // 0x10302e6
     field public static final int Widget_Material_StackView = 16974473; // 0x1030289
     field public static final int Widget_Material_Tab = 16974475; // 0x103028b
     field public static final int Widget_Material_TabWidget = 16974476; // 0x103028c
@@ -4506,8 +4510,8 @@
   }
 
   public class KeyguardManager {
+    method public android.content.Intent createConfirmDeviceCredentialIntent(java.lang.CharSequence, java.lang.CharSequence);
     method public deprecated void exitKeyguardSecurely(android.app.KeyguardManager.OnKeyguardExitResult);
-    method public android.content.Intent getConfirmDeviceCredentialIntent(java.lang.CharSequence, java.lang.CharSequence);
     method public boolean inKeyguardRestrictedInputMode();
     method public boolean isKeyguardLocked();
     method public boolean isKeyguardSecure();
@@ -5450,7 +5454,6 @@
     method public boolean getScreenCaptureDisabled(android.content.ComponentName);
     method public boolean getStorageEncryption(android.content.ComponentName);
     method public int getStorageEncryptionStatus();
-    method public java.util.List<java.lang.String> getTrustAgentFeaturesEnabled(android.content.ComponentName, android.content.ComponentName);
     method public boolean getUninstallBlocked(android.content.ComponentName, java.lang.String);
     method public boolean hasCaCertInstalled(byte[]);
     method public boolean hasGrantedPolicy(android.content.ComponentName, int);
@@ -5498,7 +5501,6 @@
     method public void setScreenCaptureDisabled(android.content.ComponentName, boolean);
     method public void setSecureSetting(android.content.ComponentName, java.lang.String, java.lang.String);
     method public int setStorageEncryption(android.content.ComponentName, boolean);
-    method public void setTrustAgentFeaturesEnabled(android.content.ComponentName, android.content.ComponentName, java.util.List<java.lang.String>);
     method public void setUninstallBlocked(android.content.ComponentName, java.lang.String, boolean);
     method public boolean switchUser(android.content.ComponentName, android.os.UserHandle);
     method public void uninstallAllUserCaCerts(android.content.ComponentName);
diff --git a/api/removed.txt b/api/removed.txt
index 1b8aef4..1fde099 100644
--- a/api/removed.txt
+++ b/api/removed.txt
@@ -1,3 +1,11 @@
+package android.app {
+
+  public class KeyguardManager {
+    method public android.content.Intent getConfirmDeviceCredentialIntent(java.lang.CharSequence, java.lang.CharSequence);
+  }
+
+}
+
 package android.media {
 
   public class AudioFormat {
diff --git a/core/java/android/app/KeyguardManager.java b/core/java/android/app/KeyguardManager.java
index 50e3a10..e055237 100644
--- a/core/java/android/app/KeyguardManager.java
+++ b/core/java/android/app/KeyguardManager.java
@@ -56,6 +56,13 @@
     public static final String EXTRA_DESCRIPTION = "android.app.extra.DESCRIPTION";
 
     /**
+     * @removed
+     */
+    public Intent getConfirmDeviceCredentialIntent(CharSequence title, CharSequence description) {
+        return createConfirmDeviceCredentialIntent(title, description);
+    }
+
+    /**
      * Get an intent to prompt the user to confirm credentials (pin, pattern or password)
      * for the current user of the device. The caller is expected to launch this activity using
      * {@link android.app.Activity#startActivityForResult(Intent, int)} and check for
@@ -63,7 +70,7 @@
      *
      * @return the intent for launching the activity or null if no password is required.
      **/
-    public Intent getConfirmDeviceCredentialIntent(CharSequence title, CharSequence description) {
+    public Intent createConfirmDeviceCredentialIntent(CharSequence title, CharSequence description) {
         if (!isKeyguardSecure()) return null;
         Intent intent = new Intent(ACTION_CONFIRM_DEVICE_CREDENTIAL);
         intent.putExtra(EXTRA_TITLE, title);
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 26c72a5..3f82157 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -2562,6 +2562,7 @@
      * @param agent Which component to enable features for.
      * @param features List of features to enable. Consult specific TrustAgent documentation for
      * the feature list.
+     * @hide
      */
     public void setTrustAgentFeaturesEnabled(ComponentName admin, ComponentName agent,
             List<String> features) {
@@ -2582,6 +2583,7 @@
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
      * @param agent Which component to get enabled features for.
      * @return List of enabled features.
+     * @hide
      */
     public List<String> getTrustAgentFeaturesEnabled(ComponentName admin, ComponentName agent) {
         if (mService != null) {
@@ -2689,10 +2691,10 @@
      * Called by a profile or device owner to set the permitted accessibility services. When
      * set by a device owner or profile owner the restriction applies to all profiles of the
      * user the device owner or profile owner is an admin for.
-     * 
+     *
      * By default the user can use any accessiblity service. When zero or more packages have
      * been added, accessiblity services that are not in the list and not part of the system
-     * can not be enabled by the user. 
+     * can not be enabled by the user.
      *
      * <p> Calling with a null value for the list disables the restriction so that all services
      * can be used, calling with an empty list only allows the builtin system's services.
diff --git a/core/java/android/hardware/camera2/ICameraDeviceCallbacks.aidl b/core/java/android/hardware/camera2/ICameraDeviceCallbacks.aidl
index caabed3..ca0935c 100644
--- a/core/java/android/hardware/camera2/ICameraDeviceCallbacks.aidl
+++ b/core/java/android/hardware/camera2/ICameraDeviceCallbacks.aidl
@@ -26,8 +26,8 @@
      * Keep up-to-date with frameworks/av/include/camera/camera2/ICameraDeviceCallbacks.h
      */
 
-    oneway void onCameraError(int errorCode, in CaptureResultExtras resultExtras);
-    oneway void onCameraIdle();
+    oneway void onDeviceError(int errorCode, in CaptureResultExtras resultExtras);
+    oneway void onDeviceIdle();
     oneway void onCaptureStarted(in CaptureResultExtras resultExtras, long timestamp);
     oneway void onResultReceived(in CameraMetadataNative result,
                                  in CaptureResultExtras resultExtras);
diff --git a/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java b/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java
index 621968b..9ca1fba 100644
--- a/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java
@@ -74,7 +74,7 @@
     private boolean mSkipUnconfigure = false;
 
     /** Is the session in the process of aborting? Pay attention to BUSY->IDLE transitions. */
-    private boolean mAborting;
+    private volatile boolean mAborting;
 
     /**
      * Create a new CameraCaptureSession.
@@ -346,6 +346,20 @@
     }
 
     /**
+     * Whether currently in mid-abort.
+     *
+     * <p>This is used by the implementation to set the capture failure
+     * reason, in lieu of more accurate error codes from the camera service.
+     * Unsynchronized to avoid deadlocks between simultaneous session->device,
+     * device->session calls.</p>
+     *
+     * <p>Package-private.</p>
+     */
+    boolean isAborting() {
+        return mAborting;
+    }
+
+    /**
      * Post calls into a CameraCaptureSession.StateListener to the user-specified {@code handler}.
      */
     private StateListener createUserStateListenerProxy(Handler handler, StateListener listener) {
@@ -502,8 +516,8 @@
 
                 // TODO: Queue captures during abort instead of failing them
                 // since the app won't be able to distinguish the two actives
+                // Don't signal the application since there's no clean mapping here
                 Log.w(TAG, "Device is now busy; do not submit new captures (TODO: allow this)");
-                mStateListener.onActive(session);
             }
 
             @Override
diff --git a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
index 79ce9df..513d222 100644
--- a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
@@ -384,7 +384,7 @@
                 catch (IllegalArgumentException e) {
                     // OK. camera service can reject stream config if it's not supported by HAL
                     // This is only the result of a programmer misusing the camera2 api.
-                    Log.e(TAG, "Stream configuration failed", e);
+                    Log.w(TAG, "Stream configuration failed");
                     return false;
                 }
 
@@ -1097,31 +1097,51 @@
          */
         static final int ERROR_CAMERA_SERVICE = 2;
 
+        /**
+         * Camera has encountered an error processing a single request.
+         */
+        static final int ERROR_CAMERA_REQUEST = 3;
+
+        /**
+         * Camera has encountered an error producing metadata for a single capture
+         */
+        static final int ERROR_CAMERA_RESULT = 4;
+
+        /**
+         * Camera has encountered an error producing an image buffer for a single capture
+         */
+        static final int ERROR_CAMERA_BUFFER = 5;
+
         @Override
         public IBinder asBinder() {
             return this;
         }
 
         @Override
-        public void onCameraError(final int errorCode, CaptureResultExtras resultExtras) {
-            Runnable r = null;
+        public void onDeviceError(final int errorCode, CaptureResultExtras resultExtras) {
+            if (DEBUG) {
+                Log.d(TAG, String.format(
+                    "Device error received, code %d, frame number %d, request ID %d, subseq ID %d",
+                    errorCode, resultExtras.getFrameNumber(), resultExtras.getRequestId(),
+                    resultExtras.getSubsequenceId()));
+            }
 
             synchronized(mInterfaceLock) {
                 if (mRemoteDevice == null) {
                     return; // Camera already closed
                 }
 
-                mInError = true;
                 switch (errorCode) {
                     case ERROR_CAMERA_DISCONNECTED:
-                        r = mCallOnDisconnected;
+                        CameraDeviceImpl.this.mDeviceHandler.post(mCallOnDisconnected);
                         break;
                     default:
                         Log.e(TAG, "Unknown error from camera device: " + errorCode);
                         // no break
                     case ERROR_CAMERA_DEVICE:
                     case ERROR_CAMERA_SERVICE:
-                        r = new Runnable() {
+                        mInError = true;
+                        Runnable r = new Runnable() {
                             @Override
                             public void run() {
                                 if (!CameraDeviceImpl.this.isClosed()) {
@@ -1129,21 +1149,19 @@
                                 }
                             }
                         };
+                        CameraDeviceImpl.this.mDeviceHandler.post(r);
+                        break;
+                    case ERROR_CAMERA_REQUEST:
+                    case ERROR_CAMERA_RESULT:
+                    case ERROR_CAMERA_BUFFER:
+                        onCaptureErrorLocked(errorCode, resultExtras);
                         break;
                 }
-                CameraDeviceImpl.this.mDeviceHandler.post(r);
-
-                // Fire onCaptureSequenceCompleted
-                if (DEBUG) {
-                    Log.v(TAG, String.format("got error frame %d", resultExtras.getFrameNumber()));
-                }
-                mFrameNumberTracker.updateTracker(resultExtras.getFrameNumber(), /*error*/true);
-                checkAndFireSequenceComplete();
             }
         }
 
         @Override
-        public void onCameraIdle() {
+        public void onDeviceIdle() {
             if (DEBUG) {
                 Log.d(TAG, "Camera now idle");
             }
@@ -1246,7 +1264,6 @@
 
                 final CaptureRequest request = holder.getRequest(resultExtras.getSubsequenceId());
 
-
                 Runnable resultDispatch = null;
 
                 // Either send a partial result or the final capture completed result
@@ -1290,11 +1307,67 @@
                 if (!isPartialResult) {
                     checkAndFireSequenceComplete();
                 }
-
             }
         }
 
-    }
+        /**
+         * Called by onDeviceError for handling single-capture failures.
+         */
+        private void onCaptureErrorLocked(int errorCode, CaptureResultExtras resultExtras) {
+
+            final int requestId = resultExtras.getRequestId();
+            final int subsequenceId = resultExtras.getSubsequenceId();
+            final long frameNumber = resultExtras.getFrameNumber();
+            final CaptureListenerHolder holder =
+                    CameraDeviceImpl.this.mCaptureListenerMap.get(requestId);
+
+            final CaptureRequest request = holder.getRequest(subsequenceId);
+
+            // No way to report buffer errors right now
+            if (errorCode == ERROR_CAMERA_BUFFER) {
+                Log.e(TAG, String.format("Lost output buffer reported for frame %d", frameNumber));
+                return;
+            }
+
+            boolean mayHaveBuffers = (errorCode == ERROR_CAMERA_RESULT);
+
+            // This is only approximate - exact handling needs the camera service and HAL to
+            // disambiguate between request failures to due abort and due to real errors.
+            // For now, assume that if the session believes we're mid-abort, then the error
+            // is due to abort.
+            int reason = (mCurrentSession != null && mCurrentSession.isAborting()) ?
+                    CaptureFailure.REASON_FLUSHED :
+                    CaptureFailure.REASON_ERROR;
+
+            final CaptureFailure failure = new CaptureFailure(
+                request,
+                reason,
+                /*dropped*/ mayHaveBuffers,
+                requestId,
+                frameNumber);
+
+            Runnable failureDispatch = new Runnable() {
+                @Override
+                public void run() {
+                    if (!CameraDeviceImpl.this.isClosed()){
+                        holder.getListener().onCaptureFailed(
+                            CameraDeviceImpl.this,
+                            request,
+                            failure);
+                    }
+                }
+            };
+            holder.getHandler().post(failureDispatch);
+
+            // Fire onCaptureSequenceCompleted if appropriate
+            if (DEBUG) {
+                Log.v(TAG, String.format("got error frame %d", frameNumber));
+            }
+            mFrameNumberTracker.updateTracker(frameNumber, /*error*/true);
+            checkAndFireSequenceComplete();
+        }
+
+    } // public class CameraDeviceCallbacks
 
     /**
      * Default handler management.
diff --git a/core/java/android/hardware/camera2/legacy/CameraDeviceUserShim.java b/core/java/android/hardware/camera2/legacy/CameraDeviceUserShim.java
index 5cbf109..410934e 100644
--- a/core/java/android/hardware/camera2/legacy/CameraDeviceUserShim.java
+++ b/core/java/android/hardware/camera2/legacy/CameraDeviceUserShim.java
@@ -211,7 +211,7 @@
         }
 
         @Override
-        public void onCameraError(final int errorCode, final CaptureResultExtras resultExtras) {
+        public void onDeviceError(final int errorCode, final CaptureResultExtras resultExtras) {
             Message msg = getHandler().obtainMessage(CAMERA_ERROR,
                 /*arg1*/ errorCode, /*arg2*/ 0,
                 /*obj*/ resultExtras);
@@ -219,7 +219,7 @@
         }
 
         @Override
-        public void onCameraIdle() {
+        public void onDeviceIdle() {
             Message msg = getHandler().obtainMessage(CAMERA_IDLE);
             getHandler().sendMessage(msg);
         }
@@ -267,11 +267,11 @@
                         case CAMERA_ERROR: {
                             int errorCode = msg.arg1;
                             CaptureResultExtras resultExtras = (CaptureResultExtras) msg.obj;
-                            mCallbacks.onCameraError(errorCode, resultExtras);
+                            mCallbacks.onDeviceError(errorCode, resultExtras);
                             break;
                         }
                         case CAMERA_IDLE:
-                            mCallbacks.onCameraIdle();
+                            mCallbacks.onDeviceIdle();
                             break;
                         case CAPTURE_STARTED: {
                             long timestamp = msg.arg2 & 0xFFFFFFFFL;
diff --git a/core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java b/core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java
index 1cf7797..ffc55f1 100644
--- a/core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java
+++ b/core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java
@@ -97,7 +97,7 @@
                         Log.d(TAG, "doing onError callback.");
                     }
                     try {
-                        mDeviceCallbacks.onCameraError(errorCode, extras);
+                        mDeviceCallbacks.onDeviceError(errorCode, extras);
                     } catch (RemoteException e) {
                         throw new IllegalStateException(
                                 "Received remote exception during onCameraError callback: ", e);
@@ -125,7 +125,7 @@
                         Log.d(TAG, "doing onIdle callback.");
                     }
                     try {
-                        mDeviceCallbacks.onCameraIdle();
+                        mDeviceCallbacks.onDeviceIdle();
                     } catch (RemoteException e) {
                         throw new IllegalStateException(
                                 "Received remote exception during onCameraIdle callback: ", e);
diff --git a/core/java/android/service/trust/TrustAgentService.java b/core/java/android/service/trust/TrustAgentService.java
index 337ae60..3ef5b37 100644
--- a/core/java/android/service/trust/TrustAgentService.java
+++ b/core/java/android/service/trust/TrustAgentService.java
@@ -89,6 +89,7 @@
     /**
      * A white list of features that the given trust agent should support when otherwise disabled
      * by device policy.
+     * @hide
      */
     public static final String KEY_FEATURES = "trust_agent_features";
 
@@ -184,6 +185,7 @@
      *
      * @param options Option feature bundle.
      * @return true if the {@link TrustAgentService} supports this feature.
+     * @hide
      */
     public boolean onSetTrustAgentFeaturesEnabled(Bundle options) {
         return false;
diff --git a/core/res/res/drawable/progress_horizontal_material.xml b/core/res/res/drawable/progress_horizontal_material.xml
index d7440a9..7a1079c 100644
--- a/core/res/res/drawable/progress_horizontal_material.xml
+++ b/core/res/res/drawable/progress_horizontal_material.xml
@@ -17,7 +17,8 @@
 <layer-list xmlns:android="http://schemas.android.com/apk/res/android">
     <item android:id="@id/background">
         <nine-patch android:src="@drawable/progress_mtrl_alpha"
-            android:tint="?attr/colorControlNormal" />
+            android:tint="?attr/colorControlNormal"
+            android:alpha="0.5" />
     </item>
     <item android:id="@id/secondaryProgress">
         <scale android:scaleWidth="100%">
diff --git a/core/res/res/values-television/dimens.xml b/core/res/res/values-television/dimens.xml
index 8266642..69c3da5 100644
--- a/core/res/res/values-television/dimens.xml
+++ b/core/res/res/values-television/dimens.xml
@@ -16,8 +16,8 @@
 <resources>
 
      <!-- Lighting and shadow properties -->
-     <dimen name="light_y">-300dp</dimen>
-     <item type="dimen" format="float" name="ambient_shadow_alpha">0.4</item>
-     <item type="dimen" format="float" name="spot_shadow_alpha">0.4</item>
+     <dimen name="light_y">-400dp</dimen>
+     <item type="dimen" format="float" name="ambient_shadow_alpha">0.06</item>
+     <item type="dimen" format="float" name="spot_shadow_alpha">0.3</item>
 
 </resources>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 82125fe..35658cf 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2535,12 +2535,17 @@
   <public type="style" name="TextAppearance.StatusBar.Material.EventContent.Time" />
   <public type="style" name="TextAppearance.StatusBar.Material.EventContent.Emphasis" />
 
-  <public type="style" name="Widget.Material.Spinner.Form" />
-  <public type="style" name="Widget.Material.Light.Spinner.Form" />
+  <public type="style" name="Widget.Material.Spinner.Underlined" />
+  <public type="style" name="Widget.Material.Light.Spinner.Underlined" />
 
   <public type="style" name="TextAppearance.Material.Widget.Toolbar.Title" />
   <public type="style" name="TextAppearance.Material.Widget.Toolbar.Subtitle" />
 
+  <public type="style" name="Theme.Material.Dialog.Alert" />
+  <public type="style" name="Theme.Material.Dialog.Presentation" />
+  <public type="style" name="Theme.Material.Light.Dialog.Alert" />
+  <public type="style" name="Theme.Material.Light.Dialog.Presentation" />
+
   <public-padding type="string" name="l_resource_pad" end="0x01040030" />
 
   <public type="string" name="config_webSettingsDefaultTextEncoding" />
diff --git a/core/res/res/values/styles_material.xml b/core/res/res/values/styles_material.xml
index fb70d6b..3ee5552 100644
--- a/core/res/res/values/styles_material.xml
+++ b/core/res/res/values/styles_material.xml
@@ -308,7 +308,7 @@
     <style name="TextAppearance.Material.Widget.TextView.PopupMenu" parent="TextAppearance.Material.Menu" />
     <style name="TextAppearance.Material.Widget.TextView.SpinnerItem" />
 
-    <style name="TextAppearance.Material.Widget.DropDownItem">
+    <style name="TextAppearance.Material.Widget.DropDownItem" parent="TextAppearance.Material.Menu">
         <item name="textColor">?attr/textColorPrimaryDisableOnly</item>
     </style>
 
@@ -759,7 +759,7 @@
         <item name="overlapAnchor">true</item>
     </style>
 
-    <style name="Widget.Material.Spinner.Form">
+    <style name="Widget.Material.Spinner.Underlined">
         <item name="background">@drawable/spinner_textfield_background_material</item>
     </style>
 
@@ -1022,7 +1022,7 @@
     <style name="Widget.Material.Light.Spinner" parent="Widget.Material.Spinner" />
     <style name="Widget.Material.Light.Spinner.DropDown" parent="Widget.Material.Spinner.DropDown"/>
     <style name="Widget.Material.Light.Spinner.DropDown.ActionBar" parent="Widget.Material.Spinner.DropDown.ActionBar"/>
-    <style name="Widget.Material.Light.Spinner.Form" parent="Widget.Material.Spinner.Form" />
+    <style name="Widget.Material.Light.Spinner.Underlined" parent="Widget.Material.Spinner.Underlined" />
     <style name="Widget.Material.Light.TabWidget" parent="Widget.Material.TabWidget"/>
     <style name="Widget.Material.Light.WebTextView" parent="Widget.Material.WebTextView"/>
     <style name="Widget.Material.Light.WebView" parent="Widget.Material.WebView"/>
diff --git a/graphics/java/android/graphics/drawable/AnimatedRotateDrawable.java b/graphics/java/android/graphics/drawable/AnimatedRotateDrawable.java
index 0bc4fdf..4c8b4f1 100644
--- a/graphics/java/android/graphics/drawable/AnimatedRotateDrawable.java
+++ b/graphics/java/android/graphics/drawable/AnimatedRotateDrawable.java
@@ -346,22 +346,24 @@
         private boolean mCanConstantState;
         private boolean mCheckedConstantState;
 
-        public AnimatedRotateState(AnimatedRotateState source, AnimatedRotateDrawable owner,
+        public AnimatedRotateState(AnimatedRotateState orig, AnimatedRotateDrawable owner,
                 Resources res) {
-            if (source != null) {
+            if (orig != null) {
                 if (res != null) {
-                    mDrawable = source.mDrawable.getConstantState().newDrawable(res);
+                    mDrawable = orig.mDrawable.getConstantState().newDrawable(res);
                 } else {
-                    mDrawable = source.mDrawable.getConstantState().newDrawable();
+                    mDrawable = orig.mDrawable.getConstantState().newDrawable();
                 }
                 mDrawable.setCallback(owner);
-                mDrawable.setLayoutDirection(source.mDrawable.getLayoutDirection());
-                mPivotXRel = source.mPivotXRel;
-                mPivotX = source.mPivotX;
-                mPivotYRel = source.mPivotYRel;
-                mPivotY = source.mPivotY;
-                mFramesCount = source.mFramesCount;
-                mFrameDuration = source.mFrameDuration;
+                mDrawable.setLayoutDirection(orig.mDrawable.getLayoutDirection());
+                mDrawable.setBounds(orig.mDrawable.getBounds());
+                mDrawable.setLevel(orig.mDrawable.getLevel());
+                mPivotXRel = orig.mPivotXRel;
+                mPivotX = orig.mPivotX;
+                mPivotYRel = orig.mPivotYRel;
+                mPivotY = orig.mPivotY;
+                mFramesCount = orig.mFramesCount;
+                mFrameDuration = orig.mFrameDuration;
                 mCanConstantState = mCheckedConstantState = true;
             }
         }
diff --git a/graphics/java/android/graphics/drawable/ClipDrawable.java b/graphics/java/android/graphics/drawable/ClipDrawable.java
index f116376..61ef81b 100644
--- a/graphics/java/android/graphics/drawable/ClipDrawable.java
+++ b/graphics/java/android/graphics/drawable/ClipDrawable.java
@@ -285,6 +285,8 @@
                 }
                 mDrawable.setCallback(owner);
                 mDrawable.setLayoutDirection(orig.mDrawable.getLayoutDirection());
+                mDrawable.setBounds(orig.mDrawable.getBounds());
+                mDrawable.setLevel(orig.mDrawable.getLevel());
                 mOrientation = orig.mOrientation;
                 mGravity = orig.mGravity;
                 mCheckedConstantState = mCanConstantState = true;
diff --git a/graphics/java/android/graphics/drawable/InsetDrawable.java b/graphics/java/android/graphics/drawable/InsetDrawable.java
index dd0f06f..a20b6d8 100644
--- a/graphics/java/android/graphics/drawable/InsetDrawable.java
+++ b/graphics/java/android/graphics/drawable/InsetDrawable.java
@@ -400,6 +400,8 @@
                 }
                 mDrawable.setCallback(owner);
                 mDrawable.setLayoutDirection(orig.mDrawable.getLayoutDirection());
+                mDrawable.setBounds(orig.mDrawable.getBounds());
+                mDrawable.setLevel(orig.mDrawable.getLevel());
                 mInsetLeft = orig.mInsetLeft;
                 mInsetTop = orig.mInsetTop;
                 mInsetRight = orig.mInsetRight;
diff --git a/graphics/java/android/graphics/drawable/LayerDrawable.java b/graphics/java/android/graphics/drawable/LayerDrawable.java
index 43bc89a..001ed88 100644
--- a/graphics/java/android/graphics/drawable/LayerDrawable.java
+++ b/graphics/java/android/graphics/drawable/LayerDrawable.java
@@ -961,20 +961,22 @@
             // Default empty constructor.
         }
 
-        ChildDrawable(ChildDrawable or, LayerDrawable owner, Resources res) {
+        ChildDrawable(ChildDrawable orig, LayerDrawable owner, Resources res) {
             if (res != null) {
-                mDrawable = or.mDrawable.getConstantState().newDrawable(res);
+                mDrawable = orig.mDrawable.getConstantState().newDrawable(res);
             } else {
-                mDrawable = or.mDrawable.getConstantState().newDrawable();
+                mDrawable = orig.mDrawable.getConstantState().newDrawable();
             }
             mDrawable.setCallback(owner);
-            mDrawable.setLayoutDirection(or.mDrawable.getLayoutDirection());
-            mThemeAttrs = or.mThemeAttrs;
-            mInsetL = or.mInsetL;
-            mInsetT = or.mInsetT;
-            mInsetR = or.mInsetR;
-            mInsetB = or.mInsetB;
-            mId = or.mId;
+            mDrawable.setLayoutDirection(orig.mDrawable.getLayoutDirection());
+            mDrawable.setBounds(orig.mDrawable.getBounds());
+            mDrawable.setLevel(orig.mDrawable.getLevel());
+            mThemeAttrs = orig.mThemeAttrs;
+            mInsetL = orig.mInsetL;
+            mInsetT = orig.mInsetT;
+            mInsetR = orig.mInsetR;
+            mInsetB = orig.mInsetB;
+            mId = orig.mId;
         }
     }
 
diff --git a/graphics/java/android/graphics/drawable/RippleDrawable.java b/graphics/java/android/graphics/drawable/RippleDrawable.java
index ca32751f..7402bdb 100644
--- a/graphics/java/android/graphics/drawable/RippleDrawable.java
+++ b/graphics/java/android/graphics/drawable/RippleDrawable.java
@@ -33,7 +33,6 @@
 import android.graphics.Rect;
 import android.util.AttributeSet;
 import android.util.DisplayMetrics;
-import android.util.Log;
 
 import com.android.internal.R;
 
@@ -41,6 +40,7 @@
 import org.xmlpull.v1.XmlPullParserException;
 
 import java.io.IOException;
+import java.util.Arrays;
 
 /**
  * Drawable that shows a ripple effect in response to state changes. The
@@ -88,7 +88,6 @@
  * @attr ref android.R.styleable#RippleDrawable_color
  */
 public class RippleDrawable extends LayerDrawable {
-    private static final String LOG_TAG = RippleDrawable.class.getSimpleName();
     private static final PorterDuffXfermode DST_IN = new PorterDuffXfermode(Mode.DST_IN);
     private static final PorterDuffXfermode SRC_ATOP = new PorterDuffXfermode(Mode.SRC_ATOP);
     private static final PorterDuffXfermode SRC_OVER = new PorterDuffXfermode(Mode.SRC_OVER);
@@ -215,10 +214,14 @@
         final Ripple[] ripples = mAnimatingRipples;
         for (int i = 0; i < count; i++) {
             ripples[i].jump();
-            ripples[i] = null;
+        }
+        if (ripples != null) {
+            Arrays.fill(ripples, 0, count, null);
         }
         mAnimatingRipplesCount = 0;
         mClearingHotspots = false;
+
+        invalidateSelf();
     }
 
     @Override
@@ -549,6 +552,15 @@
         mAnimatingRipples[mAnimatingRipplesCount++] = mRipple;
     }
 
+    @Override
+    public void invalidateSelf() {
+        // Don't invalidate when we're clearing hotspots. We'll handle that
+        // manually when we're done.
+        if (!mClearingHotspots) {
+            super.invalidateSelf();
+        }
+    }
+
     private void removeRipple() {
         if (mRipple != null) {
             mRipple.exit();
@@ -572,7 +584,9 @@
         final Ripple[] ripples = mAnimatingRipples;
         for (int i = 0; i < count; i++) {
             ripples[i].cancel();
-            ripples[i] = null;
+        }
+        if (ripples != null) {
+            Arrays.fill(ripples, 0, count, null);
         }
         mAnimatingRipplesCount = 0;
         mClearingHotspots = false;
@@ -680,7 +694,7 @@
             final int count = mAnimatingRipplesCount;
             final int index = getRippleIndex(ripple);
             if (index >= 0) {
-                System.arraycopy(ripples, index + 1, ripples, index + 1 - 1, count - (index + 1));
+                System.arraycopy(ripples, index + 1, ripples, index, count - (index + 1));
                 ripples[count - 1] = null;
                 mAnimatingRipplesCount--;
                 invalidateSelf();
diff --git a/graphics/java/android/graphics/drawable/RotateDrawable.java b/graphics/java/android/graphics/drawable/RotateDrawable.java
index 63b9e02..70482a6 100644
--- a/graphics/java/android/graphics/drawable/RotateDrawable.java
+++ b/graphics/java/android/graphics/drawable/RotateDrawable.java
@@ -507,21 +507,23 @@
         private boolean mCanConstantState;
         private boolean mCheckedConstantState;
 
-        public RotateState(RotateState source, RotateDrawable owner, Resources res) {
-            if (source != null) {
+        public RotateState(RotateState orig, RotateDrawable owner, Resources res) {
+            if (orig != null) {
                 if (res != null) {
-                    mDrawable = source.mDrawable.getConstantState().newDrawable(res);
+                    mDrawable = orig.mDrawable.getConstantState().newDrawable(res);
                 } else {
-                    mDrawable = source.mDrawable.getConstantState().newDrawable();
+                    mDrawable = orig.mDrawable.getConstantState().newDrawable();
                 }
                 mDrawable.setCallback(owner);
-                mDrawable.setLayoutDirection(source.mDrawable.getLayoutDirection());
-                mPivotXRel = source.mPivotXRel;
-                mPivotX = source.mPivotX;
-                mPivotYRel = source.mPivotYRel;
-                mPivotY = source.mPivotY;
-                mFromDegrees = mCurrentDegrees = source.mFromDegrees;
-                mToDegrees = source.mToDegrees;
+                mDrawable.setLayoutDirection(orig.mDrawable.getLayoutDirection());
+                mDrawable.setBounds(orig.mDrawable.getBounds());
+                mDrawable.setLevel(orig.mDrawable.getLevel());
+                mPivotXRel = orig.mPivotXRel;
+                mPivotX = orig.mPivotX;
+                mPivotYRel = orig.mPivotYRel;
+                mPivotY = orig.mPivotY;
+                mFromDegrees = mCurrentDegrees = orig.mFromDegrees;
+                mToDegrees = orig.mToDegrees;
                 mCanConstantState = mCheckedConstantState = true;
             }
         }
diff --git a/graphics/java/android/graphics/drawable/ScaleDrawable.java b/graphics/java/android/graphics/drawable/ScaleDrawable.java
index a954474..b40038a 100644
--- a/graphics/java/android/graphics/drawable/ScaleDrawable.java
+++ b/graphics/java/android/graphics/drawable/ScaleDrawable.java
@@ -295,6 +295,8 @@
                 }
                 mDrawable.setCallback(owner);
                 mDrawable.setLayoutDirection(orig.mDrawable.getLayoutDirection());
+                mDrawable.setBounds(orig.mDrawable.getBounds());
+                mDrawable.setLevel(orig.mDrawable.getLevel());
                 mScaleWidth = orig.mScaleWidth;
                 mScaleHeight = orig.mScaleHeight;
                 mGravity = orig.mGravity;
diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java
index dae539b..bce4074 100644
--- a/media/java/android/media/AudioService.java
+++ b/media/java/android/media/AudioService.java
@@ -4290,7 +4290,8 @@
         if ((state == 0) && ((device & mBecomingNoisyIntentDevices) != 0)) {
             int devices = 0;
             for (int dev : mConnectedDevices.keySet()) {
-                if ((dev & mBecomingNoisyIntentDevices) != 0) {
+                if (((dev & AudioSystem.DEVICE_BIT_IN) == 0) &&
+                        ((dev & mBecomingNoisyIntentDevices) != 0)) {
                    devices |= dev;
                 }
             }
diff --git a/media/java/android/media/SoundPool.java b/media/java/android/media/SoundPool.java
index 9b9c767..4f74bdd 100644
--- a/media/java/android/media/SoundPool.java
+++ b/media/java/android/media/SoundPool.java
@@ -151,6 +151,10 @@
 
         /**
          * Constructs a new Builder with the defaults format values.
+         * If not provided, the maximum number of streams is 1 (see {@link #setMaxStreams(int)} to
+         * change it), and the audio attributes have a usage value of
+         * {@link AudioAttributes#USAGE_MEDIA} (see {@link #setAudioAttributes(AudioAttributes)} to
+         * change them).
          */
         public Builder() {
         }
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java
index b6bb578..cc50c43 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java
@@ -245,7 +245,7 @@
          * android.hardware.camera2.CaptureResultExtras)
          */
         @Override
-        public void onCameraError(int errorCode, CaptureResultExtras resultExtras)
+        public void onDeviceError(int errorCode, CaptureResultExtras resultExtras)
                 throws RemoteException {
             // TODO Auto-generated method stub
 
@@ -283,7 +283,7 @@
          * @see android.hardware.camera2.ICameraDeviceCallbacks#onCameraIdle()
          */
         @Override
-        public void onCameraIdle() throws RemoteException {
+        public void onDeviceIdle() throws RemoteException {
             // TODO Auto-generated method stub
 
         }
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java
index 7b2e7dd..3cae19d 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java
@@ -88,10 +88,10 @@
         /*
          * (non-Javadoc)
          * @see
-         * android.hardware.camera2.ICameraDeviceCallbacks#onCameraError(int,
+         * android.hardware.camera2.ICameraDeviceCallbacks#onDeviceError(int,
          * android.hardware.camera2.CaptureResultExtras)
          */
-        public void onCameraError(int errorCode, CaptureResultExtras resultExtras)
+        public void onDeviceError(int errorCode, CaptureResultExtras resultExtras)
                 throws RemoteException {
             // TODO Auto-generated method stub
 
@@ -99,9 +99,9 @@
 
         /*
          * (non-Javadoc)
-         * @see android.hardware.camera2.ICameraDeviceCallbacks#onCameraIdle()
+         * @see android.hardware.camera2.ICameraDeviceCallbacks#onDeviceIdle()
          */
-        public void onCameraIdle() throws RemoteException {
+        public void onDeviceIdle() throws RemoteException {
             // TODO Auto-generated method stub
 
         }
@@ -432,7 +432,7 @@
         // Cancel and make sure we eventually quiesce
         status = mCameraUser.cancelRequest(streamingId, null);
 
-        verify(mMockCb, timeout(WAIT_FOR_IDLE_TIMEOUT_MS).times(1)).onCameraIdle();
+        verify(mMockCb, timeout(WAIT_FOR_IDLE_TIMEOUT_MS).times(1)).onDeviceIdle();
 
         // Submit a few capture requests
         int requestId1 = submitCameraRequest(request, /* streaming */false);
@@ -442,7 +442,7 @@
         int requestId5 = submitCameraRequest(request, /* streaming */false);
 
         // And wait for more idle
-        verify(mMockCb, timeout(WAIT_FOR_IDLE_TIMEOUT_MS).times(2)).onCameraIdle();
+        verify(mMockCb, timeout(WAIT_FOR_IDLE_TIMEOUT_MS).times(2)).onDeviceIdle();
 
     }
 
@@ -472,7 +472,7 @@
         status = mCameraUser.flush(null);
         assertEquals(CameraBinderTestUtils.NO_ERROR, status);
 
-        verify(mMockCb, timeout(WAIT_FOR_FLUSH_TIMEOUT_MS).times(1)).onCameraIdle();
+        verify(mMockCb, timeout(WAIT_FOR_FLUSH_TIMEOUT_MS).times(1)).onDeviceIdle();
 
         // Now a streaming request
         int streamingId = submitCameraRequest(request, /* streaming */true);
@@ -484,7 +484,7 @@
         status = mCameraUser.flush(null);
         assertEquals(CameraBinderTestUtils.NO_ERROR, status);
 
-        verify(mMockCb, timeout(WAIT_FOR_FLUSH_TIMEOUT_MS).times(2)).onCameraIdle();
+        verify(mMockCb, timeout(WAIT_FOR_FLUSH_TIMEOUT_MS).times(2)).onDeviceIdle();
 
         // TODO: When errors are hooked up, count that errors + successful
         // requests equal to 5.
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index e940b18..c84edf7 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -123,10 +123,10 @@
     <!-- The min animation duration for animating views that are newly visible. -->
     <integer name="recents_filter_animate_new_views_duration">250</integer>
     <!-- The min animation duration for animating the task bar in. -->
-    <integer name="recents_animate_task_bar_enter_duration">275</integer>
+    <integer name="recents_animate_task_bar_enter_duration">225</integer>
     <!-- The animation delay for animating the first task in. This should roughly be the animation
      duration of the transition in to recents. -->
-    <integer name="recents_animate_task_bar_enter_delay">300</integer>
+    <integer name="recents_animate_task_bar_enter_delay">275</integer>
     <!-- The min animation duration for animating the task bar out. -->
     <integer name="recents_animate_task_exit_to_home_duration">225</integer>
     <!-- The min animation duration for animating the task bar out. -->
@@ -143,6 +143,8 @@
     <integer name="recents_nav_bar_scrim_enter_duration">400</integer>
     <!-- The animation duration for animating the removal of a task view. -->
     <integer name="recents_animate_task_view_remove_duration">250</integer>
+    <!-- The animation duration for scrolling the stack to a particular item. -->
+    <integer name="recents_animate_task_stack_scroll_duration">225</integer>
     <!-- The minimum alpha for the dim applied to cards that go deeper into the stack. -->
     <integer name="recents_max_task_stack_view_dim">96</integer>
     <!-- The delay to enforce between each alt-tab key press. -->
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index bc941ca..5555aa7 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -195,17 +195,14 @@
     <!-- The size of the application icon in the recents task view. -->
     <dimen name="recents_task_view_application_icon_size">48dp</dimen>
 
-    <!-- The size of the activity icon in the recents task view. -->
-    <dimen name="recents_task_view_activity_icon_size">60dp</dimen>
-
     <!-- The radius of the rounded corners on a task view. -->
     <dimen name="recents_task_view_rounded_corners_radius">2dp</dimen>
 
     <!-- The min translation in the Z index for the last task. -->
-    <dimen name="recents_task_view_z_min">25dp</dimen>
+    <dimen name="recents_task_view_z_min">20dp</dimen>
 
     <!-- The max translation in the Z index for the last task. -->
-    <dimen name="recents_task_view_z_max">100dp</dimen>
+    <dimen name="recents_task_view_z_max">80dp</dimen>
 
     <!-- The amount to translate when animating the removal of a task. -->
     <dimen name="recents_task_view_remove_anim_translation_x">100dp</dimen>
@@ -231,6 +228,9 @@
     <!-- The side padding for the task stack as a percentage of the width. -->
     <item name="recents_stack_width_padding_percentage" format="float" type="dimen">0.04444</item>
 
+    <!-- The overscroll percentage allowed on the stack. -->
+    <item name="recents_stack_overscroll_percentage" format="float" type="dimen">0.0875</item>
+
     <!-- The top offset for the task stack. -->
     <dimen name="recents_stack_top_padding">16dp</dimen>
 
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index b39fe24..70f6031 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -33,8 +33,7 @@
         <item name="android:navigationBarColor">@android:color/transparent</item>
         <item name="android:windowDrawsSystemBarBackgrounds">true</item>
         <item name="android:windowAnimationStyle">@style/Animation.RecentsActivity</item>
-
-        <item name="android:ambientShadowAlpha">0.30</item>
+        <item name="android:ambientShadowAlpha">0.35</item>
     </style>
 
     <!-- Animations for a non-full-screen window or activity. -->
diff --git a/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java b/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java
index 0b36bdbd..d328660 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java
@@ -22,7 +22,6 @@
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
-import android.content.pm.ActivityInfo;
 import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.graphics.Bitmap;
@@ -36,7 +35,6 @@
 import com.android.systemui.RecentsComponent;
 import com.android.systemui.recents.misc.Console;
 import com.android.systemui.recents.misc.SystemServicesProxy;
-import com.android.systemui.recents.misc.Utilities;
 import com.android.systemui.recents.model.RecentsTaskLoader;
 import com.android.systemui.recents.model.Task;
 import com.android.systemui.recents.model.TaskGrouping;
@@ -99,6 +97,7 @@
     long mLastToggleTime;
 
     public AlternateRecentsComponent(Context context) {
+        RecentsTaskLoader.initialize(context);
         Resources res = context.getResources();
         mContext = context;
         mSystemServicesProxy = new SystemServicesProxy(context);
@@ -176,8 +175,9 @@
     }
 
     void showRelativeAffiliatedTask(boolean showNextTask) {
-        TaskStack stack = RecentsTaskLoader.getShallowTaskStack(mSystemServicesProxy,
-                Integer.MAX_VALUE, mContext.getResources());
+        RecentsTaskLoader loader = RecentsTaskLoader.getInstance();
+        TaskStack stack = loader.getTaskStack(mSystemServicesProxy, mContext.getResources(),
+                -1, -1, false, null, null);
         // Return early if there are no tasks
         if (stack.getTaskCount() == 0) return;
 
@@ -385,16 +385,8 @@
                 toTask);
         if (toTransform != null && toTask.key != null) {
             Rect toTaskRect = toTransform.rect;
-            ActivityInfo info = mSystemServicesProxy.getActivityInfo(
-                    toTask.key.baseIntent.getComponent(), toTask.key.userId);
-            if (toTask.activityIcon == null) {
-                toTask.activityIcon = mSystemServicesProxy.getActivityIcon(info,
-                        toTask.key.userId);
-            }
-            if (toTask.activityLabel == null) {
-                toTask.activityLabel = mSystemServicesProxy.getActivityLabel(info);
-            }
 
+            // XXX: Reduce the memory usage the to the task bar height
             Bitmap thumbnail = Bitmap.createBitmap(toTaskRect.width(), toTaskRect.height(),
                     Bitmap.Config.ARGB_8888);
             if (Constants.DebugFlags.App.EnableTransitionThumbnailDebugMode) {
@@ -420,8 +412,9 @@
     TaskViewTransform getThumbnailTransitionTransform(int runningTaskId, boolean isTopTaskHome,
                                                       Task runningTaskOut) {
         // Get the stack of tasks that we are animating into
-        TaskStack stack = RecentsTaskLoader.getShallowTaskStack(mSystemServicesProxy, -1,
-                mContext.getResources());
+        RecentsTaskLoader loader = RecentsTaskLoader.getInstance();
+        TaskStack stack = loader.getTaskStack(mSystemServicesProxy, mContext.getResources(),
+                runningTaskId, -1, false, null, null);
         if (stack.getTaskCount() == 0) {
             return null;
         }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
index a5b845d..2f9715f 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
@@ -343,7 +343,6 @@
         super.onCreate(savedInstanceState);
 
         // Initialize the loader and the configuration
-        RecentsTaskLoader.initialize(this);
         mConfig = RecentsConfiguration.reinitialize(this,
                 RecentsTaskLoader.getInstance().getSystemServicesProxy());
 
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
index 9803687..5d8181c 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
@@ -67,9 +67,11 @@
     public int searchBarSpaceHeightPx;
 
     /** Task stack */
+    public int taskStackScrollDuration;
     public int taskStackMaxDim;
     public int taskStackTopPaddingPx;
     public float taskStackWidthPaddingPct;
+    public float taskStackOverscrollPct;
 
     /** Task view animation and styles */
     public int taskViewEnterFromHomeDuration;
@@ -195,9 +197,14 @@
         searchBarAppWidgetId = settings.getInt(Constants.Values.App.Key_SearchAppWidgetId, -1);
 
         // Task stack
+        taskStackScrollDuration =
+                res.getInteger(R.integer.recents_animate_task_stack_scroll_duration);
         TypedValue widthPaddingPctValue = new TypedValue();
         res.getValue(R.dimen.recents_stack_width_padding_percentage, widthPaddingPctValue, true);
         taskStackWidthPaddingPct = widthPaddingPctValue.getFloat();
+        TypedValue stackOverscrollPctValue = new TypedValue();
+        res.getValue(R.dimen.recents_stack_overscroll_percentage, stackOverscrollPctValue, true);
+        taskStackOverscrollPct = stackOverscrollPctValue.getFloat();
         taskStackMaxDim = res.getInteger(R.integer.recents_max_task_stack_view_dim);
         taskStackTopPaddingPx = res.getDimensionPixelSize(R.dimen.recents_stack_top_padding);
 
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsPackageMonitor.java b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsPackageMonitor.java
index 31011ae..60e89bf 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsPackageMonitor.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsPackageMonitor.java
@@ -16,7 +16,6 @@
 
 package com.android.systemui.recents.model;
 
-import android.app.ActivityManager;
 import android.content.ComponentName;
 import android.content.Context;
 import android.os.Looper;
@@ -36,7 +35,7 @@
     }
 
     PackageCallbacks mCb;
-    List<ActivityManager.RecentTaskInfo> mTasks;
+    List<Task.TaskKey> mTasks;
     SystemServicesProxy mSystemServicesProxy;
 
     /** Registers the broadcast receivers with the specified callbacks. */
@@ -64,7 +63,7 @@
     }
 
     /** Sets the list of tasks to match against package broadcast changes. */
-    void setTasks(List<ActivityManager.RecentTaskInfo> tasks) {
+    void setTasks(List<Task.TaskKey> tasks) {
         mTasks = tasks;
     }
 
@@ -75,7 +74,7 @@
         // Identify all the tasks that should be removed as a result of the package being removed.
         // Using a set to ensure that we callback once per unique component.
         HashSet<ComponentName> componentsToRemove = new HashSet<ComponentName>();
-        for (ActivityManager.RecentTaskInfo t : mTasks) {
+        for (Task.TaskKey t : mTasks) {
             ComponentName cn = t.baseIntent.getComponent();
             if (cn.getPackageName().equals(packageName)) {
                 componentsToRemove.add(cn);
@@ -99,7 +98,7 @@
         // Using a set to ensure that we callback once per unique component.
         HashSet<ComponentName> componentsKnownToExist = new HashSet<ComponentName>();
         HashSet<ComponentName> componentsToRemove = new HashSet<ComponentName>();
-        for (ActivityManager.RecentTaskInfo t : mTasks) {
+        for (Task.TaskKey t : mTasks) {
             ComponentName cn = t.baseIntent.getComponent();
             if (cn.getPackageName().equals(packageName)) {
                 if (componentsKnownToExist.contains(cn)) {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java
index b93c126..a93e244 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java
@@ -35,11 +35,16 @@
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
-import java.util.LinkedHashSet;
+import java.util.HashMap;
 import java.util.List;
 import java.util.concurrent.ConcurrentLinkedQueue;
 
 
+/** Handle to an ActivityInfo */
+class ActivityInfoHandle {
+    ActivityInfo info;
+}
+
 /** A bitmap load queue */
 class TaskResourceLoadQueue {
     ConcurrentLinkedQueue<Task> mQueue = new ConcurrentLinkedQueue<Task>();
@@ -230,7 +235,6 @@
     static RecentsTaskLoader sInstance;
 
     SystemServicesProxy mSystemServicesProxy;
-    DrawableLruCache mTaskDescriptionIconCache;
     DrawableLruCache mApplicationIconCache;
     BitmapLruCache mThumbnailCache;
     StringLruCache mActivityLabelCache;
@@ -274,7 +278,6 @@
         mSystemServicesProxy = new SystemServicesProxy(context);
         mPackageMonitor = new RecentsPackageMonitor();
         mLoadQueue = new TaskResourceLoadQueue();
-        mTaskDescriptionIconCache = new DrawableLruCache(iconCacheSize);
         mApplicationIconCache = new DrawableLruCache(iconCacheSize);
         mThumbnailCache = new BitmapLruCache(thumbnailCacheSize);
         mActivityLabelCache = new StringLruCache(100);
@@ -301,103 +304,151 @@
     }
 
     /** Gets the list of recent tasks, ordered from back to front. */
-    private static List<ActivityManager.RecentTaskInfo> getRecentTasks(SystemServicesProxy ssp,
-            int numTasks) {
-        // Set a default number of tasks to query if none is provided
-        if (numTasks < 0) {
-            RecentsConfiguration config = RecentsConfiguration.getInstance();
-            numTasks = config.maxNumTasksToLoad;
-        }
+    private static List<ActivityManager.RecentTaskInfo> getRecentTasks(SystemServicesProxy ssp) {
+        RecentsConfiguration config = RecentsConfiguration.getInstance();
         List<ActivityManager.RecentTaskInfo> tasks =
-                ssp.getRecentTasks(numTasks, UserHandle.CURRENT.getIdentifier());
+                ssp.getRecentTasks(config.maxNumTasksToLoad,
+                        UserHandle.CURRENT.getIdentifier());
         Collections.reverse(tasks);
         return tasks;
     }
 
+    /** Returns the activity icon using as many cached values as we can. */
+    public Drawable getAndUpdateActivityIcon(Task.TaskKey taskKey,
+             ActivityManager.TaskDescription td, SystemServicesProxy ssp,
+             Resources res, ActivityInfoHandle infoHandle, boolean preloadTask) {
+        // Return the cached activity icon if it exists
+        Drawable icon = mApplicationIconCache.getAndInvalidateIfModified(taskKey);
+        if (icon != null) {
+            return icon;
+        }
+        // Return the task description icon if it exists
+        if (td != null && td.getIcon() != null) {
+            icon = ssp.getBadgedIcon(new BitmapDrawable(res, td.getIcon()), taskKey.userId);
+            mApplicationIconCache.put(taskKey, icon);
+            return icon;
+        }
+        // If we are preloading this task, continue to load the activity icon
+        if (preloadTask) {
+            // All short paths failed, load the icon from the activity info and cache it
+            if (infoHandle.info == null) {
+                infoHandle.info = ssp.getActivityInfo(taskKey.baseIntent.getComponent(),
+                        taskKey.userId);
+            }
+            icon = ssp.getActivityIcon(infoHandle.info, taskKey.userId);
+            mApplicationIconCache.put(taskKey, icon);
+            return icon;
+        }
+        // If we are not preloading, return the default icon to show
+        return null;
+    }
+
+    /** Returns the activity label using as many cached values as we can. */
+    public String getAndUpdateActivityLabel(Task.TaskKey taskKey,
+            ActivityManager.TaskDescription td, SystemServicesProxy ssp,
+            ActivityInfoHandle infoHandle) {
+        // Return the task description label if it exists
+        if (td != null && td.getLabel() != null) {
+            return td.getLabel();
+        }
+        // Return the cached activity label if it exists
+        String label = mActivityLabelCache.getAndInvalidateIfModified(taskKey);
+        if (label != null) {
+            return label;
+        }
+        // All short paths failed, load the label from the activity info and cache it
+        if (infoHandle.info == null) {
+            infoHandle.info = ssp.getActivityInfo(taskKey.baseIntent.getComponent(),
+                    taskKey.userId);
+        }
+        label = ssp.getActivityLabel(infoHandle.info);
+        mActivityLabelCache.put(taskKey, label);
+        return label;
+    }
+
+    /** Returns the activity's primary color. */
+    public int getActivityPrimaryColor(ActivityManager.TaskDescription td,
+            RecentsConfiguration config) {
+        if (td != null && td.getPrimaryColor() != 0) {
+            return td.getPrimaryColor();
+        }
+        return config.taskBarViewDefaultBackgroundColor;
+    }
+
     /** Reload the set of recent tasks */
     public SpaceNode reload(Context context, int preloadCount) {
-        RecentsConfiguration config = RecentsConfiguration.getInstance();
-        Resources res = context.getResources();
-        LinkedHashSet<Task> tasksToLoad = new LinkedHashSet<Task>();
-        ArrayList<Task> tasksToAdd = new ArrayList<Task>();
-        TaskStack stack = new TaskStack();
+        ArrayList<Task.TaskKey> taskKeys = new ArrayList<Task.TaskKey>();
+        ArrayList<Task> tasksToLoad = new ArrayList<Task>();
+        TaskStack stack = getTaskStack(mSystemServicesProxy, context.getResources(),
+                -1, preloadCount, true, taskKeys, tasksToLoad);
         SpaceNode root = new SpaceNode();
         root.setStack(stack);
 
-        // Get the recent tasks
-        SystemServicesProxy ssp = mSystemServicesProxy;
-        List<ActivityManager.RecentTaskInfo> tasks = getRecentTasks(ssp, -1);
+        // Start the task loader and add all the tasks we need to load
+        mLoader.start(context);
+        mLoadQueue.addTasks(tasksToLoad);
 
-        // From back to front, add each task to the task stack
+        // Update the package monitor with the list of packages to listen for
+        mPackageMonitor.setTasks(taskKeys);
+
+        return root;
+    }
+
+    /** Creates a lightweight stack of the current recent tasks, without thumbnails and icons. */
+    public TaskStack getTaskStack(SystemServicesProxy ssp, Resources res,
+            int preloadTaskId, int preloadTaskCount,
+            boolean loadTaskThumbnails, List<Task.TaskKey> taskKeysOut,
+            List<Task> tasksToLoadOut) {
+        RecentsConfiguration config = RecentsConfiguration.getInstance();
+        List<ActivityManager.RecentTaskInfo> tasks = getRecentTasks(ssp);
+        HashMap<ComponentName, ActivityInfoHandle> activityInfoCache =
+                new HashMap<ComponentName, ActivityInfoHandle>();
+        ArrayList<Task> tasksToAdd = new ArrayList<Task>();
+        TaskStack stack = new TaskStack();
+
         int taskCount = tasks.size();
         for (int i = 0; i < taskCount; i++) {
             ActivityManager.RecentTaskInfo t = tasks.get(i);
+
+            // Get an existing activity info handle if possible
+            ComponentName cn = t.baseIntent.getComponent();
+            ActivityInfoHandle infoHandle = new ActivityInfoHandle();
+            boolean hasCachedActivityInfo = false;
+            if (activityInfoCache.containsKey(cn)) {
+                infoHandle = activityInfoCache.get(cn);
+                hasCachedActivityInfo = true;
+            }
+
+            // Compose the task key
             Task.TaskKey taskKey = new Task.TaskKey(t.persistentId, t.baseIntent, t.userId,
                     t.firstActiveTime, t.lastActiveTime);
-            ComponentName cn = t.baseIntent.getComponent();
-            ActivityInfo info = null;
 
-            ActivityManager.TaskDescription av = t.taskDescription;
-            String activityLabel  = null;
-            Drawable activityIcon = mDefaultApplicationIcon;
-            int activityColor = config.taskBarViewDefaultBackgroundColor;
-            boolean loadedActivityIcon = false;
-            if (av != null) {
-                activityLabel = av.getLabel();
-                activityIcon = mTaskDescriptionIconCache.getAndInvalidateIfModified(taskKey);
-                if (activityIcon == null) {
-                    activityIcon = (av.getIcon() != null) ?
-                        ssp.getBadgedIcon(new BitmapDrawable(res, av.getIcon()), t.userId) : null;
-                    if (activityIcon != null) {
-                        mTaskDescriptionIconCache.put(taskKey, activityIcon);
-                    }
-                }
-                if (av.getPrimaryColor() != 0) {
-                    activityColor = av.getPrimaryColor();
-                }
-                loadedActivityIcon = (activityIcon != null);
-            }
-            // If there is no activity label, then try and read it from the label cache before
-            // loading it from the system
-            if (activityLabel == null) {
-                activityLabel = mActivityLabelCache.getAndInvalidateIfModified(taskKey);
-                if (activityLabel == null) {
-                    if (info == null) {
-                        info = ssp.getActivityInfo(cn, t.userId);
-                    }
-                    activityLabel = ssp.getActivityLabel(info);
-                    mActivityLabelCache.put(taskKey, activityLabel);
-                }
+            // Determine whether to preload this task
+            boolean preloadTask = false;
+            if (preloadTaskId > 0) {
+                preloadTask = (t.id == preloadTaskId);
+            } else if (preloadTaskCount > 0) {
+                preloadTask = (i >= (taskCount - preloadTaskCount));
             }
 
-            // Create a new task
+            // Load the label, icon, and color
+            String activityLabel  = getAndUpdateActivityLabel(taskKey, t.taskDescription,
+                    ssp, infoHandle);
+            Drawable activityIcon = getAndUpdateActivityIcon(taskKey, t.taskDescription,
+                    ssp, res, infoHandle, preloadTask);
+            int activityColor = getActivityPrimaryColor(t.taskDescription, config);
+
+            // Update the activity info cache
+            if (!hasCachedActivityInfo && infoHandle.info != null) {
+                activityInfoCache.put(cn, infoHandle);
+            }
+
+            // Add the task to the stack
             Task task = new Task(taskKey, (t.id > -1), t.affiliatedTaskId, t.affiliatedTaskColor,
                     activityLabel, activityIcon, activityColor, (i == (taskCount - 1)),
                     config.lockToAppEnabled);
 
-            // Preload the specified number of apps
-            if (i >= (taskCount - preloadCount)) {
-                // Load the icon from the cache if possible (only if we don't have an activity icon)
-                if (!loadedActivityIcon) {
-                    task.applicationIcon =
-                            mApplicationIconCache.getAndInvalidateIfModified(taskKey);
-                    if (task.applicationIcon == null) {
-                        // Load the icon from the system
-                        if (info == null) {
-                            info = ssp.getActivityInfo(cn, t.userId);
-                        }
-                        task.applicationIcon = ssp.getActivityIcon(info, taskKey.userId);
-                        if (task.applicationIcon != null) {
-                            mApplicationIconCache.put(taskKey, task.applicationIcon);
-                        }
-                    }
-                    if (task.applicationIcon == null) {
-                        // Either the task has changed since the last active time, or it was not
-                        // previously cached, so try and load the task anew.
-                        tasksToLoad.add(task);
-                    }
-                }
-
+            if (preloadTask && loadTaskThumbnails) {
                 // Load the thumbnail from the cache if possible
                 task.thumbnail = mThumbnailCache.getAndInvalidateIfModified(taskKey);
                 if (task.thumbnail == null) {
@@ -408,54 +459,20 @@
                         mThumbnailCache.put(taskKey, task.thumbnail);
                     }
                 }
-                if (task.thumbnail == null) {
+                if (task.thumbnail == null && tasksToLoadOut != null) {
                     // Either the task has changed since the last active time, or it was not
                     // previously cached, so try and load the task anew.
-                    tasksToLoad.add(task);
+                    tasksToLoadOut.add(task);
                 }
             }
 
+            // Add to the list of task keys
+            if (taskKeysOut != null) {
+                taskKeysOut.add(taskKey);
+            }
             // Add the task to the stack
             tasksToAdd.add(task);
         }
-
-        // Simulate the groupings that we describe
-        stack.setTasks(tasksToAdd);
-        stack.createAffiliatedGroupings(config);
-
-        // Start the task loader and add all the tasks we need to load
-        mLoader.start(context);
-        mLoadQueue.addTasks(tasksToLoad);
-
-        // Update the package monitor with the list of packages to listen for
-        mPackageMonitor.setTasks(tasks);
-
-        return root;
-    }
-
-    /** Creates a lightweight stack of the current recent tasks, without thumbnails and icons. */
-    public static TaskStack getShallowTaskStack(SystemServicesProxy ssp, int numTasks,
-            Resources resources) {
-        RecentsConfiguration config = RecentsConfiguration.getInstance();
-        List<ActivityManager.RecentTaskInfo> tasks = getRecentTasks(ssp, numTasks);
-        ArrayList<Task> tasksToAdd = new ArrayList<Task>();
-        TaskStack stack = new TaskStack();
-
-        int taskCount = tasks.size();
-        for (int i = 0; i < taskCount; i++) {
-            ActivityManager.RecentTaskInfo t = tasks.get(i);
-            ActivityManager.TaskDescription av = t.taskDescription;
-
-            BitmapDrawable icon = null;
-            if (av.getIcon() != null) {
-                icon = new BitmapDrawable(resources, av.getIcon());
-            }
-            Task.TaskKey taskKey = new Task.TaskKey(t.persistentId, t.baseIntent, t.userId,
-                    t.firstActiveTime, t.lastActiveTime);
-            tasksToAdd.add(new Task(taskKey, true, t.affiliatedTaskId, t.affiliatedTaskColor,
-                    av.getLabel(), icon, av.getPrimaryColor(), (i == (taskCount - 1)),
-                    config.lockToAppEnabled));
-        }
         stack.setTasks(tasksToAdd);
         stack.createAffiliatedGroupings(config);
         return stack;
@@ -525,21 +542,18 @@
                 // We are leaving recents, so trim the data a bit
                 mThumbnailCache.trimToSize(mMaxThumbnailCacheSize / 2);
                 mApplicationIconCache.trimToSize(mMaxIconCacheSize / 2);
-                mTaskDescriptionIconCache.trimToSize(mMaxIconCacheSize / 2);
                 break;
             case ComponentCallbacks2.TRIM_MEMORY_RUNNING_LOW:
             case ComponentCallbacks2.TRIM_MEMORY_MODERATE:
                 // We are going to be low on memory
                 mThumbnailCache.trimToSize(mMaxThumbnailCacheSize / 4);
                 mApplicationIconCache.trimToSize(mMaxIconCacheSize / 4);
-                mTaskDescriptionIconCache.trimToSize(mMaxIconCacheSize / 4);
                 break;
             case ComponentCallbacks2.TRIM_MEMORY_RUNNING_CRITICAL:
             case ComponentCallbacks2.TRIM_MEMORY_COMPLETE:
                 // We are low on memory, so release everything
                 mThumbnailCache.evictAll();
                 mApplicationIconCache.evictAll();
-                mTaskDescriptionIconCache.evictAll();
                 // The cache is small, only clear the label cache when we are critical
                 mActivityLabelCache.evictAll();
                 break;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/AnimateableViewBounds.java b/packages/SystemUI/src/com/android/systemui/recents/views/AnimateableViewBounds.java
index 34f73c6..d6889d0 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/AnimateableViewBounds.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/AnimateableViewBounds.java
@@ -33,6 +33,8 @@
     Rect mClipRect = new Rect();
     Rect mOutlineClipRect = new Rect();
     int mCornerRadius;
+    float mAlpha = 1f;
+    final float mMinAlpha = 0.25f;
 
     ObjectAnimator mClipTopAnimator;
     ObjectAnimator mClipRightAnimator;
@@ -51,6 +53,7 @@
 
     @Override
     public void getOutline(View view, Outline outline) {
+        outline.setAlpha(mMinAlpha + mAlpha / (1f - mMinAlpha));
         outline.setRoundRect(Math.max(mClipRect.left, mOutlineClipRect.left),
                 Math.max(mClipRect.top, mOutlineClipRect.top),
                 mSourceView.getMeasuredWidth() - Math.max(mClipRect.right, mOutlineClipRect.right),
@@ -58,6 +61,14 @@
                 mCornerRadius);
     }
 
+    /** Sets the view outline alpha. */
+    void setAlpha(float alpha) {
+        if (Float.compare(alpha, mAlpha) != 0) {
+            mAlpha = alpha;
+            mSourceView.invalidateOutline();
+        }
+    }
+
     /** Animates the top clip. */
     void animateClipTop(int top, int duration, ValueAnimator.AnimatorUpdateListener updateListener) {
         if (mClipTopAnimator != null) {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
index 47fda5b..1ac3bc3 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
@@ -477,10 +477,10 @@
             if (!task.group.isFrontMostTask(task)) {
                 // For affiliated tasks that are behind other tasks, we must animate the front cards
                 // out of view before starting the task transition
-                stackView.startLaunchTaskAnimation(tv, launchRunnable);
+                stackView.startLaunchTaskAnimation(tv, launchRunnable, lockToTask);
             } else {
                 // Otherwise, we can start the task transition immediately
-                stackView.startLaunchTaskAnimation(tv, null);
+                stackView.startLaunchTaskAnimation(tv, null, lockToTask);
                 postDelayed(launchRunnable, 17);
             }
         }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/SwipeHelper.java b/packages/SystemUI/src/com/android/systemui/recents/views/SwipeHelper.java
index e0298ab..fa44551 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/SwipeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/SwipeHelper.java
@@ -28,6 +28,7 @@
 import android.view.VelocityTracker;
 import android.view.View;
 import android.view.animation.LinearInterpolator;
+import com.android.systemui.recents.RecentsConfiguration;
 
 /**
  * This class facilitates swipe to dismiss. It defines an interface to be implemented by the
@@ -50,7 +51,7 @@
     private int DEFAULT_ESCAPE_ANIMATION_DURATION = 75; // ms
     private int MAX_ESCAPE_ANIMATION_DURATION = 150; // ms
     private int MAX_DISMISS_VELOCITY = 2000; // dp/sec
-    private static final int SNAP_ANIM_LEN = SLOW_ANIMATIONS ? 1000 : 150; // ms
+    private static final int SNAP_ANIM_LEN = SLOW_ANIMATIONS ? 1000 : 250; // ms
 
     public static float ALPHA_FADE_START = 0.15f; // fraction of thumbnail width
                                                  // where fade starts
@@ -265,6 +266,7 @@
         ValueAnimator anim = createTranslationAnimation(view, 0);
         int duration = SNAP_ANIM_LEN;
         anim.setDuration(duration);
+        anim.setInterpolator(RecentsConfiguration.getInstance().linearOutSlowInInterpolator);
         anim.addUpdateListener(new AnimatorUpdateListener() {
             @Override
             public void onAnimationUpdate(ValueAnimator animation) {
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 861011f..dbed136 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
@@ -105,7 +105,7 @@
         mFilterAlgorithm = new TaskStackViewFilterAlgorithm(mConfig, this, mViewPool);
         mStackScroller = new TaskStackViewScroller(context, mConfig, mLayoutAlgorithm);
         mStackScroller.setCallbacks(this);
-        mTouchHandler = new TaskStackViewTouchHandler(context, this, mStackScroller);
+        mTouchHandler = new TaskStackViewTouchHandler(context, this, mConfig, mStackScroller);
         mUIDozeTrigger = new DozeTrigger(mConfig.taskBarDismissDozeDelaySeconds, new Runnable() {
             @Override
             public void run() {
@@ -647,17 +647,17 @@
     }
 
     /** Animates a task view in this stack as it launches. */
-    public void startLaunchTaskAnimation(TaskView tv, final Runnable r) {
+    public void startLaunchTaskAnimation(TaskView tv, Runnable r, boolean lockToTask) {
         Task launchTargetTask = tv.getTask();
         int childCount = getChildCount();
         for (int i = 0; i < childCount; i++) {
             TaskView t = (TaskView) getChildAt(i);
             if (t == tv) {
-                t.startLaunchTaskAnimation(r, true, true);
+                t.startLaunchTaskAnimation(r, true, true, lockToTask);
             } else {
                 boolean occludesLaunchTarget = launchTargetTask.group.isTaskAboveTask(t.getTask(),
                         launchTargetTask);
-                t.startLaunchTaskAnimation(null, false, occludesLaunchTarget);
+                t.startLaunchTaskAnimation(null, false, occludesLaunchTarget, lockToTask);
             }
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewScroller.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewScroller.java
index 2c0dc44..5852b88 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewScroller.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewScroller.java
@@ -133,12 +133,8 @@
         stopBoundScrollAnimation();
 
         mScrollAnimator = ObjectAnimator.ofFloat(this, "stackScroll", curScroll, newScroll);
-        mScrollAnimator.setDuration(200);
-        // We would have to project the difference into the screen coords, and then use that as the
-        // duration
-//        mScrollAnimator.setDuration(Utilities.calculateTranslationAnimationDuration(newScroll -
-//                curScroll, 250));
-        mScrollAnimator.setInterpolator(mConfig.fastOutSlowInInterpolator);
+        mScrollAnimator.setDuration(mConfig.taskStackScrollDuration);
+        mScrollAnimator.setInterpolator(mConfig.linearOutSlowInInterpolator);
         mScrollAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
             @Override
             public void onAnimationUpdate(ValueAnimator animation) {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java
index 374a27f..8f9b4c2 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java
@@ -23,11 +23,13 @@
 import android.view.ViewConfiguration;
 import android.view.ViewParent;
 import com.android.systemui.recents.Constants;
+import com.android.systemui.recents.RecentsConfiguration;
 
 /* Handles touch events for a TaskStackView. */
 class TaskStackViewTouchHandler implements SwipeHelper.Callback {
     static int INACTIVE_POINTER_ID = -1;
 
+    RecentsConfiguration mConfig;
     TaskStackView mSv;
     TaskStackViewScroller mScroller;
     VelocityTracker mVelocityTracker;
@@ -52,7 +54,8 @@
     SwipeHelper mSwipeHelper;
     boolean mInterceptedBySwipeHelper;
 
-    public TaskStackViewTouchHandler(Context context, TaskStackView sv, TaskStackViewScroller scroller) {
+    public TaskStackViewTouchHandler(Context context, TaskStackView sv,
+            RecentsConfiguration config, TaskStackViewScroller scroller) {
         ViewConfiguration configuration = ViewConfiguration.get(context);
         mMinimumVelocity = configuration.getScaledMinimumFlingVelocity();
         mMaximumVelocity = configuration.getScaledMaximumFlingVelocity();
@@ -60,6 +63,7 @@
         mPagingTouchSlop = configuration.getScaledPagingTouchSlop();
         mSv = sv;
         mScroller = scroller;
+        mConfig = config;
 
         float densityScale = context.getResources().getDisplayMetrics().density;
         mSwipeHelper = new SwipeHelper(SwipeHelper.X, this, densityScale, mPagingTouchSlop);
@@ -258,7 +262,7 @@
                     if (Float.compare(overScrollAmount, 0f) != 0) {
                         // Bound the overscroll to a fixed amount, and inversely scale the y-movement
                         // relative to how close we are to the max overscroll
-                        float maxOverScroll = 0.25f;
+                        float maxOverScroll = mConfig.taskStackOverscrollPct;
                         deltaP *= (1f - (Math.min(maxOverScroll, overScrollAmount)
                                 / maxOverScroll));
                     }
@@ -280,7 +284,6 @@
                 velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);
                 int velocity = (int) velocityTracker.getYVelocity(mActivePointerId);
                 if (mIsScrolling && (Math.abs(velocity) > mMinimumVelocity)) {
-                    // XXX: Should this be calculated as a percentage of a curve?
                     int overscrollRange = (int) (Math.min(1f,
                             Math.abs((float) velocity / mMaximumVelocity)) *
                             Constants.Values.TaskStackView.TaskStackOverscrollRange);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
index dfbcce1..eecc170 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
@@ -471,7 +471,7 @@
 
     /** Animates this task view as it exits recents */
     void startLaunchTaskAnimation(final Runnable postAnimRunnable, boolean isLaunchingTask,
-            boolean occludesLaunchTarget) {
+            boolean occludesLaunchTarget, boolean lockToTask) {
         if (isLaunchingTask) {
             // Disable the thumbnail clip
             mThumbnailView.disableTaskBarClip();
@@ -487,11 +487,14 @@
             }
 
             // Animate the action button away
-            float toScale = 0.9f;
+            if (!lockToTask) {
+                float toScale = 0.9f;
+                mActionButtonView.animate()
+                        .scaleX(toScale)
+                        .scaleY(toScale);
+            }
             mActionButtonView.animate()
                     .alpha(0f)
-                    .scaleX(toScale)
-                    .scaleY(toScale)
                     .setStartDelay(0)
                     .setDuration(mConfig.taskBarExitAnimDuration)
                     .setInterpolator(mConfig.fastOutLinearInInterpolator)
@@ -621,6 +624,7 @@
     /** Sets the current task progress. */
     public void setTaskProgress(float p) {
         mTaskProgress = p;
+        mViewBounds.setAlpha(p);
         updateDimFromTaskProgress();
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
index e6eca22..8b4c2c4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
@@ -202,7 +202,7 @@
     }
 
     public void setDark(boolean dark, boolean fade) {
-        if (mDark == dark) return;
+        if (mDark == dark || mContractedChild == null) return;
         mDark = dark;
         setImageViewDark(dark, fade, com.android.internal.R.id.right_icon);
         setImageViewDark(dark, fade, com.android.internal.R.id.icon);
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index 5a836c8..e382a9f 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -545,6 +545,7 @@
     private static final int MSG_DISPATCH_SHOW_RECENTS = 9;
     private static final int MSG_DISPATCH_SHOW_GLOBAL_ACTIONS = 10;
     private static final int MSG_HIDE_BOOT_MESSAGE = 11;
+    private static final int MSG_LAUNCH_VOICE_ASSIST_WITH_WAKE_LOCK = 12;
 
     private class PolicyHandler extends Handler {
         @Override
@@ -590,6 +591,9 @@
                 case MSG_HIDE_BOOT_MESSAGE:
                     handleHideBootMessage();
                     break;
+                case MSG_LAUNCH_VOICE_ASSIST_WITH_WAKE_LOCK:
+                    launchVoiceAssistWithWakeLock(msg.arg1 != 0);
+                    break;
             }
         }
     }
@@ -2342,11 +2346,11 @@
         } else if (keyCode == KeyEvent.KEYCODE_VOICE_ASSIST) {
             if (!down) {
                 Intent voiceIntent;
-                if (!keyguardOn && mPowerManager.isInteractive()) {
+                if (!keyguardOn) {
                     voiceIntent = new Intent(RecognizerIntent.ACTION_WEB_SEARCH);
                 } else {
                     voiceIntent = new Intent(RecognizerIntent.ACTION_VOICE_SEARCH_HANDS_FREE);
-                    voiceIntent.putExtra(RecognizerIntent.EXTRA_SECURE, keyguardOn);
+                    voiceIntent.putExtra(RecognizerIntent.EXTRA_SECURE, true);
                 }
                 mContext.startActivityAsUser(voiceIntent, UserHandle.CURRENT_OR_SELF);
             }
@@ -4445,6 +4449,19 @@
                 }
                 break;
             }
+            case KeyEvent.KEYCODE_VOICE_ASSIST: {
+                // Only do this if we would otherwise not pass it to the user. In that case,
+                // interceptKeyBeforeDispatching would apply a similar but different policy in
+                // order to invoke voice assist actions. Note that we need to make a copy of the
+                // key event here because the original key event will be recycled when we return.
+                if ((result & ACTION_PASS_TO_USER) == 0 && !down) {
+                    mBroadcastWakeLock.acquire();
+                    Message msg = mHandler.obtainMessage(MSG_LAUNCH_VOICE_ASSIST_WITH_WAKE_LOCK,
+                            keyguardActive ? 1 : 0, 0);
+                    msg.setAsynchronous(true);
+                    msg.sendToTarget();
+                }
+            }
         }
 
         if (useHapticFeedback) {
@@ -4551,6 +4568,14 @@
         }
     }
 
+    void launchVoiceAssistWithWakeLock(boolean keyguardActive) {
+        Intent voiceIntent =
+            new Intent(RecognizerIntent.ACTION_VOICE_SEARCH_HANDS_FREE);
+        voiceIntent.putExtra(RecognizerIntent.EXTRA_SECURE, keyguardActive);
+        mContext.startActivityAsUser(voiceIntent, UserHandle.CURRENT_OR_SELF);
+        mBroadcastWakeLock.release();
+    }
+
     BroadcastReceiver mDockReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java
index 9674ca2..de5e7cb 100644
--- a/services/backup/java/com/android/server/backup/BackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/BackupManagerService.java
@@ -1963,8 +1963,9 @@
         return packages;
     }
 
-    // Called from the backup task: record that the given app has been successfully
-    // backed up at least once
+    // Called from the backup tasks: record that the given app has been successfully
+    // backed up at least once.  This includes both key/value and full-data backups
+    // through the transport.
     void logBackupComplete(String packageName) {
         if (packageName.equals(PACKAGE_MANAGER_SENTINEL)) return;
 
@@ -3837,6 +3838,7 @@
                         // Success!
                         EventLog.writeEvent(EventLogTags.FULL_BACKUP_SUCCESS,
                                 currentPackage.packageName);
+                        logBackupComplete(currentPackage.packageName);
                     }
                     cleanUpPipes(transportPipes);
                     cleanUpPipes(enginePipes);
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 972a86d..6ca536c 100755
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -3816,6 +3816,11 @@
      * of affiliations.
      */
     void cleanupRecentTasksLocked(int userId) {
+        if (mRecentTasks == null) {
+            // Happens when called from the packagemanager broadcast before boot.
+            return;
+        }
+
         final HashMap<ComponentName, ActivityInfo> availActCache = new HashMap<>();
         final HashMap<String, ApplicationInfo> availAppCache = new HashMap<>();
         final IPackageManager pm = AppGlobals.getPackageManager();
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 5093f97..89878ef 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -11051,34 +11051,34 @@
             Slog.w(TAG, "Attempt to delete null packageName.");
             return false;
         }
-        PackageParser.Package p;
+        PackageParser.Package pkg;
         boolean dataOnly = false;
         final int appId;
         synchronized (mPackages) {
-            p = mPackages.get(packageName);
-            if (p == null) {
+            pkg = mPackages.get(packageName);
+            if (pkg == null) {
                 dataOnly = true;
                 PackageSetting ps = mSettings.mPackages.get(packageName);
                 if ((ps == null) || (ps.pkg == null)) {
                     Slog.w(TAG, "Package named '" + packageName + "' doesn't exist.");
                     return false;
                 }
-                p = ps.pkg;
+                pkg = ps.pkg;
             }
             if (!dataOnly) {
                 // need to check this only for fully installed applications
-                if (p == null) {
+                if (pkg == null) {
                     Slog.w(TAG, "Package named '" + packageName + "' doesn't exist.");
                     return false;
                 }
-                final ApplicationInfo applicationInfo = p.applicationInfo;
+                final ApplicationInfo applicationInfo = pkg.applicationInfo;
                 if (applicationInfo == null) {
                     Slog.w(TAG, "Package " + packageName + " has no applicationInfo.");
                     return false;
                 }
             }
-            if (p != null && p.applicationInfo != null) {
-                appId = p.applicationInfo.uid;
+            if (pkg != null && pkg.applicationInfo != null) {
+                appId = pkg.applicationInfo.uid;
             } else {
                 appId = -1;
             }
@@ -11090,6 +11090,19 @@
             return false;
         }
         removeKeystoreDataIfNeeded(userId, appId);
+
+        // Create a native library symlink only if we have native libraries
+        // and if the native libraries are 32 bit libraries. We do not provide
+        // this symlink for 64 bit libraries.
+        if (pkg != null && pkg.applicationInfo.primaryCpuAbi != null &&
+                !VMRuntime.is64BitAbi(pkg.applicationInfo.primaryCpuAbi)) {
+            final String nativeLibPath = pkg.applicationInfo.nativeLibraryDir;
+            if (mInstaller.linkNativeLibraryDirectory(pkg.packageName, nativeLibPath, userId) < 0) {
+                Slog.w(TAG, "Failed linking native library dir");
+                return false;
+            }
+        }
+
         return true;
     }
 
@@ -12914,6 +12927,17 @@
                     Bundle extras) throws RemoteException {
                 Slog.d(TAG, "Install result for move: "
                         + PackageManager.installStatusToString(returnCode, msg));
+
+                // We usually have a new package now after the install, but if
+                // we failed we need to clear the pending flag on the original
+                // package object.
+                synchronized (mPackages) {
+                    final PackageParser.Package pkg = mPackages.get(packageName);
+                    if (pkg != null) {
+                        pkg.mOperationPending = false;
+                    }
+                }
+
                 final int status = PackageManager.installStatusToPublicStatus(returnCode);
                 switch (status) {
                     case PackageInstaller.STATUS_SUCCESS:
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index ad87993..8ded7ca 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -1576,6 +1576,7 @@
                     String valType = parser.getAttributeValue(null, ATTR_VALUE_TYPE);
                     String multiple = parser.getAttributeValue(null, ATTR_MULTIPLE);
                     if (multiple != null) {
+                        values.clear();
                         int count = Integer.parseInt(multiple);
                         while (count > 0 && (type = parser.next()) != XmlPullParser.END_DOCUMENT) {
                             if (type == XmlPullParser.START_TAG
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 09c4e20..9ceac41 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -41,11 +41,11 @@
 
     void addAppToken(int addPos, AppWindowToken wtoken) {
         final int lastPos = mAppTokens.size();
-        if (addPos > lastPos) {
-            // We lost an app token. Don't crash though.
-            Slog.e(TAG, "Task.addAppToken: Out of bounds attempt token=" + wtoken + " addPos="
-                    + addPos + " lastPos=" + lastPos);
-            addPos = lastPos;
+        for (int pos = 0; pos < lastPos && pos < addPos; ++pos) {
+            if (mAppTokens.get(pos).removed) {
+                // addPos assumes removed tokens are actually gone.
+                ++addPos;
+            }
         }
         mAppTokens.add(addPos, wtoken);
         mDeferRemoval = false;
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index e144bde..c70cb22 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -2382,7 +2382,6 @@
             origId = Binder.clearCallingIdentity();
 
             if (addToken) {
-                Slog.w("BadTokenDebug", "addWindow: Adding token=" + token + " attrs.token=" + attrs.token);
                 mTokenMap.put(attrs.token, token);
             }
             win.attach();
@@ -2664,9 +2663,7 @@
                 + token.windows.size());
         if (token.windows.size() == 0) {
             if (!token.explicit) {
-                WindowToken wtoken = mTokenMap.remove(token.token);
-                Slog.w("BadTokenDebug", "removeWindowInnerLocked: Removing token=" + token + " removed=" +
-                        wtoken + " Callers=" + Debug.getCallers(4));
+                mTokenMap.remove(token.token);
             } else if (atoken != null) {
                 atoken.firstWindowDrawn = false;
             }
@@ -3452,7 +3449,6 @@
                 return;
             }
             wtoken = new WindowToken(this, token, type, true);
-            Slog.w("BadTokenDebug", "addWindowToken: Adding token=" + token + " wtoken=" + wtoken);
             mTokenMap.put(token, wtoken);
             if (type == TYPE_WALLPAPER) {
                 mWallpaperTokens.add(wtoken);
@@ -3471,8 +3467,6 @@
         synchronized(mWindowMap) {
             DisplayContent displayContent = null;
             WindowToken wtoken = mTokenMap.remove(token);
-            Slog.w("BadTokenDebug", "removeWindowToken: Removing token=" + token + " removed=" + wtoken
-                    + " Callers=" + Debug.getCallers(3));
             if (wtoken != null) {
                 boolean delayed = false;
                 if (!wtoken.hidden) {
@@ -3589,7 +3583,6 @@
                 task.addAppToken(addPos, atoken);
             }
 
-            Slog.w("BadTokenDebug", "addAppToken: Adding token=" + token.asBinder() + " atoken=" + atoken);
             mTokenMap.put(token.asBinder(), atoken);
 
             // Application tokens start out hidden.
@@ -4689,7 +4682,6 @@
         final long origId = Binder.clearCallingIdentity();
         synchronized(mWindowMap) {
             WindowToken basewtoken = mTokenMap.remove(token);
-            Slog.w("BadTokenDebug", "removeAppToke: Removing token=" + token + " removed=" + basewtoken);
             if (basewtoken != null && (wtoken=basewtoken.appWindowToken) != null) {
                 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "Removing app token: " + wtoken);
                 delayed = setTokenVisibilityLocked(wtoken, null, false,