2 // Copyright 2005 The Android Open Source Project
4 // Simulated device data.
7 // For compilers that support precompilation, include "wx/wx.h".
10 // Otherwise, include all standard headers
14 #include "wx/image.h" // needed for Windows build
17 #include "PhoneData.h"
18 #include "PhoneButton.h"
19 #include "PhoneCollection.h"
23 #include <utils/AssetManager.h>
24 #include <utils/String8.h>
34 using namespace android;
36 /* image relative path hack */
37 static const char* kRelPathMagic = "::/";
41 * ===========================================================================
43 * ===========================================================================
47 * Load a <keyboard> chunk.
49 bool PhoneKeyboard::ProcessAndValidate(TiXmlNode* pNode)
55 assert(pNode->Type() == TiXmlNode::ELEMENT);
57 pElem = pNode->ToElement();
58 pElem->Attribute("qwerty", &qwerty);
59 const char *kmap = pElem->Attribute("keycharmap");
62 printf("############## PhoneKeyboard::ProcessAndValidate: qwerty = true!\n");
67 printf("############## PhoneKeyboard::ProcessAndValidate: keycharmap = %s\n", kmap);
68 mKeyMap = strdup(kmap);
76 * ===========================================================================
78 * ===========================================================================
82 * Load a <display> chunk.
84 bool PhoneDisplay::ProcessAndValidate(TiXmlNode* pNode)
91 assert(pNode->Type() == TiXmlNode::ELEMENT);
94 * Process attributes. Right now they're all mandatory, but some of
95 * them could be defaulted (e.g. "rotate").
97 * [We should do some range-checking here.]
99 pElem = pNode->ToElement();
100 name = pElem->Attribute("name");
103 if (pElem->Attribute("width", &mWidth) == NULL)
105 if (pElem->Attribute("height", &mHeight) == NULL)
107 if (pElem->Attribute("refresh", &mRefresh) == NULL)
109 format = pElem->Attribute("format");
114 mName = strdupNew(name);
116 if (strcasecmp(format, "rgb565") == 0) {
117 mFormat = android::PIXEL_FORMAT_RGB_565;
119 fprintf(stderr, "SimCFG: unexpected value for display format\n");
127 "SimCFG: <display> requires name/width/height/format/refresh\n");
133 * Returns "true" if the two displays are compatible, "false" if not.
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.
139 /*static*/ bool PhoneDisplay::IsCompatible(PhoneDisplay* pDisplay1,
140 PhoneDisplay* pDisplay2)
142 return (pDisplay1->mWidth == pDisplay2->mWidth &&
143 pDisplay1->mHeight == pDisplay2->mHeight &&
144 pDisplay1->mFormat == pDisplay2->mFormat &&
145 pDisplay1->mRefresh == pDisplay2->mRefresh);
150 * ===========================================================================
152 * ===========================================================================
156 * Load a <view> chunk.
158 bool PhoneView::ProcessAndValidate(TiXmlNode* pNode, const char* directory)
163 const char* displayName;
165 assert(pNode->Type() == TiXmlNode::ELEMENT);
168 * Process attributes. Right now they're all mandatory, but some of
169 * them could be defaulted (e.g. "rotate").
171 * [We should do some range-checking here.]
173 pElem = pNode->ToElement();
174 displayName = pElem->Attribute("display");
175 if (displayName == NULL)
177 if (pElem->Attribute("x", &mXOffset) == NULL)
179 if (pElem->Attribute("y", &mYOffset) == NULL)
181 if (pElem->Attribute("rotate", &rotate) == NULL)
185 case 0: mRotation = kRot0; break;
186 case 90: mRotation = kRot90; break;
187 case 180: mRotation = kRot180; break;
188 case 270: mRotation = kRot270; break;
190 fprintf(stderr, "SimCFG: unexpected value for rotation\n");
191 mRotation = kRotUnknown;
195 delete[] mDisplayName;
196 mDisplayName = android::strdupNew(displayName);
201 for (pChild = pNode->FirstChild(); pChild != NULL;
202 pChild = pChild->NextSibling())
204 if (pChild->Type() == TiXmlNode::COMMENT)
207 if (pChild->Type() == TiXmlNode::ELEMENT) {
208 if (strcasecmp(pChild->Value(), "image") == 0) {
209 if (!ProcessImage(pChild, directory))
211 } else if (strcasecmp(pChild->Value(), "button") == 0) {
212 if (!ProcessButton(pChild, directory))
216 "SimCFG: Warning: unexpected elements in <display>\n");
219 fprintf(stderr, "SimCFG: Warning: unexpected stuff in <display>\n");
227 "SimCFG: <view> requires display/x/y/rotate\n");
232 * Handle <image src="zzz" x="123" y="123"/>.
234 bool PhoneView::ProcessImage(TiXmlNode* pNode, const char* directory)
240 LoadableImage tmpLimg;
241 android::String8 fileName;
243 pChild = pNode->FirstChild();
244 if (pChild != NULL) {
245 fprintf(stderr, "SimCFG: <image> is funky\n");
250 * All attributes are mandatory.
252 pElem = pNode->ToElement();
253 src = pElem->Attribute("src");
256 if (pElem->Attribute("x", &x) == NULL)
258 if (pElem->Attribute("y", &y) == NULL)
261 if (strncmp(src, kRelPathMagic, strlen(kRelPathMagic)) == 0) {
262 fileName = src + strlen(kRelPathMagic);
264 fileName = directory;
269 tmpLimg.Create(fileName, x, y);
270 mImageList.push_back(tmpLimg);
275 fprintf(stderr, "SimCFG: <image> requires src/x/y\n");
280 * Handle <button keyCode="zzz" src="zzz" x="123" y="123"/> and
281 * <button keyCode="zzz"/>.
283 bool PhoneView::ProcessButton(TiXmlNode* pNode, const char* directory)
290 PhoneButton tmpButton;
291 android::String8 fileName;
293 pChild = pNode->FirstChild();
294 if (pChild != NULL) {
295 fprintf(stderr, "SimCFG: button is funky\n");
300 * Only keyCode is mandatory. If they specify "src", then "x" and "y"
303 pElem = pNode->ToElement();
304 keyCode = pElem->Attribute("keyCode");
308 src = pElem->Attribute("src");
310 if (pElem->Attribute("x", &x) == NULL)
312 if (pElem->Attribute("y", &y) == NULL)
317 tmpButton.Create(keyCode);
319 if (strncmp(src, kRelPathMagic, strlen(kRelPathMagic)) == 0) {
320 fileName = src + strlen(kRelPathMagic);
322 fileName = directory;
326 tmpButton.Create(keyCode, fileName, x, y);
329 mButtonList.push_back(tmpButton);
334 fprintf(stderr, "SimCFG: <button> requires keycode and may have src/x/y\n");
340 * Load all resources associated with the display.
342 bool PhoneView::LoadResources(void)
344 typedef List<LoadableImage>::iterator LIter;
345 typedef List<PhoneButton>::iterator BIter;
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();
355 * Unload all resources associated with the display.
357 bool PhoneView::UnloadResources(void)
359 typedef List<LoadableImage>::iterator LIter;
360 typedef List<PhoneButton>::iterator BIter;
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();
371 * Get the #of images.
373 int PhoneView::GetBkgImageCount(void) const
375 return mImageList.size();
379 * Return the Nth entry.
381 const LoadableImage* PhoneView::GetBkgImage(int idx) const
383 typedef List<LoadableImage>::const_iterator Iter;
385 for (Iter ii = mImageList.begin(); ii != mImageList.end(); ++ii) {
396 * Find the first button that covers the specified coordinates.
398 * The coordinates must be relative to the upper left corner of the
401 PhoneButton* PhoneView::FindButtonHit(int x, int y)
403 typedef List<PhoneButton>::iterator Iter;
405 for (Iter ii = mButtonList.begin(); ii != mButtonList.end(); ++ii) {
406 if ((*ii).CheckCollision(x, y))
414 * Find the first button with a matching key code.
416 PhoneButton* PhoneView::FindButtonByKey(int32_t keyCode)
418 typedef List<PhoneButton>::iterator Iter;
420 for (Iter ii = mButtonList.begin(); ii != mButtonList.end(); ++ii) {
421 if ((*ii).GetKeyCode() == keyCode)
430 * ===========================================================================
432 * ===========================================================================
436 * Process a <mode name="zzz"> chunk.
438 bool PhoneMode::ProcessAndValidate(TiXmlNode* pNode, const char* directory)
443 assert(pNode->Type() == TiXmlNode::ELEMENT);
445 name = pNode->ToElement()->Attribute("name");
447 fprintf(stderr, "SimCFG: <mode> requires name attrib\n");
452 for (pChild = pNode->FirstChild(); pChild != NULL;
453 pChild = pChild->NextSibling())
455 if (pChild->Type() == TiXmlNode::COMMENT)
458 if (pChild->Type() == TiXmlNode::ELEMENT &&
459 strcasecmp(pChild->Value(), "view") == 0)
461 PhoneView tmpDisplay;
464 result = tmpDisplay.ProcessAndValidate(pChild, directory);
468 mViewList.push_back(tmpDisplay);
470 fprintf(stderr, "SimCFG: Warning: unexpected stuff in <mode>\n");
474 if (mViewList.size() == 0) {
475 fprintf(stderr, "SimCFG: no <view> entries found\n");
484 * Load all resources associated with the phone.
486 bool PhoneMode::LoadResources(void)
488 typedef List<PhoneView>::iterator Iter;
490 for (Iter ii = mViewList.begin(); ii != mViewList.end(); ++ii)
491 (*ii).LoadResources();
496 * Unload all resources associated with the phone.
498 bool PhoneMode::UnloadResources(void)
500 typedef List<PhoneView>::iterator Iter;
502 for (Iter ii = mViewList.begin(); ii != mViewList.end(); ++ii)
503 (*ii).UnloadResources();
509 * Return the Nth entry. [make this a Vector?]
511 PhoneView* PhoneMode::GetPhoneView(int viewNum)
513 typedef List<PhoneView>::iterator Iter;
515 for (Iter ii = mViewList.begin(); ii != mViewList.end(); ++ii) {
525 * ===========================================================================
527 * ===========================================================================
532 * Look for a "layout.xml" in the specified directory. If found, parse
535 * Returns "true" on success, "false" on failure.
537 bool PhoneData::Create(const char* directory)
539 android::String8 fileName;
541 SetDirectory(directory);
543 fileName = directory;
545 fileName += PhoneCollection::kLayoutFile;
548 TiXmlDocument doc(fileName);
551 android::AssetManager* pAssetMgr = ((MyApp*)wxTheApp)->GetAssetManager();
553 android::Asset* pAsset;
556 pAsset = pAssetMgr->open(fileName, Asset::ACCESS_STREAMING);
557 if (pAsset == NULL) {
558 fprintf(stderr, "Unable to open asset '%s'\n", (const char*) fileName);
561 //printf("--- opened asset '%s'\n",
562 // (const char*) pAsset->getAssetSource());
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';
571 result = doc.Parse(buf);
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());
583 fprintf(stderr, " XML: %s\n", doc.ErrorDesc());
587 if (!ProcessAndValidate(&doc)) {
588 fprintf(stderr, "SimCFG: ERROR: failed analyzing '%s'\n",
589 (const char*) fileName);
593 printf("SimCFG: loaded data from '%s'\n", (const char*) fileName);
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.
603 * Returns "true" on success, "false" on failure.
605 bool PhoneData::ProcessAndValidate(TiXmlDocument* pDoc)
607 bool deviceFound = false;
610 assert(pDoc->Type() == TiXmlNode::DOCUMENT);
612 for (pChild = pDoc->FirstChild(); pChild != NULL;
613 pChild = pChild->NextSibling())
616 * Find the <device> entry. There should be exactly one.
618 if (pChild->Type() == TiXmlNode::ELEMENT) {
619 if (strcasecmp(pChild->Value(), "device") != 0) {
621 "SimCFG: Warning: unexpected element '%s' at top level\n",
626 fprintf(stderr, "SimCFG: one <device> per customer\n");
630 bool result = ProcessDevice(pChild);
638 fprintf(stderr, "SimCFG: no <device> section found\n");
646 * Process a <device name="zzz"> chunk.
648 bool PhoneData::ProcessDevice(TiXmlNode* pNode)
653 assert(pNode->Type() == TiXmlNode::ELEMENT);
655 name = pNode->ToElement()->Attribute("name");
657 fprintf(stderr, "SimCFG: <device> requires name attrib\n");
663 * Walk through the children and find interesting stuff.
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.
670 for (pChild = pNode->FirstChild(); pChild != NULL;
671 pChild = pChild->NextSibling())
675 if (pChild->Type() == TiXmlNode::COMMENT)
678 if (pChild->Type() == TiXmlNode::ELEMENT &&
679 strcasecmp(pChild->Value(), "title") == 0)
681 result = ProcessTitle(pChild);
684 } else if (pChild->Type() == TiXmlNode::ELEMENT &&
685 strcasecmp(pChild->Value(), "display") == 0)
687 PhoneDisplay tmpDisplay;
689 result = tmpDisplay.ProcessAndValidate(pChild);
693 mDisplayList.push_back(tmpDisplay);
694 } else if (pChild->Type() == TiXmlNode::ELEMENT &&
695 strcasecmp(pChild->Value(), "keyboard") == 0)
697 PhoneKeyboard tmpKeyboard;
698 result = tmpKeyboard.ProcessAndValidate(pChild);
702 mKeyboardList.push_back(tmpKeyboard);
703 } else if (pChild->Type() == TiXmlNode::ELEMENT &&
704 strcasecmp(pChild->Value(), "mode") == 0)
708 result = tmpMode.ProcessAndValidate(pChild, mDirectory);
712 mModeList.push_back(tmpMode);
714 fprintf(stderr, "SimCFG: Warning: unexpected stuff in <device>\n");
718 if (mDisplayList.size() == 0) {
719 fprintf(stderr, "SimCFG: no <display> entries found\n");
722 if (mModeList.size() == 0) {
723 fprintf(stderr, "SimCFG: no <mode> entries found\n");
733 bool PhoneData::ProcessTitle(TiXmlNode* pNode)
737 pChild = pNode->FirstChild();
738 if (pChild->Type() != TiXmlNode::TEXT) {
739 fprintf(stderr, "SimCFG: title is funky\n");
743 SetTitle(pChild->Value());
749 * Load all resources associated with the phone.
751 bool PhoneData::LoadResources(void)
753 typedef List<PhoneMode>::iterator Iter;
755 for (Iter ii = mModeList.begin(); ii != mModeList.end(); ++ii)
756 (*ii).LoadResources();
761 * Unload all resources associated with the phone.
763 bool PhoneData::UnloadResources(void)
765 typedef List<PhoneMode>::iterator Iter;
767 for (Iter ii = mModeList.begin(); ii != mModeList.end(); ++ii)
768 (*ii).UnloadResources();
774 * Return the PhoneMode entry with the matching name.
776 * Returns NULL if no match was found.
778 PhoneMode* PhoneData::GetPhoneMode(const char* modeName)
780 typedef List<PhoneMode>::iterator Iter;
782 for (Iter ii = mModeList.begin(); ii != mModeList.end(); ++ii) {
783 if (strcmp((*ii).GetName(), modeName) == 0)
790 * Return the Nth phone mode entry.
792 PhoneMode* PhoneData::GetPhoneMode(int idx)
794 typedef List<PhoneMode>::iterator Iter;
796 for (Iter ii = mModeList.begin(); ii != mModeList.end(); ++ii) {
806 * Return the PhoneDisplay entry with the matching name.
808 * Returns NULL if no match was found.
810 PhoneDisplay* PhoneData::GetPhoneDisplay(const char* dispName)
812 typedef List<PhoneDisplay>::iterator Iter;
814 for (Iter ii = mDisplayList.begin(); ii != mDisplayList.end(); ++ii) {
815 if (strcmp((*ii).GetName(), dispName) == 0)
822 * Return the Nth phone mode entry.
824 PhoneDisplay* PhoneData::GetPhoneDisplay(int idx)
826 typedef List<PhoneDisplay>::iterator Iter;
828 for (Iter ii = mDisplayList.begin(); ii != mDisplayList.end(); ++ii) {
837 * Find the PhoneDisplay entry with the matching name, and return its index.
839 * Returns -1 if the entry wasn't found.
841 int PhoneData::GetPhoneDisplayIndex(const char* dispName)
843 typedef List<PhoneDisplay>::iterator Iter;
846 for (Iter ii = mDisplayList.begin(); ii != mDisplayList.end(); ++ii) {
847 if (strcmp((*ii).GetName(), dispName) == 0)
856 * Return the Nth phone keyboard entry.
858 PhoneKeyboard* PhoneData::GetPhoneKeyboard(int idx)
860 typedef List<PhoneKeyboard>::iterator Iter;
862 for (Iter ii = mKeyboardList.begin(); ii != mKeyboardList.end(); ++ii) {