Merge "Make sure events handled on same looper"
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index 426f21e..e640649 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -2861,29 +2861,21 @@
         int oldTemp = -1;
         int oldVolt = -1;
         long lastTime = -1;
+        long firstTime = -1;
 
-        public void printNextItem(PrintWriter pw, HistoryItem rec, long now, boolean checkin,
+        public void printNextItem(PrintWriter pw, HistoryItem rec, long baseTime, boolean checkin,
                 boolean verbose) {
             if (!checkin) {
                 pw.print("  ");
-                if (now >= 0) {
-                    TimeUtils.formatDuration(rec.time-now, pw, TimeUtils.HUNDRED_DAY_FIELD_LEN);
-                } else {
-                    TimeUtils.formatDuration(rec.time, pw, TimeUtils.HUNDRED_DAY_FIELD_LEN);
-                }
+                TimeUtils.formatDuration(rec.time - baseTime, pw, TimeUtils.HUNDRED_DAY_FIELD_LEN);
                 pw.print(" (");
                 pw.print(rec.numReadInts);
                 pw.print(") ");
             } else {
                 if (lastTime < 0) {
-                    if (now >= 0) {
-                        pw.print("@");
-                        pw.print(rec.time-now);
-                    } else {
-                        pw.print(rec.time);
-                    }
+                    pw.print(rec.time - baseTime);
                 } else {
-                    pw.print(rec.time-lastTime);
+                    pw.print(rec.time - lastTime);
                 }
                 lastTime = rec.time;
             }
@@ -3132,10 +3124,27 @@
                     pw.println("):");
                     HistoryPrinter hprinter = new HistoryPrinter();
                     long lastTime = -1;
+                    long baseTime = -1;
+                    boolean printed = false;
                     while (getNextHistoryLocked(rec)) {
                         lastTime = rec.time;
+                        if (baseTime < 0) {
+                            baseTime = lastTime;
+                        }
                         if (rec.time >= histStart) {
-                            hprinter.printNextItem(pw, rec, histStart >= 0 ? -1 : now, false,
+                            if (histStart >= 0 && !printed) {
+                                if (rec.cmd == HistoryItem.CMD_CURRENT_TIME) {
+                                    printed = true;
+                                } else if (rec.currentTime != 0) {
+                                    printed = true;
+                                    byte cmd = rec.cmd;
+                                    rec.cmd = HistoryItem.CMD_CURRENT_TIME;
+                                    hprinter.printNextItem(pw, rec, baseTime, false,
+                                            (flags&DUMP_VERBOSE) != 0);
+                                    rec.cmd = cmd;
+                                }
+                            }
+                            hprinter.printNextItem(pw, rec, baseTime, false,
                                     (flags&DUMP_VERBOSE) != 0);
                         }
                     }
@@ -3152,8 +3161,12 @@
                 try {
                     pw.println("Old battery History:");
                     HistoryPrinter hprinter = new HistoryPrinter();
+                    long baseTime = -1;
                     while (getNextOldHistoryLocked(rec)) {
-                        hprinter.printNextItem(pw, rec, now, false, (flags&DUMP_VERBOSE) != 0);
+                        if (baseTime < 0) {
+                            baseTime = rec.time;
+                        }
+                        hprinter.printNextItem(pw, rec, baseTime, false, (flags&DUMP_VERBOSE) != 0);
                     }
                     pw.println();
                 } finally {
@@ -3226,20 +3239,42 @@
                         pw.print(BATTERY_STATS_CHECKIN_VERSION); pw.print(',');
                         pw.print(HISTORY_STRING_POOL); pw.print(',');
                         pw.print(i);
-                        pw.print(',');
-                        pw.print(getHistoryTagPoolString(i));
-                        pw.print(',');
+                        pw.print(",");
                         pw.print(getHistoryTagPoolUid(i));
+                        pw.print(",\"");
+                        String str = getHistoryTagPoolString(i);
+                        str = str.replace("\\", "\\\\");
+                        str = str.replace("\"", "\\\"");
+                        pw.print(str);
+                        pw.print("\"");
                         pw.println();
                     }
                     HistoryPrinter hprinter = new HistoryPrinter();
                     long lastTime = -1;
+                    long baseTime = -1;
+                    boolean printed = false;
                     while (getNextHistoryLocked(rec)) {
                         lastTime = rec.time;
+                        if (baseTime < 0) {
+                            baseTime = lastTime;
+                        }
                         if (rec.time >= histStart) {
+                            if (histStart >= 0 && !printed) {
+                                if (rec.cmd == HistoryItem.CMD_CURRENT_TIME) {
+                                    printed = true;
+                                } else if (rec.currentTime != 0) {
+                                    printed = true;
+                                    byte cmd = rec.cmd;
+                                    rec.cmd = HistoryItem.CMD_CURRENT_TIME;
+                                    pw.print(BATTERY_STATS_CHECKIN_VERSION); pw.print(',');
+                                    pw.print(HISTORY_DATA); pw.print(',');
+                                    hprinter.printNextItem(pw, rec, baseTime, true, false);
+                                    rec.cmd = cmd;
+                                }
+                            }
                             pw.print(BATTERY_STATS_CHECKIN_VERSION); pw.print(',');
                             pw.print(HISTORY_DATA); pw.print(',');
-                            hprinter.printNextItem(pw, rec, histStart >= 0 ? -1 : now, true, false);
+                            hprinter.printNextItem(pw, rec, baseTime, true, false);
                         }
                     }
                     if (histStart >= 0) {
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 4e4f37b..097dff0 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -3722,7 +3722,8 @@
                     if (result == InputMethodManager.DISPATCH_HANDLED) {
                         return FINISH_HANDLED;
                     } else if (result == InputMethodManager.DISPATCH_NOT_HANDLED) {
-                        return FINISH_NOT_HANDLED;
+                        // The IME could not handle it, so skip along to the next InputStage
+                        return FORWARD;
                     } else {
                         return DEFER; // callback will be invoked later
                     }
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 4c11fa9..eaedba5 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -5580,13 +5580,13 @@
             if (end) {
                 Slog.w(TAG, "New history ends before old history!");
             } else if (!out.same(mHistoryReadTmp)) {
-                long now = getHistoryBaseTime() + SystemClock.elapsedRealtime();
                 PrintWriter pw = new FastPrintWriter(new LogWriter(android.util.Log.WARN, TAG));
                 pw.println("Histories differ!");
                 pw.println("Old history:");
-                (new HistoryPrinter()).printNextItem(pw, out, now, false, true);
+                (new HistoryPrinter()).printNextItem(pw, out, 0, false, true);
                 pw.println("New history:");
-                (new HistoryPrinter()).printNextItem(pw, mHistoryReadTmp, now, false, true);
+                (new HistoryPrinter()).printNextItem(pw, mHistoryReadTmp, 0, false,
+                        true);
                 pw.flush();
             }
         }
@@ -5664,7 +5664,12 @@
             return false;
         }
 
+        final long lastRealtime = out.time;
+        final long lastWalltime = out.currentTime;
         readHistoryDelta(mHistoryBuffer, out);
+        if (out.cmd != HistoryItem.CMD_CURRENT_TIME && lastWalltime != 0) {
+            out.currentTime = lastWalltime + (out.time - lastRealtime);
+        }
         return true;
     }
 
diff --git a/media/jni/android_media_MediaDrm.cpp b/media/jni/android_media_MediaDrm.cpp
index 7c45682..4fbd2a4 100644
--- a/media/jni/android_media_MediaDrm.cpp
+++ b/media/jni/android_media_MediaDrm.cpp
@@ -297,8 +297,6 @@
 }
 
 JDrm::~JDrm() {
-    mDrm.clear();
-
     JNIEnv *env = AndroidRuntime::getJNIEnv();
 
     env->DeleteWeakGlobalRef(mObject);
@@ -363,6 +361,13 @@
     }
 }
 
+void JDrm::disconnect() {
+    if (mDrm != NULL) {
+        mDrm->destroyPlugin();
+        mDrm.clear();
+    }
+}
+
 
 // static
 bool JDrm::IsCryptoSchemeSupported(const uint8_t uuid[16], const String8 &mimeType) {
@@ -527,6 +532,7 @@
     sp<JDrm> drm = setDrm(env, thiz, NULL);
     if (drm != NULL) {
         drm->setListener(NULL);
+        drm->disconnect();
     }
 }
 
diff --git a/media/jni/android_media_MediaDrm.h b/media/jni/android_media_MediaDrm.h
index 620ad28..b7b8e5d 100644
--- a/media/jni/android_media_MediaDrm.h
+++ b/media/jni/android_media_MediaDrm.h
@@ -47,6 +47,8 @@
     void notify(DrmPlugin::EventType, int extra, const Parcel *obj);
     status_t setListener(const sp<DrmListener>& listener);
 
+    void disconnect();
+
 protected:
     virtual ~JDrm();
 
diff --git a/opengl/java/android/opengl/GLSurfaceView.java b/opengl/java/android/opengl/GLSurfaceView.java
index a9322b9..1406f6b 100644
--- a/opengl/java/android/opengl/GLSurfaceView.java
+++ b/opengl/java/android/opengl/GLSurfaceView.java
@@ -878,7 +878,7 @@
         protected int[] mConfigSpec;
 
         private int[] filterConfigSpec(int[] configSpec) {
-            if (mEGLContextClientVersion != 2) {
+            if (mEGLContextClientVersion != 2 && mEGLContextClientVersion != 3) {
                 return configSpec;
             }
             /* We know none of the subclasses define EGL_RENDERABLE_TYPE.
@@ -888,7 +888,11 @@
             int[] newConfigSpec = new int[len + 2];
             System.arraycopy(configSpec, 0, newConfigSpec, 0, len-1);
             newConfigSpec[len-1] = EGL10.EGL_RENDERABLE_TYPE;
-            newConfigSpec[len] = 4; /* EGL_OPENGL_ES2_BIT */
+            if (mEGLContextClientVersion == 2) {
+                newConfigSpec[len] = EGL14.EGL_OPENGL_ES2_BIT;  /* EGL_OPENGL_ES2_BIT */
+            } else {
+                newConfigSpec[len] = EGLExt.EGL_OPENGL_ES3_BIT_KHR; /* EGL_OPENGL_ES3_BIT_KHR */
+            }
             newConfigSpec[len+1] = EGL10.EGL_NONE;
             return newConfigSpec;
         }
diff --git a/packages/SystemUI/res/drawable-hdpi/search_bg_transparent.9.png b/packages/SystemUI/res/drawable-hdpi/search_bg_transparent.9.png
new file mode 100644
index 0000000..85db9c8
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/search_bg_transparent.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/search_bg_transparent.9.png b/packages/SystemUI/res/drawable-mdpi/search_bg_transparent.9.png
new file mode 100644
index 0000000..c4941a6
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/search_bg_transparent.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/search_bg_transparent.9.png b/packages/SystemUI/res/drawable-xhdpi/search_bg_transparent.9.png
new file mode 100644
index 0000000..4618f40
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/search_bg_transparent.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/recents_task_shadow.9.png b/packages/SystemUI/res/drawable-xxhdpi/recents_task_shadow.9.png
new file mode 100644
index 0000000..36e7e45
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/recents_task_shadow.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/search_bg_transparent.9.png b/packages/SystemUI/res/drawable-xxhdpi/search_bg_transparent.9.png
new file mode 100644
index 0000000..c0bf31d
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/search_bg_transparent.9.png
Binary files differ
diff --git a/packages/SystemUI/res/layout/recents_search_bar.xml b/packages/SystemUI/res/layout/recents_search_bar.xml
new file mode 100644
index 0000000..915283e
--- /dev/null
+++ b/packages/SystemUI/res/layout/recents_search_bar.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<FrameLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:background="@drawable/search_bg_transparent">
+    <TextView
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center"
+        android:text="@string/recents_search_bar_label"
+        android:textColor="#99ffffff"
+        android:textSize="18sp"
+        android:textAllCaps="true" />
+</FrameLayout>
+
diff --git a/packages/SystemUI/res/layout/recents_task_view.xml b/packages/SystemUI/res/layout/recents_task_view.xml
index 7f64032..4442bca 100644
--- a/packages/SystemUI/res/layout/recents_task_view.xml
+++ b/packages/SystemUI/res/layout/recents_task_view.xml
@@ -63,13 +63,6 @@
             android:maxLines="2"
             android:ellipsize="marquee"
             android:fadingEdge="horizontal" />
-        <ImageView
-            android:id="@+id/activity_icon"
-            android:layout_width="@dimen/recents_task_view_activity_icon_size"
-            android:layout_height="@dimen/recents_task_view_activity_icon_size"
-            android:layout_gravity="center_vertical|end"
-            android:padding="12dp"
-            android:visibility="invisible" />
     </com.android.systemui.recents.views.TaskBarView>
 </com.android.systemui.recents.views.TaskView>
 
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 25ae38c..3047f15 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -236,6 +236,12 @@
     <!-- 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>
 
+    <!-- The height of the search bar space. -->
+    <dimen name="recents_search_bar_space_height">40dp</dimen>
+
+    <!-- The search bar edge margins. -->
+    <dimen name="recents_search_bar_space_edge_margins">12dp</dimen>
+
     <!-- Used to calculate the translation animation duration, the expected amount of movement 
          in dps over one second of time. -->
     <dimen name="recents_animation_movement_in_dps_per_second">800dp</dimen>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 73e5e19..72d14fe 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -511,6 +511,8 @@
     <string name="recents_empty_message">RECENTS</string>
     <!-- Recents: The info panel app info button string. [CHAR LIMIT=NONE] -->
     <string name="recents_app_info_button_label">Application Info</string>
+    <!-- Recents: Temporary string for the button in the recents search bar. [CHAR LIMIT=NONE] -->
+    <string name="recents_search_bar_label">search</string>
 
 
     <!-- Glyph to be overlaid atop the battery when the level is extremely low. Do not translate. -->
diff --git a/packages/SystemUI/src/com/android/systemui/recents/Constants.java b/packages/SystemUI/src/com/android/systemui/recents/Constants.java
index 64770a4..72d9a52 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/Constants.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/Constants.java
@@ -29,6 +29,7 @@
             public static final boolean EnableTaskFiltering = true;
             public static final boolean EnableTaskStackClipping = false;
             public static final boolean EnableInfoPane = true;
+            public static final boolean EnableSearchButton = false;
 
             // This disables the bitmap and icon caches
             public static final boolean DisableBackgroundCache = false;
@@ -84,6 +85,9 @@
             public static final int TaskStackOverscrollRange = 150;
             public static final int FilterStartDelay = 25;
 
+            // The amount to inverse scale the movement if we are overscrolling
+            public static final float TouchOverscrollScaleFactor = 3f;
+
             // The padding will be applied to the smallest dimension, and then applied to all sides
             public static final float StackPaddingPct = 0.15f;
             // The overlap height relative to the task height
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
index 5e5b841..d54df13 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
@@ -44,6 +44,8 @@
     public int taskStackMaxDim;
     public int taskViewInfoPaneAnimDuration;
     public int taskViewRoundedCornerRadiusPx;
+    public int searchBarSpaceHeightPx;
+    public int searchBarSpaceEdgeMarginsPx;
 
     public boolean launchedWithThumbnailAnimation;
 
@@ -92,6 +94,9 @@
                 res.getInteger(R.integer.recents_animate_task_view_info_pane_duration);
         taskViewRoundedCornerRadiusPx =
                 res.getDimensionPixelSize(R.dimen.recents_task_view_rounded_corners_radius);
+        searchBarSpaceHeightPx = res.getDimensionPixelSize(R.dimen.recents_search_bar_space_height);
+        searchBarSpaceEdgeMarginsPx =
+                res.getDimensionPixelSize(R.dimen.recents_search_bar_space_edge_margins);
     }
 
     /** Updates the system insets */
@@ -99,6 +104,26 @@
         systemInsets.set(insets);
     }
 
+    /** Returns the search bar bounds in the specified orientation */
+    public void getSearchBarBounds(int width, int height,
+                                   Rect searchBarSpaceBounds, Rect searchBarBounds) {
+        // Return empty rects if search is not enabled
+        if (!Constants.DebugFlags.App.EnableSearchButton) {
+            searchBarSpaceBounds.set(0, 0, 0, 0);
+            searchBarBounds.set(0, 0, 0, 0);
+            return;
+        }
+
+        // Calculate the search bar bounds, and account for the system insets
+        int edgeMarginPx = searchBarSpaceEdgeMarginsPx;
+        int availableWidth = width - systemInsets.left - systemInsets.right;
+        searchBarSpaceBounds.set(0, 0, availableWidth, 2 * edgeMarginPx + searchBarSpaceHeightPx);
+
+        // Inset from the search bar space to get the search bar bounds
+        searchBarBounds.set(searchBarSpaceBounds);
+        searchBarBounds.inset(edgeMarginPx, edgeMarginPx);
+    }
+
     /** Converts from DPs to PXs */
     public int pxFromDp(float size) {
         return Math.round(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsService.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsService.java
index 06ca9e2..36b761e 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsService.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsService.java
@@ -66,22 +66,33 @@
                 Bundle replyData = new Bundle();
                 TaskViewTransform transform;
 
+                // Get the search bar bounds so that we can account for its height in the children
+                Rect searchBarSpaceBounds = new Rect();
+                Rect searchBarBounds = new Rect();
+                RecentsConfiguration config = RecentsConfiguration.getInstance();
+                config.getSearchBarBounds(windowRect.width(), windowRect.height(),
+                        searchBarSpaceBounds, searchBarBounds);
+
                 // Calculate the target task rect for when there is one task
                 // NOTE: Since the nav bar height is already accounted for in the windowRect, don't
                 // pass in a bottom inset
                 stack.addTask(new Task());
-                tsv.computeRects(windowRect.width(), windowRect.height() - systemInsets.top, 0);
+                tsv.computeRects(windowRect.width(), windowRect.height() - systemInsets.top -
+                        systemInsets.bottom - searchBarSpaceBounds.height(), 0);
                 tsv.boundScroll();
                 transform = tsv.getStackTransform(0, tsv.getStackScroll());
+                transform.rect.offset(0, searchBarSpaceBounds.height());
                 replyData.putParcelable(AlternateRecentsComponent.KEY_SINGLE_TASK_STACK_RECT,
                         new Rect(transform.rect));
 
                 // Also calculate the target task rect when there are multiple tasks
                 stack.addTask(new Task());
-                tsv.computeRects(windowRect.width(), windowRect.height() - systemInsets.top, 0);
+                tsv.computeRects(windowRect.width(), windowRect.height() - systemInsets.top -
+                        systemInsets.bottom - searchBarSpaceBounds.height(), 0);
                 tsv.setStackScrollRaw(Integer.MAX_VALUE);
                 tsv.boundScroll();
                 transform = tsv.getStackTransform(1, tsv.getStackScroll());
+                transform.rect.offset(0, searchBarSpaceBounds.height());
                 replyData.putParcelable(AlternateRecentsComponent.KEY_MULTIPLE_TASK_STACK_RECT,
                         new Rect(transform.rect));
 
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsTaskLoader.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsTaskLoader.java
index fd0f6d1..da265e1 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsTaskLoader.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsTaskLoader.java
@@ -415,7 +415,10 @@
             ActivityInfo info = ssp.getActivityInfo(t.baseIntent.getComponent(), t.userId);
             String activityLabel = (t.activityLabel == null ? ssp.getActivityLabel(info) :
                     t.activityLabel.toString());
-            Bitmap activityIcon = t.activityIcon;
+            BitmapDrawable activityIcon = null;
+            if (t.activityIcon != null) {
+                activityIcon = new BitmapDrawable(res, t.activityIcon);
+            }
             boolean isForemostTask = (i == (taskCount - 1));
 
             // Create a new task
diff --git a/packages/SystemUI/src/com/android/systemui/recents/SystemServicesProxy.java b/packages/SystemUI/src/com/android/systemui/recents/SystemServicesProxy.java
index 7f0d9ee..33ac0a8 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/SystemServicesProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/SystemServicesProxy.java
@@ -19,6 +19,8 @@
 import android.app.ActivityManager;
 import android.app.ActivityOptions;
 import android.app.AppGlobals;
+import android.app.SearchManager;
+import android.content.ActivityNotFoundException;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
@@ -26,11 +28,15 @@
 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;
 import android.os.RemoteException;
 import android.os.UserHandle;
 import android.os.UserManager;
+import android.text.TextUtils;
+import android.util.Log;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -45,6 +51,7 @@
     PackageManager mPm;
     IPackageManager mIpm;
     UserManager mUm;
+    SearchManager mSm;
     String mPackage;
 
     Bitmap mDummyIcon;
@@ -55,6 +62,7 @@
         mPm = context.getPackageManager();
         mUm = (UserManager) context.getSystemService(Context.USER_SERVICE);
         mIpm = AppGlobals.getPackageManager();
+        mSm = (SearchManager) context.getSystemService(Context.SEARCH_SERVICE);
         mPackage = context.getPackageName();
 
         if (Constants.DebugFlags.App.EnableSystemServicesProxy) {
@@ -199,4 +207,28 @@
         }
         return icon;
     }
+
+
+    /**
+     * Composes an intent to launch the global search activity.
+     */
+    public Intent getGlobalSearchIntent(Rect sourceBounds) {
+        if (mSm == null) return null;
+
+        // Try and get the global search activity
+        ComponentName globalSearchActivity = mSm.getGlobalSearchActivity();
+        if (globalSearchActivity == null) return null;
+
+        // Bundle the source of the search
+        Bundle appSearchData = new Bundle();
+        appSearchData.putString("source", mPackage);
+
+        // Compose the intent and Start the search activity
+        Intent intent = new Intent(SearchManager.INTENT_ACTION_GLOBAL_SEARCH);
+        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        intent.setComponent(globalSearchActivity);
+        intent.putExtra(SearchManager.APP_DATA, appSearchData);
+        intent.setSourceBounds(sourceBounds);
+        return intent;
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/Task.java b/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
index ff062f6c..1566a49 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
@@ -18,6 +18,7 @@
 
 import android.content.Intent;
 import android.graphics.Bitmap;
+import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.Drawable;
 
 
@@ -69,8 +70,8 @@
 
     public TaskKey key;
     public Drawable applicationIcon;
+    public Drawable activityIcon;
     public String activityLabel;
-    public Bitmap activityIcon;
     public Bitmap thumbnail;
     public boolean isActive;
     public int userId;
@@ -82,7 +83,7 @@
     }
 
     public Task(int id, boolean isActive, Intent intent, String activityTitle,
-                Bitmap activityIcon, int userId) {
+                BitmapDrawable activityIcon, int userId) {
         this.key = new TaskKey(id, intent, userId);
         this.activityLabel = activityTitle;
         this.activityIcon = activityIcon;
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 b054a22..1df4670 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
@@ -27,8 +27,11 @@
 import android.net.Uri;
 import android.os.UserHandle;
 import android.provider.Settings;
+import android.view.Gravity;
+import android.view.LayoutInflater;
 import android.view.View;
 import android.widget.FrameLayout;
+import android.widget.TextView;
 import com.android.systemui.recents.Console;
 import com.android.systemui.recents.Constants;
 import com.android.systemui.recents.RecentsConfiguration;
@@ -36,6 +39,7 @@
 import com.android.systemui.recents.model.SpaceNode;
 import com.android.systemui.recents.model.Task;
 import com.android.systemui.recents.model.TaskStack;
+import com.android.systemui.R;
 
 import java.util.ArrayList;
 
@@ -53,11 +57,16 @@
 
     // The space partitioning root of this container
     SpaceNode mBSP;
+    // Search bar view
+    View mSearchBar;
     // Recents view callbacks
     RecentsViewCallbacks mCb;
 
+    LayoutInflater mInflater;
+
     public RecentsView(Context context) {
         super(context);
+        mInflater = LayoutInflater.from(context);
         setWillNotDraw(false);
     }
 
@@ -71,12 +80,22 @@
         mBSP = n;
 
         // Create and add all the stacks for this partition of space.
+        boolean hasTasks = false;
         removeAllViews();
         ArrayList<TaskStack> stacks = mBSP.getStacks();
         for (TaskStack stack : stacks) {
             TaskStackView stackView = new TaskStackView(getContext(), stack);
             stackView.setCallbacks(this);
             addView(stackView);
+            hasTasks |= (stack.getTaskCount() > 0);
+        }
+
+        // Create the search bar (and hide it if we have no recent tasks)
+        if (Constants.DebugFlags.App.EnableSearchButton) {
+            createSearchBar();
+            if (!hasTasks) {
+                mSearchBar.setVisibility(View.GONE);
+            }
         }
     }
 
@@ -85,29 +104,45 @@
         // Get the first stack view
         int childCount = getChildCount();
         for (int i = 0; i < childCount; i++) {
-            TaskStackView stackView = (TaskStackView) getChildAt(i);
-            TaskStack stack = stackView.mStack;
-            ArrayList<Task> tasks = stack.getTasks();
+            View child = getChildAt(i);
+            if (child instanceof TaskStackView) {
+                TaskStackView stackView = (TaskStackView) child;
+                TaskStack stack = stackView.mStack;
+                ArrayList<Task> tasks = stack.getTasks();
 
-            // Get the first task in the stack
-            if (!tasks.isEmpty()) {
-                Task task = tasks.get(tasks.size() - 1);
-                TaskView tv = null;
+                // Get the first task in the stack
+                if (!tasks.isEmpty()) {
+                    Task task = tasks.get(tasks.size() - 1);
+                    TaskView tv = null;
 
-                // Try and use the first child task view as the source of the launch animation
-                if (stackView.getChildCount() > 0) {
-                    TaskView stv = (TaskView) stackView.getChildAt(stackView.getChildCount() - 1);
-                    if (stv.getTask() == task) {
-                        tv = stv;
+                    // Try and use the first child task view as the source of the launch animation
+                    if (stackView.getChildCount() > 0) {
+                        TaskView stv = (TaskView) stackView.getChildAt(stackView.getChildCount() - 1);
+                        if (stv.getTask() == task) {
+                            tv = stv;
+                        }
                     }
+                    onTaskLaunched(stackView, tv, stack, task);
+                    return true;
                 }
-                onTaskLaunched(stackView, tv, stack, task);
-                return true;
             }
         }
         return false;
     }
 
+    /** Creates and adds the search bar */
+    void createSearchBar() {
+        // Create a temporary search bar
+        mSearchBar = mInflater.inflate(R.layout.recents_search_bar, this, false);
+        mSearchBar.setOnClickListener(new OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                onSearchTriggered();
+            }
+        });
+        addView(mSearchBar);
+    }
+
     @Override
     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
         int width = MeasureSpec.getSize(widthMeasureSpec);
@@ -120,16 +155,26 @@
         Console.logTraceTime(Constants.DebugFlags.App.TimeRecentsStartup,
                 Constants.DebugFlags.App.TimeRecentsStartupKey, "RecentsView.onMeasure");
 
-        // We measure our stack views sans the status bar.  It will handle the nav bar itself.
+        // Get the search bar bounds so that we can account for its height in the children
+        Rect searchBarSpaceBounds = new Rect();
+        Rect searchBarBounds = new Rect();
         RecentsConfiguration config = RecentsConfiguration.getInstance();
+        config.getSearchBarBounds(getMeasuredWidth(), getMeasuredHeight(),
+                searchBarSpaceBounds, searchBarBounds);
+        if (mSearchBar != null) {
+            mSearchBar.measure(MeasureSpec.makeMeasureSpec(searchBarSpaceBounds.width(), widthMode),
+                    MeasureSpec.makeMeasureSpec(searchBarSpaceBounds.height(), heightMode));
+        }
+
+        // We measure our stack views sans the status bar.  It will handle the nav bar itself.
         int childWidth = width - config.systemInsets.right;
-        int childHeight = height - config.systemInsets.top;
+        int childHeight = height - config.systemInsets.top - searchBarSpaceBounds.height();
 
         // Measure each child
         int childCount = getChildCount();
         for (int i = 0; i < childCount; i++) {
-            final View child = getChildAt(i);
-            if (child.getVisibility() != GONE) {
+            View child = getChildAt(i);
+            if (child instanceof TaskStackView && child.getVisibility() != GONE) {
                 child.measure(MeasureSpec.makeMeasureSpec(childWidth, widthMode),
                         MeasureSpec.makeMeasureSpec(childHeight, heightMode));
             }
@@ -145,18 +190,30 @@
         Console.logTraceTime(Constants.DebugFlags.App.TimeRecentsStartup,
                 Constants.DebugFlags.App.TimeRecentsStartupKey, "RecentsView.onLayout");
 
-        // We offset our stack views by the status bar height.  It will handle the nav bar itself.
+        // Get the search bar bounds so that we can account for its height in the children
+        Rect searchBarSpaceBounds = new Rect();
+        Rect searchBarBounds = new Rect();
         RecentsConfiguration config = RecentsConfiguration.getInstance();
-        top += config.systemInsets.top;
+        config.getSearchBarBounds(getMeasuredWidth(), getMeasuredHeight(),
+                searchBarSpaceBounds, searchBarBounds);
+        if (mSearchBar != null) {
+            mSearchBar.layout(config.systemInsets.left + searchBarSpaceBounds.left,
+                    config.systemInsets.top + searchBarSpaceBounds.top,
+                    config.systemInsets.left + mSearchBar.getMeasuredWidth(),
+                    config.systemInsets.top + mSearchBar.getMeasuredHeight());
+        }
+
+        // We offset our stack views by the status bar height.  It will handle the nav bar itself.
+        top += config.systemInsets.top + searchBarSpaceBounds.height();
 
         // Layout each child
         // XXX: Based on the space node for that task view
         int childCount = getChildCount();
         for (int i = 0; i < childCount; i++) {
-            final View child = getChildAt(i);
-            if (child.getVisibility() != GONE) {
-                final int width = child.getMeasuredWidth();
-                final int height = child.getMeasuredHeight();
+            View child = getChildAt(i);
+            if (child instanceof TaskStackView && child.getVisibility() != GONE) {
+                int width = child.getMeasuredWidth();
+                int height = child.getMeasuredHeight();
                 child.layout(left, top, left + width, top + height);
             }
         }
@@ -188,9 +245,12 @@
             // Get the first stack view
             int childCount = getChildCount();
             for (int i = 0; i < childCount; i++) {
-                TaskStackView stackView = (TaskStackView) getChildAt(i);
-                if (stackView.closeOpenInfoPanes()) {
-                    return true;
+                View child = getChildAt(i);
+                if (child instanceof TaskStackView) {
+                    TaskStackView stackView = (TaskStackView) child;
+                    if (stackView.closeOpenInfoPanes()) {
+                        return true;
+                    }
                 }
             }
         }
@@ -315,4 +375,24 @@
         TaskStackBuilder.create(getContext())
                 .addNextIntentWithParentStack(intent).startActivities();
     }
+
+    public void onSearchTriggered() {
+        // Get the search bar source bounds
+        Rect searchBarSpaceBounds = new Rect();
+        Rect searchBarBounds = new Rect();
+        RecentsConfiguration config = RecentsConfiguration.getInstance();
+        config.getSearchBarBounds(getMeasuredWidth(), getMeasuredHeight(),
+                searchBarSpaceBounds, searchBarBounds);
+
+        // Get the search intent and start it
+        Intent searchIntent = RecentsTaskLoader.getInstance().getSystemServicesProxy()
+                .getGlobalSearchIntent(searchBarBounds);
+        if (searchIntent != null) {
+            try {
+                getContext().startActivity(searchIntent);
+            } catch (ActivityNotFoundException anfe) {
+                Console.logError(getContext(), "Could not start Search activity");
+            }
+        }
+    }
 }
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 c9a6d67..124f11e 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskBarView.java
@@ -31,7 +31,6 @@
     Task mTask;
 
     ImageView mApplicationIcon;
-    ImageView mActivityIcon;
     TextView mActivityDescription;
 
     public TaskBarView(Context context) {
@@ -54,23 +53,22 @@
     protected void onFinishInflate() {
         // Initialize the icon and description views
         mApplicationIcon = (ImageView) findViewById(R.id.application_icon);
-        mActivityIcon = (ImageView) findViewById(R.id.activity_icon);
         mActivityDescription = (TextView) findViewById(R.id.activity_description);
     }
 
     /** Binds the bar view to the task */
     void rebindToTask(Task t, boolean animate) {
         mTask = t;
-        if (t.applicationIcon != null) {
+        // If an activity icon is defined, then we use that as the primary icon to show in the bar,
+        // otherwise, we fall back to the application icon
+        if (t.activityIcon != null) {
+            mApplicationIcon.setImageDrawable(t.activityIcon);
+        } else if (t.applicationIcon != null) {
             mApplicationIcon.setImageDrawable(t.applicationIcon);
-            mActivityDescription.setText(t.activityLabel);
-            if (t.activityIcon != null) {
-                mActivityIcon.setImageBitmap(t.activityIcon);
-                mActivityIcon.setVisibility(View.VISIBLE);
-            }
-            if (animate) {
-                // XXX: Investigate how expensive it will be to create a second bitmap and crossfade
-            }
+        }
+        mActivityDescription.setText(t.activityLabel);
+        if (animate) {
+            // XXX: Investigate how expensive it will be to create a second bitmap and crossfade
         }
     }
 
@@ -78,8 +76,6 @@
     void unbindFromTask() {
         mTask = null;
         mApplicationIcon.setImageDrawable(null);
-        mActivityIcon.setImageBitmap(null);
-        mActivityIcon.setVisibility(View.INVISIBLE);
         mActivityDescription.setText("");
     }
 }
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 233e38c..a81d01c 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskInfoView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskInfoView.java
@@ -70,10 +70,8 @@
     /** Updates the positions of each of the items to fit in the rect specified */
     void updateContents(Rect visibleRect) {
         // Offset the app info button
-        LayoutParams lp = (LayoutParams) mAppInfoButton.getLayoutParams();
-        lp.topMargin = visibleRect.top +
-                (visibleRect.height() - mAppInfoButton.getMeasuredHeight()) / 2;
-        requestLayout();
+        mAppInfoButton.setTranslationY(visibleRect.top +
+                (visibleRect.height() - mAppInfoButton.getMeasuredHeight()) / 2);
     }
 
     /** Sets the circular clip radius on this panel */
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 ee92b16..a77e61d 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
@@ -395,9 +395,12 @@
         return false;
     }
 
-    /** Returns whether the current scroll is out of bounds */
+    /** Returns whether the specified scroll is out of bounds */
+    boolean isScrollOutOfBounds(int scroll) {
+        return (scroll < mMinScroll) || (scroll > mMaxScroll);
+    }
     boolean isScrollOutOfBounds() {
-        return (getStackScroll() < 0) || (getStackScroll() > mMaxScroll);
+        return isScrollOutOfBounds(getStackScroll());
     }
 
     /** Updates the min and max virtual scroll bounds */
@@ -556,7 +559,14 @@
 
         int smallestDimension = Math.min(width, height);
         int padding = (int) (Constants.Values.TaskStackView.StackPaddingPct * smallestDimension / 2f);
-        mStackRect.inset(padding, padding);
+        if (Constants.DebugFlags.App.EnableSearchButton) {
+            // Don't need to pad the top since we have some padding on the search bar already
+            mStackRect.left += padding;
+            mStackRect.right -= padding;
+            mStackRect.bottom -= padding;
+        } else {
+            mStackRect.inset(padding, padding);
+        }
         mStackRectSansPeek.set(mStackRect);
         mStackRectSansPeek.top += Constants.Values.TaskStackView.StackPeekHeightPct * mStackRect.height();
 
@@ -1275,7 +1285,12 @@
                     }
                 }
                 if (mIsScrolling) {
-                    mSv.setStackScroll(mSv.getStackScroll() + deltaY);
+                    int curStackScroll = mSv.getStackScroll();
+                    if (mSv.isScrollOutOfBounds(curStackScroll + deltaY)) {
+                        // Scale the touch if we are overscrolling
+                        deltaY /= Constants.Values.TaskStackView.TouchOverscrollScaleFactor;
+                    }
+                    mSv.setStackScroll(curStackScroll + deltaY);
                     if (mSv.isScrollOutOfBounds()) {
                         mVelocityTracker.clear();
                     }
diff --git a/services/core/java/com/android/server/BootReceiver.java b/services/core/java/com/android/server/BootReceiver.java
index bce85ce..7249985 100644
--- a/services/core/java/com/android/server/BootReceiver.java
+++ b/services/core/java/com/android/server/BootReceiver.java
@@ -106,22 +106,33 @@
             .append("Kernel: ")
             .append(FileUtils.readTextFile(new File("/proc/version"), 1024, "...\n"))
             .append("\n").toString();
+        final String bootReason = SystemProperties.get("ro.boot.bootreason", null);
 
         String recovery = RecoverySystem.handleAftermath();
         if (recovery != null && db != null) {
             db.addText("SYSTEM_RECOVERY_LOG", headers + recovery);
         }
 
+        String lastKmsgFooter = "";
+        if (bootReason != null) {
+            lastKmsgFooter = new StringBuilder(512)
+                .append("\n")
+                .append("Boot info:\n")
+                .append("Last boot reason: ").append(bootReason).append("\n")
+                .toString();
+        }
+
         if (SystemProperties.getLong("ro.runtime.firstboot", 0) == 0) {
             String now = Long.toString(System.currentTimeMillis());
             SystemProperties.set("ro.runtime.firstboot", now);
             if (db != null) db.addText("SYSTEM_BOOT", headers);
 
             // Negative sizes mean to take the *tail* of the file (see FileUtils.readTextFile())
-            addFileToDropBox(db, prefs, headers, "/proc/last_kmsg",
-                    -LOG_SIZE, "SYSTEM_LAST_KMSG");
-            addFileToDropBox(db, prefs, headers, "/sys/fs/pstore/console-ramoops",
-                    -LOG_SIZE, "SYSTEM_LAST_KMSG");
+            addFileWithFootersToDropBox(db, prefs, headers, lastKmsgFooter,
+                    "/proc/last_kmsg", -LOG_SIZE, "SYSTEM_LAST_KMSG");
+            addFileWithFootersToDropBox(db, prefs, headers, lastKmsgFooter,
+                    "/sys/fs/pstore/console-ramoops", -LOG_SIZE,
+                    "SYSTEM_LAST_KMSG");
             addFileToDropBox(db, prefs, headers, "/cache/recovery/log",
                     -LOG_SIZE, "SYSTEM_RECOVERY_LOG");
             addFileToDropBox(db, prefs, headers, "/data/dontpanic/apanic_console",
@@ -161,6 +172,14 @@
     private static void addFileToDropBox(
             DropBoxManager db, SharedPreferences prefs,
             String headers, String filename, int maxSize, String tag) throws IOException {
+        addFileWithFootersToDropBox(db, prefs, headers, "", filename, maxSize,
+                tag);
+    }
+
+    private static void addFileWithFootersToDropBox(
+            DropBoxManager db, SharedPreferences prefs,
+            String headers, String footers, String filename, int maxSize,
+            String tag) throws IOException {
         if (db == null || !db.isTagEnabled(tag)) return;  // Logging disabled
 
         File file = new File(filename);
@@ -176,7 +195,7 @@
         }
 
         Slog.i(TAG, "Copying " + filename + " to DropBox (" + tag + ")");
-        db.addText(tag, headers + FileUtils.readTextFile(file, maxSize, "[[TRUNCATED]]\n"));
+        db.addText(tag, headers + FileUtils.readTextFile(file, maxSize, "[[TRUNCATED]]\n") + footers);
     }
 
     private static void addAuditErrorsToDropBox(DropBoxManager db,  SharedPreferences prefs,