auto import from //depot/cupcake/@135843
diff --git a/libs/ui/KeyLayoutMap.cpp b/libs/ui/KeyLayoutMap.cpp
new file mode 100644
index 0000000..15ae54c
--- /dev/null
+++ b/libs/ui/KeyLayoutMap.cpp
@@ -0,0 +1,235 @@
+#define LOG_TAG "KeyLayoutMap"
+
+#include "KeyLayoutMap.h"
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include <utils/String8.h>
+#include <stdlib.h>
+#include <ui/KeycodeLabels.h>
+#include <utils/Log.h>
+
+namespace android {
+
+KeyLayoutMap::KeyLayoutMap()
+    :m_status(NO_INIT),
+     m_keys()
+{
+}
+
+KeyLayoutMap::~KeyLayoutMap()
+{
+}
+
+static String8
+next_token(char const** p, int *line)
+{
+    bool begun = false;
+    const char* begin = *p;
+    const char* end = *p;
+    while (true) {
+        if (*end == '\n') {
+            (*line)++;
+        }
+        switch (*end)
+        {
+            case '#':
+                if (begun) {
+                    *p = end;
+                    return String8(begin, end-begin);
+                } else {
+                    do {
+                        begin++;
+                        end++;
+                    } while (*begin != '\0' && *begin != '\n');
+                }
+            case '\0':
+            case ' ':
+            case '\n':
+            case '\r':
+            case '\t':
+                if (begun || (*end == '\0')) {
+                    *p = end;
+                    return String8(begin, end-begin);
+                } else {
+                    begin++;
+                    end++;
+                    break;
+                }
+            default:
+                end++;
+                begun = true;
+        }
+    }
+}
+
+static int32_t
+token_to_value(const char *literal, const KeycodeLabel *list)
+{
+    while (list->literal) {
+        if (0 == strcmp(literal, list->literal)) {
+            return list->value;
+        }
+        list++;
+    }
+    return list->value;
+}
+
+status_t
+KeyLayoutMap::load(const char* filename)
+{
+    int fd = open(filename, O_RDONLY);
+    if (fd < 0) {
+        LOGE("error opening file=%s err=%s\n", filename, strerror(errno));
+        m_status = errno;
+        return errno;
+    }
+
+    off_t len = lseek(fd, 0, SEEK_END);
+    off_t errlen = lseek(fd, 0, SEEK_SET);
+    if (len < 0 || errlen < 0) {
+        close(fd);
+        LOGE("error seeking file=%s err=%s\n", filename, strerror(errno));
+        m_status = errno;
+        return errno;
+    }
+
+    char* buf = (char*)malloc(len+1);
+    if (read(fd, buf, len) != len) {
+        LOGE("error reading file=%s err=%s\n", filename, strerror(errno));
+        m_status = errno != 0 ? errno : ((int)NOT_ENOUGH_DATA);
+        return errno != 0 ? errno : ((int)NOT_ENOUGH_DATA);
+    }
+    errno = 0;
+    buf[len] = '\0';
+
+    int32_t scancode = -1;
+    int32_t keycode = -1;
+    uint32_t flags = 0;
+    uint32_t tmp;
+    char* end;
+    status_t err = NO_ERROR;
+    int line = 1;
+    char const* p = buf;
+    enum { BEGIN, SCANCODE, KEYCODE, FLAG } state = BEGIN;
+    while (true) {
+        String8 token = next_token(&p, &line);
+        if (*p == '\0') {
+            break;
+        }
+        switch (state)
+        {
+            case BEGIN:
+                if (token == "key") {
+                    state = SCANCODE;
+                } else {
+                    LOGE("%s:%d: expected key, got '%s'\n", filename, line,
+                            token.string());
+                    err = BAD_VALUE;
+                    goto done;
+                }
+                break;
+            case SCANCODE:
+                scancode = strtol(token.string(), &end, 0);
+                if (*end != '\0') {
+                    LOGE("%s:%d: expected scancode (a number), got '%s'\n",
+                            filename, line, token.string());
+                    goto done;
+                }
+                //LOGI("%s:%d: got scancode %d\n", filename, line, scancode );
+                state = KEYCODE;
+                break;
+            case KEYCODE:
+                keycode = token_to_value(token.string(), KEYCODES);
+                //LOGI("%s:%d: got keycode %d for %s\n", filename, line, keycode, token.string() );
+                if (keycode == 0) {
+                    LOGE("%s:%d: expected keycode, got '%s'\n",
+                            filename, line, token.string());
+                    goto done;
+                }
+                state = FLAG;
+                break;
+            case FLAG:
+                if (token == "key") {
+                    if (scancode != -1) {
+                        //LOGI("got key decl scancode=%d keycode=%d"
+                        //       " flags=0x%08x\n", scancode, keycode, flags);
+                        Key k = { keycode, flags };
+                        m_keys.add(scancode, k);
+                        state = SCANCODE;
+                        scancode = -1;
+                        keycode = -1;
+                        flags = 0;
+                        break;
+                    }
+                }
+                tmp = token_to_value(token.string(), FLAGS);
+                //LOGI("%s:%d: got flags %x for %s\n", filename, line, tmp, token.string() );
+                if (tmp == 0) {
+                    LOGE("%s:%d: expected flag, got '%s'\n",
+                            filename, line, token.string());
+                    goto done;
+                }
+                flags |= tmp;
+                break;
+        }
+    }
+    if (state == FLAG && scancode != -1 ) {
+        //LOGI("got key decl scancode=%d keycode=%d"
+        //       " flags=0x%08x\n", scancode, keycode, flags);
+        Key k = { keycode, flags };
+        m_keys.add(scancode, k);
+    }
+
+done:
+    free(buf);
+    close(fd);
+
+    m_status = err;
+    return err;
+}
+
+status_t
+KeyLayoutMap::map(int32_t scancode, int32_t *keycode, uint32_t *flags) const
+{
+    if (m_status != NO_ERROR) {
+        return m_status;
+    }
+
+    ssize_t index = m_keys.indexOfKey(scancode);
+    if (index < 0) {
+        //LOGW("couldn't map scancode=%d\n", scancode);
+        return NAME_NOT_FOUND;
+    }
+
+    const Key& k = m_keys.valueAt(index);
+
+    *keycode = k.keycode;
+    *flags = k.flags;
+
+    //LOGD("mapped scancode=%d to keycode=%d flags=0x%08x\n", scancode,
+    //        keycode, flags);
+
+    return NO_ERROR;
+}
+
+status_t
+KeyLayoutMap::findScancodes(int32_t keycode, Vector<int32_t>* outScancodes) const
+{
+    if (m_status != NO_ERROR) {
+        return m_status;
+    }
+    
+    const size_t N = m_keys.size();
+    for (size_t i=0; i<N; i++) {
+        if (m_keys.valueAt(i).keycode == keycode) {
+            outScancodes->add(m_keys.keyAt(i));
+        }
+    }
+    
+    return NO_ERROR;
+}
+
+};