*/
typedef bool (*app_control_app_matched_cb)(app_control_h app_control, const char *appid, void *user_data);
+/**
+ * @brief Called when the result of the launch request is delivered.
+ *
+ * @since_tizen 5.0
+ * @remakrs The @a request is the same object for which app_control_send_launch_request_async() was called.
+ * @param[in] request The app_control handle of the launch request that has been sent
+ * @param[in] result The result value of the launch request
+ * @param[in] user_data The user data passed from the callback registration function
+ * @see app_control_send_launch_request_async()
+ */
+typedef void (*app_control_result_cb)(app_control_h request, app_control_result_e result, void *user_data);
+
typedef int (*app_control_host_res_fn)(void *data);
*/
int app_control_enable_app_started_result_event(app_control_h app_control);
+/**
+ * @brief Sends the launch request asynchronously.
+ *
+ * @details The operation is mandatory information for the launch request. \n
+ * If the operation is not specified, #APP_CONTROL_OPERATION_DEFAULT is used by default.
+ * If the operation is #APP_CONTROL_OPERATION_DEFAULT, the application ID is mandatory to explicitly launch the application.
+ * @details After the callee application is initialized or the launch request is delivered to the running application successfully, the result callback function will be invoked.
+ * @since_tizen 5.0
+ * @privlevel public
+ * @privilege %http://tizen.org/privilege/appmanager.launch
+ * @remarks The function returns #APP_CONTROL_ERROR_LAUNCH_REJECTED if the operation value is #APP_CONTROL_OPERATION_LAUNCH_ON_EVENT which is only for handling the event from the platform or other application, refer to the @a Event Module.
+ * @remarks The launch request of the service application over out of packages is restricted by the platform. Also, implicit launch requests are NOT delivered to service applications since @if MOBILE 2.4 @elseif WEARABLE 3.0 @endif. To launch a service application, an explicit launch request with application ID given by the app_control_set_app_id() must be sent.
+ * @param[in] app_control The app_control handle
+ * @param[in] result_cb The callback function to be called when the result is delivered
+ * @param[in] reply_cb The callback function to be called when the reply is delivered
+ * @param[in] user_data The user data to be passed to the callback function
+ * @return @c 0 on success,
+ * otherwise a negative error value
+ * @retval #APP_CONTROL_ERROR_NONE Successful
+ * @retval #APP_CONTROL_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #APP_CONTROL_ERROR_OUT_OF_MEMORY Out of memory
+ * @retval #APP_CONTROL_ERROR_APP_NOT_FOUND The application to run the given launch request is not found
+ * @retval #APP_CONTROL_ERROR_LAUNCH_REJECTED The application cannot be launched in current context
+ * @retval #APP_CONTROL_ERROR_LAUNCH_FAILED Failed to launch the application
+ * @retval #APP_CONTROL_ERROR_TIMED_OUT Failed due to timeout. The application that handles @a app_control may be busy
+ * @retval #APP_CONTROL_ERROR_PERMISSION_DENIED Permission denied
+ * @post If the launch request is sent for the result, the result will come back through the app_control_reply_cb() from the callee application. Additional replies may be delivered if app_control_enable_app_started_result_event() was called.
+ * @see app_control_result_cb()
+ * @see app_control_reply_to_launch_request()
+ * @see app_control_reply_cb()
+ * @see app_control_enable_app_started_result_event()
+ */
+int app_control_send_launch_request_async(app_control_h app_control,
+ app_control_result_cb result_cb,
+ app_control_reply_cb reply_cb,
+ void *user_data);
+
/**
* @}
*/
#define LAUNCH_MODE_SINGLE "single"
#define LAUNCH_MODE_GROUP "group"
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
+
typedef enum {
APP_CONTROL_TYPE_REQUEST,
APP_CONTROL_TYPE_EVENT,
typedef struct app_control_request_context_s {
app_control_h app_control;
+ app_control_result_cb result_cb;
app_control_reply_cb reply_cb;
void *user_data;
} *app_control_request_context_h;
+struct launch_request_s {
+ bool implicit_default_operation;
+ app_control_request_context_h request_context;
+ app_control_h app_control;
+ app_control_result_cb result_cb;
+ app_control_reply_cb reply_cb;
+ void *user_data;
+};
+
+typedef int (*launch_request_handler)(struct launch_request_s *req);
+
static int app_control_create_reply(bundle *data, struct app_control_s **app_control);
static const char *app_control_error_to_string(app_control_error_e error)
}
/* LCOV_EXCL_START */
-static void app_control_request_result_broker(bundle *appsvc_bundle, int appsvc_request_code, aul_svc_result_val appsvc_result, void *appsvc_data)
+static void app_control_request_reply_broker(bundle *appsvc_bundle, int appsvc_request_code, aul_svc_result_val appsvc_result, void *appsvc_data)
{
app_control_request_context_h request_context;
app_control_h request;
app_control_destroy(reply);
}
-int app_control_send_launch_request(app_control_h app_control, app_control_reply_cb callback, void *user_data)
+static app_control_error_e __launch_request_convert_error(int res)
{
- const char *operation;
- bool implicit_default_operation = false;
- int launch_pid;
- app_control_request_context_h request_context = NULL;
+ switch (res) {
+ case AUL_SVC_RET_OK:
+ return APP_CONTROL_ERROR_NONE;
+ case AUL_SVC_RET_ENOMATCH:
+ return APP_CONTROL_ERROR_APP_NOT_FOUND;
+ case AUL_SVC_RET_EILLACC:
+ return APP_CONTROL_ERROR_PERMISSION_DENIED;
+ case AUL_SVC_RET_EINVAL:
+ return APP_CONTROL_ERROR_INVALID_PARAMETER;
+ default:
+ return APP_CONTROL_ERROR_LAUNCH_REJECTED;
+ }
+}
+
+static void __handle_app_started_result(app_control_h app_control,
+ app_control_request_context_h request_context)
+{
+ char callee[256] = { 0, };
+ const char *str;
int ret;
- if (app_control_validate(app_control))
- return app_control_error(APP_CONTROL_ERROR_INVALID_PARAMETER, __FUNCTION__, NULL);
+ str = bundle_get_val(app_control->data,
+ AUL_SVC_K_LAUNCH_RESULT_APP_STARTED);
+ if (!str) {
+ aul_add_caller_cb(app_control->launch_pid,
+ __update_launch_pid, app_control);
+ return;
+ }
+
+ ret = aul_app_get_appid_bypid(app_control->launch_pid,
+ callee, sizeof(callee));
+ if (ret != AUL_R_OK) {
+ LOGE("Failed to get appliation ID. pid(%d)",
+ app_control->launch_pid);
+ }
+
+ aul_add_caller_cb(app_control->launch_pid,
+ __handle_launch_result, request_context);
+
+ if (strcmp(callee, APP_SELECTOR) &&
+ strcmp(callee, SHARE_PANEL))
+ aul_invoke_caller_cb(request_context);
+}
+
+static void app_control_request_result_broker(int request_code, int result,
+ void *user_data)
+{
+ app_control_request_context_h request_context;
+ app_control_error_e error = APP_CONTROL_ERROR_NONE;
+ app_control_h app_control;
+
+ request_context = (app_control_request_context_h)user_data;
+ if (request_context == NULL) {
+ LOGE("Invalid request");
+ return;
+ }
+
+ app_control = request_context->app_control;
+ app_control->launch_pid = result;
+ if (request_context->result_cb) {
+ if (result < 0)
+ error = __launch_request_convert_error(result);
+ request_context->result_cb(app_control, error,
+ request_context->user_data);
+ request_context->result_cb = NULL;
+ }
+
+ if (result > 0) {
+ __handle_app_started_result(app_control,
+ request_context->reply_cb ? request_context : NULL);
+ }
+
+ if (result < 0 || !request_context->reply_cb) {
+ app_control_destroy(request_context->app_control);
+ free(request_context);
+ }
+}
+
+static int __launch_request_verify_operation(struct launch_request_s *req)
+{
+ app_control_h app_control = req->app_control;
+ const char *operation;
+ const char *appid;
operation = aul_svc_get_operation(app_control->data);
- if (operation == NULL) {
- implicit_default_operation = true;
+ if (!operation) {
+ req->implicit_default_operation = true;
operation = APP_CONTROL_OPERATION_DEFAULT;
}
- if (!strcmp(operation, APP_CONTROL_OPERATION_LAUNCH_ON_EVENT))
- return app_control_error(APP_CONTROL_ERROR_LAUNCH_REJECTED, __FUNCTION__,
- "Not supported operation value");
-
- /* TODO: Check the privilege for call operation */
+ if (!strcmp(operation, APP_CONTROL_OPERATION_LAUNCH_ON_EVENT)) {
+ return app_control_error(APP_CONTROL_ERROR_LAUNCH_REJECTED,
+ __FUNCTION__, "Not supported operation value");
+ }
- /* operation : default */
if (!strcmp(operation, APP_CONTROL_OPERATION_DEFAULT)) {
- const char *appid = aul_svc_get_appid(app_control->data);
- if (appid == NULL)
- return app_control_error(APP_CONTROL_ERROR_APP_NOT_FOUND, __FUNCTION__, "package must be specified if the operation is default value");
+ appid = aul_svc_get_appid(app_control->data);
+ if (!appid) {
+ return app_control_error(APP_CONTROL_ERROR_APP_NOT_FOUND,
+ __FUNCTION__,
+ "Application ID must be specified");
+ }
}
- if (callback != NULL) {
- app_control_h request_clone = NULL;
+ return APP_CONTROL_ERROR_NONE;
+}
- request_context = calloc(1, sizeof(struct app_control_request_context_s));
- if (request_context == NULL)
- return app_control_error(APP_CONTROL_ERROR_OUT_OF_MEMORY, __FUNCTION__, NULL);
+static int __launch_request_prepare_request_context(struct launch_request_s *req)
+{
+ app_control_h app_control = req->app_control;
+ app_control_h request_clone;
+ int ret;
- request_context->reply_cb = callback;
+ if (!req->result_cb && !req->reply_cb)
+ return APP_CONTROL_ERROR_NONE;
- ret = app_control_clone(&request_clone, app_control);
- if (ret != APP_CONTROL_ERROR_NONE) {
- free(request_context);
- return app_control_error(ret, __FUNCTION__, "failed to clone the app_control request handle");
- }
+ req->request_context = calloc(1,
+ sizeof(struct app_control_request_context_s));
+ if (!req->request_context) {
+ return app_control_error(APP_CONTROL_ERROR_OUT_OF_MEMORY,
+ __FUNCTION__, "Ouf of memory");
+ }
- request_context->app_control = request_clone;
- request_context->user_data = user_data;
+ ret = app_control_clone(&request_clone, app_control);
+ if (ret != APP_CONTROL_ERROR_NONE) {
+ return app_control_error(ret, __FUNCTION__,
+ "Failed to duplicate app control handle");
}
- if (implicit_default_operation == true)
- aul_svc_set_operation(app_control->data, APP_CONTROL_OPERATION_DEFAULT);
+ req->request_context->app_control = request_clone;
+ req->request_context->result_cb = req->result_cb;
+ req->request_context->reply_cb = req->reply_cb;
+ req->request_context->user_data = req->user_data;
- launch_pid = aul_svc_run_service_for_uid(app_control->data, app_control->id, callback ? app_control_request_result_broker : NULL, request_context, getuid());
- if (implicit_default_operation == true)
- bundle_del(app_control->data, BUNDLE_KEY_OPERATION);
+ return APP_CONTROL_ERROR_NONE;
+}
- if (launch_pid < 0) {
- if (request_context) {
- if (request_context->app_control)
- app_control_destroy(request_context->app_control);
+static int __launch_request_send(struct launch_request_s *req)
+{
+ app_control_h app_control = req->app_control;
+ aul_svc_res_fn reply_cb;
+ aul_svc_err_cb result_cb;
+ int ret;
- free(request_context);
- }
+ reply_cb = req->reply_cb ? app_control_request_reply_broker : NULL;
+ result_cb = req->result_cb ? app_control_request_result_broker : NULL;
- if (launch_pid == AUL_SVC_RET_ENOMATCH)
- return app_control_error(APP_CONTROL_ERROR_APP_NOT_FOUND, __FUNCTION__, NULL);
- else if (launch_pid == AUL_SVC_RET_EILLACC)
- return app_control_error(APP_CONTROL_ERROR_PERMISSION_DENIED, __FUNCTION__, NULL);
- else if (launch_pid == AUL_SVC_RET_EINVAL)
- return app_control_error(APP_CONTROL_ERROR_INVALID_PARAMETER, __FUNCTION__, NULL);
- else
- return app_control_error(APP_CONTROL_ERROR_LAUNCH_REJECTED, __FUNCTION__, NULL);
+ if (req->implicit_default_operation) {
+ aul_svc_set_operation(app_control->data,
+ APP_CONTROL_OPERATION_DEFAULT);
}
- app_control->launch_pid = launch_pid;
- /* app_control_enable_app_started_result_event called */
- if (bundle_get_val(app_control->data, AUL_SVC_K_LAUNCH_RESULT_APP_STARTED)) {
- char callee[255] = {0,};
- if (aul_app_get_appid_bypid(launch_pid, callee, sizeof(callee)) != AUL_R_OK)
- LOGE("aul_app_get_appid_bypid failed: %d", launch_pid);
+ if (req->result_cb) {
+ ret = aul_svc_send_launch_request_for_uid(app_control->data,
+ app_control->id, reply_cb, result_cb,
+ req->request_context, getuid());
- if (request_context && request_context->app_control)
- request_context->app_control->launch_pid = launch_pid;
+ } else {
+ ret = aul_svc_run_service_for_uid(app_control->data,
+ app_control->id, reply_cb,
+ req->request_context, getuid());
+ }
- aul_add_caller_cb(launch_pid, __handle_launch_result, request_context);
+ if (req->implicit_default_operation)
+ bundle_del(req->app_control->data, BUNDLE_KEY_OPERATION);
- /* launched without app selector */
- if ((strcmp(callee, APP_SELECTOR) != 0) &&
- (strcmp(callee, SHARE_PANEL) != 0))
+ if (ret < 0) {
+ return app_control_error(__launch_request_convert_error(ret),
+ __FUNCTION__, NULL);
+ }
- aul_invoke_caller_cb(request_context);
+ app_control->launch_pid = ret;
- } else { /* default case */
- aul_add_caller_cb(launch_pid, __update_launch_pid, app_control);
- }
+ return APP_CONTROL_ERROR_NONE;
+}
+
+static int __launch_request_complete(struct launch_request_s *req)
+{
+ app_control_h app_control = req->app_control;
+ app_control_request_context_h request_context = req->request_context;
+
+ if (req->result_cb)
+ return APP_CONTROL_ERROR_NONE;
+
+ if (!request_context)
+ return APP_CONTROL_ERROR_NONE;
+
+ __handle_app_started_result(app_control,
+ request_context->reply_cb ? request_context : NULL);
return APP_CONTROL_ERROR_NONE;
}
+static int __send_launch_request(app_control_h app_control,
+ app_control_result_cb result_cb,
+ app_control_reply_cb reply_cb,
+ void *user_data)
+{
+ static launch_request_handler handlers[] = {
+ __launch_request_verify_operation,
+ __launch_request_prepare_request_context,
+ __launch_request_send,
+ __launch_request_complete,
+ };
+ struct launch_request_s req = {
+ .implicit_default_operation = false,
+ .request_context = NULL,
+ .app_control = app_control,
+ .result_cb = result_cb,
+ .reply_cb = reply_cb,
+ .user_data = user_data
+ };
+ int ret;
+ int i;
+
+ if (app_control_validate(app_control)) {
+ return app_control_error(APP_CONTROL_ERROR_INVALID_PARAMETER,
+ __FUNCTION__, NULL);
+ }
+
+ for (i = 0; i < ARRAY_SIZE(handlers); i++) {
+ if (handlers[i]) {
+ ret = handlers[i](&req);
+ if (ret != APP_CONTROL_ERROR_NONE)
+ break;
+ }
+ }
+
+ if (ret != APP_CONTROL_ERROR_NONE && req.request_context) {
+ if (req.request_context->app_control)
+ app_control_destroy(req.request_context->app_control);
+
+ free(req.request_context);
+ }
+
+ return ret;
+}
+
+int app_control_send_launch_request(app_control_h app_control,
+ app_control_reply_cb callback, void *user_data)
+{
+ int ret;
+
+ ret = __send_launch_request(app_control, NULL, callback, user_data);
+
+ return ret;
+}
+
int app_control_send_terminate_request(app_control_h app_control)
{
if (app_control_validate(app_control))
return APP_CONTROL_ERROR_NONE;
}
+
+int app_control_send_launch_request_async(app_control_h app_control,
+ app_control_result_cb result_cb,
+ app_control_reply_cb reply_cb,
+ void *user_data)
+{
+ int ret;
+
+ if (!app_control || !result_cb) {
+ return app_control_error(APP_CONTROL_ERROR_INVALID_PARAMETER,
+ __FUNCTION__, "Invalid parameter");
+ }
+
+ ret = __send_launch_request(app_control, result_cb,
+ reply_cb, user_data);
+
+ return ret;
+}