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 } 869