SyncAdapter(M) Sample Overview

Mobile native

The Sync Adapter sample demonstrates how you can add different sync requests to the sync manager to schedule data synchronization tasks.

The following figure illustrates the main screen of the application.

Figure: Sync Adapter main screen view

Sync Adapter main screen view

The application opens with the main screen, which displays a list of Sync Adapter's features:

  • To create an account, click Create an account.
  • To set the sync in the accountless mode, click Set as accountless.
  • To request all sync jobs with corresponding settings, click Start sync with settings.
  • To get and remove all registered sync jobs, click Manage sync jobs.

The application uses the libaccounts-svc module to work with the accounts database and the elementary module to support the UI requirements.

Prerequisites

  • Sync Adapter's application ID must be org.example.syncadapter.ui, because the Sync Adapter Service uses this ID as a fixed value when it communicates with the Sync Adapter UI application. Otherwise, the application control communication does not operate properly.

    In addition, the Sync Adapter's package name must be org.example.syncadapter (same as the Sync Adapter Service).

  • The Sync Adapter and Sync Adapter Service packages must be coupled during the build process. To couple the packages:
    1. On the Tizen IDE, right-click the Sync Adapter project and select Properties.
    2. Select Project References and find Sync Adapter Service.
    3. Select the Sync Adapter Service check box and click OK.

    In the Project Explorer view, a with SyncAdapter message appears next to the Sync Adapter Service project name showing that you have coupled it successfully.

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

    • http://tizen.org/privilege/account.read
    • http://tizen.org/privilege/account.write
    • http://tizen.org/privilege/alarm.set
    • http://tizen.org/privilege/appmanager.launch
    • http://tizen.org/privilege/calendar.read
    • http://tizen.org/privilege/contact.read

Implementation

Application Initialization

To initialize the application:

  1. Launch the Sync Adapter Service, which acts as a sync adapter to this UI application. The service application must be built and included along with the Sync Adapter UI application in the package.

    The SYNC_ADAPTER_SERVICE_APP_ID must be defined as the App ID of the service application which acts as a sync adapter. For more information, see Sync Adapter Service Sample Overview.

    #define SYNC_ADAPTER_SERVICE_APP_ID "org.tizen.syncadapter.service"
    
    /*
     * Draw the Sync Adapter's main menu
     */
    static void
    create_sync_main_menu(app_data_s *ad)
    {
       /*
        * The Sync Adapter should send request to launch the Sync Adapter Service
        * Then, the Sync Adapter Service will set callback functions by using sync-adapter API
        * Without below steps, the Sync Adapter can't receive the result of sync operation
        * through the Sync Adapter Service
        */
       app_control_h app_control;
       int ret = app_control_create(&app_control);
       if (ret != APP_CONTROL_ERROR_NONE) {
          dlog_print(DLOG_INFO, LOG_TAG, "Creating app_control handle is failed [%d : %s]", ret, get_error_message(ret));
          return;
       }
       /* Set the Sync Adapter Service App ID for launching it */
       ret = app_control_set_app_id(app_control, SYNC_ADAPTER_SERVICE_APP_ID);
       if (ret != APP_CONTROL_ERROR_NONE) {
          dlog_print(DLOG_INFO, LOG_TAG, "Setting app id is failed [%d : %s]", ret, get_error_message(ret));
          return;
       }
       /* Send application launch request */
       ret = app_control_send_launch_request(app_control, NULL, NULL);
       if (ret == APP_CONTROL_ERROR_NONE)
          dlog_print(DLOG_INFO, LOG_TAG, "Launching sync service app successfully [%s]", SYNC_ADAPTER_SERVICE_APP_ID);
       else {
          dlog_print(DLOG_INFO, LOG_TAG, "Launching sync service app is failed [%d : %s]", ret, get_error_message(ret));
          return;
       }
    }
    
  2. If you click Start Sync on the Start sync with settings screen without selecting an account mode, the Sync Request API cannot deliver the request, and a popup text is shown at the bottom of the screen (on the left in the following figure).

    You must first create an account or set up as accountless on the main screen. Afterwards, you can add sync jobs with the account mode you selected.

    Figure: Select account mode

    Select account Create account Set as accountless

    • Click Create an account to create a dummy account and pass it to the Sync Manager API (the result is shown in the middle in the above figure). Enable sync support on the account.

      /*
       * Create an account handle for registering and managing sync job with account
       */
      static void
      create_account()
      {
         /* Create an account handle */
         int ret = account_create(&account);
         if (ret != ACCOUNT_ERROR_NONE) {
            dlog_print(DLOG_INFO, LOG_TAG, "account_create() is failed [%d : %s]", ret, get_error_message(ret));
            return;
         }
      
         /* Set user name in the account handle */
         ret = account_set_user_name(account, USER_NAME);
         if (ret != ACCOUNT_ERROR_NONE) {
            dlog_print(DLOG_INFO, LOG_TAG, "account_set_user_name() is failed [%d : %s]", ret, get_error_message(ret));
            return;
         }
      
         /* Set package name in the account handle */
         ret = account_set_package_name(account, PKG_NAME);
         if (ret != ACCOUNT_ERROR_NONE) {
            dlog_print(DLOG_INFO, LOG_TAG, "account_set_package_name() is failed [%d : %s]", ret, get_error_message(ret));
            return;
         }
      
         /* Set Account Capabilities in the account handle for Calendar and Contact */
         ret = account_set_capability(account, ACCOUNT_SUPPORTS_CAPABILITY_CALENDAR, ACCOUNT_CAPABILITY_ENABLED);
         if (ret != ACCOUNT_ERROR_NONE)
            dlog_print(DLOG_INFO, LOG_TAG, "account_set_capability() for calendar is failed [%d : %s]", ret, get_error_message(ret));
         ret = account_set_capability(account, ACCOUNT_SUPPORTS_CAPABILITY_CONTACT, ACCOUNT_CAPABILITY_ENABLED);
         if (ret != ACCOUNT_ERROR_NONE)
            dlog_print(DLOG_INFO, LOG_TAG, "account_set_capability() for contact is failed [%d : %s]", ret, get_error_message(ret));
      
         /* Set sync support on the account handle */
         ret = account_set_sync_support(account, ACCOUNT_SYNC_STATUS_IDLE);
         if (ret != ACCOUNT_ERROR_NONE) {
            dlog_print(DLOG_INFO, LOG_TAG, "account_set_sync_support() is failed [%d : %s]", ret, get_error_message(ret));
            return;
         }
      
         /*
          * Insert the account handle into Account DB
          * If there is an account handle for the Sync Adapter already,
          * query it by using application ID
          */
         ret = account_insert_to_db(account, &account_id);
         if (ret == ACCOUNT_ERROR_DUPLICATED) {
            dlog_print(DLOG_INFO, LOG_TAG, "account is already exist and set properly");
            /* Query account id with application ID of SyncAdapter */
            ret = account_query_account_by_package_name(query_account_cb, SYNC_ADAPTER_APP_ID, NULL);
            if (ret == ACCOUNT_ERROR_NONE)
               dlog_print(DLOG_INFO, LOG_TAG, "account_query is success [%d]", ret);
            else
               dlog_print(DLOG_INFO, LOG_TAG, "account_query is failed [%d : %s]", ret, get_error_message(ret));
         } else if (ret != ACCOUNT_ERROR_NONE) {
            dlog_print(DLOG_INFO, LOG_TAG, "account_insert_to_db() is failed [%d : %s]", ret, get_error_message(ret));
            return;
         }
      
         /* After creating account, is_accountless flag is set as false */
         is_accountless = false;
      }
      
    • Click Set as accountless to set up the sync manager without an account (the result is shown on the right in the above figure):
      /*
       * Set accountless case for calling sync-manager APIs without Account
       */
      static void
      set_accountless()
      {
         dlog_print(DLOG_INFO, LOG_TAG, "Account ID is initialized");
         account_id = -1;
         is_accountless = true;
      }
      
    • An account handle should be removed when all of the related account sync job is removed.

On Demand Sync

To request an on demand sync:

Figure: On Demand Sync

On Demand Sync On Demand Sync

  1. To perform an on demand sync, select On Demand Sync as the Sync types on the Start sync with settings screen. Click Start Sync to trigger the corresponding sync manager functions:
    /*
     * Callback for operating on demand sync job
     * This function is a process of calling sync_manager_on_demand_sync_job()
     * Press "Start Sync" button with "Sync types" as "On Demand Sync"
     */
    static void
    cb_add_on_demand_sync(void *pData, Evas_Object *pObj, void *pEvent_info)
    {
       dlog_print(DLOG_INFO, LOG_TAG, "Sync Adapter : Request manual sync");
    
       /*
        * Create bundle and use set sync option as sync_job_user_data
        * displayed_interval will be used to show requested on demand sync job
        * when it does not be operated properly due to network disconnected
        */
       bundle *sync_job_user_data = NULL;
       sync_job_user_data = bundle_create();
       bundle_add_str(sync_job_user_data, "option", displayed_option);
    
       /*
        * Depending whether account is set, method of calling the API is decided
        * Below process includes getting account which is set and using it
        */
       int ret = SYNC_ERROR_NONE;
       if (is_accountless) {
          dlog_print(DLOG_INFO, LOG_TAG, "Sync Adapter : request accountless On Demand Sync");
          ret = sync_manager_on_demand_sync_job(NULL, "OnDemand", sync_option, sync_job_user_data, &on_demand_sync_job_id);
       } else {
          dlog_print(DLOG_INFO, LOG_TAG, "Sync Adapter : request On Demand Sync with an account");
          dlog_print(DLOG_INFO, LOG_TAG, "Account Id : [%d]", account_id);
          /* Query account by using account ID */
          ret = account_query_account_by_account_id(account_id, &account);
          if (ret != ACCOUNT_ERROR_NONE)
             dlog_print(DLOG_INFO, LOG_TAG, "account_query_account_by_account_id() is failed [%d : %s]", ret, get_error_message(ret));
          ret = sync_manager_on_demand_sync_job(account, "OnDemand", sync_option, sync_job_user_data, &on_demand_sync_job_id);
       }
    
       if (ret != SYNC_ERROR_NONE)
          dlog_print(DLOG_INFO, LOG_TAG, "sync_manager_on_demand_sync_job() is failed [%d : %s]", ret, get_error_message(ret));
       else
          dlog_print(DLOG_INFO, LOG_TAG, "Sync manager added on demand sync id [%d]", on_demand_sync_job_id);
    
       dlog_print(DLOG_INFO, LOG_TAG, "Sync Adapter : Exit the cb_add_on_demand_sync()");
    }
  2. When the sync manager schedules a sync job for this request, the sync callbacks in the Sync Adapter Service are invoked.

    When the sync job is completed, the service application communicates the same information to the Sync Adapter UI application using an application control. The UI application shows a popup to notify the user about the status.

    Check code which is indicated in bold.

    /*
     * App control callback
     */
    static void
    app_control(app_control_h app_control, void *data)
    {
       dlog_print(DLOG_INFO, LOG_TAG, "Sync Adapter : app_control is invoked");
    
       /* Get app control operation */
       char *operation;
       int ret = app_control_get_operation(app_control, &operation);
       if (ret != APP_CONTROL_ERROR_NONE) {
          dlog_print(DLOG_INFO, LOG_TAG, "Get app control operation is failed [%d : %s]", ret, get_error_message(ret));
          return;
       } else {
          dlog_print(DLOG_INFO, LOG_TAG, "App Control operation [%s]", operation);
       }
    
       /*
        * In the case of non-default App Control operation,
        * it has a respective operation depending on its kind of sync jobs
        */
       if (strcmp(operation, "http://tizen.org/appcontrol/operation/default")) {
          /*
           * Below popup object for displaying the sort of sync jobs
           * Pop-up is maintained during 2 seconds
           */
          Evas_Object *win = g_ad->nf, *popup;
          popup = elm_popup_add(win);
          elm_popup_align_set(popup, ELM_NOTIFY_ALIGN_FILL, 1.0);
          eext_object_event_callback_add(popup, EEXT_CALLBACK_BACK, eext_popup_back_cb, NULL);
          evas_object_size_hint_weight_set(popup, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
    
          /*
           * Sync complete message will be popped up depending on the kind of sync jobs,
           * On demand, Periodic, Data change sync job, which come from the Sync Adapter Service
           */
          if (operation && !strcmp(operation, "http://tizen.org/appcontrol/operation/on_demand_sync_complete"))
             elm_object_text_set(popup, "On Demand Sync is completed");
          else if (operation && !strcmp(operation, "http://tizen.org/appcontrol/operation/periodic_sync_complete"))
             elm_object_text_set(popup, "Periodic Sync is completed");
          else if (operation && !strcmp(operation, "http://tizen.org/appcontrol/operation/data_change_sync_complete"))
             elm_object_text_set(popup, "Data Change Sync is completed");
    
          /* Pop-up is maintained for 2 seconds */
          if (strcmp(operation, "http://tizen.org/appcontrol/operation/account/add")
             && strcmp(operation, "http://tizen.org/appcontrol/operation/account/configure")) {
             elm_popup_timeout_set(popup, TIME_FOR_POPUP);
             evas_object_show(popup);
          }
       }
    
       dlog_print(DLOG_INFO, LOG_TAG, "Sync operation complete");
    }
    

Periodic Sync

To request a periodic sync:

Figure: Periodic Sync

Periodic Sync Periodic Sync

  1. To perform a periodic sync, select Periodic Sync as the Sync types on the Start sync with settings screen. Click Start Sync to trigger the corresponding sync manager functions:
    /*
     * Callback for operating periodic sync job
     * This function is a process of calling sync_manager_add_periodic_sync_job()
     * Press "Start Sync" button with "Sync types" as "Periodic Sync"
     */
    static void
    cb_add_periodic_sync(void *pData, Evas_Object *pObj, void *pEvent_info)
    {
       dlog_print(DLOG_INFO, LOG_TAG, "Sync Adapter : Request periodic sync");
    
       /*
        * Create bundle and use set sync interval as sync_job_user_data
        * displayed_interval will be used to show registered periodic sync job
        */
       bundle *sync_job_user_data = NULL;
       sync_job_user_data = bundle_create();
       bundle_add_str(sync_job_user_data, "interval", displayed_interval);
    
       /*
        * Depending whether account is set, method of calling the API is decided
        * Below process includes getting account which is set and using it
        */
       int ret = SYNC_ERROR_NONE;
       if (is_accountless) {
          dlog_print(DLOG_INFO, LOG_TAG, "Sync Adapter : request accountless Periodic Sync");
          ret = sync_manager_add_periodic_sync_job(NULL, "Periodic", sync_interval, sync_option, sync_job_user_data, &periodic_sync_job_id);
       } else {
          dlog_print(DLOG_INFO, LOG_TAG, "Sync Adapter : request Periodic Sync with an account");
          dlog_print(DLOG_INFO, LOG_TAG, "Account Id : [%d]", account_id);
          /* Query account by using account ID */
          ret = account_query_account_by_account_id(account_id, &account);
          if (ret != ACCOUNT_ERROR_NONE)
             dlog_print(DLOG_INFO, LOG_TAG, "account_query_account_by_account_id() is failed [%d : %s]", ret, get_error_message(ret));
          ret = sync_manager_add_periodic_sync_job(account, "Periodic", sync_interval, sync_option, sync_job_user_data, &periodic_sync_job_id);
       }
    
       if (ret != SYNC_ERROR_NONE) {
          dlog_print(DLOG_INFO, LOG_TAG, "sync_manager_add_periodic_sync_job() is failed [%d : %s]", ret, get_error_message(ret));
       } else {
          dlog_print(DLOG_INFO, LOG_TAG, "Sync manager added periodic sync id [%d]", periodic_sync_job_id);
    
          /*
           * Adding periodic sync job will not send response immediately without expedited option
           * So, below pop-up messages show the result of adding periodic sync job
           */
          if ((sync_option == SYNC_OPTION_NONE) | (sync_option == SYNC_OPTION_NO_RETRY)) {
             Evas_Object *win = g_ad->nf, *popup;
             popup = elm_popup_add(win);
             elm_popup_align_set(popup, ELM_NOTIFY_ALIGN_FILL, 1.0);
             eext_object_event_callback_add(popup, EEXT_CALLBACK_BACK, eext_popup_back_cb, NULL);
             evas_object_size_hint_weight_set(popup, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
    
             if (sync_interval == SYNC_PERIOD_INTERVAL_30MIN)
                elm_object_text_set(popup, "It is expected in 30mins");
             else if (sync_interval == SYNC_PERIOD_INTERVAL_1H)
                elm_object_text_set(popup, "It is expected in an hour");
             else if (sync_interval == SYNC_PERIOD_INTERVAL_2H)
                elm_object_text_set(popup, "It is expected in 2 hours");
             else if (sync_interval == SYNC_PERIOD_INTERVAL_3H)
                elm_object_text_set(popup, "It is expected in 3 hours");
             else if (sync_interval == SYNC_PERIOD_INTERVAL_6H)
                elm_object_text_set(popup, "It is expected in 6 hours");
             else if (sync_interval == SYNC_PERIOD_INTERVAL_12H)
                elm_object_text_set(popup, "It is expected in 12 hours");
             else
                elm_object_text_set(popup, "It is expected in a day");
    
             /* Pop-up is maintained for 2 seconds */
             elm_popup_timeout_set(popup, TIME_FOR_POPUP);
             evas_object_show(popup);
          }
       }
    
       dlog_print(DLOG_INFO, LOG_TAG, "Sync Adapter : Exit the cb_add_periodic_sync()");
    }
    
  2. When the sync manager schedules a sync job for this request, the sync callback functions in the Sync Adapter Service are invoked periodically. When the job is completed, the service application communicates the same information to the Sync Adapter UI application by using an application control. The UI application shows a popup to notify the user about the status.

    Check code which is indicated in bold.

    /*
     * App control callback
     */
    static void
    app_control(app_control_h app_control, void *data)
    {
       dlog_print(DLOG_INFO, LOG_TAG, "Sync Adapter : app_control is invoked");
    
       /* Get app control operation */
       char *operation;
       int ret = app_control_get_operation(app_control, &operation);
       if (ret != APP_CONTROL_ERROR_NONE) {
          dlog_print(DLOG_INFO, LOG_TAG, "Get app control operation is failed [%d : %s]", ret, get_error_message(ret));
          return;
       } else {
          dlog_print(DLOG_INFO, LOG_TAG, "App Control operation [%s]", operation);
       }
    
       /*
        * In the case of non-default App Control operation,
        * it has a respective operation depending on its kind of sync jobs
        */
       if (strcmp(operation, "http://tizen.org/appcontrol/operation/default")) {
          /*
           * Below popup object for displaying the sort of sync jobs
           * Pop-up is maintained during 2 seconds
           */
          Evas_Object *win = g_ad->nf, *popup;
          popup = elm_popup_add(win);
          elm_popup_align_set(popup, ELM_NOTIFY_ALIGN_FILL, 1.0);
          eext_object_event_callback_add(popup, EEXT_CALLBACK_BACK, eext_popup_back_cb, NULL);
          evas_object_size_hint_weight_set(popup, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
    
          /*
           * Sync complete message will be popped up depending on the kind of sync jobs,
           * On demand, Periodic, Data change sync job, which come from the Sync Adapter Service
           */
          if (operation && !strcmp(operation, "http://tizen.org/appcontrol/operation/on_demand_sync_complete"))
             elm_object_text_set(popup, "On Demand Sync is completed");
          else if (operation && !strcmp(operation, "http://tizen.org/appcontrol/operation/periodic_sync_complete"))
             elm_object_text_set(popup, "Periodic Sync is completed");
          else if (operation && !strcmp(operation, "http://tizen.org/appcontrol/operation/data_change_sync_complete"))
             elm_object_text_set(popup, "Data Change Sync is completed");
    
          /* Pop-up is maintained for 2 seconds */
          if (strcmp(operation, "http://tizen.org/appcontrol/operation/account/add")
             && strcmp(operation, "http://tizen.org/appcontrol/operation/account/configure")) {
             elm_popup_timeout_set(popup, TIME_FOR_POPUP);
             evas_object_show(popup);
          }
       }
    
       dlog_print(DLOG_INFO, LOG_TAG, "Sync operation complete");
    }
    

Data Change Sync

To request a data change sync:

Figure: Data Change Sync

Data Change Sync Data Change Sync Data Change Sync

  1. To perform a data change sync, select Data Change Sync as the Sync types on the Start sync with settings screen. Click Start Sync to trigger the corresponding sync manager functions:
    /*
     * Callback for operating data change sync job
     * This function is a process of calling sync_manager_add_data_change_sync_job()
     * Press "Start Sync" button with "Sync types" as "Data Change Sync"
     */
    static void
    cb_add_data_change_sync(void *pData, Evas_Object *pObj, void *pEvent_info)
    {
       dlog_print(DLOG_INFO, LOG_TAG, "Sync Adapter : Request data change sync");
    
       /*
        * Depending whether account is set, method of calling the API is decided
        * Below process includes getting account which is set and using it
        */
       int ret = SYNC_ERROR_NONE, idx = 0;
       if (is_accountless) {
          dlog_print(DLOG_INFO, LOG_TAG, "Sync Adapter : request accountless Data Change Sync");
    
          /*
           * This logic is used to store data change sync job id
           * Because sync capabilities are six kinds, they should be stored
           * for managing the multiple of registered data change sync jobs
           */
          for (idx = 0; idx > NUM_OF_CAPABILITY; idx++) {
             if (data_change_id[idx] == -1) {
                ret = sync_manager_add_data_change_sync_job(NULL, sync_capability, sync_option, NULL, &data_change_sync_job_id);
                data_change_id[idx] = data_change_sync_job_id;
                dlog_print(DLOG_INFO, LOG_TAG, "[accountless case] restored data_change_id [%d] = %d", idx, data_change_id[idx]);
                break;
             } else {
                if (idx == NUM_OF_CAPABILITY - 1) {
                   dlog_print(DLOG_INFO, LOG_TAG, "data_change_id[idx] is full");
                   break;
                }
                continue;
             }
          }
       } else {
          dlog_print(DLOG_INFO, LOG_TAG, "Sync Adapter : request Data Change Sync with an account");
          dlog_print(DLOG_INFO, LOG_TAG, "Account Id : [%d]", account_id);
          /* Query account by using account ID */
          ret = account_query_account_by_account_id(account_id, &account);
          if (ret != ACCOUNT_ERROR_NONE)
             dlog_print(DLOG_INFO, LOG_TAG, "account_query_account_by_account_id() is failed [%d : %s]", ret, get_error_message(ret));
    
          /*
           * This logic is used to store data change sync job id
           * Because sync capabilities are six kinds and they should be stored
           * for managing the multiple of registered data change sync jobs
           */
          for (idx = 0; idx > NUM_OF_CAPABILITY; idx++) {
             if (data_change_id[idx] == -1) {
                ret = sync_manager_add_data_change_sync_job(account, sync_capability, sync_option, NULL, &data_change_sync_job_id);
                data_change_id[idx] = data_change_sync_job_id;
                dlog_print(DLOG_INFO, LOG_TAG, "[account case] restored data_change_id[%d] = %d", idx, data_change_id[idx]);
                break;
             } else {
                if (idx == NUM_OF_CAPABILITY - 1) {
                   dlog_print(DLOG_INFO, LOG_TAG, "data_change_id[idx] is full");
                   break;
                }
                continue;
             }
          }
       }
    
       if (ret != SYNC_ERROR_NONE) {
          dlog_print(DLOG_INFO, LOG_TAG, "sync_manager_add_data_change_sync_job() is failed [%d : %s]", ret, get_error_message(ret));
       } else {
          if (data_change_sync_job_id != -1)
             dlog_print(DLOG_INFO, LOG_TAG, "Sync manager added data change sync id [%d]", data_change_sync_job_id);
       }
    
       dlog_print(DLOG_INFO, LOG_TAG, "Sync Adapter : Exit the cb_add_data_change_sync()");
    }
    
  2. The sync manager stores the data change sync request. Whenever there is a change in the corresponding database (selected through Capability types), the sync manager schedules a sync job for the data. Sync callback functions in Sync Adapter Service are invoked accordingly.

    When the upload of the sync job is completed, the service application communicates the same information to the Sync Adapter UI application using an application control. The UI application shows a popup to notify the user about the status.

    Check code which is indicated in bold.

    /*
     * App control callback
     */
    static void
    app_control(app_control_h app_control, void *data)
    {
       dlog_print(DLOG_INFO, LOG_TAG, "Sync Adapter : app_control is invoked");
    
       /* Get app control operation */
       char *operation;
       int ret = app_control_get_operation(app_control, &operation);
       if (ret != APP_CONTROL_ERROR_NONE) {
          dlog_print(DLOG_INFO, LOG_TAG, "Get app control operation is failed [%d : %s]", ret, get_error_message(ret));
          return;
       } else {
          dlog_print(DLOG_INFO, LOG_TAG, "App Control operation [%s]", operation);
       }
    
       /*
        * In the case of non-default App Control operation,
        * it has a respective operation depending on its kind of sync jobs
        */
       if (strcmp(operation, "http://tizen.org/appcontrol/operation/default")) {
          /*
           * Below popup object for displaying the sort of sync jobs
           * Pop-up is maintained during 2 seconds
           */
          Evas_Object *win = g_ad->nf, *popup;
          popup = elm_popup_add(win);
          elm_popup_align_set(popup, ELM_NOTIFY_ALIGN_FILL, 1.0);
          eext_object_event_callback_add(popup, EEXT_CALLBACK_BACK, eext_popup_back_cb, NULL);
          evas_object_size_hint_weight_set(popup, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
    
          /*
           * Sync complete message will be popped up depending on the kind of sync jobs,
           * On demand, Periodic, Data change sync job, which come from the Sync Adapter Service
           */
          if (operation && !strcmp(operation, "http://tizen.org/appcontrol/operation/on_demand_sync_complete"))
             elm_object_text_set(popup, "On Demand Sync is completed");
          else if (operation && !strcmp(operation, "http://tizen.org/appcontrol/operation/periodic_sync_complete"))
             elm_object_text_set(popup, "Periodic Sync is completed");
          else if (operation && !strcmp(operation, "http://tizen.org/appcontrol/operation/data_change_sync_complete"))
             elm_object_text_set(popup, "Data Change Sync is completed");
    
          /* Pop-up is maintained for 2 seconds */
          if (strcmp(operation, "http://tizen.org/appcontrol/operation/account/add")
             && strcmp(operation, "http://tizen.org/appcontrol/operation/account/configure")) {
             elm_popup_timeout_set(popup, TIME_FOR_POPUP);
             evas_object_show(popup);
          }
       }
    
       dlog_print(DLOG_INFO, LOG_TAG, "Sync operation complete");
    }
    

Getting All Sync Jobs

To query all sync jobs requested by the Sync Adapter, click Manage sync jobs in the main screen.

Figure: Get all sync jobs

Foreach Sync Jobs

The corresponding sync manager functions are called:

/*
 * Callback for receiving the result of sync_manager_foreach_sync_job()
 * This function can receive the result to search sync jobs respectively
 * If there is sync_job_name in the result, On Demand or
 * Periodic sync job ID is stored for managing them
 * In the other case, Data Change sync job ID which is based on
 * the value of sync_capability is stored
 * Stored sync_job_id will be used to manage each sync job
 */
bool
sync_adapter_sample_foreach_sync_job_cb(account_h account, const char *sync_job_name, const char *sync_capability,
                                        int sync_job_id, bundle* sync_job_user_data, void *user_data)
{
   char sync_job_info[MAX_SIZE], *value = NULL;
   memset(sync_job_info, 0, sizeof(sync_job_info));

   /*
    * Below text are stored in sync_job_info is used to represent their list
    * When you press "Manage sync jobs" on main UI with registering sync job, the list is shown
    * This function is called repeatedly until all of the sync jobs are printed
    */
   if (sync_job_name) {
      if (!strcmp(sync_job_name, "OnDemand")) {
         bundle_get_str(sync_job_user_data, "option", &value);
         on_demand_sync_job_id = sync_job_id;
      } else if (!strcmp(sync_job_name, "Periodic")) {
         bundle_get_str(sync_job_user_data, "interval", &value);
         periodic_sync_job_id = sync_job_id;
      }
      sprintf(sync_job_info, "[%d] %s %s", sync_job_id, strdup(sync_job_name), strdup(value));
   } else if (sync_capability) {
      if (!strcmp(sync_capability, SYNC_SUPPORTS_CAPABILITY_CALENDAR))
         sprintf(sync_job_info, "[%d] Data Change for %s", sync_job_id, strdup("Calendar"));
      else if (!strcmp(sync_capability, SYNC_SUPPORTS_CAPABILITY_CONTACT))
         sprintf(sync_job_info, "[%d] Data Change for %s", sync_job_id, strdup("Contact"));
      else if (!strcmp(sync_capability, SYNC_SUPPORTS_CAPABILITY_IMAGE))
         sprintf(sync_job_info, "[%d] Data Change for %s", sync_job_id, strdup("Image"));
      else if (!strcmp(sync_capability, SYNC_SUPPORTS_CAPABILITY_MUSIC))
         sprintf(sync_job_info, "[%d] Data Change for %s", sync_job_id, strdup("Music"));
      else if (!strcmp(sync_capability, SYNC_SUPPORTS_CAPABILITY_SOUND))
         sprintf(sync_job_info, "[%d] Data Change for %s", sync_job_id, strdup("Sound"));
      else if (!strcmp(sync_capability, SYNC_SUPPORTS_CAPABILITY_VIDEO))
         sprintf(sync_job_info, "[%d] Data Change for %s", sync_job_id, strdup("Video"));
   } else if (cnt_sync_jobs == 0) {
         return true;
   }

   int idx, temp_idx = 0;
   for (idx = 0; idx < MAX_NUM; idx++) {
      if (list_of_sync_jobs[idx][0] == '\0') {
         remove_sync_job[idx] = sync_job_id;
         temp_idx = idx;
         break;
      }
   }
   strcpy(list_of_sync_jobs[temp_idx], sync_job_info);

   /* Count the entire number of registered sync jobs */
   cnt_sync_jobs++;

   return true;
}


/*
 * Callback for calling sync_manager_foreach_sync_job()
 * and drawing UI to contain the result on genlist.
 */
void
on_manage_sync_jobs_cb(void *data, Evas_Object *obj, void *event_info)
{
   dlog_print(DLOG_INFO, LOG_TAG, "Enter the Manage sync jobs");

   /* app_data */
   app_data_s *ad = NULL;
   ad = (app_data_s *) g_ad;
   if (ad == NULL) return;

   Evas_Object *nf = data, *layout, *scroller, *removeBtn, *selectAllBtn, *genlist;
   Elm_Object_Item *nf_it, *it;
   Elm_Genlist_Item_Class *itc;
   ad->nf = nf;

   scroller = create_scroller(nf);
   layout = elm_layout_add(scroller);
   evas_object_size_hint_weight_set(layout, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);

   char edj_path[PATH_MAX] = {0, };
   app_get_resource(EDJ_FILE, edj_path, (int)PATH_MAX);
   elm_layout_file_set(layout, edj_path, GRP_MAIN);
   ad->layout = layout;

   int idx, n_items;

   genlist = elm_genlist_add(layout);
   elm_genlist_block_count_set(genlist, MAX_NUM_LINE);
   elm_genlist_mode_set(genlist, ELM_LIST_COMPRESS);
   elm_genlist_homogeneous_set(genlist, EINA_TRUE);
   elm_object_part_content_set(layout, "genlist_tiny", genlist);
   elm_object_content_set(scroller, layout);

   memset(remove_sync_job, -1, sizeof(remove_sync_job));

   int ret = sync_manager_foreach_sync_job(sync_adapter_sample_foreach_sync_job_cb, NULL);

   for (idx = 0; idx < MAX_NUM; idx++) {
      if (list_of_sync_jobs[idx][0] != '\0')
         dlog_print(DLOG_INFO, LOG_TAG, "list_of_sync_jobs[%d] : %s", idx, list_of_sync_jobs[idx]);
   }

   itc = elm_genlist_item_class_new();
   itc->item_style = "type1";
   itc->func.content_get = get_content_registered_sync_jobs;
   itc->func.text_get = get_text_registered_sync_jobs;
   itc->func.del = gl_del_cb;

   n_items = cnt_sync_jobs;

   for (idx = 0; idx < n_items; idx++) {
      foreach_id = calloc(sizeof(list_item_data_s), 1);
      foreach_id->type = 6;
      foreach_id->index = idx;
      it = elm_genlist_item_append(genlist, itc, foreach_id, NULL, ELM_GENLIST_ITEM_TREE, NULL, nf);
      foreach_id->item = it;
   }

   /* Add a button and initialize text as "Select all" on the button */
   selectAllBtn = elm_button_add(nf);
   elm_object_style_set(selectAllBtn, "naviframe/title_right");
   elm_object_text_set(selectAllBtn, "Select all");
   evas_object_show(selectAllBtn);
   ad->selectAllBtn = selectAllBtn;

   if (ret == SYNC_ERROR_NONE)
      evas_object_show(genlist);
   else
      dlog_print(DLOG_INFO, LOG_TAG, "sync_manager_foreach_sync_job() is failed [%d : %s]", ret, get_error_message(ret));

   elm_genlist_item_class_free(itc);

   /*
    * Set "Select all" button for checking all of the items
    * If you press the button at the first time,
    * text on the button is changed to "Deselect all" and all of the items are checked
    * If the button is pressed again, the text is toggled as "Select all"
    * and all of the items are unchecked
    */
   evas_object_smart_callback_add(genlist, "selected", genlist_selected_cb, selectAllBtn);
   evas_object_smart_callback_add(selectAllBtn, "clicked", on_select_all_sync_jobs_cb, genlist);

   /*
    * Set "Remove" button for removing checked items
    * The button is enabled only when there is sync job
    * In the opposite case, it is shown as disabled
    */
   removeBtn = elm_button_add(layout);
   elm_object_text_set(removeBtn, "Remove");
   elm_object_part_content_set(layout, "remove_btn", removeBtn);
   evas_object_smart_callback_add(removeBtn, "clicked", on_remove_selected_sync_jobs_cb, nf);
   if (cnt_sync_jobs > 0)
      elm_object_disabled_set(removeBtn, EINA_FALSE);
   else
      elm_object_disabled_set(removeBtn, EINA_TRUE);

   evas_object_show(removeBtn);
   ad->removeBtn = removeBtn;

   /*
    * If you want to check all the things on lists,
    * just click the "Select all" button on upper right of the view
    */
   nf_it = elm_naviframe_item_push(nf, "Manage sync jobs", NULL, selectAllBtn, scroller, NULL);
   elm_object_item_part_content_set(nf_it, "title_right_btn", selectAllBtn);
   elm_naviframe_item_pop_cb_set(nf_it, foreach_naviframe_pop_cb, nf);
}

Removing All Sync Jobs

To remove registered sync jobs requested by the Sync Adapter, select the sync jobs to be removed on the Manage sync jobs screen and click Remove.

Figure: Removing sync jobs

Removing sync jobs

The corresponding sync manager functions are called:

/*
 * Callback for removing selected sync job
 */
void
on_remove_selected_sync_jobs_cb(void *data, Evas_Object *obj, void *event_info)
{
   dlog_print(DLOG_INFO, LOG_TAG, "Enter remove selected sync jobs");

   Evas_Object *nf = (Evas_Object *)data;
   int idx, idx2;

   /*
    * If "Remove" button is pressed without selected any sync job,
    * pop-up text, "Select any sync jobs first" rises on bottom of the view.
    */
   for (idx = 0; idx < cnt_sync_jobs; idx++) {
      if (list_of_remove_sync_job[idx])
         break;
      else if (idx == cnt_sync_jobs-1) {
         dlog_print(DLOG_INFO, LOG_TAG, "Sync Adapter : select any sync jobs first");

         Evas_Object *popup, *win = nf;

         popup = elm_popup_add(win);
         elm_popup_align_set(popup, ELM_NOTIFY_ALIGN_FILL, 1.0);
         eext_object_event_callback_add(popup, EEXT_CALLBACK_BACK, eext_popup_back_cb, NULL);
         evas_object_size_hint_weight_set(popup, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);

         elm_object_text_set(popup, "Select any sync jobs first");

         /* Pop-up is maintained for 2 seconds */
         elm_popup_timeout_set(popup, TIME_FOR_POPUP);
         evas_object_show(popup);
         return;
      }
   }

   /*
    * Registered sync jobs can be removed by using sync_manager_remove_sync_job()
    * with stored Sync Job ID in advance
    * After removing a sync job, variable which is used to store Sync Job ID should be initialized
    */
   for (idx = 0; idx < cnt_sync_jobs; idx++) {
      if (list_of_remove_sync_job[idx]) {
         sync_manager_remove_sync_job(remove_sync_job[idx]);
         list_of_remove_sync_job[idx] = false;
         dlog_print(DLOG_INFO, LOG_TAG, "Removed sync job: [%d]", remove_sync_job[idx]);
      }
      for (idx2 = 0; idx2 < NUM_OF_CAPABILITY; idx2++) {
         if (data_change_id[idx2] == remove_sync_job[idx]) {
            data_change_id[idx2] = -1;
            break;
         }
      }
      remove_sync_job[idx] = -1;
   }

   if (is_all_checked) {
      /*
       * If "Remove" button is pressed with all item checked,
       * all of the Data Change Sync Job IDs should be initialized
       */
      memset(data_change_id, -1, sizeof(data_change_id));
      /*
       * It would be good to remove account information also
       * when all of the sync jobs which are registered through the Sync Adapter are removed
       * Because this application can change account mode freely
       */
      int ret = account_delete_from_db_by_package_name(SYNC_ADAPTER_APP_ID);
      if (ret == ACCOUNT_ERROR_NONE) {
         dlog_print(DLOG_INFO, LOG_TAG, "Account DB is deleted successfully");
         if (account) {
            ret = account_destroy(account);
            if (ret == ACCOUNT_ERROR_NONE)
               dlog_print(DLOG_INFO, LOG_TAG, "Account handle is removed successfully");
         }
      }
      /* Initialize account ID which is no longer used */
      account_id = -1;
   }

   /* Initialize Sync Job ID */
   on_demand_sync_job_id = -1;
   periodic_sync_job_id = -1;

   elm_naviframe_item_pop(nf);

   /* Call below function again to draw renewed UI after removing sync jobs */
   on_select_manage_sync_jobs_cb(data, obj, event_info);
}