Merge "Implement new multi-user affordance."
diff --git a/api/current.txt b/api/current.txt
index 89261b2..164d601 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -25788,6 +25788,7 @@
     method public static boolean isatty(java.io.FileDescriptor);
     method public static void kill(int, int) throws android.system.ErrnoException;
     method public static void lchown(java.lang.String, int, int) throws android.system.ErrnoException;
+    method public static void link(java.lang.String, java.lang.String) throws android.system.ErrnoException;
     method public static void listen(java.io.FileDescriptor, int) throws android.system.ErrnoException;
     method public static long lseek(java.io.FileDescriptor, long, int) throws android.system.ErrnoException;
     method public static android.system.StructStat lstat(java.lang.String) throws android.system.ErrnoException;
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 66b82eb..b4b3c99 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -3618,13 +3618,15 @@
         }
 
         // Get the primary color and update the RecentsActivityValues for this activity
-        TypedArray a = getTheme().obtainStyledAttributes(com.android.internal.R.styleable.Theme);
-        int colorPrimary = a.getColor(com.android.internal.R.styleable.Theme_colorPrimary, 0);
-        a.recycle();
-        if (colorPrimary != 0) {
-            ActivityManager.RecentsActivityValues v = new ActivityManager.RecentsActivityValues();
-            v.colorPrimary = colorPrimary;
-            setRecentsActivityValues(v);
+        if (theme != null) {
+            TypedArray a = theme.obtainStyledAttributes(com.android.internal.R.styleable.Theme);
+            int colorPrimary = a.getColor(com.android.internal.R.styleable.Theme_colorPrimary, 0);
+            a.recycle();
+            if (colorPrimary != 0) {
+                ActivityManager.RecentsActivityValues v = new ActivityManager.RecentsActivityValues();
+                v.colorPrimary = colorPrimary;
+                setRecentsActivityValues(v);
+            }
         }
     }
 
diff --git a/docs/html/guide/topics/resources/string-resource.jd b/docs/html/guide/topics/resources/string-resource.jd
index 5a96ba1..e2326ec 100644
--- a/docs/html/guide/topics/resources/string-resource.jd
+++ b/docs/html/guide/topics/resources/string-resource.jd
@@ -20,9 +20,6 @@
 information about styling and formatting strings, see the section about <a
 href="#FormattingAndStyling">Formatting and Styling</a>.</p>
 
-
-
-
 <h2 id="String">String</h2>
 
 <p>A single string that can be referenced from the application or from other resource files (such
@@ -433,7 +430,7 @@
 
 
 
-<h3>Styling with HTML markup</h3>
+<h3 id="StylingWithHTML">Styling with HTML markup</h3>
 
 <p>You can add styling to your strings with HTML markup. For example:</p>
 <pre>
@@ -497,5 +494,107 @@
 CharSequence styledText = Html.fromHtml(text);
 </pre>
 
+<h2 id="StylingWithSpannables">Styling with Spannables</h2>
+<p>
+A {@link android.text.Spannable} is a text object that you can style with
+typeface properties such as color and font weight. You use
+{@link android.text.SpannableStringBuilder} to build
+your text and then apply styles defined in the {@link android.text.style}
+package to the text.
+</p>
 
+<p>You can use the following helper methods to set up much of the work
+of creating spannable text:</p>
 
+<pre style="pretty-print">
+/**
+ * Returns a CharSequence that concatenates the specified array of CharSequence
+ * objects and then applies a list of zero or more tags to the entire range.
+ *
+ * @param content an array of character sequences to apply a style to
+ * @param tags the styled span objects to apply to the content
+ *        such as android.text.style.StyleSpan
+ *
+ */
+private static CharSequence apply(CharSequence[] content, Object... tags) {
+    SpannableStringBuilder text = new SpannableStringBuilder();
+    openTags(text, tags);
+    for (CharSequence item : content) {
+        text.append(item);
+    }
+    closeTags(text, tags);
+    return text;
+}
+
+/**
+ * Iterates over an array of tags and applies them to the beginning of the specified
+ * Spannable object so that future text appended to the text will have the styling
+ * applied to it. Do not call this method directly.
+ */
+private static void openTags(Spannable text, Object[] tags) {
+    for (Object tag : tags) {
+        text.setSpan(tag, 0, 0, Spannable.SPAN_MARK_MARK);
+    }
+}
+
+/**
+ * "Closes" the specified tags on a Spannable by updating the spans to be
+ * endpoint-exclusive so that future text appended to the end will not take
+ * on the same styling. Do not call this method directly.
+ */
+private static void closeTags(Spannable text, Object[] tags) {
+    int len = text.length();
+    for (Object tag : tags) {
+        if (len > 0) {
+            text.setSpan(tag, 0, len, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+        } else {
+            text.removeSpan(tag);
+        }
+    }
+}
+</pre>
+
+<p>
+The following <code>bold</code>, <code>italic</code>, and <code>color</code>
+methods show you how to call the helper methods to apply
+styles defined in the {@link android.text.style} package. You
+can create similar methods to do other types of text styling.
+</p>
+
+<pre style="pretty-print">
+/**
+ * Returns a CharSequence that applies boldface to the concatenation
+ * of the specified CharSequence objects.
+ */
+public static CharSequence bold(CharSequence... content) {
+    return apply(content, new StyleSpan(Typeface.BOLD));
+}
+
+/**
+ * Returns a CharSequence that applies italics to the concatenation
+ * of the specified CharSequence objects.
+ */
+public static CharSequence italic(CharSequence... content) {
+    return apply(content, new StyleSpan(Typeface.ITALIC));
+}
+
+/**
+ * Returns a CharSequence that applies a foreground color to the
+ * concatenation of the specified CharSequence objects.
+ */
+public static CharSequence color(int color, CharSequence... content) {
+    return apply(content, new ForegroundColorSpan(color));
+}
+</pre>
+
+<p>
+Here's an example of how to chain these methods to create a character sequence
+with different types of styling applied to individual words:
+</p>
+
+<pre style="pretty-print">
+// Create an italic "hello, " a red "world",
+// and bold the entire sequence.
+CharSequence text = bold(italic(res.getString(R.string.hello)),
+    color(Color.RED, res.getString(R.string.world)));
+</pre>
\ No newline at end of file
diff --git a/docs/html/wear/images/notif_summary_framed.png b/docs/html/wear/images/notif_summary_framed.png
new file mode 100644
index 0000000..17b1703
--- /dev/null
+++ b/docs/html/wear/images/notif_summary_framed.png
Binary files differ
diff --git a/docs/html/wear/notifications/stacks.jd b/docs/html/wear/notifications/stacks.jd
index 7f955f6..a2d34ce 100644
--- a/docs/html/wear/notifications/stacks.jd
+++ b/docs/html/wear/notifications/stacks.jd
@@ -2,8 +2,8 @@
 
 @jd:body
 
-<img src="{@docRoot}wear/images/11_bundles_B.png" height="200" width="169" style="float:right;margin:0 0 20px 40px" />
-<img src="{@docRoot}wear/images/11_bundles_A.png" height="200" width="169" style="float:right;margin:0 0 20px 40px" />
+<img src="{@docRoot}wear/images/11_bundles_B.png" height="200" width="169" style="float:right;margin:0 0 20px 40px" alt="" />
+<img src="{@docRoot}wear/images/11_bundles_A.png" height="200" width="169" style="float:right;margin:0 0 20px 40px" alt="" />
 
 <p>When creating notifications for a handheld device, you should always aggregate similar
 notifications into a single summary notification. For example, if your app creates notifications
@@ -29,20 +29,44 @@
 
 <p>To create a stack, call <a
 href="{@docRoot}reference/android/preview/support/wearable/notifications/WearableNotifications.Builder.html#setGroup(java.lang.String, int)">
-<code>setGroup()</code></a> for each notification you want in the stack, passing the same
-group key. For example:</p>
+<code>setGroup()</code></a> for each notification you want in the stack and specify a
+group key. Then call <a href="{@docRoot}reference/android/preview/support/v4/app/NotificationManagerCompat.html#notify(int, android.app.Notification)"><code>notify()</code></a> to send it to the wearable.</p>
 
 <pre style="clear:right">
 final static String GROUP_KEY_EMAILS = "group_key_emails";
 
+// Build the notification and pass this builder to WearableNotifications.Builder
 NotificationCompat.Builder builder = new NotificationCompat.Builder(mContext)
-         .setContentTitle("New mail from " + sender)
-         .setContentText(subject)
+         .setContentTitle("New mail from " + sender1)
+         .setContentText(subject1)
          .setSmallIcon(R.drawable.new_mail);
 
-Notification notif = new WearableNotifications.Builder(builder)
+Notification notif1 = new WearableNotifications.Builder(builder)
          .setGroup(GROUP_KEY_EMAILS)
          .build();
+
+// Issue the notification
+NotificationManagerCompat notificationManager =
+        NotificationManagerCompat.from(this);
+notificationManager.notify(notificationId1, notif);
+</pre>
+
+<p>Later on, when you create another notification, specify
+the same group key. When you call <a href="{@docRoot}reference/android/preview/support/v4/app/NotificationManagerCompat.html#notify(int, android.app.Notification)"><code>notify()</code></a>, this notification appears
+in the same stack as the previous notification, instead of as a new card:</p>
+
+<pre style="clear:right">
+builder = new NotificationCompat.Builder(mContext)
+         .setContentTitle("New mail from " + sender2)
+         .setContentText(subject2)
+         .setSmallIcon(R.drawable.new_mail);
+
+// Use the same group as the previous notification
+Notification notif2 = new WearableNotifications.Builder(builder)
+         .setGroup(GROUP_KEY_EMAILS)
+         .build();
+
+notificationManager.notify(notificationId2, notif);
 </pre>
 
 <p>By default, notifications appear in the order in which you added them, with the most recent
@@ -54,19 +78,55 @@
 
 <h2 id="AddSummary">Add a Summary Notification</h2>
 
+<img src="{@docRoot}wear/images/notif_summary_framed.png" height="242" width="330" style="float:right;margin:0 0 20px 40px" alt="" />
+
 <p>It's important that you still provide a summary notification that appears on handheld devices.
 So in addition to adding each unique notification to the same stack group, also add a summary
 notification, but set its order position to be <a
 href="{@docRoot}reference/android/preview/support/wearable/notifications/WearableNotifications.html#GROUP_ORDER_SUMMARY"><code>GROUP_ORDER_SUMMARY</code></a>.</p>
 
-<pre>
-Notification summaryNotification = new WearableNotifications.Builder(builder)
-         .setGroup(GROUP_KEY_EMAILS, WearableNotifications.GROUP_ORDER_SUMMARY)
-         .build();
+<p>This notification does not appear in your stack of notifications on the wearable, but
+appears as the only notification on the handheld device.</p>
+
+<pre style="clear:right">
+Bitmap largeIcon = BitmapFactory.decodeResource(getResources(),
+        R.drawable.ic_large_icon);
+
+builder = new NotificationCompat.Builder(this)
+        .setSmallIcon(R.drawable.ic_small_icon)
+        .setLargeIcon(largeIcon);
+
+// Use the same group key and pass this builder to InboxStyle notification
+WearableNotifications.Builder wearableBuilder = new WearableNotifications
+        .Builder(builder)
+        .setGroup(GROUP_KEY_EMAILS,
+                WearableNotifications.GROUP_ORDER_SUMMARY);
+
+// Build the final notification to show on the handset
+Notification summaryNotification = new NotificationCompat.InboxStyle(
+        wearableBuilder.getCompatBuilder())
+        .addLine("Alex Faaborg   Check this out")
+        .addLine("Jeff Chang   Launch Party")
+        .setBigContentTitle("2 new messages")
+        .setSummaryText("johndoe@gmail.com")
+        .build();
+
+notificationManager.notify(notificationId3, summaryNotification);
 </pre>
 
-<p>This notification will not appear in your stack of notifications on the wearable, but
-appears as the only notification on the handheld device.
+<p>
+This notification uses {@link android.support.v4.app.NotificationCompat.InboxStyle},
+which gives you an easy way to create notifications for email or messaging apps.
+You can use this style, another one defined in {@link android.support.v4.app.NotificationCompat},
+or no style for the summary notification.
+</p>
 
+<p class="note"><b>Tip:</b>
+To style the text like in the example screenshot, see
+<a href="{@docRoot}guide/topics/resources/string-resource.html#StylingWithHTML">Styling
+with HTML markup</a> and
+<a href="{@docRoot}guide/topics/resources/string-resource.html#StylingWithSpannables">Styling
+with Spannables</a>.
+</p>
 </body>
-</html>
+</html>
\ No newline at end of file
diff --git a/libs/hwui/DisplayListRenderer.cpp b/libs/hwui/DisplayListRenderer.cpp
index 2391e80..a4bce3a 100644
--- a/libs/hwui/DisplayListRenderer.cpp
+++ b/libs/hwui/DisplayListRenderer.cpp
@@ -57,9 +57,6 @@
 }
 
 void DisplayListRenderer::setViewport(int width, int height) {
-    // TODO: DisplayListRenderer shouldn't have a projection matrix, as it should never be used
-    mProjectionMatrix.loadOrtho(0, width, height, 0, -1, 1);
-
     initializeViewport(width, height);
 }
 
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index 20b038d..091cdf4 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -171,7 +171,7 @@
 }
 
 void OpenGLRenderer::initViewport(int width, int height) {
-    mProjectionMatrix.loadOrtho(0, width, height, 0, -1, 1);
+    mSnapshot->orthoMatrix.loadOrtho(0, width, height, 0, -1, 1);
 
     initializeViewport(width, height);
 }
@@ -621,14 +621,13 @@
 ///////////////////////////////////////////////////////////////////////////////
 
 void OpenGLRenderer::onSnapshotRestored(const Snapshot& removed, const Snapshot& restored) {
-    bool restoreOrtho = removed.flags & Snapshot::kFlagDirtyOrtho;
+    bool restoreViewport = removed.flags & Snapshot::kFlagIsFboLayer;
     bool restoreClip = removed.flags & Snapshot::kFlagClipSet;
     bool restoreLayer = removed.flags & Snapshot::kFlagIsLayer;
 
-    if (restoreOrtho) {
+    if (restoreViewport) {
         const Rect& r = restored.viewport;
         glViewport(r.left, r.top, r.right, r.bottom);
-        mProjectionMatrix.load(removed.orthoMatrix); // TODO: should ortho be stored in 'restored'?
     }
 
     if (restoreClip) {
@@ -847,14 +846,12 @@
     layer->setFbo(mCaches.fboCache.get());
 
     mSnapshot->region = &mSnapshot->layer->region;
-    mSnapshot->flags |= Snapshot::kFlagFboTarget | Snapshot::kFlagIsFboLayer |
-            Snapshot::kFlagDirtyOrtho;
+    mSnapshot->flags |= Snapshot::kFlagFboTarget | Snapshot::kFlagIsFboLayer;
     mSnapshot->fbo = layer->getFbo();
     mSnapshot->resetTransform(-bounds.left, -bounds.top, 0.0f);
     mSnapshot->resetClip(clip.left, clip.top, clip.right, clip.bottom);
     mSnapshot->viewport.set(0.0f, 0.0f, bounds.getWidth(), bounds.getHeight());
     mSnapshot->height = bounds.getHeight();
-    mSnapshot->orthoMatrix.load(mProjectionMatrix);
 
     endTiling();
     debugOverdraw(false, false);
@@ -883,8 +880,7 @@
 
     // Change the ortho projection
     glViewport(0, 0, bounds.getWidth(), bounds.getHeight());
-
-    mProjectionMatrix.loadOrtho(0.0f, bounds.getWidth(), bounds.getHeight(), 0.0f, -1.0f, 1.0f);
+    mSnapshot->orthoMatrix.loadOrtho(0.0f, bounds.getWidth(), bounds.getHeight(), 0.0f, -1.0f, 1.0f);
 
     return true;
 }
@@ -1694,12 +1690,14 @@
     }
 
     bool dirty = right - left > 0.0f && bottom - top > 0.0f;
-    if (!ignoreTransform) {
-        mCaches.currentProgram->set(mProjectionMatrix, mModelViewMatrix, *currentTransform(), offset);
-        if (dirty && mTrackDirtyRegions) dirtyLayer(left, top, right, bottom, *currentTransform());
-    } else {
-        mCaches.currentProgram->set(mProjectionMatrix, mModelViewMatrix, mat4::identity(), offset);
-        if (dirty && mTrackDirtyRegions) dirtyLayer(left, top, right, bottom);
+    const Matrix4& transformMatrix = ignoreTransform ? Matrix4::identity() : *currentTransform();
+    mCaches.currentProgram->set(mSnapshot->orthoMatrix, mModelViewMatrix, transformMatrix, offset);
+    if (dirty && mTrackDirtyRegions) {
+        if (!ignoreTransform) {
+            dirtyLayer(left, top, right, bottom, *currentTransform());
+        } else {
+            dirtyLayer(left, top, right, bottom);
+        }
     }
 }
 
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
index 4f7f01e..d140428 100644
--- a/libs/hwui/OpenGLRenderer.h
+++ b/libs/hwui/OpenGLRenderer.h
@@ -930,9 +930,6 @@
      */
     Texture* getTexture(const SkBitmap* bitmap);
 
-    // Ortho matrix used for projection in shaders
-    mat4 mProjectionMatrix;
-
     /**
      * Model-view matrix used to position/size objects
      *
diff --git a/libs/hwui/Snapshot.cpp b/libs/hwui/Snapshot.cpp
index 6bfa203..b2df86f 100644
--- a/libs/hwui/Snapshot.cpp
+++ b/libs/hwui/Snapshot.cpp
@@ -55,6 +55,7 @@
         , empty(false)
         , viewport(s->viewport)
         , height(s->height)
+        , orthoMatrix(s->orthoMatrix)
         , alpha(s->alpha) {
 
     if (saveFlags & SkCanvas::kMatrix_SaveFlag) {
diff --git a/libs/hwui/Snapshot.h b/libs/hwui/Snapshot.h
index 038aea8..aede079 100644
--- a/libs/hwui/Snapshot.h
+++ b/libs/hwui/Snapshot.h
@@ -65,17 +65,16 @@
          * Indicates that this snapshot is a special type of layer
          * backed by an FBO. This flag only makes sense when the
          * flag kFlagIsLayer is also set.
+         *
+         * Viewport has been modified to fit the new Fbo, and must be
+         * restored when this snapshot is restored.
          */
         kFlagIsFboLayer = 0x4,
         /**
-         * Indicates that this snapshot has changed the ortho matrix.
-         */
-        kFlagDirtyOrtho = 0x8,
-        /**
          * Indicates that this snapshot or an ancestor snapshot is
          * an FBO layer.
          */
-        kFlagFboTarget = 0x10
+        kFlagFboTarget = 0x8,
     };
 
     /**
@@ -183,7 +182,7 @@
     int height;
 
     /**
-     * Contains the previous ortho matrix.
+     * Contains the current orthographic, projection matrix.
      */
     mat4 orthoMatrix;
 
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java b/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java
index b2b2bd8..9069a55 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java
@@ -436,6 +436,8 @@
         @Override
         public boolean onCreateActionMode(ActionMode mode, Menu menu) {
             mode.getMenuInflater().inflate(R.menu.mode_directory, menu);
+            mode.setTitle(getResources()
+                    .getString(R.string.mode_selected_count, mCurrentView.getCheckedItemCount()));
             return true;
         }
 
diff --git a/packages/SystemUI/res/drawable/recents_dismiss_dark.xml b/packages/SystemUI/res/drawable/recents_dismiss_dark.xml
new file mode 100644
index 0000000..c015cc8
--- /dev/null
+++ b/packages/SystemUI/res/drawable/recents_dismiss_dark.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:versionCode="1" >
+
+    <size
+        android:height="16dp"
+        android:width="16dp" />
+
+    <viewport
+        android:viewportHeight="100"
+        android:viewportWidth="100" />
+
+    <group>
+        <path
+            android:name="x"
+            android:pathData="M0,0L100,100M0,100L100,0z"
+            android:stroke="@color/recents_task_bar_dark_dismiss_color"
+            android:strokeWidth="8.0"
+            android:strokeLineCap="square" />
+    </group>
+</vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/recents_dismiss_light.xml b/packages/SystemUI/res/drawable/recents_dismiss_light.xml
new file mode 100644
index 0000000..9c93db9
--- /dev/null
+++ b/packages/SystemUI/res/drawable/recents_dismiss_light.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:versionCode="1" >
+
+    <size
+        android:height="16dp"
+        android:width="16dp" />
+
+    <viewport
+        android:viewportHeight="100"
+        android:viewportWidth="100" />
+
+    <group>
+        <path
+            android:name="x"
+            android:pathData="M0,0L100,100M0,100L100,0z"
+            android:stroke="@color/recents_task_bar_light_dismiss_color"
+            android:strokeWidth="8.0"
+            android:strokeLineCap="square" />
+    </group>
+</vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/recents_task_view.xml b/packages/SystemUI/res/layout/recents_task_view.xml
index f7df18eb..bda6431 100644
--- a/packages/SystemUI/res/layout/recents_task_view.xml
+++ b/packages/SystemUI/res/layout/recents_task_view.xml
@@ -63,6 +63,13 @@
             android:maxLines="2"
             android:ellipsize="marquee"
             android:fadingEdge="horizontal" />
+        <ImageView
+            android:id="@+id/dismiss_task"
+            android:layout_width="@dimen/recents_task_view_application_icon_size"
+            android:layout_height="@dimen/recents_task_view_application_icon_size"
+            android:layout_gravity="center_vertical|end"
+            android:padding="23dp"
+            android:src="@drawable/recents_dismiss_dark" />
     </com.android.systemui.recents.views.TaskBarView>
 </com.android.systemui.recents.views.TaskView>
 
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index c78ff8e..d23a3dc 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -52,10 +52,14 @@
     <!-- The default recents task bar background color. -->
     <color name="recents_task_bar_default_background_color">#e6444444</color>
     <!-- The default recents task bar text color. -->
-    <color name="recents_task_bar_default_text_color">#ffffffff</color>
+    <color name="recents_task_bar_default_text_color">#ffeeeeee</color>
     <!-- The recents task bar light text color to be drawn on top of dark backgrounds. -->
-    <color name="recents_task_bar_light_text_color">#ffffffff</color>
+    <color name="recents_task_bar_light_text_color">#ffeeeeee</color>
     <!-- The recents task bar dark text color to be drawn on top of light backgrounds. -->
     <color name="recents_task_bar_dark_text_color">#ff222222</color>
+    <!-- The recents task bar light dismiss icon color to be drawn on top of dark backgrounds. -->
+    <color name="recents_task_bar_light_dismiss_color">#ffeeeeee</color>
+    <!-- The recents task bar dark dismiss icon color to be drawn on top of light backgrounds. -->
+    <color name="recents_task_bar_dark_dismiss_color">#ff333333</color>
 
 </resources>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index c0376f0..21eb41c 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -119,7 +119,7 @@
     <!-- The animation duration for animating in the info pane. -->
     <integer name="recents_animate_task_view_info_pane_duration">150</integer>
     <!-- The animation duration for animating the removal of a task view. -->
-    <integer name="recents_animate_task_view_remove_duration">150</integer>
+    <integer name="recents_animate_task_view_remove_duration">250</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>
     <!-- Transposes the search bar layout in landscape -->
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 7c68600..f330b8e 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -227,7 +227,7 @@
     <dimen name="recents_task_view_z_increment">5dp</dimen>
 
     <!-- The amount to translate when animating the removal of a task. -->
-    <dimen name="recents_task_view_remove_anim_translation_x">75dp</dimen>
+    <dimen name="recents_task_view_remove_anim_translation_x">100dp</dimen>
 
     <!-- The amount of space a user has to scroll to dismiss any info panes. -->
     <dimen name="recents_task_stack_scroll_dismiss_info_pane_distance">50dp</dimen>
diff --git a/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java b/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java
index 3ef8316..19a1b11 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java
@@ -255,15 +255,10 @@
     /** Loads the first task thumbnail */
     Bitmap loadFirstTaskThumbnail() {
         SystemServicesProxy ssp = mSystemServicesProxy;
-        List<ActivityManager.RecentTaskInfo> tasks = ssp.getRecentTasks(1,
-                UserHandle.CURRENT.getIdentifier());
-        for (ActivityManager.RecentTaskInfo t : tasks) {
-            // Skip tasks in the home stack
-            if (ssp.isInHomeStack(t.persistentId)) {
-                return null;
-            }
+        List<ActivityManager.RunningTaskInfo> tasks = ssp.getRunningTasks(1);
 
-            return ssp.getTaskThumbnail(t.persistentId);
+        for (ActivityManager.RunningTaskInfo t : tasks) {
+            return ssp.getTaskThumbnail(t.id);
         }
         return null;
     }
@@ -286,17 +281,6 @@
         return (tasks.size() > 1);
     }
 
-    /** Returns whether the base intent of the top task stack was launched with the flag
-     * Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS. */
-    boolean isTopTaskExcludeFromRecents(List<ActivityManager.RecentTaskInfo> tasks) {
-        if (tasks.size() > 0) {
-            ActivityManager.RecentTaskInfo t = tasks.get(0);
-            Console.log(t.baseIntent.toString());
-            return (t.baseIntent.getFlags() & Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) != 0;
-        }
-        return false;
-    }
-
     /** Converts from the device rotation to the degree */
     float getDegreesForRotation(int value) {
         switch (value) {
@@ -416,16 +400,14 @@
         }
 
         // Otherwise, Recents is not the front-most activity and we should animate into it.  If
-        // the activity at the root of the top task stack is excluded from recents, or if that
-        // task stack is in the home stack, then we just do a simple transition.  Otherwise, we
-        // animate to the rects defined by the Recents service, which can differ depending on the
-        // number of items in the list.
+        // the activity at the root of the top task stack in the home stack, then we just do a
+        // simple transition.  Otherwise, we animate to the rects defined by the Recents service,
+        // which can differ depending on the number of items in the list.
         List<ActivityManager.RecentTaskInfo> recentTasks =
-                ssp.getRecentTasks(4, UserHandle.CURRENT.getIdentifier());
+                ssp.getRecentTasks(2, UserHandle.CURRENT.getIdentifier());
         Rect taskRect = hasMultipleRecentsTask(recentTasks) ? mMultipleCountFirstTaskRect :
                 mSingleCountFirstTaskRect;
-        boolean isTaskExcludedFromRecents = isTopTaskExcludeFromRecents(recentTasks);
-        boolean useThumbnailTransition = !isTopTaskHome && !isTaskExcludedFromRecents &&
+        boolean useThumbnailTransition = !isTopTaskHome &&
                 hasValidTaskRects();
 
         if (useThumbnailTransition) {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/BakedBezierInterpolator.java b/packages/SystemUI/src/com/android/systemui/recents/BakedBezierInterpolator.java
deleted file mode 100644
index 95ab8e8..0000000
--- a/packages/SystemUI/src/com/android/systemui/recents/BakedBezierInterpolator.java
+++ /dev/null
@@ -1,64 +0,0 @@
-package com.android.systemui.recents;
-
-import android.animation.TimeInterpolator;
-
-/**
- * A pre-baked bezier-curved interpolator for quantum-paper transitions.
- */
-public class BakedBezierInterpolator implements TimeInterpolator {
-    public static final BakedBezierInterpolator INSTANCE = new BakedBezierInterpolator();
-
-    /**
-     * Use the INSTANCE variable instead of instantiating.
-     */
-    private BakedBezierInterpolator() {
-        super();
-    }
-
-    /**
-     * Lookup table values.
-     * Generated using a Bezier curve from (0,0) to (1,1) with control points:
-     * P0 (0,0)
-     * P1 (0.4, 0)
-     * P2 (0.2, 1.0)
-     * P3 (1.0, 1.0)
-     *
-     * Values sampled with x at regular intervals between 0 and 1.
-     */
-    private static final float[] VALUES = new float[] {
-        0.0f, 0.0002f, 0.0009f, 0.0019f, 0.0036f, 0.0059f, 0.0086f, 0.0119f, 0.0157f, 0.0209f,
-        0.0257f, 0.0321f, 0.0392f, 0.0469f, 0.0566f, 0.0656f, 0.0768f, 0.0887f, 0.1033f, 0.1186f,
-        0.1349f, 0.1519f, 0.1696f, 0.1928f, 0.2121f, 0.237f, 0.2627f, 0.2892f, 0.3109f, 0.3386f,
-        0.3667f, 0.3952f, 0.4241f, 0.4474f, 0.4766f, 0.5f, 0.5234f, 0.5468f, 0.5701f, 0.5933f,
-        0.6134f, 0.6333f, 0.6531f, 0.6698f, 0.6891f, 0.7054f, 0.7214f, 0.7346f, 0.7502f, 0.763f,
-        0.7756f, 0.7879f, 0.8f, 0.8107f, 0.8212f, 0.8326f, 0.8415f, 0.8503f, 0.8588f, 0.8672f,
-        0.8754f, 0.8833f, 0.8911f, 0.8977f, 0.9041f, 0.9113f, 0.9165f, 0.9232f, 0.9281f, 0.9328f,
-        0.9382f, 0.9434f, 0.9476f, 0.9518f, 0.9557f, 0.9596f, 0.9632f, 0.9662f, 0.9695f, 0.9722f,
-        0.9753f, 0.9777f, 0.9805f, 0.9826f, 0.9847f, 0.9866f, 0.9884f, 0.9901f, 0.9917f, 0.9931f,
-        0.9944f, 0.9955f, 0.9964f, 0.9973f, 0.9981f, 0.9986f, 0.9992f, 0.9995f, 0.9998f, 1.0f, 1.0f
-    };
-
-    private static final float STEP_SIZE = 1.0f / (VALUES.length - 1);
-
-    @Override
-    public float getInterpolation(float input) {
-        if (input >= 1.0f) {
-            return 1.0f;
-        }
-
-        if (input <= 0f) {
-            return 0f;
-        }
-
-        int position = Math.min(
-                (int)(input * (VALUES.length - 1)),
-                VALUES.length - 2);
-
-        float quantized = position * STEP_SIZE;
-        float difference = input - quantized;
-        float weight = difference / STEP_SIZE;
-
-        return VALUES[position] + weight * (VALUES[position + 1] - VALUES[position]);
-    }
-
-}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/Constants.java b/packages/SystemUI/src/com/android/systemui/recents/Constants.java
index 1d6a76c..90998da 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/Constants.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/Constants.java
@@ -32,7 +32,7 @@
             // Enables the use of theme colors as the task bar background
             public static final boolean EnableTaskBarThemeColors = true;
             // Enables the info pane on long-press
-            public static final boolean EnableInfoPane = true;
+            public static final boolean EnableInfoPane = false;
             // Enables the search bar layout
             public static final boolean EnableSearchLayout = true;
             // Enables the dynamic shadows behind each task
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
index 463cf74..9afc1cb 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
@@ -23,6 +23,8 @@
 import android.graphics.Rect;
 import android.util.DisplayMetrics;
 import android.util.TypedValue;
+import android.view.animation.AnimationUtils;
+import android.view.animation.Interpolator;
 import com.android.systemui.R;
 
 
@@ -42,6 +44,8 @@
 
     public float animationPxMovementPerSecond;
 
+    public Interpolator defaultBezierInterpolator;
+
     public int filteringCurrentViewsMinAnimDuration;
     public int filteringNewViewsMinAnimDuration;
     public int taskBarEnterAnimDuration;
@@ -121,7 +125,6 @@
                 res.getDimensionPixelSize(R.dimen.recents_task_view_z_increment);
         searchBarSpaceHeightPx = res.getDimensionPixelSize(R.dimen.recents_search_bar_space_height);
 
-
         taskBarViewDefaultBackgroundColor =
                 res.getColor(R.color.recents_task_bar_default_background_color);
         taskBarViewDefaultTextColor =
@@ -131,6 +134,9 @@
         taskBarViewDarkTextColor =
                 res.getColor(R.color.recents_task_bar_dark_text_color);
 
+        defaultBezierInterpolator = AnimationUtils.loadInterpolator(context,
+                        com.android.internal.R.interpolator.fast_out_slow_in);
+
         // Update the search widget id
         SharedPreferences settings = context.getSharedPreferences(context.getPackageName(), 0);
         searchBarAppWidgetId = settings.getInt(Constants.Values.App.Key_SearchAppWidgetId, -1);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsTaskLoader.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsTaskLoader.java
index c64ca54..1ca0476 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsTaskLoader.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsTaskLoader.java
@@ -35,7 +35,6 @@
 
 import java.util.ArrayList;
 import java.util.Collections;
-import java.util.Iterator;
 import java.util.List;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentLinkedQueue;
@@ -362,7 +361,7 @@
         return mSystemServicesProxy;
     }
 
-    private List<ActivityManager.RecentTaskInfo> getRecentTasks(Context context) {
+    private List<ActivityManager.RecentTaskInfo> getRecentTasks() {
         long t1 = System.currentTimeMillis();
 
         SystemServicesProxy ssp = mSystemServicesProxy;
@@ -375,23 +374,6 @@
         Console.log(Constants.Log.App.TaskDataLoader,
                 "[RecentsTaskLoader|tasks]", "" + tasks.size());
 
-        // Remove home/recents tasks
-        Iterator<ActivityManager.RecentTaskInfo> iter = tasks.iterator();
-        while (iter.hasNext()) {
-            ActivityManager.RecentTaskInfo t = iter.next();
-
-            // Skip tasks in the home stack
-            if (ssp.isInHomeStack(t.persistentId)) {
-                iter.remove();
-                continue;
-            }
-            // Skip tasks from this Recents package
-            if (t.baseIntent.getComponent().getPackageName().equals(context.getPackageName())) {
-                iter.remove();
-                continue;
-            }
-        }
-
         return tasks;
     }
 
@@ -408,7 +390,7 @@
 
         // Get the recent tasks
         SystemServicesProxy ssp = mSystemServicesProxy;
-        List<ActivityManager.RecentTaskInfo> tasks = getRecentTasks(context);
+        List<ActivityManager.RecentTaskInfo> tasks = getRecentTasks();
 
         // Add each task to the task stack
         t1 = System.currentTimeMillis();
diff --git a/packages/SystemUI/src/com/android/systemui/recents/SystemServicesProxy.java b/packages/SystemUI/src/com/android/systemui/recents/SystemServicesProxy.java
index 0d3ee38..8d82883 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/SystemServicesProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/SystemServicesProxy.java
@@ -30,7 +30,6 @@
 import android.content.pm.IPackageManager;
 import android.content.pm.PackageManager;
 import android.graphics.Bitmap;
-import android.graphics.Rect;
 import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
 import android.os.Bundle;
@@ -40,6 +39,7 @@
 import android.util.Pair;
 
 import java.util.ArrayList;
+import java.util.Iterator;
 import java.util.List;
 import java.util.Random;
 
@@ -54,7 +54,7 @@
     IPackageManager mIpm;
     UserManager mUm;
     SearchManager mSm;
-    String mPackage;
+    String mRecentsPackage;
     ComponentName mAssistComponent;
 
     Bitmap mDummyIcon;
@@ -67,7 +67,7 @@
         mUm = (UserManager) context.getSystemService(Context.USER_SERVICE);
         mIpm = AppGlobals.getPackageManager();
         mSm = (SearchManager) context.getSystemService(Context.SEARCH_SERVICE);
-        mPackage = context.getPackageName();
+        mRecentsPackage = context.getPackageName();
 
         // Resolve the assist intent
         Intent assist = mSm.getAssistIntent(context, false);
@@ -83,14 +83,14 @@
     }
 
     /** Returns a list of the recents tasks */
-    public List<ActivityManager.RecentTaskInfo> getRecentTasks(int numTasks, int userId) {
+    public List<ActivityManager.RecentTaskInfo> getRecentTasks(int numLatestTasks, int userId) {
         if (mAm == null) return null;
 
         // If we are mocking, then create some recent tasks
         if (Constants.DebugFlags.App.EnableSystemServicesProxy) {
             ArrayList<ActivityManager.RecentTaskInfo> tasks =
                     new ArrayList<ActivityManager.RecentTaskInfo>();
-            int count = Math.min(numTasks, Constants.DebugFlags.App.SystemServicesProxyMockTaskCount);
+            int count = Math.min(numLatestTasks, Constants.DebugFlags.App.SystemServicesProxyMockTaskCount);
             for (int i = 0; i < count; i++) {
                 // Create a dummy component name
                 int packageIndex = i % Constants.DebugFlags.App.SystemServicesProxyMockPackageCount;
@@ -114,9 +114,43 @@
             return tasks;
         }
 
-        return mAm.getRecentTasksForUser(numTasks,
+        // Remove home/recents/excluded tasks
+        int minNumTasksToQuery = 10;
+        int numTasksToQuery = Math.max(minNumTasksToQuery, numLatestTasks);
+        List<ActivityManager.RecentTaskInfo> tasks = mAm.getRecentTasksForUser(numTasksToQuery,
                 ActivityManager.RECENT_IGNORE_UNAVAILABLE |
-                        ActivityManager.RECENT_INCLUDE_PROFILES, userId);
+                ActivityManager.RECENT_INCLUDE_PROFILES |
+                ActivityManager.RECENT_WITH_EXCLUDED, userId);
+        boolean isFirstValidTask = true;
+        Iterator<ActivityManager.RecentTaskInfo> iter = tasks.iterator();
+        while (iter.hasNext()) {
+            ActivityManager.RecentTaskInfo t = iter.next();
+
+            // NOTE: The order of these checks happens in the expected order of the traversal of the
+            // tasks
+
+            // Skip tasks from this Recents package
+            if (t.baseIntent.getComponent().getPackageName().equals(mRecentsPackage)) {
+                iter.remove();
+                continue;
+            }
+            // Check the first non-recents task, include this task even if it is marked as excluded
+            // from recents.  In other words, only remove excluded tasks if it is not the first task
+            boolean isExcluded = (t.baseIntent.getFlags() & Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS)
+                    == Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS;
+            if (isExcluded && !isFirstValidTask) {
+                iter.remove();
+                continue;
+            }
+            isFirstValidTask = false;
+            // Skip tasks in the home stack
+            if (isInHomeStack(t.persistentId)) {
+                iter.remove();
+                continue;
+            }
+        }
+
+        return tasks.subList(0, Math.min(tasks.size(), numLatestTasks));
     }
 
     /** Returns a list of the running tasks */
diff --git a/packages/SystemUI/src/com/android/systemui/recents/Utilities.java b/packages/SystemUI/src/com/android/systemui/recents/Utilities.java
index b602f84..46e6ee9 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/Utilities.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/Utilities.java
@@ -18,6 +18,7 @@
 
 import android.graphics.Color;
 import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
 
 /* Common code */
 public class Utilities {
@@ -54,12 +55,15 @@
                 0.0722f * Color.blue(color));
     }
 
-    /** Returns the ideal text color to draw on top of a specified background color. */
-    public static int getIdealTextColorForBackgroundColor(int color) {
-        RecentsConfiguration configuration = RecentsConfiguration.getInstance();
+    /** Returns the ideal color to draw on top of a specified background color. */
+    public static int getIdealColorForBackgroundColor(int color, int lightRes, int darkRes) {
         int greyscale = colorToGreyscale(color);
-        return (greyscale < 128) ? configuration.taskBarViewLightTextColor :
-                configuration.taskBarViewDarkTextColor;
-
+        return (greyscale < 128) ? lightRes : darkRes;
+    }
+    /** Returns the ideal drawable to draw on top of a specified background color. */
+    public static Drawable getIdealResourceForBackgroundColor(int color, Drawable lightRes,
+                                                           Drawable darkRes) {
+        int greyscale = colorToGreyscale(color);
+        return (greyscale < 128) ? lightRes : darkRes;
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskBarView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskBarView.java
index c6cb812..07caa1b 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskBarView.java
@@ -16,7 +16,10 @@
 
 package com.android.systemui.recents.views;
 
+import android.animation.ValueAnimator;
 import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.drawable.Drawable;
 import android.util.AttributeSet;
 import android.widget.FrameLayout;
 import android.widget.ImageView;
@@ -32,9 +35,13 @@
 class TaskBarView extends FrameLayout {
     Task mTask;
 
+    ImageView mDismissButton;
     ImageView mApplicationIcon;
     TextView mActivityDescription;
 
+    Drawable mLightDismissDrawable;
+    Drawable mDarkDismissDrawable;
+
     public TaskBarView(Context context) {
         this(context, null);
     }
@@ -49,6 +56,9 @@
 
     public TaskBarView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
         super(context, attrs, defStyleAttr, defStyleRes);
+        Resources res = context.getResources();
+        mLightDismissDrawable = res.getDrawable(R.drawable.recents_dismiss_light);
+        mDarkDismissDrawable = res.getDrawable(R.drawable.recents_dismiss_dark);
     }
 
     @Override
@@ -56,6 +66,28 @@
         // Initialize the icon and description views
         mApplicationIcon = (ImageView) findViewById(R.id.application_icon);
         mActivityDescription = (TextView) findViewById(R.id.activity_description);
+        mDismissButton = (ImageView) findViewById(R.id.dismiss_task);
+    }
+
+    /** Synchronizes this bar view's properties with the task's transform */
+    void updateViewPropertiesToTaskTransform(TaskViewTransform animateFromTransform,
+                                             TaskViewTransform toTransform, int duration) {
+        RecentsConfiguration config = RecentsConfiguration.getInstance();
+        if (duration > 0) {
+            if (animateFromTransform != null) {
+                mDismissButton.setAlpha(animateFromTransform.dismissAlpha);
+            }
+            mDismissButton.animate()
+                    .alpha(toTransform.dismissAlpha)
+                    .setStartDelay(0)
+                    .setDuration(duration)
+                    .setInterpolator(config.defaultBezierInterpolator)
+                    .withLayer()
+                    .start();
+        } else {
+            mDismissButton.setAlpha(toTransform.dismissAlpha);
+        }
+        mDismissButton.invalidate();
     }
 
     /** Binds the bar view to the task */
@@ -74,7 +106,10 @@
         int tint = t.colorPrimary;
         if (Constants.DebugFlags.App.EnableTaskBarThemeColors && tint != 0) {
             setBackgroundColor(tint);
-            mActivityDescription.setTextColor(Utilities.getIdealTextColorForBackgroundColor(tint));
+            mActivityDescription.setTextColor(Utilities.getIdealColorForBackgroundColor(tint,
+                    configuration.taskBarViewLightTextColor, configuration.taskBarViewDarkTextColor));
+            mDismissButton.setImageDrawable(Utilities.getIdealResourceForBackgroundColor(tint,
+                    mLightDismissDrawable, mDarkDismissDrawable));
         } else {
             setBackgroundColor(configuration.taskBarViewDefaultBackgroundColor);
             mActivityDescription.setTextColor(configuration.taskBarViewDefaultTextColor);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskInfoView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskInfoView.java
index c6c29a6..f1c362a 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskInfoView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskInfoView.java
@@ -30,7 +30,6 @@
 import android.widget.Button;
 import android.widget.FrameLayout;
 import com.android.systemui.R;
-import com.android.systemui.recents.BakedBezierInterpolator;
 import com.android.systemui.recents.Constants;
 import com.android.systemui.recents.RecentsConfiguration;
 import com.android.systemui.recents.Utilities;
@@ -111,7 +110,8 @@
         int duration = Utilities.calculateTranslationAnimationDuration((int) mMaxClipRadius);
         mCircularClipAnimator = ObjectAnimator.ofFloat(this, "circularClipRadius", toRadius);
         mCircularClipAnimator.setDuration(duration);
-        mCircularClipAnimator.setInterpolator(BakedBezierInterpolator.INSTANCE);
+        mCircularClipAnimator.setInterpolator(
+                RecentsConfiguration.getInstance().defaultBezierInterpolator);
         mCircularClipAnimator.addListener(new AnimatorListenerAdapter() {
             @Override
             public void onAnimationEnd(Animator animation) {
@@ -143,7 +143,7 @@
                 .scaleX(1f)
                 .scaleY(1f)
                 .setDuration(duration)
-                .setInterpolator(BakedBezierInterpolator.INSTANCE)
+                .setInterpolator(RecentsConfiguration.getInstance().defaultBezierInterpolator)
                 .withLayer()
                 .start();
     }
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 55c38a9..b64225e 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
@@ -37,7 +37,6 @@
 import android.widget.FrameLayout;
 import android.widget.OverScroller;
 import com.android.systemui.R;
-import com.android.systemui.recents.BakedBezierInterpolator;
 import com.android.systemui.recents.Console;
 import com.android.systemui.recents.Constants;
 import com.android.systemui.recents.RecentsConfiguration;
@@ -170,6 +169,9 @@
             transform.translationY = (int) (boundedT * overlapHeight - scaleYOffset);
         }
 
+        // Set the alphas
+        transform.dismissAlpha = Math.max(-1f, Math.min(0f, t)) + 1f;
+
         // Update the rect and visibility
         transform.rect.set(mTaskRect);
         if (t < -(numPeekCards + 1)) {
@@ -338,7 +340,7 @@
         mScrollAnimator = ObjectAnimator.ofInt(this, "stackScroll", curScroll, newScroll);
         mScrollAnimator.setDuration(Utilities.calculateTranslationAnimationDuration(newScroll -
                 curScroll, 250));
-        mScrollAnimator.setInterpolator(BakedBezierInterpolator.INSTANCE);
+        mScrollAnimator.setInterpolator(RecentsConfiguration.getInstance().defaultBezierInterpolator);
         mScrollAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
             @Override
             public void onAnimationUpdate(ValueAnimator animation) {
@@ -1036,6 +1038,15 @@
         }
     }
 
+    @Override
+    public void onTaskDismissed(TaskView tv) {
+        Task task = tv.getTask();
+        // Remove the task from the view
+        mStack.removeTask(task);
+        // Notify the callback that we've removed the task and it can clean up after it
+        mCb.onTaskRemoved(task);
+    }
+
     /**** View.OnClickListener Implementation ****/
 
     @Override
@@ -1095,6 +1106,7 @@
 
     @Override
     public void onComponentRemoved(Set<ComponentName> cns) {
+        RecentsConfiguration config = RecentsConfiguration.getInstance();
         // For other tasks, just remove them directly if they no longer exist
         ArrayList<Task> tasks = mStack.getTasks();
         for (int i = tasks.size() - 1; i >= 0; i--) {
@@ -1477,13 +1489,7 @@
     @Override
     public void onChildDismissed(View v) {
         TaskView tv = (TaskView) v;
-        Task task = tv.getTask();
-
-        // Remove the task from the view
-        mSv.mStack.removeTask(task);
-
-        // Notify the callback that we've removed the task and it can clean up after it
-        mSv.mCb.onTaskRemoved(task);
+        mSv.onTaskDismissed(tv);
 
         // Disable HW layers
         mSv.decHwLayersRefCount("swipeComplete");
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 b03f389..5fad629 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
@@ -31,7 +31,6 @@
 import android.view.animation.AccelerateInterpolator;
 import android.widget.FrameLayout;
 import com.android.systemui.R;
-import com.android.systemui.recents.BakedBezierInterpolator;
 import com.android.systemui.recents.Constants;
 import com.android.systemui.recents.RecentsConfiguration;
 import com.android.systemui.recents.model.Task;
@@ -46,6 +45,7 @@
         public void onTaskInfoPanelShown(TaskView tv);
         public void onTaskInfoPanelHidden(TaskView tv);
         public void onTaskAppInfoClicked(TaskView tv);
+        public void onTaskDismissed(TaskView tv);
 
         // public void onTaskViewReboundToTask(TaskView tv, Task t);
     }
@@ -143,6 +143,10 @@
         int minZ = config.taskViewTranslationZMinPx;
         int incZ = config.taskViewTranslationZIncrementPx;
 
+        // Update the bar view
+        mBarView.updateViewPropertiesToTaskTransform(animateFromTransform, toTransform, duration);
+
+        // Update this task view
         if (duration > 0) {
             if (animateFromTransform != null) {
                 setTranslationY(animateFromTransform.translationY);
@@ -161,7 +165,7 @@
                     .scaleY(toTransform.scale)
                     .alpha(toTransform.alpha)
                     .setDuration(duration)
-                    .setInterpolator(BakedBezierInterpolator.INSTANCE)
+                    .setInterpolator(config.defaultBezierInterpolator)
                     .withLayer()
                     .setUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                         @Override
@@ -221,8 +225,8 @@
         mBarView.setAlpha(0f);
         mBarView.animate()
                 .alpha(1f)
-                .setStartDelay(235)
-                .setInterpolator(BakedBezierInterpolator.INSTANCE)
+                .setStartDelay(250)
+                .setInterpolator(config.defaultBezierInterpolator)
                 .setDuration(config.taskBarEnterAnimDuration)
                 .withLayer()
                 .start();
@@ -234,7 +238,7 @@
         mBarView.animate()
             .alpha(0f)
             .setStartDelay(0)
-            .setInterpolator(BakedBezierInterpolator.INSTANCE)
+            .setInterpolator(config.defaultBezierInterpolator)
             .setDuration(config.taskBarExitAnimDuration)
             .withLayer()
             .withEndAction(new Runnable() {
@@ -252,7 +256,7 @@
         animate().translationX(config.taskViewRemoveAnimTranslationXPx)
             .alpha(0f)
             .setStartDelay(0)
-            .setInterpolator(BakedBezierInterpolator.INSTANCE)
+            .setInterpolator(config.defaultBezierInterpolator)
             .setDuration(config.taskViewRemoveAnimDuration)
             .withLayer()
             .withEndAction(new Runnable() {
@@ -310,7 +314,7 @@
         mInfoView.animate()
                 .alpha(0f)
                 .setDuration(config.taskViewInfoPaneAnimDuration)
-                .setInterpolator(BakedBezierInterpolator.INSTANCE)
+                .setInterpolator(config.defaultBezierInterpolator)
                 .withLayer()
                 .withEndAction(new Runnable() {
                     @Override
@@ -380,6 +384,7 @@
             mInfoView.rebindToTask(mTask, reloadingTaskData);
             // Rebind any listeners
             mBarView.mApplicationIcon.setOnClickListener(this);
+            mBarView.mDismissButton.setOnClickListener(this);
             mInfoView.mAppInfoButton.setOnClickListener(this);
         }
         mTaskDataLoaded = true;
@@ -405,6 +410,15 @@
             hideInfoPane();
         } else if (v == mBarView.mApplicationIcon) {
             mCb.onTaskIconClicked(this);
+        } else if (v == mBarView.mDismissButton) {
+            // Animate out the view and call the callback
+            final TaskView tv = this;
+            animateRemoval(new Runnable() {
+                @Override
+                public void run() {
+                    mCb.onTaskDismissed(tv);
+                }
+            });
         } else if (v == mInfoView.mAppInfoButton) {
             mCb.onTaskAppInfoClicked(this);
         }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewTransform.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewTransform.java
index 0748bbb..e6391a8 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewTransform.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewTransform.java
@@ -24,6 +24,7 @@
     public int translationY = 0;
     public float scale = 1f;
     public float alpha = 1f;
+    public float dismissAlpha = 1f;
     public boolean visible = false;
     public Rect rect = new Rect();
     float t;
@@ -36,6 +37,7 @@
         translationY = o.translationY;
         scale = o.scale;
         alpha = o.alpha;
+        dismissAlpha = o.dismissAlpha;
         visible = o.visible;
         rect.set(o.rect);
         t = o.t;
@@ -44,6 +46,6 @@
     @Override
     public String toString() {
         return "TaskViewTransform y: " + translationY + " scale: " + scale + " alpha: " + alpha +
-                " visible: " + visible + " rect: " + rect;
+                " visible: " + visible + " rect: " + rect + " dismissAlpha: " + dismissAlpha;
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarTransitions.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarTransitions.java
index e941d54..8406565 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarTransitions.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarTransitions.java
@@ -44,16 +44,12 @@
 
     public void init() {
         mLeftSide = mView.findViewById(R.id.notification_icon_area);
-        initStatus();
-        applyModeBackground(-1, getMode(), false /*animate*/);
-        applyMode(getMode(), false /*animate*/);
-    }
-
-    private void initStatus() {
         mStatusIcons = mView.findViewById(R.id.statusIcons);
         mSignalCluster = mView.findViewById(R.id.signal_cluster);
         mBattery = mView.findViewById(R.id.battery);
         mClock = mView.findViewById(R.id.clock);
+        applyModeBackground(-1, getMode(), false /*animate*/);
+        applyMode(getMode(), false /*animate*/);
     }
 
     public ObjectAnimator animateTransitionTo(View v, float toAlpha) {
@@ -83,8 +79,6 @@
 
     private void applyMode(int mode, boolean animate) {
         if (mLeftSide == null) return; // pre-init
-        if (mStatusIcons == null) initStatus();
-        if (mStatusIcons == null) return;
         float newAlpha = getNonBatteryClockAlphaFor(mode);
         float newAlphaBC = getBatteryClockAlpha(mode);
         if (mCurrentAnimation != null) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
index e6de057..084bfcf 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
@@ -63,7 +63,7 @@
     }
 
     @Override
-    public void onAttachedToWindow() {
+    public void onFinishInflate() {
         mBarTransitions.init();
     }