July 30, 2014
Hot Topics:
RSS RSS feed Download our iPhone app

Programming Palm OS Notifications

  • September 10, 2003
  • By Alex Gusev
  • Send Email »
  • More Articles »

Preface

As we discussed in the previous article, a Palm OS application may interact with other inhabitants of a PDA device by using launch codes, Exchange Manager or Local Exchange Library, general Palm OS notifications (if Notification Feature Set is available), or a Helper API. It may be difficult to decide which of them to use for each specific case. This article is targeting the last two methods.

General Notifications

As you may guess, notifications are pretty similar to launch codes. They are sent by the OS or by other applications when some events occur. The important difference is that notification can be sent to any code resource such as an application, shared library, or hack, while launch codes can deal with applications only. Also, notifications are sent only to those clients that have registered to receive them. From a performance point of view, it seems to be more efficient in comparison to launch codes, which are sent to all installed applications.

Similar to the launch codes technique, an application may define its own notifications, but it's a rare practice. In major cases, only predefined notifications are in use. When an application needs to get notifications, it must register for it. You'll find the following definitions in NotifyMgr.h:

Err SysNotifyRegister(UInt16 cardNo, LocalID dbID,
                      UInt32 notifyType,
                      SysNotifyProcPtr callbackP, Int8 priority,
                      void *userDataP);
Err SysNotifyUnregister(UInt16 cardNo, LocalID dbID,
                        UInt32 notifyType, Int8 priority);
Err SysNotifyBroadcast(SysNotifyParamType *notify);

The client calls SysNotifyRegister to register for a given notification and is kept registered until the reset or explicit call of SysNotifyUnregister. You may call SysNotifyBroadcast to send a desired notification to all registered clients. Function parameters are self-documented enough, so here we just concentrate on some important details.

The third parameter of SysNotifyRegister is a pointer to the callback function. If you register an application for notifications, you may pass NULL there. That will mean that the application should receive a sysAppLaunchCmdNotify launch code with a parameter block of the SysNotifyParamType type. It is defined as:

typedef struct SysNotifyParamType
  {
  UInt32     notifyType;        // What type of event occurred?
  UInt32     broadcaster;       // normally creator code of
                                // broadcasting app
  void *     notifyDetailsP;    // ptr to notification-specific
                                // data, if any
  void *     userDataP;         // user specified ptr passed back
                                // with notification
  Boolean    handled;           // true if event is handled yet
  UInt8      reserved2;
  } SysNotifyParamType;

In other words, userDataP will be a part of it. Note that sysAppLaunchCmdNotify has no access to global variables, so you should pass all data you need to handle this launch code through the userDataP parameter. Some notifications use notifyDetailsP to pass additional info.

When you need to notify a shared library, you may supply a Notification handler. In this case, it is the only option, because there is no PilotMain function here. What you really must remember is that the userDataP pointer must remain valid all the time from registation to notification broadcasting. Otherwise, the system will simply crash at notification time.

The last thing is priority. Usually, you will use sysNotifyNormalPriority (0), which means that the application doesn't need any additional treatment during notification receipt. The priority value controls the order in which notifications will be synchronously sent. The lower, the earlier. Only if your application really must receive notifications in a certain order, you can define a priority other than sysNotifyNormalPriority. Palm recommends to use numbers such as 0x20, 0x40, and 0x60; in other words, whose less significant bit is 0. In addition, you should be carefull in choosing a priority value to avoid conflicts with the OS or other applications.

Now, let's take a quick look at common event flow that is possible with notifications. According to SDK documentation,

three general types of event flow are possible using the notification manager:

  1. Single consumer
    Each client is notified that the event has occurred and handles it in its own way without modifying any information in the parameter block.
  2. Collaborative
    Each client can add information to the notification's parameter block, allowing the data to be accumulated for all clients. This style of notification could be used, for example, to build a menu dynamically by letting each client add its own menu text. The sysNotifyMenuCmdBarOpenEvent is similar to this style of notification.
  3. Collective
    Each client can add information to the notification's parameter block, allowing the data to be accumulated for all clients. This style of notification could be used, for example, to build a menu dynamically by letting each client add its own menu text. The sysNotifyMenuCmdBarOpenEvent is similar to this style of notification.

Thus, applications have a great choice of communication methods, determined according to their needs. The obvious fact is that it's not recommended to proceed with long-term operations inside notification handlers. The reason is pretty simple—it may block other clients from handling this notification at the proper time. In such cases, you may use the following simple trick (in the case of an application for simplicity):

Err SysNotifyProcHandler(SysNotifyParamType *notifyParamsP);
........................
// somewhere in PilotMain switch
case sysAppLaunchCmdNotify:
{
   SysNotifyParamType *notifyParamsP =
                      (SysNotifyParamType*)cmdPBP;
   if (notifyParamsP->notifyType == someEvent)
   {
      SysNotifyParamType notifyParm;

      // Define data struct and initialize it here
      GlobalDataContainer GlobalData;
      .....

      // Create new notification block for custom
      // custDeferredNotifyEvent
      notifyParam.notifyType     = custDeferredNotifyEvent;
      notifyParam.broadcaster    = custCreatorID;
      notifyParam.notifyDetailsP = NULL;
      notifyParam.handled        = false;

      // Register for this new notification
      SysNotifyRegister(cardNo, appDBID, custDeferredNotifyEvent,
                        NULL, sysNotifyNormalPriority,
                        &GlobalData);

      // Broadcast the notification
      SysNotifyBroadcastDeferred(&notifyParam, NULL);

   }
   else
   {
      if (notifyParamsP->notifyType == custDeferredNotifyEvent)
         SysNotifyProcHandler(notifyParamsP);
   }
}

The idea here is as simple as pie. When someEvent is received, the application executes a minimal procedure to define a new notification, register for it, and finally broadcast it. All the real job is performed in SysNotifyProcHandler. Note that the new notification is sent by the SysNotifyBroadcastDeferred call. In such cases, the current event will be handled first and only then a new notification will be broadcast to all registered clients. Hence, no other applications will be blocked. Well, there is one special case of notifications, the sleep and wake ones, but I'll leave it as your homework.

Helper API

Starting from Palm OS version 4.0, a special notification code was defined. This is sysNotifyHelperEvent. It was introduced as a way for one application to request some service from another one. The standard example is the Dialer application; Address Book uses it via this notification. You may want to implement both the client and server parts (application and helper according to common terms).

The helper API is a good choice when you have no knowledge about your target application or you want to communicate to any code resource. In the case of a launch code mechanism, you should know the card number and local ID of the calling application to launch it, plus which launch code needs to be sent. With notifications, you just broadcast some 'standard' event, and that's all.

sysNotifyHelperEvent defines three main possible actions: enumerate a list of available services (kHelperNotifyActionCodeEnumerate), proceed validation if service is available to be performed (kHelperNotifyActionCodeValidate), and execute service (kHelperNotifyActionCodeExecute). The HelperServiceClass.h header files describe recently available services (dialing, e-mail, sms, and fax). You may declare your own service by providing a unique creator ID (for example, your app's ID).

As an example of requesting a service, let's consider how to use Helper API to send an e-mail.

Boolean SendMessage()
{
   SysNotifyParamType param;
   HelperNotifyEventType details;
   HelperNotifyExecuteType execute;
   HelperServiceEMailDetailsType email;

   param.notifyType     = sysNotifyHelperEvent;
   param.broadcaster    = 'ALEX';
   param.notifyDetailsP = &details;
   param.handled        = false;

   details.version       = kHelperNotifyCurrentVersion;
   details.actionCode    = kHelperNotifyActionCodeExecute;
   details.data.executeP = &execute;

   execute.serviceClassID = kHelperServiceClassIDEMail;
   execute.helperAppID    = 0;
   execute.dataP          = "a_gusev@hotmail.com";
   execute.displayedName  = "Alex";
   execute.detailsP       = &email;
   execute.err            = errNone;
   
   email.version = 1;
   email.cc      = NULL;
   email.subject = "Test e-mail";
   email.message = "Hello,world!";

   SysNotifyBroadcast(&param);

   // Check error code
   if (!param.handled)
   // Not handled so exit the list - Unexpected error
      return true;
   else
      return (execute.err == errNone);
}

There are several points to be noted here:

  1. First and foremost, helper notifications should be broadcast synchronously by using the SysNotifyBroadcast function.
  2. The notifyDetailsP member of the SysNotifyParamType struct points to the HelperNotifyEventType struct, which is used for interaction between application and helper.
  3. The application declares helperAppID to select the desired service provider or puts a 0 there to use any available one.
  4. The helper can allocate memory while it handles the request. The application is responsible for freeing all allocated memory, no matter who has allocated it.
  5. And, finally, to indicate the status of operation and possible errors, the handled field of SysNotifyParamType and the err field of the HelperNotifyEventType structure are used.

Well, what's been left untouched until now is how to implement the helper. It's not a big deal. All you should do is to register for sysNotifyHelperEvent receiving and then implement handlers for three helper actions noted above (enumerate, validate, and execute). Please refer to the SDK documentation for further details.

Where to go

In addition to 'trivial' network and serial communications, Palm OS offers one more method of inter-application interaction, Exchange Manager API and Local Exchange Library. We will consider it in the next article.

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.

# # #






Comment and Contribute

 


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

 

 


Sitemap | Contact Us

Rocket Fuel