Tip #1: Code for the phone, not the emulator.
Handsets are small form factor, constrained devices ? so relative to what you’re used to on the desktop, phones have limited speed, limited resources, small screens, and a limited ARM processor. You have to remember that the emulator has amazing speed (your 2GHz desktop machine at full speed, for example), emulated resources, incorrect use of screen size for many of the skins, and an x86 processor. The emulator is just that; it’s not a phone.
Here’s a closer look at each of the four main development issues when using an emulator to code for a BREW phone:
- Speed. Phones have fairly slow processors. Don’t expect to be able to do complex math calculations in real-time for a simulation.
- Limited resources. Phones have a small amount of storage, and policy of specific phones (such as the Z-800) can make that even more limiting than it seems at first. Also, an application’s code is loaded into RAM from storage (just like a traditional PC, but unlike many PDAs). This means even less RAM is available than you may have originally expected. A good case in point is the Kyocera 3035; it has 60 kilobytes of RAM available. If your application is 35 kilobytes, then only 25 kilobytes remain for processing.
- Screen size. These are small screens, even by PDA standards. Design the UI the way you see them on other phones: That is ? keep it simple. Don’t try to do too much on one screen. Instead, break a screen up and have a menu to access the various portions of it so everything is clean and uncluttered.
- Don’t forget that the target for the application is an ARM processor. The application must compile for the ARM processor. Start with this example: make files. Although they aren’t the best design, they have the settings that are required for this particular ARM processor. Don’t try to change them to compile your application; that won’t work. Instead, fix the code. Common mistakes include doing division, using global or static variables, and, when compiling in Visual Studio, ignoring Level 4 warnings, which often become errors using the ARM compiler.
Make sure to build often with the ARM compiler and test often on the phone. QUALCOMM has recently made this much easier by providing the BREW Logger for download. This allows you to see the DBGPRINTF messages on your PC while you’re debugging on the phone. This beats grabbing debug files on the phone!
Tip #2: Remember that BREW is Asynchronous.
Writing software for BREW means writing fully asynchronous, event-driven software. This is even more pronounced than early Mac OS programming or Palm OS programming. In those systems, there was usually a way for the application to create its own event loop wherever it wanted by grabbing the next event off the system queue and seeing if that event was for it or not. If it was, it could handle it and go on; otherwise, it would dispatch it back to the system. This is not possible in BREW.
Most IO calls in BREW are non-blocking. What this means is that the action doesn’t actually take place right when the call is made. That would have made it synchronous. For instance, if you make a call to ISOCKET_Connect(), you have to provide a callback routine. What happens here, at least as far as we are concerned, is the action to do the ISOCKET_Connect() is placed on a system stack, and the call returns immediately, returning control to the application. If we want the action to actually occur, we must return to the system before it can happen.
All of this means that the best BREW applications will need to be designed from the ground up to work well within an asynchronous system. Sure, there are ways of somewhat mechanically converting a synchronous application to work in an asynchronous system, but for anything but the simplest of applications, this can get very complex very quickly.
Another effect of this is that when an application is busy, nothing else is occurring on the phone. Since this is a phone, that’s a bad thing. A phone is still primarily for voice calls. If your application is busy doing something, a voice call can’t occur (at least the part of notifying the user that a voice call is incoming) until your application returns to the system. Because of this, there is a watchdog timer. If an application spends too much time without returning to the system, the phone will reset. This means that if an application is going to do some processing, some of the flow of control should be passed via sending events to itself. This is easily accomplished by using EVT_USER events with ISHELL_PostEvent(). (I don’t recommend ISHELL_SendEvent() as that causes the event to happen synchronously, which is not what we want.)
There are a number of BREW system calls that require the application to be waiting for a callback before flow will continue. What if this never occurs? Well, the obvious effect is that control will never return to your application, and the user will think it has hung. This is actually quite a common occurrence (for example, a phone indoors may not have very good network coverage). This is easily solved by using ISHELL_SetTimer() with your own callback. Don’t worry: If the event occurs before the timer, you can easily cancel the timer by using ISHELL_CancelTimer().
Tip #3: Know How to Handle Your Events.
As mentioned in the previous tip, BREW is very event-driven. As such, an application will get many events that it may not be expecting. Controls talk to themselves using events. The system sends events to the application to tell it a variety of things about the state of the phone. All of these need some action taken by the application. Because of this, a well-designed event handler is required for a stable application.
It is the application’s responsibility to make sure all controls being used get the messages they require to function properly. It is not defined what all of the events are, so the best way to handle this is to take special action on those events you know about and may want to intercept occasionally (such as the arrow keys or CLR key) and have a default handler that passes everything else to any active controls to see if they can handle the event.
Handling the CLR key (event code of EVT_KEY with a wParam of AVK_CLR) is a special case in BREW. A well-designed application will have the CLR key behaving as a backspace when in text entry controls, as a back key to go back a screen, and exiting the application when on the main screen. This means an application needs to watch for it and perhaps do something special. If FALSE is ever returned from handling the CLR key, the application will exit. Except at the main screen, this is likely not the action you want the application to take.
One of the most important events to handle properly in any application is the suspend event (EVT_APP_SUSPEND). If an application receives this, it means that the phone wants to do something, such as notifying the user of a voice call or maybe an SMS message. QUALCOMM defines a bunch of things that an application must do before returning from a suspend event. These things including closing down all used sockets, stopping all timers, and deactivating all controls, among many other things. An application will not pass testing if these aren’t done.
Originally published in the BREW Wireless Resource Center