http://www.developer.com/

Back to article

Getting a User's Attention in Your Palm OS Applications


August 2, 2005

Alarm and Attention Managers

Even though Palm OS is not mainly a multitasking system, you definitely experienced the situations when, for example, reminders pop up to inform you about meetings, or an SMS message was just received, and so forth. Palm OS provides several managers that may be used together, to get full control over notifying the user about various events occurring in the system. Again, under term "event" I mean everything that needs a user's attention. So, coming back to formal definitions, Palm OS has Notification Manager, Attention Manager, and Alarm Manager. Notifications were discussed in previous articles, so here we will deal with Attentions.

Attention Manager is a mechanism by which your application can buzz the user if it has something to tell him. If, for instance, you develop a driver, you can interact with the user from the driver's callback functions if needed. Besides, some applications work with communication devices that have no user interface, so Attention Manager features is a way to go. It is important to notice that Attention Manager itself is responsible only for interactions with user rather than events generation. Hence, it is usually used in conjunction with other managers (like Alarm Manager) to perform desired functionality.

Alarm Manager handles real-time monitoring to detect when some point in time was reached. It can be used to perform periodic tasks or show alarms at the appropriate time. In the last case, an application is responsible for providing any required user interface because Alarm Manager doesn't have one on its own. The same is correct for sounds and other effects. You also may use Attention Manager to signal to the user about an event that occurred.

In the following sections, you will see how to use both managers in more detail.

Working with Attention Manager

Attempts types

To get started, let us take a look at different types of attention-getting attempts. The Palm documentation defines two of them: "insistent" and "subtle." They are actually the same, but differ in the manner of "irritation" the user experiences in each case. Insistent attempts interrupt the regular working flow—by producing special effects to gain your attention. Subtle attempts behave like an additional indicator on the screen to inform you about less-critical events—incoming e-mail or an SMS message. This type of attempts doesn't usually use any special effects.

Let me briefly overview each type of Attention. As was stated, an Insistent attention tries to catch the user's eye, so Attention Manager displays a dialog. You may find two types of them: Details and List.

Areas within red rectangles are drawn by the application that performs this attempt. Attention Manager will provide just a dialog box and draw a title and buttons. The function of all buttons on forms is intuitively clear from their titles. The user can accept, snooze, clear, or go to an attention item. All the rest is up to you. It will take you only a few minutes playing around with such alerts to understand all the available options.

The first picture shows an alert set to be risen at specified time. The second one illustrates the situation when several events have occurred, and now there is a list of them. To reach the details of each event, simply tap it. When may this happen? For example, when another application tries to get the user's attention. Here, your program is able to paint an icon and couple of text lines. Please note that the checkbox is provided by Attention Manager.

Events that were snoozed will be redisplayed again after some time. Attention Manager has the only "snooze" timer, so if you select this option, it will influence all events as a whole. Also, to ensure that the user will pay attention to the displayed dialog, any soft- and hardware buttons are disables at that moment.

Another type of attention attempt is subtle one. You can see an example in the following picture:

Every standard form with a title will show a blinking indicator (I've marked it by red color), except in the following cases:

  • Attention Manager's queue is empty
  • Modal Dialog style is used for the title
  • The title is too narrow to show anything else
  • The application draws in the title area
  • A custom title is used

Besides, the indicator will blink in a different manner depending on whether the user has seen all notifications or not.

Wrong Usage Scenarios

The Attention Manager was designed for specific usage. Its intended goal is to provide a mechanism for gaining the user's attention in cases that don't require immediate reaction. You can treat it as some convenient way to remind or inform the user about important but suspendable events. For emergency cases, it is not a way to go.

Next, Attention Manager doesn't deal with displayed items themselves, so dismissing the reminder doesn't influence actual data. Attention Manager should not replace regular error messages that are displaying. Thus, use it as it was supposed to be.

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.

Sitemap | Contact Us

Thanks for your registration, follow us on our social networks to keep up-to-date