Merge "Fix issue #5679504: Device stuck and sudden reboot - Watchdog reset?" into ics-mr1
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index 8ed7481..180a442 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -625,7 +625,7 @@
             return info.activityInfo.loadIcon(this);
         }
 
-        throw new NameNotFoundException(intent.toURI());
+        throw new NameNotFoundException(intent.toUri(0));
     }
 
     @Override public Drawable getDefaultActivityIcon() {
@@ -728,15 +728,22 @@
 
     private Drawable getCachedIcon(ResourceName name) {
         synchronized (sSync) {
-            WeakReference<Drawable> wr = sIconCache.get(name);
+            WeakReference<Drawable.ConstantState> wr = sIconCache.get(name);
             if (DEBUG_ICONS) Log.v(TAG, "Get cached weak drawable ref for "
                                    + name + ": " + wr);
             if (wr != null) {   // we have the activity
-                Drawable dr = wr.get();
-                if (dr != null) {
-                    if (DEBUG_ICONS) Log.v(TAG, "Get cached drawable for "
-                                           + name + ": " + dr);
-                    return dr;
+                Drawable.ConstantState state = wr.get();
+                if (state != null) {
+                    if (DEBUG_ICONS) {
+                        Log.v(TAG, "Get cached drawable state for " + name + ": " + state);
+                    }
+                    // Note: It's okay here to not use the newDrawable(Resources) variant
+                    //       of the API. The ConstantState comes from a drawable that was
+                    //       originally created by passing the proper app Resources instance
+                    //       which means the state should already contain the proper
+                    //       resources specific information (like density.) See
+                    //       BitmapDrawable.BitmapState for instance.
+                    return state.newDrawable();
                 }
                 // our entry has been purged
                 sIconCache.remove(name);
@@ -747,14 +754,12 @@
 
     private void putCachedIcon(ResourceName name, Drawable dr) {
         synchronized (sSync) {
-            sIconCache.put(name, new WeakReference<Drawable>(dr));
-            if (DEBUG_ICONS) Log.v(TAG, "Added cached drawable for "
-                                   + name + ": " + dr);
+            sIconCache.put(name, new WeakReference<Drawable.ConstantState>(dr.getConstantState()));
+            if (DEBUG_ICONS) Log.v(TAG, "Added cached drawable state for " + name + ": " + dr);
         }
     }
 
-    static final void handlePackageBroadcast(int cmd, String[] pkgList,
-                                             boolean hasPkgInfo) {
+    static void handlePackageBroadcast(int cmd, String[] pkgList, boolean hasPkgInfo) {
         boolean immediateGc = false;
         if (cmd == IApplicationThread.EXTERNAL_STORAGE_UNAVAILABLE) {
             immediateGc = true;
@@ -1226,8 +1231,8 @@
     private final IPackageManager mPM;
 
     private static final Object sSync = new Object();
-    private static HashMap<ResourceName, WeakReference<Drawable> > sIconCache
-            = new HashMap<ResourceName, WeakReference<Drawable> >();
-    private static HashMap<ResourceName, WeakReference<CharSequence> > sStringCache
-            = new HashMap<ResourceName, WeakReference<CharSequence> >();
+    private static HashMap<ResourceName, WeakReference<Drawable.ConstantState>> sIconCache
+            = new HashMap<ResourceName, WeakReference<Drawable.ConstantState>>();
+    private static HashMap<ResourceName, WeakReference<CharSequence>> sStringCache
+            = new HashMap<ResourceName, WeakReference<CharSequence>>();
 }
diff --git a/core/java/android/app/DatePickerDialog.java b/core/java/android/app/DatePickerDialog.java
index 8b70370..bf8fde0 100644
--- a/core/java/android/app/DatePickerDialog.java
+++ b/core/java/android/app/DatePickerDialog.java
@@ -91,13 +91,14 @@
 
         mCallBack = callBack;
 
-        setButton(BUTTON_POSITIVE, context.getText(R.string.date_time_set), this);
-        setButton(BUTTON_NEGATIVE, context.getText(R.string.cancel), (OnClickListener) null);
+        Context themeContext = getContext();
+        setButton(BUTTON_POSITIVE, themeContext.getText(R.string.date_time_set), this);
+        setButton(BUTTON_NEGATIVE, themeContext.getText(R.string.cancel), (OnClickListener) null);
         setIcon(0);
         setTitle(R.string.date_picker_dialog_title);
 
         LayoutInflater inflater =
-                (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+                (LayoutInflater) themeContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
         View view = inflater.inflate(R.layout.date_picker_dialog, null);
         setView(view);
         mDatePicker = (DatePicker) view.findViewById(R.id.datePicker);
diff --git a/core/java/android/app/TimePickerDialog.java b/core/java/android/app/TimePickerDialog.java
index a990ee9..353b415 100644
--- a/core/java/android/app/TimePickerDialog.java
+++ b/core/java/android/app/TimePickerDialog.java
@@ -92,16 +92,16 @@
         mInitialMinute = minute;
         mIs24HourView = is24HourView;
 
-        setCanceledOnTouchOutside(false);
         setIcon(0);
         setTitle(R.string.time_picker_dialog_title);
 
-        setButton(BUTTON_POSITIVE, context.getText(R.string.date_time_set), this);
-        setButton(BUTTON_NEGATIVE, context.getText(R.string.cancel),
+        Context themeContext = getContext();
+        setButton(BUTTON_POSITIVE, themeContext.getText(R.string.date_time_set), this);
+        setButton(BUTTON_NEGATIVE, themeContext.getText(R.string.cancel),
                 (OnClickListener) null);
 
         LayoutInflater inflater =
-                (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+                (LayoutInflater) themeContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
         View view = inflater.inflate(R.layout.time_picker_dialog, null);
         setView(view);
         mTimePicker = (TimePicker) view.findViewById(R.id.timePicker);
diff --git a/core/java/android/speech/tts/AudioPlaybackHandler.java b/core/java/android/speech/tts/AudioPlaybackHandler.java
index fd00dce..46a78dc 100644
--- a/core/java/android/speech/tts/AudioPlaybackHandler.java
+++ b/core/java/android/speech/tts/AudioPlaybackHandler.java
@@ -428,7 +428,8 @@
         final AudioTrack audioTrack = params.getAudioTrack();
 
         if (audioTrack == null) {
-            params.getDispatcher().dispatchOnError();
+            // There was already a call to handleSynthesisDone for
+            // this token.
             return;
         }
 
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 2af6e3b..7155159 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -4604,14 +4604,15 @@
         boolean UIAnimationsRunning = false;
         // Currently for each draw we compute the animation values;
         // We may in the future decide to do that independently.
-        if (mNativeClass != 0 && nativeEvaluateLayersAnimations(mNativeClass)) {
+        if (mNativeClass != 0 && !canvas.isHardwareAccelerated()
+                && nativeEvaluateLayersAnimations(mNativeClass)) {
             UIAnimationsRunning = true;
             // If we have unfinished (or unstarted) animations,
             // we ask for a repaint. We only need to do this in software
             // rendering (with hardware rendering we already have a different
             // method of requesting a repaint)
-            if (!canvas.isHardwareAccelerated())
-                invalidate();
+            mWebViewCore.sendMessage(EventHub.NOTIFY_ANIMATION_STARTED);
+            invalidate();
         }
 
         // decide which adornments to draw
@@ -8796,10 +8797,13 @@
 
     /** @hide Called by JNI when pages are swapped (only occurs with hardware
      * acceleration) */
-    protected void pageSwapCallback() {
+    protected void pageSwapCallback(boolean notifyAnimationStarted) {
         if (inEditingMode()) {
             didUpdateWebTextViewDimensions(ANYWHERE);
         }
+        if (notifyAnimationStarted) {
+            mWebViewCore.sendMessage(EventHub.NOTIFY_ANIMATION_STARTED);
+        }
     }
 
     void setNewPicture(final WebViewCore.DrawData draw, boolean updateBaseLayer) {
diff --git a/core/java/android/webkit/WebViewCore.java b/core/java/android/webkit/WebViewCore.java
index 2ad866b..d136004 100644
--- a/core/java/android/webkit/WebViewCore.java
+++ b/core/java/android/webkit/WebViewCore.java
@@ -519,7 +519,12 @@
     /**
      * Update the layers' content
      */
-    private native boolean nativeUpdateLayers(int baseLayer);
+    private native boolean nativeUpdateLayers(int nativeClass, int baseLayer);
+
+    /**
+     * Notify webkit that animations have begun (on the hardware accelerated content)
+     */
+    private native void nativeNotifyAnimationStarted(int nativeClass);
 
     private native boolean nativeFocusBoundsChanged();
 
@@ -1035,6 +1040,8 @@
 
         static final int PLUGIN_SURFACE_READY = 195;
 
+        static final int NOTIFY_ANIMATION_STARTED = 196;
+
         // private message ids
         private static final int DESTROY =     200;
 
@@ -1594,6 +1601,10 @@
                             nativePluginSurfaceReady();
                             break;
 
+                        case NOTIFY_ANIMATION_STARTED:
+                            nativeNotifyAnimationStarted(mNativeClass);
+                            break;
+
                         case ADD_PACKAGE_NAMES:
                             if (BrowserFrame.sJavaBridge == null) {
                                 throw new IllegalStateException("No WebView " +
@@ -2015,7 +2026,7 @@
             return;
         }
         // Directly update the layers we last passed to the UI side
-        if (nativeUpdateLayers(mLastDrawData.mBaseLayer)) {
+        if (nativeUpdateLayers(mNativeClass, mLastDrawData.mBaseLayer)) {
             // If anything more complex than position has been touched, let's do a full draw
             webkitDraw();
         }
diff --git a/core/java/android/widget/NumberPicker.java b/core/java/android/widget/NumberPicker.java
index 1a1b8d0..d185370 100644
--- a/core/java/android/widget/NumberPicker.java
+++ b/core/java/android/widget/NumberPicker.java
@@ -165,6 +165,11 @@
     };
 
     /**
+     * Constant for unspecified size.
+     */
+    private static final int SIZE_UNSPECIFIED = -1;
+
+    /**
      * Use a custom NumberPicker formatting callback to use two-digit minutes
      * strings like "01". Keeping a static formatter etc. is the most efficient
      * way to do this; it avoids creating temporary objects on every call to
@@ -542,16 +547,20 @@
                 getResources().getDisplayMetrics());
         mSelectionDividerHeight = attributesArray.getDimensionPixelSize(
                 R.styleable.NumberPicker_selectionDividerHeight, defSelectionDividerHeight);
-        mMinHeight = attributesArray.getDimensionPixelSize(R.styleable.NumberPicker_minHeight, 0);
+        mMinHeight = attributesArray.getDimensionPixelSize(R.styleable.NumberPicker_minHeight,
+                SIZE_UNSPECIFIED);
         mMaxHeight = attributesArray.getDimensionPixelSize(R.styleable.NumberPicker_maxHeight,
-                Integer.MAX_VALUE);
-        if (mMinHeight > mMaxHeight) {
+                SIZE_UNSPECIFIED);
+        if (mMinHeight != SIZE_UNSPECIFIED && mMaxHeight != SIZE_UNSPECIFIED
+                && mMinHeight > mMaxHeight) {
             throw new IllegalArgumentException("minHeight > maxHeight");
         }
-        mMinWidth = attributesArray.getDimensionPixelSize(R.styleable.NumberPicker_minWidth, 0);
+        mMinWidth = attributesArray.getDimensionPixelSize(R.styleable.NumberPicker_minWidth,
+                SIZE_UNSPECIFIED);
         mMaxWidth = attributesArray.getDimensionPixelSize(R.styleable.NumberPicker_maxWidth,
-                Integer.MAX_VALUE);
-        if (mMinWidth > mMaxWidth) {
+                SIZE_UNSPECIFIED);
+        if (mMinWidth != SIZE_UNSPECIFIED && mMaxWidth != SIZE_UNSPECIFIED
+                && mMinWidth > mMaxWidth) {
             throw new IllegalArgumentException("minWidth > maxWidth");
         }
         mComputeMaxWidth = (mMaxWidth == Integer.MAX_VALUE);
@@ -746,10 +755,10 @@
         final int newHeightMeasureSpec = makeMeasureSpec(heightMeasureSpec, mMaxHeight);
         super.onMeasure(newWidthMeasureSpec, newHeightMeasureSpec);
         // Flag if we are measured with width or height less than the respective min.
-        final int desiredWidth = Math.max(mMinWidth, getMeasuredWidth());
-        final int desiredHeight = Math.max(mMinHeight, getMeasuredHeight());
-        final int widthSize = resolveSizeAndState(desiredWidth, newWidthMeasureSpec, 0);
-        final int heightSize = resolveSizeAndState(desiredHeight, newHeightMeasureSpec, 0);
+        final int widthSize = resolveSizeAndStateRespectingMinSize(mMinWidth, getMeasuredWidth(),
+                widthMeasureSpec);
+        final int heightSize = resolveSizeAndStateRespectingMinSize(mMinHeight, getMeasuredHeight(),
+                heightMeasureSpec);
         setMeasuredDimension(widthSize, heightSize);
     }
 
@@ -1243,6 +1252,7 @@
         }
         updateInputTextView();
         initializeSelectorWheelIndices();
+        tryComputeMaxWidth();
     }
 
     @Override
@@ -1368,6 +1378,9 @@
      * @return A measure spec greedily imposing the max size.
      */
     private int makeMeasureSpec(int measureSpec, int maxSize) {
+        if (maxSize == SIZE_UNSPECIFIED) {
+            return measureSpec;
+        }
         final int size = MeasureSpec.getSize(measureSpec);
         final int mode = MeasureSpec.getMode(measureSpec);
         switch (mode) {
@@ -1383,6 +1396,26 @@
     }
 
     /**
+     * Utility to reconcile a desired size and state, with constraints imposed by
+     * a MeasureSpec. Tries to respect the min size, unless a different size is
+     * imposed by the constraints.
+     *
+     * @param minSize The minimal desired size.
+     * @param measuredSize The currently measured size.
+     * @param measureSpec The current measure spec.
+     * @return The resolved size and state.
+     */
+    private int resolveSizeAndStateRespectingMinSize(int minSize, int measuredSize,
+            int measureSpec) {
+        if (minSize != SIZE_UNSPECIFIED) {
+            final int desiredWidth = Math.max(minSize, measuredSize);
+            return resolveSizeAndState(desiredWidth, measureSpec, 0);
+        } else {
+            return measuredSize;
+        }
+    }
+
+    /**
      * Resets the selector indices and clear the cached
      * string representation of these indices.
      */
diff --git a/core/res/res/layout/date_picker.xml b/core/res/res/layout/date_picker.xml
index 6f0517d..9c1def2 100644
--- a/core/res/res/layout/date_picker.xml
+++ b/core/res/res/layout/date_picker.xml
@@ -32,7 +32,6 @@
     <LinearLayout android:id="@+id/pickers"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:layout_marginRight="22dip"
         android:layout_weight="1"
         android:orientation="horizontal"
         android:gravity="center">
@@ -77,7 +76,7 @@
         android:id="@+id/calendar_view"
         android:layout_width="245dip"
         android:layout_height="280dip"
-        android:layout_marginLeft="22dip"
+        android:layout_marginLeft="44dip"
         android:layout_weight="1"
         android:focusable="true"
         android:focusableInTouchMode="true"
diff --git a/include/gui/SurfaceTexture.h b/include/gui/SurfaceTexture.h
index 15c2bab..a8c7672 100644
--- a/include/gui/SurfaceTexture.h
+++ b/include/gui/SurfaceTexture.h
@@ -60,10 +60,16 @@
         virtual void onFrameAvailable() = 0;
     };
 
-    // tex indicates the name OpenGL texture to which images are to be streamed.
-    // This texture name cannot be changed once the SurfaceTexture is created.
+    // SurfaceTexture constructs a new SurfaceTexture object. tex indicates the
+    // name of the OpenGL ES texture to which images are to be streamed. This
+    // texture name cannot be changed once the SurfaceTexture is created.
+    // allowSynchronousMode specifies whether or not synchronous mode can be
+    // enabled. texTarget specifies the OpenGL ES texture target to which the
+    // texture will be bound in updateTexImage. useFenceSync specifies whether
+    // fences should be used to synchronize access to buffers if that behavior
+    // is enabled at compile-time.
     SurfaceTexture(GLuint tex, bool allowSynchronousMode = true,
-            GLenum texTarget = GL_TEXTURE_EXTERNAL_OES);
+            GLenum texTarget = GL_TEXTURE_EXTERNAL_OES, bool useFenceSync = true);
 
     virtual ~SurfaceTexture();
 
@@ -276,7 +282,8 @@
               mTransform(0),
               mScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE),
               mTimestamp(0),
-              mFrameNumber(0) {
+              mFrameNumber(0),
+              mFence(EGL_NO_SYNC_KHR) {
             mCrop.makeInvalid();
         }
 
@@ -349,6 +356,11 @@
         // mFrameNumber is the number of the queued frame for this slot.
         uint64_t mFrameNumber;
 
+        // mFence is the EGL sync object that must signal before the buffer
+        // associated with this buffer slot may be dequeued. It is initialized
+        // to EGL_NO_SYNC_KHR when the buffer is created and (optionally, based
+        // on a compile-time option) set to a new sync object in updateTexImage.
+        EGLSyncKHR mFence;
     };
 
     // mSlots is the array of buffer slots that must be mirrored on the client
@@ -472,6 +484,12 @@
     // It is set by the setName method.
     String8 mName;
 
+    // mUseFenceSync indicates whether creation of the EGL_KHR_fence_sync
+    // extension should be used to prevent buffers from being dequeued before
+    // it's safe for them to be written. It gets set at construction time and
+    // never changes.
+    const bool mUseFenceSync;
+
     // mMutex is the mutex used to prevent concurrent access to the member
     // variables of SurfaceTexture objects. It must be locked whenever the
     // member variables are accessed.
diff --git a/include/ui/GraphicBuffer.h b/include/ui/GraphicBuffer.h
index b9deafc..6ab01f4 100644
--- a/include/ui/GraphicBuffer.h
+++ b/include/ui/GraphicBuffer.h
@@ -63,6 +63,7 @@
         USAGE_HW_RENDER         = GRALLOC_USAGE_HW_RENDER,
         USAGE_HW_2D             = GRALLOC_USAGE_HW_2D,
         USAGE_HW_COMPOSER       = GRALLOC_USAGE_HW_COMPOSER,
+        USAGE_HW_VIDEO_ENCODER  = GRALLOC_USAGE_HW_VIDEO_ENCODER,
         USAGE_HW_MASK           = GRALLOC_USAGE_HW_MASK
     };
 
diff --git a/libs/gui/SurfaceTexture.cpp b/libs/gui/SurfaceTexture.cpp
index beb23f6..fcd287c 100644
--- a/libs/gui/SurfaceTexture.cpp
+++ b/libs/gui/SurfaceTexture.cpp
@@ -36,6 +36,12 @@
 #include <utils/Log.h>
 #include <utils/String8.h>
 
+// This compile option causes SurfaceTexture to return the buffer that is currently
+// attached to the GL texture from dequeueBuffer when no other buffers are
+// available.  It requires the drivers (Gralloc, GL, OMX IL, and Camera) to do
+// implicit cross-process synchronization to prevent the buffer from being
+// written to before the buffer has (a) been detached from the GL texture and
+// (b) all GL reads from the buffer have completed.
 #ifdef ALLOW_DEQUEUE_CURRENT_BUFFER
 #define FLAG_ALLOW_DEQUEUE_CURRENT_BUFFER    true
 #warning "ALLOW_DEQUEUE_CURRENT_BUFFER enabled"
@@ -43,6 +49,16 @@
 #define FLAG_ALLOW_DEQUEUE_CURRENT_BUFFER    false
 #endif
 
+// This compile option makes SurfaceTexture use the EGL_KHR_fence_sync extension
+// to synchronize access to the buffers.  It will cause dequeueBuffer to stall,
+// waiting for the GL reads for the buffer being dequeued to complete before
+// allowing the buffer to be dequeued.
+#ifdef USE_FENCE_SYNC
+#ifdef ALLOW_DEQUEUE_CURRENT_BUFFER
+#error "USE_FENCE_SYNC and ALLOW_DEQUEUE_CURRENT_BUFFER are incompatible"
+#endif
+#endif
+
 // Macros for including the SurfaceTexture name in log messages
 #define ST_LOGV(x, ...) LOGV("[%s] "x, mName.string(), ##__VA_ARGS__)
 #define ST_LOGD(x, ...) LOGD("[%s] "x, mName.string(), ##__VA_ARGS__)
@@ -99,7 +115,7 @@
 }
 
 SurfaceTexture::SurfaceTexture(GLuint tex, bool allowSynchronousMode,
-        GLenum texTarget) :
+        GLenum texTarget, bool useFenceSync) :
     mDefaultWidth(1),
     mDefaultHeight(1),
     mPixelFormat(PIXEL_FORMAT_RGBA_8888),
@@ -116,6 +132,11 @@
     mAllowSynchronousMode(allowSynchronousMode),
     mConnectedApi(NO_CONNECTED_API),
     mAbandoned(false),
+#ifdef USE_FENCE_SYNC
+    mUseFenceSync(useFenceSync),
+#else
+    mUseFenceSync(false),
+#endif
     mTexTarget(texTarget),
     mFrameCounter(0) {
     // Choose a name using the PID and a process-unique ID.
@@ -261,195 +282,225 @@
         return BAD_VALUE;
     }
 
-    Mutex::Autolock lock(mMutex);
-
     status_t returnFlags(OK);
+    EGLDisplay dpy = EGL_NO_DISPLAY;
+    EGLSyncKHR fence = EGL_NO_SYNC_KHR;
 
-    int found = -1;
-    int foundSync = -1;
-    int dequeuedCount = 0;
-    bool tryAgain = true;
-    while (tryAgain) {
-        if (mAbandoned) {
-            ST_LOGE("dequeueBuffer: SurfaceTexture has been abandoned!");
-            return NO_INIT;
-        }
+    { // Scope for the lock
+        Mutex::Autolock lock(mMutex);
 
-        // We need to wait for the FIFO to drain if the number of buffer
-        // needs to change.
-        //
-        // The condition "number of buffers needs to change" is true if
-        // - the client doesn't care about how many buffers there are
-        // - AND the actual number of buffer is different from what was
-        //   set in the last setBufferCountServer()
-        //                         - OR -
-        //   setBufferCountServer() was set to a value incompatible with
-        //   the synchronization mode (for instance because the sync mode
-        //   changed since)
-        //
-        // As long as this condition is true AND the FIFO is not empty, we
-        // wait on mDequeueCondition.
-
-        const int minBufferCountNeeded = mSynchronousMode ?
-                MIN_SYNC_BUFFER_SLOTS : MIN_ASYNC_BUFFER_SLOTS;
-
-        const bool numberOfBuffersNeedsToChange = !mClientBufferCount &&
-                ((mServerBufferCount != mBufferCount) ||
-                        (mServerBufferCount < minBufferCountNeeded));
-
-        if (!mQueue.isEmpty() && numberOfBuffersNeedsToChange) {
-            // wait for the FIFO to drain
-            mDequeueCondition.wait(mMutex);
-            // NOTE: we continue here because we need to reevaluate our
-            // whole state (eg: we could be abandoned or disconnected)
-            continue;
-        }
-
-        if (numberOfBuffersNeedsToChange) {
-            // here we're guaranteed that mQueue is empty
-            freeAllBuffersLocked();
-            mBufferCount = mServerBufferCount;
-            if (mBufferCount < minBufferCountNeeded)
-                mBufferCount = minBufferCountNeeded;
-            mCurrentTexture = INVALID_BUFFER_SLOT;
-            returnFlags |= ISurfaceTexture::RELEASE_ALL_BUFFERS;
-        }
-
-        // look for a free buffer to give to the client
-        found = INVALID_BUFFER_SLOT;
-        foundSync = INVALID_BUFFER_SLOT;
-        dequeuedCount = 0;
-        for (int i = 0; i < mBufferCount; i++) {
-            const int state = mSlots[i].mBufferState;
-            if (state == BufferSlot::DEQUEUED) {
-                dequeuedCount++;
+        int found = -1;
+        int foundSync = -1;
+        int dequeuedCount = 0;
+        bool tryAgain = true;
+        while (tryAgain) {
+            if (mAbandoned) {
+                ST_LOGE("dequeueBuffer: SurfaceTexture has been abandoned!");
+                return NO_INIT;
             }
 
-            // if buffer is FREE it CANNOT be current
-            LOGW_IF((state == BufferSlot::FREE) && (mCurrentTexture==i),
-                    "dequeueBuffer: buffer %d is both FREE and current!", i);
+            // We need to wait for the FIFO to drain if the number of buffer
+            // needs to change.
+            //
+            // The condition "number of buffers needs to change" is true if
+            // - the client doesn't care about how many buffers there are
+            // - AND the actual number of buffer is different from what was
+            //   set in the last setBufferCountServer()
+            //                         - OR -
+            //   setBufferCountServer() was set to a value incompatible with
+            //   the synchronization mode (for instance because the sync mode
+            //   changed since)
+            //
+            // As long as this condition is true AND the FIFO is not empty, we
+            // wait on mDequeueCondition.
 
-            if (FLAG_ALLOW_DEQUEUE_CURRENT_BUFFER) {
-                if (state == BufferSlot::FREE || i == mCurrentTexture) {
-                    foundSync = i;
-                    if (i != mCurrentTexture) {
-                        found = i;
-                        break;
-                    }
+            const int minBufferCountNeeded = mSynchronousMode ?
+                    MIN_SYNC_BUFFER_SLOTS : MIN_ASYNC_BUFFER_SLOTS;
+
+            const bool numberOfBuffersNeedsToChange = !mClientBufferCount &&
+                    ((mServerBufferCount != mBufferCount) ||
+                            (mServerBufferCount < minBufferCountNeeded));
+
+            if (!mQueue.isEmpty() && numberOfBuffersNeedsToChange) {
+                // wait for the FIFO to drain
+                mDequeueCondition.wait(mMutex);
+                // NOTE: we continue here because we need to reevaluate our
+                // whole state (eg: we could be abandoned or disconnected)
+                continue;
+            }
+
+            if (numberOfBuffersNeedsToChange) {
+                // here we're guaranteed that mQueue is empty
+                freeAllBuffersLocked();
+                mBufferCount = mServerBufferCount;
+                if (mBufferCount < minBufferCountNeeded)
+                    mBufferCount = minBufferCountNeeded;
+                mCurrentTexture = INVALID_BUFFER_SLOT;
+                returnFlags |= ISurfaceTexture::RELEASE_ALL_BUFFERS;
+            }
+
+            // look for a free buffer to give to the client
+            found = INVALID_BUFFER_SLOT;
+            foundSync = INVALID_BUFFER_SLOT;
+            dequeuedCount = 0;
+            for (int i = 0; i < mBufferCount; i++) {
+                const int state = mSlots[i].mBufferState;
+                if (state == BufferSlot::DEQUEUED) {
+                    dequeuedCount++;
                 }
-            } else {
-                if (state == BufferSlot::FREE) {
-                    /** For Asynchronous mode, we need to return the oldest of free buffers
-                    * There is only one instance when the Framecounter overflows, this logic
-                    * might return the earlier buffer to client. Which is a negligible impact
-                    **/
-                    if (found < 0 || mSlots[i].mFrameNumber < mSlots[found].mFrameNumber) {
+
+                // if buffer is FREE it CANNOT be current
+                LOGW_IF((state == BufferSlot::FREE) && (mCurrentTexture==i),
+                        "dequeueBuffer: buffer %d is both FREE and current!",
+                        i);
+
+                if (FLAG_ALLOW_DEQUEUE_CURRENT_BUFFER) {
+                    if (state == BufferSlot::FREE || i == mCurrentTexture) {
                         foundSync = i;
-                        found = i;
+                        if (i != mCurrentTexture) {
+                            found = i;
+                            break;
+                        }
+                    }
+                } else {
+                    if (state == BufferSlot::FREE) {
+                        /* We return the oldest of the free buffers to avoid
+                         * stalling the producer if possible.  This is because
+                         * the consumer may still have pending reads of the
+                         * buffers in flight.
+                         */
+                        bool isOlder = mSlots[i].mFrameNumber <
+                                mSlots[found].mFrameNumber;
+                        if (found < 0 || isOlder) {
+                            foundSync = i;
+                            found = i;
+                        }
                     }
                 }
             }
-        }
 
-        // clients are not allowed to dequeue more than one buffer
-        // if they didn't set a buffer count.
-        if (!mClientBufferCount && dequeuedCount) {
-            ST_LOGE("dequeueBuffer: can't dequeue multiple buffers without "
-                    "setting the buffer count");
-            return -EINVAL;
-        }
+            // clients are not allowed to dequeue more than one buffer
+            // if they didn't set a buffer count.
+            if (!mClientBufferCount && dequeuedCount) {
+                ST_LOGE("dequeueBuffer: can't dequeue multiple buffers without "
+                        "setting the buffer count");
+                return -EINVAL;
+            }
 
-        // See whether a buffer has been queued since the last setBufferCount so
-        // we know whether to perform the MIN_UNDEQUEUED_BUFFERS check below.
-        bool bufferHasBeenQueued = mCurrentTexture != INVALID_BUFFER_SLOT;
-        if (bufferHasBeenQueued) {
-            // make sure the client is not trying to dequeue more buffers
-            // than allowed.
-            const int avail = mBufferCount - (dequeuedCount+1);
-            if (avail < (MIN_UNDEQUEUED_BUFFERS-int(mSynchronousMode))) {
-                ST_LOGE("dequeueBuffer: MIN_UNDEQUEUED_BUFFERS=%d exceeded "
-                        "(dequeued=%d)",
-                        MIN_UNDEQUEUED_BUFFERS-int(mSynchronousMode),
-                        dequeuedCount);
-                return -EBUSY;
+            // See whether a buffer has been queued since the last
+            // setBufferCount so we know whether to perform the
+            // MIN_UNDEQUEUED_BUFFERS check below.
+            bool bufferHasBeenQueued = mCurrentTexture != INVALID_BUFFER_SLOT;
+            if (bufferHasBeenQueued) {
+                // make sure the client is not trying to dequeue more buffers
+                // than allowed.
+                const int avail = mBufferCount - (dequeuedCount+1);
+                if (avail < (MIN_UNDEQUEUED_BUFFERS-int(mSynchronousMode))) {
+                    ST_LOGE("dequeueBuffer: MIN_UNDEQUEUED_BUFFERS=%d exceeded "
+                            "(dequeued=%d)",
+                            MIN_UNDEQUEUED_BUFFERS-int(mSynchronousMode),
+                            dequeuedCount);
+                    return -EBUSY;
+                }
+            }
+
+            // we're in synchronous mode and didn't find a buffer, we need to
+            // wait for some buffers to be consumed
+            tryAgain = mSynchronousMode && (foundSync == INVALID_BUFFER_SLOT);
+            if (tryAgain) {
+                mDequeueCondition.wait(mMutex);
             }
         }
 
-        // we're in synchronous mode and didn't find a buffer, we need to wait
-        // for some buffers to be consumed
-        tryAgain = mSynchronousMode && (foundSync == INVALID_BUFFER_SLOT);
-        if (tryAgain) {
-            mDequeueCondition.wait(mMutex);
+        if (mSynchronousMode && found == INVALID_BUFFER_SLOT) {
+            // foundSync guaranteed to be != INVALID_BUFFER_SLOT
+            found = foundSync;
         }
-    }
 
-    if (mSynchronousMode && found == INVALID_BUFFER_SLOT) {
-        // foundSync guaranteed to be != INVALID_BUFFER_SLOT
-        found = foundSync;
-    }
-
-    if (found == INVALID_BUFFER_SLOT) {
-        // This should not happen.
-        ST_LOGE("dequeueBuffer: no available buffer slots");
-        return -EBUSY;
-    }
-
-    const int buf = found;
-    *outBuf = found;
-
-    const bool useDefaultSize = !w && !h;
-    if (useDefaultSize) {
-        // use the default size
-        w = mDefaultWidth;
-        h = mDefaultHeight;
-    }
-
-    const bool updateFormat = (format != 0);
-    if (!updateFormat) {
-        // keep the current (or default) format
-        format = mPixelFormat;
-    }
-
-    // buffer is now in DEQUEUED (but can also be current at the same time,
-    // if we're in synchronous mode)
-    mSlots[buf].mBufferState = BufferSlot::DEQUEUED;
-
-    const sp<GraphicBuffer>& buffer(mSlots[buf].mGraphicBuffer);
-    if ((buffer == NULL) ||
-        (uint32_t(buffer->width)  != w) ||
-        (uint32_t(buffer->height) != h) ||
-        (uint32_t(buffer->format) != format) ||
-        ((uint32_t(buffer->usage) & usage) != usage))
-    {
-        usage |= GraphicBuffer::USAGE_HW_TEXTURE;
-        status_t error;
-        sp<GraphicBuffer> graphicBuffer(
-                mGraphicBufferAlloc->createGraphicBuffer(
-                        w, h, format, usage, &error));
-        if (graphicBuffer == 0) {
-            ST_LOGE("dequeueBuffer: SurfaceComposer::createGraphicBuffer "
-                    "failed");
-            return error;
+        if (found == INVALID_BUFFER_SLOT) {
+            // This should not happen.
+            ST_LOGE("dequeueBuffer: no available buffer slots");
+            return -EBUSY;
         }
-        if (updateFormat) {
-            mPixelFormat = format;
+
+        const int buf = found;
+        *outBuf = found;
+
+        const bool useDefaultSize = !w && !h;
+        if (useDefaultSize) {
+            // use the default size
+            w = mDefaultWidth;
+            h = mDefaultHeight;
         }
-        mSlots[buf].mGraphicBuffer = graphicBuffer;
-        mSlots[buf].mRequestBufferCalled = false;
-        if (mSlots[buf].mEglImage != EGL_NO_IMAGE_KHR) {
-            eglDestroyImageKHR(mSlots[buf].mEglDisplay, mSlots[buf].mEglImage);
-            mSlots[buf].mEglImage = EGL_NO_IMAGE_KHR;
-            mSlots[buf].mEglDisplay = EGL_NO_DISPLAY;
+
+        const bool updateFormat = (format != 0);
+        if (!updateFormat) {
+            // keep the current (or default) format
+            format = mPixelFormat;
         }
-        if (mCurrentTexture == buf) {
-            // The current texture no longer references the buffer in this slot
-            // since we just allocated a new buffer.
-            mCurrentTexture = INVALID_BUFFER_SLOT;
+
+        // buffer is now in DEQUEUED (but can also be current at the same time,
+        // if we're in synchronous mode)
+        mSlots[buf].mBufferState = BufferSlot::DEQUEUED;
+
+        const sp<GraphicBuffer>& buffer(mSlots[buf].mGraphicBuffer);
+        if ((buffer == NULL) ||
+            (uint32_t(buffer->width)  != w) ||
+            (uint32_t(buffer->height) != h) ||
+            (uint32_t(buffer->format) != format) ||
+            ((uint32_t(buffer->usage) & usage) != usage))
+        {
+            usage |= GraphicBuffer::USAGE_HW_TEXTURE;
+            status_t error;
+            sp<GraphicBuffer> graphicBuffer(
+                    mGraphicBufferAlloc->createGraphicBuffer(
+                            w, h, format, usage, &error));
+            if (graphicBuffer == 0) {
+                ST_LOGE("dequeueBuffer: SurfaceComposer::createGraphicBuffer "
+                        "failed");
+                return error;
+            }
+            if (updateFormat) {
+                mPixelFormat = format;
+            }
+            mSlots[buf].mGraphicBuffer = graphicBuffer;
+            mSlots[buf].mRequestBufferCalled = false;
+            mSlots[buf].mFence = EGL_NO_SYNC_KHR;
+            if (mSlots[buf].mEglImage != EGL_NO_IMAGE_KHR) {
+                eglDestroyImageKHR(mSlots[buf].mEglDisplay,
+                        mSlots[buf].mEglImage);
+                mSlots[buf].mEglImage = EGL_NO_IMAGE_KHR;
+                mSlots[buf].mEglDisplay = EGL_NO_DISPLAY;
+            }
+            if (mCurrentTexture == buf) {
+                // The current texture no longer references the buffer in this slot
+                // since we just allocated a new buffer.
+                mCurrentTexture = INVALID_BUFFER_SLOT;
+            }
+            returnFlags |= ISurfaceTexture::BUFFER_NEEDS_REALLOCATION;
         }
-        returnFlags |= ISurfaceTexture::BUFFER_NEEDS_REALLOCATION;
+
+        dpy = mSlots[buf].mEglDisplay;
+        fence = mSlots[buf].mFence;
+        mSlots[buf].mFence = EGL_NO_SYNC_KHR;
     }
+
+    if (fence != EGL_NO_SYNC_KHR) {
+        EGLint result = eglClientWaitSyncKHR(dpy, fence, 0, 1000000000);
+        // If something goes wrong, log the error, but return the buffer without
+        // synchronizing access to it.  It's too late at this point to abort the
+        // dequeue operation.
+        if (result == EGL_FALSE) {
+            LOGE("dequeueBuffer: error waiting for fence: %#x", eglGetError());
+        } else if (result == EGL_TIMEOUT_EXPIRED_KHR) {
+            LOGE("dequeueBuffer: timeout waiting for fence");
+        }
+        eglDestroySyncKHR(dpy, fence);
+    }
+
     ST_LOGV("dequeueBuffer: returning slot=%d buf=%p flags=%#x", buf,
             mSlots[buf].mGraphicBuffer->handle, returnFlags);
+
     return returnFlags;
 }
 
@@ -712,8 +763,8 @@
 
         // Update the GL texture object.
         EGLImageKHR image = mSlots[buf].mEglImage;
+        EGLDisplay dpy = eglGetCurrentDisplay();
         if (image == EGL_NO_IMAGE_KHR) {
-            EGLDisplay dpy = eglGetCurrentDisplay();
             if (mSlots[buf].mGraphicBuffer == 0) {
                 ST_LOGE("buffer at slot %d is null", buf);
                 return BAD_VALUE;
@@ -746,16 +797,32 @@
             return -EINVAL;
         }
 
-        ST_LOGV("updateTexImage: (slot=%d buf=%p) -> (slot=%d buf=%p)", mCurrentTexture,
-                mCurrentTextureBuf != NULL ? mCurrentTextureBuf->handle : 0, buf,
-                mSlots[buf].mGraphicBuffer->handle);
+        if (mCurrentTexture != INVALID_BUFFER_SLOT) {
+            if (mUseFenceSync) {
+                EGLSyncKHR fence = eglCreateSyncKHR(dpy, EGL_SYNC_FENCE_KHR,
+                        NULL);
+                if (fence == EGL_NO_SYNC_KHR) {
+                    LOGE("updateTexImage: error creating fence: %#x",
+                            eglGetError());
+                    return -EINVAL;
+                }
+                glFlush();
+                mSlots[mCurrentTexture].mFence = fence;
+            }
+        }
+
+        ST_LOGV("updateTexImage: (slot=%d buf=%p) -> (slot=%d buf=%p)",
+                mCurrentTexture,
+                mCurrentTextureBuf != NULL ? mCurrentTextureBuf->handle : 0,
+                buf, mSlots[buf].mGraphicBuffer->handle);
 
         if (mCurrentTexture != INVALID_BUFFER_SLOT) {
             // The current buffer becomes FREE if it was still in the queued
             // state. If it has already been given to the client
             // (synchronous mode), then it stays in DEQUEUED state.
-            if (mSlots[mCurrentTexture].mBufferState == BufferSlot::QUEUED)
+            if (mSlots[mCurrentTexture].mBufferState == BufferSlot::QUEUED) {
                 mSlots[mCurrentTexture].mBufferState = BufferSlot::FREE;
+            }
         }
 
         // Update the SurfaceTexture state.
diff --git a/libs/gui/tests/SurfaceTexture_test.cpp b/libs/gui/tests/SurfaceTexture_test.cpp
index 6d1b951..c313904 100644
--- a/libs/gui/tests/SurfaceTexture_test.cpp
+++ b/libs/gui/tests/SurfaceTexture_test.cpp
@@ -536,6 +536,20 @@
     }
 }
 
+void fillRGBA8BufferSolid(uint8_t* buf, int w, int h, int stride, uint8_t r,
+        uint8_t g, uint8_t b, uint8_t a) {
+    const size_t PIXEL_SIZE = 4;
+    for (int y = 0; y < h; y++) {
+        for (int x = 0; x < h; x++) {
+            off_t offset = (y * stride + x) * PIXEL_SIZE;
+            buf[offset + 0] = r;
+            buf[offset + 1] = g;
+            buf[offset + 2] = b;
+            buf[offset + 3] = a;
+        }
+    }
+}
+
 TEST_F(SurfaceTextureGLTest, TexturingFromCpuFilledYV12BufferNpot) {
     const int texWidth = 64;
     const int texHeight = 66;
@@ -1616,4 +1630,101 @@
     }
 }
 
+class SurfaceTextureFBOTest : public SurfaceTextureGLTest {
+protected:
+
+    virtual void SetUp() {
+        SurfaceTextureGLTest::SetUp();
+
+        glGenFramebuffers(1, &mFbo);
+        ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
+
+        glGenTextures(1, &mFboTex);
+        glBindTexture(GL_TEXTURE_2D, mFboTex);
+        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, getSurfaceWidth(),
+                getSurfaceHeight(), 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
+        glBindTexture(GL_TEXTURE_2D, 0);
+        ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
+
+        glBindFramebuffer(GL_FRAMEBUFFER, mFbo);
+        glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
+                GL_TEXTURE_2D, mFboTex, 0);
+        glBindFramebuffer(GL_FRAMEBUFFER, 0);
+        ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
+    }
+
+    virtual void TearDown() {
+        SurfaceTextureGLTest::TearDown();
+
+        glDeleteTextures(1, &mFboTex);
+        glDeleteFramebuffers(1, &mFbo);
+    }
+
+    GLuint mFbo;
+    GLuint mFboTex;
+};
+
+// This test is intended to verify that proper synchronization is done when
+// rendering into an FBO.
+TEST_F(SurfaceTextureFBOTest, BlitFromCpuFilledBufferToFbo) {
+    const int texWidth = 64;
+    const int texHeight = 64;
+
+    ASSERT_EQ(NO_ERROR, native_window_set_buffers_geometry(mANW.get(),
+            texWidth, texHeight, HAL_PIXEL_FORMAT_RGBA_8888));
+    ASSERT_EQ(NO_ERROR, native_window_set_usage(mANW.get(),
+            GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN));
+
+    android_native_buffer_t* anb;
+    ASSERT_EQ(NO_ERROR, mANW->dequeueBuffer(mANW.get(), &anb));
+    ASSERT_TRUE(anb != NULL);
+
+    sp<GraphicBuffer> buf(new GraphicBuffer(anb, false));
+    ASSERT_EQ(NO_ERROR, mANW->lockBuffer(mANW.get(), buf->getNativeBuffer()));
+
+    // Fill the buffer with green
+    uint8_t* img = NULL;
+    buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img));
+    fillRGBA8BufferSolid(img, texWidth, texHeight, buf->getStride(), 0, 255,
+            0, 255);
+    buf->unlock();
+    ASSERT_EQ(NO_ERROR, mANW->queueBuffer(mANW.get(), buf->getNativeBuffer()));
+
+    ASSERT_EQ(NO_ERROR, mST->updateTexImage());
+
+    glBindFramebuffer(GL_FRAMEBUFFER, mFbo);
+    drawTexture();
+    glBindFramebuffer(GL_FRAMEBUFFER, 0);
+
+    for (int i = 0; i < 4; i++) {
+        SCOPED_TRACE(String8::format("frame %d", i).string());
+
+        ASSERT_EQ(NO_ERROR, mANW->dequeueBuffer(mANW.get(), &anb));
+        ASSERT_TRUE(anb != NULL);
+
+        buf = new GraphicBuffer(anb, false);
+        ASSERT_EQ(NO_ERROR, mANW->lockBuffer(mANW.get(),
+                buf->getNativeBuffer()));
+
+        // Fill the buffer with red
+        ASSERT_EQ(NO_ERROR, buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN,
+                (void**)(&img)));
+        fillRGBA8BufferSolid(img, texWidth, texHeight, buf->getStride(), 255, 0,
+                0, 255);
+        ASSERT_EQ(NO_ERROR, buf->unlock());
+        ASSERT_EQ(NO_ERROR, mANW->queueBuffer(mANW.get(),
+                buf->getNativeBuffer()));
+
+        ASSERT_EQ(NO_ERROR, mST->updateTexImage());
+
+        drawTexture();
+
+        EXPECT_TRUE(checkPixel( 24, 39, 255, 0, 0, 255));
+    }
+
+    glBindFramebuffer(GL_FRAMEBUFFER, mFbo);
+
+    EXPECT_TRUE(checkPixel( 24, 39, 0, 255, 0, 255));
+}
+
 } // namespace android
diff --git a/media/libstagefright/SurfaceMediaSource.cpp b/media/libstagefright/SurfaceMediaSource.cpp
index 2b27ee2..86b33d1 100644
--- a/media/libstagefright/SurfaceMediaSource.cpp
+++ b/media/libstagefright/SurfaceMediaSource.cpp
@@ -336,7 +336,7 @@
         (uint32_t(buffer->height) != h) ||
         (uint32_t(buffer->format) != format) ||
         ((uint32_t(buffer->usage) & usage) != usage)) {
-            usage |= GraphicBuffer::USAGE_HW_TEXTURE;
+            usage |= GraphicBuffer::USAGE_HW_VIDEO_ENCODER;
             status_t error;
             sp<GraphicBuffer> graphicBuffer(
                     mGraphicBufferAlloc->createGraphicBuffer(
diff --git a/opengl/libs/EGL/eglApi.cpp b/opengl/libs/EGL/eglApi.cpp
index a63d5b0..2b0ed5d 100644
--- a/opengl/libs/EGL/eglApi.cpp
+++ b/opengl/libs/EGL/eglApi.cpp
@@ -49,6 +49,8 @@
 
 // ----------------------------------------------------------------------------
 
+#define EGL_VERSION_HW_ANDROID  0x3143
+
 struct extention_map_t {
     const char* name;
     __eglMustCastToProperFunctionPointerType address;
@@ -972,6 +974,12 @@
             return dp->getExtensionString();
         case EGL_CLIENT_APIS:
             return dp->getClientApiString();
+        case EGL_VERSION_HW_ANDROID: {
+            if (gEGLImpl[IMPL_HARDWARE].dso) {
+                return dp->disp[IMPL_HARDWARE].queryString.version;
+            }
+            return dp->disp[IMPL_SOFTWARE].queryString.version;
+        }
     }
     return setError(EGL_BAD_PARAMETER, (const char *)0);
 }
diff --git a/opengl/specs/README b/opengl/specs/README
index 2fa2587..16b278f 100644
--- a/opengl/specs/README
+++ b/opengl/specs/README
@@ -9,4 +9,5 @@
 0x3140               EGL_ANDROID_image_native_buffer
 0x3141               (unused)
 0x3142               EGL_ANDROID_recordable
-0x3143 - 0x314F      (unused)
+0x3143               EGL_VERSION_HW_ANDROID (internal use)
+0x3144 - 0x314F      (unused)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
index 55a5b0a..135a04c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
@@ -898,7 +898,7 @@
             combinedSignalIconId = mDataSignalIconId; // set by updateDataIcon()
             mContentDescriptionCombinedSignal = mContentDescriptionDataType;
         }
-        
+
         if (mWifiConnected) {
             if (mWifiSsid == null) {
                 label = context.getString(R.string.status_bar_settings_signal_meter_wifi_nossid);
@@ -932,19 +932,23 @@
             mContentDescriptionCombinedSignal = mContext.getString(
                     R.string.accessibility_bluetooth_tether);
         }
-        
+
         if (mAirplaneMode &&
                 (mServiceState == null || (!hasService() && !mServiceState.isEmergencyOnly()))) {
             // Only display the flight-mode icon if not in "emergency calls only" mode.
-            label = context.getString(R.string.status_bar_settings_signal_meter_disconnected);
-            mContentDescriptionCombinedSignal = mContentDescriptionPhoneSignal
-                = mContext.getString(R.string.accessibility_airplane_mode);
-            
+
             // look again; your radios are now airplanes
+            mContentDescriptionPhoneSignal = mContext.getString(
+                    R.string.accessibility_airplane_mode);
             mPhoneSignalIconId = mDataSignalIconId = R.drawable.stat_sys_signal_flightmode;
             mDataTypeIconId = 0;
 
-            combinedSignalIconId = mDataSignalIconId;
+            // combined values from connected wifi take precedence over airplane mode
+            if (!mWifiConnected) {
+                label = context.getString(R.string.status_bar_settings_signal_meter_disconnected);
+                mContentDescriptionCombinedSignal = mContentDescriptionPhoneSignal;
+                combinedSignalIconId = mDataSignalIconId;
+            }
         }
         else if (!mDataConnected && !mWifiConnected && !mBluetoothTethered && !mWimaxConnected) {
             // pretty much totally disconnected
diff --git a/services/java/com/android/server/EventLogTags.logtags b/services/java/com/android/server/EventLogTags.logtags
index 5408436..4dad209 100644
--- a/services/java/com/android/server/EventLogTags.logtags
+++ b/services/java/com/android/server/EventLogTags.logtags
@@ -50,12 +50,12 @@
 # NotificationManagerService.java
 # ---------------------------
 # when a NotificationManager.notify is called
-2750 notification_enqueue (pkg|3),(id|1|5),(notification|3)
+2750 notification_enqueue (pkg|3),(id|1|5),(tag|3),(notification|3)
 # when someone tries to cancel a notification, the notification manager sometimes
 # calls this with flags too
-2751 notification_cancel (pkg|3),(id|1|5),(required_flags|1)
+2751 notification_cancel (pkg|3),(id|1|5),(tag|3),(required_flags|1),(forbidden_flags|1)
 # when someone tries to cancel all of the notifications for a particular package
-2752 notification_cancel_all (pkg|3),(required_flags|1)
+2752 notification_cancel_all (pkg|3),(required_flags|1),(forbidden_flags|1)
 
 
 # ---------------------------
diff --git a/services/java/com/android/server/NotificationManagerService.java b/services/java/com/android/server/NotificationManagerService.java
index 7d1d976..5039294 100755
--- a/services/java/com/android/server/NotificationManagerService.java
+++ b/services/java/com/android/server/NotificationManagerService.java
@@ -707,7 +707,8 @@
         //     behalf of the download manager without affecting other apps.
         if (!pkg.equals("com.android.providers.downloads")
                 || Log.isLoggable("DownloadManager", Log.VERBOSE)) {
-            EventLog.writeEvent(EventLogTags.NOTIFICATION_ENQUEUE, pkg, id, notification.toString());
+            EventLog.writeEvent(EventLogTags.NOTIFICATION_ENQUEUE, pkg, id, tag,
+                    notification.toString());
         }
 
         if (pkg == null || notification == null) {
@@ -944,7 +945,8 @@
      */
     private void cancelNotification(String pkg, String tag, int id, int mustHaveFlags,
             int mustNotHaveFlags, boolean sendDelete) {
-        EventLog.writeEvent(EventLogTags.NOTIFICATION_CANCEL, pkg, id, mustHaveFlags);
+        EventLog.writeEvent(EventLogTags.NOTIFICATION_CANCEL, pkg, id, tag,
+                mustHaveFlags, mustNotHaveFlags);
 
         synchronized (mNotificationList) {
             int index = indexOfNotificationLocked(pkg, tag, id);
@@ -972,7 +974,8 @@
      */
     boolean cancelAllNotificationsInt(String pkg, int mustHaveFlags,
             int mustNotHaveFlags, boolean doit) {
-        EventLog.writeEvent(EventLogTags.NOTIFICATION_CANCEL_ALL, pkg, mustHaveFlags);
+        EventLog.writeEvent(EventLogTags.NOTIFICATION_CANCEL_ALL, pkg, mustHaveFlags,
+                mustNotHaveFlags);
 
         synchronized (mNotificationList) {
             final int N = mNotificationList.size();
diff --git a/services/java/com/android/server/WallpaperManagerService.java b/services/java/com/android/server/WallpaperManagerService.java
index 7fa404e..4925a4e 100644
--- a/services/java/com/android/server/WallpaperManagerService.java
+++ b/services/java/com/android/server/WallpaperManagerService.java
@@ -476,6 +476,13 @@
     ParcelFileDescriptor updateWallpaperBitmapLocked(String name) {
         if (name == null) name = "";
         try {
+            if (!WALLPAPER_DIR.exists()) {
+                WALLPAPER_DIR.mkdir();
+                FileUtils.setPermissions(
+                        WALLPAPER_DIR.getPath(),
+                        FileUtils.S_IRWXU|FileUtils.S_IRWXG|FileUtils.S_IXOTH,
+                        -1, -1);
+            }
             ParcelFileDescriptor fd = ParcelFileDescriptor.open(WALLPAPER_FILE,
                     MODE_CREATE|MODE_READ_WRITE);
             mName = name;
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 367844d..b36ba3a 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -14249,7 +14249,7 @@
 
         if (app.curAdj != app.setAdj) {
             if (Process.setOomAdj(app.pid, app.curAdj)) {
-                if (true || DEBUG_SWITCH || DEBUG_OOM_ADJ) Slog.v(
+                if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Slog.v(
                     TAG, "Set " + app.pid + " " + app.processName +
                     " adj " + app.curAdj + ": " + app.adjType);
                 app.setAdj = app.curAdj;
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 1b00e93..f38e948 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -65,6 +65,8 @@
 #define AID_GRAPHICS 1003
 #endif
 
+#define EGL_VERSION_HW_ANDROID  0x3143
+
 #define DISPLAY_COUNT       1
 
 namespace android {
@@ -1527,7 +1529,7 @@
          * Dump the layers in the purgatory
          */
 
-        const size_t purgatorySize =  mLayerPurgatory.size();
+        const size_t purgatorySize = mLayerPurgatory.size();
         snprintf(buffer, SIZE, "Purgatory state (%d entries)\n", purgatorySize);
         result.append(buffer);
         for (size_t i=0 ; i<purgatorySize ; i++) {
@@ -1548,6 +1550,12 @@
                 extensions.getRenderer(),
                 extensions.getVersion());
         result.append(buffer);
+
+        snprintf(buffer, SIZE, "EGL : %s\n",
+                eglQueryString(graphicPlane(0).getEGLDisplay(),
+                        EGL_VERSION_HW_ANDROID));
+        result.append(buffer);
+
         snprintf(buffer, SIZE, "EXTS: %s\n", extensions.getExtension());
         result.append(buffer);
 
diff --git a/services/surfaceflinger/SurfaceTextureLayer.cpp b/services/surfaceflinger/SurfaceTextureLayer.cpp
index 4390ca1..5020e00 100644
--- a/services/surfaceflinger/SurfaceTextureLayer.cpp
+++ b/services/surfaceflinger/SurfaceTextureLayer.cpp
@@ -28,7 +28,7 @@
 
 
 SurfaceTextureLayer::SurfaceTextureLayer(GLuint tex, const sp<Layer>& layer)
-    : SurfaceTexture(tex), mLayer(layer) {
+    : SurfaceTexture(tex, true, GL_TEXTURE_EXTERNAL_OES, false), mLayer(layer) {
 }
 
 SurfaceTextureLayer::~SurfaceTextureLayer() {
diff --git a/tests/TileBenchmark/src/com/test/tilebenchmark/ProfiledWebView.java b/tests/TileBenchmark/src/com/test/tilebenchmark/ProfiledWebView.java
index b1cef15c..10802b4 100644
--- a/tests/TileBenchmark/src/com/test/tilebenchmark/ProfiledWebView.java
+++ b/tests/TileBenchmark/src/com/test/tilebenchmark/ProfiledWebView.java
@@ -110,9 +110,9 @@
      * been redrawn.
      */
     @Override
-    protected void pageSwapCallback() {
+    protected void pageSwapCallback(boolean startAnim) {
         mContentInvalMillis = System.currentTimeMillis() - mContentInvalMillis;
-        super.pageSwapCallback();
+        super.pageSwapCallback(startAnim);
         Log.d("ProfiledWebView", "REDRAW TOOK " + mContentInvalMillis
                 + "millis");
         mIsTesting = true;