Merge "Document that autoFocus must be called in auto and macro mode." into gingerbread
diff --git a/include/ui/EventHub.h b/include/ui/EventHub.h
index dab35b3..3132941 100644
--- a/include/ui/EventHub.h
+++ b/include/ui/EventHub.h
@@ -266,6 +266,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/libs/ui/EventHub.cpp b/libs/ui/EventHub.cpp
index 124f7b3..33393fe 100644
--- a/libs/ui/EventHub.cpp
+++ b/libs/ui/EventHub.cpp
@@ -100,6 +100,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
@@ -343,13 +344,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 +352,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 +383,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 +490,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();
@@ -584,6 +597,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) {
@@ -640,6 +659,7 @@
 
     mFDs[mFDCount].fd = fd;
     mFDs[mFDCount].events = POLLIN;
+    mFDs[mFDCount].revents = 0;
 
     // Figure out the kinds of events the device reports.
     
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) {