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 */
ProcessAndValidate(TiXmlNode * pNode)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 */
ProcessAndValidate(TiXmlNode * pNode)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 */
IsCompatible(PhoneDisplay * pDisplay1,PhoneDisplay * pDisplay2)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 */
ProcessAndValidate(TiXmlNode * pNode,const char * directory)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 */
ProcessImage(TiXmlNode * pNode,const char * directory)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 */
ProcessButton(TiXmlNode * pNode,const char * directory)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 */
LoadResources(void)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 */
UnloadResources(void)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 */
GetBkgImageCount(void) const373 int PhoneView::GetBkgImageCount(void) const
374 {
375 return mImageList.size();
376 }
377
378 /*
379 * Return the Nth entry.
380 */
GetBkgImage(int idx) const381 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 */
FindButtonHit(int x,int y)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 */
FindButtonByKey(int32_t keyCode)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 */
ProcessAndValidate(TiXmlNode * pNode,const char * directory)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 */
LoadResources(void)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 */
UnloadResources(void)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 */
GetPhoneView(int viewNum)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 */
Create(const char * directory)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 */
ProcessAndValidate(TiXmlDocument * pDoc)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 */
ProcessDevice(TiXmlNode * pNode)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 */
ProcessTitle(TiXmlNode * pNode)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 */
LoadResources(void)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 */
UnloadResources(void)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 */
GetPhoneMode(const char * modeName)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 */
GetPhoneMode(int idx)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 */
GetPhoneDisplay(const char * dispName)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 */
GetPhoneDisplay(int idx)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 */
GetPhoneDisplayIndex(const char * dispName)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 */
GetPhoneKeyboard(int idx)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 }
869