October 22, 2014
Hot Topics:
RSS RSS feed Download our iPhone app

Getting a User's Attention in Your Palm OS Applications

  • August 2, 2005
  • By Alex Gusev
  • Send Email »
  • More Articles »

Move to the Code

Bringing Your Information up to the User's Attention

Now, having all this theory in mind, you are ready to code some meaningful example. First of all, look at the available Attention Manager's functions:

Err AttnGetAttention (UInt16 cardNo, LocalID dbID, UInt32 userData,
                      AttnCallbackProc *callbackFnP,
                      AttnLevelType level, AttnFlagsType flags,
                      UInt16 nagRateInSeconds,
                      UInt16 nagRepeatLimit);
Boolean AttnUpdate (UInt16 cardNo, LocalID dbID, UInt32 userData,
                    AttnCallbackProc *callbackFnP,
                    AttnFlagsType *flagsP,
                    UInt16 *nagRateInSecondsP,
                    UInt16 *nagRepeatLimitP);
Boolean AttnForgetIt (UInt16 cardNo, LocalID dbID, UInt32 userData);
UInt16 AttnGetCounts (UInt16 cardNo, LocalID dbID,
                      UInt16 *insistentCountP, UInt16 *subtleCountP);
void AttnListOpen (void);
void AttnIterate (UInt16 cardNo, LocalID dbID, UInt32 iterationData);
Err AttnDoSpecialEffects(AttnFlagsType flags);
void AttnIndicatorEnable(Boolean enableIt);
Boolean AttnIndicatorEnabled(void);

As you see, there are quite a few functions. Your interest will be focused on the first two functions; these allow you to generate and update an Attention attempt. They both have similar parameters, and the first three uniquely identify the attention attempt.

Let me briefly discuss the rest of the parameters. AttnCallbackProc *callbackFnP is a pointer to the callback function that is called by Attention Manager in response to various user reactions or when an attention item is to be redrawn. If this parameter is NULL, Attention Manager will send a sysAppLaunchCmdAttention launch code to your application instead of calling a callback function. AttnLevelType level allows you to select either an kAttnLevelInsistent or kAttnLevelSubtle attempt type. AttnFlagsType flags tell Attention Manager which effects to apply for a given item. You can use sound, LED blinking, vibration, or some custom effects. These flags also command the Attention Manager how to relate to the default behavior defined in the general user's preferences. And finally, the last two parameters control nagging stuff. AttnUpdate, in addition to AttnGetAttention, allows you to update an existing attention item; for example, you can assess a new callback procedure or change all other parameters.

A decision of which 'notification' method (callback or launch code) to choose for specific situation highly depends on a structure of your application. For relatively small programs, it doesn't matter at all; but for large projects, the callback funtion may cause some problems. The matter is that you have to be sure that at the moment Attention Manager calls your callback this particular code segment is still available; in other words, located at the same memory address or was not deleted. The launch codes mechanism usually doesn't result in such scenarios.

Before you glance at the code sample, let me note a couple of simple functions: AttnForgetIt and AttnIterate. The first one is used to inform Attention Manager that a given item is no longer relevant, so Attention Manager may forget about it. Usually, you will call it in response to a "Go To" button press—when a user has decided to look into your attention item. AttnIterate causes the Attention Manager to call a callback routine or send a launch code for every pending item that matches a given cardNo and dbID. Such iteration may be required, for instance, after a HotSync session and so forth to update pending attentions.

Well, let me start with samples. First, the Attention callback function is listed below:

static Err AttnCallbackFunc(AttnCommandType command,
                            UInt32 userData,
                            AttnCommandArgsType *commandArgsP)
{
   char szText[] = "Visit Developer.com";
   if ( kAttnCommandDrawDetail == command )
   {
      Coord x = commandArgsP->drawDetail.bounds.topLeft.x;
      Coord y = commandArgsP->drawDetail.bounds.topLeft.y;
      Coord w = commandArgsP->drawDetail.bounds.extent.x;
      MemHandle resH = DmGetResource(bitmapRsc, TestBmp);
      WinDrawBitmap((BitmapType*)MemHandleLock(resH), x, y + 3);
      MemHandleUnlock(resH);
      DmReleaseResource(resH);
      FontID curFont = FntSetFont (largeBoldFont);
      WinDrawTruncChars(szText, StrLen(szText),
                        x + 27,
                        y + 3,
                        w - x);
      FntSetFont (curFont);
   }
   else if ( kAttnCommandDrawList == command )
   {
      Coord x = commandArgsP->drawList.bounds.topLeft.x;
      Coord y = commandArgsP->drawList.bounds.topLeft.y;
      Coord w = commandArgsP->drawList.bounds.extent.x;
      FontID curFont = FntSetFont (boldFont);
      WinDrawTruncChars(szText, StrLen(szText),
                        x + 3,
                        y,
                        w - x);
      FntSetFont (curFont);
   }
   else if ( kAttnCommandGoThere == command )
   {
      Err err;
      UInt16 cardNo;
      LocalID dbID;
      err = SysCurAppDatabase(&cardNo,&dbID);
      AttnForgetIt(cardNo, dbID, userData);
   }
   else if ( kAttnCommandPlaySound == command )
   {
      SndPlaySystemSound(sndWarning);
   }
   return errNone;
}

This callback receives full info about what Attention Manager wants from the recent attention item and acts accordingly. It means that the callback knows what a command is, what the drawing area is, and so forth. Actually, the same function is called from the launch code handler.

The next code snippets illustrates a usage of different API to get user's attention, update pending items, and so forth:

static Boolean OnGetAttn()
{
   Err err;
   UInt16 cardNo;
   LocalID dbID;
   err = SysCurAppDatabase(&cardNo,&dbID);
   err = AttnGetAttention(cardNo, dbID,
                          g_nEventID++,
                          AttnCallbackFunc,
                          kAttnLevelInsistent, kAttnFlagsAlwaysLED,
                          300, 10);
   return true;
}
static Boolean OnGetSubtleAttn()
{
   Err err;
   UInt16 cardNo;
   LocalID dbID;
   err = SysCurAppDatabase(&cardNo,&dbID);
   err = AttnGetAttention(cardNo, dbID,
                          g_nEventID++,
                          AttnCallbackFunc,
                          kAttnLevelSubtle, kAttnFlagsAlwaysLED,
                          300, 10);
   return true;
}
static Boolean OnUseLaunchCode()
{
   Err err;
   UInt16 cardNo;
   LocalID dbID;
   err = SysCurAppDatabase(&cardNo,&dbID);
   err = AttnGetAttention(cardNo, dbID,
                          g_nEventID++,
                          NULL,
                          kAttnLevelInsistent, kAttnFlagsAlwaysLED,
                          300, 10);
   return true;
}
static Boolean OnUpdateAttn()
{
   Err err;
   UInt16 cardNo;
   LocalID dbID;
   UInt16 nagRateInSeconds = 30, nagRepeatLimit = 2;
   AttnFlagsType flags = kAttnFlagsAlwaysSound;
   err = SysCurAppDatabase(&cardNo,&dbID);
   err = AttnUpdate(cardNo, dbID,
                    g_nEventID-1,    // for the last attention only
                    AttnCallbackNewFunc,
                    &flags,
                    &nagRateInSeconds, &nagRepeatLimit);
   return true;
}

For simplicity, all these functions increase userData parameter at every call. In real situation you can apply your own logic here.

Let me discuss one scenario when you might want to dismiss the Attention Manager dialog completely. This is not so rare a case as you might think. Suppose that you handle extansion cards' insertion or removal or any hardware events that may occur while the Attention Manager dialog is open for some reason. In response to such incoming notifications, you can call the AttnForgetIt function to get rid of some pending attention items. The problem is that the whole dialog will remain on the screen regardless of how many items are left there. So, in the worst case, Attention Manager's dialog will be empty. Naturally, you would like to close it somehow. The simplest way to do it is to simulate a button tap on this dialog so that FrmDoDialog will exit:

// Get recently active form
FormType *frmP = FrmGetActiveForm();
UInt16 defaultButtonID = FrmGlueGetDefaultButtonID(frmP);
// Create new event and place in to the event queue
EventType newEvent;
MemSet(&newEvent, sizeof(newEvent), 0);
newEvent.eType = ctlSelectEvent;
newEvent.data.ctlSelect.controlID = defaultButtonID;
newEvent.data.ctlSelect.pControl = (ControlType*)FrmGetObjectPtr(frmP,
                                   FrmGetObjectIndex(frmP,
                                   defaultButtonID));
EvtAddEventToQueue(&newEvent);
// and finally dismiss an item
AttnForgetIt(cardNo, dbID, userData);

Making Special Effects

As I have noted above, you can request some special effects upon generating an attention item; for example, LED blinking, vibration, playing a sound, or any other custom effect. A good practice is to verify whether the PDA has desired capabilities, for instance as follows:

UInt32 caps;
FtrGet(kAttnFtrCreator,kAttnFtrCapabilities,&caps);
if ( caps & kAttnFlagsHasLED == kAttnFlagsHasLED )
{
// set appropriate flags
}

If you have a requested sound effect, Attention Manager will send a kAttnCommandPlaySound command. Your application, in turn, may the play sound based either on user's preferences or its own using Sound Manager; say, calling SndPlaySystemSound as a simplest example.

If you have specified a kAttnFlagsAlwaysCustomEffect flag, you'll be able to surprise the user by producing something gorgeous in response to a kAttnCommandCustomEffect command. Anyway, in both cases, the system doesn't inform you which sound to play or what is a special effect. You have to store it in the application's preferences or hardcode it.

Download

Download the accompanying code's zip file here.

About the Author

Alex Gusev started to play with mainframes at the end of the 1980s, using Pascal and REXX, but soon switched to C/C++ and Java on different platforms. When mobile PDAs seriously rose their heads in the IT market, Alex did it too. Now, he works at an international retail software company as a team leader of the Mobile R department, making programmers' lives in the mobile jungles a little bit simpler.





Page 2 of 2



Comment and Contribute

 


(Maximum characters: 1200). You have characters left.

 

 


Sitemap | Contact Us

Rocket Fuel