Published on 25th of October 2017
Application Package Manager

In this lesson we'll look at the package manager, its main functions and data types. We will show you how to make changes to the application by adding information about packages installed to the device.

Basic Functionality of the Package Manager

The package manager is designed to obtain detailed information about the installed on the device packages. This data includes the package name, application name, path to the application icon, etc.

To use the package manager functions and data types, add the following header file to the application:

#include <package_manager.h>

Also, to be able to get information about the package, add the following privilege to the project file manifest:

"http://tizen.org/privilege/packagemanager.info"

The main data type of the package manager module is:

package_info_h

Note that the object of this type is some kind of descriptor that serves for the identification of the package, and for obtaining detailed information. To work with it, you have to use the functions that will be considered in this lesson.

If you want to get the entire list of packages installed on the device, which is the most common example of use, consider the following function:

int package_manager_foreach_package_info(package_manager_package_info_cb callback,void *user_data);

The first parameter is a pointer to the selection function that will be called for each unique package (contains information about the package). The second parameter is the user data, which will be passed together with the call of the iterating function. The function returns code 0 in case of success, and a negative number in case of an error.

Let's consider in more detail the declaration of the sample function handler:

typedef bool (*package_manager_package_info_cb) (package_info_h package_info, void *user_data);

The first parameter is the object needed to get information about the package; the second parameter is a pointer to the user data that you’ve passed in the previous function call. The method returns a logical indication of whether to continue to retrieve the packets or not.

It should be noted that this function is used when there is no exact information about the required package or it is necessary to view all device packages. But if you need to get information about a particular package, and you know its indicator, use the following function to avoid wasting your time.

int package_info_create(const char *package,  package_info_h *package_info);

The first parameter is a pointer to a string containing the requested package identifier; the second parameter is a pointer to the package manager object that will be initialized inside the call of this function. The function returns code 0 in case of success, and a negative number in case of an error.

You can use another function to get the same result. Let's consider it:

int package_manager_get_package_info(const char *package_id, package_info_h *package_info);

All parameters in this function are similar to the previously considered function. But then the question arises: what is the difference between these two functions? The difference is in the return value. By calling the first function, you can check whether the requested package is installed on the device or not, for this check the return result of the function with the following macro:

PACKAGE_MANAGER_ERROR_NO_SUCH_PACKAGE

Unlike the first one, the second function does not return a specific error.

After a successful call of the creating a package object function, delete the received object by calling the following function:

int package_info_destroy(package_info_h package_info);

The function returns code 0 in case of success, and a negative number in case of an error. Note that you should call the function for object deletion only if you have created this object.

Get a List of All Packages Installed on the Device

Let's finally start practical part. Add call of a function to get a list of all the packages installed on the device. Also add the output to the log that the registered sample handler finished its work. Firstly, add the privilege to the manifest file of the project, to have the ability to get information about the packages in the application. Open the tizen-manifest.xml file of the project.

Go to the Privileges tab.

nw_025_01_en

Click "+" button.

In the opened dialog window, select the necessary privilege and click OK.

nw_025_02_en

Save the file.

Also add a header file to use the package manager functions and data types:

#include <package_manager.h>

Add a function to iterate all packages, installed on the device, and pass there a pointer to the iterator handler:

static bool
_app_create_cb(void *data)
{
   ...

   package_manager_foreach_package_info(_package_foreach_info_get, NULL);

   ...
}

Implement to the log window the handler with the messages output.

static bool
_package_foreach_info_get(package_info_h package_info, void *user_data)
{
   dlog_print(DLOG_INFO, "lesson25", " Package handler ");

   return true;
}

Run the application and open the logging window. Here we will see that our handler is called a number of times, since it is called for all, including system, packages.

nw_025_03_en
Getting Information about the Package

Let's look at the functions for getting detailed information about the package, using the received object.

Consider the group of functions that have the same parameters, to obtain such textual information about packages as:

Getting the package name:

int package_info_get_package(package_info_h package_info, char **package);

Getting the name of the application:

int package_info_get_label(package_info_h package_info, char **label);

Note that the function returns the name, depending on the language settings, installed on the device, when changing the language, it is necessary to recall this function again to get the name in the new current language.

Getting the absolute path to the application icon:

int package_info_get_icon(package_info_h package_info, char **path);

Getting the version number:

int package_info_get_version(package_info_h package_info, char **version);

Getting a package type (wgt - for web applications or tpk - for native ones):

int package_info_get_type(package_info_h package_info, char **type);

Getting the root path where the package is installed:

int package_info_get_root_path(package_info_h package_info, char **path);

The first parameter of these functions is the initialized object of the package manager; the second parameter is a double pointer to the string that will be completed inside the called function. The function returns code 0 in case of success, and a negative number in case of an error. Note that the received string should be deleted. And now consider a group of functions for verification that have the same parameters. Check if it is a system package or not:

int package_info_is_system_package(package_info_h package_info, bool *system);

Checking whether it is possible to delete a package:

int package_info_is_preload_package(package_info_h package_info, bool *preload);

The first parameter is the initialized object of the package information; the second parameter is a pointer to the Boolean variable that is set to the corresponding value after the call. The function returns code 0 in case of success, and a negative number in case of an error.

Now it's time to apply some of the considered functions in the demo application.

Add to the rotary selector widget the displaying of the information (package name, application name, icon path and version) only about the packages to be deleted. In addition, in the log will be displayed information about all installed packages. Let's create a structure, in which information about the package will be stored (package name, absolute path to the icon, and package version).

typedef struct _Install_Package_Info {
   char *label;
   char *path_icon;
   char *version;
} Install_Package_Info;

Let's add to the UIData structure a list for adding the Install_Package_Info objects of the structure:

typedef struct _UIData {
   ...

   Eina_List *list_package;
} UIData;

Use a data list from the built-in Eina library as a repository for information about packages. In the following lessons the work with this list will be considered in detail. Now we will not dwell on it.

Let's change the callback by adding a pointer to the UIData structure. Then we will fill the list, which is located in this structure, with the installed packages from the callback:

static bool
_app_create_cb(void *data)
{
   ...

   package_manager_foreach_package_info(_package_foreach_info_get, ui);

   _window_create(ui);

   ...
}

Rewrite the packet selection handler: add some calls to the above functions of getting information about the package, save the information in the Install_Package_Info structure. Then check if the package is removable, add it to the list. Output all received information about the package in the log.

static bool
_package_foreach_info_get(package_info_h package_info, void *user_data)
{
   UIData *ui = user_data;
   Install_Package_Info *install_pkg_info = calloc(1, sizeof(Install_Package_Info));
   if (!install_pkg_info) return false;

   memset(install_pkg_info, 0x0, sizeof(Install_Package_Info));

   package_info_get_label(package_info, &(install_pkg_info->label));
   package_info_get_icon(package_info, &(install_pkg_info->path_icon));
   package_info_get_version(package_info, &(install_pkg_info->version));

   bool is_removable = false;
   package_info_is_removable_package(package_info, &is_removable);
   if (is_removable)
     ui->list_package = eina_list_append(ui->list_package, install_pkg_info);

   char *root_path = NULL;
   package_info_get_root_path(package_info, &root_path);
   if (root_path)
     {
        dlog_print(DLOG_INFO, "lesson25", " The root directory of the package: %s", root_path);
        free(root_path);
     }

   dlog_print(DLOG_INFO, "lesson25", " Name: %s", install_pkg_info->label);
   dlog_print(DLOG_INFO, "lesson25", " Path to the icon: %s", install_pkg_info->path_icon);
   dlog_print(DLOG_INFO, "lesson25", " Version: %s", install_pkg_info->version); 

   if (!is_removable)
     {
        FREE_RESOURCE(install_pkg_info->label);
        FREE_RESOURCE(install_pkg_info->path_icon);
        FREE_RESOURCE(install_pkg_info->version);
        FREE_RESOURCE(install_pkg_info);
     }

   return true;
}

Don’t forget to implement the memory clearing for the newly allocated resources. In the function of the application termination handler, write the following code:

static void
_app_terminate_cb(void *data)
{
   ...

   Install_Package_Info *install_package_info = NULL;
   EINA_LIST_FREE(ui->list_package, install_package_info)
     {
        FREE_RESOURCE(install_package_info->label);
        FREE_RESOURCE(install_package_info->path_icon);
        FREE_RESOURCE(install_package_info->version);
        FREE_RESOURCE(install_package_info);
     }

   ...
}

FREE_RESOURCE macro (to clean up the resource) was implemented as follows:

#define FREE_RESOURCE(resource) \
   if (resource)                \
     free(resource);

We have received all the necessary information for displaying in the user interface. Change the function of creating the rotary selector widget by adding the list of received information about the deleted packages. Now the widget creation function looks like this:

static void
_rotary_selector_create(UIData *ui)
{
   ui->rotary_selector = eext_rotary_selector_add(ui->conform);
   eext_rotary_object_event_activated_set(ui->rotary_selector, EINA_TRUE);

   Eina_List *iterator = NULL;
   Install_Package_Info *install_package_info = NULL;
   EINA_LIST_FOREACH(ui->list_package, iterator, install_package_info)
     {
       Eext_Object_Item *item = eext_rotary_selector_item_append(ui->rotary_selector);

       Evas_Object *icon = elm_image_add(ui->rotary_selector);
       elm_image_file_set(icon, install_package_info->path_icon, NULL);
       
       evas_object_show(icon);
       eext_rotary_selector_item_part_content_set(item,
                                                  "item,bg_image",
                                                  EEXT_ROTARY_SELECTOR_ITEM_STATE_NORMAL,
                                                  icon);

       eext_rotary_selector_item_part_text_set(item,
                                               "selector,main_text",
                                               install_package_info->label);

       eext_rotary_selector_item_part_text_set(item,
                                               "selector,sub_text",
                                               install_package_info->version);
     }

   elm_object_content_set(ui->conform, ui->rotary_selector);
   evas_object_show(ui->rotary_selector);
}

There were removed the smart-callback handlers (created in the last lesson) for selecting and clicking elements that supposed to change the color of the elements. In this function, we iterate all the elements from the list. Next, create the rotary selector element and add there the following information:

- insert package name as the main text;

- insert package version as an additional text;

- insert the package icon as background content.

Run the application:

There is how it supposed looks like on the device Samsung Gear S3.

nw_025_04_en

As you can see there are installed applications displayed as the icons, the main text as the name of the application, and the version number as an additional text.

If you start rotating the bezel, then you will see that name and version number will change in accordance with the highlighted application.

Now if you launch the log window and filter messages by your tag, you will see a lot of information about all packages installed on the device.

In this example, was added a structure to store information about the packages. Still why for saving the data we need to create a separate structure and store its objects? This is done because the object of application control, which is passed to the function of the output handler, is temporary and after the execution of the handler body it is no longer valid. But there is a function that allows you to make copy of this object, let's consider it:

int package_info_clone(package_info_h *clone, package_info_h package_info);

The first parameter is a pointer to the object of the package manager that will contain this copy; the second parameter is the actual object that will be copied. The function returns code 0 in case of success, and a negative number in case of an error. Note that in this case the copied object ought to be deleted.

Using this function instead of creating structures, you can make a list of package manager objects, and when creating widget elements, call functions to get information about packages and add this information to the created items.

Important Functions

In this section, we will describe the list of functions to which you should pay attention during writing your applications. The first one is very simple. It can be useful if you have an application identifier and you need to know the identifier of the package to which the application belongs. Let’s look at the following function:

int package_manager_get_package_id_by_app_id(const char *app_id, char **package_id);

The first parameter is a pointer to a string containing the application identifier. The second parameter is a double pointer to a string containing the requested package identifier that will be filled in the calling function. Do not forget to delete the received line. The function returns code 0 in case of success, and a negative number in case of an error.

The second one is very interesting function for registering the handler for system packet events, such as removal, installation, and packages update. Let's look at the declaration of this function:

int package_manager_set_event_cb(package_manager_h manager,
                                 package_manager_event_cb callback,
                                 void *user_data);

The first parameter is the package manager object that should be created, using the package_manager_create function. The second parameter is the event handler connected to the package. And the third parameter is a pointer to user data. The function returns code 0 in case of success, and a negative number in case of an error. Note that the type of the package_manager_h object differs from the package_info_h object type, considered earlier, and should not be mixed-up. The most interesting thing in this function is the handler itself, let's consider its declaration:

typedef void (*package_manager_event_cb) (const char *type, 
                                          const char *package,
                                          package_manager_event_type_e event_type,
                                          package_manager_event_state_e event_state,
                                          int progress,
                                          package_manager_error_e error, 
                                          void *user_data);

As you can see the list of parameters is quit long, let's consider the most interesting of them. The second parameter is a pointer to a string containing the name of the package with which the current event is associated. The third parameter is the type of event.

Possible events:

- PACKAGE_MANAGER_EVENT_TYPE_INSTALL – the event is associated with a package installation;

- PACKAGE_MANAGER_EVENT_TYPE_UNINSTALL – the event is associated with a package removal

- PACKAGE_MANAGER_EVENT_TYPE_UPDATE – the event is associated with a package update.

The fourth parameter is the state of the packet with which the event is connected.

Let’s list the possible states:

- PACKAGE_MANAGER_EVENT_STATE_STARTED – beginning of the event;

- PACKAGE_MANAGER_EVENT_STATE_PROCESSING – the event in progress;

- PACKAGE_MANAGER_EVENT_STATE_COMPLETED – event is completed successfully;

- PACKAGE_MANAGER_EVENT_STATE_FAILED – the event completed with error.

If the event is in progress, you can use the fifth parameter to display the process of execution (% of performed work).

The last, third function, on which you should pay attention, is a function that iterate all application identifiers in the mentioned package with the specifying a type of the application.

The package can contain several applications, for example, one service application and one with a graphical interface.

int package_info_foreach_app_from_package(package_info_h package_info,
                                          package_info_app_component_type_e comp_type,
                                          package_info_app_cb callback,
                                          void *user_data);

The first parameter of the function is the package manager object, the second parameter is the type of application that you are interested in, the third parameter is the handler iterator for the package application identifiers, and the fourth parameter is a pointer to the user data. The function returns code 0 in case of success, and a negative number in case of an error.

Let’s list the possible application types:

- PACKAGE_INFO_ALLAPP – all applications;

- PACKAGE_INFO_UIAPP – applications with a graphical interface only;

- PACKAGE_INFO_SERVICEAPP – service applications only.

There is the declaration of the received application identifier handlers:

typedef bool (*package_info_app_cb) (package_info_app_component_type_e comp_type,
                                     const char *app_id,
                                     void *user_data);

The first parameter is the type of application that was mentioned above, the second parameter is the application identifier, and the third parameter is the passed user data. The function returns a Boolean value, indicating whether to continue the selection or not.

The full source code of this tutorial is available here WearLesson025

Leave a Reply

Your email address will not be published. Required fields are marked *