OSDN Git Service

Merge "Update samples to use new getMotionRanges() API." into honeycomb-mr1
[android-x86/development.git] / simulator / app / PhoneData.cpp
1 //
2 // Copyright 2005 The Android Open Source Project
3 //
4 // Simulated device data.
5 //
6
7 // For compilers that support precompilation, include "wx/wx.h".
8 #include "wx/wxprec.h"
9
10 // Otherwise, include all standard headers
11 #ifndef WX_PRECOMP
12 # include "wx/wx.h"
13 #endif
14 #include "wx/image.h"   // needed for Windows build
15
16
17 #include "PhoneData.h"
18 #include "PhoneButton.h"
19 #include "PhoneCollection.h"
20 #include "MyApp.h"
21
22 #include "utils.h"
23 #include <utils/AssetManager.h>
24 #include <utils/String8.h>
25
26 #include "tinyxml.h"
27
28 #include <stdlib.h>
29 #include <unistd.h>
30 #include <stdio.h>
31 #include <string.h>
32 #include <assert.h>
33
34 using namespace android;
35
36 /* image relative path hack */
37 static const char* kRelPathMagic = "::/";
38
39
40 /*
41  * ===========================================================================
42  *      PhoneKeyboard
43  * ===========================================================================
44  */
45
46 /*
47  * Load a <keyboard> chunk.
48  */
49 bool PhoneKeyboard::ProcessAndValidate(TiXmlNode* pNode)
50 {
51     //TiXmlNode* pChild;
52     TiXmlElement* pElem;
53     int qwerty = 0;
54     
55     assert(pNode->Type() == TiXmlNode::ELEMENT);
56
57     pElem = pNode->ToElement();
58     pElem->Attribute("qwerty", &qwerty);
59     const char *kmap = pElem->Attribute("keycharmap");
60
61     if (qwerty == 1) {
62         printf("############## PhoneKeyboard::ProcessAndValidate: qwerty = true!\n");
63         mQwerty = true;
64     }
65
66     if (kmap != NULL) {
67         printf("############## PhoneKeyboard::ProcessAndValidate: keycharmap = %s\n", kmap);
68         mKeyMap = strdup(kmap);
69     }
70     
71     return true;
72 }
73
74
75 /*
76  * ===========================================================================
77  *      PhoneDisplay
78  * ===========================================================================
79  */
80
81 /*
82  * Load a <display> chunk.
83  */
84 bool PhoneDisplay::ProcessAndValidate(TiXmlNode* pNode)
85 {
86     //TiXmlNode* pChild;
87     TiXmlElement* pElem;
88     const char* name;
89     const char* format;
90
91     assert(pNode->Type() == TiXmlNode::ELEMENT);
92
93     /*
94      * Process attributes.  Right now they're all mandatory, but some of
95      * them could be defaulted (e.g. "rotate").
96      *
97      * [We should do some range-checking here.]
98      */
99     pElem = pNode->ToElement();
100     name = pElem->Attribute("name");
101     if (name == NULL)
102         goto missing;
103     if (pElem->Attribute("width", &mWidth) == NULL)
104         goto missing;
105     if (pElem->Attribute("height", &mHeight) == NULL)
106         goto missing;
107     if (pElem->Attribute("refresh", &mRefresh) == NULL)
108         goto missing;
109     format = pElem->Attribute("format");
110     if (format == NULL)
111         goto missing;
112
113     delete[] mName;
114     mName = strdupNew(name);
115
116     if (strcasecmp(format, "rgb565") == 0) {
117         mFormat = android::PIXEL_FORMAT_RGB_565;
118     } else {
119         fprintf(stderr, "SimCFG: unexpected value for display format\n");
120         return false;
121     }
122
123     return true;
124
125 missing:
126     fprintf(stderr,
127         "SimCFG: <display> requires name/width/height/format/refresh\n");
128     return false;
129 }
130
131
132 /*
133  * Returns "true" if the two displays are compatible, "false" if not.
134  *
135  * Compatibility means they have the same resolution, format, refresh
136  * rate, and so on.  Anything transmitted to the runtime as part of the
137  * initial configuration setup should be tested.
138  */
139 /*static*/ bool PhoneDisplay::IsCompatible(PhoneDisplay* pDisplay1,
140     PhoneDisplay* pDisplay2)
141 {
142     return (pDisplay1->mWidth == pDisplay2->mWidth &&
143             pDisplay1->mHeight == pDisplay2->mHeight &&
144             pDisplay1->mFormat == pDisplay2->mFormat &&
145             pDisplay1->mRefresh == pDisplay2->mRefresh);
146 }
147
148
149 /*
150  * ===========================================================================
151  *      PhoneView
152  * ===========================================================================
153  */
154
155 /*
156  * Load a <view> chunk.
157  */
158 bool PhoneView::ProcessAndValidate(TiXmlNode* pNode, const char* directory)
159 {
160     TiXmlNode* pChild;
161     TiXmlElement* pElem;
162     int rotate;
163     const char* displayName;
164
165     assert(pNode->Type() == TiXmlNode::ELEMENT);
166
167     /*
168      * Process attributes.  Right now they're all mandatory, but some of
169      * them could be defaulted (e.g. "rotate").
170      *
171      * [We should do some range-checking here.]
172      */
173     pElem = pNode->ToElement();
174     displayName = pElem->Attribute("display");
175     if (displayName == NULL)
176         goto missing;
177     if (pElem->Attribute("x", &mXOffset) == NULL)
178         goto missing;
179     if (pElem->Attribute("y", &mYOffset) == NULL)
180         goto missing;
181     if (pElem->Attribute("rotate", &rotate) == NULL)
182         goto missing;
183
184     switch (rotate) {
185     case 0:     mRotation = kRot0;      break;
186     case 90:    mRotation = kRot90;     break;
187     case 180:   mRotation = kRot180;    break;
188     case 270:   mRotation = kRot270;    break;
189     default:
190                 fprintf(stderr, "SimCFG: unexpected value for rotation\n");
191                 mRotation = kRotUnknown;
192                 return false;
193     }
194
195     delete[] mDisplayName;
196     mDisplayName = android::strdupNew(displayName);
197
198     /*
199      * Process elements.
200      */
201     for (pChild = pNode->FirstChild(); pChild != NULL;
202         pChild = pChild->NextSibling())
203     {
204         if (pChild->Type() == TiXmlNode::COMMENT)
205             continue;
206
207         if (pChild->Type() == TiXmlNode::ELEMENT) {
208             if (strcasecmp(pChild->Value(), "image") == 0) {
209                 if (!ProcessImage(pChild, directory))
210                     return false;
211             } else if (strcasecmp(pChild->Value(), "button") == 0) {
212                 if (!ProcessButton(pChild, directory))
213                     return false;
214             } else {
215                 fprintf(stderr,
216                     "SimCFG: Warning: unexpected elements in <display>\n");
217             }
218         } else {
219             fprintf(stderr, "SimCFG: Warning: unexpected stuff in <display>\n");
220         }
221     }
222
223     return true;
224
225 missing:
226     fprintf(stderr,
227         "SimCFG: <view> requires display/x/y/rotate\n");
228     return false;
229 }
230
231 /*
232  * Handle <image src="zzz" x="123" y="123"/>.
233  */
234 bool PhoneView::ProcessImage(TiXmlNode* pNode, const char* directory)
235 {
236     TiXmlNode* pChild;
237     TiXmlElement* pElem;
238     int x, y;
239     const char* src;
240     LoadableImage tmpLimg;
241     android::String8 fileName;
242
243     pChild = pNode->FirstChild();
244     if (pChild != NULL) {
245         fprintf(stderr, "SimCFG: <image> is funky\n");
246         return false;
247     }
248
249     /*
250      * All attributes are mandatory.
251      */
252     pElem = pNode->ToElement();
253     src = pElem->Attribute("src");
254     if (src == NULL)
255         goto missing;
256     if (pElem->Attribute("x", &x) == NULL)
257         goto missing;
258     if (pElem->Attribute("y", &y) == NULL)
259         goto missing;
260
261     if (strncmp(src, kRelPathMagic, strlen(kRelPathMagic)) == 0) {
262         fileName = src + strlen(kRelPathMagic);
263     } else {
264         fileName = directory;
265         fileName += "/";
266         fileName += src;
267     }
268
269     tmpLimg.Create(fileName, x, y);
270     mImageList.push_back(tmpLimg);
271
272     return true;
273
274 missing:
275     fprintf(stderr, "SimCFG: <image> requires src/x/y\n");
276     return false;
277 }
278
279 /*
280  * Handle <button keyCode="zzz" src="zzz" x="123" y="123"/> and
281  * <button keyCode="zzz"/>.
282  */
283 bool PhoneView::ProcessButton(TiXmlNode* pNode, const char* directory)
284 {
285     TiXmlNode* pChild;
286     TiXmlElement* pElem;
287     int x, y;
288     const char* keyCode;
289     const char* src;
290     PhoneButton tmpButton;
291     android::String8 fileName;
292
293     pChild = pNode->FirstChild();
294     if (pChild != NULL) {
295         fprintf(stderr, "SimCFG: button is funky\n");
296         return false;
297     }
298
299     /*
300      * Only keyCode is mandatory.  If they specify "src", then "x" and "y"
301      * are also required.
302      */
303     pElem = pNode->ToElement();
304     keyCode = pElem->Attribute("keyCode");
305     if (keyCode == NULL)
306         goto missing;
307
308     src = pElem->Attribute("src");
309     if (src != NULL) {
310         if (pElem->Attribute("x", &x) == NULL)
311             goto missing;
312         if (pElem->Attribute("y", &y) == NULL)
313             goto missing;
314     }
315
316     if (src == NULL)
317         tmpButton.Create(keyCode);
318     else {
319         if (strncmp(src, kRelPathMagic, strlen(kRelPathMagic)) == 0) {
320             fileName = src + strlen(kRelPathMagic);
321         } else {
322             fileName = directory;
323             fileName += "/";
324             fileName += src;
325         }
326         tmpButton.Create(keyCode, fileName, x, y);
327     }
328
329     mButtonList.push_back(tmpButton);
330
331     return true;
332
333 missing:
334     fprintf(stderr, "SimCFG: <button> requires keycode and may have src/x/y\n");
335     return false;
336 }
337
338
339 /*
340  * Load all resources associated with the display.
341  */
342 bool PhoneView::LoadResources(void)
343 {
344     typedef List<LoadableImage>::iterator LIter;
345     typedef List<PhoneButton>::iterator BIter;
346
347     for (LIter ii = mImageList.begin(); ii != mImageList.end(); ++ii)
348         (*ii).LoadResources();
349     for (BIter ii = mButtonList.begin(); ii != mButtonList.end(); ++ii)
350         (*ii).LoadResources();
351     return true;
352 }
353
354 /*
355  * Unload all resources associated with the display.
356  */
357 bool PhoneView::UnloadResources(void)
358 {
359     typedef List<LoadableImage>::iterator LIter;
360     typedef List<PhoneButton>::iterator BIter;
361
362     for (LIter ii = mImageList.begin(); ii != mImageList.end(); ++ii)
363         (*ii).UnloadResources();
364     for (BIter ii = mButtonList.begin(); ii != mButtonList.end(); ++ii)
365         (*ii).UnloadResources();
366     return true;
367 }
368
369
370 /*
371  * Get the #of images.
372  */
373 int PhoneView::GetBkgImageCount(void) const
374 {
375     return mImageList.size();
376 }
377
378 /*
379  * Return the Nth entry.
380  */
381 const LoadableImage* PhoneView::GetBkgImage(int idx) const
382 {
383     typedef List<LoadableImage>::const_iterator Iter;
384
385     for (Iter ii = mImageList.begin(); ii != mImageList.end(); ++ii) {
386         if (!idx)
387             return &(*ii);
388         --idx;
389     }
390
391     return NULL;
392 }
393
394
395 /*
396  * Find the first button that covers the specified coordinates.
397  *
398  * The coordinates must be relative to the upper left corner of the
399  * phone image.
400  */
401 PhoneButton* PhoneView::FindButtonHit(int x, int y)
402 {
403     typedef List<PhoneButton>::iterator Iter;
404
405     for (Iter ii = mButtonList.begin(); ii != mButtonList.end(); ++ii) {
406         if ((*ii).CheckCollision(x, y))
407             return &(*ii);
408     }
409
410     return NULL;
411 }
412
413 /*
414  * Find the first button with a matching key code.
415  */
416 PhoneButton* PhoneView::FindButtonByKey(int32_t keyCode)
417 {
418     typedef List<PhoneButton>::iterator Iter;
419
420     for (Iter ii = mButtonList.begin(); ii != mButtonList.end(); ++ii) {
421         if ((*ii).GetKeyCode() == keyCode)
422             return &(*ii);
423     }
424
425     return NULL;
426 }
427
428
429 /*
430  * ===========================================================================
431  *      PhoneMode
432  * ===========================================================================
433  */
434
435 /*
436  * Process a <mode name="zzz"> chunk.
437  */
438 bool PhoneMode::ProcessAndValidate(TiXmlNode* pNode, const char* directory)
439 {
440     TiXmlNode* pChild;
441     const char* name;
442
443     assert(pNode->Type() == TiXmlNode::ELEMENT);
444
445     name = pNode->ToElement()->Attribute("name");
446     if (name == NULL) {
447         fprintf(stderr, "SimCFG: <mode> requires name attrib\n");
448         return false;
449     }
450     SetName(name);
451
452     for (pChild = pNode->FirstChild(); pChild != NULL;
453         pChild = pChild->NextSibling())
454     {
455         if (pChild->Type() == TiXmlNode::COMMENT)
456             continue;
457
458         if (pChild->Type() == TiXmlNode::ELEMENT &&
459             strcasecmp(pChild->Value(), "view") == 0)
460         {
461             PhoneView tmpDisplay;
462             bool result;
463
464             result = tmpDisplay.ProcessAndValidate(pChild, directory);
465             if (!result)
466                 return false;
467
468             mViewList.push_back(tmpDisplay);
469         } else {
470             fprintf(stderr, "SimCFG: Warning: unexpected stuff in <mode>\n");
471         }
472     }
473
474     if (mViewList.size() == 0) {
475         fprintf(stderr, "SimCFG: no <view> entries found\n");
476         return false;
477     }
478
479     return true;
480 }
481
482
483 /*
484  * Load all resources associated with the phone.
485  */
486 bool PhoneMode::LoadResources(void)
487 {
488     typedef List<PhoneView>::iterator Iter;
489
490     for (Iter ii = mViewList.begin(); ii != mViewList.end(); ++ii)
491         (*ii).LoadResources();
492     return true;
493 }
494
495 /*
496  * Unload all resources associated with the phone.
497  */
498 bool PhoneMode::UnloadResources(void)
499 {
500     typedef List<PhoneView>::iterator Iter;
501
502     for (Iter ii = mViewList.begin(); ii != mViewList.end(); ++ii)
503         (*ii).UnloadResources();
504     return true;
505 }
506
507
508 /*
509  * Return the Nth entry.  [make this a Vector?]
510  */
511 PhoneView* PhoneMode::GetPhoneView(int viewNum)
512 {
513     typedef List<PhoneView>::iterator Iter;
514
515     for (Iter ii = mViewList.begin(); ii != mViewList.end(); ++ii) {
516         if (viewNum == 0)
517             return &(*ii);
518         --viewNum;
519     }
520     return NULL;
521 }
522
523
524 /*
525  * ===========================================================================
526  *      PhoneData
527  * ===========================================================================
528  */
529
530
531 /*
532  * Look for a "layout.xml" in the specified directory.  If found, parse
533  * the contents out.
534  *
535  * Returns "true" on success, "false" on failure.
536  */
537 bool PhoneData::Create(const char* directory)
538 {
539     android::String8 fileName;
540
541     SetDirectory(directory);
542
543     fileName = directory;
544     fileName += "/";
545     fileName += PhoneCollection::kLayoutFile;
546
547 #ifdef BEFORE_ASSET
548     TiXmlDocument doc(fileName);
549     if (!doc.LoadFile())
550 #else
551     android::AssetManager* pAssetMgr = ((MyApp*)wxTheApp)->GetAssetManager();
552     TiXmlDocument doc;
553     android::Asset* pAsset;
554     bool result;
555
556     pAsset = pAssetMgr->open(fileName, Asset::ACCESS_STREAMING);
557     if (pAsset == NULL) {
558         fprintf(stderr, "Unable to open asset '%s'\n", (const char*) fileName);
559         return false;
560     } else {
561         //printf("--- opened asset '%s'\n",
562         //    (const char*) pAsset->getAssetSource());
563     }
564
565     /* TinyXml insists that the buffer be NULL-terminated... ugh */
566     char* buf = new char[pAsset->getLength() +1];
567     pAsset->read(buf, pAsset->getLength());
568     buf[pAsset->getLength()] = '\0';
569
570     delete pAsset;
571     result = doc.Parse(buf);
572     delete[] buf;
573
574     if (!result)
575 #endif
576     {
577         fprintf(stderr, "SimCFG: ERROR: failed parsing '%s'\n",
578             (const char*) fileName);
579         if (doc.ErrorRow() != 0)
580             fprintf(stderr, "    XML: %s (row=%d col=%d)\n",
581                 doc.ErrorDesc(), doc.ErrorRow(), doc.ErrorCol());
582         else
583             fprintf(stderr, "    XML: %s\n", doc.ErrorDesc());
584         return false;
585     }
586
587     if (!ProcessAndValidate(&doc)) {
588         fprintf(stderr, "SimCFG: ERROR: failed analyzing '%s'\n",
589             (const char*) fileName);
590         return false;
591     }
592
593     printf("SimCFG: loaded data from '%s'\n", (const char*) fileName);
594
595     return true;
596 }
597
598 /*
599  * TinyXml has loaded and parsed the XML document for us.  We need to
600  * run through the DOM tree, pull out the interesting bits, and make
601  * sure the stuff we need is present.
602  *
603  * Returns "true" on success, "false" on failure.
604  */
605 bool PhoneData::ProcessAndValidate(TiXmlDocument* pDoc)
606 {
607     bool deviceFound = false;
608     TiXmlNode* pChild;
609
610     assert(pDoc->Type() == TiXmlNode::DOCUMENT);
611
612     for (pChild = pDoc->FirstChild(); pChild != NULL;
613         pChild = pChild->NextSibling())
614     {
615         /*
616          * Find the <device> entry.  There should be exactly one.
617          */
618         if (pChild->Type() == TiXmlNode::ELEMENT) {
619             if (strcasecmp(pChild->Value(), "device") != 0) {
620                 fprintf(stderr,
621                     "SimCFG: Warning: unexpected element '%s' at top level\n",
622                     pChild->Value());
623                 continue;
624             }
625             if (deviceFound) {
626                 fprintf(stderr, "SimCFG: one <device> per customer\n");
627                 return false;
628             }
629
630             bool result = ProcessDevice(pChild);
631             if (!result)
632                 return false;
633             deviceFound = true;
634         }
635     }
636
637     if (!deviceFound) {
638         fprintf(stderr, "SimCFG: no <device> section found\n");
639         return false;
640     }
641
642     return true;
643 }
644
645 /*
646  * Process a <device name="zzz"> chunk.
647  */
648 bool PhoneData::ProcessDevice(TiXmlNode* pNode)
649 {
650     TiXmlNode* pChild;
651     const char* name;
652
653     assert(pNode->Type() == TiXmlNode::ELEMENT);
654
655     name = pNode->ToElement()->Attribute("name");
656     if (name == NULL) {
657         fprintf(stderr, "SimCFG: <device> requires name attrib\n");
658         return false;
659     }
660     SetName(name);
661
662     /*
663      * Walk through the children and find interesting stuff.
664      *
665      * Might be more correct to process all <display> entries and
666      * then process all <view> entries, since <view> has "pointers"
667      * to <display>.  We're deferring the lookup until later, though,
668      * so for now it doesn't really matter.
669      */
670     for (pChild = pNode->FirstChild(); pChild != NULL;
671         pChild = pChild->NextSibling())
672     {
673         bool result;
674
675         if (pChild->Type() == TiXmlNode::COMMENT)
676             continue;
677
678         if (pChild->Type() == TiXmlNode::ELEMENT &&
679             strcasecmp(pChild->Value(), "title") == 0)
680         {
681             result = ProcessTitle(pChild);
682             if (!result)
683                 return false;
684         } else if (pChild->Type() == TiXmlNode::ELEMENT &&
685             strcasecmp(pChild->Value(), "display") == 0)
686         {
687             PhoneDisplay tmpDisplay;
688
689             result = tmpDisplay.ProcessAndValidate(pChild);
690             if (!result)
691                 return false;
692
693             mDisplayList.push_back(tmpDisplay);
694         } else if (pChild->Type() == TiXmlNode::ELEMENT &&
695             strcasecmp(pChild->Value(), "keyboard") == 0)
696         {
697             PhoneKeyboard tmpKeyboard;
698             result = tmpKeyboard.ProcessAndValidate(pChild);
699             if (!result)
700                 return false;
701                 
702             mKeyboardList.push_back(tmpKeyboard);           
703         } else if (pChild->Type() == TiXmlNode::ELEMENT &&
704             strcasecmp(pChild->Value(), "mode") == 0)
705         {
706             PhoneMode tmpMode;
707
708             result = tmpMode.ProcessAndValidate(pChild, mDirectory);
709             if (!result)
710                 return false;
711
712             mModeList.push_back(tmpMode);
713         } else {
714             fprintf(stderr, "SimCFG: Warning: unexpected stuff in <device>\n");
715         }
716     }
717
718     if (mDisplayList.size() == 0) {
719         fprintf(stderr, "SimCFG: no <display> entries found\n");
720         return false;
721     }
722     if (mModeList.size() == 0) {
723         fprintf(stderr, "SimCFG: no <mode> entries found\n");
724         return false;
725     }
726
727     return true;
728 }
729
730 /*
731  * Handle <title>.
732  */
733 bool PhoneData::ProcessTitle(TiXmlNode* pNode)
734 {
735     TiXmlNode* pChild;
736
737     pChild = pNode->FirstChild();
738     if (pChild->Type() != TiXmlNode::TEXT) {
739         fprintf(stderr, "SimCFG: title is funky\n");
740         return false;
741     }
742
743     SetTitle(pChild->Value());
744     return true;
745 }
746
747
748 /*
749  * Load all resources associated with the phone.
750  */
751 bool PhoneData::LoadResources(void)
752 {
753     typedef List<PhoneMode>::iterator Iter;
754
755     for (Iter ii = mModeList.begin(); ii != mModeList.end(); ++ii)
756         (*ii).LoadResources();
757     return true;
758 }
759
760 /*
761  * Unload all resources associated with the phone.
762  */
763 bool PhoneData::UnloadResources(void)
764 {
765     typedef List<PhoneMode>::iterator Iter;
766
767     for (Iter ii = mModeList.begin(); ii != mModeList.end(); ++ii)
768         (*ii).UnloadResources();
769     return true;
770 }
771
772
773 /*
774  * Return the PhoneMode entry with the matching name.
775  *
776  * Returns NULL if no match was found.
777  */
778 PhoneMode* PhoneData::GetPhoneMode(const char* modeName)
779 {
780     typedef List<PhoneMode>::iterator Iter;
781
782     for (Iter ii = mModeList.begin(); ii != mModeList.end(); ++ii) {
783         if (strcmp((*ii).GetName(), modeName) == 0)
784             return &(*ii);
785     }
786     return NULL;
787 }
788
789 /*
790  * Return the Nth phone mode entry.
791  */
792 PhoneMode* PhoneData::GetPhoneMode(int idx)
793 {
794     typedef List<PhoneMode>::iterator Iter;
795
796     for (Iter ii = mModeList.begin(); ii != mModeList.end(); ++ii) {
797         if (!idx)
798             return &(*ii);
799         --idx;
800     }
801     return NULL;
802 }
803
804
805 /*
806  * Return the PhoneDisplay entry with the matching name.
807  *
808  * Returns NULL if no match was found.
809  */
810 PhoneDisplay* PhoneData::GetPhoneDisplay(const char* dispName)
811 {
812     typedef List<PhoneDisplay>::iterator Iter;
813
814     for (Iter ii = mDisplayList.begin(); ii != mDisplayList.end(); ++ii) {
815         if (strcmp((*ii).GetName(), dispName) == 0)
816             return &(*ii);
817     }
818     return NULL;
819 }
820
821 /*
822  * Return the Nth phone mode entry.
823  */
824 PhoneDisplay* PhoneData::GetPhoneDisplay(int idx)
825 {
826     typedef List<PhoneDisplay>::iterator Iter;
827
828     for (Iter ii = mDisplayList.begin(); ii != mDisplayList.end(); ++ii) {
829         if (!idx)
830             return &(*ii);
831         --idx;
832     }
833     return NULL;
834 }
835
836 /*
837  * Find the PhoneDisplay entry with the matching name, and return its index.
838  *
839  * Returns -1 if the entry wasn't found.
840  */
841 int PhoneData::GetPhoneDisplayIndex(const char* dispName)
842 {
843     typedef List<PhoneDisplay>::iterator Iter;
844     int idx = 0;
845
846     for (Iter ii = mDisplayList.begin(); ii != mDisplayList.end(); ++ii) {
847         if (strcmp((*ii).GetName(), dispName) == 0)
848             return idx;
849         idx++;
850     }
851     return -1;
852 }
853
854
855 /*
856  * Return the Nth phone keyboard entry.
857  */
858 PhoneKeyboard* PhoneData::GetPhoneKeyboard(int idx)
859 {
860     typedef List<PhoneKeyboard>::iterator Iter;
861
862     for (Iter ii = mKeyboardList.begin(); ii != mKeyboardList.end(); ++ii) {
863         if (!idx)
864             return &(*ii);
865         --idx;
866     }
867     return NULL;
868 }