Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Mobile / Android

Gynoid: Framework for Mobile Development

4.97/5 (13 votes)
29 May 2009LGPL37 min read 41.7K   537  
Gynoid is a wrapper around mobile phone APIs (WinCE, symbian, iPhone)
addrbook_src

Introduction 

Mobile developments are something very exciting because generally it implies to use
all domains of computing. Since you are developing for the end user, you need to create a nice GUI, handle data connections and databases, etc.

The only thing I do not like is the fact that for each platform, you need to learn a new language, new APIs and if you want to port it from one platform to another, you almost always need to write it again.

Big companies like Sun have tried to impose Java to accomplish the sweet dream "Write Once Run Anywhere" but as you already know it didn't succeed and especially in the mobile world.
For politics reasons, Java is not really supported on Windows mobile and iPhone and personally, I don't think managed languages should be used because they are slow, consume more memory, and so on.

The problem is that developers now are used to focus only on the feature they want to implement and they don't want to manage memory anymore. I am not even talking about new developers that don't even know what a pointer is, but that's another problem...  

With these considerations in mind, it's been a long time I wanted to write a framework with the following characteristics (lines in italic needs a proof of concept and may change):  

  • native code
  • fast and small footprint (we don't reinvent the wheel, we only wrap native APIs)   
  • multi-OS (wince, symbian, iPhone and may be Android if Google allows it and provides a native toolchain with enough permissions) 
  • Object oriented (done with wrapper above C APIs)
  • can be called by any language (Ruby, Python, .NET, ...)  
  • open source under LGPL license to allow its use in commercial products.
    iPhone is a special case and will use a commercial license because Apple doesn't allow dynamic linking with third parties libs. 
  • Common IDE (I am already using codelite to compile with msvc compiler, cegcc, iPhone toolchain)   
  • Garbage collected : will be based on D language but compiler is not ready yet and I hope support for gnu compilers will be better in future.  I already have a D cross-compiler targeting windows CE but when it was done we did it with the 2.0 language version that is not stable. In the future, I hope someone will contribute to the D gnu compiler.

So here it is a PRE-ALPHA PREVIEW since I started one month ago but as you will see, we are able to do some simple action with address book. 

To finish this introduction, Gynoid name is a human robot designed to look like a human female
and is a joke with Android, the Google's Framework. If you want to tell me that this framework is nonsense and cannot work or this is a lot of work to wrap phone API, I already know it;-)
Actually for this preview, I have only started the Windows CE part and the next step is to do it for iPhone. If it works, I would have proven that it can be done and I will keep on implementing.

Background     

To be able to respect all the above criteria, I first studied 3 different platforms and here is what is interesting for Gynoid framework:  

  • Windows CE: APIs are natively in Unicode(utf16) and can be called from C language.
  • iPhone: APIs are in Objective-C and strings are encoded in utf8. 
  • Symbian: APIs are in a custom C++ language (see Symbian_OS_design_faults.aspx)  and support ANSI and Unicode(utf16) 

Three different platforms and three incompatible SDKs, so the only choice was to wrap API using C language.  

Architecture

So this framework uses C APIs that can be used with static or dynamic linking and for this first publication, I will explain how it works using the address book API.

So let's start with a sample code in plain C:

C++
ErrorCode err = 0;
int iCount = 0;
GDAddrBook* pAddrBook = NULL;
GDAbItem* pAbItem = NULL;
GDPropVal* pPropVal = NULL;
//GDStream* gdStream; // NOT YET IMPLEMENTED
int nCount;
GDArray* gdArray = NULL;

if (!GDAddrBook_Alloc(&pAddrBook) && 
	!GDAddrBook_Init(pAddrBook, 0) )
{
	if (GDAddrBook_GetCount(pAddrBook, &iCount) == 0)
	{
		////////////////////////////////////////////////////////////////
		// If there is no item in address book we create one
		////////////////////////////////////////////////////////////////
		if (iCount == 0)
		{
			if (GDAddrBook_AddItem(pAddrBook, &pAbItem) == 0)
			{
				err = GDAbItem_SetProperty
					(pAbItem, eAbFirstName, _T("Vincent") );
				err = GDAbItem_SetProperty
				(pAbItem, eAbLastName,_T("emmohcir") );
				err = GDAbItem_SetProperty
				(pAbItem, eAbMobileTelNumber, _T("0611000000") );
				err = GDAbItem_SetProperty(pAbItem, 
				eAbEmail1Address,	_T("v.emmohcir@gynoid.com") );
				err = GDAbItem_SetProperty(pAbItem, 
				eAbEmail2Address,	_T("vemmohcir@gynoid.com") );

				//GDStream_Init(&gdStream);
				//GDAbItem_SetProperty(pAbItem, eAbPicture, 
								gdStream );
				GDObject_Release(pAbItem);	
			}
		}

		GDAddrBook_GetCount(pAddrBook, &iCount);

		/////////////////////////////////////////////////////////////////
		//Now we can retrieve contacts items and their properties
		////////////////////////////////////////////////////////////////
		for (int i = 0; i < iCount; i++)
		{
			if (GDAddrBook_GetItem(pAddrBook, i, &pAbItem) == 0)
			{
				//GDCTSTR lpFirstName = AbCastString
				( AbItem_GetProperty(pAbItem, eAbFirstName) );
				GDCTSTR lpFirstName = (GDCTSTR) 
				GDAbItem_GetProperty(pAbItem, eAbFirstName);
				GDCTSTR lpLastName  = (GDCTSTR) 
				GDAbItem_GetProperty(pAbItem, eAbLastName);
				GDCTSTR lpMobTel	= (GDCTSTR) 
				GDAbItem_GetProperty(pAbItem, eAbMobileTelNumber);

				//GDConsole_Writeln(_T
					("FirstName %s\nLastName %s\n", ...);
				gyn_printf( _T("[%d] %s %s %s\n"), 
					i, lpFirstName, lpLastName,  lpMobTel);

				//
				//Contact_GetProperty
				//(pContact, eContactLastName, &pPropVal);
				GDObject_Release(pAbItem);
			}
		}
	}
}

GDObject_Release(pAddrBook); 

Even if gynoid is using C interfaces, I have chosen to adopt an oriented approach and API is split in GDAddrBook object and GDAbBitem.
All these GDxxxx objects are actually structures "inheriting" from a GDObject structure declared like this:

C++
typedef struct _GDObject
{
	long cRefs;
	PFNGDDESTROY pfnDestroy;
} GDObject; 

This structure allows to use reference counting to manage object life and once again will simplify object-oriented wrapper. First I started to code gynoid objects using a void as GDObject but to be able to propose a C++ wrapper I needed to use a shared_pointer or that kind of smart pointers that would be able to transfer ownership of underlying gynoid pointers.
I didn't like this solution because I wanted to keep things simple but nothing prevents you from providing different C++ wrappers and I might change my mind and use smart pointers in the future.

Let's keep on discovering gynoid, when using a GDObject you first need to allocate it and then initialize it as show here:

C++
if (!GDAddrBook_Alloc(&pAddrBook) && 
	!GDAddrBook_Init(pAddrBook, 0) )
{
...
}

iPhone developers won't be lost and it will remind them of the way they build an object in objective-c 2.0:

C++
Iphone sample code to get address book:
// For people not talking objective-ce the code below is a nested
// construct where alloc message is sent to 
// ABPeoplePickerNavigationController and then return object is 
// sent a init message

ABPeoplePickerNavigationController *controller = 
[[ABPeoplePickerNavigationController alloc] init]; 

So if we come back to our address book example, we first allocate and init a GDAddrbook "object", then we can start to retrieve associated properties and that's what we do when we call GDAddrBook_GetCount to retrieve the contact number.
One remark is the fact that all getter/setters are done with arguments and not by return code, it will allow a strict error checking.

Once we know how many items we have in the address book, we can start to create an item with some properties by using GDAddrBook_AddItem (that returns a GDAbItem object) and GDAbItem_SetProperty.

Once we have finished adding properties, we only need to release the object by calling the generic function GDObject_Release().

So now you have a global idea of how things work, but I can understand that some developers don't like to code in C especially when designing GUI application and we could benefit from some facilities offered by high level languages.

Object Oriented Wrappers

The easiest object oriented language to use for wrapping is C++ and since memory management is done by our low level C interfaces you will see that, wrappers are nothing more than containers for our GDObject pointers. 

Here is the class I have used to wrap GDAbItem pointers:

C++
class AddrBookItem
	{
	public:
		AddrBookItem(): m_gpAbItem(0)
		{}

		AddrBookItem(const AddrBook& addrBook)
		{}

		AddrBookItem(GDAbItem* gpAbItem): m_gpAbItem(gpAbItem)
		{}

		AddrBookItem::AddrBookItem(const AddrBookItem &s) : m_gpAbItem(0)
		{	
			*this = s;
		}

		AddrBookItem& AddrBookItem::operator =(const AddrBookItem &s)
		{
			// If we are already holding an item we release it
			if (m_gpAbItem != NULL) 
			{
				GDObject_Release(m_gpAbItem);
				m_gpAbItem = NULL;
			}

			m_gpAbItem = s.m_gpAbItem;
			GDObject_AddRef(m_gpAbItem);

			return *this;
		}

		virtual AddrBookItem::~AddrBookItem()
		{
			release();
		}

		void* getProperty(EAbItemProp eAbitemProp)
		{
			return GDAbItem_GetProperty(m_gpAbItem, eAbitemProp);
		}

		ErrorCode setProperty(EAbItemProp eContactProp, GDCTSTR lpPropValue)
		{
			return GDAbItem_SetProperty
				(m_gpAbItem, eContactProp, lpPropValue);
		}

		ErrorCode show()
		{
			return GDAbItem_Show(m_gpAbItem);
		}
	protected:

		long release()
		{
			return GDObject_Release(m_gpAbItem);
		}
	protected:
		GDAbItem* m_gpAbItem;

	};  

So what if we try to rewrite our first example but this time by using our new C++ wrapper:

C++
////////////////////////////////////////////////////////////////
// Same example done with C++ wrapper
////////////////////////////////////////////////////////////////

using namespace gynoid;

int nCount;
AddrBook addrBook;

iCount = addrBook.getCount();
if (iCount == 0)
{
	AddrBookItem abItem = m_addrBook.addItem();
	abItem.setProperty(eAbFirstName, _T("Vincent") );
	abItem.setProperty(eAbLastName,	_T("emmohcir") );
	abItem.setProperty(eAbEmail1Address, _T("v.emmohcir@gynoid.com") );
	abItem.setProperty(eAbEmail2Address, _T("vemmohcir@gynoid.com") );
}
iCount = addrBook.getCount();
for (int i = 0; i < iCount; i++)
{
	AddrBookItem abItem = addrBook.getItem(i);
	CString sFirstName = abItem.getProperty(eAbFirstName);
	CString sLastName = abItem.getProperty(eAbLastName);
	CString sMobTel = abItem.getProperty(eAbMobileTelNumber);
	gyn_printf( _T("[%d] %s %s %s\n"), 
					i, lpFirstName, lpLastName,  lpMobTel);
} 

So this time as you can see, we have used AddrBook and AddrBookItem objects and we don't even need to handle code deallocation since object destructor does the job for us.
I have used CString object to manage strings but very soon it will be replaced by GDString object.
To finish with object oriented wrappers, there is something that I cannot forget to write about and this is error checking with the questions, exceptions or not exceptions.

Error Handling  (Exceptions or Not Exceptions)

Error handling is a difficult question and with gynoid current state, it's a bit early to answer.
But as soon as we start to use an object oriented language, the question about using exceptions is generally not very far. I will try to answer it in the next update of this article.

Sample Code  

To illustrate the use of address book API and since I haven't coded the graphical part, I have used WTL and a great touch control made by Windows mobile guru João Paulo Figueira.

In the next article I hope I will be able to use a platform independent GUI (it's already possible to do it using SDL, guichan or efl). 

Conclusion 

This project is very young and maybe won't go very far, it depends on the next challenge, wrapping address book API from iPhone. Anyway if it doesn't become a multiplatform framework, it will still be useful for Windows CE developers because it simplifies access to native APIs, hides ugly COM interfaces and provides an OO wrapper but only if you need it.

Do not hesitate to contribute and you can follow activity on Sourceforge

History  

  • 29 May 2009: First publication

License

This article, along with any associated source code and files, is licensed under The GNU Lesser General Public License (LGPLv3)