Merge changes Ib809d4c5,I05d69da4 into honeycomb

* changes:
  This makes the events at the edge of the screen find the button.
  some touch event debugging
diff --git a/api/current.xml b/api/current.xml
index 112c147..610542d 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -85932,6 +85932,97 @@
 </parameter>
 </constructor>
 </class>
+<class name="SurfaceTexture"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="SurfaceTexture"
+ type="android.graphics.SurfaceTexture"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="texName" type="int">
+</parameter>
+</constructor>
+<method name="setOnFrameAvailableListener"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="l" type="android.graphics.SurfaceTexture.OnFrameAvailableListener">
+</parameter>
+</method>
+<method name="updateTexImage"
+ return="void"
+ abstract="false"
+ native="true"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
+<interface name="SurfaceTexture.OnFrameAvailableListener"
+ abstract="true"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="onFrameAvailable"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="surfaceTexture" type="android.graphics.SurfaceTexture">
+</parameter>
+</method>
+</interface>
+<class name="SurfaceTexture.OutOfResourcesException"
+ extends="java.lang.Exception"
+ abstract="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="SurfaceTexture.OutOfResourcesException"
+ type="android.graphics.SurfaceTexture.OutOfResourcesException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<constructor name="SurfaceTexture.OutOfResourcesException"
+ type="android.graphics.SurfaceTexture.OutOfResourcesException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="name" type="java.lang.String">
+</parameter>
+</constructor>
+</class>
 <class name="SweepGradient"
  extends="android.graphics.Shader"
  abstract="false"
diff --git a/core/java/android/bluetooth/BluetoothClass.java b/core/java/android/bluetooth/BluetoothClass.java
index e604e6b..54bf4af 100644
--- a/core/java/android/bluetooth/BluetoothClass.java
+++ b/core/java/android/bluetooth/BluetoothClass.java
@@ -226,6 +226,24 @@
         public static final int HEALTH_PULSE_OXIMETER               = 0x0914;
         public static final int HEALTH_PULSE_RATE                   = 0x0918;
         public static final int HEALTH_DATA_DISPLAY                 = 0x091C;
+
+        // Devices in PERIPHERAL major class
+        /**
+         * @hide
+         */
+        public static final int PERIPHERAL_NON_KEYBOARD_NON_POINTING = 0x0500;
+        /**
+         * @hide
+         */
+        public static final int PERIPHERAL_KEYBOARD                  = 0x0540;
+        /**
+         * @hide
+         */
+        public static final int PERIPHERAL_POINTING                  = 0x0580;
+        /**
+         * @hide
+         */
+        public static final int PERIPHERAL_KEYBOARD_POINTING         = 0x05C0;
     }
 
     /**
diff --git a/core/java/android/bluetooth/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java
index e15d003..24217d7 100644
--- a/core/java/android/bluetooth/BluetoothDevice.java
+++ b/core/java/android/bluetooth/BluetoothDevice.java
@@ -239,7 +239,7 @@
     public static final String EXTRA_PAIRING_VARIANT =
             "android.bluetooth.device.extra.PAIRING_VARIANT";
     /** @hide */
-    public static final String EXTRA_PASSKEY = "android.bluetooth.device.extra.PASSKEY";
+    public static final String EXTRA_PAIRING_KEY = "android.bluetooth.device.extra.PAIRING_KEY";
 
     /**
      * Broadcast Action: This intent is used to broadcast the {@link UUID}
@@ -276,58 +276,113 @@
     public static final String ACTION_PAIRING_CANCEL =
             "android.bluetooth.device.action.PAIRING_CANCEL";
 
-    /** A bond attempt succeeded
-     * @hide */
+    /**
+     * A bond attempt succeeded
+     * @hide
+     */
     public static final int BOND_SUCCESS = 0;
-    /** A bond attempt failed because pins did not match, or remote device did
+
+    /**
+     * A bond attempt failed because pins did not match, or remote device did
      * not respond to pin request in time
-     * @hide */
+     * @hide
+     */
     public static final int UNBOND_REASON_AUTH_FAILED = 1;
-    /** A bond attempt failed because the other side explicitly rejected
+
+    /**
+     * A bond attempt failed because the other side explicitly rejected
      * bonding
-     * @hide */
+     * @hide
+     */
     public static final int UNBOND_REASON_AUTH_REJECTED = 2;
-    /** A bond attempt failed because we canceled the bonding process
-     * @hide */
+
+    /**
+     * A bond attempt failed because we canceled the bonding process
+     * @hide
+     */
     public static final int UNBOND_REASON_AUTH_CANCELED = 3;
-    /** A bond attempt failed because we could not contact the remote device
-     * @hide */
+
+    /**
+     * A bond attempt failed because we could not contact the remote device
+     * @hide
+     */
     public static final int UNBOND_REASON_REMOTE_DEVICE_DOWN = 4;
-    /** A bond attempt failed because a discovery is in progress
-     * @hide */
+
+    /**
+     * A bond attempt failed because a discovery is in progress
+     * @hide
+     */
     public static final int UNBOND_REASON_DISCOVERY_IN_PROGRESS = 5;
-    /** A bond attempt failed because of authentication timeout
-     * @hide */
+
+    /**
+     * A bond attempt failed because of authentication timeout
+     * @hide
+     */
     public static final int UNBOND_REASON_AUTH_TIMEOUT = 6;
-    /** A bond attempt failed because of repeated attempts
-     * @hide */
+
+    /**
+     * A bond attempt failed because of repeated attempts
+     * @hide
+     */
     public static final int UNBOND_REASON_REPEATED_ATTEMPTS = 7;
-    /** A bond attempt failed because we received an Authentication Cancel
-     *  by remote end
-     * @hide */
+
+    /**
+     * A bond attempt failed because we received an Authentication Cancel
+     * by remote end
+     * @hide
+     */
     public static final int UNBOND_REASON_REMOTE_AUTH_CANCELED = 8;
-    /** An existing bond was explicitly revoked
-     * @hide */
+
+    /**
+     * An existing bond was explicitly revoked
+     * @hide
+     */
     public static final int UNBOND_REASON_REMOVED = 9;
 
-    /** The user will be prompted to enter a pin
-     * @hide */
+    /**
+     * The user will be prompted to enter a pin
+     * @hide
+     */
     public static final int PAIRING_VARIANT_PIN = 0;
-    /** The user will be prompted to enter a passkey
-     * @hide */
+
+    /**
+     * The user will be prompted to enter a passkey
+     * @hide
+     */
     public static final int PAIRING_VARIANT_PASSKEY = 1;
-    /** The user will be prompted to confirm the passkey displayed on the screen
-     * @hide */
+
+    /**
+     * The user will be prompted to confirm the passkey displayed on the screen
+     * @hide
+     */
     public static final int PAIRING_VARIANT_PASSKEY_CONFIRMATION = 2;
-    /** The user will be prompted to accept or deny the incoming pairing request
-     * @hide */
+
+    /**
+     * The user will be prompted to accept or deny the incoming pairing request
+     * @hide
+     */
     public static final int PAIRING_VARIANT_CONSENT = 3;
-    /** The user will be prompted to enter the passkey displayed on remote device
-     * @hide */
+
+    /**
+     * The user will be prompted to enter the passkey displayed on remote device
+     * This is used for Bluetooth 2.1 pairing.
+     * @hide
+     */
     public static final int PAIRING_VARIANT_DISPLAY_PASSKEY = 4;
-    /** The user will be prompted to accept or deny the OOB pairing request
-     * @hide */
-    public static final int PAIRING_VARIANT_OOB_CONSENT = 5;
+
+    /**
+     * The user will be prompted to enter the PIN displayed on remote device.
+     * This is used for Bluetooth 2.0 pairing.
+     * @hide
+     */
+    public static final int PAIRING_VARIANT_DISPLAY_PIN = 5;
+
+    /**
+     * The user will be prompted to accept or deny the OOB pairing request
+     * @hide
+     */
+    public static final int PAIRING_VARIANT_OOB_CONSENT = 6;
+
     /**
      * Used as an extra field in {@link #ACTION_UUID} intents,
      * Contains the {@link android.os.ParcelUuid}s of the remote device which
diff --git a/core/java/android/bluetooth/BluetoothDeviceProfileState.java b/core/java/android/bluetooth/BluetoothDeviceProfileState.java
index 80a80bd..21144f2 100644
--- a/core/java/android/bluetooth/BluetoothDeviceProfileState.java
+++ b/core/java/android/bluetooth/BluetoothDeviceProfileState.java
@@ -149,10 +149,6 @@
                     newState == BluetoothInputDevice.STATE_DISCONNECTED) {
                     sendMessage(TRANSITION_TO_STABLE);
                 }
-            } else if (action.equals(BluetoothDevice.ACTION_ACL_CONNECTED)) {
-                Message msg = new Message();
-                msg.what = AUTO_CONNECT_PROFILES;
-                sendMessage(msg);
             } else if (action.equals(BluetoothDevice.ACTION_ACL_DISCONNECTED)) {
                 // This is technically not needed, but we can get stuck sometimes.
                 // For example, if incoming A2DP fails, we are not informed by Bluez
diff --git a/core/java/android/database/BulkCursorToCursorAdaptor.java b/core/java/android/database/BulkCursorToCursorAdaptor.java
index 2cb2aec..16becf5 100644
--- a/core/java/android/database/BulkCursorToCursorAdaptor.java
+++ b/core/java/android/database/BulkCursorToCursorAdaptor.java
@@ -154,7 +154,10 @@
                     false /* the window will be accessed across processes */));
             if (mCount != -1) {
                 mPos = -1;
-                mWindow = null;
+                if (mWindow != null) {
+                    mWindow.close();
+                    mWindow = null;
+                }
 
                 // super.requery() will call onChanged. Do it here instead of relying on the
                 // observer from the far side so that observers can see a correct value for mCount
diff --git a/core/java/android/database/CursorWindow.java b/core/java/android/database/CursorWindow.java
index d15fb88..bd78063 100644
--- a/core/java/android/database/CursorWindow.java
+++ b/core/java/android/database/CursorWindow.java
@@ -17,12 +17,14 @@
 package android.database;
 
 import android.content.res.Resources;
+import android.database.sqlite.DatabaseObjectNotClosedException;
 import android.database.sqlite.SQLiteClosable;
 import android.os.Binder;
 import android.os.IBinder;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.os.Process;
+import android.os.StrictMode;
 import android.util.Log;
 import android.util.SparseIntArray;
 
@@ -45,6 +47,7 @@
     private int nWindow;
 
     private int mStartPos;
+    private final Throwable mStackTrace;
 
     /**
      * Creates a new empty window.
@@ -56,6 +59,7 @@
         int rslt = native_init(sCursorWindowSize, localWindow);
         printDebugMsgIfError(rslt);
         recordNewWindow(Binder.getCallingPid(), nWindow);
+        mStackTrace = new DatabaseObjectNotClosedException().fillInStackTrace();
     }
 
     private void printDebugMsgIfError(int rslt) {
@@ -561,7 +565,16 @@
 
     @Override
     protected void finalize() {
-        // Just in case someone forgot to call close...
+        if (nWindow == 0) {
+            return;
+        }
+        if (StrictMode.vmSqliteObjectLeaksEnabled()) {
+            StrictMode.onSqliteObjectLeaked(
+                    "Releasing cursor in a finalizer. Please ensure " +
+                    "that you explicitly call close() on your cursor: ",
+                    mStackTrace);
+        }
+        recordClosingOfWindow(nWindow);
         close_native();
     }
     
@@ -593,6 +606,7 @@
         IBinder nativeBinder = source.readStrongBinder();
         mStartPos = source.readInt();
         int rslt = native_init(nativeBinder);
+        mStackTrace = new DatabaseObjectNotClosedException().fillInStackTrace();
         printDebugMsgIfError(rslt);
     }
 
@@ -607,8 +621,7 @@
 
     @Override
     protected void onAllReferencesReleased() {
-        int windowId = nWindow;
-        recordClosingOfWindow(Binder.getCallingPid(), nWindow);
+        recordClosingOfWindow(nWindow);
         close_native();
     }
 
@@ -623,7 +636,7 @@
         }
     }
 
-    private void recordClosingOfWindow(int pid, int window) {
+    private void recordClosingOfWindow(int window) {
         synchronized (sWindowToPidMap) {
             if (sWindowToPidMap.size() == 0) {
                 // this means we are not in the ContentProvider.
diff --git a/core/java/android/database/sqlite/SQLiteDatabase.java b/core/java/android/database/sqlite/SQLiteDatabase.java
index 57a18bc..b1c84a1 100644
--- a/core/java/android/database/sqlite/SQLiteDatabase.java
+++ b/core/java/android/database/sqlite/SQLiteDatabase.java
@@ -958,13 +958,7 @@
             sBlockSize = new StatFs("/data").getBlockSize();
         }
         sqliteDatabase.setPageSize(sBlockSize);
-        //STOPSHIP - uncomment the following line
-        //sqliteDatabase.setJournalMode(path, "TRUNCATE");
-        // STOPSHIP remove the following lines
-        if (!path.equalsIgnoreCase(MEMORY_DB_PATH)) {
-            sqliteDatabase.enableWriteAheadLogging();
-        }
-        // END STOPSHIP
+        sqliteDatabase.setJournalMode(path, "TRUNCATE");
 
         // add this database to the list of databases opened in this process
         synchronized(mActiveDatabases) {
diff --git a/core/java/android/server/BluetoothEventLoop.java b/core/java/android/server/BluetoothEventLoop.java
index c04bb52..ae729d2d 100644
--- a/core/java/android/server/BluetoothEventLoop.java
+++ b/core/java/android/server/BluetoothEventLoop.java
@@ -493,7 +493,7 @@
         mWakeLock.acquire();
         Intent intent = new Intent(BluetoothDevice.ACTION_PAIRING_REQUEST);
         intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mAdapter.getRemoteDevice(address));
-        intent.putExtra(BluetoothDevice.EXTRA_PASSKEY, passkey);
+        intent.putExtra(BluetoothDevice.EXTRA_PAIRING_KEY, passkey);
         intent.putExtra(BluetoothDevice.EXTRA_PAIRING_VARIANT,
                 BluetoothDevice.PAIRING_VARIANT_PASSKEY_CONFIRMATION);
         mContext.sendBroadcast(intent, BLUETOOTH_ADMIN_PERM);
@@ -523,6 +523,9 @@
 
         String pendingOutgoingAddress =
                 mBluetoothService.getPendingOutgoingBonding();
+        BluetoothClass btClass = new BluetoothClass(mBluetoothService.getRemoteClass(address));
+        int btDeviceClass = btClass.getDeviceClass();
+
         if (address.equals(pendingOutgoingAddress)) {
             // we initiated the bonding
 
@@ -533,10 +536,8 @@
                 return;
             }
 
-            BluetoothClass btClass = new BluetoothClass(mBluetoothService.getRemoteClass(address));
-
             // try 0000 once if the device looks dumb
-            switch (btClass.getDeviceClass()) {
+            switch (btDeviceClass) {
             case BluetoothClass.Device.AUDIO_VIDEO_WEARABLE_HEADSET:
             case BluetoothClass.Device.AUDIO_VIDEO_HANDSFREE:
             case BluetoothClass.Device.AUDIO_VIDEO_HEADPHONES:
@@ -546,6 +547,27 @@
                 if (mBluetoothService.attemptAutoPair(address)) return;
            }
         }
+
+        // STOPSHIP: Hack for MOT keyboards
+        boolean motKeyboard = false;
+        String name = mBluetoothService.getRemoteName(address);
+        if (name == null && address.startsWith("00:0F:F6") ||
+            (name != null && name.startsWith("Motorola"))) {
+                motKeyboard = true;
+        }
+
+        if (!motKeyboard) {
+            if (btDeviceClass == BluetoothClass.Device.PERIPHERAL_KEYBOARD ||
+                btDeviceClass == BluetoothClass.Device.PERIPHERAL_KEYBOARD_POINTING) {
+                // Its a keyboard. Follow the HID spec recommendation of creating the
+                // passkey and displaying it to the user.
+                // Generate a variable PIN. This is not truly random but good enough.
+                int pin = (int) Math.floor(Math.random() * 10000);
+                sendDisplayPinIntent(address, pin);
+                return;
+            }
+        }
+
         // Acquire wakelock during PIN code request to bring up LCD display
         mWakeLock.acquire();
         Intent intent = new Intent(BluetoothDevice.ACTION_PAIRING_REQUEST);
@@ -565,7 +587,7 @@
         mWakeLock.acquire();
         Intent intent = new Intent(BluetoothDevice.ACTION_PAIRING_REQUEST);
         intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mAdapter.getRemoteDevice(address));
-        intent.putExtra(BluetoothDevice.EXTRA_PASSKEY, passkey);
+        intent.putExtra(BluetoothDevice.EXTRA_PAIRING_KEY, passkey);
         intent.putExtra(BluetoothDevice.EXTRA_PAIRING_VARIANT,
                         BluetoothDevice.PAIRING_VARIANT_DISPLAY_PASSKEY);
         mContext.sendBroadcast(intent, BLUETOOTH_ADMIN_PERM);
@@ -573,6 +595,19 @@
         mWakeLock.release();
     }
 
+    private void sendDisplayPinIntent(String address, int pin) {
+        // Acquire wakelock during PIN code request to bring up LCD display
+        mWakeLock.acquire();
+        Intent intent = new Intent(BluetoothDevice.ACTION_PAIRING_REQUEST);
+        intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mAdapter.getRemoteDevice(address));
+        intent.putExtra(BluetoothDevice.EXTRA_PAIRING_KEY, pin);
+        intent.putExtra(BluetoothDevice.EXTRA_PAIRING_VARIANT,
+                        BluetoothDevice.PAIRING_VARIANT_DISPLAY_PIN);
+        mContext.sendBroadcast(intent, BLUETOOTH_ADMIN_PERM);
+        //Release wakelock to allow the LCD to go off after the PIN popup notifcation.
+        mWakeLock.release();
+    }
+
     private void onRequestOobData(String objectPath , int nativeData) {
         String address = checkPairingRequestAndGetAddress(objectPath, nativeData);
         if (address == null) return;
diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/GLES20Canvas.java
index 67b22fa..311002c 100644
--- a/core/java/android/view/GLES20Canvas.java
+++ b/core/java/android/view/GLES20Canvas.java
@@ -85,7 +85,7 @@
 
     protected void setupRenderer(boolean record) {
         if (record) {
-            mRenderer = nCreateDisplayListRenderer();
+            mRenderer = nGetDisplayListRenderer(mRenderer);
         } else {
             mRenderer = nCreateRenderer();
         }
@@ -93,28 +93,33 @@
         if (mRenderer == 0) {
             throw new IllegalStateException("Could not create GLES20Canvas renderer");
         } else {
-            if (mFinalizer == null) {
-                mFinalizer = new CanvasFinalizer(mRenderer);
-            } else {
-                mFinalizer.replaceNativeObject(mRenderer);
-            }
+            mFinalizer = CanvasFinalizer.getFinalizer(mFinalizer, mRenderer);
         }
     }
 
-    private native int nCreateRenderer();    
-    private native int nCreateDisplayListRenderer();    
-
+    private native int nCreateRenderer();
+    private static native int nGetDisplayListRenderer(int renderer);
     private static native void nDestroyRenderer(int renderer);
 
     private static class CanvasFinalizer {
         int mRenderer;
 
-        CanvasFinalizer(int renderer) {
+        // Factory method returns new instance if old one is null, or old instance
+        // otherwise, destroying native renderer along the way as necessary
+        static CanvasFinalizer getFinalizer(CanvasFinalizer oldFinalizer, int renderer) {
+            if (oldFinalizer == null) {
+                return new CanvasFinalizer(renderer);
+            }
+            oldFinalizer.replaceNativeObject(renderer);
+            return oldFinalizer;
+        }
+
+        private CanvasFinalizer(int renderer) {
             mRenderer = renderer;
         }
 
-        void replaceNativeObject(int newRenderer) {
-            if (mRenderer != 0) {
+        private void replaceNativeObject(int newRenderer) {
+            if (mRenderer != 0 && newRenderer != mRenderer) {
                 nDestroyRenderer(mRenderer);
             }
             mRenderer = newRenderer;
@@ -199,10 +204,10 @@
     ///////////////////////////////////////////////////////////////////////////
 
     int getDisplayList() {
-        return nCreateDisplayList(mRenderer);
+        return nGetDisplayList(mRenderer);
     }
 
-    private native int nCreateDisplayList(int renderer);
+    private native int nGetDisplayList(int renderer);
     
     static void destroyDisplayList(int displayList) {
         nDestroyDisplayList(displayList);
diff --git a/core/java/android/view/GLES20DisplayList.java b/core/java/android/view/GLES20DisplayList.java
index bd18fdd..c548659 100644
--- a/core/java/android/view/GLES20DisplayList.java
+++ b/core/java/android/view/GLES20DisplayList.java
@@ -70,11 +70,7 @@
             mRecorded = true;
 
             mNativeDisplayList = mCanvas.getDisplayList();
-            if (mFinalizer == null) {
-                mFinalizer = new DisplayListFinalizer(mNativeDisplayList);
-            } else {
-                mFinalizer.replaceNativeObject(mNativeDisplayList);
-            }
+            mFinalizer = DisplayListFinalizer.getFinalizer(mFinalizer, mNativeDisplayList);
         }
     }
 
@@ -86,12 +82,23 @@
     private static class DisplayListFinalizer {
         int mNativeDisplayList;
 
-        DisplayListFinalizer(int nativeDisplayList) {
+        // Factory method returns new instance if old one is null, or old instance
+        // otherwise, destroying native display list along the way as necessary
+        static DisplayListFinalizer getFinalizer(DisplayListFinalizer oldFinalizer,
+                int nativeDisplayList) {
+            if (oldFinalizer == null) {
+                return new DisplayListFinalizer(nativeDisplayList);
+            }
+            oldFinalizer.replaceNativeObject(nativeDisplayList);
+            return oldFinalizer;
+        }
+
+        private DisplayListFinalizer(int nativeDisplayList) {
             mNativeDisplayList = nativeDisplayList;
         }
 
-        void replaceNativeObject(int newNativeDisplayList) {
-            if (mNativeDisplayList != 0) {
+        private void replaceNativeObject(int newNativeDisplayList) {
+            if (mNativeDisplayList != 0 && mNativeDisplayList != newNativeDisplayList) {
                 GLES20Canvas.destroyDisplayList(mNativeDisplayList);
             }
             mNativeDisplayList = newNativeDisplayList;
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index bd268e1..d068d82 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -4599,6 +4599,8 @@
 
         if (isEnterActionKey(keyCode)) {
             switchOutDrawHistory();
+            boolean wantsKeyEvents = nativeCursorNodePointer() == 0
+                || nativeCursorWantsKeyEvents();
             if (event.getRepeatCount() == 0) {
                 if (mSelectingText) {
                     return true; // discard press if copy in progress
@@ -4609,10 +4611,10 @@
                 // Already checked mNativeClass, so we do not need to check it
                 // again.
                 nativeRecordButtons(hasFocus() && hasWindowFocus(), true, true);
-                return true;
+                if (!wantsKeyEvents) return true;
             }
             // Bubble up the key event as WebView doesn't handle it
-            return false;
+            if (!wantsKeyEvents) return false;
         }
 
         if (keyCode != KeyEvent.KEYCODE_SHIFT_LEFT
@@ -4771,11 +4773,14 @@
             }
             clearTextEntry();
             nativeShowCursorTimed();
-            if (!mCallbackProxy.uiOverrideUrlLoading(nativeCursorText())) {
+            if (mCallbackProxy.uiOverrideUrlLoading(nativeCursorText())) {
+                return true;
+            }
+            if (nativeCursorNodePointer() != 0 && !nativeCursorWantsKeyEvents()) {
                 mWebViewCore.sendMessage(EventHub.CLICK, data.mFrame,
                         nativeCursorNodePointer());
+                return true;
             }
-            return true;
         }
 
         // TODO: should we pass all the keys to DOM or check the meta tag
diff --git a/core/java/android/webkit/ZoomManager.java b/core/java/android/webkit/ZoomManager.java
index 075ecbc..2fd5bb1 100644
--- a/core/java/android/webkit/ZoomManager.java
+++ b/core/java/android/webkit/ZoomManager.java
@@ -260,8 +260,9 @@
     public final float getReadingLevelScale() {
         // The reading scale is at least 0.5f apart from the overview scale.
         final float MIN_SCALE_DIFF = 0.5f;
-        return Math.max(getZoomOverviewScale() + MIN_SCALE_DIFF,
-            DEFAULT_READING_LEVEL_SCALE);
+        return computeScaleWithLimits(
+                   Math.max(getZoomOverviewScale() + MIN_SCALE_DIFF,
+                            DEFAULT_READING_LEVEL_SCALE));
     }
 
     public final float getInvDefaultScale() {
diff --git a/core/java/com/android/internal/view/menu/ActionMenuView.java b/core/java/com/android/internal/view/menu/ActionMenuView.java
index 96c1ed3..f927fae 100644
--- a/core/java/com/android/internal/view/menu/ActionMenuView.java
+++ b/core/java/com/android/internal/view/menu/ActionMenuView.java
@@ -47,9 +47,7 @@
     private boolean mReserveOverflow;
     private OverflowMenuButton mOverflowButton;
     private MenuPopupHelper mOverflowPopup;
-    
-    private float mButtonPaddingLeft;
-    private float mButtonPaddingRight;
+
     private float mDividerPadding;
     
     private Drawable mDivider;
@@ -94,16 +92,9 @@
                 Configuration.SCREENLAYOUT_SIZE_XLARGE;
         
         TypedArray a = context.obtainStyledAttributes(com.android.internal.R.styleable.Theme);
-        final int buttonStyle = a.getResourceId(
-                com.android.internal.R.styleable.Theme_actionButtonStyle, 0);
         mDivider = a.getDrawable(com.android.internal.R.styleable.Theme_dividerVertical);
         a.recycle();
         
-        a = context.obtainStyledAttributes(buttonStyle, com.android.internal.R.styleable.View);
-        mButtonPaddingLeft = a.getDimension(com.android.internal.R.styleable.View_paddingLeft, 0);
-        mButtonPaddingRight = a.getDimension(com.android.internal.R.styleable.View_paddingRight, 0);
-        a.recycle();
-        
         mDividerPadding = DIVIDER_PADDING * res.getDisplayMetrics().density;
 
         setBaselineAligned(false);
@@ -295,10 +286,7 @@
     }
 
     private LayoutParams makeActionViewLayoutParams(View view) {
-        LayoutParams params = generateLayoutParams(view.getLayoutParams());
-        params.leftMargin = (int) mButtonPaddingLeft;
-        params.rightMargin = (int) mButtonPaddingRight;
-        return params;
+        return generateLayoutParams(view.getLayoutParams());
     }
 
     private class OverflowMenuButton extends ImageButton {
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index 241bc3e..c635b39 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -111,6 +111,7 @@
 	android/graphics/Rasterizer.cpp \
 	android/graphics/Region.cpp \
 	android/graphics/Shader.cpp \
+	android/graphics/SurfaceTexture.cpp \
 	android/graphics/TextLayout.cpp \
 	android/graphics/Typeface.cpp \
 	android/graphics/Utils.cpp \
diff --git a/core/jni/android/graphics/SurfaceTexture.cpp b/core/jni/android/graphics/SurfaceTexture.cpp
new file mode 100644
index 0000000..2645045
--- /dev/null
+++ b/core/jni/android/graphics/SurfaceTexture.cpp
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "SurfaceTexture"
+
+#include <stdio.h>
+
+#include <gui/SurfaceTexture.h>
+
+#include <android_runtime/AndroidRuntime.h>
+
+#include <utils/Log.h>
+#include <utils/misc.h>
+
+#include "android/graphics/GraphicsJNI.h"
+#include "jni.h"
+
+// ----------------------------------------------------------------------------
+
+namespace android {
+
+static const char* const OutOfResourcesException =
+    "android/graphics/SurfaceTexture$OutOfResourcesException";
+
+struct st_t {
+    jfieldID surfaceTexture;
+};
+static st_t st;
+
+// ----------------------------------------------------------------------------
+
+static void setSurfaceTexture(JNIEnv* env, jobject clazz,
+        const sp<SurfaceTexture>& surfaceTexture)
+{
+    SurfaceTexture* const p =
+        (SurfaceTexture*)env->GetIntField(clazz, st.surfaceTexture);
+    if (surfaceTexture.get()) {
+        surfaceTexture->incStrong(clazz);
+    }
+    if (p) {
+        p->decStrong(clazz);
+    }
+    env->SetIntField(clazz, st.surfaceTexture, (int)surfaceTexture.get());
+}
+
+sp<SurfaceTexture> getSurfaceTexture(JNIEnv* env, jobject clazz)
+{
+    sp<SurfaceTexture> surfaceTexture(
+        (SurfaceTexture*)env->GetIntField(clazz, st.surfaceTexture));
+    return surfaceTexture;
+}
+
+// ----------------------------------------------------------------------------
+
+static void SurfaceTexture_init(JNIEnv* env, jobject clazz, jint texName)
+{
+    sp<SurfaceTexture> surfaceTexture(new SurfaceTexture(texName));
+
+    if (surfaceTexture == 0) {
+        doThrow(env, OutOfResourcesException);
+        return;
+    }
+    setSurfaceTexture(env, clazz, surfaceTexture);
+}
+
+static void SurfaceTexture_updateTexImage(JNIEnv* env, jobject clazz)
+{
+    sp<SurfaceTexture> surfaceTexture(getSurfaceTexture(env, clazz));
+    surfaceTexture->updateTexImage();
+}
+
+// ----------------------------------------------------------------------------
+
+const char* const kSurfaceTextureClassPathName = "android/graphics/SurfaceTexture";
+static void nativeClassInit(JNIEnv* env, jclass clazz);
+
+static JNINativeMethod gSurfaceTextureMethods[] = {
+    {"nativeClassInit",     "()V",  (void*)nativeClassInit },
+    {"init",                "(I)V", (void*)SurfaceTexture_init },
+    {"updateTexImage",      "()V",  (void*)SurfaceTexture_updateTexImage },
+};
+
+static void nativeClassInit(JNIEnv* env, jclass clazz)
+{
+    st.surfaceTexture = env->GetFieldID(clazz,
+            ANDROID_GRAPHICS_SURFACETEXTURE_JNI_ID, "I");
+}
+
+int register_android_graphics_SurfaceTexture(JNIEnv* env)
+{
+    int err = 0;
+    err = AndroidRuntime::registerNativeMethods(env, kSurfaceTextureClassPathName,
+            gSurfaceTextureMethods, NELEM(gSurfaceTextureMethods));
+    return err;
+}
+
+} // namespace android
diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp
index c3d3572..b4c868f 100644
--- a/core/jni/android_view_GLES20Canvas.cpp
+++ b/core/jni/android_view_GLES20Canvas.cpp
@@ -417,16 +417,21 @@
 // Display lists
 // ----------------------------------------------------------------------------
 
-static OpenGLRenderer* android_view_GLES20Canvas_createDisplayListRenderer(
-        JNIEnv* env, jobject canvas) {
-    return new DisplayListRenderer;
-}
-
-static DisplayList* android_view_GLES20Canvas_createDisplayList(JNIEnv* env,
+static DisplayList* android_view_GLES20Canvas_getDisplayList(JNIEnv* env,
         jobject canvas, DisplayListRenderer* renderer) {
     return renderer->getDisplayList();
 }
 
+static OpenGLRenderer* android_view_GLES20Canvas_getDisplayListRenderer(JNIEnv* env,
+        jobject clazz, DisplayListRenderer* renderer) {
+    if (renderer == NULL) {
+        renderer = new DisplayListRenderer;
+    } else {
+        renderer->reset();
+    }
+    return renderer;
+}
+
 static void android_view_GLES20Canvas_destroyDisplayList(JNIEnv* env,
         jobject clazz, DisplayList* displayList) {
     delete displayList;
@@ -517,9 +522,9 @@
     { "nGetClipBounds",     "(ILandroid/graphics/Rect;)Z",
             (void*) android_view_GLES20Canvas_getClipBounds },
 
-    { "nCreateDisplayListRenderer", "()I",     (void*) android_view_GLES20Canvas_createDisplayListRenderer },
-    { "nCreateDisplayList",  "(I)I",           (void*) android_view_GLES20Canvas_createDisplayList },
+    { "nGetDisplayList",  "(I)I",           (void*) android_view_GLES20Canvas_getDisplayList },
     { "nDestroyDisplayList", "(I)V",           (void*) android_view_GLES20Canvas_destroyDisplayList },
+    { "nGetDisplayListRenderer", "(I)I",     (void*) android_view_GLES20Canvas_getDisplayListRenderer },
     { "nDrawDisplayList",    "(II)V",          (void*) android_view_GLES20Canvas_drawDisplayList },
 
 #endif
diff --git a/core/res/res/layout/action_menu_item_layout.xml b/core/res/res/layout/action_menu_item_layout.xml
index 94fcc2f..e502b1e 100644
--- a/core/res/res/layout/action_menu_item_layout.xml
+++ b/core/res/res/layout/action_menu_item_layout.xml
@@ -29,7 +29,11 @@
                  android:layout_height="wrap_content"
                  android:layout_gravity="center"
                  android:visibility="gone"
-                 style="?attr/actionButtonStyle" />
+                 android:paddingLeft="4dip"
+                 android:paddingRight="4dip"
+                 android:minHeight="56dip"
+                 android:scaleType="center"
+                 android:background="@null" />
     <Button android:id="@+id/textButton"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
diff --git a/core/res/res/layout/popup_menu_item_layout.xml b/core/res/res/layout/popup_menu_item_layout.xml
index c30c4f2..2bbb4d0 100644
--- a/core/res/res/layout/popup_menu_item_layout.xml
+++ b/core/res/res/layout/popup_menu_item_layout.xml
@@ -16,7 +16,9 @@
 
 <com.android.internal.view.menu.ListMenuItemView xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
-    android:layout_height="?android:attr/listPreferredItemHeight">
+    android:layout_height="?android:attr/listPreferredItemHeight"
+    android:paddingLeft="16dip"
+    android:paddingRight="16dip">
     
     <!-- Icon will be inserted here. -->
     
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index 470fb36..ec5ef83 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -1030,7 +1030,7 @@
     </style>
 
     <style name="Widget.ActionButton">
-        <item name="android:background">@null</item>
+        <item name="android:background">?android:attr/selectableItemBackground</item>
         <item name="android:paddingLeft">16dip</item>
         <item name="android:paddingRight">16dip</item>
     </style>
@@ -1651,8 +1651,8 @@
     </style>
 
     <style name="Widget.Holo.ActionButton" parent="Widget.ActionButton">
-        <item name="android:paddingLeft">4dip</item>
-        <item name="android:paddingRight">4dip</item>
+        <item name="android:paddingLeft">16dip</item>
+        <item name="android:paddingRight">16dip</item>
         <item name="android:minHeight">56dip</item>
         <item name="android:scaleType">center</item>
     </style>
@@ -1981,7 +1981,6 @@
 
     <style name="Widget.Holo.Light.ActionButton.Overflow">
         <item name="android:src">@android:drawable/ic_menu_moreoverflow_holo_light</item>
-        <item name="android:background">?android:attr/selectableItemBackground</item>
         <item name="android:paddingLeft">16dip</item>
         <item name="android:paddingRight">16dip</item>
     </style>
diff --git a/graphics/java/android/graphics/SurfaceTexture.java b/graphics/java/android/graphics/SurfaceTexture.java
new file mode 100644
index 0000000..883c4eb
--- /dev/null
+++ b/graphics/java/android/graphics/SurfaceTexture.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.graphics;
+
+/**
+ * Captures frames from an image stream as an OpenGL ES texture.
+ *
+ * <p>The image stream may come from either video playback or camera preview.  A SurfaceTexture may
+ * be used in place of a SurfaceHolder when specifying the output destination of a MediaPlayer or
+ * Camera object.  This will cause all the frames from that image stream to be sent to the
+ * SurfaceTexture object rather than to the device's display.  When {@link #updateTexImage} is
+ * called, the contents of the texture object specified when the SurfaceTexture was created is
+ * updated to contain the most recent image from the image stream.  This may cause some frames of
+ * the stream to be skipped.
+ *
+ * <p>The texture object uses the GL_TEXTURE_EXTERNAL_OES texture target, which is defined by the
+ * OES_EGL_image_external OpenGL ES extension.  This limits how the texture may be used.
+ */
+public class SurfaceTexture {
+
+    @SuppressWarnings("unused")
+    private int mSurfaceTexture;
+
+    /**
+     * Callback interface for being notified that a new stream frame is available.
+     */
+    public interface OnFrameAvailableListener {
+        void onFrameAvailable(SurfaceTexture surfaceTexture);
+    }
+
+    /**
+     * Exception thrown when a surface couldn't be created or resized
+     */
+    public static class OutOfResourcesException extends Exception {
+        public OutOfResourcesException() {
+        }
+        public OutOfResourcesException(String name) {
+            super(name);
+        }
+    }
+
+    /**
+     * Construct a new SurfaceTexture to stream images to a given OpenGL texture.
+     *
+     * @param texName the OpenGL texture object name (e.g. generated via glGenTextures)
+     */
+    public SurfaceTexture(int texName) {
+        init(texName);
+    }
+
+    /**
+     * Register a callback to be invoked when a new image frame becomes available to the
+     * SurfaceTexture.  Note that this callback may be called on an arbitrary thread, so it is not
+     * safe to call {@link #updateTexImage} without first binding the OpenGL ES context to the
+     * thread invoking the callback.
+     */
+    public void setOnFrameAvailableListener(OnFrameAvailableListener l) {
+        // TODO: Implement this!
+    }
+
+    /**
+     * Update the texture image to the most recent frame from the image stream.  This may only be
+     * called while the OpenGL ES context that owns the texture is bound to the thread.  It will
+     * implicitly bind its texture to the GL_TEXTURE_EXTERNAL_OES texture target.
+     */
+    public native void updateTexImage();
+
+    private native void init(int texName);
+
+    /*
+     * We use a class initializer to allow the native code to cache some
+     * field offsets.
+     */
+    private static native void nativeClassInit();
+    static { nativeClassInit(); }
+}
diff --git a/include/camera/Camera.h b/include/camera/Camera.h
index c95f31e..e5f7e62 100644
--- a/include/camera/Camera.h
+++ b/include/camera/Camera.h
@@ -19,6 +19,7 @@
 
 #include <utils/Timers.h>
 #include <camera/ICameraClient.h>
+#include <gui/ISurfaceTexture.h>
 
 namespace android {
 
@@ -175,6 +176,9 @@
             // pass the buffered Surface to the camera service
             status_t    setPreviewDisplay(const sp<Surface>& surface);
 
+            // pass the buffered ISurfaceTexture to the camera service
+            status_t    setPreviewTexture(const sp<ISurfaceTexture>& surfaceTexture);
+
             // start preview mode, must call setPreviewDisplay first
             status_t    startPreview();
 
diff --git a/include/camera/ICamera.h b/include/camera/ICamera.h
index b69e075..b2310a6 100644
--- a/include/camera/ICamera.h
+++ b/include/camera/ICamera.h
@@ -24,6 +24,7 @@
 #include <binder/IMemory.h>
 #include <utils/String8.h>
 #include <camera/Camera.h>
+#include <gui/ISurfaceTexture.h>
 
 namespace android {
 
@@ -48,6 +49,10 @@
     // pass the buffered Surface to the camera service
     virtual status_t        setPreviewDisplay(const sp<Surface>& surface) = 0;
 
+    // pass the buffered ISurfaceTexture to the camera service
+    virtual status_t        setPreviewTexture(
+            const sp<ISurfaceTexture>& surfaceTexture) = 0;
+
     // set the preview callback flag to affect how the received frames from
     // preview are handled.
     virtual void            setPreviewCallbackFlag(int flag) = 0;
diff --git a/include/gui/ISurfaceTexture.h b/include/gui/ISurfaceTexture.h
new file mode 100644
index 0000000..77d37f1
--- /dev/null
+++ b/include/gui/ISurfaceTexture.h
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_GUI_ISURFACETEXTURE_H
+#define ANDROID_GUI_ISURFACETEXTURE_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/Errors.h>
+#include <utils/RefBase.h>
+
+#include <binder/IInterface.h>
+
+#include <ui/GraphicBuffer.h>
+#include <ui/Rect.h>
+
+namespace android {
+// ----------------------------------------------------------------------------
+
+class ISurfaceTexture : public IInterface
+{
+public:
+    DECLARE_META_INTERFACE(SurfaceTexture);
+
+    // requestBuffer requests a new buffer for the given index. The server (i.e.
+    // the ISurfaceTexture implementation) assigns the newly created buffer to
+    // the given slot index, and the client is expected to mirror the
+    // slot->buffer mapping so that it's not necessary to transfer a
+    // GraphicBuffer for every dequeue operation.
+    virtual sp<GraphicBuffer> requestBuffer(int slot, uint32_t w, uint32_t h,
+            uint32_t format, uint32_t usage) = 0;
+
+    // setBufferCount sets the number of buffer slots available. Calling this
+    // will also cause all buffer slots to be emptied. The caller should empty
+    // its mirrored copy of the buffer slots when calling this method.
+    virtual status_t setBufferCount(int bufferCount) = 0;
+
+    // dequeueBuffer requests a new buffer slot for the client to use. Ownership
+    // of the slot is transfered to the client, meaning that the server will not
+    // use the contents of the buffer associated with that slot. The slot index
+    // returned may or may not contain a buffer. If the slot is empty the client
+    // should call requestBuffer to assign a new buffer to that slot. The client
+    // is expected to either call cancelBuffer on the dequeued slot or to fill
+    // in the contents of its associated buffer contents and call queueBuffer.
+    virtual status_t dequeueBuffer(int *slot) = 0;
+
+    // queueBuffer indicates that the client has finished filling in the
+    // contents of the buffer associated with slot and transfers ownership of
+    // that slot back to the server. It is not valid to call queueBuffer on a
+    // slot that is not owned by the client or one for which a buffer associated
+    // via requestBuffer.
+    virtual status_t queueBuffer(int slot) = 0;
+
+    // cancelBuffer indicates that the client does not wish to fill in the
+    // buffer associated with slot and transfers ownership of the slot back to
+    // the server.
+    virtual void cancelBuffer(int slot) = 0;
+
+    virtual status_t setCrop(const Rect& reg) = 0;
+    virtual status_t setTransform(uint32_t transform) = 0;
+};
+
+// ----------------------------------------------------------------------------
+
+class BnSurfaceTexture : public BnInterface<ISurfaceTexture>
+{
+public:
+    virtual status_t    onTransact( uint32_t code,
+                                    const Parcel& data,
+                                    Parcel* reply,
+                                    uint32_t flags = 0);
+};
+
+// ----------------------------------------------------------------------------
+}; // namespace android
+
+#endif // ANDROID_GUI_ISURFACETEXTURE_H
diff --git a/include/gui/SurfaceTexture.h b/include/gui/SurfaceTexture.h
new file mode 100644
index 0000000..ff92e08
--- /dev/null
+++ b/include/gui/SurfaceTexture.h
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_GUI_SURFACETEXTURE_H
+#define ANDROID_GUI_SURFACETEXTURE_H
+
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+#include <GLES2/gl2.h>
+
+#include <gui/ISurfaceTexture.h>
+
+#include <ui/GraphicBuffer.h>
+
+#include <utils/threads.h>
+
+#define ANDROID_GRAPHICS_SURFACETEXTURE_JNI_ID "mSurfaceTexture"
+
+namespace android {
+// ----------------------------------------------------------------------------
+
+class SurfaceTexture : public BnSurfaceTexture {
+public:
+    enum { MIN_BUFFER_SLOTS = 3 };
+    enum { NUM_BUFFER_SLOTS = 32 };
+
+    // 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(GLuint tex);
+
+    virtual ~SurfaceTexture();
+
+    // setBufferCount updates the number of available buffer slots.  After
+    // calling this all buffer slots are both unallocated and owned by the
+    // SurfaceTexture object (i.e. they are not owned by the client).
+    virtual status_t setBufferCount(int bufferCount);
+
+    virtual sp<GraphicBuffer> requestBuffer(int buf, uint32_t w, uint32_t h,
+            uint32_t format, uint32_t usage);
+
+    // dequeueBuffer gets the next buffer slot index for the client to use. If a
+    // buffer slot is available then that slot index is written to the location
+    // pointed to by the buf argument and a status of OK is returned.  If no
+    // slot is available then a status of -EBUSY is returned and buf is
+    // unmodified.
+    virtual status_t dequeueBuffer(int *buf);
+
+    virtual status_t queueBuffer(int buf);
+    virtual void cancelBuffer(int buf);
+    virtual status_t setCrop(const Rect& reg);
+    virtual status_t setTransform(uint32_t transform);
+
+    // updateTexImage sets the image contents of the target texture to that of
+    // the most recently queued buffer.
+    //
+    // This call may only be made while the OpenGL ES context to which the
+    // target texture belongs is bound to the calling thread.
+    status_t updateTexImage();
+
+private:
+
+    // freeAllBuffers frees the resources (both GraphicBuffer and EGLImage) for
+    // all slots.
+    void freeAllBuffers();
+
+    // createImage creates a new EGLImage from a GraphicBuffer.
+    EGLImageKHR createImage(EGLDisplay dpy,
+            const sp<GraphicBuffer>& graphicBuffer);
+
+    enum { INVALID_BUFFER_SLOT = -1 };
+
+    struct BufferSlot {
+        // mGraphicBuffer points to the buffer allocated for this slot or is NULL
+        // if no buffer has been allocated.
+        sp<GraphicBuffer> mGraphicBuffer;
+
+        // mEglImage is the EGLImage created from mGraphicBuffer.
+        EGLImageKHR mEglImage;
+
+        // mEglDisplay is the EGLDisplay used to create mEglImage.
+        EGLDisplay mEglDisplay;
+
+        // mOwnedByClient indicates whether the slot is currently accessible to a
+        // client and should not be used by the SurfaceTexture object. It gets
+        // set to true when dequeueBuffer returns the slot and is reset to false
+        // when the client calls either queueBuffer or cancelBuffer on the slot.
+        bool mOwnedByClient;
+    };
+
+    // mSlots is the array of buffer slots that must be mirrored on the client
+    // side. This allows buffer ownership to be transferred between the client
+    // and server without sending a GraphicBuffer over binder. The entire array
+    // is initialized to NULL at construction time, and buffers are allocated
+    // for a slot when requestBuffer is called with that slot's index.
+    BufferSlot mSlots[NUM_BUFFER_SLOTS];
+
+    // mBufferCount is the number of buffer slots that the client and server
+    // must maintain. It defaults to MIN_BUFFER_SLOTS and can be changed by
+    // calling setBufferCount.
+    int mBufferCount;
+
+    // mCurrentTexture is the buffer slot index of the buffer that is currently
+    // bound to the OpenGL texture. A value of INVALID_BUFFER_SLOT, indicating
+    // that no buffer is currently bound to the texture.
+    int mCurrentTexture;
+
+    // mLastQueued is the buffer slot index of the most recently enqueued buffer.
+    // At construction time it is initialized to INVALID_BUFFER_SLOT, and is
+    // updated each time queueBuffer is called.
+    int mLastQueued;
+
+    // mTexName is the name of the OpenGL texture to which streamed images will
+    // be bound when updateTexImage is called. It is set at construction time 
+    // changed with a call to setTexName.
+    const GLuint mTexName;
+
+    // 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.
+    Mutex mMutex;
+};
+
+// ----------------------------------------------------------------------------
+}; // namespace android
+
+#endif // ANDROID_GUI_SURFACETEXTURE_H
diff --git a/include/gui/SurfaceTextureClient.h b/include/gui/SurfaceTextureClient.h
new file mode 100644
index 0000000..dd1d490
--- /dev/null
+++ b/include/gui/SurfaceTextureClient.h
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_GUI_SURFACETEXTURECLIENT_H
+#define ANDROID_GUI_SURFACETEXTURECLIENT_H
+
+#include <gui/ISurfaceTexture.h>
+#include <gui/SurfaceTexture.h>
+
+#include <ui/egl/android_natives.h>
+
+#include <utils/RefBase.h>
+#include <utils/threads.h>
+
+namespace android {
+
+class SurfaceTextureClient
+    : public EGLNativeBase<ANativeWindow, SurfaceTextureClient, RefBase>
+{
+public:
+    SurfaceTextureClient(const sp<ISurfaceTexture>& surfaceTexture);
+
+private:
+
+    // can't be copied
+    SurfaceTextureClient& operator = (const SurfaceTextureClient& rhs);
+    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 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, ...);
+
+    int setSwapInterval(int interval);
+    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 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 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);
+
+    void freeAllBuffers();
+
+    enum { MIN_BUFFER_SLOTS = SurfaceTexture::MIN_BUFFER_SLOTS };
+    enum { NUM_BUFFER_SLOTS = SurfaceTexture::NUM_BUFFER_SLOTS };
+    enum { DEFAULT_FORMAT = PIXEL_FORMAT_RGBA_8888 };
+
+    // mSurfaceTexture is the interface to the surface texture server. All
+    // operations on the surface texture client ultimately translate into
+    // interactions with the server using this interface.
+    sp<ISurfaceTexture> mSurfaceTexture;
+
+    // mSlots stores the buffers that have been allocated for each buffer slot.
+    // It is initialized to null pointers, and gets filled in with the result of
+    // ISurfaceTexture::requestBuffer when the client dequeues a buffer from a
+    // slot that has not yet been used. The buffer allocated to a slot will also
+    // be replaced if the requested buffer usage or geometry differs from that
+    // of the buffer allocated to a slot.
+    sp<GraphicBuffer> mSlots[NUM_BUFFER_SLOTS];
+
+    // mReqWidth is the buffer width that will be requested at the next dequeue
+    // operation. It is initialized to 1.
+    uint32_t mReqWidth;
+
+    // mReqHeight is the buffer height that will be requested at the next deuque
+    // operation. It is initialized to 1.
+    uint32_t mReqHeight;
+
+    // mReqFormat is the buffer pixel format that will be requested at the next
+    // deuque operation. It is initialized to PIXEL_FORMAT_RGBA_8888.
+    uint32_t mReqFormat;
+
+    // mReqUsage is the set of buffer usage flags that will be requested
+    // at the next deuque operation. It is initialized to 0.
+    uint32_t mReqUsage;
+
+    // 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.
+    Mutex mMutex;
+};
+
+}; // namespace android
+
+#endif  // ANDROID_GUI_SURFACETEXTURECLIENT_H
diff --git a/include/media/stagefright/ColorConverter.h b/include/media/stagefright/ColorConverter.h
index 2b61f58..2ae8a5b 100644
--- a/include/media/stagefright/ColorConverter.h
+++ b/include/media/stagefright/ColorConverter.h
@@ -21,6 +21,7 @@
 #include <sys/types.h>
 
 #include <stdint.h>
+#include <utils/Errors.h>
 
 #include <OMX_Video.h>
 
@@ -32,7 +33,7 @@
 
     bool isValid() const;
 
-    void convert(
+    status_t convert(
             const void *srcBits,
             size_t srcWidth, size_t srcHeight,
             size_t srcCropLeft, size_t srcCropTop,
@@ -63,16 +64,16 @@
 
     uint8_t *initClip();
 
-    void convertCbYCrY(
+    status_t convertCbYCrY(
             const BitmapParams &src, const BitmapParams &dst);
 
-    void convertYUV420Planar(
+    status_t convertYUV420Planar(
             const BitmapParams &src, const BitmapParams &dst);
 
-    void convertQCOMYUV420SemiPlanar(
+    status_t convertQCOMYUV420SemiPlanar(
             const BitmapParams &src, const BitmapParams &dst);
 
-    void convertYUV420SemiPlanar(
+    status_t convertYUV420SemiPlanar(
             const BitmapParams &src, const BitmapParams &dst);
 
     ColorConverter(const ColorConverter &);
diff --git a/include/surfaceflinger/ISurfaceComposer.h b/include/surfaceflinger/ISurfaceComposer.h
index 693fbfb..1bab7d7 100644
--- a/include/surfaceflinger/ISurfaceComposer.h
+++ b/include/surfaceflinger/ISurfaceComposer.h
@@ -131,6 +131,13 @@
      * This is an ASYNCHRONOUS call.
      */
     virtual void signal() const = 0;
+
+    /* Create a new GraphicBuffer for the client to use.  SurfaceFlinger will
+     * not maintain a reference to the GraphicBuffer, so the underlying native
+     * handle will be freed once the client references are released.
+     */
+    virtual sp<GraphicBuffer> createGraphicBuffer(uint32_t w, uint32_t h,
+            PixelFormat format, uint32_t usage) const = 0;
 };
 
 // ----------------------------------------------------------------------------
@@ -144,6 +151,7 @@
         BOOT_FINISHED = IBinder::FIRST_CALL_TRANSACTION,
         CREATE_CONNECTION,
         CREATE_CLIENT_CONNECTION,
+        CREATE_GRAPHIC_BUFFER,
         GET_CBLK,
         OPEN_GLOBAL_TRANSACTION,
         CLOSE_GLOBAL_TRANSACTION,
diff --git a/include/ui/GraphicBuffer.h b/include/ui/GraphicBuffer.h
index aa65d93..8b256f4 100644
--- a/include/ui/GraphicBuffer.h
+++ b/include/ui/GraphicBuffer.h
@@ -121,6 +121,7 @@
     friend class Surface;
     friend class BpSurface;
     friend class BnSurface;
+    friend class SurfaceTextureClient;
     friend class LightRefBase<GraphicBuffer>;
     GraphicBuffer(const GraphicBuffer& rhs);
     GraphicBuffer& operator = (const GraphicBuffer& rhs);
diff --git a/libs/camera/Android.mk b/libs/camera/Android.mk
index 03ff229..2f16923 100644
--- a/libs/camera/Android.mk
+++ b/libs/camera/Android.mk
@@ -14,7 +14,8 @@
 	libbinder \
 	libhardware \
 	libsurfaceflinger_client \
-	libui
+	libui \
+	libgui
 
 LOCAL_MODULE:= libcamera_client
 
diff --git a/libs/camera/Camera.cpp b/libs/camera/Camera.cpp
index ab626ad..907f119 100644
--- a/libs/camera/Camera.cpp
+++ b/libs/camera/Camera.cpp
@@ -182,6 +182,20 @@
     }
 }
 
+// pass the buffered ISurfaceTexture to the camera service
+status_t Camera::setPreviewTexture(const sp<ISurfaceTexture>& surfaceTexture)
+{
+    LOGV("setPreviewTexture(%p)", surfaceTexture.get());
+    sp <ICamera> c = mCamera;
+    if (c == 0) return NO_INIT;
+    if (surfaceTexture != 0) {
+        return c->setPreviewTexture(surfaceTexture);
+    } else {
+        LOGD("app passed NULL surface");
+        return c->setPreviewTexture(0);
+    }
+}
+
 // start preview mode
 status_t Camera::startPreview()
 {
diff --git a/libs/camera/ICamera.cpp b/libs/camera/ICamera.cpp
index 7ba8d12..0881d65 100644
--- a/libs/camera/ICamera.cpp
+++ b/libs/camera/ICamera.cpp
@@ -28,6 +28,7 @@
 enum {
     DISCONNECT = IBinder::FIRST_CALL_TRANSACTION,
     SET_PREVIEW_DISPLAY,
+    SET_PREVIEW_TEXTURE,
     SET_PREVIEW_CALLBACK_FLAG,
     START_PREVIEW,
     STOP_PREVIEW,
@@ -78,6 +79,18 @@
         return reply.readInt32();
     }
 
+    // pass the buffered SurfaceTexture to the camera service
+    status_t setPreviewTexture(const sp<ISurfaceTexture>& surfaceTexture)
+    {
+        LOGV("setPreviewTexture");
+        Parcel data, reply;
+        data.writeInterfaceToken(ICamera::getInterfaceDescriptor());
+        sp<IBinder> b(surfaceTexture->asBinder());
+        data.writeStrongBinder(b);
+        remote()->transact(SET_PREVIEW_TEXTURE, data, &reply);
+        return reply.readInt32();
+    }
+
     // set the preview callback flag to affect how the received frames from
     // preview are handled. See Camera.h for details.
     void setPreviewCallbackFlag(int flag)
@@ -296,6 +309,13 @@
             reply->writeInt32(setPreviewDisplay(surface));
             return NO_ERROR;
         } break;
+        case SET_PREVIEW_TEXTURE: {
+            LOGV("SET_PREVIEW_TEXTURE");
+            CHECK_INTERFACE(ICamera, data, reply);
+            sp<ISurfaceTexture> st = interface_cast<ISurfaceTexture>(data.readStrongBinder());
+            reply->writeInt32(setPreviewTexture(st));
+            return NO_ERROR;
+        } break;
         case SET_PREVIEW_CALLBACK_FLAG: {
             LOGV("SET_PREVIEW_CALLBACK_TYPE");
             CHECK_INTERFACE(ICamera, data, reply);
diff --git a/libs/gui/Android.mk b/libs/gui/Android.mk
index 249558a..d1a6af1 100644
--- a/libs/gui/Android.mk
+++ b/libs/gui/Android.mk
@@ -4,17 +4,25 @@
 LOCAL_SRC_FILES:= \
 	ISensorEventConnection.cpp \
 	ISensorServer.cpp \
+	ISurfaceTexture.cpp \
 	Sensor.cpp \
 	SensorChannel.cpp \
 	SensorEventQueue.cpp \
-	SensorManager.cpp
+	SensorManager.cpp \
+	SurfaceTexture.cpp \
+	SurfaceTextureClient.cpp
 
 LOCAL_SHARED_LIBRARIES := \
 	libcutils \
 	libutils \
 	libbinder \
 	libhardware \
-	libhardware_legacy
+	libhardware_legacy \
+	libui \
+	libEGL \
+	libGLESv2 \
+	libsurfaceflinger_client
+
 
 LOCAL_MODULE:= libgui
 
diff --git a/libs/gui/ISurfaceTexture.cpp b/libs/gui/ISurfaceTexture.cpp
new file mode 100644
index 0000000..90bca3c
--- /dev/null
+++ b/libs/gui/ISurfaceTexture.cpp
@@ -0,0 +1,204 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/Errors.h>
+#include <utils/RefBase.h>
+#include <utils/Vector.h>
+#include <utils/Timers.h>
+
+#include <binder/Parcel.h>
+#include <binder/IInterface.h>
+
+#include <gui/ISurfaceTexture.h>
+
+namespace android {
+// ----------------------------------------------------------------------------
+
+enum {
+    REQUEST_BUFFER = IBinder::FIRST_CALL_TRANSACTION,
+    SET_BUFFER_COUNT,
+    DEQUEUE_BUFFER,
+    QUEUE_BUFFER,
+    CANCEL_BUFFER,
+    SET_CROP,
+    SET_TRANSFORM,
+};
+
+
+class BpSurfaceTexture : public BpInterface<ISurfaceTexture>
+{
+public:
+    BpSurfaceTexture(const sp<IBinder>& impl)
+        : BpInterface<ISurfaceTexture>(impl)
+    {
+    }
+
+    virtual sp<GraphicBuffer> requestBuffer(int bufferIdx,
+            uint32_t w, uint32_t h, uint32_t format, uint32_t usage) {
+        Parcel data, reply;
+        data.writeInterfaceToken(ISurfaceTexture::getInterfaceDescriptor());
+        data.writeInt32(bufferIdx);
+        data.writeInt32(w);
+        data.writeInt32(h);
+        data.writeInt32(format);
+        data.writeInt32(usage);
+        remote()->transact(REQUEST_BUFFER, data, &reply);
+        sp<GraphicBuffer> buffer;
+        bool nonNull = reply.readInt32();
+        if (nonNull) {
+            buffer = new GraphicBuffer();
+            reply.read(*buffer);
+        }
+        return buffer;
+    }
+
+    virtual status_t setBufferCount(int bufferCount)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(ISurfaceTexture::getInterfaceDescriptor());
+        data.writeInt32(bufferCount);
+        remote()->transact(SET_BUFFER_COUNT, data, &reply);
+        status_t err = reply.readInt32();
+        return err;
+    }
+
+    virtual status_t dequeueBuffer(int *buf) {
+        Parcel data, reply;
+        data.writeInterfaceToken(ISurfaceTexture::getInterfaceDescriptor());
+        remote()->transact(DEQUEUE_BUFFER, data, &reply);
+        *buf = reply.readInt32();
+        int result = reply.readInt32();
+        return result;
+    }
+
+    virtual status_t queueBuffer(int buf) {
+        Parcel data, reply;
+        data.writeInterfaceToken(ISurfaceTexture::getInterfaceDescriptor());
+        data.writeInt32(buf);
+        remote()->transact(QUEUE_BUFFER, data, &reply);
+        status_t result = reply.readInt32();
+        return result;
+    }
+
+    virtual void cancelBuffer(int buf) {
+        Parcel data, reply;
+        data.writeInterfaceToken(ISurfaceTexture::getInterfaceDescriptor());
+        data.writeInt32(buf);
+        remote()->transact(CANCEL_BUFFER, data, &reply);
+    }
+
+    virtual status_t setCrop(const Rect& reg) {
+        Parcel data, reply;
+        data.writeInterfaceToken(ISurfaceTexture::getInterfaceDescriptor());
+        data.writeFloat(reg.left);
+        data.writeFloat(reg.top);
+        data.writeFloat(reg.right);
+        data.writeFloat(reg.bottom);
+        remote()->transact(SET_CROP, data, &reply);
+        status_t result = reply.readInt32();
+        return result;
+    }
+
+    virtual status_t setTransform(uint32_t transform) {
+        Parcel data, reply;
+        data.writeInterfaceToken(ISurfaceTexture::getInterfaceDescriptor());
+        data.writeInt32(transform);
+        remote()->transact(SET_TRANSFORM, data, &reply);
+        status_t result = reply.readInt32();
+        return result;
+    }
+};
+
+IMPLEMENT_META_INTERFACE(SurfaceTexture, "android.gui.SurfaceTexture");
+
+// ----------------------------------------------------------------------
+
+status_t BnSurfaceTexture::onTransact(
+    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+    switch(code) {
+        case REQUEST_BUFFER: {
+            CHECK_INTERFACE(ISurfaceTexture, data, reply);
+            int bufferIdx   = data.readInt32();
+            uint32_t w      = data.readInt32();
+            uint32_t h      = data.readInt32();
+            uint32_t format = data.readInt32();
+            uint32_t usage  = data.readInt32();
+            sp<GraphicBuffer> buffer(requestBuffer(bufferIdx, w, h, format,
+                    usage));
+            reply->writeInt32(buffer != 0);
+            if (buffer != 0) {
+                reply->write(*buffer);
+            }
+            return NO_ERROR;
+        } break;
+        case SET_BUFFER_COUNT: {
+            CHECK_INTERFACE(ISurfaceTexture, data, reply);
+            int bufferCount = data.readInt32();
+            int result = setBufferCount(bufferCount);
+            reply->writeInt32(result);
+            return NO_ERROR;
+        } break;
+        case DEQUEUE_BUFFER: {
+            CHECK_INTERFACE(ISurfaceTexture, data, reply);
+            int buf;
+            int result = dequeueBuffer(&buf);
+            reply->writeInt32(buf);
+            reply->writeInt32(result);
+            return NO_ERROR;
+        } break;
+        case QUEUE_BUFFER: {
+            CHECK_INTERFACE(ISurfaceTexture, data, reply);
+            int buf = data.readInt32();
+            status_t result = queueBuffer(buf);
+            reply->writeInt32(result);
+            return NO_ERROR;
+        } break;
+        case CANCEL_BUFFER: {
+            CHECK_INTERFACE(ISurfaceTexture, data, reply);
+            int buf = data.readInt32();
+            cancelBuffer(buf);
+            return NO_ERROR;
+        } break;
+        case SET_CROP: {
+            Rect reg;
+            CHECK_INTERFACE(ISurfaceTexture, data, reply);
+            reg.left = data.readFloat();
+            reg.top = data.readFloat();
+            reg.right = data.readFloat();
+            reg.bottom = data.readFloat();
+            status_t result = setCrop(reg);
+            reply->writeInt32(result);
+            return NO_ERROR;
+        } break;
+        case SET_TRANSFORM: {
+            Rect reg;
+            CHECK_INTERFACE(ISurfaceTexture, data, reply);
+            uint32_t transform = data.readInt32();
+            status_t result = setTransform(transform);
+            reply->writeInt32(result);
+            return NO_ERROR;
+        } break;
+    }
+    return BBinder::onTransact(code, data, reply, flags);
+}
+
+// ----------------------------------------------------------------------------
+
+}; // namespace android
diff --git a/libs/gui/SurfaceTexture.cpp b/libs/gui/SurfaceTexture.cpp
new file mode 100644
index 0000000..9579996
--- /dev/null
+++ b/libs/gui/SurfaceTexture.cpp
@@ -0,0 +1,199 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "SurfaceTexture"
+
+#define GL_GLEXT_PROTOTYPES
+#define EGL_EGLEXT_PROTOTYPES
+
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+
+#include <gui/SurfaceTexture.h>
+
+#include <surfaceflinger/ISurfaceComposer.h>
+#include <surfaceflinger/SurfaceComposerClient.h>
+
+#include <utils/Log.h>
+
+namespace android {
+
+SurfaceTexture::SurfaceTexture(GLuint tex) :
+    mBufferCount(MIN_BUFFER_SLOTS), mCurrentTexture(INVALID_BUFFER_SLOT),
+    mLastQueued(INVALID_BUFFER_SLOT), mTexName(tex) {
+}
+
+SurfaceTexture::~SurfaceTexture() {
+    freeAllBuffers();
+}
+
+status_t SurfaceTexture::setBufferCount(int bufferCount) {
+    Mutex::Autolock lock(mMutex);
+    freeAllBuffers();
+    mBufferCount = bufferCount;
+    return OK;
+}
+
+sp<GraphicBuffer> SurfaceTexture::requestBuffer(int buf,
+        uint32_t w, uint32_t h, uint32_t format, uint32_t usage) {
+    Mutex::Autolock lock(mMutex);
+    if (buf < 0 || mBufferCount <= buf) {
+        LOGE("requestBuffer: slot index out of range [0, %d]: %d",
+                mBufferCount, buf);
+        return 0;
+    }
+    usage |= GraphicBuffer::USAGE_HW_TEXTURE;
+    sp<ISurfaceComposer> composer(ComposerService::getComposerService());
+    sp<GraphicBuffer> graphicBuffer(composer->createGraphicBuffer(w, h,
+            format, usage));
+    if (graphicBuffer == 0) {
+        LOGE("requestBuffer: SurfaceComposer::createGraphicBuffer failed");
+    } else {
+        mSlots[buf].mGraphicBuffer = graphicBuffer;
+        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;
+        }
+    }
+    return graphicBuffer;
+}
+
+status_t SurfaceTexture::dequeueBuffer(int *buf) {
+    Mutex::Autolock lock(mMutex);
+    int found = INVALID_BUFFER_SLOT;
+    for (int i = 0; i < mBufferCount; i++) {
+        if (!mSlots[i].mOwnedByClient && i != mCurrentTexture) {
+            mSlots[i].mOwnedByClient = true;
+            found = i;
+            break;
+        }
+    }
+    if (found == INVALID_BUFFER_SLOT) {
+        return -EBUSY;
+    }
+    *buf = found;
+    return OK;
+}
+
+status_t SurfaceTexture::queueBuffer(int buf) {
+    Mutex::Autolock lock(mMutex);
+    if (buf < 0 || mBufferCount <= buf) {
+        LOGE("queueBuffer: slot index out of range [0, %d]: %d",
+                mBufferCount, buf);
+        return -EINVAL;
+    } else if (!mSlots[buf].mOwnedByClient) {
+        LOGE("queueBuffer: slot %d is not owned by the client", buf);
+        return -EINVAL;
+    } else if (mSlots[buf].mGraphicBuffer == 0) {
+        LOGE("queueBuffer: slot %d was enqueued without requesting a buffer",
+                buf);
+        return -EINVAL;
+    }
+    mSlots[buf].mOwnedByClient = false;
+    mLastQueued = buf;
+    return OK;
+}
+
+void SurfaceTexture::cancelBuffer(int buf) {
+    Mutex::Autolock lock(mMutex);
+    if (buf < 0 || mBufferCount <= buf) {
+        LOGE("cancelBuffer: slot index out of range [0, %d]: %d", mBufferCount,
+                buf);
+        return;
+    } else if (!mSlots[buf].mOwnedByClient) {
+        LOGE("cancelBuffer: slot %d is not owned by the client", buf);
+        return;
+    }
+    mSlots[buf].mOwnedByClient = false;
+}
+
+status_t SurfaceTexture::setCrop(const Rect& reg) {
+    Mutex::Autolock lock(mMutex);
+    // XXX: How should we handle crops?
+    return OK;
+}
+
+status_t SurfaceTexture::setTransform(uint32_t transform) {
+    Mutex::Autolock lock(mMutex);
+    // XXX: How should we handle transforms?
+    return OK;
+}
+
+status_t SurfaceTexture::updateTexImage() {
+    Mutex::Autolock lock(mMutex);
+
+    // We always bind the texture even if we don't update its contents.
+    glBindTexture(GL_TEXTURE_EXTERNAL_OES, mTexName);
+
+    // Initially both mCurrentTexture and mLastQueued are INVALID_BUFFER_SLOT,
+    // so this check will fail until a buffer gets queued.
+    if (mCurrentTexture != mLastQueued) {
+        // XXX: Figure out the right target.
+        mCurrentTexture = mLastQueued;
+        EGLImageKHR image = mSlots[mCurrentTexture].mEglImage;
+        if (image == EGL_NO_IMAGE_KHR) {
+            EGLDisplay dpy = eglGetCurrentDisplay();
+            sp<GraphicBuffer> graphicBuffer = mSlots[mCurrentTexture].mGraphicBuffer;
+            image = createImage(dpy, graphicBuffer);
+            mSlots[mCurrentTexture].mEglImage = image;
+            mSlots[mCurrentTexture].mEglDisplay = dpy;
+        }
+        glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, (GLeglImageOES)image);
+        GLint error = glGetError();
+        if (error != GL_NO_ERROR) {
+            LOGE("error binding external texture image %p (slot %d): %#04x",
+                    image, mCurrentTexture, error);
+            return -EINVAL;
+        }
+    }
+    return OK;
+}
+
+void SurfaceTexture::freeAllBuffers() {
+    for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
+        mSlots[i].mGraphicBuffer = 0;
+        mSlots[i].mOwnedByClient = false;
+        if (mSlots[i].mEglImage != EGL_NO_IMAGE_KHR) {
+            eglDestroyImageKHR(mSlots[i].mEglDisplay, mSlots[i].mEglImage);
+            mSlots[i].mEglImage = EGL_NO_IMAGE_KHR;
+            mSlots[i].mEglDisplay = EGL_NO_DISPLAY;
+        }
+    }
+}
+
+EGLImageKHR SurfaceTexture::createImage(EGLDisplay dpy,
+        const sp<GraphicBuffer>& graphicBuffer) {
+    EGLClientBuffer cbuf = (EGLClientBuffer)graphicBuffer->getNativeBuffer();
+    EGLint attrs[] = {
+        EGL_IMAGE_PRESERVED_KHR,    EGL_TRUE,
+        EGL_NONE,
+    };
+    EGLImageKHR image = eglCreateImageKHR(dpy, EGL_NO_CONTEXT,
+            EGL_NATIVE_BUFFER_ANDROID, cbuf, attrs);
+    EGLint error = eglGetError();
+    if (error != EGL_SUCCESS) {
+        LOGE("error creating EGLImage: %#x", error);
+    } else if (image == EGL_NO_IMAGE_KHR) {
+        LOGE("no error reported, but no image was returned by "
+                "eglCreateImageKHR");
+    }
+    return image;
+}
+
+}; // namespace android
diff --git a/libs/gui/SurfaceTextureClient.cpp b/libs/gui/SurfaceTextureClient.cpp
new file mode 100644
index 0000000..8a59144
--- /dev/null
+++ b/libs/gui/SurfaceTextureClient.cpp
@@ -0,0 +1,285 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "SurfaceTextureClient"
+
+#include <gui/SurfaceTextureClient.h>
+
+#include <utils/Log.h>
+
+namespace android {
+
+SurfaceTextureClient::SurfaceTextureClient(
+        const sp<ISurfaceTexture>& surfaceTexture):
+        mSurfaceTexture(surfaceTexture), mReqWidth(1), mReqHeight(1),
+        mReqFormat(DEFAULT_FORMAT), mReqUsage(0), mMutex() {
+    // Initialize the ANativeWindow function pointers.
+    ANativeWindow::setSwapInterval  = setSwapInterval;
+    ANativeWindow::dequeueBuffer    = dequeueBuffer;
+    ANativeWindow::cancelBuffer     = cancelBuffer;
+    ANativeWindow::lockBuffer       = lockBuffer;
+    ANativeWindow::queueBuffer      = queueBuffer;
+    ANativeWindow::query            = query;
+    ANativeWindow::perform          = perform;
+}
+
+int SurfaceTextureClient::setSwapInterval(ANativeWindow* window, int interval) {
+    SurfaceTextureClient* c = getSelf(window);
+    return c->setSwapInterval(interval);
+}
+
+int SurfaceTextureClient::dequeueBuffer(ANativeWindow* window,
+        android_native_buffer_t** buffer) {
+    SurfaceTextureClient* c = getSelf(window);
+    return c->dequeueBuffer(buffer);
+}
+
+int SurfaceTextureClient::cancelBuffer(ANativeWindow* window,
+        android_native_buffer_t* buffer) {
+    SurfaceTextureClient* c = getSelf(window);
+    return c->cancelBuffer(buffer);
+}
+
+int SurfaceTextureClient::lockBuffer(ANativeWindow* window,
+        android_native_buffer_t* buffer) {
+    SurfaceTextureClient* c = getSelf(window);
+    return c->lockBuffer(buffer);
+}
+
+int SurfaceTextureClient::queueBuffer(ANativeWindow* window,
+        android_native_buffer_t* buffer) {
+    SurfaceTextureClient* c = getSelf(window);
+    return c->queueBuffer(buffer);
+}
+
+int SurfaceTextureClient::query(ANativeWindow* window, int what, int* value) {
+    SurfaceTextureClient* c = getSelf(window);
+    return c->query(what, value);
+}
+
+int SurfaceTextureClient::perform(ANativeWindow* window, int operation, ...) {
+    va_list args;
+    va_start(args, operation);
+    SurfaceTextureClient* c = getSelf(window);
+    return c->perform(operation, args);
+}
+
+int SurfaceTextureClient::setSwapInterval(int interval) {
+    return INVALID_OPERATION;
+}
+
+int SurfaceTextureClient::dequeueBuffer(android_native_buffer_t** buffer) {
+    Mutex::Autolock lock(mMutex);
+    int buf = -1;
+    status_t err = mSurfaceTexture->dequeueBuffer(&buf);
+    if (err < 0) {
+        return err;
+    }
+    sp<GraphicBuffer>& gbuf(mSlots[buf]);
+    if (gbuf == 0 || gbuf->getWidth() != mReqWidth ||
+        gbuf->getHeight() != mReqHeight ||
+        uint32_t(gbuf->getPixelFormat()) != mReqFormat ||
+        (gbuf->getUsage() & mReqUsage) != mReqUsage) {
+        gbuf = mSurfaceTexture->requestBuffer(buf, mReqWidth, mReqHeight,
+                mReqFormat, mReqUsage);
+        if (gbuf == 0) {
+            return NO_MEMORY;
+        }
+    }
+    *buffer = gbuf.get();
+    return OK;
+}
+
+int SurfaceTextureClient::cancelBuffer(android_native_buffer_t* buffer) {
+    Mutex::Autolock lock(mMutex);
+    for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
+        if (mSlots[i].get() == buffer) {
+            mSurfaceTexture->cancelBuffer(i);
+            return OK;
+        }
+    }
+    return BAD_VALUE;
+}
+
+int SurfaceTextureClient::lockBuffer(android_native_buffer_t* buffer) {
+    Mutex::Autolock lock(mMutex);
+    return OK;
+}
+
+int SurfaceTextureClient::queueBuffer(android_native_buffer_t* buffer) {
+    Mutex::Autolock lock(mMutex);
+    for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
+        if (mSlots[i].get() == GraphicBuffer::getSelf(buffer)) {
+            return mSurfaceTexture->queueBuffer(i);
+        }
+    }
+    LOGE("queueBuffer: unknown buffer queued");
+    return BAD_VALUE;
+}
+
+int SurfaceTextureClient::query(int what, int* value) {
+    Mutex::Autolock lock(mMutex);
+    // XXX: Implement this!
+    return INVALID_OPERATION;
+}
+
+int SurfaceTextureClient::perform(int operation, va_list args)
+{
+    int res = NO_ERROR;
+    switch (operation) {
+    case NATIVE_WINDOW_CONNECT:
+        res = dispatchConnect(args);
+        break;
+    case NATIVE_WINDOW_DISCONNECT:
+        res = dispatchDisconnect(args);
+        break;
+    case NATIVE_WINDOW_SET_USAGE:
+        res = dispatchSetUsage(args);
+        break;
+    case NATIVE_WINDOW_SET_CROP:
+        res = dispatchSetCrop(args);
+        break;
+    case NATIVE_WINDOW_SET_BUFFER_COUNT:
+        res = dispatchSetBufferCount(args);
+        break;
+    case NATIVE_WINDOW_SET_BUFFERS_GEOMETRY:
+        res = dispatchSetBuffersGeometry(args);
+        break;
+    case NATIVE_WINDOW_SET_BUFFERS_TRANSFORM:
+        res = dispatchSetBuffersTransform(args);
+        break;
+    default:
+        res = NAME_NOT_FOUND;
+        break;
+    }
+    return res;
+}
+
+int SurfaceTextureClient::dispatchConnect(va_list args) {
+    int api = va_arg(args, int);
+    return connect(api);
+}
+
+int SurfaceTextureClient::dispatchDisconnect(va_list args) {
+    int api = va_arg(args, int);
+    return disconnect(api);
+}
+
+int SurfaceTextureClient::dispatchSetUsage(va_list args) {
+    int usage = va_arg(args, int);
+    return setUsage(usage);
+}
+
+int SurfaceTextureClient::dispatchSetCrop(va_list args) {
+    android_native_rect_t const* rect = va_arg(args, android_native_rect_t*);
+    return setCrop(reinterpret_cast<Rect const*>(rect));
+}
+
+int SurfaceTextureClient::dispatchSetBufferCount(va_list args) {
+    size_t bufferCount = va_arg(args, size_t);
+    return setBufferCount(bufferCount);
+}
+
+int SurfaceTextureClient::dispatchSetBuffersGeometry(va_list args) {
+    int w = va_arg(args, int);
+    int h = va_arg(args, int);
+    int f = va_arg(args, int);
+    return setBuffersGeometry(w, h, f);
+}
+
+int SurfaceTextureClient::dispatchSetBuffersTransform(va_list args) {
+    int transform = va_arg(args, int);
+    return setBuffersTransform(transform);
+}
+
+int SurfaceTextureClient::connect(int api) {
+    // XXX: Implement this!
+    return INVALID_OPERATION;
+}
+
+int SurfaceTextureClient::disconnect(int api) {
+    // XXX: Implement this!
+    return INVALID_OPERATION;
+}
+
+int SurfaceTextureClient::setUsage(uint32_t reqUsage)
+{
+    Mutex::Autolock lock(mMutex);
+    mReqUsage = reqUsage;
+    return OK;
+}
+
+int SurfaceTextureClient::setCrop(Rect const* rect)
+{
+    Mutex::Autolock lock(mMutex);
+
+    // empty/invalid rects are not allowed
+    if (rect->isEmpty())
+        return BAD_VALUE;
+
+    status_t err = mSurfaceTexture->setCrop(*rect);
+    LOGE_IF(err, "ISurfaceTexture::setCrop(...) returned %s",
+            strerror(-err));
+
+    return err;
+}
+
+int SurfaceTextureClient::setBufferCount(int bufferCount)
+{
+    Mutex::Autolock lock(mMutex);
+
+    status_t err = mSurfaceTexture->setBufferCount(bufferCount);
+    LOGE_IF(err, "ISurfaceTexture::setBufferCount(%d) returned %s",
+            bufferCount, strerror(-err));
+
+    if (err == NO_ERROR) {
+        freeAllBuffers();
+    }
+
+    return err;
+}
+
+int SurfaceTextureClient::setBuffersGeometry(int w, int h, int format)
+{
+    Mutex::Autolock lock(mMutex);
+
+    if (w<0 || h<0 || format<0)
+        return BAD_VALUE;
+
+    if ((w && !h) || (!w && h))
+        return BAD_VALUE;
+
+    mReqWidth = w;
+    mReqHeight = h;
+    mReqFormat = format;
+
+    return NO_ERROR;
+}
+
+int SurfaceTextureClient::setBuffersTransform(int transform)
+{
+    Mutex::Autolock lock(mMutex);
+    status_t err = mSurfaceTexture->setTransform(transform);
+    return err;
+}
+
+void SurfaceTextureClient::freeAllBuffers() {
+    for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
+        mSlots[i] = 0;
+    }
+}
+
+}; // namespace android
diff --git a/libs/hwui/DisplayListRenderer.cpp b/libs/hwui/DisplayListRenderer.cpp
index 77d628a..afb82bf 100644
--- a/libs/hwui/DisplayListRenderer.cpp
+++ b/libs/hwui/DisplayListRenderer.cpp
@@ -82,6 +82,43 @@
 ///////////////////////////////////////////////////////////////////////////////
 
 DisplayList::DisplayList(const DisplayListRenderer& recorder) {
+    initFromDisplayListRenderer(recorder);
+}
+
+DisplayList::~DisplayList() {
+    sk_free((void*) mReader.base());
+
+    Caches& caches = Caches::getInstance();
+
+    for (size_t i = 0; i < mBitmapResources.size(); i++) {
+        caches.resourceCache.decrementRefcount(mBitmapResources.itemAt(i));
+    }
+    mBitmapResources.clear();
+
+    for (size_t i = 0; i < mShaderResources.size(); i++) {
+        caches.resourceCache.decrementRefcount(mShaderResources.itemAt(i));
+    }
+    mShaderResources.clear();
+
+    for (size_t i = 0; i < mPaints.size(); i++) {
+        delete mPaints.itemAt(i);
+    }
+    mPaints.clear();
+
+    for (size_t i = 0; i < mMatrices.size(); i++) {
+        delete mMatrices.itemAt(i);
+    }
+    mMatrices.clear();
+
+    if (mPathHeap) {
+        for (int i = 0; i < mPathHeap->count(); i++) {
+            caches.pathCache.removeDeferred(&(*mPathHeap)[i]);
+        }
+        mPathHeap->safeUnref();
+    }
+}
+
+void DisplayList::initFromDisplayListRenderer(const DisplayListRenderer& recorder) {
     const SkWriter32& writer = recorder.writeStream();
     init();
 
@@ -132,39 +169,6 @@
     }
 }
 
-DisplayList::~DisplayList() {
-    sk_free((void*) mReader.base());
-
-    Caches& caches = Caches::getInstance();
-
-    for (size_t i = 0; i < mBitmapResources.size(); i++) {
-        caches.resourceCache.decrementRefcount(mBitmapResources.itemAt(i));
-    }
-    mBitmapResources.clear();
-
-    for (size_t i = 0; i < mShaderResources.size(); i++) {
-        caches.resourceCache.decrementRefcount(mShaderResources.itemAt(i));
-    }
-    mShaderResources.clear();
-
-    for (size_t i = 0; i < mPaints.size(); i++) {
-        delete mPaints.itemAt(i);
-    }
-    mPaints.clear();
-
-    for (size_t i = 0; i < mMatrices.size(); i++) {
-        delete mMatrices.itemAt(i);
-    }
-    mMatrices.clear();
-
-    if (mPathHeap) {
-        for (int i = 0; i < mPathHeap->count(); i++) {
-            caches.pathCache.removeDeferred(&(*mPathHeap)[i]);
-        }
-        mPathHeap->safeUnref();
-    }
-}
-
 void DisplayList::init() {
     mPathHeap = NULL;
 }
@@ -327,6 +331,7 @@
 DisplayListRenderer::DisplayListRenderer():
         mHeap(HEAP_BLOCK_SIZE), mWriter(MIN_WRITER_SIZE) {
     mPathHeap = NULL;
+    mDisplayList = NULL;
 }
 
 DisplayListRenderer::~DisplayListRenderer() {
@@ -367,6 +372,15 @@
 // Operations
 ///////////////////////////////////////////////////////////////////////////////
 
+DisplayList* DisplayListRenderer::getDisplayList() {
+    if (mDisplayList == NULL) {
+        mDisplayList = new DisplayList(*this);
+    } else {
+        mDisplayList->initFromDisplayListRenderer(*this);
+    }
+    return mDisplayList;
+}
+
 void DisplayListRenderer::setViewport(int width, int height) {
     mOrthoMatrix.loadOrtho(0, width, height, 0, -1, 1);
 
diff --git a/libs/hwui/DisplayListRenderer.h b/libs/hwui/DisplayListRenderer.h
index b608381..fedb174 100644
--- a/libs/hwui/DisplayListRenderer.h
+++ b/libs/hwui/DisplayListRenderer.h
@@ -110,6 +110,8 @@
         SetupShadow
     };
 
+    void initFromDisplayListRenderer(const DisplayListRenderer& recorder);
+
     void replay(OpenGLRenderer& renderer);
 
 private:
@@ -216,6 +218,8 @@
     DisplayListRenderer();
     ~DisplayListRenderer();
 
+    DisplayList* getDisplayList();
+
     void setViewport(int width, int height);
     void prepare(bool opaque);
 
@@ -266,10 +270,6 @@
 
     void reset();
 
-    DisplayList* getDisplayList() const {
-        return new DisplayList(*this);
-    }
-
     const SkWriter32& writeStream() const {
         return mWriter;
     }
@@ -422,6 +422,8 @@
     SkRefCntRecorder mRCRecorder;
     SkRefCntRecorder mTFRecorder;
 
+    DisplayList *mDisplayList;
+
     friend class DisplayList;
 
 }; // class DisplayListRenderer
diff --git a/libs/surfaceflinger_client/ISurfaceComposer.cpp b/libs/surfaceflinger_client/ISurfaceComposer.cpp
index b8a7a79..a42b49d 100644
--- a/libs/surfaceflinger_client/ISurfaceComposer.cpp
+++ b/libs/surfaceflinger_client/ISurfaceComposer.cpp
@@ -26,6 +26,7 @@
 #include <binder/IServiceManager.h>
 
 #include <ui/DisplayInfo.h>
+#include <ui/GraphicBuffer.h>
 
 #include <surfaceflinger/ISurfaceComposer.h>
 
@@ -169,6 +170,25 @@
         data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
         remote()->transact(BnSurfaceComposer::SIGNAL, data, &reply, IBinder::FLAG_ONEWAY);
     }
+
+    virtual sp<GraphicBuffer> createGraphicBuffer(uint32_t w, uint32_t h,
+            PixelFormat format, uint32_t usage) const {
+        Parcel data, reply;
+        data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
+        data.writeInt32(w);
+        data.writeInt32(h);
+        data.writeInt32(format);
+        data.writeInt32(usage);
+        remote()->transact(BnSurfaceComposer::CREATE_GRAPHIC_BUFFER, data,
+                &reply);
+        sp<GraphicBuffer> graphicBuffer;
+        bool nonNull = (bool)reply.readInt32();
+        if (nonNull) {
+            graphicBuffer = new GraphicBuffer();
+            reply.read(*graphicBuffer);
+        }
+        return graphicBuffer;
+    }
 };
 
 IMPLEMENT_META_INTERFACE(SurfaceComposer, "android.ui.ISurfaceComposer");
@@ -247,6 +267,18 @@
             reply->writeInt32(f);
             reply->writeInt32(res);
         } break;
+        case CREATE_GRAPHIC_BUFFER: {
+            CHECK_INTERFACE(ISurfaceComposer, data, reply);
+            uint32_t w = data.readInt32();
+            uint32_t h = data.readInt32();
+            PixelFormat format = data.readInt32();
+            uint32_t usage = data.readInt32();
+            sp<GraphicBuffer> result(createGraphicBuffer(w, h, format, usage));
+            reply->writeInt32(result != 0);
+            if (result != 0) {
+                reply->write(*result);
+            }
+        } break;
         case TURN_ELECTRON_BEAM_OFF: {
             CHECK_INTERFACE(ISurfaceComposer, data, reply);
             int32_t mode = data.readInt32();
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index 97c541a..439e4ce 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -733,8 +733,8 @@
     }
 
     char value[PROPERTY_VALUE_MAX];
-    if (property_get("media.httplive.enable-nuplayer", value, NULL)
-            && (!strcasecmp(value, "true") || !strcmp(value, "1"))) {
+    if (!property_get("media.httplive.disable-nuplayer", value, NULL)
+            || (strcasecmp(value, "true") && strcmp(value, "1"))) {
         if (!strncasecmp("http://", url, 7)) {
             size_t len = strlen(url);
             if (len >= 5 && !strcasecmp(".m3u8", &url[len - 5])) {
diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp
index f63774a..8efd963 100644
--- a/media/libstagefright/OMXCodec.cpp
+++ b/media/libstagefright/OMXCodec.cpp
@@ -1506,7 +1506,7 @@
 OMXCodec::~OMXCodec() {
     mSource.clear();
 
-    CHECK(mState == LOADED || mState == ERROR);
+    CHECK(mState == LOADED || mState == ERROR || mState == LOADED_TO_IDLE);
 
     status_t err = mOMX->freeNode(mNode);
     CHECK_EQ(err, (status_t)OK);
diff --git a/media/libstagefright/StagefrightMetadataRetriever.cpp b/media/libstagefright/StagefrightMetadataRetriever.cpp
index 6331a63..8cd2998 100644
--- a/media/libstagefright/StagefrightMetadataRetriever.cpp
+++ b/media/libstagefright/StagefrightMetadataRetriever.cpp
@@ -238,7 +238,7 @@
             (OMX_COLOR_FORMATTYPE)srcFormat, OMX_COLOR_Format16bitRGB565);
     CHECK(converter.isValid());
 
-    converter.convert(
+    err = converter.convert(
             (const uint8_t *)buffer->data() + buffer->range_offset(),
             width, height,
             crop_left, crop_top, crop_right, crop_bottom,
@@ -252,6 +252,13 @@
 
     decoder->stop();
 
+    if (err != OK) {
+        LOGE("Colorconverter failed to convert frame.");
+
+        delete frame;
+        frame = NULL;
+    }
+
     return frame;
 }
 
diff --git a/media/libstagefright/colorconversion/ColorConverter.cpp b/media/libstagefright/colorconversion/ColorConverter.cpp
index 600f040..d518c97 100644
--- a/media/libstagefright/colorconversion/ColorConverter.cpp
+++ b/media/libstagefright/colorconversion/ColorConverter.cpp
@@ -16,6 +16,7 @@
 
 #include <media/stagefright/ColorConverter.h>
 #include <media/stagefright/MediaDebug.h>
+#include <media/stagefright/MediaErrors.h>
 
 namespace android {
 
@@ -72,7 +73,7 @@
     return mCropBottom - mCropTop + 1;
 }
 
-void ColorConverter::convert(
+status_t ColorConverter::convert(
         const void *srcBits,
         size_t srcWidth, size_t srcHeight,
         size_t srcCropLeft, size_t srcCropTop,
@@ -81,7 +82,9 @@
         size_t dstWidth, size_t dstHeight,
         size_t dstCropLeft, size_t dstCropTop,
         size_t dstCropRight, size_t dstCropBottom) {
-    CHECK_EQ(mDstFormat, OMX_COLOR_Format16bitRGB565);
+    if (mDstFormat != OMX_COLOR_Format16bitRGB565) {
+        return ERROR_UNSUPPORTED;
+    }
 
     BitmapParams src(
             const_cast<void *>(srcBits),
@@ -93,21 +96,23 @@
             dstWidth, dstHeight,
             dstCropLeft, dstCropTop, dstCropRight, dstCropBottom);
 
+    status_t err;
+
     switch (mSrcFormat) {
         case OMX_COLOR_FormatYUV420Planar:
-            convertYUV420Planar(src, dst);
+            err = convertYUV420Planar(src, dst);
             break;
 
         case OMX_COLOR_FormatCbYCrY:
-            convertCbYCrY(src, dst);
+            err = convertCbYCrY(src, dst);
             break;
 
         case OMX_QCOM_COLOR_FormatYVU420SemiPlanar:
-            convertQCOMYUV420SemiPlanar(src, dst);
+            err = convertQCOMYUV420SemiPlanar(src, dst);
             break;
 
         case OMX_COLOR_FormatYUV420SemiPlanar:
-            convertYUV420SemiPlanar(src, dst);
+            err = convertYUV420SemiPlanar(src, dst);
             break;
 
         default:
@@ -116,17 +121,21 @@
             break;
         }
     }
+
+    return err;
 }
 
-void ColorConverter::convertCbYCrY(
+status_t ColorConverter::convertCbYCrY(
         const BitmapParams &src, const BitmapParams &dst) {
     // XXX Untested
 
     uint8_t *kAdjustedClip = initClip();
 
-    CHECK((src.mCropLeft & 1) == 0);
-    CHECK_EQ(src.cropWidth(), dst.cropWidth());
-    CHECK_EQ(src.cropHeight(), dst.cropHeight());
+    if (!((src.mCropLeft & 1) == 0
+        && src.cropWidth() == dst.cropWidth()
+        && src.cropHeight() == dst.cropHeight())) {
+        return ERROR_UNSUPPORTED;
+    }
 
     uint32_t *dst_ptr = (uint32_t *)dst.mBits
         + (dst.mCropTop * dst.mWidth + dst.mCropLeft) / 2;
@@ -172,16 +181,20 @@
         src_ptr += src.mWidth * 2;
         dst_ptr += dst.mWidth / 2;
     }
+
+    return OK;
 }
 
-void ColorConverter::convertYUV420Planar(
+status_t ColorConverter::convertYUV420Planar(
         const BitmapParams &src, const BitmapParams &dst) {
-    uint8_t *kAdjustedClip = initClip();
+    if (!((dst.mWidth & 3) == 0
+            && (src.mCropLeft & 1) == 0
+            && src.cropWidth() == dst.cropWidth()
+            && src.cropHeight() == dst.cropHeight())) {
+        return ERROR_UNSUPPORTED;
+    }
 
-    CHECK((dst.mWidth & 3) == 0);
-    CHECK((src.mCropLeft & 1) == 0);
-    CHECK_EQ(src.cropWidth(), dst.cropWidth());
-    CHECK_EQ(src.cropHeight(), dst.cropHeight());
+    uint8_t *kAdjustedClip = initClip();
 
     uint32_t *dst_ptr = (uint32_t *)dst.mBits
         + (dst.mCropTop * dst.mWidth + dst.mCropLeft) / 2;
@@ -259,16 +272,20 @@
 
         dst_ptr += dst.mWidth / 2;
     }
+
+    return OK;
 }
 
-void ColorConverter::convertQCOMYUV420SemiPlanar(
+status_t ColorConverter::convertQCOMYUV420SemiPlanar(
         const BitmapParams &src, const BitmapParams &dst) {
     uint8_t *kAdjustedClip = initClip();
 
-    CHECK((dst.mWidth & 3) == 0);
-    CHECK((src.mCropLeft & 1) == 0);
-    CHECK_EQ(src.cropWidth(), dst.cropWidth());
-    CHECK_EQ(src.cropHeight(), dst.cropHeight());
+    if (!((dst.mWidth & 3) == 0
+            && (src.mCropLeft & 1) == 0
+            && src.cropWidth() == dst.cropWidth()
+            && src.cropHeight() == dst.cropHeight())) {
+        return ERROR_UNSUPPORTED;
+    }
 
     uint32_t *dst_ptr = (uint32_t *)dst.mBits
         + (dst.mCropTop * dst.mWidth + dst.mCropLeft) / 2;
@@ -324,18 +341,22 @@
 
         dst_ptr += dst.mWidth / 2;
     }
+
+    return OK;
 }
 
-void ColorConverter::convertYUV420SemiPlanar(
+status_t ColorConverter::convertYUV420SemiPlanar(
         const BitmapParams &src, const BitmapParams &dst) {
     // XXX Untested
 
     uint8_t *kAdjustedClip = initClip();
 
-    CHECK((dst.mWidth & 3) == 0);
-    CHECK((src.mCropLeft & 1) == 0);
-    CHECK_EQ(src.cropWidth(), dst.cropWidth());
-    CHECK_EQ(src.cropHeight(), dst.cropHeight());
+    if (!((dst.mWidth & 3) == 0
+            && (src.mCropLeft & 1) == 0
+            && src.cropWidth() == dst.cropWidth()
+            && src.cropHeight() == dst.cropHeight())) {
+        return ERROR_UNSUPPORTED;
+    }
 
     uint32_t *dst_ptr = (uint32_t *)dst.mBits
         + (dst.mCropTop * dst.mWidth + dst.mCropLeft) / 2;
@@ -391,6 +412,8 @@
 
         dst_ptr += dst.mWidth / 2;
     }
+
+    return OK;
 }
 
 uint8_t *ColorConverter::initClip() {
diff --git a/media/libstagefright/httplive/LiveSession.cpp b/media/libstagefright/httplive/LiveSession.cpp
index 6fd0171..9e63c41 100644
--- a/media/libstagefright/httplive/LiveSession.cpp
+++ b/media/libstagefright/httplive/LiveSession.cpp
@@ -158,8 +158,8 @@
         mBandwidthItems.sort(SortByBandwidth);
 
         char value[PROPERTY_VALUE_MAX];
-        if (!property_get("media.httplive.enable-nuplayer", value, NULL)
-                || (strcasecmp(value, "true") && strcmp(value, "1"))) {
+        if (property_get("media.httplive.disable-nuplayer", value, NULL)
+                && (!strcasecmp(value, "true") || !strcmp(value, "1"))) {
             // The "legacy" player cannot deal with audio format changes,
             // some streams use different audio encoding parameters for
             // their lowest bandwidth stream.
@@ -340,6 +340,7 @@
 void LiveSession::onDownloadNext() {
     size_t bandwidthIndex = getBandwidthIndex();
 
+rinse_repeat:
     int64_t nowUs = ALooper::GetNowUs();
 
     if (mLastPlaylistFetchTimeUs < 0
@@ -437,6 +438,18 @@
 
     if (mSeqNumber < firstSeqNumberInPlaylist
             || mSeqNumber > lastSeqNumberInPlaylist) {
+        if (mSeqNumber < firstSeqNumberInPlaylist
+                && mPrevBandwidthIndex != (ssize_t)bandwidthIndex) {
+            // Go back to the previous bandwidth.
+
+            LOGI("new bandwidth does not have the sequence number "
+                 "we're looking for, switching back to previous bandwidth");
+
+            mLastPlaylistFetchTimeUs = -1;
+            bandwidthIndex = mPrevBandwidthIndex;
+            goto rinse_repeat;
+        }
+
         if (!mPlaylist->isComplete()
                 && mSeqNumber > lastSeqNumberInPlaylist
                 && mNumRetries < kMaxNumRetries) {
diff --git a/services/camera/libcameraservice/Android.mk b/services/camera/libcameraservice/Android.mk
index 87975af..b52fc69 100644
--- a/services/camera/libcameraservice/Android.mk
+++ b/services/camera/libcameraservice/Android.mk
@@ -49,7 +49,8 @@
     libcutils \
     libmedia \
     libcamera_client \
-    libsurfaceflinger_client
+    libsurfaceflinger_client \
+    libgui
 
 LOCAL_MODULE:= libcameraservice
 
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index 15f6a44..3d8ca7a 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -27,6 +27,7 @@
 #include <binder/MemoryHeapBase.h>
 #include <cutils/atomic.h>
 #include <cutils/properties.h>
+#include <gui/SurfaceTextureClient.h>
 #include <hardware/hardware.h>
 #include <media/AudioSystem.h>
 #include <media/mediaplayer.h>
@@ -306,6 +307,8 @@
     mCameraFacing = cameraFacing;
     mClientPid = clientPid;
     mMsgEnabled = 0;
+    mSurface = 0;
+    mPreviewWindow = 0;
     mHardware->setCallbacks(notifyCallback,
                             dataCallback,
                             dataCallbackTimestamp,
@@ -470,19 +473,16 @@
 
     // return if no change in surface.
     // asBinder() is safe on NULL (returns NULL)
-    if (getISurface(surface)->asBinder() == mSurface->asBinder()) {
+    if (getISurface(surface)->asBinder() == mSurface) {
         return result;
     }
 
     if (mSurface != 0) {
         LOG1("clearing old preview surface %p", mSurface.get());
     }
-    if (surface != 0) {
-        mSurface = getISurface(surface);
-    } else {
-        mSurface = 0;
-    }
+    mSurface = getISurface(surface)->asBinder();
     mPreviewWindow = surface;
+
     // If preview has been already started, register preview
     // buffers now.
     if (mHardware->previewEnabled()) {
@@ -496,6 +496,45 @@
     return result;
 }
 
+// set the SurfaceTexture that the preview will use
+status_t CameraService::Client::setPreviewTexture(
+        const sp<ISurfaceTexture>& surfaceTexture) {
+    LOG1("setPreviewTexture(%p) (pid %d)", surfaceTexture.get(),
+            getCallingPid());
+    Mutex::Autolock lock(mLock);
+    status_t result = checkPidAndHardware();
+    if (result != NO_ERROR) return result;
+
+    // return if no change in surface.
+    // asBinder() is safe on NULL (returns NULL)
+    if (surfaceTexture->asBinder() == mSurface) {
+        return result;
+    }
+
+    if (mSurface != 0) {
+        LOG1("clearing old preview surface %p", mSurface.get());
+    }
+    mSurface = surfaceTexture->asBinder();
+    if (surfaceTexture != 0) {
+        mPreviewWindow = new SurfaceTextureClient(surfaceTexture);
+    } else {
+        mPreviewWindow = 0;
+    }
+
+    // If preview has been already started, set overlay or register preview
+    // buffers now.
+    if (mHardware->previewEnabled()) {
+        // XXX: What if the new preview window is 0?
+        if (mPreviewWindow != 0) {
+            native_window_set_buffers_transform(mPreviewWindow.get(),
+                                                mOrientation);
+            result = mHardware->setPreviewWindow(mPreviewWindow);
+        }
+    }
+
+    return result;
+}
+
 // set the preview callback flag to affect how the received frames from
 // preview are handled.
 void CameraService::Client::setPreviewCallbackFlag(int callback_flag) {
@@ -960,23 +999,6 @@
     }
     disableMsgType(CAMERA_MSG_SHUTTER);
 
-    // It takes some time before yuvPicture callback to be called.
-    // Register the buffer for raw image here to reduce latency.
-    if (mSurface != 0) {
-        int w, h;
-        CameraParameters params(mHardware->getParameters());
-        if (size == NULL) {
-            params.getPictureSize(&w, &h);
-        } else {
-            w = size->width;
-            h = size->height;
-            w &= ~1;
-            h &= ~1;
-            LOG1("Snapshot image width=%d, height=%d", w, h);
-        }
-        IPCThreadState::self()->flushCommands();
-    }
-
     mLock.unlock();
 }
 
diff --git a/services/camera/libcameraservice/CameraService.h b/services/camera/libcameraservice/CameraService.h
index d78d7e5..ccb9cf7 100644
--- a/services/camera/libcameraservice/CameraService.h
+++ b/services/camera/libcameraservice/CameraService.h
@@ -94,6 +94,7 @@
         virtual status_t        lock();
         virtual status_t        unlock();
         virtual status_t        setPreviewDisplay(const sp<Surface>& surface);
+        virtual status_t        setPreviewTexture(const sp<ISurfaceTexture>& surfaceTexture);
         virtual void            setPreviewCallbackFlag(int flag);
         virtual status_t        startPreview();
         virtual void            stopPreview();
@@ -180,7 +181,8 @@
 
         // Ensures atomicity among the public methods
         mutable Mutex                   mLock;
-        sp<ISurface>                    mSurface;
+        // This is a binder of Surface or SurfaceTexture.
+        sp<IBinder>                     mSurface;
         sp<ANativeWindow>               mPreviewWindow;
 
         // If the user want us to return a copy of the preview frame (instead
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 825d90b..c982ea5 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -2267,6 +2267,25 @@
 
 // ---------------------------------------------------------------------------
 
+sp<GraphicBuffer> SurfaceFlinger::createGraphicBuffer(uint32_t w, uint32_t h,
+        PixelFormat format, uint32_t usage) const {
+    // XXX: HACK HACK HACK!!!  This should NOT be static, but it is to fix a
+    // race between SurfaceFlinger unref'ing the buffer and the client ref'ing
+    // it.
+    static sp<GraphicBuffer> graphicBuffer(new GraphicBuffer(w, h, format, usage));
+    status_t err = graphicBuffer->initCheck();
+    if (err != 0) {
+        LOGE("createGraphicBuffer: init check failed: %d", err);
+        return 0;
+    } else if (graphicBuffer->handle == 0) {
+        LOGE("createGraphicBuffer: unable to create GraphicBuffer");
+        return 0;
+    }
+    return graphicBuffer;
+}
+
+// ---------------------------------------------------------------------------
+
 Client::Client(const sp<SurfaceFlinger>& flinger)
     : mFlinger(flinger), mNameGenerator(1)
 {
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index ca7d27d..48642d4 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -322,6 +322,8 @@
             status_t electronBeamOnAnimationImplLocked();
             status_t renderScreenToTextureLocked(DisplayID dpy,
                     GLuint* textureName, GLfloat* uOut, GLfloat* vOut);
+            sp<GraphicBuffer> createGraphicBuffer(uint32_t w, uint32_t h,
+                    PixelFormat format, uint32_t usage) const;
 
             friend class FreezeLock;
             sp<FreezeLock> getFreezeLock() const;
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
index 5f40854..7a95c09 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
@@ -180,12 +180,9 @@
         return mCapabilities;
     }
 
-    /*
-     * (non-Javadoc)
-     * @see com.android.layoutlib.api.ILayoutLibBridge#init(java.io.File, java.util.Map)
-     */
     @Override
-    public boolean init(File fontLocation, Map<String, Map<String, Integer>> enumValueMap) {
+    public boolean init(File fontLocation, Map<String, Map<String, Integer>> enumValueMap,
+            LayoutLog log) {
         sEnumValueMap = enumValueMap;
 
         // don't use EnumSet.allOf(), because the bridge doesn't come with its specific version
@@ -242,11 +239,6 @@
         // now parse com.android.internal.R (and only this one as android.R is a subset of
         // the internal version), and put the content in the maps.
         try {
-            // WARNING: this only works because the class is already loaded, and therefore
-            // the objects returned by Field.get() are the same as the ones used by
-            // the code accessing the R class.
-            // int[] does not implement equals/hashCode, and if the parsing used a different class
-            // loader for the R class, this would NOT work.
             Class<?> r = com.android.internal.R.class;
 
             for (Class<?> inner : r.getDeclaredClasses()) {
@@ -262,7 +254,9 @@
                     if (Modifier.isStatic(modifiers)) {
                         Class<?> type = f.getType();
                         if (type.isArray() && type.getComponentType() == int.class) {
-                            // if the object is an int[] we put it in sRArrayMap
+                            // if the object is an int[] we put it in sRArrayMap using an IntArray
+                            // wrapper that properly implements equals and hashcode for the array
+                            // objects, as required by the map contract.
                             sRArrayMap.put(new IntArray((int[]) f.get(null)), f.getName());
                         } else if (type == int.class) {
                             Integer value = (Integer) f.get(null);
@@ -274,12 +268,12 @@
                     }
                 }
             }
-        } catch (IllegalArgumentException e) {
-            // FIXME: log/return the error (there's no logger object at this point!)
-            e.printStackTrace();
-            return false;
-        } catch (IllegalAccessException e) {
-            e.printStackTrace();
+        } catch (Throwable throwable) {
+            if (log != null) {
+                log.error(null,
+                        "Failed to load com.android.internal.R from the layout library jar",
+                        throwable);
+            }
             return false;
         }