Merge "Get rid of redundant media profiles"
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index c502e6f..3a82c78 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -66,6 +66,7 @@
 import android.view.MenuItem;
 import android.view.MotionEvent;
 import android.view.View;
+import android.view.WindowManagerImpl;
 import android.view.View.OnCreateContextMenuListener;
 import android.view.ViewGroup;
 import android.view.ViewGroup.LayoutParams;
@@ -4402,6 +4403,9 @@
         if (mStopped) {
             mStopped = false;
             mCalled = false;
+            if (mToken != null && mParent == null) {
+                WindowManagerImpl.getDefault().setStoppedState(mToken, false);
+            }
             mInstrumentation.callActivityOnRestart(this);
             if (!mCalled) {
                 throw new SuperNotCalledException(
@@ -4478,6 +4482,10 @@
                 mWindow.closeAllPanels();
             }
 
+            if (mToken != null && mParent == null) {
+                WindowManagerImpl.getDefault().setStoppedState(mToken, true);
+            }
+            
             mFragments.dispatchStop();
             
             mCalled = false;
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 5c06151..af4c221 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -2447,21 +2447,26 @@
                 }
                 cache = child.getDrawingCache(true);
             } else {
-                if (layerType == LAYER_TYPE_SOFTWARE) {
-                    child.buildDrawingCache(true);
-                    cache = child.getDrawingCache(true);
-                } else if (layerType == LAYER_TYPE_NONE) {
-                    // Delay getting the display list until animation-driven alpha values are
-                    // set up and possibly passed on to the view
-                    hasDisplayList = child.canHaveDisplayList();
+                switch (layerType) {
+                    case LAYER_TYPE_SOFTWARE:
+                        child.buildDrawingCache(true);
+                        cache = child.getDrawingCache(true);
+                        break;
+                    case LAYER_TYPE_NONE:
+                        // Delay getting the display list until animation-driven alpha values are
+                        // set up and possibly passed on to the view
+                        hasDisplayList = child.canHaveDisplayList();
+                        break;
                 }
             }
         }
 
         final boolean hasNoCache = cache == null || hasDisplayList;
+        final boolean offsetForScroll = cache == null && !hasDisplayList &&
+                layerType != LAYER_TYPE_HARDWARE;
 
         final int restoreTo = canvas.save();
-        if (cache == null && !hasDisplayList) {
+        if (offsetForScroll) {
             canvas.translate(cl - sx, ct - sy);
         } else {
             canvas.translate(cl, ct);
@@ -2477,7 +2482,7 @@
                 int transX = 0;
                 int transY = 0;
 
-                if (cache == null && !hasDisplayList) {
+                if (offsetForScroll) {
                     transX = -sx;
                     transY = -sy;
                 }
@@ -2517,8 +2522,10 @@
                             layerFlags |= Canvas.CLIP_TO_LAYER_SAVE_FLAG;
                         }
                         if (layerType == LAYER_TYPE_NONE) {
-                            canvas.saveLayerAlpha(sx, sy, sx + cr - cl, sy + cb - ct,
-                                    multipliedAlpha, layerFlags);
+                            final int scrollX = hasDisplayList ? 0 : sx;
+                            final int scrollY = hasDisplayList ? 0 : sy;
+                            canvas.saveLayerAlpha(scrollX, scrollY, scrollX + cr - cl,
+                                    scrollY + cb - ct, multipliedAlpha, layerFlags);
                         }
                     } else {
                         // Alpha is handled by the child directly, clobber the layer's alpha
@@ -2532,7 +2539,7 @@
         }
 
         if ((flags & FLAG_CLIP_CHILDREN) == FLAG_CLIP_CHILDREN) {
-            if (cache == null && !hasDisplayList) {
+            if (offsetForScroll) {
                 canvas.clipRect(sx, sy, sx + (cr - cl), sy + (cb - ct));
             } else {
                 if (!scalingRequired || cache == null) {
@@ -2556,7 +2563,10 @@
                     ((HardwareCanvas) canvas).drawHardwareLayer(layer, 0, 0, child.mLayerPaint);
                     layerRendered = true;
                 } else {
-                    canvas.saveLayer(sx, sy, sx + cr - cl, sy + cb - ct, child.mLayerPaint,
+                    final int scrollX = hasDisplayList ? 0 : sx;
+                    final int scrollY = hasDisplayList ? 0 : sy;                    
+                    canvas.saveLayer(scrollX, scrollY,
+                            scrollX + cr - cl, scrollY + cb - ct, child.mLayerPaint,
                             Canvas.HAS_ALPHA_LAYER_SAVE_FLAG | Canvas.CLIP_TO_LAYER_SAVE_FLAG);
                 }
             }
diff --git a/core/java/android/view/ViewRoot.java b/core/java/android/view/ViewRoot.java
index c7b1955..965c959 100644
--- a/core/java/android/view/ViewRoot.java
+++ b/core/java/android/view/ViewRoot.java
@@ -155,6 +155,10 @@
     int mViewVisibility;
     boolean mAppVisible = true;
 
+    // Set to true if the owner of this window is in the stopped state,
+    // so the window should no longer be active.
+    boolean mStopped = false;
+    
     SurfaceHolder.Callback2 mSurfaceHolderCallback;
     BaseSurfaceHolder mSurfaceHolder;
     boolean mIsCreating;
@@ -618,6 +622,15 @@
         scheduleTraversals();
     }
 
+    void setStopped(boolean stopped) {
+        if (mStopped != stopped) {
+            mStopped = stopped;
+            if (!stopped) {
+                scheduleTraversals();
+            }
+        }
+    }
+    
     public ViewParent getParent() {
         return null;
     }
@@ -760,7 +773,7 @@
 
         boolean insetsChanged = false;
 
-        if (mLayoutRequested) {
+        if (mLayoutRequested && !mStopped) {
             // Execute enqueued actions on every layout in case a view that was detached
             // enqueued an action after being detached
             getRunQueue().executeActions(attachInfo.mHandler);
@@ -1143,54 +1156,56 @@
                 mAttachInfo.mHardwareRenderer.setup(mWidth, mHeight);
             }
 
-            boolean focusChangedDueToTouchMode = ensureTouchModeLocally(
-                    (relayoutResult&WindowManagerImpl.RELAYOUT_IN_TOUCH_MODE) != 0);
-            if (focusChangedDueToTouchMode || mWidth != host.getMeasuredWidth()
-                    || mHeight != host.getMeasuredHeight() || contentInsetsChanged) {
-                childWidthMeasureSpec = getRootMeasureSpec(mWidth, lp.width);
-                childHeightMeasureSpec = getRootMeasureSpec(mHeight, lp.height);
-
-                if (DEBUG_LAYOUT) Log.v(TAG, "Ooops, something changed!  mWidth="
-                        + mWidth + " measuredWidth=" + host.getMeasuredWidth()
-                        + " mHeight=" + mHeight
-                        + " measuredHeight=" + host.getMeasuredHeight()
-                        + " coveredInsetsChanged=" + contentInsetsChanged);
-
-                 // Ask host how big it wants to be
-                host.measure(childWidthMeasureSpec, childHeightMeasureSpec);
-
-                // Implementation of weights from WindowManager.LayoutParams
-                // We just grow the dimensions as needed and re-measure if
-                // needs be
-                int width = host.getMeasuredWidth();
-                int height = host.getMeasuredHeight();
-                boolean measureAgain = false;
-
-                if (lp.horizontalWeight > 0.0f) {
-                    width += (int) ((mWidth - width) * lp.horizontalWeight);
-                    childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(width,
-                            MeasureSpec.EXACTLY);
-                    measureAgain = true;
-                }
-                if (lp.verticalWeight > 0.0f) {
-                    height += (int) ((mHeight - height) * lp.verticalWeight);
-                    childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(height,
-                            MeasureSpec.EXACTLY);
-                    measureAgain = true;
-                }
-
-                if (measureAgain) {
-                    if (DEBUG_LAYOUT) Log.v(TAG,
-                            "And hey let's measure once more: width=" + width
-                            + " height=" + height);
+            if (!mStopped) {
+                boolean focusChangedDueToTouchMode = ensureTouchModeLocally(
+                        (relayoutResult&WindowManagerImpl.RELAYOUT_IN_TOUCH_MODE) != 0);
+                if (focusChangedDueToTouchMode || mWidth != host.getMeasuredWidth()
+                        || mHeight != host.getMeasuredHeight() || contentInsetsChanged) {
+                    childWidthMeasureSpec = getRootMeasureSpec(mWidth, lp.width);
+                    childHeightMeasureSpec = getRootMeasureSpec(mHeight, lp.height);
+    
+                    if (DEBUG_LAYOUT) Log.v(TAG, "Ooops, something changed!  mWidth="
+                            + mWidth + " measuredWidth=" + host.getMeasuredWidth()
+                            + " mHeight=" + mHeight
+                            + " measuredHeight=" + host.getMeasuredHeight()
+                            + " coveredInsetsChanged=" + contentInsetsChanged);
+    
+                     // Ask host how big it wants to be
                     host.measure(childWidthMeasureSpec, childHeightMeasureSpec);
+    
+                    // Implementation of weights from WindowManager.LayoutParams
+                    // We just grow the dimensions as needed and re-measure if
+                    // needs be
+                    int width = host.getMeasuredWidth();
+                    int height = host.getMeasuredHeight();
+                    boolean measureAgain = false;
+    
+                    if (lp.horizontalWeight > 0.0f) {
+                        width += (int) ((mWidth - width) * lp.horizontalWeight);
+                        childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(width,
+                                MeasureSpec.EXACTLY);
+                        measureAgain = true;
+                    }
+                    if (lp.verticalWeight > 0.0f) {
+                        height += (int) ((mHeight - height) * lp.verticalWeight);
+                        childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(height,
+                                MeasureSpec.EXACTLY);
+                        measureAgain = true;
+                    }
+    
+                    if (measureAgain) {
+                        if (DEBUG_LAYOUT) Log.v(TAG,
+                                "And hey let's measure once more: width=" + width
+                                + " height=" + height);
+                        host.measure(childWidthMeasureSpec, childHeightMeasureSpec);
+                    }
+    
+                    mLayoutRequested = true;
                 }
-
-                mLayoutRequested = true;
             }
         }
 
-        final boolean didLayout = mLayoutRequested;
+        final boolean didLayout = mLayoutRequested && !mStopped;
         boolean triggerGlobalLayoutListener = didLayout
                 || attachInfo.mRecomputeGlobalAttributes;
         if (didLayout) {
diff --git a/core/java/android/view/WindowManagerImpl.java b/core/java/android/view/WindowManagerImpl.java
index 07953d6..a4c4544 100644
--- a/core/java/android/view/WindowManagerImpl.java
+++ b/core/java/android/view/WindowManagerImpl.java
@@ -302,6 +302,20 @@
         }
     }
     
+    public void setStoppedState(IBinder token, boolean stopped) {
+        synchronized (this) {
+            if (mViews == null)
+                return;
+            int count = mViews.length;
+            for (int i=0; i<count; i++) {
+                if (token == null || mParams[i].token == token) {
+                    ViewRoot root = mRoots[i];
+                    root.setStopped(stopped);
+                }
+            }
+        }
+    }
+    
     public WindowManager.LayoutParams getRootViewLayoutParameter(View view) {
         ViewParent vp = view.getParent();
         while (vp != null && !(vp instanceof ViewRoot)) {
diff --git a/core/java/android/webkit/HTML5VideoViewProxy.java b/core/java/android/webkit/HTML5VideoViewProxy.java
index 2cc3881..85763da 100644
--- a/core/java/android/webkit/HTML5VideoViewProxy.java
+++ b/core/java/android/webkit/HTML5VideoViewProxy.java
@@ -184,12 +184,13 @@
             mVideoView.setWillNotDraw(false);
             mVideoView.setMediaController(new MediaController(proxy.getContext()));
 
-            String cookieValue = CookieManager.getInstance().getCookie(url);
+            boolean isPrivate = mCurrentProxy.getWebView().isPrivateBrowsingEnabled();
+            String cookieValue = CookieManager.getInstance().getCookie(url, isPrivate);
             Map<String, String> headers = new HashMap<String, String>();
             if (cookieValue != null) {
                 headers.put(COOKIE, cookieValue);
             }
-            if (mCurrentProxy.getWebView().isPrivateBrowsingEnabled()) {
+            if (isPrivate) {
                 headers.put(HIDE_URL_LOGS, "true");
             }
 
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index b1fdae0..2925632 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -1251,6 +1251,7 @@
         if (mOnScrollListener != null) {
             mOnScrollListener.onScroll(this, mFirstPosition, getChildCount(), mItemCount);
         }
+        onScrollChanged(0, 0, 0, 0); // dummy values, View's implementation does not use these.
     }
 
     /**
@@ -2789,8 +2790,9 @@
                 if (!mDataChanged) {
                     if ((mTouchMode != TOUCH_MODE_FLING) && (motionPosition >= 0)
                             && (getAdapter().isEnabled(motionPosition))) {
-                        // User clicked on an actual view (and was not stopping a fling). It might be a
-                        // click or a scroll. Assume it is a click until proven otherwise
+                        // User clicked on an actual view (and was not stopping a fling).
+                        // It might be a click or a scroll. Assume it is a click until
+                        // proven otherwise
                         mTouchMode = TOUCH_MODE_DOWN;
                         // FIXME Debounce
                         if (mPendingCheckForTap == null) {
@@ -2799,9 +2801,10 @@
                         postDelayed(mPendingCheckForTap, ViewConfiguration.getTapTimeout());
                     } else {
                         if (ev.getEdgeFlags() != 0 && motionPosition < 0) {
-                            // If we couldn't find a view to click on, but the down event was touching
-                            // the edge, we will bail out and try again. This allows the edge correcting
-                            // code in ViewRoot to try to find a nearby view to select
+                            // If we couldn't find a view to click on, but the down event
+                            // was touching the edge, we will bail out and try again.
+                            // This allows the edge correcting code in ViewRoot to try to
+                            // find a nearby view to select
                             return false;
                         }
 
@@ -3015,7 +3018,11 @@
             case TOUCH_MODE_DONE_WAITING:
                 final int motionPosition = mMotionPosition;
                 final View child = getChildAt(motionPosition - mFirstPosition);
-                if (child != null && !child.hasFocusable()) {
+
+                final float x = ev.getX();
+                final boolean inList = x > mListPadding.left && x < getWidth() - mListPadding.right;
+
+                if (child != null && !child.hasFocusable() && inList) {
                     if (mTouchMode != TOUCH_MODE_DOWN) {
                         child.setPressed(false);
                     }
@@ -3264,18 +3271,20 @@
     }
 
     @Override
-    protected void onOverScrolled(int scrollX, int scrollY,
-            boolean clampedX, boolean clampedY) {
-        mScrollY = scrollY;
-        invalidateParentIfNeeded();
+    protected void onOverScrolled(int scrollX, int scrollY, boolean clampedX, boolean clampedY) {
+        if (mScrollY != scrollY) {
+            onScrollChanged(mScrollX, scrollY, mScrollX, mScrollY);
+            mScrollY = scrollY;
+            invalidateParentIfNeeded();
 
-        if (clampedY) {
-            // Velocity is broken by hitting the limit; don't start a fling off of this.
-            if (mVelocityTracker != null) {
-                mVelocityTracker.clear();
+            if (clampedY) {
+                // Velocity is broken by hitting the limit; don't start a fling off of this.
+                if (mVelocityTracker != null) {
+                    mVelocityTracker.clear();
+                }
             }
+            awakenScrollBars();
         }
-        awakenScrollBars();
     }
 
     @Override
@@ -4293,17 +4302,12 @@
             mLastPositionDistanceGuess += incrementalDeltaY;
         }
 
-        if (firstPosition == 0 && firstTop >= listPadding.top && incrementalDeltaY >= 0) {
-            // Don't need to move views down if the top of the first position
-            // is already visible
-            return incrementalDeltaY != 0;
-        }
+        final boolean cannotScrollDown = (firstPosition == 0 &&
+                firstTop >= listPadding.top && incrementalDeltaY >= 0);
+        final boolean cannotScrollUp = (firstPosition + childCount == mItemCount &&
+                lastBottom <= getHeight() - listPadding.bottom && incrementalDeltaY <= 0);
 
-        if (firstPosition + childCount == mItemCount &&
-                lastBottom <= getHeight() - listPadding.bottom &&
-                incrementalDeltaY <= 0) {
-            // Don't need to move views up if the bottom of the last position
-            // is already visible
+        if (cannotScrollDown || cannotScrollUp) {
             return incrementalDeltaY != 0;
         }
 
diff --git a/core/java/android/widget/StackView.java b/core/java/android/widget/StackView.java
index e6cf31e..bab469b 100644
--- a/core/java/android/widget/StackView.java
+++ b/core/java/android/widget/StackView.java
@@ -33,6 +33,7 @@
 import android.graphics.TableMaskFilter;
 import android.util.AttributeSet;
 import android.util.Log;
+import android.view.InputDevice;
 import android.view.MotionEvent;
 import android.view.VelocityTracker;
 import android.view.View;
@@ -114,6 +115,8 @@
 
     private static final int MIN_TIME_BETWEEN_INTERACTION_AND_AUTOADVANCE = 5000;
 
+    private static long MIN_TIME_BETWEEN_SCROLLS = 100;
+
     /**
      * These variables are all related to the current state of touch interaction
      * with the stack
@@ -137,6 +140,7 @@
     private StackSlider mStackSlider;
     private boolean mFirstLayoutHappened = false;
     private long mLastInteractionTime = 0;
+    private long mLastScrollTime;
     private int mStackMode;
     private int mFramePadding;
     private final Rect stackInvalidateRect = new Rect();
@@ -565,6 +569,38 @@
         }
     }
 
+    @Override
+    public boolean onGenericMotionEvent(MotionEvent event) {
+        if ((event.getSource() & InputDevice.SOURCE_CLASS_POINTER) != 0) {
+            switch (event.getAction()) {
+                case MotionEvent.ACTION_SCROLL: {
+                    final float vscroll = event.getAxisValue(MotionEvent.AXIS_VSCROLL);
+                    if (vscroll < 0) {
+                        pacedScroll(false);
+                        return true;
+                    } else if (vscroll > 0) {
+                        pacedScroll(true);
+                        return true;
+                    }
+                }
+            }
+        }
+        return super.onGenericMotionEvent(event);
+    }
+
+    // This ensures that the frequency of stack flips caused by scrolls is capped
+    private void pacedScroll(boolean up) {
+        long timeSinceLastScroll = System.currentTimeMillis() - mLastScrollTime;
+        if (timeSinceLastScroll > MIN_TIME_BETWEEN_SCROLLS) {
+            if (up) {
+                showPrevious();
+            } else {
+                showNext();
+            }
+            mLastScrollTime = System.currentTimeMillis();
+        }
+    }
+
     /**
      * {@inheritDoc}
      */
diff --git a/include/gui/SurfaceTexture.h b/include/gui/SurfaceTexture.h
index 31615d0..9bf38f7 100644
--- a/include/gui/SurfaceTexture.h
+++ b/include/gui/SurfaceTexture.h
@@ -37,7 +37,8 @@
 
 class SurfaceTexture : public BnSurfaceTexture {
 public:
-    enum { MIN_BUFFER_SLOTS = 3 };
+    enum { MIN_UNDEQUEUED_BUFFERS = 2 };
+    enum { MIN_BUFFER_SLOTS = MIN_UNDEQUEUED_BUFFERS + 1 };
     enum { NUM_BUFFER_SLOTS = 32 };
 
     struct FrameAvailableListener : public virtual RefBase {
diff --git a/include/gui/SurfaceTextureClient.h b/include/gui/SurfaceTextureClient.h
index ff2251d..4cdece9 100644
--- a/include/gui/SurfaceTextureClient.h
+++ b/include/gui/SurfaceTextureClient.h
@@ -40,40 +40,41 @@
     SurfaceTextureClient(const SurfaceTextureClient& rhs);
 
     // ANativeWindow hooks
-    static int setSwapInterval(ANativeWindow* window, int interval);
-    static int dequeueBuffer(ANativeWindow* window, android_native_buffer_t** buffer);
     static int cancelBuffer(ANativeWindow* window, android_native_buffer_t* buffer);
+    static int dequeueBuffer(ANativeWindow* window, android_native_buffer_t** buffer);
     static int lockBuffer(ANativeWindow* window, android_native_buffer_t* buffer);
-    static int queueBuffer(ANativeWindow* window, android_native_buffer_t* buffer);
-    static int query(ANativeWindow* window, int what, int* value);
     static int perform(ANativeWindow* window, int operation, ...);
+    static int query(ANativeWindow* window, int what, int* value);
+    static int queueBuffer(ANativeWindow* window, android_native_buffer_t* buffer);
+    static int setSwapInterval(ANativeWindow* window, int interval);
 
-    int setSwapInterval(int interval);
+    int cancelBuffer(android_native_buffer_t* buffer);
     int dequeueBuffer(android_native_buffer_t** buffer);
     int lockBuffer(android_native_buffer_t* buffer);
-    int queueBuffer(android_native_buffer_t* buffer);
-    int cancelBuffer(android_native_buffer_t* buffer);
-    int query(int what, int* value);
     int perform(int operation, va_list args);
+    int query(int what, int* value);
+    int queueBuffer(android_native_buffer_t* buffer);
+    int setSwapInterval(int interval);
 
-    int dispatchSetUsage(va_list args);
     int dispatchConnect(va_list args);
     int dispatchDisconnect(va_list args);
-    int dispatchSetCrop(va_list args);
     int dispatchSetBufferCount(va_list args);
     int dispatchSetBuffersGeometry(va_list args);
     int dispatchSetBuffersTransform(va_list args);
+    int dispatchSetCrop(va_list args);
+    int dispatchSetUsage(va_list args);
 
     int connect(int api);
     int disconnect(int api);
-    int setUsage(uint32_t reqUsage);
-    int setCrop(Rect const* rect);
     int setBufferCount(int bufferCount);
     int setBuffersGeometry(int w, int h, int format);
     int setBuffersTransform(int transform);
+    int setCrop(Rect const* rect);
+    int setUsage(uint32_t reqUsage);
 
     void freeAllBuffers();
 
+    enum { MIN_UNDEQUEUED_BUFFERS = SurfaceTexture::MIN_UNDEQUEUED_BUFFERS };
     enum { MIN_BUFFER_SLOTS = SurfaceTexture::MIN_BUFFER_SLOTS };
     enum { NUM_BUFFER_SLOTS = SurfaceTexture::NUM_BUFFER_SLOTS };
     enum { DEFAULT_FORMAT = PIXEL_FORMAT_RGBA_8888 };
diff --git a/include/surfaceflinger/Surface.h b/include/surfaceflinger/Surface.h
index d783caf..9e0b5bb 100644
--- a/include/surfaceflinger/Surface.h
+++ b/include/surfaceflinger/Surface.h
@@ -242,6 +242,10 @@
     status_t validate(bool inCancelBuffer = false) const;
     sp<ISurface> getISurface() const;
 
+    // When the buffer pool is a fixed size we want to make sure SurfaceFlinger
+    // won't stall clients, so we require an extra buffer.
+    enum { MIN_UNDEQUEUED_BUFFERS = 2 };
+
     inline const GraphicBufferMapper& getBufferMapper() const { return mBufferMapper; }
     inline GraphicBufferMapper& getBufferMapper() { return mBufferMapper; }
 
diff --git a/include/ui/egl/android_natives.h b/include/ui/egl/android_natives.h
index fdc8105..fd83f46 100644
--- a/include/ui/egl/android_natives.h
+++ b/include/ui/egl/android_natives.h
@@ -75,6 +75,26 @@
     NATIVE_WINDOW_WIDTH     = 0,
     NATIVE_WINDOW_HEIGHT,
     NATIVE_WINDOW_FORMAT,
+
+    /* The minimum number of buffers that must remain un-dequeued after a buffer
+     * has been queued.  This value applies only if set_buffer_count was used to
+     * override the number of buffers and if a buffer has since been queued.
+     * Users of the set_buffer_count ANativeWindow method should query this
+     * value before calling set_buffer_count.  If it is necessary to have N
+     * buffers simultaneously dequeued as part of the steady-state operation,
+     * and this query returns M then N+M buffers should be requested via
+     * native_window_set_buffer_count.
+     *
+     * Note that this value does NOT apply until a single buffer has been
+     * queued.  In particular this means that it is possible to:
+     *
+     * 1. Query M = min undequeued buffers
+     * 2. Set the buffer count to N + M
+     * 3. Dequeue all N + M buffers
+     * 4. Cancel M buffers
+     * 5. Queue, dequeue, queue, dequeue, ad infinitum
+     */
+    NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS,
 };
 
 /* valid operations for the (*perform)() hook */
diff --git a/libs/gui/SurfaceTexture.cpp b/libs/gui/SurfaceTexture.cpp
index 223cf09..3bed959 100644
--- a/libs/gui/SurfaceTexture.cpp
+++ b/libs/gui/SurfaceTexture.cpp
@@ -96,6 +96,11 @@
 
 status_t SurfaceTexture::setBufferCount(int bufferCount) {
     LOGV("SurfaceTexture::setBufferCount");
+
+    if (bufferCount < MIN_BUFFER_SLOTS) {
+        return BAD_VALUE;
+    }
+
     Mutex::Autolock lock(mMutex);
     freeAllBuffers();
     mBufferCount = bufferCount;
diff --git a/libs/gui/SurfaceTextureClient.cpp b/libs/gui/SurfaceTextureClient.cpp
index ee14ac9..43b330c 100644
--- a/libs/gui/SurfaceTextureClient.cpp
+++ b/libs/gui/SurfaceTextureClient.cpp
@@ -143,8 +143,21 @@
 int SurfaceTextureClient::query(int what, int* value) {
     LOGV("SurfaceTextureClient::query");
     Mutex::Autolock lock(mMutex);
-    // XXX: Implement this!
-    return INVALID_OPERATION;
+    switch (what) {
+    case NATIVE_WINDOW_WIDTH:
+    case NATIVE_WINDOW_HEIGHT:
+        // XXX: How should SurfaceTexture behave if setBuffersGeometry didn't
+        // override the size?
+        *value = 0;
+        return NO_ERROR;
+    case NATIVE_WINDOW_FORMAT:
+        *value = DEFAULT_FORMAT;
+        return NO_ERROR;
+    case NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS:
+        *value = MIN_UNDEQUEUED_BUFFERS;
+        return NO_ERROR;
+    }
+    return BAD_VALUE;
 }
 
 int SurfaceTextureClient::perform(int operation, va_list args)
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index 48b3d6e..361815a 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -213,6 +213,17 @@
     if (mDirtyClip) {
         setScissorFromClip();
     }
+
+#if RENDER_LAYERS_AS_REGIONS
+    // Since we don't know what the functor will draw, let's dirty
+    // tne entire clip region
+    if (hasLayer()) {
+        Rect clip(*mSnapshot->clipRect);
+        clip.snapToPixelBoundaries();
+        dirtyLayerUnchecked(clip, getRegion());
+    }
+#endif
+
     status_t result = (*functor)();
     resume();
     return (result == 0) ? false : true;
diff --git a/libs/hwui/TextDropShadowCache.cpp b/libs/hwui/TextDropShadowCache.cpp
index 3256790..8f6f860 100644
--- a/libs/hwui/TextDropShadowCache.cpp
+++ b/libs/hwui/TextDropShadowCache.cpp
@@ -147,6 +147,9 @@
             if (mDebugEnabled) {
                 LOGD("Shadow texture created, size = %d", texture->bitmapSize);
             }
+
+            entry.copyTextLocally();
+
             mSize += size;
             mCache.put(entry, texture);
         } else {
diff --git a/libs/hwui/TextDropShadowCache.h b/libs/hwui/TextDropShadowCache.h
index 1e065d1..62c4250 100644
--- a/libs/hwui/TextDropShadowCache.h
+++ b/libs/hwui/TextDropShadowCache.h
@@ -21,7 +21,7 @@
 
 #include <SkPaint.h>
 
-#include <utils/String8.h>
+#include <utils/String16.h>
 
 #include "utils/Compare.h"
 #include "utils/GenerationCache.h"
@@ -37,18 +37,13 @@
 
     ShadowText(SkPaint* paint, uint32_t radius, uint32_t len, const char* srcText):
             radius(radius), len(len) {
-        // The source text we receive is in UTF-16, convert to UTF-8
-        str.setTo((const char16_t*) srcText, len >> 1);
+        // TODO: Propagate this through the API, we should not cast here
+        text = (const char16_t*) srcText;
 
         textSize = paint->getTextSize();
         typeface = paint->getTypeface();
     }
 
-    ShadowText(const ShadowText& shadow):
-            radius(shadow.radius), len(shadow.len), textSize(shadow.textSize),
-            typeface(shadow.typeface), str(shadow.str) {
-    }
-
     ~ShadowText() {
     }
 
@@ -56,16 +51,21 @@
     uint32_t len;
     float textSize;
     SkTypeface* typeface;
-    String8 str;
+    const char16_t* text;
+    String16 str;
+
+    void copyTextLocally() {
+        str.setTo((const char16_t*) text, len >> 1);
+        text = str.string();
+    }
 
     // TODO: Should take into account fake bold and text skew
     bool operator<(const ShadowText& rhs) const {
         LTE_INT(len) {
             LTE_INT(radius) {
                 LTE_FLOAT(textSize) {
-                    if (typeface < rhs.typeface) return true;
-                    else if (typeface == rhs.typeface) {
-                        return str.compare(rhs.str) < 0;
+                    LTE_INT(typeface) {
+                        return strncmp16(text, rhs.text, len >> 1) < 0;
                     }
                 }
             }
diff --git a/libs/surfaceflinger_client/Surface.cpp b/libs/surfaceflinger_client/Surface.cpp
index 68611d6..818114a 100644
--- a/libs/surfaceflinger_client/Surface.cpp
+++ b/libs/surfaceflinger_client/Surface.cpp
@@ -709,6 +709,9 @@
     case NATIVE_WINDOW_FORMAT:
         *value = int(mFormat);
         return NO_ERROR;
+    case NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS:
+        *value = MIN_UNDEQUEUED_BUFFERS;
+        return NO_ERROR;
     }
     return BAD_VALUE;
 }
diff --git a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
index ebe3302..0b061db 100644
--- a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
+++ b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
@@ -53,6 +53,11 @@
 namespace android {
 namespace {
 
+// Flag to allow a one time init of global memory, only happens on first call ever
+int LvmInitFlag = LVM_FALSE;
+SessionContext GlobalSessionMemory[LVM_MAX_SESSIONS];
+int SessionIndex[LVM_MAX_SESSIONS];
+
 /* local functions */
 #define CHECK_ARG(cond) {                     \
     if (!(cond)) {                            \
@@ -61,11 +66,6 @@
     }                                         \
 }
 
-// Flag to allow a one time init of global memory, only happens on first call ever
-int LvmInitFlag = LVM_FALSE;
-SessionContext GlobalSessionMemory[LVM_MAX_SESSIONS];
-
-int SessionIndex[LVM_MAX_SESSIONS];
 
 // NXP SW BassBoost UUID
 const effect_descriptor_t gBassBoostDescriptor = {
@@ -2588,9 +2588,11 @@
             pContext->pBundledContext->SamplesToExitCountBb -= outBuffer->frameCount * 2; // STEREO
             //LOGV("\tEffect_process: Waiting to turn off BASS_BOOST, %d samples left",
             //    pContext->pBundledContext->SamplesToExitCountBb);
-        } else {
+        }
+        if(pContext->pBundledContext->SamplesToExitCountBb <= 0) {
             status = -ENODATA;
             pContext->pBundledContext->NumberEffectsEnabled--;
+            LOGV("\tEffect_process() this is the last frame for LVM_BASS_BOOST");
         }
     }
     if ((pContext->pBundledContext->bVolumeEnabled == LVM_FALSE)&&
@@ -2606,9 +2608,11 @@
             pContext->pBundledContext->SamplesToExitCountEq -= outBuffer->frameCount * 2; // STEREO
             //LOGV("\tEffect_process: Waiting to turn off EQUALIZER, %d samples left",
             //    pContext->pBundledContext->SamplesToExitCountEq);
-        } else {
+        }
+        if(pContext->pBundledContext->SamplesToExitCountEq <= 0) {
             status = -ENODATA;
             pContext->pBundledContext->NumberEffectsEnabled--;
+            LOGV("\tEffect_process() this is the last frame for LVM_EQUALIZER");
         }
     }
     if ((pContext->pBundledContext->bVirtualizerEnabled == LVM_FALSE)&&
@@ -2618,9 +2622,11 @@
             pContext->pBundledContext->SamplesToExitCountVirt -= outBuffer->frameCount * 2;// STEREO
             //LOGV("\tEffect_process: Waiting for to turn off VIRTUALIZER, %d samples left",
             //    pContext->pBundledContext->SamplesToExitCountVirt);
-        } else {
+        }
+        if(pContext->pBundledContext->SamplesToExitCountVirt <= 0) {
             status = -ENODATA;
             pContext->pBundledContext->NumberEffectsEnabled--;
+            LOGV("\tEffect_process() this is the last frame for LVM_VIRTUALIZER");
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/RecentAppsPanel.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/RecentAppsPanel.java
index ebe1a7c..1135b73 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/RecentAppsPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/RecentAppsPanel.java
@@ -40,7 +40,6 @@
 import android.graphics.Shader.TileMode;
 import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.Drawable;
-import android.os.Parcelable;
 import android.util.AttributeSet;
 import android.util.DisplayMetrics;
 import android.util.Log;
@@ -64,7 +63,6 @@
     private static final boolean DEBUG = TabletStatusBar.DEBUG;
     private static final int DISPLAY_TASKS = 20;
     private static final int MAX_TASKS = DISPLAY_TASKS + 1; // allow extra for non-apps
-    private static final int BOTTOM_OFFSET = 28; // TODO: Get from dimens.xml
     private TabletStatusBar mBar;
     private ArrayList<ActivityDescription> mActivityDescriptions;
     private int mIconDpi;
@@ -104,7 +102,7 @@
         }
     };
 
-    private static class ViewHolder {
+    /* package */ final static class ViewHolder {
         private ImageView thumbnailView;
         private ImageView iconView;
         private TextView labelView;
@@ -112,7 +110,7 @@
         private ActivityDescription activityDescription;
     }
 
-    private class ActvityDescriptionAdapter extends BaseAdapter {
+    /* package */ final class ActvityDescriptionAdapter extends BaseAdapter {
         private LayoutInflater mInflater;
 
         public ActvityDescriptionAdapter(Context context) {
@@ -361,7 +359,7 @@
         View footer = inflater.inflate(R.layout.status_bar_recent_panel_footer,
                 mRecentsContainer, false);
         mRecentsContainer.setScrollbarFadingEnabled(true);
-        mRecentsContainer.addFooterView(footer);
+        mRecentsContainer.addFooterView(footer, null, false);
         mRecentsContainer.setAdapter(mListAdapter = new ActvityDescriptionAdapter(mContext));
         mRecentsContainer.setOnItemClickListener(this);
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
index f0408a2..c123cea 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
@@ -586,8 +586,7 @@
                 case MSG_OPEN_RECENTS_PANEL:
                     if (DEBUG) Slog.d(TAG, "opening recents panel");
                     if (mRecentsPanel != null) {
-                        disable(StatusBarManager.DISABLE_NAVIGATION
-                                | StatusBarManager.DISABLE_BACK);
+                        disable(StatusBarManager.DISABLE_BACK);
                         mRecentsPanel.setVisibility(View.VISIBLE);
                         mRecentsPanel.show(true, true);
                     }
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 8d30868..ea49661 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -9114,15 +9114,17 @@
                 ServiceRecord.StartItem si = r.pendingStarts.remove(0);
                 if (DEBUG_SERVICE) Slog.v(TAG, "Sending arguments to: "
                         + r + " " + r.intent + " args=" + si.intent);
-                if (si.intent == null) {
-                    // If somehow we got a dummy start at the front, then
-                    // just drop it here.
+                if (si.intent == null && N > 1) {
+                    // If somehow we got a dummy null intent in the middle,
+                    // then skip it.  DO NOT skip a null intent when it is
+                    // the only one in the list -- this is to support the
+                    // onStartCommand(null) case.
                     continue;
                 }
                 si.deliveredTime = SystemClock.uptimeMillis();
                 r.deliveredStarts.add(si);
                 si.deliveryCount++;
-                if (si.targetPermissionUid >= 0) {
+                if (si.targetPermissionUid >= 0 && si.intent != null) {
                     grantUriPermissionUncheckedFromIntentLocked(si.targetPermissionUid,
                             r.packageName, si.intent, si.getUriPermissionsLocked());
                 }