Merge "const correctness, validPixel test."
diff --git a/include/ui/EventHub.h b/include/ui/EventHub.h
index dab35b3..3d42856 100644
--- a/include/ui/EventHub.h
+++ b/include/ui/EventHub.h
@@ -224,6 +224,7 @@
         uint8_t*        keyBitmask;
         KeyLayoutMap*   layoutMap;
         String8         keylayoutFilename;
+        int             fd;
         device_t*       next;
         
         device_t(int32_t _id, const char* _path, const char* name);
@@ -266,6 +267,12 @@
 #ifdef EV_SW
     int32_t         mSwitches[SW_MAX + 1];
 #endif
+
+    static const int INPUT_BUFFER_SIZE = 64;
+    struct input_event mInputBufferData[INPUT_BUFFER_SIZE];
+    int32_t mInputBufferIndex;
+    int32_t mInputBufferCount;
+    int32_t mInputDeviceIndex;
 };
 
 }; // namespace android
diff --git a/include/ui/InputDispatcher.h b/include/ui/InputDispatcher.h
index d3495fe..2505cb0 100644
--- a/include/ui/InputDispatcher.h
+++ b/include/ui/InputDispatcher.h
@@ -554,6 +554,8 @@
     // All registered connections mapped by receive pipe file descriptor.
     KeyedVector<int, sp<Connection> > mConnectionsByReceiveFd;
 
+    ssize_t getConnectionIndex(const sp<InputChannel>& inputChannel);
+
     // Active connections are connections that have a non-empty outbound queue.
     // We don't use a ref-counted pointer here because we explicitly abort connections
     // during unregistration which causes the connection's outbound queue to be cleared
diff --git a/include/ui/InputReader.h b/include/ui/InputReader.h
index 71c6c51..56d2765 100644
--- a/include/ui/InputReader.h
+++ b/include/ui/InputReader.h
@@ -480,10 +480,6 @@
         inline void clear() {
             fields = 0;
         }
-
-        inline bool isDirty() {
-            return fields != 0;
-        }
     } mAccumulator;
 
     float mXScale;
@@ -702,7 +698,7 @@
         } historyData[AVERAGING_HISTORY_SIZE];
     } mAveragingTouchFilter;
 
-    struct JumpTouchFilterState {
+    struct JumpyTouchFilterState {
         uint32_t jumpyPointsDropped;
     } mJumpyTouchFilter;
 
@@ -765,10 +761,6 @@
         inline void clear() {
             fields = 0;
         }
-
-        inline bool isDirty() {
-            return fields != 0;
-        }
     } mAccumulator;
 
     bool mDown;
@@ -804,7 +796,8 @@
             FIELD_ABS_MT_WIDTH_MAJOR = 16,
             FIELD_ABS_MT_WIDTH_MINOR = 32,
             FIELD_ABS_MT_ORIENTATION = 64,
-            FIELD_ABS_MT_TRACKING_ID = 128
+            FIELD_ABS_MT_TRACKING_ID = 128,
+            FIELD_ABS_MT_PRESSURE = 256,
         };
 
         uint32_t pointerCount;
@@ -819,6 +812,7 @@
             int32_t absMTWidthMinor;
             int32_t absMTOrientation;
             int32_t absMTTrackingId;
+            int32_t absMTPressure;
 
             inline void clear() {
                 fields = 0;
@@ -829,10 +823,6 @@
             pointerCount = 0;
             pointers[0].clear();
         }
-
-        inline bool isDirty() {
-            return pointerCount != 0;
-        }
     } mAccumulator;
 
     void initialize();
diff --git a/include/utils/AssetManager.h b/include/utils/AssetManager.h
index 97694ff..9e2bf37 100644
--- a/include/utils/AssetManager.h
+++ b/include/utils/AssetManager.h
@@ -129,6 +129,8 @@
      */
     void setConfiguration(const ResTable_config& config, const char* locale = NULL);
 
+    void getConfiguration(ResTable_config* outConfig) const;
+
     typedef Asset::AccessMode AccessMode;       // typing shortcut
 
     /*
diff --git a/include/utils/ObbFile.h b/include/utils/ObbFile.h
index 075927c..d2ca82e 100644
--- a/include/utils/ObbFile.h
+++ b/include/utils/ObbFile.h
@@ -35,6 +35,8 @@
     bool readFrom(int fd);
     bool writeTo(const char* filename);
     bool writeTo(int fd);
+    bool removeFrom(const char* filename);
+    bool removeFrom(int fd);
 
     const char* getFileName() const {
         return mFileName;
@@ -78,6 +80,8 @@
 
     size_t mFileSize;
 
+    size_t mFooterStart;
+
     unsigned char* mReadBuf;
 
     bool parseObbFile(int fd);
diff --git a/include/utils/ResourceTypes.h b/include/utils/ResourceTypes.h
index c7d9ff1..da86da4 100644
--- a/include/utils/ResourceTypes.h
+++ b/include/utils/ResourceTypes.h
@@ -31,6 +31,8 @@
 #include <stdint.h>
 #include <sys/types.h>
 
+#include <android/configuration.h>
+
 namespace android {
 
 /** ********************************************************************
@@ -822,25 +824,25 @@
     };
     
     enum {
-        ORIENTATION_ANY  = 0x0000,
-        ORIENTATION_PORT = 0x0001,
-        ORIENTATION_LAND = 0x0002,
-        ORIENTATION_SQUARE = 0x0003,
+        ORIENTATION_ANY  = ACONFIGURATION_ORIENTATION_ANY,
+        ORIENTATION_PORT = ACONFIGURATION_ORIENTATION_PORT,
+        ORIENTATION_LAND = ACONFIGURATION_ORIENTATION_LAND,
+        ORIENTATION_SQUARE = ACONFIGURATION_ORIENTATION_SQUARE,
     };
     
     enum {
-        TOUCHSCREEN_ANY  = 0x0000,
-        TOUCHSCREEN_NOTOUCH  = 0x0001,
-        TOUCHSCREEN_STYLUS  = 0x0002,
-        TOUCHSCREEN_FINGER  = 0x0003,
+        TOUCHSCREEN_ANY  = ACONFIGURATION_TOUCHSCREEN_ANY,
+        TOUCHSCREEN_NOTOUCH  = ACONFIGURATION_TOUCHSCREEN_NOTOUCH,
+        TOUCHSCREEN_STYLUS  = ACONFIGURATION_TOUCHSCREEN_STYLUS,
+        TOUCHSCREEN_FINGER  = ACONFIGURATION_TOUCHSCREEN_FINGER,
     };
     
     enum {
-        DENSITY_DEFAULT = 0,
-        DENSITY_LOW = 120,
-        DENSITY_MEDIUM = 160,
-        DENSITY_HIGH = 240,
-        DENSITY_NONE = 0xffff
+        DENSITY_DEFAULT = ACONFIGURATION_DENSITY_DEFAULT,
+        DENSITY_LOW = ACONFIGURATION_DENSITY_LOW,
+        DENSITY_MEDIUM = ACONFIGURATION_DENSITY_MEDIUM,
+        DENSITY_HIGH = ACONFIGURATION_DENSITY_HIGH,
+        DENSITY_NONE = ACONFIGURATION_DENSITY_NONE
     };
     
     union {
@@ -853,33 +855,34 @@
     };
     
     enum {
-        KEYBOARD_ANY  = 0x0000,
-        KEYBOARD_NOKEYS  = 0x0001,
-        KEYBOARD_QWERTY  = 0x0002,
-        KEYBOARD_12KEY  = 0x0003,
+        KEYBOARD_ANY  = ACONFIGURATION_KEYBOARD_ANY,
+        KEYBOARD_NOKEYS  = ACONFIGURATION_KEYBOARD_NOKEYS,
+        KEYBOARD_QWERTY  = ACONFIGURATION_KEYBOARD_QWERTY,
+        KEYBOARD_12KEY  = ACONFIGURATION_KEYBOARD_12KEY,
     };
     
     enum {
-        NAVIGATION_ANY  = 0x0000,
-        NAVIGATION_NONAV  = 0x0001,
-        NAVIGATION_DPAD  = 0x0002,
-        NAVIGATION_TRACKBALL  = 0x0003,
-        NAVIGATION_WHEEL  = 0x0004,
+        NAVIGATION_ANY  = ACONFIGURATION_NAVIGATION_ANY,
+        NAVIGATION_NONAV  = ACONFIGURATION_NAVIGATION_NONAV,
+        NAVIGATION_DPAD  = ACONFIGURATION_NAVIGATION_DPAD,
+        NAVIGATION_TRACKBALL  = ACONFIGURATION_NAVIGATION_TRACKBALL,
+        NAVIGATION_WHEEL  = ACONFIGURATION_NAVIGATION_WHEEL,
     };
     
     enum {
         MASK_KEYSHIDDEN = 0x0003,
-        KEYSHIDDEN_ANY = 0x0000,
-        KEYSHIDDEN_NO = 0x0001,
-        KEYSHIDDEN_YES = 0x0002,
-        KEYSHIDDEN_SOFT = 0x0003,
+        KEYSHIDDEN_ANY = ACONFIGURATION_KEYSHIDDEN_ANY,
+        KEYSHIDDEN_NO = ACONFIGURATION_KEYSHIDDEN_NO,
+        KEYSHIDDEN_YES = ACONFIGURATION_KEYSHIDDEN_YES,
+        KEYSHIDDEN_SOFT = ACONFIGURATION_KEYSHIDDEN_SOFT,
     };
     
     enum {
         MASK_NAVHIDDEN = 0x000c,
-        NAVHIDDEN_ANY = 0x0000,
-        NAVHIDDEN_NO = 0x0004,
-        NAVHIDDEN_YES = 0x0008,
+        SHIFT_NAVHIDDEN = 2,
+        NAVHIDDEN_ANY = ACONFIGURATION_NAVHIDDEN_ANY << SHIFT_NAVHIDDEN,
+        NAVHIDDEN_NO = ACONFIGURATION_NAVHIDDEN_NO << SHIFT_NAVHIDDEN,
+        NAVHIDDEN_YES = ACONFIGURATION_NAVHIDDEN_YES << SHIFT_NAVHIDDEN,
     };
     
     union {
@@ -929,32 +932,34 @@
     enum {
         // screenLayout bits for screen size class.
         MASK_SCREENSIZE = 0x0f,
-        SCREENSIZE_ANY  = 0x00,
-        SCREENSIZE_SMALL = 0x01,
-        SCREENSIZE_NORMAL = 0x02,
-        SCREENSIZE_LARGE = 0x03,
-        SCREENSIZE_XLARGE = 0x04,
+        SCREENSIZE_ANY = ACONFIGURATION_SCREENSIZE_ANY,
+        SCREENSIZE_SMALL = ACONFIGURATION_SCREENSIZE_SMALL,
+        SCREENSIZE_NORMAL = ACONFIGURATION_SCREENSIZE_NORMAL,
+        SCREENSIZE_LARGE = ACONFIGURATION_SCREENSIZE_LARGE,
+        SCREENSIZE_XLARGE = ACONFIGURATION_SCREENSIZE_XLARGE,
         
         // screenLayout bits for wide/long screen variation.
         MASK_SCREENLONG = 0x30,
-        SCREENLONG_ANY = 0x00,
-        SCREENLONG_NO = 0x10,
-        SCREENLONG_YES = 0x20,
+        SHIFT_SCREENLONG = 4,
+        SCREENLONG_ANY = ACONFIGURATION_SCREENLONG_ANY << SHIFT_SCREENLONG,
+        SCREENLONG_NO = ACONFIGURATION_SCREENLONG_NO << SHIFT_SCREENLONG,
+        SCREENLONG_YES = ACONFIGURATION_SCREENLONG_YES << SHIFT_SCREENLONG,
     };
     
     enum {
         // uiMode bits for the mode type.
         MASK_UI_MODE_TYPE = 0x0f,
-        UI_MODE_TYPE_ANY = 0x00,
-        UI_MODE_TYPE_NORMAL = 0x01,
-        UI_MODE_TYPE_DESK = 0x02,
-        UI_MODE_TYPE_CAR = 0x03,
+        UI_MODE_TYPE_ANY = ACONFIGURATION_UI_MODE_TYPE_ANY,
+        UI_MODE_TYPE_NORMAL = ACONFIGURATION_UI_MODE_TYPE_NORMAL,
+        UI_MODE_TYPE_DESK = ACONFIGURATION_UI_MODE_TYPE_DESK,
+        UI_MODE_TYPE_CAR = ACONFIGURATION_UI_MODE_TYPE_CAR,
 
         // uiMode bits for the night switch.
         MASK_UI_MODE_NIGHT = 0x30,
-        UI_MODE_NIGHT_ANY = 0x00,
-        UI_MODE_NIGHT_NO = 0x10,
-        UI_MODE_NIGHT_YES = 0x20,
+        SHIFT_UI_MODE_NIGHT = 4,
+        UI_MODE_NIGHT_ANY = ACONFIGURATION_UI_MODE_NIGHT_ANY << SHIFT_UI_MODE_NIGHT,
+        UI_MODE_NIGHT_NO = ACONFIGURATION_UI_MODE_NIGHT_NO << SHIFT_UI_MODE_NIGHT,
+        UI_MODE_NIGHT_YES = ACONFIGURATION_UI_MODE_NIGHT_YES << SHIFT_UI_MODE_NIGHT,
     };
 
     union {
@@ -1023,19 +1028,19 @@
     // match the corresponding ones in android.content.pm.ActivityInfo and
     // attrs_manifest.xml.
     enum {
-        CONFIG_MCC = 0x0001,
-        CONFIG_MNC = 0x0002,
-        CONFIG_LOCALE = 0x0004,
-        CONFIG_TOUCHSCREEN = 0x0008,
-        CONFIG_KEYBOARD = 0x0010,
-        CONFIG_KEYBOARD_HIDDEN = 0x0020,
-        CONFIG_NAVIGATION = 0x0040,
-        CONFIG_ORIENTATION = 0x0080,
-        CONFIG_DENSITY = 0x0100,
-        CONFIG_SCREEN_SIZE = 0x0200,
-        CONFIG_VERSION = 0x0400,
-        CONFIG_SCREEN_LAYOUT = 0x0800,
-        CONFIG_UI_MODE = 0x1000
+        CONFIG_MCC = ACONFIGURATION_MCC,
+        CONFIG_MNC = ACONFIGURATION_MCC,
+        CONFIG_LOCALE = ACONFIGURATION_LOCALE,
+        CONFIG_TOUCHSCREEN = ACONFIGURATION_TOUCHSCREEN,
+        CONFIG_KEYBOARD = ACONFIGURATION_KEYBOARD,
+        CONFIG_KEYBOARD_HIDDEN = ACONFIGURATION_KEYBOARD_HIDDEN,
+        CONFIG_NAVIGATION = ACONFIGURATION_NAVIGATION,
+        CONFIG_ORIENTATION = ACONFIGURATION_ORIENTATION,
+        CONFIG_DENSITY = ACONFIGURATION_DENSITY,
+        CONFIG_SCREEN_SIZE = ACONFIGURATION_SCREEN_SIZE,
+        CONFIG_VERSION = ACONFIGURATION_VERSION,
+        CONFIG_SCREEN_LAYOUT = ACONFIGURATION_SCREEN_LAYOUT,
+        CONFIG_UI_MODE = ACONFIGURATION_UI_MODE
     };
     
     // Compare two configuration, returning CONFIG_* flags set for each value
diff --git a/include/utils/String8.h b/include/utils/String8.h
index 4e41410..ef0b51a 100644
--- a/include/utils/String8.h
+++ b/include/utils/String8.h
@@ -171,7 +171,8 @@
             status_t            append(const char* other);
             status_t            append(const char* other, size_t numChars);
 
-            status_t            appendFormat(const char* fmt, ...);
+            status_t            appendFormat(const char* fmt, ...)
+                    __attribute__((format (printf, 2, 3)));
 
             // Note that this function takes O(N) time to calculate the value.
             // No cache value is stored.
diff --git a/libs/ui/EventHub.cpp b/libs/ui/EventHub.cpp
index 124f7b3..891661d 100644
--- a/libs/ui/EventHub.cpp
+++ b/libs/ui/EventHub.cpp
@@ -60,7 +60,6 @@
 #define ID_MASK  0x0000ffff
 #define SEQ_MASK 0x7fff0000
 #define SEQ_SHIFT 16
-#define id_to_index(id)         ((id&ID_MASK)+1)
 
 #ifndef ABS_MT_TOUCH_MAJOR
 #define ABS_MT_TOUCH_MAJOR      0x30    /* Major axis of touching ellipse */
@@ -87,7 +86,7 @@
 
 EventHub::device_t::device_t(int32_t _id, const char* _path, const char* name)
     : id(_id), path(_path), name(name), classes(0)
-    , keyBitmask(NULL), layoutMap(new KeyLayoutMap()), next(NULL) {
+    , keyBitmask(NULL), layoutMap(new KeyLayoutMap()), fd(-1), next(NULL) {
 }
 
 EventHub::device_t::~device_t() {
@@ -100,6 +99,7 @@
     , mDevicesById(0), mNumDevicesById(0)
     , mOpeningDevices(0), mClosingDevices(0)
     , mDevices(0), mFDs(0), mFDCount(0), mOpened(false)
+    , mInputBufferIndex(0), mInputBufferCount(0), mInputDeviceIndex(0)
 {
     acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_ID);
 #ifdef EV_SW
@@ -151,9 +151,9 @@
 
     struct input_absinfo info;
 
-    if(ioctl(mFDs[id_to_index(device->id)].fd, EVIOCGABS(axis), &info)) {
+    if(ioctl(device->fd, EVIOCGABS(axis), &info)) {
         LOGW("Error reading absolute controller %d for device %s fd %d\n",
-             axis, device->name.string(), mFDs[id_to_index(device->id)].fd);
+             axis, device->name.string(), device->fd);
         return -errno;
     }
 
@@ -182,7 +182,7 @@
 int32_t EventHub::getScanCodeStateLocked(device_t* device, int32_t scanCode) const {
     uint8_t key_bitmask[sizeof_bit_array(KEY_MAX + 1)];
     memset(key_bitmask, 0, sizeof(key_bitmask));
-    if (ioctl(mFDs[id_to_index(device->id)].fd,
+    if (ioctl(device->fd,
                EVIOCGKEY(sizeof(key_bitmask)), key_bitmask) >= 0) {
         return test_bit(scanCode, key_bitmask) ? AKEY_STATE_DOWN : AKEY_STATE_UP;
     }
@@ -205,8 +205,7 @@
 
     uint8_t key_bitmask[sizeof_bit_array(KEY_MAX + 1)];
     memset(key_bitmask, 0, sizeof(key_bitmask));
-    if (ioctl(mFDs[id_to_index(device->id)].fd,
-               EVIOCGKEY(sizeof(key_bitmask)), key_bitmask) >= 0) {
+    if (ioctl(device->fd, EVIOCGKEY(sizeof(key_bitmask)), key_bitmask) >= 0) {
         #if 0
         for (size_t i=0; i<=KEY_MAX; i++) {
             LOGI("(Scan code %d: down=%d)", i, test_bit(i, key_bitmask));
@@ -242,7 +241,7 @@
 int32_t EventHub::getSwitchStateLocked(device_t* device, int32_t sw) const {
     uint8_t sw_bitmask[sizeof_bit_array(SW_MAX + 1)];
     memset(sw_bitmask, 0, sizeof(sw_bitmask));
-    if (ioctl(mFDs[id_to_index(device->id)].fd,
+    if (ioctl(device->fd,
                EVIOCGSW(sizeof(sw_bitmask)), sw_bitmask) >= 0) {
         return test_bit(sw, sw_bitmask) ? AKEY_STATE_DOWN : AKEY_STATE_UP;
     }
@@ -343,13 +342,6 @@
     outEvent->value = 0;
     outEvent->when = 0;
 
-    status_t err;
-
-    int i;
-    int res;
-    int pollres;
-    struct input_event iev;
-
     // Note that we only allow one caller to getEvent(), so don't need
     // to do locking here...  only when adding/removing devices.
 
@@ -358,9 +350,8 @@
         mOpened = true;
     }
 
-    while(1) {
-
-        // First, report any devices that had last been added/removed.
+    for (;;) {
+        // Report any devices that had last been added/removed.
         if (mClosingDevices != NULL) {
             device_t* device = mClosingDevices;
             LOGV("Reporting device closed: id=0x%x, name=%s\n",
@@ -390,77 +381,96 @@
             return true;
         }
 
-        release_wake_lock(WAKE_LOCK_ID);
+        // Grab the next input event.
+        for (;;) {
+            // Consume buffered input events, if any.
+            if (mInputBufferIndex < mInputBufferCount) {
+                const struct input_event& iev = mInputBufferData[mInputBufferIndex++];
+                const device_t* device = mDevices[mInputDeviceIndex];
 
-        pollres = poll(mFDs, mFDCount, -1);
-
-        acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_ID);
-
-        if (pollres <= 0) {
-            if (errno != EINTR) {
-                LOGW("select failed (errno=%d)\n", errno);
-                usleep(100000);
-            }
-            continue;
-        }
-
-        //printf("poll %d, returned %d\n", mFDCount, pollres);
-
-        // mFDs[0] is used for inotify, so process regular events starting at mFDs[1]
-        for(i = 1; i < mFDCount; i++) {
-            if(mFDs[i].revents) {
-                LOGV("revents for %d = 0x%08x", i, mFDs[i].revents);
-                if(mFDs[i].revents & POLLIN) {
-                    res = read(mFDs[i].fd, &iev, sizeof(iev));
-                    if (res == sizeof(iev)) {
-                        device_t* device = mDevices[i];
-                        LOGV("%s got: t0=%d, t1=%d, type=%d, code=%d, v=%d",
-                             device->path.string(),
-                             (int) iev.time.tv_sec, (int) iev.time.tv_usec,
-                             iev.type, iev.code, iev.value);
-                        if (device->id == mFirstKeyboardId) {
-                            outEvent->deviceId = 0;
-                        } else {
-                            outEvent->deviceId = device->id;
-                        }
-                        outEvent->type = iev.type;
-                        outEvent->scanCode = iev.code;
-                        if (iev.type == EV_KEY) {
-                            err = device->layoutMap->map(iev.code,
-                                    & outEvent->keyCode, & outEvent->flags);
-                            LOGV("iev.code=%d keyCode=%d flags=0x%08x err=%d\n",
-                                iev.code, outEvent->keyCode, outEvent->flags, err);
-                            if (err != 0) {
-                                outEvent->keyCode = AKEYCODE_UNKNOWN;
-                                outEvent->flags = 0;
-                            }
-                        } else {
-                            outEvent->keyCode = iev.code;
-                        }
-                        outEvent->value = iev.value;
-
-                        // Use an event timestamp in the same timebase as
-                        // java.lang.System.nanoTime() and android.os.SystemClock.uptimeMillis()
-                        // as expected by the rest of the system.
-                        outEvent->when = systemTime(SYSTEM_TIME_MONOTONIC);
-                        return true;
-                    } else {
-                        if (res<0) {
-                            LOGW("could not get event (errno=%d)", errno);
-                        } else {
-                            LOGE("could not get event (wrong size: %d)", res);
-                        }
-                        continue;
+                LOGV("%s got: t0=%d, t1=%d, type=%d, code=%d, v=%d", device->path.string(),
+                     (int) iev.time.tv_sec, (int) iev.time.tv_usec, iev.type, iev.code, iev.value);
+                if (device->id == mFirstKeyboardId) {
+                    outEvent->deviceId = 0;
+                } else {
+                    outEvent->deviceId = device->id;
+                }
+                outEvent->type = iev.type;
+                outEvent->scanCode = iev.code;
+                if (iev.type == EV_KEY) {
+                    status_t err = device->layoutMap->map(iev.code,
+                            & outEvent->keyCode, & outEvent->flags);
+                    LOGV("iev.code=%d keyCode=%d flags=0x%08x err=%d\n",
+                        iev.code, outEvent->keyCode, outEvent->flags, err);
+                    if (err != 0) {
+                        outEvent->keyCode = AKEYCODE_UNKNOWN;
+                        outEvent->flags = 0;
                     }
+                } else {
+                    outEvent->keyCode = iev.code;
+                }
+                outEvent->value = iev.value;
+
+                // Use an event timestamp in the same timebase as
+                // java.lang.System.nanoTime() and android.os.SystemClock.uptimeMillis()
+                // as expected by the rest of the system.
+                outEvent->when = systemTime(SYSTEM_TIME_MONOTONIC);
+                return true;
+            }
+
+            // Finish reading all events from devices identified in previous poll().
+            // This code assumes that mInputDeviceIndex is initially 0 and that the
+            // revents member of pollfd is initialized to 0 when the device is first added.
+            // Since mFDs[0] is used for inotify, we process regular events starting at index 1.
+            mInputDeviceIndex += 1;
+            if (mInputDeviceIndex >= mFDCount) {
+                mInputDeviceIndex = 0;
+                break;
+            }
+
+            const struct pollfd &pfd = mFDs[mInputDeviceIndex];
+            if (pfd.revents & POLLIN) {
+                int32_t readSize = read(pfd.fd, mInputBufferData,
+                        sizeof(struct input_event) * INPUT_BUFFER_SIZE);
+                if (readSize < 0) {
+                    if (errno != EAGAIN && errno != EINTR) {
+                        LOGW("could not get event (errno=%d)", errno);
+                    }
+                } else if ((readSize % sizeof(struct input_event)) != 0) {
+                    LOGE("could not get event (wrong size: %d)", readSize);
+                } else {
+                    mInputBufferCount = readSize / sizeof(struct input_event);
+                    mInputBufferIndex = 0;
                 }
             }
         }
-        
+
         // read_notify() will modify mFDs and mFDCount, so this must be done after
         // processing all other events.
         if(mFDs[0].revents & POLLIN) {
             read_notify(mFDs[0].fd);
         }
+
+        // Poll for events.  Mind the wake lock dance!
+        // We hold a wake lock at all times except during poll().  This works due to some
+        // subtle choreography.  When a device driver has pending (unread) events, it acquires
+        // a kernel wake lock.  However, once the last pending event has been read, the device
+        // driver will release the kernel wake lock.  To prevent the system from going to sleep
+        // when this happens, the EventHub holds onto its own user wake lock while the client
+        // is processing events.  Thus the system can only sleep if there are no events
+        // pending or currently being processed.
+        release_wake_lock(WAKE_LOCK_ID);
+
+        int pollResult = poll(mFDs, mFDCount, -1);
+
+        acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_ID);
+
+        if (pollResult <= 0) {
+            if (errno != EINTR) {
+                LOGW("select failed (errno=%d)\n", errno);
+                usleep(100000);
+            }
+        }
     }
 }
 
@@ -478,6 +488,7 @@
     mFDs = (pollfd *)calloc(1, sizeof(mFDs[0]));
     mDevices = (device_t **)calloc(1, sizeof(mDevices[0]));
     mFDs[0].events = POLLIN;
+    mFDs[0].revents = 0;
     mDevices[0] = NULL;
 #ifdef HAVE_INOTIFY
     mFDs[0].fd = inotify_init();
@@ -570,7 +581,6 @@
         if (strcmp(name, test) == 0) {
             LOGI("ignoring event id %s driver %s\n", deviceName, test);
             close(fd);
-            fd = -1;
             return -1;
         }
     }
@@ -584,6 +594,12 @@
         idstr[0] = '\0';
     }
 
+    if (fcntl(fd, F_SETFL, O_NONBLOCK)) {
+        LOGE("Error %d making device file descriptor non-blocking.", errno);
+        close(fd);
+        return -1;
+    }
+
     int devid = 0;
     while (devid < mNumDevicesById) {
         if (mDevicesById[devid].device == NULL) {
@@ -638,8 +654,10 @@
         return -1;
     }
 
+    device->fd = fd;
     mFDs[mFDCount].fd = fd;
     mFDs[mFDCount].events = POLLIN;
+    mFDs[mFDCount].revents = 0;
 
     // Figure out the kinds of events the device reports.
     
@@ -794,6 +812,14 @@
                 device->id, name, propName, keylayoutFilename);
     }
 
+    // If the device isn't recognized as something we handle, don't monitor it.
+    if (device->classes == 0) {
+        LOGV("Dropping device %s %p, id = %d\n", deviceName, device, devid);
+        close(fd);
+        delete device;
+        return -1;
+    }
+
     LOGI("New device: path=%s name=%s id=0x%x (of 0x%x) index=%d fd=%d classes=0x%x\n",
          deviceName, name, device->id, mNumDevicesById, mFDCount, fd, device->classes);
          
diff --git a/libs/ui/InputDispatcher.cpp b/libs/ui/InputDispatcher.cpp
index b53f140..13030b5 100644
--- a/libs/ui/InputDispatcher.cpp
+++ b/libs/ui/InputDispatcher.cpp
@@ -433,8 +433,7 @@
     for (size_t i = 0; i < mCurrentInputTargets.size(); i++) {
         const InputTarget& inputTarget = mCurrentInputTargets.itemAt(i);
 
-        ssize_t connectionIndex = mConnectionsByReceiveFd.indexOfKey(
-                inputTarget.inputChannel->getReceivePipeFd());
+        ssize_t connectionIndex = getConnectionIndex(inputTarget.inputChannel);
         if (connectionIndex >= 0) {
             sp<Connection> connection = mConnectionsByReceiveFd.valueAt(connectionIndex);
             prepareDispatchCycleLocked(currentTime, connection, eventEntry, & inputTarget,
@@ -1367,12 +1366,10 @@
     LOGD("channel '%s' ~ registerInputChannel", inputChannel->getName().string());
 #endif
 
-    int receiveFd;
     { // acquire lock
         AutoMutex _l(mLock);
 
-        receiveFd = inputChannel->getReceivePipeFd();
-        if (mConnectionsByReceiveFd.indexOfKey(receiveFd) >= 0) {
+        if (getConnectionIndex(inputChannel) >= 0) {
             LOGW("Attempted to register already registered input channel '%s'",
                     inputChannel->getName().string());
             return BAD_VALUE;
@@ -1386,12 +1383,13 @@
             return status;
         }
 
+        int32_t receiveFd = inputChannel->getReceivePipeFd();
         mConnectionsByReceiveFd.add(receiveFd, connection);
 
+        mPollLoop->setCallback(receiveFd, POLLIN, handleReceiveCallback, this);
+
         runCommandsLockedInterruptible();
     } // release lock
-
-    mPollLoop->setCallback(receiveFd, POLLIN, handleReceiveCallback, this);
     return OK;
 }
 
@@ -1400,12 +1398,10 @@
     LOGD("channel '%s' ~ unregisterInputChannel", inputChannel->getName().string());
 #endif
 
-    int32_t receiveFd;
     { // acquire lock
         AutoMutex _l(mLock);
 
-        receiveFd = inputChannel->getReceivePipeFd();
-        ssize_t connectionIndex = mConnectionsByReceiveFd.indexOfKey(receiveFd);
+        ssize_t connectionIndex = getConnectionIndex(inputChannel);
         if (connectionIndex < 0) {
             LOGW("Attempted to unregister already unregistered input channel '%s'",
                     inputChannel->getName().string());
@@ -1417,20 +1413,32 @@
 
         connection->status = Connection::STATUS_ZOMBIE;
 
+        mPollLoop->removeCallback(inputChannel->getReceivePipeFd());
+
         nsecs_t currentTime = now();
         abortDispatchCycleLocked(currentTime, connection, true /*broken*/);
 
         runCommandsLockedInterruptible();
     } // release lock
 
-    mPollLoop->removeCallback(receiveFd);
-
     // Wake the poll loop because removing the connection may have changed the current
     // synchronization state.
     mPollLoop->wake();
     return OK;
 }
 
+ssize_t InputDispatcher::getConnectionIndex(const sp<InputChannel>& inputChannel) {
+    ssize_t connectionIndex = mConnectionsByReceiveFd.indexOfKey(inputChannel->getReceivePipeFd());
+    if (connectionIndex >= 0) {
+        sp<Connection> connection = mConnectionsByReceiveFd.valueAt(connectionIndex);
+        if (connection->inputChannel.get() == inputChannel.get()) {
+            return connectionIndex;
+        }
+    }
+
+    return -1;
+}
+
 void InputDispatcher::activateConnectionLocked(Connection* connection) {
     for (size_t i = 0; i < mActiveConnections.size(); i++) {
         if (mActiveConnections.itemAt(i) == connection) {
diff --git a/libs/ui/InputReader.cpp b/libs/ui/InputReader.cpp
index 5f5a4ac..6f042ec 100644
--- a/libs/ui/InputReader.cpp
+++ b/libs/ui/InputReader.cpp
@@ -945,7 +945,6 @@
         mAccumulator.fields = Accumulator::FIELD_BTN_MOUSE;
         mAccumulator.btnMouse = false;
         sync(when);
-        mAccumulator.clear();
     }
 
     InputMapper::reset();
@@ -958,9 +957,9 @@
         case BTN_MOUSE:
             mAccumulator.fields |= Accumulator::FIELD_BTN_MOUSE;
             mAccumulator.btnMouse = rawEvent->value != 0;
-
+            // Sync now since BTN_MOUSE is not necessarily followed by SYN_REPORT and
+            // we need to ensure that we report the up/down promptly.
             sync(rawEvent->when);
-            mAccumulator.clear();
             break;
         }
         break;
@@ -981,10 +980,7 @@
     case EV_SYN:
         switch (rawEvent->scanCode) {
         case SYN_REPORT:
-            if (mAccumulator.isDirty()) {
-                sync(rawEvent->when);
-                mAccumulator.clear();
-            }
+            sync(rawEvent->when);
             break;
         }
         break;
@@ -992,13 +988,17 @@
 }
 
 void TrackballInputMapper::sync(nsecs_t when) {
+    uint32_t fields = mAccumulator.fields;
+    if (fields == 0) {
+        return; // no new state changes, so nothing to do
+    }
+
     int motionEventAction;
     PointerCoords pointerCoords;
     nsecs_t downTime;
     { // acquire lock
         AutoMutex _l(mLock);
 
-        uint32_t fields = mAccumulator.fields;
         bool downChanged = fields & Accumulator::FIELD_BTN_MOUSE;
 
         if (downChanged) {
@@ -1061,6 +1061,8 @@
     } // release lock
 
     applyPolicyAndDispatch(when, motionEventAction, & pointerCoords, downTime);
+
+    mAccumulator.clear();
 }
 
 void TrackballInputMapper::applyPolicyAndDispatch(nsecs_t when, int32_t motionEventAction,
@@ -2380,8 +2382,8 @@
     mDown = false;
     mX = 0;
     mY = 0;
-    mPressure = 0;
-    mSize = 0;
+    mPressure = 1; // default to 1 for devices that don't report pressure
+    mSize = 0; // default to 0 for devices that don't report size
 }
 
 void SingleTouchInputMapper::reset() {
@@ -2397,9 +2399,9 @@
         case BTN_TOUCH:
             mAccumulator.fields |= Accumulator::FIELD_BTN_TOUCH;
             mAccumulator.btnTouch = rawEvent->value != 0;
-
-            sync(rawEvent->when);
-            mAccumulator.clear();
+            // Don't sync immediately.  Wait until the next SYN_REPORT since we might
+            // not have received valid position information yet.  This logic assumes that
+            // BTN_TOUCH is always followed by SYN_REPORT as part of a complete packet.
             break;
         }
         break;
@@ -2428,10 +2430,7 @@
     case EV_SYN:
         switch (rawEvent->scanCode) {
         case SYN_REPORT:
-            if (mAccumulator.isDirty()) {
-                sync(rawEvent->when);
-                mAccumulator.clear();
-            }
+            sync(rawEvent->when);
             break;
         }
         break;
@@ -2439,9 +2438,10 @@
 }
 
 void SingleTouchInputMapper::sync(nsecs_t when) {
-    /* Update device state */
-
     uint32_t fields = mAccumulator.fields;
+    if (fields == 0) {
+        return; // no new state changes, so nothing to do
+    }
 
     if (fields & Accumulator::FIELD_BTN_TOUCH) {
         mDown = mAccumulator.btnTouch;
@@ -2472,8 +2472,8 @@
         mCurrentTouch.pointers[0].y = mY;
         mCurrentTouch.pointers[0].pressure = mPressure;
         mCurrentTouch.pointers[0].size = mSize;
-        mCurrentTouch.pointers[0].touchMajor = mPressure;
-        mCurrentTouch.pointers[0].touchMinor = mPressure;
+        mCurrentTouch.pointers[0].touchMajor = mSize;
+        mCurrentTouch.pointers[0].touchMinor = mSize;
         mCurrentTouch.pointers[0].toolMajor = mSize;
         mCurrentTouch.pointers[0].toolMinor = mSize;
         mCurrentTouch.pointers[0].orientation = 0;
@@ -2482,6 +2482,8 @@
     }
 
     syncTouch(when, true);
+
+    mAccumulator.clear();
 }
 
 void SingleTouchInputMapper::configureAxes() {
@@ -2494,8 +2496,8 @@
     getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_PRESSURE, & mAxes.pressure);
     getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_TOOL_WIDTH, & mAxes.size);
 
-    mAxes.touchMajor = mAxes.pressure;
-    mAxes.touchMinor = mAxes.pressure;
+    mAxes.touchMajor = mAxes.size;
+    mAxes.touchMinor = mAxes.size;
     mAxes.toolMajor = mAxes.size;
     mAxes.toolMinor = mAxes.size;
 }
@@ -2585,10 +2587,7 @@
         }
 
         case SYN_REPORT:
-            if (mAccumulator.isDirty()) {
-                sync(rawEvent->when);
-                mAccumulator.clear();
-            }
+            sync(rawEvent->when);
             break;
         }
         break;
@@ -2598,11 +2597,7 @@
 void MultiTouchInputMapper::sync(nsecs_t when) {
     static const uint32_t REQUIRED_FIELDS =
             Accumulator::FIELD_ABS_MT_POSITION_X
-            | Accumulator::FIELD_ABS_MT_POSITION_Y
-            | Accumulator::FIELD_ABS_MT_TOUCH_MAJOR
-            | Accumulator::FIELD_ABS_MT_WIDTH_MAJOR;
-
-    /* Update device state */
+            | Accumulator::FIELD_ABS_MT_POSITION_Y;
 
     uint32_t inCount = mAccumulator.pointerCount;
     uint32_t outCount = 0;
@@ -2611,53 +2606,76 @@
     mCurrentTouch.clear();
 
     for (uint32_t inIndex = 0; inIndex < inCount; inIndex++) {
-        uint32_t fields = mAccumulator.pointers[inIndex].fields;
+        const Accumulator::Pointer& inPointer = mAccumulator.pointers[inIndex];
+        uint32_t fields = inPointer.fields;
 
         if ((fields & REQUIRED_FIELDS) != REQUIRED_FIELDS) {
-#if DEBUG_POINTERS
-            LOGD("Pointers: Missing required multitouch pointer fields: index=%d, fields=%d",
-                    inIndex, fields);
-            continue;
-#endif
-        }
-
-        if (mAccumulator.pointers[inIndex].absMTTouchMajor <= 0) {
-            // Pointer is not down.  Drop it.
+            // Some drivers send empty MT sync packets without X / Y to indicate a pointer up.
+            // Drop this finger.
             continue;
         }
 
-        mCurrentTouch.pointers[outCount].x = mAccumulator.pointers[inIndex].absMTPositionX;
-        mCurrentTouch.pointers[outCount].y = mAccumulator.pointers[inIndex].absMTPositionY;
+        PointerData& outPointer = mCurrentTouch.pointers[outCount];
+        outPointer.x = inPointer.absMTPositionX;
+        outPointer.y = inPointer.absMTPositionY;
 
-        mCurrentTouch.pointers[outCount].touchMajor =
-                mAccumulator.pointers[inIndex].absMTTouchMajor;
-        mCurrentTouch.pointers[outCount].touchMinor =
-                (fields & Accumulator::FIELD_ABS_MT_TOUCH_MINOR) != 0
-                ? mAccumulator.pointers[inIndex].absMTTouchMinor
-                        : mAccumulator.pointers[inIndex].absMTTouchMajor;
+        if (fields & Accumulator::FIELD_ABS_MT_TOUCH_MAJOR) {
+            int32_t value = inPointer.absMTTouchMajor;
+            if (value <= 0) {
+                // Some devices send sync packets with X / Y but with a 0 touch major to indicate
+                // a pointer up.  Drop this finger.
+                continue;
+            }
+            outPointer.touchMajor = inPointer.absMTTouchMajor;
+        } else {
+            outPointer.touchMajor = 0;
+        }
 
-        mCurrentTouch.pointers[outCount].toolMajor =
-                mAccumulator.pointers[inIndex].absMTWidthMajor;
-        mCurrentTouch.pointers[outCount].toolMinor =
-                (fields & Accumulator::FIELD_ABS_MT_WIDTH_MINOR) != 0
-                ? mAccumulator.pointers[inIndex].absMTWidthMinor
-                        : mAccumulator.pointers[inIndex].absMTWidthMajor;
+        if (fields & Accumulator::FIELD_ABS_MT_TOUCH_MINOR) {
+            outPointer.touchMinor = inPointer.absMTTouchMinor;
+        } else {
+            outPointer.touchMinor = outPointer.touchMajor;
+        }
 
-        mCurrentTouch.pointers[outCount].orientation =
-                (fields & Accumulator::FIELD_ABS_MT_ORIENTATION) != 0
-                ? mAccumulator.pointers[inIndex].absMTOrientation : 0;
+        if (fields & Accumulator::FIELD_ABS_MT_WIDTH_MAJOR) {
+            outPointer.toolMajor = inPointer.absMTWidthMajor;
+        } else {
+            outPointer.toolMajor = outPointer.touchMajor;
+        }
 
-        // Derive an approximation of pressure and size.
-        // FIXME assignment of pressure may be incorrect, probably better to let
-        // pressure = touch / width.  Later on we pass width to MotionEvent as a size, which
-        // isn't quite right either.  Should be using touch for that.
-        mCurrentTouch.pointers[outCount].pressure = mAccumulator.pointers[inIndex].absMTTouchMajor;
-        mCurrentTouch.pointers[outCount].size = mAccumulator.pointers[inIndex].absMTWidthMajor;
+        if (fields & Accumulator::FIELD_ABS_MT_WIDTH_MINOR) {
+            outPointer.toolMinor = inPointer.absMTWidthMinor;
+        } else {
+            outPointer.toolMinor = outPointer.toolMajor;
+        }
+
+        if (fields & Accumulator::FIELD_ABS_MT_ORIENTATION) {
+            outPointer.orientation = inPointer.absMTOrientation;
+        } else {
+            outPointer.orientation = 0;
+        }
+
+        if (fields & Accumulator::FIELD_ABS_MT_PRESSURE) {
+            outPointer.pressure = inPointer.absMTPressure;
+        } else {
+            // Derive an approximation of pressure.
+            // FIXME Traditionally we have just passed a normalized value based on
+            //       ABS_MT_TOUCH_MAJOR as an estimate of pressure but the result is not
+            //       very meaningful, particularly on large displays.  We should probably let
+            //       pressure = touch_major / tool_major but it is unclear whether that will
+            //       break applications.
+            outPointer.pressure = outPointer.touchMajor;
+        }
+
+        // Size is an alias for a normalized tool width.
+        // FIXME Normalized tool width doesn't actually make much sense since it literally
+        //       means the approaching contact major axis is divided by its full range as
+        //       reported by the driver.  On a large display this could produce very small values.
+        outPointer.size = outPointer.toolMajor;
 
         if (havePointerIds) {
-            if (fields & Accumulator::
-                    FIELD_ABS_MT_TRACKING_ID) {
-                uint32_t id = uint32_t(mAccumulator.pointers[inIndex].absMTTrackingId);
+            if (fields & Accumulator::FIELD_ABS_MT_TRACKING_ID) {
+                uint32_t id = uint32_t(inPointer.absMTTrackingId);
 
                 if (id > MAX_POINTER_ID) {
 #if DEBUG_POINTERS
@@ -2668,7 +2686,7 @@
                     havePointerIds = false;
                 }
                 else {
-                    mCurrentTouch.pointers[outCount].id = id;
+                    outPointer.id = id;
                     mCurrentTouch.idToIndex[id] = outCount;
                     mCurrentTouch.idBits.markBit(id);
                 }
@@ -2683,6 +2701,8 @@
     mCurrentTouch.pointerCount = outCount;
 
     syncTouch(when, havePointerIds);
+
+    mAccumulator.clear();
 }
 
 void MultiTouchInputMapper::configureAxes() {
@@ -2697,6 +2717,7 @@
     getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_MT_WIDTH_MAJOR, & mAxes.toolMajor);
     getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_MT_WIDTH_MINOR, & mAxes.toolMinor);
     getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_MT_ORIENTATION, & mAxes.orientation);
+    getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_MT_PRESSURE, & mAxes.pressure);
 
     if (! mAxes.touchMinor.valid) {
         mAxes.touchMinor = mAxes.touchMajor;
@@ -2706,7 +2727,10 @@
         mAxes.toolMinor = mAxes.toolMajor;
     }
 
-    mAxes.pressure = mAxes.touchMajor;
+    if (! mAxes.pressure.valid) {
+        mAxes.pressure = mAxes.touchMajor;
+    }
+
     mAxes.size = mAxes.toolMajor;
 }
 
diff --git a/libs/utils/AssetManager.cpp b/libs/utils/AssetManager.cpp
index 60a0d82..e09e755 100644
--- a/libs/utils/AssetManager.cpp
+++ b/libs/utils/AssetManager.cpp
@@ -232,6 +232,12 @@
     }
 }
 
+void AssetManager::getConfiguration(ResTable_config* outConfig) const
+{
+    AutoMutex _l(mLock);
+    *outConfig = *mConfig;
+}
+
 /*
  * Open an asset.
  *
diff --git a/libs/utils/ObbFile.cpp b/libs/utils/ObbFile.cpp
index fe49300..adedf0c 100644
--- a/libs/utils/ObbFile.cpp
+++ b/libs/utils/ObbFile.cpp
@@ -156,9 +156,9 @@
             return false;
         }
 
-        if (footerSize < kFooterMinSize) {
-            LOGW("claimed footer size is too small (%08zx; minimum size is 0x%x)\n",
-                    footerSize, kFooterMinSize);
+        if (footerSize < (kFooterMinSize - kFooterTagSize)) {
+            LOGW("claimed footer size is too small (0x%zx; minimum size is 0x%x)\n",
+                    footerSize, kFooterMinSize - kFooterTagSize);
             return false;
         }
     }
@@ -169,6 +169,8 @@
         return false;
     }
 
+    mFooterStart = fileOffset;
+
     char* scanBuf = (char*)malloc(footerSize);
     if (scanBuf == NULL) {
         LOGW("couldn't allocate scanBuf: %s\n", strerror(errno));
@@ -293,4 +295,38 @@
     return true;
 }
 
+bool ObbFile::removeFrom(const char* filename)
+{
+    int fd;
+    bool success = false;
+
+    fd = ::open(filename, O_RDWR);
+    if (fd < 0) {
+        goto out;
+    }
+    success = removeFrom(fd);
+    close(fd);
+
+out:
+    if (!success) {
+        LOGW("failed to remove signature from %s: %s\n", filename, strerror(errno));
+    }
+    return success;
+}
+
+bool ObbFile::removeFrom(int fd)
+{
+    if (fd < 0) {
+        return false;
+    }
+
+    if (!readFrom(fd)) {
+        return false;
+    }
+
+    ftruncate(fd, mFooterStart);
+
+    return true;
+}
+
 }
diff --git a/opengl/libs/EGL/egl.cpp b/opengl/libs/EGL/egl.cpp
index 315a2a3..94b60a1 100644
--- a/opengl/libs/EGL/egl.cpp
+++ b/opengl/libs/EGL/egl.cpp
@@ -1409,7 +1409,9 @@
                 egl_connection_t* const cnx = &gEGLImpl[i];
                 if (cnx->dso && cnx->egl.eglGetProcAddress) {
                     found = true;
-                    cnx->hooks[i]->ext.extensions[slot] =
+                    // Extensions are independent of the bound context
+                    cnx->hooks[GLESv1_INDEX]->ext.extensions[slot] =
+                    cnx->hooks[GLESv2_INDEX]->ext.extensions[slot] =
                             cnx->egl.eglGetProcAddress(procname);
                 }
             }
@@ -1421,7 +1423,6 @@
         }
 
     pthread_mutex_unlock(&gInitDriverMutex);
-
     return addr;
 }
 
diff --git a/services/surfaceflinger/Android.mk b/services/surfaceflinger/Android.mk
index a14bfb5..79772ed 100644
--- a/services/surfaceflinger/Android.mk
+++ b/services/surfaceflinger/Android.mk
@@ -5,6 +5,7 @@
     clz.cpp.arm \
     DisplayHardware/DisplayHardware.cpp \
     DisplayHardware/DisplayHardwareBase.cpp \
+    DisplayHardware/HWComposer.cpp \
     BlurFilter.cpp.arm \
     GLExtensions.cpp \
     Layer.cpp \
diff --git a/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp b/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp
index 2eac0a8..166c528 100644
--- a/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp
+++ b/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp
@@ -36,11 +36,11 @@
 
 #include "DisplayHardware/DisplayHardware.h"
 
-#include <hardware/copybit.h>
 #include <hardware/overlay.h>
 #include <hardware/gralloc.h>
 
 #include "GLExtensions.h"
+#include "HWComposer.h"
 
 using namespace android;
 
@@ -76,7 +76,7 @@
         const sp<SurfaceFlinger>& flinger,
         uint32_t dpy)
     : DisplayHardwareBase(flinger, dpy),
-      mFlags(0)
+      mFlags(0), mHwc(0)
 {
     init(dpy);
 }
@@ -262,6 +262,17 @@
 
     // Unbind the context from this thread
     eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
+
+
+    // initialize the H/W composer
+    mHwc = new HWComposer();
+    if (mHwc->initCheck() == NO_ERROR) {
+        mHwc->setFrameBuffer(mDisplay, mSurface);
+    }
+}
+
+HWComposer& DisplayHardware::getHwComposer() const {
+    return *mHwc;
 }
 
 /*
@@ -317,7 +328,12 @@
     }
     
     mPageFlipCount++;
-    eglSwapBuffers(dpy, surface);
+
+    if (mHwc->initCheck() == NO_ERROR) {
+        mHwc->commit();
+    } else {
+        eglSwapBuffers(dpy, surface);
+    }
     checkEGLErrors("eglSwapBuffers");
 
     // for debugging
diff --git a/services/surfaceflinger/DisplayHardware/DisplayHardware.h b/services/surfaceflinger/DisplayHardware/DisplayHardware.h
index 66bf521..f2cfd2d 100644
--- a/services/surfaceflinger/DisplayHardware/DisplayHardware.h
+++ b/services/surfaceflinger/DisplayHardware/DisplayHardware.h
@@ -34,12 +34,11 @@
 #include "DisplayHardware/DisplayHardwareBase.h"
 
 struct overlay_control_device_t;
-struct framebuffer_device_t;
-struct copybit_image_t;
 
 namespace android {
 
 class FramebufferNativeWindow;
+class HWComposer;
 
 class DisplayHardware : public DisplayHardwareBase
 {
@@ -80,6 +79,9 @@
     uint32_t getPageFlipCount() const;
     EGLDisplay getEGLDisplay() const { return mDisplay; }
     overlay_control_device_t* getOverlayEngine() const { return mOverlayEngine; }
+
+    // Hardware Composer
+    HWComposer& getHwComposer() const;
     
     status_t compositionComplete() const;
     
@@ -107,6 +109,8 @@
     GLint           mMaxViewportDims;
     GLint           mMaxTextureSize;
     
+    HWComposer*     mHwc;
+
     sp<FramebufferNativeWindow> mNativeWindow;
     overlay_control_device_t* mOverlayEngine;
 };
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
new file mode 100644
index 0000000..0291d78
--- /dev/null
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -0,0 +1,99 @@
+/*
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+
+#include <utils/Errors.h>
+
+#include <hardware/hardware.h>
+
+#include <cutils/log.h>
+
+#include <EGL/egl.h>
+
+#include "HWComposer.h"
+
+namespace android {
+// ---------------------------------------------------------------------------
+
+HWComposer::HWComposer()
+    : mModule(0), mHwc(0), mList(0), mCapacity(0),
+      mDpy(EGL_NO_DISPLAY), mSur(EGL_NO_SURFACE)
+{
+    int err = hw_get_module(HWC_HARDWARE_MODULE_ID, &mModule);
+    LOGW_IF(err, "%s module not found", HWC_HARDWARE_MODULE_ID);
+    if (err == 0) {
+        err = hwc_open(mModule, &mHwc);
+        LOGE_IF(err, "%s device failed to initialize (%s)",
+                HWC_HARDWARE_COMPOSER, strerror(-err));
+    }
+}
+
+HWComposer::~HWComposer() {
+    free(mList);
+    if (mHwc) {
+        hwc_close(mHwc);
+    }
+}
+
+status_t HWComposer::initCheck() const {
+    return mHwc ? NO_ERROR : NO_INIT;
+}
+
+void HWComposer::setFrameBuffer(EGLDisplay dpy, EGLSurface sur) {
+    mDpy = (hwc_display_t)dpy;
+    mSur = (hwc_surface_t)sur;
+}
+
+status_t HWComposer::createWorkList(size_t numLayers) {
+    if (mHwc) {
+        if (!mList || mCapacity < numLayers) {
+            free(mList);
+            size_t size = sizeof(hwc_layer_list) + numLayers*sizeof(hwc_layer_t);
+            mList = (hwc_layer_list_t*)malloc(size);
+            mCapacity = numLayers;
+        }
+        mList->flags = HWC_GEOMETRY_CHANGED;
+        mList->numHwLayers = numLayers;
+    }
+    return NO_ERROR;
+}
+
+status_t HWComposer::prepare() const {
+    int err = mHwc->prepare(mHwc, mList);
+    return (status_t)err;
+}
+
+status_t HWComposer::commit() const {
+    int err = mHwc->set(mHwc, mDpy, mSur, mList);
+    mList->flags &= ~HWC_GEOMETRY_CHANGED;
+    return (status_t)err;
+}
+
+size_t HWComposer::getNumLayers() const {
+    return mList ? mList->numHwLayers : 0;
+}
+
+hwc_layer_t* HWComposer::getLayers() const {
+    return mList ? mList->hwLayers : 0;
+}
+
+// ---------------------------------------------------------------------------
+}; // namespace android
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
new file mode 100644
index 0000000..c5d5c2b
--- /dev/null
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -0,0 +1,68 @@
+/*
+ * 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_SF_HWCOMPOSER_H
+#define ANDROID_SF_HWCOMPOSER_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <EGL/egl.h>
+
+#include <hardware/hwcomposer.h>
+
+namespace android {
+// ---------------------------------------------------------------------------
+
+class HWComposer
+{
+public:
+
+    HWComposer();
+    ~HWComposer();
+
+    status_t initCheck() const;
+
+    // tells the HAL what the framebuffer is
+    void setFrameBuffer(EGLDisplay dpy, EGLSurface sur);
+
+    // create a work list for numLayers layer
+    status_t createWorkList(size_t numLayers);
+
+    // Asks the HAL what it can do
+    status_t prepare() const;
+
+    // commits the list
+    status_t commit() const;
+
+
+    size_t getNumLayers() const;
+    hwc_layer_t* getLayers() const;
+
+private:
+    hw_module_t const*      mModule;
+    hwc_composer_device_t*  mHwc;
+    hwc_layer_list_t*       mList;
+    size_t                  mCapacity;
+    hwc_display_t           mDpy;
+    hwc_surface_t           mSur;
+};
+
+
+// ---------------------------------------------------------------------------
+}; // namespace android
+
+#endif // ANDROID_SF_HWCOMPOSER_H
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 629d993..3720e16 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -35,6 +35,7 @@
 #include "Layer.h"
 #include "SurfaceFlinger.h"
 #include "DisplayHardware/DisplayHardware.h"
+#include "DisplayHardware/HWComposer.h"
 
 
 #define DEBUG_RESIZE    0
@@ -177,6 +178,62 @@
     return NO_ERROR;
 }
 
+void Layer::setGeometry(hwc_layer_t* hwcl)
+{
+    hwcl->compositionType = HWC_FRAMEBUFFER;
+    hwcl->hints = 0;
+    hwcl->flags = 0;
+    hwcl->transform = 0;
+    hwcl->blending = HWC_BLENDING_NONE;
+
+    // we can't do alpha-fade with the hwc HAL
+    const State& s(drawingState());
+    if (s.alpha < 0xFF) {
+        hwcl->flags = HWC_SKIP_LAYER;
+        return;
+    }
+
+    // we can only handle simple transformation
+    if (mOrientation & Transform::ROT_INVALID) {
+        hwcl->flags = HWC_SKIP_LAYER;
+        return;
+    }
+
+    hwcl->transform = mOrientation;
+
+    if (needsBlending()) {
+        hwcl->blending = mPremultipliedAlpha ?
+                HWC_BLENDING_PREMULT : HWC_BLENDING_COVERAGE;
+    }
+
+    hwcl->displayFrame.left   = mTransformedBounds.left;
+    hwcl->displayFrame.top    = mTransformedBounds.top;
+    hwcl->displayFrame.right  = mTransformedBounds.right;
+    hwcl->displayFrame.bottom = mTransformedBounds.bottom;
+
+    hwcl->visibleRegionScreen.rects =
+            reinterpret_cast<hwc_rect_t const *>(
+                    visibleRegionScreen.getArray(
+                            &hwcl->visibleRegionScreen.numRects));
+}
+
+void Layer::setPerFrameData(hwc_layer_t* hwcl) {
+    sp<GraphicBuffer> buffer(mBufferManager.getActiveBuffer());
+    if (buffer == NULL) {
+        // this situation can happen if we ran out of memory for instance.
+        // not much we can do. continue to use whatever texture was bound
+        // to this context.
+        hwcl->handle = NULL;
+        return;
+    }
+    hwcl->handle = const_cast<native_handle_t*>(buffer->handle);
+    // TODO: set the crop value properly
+    hwcl->sourceCrop.left   = 0;
+    hwcl->sourceCrop.top    = 0;
+    hwcl->sourceCrop.right  = buffer->width;
+    hwcl->sourceCrop.bottom = buffer->height;
+}
+
 void Layer::reloadTexture(const Region& dirty)
 {
     sp<GraphicBuffer> buffer(mBufferManager.getActiveBuffer());
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index e1d283b..188da6a 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -68,6 +68,8 @@
     bool isFixedSize() const;
 
     // LayerBase interface
+    virtual void setGeometry(hwc_layer_t* hwcl);
+    virtual void setPerFrameData(hwc_layer_t* hwcl);
     virtual void onDraw(const Region& clip) const;
     virtual uint32_t doTransaction(uint32_t transactionFlags);
     virtual void lockPageFlip(bool& recomputeVisibleRegions);
diff --git a/services/surfaceflinger/LayerBase.cpp b/services/surfaceflinger/LayerBase.cpp
index d5aa53f..043d54d 100644
--- a/services/surfaceflinger/LayerBase.cpp
+++ b/services/surfaceflinger/LayerBase.cpp
@@ -39,8 +39,11 @@
 
 // ---------------------------------------------------------------------------
 
+int32_t LayerBase::sSequence = 1;
+
 LayerBase::LayerBase(SurfaceFlinger* flinger, DisplayID display)
     : dpy(display), contentDirty(false),
+      sequence(uint32_t(android_atomic_inc(&sSequence))),
       mFlinger(flinger),
       mNeedsFiltering(false),
       mOrientation(0),
@@ -304,22 +307,17 @@
     }
 }
 
-void LayerBase::draw(const Region& inClip) const
+void LayerBase::setGeometry(hwc_layer_t* hwcl) {
+    hwcl->flags |= HWC_SKIP_LAYER;
+}
+
+void LayerBase::setPerFrameData(hwc_layer_t* hwcl) {
+    hwcl->compositionType = HWC_FRAMEBUFFER;
+    hwcl->handle = NULL;
+}
+
+void LayerBase::draw(const Region& clip) const
 {
-    // invalidate the region we'll update
-    Region clip(inClip);  // copy-on-write, so no-op most of the time
-
-    // Remove the transparent area from the clipping region
-    const State& s = drawingState();
-    if (LIKELY(!s.transparentRegion.isEmpty())) {
-        clip.subtract(transparentRegionScreen);
-        if (clip.isEmpty()) {
-            // usually this won't happen because this should be taken care of
-            // by SurfaceFlinger::computeVisibleRegions()
-            return;
-        }        
-    }
-
     // reset GL state
     glEnable(GL_SCISSOR_TEST);
 
diff --git a/services/surfaceflinger/LayerBase.h b/services/surfaceflinger/LayerBase.h
index 4288cf7..dd1cd05 100644
--- a/services/surfaceflinger/LayerBase.h
+++ b/services/surfaceflinger/LayerBase.h
@@ -35,6 +35,8 @@
 
 #include <pixelflinger/pixelflinger.h>
 
+#include <hardware/hwcomposer.h>
+
 #include "Transform.h"
 
 namespace android {
@@ -53,6 +55,8 @@
 
 class LayerBase : public RefBase
 {
+    static int32_t sSequence;
+
 public:
             LayerBase(SurfaceFlinger* flinger, DisplayID display);
 
@@ -61,6 +65,7 @@
             Region      visibleRegionScreen;
             Region      transparentRegionScreen;
             Region      coveredRegionScreen;
+            int32_t     sequence;
             
             struct State {
                 uint32_t        w;
@@ -105,6 +110,10 @@
 
     virtual const char* getTypeId() const { return "LayerBase"; }
 
+    virtual void setGeometry(hwc_layer_t* hwcl);
+
+    virtual void setPerFrameData(hwc_layer_t* hwcl);
+
     /**
      * draw - performs some global clipping optimizations
      * and calls onDraw().
@@ -210,12 +219,6 @@
     inline  const State&    currentState() const    { return mCurrentState; }
     inline  State&          currentState()          { return mCurrentState; }
 
-    static int compareCurrentStateZ(
-            sp<LayerBase> const * layerA,
-            sp<LayerBase> const * layerB) {
-        return layerA[0]->currentState().z - layerB[0]->currentState().z;
-    }
-
     int32_t  getOrientation() const { return mOrientation; }
     int  tx() const             { return mLeft; }
     int  ty() const             { return mTop; }
diff --git a/services/surfaceflinger/LayerBuffer.cpp b/services/surfaceflinger/LayerBuffer.cpp
index 5f83636..e8b2ebf 100644
--- a/services/surfaceflinger/LayerBuffer.cpp
+++ b/services/surfaceflinger/LayerBuffer.cpp
@@ -495,7 +495,7 @@
     const ISurface::BufferHeap& buffers(mBufferHeap);
     uint32_t w = mLayer.mTransformedBounds.width();
     uint32_t h = mLayer.mTransformedBounds.height();
-    if (buffers.w * h != buffers.h * w) {
+    if (mLayer.getOrientation() & (Transform::ROT_90 | Transform::ROT_270)) {
         int t = w; w = h; h = t;
     }
 
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 3167c4c..d257897 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -52,6 +52,7 @@
 #include "SurfaceFlinger.h"
 
 #include "DisplayHardware/DisplayHardware.h"
+#include "DisplayHardware/HWComposer.h"
 
 /* ideally AID_GRAPHICS would be in a semi-public header
  * or there would be a way to map a user/group name to its id
@@ -65,95 +66,6 @@
 namespace android {
 // ---------------------------------------------------------------------------
 
-SurfaceFlinger::LayerVector::LayerVector(const SurfaceFlinger::LayerVector& rhs)
-    : lookup(rhs.lookup), layers(rhs.layers)
-{
-}
-
-ssize_t SurfaceFlinger::LayerVector::indexOf(
-        const sp<LayerBase>& key, size_t guess) const
-{
-    if (guess<size() && lookup.keyAt(guess) == key)
-        return guess;
-    const ssize_t i = lookup.indexOfKey(key);
-    if (i>=0) {
-        const size_t idx = lookup.valueAt(i);
-        LOGE_IF(layers[idx]!=key,
-            "LayerVector[%p]: layers[%d]=%p, key=%p",
-            this, int(idx), layers[idx].get(), key.get());
-        return idx;
-    }
-    return i;
-}
-
-ssize_t SurfaceFlinger::LayerVector::add(
-        const sp<LayerBase>& layer,
-        Vector< sp<LayerBase> >::compar_t cmp)
-{
-    size_t count = layers.size();
-    ssize_t l = 0;
-    ssize_t h = count-1;
-    ssize_t mid;
-    sp<LayerBase> const* a = layers.array();
-    while (l <= h) {
-        mid = l + (h - l)/2;
-        const int c = cmp(a+mid, &layer);
-        if (c == 0)     { l = mid; break; }
-        else if (c<0)   { l = mid+1; }
-        else            { h = mid-1; }
-    }
-    size_t order = l;
-    while (order<count && !cmp(&layer, a+order)) {
-        order++;
-    }
-    count = lookup.size();
-    for (size_t i=0 ; i<count ; i++) {
-        if (lookup.valueAt(i) >= order) {
-            lookup.editValueAt(i)++;
-        }
-    }
-    layers.insertAt(layer, order);
-    lookup.add(layer, order);
-    return order;
-}
-
-ssize_t SurfaceFlinger::LayerVector::remove(const sp<LayerBase>& layer)
-{
-    const ssize_t keyIndex = lookup.indexOfKey(layer);
-    if (keyIndex >= 0) {
-        const size_t index = lookup.valueAt(keyIndex);
-        LOGE_IF(layers[index]!=layer,
-                "LayerVector[%p]: layers[%u]=%p, layer=%p",
-                this, int(index), layers[index].get(), layer.get());
-        layers.removeItemsAt(index);
-        lookup.removeItemsAt(keyIndex);
-        const size_t count = lookup.size();
-        for (size_t i=0 ; i<count ; i++) {
-            if (lookup.valueAt(i) >= size_t(index)) {
-                lookup.editValueAt(i)--;
-            }
-        }
-        return index;
-    }
-    return NAME_NOT_FOUND;
-}
-
-ssize_t SurfaceFlinger::LayerVector::reorder(
-        const sp<LayerBase>& layer,
-        Vector< sp<LayerBase> >::compar_t cmp)
-{
-    // XXX: it's a little lame. but oh well...
-    ssize_t err = remove(layer);
-    if (err >=0)
-        err = add(layer, cmp);
-    return err;
-}
-
-// ---------------------------------------------------------------------------
-#if 0
-#pragma mark -
-#endif
-
 SurfaceFlinger::SurfaceFlinger()
     :   BnSurfaceComposer(), Thread(false),
         mTransactionFlags(0),
@@ -165,6 +77,7 @@
         mAccessSurfaceFlinger("android.permission.ACCESS_SURFACE_FLINGER"),
         mDump("android.permission.DUMP"),
         mVisibleRegionsDirty(false),
+        mHwWorkListDirty(false),
         mDeferReleaseConsole(false),
         mFreezeDisplay(false),
         mFreezeCount(0),
@@ -457,6 +370,11 @@
     // post surfaces (if needed)
     handlePageFlip();
 
+    if (UNLIKELY(mHwWorkListDirty)) {
+        // build the h/w work list
+        handleWorkList();
+    }
+
     const DisplayHardware& hw(graphicPlane(0).displayHardware());
     if (LIKELY(hw.canDraw() && !isFrozen())) {
         // repaint the framebuffer (if needed)
@@ -521,6 +439,10 @@
 {
     Vector< sp<LayerBase> > ditchedLayers;
 
+    /*
+     * Perform and commit the transaction
+     */
+
     { // scope for the lock
         Mutex::Autolock _l(mStateLock);
         const nsecs_t now = systemTime();
@@ -528,9 +450,15 @@
         handleTransactionLocked(transactionFlags, ditchedLayers);
         mLastTransactionTime = systemTime() - now;
         mDebugInTransaction = 0;
+        mHwWorkListDirty = true;
+        // here the transaction has been committed
     }
 
-    // do this without lock held
+    /*
+     * Clean-up all layers that went away
+     * (do this without the lock held)
+     */
+
     const size_t count = ditchedLayers.size();
     for (size_t i=0 ; i<count ; i++) {
         if (ditchedLayers[i] != 0) {
@@ -764,8 +692,8 @@
 void SurfaceFlinger::handlePageFlip()
 {
     bool visibleRegions = mVisibleRegionsDirty;
-    LayerVector& currentLayers = const_cast<LayerVector&>(
-            mDrawingState.layersSortedByZ);
+    LayerVector& currentLayers(
+            const_cast<LayerVector&>(mDrawingState.layersSortedByZ));
     visibleRegions |= lockPageFlip(currentLayers);
 
         const DisplayHardware& hw = graphicPlane(0).displayHardware();
@@ -773,8 +701,22 @@
         if (visibleRegions) {
             Region opaqueRegion;
             computeVisibleRegions(currentLayers, mDirtyRegion, opaqueRegion);
+
+            /*
+             *  rebuild the visible layer list
+             */
+            mVisibleLayersSortedByZ.clear();
+            const LayerVector& currentLayers(mDrawingState.layersSortedByZ);
+            size_t count = currentLayers.size();
+            mVisibleLayersSortedByZ.setCapacity(count);
+            for (size_t i=0 ; i<count ; i++) {
+                if (!currentLayers[i]->visibleRegionScreen.isEmpty())
+                    mVisibleLayersSortedByZ.add(currentLayers[i]);
+            }
+
             mWormholeRegion = screenRegion.subtract(opaqueRegion);
             mVisibleRegionsDirty = false;
+            mHwWorkListDirty = true;
         }
 
     unlockPageFlip(currentLayers);
@@ -805,6 +747,20 @@
     }
 }
 
+void SurfaceFlinger::handleWorkList()
+{
+    mHwWorkListDirty = false;
+    HWComposer& hwc(graphicPlane(0).displayHardware().getHwComposer());
+    if (hwc.initCheck() == NO_ERROR) {
+        const Vector< sp<LayerBase> >& currentLayers(mVisibleLayersSortedByZ);
+        const size_t count = currentLayers.size();
+        hwc.createWorkList(count);
+        hwc_layer_t* const cur(hwc.getLayers());
+        for (size_t i=0 ; cur && i<count ; i++) {
+            currentLayers[i]->setGeometry(&cur[i]);
+        }
+    }
+}
 
 void SurfaceFlinger::handleRepaint()
 {
@@ -869,19 +825,77 @@
         // draw something...
         drawWormhole();
     }
-    const SurfaceFlinger& flinger(*this);
-    const LayerVector& drawingLayers(mDrawingState.layersSortedByZ);
-    const size_t count = drawingLayers.size();
-    sp<LayerBase> const* const layers = drawingLayers.array();
-    for (size_t i=0 ; i<count ; ++i) {
-        const sp<LayerBase>& layer = layers[i];
-        const Region& visibleRegion(layer->visibleRegionScreen);
-        if (!visibleRegion.isEmpty())  {
-            const Region clip(dirty.intersect(visibleRegion));
-            if (!clip.isEmpty()) {
-                layer->draw(clip);
+
+    status_t err = NO_ERROR;
+    const Vector< sp<LayerBase> >& layers(mVisibleLayersSortedByZ);
+    size_t count = layers.size();
+
+    const DisplayHardware& hw(graphicPlane(0).displayHardware());
+    HWComposer& hwc(hw.getHwComposer());
+    hwc_layer_t* const cur(hwc.getLayers());
+
+    LOGE_IF(cur && hwc.getNumLayers() != count,
+            "HAL number of layers (%d) doesn't match surfaceflinger (%d)",
+            hwc.getNumLayers(), count);
+
+    // just to be extra-safe, use the smallest count
+    if (hwc.initCheck() == NO_ERROR) {
+        count = count < hwc.getNumLayers() ? count : hwc.getNumLayers();
+    }
+
+    /*
+     *  update the per-frame h/w composer data for each layer
+     *  and build the transparent region of the FB
+     */
+    Region transparent;
+    if (cur) {
+        for (size_t i=0 ; i<count ; i++) {
+            const sp<LayerBase>& layer(layers[i]);
+            layer->setPerFrameData(&cur[i]);
+            if (cur[i].hints & HWC_HINT_CLEAR_FB) {
+                if (!(layer->needsBlending())) {
+                    transparent.orSelf(layer->visibleRegionScreen);
+                }
             }
         }
+        err = hwc.prepare();
+        LOGE_IF(err, "HWComposer::prepare failed (%s)", strerror(-err));
+    }
+
+    /*
+     *  clear the area of the FB that need to be transparent
+     */
+    transparent.andSelf(dirty);
+    if (!transparent.isEmpty()) {
+        glClearColor(0,0,0,0);
+        Region::const_iterator it = transparent.begin();
+        Region::const_iterator const end = transparent.end();
+        const int32_t height = hw.getHeight();
+        while (it != end) {
+            const Rect& r(*it++);
+            const GLint sy = height - (r.top + r.height());
+            glScissor(r.left, sy, r.width(), r.height());
+            glClear(GL_COLOR_BUFFER_BIT);
+        }
+    }
+
+
+    /*
+     * and then, render the layers targeted at the framebuffer
+     */
+    for (size_t i=0 ; i<count ; i++) {
+        if (cur) {
+            if (!(cur[i].compositionType == HWC_FRAMEBUFFER) ||
+                    cur[i].flags & HWC_SKIP_LAYER) {
+                // skip layers handled by the HAL
+                continue;
+            }
+        }
+        const sp<LayerBase>& layer(layers[i]);
+        const Region clip(dirty.intersect(layer->visibleRegionScreen));
+        if (!clip.isEmpty()) {
+            layer->draw(clip);
+        }
     }
 }
 
@@ -1029,8 +1043,7 @@
 
 status_t SurfaceFlinger::addLayer_l(const sp<LayerBase>& layer)
 {
-    ssize_t i = mCurrentState.layersSortedByZ.add(
-                layer, &LayerBase::compareCurrentStateZ);
+    ssize_t i = mCurrentState.layersSortedByZ.add(layer);
     return (i < 0) ? status_t(i) : status_t(NO_ERROR);
 }
 
@@ -1372,9 +1385,10 @@
                     flags |= eTraversalNeeded;
             }
             if (what & eLayerChanged) {
+                ssize_t idx = mCurrentState.layersSortedByZ.indexOf(layer);
                 if (layer->setLayer(s.z)) {
-                    mCurrentState.layersSortedByZ.reorder(
-                            layer, &Layer::compareCurrentStateZ);
+                    mCurrentState.layersSortedByZ.removeAt(idx);
+                    mCurrentState.layersSortedByZ.add(layer);
                     // we need traversal (state changed)
                     // AND transaction (list changed)
                     flags |= eTransactionNeeded|eTraversalNeeded;
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 8821e5c..8e286e5 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -40,9 +40,6 @@
 
 #include "MessageQueue.h"
 
-struct copybit_device_t;
-struct overlay_device_t;
-
 namespace android {
 
 // ---------------------------------------------------------------------------
@@ -246,21 +243,19 @@
     status_t setClientState(const sp<Client>& client,
             int32_t count, const layer_state_t* states);
 
-
-    class LayerVector {
+    class LayerVector : public SortedVector< sp<LayerBase> > {
     public:
-        inline              LayerVector() { }
-                            LayerVector(const LayerVector&);
-        inline size_t       size() const { return layers.size(); }
-        inline sp<LayerBase> const* array() const { return layers.array(); }
-        ssize_t             add(const sp<LayerBase>&, Vector< sp<LayerBase> >::compar_t);
-        ssize_t             remove(const sp<LayerBase>&);
-        ssize_t             reorder(const sp<LayerBase>&, Vector< sp<LayerBase> >::compar_t);
-        ssize_t             indexOf(const sp<LayerBase>& key, size_t guess=0) const;
-        inline sp<LayerBase> operator [] (size_t i) const { return layers[i]; }
-    private:
-        KeyedVector< sp<LayerBase> , size_t> lookup;
-        Vector< sp<LayerBase> >              layers;
+        LayerVector() { }
+        LayerVector(const LayerVector& rhs) : SortedVector< sp<LayerBase> >(rhs) { }
+        virtual int do_compare(const void* lhs, const void* rhs) const {
+            const sp<LayerBase>& l(*reinterpret_cast<const sp<LayerBase>*>(lhs));
+            const sp<LayerBase>& r(*reinterpret_cast<const sp<LayerBase>*>(rhs));
+            // sort layers by Z order
+            uint32_t lz = l->currentState().z;
+            uint32_t rz = r->currentState().z;
+            // then by sequence, so we get a stable ordering
+            return (lz != rz) ? (lz - rz) : (l->sequence - r->sequence);
+        }
     };
 
     struct State {
@@ -301,6 +296,7 @@
             void        handlePageFlip();
             bool        lockPageFlip(const LayerVector& currentLayers);
             void        unlockPageFlip(const LayerVector& currentLayers);
+            void        handleWorkList();
             void        handleRepaint();
             void        postFramebuffer();
             void        composeSurfaces(const Region& dirty);
@@ -375,10 +371,13 @@
                 Region                      mInvalidRegion;
                 Region                      mWormholeRegion;
                 bool                        mVisibleRegionsDirty;
+                bool                        mHwWorkListDirty;
                 bool                        mDeferReleaseConsole;
                 bool                        mFreezeDisplay;
                 int32_t                     mFreezeCount;
                 nsecs_t                     mFreezeDisplayTime;
+                Vector< sp<LayerBase> >     mVisibleLayersSortedByZ;
+
 
                 // don't use a lock for these, we don't care
                 int                         mDebugRegion;
diff --git a/services/surfaceflinger/TextureManager.cpp b/services/surfaceflinger/TextureManager.cpp
index 3b326df..0f448e0 100644
--- a/services/surfaceflinger/TextureManager.cpp
+++ b/services/surfaceflinger/TextureManager.cpp
@@ -190,7 +190,7 @@
         return err;
     }
 
-    if (texture->target != GL_TEXTURE_2D)
+    if (texture->target != Texture::TEXTURE_2D)
         return INVALID_OPERATION;
 
     glBindTexture(GL_TEXTURE_2D, texture->name);