У цьому уроку ми розглянемо менеджер пакетів, його основні функції і типи даних. Подивимось як можна змінити додаток, доповнивши його інформацією про встановлені на пристрій пакети.
Менеджер пакетів передбачений для отримання детальної інформації про встановлені на пристрій пакети. Ця інформація включає в себе: ім’я пакету, назву додатку, шлях до іконки додатку і т. д.
Для використання функцій і типів даних менеджера пакетів, необхідно додати в вашу програму наступний заголовний файл:
#include <package_manager.h>
Також для того аби мати можливість отримувати інформацію про
пакет, необхідно додати в файл маніфесту проекту наступний привілей:
"http://tizen.org/privilege/packagemanager.info"
Основним типом даних модулю менеджера пакетів є:
package_info_h
Варто зазначити, що об’єкт даного типу – це свого роду дескриптор, який слугує для ідентифікації пакета і для отримання детальної інформації.
Для роботи з ним необхідно використовувати функції, які будуть розглянуті в цьому уроку.
Якщо необхідно отримати список встановлених на пристрої пакетів, що і є найбільш популярним прикладом використання, розгляньте наступні функції:
int package_manager_foreach_package_info(package_manager_package_info_cb callback, void *user_data);
Перший параметр – це вказівник на функцію вибірки, яка буде викликатись для кожного унікального пакету з інформацією про нього,
другий параметр – це дані користувача, які будуть передаватись разом з викликом функції вибірки. У разі успішного виконання функція повертає код 0, і в разі помилки – негативне число. Розглянемо більш детально оголошення обробника функції вибірки.
typedef bool (*package_manager_package_info_cb) (package_info_h package_info,void *user_data);
Перший параметр – це об’єкт необхідний для отримання інформації про пакет, другий параметр – це вказівник на дані користувача, які ви передали під час виклику попередньої функції. Метод повертає логічний признак продовжити вибірку пакетів чи ні.
Варто відзначити, що дана функція використовується, коли нема точної інформації про необхідний пакет чи необхідно подивитись всі пакети на пристрої. Якщо вам необхідно отримати інформацію про конкретний пакет і ви знаєте його ідентифікатор, аби уникнути непотрібних затрат часу на перебирання всіх пакетів, викличте цю функцію:
int package_info_create(const char *package, package_info_h *package_info);
Перший параметр – це вказівник на рядок, який мітить запитуваний ідентифікатор пакету, другий параметр – це вказівник на об’єкт менеджера пакетів, який буде проініціалізований всередині виклику цієї функції. У разі успішного виконання функція повертає код 0, а у випадку помилки – негативне число. Можна використовувати й іншу функцію для отримання такого ж результату. Давайте її розглянемо:
int package_manager_get_package_info(const char *package_id, package_info_h *package_info);
Всі параметри в цій функції аналогічні попередній.
Виникає питання. У чому ж різниця між цими двома функціями? А різниця у значенні, яке вони повертають. Іншими словами, викликавши першу функцію, можна перевірити чи встановлений певний пакет на пристрої. Для цього необхідно перевірити повернений результат виклику функції з наступним макросом:
PACKAGE_MANAGER_ERROR_NO_SUCH_PACKAGE
Після успішного виклику функції створення об’єкту пакету, необхідно видалити отриманий об’єкт, викликавши для цього наступну функцію:
int package_info_destroy(package_info_h package_info);
Функція приймає об’єкт менеджера пакетів, що видаляється і у разі успішного виконання повертає код 0, а в разі помилки – негативне число. Необхідно пам’ятати, що функцію видалення об’єкту варто викликати лише за умови, що ви самі його створюєте.
Давайте нарешті перейдемо до практики, додавши виклик функції для отримання списку всіх встановлених на пристрій пакетів. Далі у логування необхідно додати вивід про те, що зареєстрований обробник вибірки спрацював.
Спочатку додайте в маніфест-файл проекту вашого додатку привілей для отримання інформації про пакети.
Для цього в проекті відкрийте tizen-mainfest.xml файл.
Перейдіть у вкладку Privileges.
Натисніть кнопку "+".
У діалоговому вікні, що відкрилось, виберіть необхідний привілей і натисніть ОК.
Збережіть файл.
Крім того, необхідно додати заголовний файл для використання функції і типів даних менеджера пакетів.
#include <package_manager.h>
Додайте функцію для вибірки всіх встановлених пакетів на пристрої і передайте туди вказівник на обробник вибірки.
static bool
_app_create_cb(void *data)
{
...
package_manager_foreach_package_info(_package_foreach_info_get, NULL);
...
}
Потім реалізуйте сам обробник з виводом повідомлень у вікно логування.
static bool
_package_foreach_info_get(package_info_h package_info, void *user_data)
{
dlog_print(DLOG_INFO, "lesson25", "Обробник пакета");
return true;
}
Запустіть ваш додаток і відкрийте вікно логування. У ньому ви побачите, що ваш обробник викликається багато разів, так як він спрацьовує для всіх пакетів, включаючи системні.
Використовуючи отриманий об’єкт, давайте розглянемо функції для отримання детальної інформації про пакет. Розберемо групу функцій (мають однакові параметри) для отримання текстової інформації про пакет.
Отримання імені пакету:
int package_info_get_package(package_info_h package_info, char **package);
Отримання назви додатку:
int package_info_get_label(package_info_h package_info, char **label);
Тут варто звернути увагу не те, що функція повертає назву в залежності від мови, встановленої на пристрої. При зміні мови необхідно заново викликати цю функцію для отримання назви на поточній встановленій мові.
Отримання абсолютного шляху до іконки додатку:
int package_info_get_icon(package_info_h package_info, char **path);
Отримання номеру версії:
int package_info_get_version(package_info_h package_info, char **version);
Отримання типу пакету (wgt - для веб додатків чи tpk - для нативних):
int package_info_get_type(package_info_h package_info, char **type);
Отримання кореневого шляху, де встановлений пакет:
int package_info_get_root_path(package_info_h package_info, char **path);
Перший параметр функції – це проініціалізований об’єкт менеджера пакета, другий параметр – це подвійний вказівник на рядок, який буде заповнений всередині функції, що викликається. У разі успішного виконання функція повертає код 0, а у випадку помилки – негативне число. Необхідно запам’ятати, що отриманий рядок необхідно буде видалити.
А тепер розглянемо групу функцій з однаковими параметрами, передбачені для різних перевірок.
Чи є пакет системним:
int package_info_is_system_package(package_info_h package_info, bool *system);
Чи можливо видалити пакет:
int package_info_is_removable_package(package_info_h package_info, bool *removable);
Чи є пакет наперед встановленим в прошивці пристрою:
int package_info_is_preload_package(package_info_h package_info, bool *preload);
Перший параметр – це проініціалізований об’єкт інформації пакету, другий параметр – вказівник на логічну змінну, яка встановиться у відповідне значення після виклику функції. У разі успішного виконання функція повертає код 0, а в разі помилки – негативне число.
Тепер пора застосувати деякі, розглянуті вище, функції у демо-додатку. Додайте в rotary selector віджет відображення функції про пакети, що видаляються (назва пакету, назва додатку, шлях до іконки і версію), а в логування виводьте інформацію про всі встановлені пакети. Створіть структуру для збереження інформація про пакет(назву, абсолютний шлях до іконки і версію пакету).
typedef struct _Install_Package_Info {
char *label;
char *path_icon;
char *version;
} Install_Package_Info;
typedef struct _UIData {
...
Eina_List *list_package;
} UIData;
У якості сховища інформації про пакети, тут використовується список даних із вбудованої бібліотеки Eina. Зараз ми не будемо на цьому зупинятись і більш детально розглянемо роботу з цим списком в наступних уроках.
Змініть колбек, додавши вказівник на структуру UIData. Потім наповніть список, що знаходиться в даній структурі, встановленими пакетами з колбека:
static bool
_app_create_cb(void *data)
{
...
package_manager_foreach_package_info(_package_foreach_info_get, ui);
_window_create(ui);
...
}
А тапер необхідно написати обробник вибірки пакетів, додавши в нього деякі виклики функцій для отримання інформації про пакети, які були розглянуті вище. Збережіть отриману інформацію в об’єкті структури Install_Package_Info і далі перевірте: якщо пакет можна видалити – додайте його в список. А всю отриману інформацію про пакет, виведіть в логування.
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", "Кореневий каталог проекту: %s", root_path);
free(root_path);
}
dlog_print(DLOG_INFO, "lesson25", "Назва: %s", install_pkg_info->label);
dlog_print(DLOG_INFO, "lesson25", "Шлях до іконки: %s", install_pkg_info->path_icon);
dlog_print(DLOG_INFO, "lesson25", "Версія: %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;
}
Одразу реалізуйте очистку пам’яті для ресурсів, що були щойно виділені, для цього у функцію обробник завершення додатку напишіть наступний код:
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 для очищення ресурсу наступним чином:
#define FREE_RESOURCE(resource) \
if (resource) \
free(resource);
Ви отримали всю необхідну інформацію для відображення в інтерфейсі користувача.
Потрібно змінити функцію створення віджета rotary selector, додавши в нього відображення списку отриманої інформації про пакети, що мають бути видалені. Тепер функція створення віджету виглядають наступним образом:
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);
}
Були видалені обробники смарт-колбеків для вибору і натискання на елемент, створені в минулому уроку, для зміни кольору елементів.
У цій функції перебираються всі елементи списку. Далі створіть елемент rotary selector і додайте в нього наступну інформацію:
- в якості основного тексту вставте назву пакету;
- в якості додаткового тексту- версію пакету;
- в якості фонового контенту елемента – іконку пакета.
Запустіть додаток.
На пристрої Samsung Gear S3 у вас повинна вийти наступна картина.
Як бачите, в якості іконок відображаються встановлені додатки, в якості основного тексту – назви додатків і в якості додаткового тексту ви можете бачити номер версії.
Якщо ви почнете обертати безель, то побачите, що номер версії додатку буде змінюватись у відповідності з виділеним додатком.
Тепер якщо запустити вікно логування і відфільтрувати повідомлення по вашому тегу, то побачите багато інформації про всі встановлені на пристрої пакети.
У даному прикладі ви додали структуру для зберігання інформації про пакети. Тут може виникнути питання: «Навіщо для зберігання даних об’єктів необхідно зберігати окрему структуру і зберігати її об’єкти ?». Це зроблено тому, що об’єкт управління додатком, який передається у функцію обробника вибірки, є тимчасовим і після виконання тіла обробника він більш не є валідним. Але є функція, яка дозволяє робити копію цього об’єкта. Давайте її розглянемо.
int package_info_clone(package_info_h *clone, package_info_h package_info);
Перший параметр – це вказівник на менеджера пакетів, який буде містити копію, другий параметр – це власне об’єкт, який потрібно скопіювати. У разі успішного виконання – функція повертає код: 0, а у випадку помилки – негативне число. Необхідно пам’ятати, що в цьому випадку, об’єкт, що копіюється необхідно буде видалити.
Використавши цю функцію замість функції для створення структур, можна ініціалізувати список об’єктів менеджера пакетів і при створенні елементів віджета, викликати функції для отримання інформації про пакети і додавати цю інформацію в створені елементи.
У цьому розділі ми розглянемо ряд функцій, на які варто звернути увагу при написанні додатку.
Перша з них дуже проста. Вона може знадобитись, якщо у вас є ідентифікатор додатку і вам необхідно дізнатись ідентифікатор пакету, до якого належить цей додаток.
Розглянемо наступну функцію:
int package_manager_get_package_id_by_app_id(const char *app_id, char **package_id);
Перший параметр – це вказівник на рядок, що містить ідентифікатор додатку, другий параметр – це подвійний вказівник на рядок, що містить запитуваний індикатор пакету, який буде заповнено у функції, що викликається. Отриманий рядок необхідно обов’язково видалити. У разі успішного виконання функція повертає код 0, а в разі помилки – негативне число.
Друга дуже цікава функція, передбачена для реєстрації обробника на системні події пакетів(видалення, встановлення і оновлення). Давайте розглянемо оголошення цієї функції:
int package_manager_set_event_cb(package_manager_h manager,
package_manager_event_cb callback,
void *user_data);
Перший параметр – це об’єкт менеджера пакетів, який необхідно створити з допомогою функції package_manager_create, другий параметр – це обробник подій пов’язаних з пакетом, третій параметр – це вказівник на дані користувача. У разі успішного виконання функція повертає код 0, а в разі помилки – негативне число.
Варто зазначити, що тип об’єкта package_manager_h відрізняється від типу об’єкта package_info_h, який ми розглядали раніше.
Саме цікаве в цій функції – це власне обробник, давайте розглянемо його оголошення.
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);
Як ви можете бачити, перелік параметрів дуже великий, давайте розглянемо найбільш цікаві з них. Другий параметр – це вказівник на рядок, який містить ім’я пакету з яким пов’язана поточна подія. Третій параметр – це тип події.
Перелік можливих подій:
- PACKAGE_MANAGER_EVENT_TYPE_INSTALL – подія пов’язана з встановленням пакету;
- PACKAGE_MANAGER_EVENT_TYPE_UNINSTALL – подія пов’язана з видаленням пакету;
- PACKAGE_MANAGER_EVENT_TYPE_UPDATE – подія пов’язана з оновленням пакету.
Четвертий параметр – це стан, в якому знаходиться пакет, з яким пов’язана подія.
Перелік можливих подій:
- PACKAGE_MANAGER_EVENT_STATE_STARTED - початок події;
- PACKAGE_MANAGER_EVENT_STATE_PROCESSING – виконання події в процесі;
- PACKAGE_MANAGER_EVENT_STATE_COMPLETED –подія завершення успішного виконання;
- PACKAGE_MANAGER_EVENT_STATE_FAILED – подія закінчилась помилкою;
Якщо виконання події знаходиться в процесі, то можна використовувати п’ятий параметр для відображення відсотку виконання. Ну і остання, третя функція, на яку варто було б звернути увагу – це функція, що виконує вибірку всіх ідентифікаторів додатків у вибраному пакеті, з вказанням типу додатку. Тут варто зазначити, що пакет може містити в собі декілька додатків, наприклад, один сервіс-додаток і один з графічним інтерфейсом.
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);
Перший параметр функції – це об’єкт менеджера пакета, другий параметр – тип зображення, який вас цікавить, третій – обробник вибірки ідентифікаторів додатків пакету і четвертий параметр – вказівник на дані користувача. У разі успішного виконання функція повертає 0, а в разі помилки – негативне число.
Можливі типи додатків:
- PACKAGE_INFO_ALLAPP – всі додатки;
- PACKAGE_INFO_UIAPP – тільки додатки, що мають графічний інтерфейс;
- PACKAGE_INFO_SERVICEAPP – тільки сервісні додатки;
Розглянемо оголошення функції обробника отримання ідентифікаторів додатку.
typedef bool (*package_info_app_cb) (package_info_app_component_type_e comp_type,
const char *app_id,
void *user_data);
Перший параметр – це тип додатку, який був розглянутий вище, другий параметр – це власне ідентифікатор додатку і третій – передані дані користувача. Функція повертає логічне значення, що вказує продовжувати вибірку чи ні.
Проект з повним початковим кодом цього уроку доступний для скачування тут WearLesson025.