Taskmanager / src /

data.c

/*
 * Copyright (c) 2016 Samsung Electronics Co., Ltd
 *
 * Licensed under the Flora License, Version 1.1 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://floralicense.org/license/
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <package_manager.h>
#include <app_common.h>
#include <app_manager.h>
#include <Elementary.h>

#include "data.h"
#include "$(appName).h"
#include "item.h"
#include "defines.h"

static struct data_info {
	app_info_filter_h app_info_filter;
	Eina_List *apps_list;
	char *taskmgr_id;
} s_info = {
		.app_info_filter = NULL,
		.apps_list = NULL,
		.taskmgr_id = NULL
};

app_item_t *_item_create(const char *app_id, const char *icon_path);
static void _clear_application_list(void);
static bool _app_info_cb(app_info_h app_info, void *user_data);
static int _compare_strings(char *app_id1, char *app_id2);
static int _compare_items_cb(const void *data1, const void *data2);
static void _remove_app_from_list(char *app_id);


/**
 * @brief Initialization function for data module.
 */
void data_initialize(void)
{
	if (app_info_filter_create(&s_info.app_info_filter) != APP_MANAGER_ERROR_NONE) {
		dlog_print(DLOG_ERROR, LOG_TAG, "Failed to create app info filter");
		return;
	}

	if (app_info_filter_add_bool(s_info.app_info_filter, PACKAGE_INFO_PROP_APP_NODISPLAY, false) != APP_MANAGER_ERROR_NONE) {
		dlog_print(DLOG_ERROR, LOG_TAG, "Failed to set nodisplay property for filter");
		return;
	}

	if (app_get_id(&s_info.taskmgr_id) != APP_ERROR_NONE)
		dlog_print(DLOG_ERROR, LOG_TAG, "Failed to get taskmgr id");
}

/**
 * @brief Finalization function for data module.
 */
void data_finalize(void)
{
	if (app_info_filter_destroy(s_info.app_info_filter) != APP_MANAGER_ERROR_NONE)
		dlog_print(DLOG_ERROR, LOG_TAG, "Failed to destroy filter handle");

	s_info.app_info_filter = NULL;

	_clear_application_list();
}

/**
 * @brief Function which obtains a list of all the running applications.
 * For each found running application, an additional data is acquired:
 * - application identifier,
 * - application icon path.
 * These information is wrapped with app_item_t structure and packed into
 * a list.
 * @return This function returns the applications list if it was successfully
 * created, otherwise NULL is returned.
 */
Eina_List * data_application_mgr_get_running_apps(void)
{
	if (s_info.apps_list)
		_clear_application_list();

	if (!s_info.app_info_filter) {
		dlog_print(DLOG_ERROR, LOG_TAG, "App info filter not initialized");
		return NULL;
	}

	if (app_info_filter_foreach_appinfo(s_info.app_info_filter, _app_info_cb, NULL) != APP_MANAGER_ERROR_NONE) {
		dlog_print(DLOG_ERROR, LOG_TAG, "Failed to execute callback for each filtered application");
		return NULL;
	}

	s_info.apps_list = eina_list_sort(s_info.apps_list, 0, _compare_items_cb);

	return s_info.apps_list;
}

/**
 * @brief Function which terminates an application with given identifier.
 * @param[in] app_id The identifier of the application to be terminated.
 * @return This function returns 'true' if a requested application was successfully
 * terminated, otherwise 'false' is returned.
 */
bool data_application_mgr_terminate_app(char *app_id)
{
	app_context_h app_context = NULL;

	if (!app_id) {
		dlog_print(DLOG_ERROR, LOG_TAG, "Invalid parameter");
		return false;
	}

	if (app_manager_get_app_context(app_id, &app_context) != APP_MANAGER_ERROR_NONE) {
		dlog_print(DLOG_ERROR, LOG_TAG, "Failed to get app context");
		return false;
	}

	if (app_manager_request_terminate_bg_app(app_context) != APP_MANAGER_ERROR_NONE) {
		dlog_print(DLOG_ERROR, LOG_TAG, "Failed to terminate app");
		return false;
	}

	if (app_context_destroy(app_context) != APP_MANAGER_ERROR_NONE) {
		dlog_print(DLOG_ERROR, LOG_TAG, "Failed to destroy context handle");
		return false;
	}

	_remove_app_from_list(app_id);

	return true;
}

/**
 * @brief Function which resumes an application with given identifier.
 * @param[in] app_id The identifier of the application to be resumed.
 * @return This function returns 'true' if a requested application was successfully
 * resumed, otherwise 'false' is returned.
 */
bool data_application_mgr_resume_app(char *app_id)
{
	app_context_h app_context = NULL;

	if (!app_id) {
		dlog_print(DLOG_ERROR, LOG_TAG, "Invalid parameter");
		return false;
	}

	if (app_manager_get_app_context(app_id, &app_context) != APP_MANAGER_ERROR_NONE) {
		dlog_print(DLOG_ERROR, LOG_TAG, "Failed to get app context");
		return false;
	}

	if (app_manager_resume_app(app_context) != APP_MANAGER_ERROR_NONE) {
		dlog_print(DLOG_ERROR, LOG_TAG, "Failed to resume app");
		return false;
	}

	if (app_context_destroy(app_context) != APP_MANAGER_ERROR_NONE) {
		dlog_print(DLOG_ERROR, LOG_TAG, "Failed to destroy context handle");
		return false;
	}

	return true;
}

/**
 * @brief Internal function which creates an item for application's information
 * display (icon and application's identifier).
 * @param[in] app_id The identifier of an application which is to be displayed.
 * @param[in] icon_path The path to the application's icon to be displayed.
 * @return This function returns an allocated app_item_t structure with provided
 * data stored. If the function fails, then NULL is returned.
 */
app_item_t *_item_create(const char *app_id, const char *icon_path)
{
	app_item_t *item;

	if (!app_id || !icon_path) {
		dlog_print(DLOG_ERROR, LOG_TAG, "Invalid parameter");
		return NULL;
	}

	item = (app_item_t *)calloc(1, sizeof(app_item_t));
	if (!item) {
		dlog_print(DLOG_ERROR, LOG_TAG, "Allocation failed");
		return NULL;
	}

	item->app_id = strdup(app_id);
	item->icon_path = strdup(icon_path);

	return item;
}

/**
 * @brief Internal function which clears the applications list from all the
 * app_item_t structures.
 */
static void _clear_application_list(void)
{
	Eina_List *it = NULL;
	app_item_t *item = NULL;

	EINA_LIST_FOREACH(s_info.apps_list, it, item)
	{
		free(item->app_id);
		free(item->icon_path);
		free(item);
	}

	eina_list_free(s_info.apps_list);
	s_info.apps_list = NULL;
}

/**
 * @brief Internal callback function responsible for applications list creation.
 * This callback function is attached with app_info_filter_foreach_appinfo() function
 * and is invoked for each installed application which does not have 'no display' flag set.
 * Once this callback function is invoked, it obtains the application identifier,
 * associated icon's path and running state. If the running state is set to 'false',
 * then this function ends its execution, otherwise all the acquired information
 * is stored in a list in a form of app_item_t structure.
 * @param[in] app_info The application information handle which is used for application's
 * identifier and icon's path acquisition.
 * @param[in] user_data The user data passed to the app_info_filter_foreach_appinfo() function.
 * @return This function returns 'true' if provided app_info represents running application,
 * otherwise 'false' is returned.
 */
static bool _app_info_cb(app_info_h app_info, void *user_data)
{
	char *app_id = NULL;
	char *app_icon = NULL;
	bool running = false;
	app_item_t *new_item = NULL;

	if (app_info_get_app_id(app_info, &app_id) != APP_MANAGER_ERROR_NONE) {
		dlog_print(DLOG_ERROR, LOG_TAG, "Failed to get app id");
		return false;
	}

	if (app_info_get_icon(app_info, &app_icon) != APP_MANAGER_ERROR_NONE) {
		char *res_path = app_get_shared_resource_path();
		if(!res_path) {
			dlog_print(DLOG_ERROR, LOG_TAG, "Failed to get app icon");
			return false;
		}
		const char *common_icon = "taskmanager.png";
		app_icon = (char*)malloc(1 + strlen(res_path) + strlen(common_icon));
		sprintf(app_icon, "%s%s", res_path, common_icon);
	}

	if (app_manager_is_running(app_id, &running) != APP_MANAGER_ERROR_NONE) {
		free(app_id);
		free(app_icon);
		dlog_print(DLOG_ERROR, LOG_TAG, "Failed to get running state");
		return false;
	}

	if (running && _compare_strings(app_id, s_info.taskmgr_id)) {
		new_item = _item_create(app_id, app_icon);
		if (!new_item) {
			free(app_id);
			free(app_icon);
			dlog_print(DLOG_ERROR, LOG_TAG, "Failed to create new item");
			return false;
		}

		s_info.apps_list = eina_list_append(s_info.apps_list, new_item);
	}

	free(app_id);
	free(app_icon);

	return true;
}

/**
 * @brief Internal function which performs two strings comparison with length checking.
 * @param[in] app_id1 The first string.
 * @param[in] app_id2 The second string.
 * @return This function returns:
 * - -1 if the first character that does not match has a lower value in app_id1 than in app_id2
 *   or if both strings are equal,
 * - 1 if the first character that does not match has a greater value in app_id1 than in app_id2.
 */
static int _compare_strings(char *app_id1, char *app_id2)
{
	int ret = strncmp(app_id1, app_id2, ITEM_APP_ID_STR_MAX_LENGTH);

	if (strlen(app_id1) == strlen(app_id2) && !ret)
		return 0;
	else
		return ret > 0 ? 1 : -1;
}

/**
 * @brief Internal callback function responsible for two app_item_t structures comparison.
 * This function is attached with the eina_list_sort() function and is used for list
 * items sorting.
 * @param[in] data1 The first data object to compare.
 * @param[in] data2 The second data object to compare.
 * @return This function returns:
 * - -1 if the first character that does not match has a lower value in app_id1 than in app_id2
 *   or if both strings are equal,
 * - 1 if the first character that does not match has a greater value in app_id1 than in app_id2.
 */
static int _compare_items_cb(const void *data1, const void *data2)
{
	app_item_t *item1 = NULL;
	app_item_t *item2 = NULL;

	if (!data1 || !data2) {
		dlog_print(DLOG_ERROR, LOG_TAG, "Invalid parameter");
		return 0;
	}

	item1 = (app_item_t *)data1;
	item2 = (app_item_t *)data2;

	return _compare_strings(item1->app_id, item2->app_id);
}

/**
 * @brief Internal function responsible for app_item structure with given application
 * identifier removal from the list.
 * @param[in] app_id The application identifier which structure is to be removed.
 */
static void _remove_app_from_list(char *app_id)
{
	Eina_List *it = NULL;
	app_item_t *item = NULL;

	EINA_LIST_FOREACH(s_info.apps_list, it, item)
		if (!_compare_strings(item->app_id, app_id)) {
			s_info.apps_list = eina_list_remove(s_info.apps_list, item);
			free(item->app_id);
			free(item->icon_path);
			free(item);
			break;
		}
}