Can You Build One Set of BREW User Interfaces for All Targeted Devices?

In this installment, you’ll explore the challenges a developer faces whentrying to build a single set of user interface code that will work on alltargeted platforms. You’ll see what goes into creating a multi-control BREWDialog at run time. Differences between the emulator and actual handsets, inaddition to differences between handsets themselves, are highlighted andworkarounds are given. The conclusion underscores what is possibly the mostimportant principle of BREW development: as you develop your application, testit on the actual, targeted handsets at frequent intervals.

BREW Dialogs

Figure 1 – A dialog occupies the lower portion of thescreen while the drawing activity it controls occurs in the upper portion.

Figure 1 shows a simple UI that controls shape rendering in the upperportion of the screen. The UI itself consists of two list controls and asoft key menu contained by a BREW dialog. The dialog was composed using the BREW ResourceEditor (please refer to the BREW Resource Editor Guide for more information). The two list controls determine which shape is drawn in the upperportion of the display and which color is used to do the drawing. The softkey menu choices are Shape, used to move the focus to the list controlthat handles shape choice, Color, used to transfer control to the secondlist control which controls drawing color, and Done, which simply exits the application. The leftand right keys are used to navigate between the two list controls.

Figure 2 – A dialog containing 2 text controls and amenu.

The following sample application creates and displays the dialogshown running on the emulator in Figure 2. (Be warned: this coderequires augmentation before it will work properly on a handset — more on this later).

For an admittedly contrived example, the displayed result looks reasonablyattractive. Now, what happens if we try to port the application to adevice with a significantly smaller screen? For starters, in order toshrink the dialog, the soft key menu would have to go! (Arguably, itshould not have been there in the first place, since the Clear and Endkeys can be used to exit the application. For the time being, please bearwith me and imagine that the soft key menu serves some useful purpose.) Generally, such a situation would lead to a complete dialog redesign, using theresource editor. Thus, a separate .bar file would be compiled, exclusivelyfor the newlytargeted phone. Even if the questionable soft key menu had been excluded from theoutset, the dialog’s size would still have to change to accommodate the smallerdisplay. Since a dialog’s rectangle can’t be modified at run time, thismeans we’re stuck with creating, and, worse, maintaining a separateversion of the resource file just to get the application working on a lessgenerously proportioned screen. Is there another way?

Building Dialogs at Run Time
As you will see, the code for constructing a dialog at run time is relativelycomplex and fraught with subtle idiosyncrasies.

#include "AEEModGen.h"          // Module interface definitions#include "AEEAppGen.h"          // Applet interface definitions#include "AEEShell.h"           // Shell interface definitions#include "AEEMenu.h"#include "AEEText.h"#include "AEEStdLib.h"#include "dlghard.bid"/*   The use of BREW SDK 1.0 and BREW Emulator 2.0 are assumed.   This example demonstrates how to create a dialog at run time.  The dialog   has 3 controls: 2 ITextCtls, and 1 IMenuCtl.*/#define IDTXT1 (uint16)1#define IDTXT2 (uint16)2#define TXTPROPS TP_FRAME#define IDMNU (uint16)3#define MNUPROPS (uint16)0#define IDMNULI1 (uint16)1#define IDMNULI2 (uint16)2#define IDMNULI3 (uint16)3#define NUMMNUITEMS 0#define DLGID (uint16)1#define NUMCTLS (uint16)3#define DLGPROPS CP_3D_BORDER#define FOCUSCTL IDTXT1// dialog layout parameters#define MARGIN 15#define INSET 1typedef struct _dlghardapp{   AEEApplet a;   IDialog *m_pDlg;} dlghardapp;/*-------------------------------------------------------------------Function Prototypes-------------------------------------------------------------------*/static boolean dlghard_HandleEvent(IApplet * pi, AEEEvent eCode,                                       uint16 wParam, uint32 dwParam);static boolean initData(dlghardapp *papp);int AEEClsCreateInstance(AEECLSID ClsId,IShell * pIShell,IModule * po,                         void ** ppObj){   *ppObj = NULL;         if(ClsId == AEECLSID_DLGHARD)   {      if(AEEApplet_New(sizeof(dlghardapp), ClsId, pIShell,po,(IApplet**)ppObj,         (AEEHANDLER)dlghard_HandleEvent,NULL) == TRUE)      {         if(initData((dlghardapp*)*ppObj))            return (AEE_SUCCESS);      }   }   return (EFAILED);}static boolean initData(dlghardapp *papp){   papp->m_pDlg = NULL;   return TRUE;}

The above code is shown merely for the sake of completeness. The only twothings of interest are the #defines and the global definition ofthe application data structure type, dlghardapp. The typename is intended to capture the fact that this example shows how to createdialogs the hard way.

static boolean dlghard_HandleEvent(IApplet * pi, AEEEvent eCode, uint16 wParam,                                   uint32 dwParam){   dlghardapp *papp = (dlghardapp*)pi;   switch (eCode)    {      case EVT_APP_START:      {         int bold_h = IDISPLAY_GetFontMetrics(papp->a.m_pIDisplay,                         AEE_FONT_BOLD, NULL, NULL);         int norm_h = IDISPLAY_GetFontMetrics(papp->a.m_pIDisplay,                         AEE_FONT_NORMAL, NULL, NULL);         IMenuCtl *pmnu = NULL;         ITextCtl *ptxt = NULL;         int r = 0;   // return value from ISHELL_CreateDialog()         AEEDeviceInfo *pdevinfo = (AEEDeviceInfo*)MALLOC(sizeof(AEEDeviceInfo));         int vert_space = 0;  // inter-control spacing                  /*             Allocate memory for a DialogInfo struct with NUMCTLS controls                     Notes:            ======            The DialogInfo struct includes space for 1 DialogItem.  Thus, we            only need to allocate space for NUMCTLS-1 (2) additional DialogItems.         */         DialogInfo *pdi = (DialogInfo*) MALLOC(sizeof(DialogInfo) +             (NUMCTLS-1) * sizeof(DialogItem));         DialogItem di;         ISHELL_GetDeviceInfo(papp->a.m_pIShell, pdevinfo);         // calculate the size of a vertical, inter-control spacer         vert_space = (pdevinfo->cyScreen - (3*bold_h+3*norm_h+22*INSET))/4;

The above code snippet shows the beginning of the application eventhandler. At the top of the EVT_APP_START case, the heights of thedevice’s bold and normal fontsare determined. These measurements are later used to lay out thescreen.

After allocating memory for an AEEDeviceInfo struct,memory is allocated for the DialogInfo struct thatwill be passed to ISHELL_CreateDialog(). Figure 3, below,shows what goes into populating a DialogInfo struct. For those of you unfamiliar with Unified Modeling Language (UML) notation thediagram shows that a DialogInfo struct has 1, and only 1, DialogInfoHeadand 0 to many DialogItems (though one would not, in practice,create a dialog without any DialogItems, it is technically possibleto do so).  In turn, a DialogInfoHead has 1 AEERectand each DialogItem has a single DialogItemHead and 0to many DListItems (the example shown here uses 0 DListItems). Lastly, a DialogItemHead also includes a single AEERectthat determines the DialogItem‘s position and size.

A control is a DialogItem (e.g. a menu or text control). Asshown in Figure 2, the dialog under consideration contains 3 DialogItems?2 text controls and a menu. Given that the DialogInfo‘s controlsarray only includes room for 1 DialogItem, space for the 2 additionalcontrols must be included in the call to MALLOC().

A DListItem represents a single menu selection. A textcontrol has no DListItems while a menu may have several. Inthis sample, no DListItem‘s are added to the DialogItemstruct. Instead, as shown later, the menu items are created by calling IMENUCTL_AddItem()after the dialog has been instantiated.

The subsequent call to ISHELL_GetDeviceInfo() provides access tothe screen dimensions. The height of the display (pdevinfo->cyScreen)is used to calculate the amount of vertical, inter-control spacing that willspread the controls evenly over the available space. As indicated in thecalculation, each of the 3 controls occupies bold_h + norm_h plusan allowance for a border around the control’s contents.

Figure 3 – The structs nested within a DialogInfostruct.

         // populate the DialogInfoHead         pdi->h.wID = DLGID;          // the dialog's 16 bit ID         pdi->h.nControls = NUMCTLS;  // total number of controls in dialog         // use default rect (-1, -1, -1, -1) ==> Full Screen         pdi->h.rc.x = -1;         pdi->h.rc.y = -1;            // dialog rectangle         pdi->h.rc.dx = -1;         pdi->h.rc.dy = -1;         pdi->h.dwProps = DLGPROPS;   // dialog properties         // dialog title not supported         pdi->h.wTitle = 0;         pdi->h.wFocusID = FOCUSCTL;  // ID of control with initial focus

The initialization of the DialogInfoHead member of the DialogInfo struct is very straightforward.  For more information on thestructs used, please see the Data Structures section of the BREW API Reference.

         // populate first DialogItem directly         pdi->controls[0].h.cls = AEECLSID_MENUCTL; // classID of control          pdi->controls[0].h.wID = IDMNU;  // control ID          pdi->controls[0].h.nItems = NUMMNUITEMS;  // # menu items          pdi->controls[0].h.dwProps = 0;  // menu properties          pdi->controls[0].h.wTextID = 0;  // ID of text string          pdi->controls[0].h.wTitleID = 0; // ID of title string          pdi->controls[0].h.rc.x = MARGIN; // rectangle dimensions          pdi->controls[0].h.rc.dy = bold_h + norm_h + 10*INSET;          pdi->controls[0].h.rc.y = pdevinfo->cyScreen - vert_space -              pdi->controls[0].h.rc.dy;          pdi->controls[0].h.rc.dx = pdevinfo->cxScreen - 2*MARGIN; 

The DialogItems are added to the controls array inreverse focus order. In other words, the control that is last in the focusorder (in this case, the menu) should be first in the controls array and the control that isfirst in the focus order should be last in the controlsarray. As a direct consequence of this reverse packing scheme, thecontrols’ rectangles are laid out from the bottom of the dialog up. Thiswill become more evident as we add the next two controls.

The wTextID and wTitleID are set to zero sincetheir inclusion here would serve no useful purpose. This is due to thefact that the call to ISHELL_CreateDialog() ignores the resourcefile name parameter when a DialogInfo pointer is supplied (i.e.when the dialog is not defined in a resource file). This is not a problem,however, since the text and title can be set after the dialog has beencreated. Specifically, each menu item’s text will be set by IMENUCTL_AddItem()and the menu’s title will be set by calling IMENUCTL_SetTitle().

         // set up next DialogItem.          // memory contents will be copied to pdi->controls[1]         di.h.cls = AEECLSID_TEXTCTL;  // Class ID         di.h.wID = IDTXT2;            // Control ID         di.h.nItems = 0;      // a text ctl has no items         di.h.dwProps = TXTPROPS; // control properties         di.h.wTextID = 0;         di.h.wTitleID = 0;         di.h.rc.x = MARGIN;  // position the control's rectangle         di.h.rc.dy = bold_h + norm_h + 6*INSET;         di.h.rc.y = pdi->controls[0].h.rc.y - vert_space - di.h.rc.dy;         di.h.rc.dx = pdi->controls[0].h.rc.dx;         // copy the DialogItem into controls[1]         MEMCPY((void*)((long)&pdi->controls[0] + sizeof(DialogItem) -             sizeof(DListItem)), &di, sizeof(DialogItem));

Here again, the wTextID and wTitleID are notused. The text control’s title will be set after the dialog has beencreated, using ITEXTCTL_SetTitle() and the user will enter his / her own text.

The call to MEMCPY() requires some explanation. First ofall, the address of the controls array’s first element must be cast to type longin order for the address to be computed correctly. According to BREWTechnical Support, there is no known explanation for this requirement at thistime. In determining the address of the next element, the first elementmust be left untouched. Thus, the address calculation hops over the memoryallocated to controls[0]. Recall that no DListItems were added to thefirst element (i.e. the menu). For this reason, the size of a DListItemmust be subtracted from the size of the previously included DialogItem,in calculating the next element’s address. (Aside: I owe a big thank you to theBREW Technical Support people for helping me figure this out)

         // menu         di.h.cls = AEECLSID_TEXTCTL;         di.h.wID = IDTXT1;         di.h.nItems = 0;                  di.h.dwProps = TXTPROPS;         di.h.wTextID = 0;         di.h.wTitleID = 0;         di.h.rc.dy = bold_h + norm_h + 6*INSET;         di.h.rc.y -= vert_space + di.h.rc.dy;         MEMCPY((void*)((long)&pdi->controls[0] + 2*sizeof(DialogItem) -             2*sizeof(DListItem)), &di, sizeof(DialogItem));         // create the dialog         r = ISHELL_CreateDialog(papp->a.m_pIShell,NULL , 0, pdi);

Above, the stack-based DialogItem is reused to set up theremaining text control, prior to inclusion in the DialogInfo structas controls[2]. In this case, the address calculation in thecall to MEMCPY() must skip over 2 DialogItems, lessthe size of 2 DListItems. A second DListItemmust be factored into the calculation since the previously added text controlalso did not include any DListItems.

Finally, the call to ISHELL_CreateDialog() instantiates thedialog using the DialogInfo struct just populated.

         if(r == SUCCESS)         {            papp->m_pDlg = ISHELL_GetActiveDialog(papp->a.m_pIShell);            ptxt = (ITextCtl*)IDIALOG_GetControl(papp->m_pDlg, IDTXT1);            if(ptxt)            {               ITEXTCTL_SetTitle(ptxt, NULL, 0, L"Text Control 1");               ITEXTCTL_SetActive(ptxt, TRUE); // redraws control            }            ptxt = (ITextCtl*)IDIALOG_GetControl(papp->m_pDlg, IDTXT2);            if(ptxt)            {               ITEXTCTL_SetTitle(ptxt, NULL, 0, L"Text Control 2");               ITEXTCTL_Redraw(ptxt);            }            pmnu = (IMenuCtl*)IDIALOG_GetControl(papp->m_pDlg, IDMNU);            if(pmnu)            {               IMENUCTL_AddItem(pmnu, NULL, 0, IDMNULI1, L"Menu Item 1", 0);               IMENUCTL_AddItem(pmnu, NULL, 0, IDMNULI2, L"Menu Item 2", 0);               IMENUCTL_AddItem(pmnu, NULL, 0, IDMNULI3, L"Menu Item 3", 0);               IMENUCTL_SetTitle(pmnu, NULL, 0, L"Menu");               IMENUCTL_Redraw(pmnu);            }            FREE(pdi);            FREE(pdevinfo);                     return TRUE;         }         else         {            FREE(pdi);            FREE(pdevinfo);            ISHELL_CloseApplet(papp->a.m_pIShell, TRUE);            return FALSE;         }      }

If the call to ISHELL_CreateDialog() succeeds, each of thecontrols is set up in turn, otherwise dynamically allocated memory is releasedand the applet is closed.  Note that setting the focus ID in the DialogInfo header does not activate the control. For this reason, it isnecessary to call ITEXTCTL_SetActive() when IDTXT1 is set up. This callensures that the text control’s frame is drawn when the application starts. All of the API calls shown here are self-explanatory.  If more detail isrequired, please read the relevant section in the BREW API Reference that comeswith the SDK.

For completeness, the remainder of the application’s code is shown below. EVT_DIALOG_INIT, EVT_DIALOG_START, and EVT_DIALOG_ENDmust, at minimum, return TRUE in order for the dialog to workproperly.  The AVK_CLR handler returns FALSE, sothat the AEE will automatically cause the application to exit whenthe clear key is pressed whenever the menu has the focus (a text controlhandles AVK_CLR — later it will be shown that, in some cases, it willautomatically cause the application to exit if  the text control is empty).  Lastly, since the dialog was created in EVT_APP_START,it is released in EVT_APP_STOP, via the call to ISHELL_EndDialog().

      case EVT_DIALOG_INIT:     case EVT_DIALOG_START:      case EVT_DIALOG_END:         return TRUE;      case EVT_KEY:         switch(wParam)         {            case AVK_CLR:               return FALSE;   // exit app.         }         return TRUE;      case EVT_APP_STOP:      {         ISHELL_EndDialog(papp->a.m_pIShell);         return TRUE;      }      default:         break;   }   return FALSE;} 

This code runs flawlessly on the BREW Emulator (v2.0). The user cannavigate between the 2 text controls, and from a text control to the menu , using the phone’s up and down keys (pressing up while on IDTXT1 moves the focus to the menu, as does pressingdown on IDTXT2). The focus is moved fromthe menu to IDTXT2 using the left key, and from the menu to IDTXT1 by pressingthe right key.

Due to a known, but undocumented, bug in BREW 1.x, this automatic dialog navigation fails completely when the applicationis ported to any handset equipped with version 1.x of the AEE (the Motorola T720(BREW AEE 1.1) and the Sharp Z800 (BREW AEE 1.0) were the onlyhandsets tested). On the phones, pressing direction keys has absolutely no affect onthe dialog’s focus. This navigation bug is fixed in BREW 2.0 (and subsequentversions).  

There are a couple of other differences between the application’s behavior onthe handsets versus what is observed when the same code runs on theemulator.  On the Sharp Z800, both text controlsappear active on startup (i.e. the frames are displayed and the cursors are visible). On the T720, the menu shows 2 items at the same time, due to that phone’sdifferent allowance for space around thetitle and menu item text (i.e. the INSET amount required on the emulator and theZ800 is excessive for the smaller text border on the T720).

These observations underscore the importance of testing all code on eachtargeted handset, throughout the development process.

Making the Same Code Work on Both the Handsets and the Emulator
The following changes are required to ensure that the same set of code willoperate on both handsets, in addition to the emulator:

  1. Code must be added to handle inter-control navigation.
  2. IDTXT2 must be set to inactive at startup (for the Z800).
  3. A list control should be used in place of the menu (for the T720), as it is designed to show only one selection at a time.  The list control appears to be unaffected by the apparent difference between the size of the control’s text border on each phone.

The necessary code revisions are shown below.  The necessarychanges are highlighted with comments.

.../*   The use of BREW SDK 1.0 is assumed.   This example demonstrates how to create a dialog at run time.  The dialog   has 3 controls: 2 ITextCtls, and 1 IMenuCtl.      This code, with only 1 exception, behaves the same way on the BREW Emulator    v2.0, and both tested handsets (the Sharp Z800 and Motorola T720).      The exception occurs when the clear key (key code AVK_CLR) is pressed while   an empty ITextCtl has the focus.  Specifically, the Sharp phone handles     AVK_CLR by returning TRUE from ITEXTCTL_HandleEvent(), whether the text    control is empty or not.  Recall that, in order for AVK_CLR to cause an    application to exit, the application's event handler must return FALSE   in response to the key event.  This difference does not mean there is   anything wrong with the Z800, it merely reflects the OEM's implementation   decision regarding AVK_CLR handling.  Thus different handsets can behave    differently in response to the same code. */...// The revised applet data structure..typedef struct _dlghardapp{   AEEApplet a;   IDialog *m_pDlg;  // control pointers added to app. data struct   ITextCtl *m_pTxt1, *m_pTxt2;   IMenuCtl *m_pMnu;   IControl *m_pFocusCtl;} dlghardapp;...static boolean dlghard_HandleEvent(IApplet * pi, AEEEvent eCode, uint16 wParam,                                   uint32 dwParam){   dlghardapp *papp = (dlghardapp*)pi;   switch (eCode)    {      case EVT_APP_START:      {         ...         /* Set up the first DialogItem for controls[0].  A list menu control             is used in place of a standard menu control.         */         pdi->controls[0].h.cls = AEECLSID_LISTCTL; // control's class ID         ...         if(papp->m_pTxt2)         {            ITEXTCTL_SetTitle(papp->m_pTxt2, NULL, 0, L"Text Control 2");            /* Call to SetActive() is needed for Sharp Z800 since both text                controls otherwise appear active when the application starts on                this phone.  The frame appears around the text control for a                split second on startup, then it disappears due to this call.            */            ITEXTCTL_SetActive(papp->m_pTxt2, FALSE); // unnecessary on MOT720            ITEXTCTL_Redraw(papp->m_pTxt2);         }/* IMENUCTL_SetTitle() is commented out since the title skews the List control   to the right by the length, in pixels, of the word "Menu".      If a title is really required, IDISPLAY_DrawText() could be used to position   it above the list control, thereby maintaining the list control's    horizontal size.            IMENUCTL_SetTitle(papp->m_pMnu, NULL, 0, L"Menu");*/         ...      /* Every key press generates the event sequence EVT_KEY_PRESS, EVT_KEY,          EVT_KEY_RELEASE.  The dialog first sends EVT_KEY_PRESS to the          application's event handler.  Then, the dialog gives the currently         active control (i.e. the control that has the focus) a chance to          handle the EVT_KEY event associated with the same key press.  The          EVT_KEY event will only be passed to the application if the control          with the focus does not handle it.  Thus, one can say that a control          "consumes" an event that it handles.                  EVT_KEY_PRESS must NOT be used for navigation as the EVT_KEY          associated with the same key press would be processed by the control         to which the focus is sent.  For example, if EVT_KEY_PRESS was used          for navigation and the DOWN key was pressed while IDTXT2 has the focus,          the EVT_KEY_PRESS handler would respond by moving the focus to the          list control (papp->m_pMnu), where the associated EVT_KEY would be          consumed, causing the list selection to change in response to the same          DOWN key!        */      case EVT_KEY:         switch(wParam)         {            /* On the emulator, MOT720 and Sharp Z800, pressing the clear key                in a text control deletes a char to the left of the cursor,                until the front of the control is reached.  If the text control               is empty, pressing the clear key at the front exits the                application only on the MOT720 (BREW v1.1) and the emulator                (v2.0).  On the Sharp Z800 (BREW v1.0), there is no response,               due to the aforementioned AVK_CLR handling.               If the list ctl is active, pressing the clear key causes the app.               to exit regardless of what platform the app. is running on.  This               is due to the fact that the EVT_KEY associated with the AVK_CLR               gets passed to this application event handler, since it is not               consumed by the list control (i.e. the list control is not                interested in AVK_CLR).                              In order to make the application's behavior on the Sharp Z800                conform to that observed on the other 2 platforms, a cursor               position tracking scheme would have to be implemented.  Then,               when the insertion point is positioned at the front of the                text control, and the length of the control's string is zero,               EVT_KEY_PRESS could be used to intercept the AVK_CLR and cause                the application to exit, via a call to ISHELL_CloseApplet().                              Please see the article "Low Level Management of Multi-Control                Screens Under BREW" for an example of a cursor position tracking               scheme that could be employed for this purpose.                           */            case AVK_CLR:               return FALSE;    // exit app.            /* For the phones, due to a bug in the BREW 1.x implementation, the                programmer must supply the navigation scheme that came for free with               the initial version of this code running on v2.0 of the emulator.               Note that this bug has been eliminated in BREW version 2.0.              */            case AVK_UP:               if(papp->m_pFocusCtl == (IControl*)papp->m_pTxt1)               {                  IDIALOG_SetFocus(papp->m_pDlg, IDMNU);                  papp->m_pFocusCtl = (IControl*)papp->m_pMnu;               }               else if(papp->m_pFocusCtl == (IControl*)papp->m_pTxt2)               {                  IDIALOG_SetFocus(papp->m_pDlg, IDTXT1);                  papp->m_pFocusCtl = (IControl*)papp->m_pTxt1;               }               break;            case AVK_DOWN:               if(papp->m_pFocusCtl == (IControl*)papp->m_pTxt1)               {                  IDIALOG_SetFocus(papp->m_pDlg, IDTXT2);                  papp->m_pFocusCtl = (IControl*)papp->m_pTxt2;               }               else if(papp->m_pFocusCtl == (IControl*)papp->m_pTxt2)               {                  IDIALOG_SetFocus(papp->m_pDlg, IDMNU);                  papp->m_pFocusCtl = (IControl*)papp->m_pMnu;               }               break;            case AVK_LEFT:               if(papp->m_pFocusCtl == (IControl*)papp->m_pMnu)               {                  IDIALOG_SetFocus(papp->m_pDlg, IDTXT2);                  papp->m_pFocusCtl = (IControl*)papp->m_pTxt2;               }               break;            case AVK_RIGHT:               if(papp->m_pFocusCtl == (IControl*)papp->m_pMnu)               {                  IDIALOG_SetFocus(papp->m_pDlg, IDTXT1);                  papp->m_pFocusCtl = (IControl*)papp->m_pTxt1;               }               break;         }   	         return TRUE;      ...   }   return FALSE;}

Conclusion
When the amount of code required to initialize the DialogInfo struct is comparedto that saved by using a dialog, it becomes clear that a developer seeking aplatform-agnostic code base should dispense with the dialog altogether. Instead, BREW programmers should use the individual controls to lay out eachuser interface at run time.  Even then, as demonstrated by the menu controlon the MOT720, the developer cannot be sure that one handset’s ideal UI codewill automatically perform as expected when ported to a different handset.

Thus, the dialog-based approach to user interface design covered in thisarticle is not recommended for general use.  Even so, the information presentedhere is useful because it helps a developer gain a deeper understanding of userinterface elements, event handling and BREW in general.

Source code for a non-dialog-based solution, behaviorally identical tothe dialog version just presented, is available for download (9K).  As with the dialog-based version above,pressing clear on the Sharp Z800 will onlycause the application to exit if the menu has the focus.  On the other twoplatforms, pressing clear while an empty text control has the focus will also cause the application toexit.  For another UI example that uses only the low-level controls, pleasesee the article Low Level Management of Multi-Control Screens Under BREW.

Perhaps the single, greatest lesson that can be gleaned from this article isthat one should regularly test code on the targeted handsets, instead of relyingexclusively on the emulator until development nears completion.

Originally published in the BREW Wireless Resource Center

Share the Post:
Share on facebook
Share on twitter
Share on linkedin

Overview

Recent Articles: