Alarm Sample Overview

Mobile native

The Alarm sample application demonstrates how you can implement recurring and on-time alarms using the Alarm API from the Tizen Application Framework.

The following figure illustrates the application views.

Figure: Alarm screens

Main view Recurring alarm view On time alarm view

The application is user non-interactive. After it is launched, 2 alarms are registered:

  • Recurring alarm is invoked 5 times with a 15-minute interval.
  • On-time alarm is invoked once, 15 minutes after the last recurring alarm invocation.

The registered alarms are invoked through the app_control event callback. When the callback is triggered, the predefined image and respective alarm text start blinking.

The following figure illustrates the user interface layout structure.

Figure: UI layout structure

UI layout structure

Prerequisites

To ensure proper application execution, the following privileges must be set:

  • http://tizen.org/privilege/systemsettings
  • http://tizen.org/privilege/alarm.set

Implementation

The Alarm application is very simple, so once it is created it handles only 2 types of application life-cycle events: app_create and app_control:

int
main(int argc, char *argv[])
{
   ui_app_lifecycle_callback_s event_callback = 
   {
      .create = app_create,
      .app_control = app_control,
   };

   int ret = ui_app_main(argc, argv, &event_callback, &ad);

   return ret;
}

In the above code snippet, the ad variable is used to store application-related data, such as UI object pointers or alarm identifiers.

The application life-cycle event callback functions are called in the following order:

  1. app_create()

    The app_create() function is responsible for creating the UI and initializing the alarms by calling the create_base_gui() and initialize_alarms() functions.

  2. app_control()

    The app_control() function handles incoming application control requests.

As the UI is not the subject of this application, its implementation is not covered in detail - just the following shortened snippet:

static void
create_base_gui(appdata_s *ad)
{
   // Window
   ad->win = elm_win_util_standard_add(PACKAGE, PACKAGE);

   // Conformant
   ad->conform = elm_conformant_add(ad->win);

   // Layout
   ad->layout = elm_layout_add(ad->win);

   // Show the window after the base GUI is set up
   evas_object_show(ad->win);
}

Creating Alarms

To initialize 2 types of alarms, the initialize_alarms() function invokes 2 subfunctions: recurring_alarm_set() and ontime_alarm_set():

  • The flow of creating a new recurring alarm that is fired with a 15-minute delay at 15-minute intervals is shown in the following code snippet:

    1. The recurring_alarm_set() function obtains an application control handle through the app_control_create() function.
    2. If the application control handle is obtained successfully, the APP_CONTROL_OPERATION_ALARM_RECURRING custom operation is bound by invoking the app_control_set_operation() function.

      This operation name is used to identify the alarm within the app_control callback and to distinguish alarm types.

      If the operation is successful, the target application package name is bound next using the app_control_set_app_id() function.

      Based on the provided package name, the alarm is invoked within the context of the referenced application by the provided package name.

    3. The recurring alarm is set using the alarm_schedule_after_delay() function.

      In this case, the alarm is scheduled with the ALARM_DELAY (15 minutes) delay and ALARMS_INTERVAL (15 minutes) period. As a result, the first alarm invocation occurs after a 15-minute delay, and the subsequent alarm invocations occur at 15-minute intervals.

      If ALARMS_INTERVAL is set to 0, the alarm is invoked only once after the ALARM_DELAY (15 minutes).

    4. If the alarm_schedule_after_delay() function succeeds, the alarm ID is returned and stored in the appdata_s structure. The returned alarm ID is assigned to the extra data of the app_control handle by default.
    5. The application control handle is released with the app_control_destroy() function.

    For convenience, the TRACE_ERROR_IF() macro is used to dump the output to the log subsystem.

    void
    recurring_alarm_set(appdata_s *appdata)
    {
       int ret;
       app_control_h app_control;
    
       ret = app_control_create(&app_control);
       if (TRACE_ERROR_IF(ret, "Function app_control_create() failed.")) 
       {
          return;
       }
    
       ret = app_control_set_operation(app_control, APP_CONTROL_OPERATION_ALARM_RECURRING);
       if (TRACE_ERROR_IF(ret, "Function app_control_set_operation() failed.")) 
       {
          app_control_destroy(app_control);
    
          return;
       }
    
       ret = app_control_set_app_id(app_control, PACKAGE);
       if (TRACE_ERROR_IF(ret, "Function app_control_set_app_id() failed.")) 
       {
          app_control_destroy(app_control);
    
          return;
       }
    
       ret = alarm_schedule_after_delay(app_control, ALARM_DELAY, ALARMS_INTERVAL, &appdata->recurring_alarm_id);
       TRACE_ERROR_IF(ret, "Function alarm_schedule_after_delay() failed.");
    
       ret = app_control_destroy(app_control);
       TRACE_ERROR_IF(ret, "Function app_control_destroy() failed.");
    }
    
  • The flow of creating a new on-time alarm that is fired at a specified date and time is shown in the following code snippet:

    1. The ontime_alarm_set() function obtains an application control handle through the app_control_create() function.
    2. If the application control handle is obtained successfully, the APP_CONTROL_OPERATION_ALARM_ONTIME custom operation is bound by invoking the app_control_set_operation() function.

      This operation name is used to identify the alarm within the app_control callback and to distinguish alarm types.

      If the operation is successful, the target application package name is bound next using the app_control_set_app_id() function.

      Based on the provided package name, the alarm is invoked within the context of the referenced application.

    3. The on-time alarm is set using the alarm_schedule_at_date() function.

      In this case, the alarm is scheduled at a specified point in time:

      time_t t_alarm = time(NULL) + ALARM_DELAY + ALARMS_INTERVAL * RECURRING_ALARMS_TO_BE_INVOKED;

      As a result, the on-time alarm is invoked ALARMS_INTERVAL (15 minutes) after the last recurring alarm is fired.

    4. If the alarm_schedule_at_date() function succeeds, the alarm ID is returned and stored in the appdata_s structure. The returned alarm ID is assigned to the extra data of the app_control handle by default.
    5. The application control handle is released with the app_control_destroy() function.

    For convenience, the TRACE_ERROR_IF() macro is used to dump the output to the log subsystem.

    static void
    ontime_alarm_set(appdata_s *appdata)
    {
       int ret;
       app_control_h app_control;
    
       ret = app_control_create(&app_control);
       if (TRACE_ERROR_IF(ret, "Function app_control_create() failed.")) 
       {
          return;
       }
    
       ret = app_control_set_operation(app_control, APP_CONTROL_OPERATION_ALARM_ONTIME);
       if (TRACE_ERROR_IF(ret, "Function app_control_set_operation() failed.")) 
       {
          app_control_destroy(app_control);
    
          return;
       }
    
       ret = app_control_set_app_id(app_control, PACKAGE);
       if (TRACE_ERROR_IF(ret, "Function app_control_set_app_id() failed.")) 
       {
          app_control_destroy(app_control);
    
          return;
       }
    
       time_t t_alarm = time(NULL) + ALARM_DELAY + ALARMS_INTERVAL * RECURRING_ALARMS_TO_BE_INVOKED;
    
       ret = alarm_schedule_at_date(app_control, localtime(&t_alarm), 0, &appdata->ontime_alarm_id);
       TRACE_ERROR_IF(ret, "Function alarm_schedule_at_date() failed.");
    
       ret = app_control_destroy(app_control);
       TRACE_ERROR_IF(ret, "Function app_control_destroy() failed.");
    }
    

At this point, all alarms are set and ready to fire as scheduled.

Receiving Alarms

In order to receive the alarms, you must handle them properly within the app_control() callback function:

  1. The app_control() callback function is called whenever an external call from the application framework arrives. First of all, the received operation must be extracted using the app_control_get_operation() function. The operation variable holds the name of the operation to be executed and is used to handle appropriate tasks by means of the function execution assigned to the operations:

    • recurring_alarm_invoked() for APP_CONTROL_OPERATION_ALARM_RECURRING
    • ontime_alarm_invoked() for APP_CONTROL_OPERATION_ALARM_ONTIME

    In case of this application, only 2 types of application control operations are supported.

    For convenience, the TRACE_ERROR_IF() macro is used to dump the output to the log subsystem.

    static void
    app_control(app_control_h app_control, void *data)
    {
       appdata_s *appdata = (appdata_s*)data;
       char *operation = NULL;
       int ret;
    
       ret = app_control_get_operation(app_control, &operation);
       if (TRACE_ERROR_IF(ret, "Function app_control_get_operation() failed.")) 
       {
          return;
       }
    
       if (!strncmp(APP_CONTROL_OPERATION_ALARM_RECURRING, operation, strlen(APP_CONTROL_OPERATION_ALARM_RECURRING))) 
       {
          recurring_alarm_invoked(app_control, appdata);
       } 
       else if (!strncmp(APP_CONTROL_OPERATION_ALARM_ONTIME, operation, strlen(APP_CONTROL_OPERATION_ALARM_ONTIME))) 
       {
          ontime_alarm_invoked(app_control, appdata);
       }
    
       free(operation);
    }
    
  2. If the alarm control arrives and is recognized as a recurring alarm, the recurring_alarm_invoked() function is called:

    1. Identify the alarm by extracting the extra data from the app_control handle using the app_control_get_extra_data() function with a predefined APP_CONTROL_DATA_ALARM_ID key name.
    2. The extracted data contains an identifier of the arrived alarm in a string format. Compare it to the identifier stored in the appdata structure for the created recurring alarm. If the IDs do not match, this is not the alarm you are waiting for.
    3. To notify the end user about the alarm, send EDJE signals to the UI layer to display visual notifications (image and text message). An additional timer is set to hide the visual notifications after a predefined time interval.

    This application assumes that the recurring alarm is invoked RECURRING_ALARMS_TO_BE_INVOKED (5) times. So, if the number of recurring alarms invocations exceeds 5, the alarm is canceled with the alarm_cancel() function.

    static void
    recurring_alarm_invoked(app_control_h app_control, appdata_s *appdata)
    {
       int ret;
       char *alarm_data = NULL;
    
       ret = app_control_get_extra_data(app_control, APP_CONTROL_DATA_ALARM_ID, &alarm_data);
       if (TRACE_ERROR_IF(ret, "Function app_control_get_extra_data() failed.")) 
       {
          return;
       }
    
       if (atoi(alarm_data) != appdata->recurring_alarm_id) 
       {
          return;
       }
    
       appdata->recurring_alarm_count++;
    
       alarm_fired_signal_emit(appdata, PART_RECURRING_ALARM_STATE_TEXT);
    
       ecore_timer_add(ALARM_MESSAGE_TIMEOUT, recurring_alarm_timer_cb, appdata);
    
       char *time_str = current_time_get();
       TRACE_INFO("Recurring alarm #%d invoked at %s", appdata->recurring_alarm_count, time_str);
       free(time_str);
    
       if (appdata->recurring_alarm_count < RECURRING_ALARMS_TO_BE_INVOKED) 
       {
          return;
       }
    
       ret = alarm_cancel(appdata->recurring_alarm_id);
       if (TRACE_ERROR_IF(ret, "Function alarm_cancel() failed.")) 
       {
          return;
       }
    
       TRACE_INFO("Recurring alarm canceled");
    }
    
  3. If the alarm control arrives and is recognized as an on-time alarm, the ontime_alarm_invoked() function is called:

    1. Identify the alarm by extracting the extra data from the app_control handle using the app_control_get_extra_data() function with a predefined APP_CONTROL_DATA_ALARM_ID key name.
    2. The extracted data contains an identifier of the arrived alarm in a string format. Compare it to the identifier stored in the appdata structure for the created on-time alarm. If the IDs do not match, this is not the alarm you are waiting for.
    3. To notify the end user about the alarm, send EDJE signals to the UI layer to display visual notifications (image and text message).

    The on-time alarm needs no canceling, as it is invoked only once.

    static void
    ontime_alarm_invoked(app_control_h app_control, appdata_s *appdata)
    {
       int ret;
       char *alarm_data = NULL;
    
       ret = app_control_get_extra_data(app_control, APP_CONTROL_DATA_ALARM_ID, &alarm_data);
       if (TRACE_ERROR_IF(ret, "Function app_control_get_extra_data() failed.")) 
       {
          return;
       }
    
       if (atoi(alarm_data) != appdata->ontime_alarm_id) 
       {
          return;
       }
    
       alarm_fired_signal_emit(appdata, PART_ONTIME_ALARM_STATE_TEXT);
    
       char *time_str = current_time_get();
    
       TRACE_INFO("Ontime alarm invoked at %s", time_str);
       free(time_str);
    }