auto import from //depot/cupcake/@135843
diff --git a/simulator/app/PhoneData.cpp b/simulator/app/PhoneData.cpp
new file mode 100644
index 0000000..48614fd
--- /dev/null
+++ b/simulator/app/PhoneData.cpp
@@ -0,0 +1,868 @@
+//
+// Copyright 2005 The Android Open Source Project
+//
+// Simulated device data.
+//
+
+// For compilers that support precompilation, include "wx/wx.h".
+#include "wx/wxprec.h"
+
+// Otherwise, include all standard headers
+#ifndef WX_PRECOMP
+# include "wx/wx.h"
+#endif
+#include "wx/image.h"   // needed for Windows build
+
+
+#include "PhoneData.h"
+#include "PhoneButton.h"
+#include "PhoneCollection.h"
+#include "MyApp.h"
+
+#include <utils.h>
+#include <utils/AssetManager.h>
+#include <utils/String8.h>
+
+#include "tinyxml.h"
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+
+using namespace android;
+
+/* image relative path hack */
+static const char* kRelPathMagic = "::/";
+
+
+/*
+ * ===========================================================================
+ *      PhoneKeyboard
+ * ===========================================================================
+ */
+
+/*
+ * Load a <keyboard> chunk.
+ */
+bool PhoneKeyboard::ProcessAndValidate(TiXmlNode* pNode)
+{
+    //TiXmlNode* pChild;
+    TiXmlElement* pElem;
+    int qwerty = 0;
+    
+    assert(pNode->Type() == TiXmlNode::ELEMENT);
+
+    pElem = pNode->ToElement();
+    pElem->Attribute("qwerty", &qwerty);
+    const char *kmap = pElem->Attribute("keycharmap");
+
+    if (qwerty == 1) {
+        printf("############## PhoneKeyboard::ProcessAndValidate: qwerty = true!\n");
+        mQwerty = true;
+    }
+
+    if (kmap != NULL) {
+        printf("############## PhoneKeyboard::ProcessAndValidate: keycharmap = %s\n", kmap);
+        mKeyMap = strdup(kmap);
+    }
+    
+    return true;
+}
+
+
+/*
+ * ===========================================================================
+ *      PhoneDisplay
+ * ===========================================================================
+ */
+
+/*
+ * Load a <display> chunk.
+ */
+bool PhoneDisplay::ProcessAndValidate(TiXmlNode* pNode)
+{
+    //TiXmlNode* pChild;
+    TiXmlElement* pElem;
+    const char* name;
+    const char* format;
+
+    assert(pNode->Type() == TiXmlNode::ELEMENT);
+
+    /*
+     * Process attributes.  Right now they're all mandatory, but some of
+     * them could be defaulted (e.g. "rotate").
+     *
+     * [We should do some range-checking here.]
+     */
+    pElem = pNode->ToElement();
+    name = pElem->Attribute("name");
+    if (name == NULL)
+        goto missing;
+    if (pElem->Attribute("width", &mWidth) == NULL)
+        goto missing;
+    if (pElem->Attribute("height", &mHeight) == NULL)
+        goto missing;
+    if (pElem->Attribute("refresh", &mRefresh) == NULL)
+        goto missing;
+    format = pElem->Attribute("format");
+    if (format == NULL)
+        goto missing;
+
+    delete[] mName;
+    mName = strdupNew(name);
+
+    if (strcasecmp(format, "rgb565") == 0) {
+        mFormat = android::PIXEL_FORMAT_RGB_565;
+    } else {
+        fprintf(stderr, "SimCFG: unexpected value for display format\n");
+        return false;
+    }
+
+    return true;
+
+missing:
+    fprintf(stderr,
+        "SimCFG: <display> requires name/width/height/format/refresh\n");
+    return false;
+}
+
+
+/*
+ * Returns "true" if the two displays are compatible, "false" if not.
+ *
+ * Compatibility means they have the same resolution, format, refresh
+ * rate, and so on.  Anything transmitted to the runtime as part of the
+ * initial configuration setup should be tested.
+ */
+/*static*/ bool PhoneDisplay::IsCompatible(PhoneDisplay* pDisplay1,
+    PhoneDisplay* pDisplay2)
+{
+    return (pDisplay1->mWidth == pDisplay2->mWidth &&
+            pDisplay1->mHeight == pDisplay2->mHeight &&
+            pDisplay1->mFormat == pDisplay2->mFormat &&
+            pDisplay1->mRefresh == pDisplay2->mRefresh);
+}
+
+
+/*
+ * ===========================================================================
+ *      PhoneView
+ * ===========================================================================
+ */
+
+/*
+ * Load a <view> chunk.
+ */
+bool PhoneView::ProcessAndValidate(TiXmlNode* pNode, const char* directory)
+{
+    TiXmlNode* pChild;
+    TiXmlElement* pElem;
+    int rotate;
+    const char* displayName;
+
+    assert(pNode->Type() == TiXmlNode::ELEMENT);
+
+    /*
+     * Process attributes.  Right now they're all mandatory, but some of
+     * them could be defaulted (e.g. "rotate").
+     *
+     * [We should do some range-checking here.]
+     */
+    pElem = pNode->ToElement();
+    displayName = pElem->Attribute("display");
+    if (displayName == NULL)
+        goto missing;
+    if (pElem->Attribute("x", &mXOffset) == NULL)
+        goto missing;
+    if (pElem->Attribute("y", &mYOffset) == NULL)
+        goto missing;
+    if (pElem->Attribute("rotate", &rotate) == NULL)
+        goto missing;
+
+    switch (rotate) {
+    case 0:     mRotation = kRot0;      break;
+    case 90:    mRotation = kRot90;     break;
+    case 180:   mRotation = kRot180;    break;
+    case 270:   mRotation = kRot270;    break;
+    default:
+                fprintf(stderr, "SimCFG: unexpected value for rotation\n");
+                mRotation = kRotUnknown;
+                return false;
+    }
+
+    delete[] mDisplayName;
+    mDisplayName = android::strdupNew(displayName);
+
+    /*
+     * Process elements.
+     */
+    for (pChild = pNode->FirstChild(); pChild != NULL;
+        pChild = pChild->NextSibling())
+    {
+        if (pChild->Type() == TiXmlNode::COMMENT)
+            continue;
+
+        if (pChild->Type() == TiXmlNode::ELEMENT) {
+            if (strcasecmp(pChild->Value(), "image") == 0) {
+                if (!ProcessImage(pChild, directory))
+                    return false;
+            } else if (strcasecmp(pChild->Value(), "button") == 0) {
+                if (!ProcessButton(pChild, directory))
+                    return false;
+            } else {
+                fprintf(stderr,
+                    "SimCFG: Warning: unexpected elements in <display>\n");
+            }
+        } else {
+            fprintf(stderr, "SimCFG: Warning: unexpected stuff in <display>\n");
+        }
+    }
+
+    return true;
+
+missing:
+    fprintf(stderr,
+        "SimCFG: <view> requires display/x/y/rotate\n");
+    return false;
+}
+
+/*
+ * Handle <image src="zzz" x="123" y="123"/>.
+ */
+bool PhoneView::ProcessImage(TiXmlNode* pNode, const char* directory)
+{
+    TiXmlNode* pChild;
+    TiXmlElement* pElem;
+    int x, y;
+    const char* src;
+    LoadableImage tmpLimg;
+    android::String8 fileName;
+
+    pChild = pNode->FirstChild();
+    if (pChild != NULL) {
+        fprintf(stderr, "SimCFG: <image> is funky\n");
+        return false;
+    }
+
+    /*
+     * All attributes are mandatory.
+     */
+    pElem = pNode->ToElement();
+    src = pElem->Attribute("src");
+    if (src == NULL)
+        goto missing;
+    if (pElem->Attribute("x", &x) == NULL)
+        goto missing;
+    if (pElem->Attribute("y", &y) == NULL)
+        goto missing;
+
+    if (strncmp(src, kRelPathMagic, strlen(kRelPathMagic)) == 0) {
+        fileName = src + strlen(kRelPathMagic);
+    } else {
+        fileName = directory;
+        fileName += "/";
+        fileName += src;
+    }
+
+    tmpLimg.Create(fileName, x, y);
+    mImageList.push_back(tmpLimg);
+
+    return true;
+
+missing:
+    fprintf(stderr, "SimCFG: <image> requires src/x/y\n");
+    return false;
+}
+
+/*
+ * Handle <button keyCode="zzz" src="zzz" x="123" y="123"/> and
+ * <button keyCode="zzz"/>.
+ */
+bool PhoneView::ProcessButton(TiXmlNode* pNode, const char* directory)
+{
+    TiXmlNode* pChild;
+    TiXmlElement* pElem;
+    int x, y;
+    const char* keyCode;
+    const char* src;
+    PhoneButton tmpButton;
+    android::String8 fileName;
+
+    pChild = pNode->FirstChild();
+    if (pChild != NULL) {
+        fprintf(stderr, "SimCFG: button is funky\n");
+        return false;
+    }
+
+    /*
+     * Only keyCode is mandatory.  If they specify "src", then "x" and "y"
+     * are also required.
+     */
+    pElem = pNode->ToElement();
+    keyCode = pElem->Attribute("keyCode");
+    if (keyCode == NULL)
+        goto missing;
+
+    src = pElem->Attribute("src");
+    if (src != NULL) {
+        if (pElem->Attribute("x", &x) == NULL)
+            goto missing;
+        if (pElem->Attribute("y", &y) == NULL)
+            goto missing;
+    }
+
+    if (src == NULL)
+        tmpButton.Create(keyCode);
+    else {
+        if (strncmp(src, kRelPathMagic, strlen(kRelPathMagic)) == 0) {
+            fileName = src + strlen(kRelPathMagic);
+        } else {
+            fileName = directory;
+            fileName += "/";
+            fileName += src;
+        }
+        tmpButton.Create(keyCode, fileName, x, y);
+    }
+
+    mButtonList.push_back(tmpButton);
+
+    return true;
+
+missing:
+    fprintf(stderr, "SimCFG: <button> requires keycode and may have src/x/y\n");
+    return false;
+}
+
+
+/*
+ * Load all resources associated with the display.
+ */
+bool PhoneView::LoadResources(void)
+{
+    typedef List<LoadableImage>::iterator LIter;
+    typedef List<PhoneButton>::iterator BIter;
+
+    for (LIter ii = mImageList.begin(); ii != mImageList.end(); ++ii)
+        (*ii).LoadResources();
+    for (BIter ii = mButtonList.begin(); ii != mButtonList.end(); ++ii)
+        (*ii).LoadResources();
+    return true;
+}
+
+/*
+ * Unload all resources associated with the display.
+ */
+bool PhoneView::UnloadResources(void)
+{
+    typedef List<LoadableImage>::iterator LIter;
+    typedef List<PhoneButton>::iterator BIter;
+
+    for (LIter ii = mImageList.begin(); ii != mImageList.end(); ++ii)
+        (*ii).UnloadResources();
+    for (BIter ii = mButtonList.begin(); ii != mButtonList.end(); ++ii)
+        (*ii).UnloadResources();
+    return true;
+}
+
+
+/*
+ * Get the #of images.
+ */
+int PhoneView::GetBkgImageCount(void) const
+{
+    return mImageList.size();
+}
+
+/*
+ * Return the Nth entry.
+ */
+const LoadableImage* PhoneView::GetBkgImage(int idx) const
+{
+    typedef List<LoadableImage>::const_iterator Iter;
+
+    for (Iter ii = mImageList.begin(); ii != mImageList.end(); ++ii) {
+        if (!idx)
+            return &(*ii);
+        --idx;
+    }
+
+    return NULL;
+}
+
+
+/*
+ * Find the first button that covers the specified coordinates.
+ *
+ * The coordinates must be relative to the upper left corner of the
+ * phone image.
+ */
+PhoneButton* PhoneView::FindButtonHit(int x, int y)
+{
+    typedef List<PhoneButton>::iterator Iter;
+
+    for (Iter ii = mButtonList.begin(); ii != mButtonList.end(); ++ii) {
+        if ((*ii).CheckCollision(x, y))
+            return &(*ii);
+    }
+
+    return NULL;
+}
+
+/*
+ * Find the first button with a matching key code.
+ */
+PhoneButton* PhoneView::FindButtonByKey(KeyCode keyCode)
+{
+    typedef List<PhoneButton>::iterator Iter;
+
+    for (Iter ii = mButtonList.begin(); ii != mButtonList.end(); ++ii) {
+        if ((*ii).GetKeyCode() == keyCode)
+            return &(*ii);
+    }
+
+    return NULL;
+}
+
+
+/*
+ * ===========================================================================
+ *      PhoneMode
+ * ===========================================================================
+ */
+
+/*
+ * Process a <mode name="zzz"> chunk.
+ */
+bool PhoneMode::ProcessAndValidate(TiXmlNode* pNode, const char* directory)
+{
+    TiXmlNode* pChild;
+    const char* name;
+
+    assert(pNode->Type() == TiXmlNode::ELEMENT);
+
+    name = pNode->ToElement()->Attribute("name");
+    if (name == NULL) {
+        fprintf(stderr, "SimCFG: <mode> requires name attrib\n");
+        return false;
+    }
+    SetName(name);
+
+    for (pChild = pNode->FirstChild(); pChild != NULL;
+        pChild = pChild->NextSibling())
+    {
+        if (pChild->Type() == TiXmlNode::COMMENT)
+            continue;
+
+        if (pChild->Type() == TiXmlNode::ELEMENT &&
+            strcasecmp(pChild->Value(), "view") == 0)
+        {
+            PhoneView tmpDisplay;
+            bool result;
+
+            result = tmpDisplay.ProcessAndValidate(pChild, directory);
+            if (!result)
+                return false;
+
+            mViewList.push_back(tmpDisplay);
+        } else {
+            fprintf(stderr, "SimCFG: Warning: unexpected stuff in <mode>\n");
+        }
+    }
+
+    if (mViewList.size() == 0) {
+        fprintf(stderr, "SimCFG: no <view> entries found\n");
+        return false;
+    }
+
+    return true;
+}
+
+
+/*
+ * Load all resources associated with the phone.
+ */
+bool PhoneMode::LoadResources(void)
+{
+    typedef List<PhoneView>::iterator Iter;
+
+    for (Iter ii = mViewList.begin(); ii != mViewList.end(); ++ii)
+        (*ii).LoadResources();
+    return true;
+}
+
+/*
+ * Unload all resources associated with the phone.
+ */
+bool PhoneMode::UnloadResources(void)
+{
+    typedef List<PhoneView>::iterator Iter;
+
+    for (Iter ii = mViewList.begin(); ii != mViewList.end(); ++ii)
+        (*ii).UnloadResources();
+    return true;
+}
+
+
+/*
+ * Return the Nth entry.  [make this a Vector?]
+ */
+PhoneView* PhoneMode::GetPhoneView(int viewNum)
+{
+    typedef List<PhoneView>::iterator Iter;
+
+    for (Iter ii = mViewList.begin(); ii != mViewList.end(); ++ii) {
+        if (viewNum == 0)
+            return &(*ii);
+        --viewNum;
+    }
+    return NULL;
+}
+
+
+/*
+ * ===========================================================================
+ *      PhoneData
+ * ===========================================================================
+ */
+
+
+/*
+ * Look for a "layout.xml" in the specified directory.  If found, parse
+ * the contents out.
+ *
+ * Returns "true" on success, "false" on failure.
+ */
+bool PhoneData::Create(const char* directory)
+{
+    android::String8 fileName;
+
+    SetDirectory(directory);
+
+    fileName = directory;
+    fileName += "/";
+    fileName += PhoneCollection::kLayoutFile;
+
+#ifdef BEFORE_ASSET
+    TiXmlDocument doc(fileName);
+    if (!doc.LoadFile())
+#else
+    android::AssetManager* pAssetMgr = ((MyApp*)wxTheApp)->GetAssetManager();
+    TiXmlDocument doc;
+    android::Asset* pAsset;
+    bool result;
+
+    pAsset = pAssetMgr->open(fileName, Asset::ACCESS_STREAMING);
+    if (pAsset == NULL) {
+        fprintf(stderr, "Unable to open asset '%s'\n", (const char*) fileName);
+        return false;
+    } else {
+        //printf("--- opened asset '%s'\n",
+        //    (const char*) pAsset->getAssetSource());
+    }
+
+    /* TinyXml insists that the buffer be NULL-terminated... ugh */
+    char* buf = new char[pAsset->getLength() +1];
+    pAsset->read(buf, pAsset->getLength());
+    buf[pAsset->getLength()] = '\0';
+
+    delete pAsset;
+    result = doc.Parse(buf);
+    delete[] buf;
+
+    if (!result)
+#endif
+    {
+        fprintf(stderr, "SimCFG: ERROR: failed parsing '%s'\n",
+            (const char*) fileName);
+        if (doc.ErrorRow() != 0)
+            fprintf(stderr, "    XML: %s (row=%d col=%d)\n",
+                doc.ErrorDesc(), doc.ErrorRow(), doc.ErrorCol());
+        else
+            fprintf(stderr, "    XML: %s\n", doc.ErrorDesc());
+        return false;
+    }
+
+    if (!ProcessAndValidate(&doc)) {
+        fprintf(stderr, "SimCFG: ERROR: failed analyzing '%s'\n",
+            (const char*) fileName);
+        return false;
+    }
+
+    printf("SimCFG: loaded data from '%s'\n", (const char*) fileName);
+
+    return true;
+}
+
+/*
+ * TinyXml has loaded and parsed the XML document for us.  We need to
+ * run through the DOM tree, pull out the interesting bits, and make
+ * sure the stuff we need is present.
+ *
+ * Returns "true" on success, "false" on failure.
+ */
+bool PhoneData::ProcessAndValidate(TiXmlDocument* pDoc)
+{
+    bool deviceFound = false;
+    TiXmlNode* pChild;
+
+    assert(pDoc->Type() == TiXmlNode::DOCUMENT);
+
+    for (pChild = pDoc->FirstChild(); pChild != NULL;
+        pChild = pChild->NextSibling())
+    {
+        /*
+         * Find the <device> entry.  There should be exactly one.
+         */
+        if (pChild->Type() == TiXmlNode::ELEMENT) {
+            if (strcasecmp(pChild->Value(), "device") != 0) {
+                fprintf(stderr,
+                    "SimCFG: Warning: unexpected element '%s' at top level\n",
+                    pChild->Value());
+                continue;
+            }
+            if (deviceFound) {
+                fprintf(stderr, "SimCFG: one <device> per customer\n");
+                return false;
+            }
+
+            bool result = ProcessDevice(pChild);
+            if (!result)
+                return false;
+            deviceFound = true;
+        }
+    }
+
+    if (!deviceFound) {
+        fprintf(stderr, "SimCFG: no <device> section found\n");
+        return false;
+    }
+
+    return true;
+}
+
+/*
+ * Process a <device name="zzz"> chunk.
+ */
+bool PhoneData::ProcessDevice(TiXmlNode* pNode)
+{
+    TiXmlNode* pChild;
+    const char* name;
+
+    assert(pNode->Type() == TiXmlNode::ELEMENT);
+
+    name = pNode->ToElement()->Attribute("name");
+    if (name == NULL) {
+        fprintf(stderr, "SimCFG: <device> requires name attrib\n");
+        return false;
+    }
+    SetName(name);
+
+    /*
+     * Walk through the children and find interesting stuff.
+     *
+     * Might be more correct to process all <display> entries and
+     * then process all <view> entries, since <view> has "pointers"
+     * to <display>.  We're deferring the lookup until later, though,
+     * so for now it doesn't really matter.
+     */
+    for (pChild = pNode->FirstChild(); pChild != NULL;
+        pChild = pChild->NextSibling())
+    {
+        bool result;
+
+        if (pChild->Type() == TiXmlNode::COMMENT)
+            continue;
+
+        if (pChild->Type() == TiXmlNode::ELEMENT &&
+            strcasecmp(pChild->Value(), "title") == 0)
+        {
+            result = ProcessTitle(pChild);
+            if (!result)
+                return false;
+        } else if (pChild->Type() == TiXmlNode::ELEMENT &&
+            strcasecmp(pChild->Value(), "display") == 0)
+        {
+            PhoneDisplay tmpDisplay;
+
+            result = tmpDisplay.ProcessAndValidate(pChild);
+            if (!result)
+                return false;
+
+            mDisplayList.push_back(tmpDisplay);
+        } else if (pChild->Type() == TiXmlNode::ELEMENT &&
+            strcasecmp(pChild->Value(), "keyboard") == 0)
+        {
+            PhoneKeyboard tmpKeyboard;
+            result = tmpKeyboard.ProcessAndValidate(pChild);
+            if (!result)
+                return false;
+                
+            mKeyboardList.push_back(tmpKeyboard);           
+        } else if (pChild->Type() == TiXmlNode::ELEMENT &&
+            strcasecmp(pChild->Value(), "mode") == 0)
+        {
+            PhoneMode tmpMode;
+
+            result = tmpMode.ProcessAndValidate(pChild, mDirectory);
+            if (!result)
+                return false;
+
+            mModeList.push_back(tmpMode);
+        } else {
+            fprintf(stderr, "SimCFG: Warning: unexpected stuff in <device>\n");
+        }
+    }
+
+    if (mDisplayList.size() == 0) {
+        fprintf(stderr, "SimCFG: no <display> entries found\n");
+        return false;
+    }
+    if (mModeList.size() == 0) {
+        fprintf(stderr, "SimCFG: no <mode> entries found\n");
+        return false;
+    }
+
+    return true;
+}
+
+/*
+ * Handle <title>.
+ */
+bool PhoneData::ProcessTitle(TiXmlNode* pNode)
+{
+    TiXmlNode* pChild;
+
+    pChild = pNode->FirstChild();
+    if (pChild->Type() != TiXmlNode::TEXT) {
+        fprintf(stderr, "SimCFG: title is funky\n");
+        return false;
+    }
+
+    SetTitle(pChild->Value());
+    return true;
+}
+
+
+/*
+ * Load all resources associated with the phone.
+ */
+bool PhoneData::LoadResources(void)
+{
+    typedef List<PhoneMode>::iterator Iter;
+
+    for (Iter ii = mModeList.begin(); ii != mModeList.end(); ++ii)
+        (*ii).LoadResources();
+    return true;
+}
+
+/*
+ * Unload all resources associated with the phone.
+ */
+bool PhoneData::UnloadResources(void)
+{
+    typedef List<PhoneMode>::iterator Iter;
+
+    for (Iter ii = mModeList.begin(); ii != mModeList.end(); ++ii)
+        (*ii).UnloadResources();
+    return true;
+}
+
+
+/*
+ * Return the PhoneMode entry with the matching name.
+ *
+ * Returns NULL if no match was found.
+ */
+PhoneMode* PhoneData::GetPhoneMode(const char* modeName)
+{
+    typedef List<PhoneMode>::iterator Iter;
+
+    for (Iter ii = mModeList.begin(); ii != mModeList.end(); ++ii) {
+        if (strcmp((*ii).GetName(), modeName) == 0)
+            return &(*ii);
+    }
+    return NULL;
+}
+
+/*
+ * Return the Nth phone mode entry.
+ */
+PhoneMode* PhoneData::GetPhoneMode(int idx)
+{
+    typedef List<PhoneMode>::iterator Iter;
+
+    for (Iter ii = mModeList.begin(); ii != mModeList.end(); ++ii) {
+        if (!idx)
+            return &(*ii);
+        --idx;
+    }
+    return NULL;
+}
+
+
+/*
+ * Return the PhoneDisplay entry with the matching name.
+ *
+ * Returns NULL if no match was found.
+ */
+PhoneDisplay* PhoneData::GetPhoneDisplay(const char* dispName)
+{
+    typedef List<PhoneDisplay>::iterator Iter;
+
+    for (Iter ii = mDisplayList.begin(); ii != mDisplayList.end(); ++ii) {
+        if (strcmp((*ii).GetName(), dispName) == 0)
+            return &(*ii);
+    }
+    return NULL;
+}
+
+/*
+ * Return the Nth phone mode entry.
+ */
+PhoneDisplay* PhoneData::GetPhoneDisplay(int idx)
+{
+    typedef List<PhoneDisplay>::iterator Iter;
+
+    for (Iter ii = mDisplayList.begin(); ii != mDisplayList.end(); ++ii) {
+        if (!idx)
+            return &(*ii);
+        --idx;
+    }
+    return NULL;
+}
+
+/*
+ * Find the PhoneDisplay entry with the matching name, and return its index.
+ *
+ * Returns -1 if the entry wasn't found.
+ */
+int PhoneData::GetPhoneDisplayIndex(const char* dispName)
+{
+    typedef List<PhoneDisplay>::iterator Iter;
+    int idx = 0;
+
+    for (Iter ii = mDisplayList.begin(); ii != mDisplayList.end(); ++ii) {
+        if (strcmp((*ii).GetName(), dispName) == 0)
+            return idx;
+        idx++;
+    }
+    return -1;
+}
+
+
+/*
+ * Return the Nth phone keyboard entry.
+ */
+PhoneKeyboard* PhoneData::GetPhoneKeyboard(int idx)
+{
+    typedef List<PhoneKeyboard>::iterator Iter;
+
+    for (Iter ii = mKeyboardList.begin(); ii != mKeyboardList.end(); ++ii) {
+        if (!idx)
+            return &(*ii);
+        --idx;
+    }
+    return NULL;
+}