From 0adb3c936f34a5d1758e4d54c9da33488692df6e Mon Sep 17 00:00:00 2001 From: Hwankyu Jhun Date: Tue, 18 Dec 2018 09:31:04 +0900 Subject: [PATCH] Add a new API for sending launch request synchronously The functions supports to send the launch request synchronously. If the callee application is not replied, the function returns a negative error value. Adds: - app_control_send_launch_request_sync() Requires: - https://review.tizen.org/gerrit/#/c/platform/core/api/app-control/+/195749/ - https://review.tizen.org/gerrit/#/c/platform/core/appfw/aul-1/+/195971/ - https://review.tizen.org/gerrit/#/c/platform/core/appfw/amd/+/196292/ Change-Id: I1cb8dfc7cc74bb76a5c265714afe61a6e46dbed9 Signed-off-by: Hwankyu Jhun --- include/app_control.h | 31 ++++++++++++ src/app_control.c | 138 ++++++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 153 insertions(+), 16 deletions(-) diff --git a/include/app_control.h b/include/app_control.h index ad694f8..174e7f7 100755 --- a/include/app_control.h +++ b/include/app_control.h @@ -1306,6 +1306,37 @@ int app_control_send_launch_request_async(app_control_h app_control, void *user_data); /** + * @brief Sends the launch request synchronously. + * + * @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. + * @since_tizen 5.5 + * @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 applications, refer to the @ref Event Module. + * @remarks The platform does not allow launching service applications from packages other than the requesting application's package. 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 set by app_control_set_app_id() must be sent. + * @remarks If the callee application doesn't respond, the function returns a negative error value. + * @remarks The @a reply must be released using app_control_destroy(). + * @param[in] app_control The app_control handle + * @param[out] reply The app_control handle in which the results of the callee are contained + * @param[out] result The result code of the launch request + * @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 + * @see app_control_destroy() + */ +int app_control_send_launch_request_sync(app_control_h app_control, + app_control_h *reply, app_control_result_e *result); + +/** * @} */ diff --git a/src/app_control.c b/src/app_control.c index 5a3c4e6..99f0241 100644 --- a/src/app_control.c +++ b/src/app_control.c @@ -83,6 +83,8 @@ struct launch_request_s { app_control_result_cb result_cb; app_control_reply_cb reply_cb; void *user_data; + app_control_h reply; + app_control_result_e result; }; typedef int (*launch_request_handler)(struct launch_request_s *req); @@ -168,6 +170,29 @@ int app_control_validate_internal_key(const char *key) return 0; } +static app_control_result_e __get_app_control_result( + aul_svc_result_val appsvc_result) +{ + app_control_result_e result; + + switch (appsvc_result) { + case AUL_SVC_RES_OK: + result = APP_CONTROL_RESULT_SUCCEEDED; + break; + case AUL_SVC_RES_NOT_OK: + result = APP_CONTROL_RESULT_FAILED; + break; + case AUL_SVC_RES_CANCEL: + result = APP_CONTROL_RESULT_CANCELED; + break; + default: + result = APP_CONTROL_RESULT_CANCELED; + break; + } + + return result; +} + /* LCOV_EXCL_START */ static void app_control_request_reply_broker(bundle *appsvc_bundle, int appsvc_request_code, aul_svc_result_val appsvc_result, void *appsvc_data) { @@ -190,21 +215,7 @@ static void app_control_request_reply_broker(bundle *appsvc_bundle, int appsvc_r request_context = appsvc_data; request = request_context->app_control; - - switch (appsvc_result) { - case AUL_SVC_RES_OK: - result = APP_CONTROL_RESULT_SUCCEEDED; - break; - case AUL_SVC_RES_NOT_OK: - result = APP_CONTROL_RESULT_FAILED; - break; - case AUL_SVC_RES_CANCEL: - result = APP_CONTROL_RESULT_CANCELED; - break; - default: - result = APP_CONTROL_RESULT_CANCELED; - break; - } + result = __get_app_control_result(appsvc_result); user_data = request_context->user_data; reply_cb = request_context->reply_cb; @@ -938,7 +949,9 @@ static int __send_launch_request(app_control_h app_control, .app_control = app_control, .result_cb = result_cb, .reply_cb = reply_cb, - .user_data = user_data + .user_data = user_data, + .reply = NULL, + .result = APP_CONTROL_RESULT_FAILED, }; int ret; int i; @@ -1476,3 +1489,96 @@ int app_control_send_launch_request_async(app_control_h app_control, return ret; } + +static int __launch_request_send_sync(struct launch_request_s *req) +{ + app_control_h request = req->app_control; + bundle *reply_bundle = NULL; + aul_svc_result_val appsvc_result; + int ret; + + if (req->implicit_default_operation) { + aul_svc_set_operation(request->data, + APP_CONTROL_OPERATION_DEFAULT); + } + + ret = aul_svc_send_launch_request_sync_for_uid(request->data, + request->id, &reply_bundle, &appsvc_result, getuid()); + + if (req->implicit_default_operation) + bundle_del(request->data, BUNDLE_KEY_OPERATION); + + if (ret < 0) { + return app_control_error(__launch_request_convert_error(ret), + __FUNCTION__, NULL); + } + + request->launch_pid = ret; + + if (app_control_create_reply(reply_bundle, &req->reply) != 0) { + return app_control_error(APP_CONTROL_ERROR_INVALID_PARAMETER, + __FUNCTION__, "Failed to create reply handle"); + } + + req->result = __get_app_control_result(appsvc_result); + + return APP_CONTROL_ERROR_NONE; +} + +static int __send_launch_request_sync(app_control_h request, + app_control_h *reply, app_control_result_e *result) +{ + static launch_request_handler handlers[] = { + __launch_request_verify_operation, + __launch_request_send_sync, + }; + struct launch_request_s req = { + .implicit_default_operation = false, + .request_context = NULL, + .app_control = request, + .result_cb = NULL, + .reply_cb = NULL, + .user_data = NULL, + .reply = NULL, + .result = APP_CONTROL_RESULT_FAILED, + }; + int ret; + int i; + + if (app_control_validate(request)) { + 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) { + if (reply) { + *reply = req.reply; + } else { + app_control_destroy(req.reply); + } + + if (result) + *result = req.result; + } + + return ret; +} + +int app_control_send_launch_request_sync(app_control_h app_control, + app_control_h *reply, app_control_result_e *result) +{ + if (!app_control || !reply || !result) { + return app_control_error(APP_CONTROL_ERROR_INVALID_PARAMETER, + __FUNCTION__, "Invalid parameter"); + } + + return __send_launch_request_sync(app_control, reply, result); +} -- 2.7.4